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

jonah pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 13cb65e441 Infer count() aggregation is not null (#11256)
13cb65e441 is described below

commit 13cb65e44136711befb87dd75fb8b41f814af16f
Author: Piotr Findeisen <[email protected]>
AuthorDate: Sat Jul 6 06:05:38 2024 +0200

    Infer count() aggregation is not null (#11256)
    
    * Fix test function name typo
    
    * Improve formatting
    
    * Infer count() aggregation is not null
    
    `count([DISTINCT [expr]])` aggregate function never returns null. Infer
    non-nullness of such aggregate expression. This allows elimination of
    the HAVING filter for a query such as
    
        SELECT ... count(*) AS c
        FROM ...
        GROUP BY ...
        HAVING c IS NOT NULL
---
 datafusion/core/tests/dataframe/mod.rs             |  1 +
 datafusion/expr/src/expr_schema.rs                 |  3 ++
 .../optimizer/src/analyzer/count_wildcard_rule.rs  | 32 ++++++-------
 .../optimizer/src/single_distinct_to_groupby.rs    | 54 +++++++++++-----------
 .../optimizer/tests/optimizer_integration.rs       | 15 ++++++
 5 files changed, 62 insertions(+), 43 deletions(-)

diff --git a/datafusion/core/tests/dataframe/mod.rs 
b/datafusion/core/tests/dataframe/mod.rs
index c3bc2fcca2..e46a92e928 100644
--- a/datafusion/core/tests/dataframe/mod.rs
+++ b/datafusion/core/tests/dataframe/mod.rs
@@ -234,6 +234,7 @@ async fn test_count_wildcard_on_aggregate() -> Result<()> {
 
     Ok(())
 }
+
 #[tokio::test]
 async fn test_count_wildcard_on_where_scalar_subquery() -> Result<()> {
     let ctx = create_join_context()?;
diff --git a/datafusion/expr/src/expr_schema.rs 
b/datafusion/expr/src/expr_schema.rs
index 45ade5c599..1df5d6c4d7 100644
--- a/datafusion/expr/src/expr_schema.rs
+++ b/datafusion/expr/src/expr_schema.rs
@@ -330,6 +330,9 @@ impl ExprSchemable for Expr {
                 match func_def {
                     AggregateFunctionDefinition::BuiltIn(fun) => 
fun.nullable(),
                     // TODO: UDF should be able to customize nullability
+                    AggregateFunctionDefinition::UDF(udf) if udf.name() == 
"count" => {
+                        Ok(false)
+                    }
                     AggregateFunctionDefinition::UDF(_) => Ok(true),
                 }
             }
diff --git a/datafusion/optimizer/src/analyzer/count_wildcard_rule.rs 
b/datafusion/optimizer/src/analyzer/count_wildcard_rule.rs
index 34f9802b1f..959ffdaaa2 100644
--- a/datafusion/optimizer/src/analyzer/count_wildcard_rule.rs
+++ b/datafusion/optimizer/src/analyzer/count_wildcard_rule.rs
@@ -127,9 +127,9 @@ mod tests {
             .project(vec![count(wildcard())])?
             .sort(vec![count(wildcard()).sort(true, false)])?
             .build()?;
-        let expected = "Sort: count(*) ASC NULLS LAST [count(*):Int64;N]\
-        \n  Projection: count(*) [count(*):Int64;N]\
-        \n    Aggregate: groupBy=[[test.b]], aggr=[[count(Int64(1)) AS 
count(*)]] [b:UInt32, count(*):Int64;N]\
+        let expected = "Sort: count(*) ASC NULLS LAST [count(*):Int64]\
+        \n  Projection: count(*) [count(*):Int64]\
+        \n    Aggregate: groupBy=[[test.b]], aggr=[[count(Int64(1)) AS 
count(*)]] [b:UInt32, count(*):Int64]\
         \n      TableScan: test [a:UInt32, b:UInt32, c:UInt32]";
         assert_plan_eq(plan, expected)
     }
@@ -152,9 +152,9 @@ mod tests {
             .build()?;
 
         let expected = "Filter: t1.a IN (<subquery>) [a:UInt32, b:UInt32, 
c:UInt32]\
-        \n  Subquery: [count(*):Int64;N]\
-        \n    Projection: count(*) [count(*):Int64;N]\
-        \n      Aggregate: groupBy=[[]], aggr=[[count(Int64(1)) AS count(*)]] 
[count(*):Int64;N]\
+        \n  Subquery: [count(*):Int64]\
+        \n    Projection: count(*) [count(*):Int64]\
+        \n      Aggregate: groupBy=[[]], aggr=[[count(Int64(1)) AS count(*)]] 
[count(*):Int64]\
         \n        TableScan: t2 [a:UInt32, b:UInt32, c:UInt32]\
         \n  TableScan: t1 [a:UInt32, b:UInt32, c:UInt32]";
         assert_plan_eq(plan, expected)
