From 61d203c3fc0bf2d33d14e961f2484e9eb2230a71 Mon Sep 17 00:00:00 2001 From: HairstonE Date: Mon, 11 May 2026 16:33:08 -0400 Subject: [PATCH 1/3] remove unneeded guard condition and update unit test --- .../optimizer/src/eliminate_group_by_constant.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/datafusion/optimizer/src/eliminate_group_by_constant.rs b/datafusion/optimizer/src/eliminate_group_by_constant.rs index e21241ba7d993..e3a75b64d5f11 100644 --- a/datafusion/optimizer/src/eliminate_group_by_constant.rs +++ b/datafusion/optimizer/src/eliminate_group_by_constant.rs @@ -64,10 +64,10 @@ impl OptimizerRule for EliminateGroupByConstant { .group_expr .iter() .partition(|expr| is_redundant_group_expr(expr, &group_by_columns)); + // Only eliminate when at least one required group expression remains. A grouping + // aggregate emits 0 rows on empty input; a global aggregate emits 1 NULL row. - if redundant.is_empty() - || (required.is_empty() && aggregate.aggr_expr.is_empty()) - { + if redundant.is_empty() || required.is_empty() { return Ok(Transformed::no(LogicalPlan::Aggregate(aggregate))); } @@ -228,9 +228,8 @@ mod tests { .build()?; assert_optimized_plan_equal!(plan, @r#" - Projection: Utf8("test"), UInt32(123), count(test.c) - Aggregate: groupBy=[[]], aggr=[[count(test.c)]] - TableScan: test + Aggregate: groupBy=[[Utf8("test"), UInt32(123)]], aggr=[[count(test.c)]] + TableScan: test "#) } From 7ab8ca654d991ec5c7e30a192e0d6895198ae94c Mon Sep 17 00:00:00 2001 From: HairstonE Date: Tue, 12 May 2026 11:17:21 -0400 Subject: [PATCH 2/3] add sqllogictest for reproducer, test outputs --- .../sqllogictest/test_files/aggregate.slt | 5 +++++ .../optimizer_group_by_constant.slt | 20 +++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/datafusion/sqllogictest/test_files/aggregate.slt b/datafusion/sqllogictest/test_files/aggregate.slt index 70acff3cb7b9a..bda41a4388449 100644 --- a/datafusion/sqllogictest/test_files/aggregate.slt +++ b/datafusion/sqllogictest/test_files/aggregate.slt @@ -7842,6 +7842,11 @@ CREATE TABLE t1(v1 int); statement error DataFusion error: Error during planning: Aggregate functions are not allowed in the WHERE clause. Consider using HAVING instead SELECT v1 FROM t1 WHERE ((count(v1) % 1) << 1) > 0; +# issue: https://github.com/apache/datafusion/issues/11748 +query R +SELECT AVG(v1) FROM t1 GROUP BY false HAVING false; +---- + statement ok DROP TABLE t1; diff --git a/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt b/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt index da1e7de22bb7a..9df55512413f3 100644 --- a/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt +++ b/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt @@ -60,10 +60,9 @@ FROM test_table t group by 1, 2, 3 ---- logical_plan -01)Projection: Int64(123), Int64(456), Int64(789), count(Int64(1)), avg(t.c12) -02)--Aggregate: groupBy=[[]], aggr=[[count(Int64(1)), avg(t.c12)]] -03)----SubqueryAlias: t -04)------TableScan: test_table projection=[c12] +01)Aggregate: groupBy=[[Int64(123), Int64(456), Int64(789)]], aggr=[[count(Int64(1)), avg(t.c12)]] +02)--SubqueryAlias: t +03)----TableScan: test_table projection=[c12] query TT EXPLAIN @@ -72,8 +71,8 @@ FROM test_table t GROUP BY 1, 2 ---- logical_plan -01)Projection: Date32("2023-05-04") AS dt, Boolean(true) AS today_filter, count(Int64(1)) -02)--Aggregate: groupBy=[[]], aggr=[[count(Int64(1))]] +01)Projection: to_date(Utf8("2023-05-04")) AS dt, date_part(Utf8("DAY"),now()) < Int64(1000) AS today_filter, count(Int64(1)) +02)--Aggregate: groupBy=[[Date32("2023-05-04") AS to_date(Utf8("2023-05-04")), Boolean(true) AS date_part(Utf8("DAY"),now()) < Int64(1000)]], aggr=[[count(Int64(1))]] 03)----SubqueryAlias: t 04)------TableScan: test_table projection=[] @@ -90,10 +89,9 @@ FROM test_table t GROUP BY 1 ---- logical_plan -01)Projection: Boolean(true) AS NOT date_part(Utf8("MONTH"),now()) BETWEEN Int64(50) AND Int64(60), count(Int64(1)) -02)--Aggregate: groupBy=[[]], aggr=[[count(Int64(1))]] -03)----SubqueryAlias: t -04)------TableScan: test_table projection=[] +01)Aggregate: groupBy=[[Boolean(true) AS NOT date_part(Utf8("MONTH"),now()) BETWEEN Int64(50) AND Int64(60)]], aggr=[[count(Int64(1))]] +02)--SubqueryAlias: t +03)----TableScan: test_table projection=[] query TT EXPLAIN @@ -119,7 +117,7 @@ logical_plan # Config reset -# The SLT runner sets `target_partitions` to 4 instead of using the default, so +# The SLT runner sets `target_partitions` to 4 instead of using the default, so # reset it explicitly. statement ok set datafusion.execution.target_partitions = 4; From 815a2002a27521b336132d9bf9b246f8878cfb49 Mon Sep 17 00:00:00 2001 From: HairstonE Date: Wed, 13 May 2026 11:33:01 -0400 Subject: [PATCH 3/3] add non HAVING and non-empty GROUP BY false tests per review. --- datafusion/sqllogictest/test_files/aggregate.slt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/datafusion/sqllogictest/test_files/aggregate.slt b/datafusion/sqllogictest/test_files/aggregate.slt index bda41a4388449..fdb4b33e93069 100644 --- a/datafusion/sqllogictest/test_files/aggregate.slt +++ b/datafusion/sqllogictest/test_files/aggregate.slt @@ -7847,6 +7847,18 @@ query R SELECT AVG(v1) FROM t1 GROUP BY false HAVING false; ---- +query R +SELECT AVG(v1) FROM t1 GROUP BY false; +---- + +statement ok +INSERT INTO t1 VALUES (1), (2), (3); + +query R +SELECT AVG(v1) FROM t1 GROUP BY false; +---- +2 + statement ok DROP TABLE t1;