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]