@@ -175,9 +175,9 @@ mod tests {
             .build()?;
 
         let expected = "Filter: EXISTS (<subquery>) [a:UInt32, b:UInt32, 
c:UInt32]\
-        \n  Subquery: [count(*):Int64;N]\
-        \n    Projection: count(*) [count(*):Int64;N]\
-        \n      Aggregate: groupBy=[[]], aggr=[[count(Int64(1)) AS count(*)]] 
[count(*):Int64;N]\
+        \n  Subquery: [count(*):Int64]\
+        \n    Projection: count(*) [count(*):Int64]\
+        \n      Aggregate: groupBy=[[]], aggr=[[count(Int64(1)) AS count(*)]] 
[count(*):Int64]\
         \n        TableScan: t2 [a:UInt32, b:UInt32, c:UInt32]\
         \n  TableScan: t1 [a:UInt32, b:UInt32, c:UInt32]";
         assert_plan_eq(plan, expected)
@@ -207,9 +207,9 @@ mod tests {
 
         let expected = "Projection: t1.a, t1.b [a:UInt32, b:UInt32]\
               \n  Filter: (<subquery>) > UInt8(0) [a:UInt32, b:UInt32, 
c:UInt32]\
-              \n    Subquery: [count(Int64(1)):Int64;N]\
-              \n      Projection: count(Int64(1)) [count(Int64(1)):Int64;N]\
-              \n        Aggregate: groupBy=[[]], aggr=[[count(Int64(1))]] 
[count(Int64(1)):Int64;N]\
+              \n    Subquery: [count(Int64(1)):Int64]\
+              \n      Projection: count(Int64(1)) [count(Int64(1)):Int64]\
+              \n        Aggregate: groupBy=[[]], aggr=[[count(Int64(1))]] 
[count(Int64(1)):Int64]\
               \n          Filter: outer_ref(t1.a) = t2.a [a:UInt32, b:UInt32, 
c:UInt32]\
               \n            TableScan: t2 [a:UInt32, b:UInt32, c:UInt32]\
               \n    TableScan: t1 [a:UInt32, b:UInt32, c:UInt32]";
