You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by xi...@apache.org on 2021/12/18 11:15:20 UTC

[calcite] branch master updated: [CALCITE-4700] AggregateUnionTransposeRule produces wrong group sets for the top Aggregate (Vladimir Ozerov)

This is an automated email from the ASF dual-hosted git repository.

xiong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/master by this push:
     new 538016e  [CALCITE-4700] AggregateUnionTransposeRule produces wrong group sets for the top Aggregate (Vladimir Ozerov)
538016e is described below

commit 538016eec2b174ac159dfc0b8886671670ee555a
Author: Vladimir Ozerov <pp...@gmail.com>
AuthorDate: Mon Jul 26 09:40:49 2021 +0300

    [CALCITE-4700] AggregateUnionTransposeRule produces wrong group sets for the top Aggregate (Vladimir Ozerov)
---
 .../rel/rules/AggregateUnionTransposeRule.java     | 29 ++++++++++++++++++-
 .../org/apache/calcite/test/RelOptRulesTest.java   | 11 ++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 33 ++++++++++++++++++++++
 3 files changed, 72 insertions(+), 1 deletion(-)

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 e67ef89..215b12a 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
@@ -39,6 +39,10 @@ import org.apache.calcite.sql.fun.SqlSumAggFunction;
 import org.apache.calcite.sql.fun.SqlSumEmptyIsZeroAggFunction;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.mapping.Mapping;
+import org.apache.calcite.util.mapping.MappingType;
+import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.collect.ImmutableList;
 
@@ -156,8 +160,31 @@ public class AggregateUnionTransposeRule
 
     // create a new union whose children are the aggregates created above
     relBuilder.union(true, union.getInputs().size());
+
+    // Create the top aggregate. We must adjust group key indexes of the
+    // original aggregate. E.g., if the original tree was:
+    //
+    // Aggregate[groupSet=$1, ...]
+    //   Union[...]
+    //
+    // Then the new tree should be:
+    // Aggregate[groupSet=$0, ...]
+    //   Union[...]
+    //     Aggregate[groupSet=$1, ...]
+    ImmutableBitSet groupSet = aggRel.getGroupSet();
+    Mapping topGroupMapping = Mappings.create(MappingType.INVERSE_SURJECTION,
+        union.getRowType().getFieldCount(),
+        aggRel.getGroupCount());
+    for (int i = 0; i < groupSet.cardinality(); i++) {
+      topGroupMapping.set(groupSet.nth(i), i);
+    }
+
+    ImmutableBitSet topGroupSet = Mappings.apply(topGroupMapping, groupSet);
+    ImmutableList<ImmutableBitSet> topGroupSets =
+        Mappings.apply2(topGroupMapping, aggRel.getGroupSets());
+
     relBuilder.aggregate(
-        relBuilder.groupKey(aggRel.getGroupSet(), aggRel.getGroupSets()),
+        relBuilder.groupKey(topGroupSet, topGroupSets),
         transformedAggCalls);
     call.transformTo(relBuilder.build());
   }
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 e2276b5..864cb95 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -5405,6 +5405,17 @@ class RelOptRulesTest extends RelOptTestBase {
         .checkUnchanged();
   }
 
+  @Test void testAggregateUnionTransposeWithTopLevelGroupSetRemapping() {
+    final String sql = "select count(t1), t2 from (\n"
+        + "select (case when deptno=0 then 1 else null end) as t1, 1 as t2 from sales.emp e1\n"
+        + "union all\n"
+        + "select (case when deptno=0 then 1 else null end) as t1, 2 as t2 from sales.emp e2)\n"
+        + "group by t2";
+    sql(sql)
+        .withPreRule(CoreRules.AGGREGATE_PROJECT_MERGE)
+        .withRule(CoreRules.AGGREGATE_UNION_TRANSPOSE)
+        .check();
+  }
 
   @Test void testSortJoinTranspose1() {
     final String sql = "select * from sales.emp e left join (\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 8991b55..b81a3be 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1097,6 +1097,39 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)])
 ]]>
     </Resource>
   </TestCase>
+  <TestCase name="testAggregateUnionTransposeWithTopLevelGroupSetRemapping">
+    <Resource name="sql">
+      <![CDATA[select count(t1), t2 from (
+select (case when deptno=0 then 1 else null end) as t1, 1 as t2 from sales.emp e1
+union all
+select (case when deptno=0 then 1 else null end) as t1, 2 as t2 from sales.emp e2)
+group by t2]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[$1], T2=[$0])
+  LogicalAggregate(group=[{1}], EXPR$0=[COUNT($0)])
+    LogicalUnion(all=[true])
+      LogicalProject(T1=[CASE(=($7, 0), 1, null:INTEGER)], T2=[1])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalProject(T1=[CASE(=($7, 0), 1, null:INTEGER)], T2=[2])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[$1], T2=[$0])
+  LogicalAggregate(group=[{0}], EXPR$0=[$SUM0($1)])
+    LogicalUnion(all=[true])
+      LogicalAggregate(group=[{1}], EXPR$0=[COUNT($0)])
+        LogicalProject(T1=[CASE(=($7, 0), 1, null:INTEGER)], T2=[1])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+      LogicalAggregate(group=[{1}], EXPR$0=[COUNT($0)])
+        LogicalProject(T1=[CASE(=($7, 0), 1, null:INTEGER)], T2=[2])
+          LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
   <TestCase name="testAggregateWithDynamicParam">
     <Resource name="sql">
       <![CDATA[SELECT sal, COUNT(1) AS count_val