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

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


The following commit(s) were added to refs/heads/main by this push:
     new add1f8b8da [CALCITE-6642] AggregateUnionTransposeRule should account 
for changes in nullability of pushed down aggregates
add1f8b8da is described below

commit add1f8b8dac86bfbd8a9de5169baa97347119256
Author: Claude Brisson <[email protected]>
AuthorDate: Fri Oct 25 04:53:33 2024 +0200

    [CALCITE-6642] AggregateUnionTransposeRule should account for changes in 
nullability of pushed down aggregates
---
 .../rel/rules/AggregateUnionTransposeRule.java     | 24 ++++++++++++++++-
 .../org/apache/calcite/test/RelOptRulesTest.java   | 15 +++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 31 ++++++++++++++++++++++
 3 files changed, 69 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 4721d6997c..4d3d55e26f 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
@@ -152,10 +152,32 @@ public class AggregateUnionTransposeRule
 
     // create corresponding aggregates on top of each union child
     final RelBuilder relBuilder = call.builder();
+    RelDataType origUnionType = union.getRowType();
     for (RelNode input : union.getInputs()) {
+      List<AggregateCall> childAggCalls = new 
ArrayList<>(aggRel.getAggCallList());
+      // if the nullability of a specific input column differs from the 
nullability
+      // of the union'ed column, we need to re-evaluate the nullability of the 
aggregate
+      RelDataType inputRowType = input.getRowType();
+      for (int i = 0; i < childAggCalls.size(); ++i) {
+        AggregateCall origCall = aggRel.getAggCallList().get(i);
+        if (origCall.getAggregation() == SqlStdOperatorTable.COUNT) {
+          continue;
+        }
+        assert origCall.getArgList().size() == 1;
+        int field = origCall.getArgList().get(0);
+        if (origUnionType.getFieldList().get(field).getType().isNullable()
+            != inputRowType.getFieldList().get(field).getType().isNullable()) {
+          AggregateCall newCall =
+              AggregateCall.create(origCall.getParserPosition(), 
origCall.getAggregation(),
+                  origCall.isDistinct(), origCall.isApproximate(), 
origCall.ignoreNulls(),
+                  origCall.rexList, origCall.getArgList(), -1, 
origCall.distinctKeys,
+                  origCall.collation, groupCount, input, null, 
origCall.getName());
+          childAggCalls.set(i, newCall);
+        }
+      }
       relBuilder.push(input);
       relBuilder.aggregate(relBuilder.groupKey(aggRel.getGroupSet()),
-          aggRel.getAggCallList());
+          childAggCalls);
     }
 
     // create a new union whose children are the aggregates created above
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 26571b70bd..cabd12612e 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -7434,6 +7434,21 @@ class RelOptRulesTest extends RelOptTestBase {
         .check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-6642";>[CALCITE-6642]
+   * AggregateUnionTransposeRule throws an assertion error when creating 
children aggregates
+   * when one input only has a non-nullable column</a>. */
+  @Test void testAggregateUnionTransposeWithOneInputNonNullable() {
+    final String sql = "select deptno, SUM(t) from (\n"
+        + "select deptno, 1 as t from sales.emp e1\n"
+        + "union all\n"
+        + "select deptno, nullif(sal, 0) 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() {
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 da7c881b22..d5c1bbc4d2 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1023,6 +1023,37 @@ 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="testAggregateUnionTransposeWithOneInputNonNullable">
+    <Resource name="sql">
+      <![CDATA[select deptno, SUM(t) from (
+select deptno, 1 as t from sales.emp e1
+union all
+select deptno, nullif(sal, 0) 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]])
+    LogicalProject(DEPTNO=[$7], T=[CASE(=($5, 0), null:INTEGER, $5)])
+      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)])
+      LogicalProject(DEPTNO=[$7], T=[CASE(=($5, 0), null:INTEGER, $5)])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
     </Resource>
   </TestCase>

Reply via email to