@@ -235,7 +235,7 @@ mod tests {
             .project(vec![count(wildcard())])?
             .build()?;
 
-        let expected = "Projection: count(Int64(1)) AS count(*) 
[count(*):Int64;N]\
+        let expected = "Projection: count(Int64(1)) AS count(*) 
[count(*):Int64]\
         \n  WindowAggr: windowExpr=[[count(Int64(1)) ORDER BY [test.a DESC 
NULLS FIRST] RANGE BETWEEN 6 PRECEDING AND 2 FOLLOWING AS count(*) ORDER BY 
[test.a DESC NULLS FIRST] RANGE BETWEEN 6 PRECEDING AND 2 FOLLOWING]] 
[a:UInt32, b:UInt32, c:UInt32, count(*) ORDER BY [test.a DESC NULLS FIRST] 
RANGE BETWEEN 6 PRECEDING AND 2 FOLLOWING:Int64;N]\
         \n    TableScan: test [a:UInt32, b:UInt32, c:UInt32]";
         assert_plan_eq(plan, expected)
@@ -249,8 +249,8 @@ mod tests {
             .project(vec![count(wildcard())])?
             .build()?;
 
-        let expected = "Projection: count(*) [count(*):Int64;N]\
-        \n  Aggregate: groupBy=[[]], aggr=[[count(Int64(1)) AS count(*)]] 
[count(*):Int64;N]\
+        let expected = "Projection: count(*) [count(*):Int64]\
+        \n  Aggregate: groupBy=[[]], aggr=[[count(Int64(1)) AS count(*)]] 
[count(*):Int64]\
         \n    TableScan: test [a:UInt32, b:UInt32, c:UInt32]";
         assert_plan_eq(plan, expected)
     }
@@ -272,7 +272,7 @@ mod tests {
             .project(vec![count(wildcard())])?
             .build()?;
 
-        let expected = "Projection: count(Int64(1)) AS count(*) 
[count(*):Int64;N]\
+        let expected = "Projection: count(Int64(1)) AS count(*) 
[count(*):Int64]\
         \n  Aggregate: groupBy=[[]], aggr=[[MAX(count(Int64(1))) AS 
MAX(count(*))]] [MAX(count(*)):Int64;N]\
         \n    TableScan: test [a:UInt32, b:UInt32, c:UInt32]";
         assert_plan_eq(plan, expected)
diff --git a/datafusion/optimizer/src/single_distinct_to_groupby.rs 
b/datafusion/optimizer/src/single_distinct_to_groupby.rs
index b3562b7065..7c66d659cb 100644
--- a/datafusion/optimizer/src/single_distinct_to_groupby.rs
+++ b/datafusion/optimizer/src/single_distinct_to_groupby.rs
@@ -396,8 +396,8 @@ mod tests {
             .build()?;
 
         // Should work
-        let expected = "Projection: count(alias1) AS count(DISTINCT test.b) 
[count(DISTINCT test.b):Int64;N]\
-                            \n  Aggregate: groupBy=[[]], 
aggr=[[count(alias1)]] [count(alias1):Int64;N]\
+        let expected = "Projection: count(alias1) AS count(DISTINCT test.b) 
[count(DISTINCT test.b):Int64]\
+                            \n  Aggregate: groupBy=[[]], 
aggr=[[count(alias1)]] [count(alias1):Int64]\
                             \n    Aggregate: groupBy=[[test.b AS alias1]], 
aggr=[[]] [alias1:UInt32]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -419,7 +419,7 @@ mod tests {
             .build()?;
 
         // Should not be optimized
-        let expected = "Aggregate: groupBy=[[GROUPING SETS ((test.a), 
(test.b))]], aggr=[[count(DISTINCT test.c)]] [a:UInt32;N, b:UInt32;N, 
count(DISTINCT test.c):Int64;N]\
+        let expected = "Aggregate: groupBy=[[GROUPING SETS ((test.a), 
(test.b))]], aggr=[[count(DISTINCT test.c)]] [a:UInt32;N, b:UInt32;N, 
count(DISTINCT test.c):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -437,7 +437,7 @@ mod tests {
             .build()?;
 
         // Should not be optimized
-        let expected = "Aggregate: groupBy=[[CUBE (test.a, test.b)]], 
aggr=[[count(DISTINCT test.c)]] [a:UInt32;N, b:UInt32;N, count(DISTINCT 
test.c):Int64;N]\
+        let expected = "Aggregate: groupBy=[[CUBE (test.a, test.b)]], 
aggr=[[count(DISTINCT test.c)]] [a:UInt32;N, b:UInt32;N, count(DISTINCT 
test.c):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -456,7 +456,7 @@ mod tests {
             .build()?;
 
         // Should not be optimized
-        let expected = "Aggregate: groupBy=[[ROLLUP (test.a, test.b)]], 
aggr=[[count(DISTINCT test.c)]] [a:UInt32;N, b:UInt32;N, count(DISTINCT 
test.c):Int64;N]\
+        let expected = "Aggregate: groupBy=[[ROLLUP (test.a, test.b)]], 
aggr=[[count(DISTINCT test.c)]] [a:UInt32;N, b:UInt32;N, count(DISTINCT 
test.c):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -470,8 +470,8 @@ mod tests {
             .aggregate(Vec::<Expr>::new(), vec![count_distinct(lit(2) * 
col("b"))])?
             .build()?;
 
-        let expected = "Projection: count(alias1) AS count(DISTINCT Int32(2) * 
test.b) [count(DISTINCT Int32(2) * test.b):Int64;N]\
-                            \n  Aggregate: groupBy=[[]], 
aggr=[[count(alias1)]] [count(alias1):Int64;N]\
+        let expected = "Projection: count(alias1) AS count(DISTINCT Int32(2) * 
test.b) [count(DISTINCT Int32(2) * test.b):Int64]\
+                            \n  Aggregate: groupBy=[[]], 
aggr=[[count(alias1)]] [count(alias1):Int64]\
                             \n    Aggregate: groupBy=[[Int32(2) * test.b AS 
alias1]], aggr=[[]] [alias1:Int32]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -487,8 +487,8 @@ mod tests {
             .build()?;
 
         // Should work
-        let expected = "Projection: test.a, count(alias1) AS count(DISTINCT 
test.b) [a:UInt32, count(DISTINCT test.b):Int64;N]\
-                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[count(alias1)]] [a:UInt32, count(alias1):Int64;N]\
+        let expected = "Projection: test.a, count(alias1) AS count(DISTINCT 
test.b) [a:UInt32, count(DISTINCT test.b):Int64]\
+                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[count(alias1)]] [a:UInt32, count(alias1):Int64]\
                             \n    Aggregate: groupBy=[[test.a, test.b AS 
alias1]], aggr=[[]] [a:UInt32, alias1:UInt32]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -507,7 +507,7 @@ mod tests {
             .build()?;
 
         // Do nothing
-        let expected = "Aggregate: groupBy=[[test.a]], aggr=[[count(DISTINCT 
test.b), count(DISTINCT test.c)]] [a:UInt32, count(DISTINCT test.b):Int64;N, 
count(DISTINCT test.c):Int64;N]\
+        let expected = "Aggregate: groupBy=[[test.a]], aggr=[[count(DISTINCT 
test.b), count(DISTINCT test.c)]] [a:UInt32, count(DISTINCT test.b):Int64, 
count(DISTINCT test.c):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -534,8 +534,8 @@ mod tests {
             )?
             .build()?;
         // Should work
-        let expected = "Projection: test.a, count(alias1) AS count(DISTINCT 
test.b), MAX(alias1) AS MAX(DISTINCT test.b) [a:UInt32, count(DISTINCT 
test.b):Int64;N, MAX(DISTINCT test.b):UInt32;N]\
-                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[count(alias1), MAX(alias1)]] [a:UInt32, count(alias1):Int64;N, 
MAX(alias1):UInt32;N]\
+        let expected = "Projection: test.a, count(alias1) AS count(DISTINCT 
test.b), MAX(alias1) AS MAX(DISTINCT test.b) [a:UInt32, count(DISTINCT 
test.b):Int64, MAX(DISTINCT test.b):UInt32;N]\
+                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[count(alias1), MAX(alias1)]] [a:UInt32, count(alias1):Int64, 
MAX(alias1):UInt32;N]\
                             \n    Aggregate: groupBy=[[test.a, test.b AS 
alias1]], aggr=[[]] [a:UInt32, alias1:UInt32]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -554,7 +554,7 @@ mod tests {
             .build()?;
 
         // Do nothing
-        let expected = "Aggregate: groupBy=[[test.a]], aggr=[[count(DISTINCT 
test.b), count(test.c)]] [a:UInt32, count(DISTINCT test.b):Int64;N, 
count(test.c):Int64;N]\
+        let expected = "Aggregate: groupBy=[[test.a]], aggr=[[count(DISTINCT 
test.b), count(test.c)]] [a:UInt32, count(DISTINCT test.b):Int64, 
count(test.c):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -569,8 +569,8 @@ mod tests {
             .build()?;
 
         // Should work
-        let expected = "Projection: group_alias_0 AS test.a + Int32(1), 
count(alias1) AS count(DISTINCT test.c) [test.a + Int32(1):Int32, 
count(DISTINCT test.c):Int64;N]\
-                            \n  Aggregate: groupBy=[[group_alias_0]], 
aggr=[[count(alias1)]] [group_alias_0:Int32, count(alias1):Int64;N]\
+        let expected = "Projection: group_alias_0 AS test.a + Int32(1), 
count(alias1) AS count(DISTINCT test.c) [test.a + Int32(1):Int32, 
count(DISTINCT test.c):Int64]\
+                            \n  Aggregate: groupBy=[[group_alias_0]], 
aggr=[[count(alias1)]] [group_alias_0:Int32, count(alias1):Int64]\
                             \n    Aggregate: groupBy=[[test.a + Int32(1) AS 
group_alias_0, test.c AS alias1]], aggr=[[]] [group_alias_0:Int32, 
alias1:UInt32]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -599,8 +599,8 @@ mod tests {
             )?
             .build()?;
         // Should work
-        let expected = "Projection: test.a, sum(alias2) AS sum(test.c), 
count(alias1) AS count(DISTINCT test.b), MAX(alias1) AS MAX(DISTINCT test.b) 
[a:UInt32, sum(test.c):UInt64;N, count(DISTINCT test.b):Int64;N, MAX(DISTINCT 
test.b):UInt32;N]\
-                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[sum(alias2), count(alias1), MAX(alias1)]] [a:UInt32, 
sum(alias2):UInt64;N, count(alias1):Int64;N, MAX(alias1):UInt32;N]\
+        let expected = "Projection: test.a, sum(alias2) AS sum(test.c), 
count(alias1) AS count(DISTINCT test.b), MAX(alias1) AS MAX(DISTINCT test.b) 
[a:UInt32, sum(test.c):UInt64;N, count(DISTINCT test.b):Int64, MAX(DISTINCT 
test.b):UInt32;N]\
+                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[sum(alias2), count(alias1), MAX(alias1)]] [a:UInt32, 
sum(alias2):UInt64;N, count(alias1):Int64, MAX(alias1):UInt32;N]\
                             \n    Aggregate: groupBy=[[test.a, test.b AS 
alias1]], aggr=[[sum(test.c) AS alias2]] [a:UInt32, alias1:UInt32, 
alias2:UInt64;N]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -608,7 +608,7 @@ mod tests {
     }
 
     #[test]
