This is an automated email from the ASF dual-hosted git repository.
xiong 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 8a286c5076 [CALCITE-5578] RelOptRulesTest testAggregateCaseToFilter
optimized plan not semantically equivalent to the original one after conversion
8a286c5076 is described below
commit 8a286c50769b309252c0ad9917002b390ee0b225
Author: Xiong Duan <[email protected]>
AuthorDate: Fri Jan 23 19:54:26 2026 +0800
[CALCITE-5578] RelOptRulesTest testAggregateCaseToFilter optimized plan not
semantically equivalent to the original one after conversion
---
.../calcite/rel/rel2sql/RelToSqlConverterTest.java | 40 ++++++++++++++
core/src/test/resources/sql/blank.iq | 61 ++++++++++++++++++++++
2 files changed, 101 insertions(+)
diff --git
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index 0c8e009c6e..d161f774b5 100644
---
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -11003,6 +11003,46 @@ private void checkLiteral2(String expression, String
expected) {
.ok(expected);
}
+
+ /** Test case of
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-5578">[CALCITE-5578]
+ * RelOptRulesTest testAggregateCaseToFilter optimized plan not semantically
+ * equivalent to the original one after conversion</a>. */
+ @Test void testAggregateCaseToFilter() {
+ final String sql = "select\n"
+ + " sum(sal) as sum_sal,\n"
+ + " count(distinct case\n"
+ + " when job = 'CLERK'\n"
+ + " then deptno else null end) as count_distinct_clerk,\n"
+ + " sum(case when deptno = 10 then sal end) as sum_sal_d10,\n"
+ + " sum(case when deptno = 20 then sal else 0 end) as sum_sal_d20,\n"
+ + " sum(case when deptno = 30 then 1 else 0 end) as count_d30,\n"
+ + " count(case when deptno = 40 then 'x' end) as count_d40,\n"
+ + " sum(case when deptno = 45 then 1 end) as count_d45,\n"
+ + " sum(case when deptno = 50 then 1 else null end) as count_d50,\n"
+ + " sum(case when deptno = 60 then null end) as sum_null_d60,\n"
+ + " sum(case when deptno = 70 then null else 1 end) as sum_null_d70,\n"
+ + " count(case when deptno = 20 then 1 end) as count_d20\n"
+ + "from emp";
+ final String expected = "SELECT"
+ + " SUM(\"SAL\") AS \"SUM_SAL\","
+ + " COUNT(DISTINCT \"DEPTNO\") FILTER (WHERE \"JOB\" = 'CLERK' IS
TRUE) AS \"COUNT_DISTINCT_CLERK\","
+ + " SUM(\"SAL\") FILTER (WHERE CAST(\"DEPTNO\" AS INTEGER) = 10 IS
TRUE) AS \"SUM_SAL_D10\","
+ + " SUM(CASE WHEN CAST(\"DEPTNO\" AS INTEGER) = 20 THEN CAST(\"SAL\"
AS DECIMAL(12, 2)) ELSE 0.00 END) AS \"SUM_SAL_D20\","
+ + " SUM(CASE WHEN CAST(\"DEPTNO\" AS INTEGER) = 30 THEN 1 ELSE 0 END)
AS \"COUNT_D30\","
+ + " COUNT(*) FILTER (WHERE CAST(\"DEPTNO\" AS INTEGER) = 40 IS TRUE)
AS \"COUNT_D40\","
+ + " SUM(1) FILTER (WHERE CAST(\"DEPTNO\" AS INTEGER) = 45 IS TRUE) AS
\"COUNT_D45\","
+ + " SUM(1) FILTER (WHERE CAST(\"DEPTNO\" AS INTEGER) = 50 IS TRUE) AS
\"COUNT_D50\","
+ + " SUM(CAST(NULL AS DECIMAL(19, 9))) AS \"SUM_NULL_D60\","
+ + " SUM(1) FILTER (WHERE CAST(\"DEPTNO\" AS INTEGER) = 70 IS NOT TRUE)
AS \"SUM_NULL_D70\","
+ + " COUNT(*) FILTER (WHERE CAST(\"DEPTNO\" AS INTEGER) = 20 IS TRUE)
AS \"COUNT_D20\"\n"
+ + "FROM \"scott\".\"EMP\"";
+ sql(sql)
+ .schema(CalciteAssert.SchemaSpec.SCOTT)
+ .optimize(RuleSets.ofList(CoreRules.AGGREGATE_CASE_TO_FILTER), null)
+ .ok(expected);
+ }
+
@Test void testAggregateFilterToCase() {
final String query = "select\n"
+ " sum(sal) filter(where deptno = 10) as sum_match,\n"
diff --git a/core/src/test/resources/sql/blank.iq
b/core/src/test/resources/sql/blank.iq
index 206707287e..c92dc0f095 100644
--- a/core/src/test/resources/sql/blank.iq
+++ b/core/src/test/resources/sql/blank.iq
@@ -233,4 +233,65 @@ from complex_t;
!ok
+# Test case for [CALCITE-5578] RelOptRulesTest testAggregateCaseToFilter
optimized plan not semantically equivalent to the original one after conversion
+
+CREATE TABLE EMP (
+ EMPNO INTEGER,
+ DEPTNO INTEGER,
+ ENAME VARCHAR(20),
+ JOB VARCHAR(20),
+ MGR INTEGER,
+ HIREDATE DATE,
+ SAL INTEGER,
+ COMM INTEGER,
+ SLACKER INTEGER
+);
+
+(0 rows modified)
+
+!update
+
+INSERT INTO EMP VALUES (0, 70, '-2147483649', '-6721455509335307966', 0,
'1970-01-01', 0, 0, 1);
+
+(1 row modified)
+
+!update
+
+select
+ sum(sal) as sum_sal,
+ count(distinct case
+ when job = 'CLERK'
+ then deptno else null end) as count_distinct_clerk,
+ sum(case when deptno = 10 then sal end) as sum_sal_d10,
+ sum(case when deptno = 20 then sal else 0 end) as sum_sal_d20,
+ sum(case when deptno = 30 then 1 else 0 end) as count_d30,
+ count(case when deptno = 40 then 'x' end) as count_d40,
+ sum(case when deptno = 45 then 1 end) as count_d45,
+ sum(case when deptno = 50 then 1 else null end) as count_d50,
+ sum(case when deptno = 60 then null end) as sum_null_d60,
+ sum(case when deptno = 70 then null else 1 end) as sum_null_d70,
+ count(case when deptno = 20 then 1 end) as count_d20
+from emp;
++---------+----------------------+-------------+-------------+-----------+-----------+-----------+-----------+--------------+--------------+-----------+
+| SUM_SAL | COUNT_DISTINCT_CLERK | SUM_SAL_D10 | SUM_SAL_D20 | COUNT_D30 |
COUNT_D40 | COUNT_D45 | COUNT_D50 | SUM_NULL_D60 | SUM_NULL_D70 | COUNT_D20 |
++---------+----------------------+-------------+-------------+-----------+-----------+-----------+-----------+--------------+--------------+-----------+
+| 0 | 0 | | 0 | 0 |
0 | | | | | 0 |
++---------+----------------------+-------------+-------------+-----------+-----------+-----------+-----------+--------------+--------------+-----------+
+(1 row)
+
+!ok
+
+# Test same sql after apply AGGREGATE_CASE_TO_FILTER
+
+SELECT SUM("SAL") AS "SUM_SAL", COUNT(DISTINCT "DEPTNO") FILTER (WHERE "JOB" =
'CLERK' IS TRUE) AS "COUNT_DISTINCT_CLERK", SUM("SAL") FILTER (WHERE
CAST("DEPTNO" AS INTEGER) = 10 IS TRUE) AS "SUM_SAL_D10", SUM(CASE WHEN
CAST("DEPTNO" AS INTEGER) = 20 THEN CAST("SAL" AS DECIMAL(12, 2)) ELSE 0.00
END) AS "SUM_SAL_D20", SUM(CASE WHEN CAST("DEPTNO" AS INTEGER) = 30 THEN 1 ELSE
0 END) AS "COUNT_D30", COUNT(*) FILTER (WHERE CAST("DEPTNO" AS INTEGER) = 40 IS
TRUE) AS "COUNT_D40", SUM(1) FILTER [...]
+FROM "EMP";
++---------+----------------------+-------------+-------------+-----------+-----------+-----------+-----------+--------------+--------------+-----------+
+| SUM_SAL | COUNT_DISTINCT_CLERK | SUM_SAL_D10 | SUM_SAL_D20 | COUNT_D30 |
COUNT_D40 | COUNT_D45 | COUNT_D50 | SUM_NULL_D60 | SUM_NULL_D70 | COUNT_D20 |
++---------+----------------------+-------------+-------------+-----------+-----------+-----------+-----------+--------------+--------------+-----------+
+| 0 | 0 | | 0.00 | 0 |
0 | | | | | 0 |
++---------+----------------------+-------------+-------------+-----------+-----------+-----------+-----------+--------------+--------------+-----------+
+(1 row)
+
+!ok
+
# End blank.iq