From bf1d50929cdbea77b4e4fa6285dda1dcbcb79c60 Mon Sep 17 00:00:00 2001 From: nobigo Date: Sun, 16 Feb 2025 08:31:26 +0800 Subject: [PATCH 1/3] [CALCITE-6834] In query that applies COALESCE to nullable SUM, EnumerableProjectToCalcRule throws AssertionError --- .../rel/rules/ProjectAggregateMergeRule.java | 21 ++++++++- .../apache/calcite/test/RelOptRulesTest.java | 7 +++ .../apache/calcite/test/RelOptRulesTest.xml | 22 +++++++++ core/src/test/resources/sql/agg.iq | 47 +++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java index 42b209fa2d39..6e584f062420 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java @@ -38,6 +38,8 @@ import org.apache.calcite.util.mapping.MappingType; import org.apache.calcite.util.mapping.Mappings; +import com.google.common.collect.ImmutableList; + import org.immutables.value.Value; import java.math.BigDecimal; @@ -154,8 +156,23 @@ && kindCount(project.getProjects(), SqlKind.CASE) == 0) { builder.push(aggregate.getInput()); builder.aggregate( builder.groupKey(aggregate.getGroupSet(), aggregate.groupSets), aggCallList); - builder.project( - RexPermuteInputsShuttle.of(mapping).visitList(projects2)); + // If the output type of Aggregate does not match the input type required by original Project, + // CAST needs to be added + List rexInputRefs = RexPermuteInputsShuttle.of(mapping).visitList(projects2); + final ImmutableList.Builder selectList = ImmutableList.builder(); + final RexShuttle rexShuttle = new RexShuttle() { + @Override public RexNode visitInputRef(RexInputRef inputRef) { + if (builder.fields().get(inputRef.getIndex()).getType() != inputRef.getType()) { + return builder.getRexBuilder().makeCast(inputRef.getType(), + builder.fields().get(inputRef.getIndex())); + } + return inputRef; + } + }; + for (RexNode rexInputRef : rexInputRefs) { + selectList.add(rexInputRef.accept(rexShuttle)); + } + builder.project(selectList.build()); call.transformTo(builder.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 b02a929e675e..bc1837c52ed3 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -6925,6 +6925,13 @@ private HepProgram getTransitiveProgram() { .check(); } + @Test void testProjectAggregateMergeSum01() { + final String sql = "select coalesce(sum(cast(mgr as tinyint)), 0) as ss0\n" + + "from sales.emp"; + sql(sql).withRule(CoreRules.PROJECT_AGGREGATE_MERGE) + .check(); + } + /** As {@link #testProjectAggregateMergeSum0()} but there is another use of * {@code SUM} that cannot be converted to {@code SUM0}. */ @Test void testProjectAggregateMergeSum0AndSum() { 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 60c683ee50e6..86d4f051adcc 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -8126,6 +8126,28 @@ LogicalProject(SS0=[CASE(IS NOT NULL($0), CAST($0):INTEGER NOT NULL, 0)]) LogicalAggregate(group=[{}], agg#0=[$SUM0($0)]) LogicalProject(SAL=[$5]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + + + + + + + + + + + diff --git a/core/src/test/resources/sql/agg.iq b/core/src/test/resources/sql/agg.iq index 7322b84da2b2..5dfd8e9d9350 100644 --- a/core/src/test/resources/sql/agg.iq +++ b/core/src/test/resources/sql/agg.iq @@ -3815,4 +3815,51 @@ select distinct sum(deptno + '1') as deptsum from dept order by 1; !ok +# [CALCITE-2192] In query that applies COALESCE to nullable SUM, EnumerableProjectToCalcRule throws AssertionError +# sum(mgr) return TINYINT, coalesce(sum(mgr),0) return INTEGER, so need CAST +select coalesce(sum(mgr),0) as m +from emp; +java.sql.SQLException: Error while executing SQL "select coalesce(sum(mgr),0) as m +from emp": Value 38835 out of range +!error +EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):INTEGER NOT NULL], $f0=[$t1]) + EnumerableAggregate(group=[{}], agg#0=[$SUM0($3)]) + EnumerableTableScan(table=[[scott, EMP]]) +!plan + +# sum(cast(mgr as int)) return INTEGER, coalesce(sum(cast(mgr as int)),0) return INTEGER, so don't need CAST +select coalesce(sum(cast(mgr as int)),0) as m +from emp; ++--------+ +| M | ++--------+ +| 100611 | ++--------+ +(1 row) + +!ok + +EnumerableAggregate(group=[{}], agg#0=[$SUM0($0)]) + EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t3):INTEGER], $f0=[$t8]) + EnumerableTableScan(table=[[scott, EMP]]) +!plan + +# sum(mgr) return INTEGER, coalesce(sum(mgr),0) return BIGINT, so need CAST +select coalesce(sum(cast(mgr as int)),cast(0 as bigint)) as m +from emp; ++--------+ +| M | ++--------+ +| 100611 | ++--------+ +(1 row) + +!ok + +EnumerableCalc(expr#0=[{inputs}], expr#1=[CAST($t0):BIGINT NOT NULL], $f0=[$t1]) + EnumerableAggregate(group=[{}], agg#0=[$SUM0($0)]) + EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t3):INTEGER], $f0=[$t8]) + EnumerableTableScan(table=[[scott, EMP]]) +!plan + # End agg.iq From 2a09afe2bf53b46b9fff3edbc39cae7e1b5a276e Mon Sep 17 00:00:00 2001 From: nobigo Date: Wed, 19 Feb 2025 12:46:12 +0800 Subject: [PATCH 2/3] [CALCITE-6834] In query that applies COALESCE to nullable SUM, EnumerableProjectToCalcRule throws AssertionError --- .../calcite/rel/rules/ProjectAggregateMergeRule.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java index 6e584f062420..4b785dd1812b 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/ProjectAggregateMergeRule.java @@ -162,11 +162,10 @@ && kindCount(project.getProjects(), SqlKind.CASE) == 0) { final ImmutableList.Builder selectList = ImmutableList.builder(); final RexShuttle rexShuttle = new RexShuttle() { @Override public RexNode visitInputRef(RexInputRef inputRef) { - if (builder.fields().get(inputRef.getIndex()).getType() != inputRef.getType()) { - return builder.getRexBuilder().makeCast(inputRef.getType(), - builder.fields().get(inputRef.getIndex())); - } - return inputRef; + return builder.getRexBuilder().ensureType( + inputRef.getType(), + builder.fields().get(inputRef.getIndex()), + true); } }; for (RexNode rexInputRef : rexInputRefs) { From be93be0f6b91e63c061c3d94675c2325a03a3a03 Mon Sep 17 00:00:00 2001 From: nobigo Date: Fri, 21 Feb 2025 19:48:56 +0800 Subject: [PATCH 3/3] [CALCITE-6834] Code Review --- .../test/java/org/apache/calcite/test/RelOptRulesTest.java | 4 ++++ core/src/test/resources/sql/agg.iq | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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 bc1837c52ed3..8ac93dcb4537 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -6925,6 +6925,10 @@ private HepProgram getTransitiveProgram() { .check(); } + /** Test case for + * [CALCITE-6834] + * In query that applies COALESCE to nullable SUM, EnumerableProjectToCalcRule + * throws AssertionError. */ @Test void testProjectAggregateMergeSum01() { final String sql = "select coalesce(sum(cast(mgr as tinyint)), 0) as ss0\n" + "from sales.emp"; diff --git a/core/src/test/resources/sql/agg.iq b/core/src/test/resources/sql/agg.iq index 5dfd8e9d9350..0b4999acc969 100644 --- a/core/src/test/resources/sql/agg.iq +++ b/core/src/test/resources/sql/agg.iq @@ -3815,7 +3815,7 @@ select distinct sum(deptno + '1') as deptsum from dept order by 1; !ok -# [CALCITE-2192] In query that applies COALESCE to nullable SUM, EnumerableProjectToCalcRule throws AssertionError +# [CALCITE-6834] In query that applies COALESCE to nullable SUM, EnumerableProjectToCalcRule throws AssertionError # sum(mgr) return TINYINT, coalesce(sum(mgr),0) return INTEGER, so need CAST select coalesce(sum(mgr),0) as m from emp;