fix(parity): close P11 — SELECT alias on the LHS of an IN-subquery#39
Merged
Conversation
`WHERE dbl IN (SELECT ...)` where `dbl` aliases `price * 2` errored with "Column 'dbl' not found". Fixing it took two layers; the second was a pre-existing bug the alias case merely exposed. 1. R2 migration of WhereAliasExpander. Rewrote expand_expression to intercept only the two nodes that carry a real rule (a bare column naming an alias; a method-call string receiver the walker can't reach) and delegate all structural recursion to walk::map_children. That retires the hand-rolled arms and the `_ => (clone, false)` catch-all (R3), and picks up the four subquery-LHS variants for free: the walker visits their same-scope operands while treating the nested SelectStatement as an opaque scope boundary, so an alias name reused inside the subquery body is correctly left alone. 2. Expression LHS in evaluate_in_list / evaluate_between. Once the alias expands, the LHS is `price * 2` — and `price * 2 IN (SELECT ...)` fails even with no alias, because the InOperatorLifter (which lifts an expression-LHS IN-list into a computed CTE column) only matches InList/NotInList, while an IN-subquery's InList is synthesized later by SubqueryExecutor, after the lifter ran. Added RecursiveWhereEvaluator::evaluate_operand_value, which looks up a plain column but evaluates any other expression via ArithmeticEvaluator — the same delegation evaluate_binary_op already does for its LHS. Corpus select_alias_in_in_subquery now AGREEs (77 AGREE / 1 DIFFER / 5 GAP). Regression test: where_alias_expander::test_expands_alias_on_in_subquery_lhs_not_body. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
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
Closes P11:
SELECT symbol, price * 2 AS dbl FROM trades WHERE dbl IN (SELECT price * 2 FROM trades WHERE price > 185)errored withColumn 'dbl' not found. Parity board moves 76 → 77 AGREE, 6 → 5 GAP; the corpus caseselect_alias_in_in_subquerynow AGREEs and the--checkgate locks it.Fixing it took two layers — the second was a pre-existing bug the alias case merely exposed.
1. R2 migration of
WhereAliasExpanderThe transformer was a hand-rolled recursion ending in a
_ => (clone, false)catch-all (an R3 pattern), so it silently droppedInSubquery/NotInSubquery/ the tuple forms — the same-scope LHS operand was skipped along with the subquery body.Rewrote
expand_expressionto intercept only the two nodes that carry a real rule (a bare column that names an alias; a method-call string receiver the walker can't reach) and delegate all structural recursion towalk::map_children. That:SelectStatementas an opaque scope boundary, so an alias name reused inside the subquery body is correctly left untouched.Regression:
where_alias_expander::test_expands_alias_on_in_subquery_lhs_not_body.2. Expression LHS in
evaluate_in_list/evaluate_betweenOnce
dblexpands toprice * 2, the LHS is a compound expression — andprice * 2 IN (SELECT ...)fails even with no alias. TheInOperatorLifternormally lifts an expression-LHSIN-list into a computed CTE column, but it only matchesInList/NotInList; anIN-subquery'sInListis synthesized later bySubqueryExecutor, after the lifter has run, soevaluate_in_listreceived a raw expression LHS and itsextract_column_nameerrored.Added
RecursiveWhereEvaluator::evaluate_operand_value, which looks up a plain column but evaluates any other expression through theArithmeticEvaluator— the same delegationevaluate_binary_opalready does for its LHS.INandBETWEENnow both accept a compound LHS. This stands on its own (it also fixes alias-freeexpr IN (subquery)); the long-term home is the R7 per-row subquery evaluation.Testing
77 AGREE / 1 DIFFER / 5 GAP, contract holds (83 cases).cargo test --lib: 687 passed, 0 failed (incl. the new expander test).cargo test --test integration: 407 passed, 0 failed.cargo fmtclean.🤖 Generated with Claude Code