fix: IN(subquery) data corruption in ungrouped aggregates with NOT NULL columns#5591
Merged
jussisaurio merged 2 commits intotursodatabase:mainfrom Feb 27, 2026
Conversation
…aggregates IN(subquery) returns 1 instead of NULL when used in an ungrouped aggregate query where no rows pass the WHERE clause. The stale cursor value is evaluated against the subquery instead of NULL, and wrong data gets physically stored via INSERT...SELECT. Reproducer: SELECT val IN (SELECT a FROM t), AVG(1) FROM t WHERE false; Differential fuzzer seed: 16648648351493581373 Simulator gap: IN(subquery) generation is commented out in sql_generation/generation/expr.rs line 177.
… column The IN expression compiler skipped the IsNull check on the LHS value when the column was declared NOT NULL. However, NullRow (used in ungrouped aggregates when no rows match the WHERE clause) overrides all column values to NULL regardless of the NOT NULL constraint. This caused IN(subquery) to evaluate against stale cursor data instead of NULL, returning 1 (true) when it should return NULL. Wrong values were then physically stored via INSERT...SELECT. Fix: always emit IsNull before NotFound/Found in IN expressions, even for NOT NULL columns. Differential fuzzer seed: 16648648351493581373 Simulator gap: IN(subquery) generation is commented out in sql_generation/generation/expr.rs line 177.
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.
Summary
IN(subquery)returns1instead ofNULLin ungrouped aggregate queries where no rows match theWHEREclause, when the LHS column is declaredNOT NULLINSERT...SELECT, corrupting persistent dataIsNullcheck when the LHS column wasNOT NULL, butNullRow(used in ungrouped aggregates with no matching rows) overrides all column values to NULL regardless of constraintsIsNullbeforeNotFound/Foundin IN expressionsReproducer
Simulator gap
IN(subquery)expression generation is commented out insql_generation/generation/expr.rsline 177:// TODO: skip InSelect as still need to implement ArbitratyFrom for SelectThe differential fuzzer (which does generate IN subqueries) found this bug with seed
16648648351493581373.Test plan
testing/runner/tests/in-subquery-ungrouped-aggregate.sqltest(all pass)cargo clippyclean