Skip to content

fix: keep filters with subqueries correlated on an alias above the SubqueryAlias - #26596

Open
abp002 wants to merge 2 commits into
apache:mainfrom
abp002:any-subquery-join-alias
Open

abp002 wants to merge 2 commits into
apache:mainfrom
abp002:any-subquery-join-alias

Conversation

@abp002

@abp002 abp002 commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

A subquery in a JOIN ... ON that correlates on an aliased table fails to plan with No field named x.a. This is not specific to = ANY: EXISTS (... WHERE s.b = x.a) and a correlated IN in the same place fail the same way.

The ON predicate ends up in a Filter that push_down_filter pushes through SubqueryAlias: x. replace_cols_by_name rewrites x.a to t.a in the columns of the predicate, but not in the outer references of its subqueries, so below the alias they name x.a, which no longer exists.

What changes are included in this PR?

When pushing a filter through a SubqueryAlias, the conjuncts with a subquery correlated on a column of the alias stay above it, and the rest is pushed down as before. decorrelate_predicate_subquery then turns them into a join above the alias. A subquery correlated only on columns from further out is still pushed.

What is the testing strategy for this PR?

New subquery_alias_outer_referenced_column in push_down_filter.rs, which fails without the fix, and subquery.slt cases for = ANY, > ALL and EXISTS in a JOIN ... ON over an aliased table.

Are there any user-facing changes?

No.

@github-actions github-actions Bot added optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) labels Oct 22, 2026

@namanjain24-sudo namanjain24-sudo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this out and reverted the change to see what it covers. These all fail without it with Schema error: No field named x.a and pass with it, but none are covered by the added cases:

-- NOT EXISTS
SELECT * FROM t AS x JOIN t AS y ON NOT EXISTS (SELECT 1 FROM s WHERE s.b = x.a);
-- correlated IN
SELECT * FROM t AS x JOIN t AS y ON x.a IN (SELECT s.b FROM s WHERE s.b = x.a);
-- subquery nested in an OR, so it isn't a top-level conjunct
SELECT * FROM t AS x JOIN t AS y ON (EXISTS (SELECT 1 FROM s WHERE s.b = x.a) OR x.a = 99);

The OR one is the one I'd most want pinned: it only works because has_outer_ref_to_any walks the whole expression with exists(), so a later change that inspected only top-level conjuncts would break it silently while the current cases stayed green.

Unrelated to this PR, but noting it since it turned up next door: a correlated scalar subquery in the same position still fails with "Correlated scalar subquery can only be used in Projection, Filter, Aggregate and MERGE DML plan nodes", which looks like a separate limitation rather than something this should cover.

@abp002
abp002 force-pushed the any-subquery-join-alias branch from 104c3dd to dc8c9d5 Compare October 23, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

= ANY (subquery) in a JOIN ... ON over an aliased table fails: "No field named x.a"

2 participants