From 534173058666883ea70857bd9b17ff43dd865831 Mon Sep 17 00:00:00 2001 From: xiejiajun Date: Thu, 17 Oct 2024 14:41:57 +0800 Subject: [PATCH] [CALCITE-6632] Wrong optimization because window missing constants in digest --- .../org/apache/calcite/rel/core/Window.java | 3 ++ .../org/apache/calcite/test/JdbcTest.java | 2 +- .../apache/calcite/test/RelOptRulesTest.java | 14 ++++++ .../apache/calcite/test/RelOptRulesTest.xml | 48 +++++++++++++++---- core/src/test/resources/sql/winagg.iq | 2 +- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/rel/core/Window.java b/core/src/main/java/org/apache/calcite/rel/core/Window.java index 7c07bb6f8d7a..ab3a5e515c37 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Window.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Window.java @@ -163,6 +163,9 @@ public Window(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, for (Ord window : Ord.zip(groups)) { pw.item("window#" + window.i, window.e.toString()); } + if (this.constants != null && this.constants.size() > 0) { + pw.item("constants", constants); + } return pw; } diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java index 7aaef4cf77ed..ce220b095a1b 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java @@ -4123,7 +4123,7 @@ void testOrderByOnSortedTable2(String format) { "[deptno INTEGER NOT NULL, empid INTEGER NOT NULL, S REAL, FIVE INTEGER NOT NULL, M REAL, C BIGINT NOT NULL]") .explainContains("" + "EnumerableCalc(expr#0..7=[{inputs}], expr#8=[0:BIGINT], expr#9=[>($t4, $t8)], expr#10=[null:JavaType(class java.lang.Float)], expr#11=[CASE($t9, $t5, $t10)], expr#12=[5], deptno=[$t1], empid=[$t0], S=[$t11], FIVE=[$t12], M=[$t6], C=[$t7])\n" - + " EnumerableWindow(window#0=[window(partition {1} order by [0] rows between $4 PRECEDING and CURRENT ROW aggs [COUNT($3), $SUM0($3), MIN($2), COUNT()])])\n" + + " EnumerableWindow(window#0=[window(partition {1} order by [0] rows between $4 PRECEDING and CURRENT ROW aggs [COUNT($3), $SUM0($3), MIN($2), COUNT()])], constants=[[1]])\n" + " EnumerableCalc(expr#0..4=[{inputs}], expr#5=[+($t3, $t0)], proj#0..1=[{exprs}], salary=[$t3], $3=[$t5])\n" + " EnumerableTableScan(table=[[hr, emps]])\n") .returnsUnordered( 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 4862a89039e9..904643cdf223 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -5892,6 +5892,20 @@ private HepProgram getTransitiveProgram() { .check(); } + /** Test case for + * [CALCITE-6632] + * Wrong optimization because window missing constants in digest. */ + @Test void testWindowMissingConstantInDigest() { + final String sql = "select sum(100) over (partition by deptno order by sal) as s\n" + + "from emp\n" + + "union all\n" + + "select sum(1000) over(partition by deptno order by sal) as s\n" + + "from emp\n"; + sql(sql) + .withRule(CoreRules.PROJECT_TO_LOGICAL_PROJECT_AND_WINDOW) + .check(); + } + /** While it's probably valid relational algebra for a Project to contain * a RexOver inside a RexOver, ProjectMergeRule should not bring it about. */ @Test void testProjectMergeShouldIgnoreOver() { 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 babaae620137..a0070f59222b 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -4441,7 +4441,7 @@ ROWS BETWEEN 5 + 5 PRECEDING AND 1 PRECEDING) AS w_count from emp @@ -5328,7 +5328,7 @@ LogicalProject(EMPNO=[$0], DEPTNO=[$1], W_COUNT=[$2]) @@ -8409,7 +8409,7 @@ LogicalProject(EXPR$0=[CAST(/(CASE(>(COUNT($5) OVER (ORDER BY $0 ROWS 3 PRECEDIN ($2, 0), $3, null:INTEGER), $2)):INTEGER]) - LogicalWindow(window#0=[window(order by [0] rows between $2 PRECEDING and CURRENT ROW aggs [COUNT($1), $SUM0($1)])]) + LogicalWindow(window#0=[window(order by [0] rows between $2 PRECEDING and CURRENT ROW aggs [COUNT($1), $SUM0($1)])], constants=[[3]]) LogicalProject(EMPNO=[$0], SAL=[$5]) LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> @@ -8509,7 +8509,7 @@ from ( @@ -10603,7 +10603,7 @@ where DEPTNO = 1]]> LogicalProject(NAME=[$0], DEPTNO=[$1], CNT=[$2], ALL_SUM=[$3]) LogicalFilter(condition=[=($1, 1)]) LogicalProject(NAME=[$1], DEPTNO=[$0], CNT=[$2], ALL_SUM=[$3]) - LogicalWindow(window#0=[window(partition {0, 1} aggs [COUNT()])], window#1=[window(partition {0} aggs [SUM($2)])]) + LogicalWindow(window#0=[window(partition {0, 1} aggs [COUNT()])], window#1=[window(partition {0} aggs [SUM($2)])], constants=[[1]]) LogicalTableScan(table=[[CATALOG, SALES, DEPT]]) ]]> @@ -10611,7 +10611,7 @@ LogicalProject(NAME=[$0], DEPTNO=[$1], CNT=[$2], ALL_SUM=[$3]) @@ -13055,7 +13055,7 @@ from ( + + + + + + + + + + + diff --git a/core/src/test/resources/sql/winagg.iq b/core/src/test/resources/sql/winagg.iq index 762e8a351e0a..feb4dc695107 100644 --- a/core/src/test/resources/sql/winagg.iq +++ b/core/src/test/resources/sql/winagg.iq @@ -760,7 +760,7 @@ select emp."ENAME", emp."DEPTNO", nth_value(emp."DEPTNO", 10) over() as "tenth_value" from emp order by emp."ENAME"; EnumerableSort(sort0=[$0], dir0=[ASC]) - EnumerableWindow(window#0=[window(aggs [NTH_VALUE($1, $2), NTH_VALUE($1, $3), NTH_VALUE($1, $4), NTH_VALUE($1, $5), NTH_VALUE($1, $6)])]) + EnumerableWindow(window#0=[window(aggs [NTH_VALUE($1, $2), NTH_VALUE($1, $3), NTH_VALUE($1, $4), NTH_VALUE($1, $5), NTH_VALUE($1, $6)])], constants=[[1, 2, 5, 8, 10]]) EnumerableValues(tuples=[[{ 'Jane ', 10 }, { 'Bob ', 10 }, { 'Eric ', 20 }, { 'Susan', 30 }, { 'Alice', 30 }, { 'Adam ', 50 }, { 'Eve ', 50 }, { 'Grace', 60 }, { 'Wilma', null }]]) !plan +-------+--------+-------------+--------------+-------------+--------------+-------------+