diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java index 12222b218b09..b4f572d04cef 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -3580,11 +3580,25 @@ private void createAggImpl(Blackboard bb, final RelNode inputRel = bb.root(); // Project the expressions required by agg and having. - bb.setRoot( - relBuilder.push(inputRel) - .projectNamed(preExprs.leftList(), preExprs.rightList(), false) - .build(), - false); + RelNode intermediateProject = relBuilder.push(inputRel) + .projectNamed(preExprs.leftList(), preExprs.rightList(), false) + .build(); + final RelNode r2; + // deal with correlation + final CorrelationUse p = getCorrelationUse(bb, intermediateProject); + if (p != null) { + assert p.r instanceof Project; + // correlation variables have been normalized in p.r, we should use expressions + // in p.r instead of the original exprs + Project project1 = (Project) p.r; + r2 = relBuilder.push(bb.root()) + .projectNamed(project1.getProjects(), project1.getRowType().getFieldNames(), + true, ImmutableSet.of(p.id)) + .build(); + } else { + r2 = intermediateProject; + } + bb.setRoot(r2, false); bb.mapRootRelToFieldProjection.put(bb.root(), r.groupExprProjection); // REVIEW jvs 31-Oct-2007: doesn't the declaration of diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index 7e4819aee4c2..345db9eb6206 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -3770,6 +3770,46 @@ void checkCorrelatedMapSubQuery(boolean expand) { sql(sql).withExpand(false).withDecorrelate(false).ok(); } + /** Test case for + * [CALCITE-6554] + * Nested correlated sub-query in aggregation does not have inner correlation variable bound + * to inner projection. */ + @Test void testCorrelationInProjectionWith1xNestedCorrelatedProjection() { + final String sql = "select e1.empno,\n" + + " (select sum(e2.sal +\n" + + " (select sum(e3.sal) from emp e3 where e3.mgr = e2.empno)\n" + + " ) from emp e2 where e2.mgr = e1.empno)\n" + + "from emp e1"; + sql(sql).withExpand(false).withDecorrelate(false).ok(); + } + + /** Test case for + * [CALCITE-6554] + * Nested correlated sub-query in aggregation does not have inner correlation variable bound + * to inner projection. */ + @Test void testCorrelationInProjectionWith2xNestedCorrelatedProjection() { + final String sql = "select e1.empno,\n" + + " (select sum(e2.sal +\n" + + " (select sum(e3.sal + (select sum(e4.sal) from emp e4 where e4.mgr = e3.empno)\n" + + " ) from emp e3 where e3.mgr = e2.empno)\n" + + " ) from emp e2 where e2.mgr = e1.empno)\n" + + "from emp e1"; + sql(sql).withExpand(false).withDecorrelate(false).ok(); + } + + /** Test case for + * [CALCITE-6554] + * Nested correlated sub-query in aggregation does not have inner correlation variable bound + * to inner projection. */ + @Test void testCorrelationInProjectionWithCorrelatedProjectionWithNestedNonCorrelatedSubquery() { + final String sql = "select e1.empno,\n" + + " (select sum(e2.sal +\n" + + " (select sum(e3.sal) from emp e3 where e3.mgr = e1.empno)\n" + + " ) from emp e2 where e2.mgr = e1.empno)\n" + + "from emp e1"; + sql(sql).withExpand(false).withDecorrelate(false).ok(); + } + @Test void testCustomColumnResolving() { final String sql = "select k0 from struct.t"; sql(sql).ok(); diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index 4946f20873b1..3feb6be58a2d 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -1128,6 +1128,62 @@ where exists (select * from emp and emp.deptno in (dept.deptno, dept.deptno))]]> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/test/resources/sql/sub-query.iq b/core/src/test/resources/sql/sub-query.iq index 27e3321b84f5..7bfedac3a859 100644 --- a/core/src/test/resources/sql/sub-query.iq +++ b/core/src/test/resources/sql/sub-query.iq @@ -668,6 +668,53 @@ FROM (SELECT 1 AS a) AS t; !ok +# [CALCITE-6554] nested correlated sub-query in aggregation does not have inner correlation variable bound to inner projection +SELECT ename, + (SELECT Sum(sal + COALESCE((SELECT Sum(sal) FROM "scott".emp AS subord2 + WHERE + subord2.mgr = + subord.empno), 0)) + FROM "scott".emp AS subord + WHERE subord.mgr = bosses.empno) AS deep2sal +FROM "scott".emp AS bosses; ++--------+----------+ +| ENAME | DEEP2SAL | ++--------+----------+ +| ADAMS | | +| ALLEN | | +| BLAKE | 6550.00 | +| CLARK | 1300.00 | +| FORD | 800.00 | +| JAMES | | +| JONES | 7900.00 | +| KING | 22125.00 | +| MARTIN | | +| MILLER | | +| SCOTT | 1100.00 | +| SMITH | | +| TURNER | | +| WARD | | ++--------+----------+ +(14 rows) + +!ok + +EnumerableCalc(expr#0..3=[{inputs}], ENAME=[$t1], DEEP2SAL=[$t3]) + EnumerableMergeJoin(condition=[=($0, $2)], joinType=[left]) + EnumerableCalc(expr#0..7=[{inputs}], proj#0..1=[{exprs}]) + EnumerableTableScan(table=[[scott, EMP]]) + EnumerableSort(sort0=[$0], dir0=[ASC]) + EnumerableAggregate(group=[{0}], EXPR$0=[SUM($1)]) + EnumerableCalc(expr#0..4=[{inputs}], expr#5=[IS NOT NULL($t4)], expr#6=[0.00:DECIMAL(19, 2)], expr#7=[CASE($t5, $t4, $t6)], expr#8=[+($t2, $t7)], MGR9=[$t1], $f0=[$t8]) + EnumerableMergeJoin(condition=[=($0, $3)], joinType=[left]) + EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t3)], EMPNO=[$t0], MGR=[$t3], SAL=[$t5], $condition=[$t8]) + EnumerableTableScan(table=[[scott, EMP]]) + EnumerableSort(sort0=[$0], dir0=[ASC]) + EnumerableAggregate(group=[{3}], EXPR$0=[SUM($5)]) + EnumerableCalc(expr#0..7=[{inputs}], expr#8=[IS NOT NULL($t3)], proj#0..7=[{exprs}], $condition=[$t8]) + EnumerableTableScan(table=[[scott, EMP]]) +!plan + # [CALCITE-1494] Inefficient plan for correlated sub-queries # Plan must have only one scan each of emp and dept. select sal