Darpan Lunagariya (e6data) created CALCITE-7898:
---------------------------------------------------
Summary: SubQueryRemoveRule corrupts plans when a join condition
holds multiple correlated sub-queries sharing one correlation id
Key: CALCITE-7898
URL: https://issues.apache.org/jira/browse/CALCITE-7898
Project: Calcite
Issue Type: Bug
Components: core
Affects Versions: 1.42.0
Reporter: Darpan Lunagariya (e6data)
Assignee: Darpan Lunagariya (e6data)
{{JoinSubQueryToCorrelateRule}} ({{SubQueryRemoveRule.matchJoin}}) removes
correlated sub-queries from a {{Join}} condition one at a time. Each removal
wraps the input in a new {{LogicalCorrelate}}. When two or more correlated
sub-queries in the same condition use the *same* correlation id (e.g. both
reference {{$cor0}} from the join), the rewrites all reuse that id. The result
is two nested {{Correlate}} nodes bound to the same id, so the inner binding
shadows the outer and the sub-queries read the wrong correlated value. The
produced plan is semantically wrong.
Two problems combine:
# The id is not freshened per rewrite, so nested {{Correlate}}s collide on one
id.
# The intermediate {{Join}} rebuilt between rewrites drops the correlation ids
still needed by the sub-queries that have not been removed yet (its
{{variablesSet}} is not carried over), so later rewrites lose their correlation
scope.
This is the join-condition analogue of CALCITE-7753
({{CorrelateProjectExtractor corrupts plans with nested Correlates that reuse
the same correlation id}}).
h2. Reproducer
{code:sql}
SELECT e.empno FROM emp e JOIN dept d
ON e.deptno = d.deptno AND (
EXISTS (SELECT 1 FROM emp e2 WHERE e2.mgr = e.empno AND e2.sal > 10)
OR EXISTS (SELECT 1 FROM emp e3 WHERE e3.mgr = e.empno AND e3.sal > 20))
{code}
Plan it generates:
{code:java}
LogicalProject(EMPNO=[$0])
LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4],
SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$10], NAME=[$11])
LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4],
SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], i=[$9], DEPTNO0=[$10],
NAME=[$11])
LogicalJoin(condition=[AND(=($7, $10), OR(IS NOT NULL($9), IS NOT
NULL($12)))], joinType=[inner])
LogicalCorrelate(correlation=[$cor0], joinType=[left],
requiredColumns=[{0}])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalAggregate(group=[{0}])
LogicalProject(i=[true])
LogicalFilter(condition=[AND(=($3, $cor0.EMPNO), >($5, 10))])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
LogicalJoin(condition=[true], joinType=[left])
LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
LogicalAggregate(group=[{0}])
LogicalProject(i=[true])
LogicalFilter(condition=[AND(=($3, $cor0.EMPNO), >($5, 20))])
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
{code}
Both {{EXISTS}} sub-queries correlate on {{$cor0}} (the join row). The rewrite
emits two stacked {{LogicalCorrelate}} nodes bound to the same id instead of
distinct ids, so the second {{EXISTS}} evaluates against the wrong correlation
binding.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)