Repository navigation
Register a bare query operand as a subquery scope - #10
Merged
Merged
Conversation
build_scope only registered a subquery wrapper, EXISTS, IN and ANY/ALL operands, and walk_in_scope stops at a bare Select/Union/Intersect/Except. A query that is a plain operand of an expression, such as the argument of ARRAY(SELECT ...), therefore got no scope, and its tables and columns were invisible to everything built on the scope tree. sqlglot treats every unwrapped query in scope as a subquery. collect_subqueries_in_expr now also registers each bare query among the children of a node the walk yields, through the same branch/build_child path, so ScopeVisitor reports it. The existing pointer dedup keeps each operand to a single scope. FROM/JOIN items, CTE bodies and set operation branches are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fa6xBWiFS7JFH5kt1epZ7o
…ry public enter_scope now receives the node from the expression given to build_scope_with instead of the scope's own copy, matching reference and skipped, so a visitor can link nodes of the input to the scopes built for them. scope_query is public and re-exported alongside build_scope_with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fa6xBWiFS7JFH5kt1epZ7o
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fa6xBWiFS7JFH5kt1epZ7o
The quantified-expression arm registered its operand as a scope whatever its shape, so `x = ANY(ARRAY(SELECT y FROM u))` produced an empty scope for the ARRAY(...) function in addition to the scope of the inner query that the bare operand arm now registers. Register the operand only when it is itself a query; an array or value operand is walked like any other expression, so the statement yields one subquery scope with the inner query's sources. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fa6xBWiFS7JFH5kt1epZ7o
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fa6xBWiFS7JFH5kt1epZ7o
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fa6xBWiFS7JFH5kt1epZ7o
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fa6xBWiFS7JFH5kt1epZ7o
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.
build_scopegives no scope to a query that is a plain operand of an expression, such as the argument ofARRAY(SELECT x FROM t). That query's tables and columns are invisible to everything built on the scope tree.It happens because of two gaps:
build_scoperegisters a subquery scope only for an unaliasedSubquerywrapper and forEXISTS,INandANY/ALLoperands.walk_in_scopestops at a bareSelect/Union/Intersect/Except.sqlglot treats every unwrapped query in scope as a subquery, so this is a parity fix.
Where the shape occurs
ARRAY(<query>)parses to a function with a bare query argument in every dialect, including when the argument is aUNION.f(SELECT ...)).What changes
collect_subqueries_in_exprnow also registers every bare query that is a child of a node the walk yields. It uses the samebranch/build_childpath as the other operands, soScopeVisitorreports the new scopes too.IN/EXISTS/Subquery/ANY/ALLoperand exactly one scope.walk_in_scope, which still stops at bare queries. The small helperis_bare_queryis shared withshould_stop_at.ANY/ALLnow register their operand only when it is a query.x = ANY(ARRAY(SELECT ...))used to produce an empty scope for theARRAY(...)operand plus the inner query's scope. It now yields one subquery scope, with the inner query's sources.ORDER BY/LIMIT.Tests
ARRAY(SELECT ...)in Generic, BigQuery and PostgreSQL, aUNIONargument, and a ClickHousef(SELECT ...), in the projection, WHERE, GROUP BY, HAVING, ORDER BY, QUALIFY and JOIN ON.ANY(ARRAY(SELECT ...))andALL(ARRAY(SELECT ...))give exactly one subquery scope.INandEXISTSsubqueries each register once.ScopeVisitortest shows the new scope reported asScopeType::Subquery.Run locally on this head, which includes
main:cargo fmt --all -- --check,make check-consistency, clippy-D warningson the ffi and wasm crates, andmake test-rust-verify-core(1,330 lib tests and the integration suites) all pass.🤖 Generated with Claude Code
Generated by Claude Code