Skip to content

docs(sql-api): correct stale claim that CASE expressions can't be pushed down - #11385

Open
igorlukanin wants to merge 4 commits into
masterfrom
igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api
Open

docs(sql-api): correct stale claim that CASE expressions can't be pushed down#11385
igorlukanin wants to merge 4 commits into
masterfrom
igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api

Conversation

@igorlukanin

@igorlukanin igorlukanin commented Jul 27, 2026

Copy link
Copy Markdown
Member

Summary

  • The SQL API docs claimed a CASE expression "won't work" and that "it is not possible to translate CASE expressions in measures". That has been stale since query pushdown was enabled by default (feat: Enable CUBESQL_SQL_PUSH_DOWN by default #8814, v1.0.0). Both the example the page called impossible and its MAX(CASE ...) variant execute correctly today.
  • Replaced the passage with a working example — a fiscal year derived via CASE/EXTRACT and grouped with MEASURE() — and documented the actual failure modes for Can't detect Cube query and it may be not supported yet: query pushdown disabled via CUBESQL_SQL_PUSH_DOWN, or a data source that doesn't support pushing down one of the expressions used.
  • Kept the nested-query fallback, but corrected it. The inner query now uses a plain DATE_TRUNC granularity instead of EXTRACT, so it stays a regular-query shape; an EXTRACT-based inner query itself needs pushdown and so is useless in the exact configuration the workaround is offered for.

The failure is not specific to combining MEASURE with an expression — a CASE/EXTRACT query with no measure at all fails identically when pushdown is off. The boundary is that any expression over a dimension requires the pushdown wrapper. This matches the code: the error is raised in rewrite/converter.rs gated only on !wrapped, and the rules owning wrapper/case.rs / wrapper/extract.rs are registered only when sql_push_down is enabled (rewrite/rewriter.rs).

Support is also driver-dependent: expressions/extract is added per-driver (PostgresQuery.ts) rather than in BaseQuery.js, so a data source without that template can hit the same error even with pushdown enabled. The page now says so instead of implying the behavior is universal.

Docs-only; no runtime code changes.

Test plan

Verified against Cube v1.7.4 with Postgres, on a minimal orders cube:

  • The new primary example returns correct fiscal years with default settings; EXPLAIN shows CubeScanWrappedSql with EXTRACT pushed to the datasource
  • With CUBESQL_SQL_PUSH_DOWN=false, it reproduces the documented error verbatim
  • The nested-query example returns identical correct results with pushdown both on and off
  • Same behavior on the legacy planner (CUBEJS_TESSERACT_SQL_PLANNER=false), so the planner is not a factor
  • The removed warning covers no still-true limitation — CASE in a WHERE clause and MEASURE nested inside a CASE both work
  • mintlify broken-links --check-anchors reports no new broken links (the 16 reported are pre-existing in embedding/iframe/, untouched here); docs.json still valid

@igorlukanin
igorlukanin requested a review from keydunov as a code owner July 27, 2026 22:50
@claude

claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 2m 3s —— View job


Review: docs-only correction, well-targeted — 1 medium, 3 low

The core claim is right and the fix is a real improvement: the old "won't work / not possible to translate CASE expressions in measures" passage has been stale since pushdown became default in 1.0. Verified against the code — the Can't detect Cube query error is raised in rewrite/converter.rs gated only on !wrapped, and the wrapper/case.rs / wrapper/extract.rs rules are registered only under sql_push_down, so "any expression over a dimension needs the pushdown wrapper" is the correct boundary. Nice catch that the old workaround's EXTRACT-based inner query was itself useless in the one configuration it was offered for.

4 inline comments posted. Nothing blocking.

Full review — findings, verification notes, and task list

Findings

# Severity Location Issue
1 Medium query-format.mdx:176-197 Nested-query fallback is only result-correct for additive measures; silently wrong for count_distinct / avg / ratio measures (incl. this page's own completed_percentage). Worth one caveat sentence.
2 Low query-format.mdx:166 Verbatim error block has a trailing period; source string (converter.rs:1751, :1973) has none.
3 Low query-format.mdx:143-146 "Expressions that have no post-processing shape" is undefined jargon; the plainer "expressions over dimensions" rule is both simpler and matches the code.
4 Low query-format.mdx:190 MEASURE(count) AS count + outer SUM(count) reads as calling the count aggregate.

Structural note (not filed inline)

Lines 143–197 sit under ### Query post-processing (99) but now explain pushdown behavior, the CUBESQL_SQL_PUSH_DOWN env var, and the fallback — all forward-referencing ### Query pushdown (199). The old text had the same placement, so this is pre-existing, but the new copy leans on pushdown much harder. Consider relocating the passage after line 209 in a follow-up.

What checks out

  • [ref-env-var-push-down] is defined at line 421 and #cubesql_sql_push_down matches the ## CUBESQL_SQL_PUSH_DOWN heading in environment-variables.mdx:1496, consistent with the underscore-anchor convention used elsewhere (e.g. sql-api/index.mdx:201).
  • [ref-queries-wpp] / [ref-regular-queries] were already defined; no dangling references introduced.
  • #query-pushdown in-page anchor resolves to the ### Query pushdown heading.
  • count / orders / created_at member naming matches the rest of the page.
  • Error string matches the Rust source apart from finding MUTEX for requests #2.
  • Choosing DATE_TRUNC over EXTRACT for the inner query is the right call — it maps to a granularity in a regular query, so the fallback survives with pushdown off.
  • Docs-only; no runtime code touched, so no security, performance, or test-coverage surface. Style conforms to docs-mintlify/CLAUDE.md (surgical edit to an existing page, no padding).

Not independently verified

I did not stand up a Cube instance, so the runtime claims in your test plan (both queries executing, the EXPLAIN plan, the pushdown-off reproduction) rest on your verification against v1.7.4. The static/code-level reasoning behind them holds up.

Task list

  • Read PR context and diff against origin/master
  • Classify request (code review)
  • Verify the staleness claim against CubeSQL rewrite rules
  • Verify link references and anchor targets resolve
  • Check error-message text against source
  • Review both SQL examples for correctness and member-naming consistency
  • Check docs-mintlify/CLAUDE.md style conventions
  • Check for prior unresolved Claude threads (none exist on this PR)
  • Post inline comments and summary
• branch [`igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api`](https://github.com/cube-js/cube/tree/igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api)

@mintlify

mintlify Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
cubed3 🟢 Ready View Preview Jul 27, 2026, 10:51 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Comment thread docs-mintlify/reference/core-data-apis/sql-api/query-format.mdx
Comment thread docs-mintlify/reference/core-data-apis/sql-api/query-format.mdx
Comment thread docs-mintlify/reference/core-data-apis/sql-api/query-format.mdx Outdated
@claude

claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 1m 2s —— View job


Review complete — docs-only, accurate on the main claim; 4 prior threads still apply (0 high, 1 medium, 3 low)

Full review
  • Gather context (diff vs origin/master, current file state)
  • Verify the core claim against the Rust source
  • Check link references and anchors resolve
  • Dedupe against my own prior review threads
  • Post review

Verdict

The central correction is right. wrapper/case.rs and wrapper/extract.rs rules are registered only under sql_push_down (rust/cubesql/cubesql/src/compile/rewrite/rewriter.rs), and the "can't detect Cube query" bail in converter.rs is gated on !wrapped — so CASE/EXTRACT over a dimension works today via pushdown and fails only with pushdown off. The old "won't work" passage was genuinely stale. Replacing an impossible example with a working one, plus a corrected fallback whose inner query stays a regular-query shape, is a real improvement.

Link references check out: [ref-regular-queries] (:416), [ref-queries-wpp] (:417), and the new [ref-env-var-push-down] (:423) all resolve, and #cubesql_sql_push_down exists at docs-mintlify/reference/configuration/environment-variables.mdx:1496.

The second commit's additions read well — "or if the data source doesn't support pushing down one of the expressions used" correctly widens the failure surface, and "applied as post-processing on top of the cube query" is a more accurate framing than the old "not part of the SQL query that being rewritten".

Re-affirmed prior threads

The file is unchanged (blob 74f1df4) since my earlier comments, so all four threads still apply as posted — no duplicates created:

Line Severity Concern
197 Medium Nested-query fallback is only result-correct for additive measures; silently wrong for count_distinct / avg / ratio measures (incl. this page's own completed_percentage)
146 Low "Expressions that have no post-processing shape" is undefined jargon; the simpler rule — any expression over a dimension needs the pushdown wrapper — is both truer and more useful
166 Low Error string has no trailing period in source (converter.rs:1751, :1973); readers will string-match this block
190 Low MEASURE(count) AS count + outer SUM(count) reads like calling the count aggregate; a distinct alias makes the two levels obvious

Not applicable

Security, performance, and test-coverage dimensions are moot here — no runtime code changed, and there's no test surface for prose. The author's manual verification against v1.7.4 with pushdown on and off is the right validation for this change; I did not re-run it (no Cube instance in this environment).

• branch [`igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api`](https://github.com/cube-js/cube/tree/igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api)

Comment thread docs-mintlify/reference/core-data-apis/sql-api/query-format.mdx
@claude

claude Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 56s —— View job


Re-review after push — all 4 prior findings addressed; nothing new blocking (0 high, 0 medium, 1 low)

Full review — verification, resolved threads, one optional refinement
  • Diff current HEAD against origin/master
  • Read the updated passage (query-format.mdx:143-205)
  • Check each of my 4 prior threads against the new text
  • Verify the error string still matches the Rust source
  • Verify link references and anchors still resolve
  • Resolve my own now-addressed threads
  • Post summary

Prior findings — all fixed

Prior severity Concern Status
Medium Nested-query fallback silently wrong for non-additive measures Fixed — caveat added at :202-205, and you confirmed the count_distinct repro (3 vs 2 unique customers)
Low Trailing period on the verbatim error block Fixed — :168 now matches converter.rs:1751 / :1973 exactly
Low "no post-processing shape" jargon Fixed — :143-147 now states the actual rule (expressions over dimensions need the pushdown wrapper)
Low MEASURE(count) AS count / SUM(count) reads as an aggregate call Fixed — orders_count on both levels (:189, :193); innerinner_query is a good extra touch

All four threads resolved on my side. No human-reviewer threads were touched.

Still checks out

  • [ref-env-var-push-down] (:429) → #cubesql_sql_push_down, which exists at environment-variables.mdx:1496; [ref-regular-queries] and [ref-queries-wpp] unchanged and defined.
  • #query-pushdown resolves to the ### Query pushdown heading at :207.
  • The inner query stays a regular-query shape (DATE_TRUNC granularity, no expressions), so the fallback survives with pushdown off — the whole point of the correction.
  • Docs-only. No runtime code, so no security, performance, or test surface. Style matches docs-mintlify/CLAUDE.md: surgical edit, no padding, text/sql fences.

One optional refinement (low, non-blocking)

The caveat I suggested — "group the inner query by the same granularity you need in the output" — is sound in general but doesn't fully resolve this page's own example. Fiscal year isn't expressible as a regular-query granularity (year starts in January), so a reader with a count_distinct measure who needs a fiscal-year grouping has no working fallback at all when pushdown is off. If you want to close that loop, one clause would do it, e.g. after "would produce incorrect values":

If no supported granularity matches the grouping you need, such as a fiscal year, enable query pushdown or define the grouping as a dimension in your data model.

Entirely your call — the current text isn't wrong, just leaves that dead end implicit.

Not independently verified

I did not stand up a Cube instance, so the runtime claims (both queries executing, the EXPLAIN plan, the pushdown-off reproduction, the count_distinct repro) rest on your verification against v1.7.4. The code-level reasoning behind them holds.

• branch [`igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api`](https://github.com/cube-js/cube/tree/igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api)

@igorlukanin
igorlukanin force-pushed the igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api branch from 7e8eab6 to ed2ff99 Compare July 30, 2026 18:09
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 54s —— View job


Re-review after push — no content change since the last pass; nothing blocking (0 high, 0 medium, 0 new low)

Full review — verification, prior threads, one still-open optional refinement
  • Diff current HEAD against origin/master
  • Compare against the state reviewed previously
  • Re-verify the error string against the Rust source
  • Re-verify link references and anchor targets
  • Check prior review threads (dedupe / resolve)
  • Post summary

What changed

Nothing in the content. HEAD is still ed2ff99, the same three commits (66e5537, d338275, ed2ff99) and the same blob (05c1ecf) I reviewed on the previous pass — this synchronize carried no new edits to query-format.mdx. So the previous verdict stands unchanged: the core correction is right, and all four earlier findings are already fixed in the tree.

Re-verified against the current tree

Check Result
Error block text :168 matches converter.rs:1751 / :1973 exactly — no trailing period
[ref-regular-queries] defined at :422
[ref-queries-wpp] defined at :423
[ref-env-var-push-down] defined at :429#cubesql_sql_push_down; heading exists at environment-variables.mdx:1498, and the backtick-stripped anchor form matches the convention used in sql-api/index.mdx:201 and queries.mdx:49
#query-pushdown resolves to the ### Query pushdown heading
Additive caveat present at the end of the nested-query section
Aliasing orders_count used consistently on both levels; AS inner_query

Docs-only — no runtime code, so security, performance, and test-coverage dimensions have no surface here. Style still matches docs-mintlify/CLAUDE.md.

Prior threads

All four of my earlier threads are already resolved on the PR; none were re-opened by this push, and I created no new inline comments (nothing new to raise). No human-reviewer threads touched.

One optional refinement, still open (low, non-blocking)

Carried over from the last pass, unaddressed and entirely your call. The additive caveat tells a reader with a count_distinct measure to "group the inner query by the same granularity you need in the output" — but a fiscal year isn't expressible as a regular-query granularity, so for this page's own example that reader has no working fallback when pushdown is off. One clause after "would produce incorrect values" would close the loop:

If no supported granularity matches the grouping you need, such as a fiscal year, enable query pushdown or define the grouping as a dimension in your data model.

Fix this →

Not independently verified

I did not stand up a Cube instance, so the runtime claims (both queries executing, the EXPLAIN plan, the pushdown-off reproduction, the count_distinct repro) continue to rest on your verification against v1.7.4. The code-level reasoning behind them holds.

• branch igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api

@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude finished @igorlukanin's task in 44s —— View job


Re-review after push — the last open refinement is now closed; nothing blocking (0 high, 0 medium, 0 low)

Full review — what changed, verification, thread status
  • Diff current HEAD against origin/master
  • Review the new commit (b91b67c)
  • Re-verify link references and anchor targets
  • Check prior review threads (dedupe / resolve)
  • Post summary

What changed

One new commit on top of the previously reviewed state: b91b67c docs(sql-api): point non-additive measures without a matching granularity at pushdown. It appends the clause I flagged as the one remaining loose end (query-format.mdx:204-206):

If no supported granularity matches that grouping, as is the case for a fiscal year, enable query pushdown or define the grouping as a dimension in your data model.

That closes the dead end the additive caveat left implicit — a reader with a count_distinct measure who needs a fiscal-year grouping and has pushdown off now has an explicit direction instead of a workaround that can't express the grouping. Wording is tighter than my suggestion and reads better in place. Nothing else in the file moved.

With that, I have no open findings on this PR.

Re-verified against the current tree

Check Result
Error block text :169 matches converter.rs:1751 / :1973 exactly — no trailing period
[ref-regular-queries] defined at :424
[ref-queries-wpp] defined at :425
[ref-env-var-push-down] defined at :431#cubesql_sql_push_down; heading exists at environment-variables.mdx:1498
#query-pushdown resolves to the ### Query pushdown heading at :209
Additive caveat + new clause present at :201-206, immediately after the nested-query block
Aliasing orders_count on both levels; AS inner_query
Non-additive examples named count_distinct / avg, both real measure types (:59); the page's own completed_percentage (:271) is the ratio case this protects

Core claim still holds against the source: wrapper/case.rs and wrapper/extract.rs rules are registered only under sql_push_down in rewrite/rewriter.rs, and the "can't detect Cube query" bail in converter.rs is gated on !wrapped — so CASE/EXTRACT over a dimension works today via pushdown and fails only with pushdown off or an unsupported data source.

Docs-only. No runtime code, so security, performance, and test-coverage dimensions have no surface here. Style matches docs-mintlify/CLAUDE.md: surgical edit to an existing page, no padding, text/sql fences, root-relative link refs.

Prior threads

All four of my earlier threads are resolved; none were re-opened by this push, and I created no new inline comments — nothing new to raise. No human-reviewer threads touched.

Not independently verified

I did not stand up a Cube instance, so the runtime claims (both queries executing, the EXPLAIN plan, the pushdown-off reproduction, the count_distinct repro) continue to rest on your verification against v1.7.4. The code-level reasoning behind them holds.

• branch igor/core-441-ai-generated-fiscal-year-query-not-runnable-via-the-sql-api

@igorlukanin

Copy link
Copy Markdown
Member Author

Took the optional refinement in b91b67c — a count_distinct over a fiscal year had no working fallback with pushdown off, since a fiscal year isn't a regular-query granularity. The caveat now points at pushdown or a dimension in the data model.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant