Repository navigation
fix(query): run an expression reading an or-bound variable after the ors (#625) - #629
Merged
Merged
Conversation
…ors (#625) optimizer::plan places expressions among the patterns and nots; or / or-join run after the planned list. An expression whose variable only an or binds was appended to the end of that list, so it ran before the or bound it and dropped every row -- on the executor, the streaming engine and in rule bodies. plan_seeded now defers an expression that reads a variable no pattern in the list and no expression placed before it binds, ahead of the deferred nots and in text order. The executor's two deferred passes run such expressions after apply_or_clauses (expressions cost 0, so the stable cheapest-first sort keeps them before the nots), the rule-body evaluator applies them after its or pass, and the engine already builds the deferred clauses after its Union steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PtCdzbJMSS1V8qEPaJ4jXz
…helper The coverage job runs without test-oracle, so the rule-body branch of the fix went uncovered (evaluator.rs branches 80.36%, floor 84%). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PtCdzbJMSS1V8qEPaJ4jXz
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This was referenced Oct 19, 2026
adityamukho
added a commit
that referenced
this pull request
Oct 19, 2026
…ors (#625, backport) (#630) Backport of #629 from v3. optimizer::plan appended an expression whose variable only an or / or-join binds to the end of the planned list, and the ors run after that list, so the expression saw the variable unbound and dropped every row, in queries and in rule bodies. plan now defers an expression that reads a variable no pattern in the list and no expression placed before it binds, ahead of the deferred nots and in text order. Both executor deferred passes run it after apply_or_clauses (via apply_expr_clauses; expressions cost 0, so the stable cheapest-first sort keeps them first), and the rule-body evaluator applies it after its or pass. Claude-Session: https://claude.ai/code/session_01PtCdzbJMSS1V8qEPaJ4jXz Co-authored-by: Claude Opus 5.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.
Part of #625 (data-integrity known issue; stays open until the v2.x patch ships, then a
mainbackport follows).Problem
optimizer::planplaces expressions among the patterns andnots;or/or-joinrun after the planned list. An expression whose variable only anorbinds was appended to the end of that list, so it ran before?xwas bound and dropped every row:Same on the executor, the streaming engine and in rule bodies.
Fix
plan_seededdefers an expression that reads a variable no pattern in the list and no expression placed before it binds (seeded variables count as bound). Deferred expressions come first in the deferred list, in text order, ahead of the deferrednots, which may read what they bind.apply_or_clausesnow runsExprtoo. Expressions cost 0, so the stable cheapest-first sort keeps them ahead of thenots.orpass (itsdeferredwas always empty before).Unionsteps, in the top-level plan and in hashed and correlated bodies. Only the comment changed.Tests
tests/plan_independence_test.rs(+3): the issue's query, a mixed pattern/orexpression, a binding-expression chain, anotreading a deferred expression's output, a query calling a rule, and a rule body. Every plan mode on executor and cursor, with the oracle.optimizerunit tests: the deferral itself (replacestest_expr_unbound_var_goes_to_end), chains of placed expressions stay planned, deferred order is exprs thennots.tests/disjunction_test.rs(+2): the same cases withouttest-oracle, so the coverage job reaches the rule-body path.cargo test: 1592 tests (1582 passing, 10 ignored).--features test-oracleall pass. clippy (default and--all-features) and fmt clean.Review
Codex (read-only) traced every
plancaller and found them consistent. It raised one case, a binding expression placed before anorthat binds its input. The parser rejects that with INT-018, so it cannot happen.🤖 Generated with Claude Code
https://claude.ai/code/session_01PtCdzbJMSS1V8qEPaJ4jXz