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

xiedeyantu 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 763ab1d7fd [CALCITE-7645] AggregateUnionTransposeRule drops aggregate 
FILTER when rebuilding child aggregate calls
763ab1d7fd is described below

commit 763ab1d7fd503799634c22e92afb4ab3b1a6fa0d
Author: Zhen Chen <[email protected]>
AuthorDate: Sun Jul 5 20:01:47 2026 +0800

    [CALCITE-7645] AggregateUnionTransposeRule drops aggregate FILTER when 
rebuilding child aggregate calls
    
    Signed-off-by: xiedeyantu <[email protected]>
---
 .../rel/rules/AggregateUnionTransposeRule.java     |  5 ++--
 .../org/apache/calcite/test/RelOptRulesTest.java   | 16 +++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 32 ++++++++++++++++++++++
 core/src/test/resources/sql/hep.iq                 | 19 +++++++++++++
 4 files changed, 70 insertions(+), 2 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 923311a4f5..614c510a4e 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
@@ -166,8 +166,9 @@ public AggregateUnionTransposeRule(Class<? extends 
Aggregate> aggregateClass,
           AggregateCall newCall =
               AggregateCall.create(origCall.getParserPosition(), 
origCall.getAggregation(),
                   origCall.isDistinct(), origCall.isApproximate(), 
origCall.ignoreNulls(),
-                  origCall.rexList, origCall.getArgList(), -1, 
origCall.distinctKeys,
-                  origCall.collation, aggRel.getGroupSet().isEmpty(), input, 
null,
+                  origCall.rexList, origCall.getArgList(), origCall.filterArg,
+                  origCall.distinctKeys, origCall.collation,
+                  aggRel.getGroupSet().isEmpty(), input, null,
                   origCall.getName());
           childAggCalls.set(i, newCall);
         }
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 d56bde9808..18777b1ad7 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -8641,6 +8641,22 @@ private void checkSemiJoinRuleOnAntiJoin(RelOptRule 
rule) {
         .check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7645";>[CALCITE-7645]
+   * AggregateUnionTransposeRule drops aggregate FILTER when rebuilding
+   * pushed-down aggregate calls</a>. */
+  @Test void testAggregateUnionTransposeWithFilterAndNullableInput() {
+    final String sql = "select min(v) filter (where p)\n"
+        + "from (\n"
+        + "  select * from (values (10, false), (100, true)) as t(v, p)\n"
+        + "  union all\n"
+        + "  select * from (values (cast(null as integer), true), (200, true)) 
as t(v, p)\n"
+        + ")";
+    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 cdf6956ae4..2eb42b693c 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1308,6 +1308,38 @@ 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="testAggregateUnionTransposeWithFilterAndNullableInput">
+    <Resource name="sql">
+      <![CDATA[select min(v) filter (where p)
+from (
+  select * from (values (10, false), (100, true)) as t(v, p)
+  union all
+  select * from (values (cast(null as integer), true), (200, true)) as t(v, p)
+)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalAggregate(group=[{}], EXPR$0=[MIN($0) FILTER $1])
+  LogicalUnion(all=[true])
+    LogicalProject(V=[$0], P=[$1])
+      LogicalValues(tuples=[[{ 10, false }, { 100, true }]])
+    LogicalProject(V=[$0], P=[$1])
+      LogicalValues(tuples=[[{ null, true }, { 200, true }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalAggregate(group=[{}], EXPR$0=[MIN($0)])
+  LogicalUnion(all=[true])
+    LogicalAggregate(group=[{}], EXPR$0=[MIN($0) FILTER $1])
+      LogicalProject(V=[$0], P=[$1])
+        LogicalValues(tuples=[[{ 10, false }, { 100, true }]])
+    LogicalAggregate(group=[{}], EXPR$0=[MIN($0) FILTER $1])
+      LogicalProject(V=[$0], P=[$1])
+        LogicalValues(tuples=[[{ null, true }, { 200, true }]])
 ]]>
     </Resource>
   </TestCase>
diff --git a/core/src/test/resources/sql/hep.iq 
b/core/src/test/resources/sql/hep.iq
index 18cdaf2722..812663177a 100644
--- a/core/src/test/resources/sql/hep.iq
+++ b/core/src/test/resources/sql/hep.iq
@@ -103,6 +103,25 @@ EnumerableSort(sort0=[$1], dir0=[ASC])
     EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t3):INTEGER], 
expr#9=[7698], expr#10=[=($t8, $t9)], expr#11=[CAST($t6):DECIMAL(12, 2)], 
expr#12=[500.00:DECIMAL(12, 2)], expr#13=[=($t11, $t12)], expr#14=[IS NOT 
TRUE($t13)], expr#15=[AND($t10, $t14)], MGR=[$t3], COMM=[$t6], 
$condition=[$t15])
       EnumerableTableScan(table=[[scott, EMP]])
 !plan
+
+# [CALCITE-7645] AggregateUnionTransposeRule must preserve aggregate FILTER 
when creating pushed-down aggregates
+!set hep-rules "
++AGGREGATE_UNION_TRANSPOSE"
+
+select min(v) filter (where p) as m
+from (
+  select * from (values (10, false), (100, true)) as t(v, p)
+  union all
+  select * from (values (cast(null as integer), true), (200, true)) as t(v, p)
+);
++-----+
+| M   |
++-----+
+| 100 |
++-----+
+(1 row)
+
+!ok
 !set hep-rules original
 
 # Testing with the planner-rules shows that due to cost-based selection issues,

Reply via email to