-    fn one_distinctand_and_two_common() -> Result<()> {
+    fn one_distinct_and_two_common() -> Result<()> {
         let table_scan = test_table_scan()?;
 
         let plan = LogicalPlanBuilder::from(table_scan)
@@ -618,8 +618,8 @@ mod tests {
             )?
             .build()?;
         // Should work
-        let expected = "Projection: test.a, sum(alias2) AS sum(test.c), 
MAX(alias3) AS MAX(test.c), count(alias1) AS count(DISTINCT test.b) [a:UInt32, 
sum(test.c):UInt64;N, MAX(test.c):UInt32;N, count(DISTINCT test.b):Int64;N]\
-                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[sum(alias2), MAX(alias3), count(alias1)]] [a:UInt32, 
sum(alias2):UInt64;N, MAX(alias3):UInt32;N, count(alias1):Int64;N]\
+        let expected = "Projection: test.a, sum(alias2) AS sum(test.c), 
MAX(alias3) AS MAX(test.c), count(alias1) AS count(DISTINCT test.b) [a:UInt32, 
sum(test.c):UInt64;N, MAX(test.c):UInt32;N, count(DISTINCT test.b):Int64]\
+                            \n  Aggregate: groupBy=[[test.a]], 
aggr=[[sum(alias2), MAX(alias3), count(alias1)]] [a:UInt32, 
sum(alias2):UInt64;N, MAX(alias3):UInt32;N, count(alias1):Int64]\
                             \n    Aggregate: groupBy=[[test.a, test.b AS 
alias1]], aggr=[[sum(test.c) AS alias2, MAX(test.c) AS alias3]] [a:UInt32, 
alias1:UInt32, alias2:UInt64;N, alias3:UInt32;N]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -637,8 +637,8 @@ mod tests {
             )?
             .build()?;
         // Should work
-        let expected = "Projection: test.c, MIN(alias2) AS MIN(test.a), 
count(alias1) AS count(DISTINCT test.b) [c:UInt32, MIN(test.a):UInt32;N, 
count(DISTINCT test.b):Int64;N]\
-                            \n  Aggregate: groupBy=[[test.c]], 
aggr=[[MIN(alias2), count(alias1)]] [c:UInt32, MIN(alias2):UInt32;N, 
count(alias1):Int64;N]\
+        let expected = "Projection: test.c, MIN(alias2) AS MIN(test.a), 
count(alias1) AS count(DISTINCT test.b) [c:UInt32, MIN(test.a):UInt32;N, 
count(DISTINCT test.b):Int64]\
+                            \n  Aggregate: groupBy=[[test.c]], 
aggr=[[MIN(alias2), count(alias1)]] [c:UInt32, MIN(alias2):UInt32;N, 
count(alias1):Int64]\
                             \n    Aggregate: groupBy=[[test.c, test.b AS 
alias1]], aggr=[[MIN(test.a) AS alias2]] [c:UInt32, alias1:UInt32, 
alias2:UInt32;N]\
                             \n      TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
@@ -662,7 +662,7 @@ mod tests {
             .aggregate(vec![col("c")], vec![expr, count_distinct(col("b"))])?
             .build()?;
         // Do nothing
-        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a) 
FILTER (WHERE test.a > Int32(5)), count(DISTINCT test.b)]] [c:UInt32, 
sum(test.a) FILTER (WHERE test.a > Int32(5)):UInt64;N, count(DISTINCT 
test.b):Int64;N]\
+        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a) 
FILTER (WHERE test.a > Int32(5)), count(DISTINCT test.b)]] [c:UInt32, 
sum(test.a) FILTER (WHERE test.a > Int32(5)):UInt64;N, count(DISTINCT 
test.b):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -682,7 +682,7 @@ mod tests {
             .aggregate(vec![col("c")], vec![sum(col("a")), expr])?
             .build()?;
         // Do nothing
-        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a), 
count(DISTINCT test.a) FILTER (WHERE test.a > Int32(5))]] [c:UInt32, 
sum(test.a):UInt64;N, count(DISTINCT test.a) FILTER (WHERE test.a > 
Int32(5)):Int64;N]\
+        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a), 
count(DISTINCT test.a) FILTER (WHERE test.a > Int32(5))]] [c:UInt32, 
sum(test.a):UInt64;N, count(DISTINCT test.a) FILTER (WHERE test.a > 
Int32(5)):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -705,7 +705,7 @@ mod tests {
             .aggregate(vec![col("c")], vec![expr, count_distinct(col("b"))])?
             .build()?;
         // Do nothing
-        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a) 
ORDER BY [test.a], count(DISTINCT test.b)]] [c:UInt32, sum(test.a) ORDER BY 
[test.a]:UInt64;N, count(DISTINCT test.b):Int64;N]\
+        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a) 
ORDER BY [test.a], count(DISTINCT test.b)]] [c:UInt32, sum(test.a) ORDER BY 
[test.a]:UInt64;N, count(DISTINCT test.b):Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -725,7 +725,7 @@ mod tests {
             .aggregate(vec![col("c")], vec![sum(col("a")), expr])?
             .build()?;
         // Do nothing
-        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a), 
count(DISTINCT test.a) ORDER BY [test.a ASC NULLS LAST]]] [c:UInt32, 
sum(test.a):UInt64;N, count(DISTINCT test.a) ORDER BY [test.a ASC NULLS 
LAST]:Int64;N]\
+        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a), 
count(DISTINCT test.a) ORDER BY [test.a ASC NULLS LAST]]] [c:UInt32, 
sum(test.a):UInt64;N, count(DISTINCT test.a) ORDER BY [test.a ASC NULLS 
LAST]:Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
@@ -746,7 +746,7 @@ mod tests {
             .aggregate(vec![col("c")], vec![sum(col("a")), expr])?
             .build()?;
         // Do nothing
-        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a), 
count(DISTINCT test.a) FILTER (WHERE test.a > Int32(5)) ORDER BY [test.a ASC 
NULLS LAST]]] [c:UInt32, sum(test.a):UInt64;N, count(DISTINCT test.a) FILTER 
(WHERE test.a > Int32(5)) ORDER BY [test.a ASC NULLS LAST]:Int64;N]\
+        let expected = "Aggregate: groupBy=[[test.c]], aggr=[[sum(test.a), 
count(DISTINCT test.a) FILTER (WHERE test.a > Int32(5)) ORDER BY [test.a ASC 
NULLS LAST]]] [c:UInt32, sum(test.a):UInt64;N, count(DISTINCT test.a) FILTER 
(WHERE test.a > Int32(5)) ORDER BY [test.a ASC NULLS LAST]:Int64]\
                             \n  TableScan: test [a:UInt32, b:UInt32, 
c:UInt32]";
 
         assert_optimized_plan_equal(plan, expected)
diff --git a/datafusion/optimizer/tests/optimizer_integration.rs 
b/datafusion/optimizer/tests/optimizer_integration.rs
index c501d5aaa4..c0863839db 100644
--- a/datafusion/optimizer/tests/optimizer_integration.rs
+++ b/datafusion/optimizer/tests/optimizer_integration.rs
@@ -294,6 +294,21 @@ fn eliminate_nested_filters() {
     assert_eq!(expected, format!("{plan:?}"));
 }
 
+#[test]
+fn eliminate_redundant_null_check_on_count() {
+    let sql = "\
+        SELECT col_int32, count(*) c
+        FROM test
+        GROUP BY col_int32
+        HAVING c IS NOT NULL";
+    let plan = test_sql(sql).unwrap();
+    let expected = "\
+        Projection: test.col_int32, count(*) AS c\
+        \n  Aggregate: groupBy=[[test.col_int32]], aggr=[[count(Int64(1)) AS 
count(*)]]\
+        \n    TableScan: test projection=[col_int32]";
+    assert_eq!(expected, format!("{plan:?}"));
+}
+
 #[test]
 fn test_propagate_empty_relation_inner_join_and_unions() {
     let sql = "\


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to