This is an automated email from the ASF dual-hosted git repository. jhyde pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/calcite.git
commit 948127710f7fb44b795b25dfb4d9c2214c1392c7 Author: Vladimir Ozerov <[email protected]> AuthorDate: Wed Jul 21 07:35:59 2021 +0300 [CALCITE-4616] AggregateUnionTransposeRule causes row type mismatch when some inputs have unique grouping key Close apache/calcite#2437 --- .../rel/rules/AggregateUnionTransposeRule.java | 20 ++++--- .../org/apache/calcite/test/RelOptRulesTest.java | 29 ++++++++++ .../org/apache/calcite/test/RelOptRulesTest.xml | 66 ++++++++++++++++++++++ 3 files changed, 107 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java index 54d89c4..7d61d00 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionTransposeRule.java @@ -127,30 +127,34 @@ public class AggregateUnionTransposeRule return; } - // create corresponding aggregates on top of each union child - final RelBuilder relBuilder = call.builder(); - int transformCount = 0; + boolean hasUniqueKeyInAllInputs = true; final RelMetadataQuery mq = call.getMetadataQuery(); for (RelNode input : union.getInputs()) { boolean alreadyUnique = RelMdUtil.areColumnsDefinitelyUnique(mq, input, aggRel.getGroupSet()); - relBuilder.push(input); if (!alreadyUnique) { - ++transformCount; - relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet()), - aggRel.getAggCallList()); + hasUniqueKeyInAllInputs = false; + break; } } - if (transformCount == 0) { + if (hasUniqueKeyInAllInputs) { // none of the children could benefit from the push-down, // so bail out (preventing the infinite loop to which most // planners would succumb) return; } + // create corresponding aggregates on top of each union child + final RelBuilder relBuilder = call.builder(); + for (RelNode input : union.getInputs()) { + relBuilder.push(input); + relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet()), + aggRel.getAggCallList()); + } + // create a new union whose children are the aggregates created above relBuilder.union(true, union.getInputs().size()); relBuilder.aggregate( diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java index c5bfadb..df4cd85 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -5269,6 +5269,35 @@ class RelOptRulesTest extends RelOptTestBase { .check(); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-4616">[CALCITE-4616] + * AggregateUnionTransposeRule causes row type mismatch when some inputs have + * unique grouping key</a>. */ + @Test void testAggregateUnionTransposeWithOneInputUnique() { + final String sql = "select deptno, SUM(t) from (\n" + + "select deptno, 1 as t from sales.emp e1\n" + + "union all\n" + + "select distinct deptno, 2 as t from sales.emp e2)\n" + + "group by deptno"; + sql(sql) + .withRule(CoreRules.AGGREGATE_UNION_TRANSPOSE) + .check(); + } + + /** If all inputs to UNION are already unique, AggregateUnionTransposeRule is + * a no-op. */ + @Test void testAggregateUnionTransposeWithAllInputsUnique() { + final String sql = "select deptno, SUM(t) from (\n" + + "select distinct deptno, 1 as t from sales.emp e1\n" + + "union all\n" + + "select distinct deptno, 2 as t from sales.emp e2)\n" + + "group by deptno"; + sql(sql) + .withRule(CoreRules.AGGREGATE_UNION_TRANSPOSE) + .checkUnchanged(); + } + + @Test void testSortJoinTranspose1() { final String sql = "select * from sales.emp e left join (\n" + " select * from sales.dept d) d on e.deptno = d.deptno\n" diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml index 01a9142..ec91207 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -1031,6 +1031,72 @@ LogicalProject(MGR=[$0], SUM_SAL=[$2]) ]]> </Resource> </TestCase> + <TestCase name="testAggregateUnionTransposeWithAllInputsUnique"> + <Resource name="sql"> + <![CDATA[select deptno, SUM(t) from ( +select deptno, 1 as t from sales.emp e1 +union all +select distinct deptno, 2 as t from sales.emp e2) +group by deptno]]> + </Resource> + <Resource name="planBefore"> + <![CDATA[ +LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)]) + LogicalUnion(all=[true]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], T=[1]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], T=[2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + <Resource name="planAfter"> + <![CDATA[ +LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)]) + LogicalUnion(all=[true]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], T=[1]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], T=[2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + </TestCase> + <TestCase name="testAggregateUnionTransposeWithOneInputUnique"> + <Resource name="sql"> + <![CDATA[select deptno, SUM(t) from ( +select deptno, 1 as t from sales.emp e1 +union all +select distinct deptno, 2 as t from sales.emp e2) +group by deptno]]> + </Resource> + <Resource name="planBefore"> + <![CDATA[ +LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)]) + LogicalUnion(all=[true]) + LogicalProject(DEPTNO=[$7], T=[1]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], T=[2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + <Resource name="planAfter"> + <![CDATA[ +LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)]) + LogicalUnion(all=[true]) + LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)]) + LogicalProject(DEPTNO=[$7], T=[1]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], T=[2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + </TestCase> <TestCase name="testAll"> <Resource name="sql"> <