test(cubestore): failing test for the result corruption in #11545 - #11833
Open
connor-wayne-mcelroy wants to merge 1 commit into
Open
Conversation
A multi_stage measure that gates one base measure on another is served from a rollup as two leaf aggregations, a DISTINCT key set over their UNION ALL and a LEFT JOIN back to each leaf. Past 2048 join keys that query returns sums larger than the number of keys feeding them, but only while it carries both a top-level ORDER BY and a LIMIT -- dropping either returns correct values. Short date ranges stay under the boundary, which is why the corruption is invisible to spot checks and shifts months as the range widens. Adds the reduced, self-contained repro the issue asked for: one table, plain INSERTs, no Cube and no source database. Signed-off-by: Connor McElroy <connor.mcelroy@xyzz.dev> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Failing test for #11545, as requested.
multi_stage_gated_join_with_sort_and_limitinrust/cubestore/cubestore/src/sql/mod.rsis a self-contained Cube Store test — one table, plainINSERTs, no Cube, no pre-aggregation matching, no source database. It currently fails.What it asserts
A single rollup-shaped table holds 1100 orders in each of two months. The query is the SQL Cube's Tesseract planner emits verbatim for a
multi_stagemeasure that gates one base measure on another (CASE WHEN {sale} > 0 THEN {ticket_fraction} ENDwithadd_group_by), with only the table name substituted: two per-key leaf aggregations over the same table, aDISTINCTkey set built from theirUNION ALL, aLEFT JOINback to each leaf, and a top-levelORDER BY ... LIMIT.Each order contributes exactly
1toticket_fraction, so every month must return1100.Same table, same query text, same physical rows — only the two date literals differ. 1401 is larger than the number of distinct keys that feed the sum, which this query's algebra cannot produce: the key set is
SELECT DISTINCT, each leaf is pre-grouped to one row per(order, month), and the joins are on the full composite key.What narrows it down
While reducing this from a production model, three things turned out to be load-bearing:
ORDER BYandLIMITtogether. Removing either one — theORDER BY, or theLIMIT— makes the same query return correct values. That points at the sort/limit pushdown intoClusterSend(pull_up_cluster_send'sLogicalPlan::Sortbranch and theworker_sort_and_limitdescriptor) rather than at the join.LIMIT 10000is far above the 2-row result, so it is the pushdown, not the limit value.(order, month)keys the query is always correct; at 2049+ it corrupts. The test sits just over that line at 2200 keys. This is why the bug is invisible on short date ranges and why which months are wrong shifts with the width of the range asked for.ORDER BY. Order ids interleave across the two months, so index order (by id) and the leaves'ORDER BY monthdisagree, as they do for real order ids. With ids assigned month-by-month (so the two orders agree) the same query returns correct values.Row counts are right throughout —
SELECT count(*)over the key set and over each join stage all return 2200. Only the summed values are wrong, so nothing duplicates rows; the join pairs keys with values that do not belong to them.One note on the test harness
The test runs its runtime on an explicitly sized thread. Planning this query shape recurses deeply enough to overflow libtest's default 2 MiB stack in a debug build — it aborts the whole test binary with
fatal runtime error: stack overflowbefore reaching any assertion, which is why the explicit stack is there. That looks unrelated to the corruption (release frames are much smaller, and production gives select workers 4 MiB viaCUBESTORE_SELECT_WORKER_STACK_SIZE), but it may be the same deep-recursion path as the "recursion limit reached" crash, so flagging it rather than burying it.Current output:
Versions
Reproduces identically on
cubejs/cubestore:v1.7.4,v1.7.19andlatest, single-node and router+workers, on freshly built tables. Decimal measures behave the same as the ints used here; the test uses ints to keep the assertions readable.Signed-off-by: Connor McElroy connor.mcelroy@xyzz.dev