fix(cubesql): Push LIMIT 0 down to CubeScan - #11589
Conversation
Signed-off-by: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com>
|
Claude encountered an error after 5s —— View job I'll analyze this and get back to you. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #11589 +/- ##
==========================================
- Coverage 84.06% 79.54% -4.53%
==========================================
Files 257 484 +227
Lines 81582 99840 +18258
Branches 0 3679 +3679
==========================================
+ Hits 68581 79415 +10834
- Misses 13001 19877 +6876
- Partials 0 548 +548
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Claude finished @MazterQyou's task in 5m 44s —— View job Review: looks correct overall — 1 medium (MSSQL legacy pre-agg path), 4 low/nit; 2 inline comments postedFull review — click to expand
What the change doesThe core fix is the removal of the On the JS side, Good, careful work: the FindingsMedium — MSSQL legacy-planner pre-aggregation path silently drops the zero limit (inline on Low — no test covers the Tesseract MSSQL template change in isolation. Low — Low — Oracle Nit — duplicated/divergent parse logic between the two dialects (inline on Other notes
|
| // T-SQL requires FETCH NEXT to be greater than zero, so a zero row limit is | ||
| // rendered as `TOP 0` by topLimit() instead, and OFFSET is redundant for it | ||
| if (this.parsedRowLimit() === 0) { | ||
| return ''; | ||
| } |
There was a problem hiding this comment.
Returning '' here makes the zero limit depend entirely on topLimit() being rendered in the same statement. That holds for BaseQuery.commonQuery()/fullKeyQueryAggregate(), but not for the legacy-planner rollup path in PreAggregations.ts:1628:
const query = `SELECT ${this.query.selectAllDimensionsAndMeasures(measures)} FROM ${from} ...`
+ this.query.groupByClause();
return isFullSimpleQuery
? this.query.baseHaving(...) + this.query.orderBy() + this.query.groupByDimensionLimit()
: query;There is no topLimit() in that SELECT, so with CUBEJS_TESSERACT_SQL_PLANNER=false a rowLimit: 0 query served from a pre-aggregation on MSSQL emits no row-limiting clause at all and scans the whole rollup — the opposite of the cheap "schema probe" this PR is enabling. (Before this PR the same path emitted nothing either, since if (this.rowLimit) was falsy for 0, so it's a pre-existing gap rather than a regression — but this PR is the natural place to close it, and it's the one path where "no clause" now silently means "all rows" for an explicit LIMIT 0.)
Options: render the zero limit as a WHERE-level guard in groupByDimensionLimit()-less paths, teach PreAggregations.rollupPreAggregation to include topLimit(), or at minimum add a legacy-planner + pre-agg test for MSSQL so the behaviour is pinned. HiveQuery.simpleQuery() has the same shape (no topLimit()), though Hive isn't affected by the T-SQL constraint.
| const parsedRowLimit = this.rowLimit != null ? parseInt(this.rowLimit, 10) : NaN; | ||
| const rowLimit = Number.isNaN(parsedRowLimit) ? 10000 : parsedRowLimit; | ||
| const limitClause = this.rowLimit === null ? '' : ` FETCH NEXT ${rowLimit} ROWS ONLY`; |
There was a problem hiding this comment.
Two small things here:
-
This duplicates the parsing logic that
MssqlQuery.parsedRowLimit()now encapsulates, with a subtly different NaN policy (MSSQL:NaN → null → TOP 10000; here:NaN → 10000). Both land on 10000, but a shared protected helper onBaseQuery(e.g.parsedRowLimit()) would keep the two dialects from drifting and make the intent one-line obvious. -
this.rowLimit === nullis still a strict-null check while the parse above uses!= null, sorowLimit: undefinedrendersFETCH NEXT 10000 ROWS ONLYrather than no clause. That's pre-existing behaviour, but since this line is being touched it's worth deciding deliberately (a comment or!= nulleither way).
Check List
Description of Changes Made
This PR makes a row limit of 0 push all the way down to the database instead of being replaced by the default row limit. Related tests are included.