This is an automated email from the ASF dual-hosted git repository.
alamb 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 fdd1e3db71 Convert Average to UDAF #10942 (#10964)
fdd1e3db71 is described below
commit fdd1e3db71c07f412366912396f51520147f3a10
Author: Dharan Aditya <[email protected]>
AuthorDate: Sun Jun 23 15:48:57 2024 +0530
Convert Average to UDAF #10942 (#10964)
* add avg udaf
* remove avg from expr
* add test stub
* migrate avg udaf
* change avg udaf signature
remove avg phy expr
* fix tests
* fix state_fields fn
* fix ut in phy-plan aggr
* refactor Average to Avg
* refactor Average to Avg
* fix type coercion tests
* fix example and logic tests
* fix py expr failing ut
* update docs
* fix failing tests
* formatting examples
* remove duplicate code and fix uts
* addressing PR comments
* add ut for logical avg window
* fix physical plan roundtrip_window test case
---
datafusion-examples/examples/dataframe_subquery.rs | 1 +
.../examples/simplify_udaf_expression.rs | 38 +-
.../examples/simplify_udwf_expression.rs | 10 +-
datafusion/core/src/dataframe/mod.rs | 12 +-
datafusion/core/tests/dataframe/mod.rs | 8 +-
.../tests/user_defined/user_defined_aggregates.rs | 3 +-
.../user_defined/user_defined_scalar_functions.rs | 4 +-
datafusion/expr/src/aggregate_function.rs | 22 --
datafusion/expr/src/expr.rs | 7 -
datafusion/expr/src/expr_fn.rs | 12 -
datafusion/expr/src/expr_rewriter/order_by.rs | 8 +-
datafusion/expr/src/test/function_stub.rs | 80 +++-
datafusion/expr/src/type_coercion/aggregates.rs | 86 ++---
.../src}/average.rs | 410 ++++++++++-----------
datafusion/functions-aggregate/src/lib.rs | 3 +
datafusion/optimizer/src/analyzer/type_coercion.rs | 39 +-
.../optimizer/src/common_subexpr_eliminate.rs | 34 +-
.../optimizer/tests/optimizer_integration.rs | 10 +-
datafusion/physical-expr/src/aggregate/build_in.rs | 74 +---
.../src/aggregate/groups_accumulator/mod.rs | 1 +
datafusion/physical-expr/src/aggregate/mod.rs | 1 -
datafusion/physical-expr/src/expressions/mod.rs | 2 -
datafusion/physical-plan/src/aggregates/mod.rs | 73 ++--
datafusion/proto/proto/datafusion.proto | 2 +-
datafusion/proto/src/generated/pbjson.rs | 3 -
datafusion/proto/src/generated/prost.rs | 4 +-
datafusion/proto/src/logical_plan/from_proto.rs | 1 -
datafusion/proto/src/logical_plan/to_proto.rs | 2 -
datafusion/proto/src/physical_plan/to_proto.rs | 35 +-
.../proto/tests/cases/roundtrip_logical_plan.rs | 15 +-
.../proto/tests/cases/roundtrip_physical_plan.rs | 52 ++-
datafusion/sql/tests/sql_integration.rs | 14 +-
datafusion/sqllogictest/test_files/aggregate.slt | 14 +-
datafusion/sqllogictest/test_files/errors.slt | 2 +-
datafusion/sqllogictest/test_files/group_by.slt | 4 +-
.../test_files/optimizer_group_by_constant.slt | 4 +-
datafusion/sqllogictest/test_files/predicates.slt | 4 +-
.../sqllogictest/test_files/tpch/q1.slt.part | 10 +-
.../sqllogictest/test_files/tpch/q17.slt.part | 14 +-
.../sqllogictest/test_files/tpch/q22.slt.part | 10 +-
datafusion/sqllogictest/test_files/window.slt | 26 +-
.../substrait/tests/cases/consumer_integration.rs | 4 +-
.../tests/cases/roundtrip_logical_plan.rs | 2 +-
43 files changed, 564 insertions(+), 596 deletions(-)
diff --git a/datafusion-examples/examples/dataframe_subquery.rs
b/datafusion-examples/examples/dataframe_subquery.rs
index 9fb61008b9..e798751b33 100644
--- a/datafusion-examples/examples/dataframe_subquery.rs
+++ b/datafusion-examples/examples/dataframe_subquery.rs
@@ -19,6 +19,7 @@ use arrow_schema::DataType;
use std::sync::Arc;
use datafusion::error::Result;
+use datafusion::functions_aggregate::average::avg;
use datafusion::prelude::*;
use datafusion::test_util::arrow_test_data;
use datafusion_common::ScalarValue;
diff --git a/datafusion-examples/examples/simplify_udaf_expression.rs
b/datafusion-examples/examples/simplify_udaf_expression.rs
index d2c8c6a86c..aedc511c62 100644
--- a/datafusion-examples/examples/simplify_udaf_expression.rs
+++ b/datafusion-examples/examples/simplify_udaf_expression.rs
@@ -15,21 +15,21 @@
// specific language governing permissions and limitations
// under the License.
-use arrow_schema::{Field, Schema};
-use datafusion::{arrow::datatypes::DataType, logical_expr::Volatility};
-use datafusion_expr::function::{AggregateFunctionSimplification,
StateFieldsArgs};
-use datafusion_expr::simplify::SimplifyInfo;
-
use std::{any::Any, sync::Arc};
+use arrow_schema::{Field, Schema};
+
use datafusion::arrow::{array::Float32Array, record_batch::RecordBatch};
use datafusion::error::Result;
+use datafusion::functions_aggregate::average::avg_udaf;
+use datafusion::{arrow::datatypes::DataType, logical_expr::Volatility};
use datafusion::{assert_batches_eq, prelude::*};
use datafusion_common::cast::as_float64_array;
+use datafusion_expr::function::{AggregateFunctionSimplification,
StateFieldsArgs};
+use datafusion_expr::simplify::SimplifyInfo;
use datafusion_expr::{
- expr::{AggregateFunction, AggregateFunctionDefinition},
- function::AccumulatorArgs,
- Accumulator, AggregateUDF, AggregateUDFImpl, GroupsAccumulator, Signature,
+ expr::AggregateFunction, function::AccumulatorArgs, Accumulator,
AggregateUDF,
+ AggregateUDFImpl, GroupsAccumulator, Signature,
};
/// This example shows how to use the AggregateUDFImpl::simplify API to
simplify/replace user
@@ -92,18 +92,16 @@ impl AggregateUDFImpl for BetterAvgUdaf {
// with build-in aggregate function to illustrate the use
let simplify = |aggregate_function:
datafusion_expr::expr::AggregateFunction,
_: &dyn SimplifyInfo| {
- Ok(Expr::AggregateFunction(AggregateFunction {
- func_def: AggregateFunctionDefinition::BuiltIn(
- // yes it is the same Avg, `BetterAvgUdaf` was just a
- // marketing pitch :)
-
datafusion_expr::aggregate_function::AggregateFunction::Avg,
- ),
- args: aggregate_function.args,
- distinct: aggregate_function.distinct,
- filter: aggregate_function.filter,
- order_by: aggregate_function.order_by,
- null_treatment: aggregate_function.null_treatment,
- }))
+ Ok(Expr::AggregateFunction(AggregateFunction::new_udf(
+ avg_udaf(),
+ // yes it is the same Avg, `BetterAvgUdaf` was just a
+ // marketing pitch :)
+ aggregate_function.args,
+ aggregate_function.distinct,
+ aggregate_function.filter,
+ aggregate_function.order_by,
+ aggregate_function.null_treatment,
+ )))
};
Some(Box::new(simplify))
diff --git a/datafusion-examples/examples/simplify_udwf_expression.rs
b/datafusion-examples/examples/simplify_udwf_expression.rs
index 4e8d03c38e..a17e45dba2 100644
--- a/datafusion-examples/examples/simplify_udwf_expression.rs
+++ b/datafusion-examples/examples/simplify_udwf_expression.rs
@@ -18,12 +18,14 @@
use std::any::Any;
use arrow_schema::DataType;
+
use datafusion::execution::context::SessionContext;
+use datafusion::functions_aggregate::average::avg_udaf;
use datafusion::{error::Result, execution::options::CsvReadOptions};
use datafusion_expr::function::WindowFunctionSimplification;
use datafusion_expr::{
- expr::WindowFunction, simplify::SimplifyInfo, AggregateFunction, Expr,
- PartitionEvaluator, Signature, Volatility, WindowUDF, WindowUDFImpl,
+ expr::WindowFunction, simplify::SimplifyInfo, Expr, PartitionEvaluator,
Signature,
+ Volatility, WindowUDF, WindowUDFImpl,
};
/// This UDWF will show how to use the WindowUDFImpl::simplify() API
@@ -71,9 +73,7 @@ impl WindowUDFImpl for SimplifySmoothItUdf {
let simplify = |window_function: datafusion_expr::expr::WindowFunction,
_: &dyn SimplifyInfo| {
Ok(Expr::WindowFunction(WindowFunction {
- fun:
datafusion_expr::WindowFunctionDefinition::AggregateFunction(
- AggregateFunction::Avg,
- ),
+ fun:
datafusion_expr::WindowFunctionDefinition::AggregateUDF(avg_udaf()),
args: window_function.args,
partition_by: window_function.partition_by,
order_by: window_function.order_by,
diff --git a/datafusion/core/src/dataframe/mod.rs
b/datafusion/core/src/dataframe/mod.rs
index 90cde08768..e1fc8273e6 100644
--- a/datafusion/core/src/dataframe/mod.rs
+++ b/datafusion/core/src/dataframe/mod.rs
@@ -48,13 +48,11 @@ use datafusion_common::config::{CsvOptions, FormatOptions,
JsonOptions};
use datafusion_common::{
plan_err, Column, DFSchema, DataFusionError, ParamValues, SchemaError,
UnnestOptions,
};
-use datafusion_expr::lit;
+use datafusion_expr::{case, is_null, lit};
use datafusion_expr::{
- avg, max, min, utils::COUNT_STAR_EXPANSION, TableProviderFilterPushDown,
- UNNAMED_TABLE,
+ max, min, utils::COUNT_STAR_EXPANSION, TableProviderFilterPushDown,
UNNAMED_TABLE,
};
-use datafusion_expr::{case, is_null};
-use datafusion_functions_aggregate::expr_fn::{count, median, stddev, sum};
+use datafusion_functions_aggregate::expr_fn::{avg, count, median, stddev, sum};
use async_trait::async_trait;
@@ -561,7 +559,7 @@ impl DataFrame {
/// # async fn main() -> Result<()> {
/// let ctx = SessionContext::new();
/// let df = ctx.read_csv("tests/data/example.csv",
CsvReadOptions::new()).await?
- /// // Return a single row (a, b) for each distinct value of a
+ /// // Return a single row (a, b) for each distinct value of a
/// .distinct_on(vec![col("a")], vec![col("a"), col("b")], None)?;
/// # Ok(())
/// # }
@@ -2045,7 +2043,7 @@ mod tests {
assert_batches_sorted_eq!(
["+----+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-------------------------------+----------------------------------------+",
- "| c1 | MIN(aggregate_test_100.c12) |
MAX(aggregate_test_100.c12) | AVG(aggregate_test_100.c12) |
sum(aggregate_test_100.c12) | count(aggregate_test_100.c12) | count(DISTINCT
aggregate_test_100.c12) |",
+ "| c1 | MIN(aggregate_test_100.c12) |
MAX(aggregate_test_100.c12) | avg(aggregate_test_100.c12) |
sum(aggregate_test_100.c12) | count(aggregate_test_100.c12) | count(DISTINCT
aggregate_test_100.c12) |",
"+----+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-------------------------------+----------------------------------------+",
"| a | 0.02182578039211991 | 0.9800193410444061
| 0.48754517466109415 | 10.238448667882977 | 21
| 21 |",
"| b | 0.04893135681998029 | 0.9185813970744787
| 0.41040709263815384 | 7.797734760124923 | 19
| 19 |",
diff --git a/datafusion/core/tests/dataframe/mod.rs
b/datafusion/core/tests/dataframe/mod.rs
index c018ebec4b..700bc53af7 100644
--- a/datafusion/core/tests/dataframe/mod.rs
+++ b/datafusion/core/tests/dataframe/mod.rs
@@ -52,11 +52,11 @@ use datafusion_execution::runtime_env::RuntimeEnv;
use datafusion_expr::expr::{GroupingSet, Sort};
use datafusion_expr::var_provider::{VarProvider, VarType};
use datafusion_expr::{
- array_agg, avg, cast, col, exists, expr, in_subquery, lit, max,
out_ref_col,
- placeholder, scalar_subquery, when, wildcard, Expr, ExprSchemable,
WindowFrame,
- WindowFrameBound, WindowFrameUnits, WindowFunctionDefinition,
+ array_agg, cast, col, exists, expr, in_subquery, lit, max, out_ref_col,
placeholder,
+ scalar_subquery, when, wildcard, Expr, ExprSchemable, WindowFrame,
WindowFrameBound,
+ WindowFrameUnits, WindowFunctionDefinition,
};
-use datafusion_functions_aggregate::expr_fn::{count, sum};
+use datafusion_functions_aggregate::expr_fn::{avg, count, sum};
#[tokio::test]
async fn test_count_wildcard_on_sort() -> Result<()> {
diff --git a/datafusion/core/tests/user_defined/user_defined_aggregates.rs
b/datafusion/core/tests/user_defined/user_defined_aggregates.rs
index 66cdeb575a..d591c662d8 100644
--- a/datafusion/core/tests/user_defined/user_defined_aggregates.rs
+++ b/datafusion/core/tests/user_defined/user_defined_aggregates.rs
@@ -48,7 +48,8 @@ use datafusion_expr::{
create_udaf, function::AccumulatorArgs, AggregateUDFImpl,
GroupsAccumulator,
SimpleAggregateUDF,
};
-use datafusion_physical_expr::expressions::AvgAccumulator;
+use datafusion_functions_aggregate::average::AvgAccumulator;
+
/// Test to show the contents of the setup
#[tokio::test]
async fn test_setup() {
diff --git
a/datafusion/core/tests/user_defined/user_defined_scalar_functions.rs
b/datafusion/core/tests/user_defined/user_defined_scalar_functions.rs
index a81fc9159e..5e3c44c039 100644
--- a/datafusion/core/tests/user_defined/user_defined_scalar_functions.rs
+++ b/datafusion/core/tests/user_defined/user_defined_scalar_functions.rs
@@ -51,7 +51,7 @@ async fn csv_query_custom_udf_with_cast() -> Result<()> {
let actual = plan_and_collect(&ctx, sql).await.unwrap();
let expected = [
"+------------------------------------------+",
- "| AVG(custom_sqrt(aggregate_test_100.c11)) |",
+ "| avg(custom_sqrt(aggregate_test_100.c11)) |",
"+------------------------------------------+",
"| 0.6584408483418835 |",
"+------------------------------------------+",
@@ -69,7 +69,7 @@ async fn csv_query_avg_sqrt() -> Result<()> {
let actual = plan_and_collect(&ctx, sql).await.unwrap();
let expected = [
"+------------------------------------------+",
- "| AVG(custom_sqrt(aggregate_test_100.c12)) |",
+ "| avg(custom_sqrt(aggregate_test_100.c12)) |",
"+------------------------------------------+",
"| 0.6706002946036459 |",
"+------------------------------------------+",
diff --git a/datafusion/expr/src/aggregate_function.rs
b/datafusion/expr/src/aggregate_function.rs
index 967ccc0b08..7663dcd610 100644
--- a/datafusion/expr/src/aggregate_function.rs
+++ b/datafusion/expr/src/aggregate_function.rs
@@ -37,8 +37,6 @@ pub enum AggregateFunction {
Min,
/// Maximum
Max,
- /// Average
- Avg,
/// Aggregation into an array
ArrayAgg,
/// N'th value in a group according to some ordering
@@ -55,7 +53,6 @@ impl AggregateFunction {
match self {
Min => "MIN",
Max => "MAX",
- Avg => "AVG",
ArrayAgg => "ARRAY_AGG",
NthValue => "NTH_VALUE",
Correlation => "CORR",
@@ -75,9 +72,7 @@ impl FromStr for AggregateFunction {
fn from_str(name: &str) -> Result<AggregateFunction> {
Ok(match name {
// general
- "avg" => AggregateFunction::Avg,
"max" => AggregateFunction::Max,
- "mean" => AggregateFunction::Avg,
"min" => AggregateFunction::Min,
"array_agg" => AggregateFunction::ArrayAgg,
"nth_value" => AggregateFunction::NthValue,
@@ -123,7 +118,6 @@ impl AggregateFunction {
AggregateFunction::Correlation => {
correlation_return_type(&coerced_data_types[0])
}
- AggregateFunction::Avg => avg_return_type(&coerced_data_types[0]),
AggregateFunction::ArrayAgg =>
Ok(DataType::List(Arc::new(Field::new(
"item",
coerced_data_types[0].clone(),
@@ -135,19 +129,6 @@ impl AggregateFunction {
}
}
-/// Returns the internal sum datatype of the avg aggregate function.
-pub fn sum_type_of_avg(input_expr_types: &[DataType]) -> Result<DataType> {
- // Note that this function *must* return the same type that the respective
physical expression returns
- // or the execution panics.
- let fun = AggregateFunction::Avg;
- let coerced_data_types = crate::type_coercion::aggregates::coerce_types(
- &fun,
- input_expr_types,
- &fun.signature(),
- )?;
- avg_sum_type(&coerced_data_types[0])
-}
-
impl AggregateFunction {
/// the signatures supported by the function `fun`.
pub fn signature(&self) -> Signature {
@@ -168,9 +149,6 @@ impl AggregateFunction {
.collect::<Vec<_>>();
Signature::uniform(1, valid, Volatility::Immutable)
}
- AggregateFunction::Avg => {
- Signature::uniform(1, NUMERICS.to_vec(), Volatility::Immutable)
- }
AggregateFunction::NthValue => Signature::any(2,
Volatility::Immutable),
AggregateFunction::Correlation => {
Signature::uniform(2, NUMERICS.to_vec(), Volatility::Immutable)
diff --git a/datafusion/expr/src/expr.rs b/datafusion/expr/src/expr.rs
index 0de4a87b94..409ccf7b47 100644
--- a/datafusion/expr/src/expr.rs
+++ b/datafusion/expr/src/expr.rs
@@ -2280,7 +2280,6 @@ mod test {
"nth_value",
"min",
"max",
- "avg",
];
for name in names {
let fun = find_df_window_func(name).unwrap();
@@ -2309,12 +2308,6 @@ mod test {
aggregate_function::AggregateFunction::Min
))
);
- assert_eq!(
- find_df_window_func("avg"),
- Some(WindowFunctionDefinition::AggregateFunction(
- aggregate_function::AggregateFunction::Avg
- ))
- );
assert_eq!(
find_df_window_func("cume_dist"),
Some(WindowFunctionDefinition::BuiltInWindowFunction(
diff --git a/datafusion/expr/src/expr_fn.rs b/datafusion/expr/src/expr_fn.rs
index deac205557..8b0213fd52 100644
--- a/datafusion/expr/src/expr_fn.rs
+++ b/datafusion/expr/src/expr_fn.rs
@@ -183,18 +183,6 @@ pub fn array_agg(expr: Expr) -> Expr {
))
}
-/// Create an expression to represent the avg() aggregate function
-pub fn avg(expr: Expr) -> Expr {
- Expr::AggregateFunction(AggregateFunction::new(
- aggregate_function::AggregateFunction::Avg,
- vec![expr],
- false,
- None,
- None,
- None,
- ))
-}
-
/// Return a new expression with bitwise AND
pub fn bitwise_and(left: Expr, right: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr::new(
diff --git a/datafusion/expr/src/expr_rewriter/order_by.rs
b/datafusion/expr/src/expr_rewriter/order_by.rs
index eb38fee7ca..4b56ca3d1c 100644
--- a/datafusion/expr/src/expr_rewriter/order_by.rs
+++ b/datafusion/expr/src/expr_rewriter/order_by.rs
@@ -156,8 +156,8 @@ mod test {
use arrow::datatypes::{DataType, Field, Schema};
use crate::{
- avg, cast, col, lit, logical_plan::builder::LogicalTableSource, min,
try_cast,
- LogicalPlanBuilder,
+ cast, col, lit, logical_plan::builder::LogicalTableSource, min,
+ test::function_stub::avg, try_cast, LogicalPlanBuilder,
};
use super::*;
@@ -246,9 +246,9 @@ mod test {
expected: sort(col("c1") + col("MIN(t.c2)")),
},
TestCase {
- desc: r#"avg(c3) --> "AVG(t.c3)" as average (column *named*
"AVG(t.c3)", aliased)"#,
+ desc: r#"avg(c3) --> "avg(t.c3)" as average (column *named*
"avg(t.c3)", aliased)"#,
input: sort(avg(col("c3"))),
- expected: sort(col("AVG(t.c3)").alias("average")),
+ expected: sort(col("avg(t.c3)").alias("average")),
},
];
diff --git a/datafusion/expr/src/test/function_stub.rs
b/datafusion/expr/src/test/function_stub.rs
index ac98ee9747..14a6522ebe 100644
--- a/datafusion/expr/src/test/function_stub.rs
+++ b/datafusion/expr/src/test/function_stub.rs
@@ -21,6 +21,14 @@
use std::any::Any;
+use arrow::datatypes::{
+ DataType, Field, DECIMAL128_MAX_PRECISION, DECIMAL256_MAX_PRECISION,
+};
+
+use datafusion_common::{exec_err, not_impl_err, Result};
+
+use crate::type_coercion::aggregates::{avg_return_type, coerce_avg_type,
NUMERICS};
+use crate::Volatility::Immutable;
use crate::{
expr::AggregateFunction,
function::{AccumulatorArgs, StateFieldsArgs},
@@ -28,10 +36,6 @@ use crate::{
Accumulator, AggregateUDFImpl, Expr, GroupsAccumulator, ReversedUDAF,
Signature,
Volatility,
};
-use arrow::datatypes::{
- DataType, Field, DECIMAL128_MAX_PRECISION, DECIMAL256_MAX_PRECISION,
-};
-use datafusion_common::{exec_err, not_impl_err, Result};
macro_rules! create_func {
($UDAF:ty, $AGGREGATE_UDF_FN:ident) => {
@@ -82,6 +86,19 @@ pub fn count(expr: Expr) -> Expr {
))
}
+create_func!(Avg, avg_udaf);
+
+pub fn avg(expr: Expr) -> Expr {
+ Expr::AggregateFunction(AggregateFunction::new_udf(
+ avg_udaf(),
+ vec![expr],
+ false,
+ None,
+ None,
+ None,
+ ))
+}
+
/// Stub `sum` used for optimizer testing
#[derive(Debug)]
pub struct Sum {
@@ -273,3 +290,58 @@ impl AggregateUDFImpl for Count {
ReversedUDAF::Identical
}
}
+
+/// Testing stub implementation of avg aggregate
+#[derive(Debug)]
+pub struct Avg {
+ signature: Signature,
+ aliases: Vec<String>,
+}
+
+impl Avg {
+ pub fn new() -> Self {
+ Self {
+ aliases: vec![String::from("mean")],
+ signature: Signature::uniform(1, NUMERICS.to_vec(), Immutable),
+ }
+ }
+}
+
+impl Default for Avg {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl AggregateUDFImpl for Avg {
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+
+ fn name(&self) -> &str {
+ "avg"
+ }
+
+ fn signature(&self) -> &Signature {
+ &self.signature
+ }
+
+ fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
+ avg_return_type(self.name(), &arg_types[0])
+ }
+
+ fn accumulator(&self, _acc_args: AccumulatorArgs) -> Result<Box<dyn
Accumulator>> {
+ not_impl_err!("no impl for stub")
+ }
+
+ fn state_fields(&self, _args: StateFieldsArgs) -> Result<Vec<Field>> {
+ not_impl_err!("no impl for stub")
+ }
+ fn aliases(&self) -> &[String] {
+ &self.aliases
+ }
+
+ fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
+ coerce_avg_type(self.name(), arg_types)
+ }
+}
diff --git a/datafusion/expr/src/type_coercion/aggregates.rs
b/datafusion/expr/src/type_coercion/aggregates.rs
index 428fc99070..7448af2502 100644
--- a/datafusion/expr/src/type_coercion/aggregates.rs
+++ b/datafusion/expr/src/type_coercion/aggregates.rs
@@ -17,14 +17,15 @@
use std::ops::Deref;
-use crate::{AggregateFunction, Signature, TypeSignature};
-
use arrow::datatypes::{
DataType, TimeUnit, DECIMAL128_MAX_PRECISION, DECIMAL128_MAX_SCALE,
DECIMAL256_MAX_PRECISION, DECIMAL256_MAX_SCALE,
};
+
use datafusion_common::{internal_err, plan_err, Result};
+use crate::{AggregateFunction, Signature, TypeSignature};
+
pub static STRINGS: &[DataType] = &[DataType::Utf8, DataType::LargeUtf8];
pub static SIGNED_INTEGERS: &[DataType] = &[
@@ -101,26 +102,6 @@ pub fn coerce_types(
// unpack the dictionary to get the value
get_min_max_result_type(input_types)
}
- AggregateFunction::Avg => {
- // Refer to
https://www.postgresql.org/docs/8.2/functions-aggregate.html doc
- // smallint, int, bigint, real, double precision, decimal, or
interval
- let v = match &input_types[0] {
- Decimal128(p, s) => Decimal128(*p, *s),
- Decimal256(p, s) => Decimal256(*p, *s),
- d if d.is_numeric() => Float64,
- Dictionary(_, v) => {
- return coerce_types(agg_fun, &[v.as_ref().clone()],
signature)
- }
- _ => {
- return plan_err!(
- "The function {:?} does not support inputs of type
{:?}.",
- agg_fun,
- input_types[0]
- )
- }
- };
- Ok(vec![v])
- }
AggregateFunction::Correlation => {
if !is_correlation_support_arg_type(&input_types[0]) {
return plan_err!(
@@ -262,7 +243,7 @@ pub fn correlation_return_type(arg_type: &DataType) ->
Result<DataType> {
}
/// function return type of an average
-pub fn avg_return_type(arg_type: &DataType) -> Result<DataType> {
+pub fn avg_return_type(func_name: &str, arg_type: &DataType) ->
Result<DataType> {
match arg_type {
DataType::Decimal128(precision, scale) => {
// in the spark, the result type is DECIMAL(min(38,precision+4),
min(38,scale+4)).
@@ -280,9 +261,9 @@ pub fn avg_return_type(arg_type: &DataType) ->
Result<DataType> {
}
arg_type if NUMERICS.contains(arg_type) => Ok(DataType::Float64),
DataType::Dictionary(_, dict_value_type) => {
- avg_return_type(dict_value_type.as_ref())
+ avg_return_type(func_name, dict_value_type.as_ref())
}
- other => plan_err!("AVG does not support {other:?}"),
+ other => plan_err!("{func_name} does not support {other:?}"),
}
}
@@ -358,10 +339,29 @@ pub fn is_integer_arg_type(arg_type: &DataType) -> bool {
arg_type.is_integer()
}
+pub fn coerce_avg_type(func_name: &str, arg_types: &[DataType]) ->
Result<Vec<DataType>> {
+ // Supported types smallint, int, bigint, real, double precision, decimal,
or interval
+ // Refer to https://www.postgresql.org/docs/8.2/functions-aggregate.html
doc
+ fn coerced_type(func_name: &str, data_type: &DataType) -> Result<DataType>
{
+ return match &data_type {
+ DataType::Decimal128(p, s) => Ok(DataType::Decimal128(*p, *s)),
+ DataType::Decimal256(p, s) => Ok(DataType::Decimal256(*p, *s)),
+ d if d.is_numeric() => Ok(DataType::Float64),
+ DataType::Dictionary(_, v) => return coerced_type(func_name,
v.as_ref()),
+ _ => {
+ return plan_err!(
+ "The function {:?} does not support inputs of type {:?}.",
+ func_name,
+ data_type
+ )
+ }
+ };
+ }
+ Ok(vec![coerced_type(func_name, &arg_types[0])?])
+}
#[cfg(test)]
mod tests {
use super::*;
-
#[test]
fn test_aggregate_coerce_types() {
// test input args with error number input types
@@ -371,16 +371,6 @@ mod tests {
let result = coerce_types(&fun, &input_types, &signature);
assert_eq!("Error during planning: The function MIN expects 1
arguments, but 2 were provided", result.unwrap_err().strip_backtrace());
- let fun = AggregateFunction::Avg;
- // test input args is invalid data type for avg
- let input_types = vec![DataType::Utf8];
- let signature = fun.signature();
- let result = coerce_types(&fun, &input_types, &signature);
- assert_eq!(
- "Error during planning: The function Avg does not support inputs
of type Utf8.",
- result.unwrap_err().strip_backtrace()
- );
-
// test count, array_agg, approx_distinct, min, max.
// the coerced types is same with input types
let funs = vec![
@@ -401,30 +391,6 @@ mod tests {
assert_eq!(*input_type, result.unwrap());
}
}
-
- // test avg
- let fun = AggregateFunction::Avg;
- let signature = fun.signature();
- let r = coerce_types(&fun, &[DataType::Int32], &signature).unwrap();
- assert_eq!(r[0], DataType::Float64);
- let r = coerce_types(&fun, &[DataType::Float32], &signature).unwrap();
- assert_eq!(r[0], DataType::Float64);
- let r = coerce_types(&fun, &[DataType::Decimal128(20, 3)],
&signature).unwrap();
- assert_eq!(r[0], DataType::Decimal128(20, 3));
- let r = coerce_types(&fun, &[DataType::Decimal256(20, 3)],
&signature).unwrap();
- assert_eq!(r[0], DataType::Decimal256(20, 3));
- }
-
- #[test]
- fn test_avg_return_data_type() -> Result<()> {
- let data_type = DataType::Decimal128(10, 5);
- let result_type = avg_return_type(&data_type)?;
- assert_eq!(DataType::Decimal128(14, 9), result_type);
-
- let data_type = DataType::Decimal128(36, 10);
- let result_type = avg_return_type(&data_type)?;
- assert_eq!(DataType::Decimal128(38, 14), result_type);
- Ok(())
}
#[test]
diff --git a/datafusion/physical-expr/src/aggregate/average.rs
b/datafusion/functions-aggregate/src/average.rs
similarity index 76%
rename from datafusion/physical-expr/src/aggregate/average.rs
rename to datafusion/functions-aggregate/src/average.rs
index 80fcc9b70c..1dc1f10afc 100644
--- a/datafusion/physical-expr/src/aggregate/average.rs
+++ b/datafusion/functions-aggregate/src/average.rs
@@ -15,77 +15,85 @@
// specific language governing permissions and limitations
// under the License.
-//! Defines physical expressions that can evaluated at runtime during query
execution
+//! Defines `Avg` & `Mean` aggregate & accumulators
-use arrow::array::{AsArray, PrimitiveBuilder};
+use arrow::array::{
+ self, Array, ArrayRef, ArrowNativeTypeOp, ArrowNumericType,
ArrowPrimitiveType,
+ AsArray, PrimitiveArray, PrimitiveBuilder, UInt64Array,
+};
+use arrow::compute::sum;
+use arrow::datatypes::{
+ i256, ArrowNativeType, DataType, Decimal128Type, Decimal256Type,
DecimalType, Field,
+ Float64Type, UInt64Type,
+};
+use datafusion_common::{exec_err, not_impl_err, Result, ScalarValue};
+use datafusion_expr::function::{AccumulatorArgs, StateFieldsArgs};
+use datafusion_expr::type_coercion::aggregates::{avg_return_type,
coerce_avg_type};
+use datafusion_expr::utils::format_state_name;
+use datafusion_expr::Volatility::Immutable;
+use datafusion_expr::{
+ Accumulator, AggregateUDFImpl, EmitTo, GroupsAccumulator, ReversedUDAF,
Signature,
+};
+use
datafusion_physical_expr_common::aggregate::groups_accumulator::accumulate::NullState;
+use datafusion_physical_expr_common::aggregate::utils::DecimalAverager;
use log::debug;
-
use std::any::Any;
use std::fmt::Debug;
use std::sync::Arc;
-use crate::aggregate::groups_accumulator::accumulate::NullState;
-use crate::aggregate::utils::down_cast_any_ref;
-use crate::expressions::format_state_name;
-use crate::{AggregateExpr, PhysicalExpr};
-use arrow::compute::sum;
-use arrow::datatypes::{DataType, Decimal128Type, Float64Type, UInt64Type};
-use arrow::{
- array::{ArrayRef, UInt64Array},
- datatypes::Field,
-};
-use arrow_array::types::{Decimal256Type, DecimalType};
-use arrow_array::{
- Array, ArrowNativeTypeOp, ArrowNumericType, ArrowPrimitiveType,
PrimitiveArray,
-};
-use arrow_buffer::{i256, ArrowNativeType};
-use datafusion_common::{not_impl_err, Result, ScalarValue};
-use datafusion_expr::type_coercion::aggregates::avg_return_type;
-use datafusion_expr::{Accumulator, EmitTo, GroupsAccumulator};
+make_udaf_expr_and_func!(
+ Avg,
+ avg,
+ expression,
+ "Returns the avg of a group of values.",
+ avg_udaf
+);
-use super::utils::DecimalAverager;
-
-/// AVG aggregate expression
-#[derive(Debug, Clone)]
+#[derive(Debug)]
pub struct Avg {
- name: String,
- expr: Arc<dyn PhysicalExpr>,
- input_data_type: DataType,
- result_data_type: DataType,
+ signature: Signature,
+ aliases: Vec<String>,
}
impl Avg {
- /// Create a new AVG aggregate function
- pub fn new(
- expr: Arc<dyn PhysicalExpr>,
- name: impl Into<String>,
- data_type: DataType,
- ) -> Self {
- let result_data_type = avg_return_type(&data_type).unwrap();
-
+ pub fn new() -> Self {
Self {
- name: name.into(),
- expr,
- input_data_type: data_type,
- result_data_type,
+ signature: Signature::user_defined(Immutable),
+ aliases: vec![String::from("mean")],
}
}
}
-impl AggregateExpr for Avg {
- /// Return a reference to Any that can be used for downcasting
+impl Default for Avg {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl AggregateUDFImpl for Avg {
fn as_any(&self) -> &dyn Any {
self
}
- fn field(&self) -> Result<Field> {
- Ok(Field::new(&self.name, self.result_data_type.clone(), true))
+ fn name(&self) -> &str {
+ "avg"
+ }
+
+ fn signature(&self) -> &Signature {
+ &self.signature
+ }
+
+ fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
+ avg_return_type(self.name(), &arg_types[0])
}
- fn create_accumulator(&self) -> Result<Box<dyn Accumulator>> {
+ fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn
Accumulator>> {
+ if acc_args.is_distinct {
+ return exec_err!("avg(DISTINCT) aggregations are not available");
+ }
use DataType::*;
// instantiate specialized accumulator based for the type
- match (&self.input_data_type, &self.result_data_type) {
+ match (acc_args.input_type, acc_args.data_type) {
(Float64, Float64) => Ok(Box::<AvgAccumulator>::default()),
(
Decimal128(sum_precision, sum_scale),
@@ -110,59 +118,47 @@ impl AggregateExpr for Avg {
target_precision: *target_precision,
target_scale: *target_scale,
})),
- _ => not_impl_err!(
+ _ => exec_err!(
"AvgAccumulator for ({} --> {})",
- self.input_data_type,
- self.result_data_type
+ acc_args.input_type,
+ acc_args.data_type
),
}
}
- fn state_fields(&self) -> Result<Vec<Field>> {
+ fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<Field>> {
Ok(vec![
Field::new(
- format_state_name(&self.name, "count"),
+ format_state_name(args.name, "count"),
DataType::UInt64,
true,
),
Field::new(
- format_state_name(&self.name, "sum"),
- self.input_data_type.clone(),
+ format_state_name(args.name, "sum"),
+ args.input_type.clone(),
true,
),
])
}
- fn expressions(&self) -> Vec<Arc<dyn PhysicalExpr>> {
- vec![self.expr.clone()]
- }
-
- fn name(&self) -> &str {
- &self.name
- }
-
- fn reverse_expr(&self) -> Option<Arc<dyn AggregateExpr>> {
- Some(Arc::new(self.clone()))
- }
-
- fn create_sliding_accumulator(&self) -> Result<Box<dyn Accumulator>> {
- self.create_accumulator()
- }
-
- fn groups_accumulator_supported(&self) -> bool {
- use DataType::*;
-
- matches!(&self.result_data_type, Float64 | Decimal128(_, _))
+ fn groups_accumulator_supported(&self, args: AccumulatorArgs) -> bool {
+ matches!(
+ args.data_type,
+ DataType::Float64 | DataType::Decimal128(_, _)
+ )
}
- fn create_groups_accumulator(&self) -> Result<Box<dyn GroupsAccumulator>> {
+ fn create_groups_accumulator(
+ &self,
+ args: AccumulatorArgs,
+ ) -> Result<Box<dyn GroupsAccumulator>> {
use DataType::*;
// instantiate specialized accumulator based for the type
- match (&self.input_data_type, &self.result_data_type) {
+ match (args.input_type, args.data_type) {
(Float64, Float64) => {
Ok(Box::new(AvgGroupsAccumulator::<Float64Type, _>::new(
- &self.input_data_type,
- &self.result_data_type,
+ args.input_type,
+ args.data_type,
|sum: f64, count: u64| Ok(sum / count as f64),
)))
}
@@ -180,8 +176,8 @@ impl AggregateExpr for Avg {
move |sum: i128, count: u64| decimal_averager.avg(sum,
count as i128);
Ok(Box::new(AvgGroupsAccumulator::<Decimal128Type, _>::new(
- &self.input_data_type,
- &self.result_data_type,
+ args.input_type,
+ args.data_type,
avg_fn,
)))
}
@@ -201,32 +197,40 @@ impl AggregateExpr for Avg {
};
Ok(Box::new(AvgGroupsAccumulator::<Decimal256Type, _>::new(
- &self.input_data_type,
- &self.result_data_type,
+ args.input_type,
+ args.data_type,
avg_fn,
)))
}
_ => not_impl_err!(
"AvgGroupsAccumulator for ({} --> {})",
- self.input_data_type,
- self.result_data_type
+ args.input_type,
+ args.data_type
),
}
}
-}
-impl PartialEq<dyn Any> for Avg {
- fn eq(&self, other: &dyn Any) -> bool {
- down_cast_any_ref(other)
- .downcast_ref::<Self>()
- .map(|x| {
- self.name == x.name
- && self.input_data_type == x.input_data_type
- && self.result_data_type == x.result_data_type
- && self.expr.eq(&x.expr)
- })
- .unwrap_or(false)
+ fn aliases(&self) -> &[String] {
+ &self.aliases
+ }
+
+ fn create_sliding_accumulator(
+ &self,
+ args: AccumulatorArgs,
+ ) -> Result<Box<dyn Accumulator>> {
+ self.accumulator(args)
+ }
+
+ fn reverse_expr(&self) -> ReversedUDAF {
+ ReversedUDAF::Identical
+ }
+
+ fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
+ if arg_types.len() != 1 {
+ return exec_err!("{} expects exactly one argument.", self.name());
+ }
+ coerce_avg_type(self.name(), arg_types)
}
}
@@ -238,13 +242,6 @@ pub struct AvgAccumulator {
}
impl Accumulator for AvgAccumulator {
- fn state(&mut self) -> Result<Vec<ScalarValue>> {
- Ok(vec![
- ScalarValue::from(self.count),
- ScalarValue::Float64(self.sum),
- ])
- }
-
fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
let values = values[0].as_primitive::<Float64Type>();
self.count += (values.len() - values.null_count()) as u64;
@@ -255,13 +252,21 @@ impl Accumulator for AvgAccumulator {
Ok(())
}
- fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
- let values = values[0].as_primitive::<Float64Type>();
- self.count -= (values.len() - values.null_count()) as u64;
- if let Some(x) = sum(values) {
- self.sum = Some(self.sum.unwrap() - x);
- }
- Ok(())
+ fn evaluate(&mut self) -> Result<ScalarValue> {
+ Ok(ScalarValue::Float64(
+ self.sum.map(|f| f / self.count as f64),
+ ))
+ }
+
+ fn size(&self) -> usize {
+ std::mem::size_of_val(self)
+ }
+
+ fn state(&mut self) -> Result<Vec<ScalarValue>> {
+ Ok(vec![
+ ScalarValue::from(self.count),
+ ScalarValue::Float64(self.sum),
+ ])
}
fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
@@ -275,23 +280,23 @@ impl Accumulator for AvgAccumulator {
}
Ok(())
}
-
- fn evaluate(&mut self) -> Result<ScalarValue> {
- Ok(ScalarValue::Float64(
- self.sum.map(|f| f / self.count as f64),
- ))
+ fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
+ let values = values[0].as_primitive::<Float64Type>();
+ self.count -= (values.len() - values.null_count()) as u64;
+ if let Some(x) = sum(values) {
+ self.sum = Some(self.sum.unwrap() - x);
+ }
+ Ok(())
}
+
fn supports_retract_batch(&self) -> bool {
true
}
-
- fn size(&self) -> usize {
- std::mem::size_of_val(self)
- }
}
/// An accumulator to compute the average for decimals
-struct DecimalAvgAccumulator<T: DecimalType + ArrowNumericType> {
+#[derive(Debug)]
+struct DecimalAvgAccumulator<T: DecimalType + ArrowNumericType + Debug> {
sum: Option<T::Native>,
count: u64,
sum_scale: i8,
@@ -300,56 +305,12 @@ struct DecimalAvgAccumulator<T: DecimalType +
ArrowNumericType> {
target_scale: i8,
}
-impl<T: DecimalType + ArrowNumericType> Debug for DecimalAvgAccumulator<T> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("DecimalAvgAccumulator")
- .field("sum", &self.sum)
- .field("count", &self.count)
- .field("sum_scale", &self.sum_scale)
- .field("sum_precision", &self.sum_precision)
- .field("target_precision", &self.target_precision)
- .field("target_scale", &self.target_scale)
- .finish()
- }
-}
-
-impl<T: DecimalType + ArrowNumericType> Accumulator for
DecimalAvgAccumulator<T> {
- fn state(&mut self) -> Result<Vec<ScalarValue>> {
- Ok(vec![
- ScalarValue::from(self.count),
- ScalarValue::new_primitive::<T>(
- self.sum,
- &T::TYPE_CONSTRUCTOR(self.sum_precision, self.sum_scale),
- )?,
- ])
- }
-
+impl<T: DecimalType + ArrowNumericType + Debug> Accumulator for
DecimalAvgAccumulator<T> {
fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
let values = values[0].as_primitive::<T>();
-
self.count += (values.len() - values.null_count()) as u64;
- if let Some(x) = sum(values) {
- let v = self.sum.get_or_insert(T::Native::default());
- self.sum = Some(v.add_wrapping(x));
- }
- Ok(())
- }
- fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
- let values = values[0].as_primitive::<T>();
- self.count -= (values.len() - values.null_count()) as u64;
if let Some(x) = sum(values) {
- self.sum = Some(self.sum.unwrap().sub_wrapping(x));
- }
- Ok(())
- }
-
- fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
- // counts are summed
- self.count +=
sum(states[0].as_primitive::<UInt64Type>()).unwrap_or_default();
-
- // sums are summed
- if let Some(x) = sum(states[1].as_primitive::<T>()) {
let v = self.sum.get_or_insert(T::Native::default());
self.sum = Some(v.add_wrapping(x));
}
@@ -374,13 +335,44 @@ impl<T: DecimalType + ArrowNumericType> Accumulator for
DecimalAvgAccumulator<T>
&T::TYPE_CONSTRUCTOR(self.target_precision, self.target_scale),
)
}
- fn supports_retract_batch(&self) -> bool {
- true
- }
fn size(&self) -> usize {
std::mem::size_of_val(self)
}
+
+ fn state(&mut self) -> Result<Vec<ScalarValue>> {
+ Ok(vec![
+ ScalarValue::from(self.count),
+ ScalarValue::new_primitive::<T>(
+ self.sum,
+ &T::TYPE_CONSTRUCTOR(self.sum_precision, self.sum_scale),
+ )?,
+ ])
+ }
+
+ fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
+ // counts are summed
+ self.count +=
sum(states[0].as_primitive::<UInt64Type>()).unwrap_or_default();
+
+ // sums are summed
+ if let Some(x) = sum(states[1].as_primitive::<T>()) {
+ let v = self.sum.get_or_insert(T::Native::default());
+ self.sum = Some(v.add_wrapping(x));
+ }
+ Ok(())
+ }
+ fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
+ let values = values[0].as_primitive::<T>();
+ self.count -= (values.len() - values.null_count()) as u64;
+ if let Some(x) = sum(values) {
+ self.sum = Some(self.sum.unwrap().sub_wrapping(x));
+ }
+ Ok(())
+ }
+
+ fn supports_retract_batch(&self) -> bool {
+ true
+ }
}
/// An accumulator to compute the average of `[PrimitiveArray<T>]`.
@@ -444,7 +436,7 @@ where
&mut self,
values: &[ArrayRef],
group_indices: &[usize],
- opt_filter: Option<&arrow_array::BooleanArray>,
+ opt_filter: Option<&array::BooleanArray>,
total_num_groups: usize,
) -> Result<()> {
assert_eq!(values.len(), 1, "single argument to update_batch");
@@ -469,45 +461,6 @@ where
Ok(())
}
- fn merge_batch(
- &mut self,
- values: &[ArrayRef],
- group_indices: &[usize],
- opt_filter: Option<&arrow_array::BooleanArray>,
- total_num_groups: usize,
- ) -> Result<()> {
- assert_eq!(values.len(), 2, "two arguments to merge_batch");
- // first batch is counts, second is partial sums
- let partial_counts = values[0].as_primitive::<UInt64Type>();
- let partial_sums = values[1].as_primitive::<T>();
- // update counts with partial counts
- self.counts.resize(total_num_groups, 0);
- self.null_state.accumulate(
- group_indices,
- partial_counts,
- opt_filter,
- total_num_groups,
- |group_index, partial_count| {
- self.counts[group_index] += partial_count;
- },
- );
-
- // update sums
- self.sums.resize(total_num_groups, T::default_value());
- self.null_state.accumulate(
- group_indices,
- partial_sums,
- opt_filter,
- total_num_groups,
- |group_index, new_value: <T as ArrowPrimitiveType>::Native| {
- let sum = &mut self.sums[group_index];
- *sum = sum.add_wrapping(new_value);
- },
- );
-
- Ok(())
- }
-
fn evaluate(&mut self, emit_to: EmitTo) -> Result<ArrayRef> {
let counts = emit_to.take_needed(&mut self.counts);
let sums = emit_to.take_needed(&mut self.sums);
@@ -536,7 +489,7 @@ where
.into_iter()
.zip(counts.into_iter())
.map(|(sum, count)| (self.avg_fn)(sum, count))
- .collect::<Result<Vec<_>>>()?;
+ .collect::<datafusion_common::Result<Vec<_>>>()?;
PrimitiveArray::new(averages.into(), Some(nulls)) // no copy
.with_data_type(self.return_data_type.clone())
};
@@ -562,6 +515,45 @@ where
])
}
+ fn merge_batch(
+ &mut self,
+ values: &[ArrayRef],
+ group_indices: &[usize],
+ opt_filter: Option<&array::BooleanArray>,
+ total_num_groups: usize,
+ ) -> Result<()> {
+ assert_eq!(values.len(), 2, "two arguments to merge_batch");
+ // first batch is counts, second is partial sums
+ let partial_counts = values[0].as_primitive::<UInt64Type>();
+ let partial_sums = values[1].as_primitive::<T>();
+ // update counts with partial counts
+ self.counts.resize(total_num_groups, 0);
+ self.null_state.accumulate(
+ group_indices,
+ partial_counts,
+ opt_filter,
+ total_num_groups,
+ |group_index, partial_count| {
+ self.counts[group_index] += partial_count;
+ },
+ );
+
+ // update sums
+ self.sums.resize(total_num_groups, T::default_value());
+ self.null_state.accumulate(
+ group_indices,
+ partial_sums,
+ opt_filter,
+ total_num_groups,
+ |group_index, new_value: <T as ArrowPrimitiveType>::Native| {
+ let sum = &mut self.sums[group_index];
+ *sum = sum.add_wrapping(new_value);
+ },
+ );
+
+ Ok(())
+ }
+
fn size(&self) -> usize {
self.counts.capacity() * std::mem::size_of::<u64>()
+ self.sums.capacity() * std::mem::size_of::<T>()
diff --git a/datafusion/functions-aggregate/src/lib.rs
b/datafusion/functions-aggregate/src/lib.rs
index 260d6dab31..6b38c4ed61 100644
--- a/datafusion/functions-aggregate/src/lib.rs
+++ b/datafusion/functions-aggregate/src/lib.rs
@@ -69,6 +69,7 @@ pub mod variance;
pub mod approx_median;
pub mod approx_percentile_cont;
pub mod approx_percentile_cont_with_weight;
+pub mod average;
pub mod bit_and_or_xor;
pub mod bool_and_or;
pub mod string_agg;
@@ -86,6 +87,7 @@ pub mod expr_fn {
pub use super::approx_median::approx_median;
pub use super::approx_percentile_cont::approx_percentile_cont;
pub use
super::approx_percentile_cont_with_weight::approx_percentile_cont_with_weight;
+ pub use super::average::avg;
pub use super::bit_and_or_xor::bit_and;
pub use super::bit_and_or_xor::bit_or;
pub use super::bit_and_or_xor::bit_xor;
@@ -147,6 +149,7 @@ pub fn all_default_aggregate_functions() ->
Vec<Arc<AggregateUDF>> {
bit_and_or_xor::bit_xor_udaf(),
bool_and_or::bool_and_udaf(),
bool_and_or::bool_or_udaf(),
+ average::avg_udaf(),
]
}
diff --git a/datafusion/optimizer/src/analyzer/type_coercion.rs
b/datafusion/optimizer/src/analyzer/type_coercion.rs
index acc21f14f4..4fecb243fb 100644
--- a/datafusion/optimizer/src/analyzer/type_coercion.rs
+++ b/datafusion/optimizer/src/analyzer/type_coercion.rs
@@ -815,13 +815,14 @@ mod test {
use datafusion_common::{DFSchema, DFSchemaRef, Result, ScalarValue};
use datafusion_expr::expr::{self, InSubquery, Like, ScalarFunction};
use datafusion_expr::logical_plan::{EmptyRelation, Projection};
+ use datafusion_expr::test::function_stub::avg_udaf;
use datafusion_expr::{
- cast, col, create_udaf, is_true, lit, AccumulatorFactoryFunction,
- AggregateFunction, AggregateUDF, BinaryExpr, Case, ColumnarValue, Expr,
- ExprSchemable, Filter, LogicalPlan, Operator, ScalarUDF, ScalarUDFImpl,
- Signature, SimpleAggregateUDF, Subquery, Volatility,
+ cast, col, create_udaf, is_true, lit, AccumulatorFactoryFunction,
AggregateUDF,
+ BinaryExpr, Case, ColumnarValue, Expr, ExprSchemable, Filter,
LogicalPlan,
+ Operator, ScalarUDF, ScalarUDFImpl, Signature, SimpleAggregateUDF,
Subquery,
+ Volatility,
};
- use datafusion_physical_expr::expressions::AvgAccumulator;
+ use datafusion_functions_aggregate::average::AvgAccumulator;
use crate::analyzer::type_coercion::{
coerce_case_expression, TypeCoercion, TypeCoercionRewriter,
@@ -1003,31 +1004,29 @@ mod test {
#[test]
fn agg_function_case() -> Result<()> {
let empty = empty();
- let fun: AggregateFunction = AggregateFunction::Avg;
- let agg_expr = Expr::AggregateFunction(expr::AggregateFunction::new(
- fun,
- vec![lit(12i64)],
+ let agg_expr =
Expr::AggregateFunction(expr::AggregateFunction::new_udf(
+ avg_udaf(),
+ vec![lit(12f64)],
false,
None,
None,
None,
));
let plan = LogicalPlan::Projection(Projection::try_new(vec![agg_expr],
empty)?);
- let expected = "Projection: AVG(CAST(Int64(12) AS Float64))\n
EmptyRelation";
+ let expected = "Projection: avg(Float64(12))\n EmptyRelation";
assert_analyzed_plan_eq(Arc::new(TypeCoercion::new()), plan,
expected)?;
let empty = empty_with_type(DataType::Int32);
- let fun: AggregateFunction = AggregateFunction::Avg;
- let agg_expr = Expr::AggregateFunction(expr::AggregateFunction::new(
- fun,
- vec![col("a")],
+ let agg_expr =
Expr::AggregateFunction(expr::AggregateFunction::new_udf(
+ avg_udaf(),
+ vec![cast(col("a"), DataType::Float64)],
false,
None,
None,
None,
));
let plan = LogicalPlan::Projection(Projection::try_new(vec![agg_expr],
empty)?);
- let expected = "Projection: AVG(CAST(a AS Float64))\n EmptyRelation";
+ let expected = "Projection: avg(CAST(a AS Float64))\n EmptyRelation";
assert_analyzed_plan_eq(Arc::new(TypeCoercion::new()), plan,
expected)?;
Ok(())
}
@@ -1035,9 +1034,8 @@ mod test {
#[test]
fn agg_function_invalid_input_avg() -> Result<()> {
let empty = empty();
- let fun: AggregateFunction = AggregateFunction::Avg;
- let agg_expr = Expr::AggregateFunction(expr::AggregateFunction::new(
- fun,
+ let agg_expr =
Expr::AggregateFunction(expr::AggregateFunction::new_udf(
+ avg_udaf(),
vec![lit("1")],
false,
None,
@@ -1048,10 +1046,7 @@ mod test {
.err()
.unwrap()
.strip_backtrace();
- assert_eq!(
- "Error during planning: No function matches the given name and
argument types 'AVG(Utf8)'. You might need to add explicit type
casts.\n\tCandidate
functions:\n\tAVG(Int8/Int16/Int32/Int64/UInt8/UInt16/UInt32/UInt64/Float32/Float64)",
- err
- );
+ assert!(err.starts_with("Error during planning: Error during planning:
Coercion from [Utf8] to the signature Uniform(1, [Int8, Int16, Int32, Int64,
UInt8, UInt16, UInt32, UInt64, Float32, Float64]) failed."));
Ok(())
}
diff --git a/datafusion/optimizer/src/common_subexpr_eliminate.rs
b/datafusion/optimizer/src/common_subexpr_eliminate.rs
index 5f54354df4..66c23fdced 100644
--- a/datafusion/optimizer/src/common_subexpr_eliminate.rs
+++ b/datafusion/optimizer/src/common_subexpr_eliminate.rs
@@ -1010,15 +1010,15 @@ mod test {
use datafusion_expr::logical_plan::{table_scan, JoinType};
- use datafusion_expr::{avg, lit, logical_plan::builder::LogicalPlanBuilder};
use datafusion_expr::{
grouping_set, AccumulatorFactoryFunction, AggregateUDF, Signature,
SimpleAggregateUDF, Volatility,
};
+ use datafusion_expr::{lit, logical_plan::builder::LogicalPlanBuilder};
use crate::optimizer::OptimizerContext;
use crate::test::*;
- use datafusion_expr::test::function_stub::sum;
+ use datafusion_expr::test::function_stub::{avg, sum};
use super::*;
@@ -1065,8 +1065,8 @@ mod test {
expr_to_identifier(&expr, &mut HashMap::new(), &mut id_array,
ExprMask::Normal)?;
let expected = vec![
- (8, "{(sum(a + Int32(1)) - AVG(c)) * Int32(2)|{Int32(2)}|{sum(a +
Int32(1)) - AVG(c)|{AVG(c)|{c}}|{sum(a + Int32(1))|{a +
Int32(1)|{Int32(1)}|{a}}}}}"),
- (6, "{sum(a + Int32(1)) - AVG(c)|{AVG(c)|{c}}|{sum(a +
Int32(1))|{a + Int32(1)|{Int32(1)}|{a}}}}"),
+ (8, "{(sum(a + Int32(1)) - avg(c)) * Int32(2)|{Int32(2)}|{sum(a +
Int32(1)) - avg(c)|{avg(c)|{c}}|{sum(a + Int32(1))|{a +
Int32(1)|{Int32(1)}|{a}}}}}"),
+ (6, "{sum(a + Int32(1)) - avg(c)|{avg(c)|{c}}|{sum(a +
Int32(1))|{a + Int32(1)|{Int32(1)}|{a}}}}"),
(3, ""),
(2, "{a + Int32(1)|{Int32(1)}|{a}}"),
(0, ""),
@@ -1090,13 +1090,13 @@ mod test {
)?;
let expected = vec![
- (8, "{(sum(a + Int32(1)) - AVG(c)) * Int32(2)|{Int32(2)}|{sum(a +
Int32(1)) - AVG(c)|{AVG(c)|{c}}|{sum(a + Int32(1))|{a +
Int32(1)|{Int32(1)}|{a}}}}}"),
- (6, "{sum(a + Int32(1)) - AVG(c)|{AVG(c)|{c}}|{sum(a +
Int32(1))|{a + Int32(1)|{Int32(1)}|{a}}}}"),
+ (8, "{(sum(a + Int32(1)) - avg(c)) * Int32(2)|{Int32(2)}|{sum(a +
Int32(1)) - avg(c)|{avg(c)|{c}}|{sum(a + Int32(1))|{a +
Int32(1)|{Int32(1)}|{a}}}}}"),
+ (6, "{sum(a + Int32(1)) - avg(c)|{avg(c)|{c}}|{sum(a +
Int32(1))|{a + Int32(1)|{Int32(1)}|{a}}}}"),
(3, "{sum(a + Int32(1))|{a + Int32(1)|{Int32(1)}|{a}}}"),
(2, "{a + Int32(1)|{Int32(1)}|{a}}"),
(0, ""),
(1, ""),
- (5, "{AVG(c)|{c}}"),
+ (5, "{avg(c)|{c}}"),
(4, ""),
(7, "")
]
@@ -1203,8 +1203,8 @@ mod test {
)?
.build()?;
- let expected = "Projection: __common_expr_1 AS col1, __common_expr_1
AS col2, col3, __common_expr_3 AS AVG(test.c), __common_expr_2 AS col4,
__common_expr_2 AS col5, col6, __common_expr_4 AS my_agg(test.c)\
- \n Aggregate: groupBy=[[]], aggr=[[AVG(test.a) AS __common_expr_1,
my_agg(test.a) AS __common_expr_2, AVG(test.b) AS col3, AVG(test.c) AS
__common_expr_3, my_agg(test.b) AS col6, my_agg(test.c) AS __common_expr_4]]\
+ let expected = "Projection: __common_expr_1 AS col1, __common_expr_1
AS col2, col3, __common_expr_3 AS avg(test.c), __common_expr_2 AS col4,
__common_expr_2 AS col5, col6, __common_expr_4 AS my_agg(test.c)\
+ \n Aggregate: groupBy=[[]], aggr=[[avg(test.a) AS __common_expr_1,
my_agg(test.a) AS __common_expr_2, avg(test.b) AS col3, avg(test.c) AS
__common_expr_3, my_agg(test.b) AS col6, my_agg(test.c) AS __common_expr_4]]\
\n TableScan: test";
assert_optimized_plan_eq(expected, plan, None);
@@ -1222,8 +1222,8 @@ mod test {
)?
.build()?;
- let expected = "Projection: Int32(1) + __common_expr_1 AS AVG(test.a),
Int32(1) - __common_expr_1 AS AVG(test.a), Int32(1) + __common_expr_2 AS
my_agg(test.a), Int32(1) - __common_expr_2 AS my_agg(test.a)\
- \n Aggregate: groupBy=[[]], aggr=[[AVG(test.a) AS __common_expr_1,
my_agg(test.a) AS __common_expr_2]]\
+ let expected = "Projection: Int32(1) + __common_expr_1 AS avg(test.a),
Int32(1) - __common_expr_1 AS avg(test.a), Int32(1) + __common_expr_2 AS
my_agg(test.a), Int32(1) - __common_expr_2 AS my_agg(test.a)\
+ \n Aggregate: groupBy=[[]], aggr=[[avg(test.a) AS __common_expr_1,
my_agg(test.a) AS __common_expr_2]]\
\n TableScan: test";
assert_optimized_plan_eq(expected, plan, None);
@@ -1239,7 +1239,7 @@ mod test {
)?
.build()?;
- let expected ="Aggregate: groupBy=[[]], aggr=[[AVG(__common_expr_1) AS
col1, my_agg(__common_expr_1) AS col2]]\
+ let expected ="Aggregate: groupBy=[[]], aggr=[[avg(__common_expr_1) AS
col1, my_agg(__common_expr_1) AS col2]]\
\n Projection: UInt32(1) + test.a AS __common_expr_1, test.a, test.b,
test.c\
\n TableScan: test";
@@ -1256,7 +1256,7 @@ mod test {
)?
.build()?;
- let expected = "Aggregate: groupBy=[[__common_expr_1 AS UInt32(1) +
test.a]], aggr=[[AVG(__common_expr_1) AS col1, my_agg(__common_expr_1) AS
col2]]\
+ let expected = "Aggregate: groupBy=[[__common_expr_1 AS UInt32(1) +
test.a]], aggr=[[avg(__common_expr_1) AS col1, my_agg(__common_expr_1) AS
col2]]\
\n Projection: UInt32(1) + test.a AS __common_expr_1, test.a, test.b,
test.c\
\n TableScan: test";
@@ -1277,8 +1277,8 @@ mod test {
)?
.build()?;
- let expected = "Projection: UInt32(1) + test.a, UInt32(1) +
__common_expr_2 AS col1, UInt32(1) - __common_expr_2 AS col2, __common_expr_4
AS AVG(UInt32(1) + test.a), UInt32(1) + __common_expr_3 AS col3, UInt32(1) -
__common_expr_3 AS col4, __common_expr_5 AS my_agg(UInt32(1) + test.a)\
- \n Aggregate: groupBy=[[__common_expr_1 AS UInt32(1) + test.a]],
aggr=[[AVG(__common_expr_1) AS __common_expr_2, my_agg(__common_expr_1) AS
__common_expr_3, AVG(__common_expr_1 AS UInt32(1) + test.a) AS __common_expr_4,
my_agg(__common_expr_1 AS UInt32(1) + test.a) AS __common_expr_5]]\
+ let expected = "Projection: UInt32(1) + test.a, UInt32(1) +
__common_expr_2 AS col1, UInt32(1) - __common_expr_2 AS col2, __common_expr_4
AS avg(UInt32(1) + test.a), UInt32(1) + __common_expr_3 AS col3, UInt32(1) -
__common_expr_3 AS col4, __common_expr_5 AS my_agg(UInt32(1) + test.a)\
+ \n Aggregate: groupBy=[[__common_expr_1 AS UInt32(1) + test.a]],
aggr=[[avg(__common_expr_1) AS __common_expr_2, my_agg(__common_expr_1) AS
__common_expr_3, avg(__common_expr_1 AS UInt32(1) + test.a) AS __common_expr_4,
my_agg(__common_expr_1 AS UInt32(1) + test.a) AS __common_expr_5]]\
\n Projection: UInt32(1) + test.a AS __common_expr_1, test.a,
test.b, test.c\
\n TableScan: test";
@@ -1304,8 +1304,8 @@ mod test {
)?
.build()?;
- let expected = "Projection: table.test.col.a, UInt32(1) +
__common_expr_2 AS AVG(UInt32(1) + table.test.col.a), __common_expr_2 AS
AVG(UInt32(1) + table.test.col.a)\
- \n Aggregate: groupBy=[[table.test.col.a]],
aggr=[[AVG(__common_expr_1 AS UInt32(1) + table.test.col.a) AS
__common_expr_2]]\
+ let expected = "Projection: table.test.col.a, UInt32(1) +
__common_expr_2 AS avg(UInt32(1) + table.test.col.a), __common_expr_2 AS
avg(UInt32(1) + table.test.col.a)\
+ \n Aggregate: groupBy=[[table.test.col.a]],
aggr=[[avg(__common_expr_1 AS UInt32(1) + table.test.col.a) AS
__common_expr_2]]\
\n Projection: UInt32(1) + table.test.col.a AS __common_expr_1,
table.test.col.a\
\n TableScan: table.test";
diff --git a/datafusion/optimizer/tests/optimizer_integration.rs
b/datafusion/optimizer/tests/optimizer_integration.rs
index 7030818330..c501d5aaa4 100644
--- a/datafusion/optimizer/tests/optimizer_integration.rs
+++ b/datafusion/optimizer/tests/optimizer_integration.rs
@@ -25,6 +25,7 @@ use datafusion_common::config::ConfigOptions;
use datafusion_common::{plan_err, Result};
use datafusion_expr::test::function_stub::sum_udaf;
use datafusion_expr::{AggregateUDF, LogicalPlan, ScalarUDF, TableSource,
WindowUDF};
+use datafusion_functions_aggregate::average::avg_udaf;
use datafusion_functions_aggregate::count::count_udaf;
use datafusion_optimizer::analyzer::Analyzer;
use datafusion_optimizer::optimizer::Optimizer;
@@ -64,16 +65,16 @@ fn subquery_filter_with_cast() -> Result<()> {
// regression test for https://github.com/apache/datafusion/issues/3760
let sql = "SELECT col_int32 FROM test \
WHERE col_int32 > (\
- SELECT AVG(col_int32) FROM test \
+ SELECT avg(col_int32) FROM test \
WHERE col_utf8 BETWEEN '2002-05-08' \
AND (cast('2002-05-08' as date) + interval '5 days')\
)";
let plan = test_sql(sql)?;
let expected = "Projection: test.col_int32\
- \n Inner Join: Filter: CAST(test.col_int32 AS Float64) >
__scalar_sq_1.AVG(test.col_int32)\
+ \n Inner Join: Filter: CAST(test.col_int32 AS Float64) >
__scalar_sq_1.avg(test.col_int32)\
\n TableScan: test projection=[col_int32]\
\n SubqueryAlias: __scalar_sq_1\
- \n Aggregate: groupBy=[[]], aggr=[[AVG(CAST(test.col_int32 AS
Float64))]]\
+ \n Aggregate: groupBy=[[]], aggr=[[avg(CAST(test.col_int32 AS
Float64))]]\
\n Projection: test.col_int32\
\n Filter: test.col_utf8 >= Utf8(\"2002-05-08\") AND
test.col_utf8 <= Utf8(\"2002-05-13\")\
\n TableScan: test projection=[col_int32, col_utf8]";
@@ -326,7 +327,8 @@ fn test_sql(sql: &str) -> Result<LogicalPlan> {
let statement = &ast[0];
let context_provider = MyContextProvider::default()
.with_udaf(sum_udaf())
- .with_udaf(count_udaf());
+ .with_udaf(count_udaf())
+ .with_udaf(avg_udaf());
let sql_to_rel = SqlToRel::new(&context_provider);
let plan = sql_to_rel.sql_statement_to_plan(statement.clone()).unwrap();
diff --git a/datafusion/physical-expr/src/aggregate/build_in.rs
b/datafusion/physical-expr/src/aggregate/build_in.rs
index 53cfcfb033..2b80af9bf3 100644
--- a/datafusion/physical-expr/src/aggregate/build_in.rs
+++ b/datafusion/physical-expr/src/aggregate/build_in.rs
@@ -33,7 +33,6 @@ use arrow::datatypes::Schema;
use datafusion_common::{exec_err, not_impl_err, Result};
use datafusion_expr::AggregateFunction;
-use crate::aggregate::average::Avg;
use crate::expressions::{self, Literal};
use crate::{AggregateExpr, PhysicalExpr, PhysicalSortExpr};
@@ -108,12 +107,6 @@ pub fn create_aggregate_expr(
name,
data_type,
)),
- (AggregateFunction::Avg, false) => {
- Arc::new(Avg::new(input_phy_exprs[0].clone(), name, data_type))
- }
- (AggregateFunction::Avg, true) => {
- return not_impl_err!("AVG(DISTINCT) aggregations are not
available");
- }
(AggregateFunction::Correlation, false) => {
Arc::new(expressions::Correlation::new(
input_phy_exprs[0].clone(),
@@ -155,7 +148,7 @@ mod tests {
use datafusion_common::plan_err;
use datafusion_expr::{type_coercion, Signature};
- use crate::expressions::{try_cast, ArrayAgg, Avg, DistinctArrayAgg, Max,
Min};
+ use crate::expressions::{try_cast, ArrayAgg, DistinctArrayAgg, Max, Min};
use super::*;
#[test]
@@ -269,44 +262,6 @@ mod tests {
Ok(())
}
- #[test]
- fn test_sum_avg_expr() -> Result<()> {
- let funcs = vec![AggregateFunction::Avg];
- let data_types = vec![
- DataType::UInt32,
- DataType::UInt64,
- DataType::Int32,
- DataType::Int64,
- DataType::Float32,
- DataType::Float64,
- ];
- for fun in funcs {
- for data_type in &data_types {
- let input_schema =
- Schema::new(vec![Field::new("c1", data_type.clone(),
true)]);
- let input_phy_exprs: Vec<Arc<dyn PhysicalExpr>> =
vec![Arc::new(
- expressions::Column::new_with_schema("c1",
&input_schema).unwrap(),
- )];
- let result_agg_phy_exprs = create_physical_agg_expr_for_test(
- &fun,
- false,
- &input_phy_exprs[0..1],
- &input_schema,
- "c1",
- )?;
- if fun == AggregateFunction::Avg {
- assert!(result_agg_phy_exprs.as_any().is::<Avg>());
- assert_eq!("c1", result_agg_phy_exprs.name());
- assert_eq!(
- Field::new("c1", DataType::Float64, true),
- result_agg_phy_exprs.field().unwrap()
- );
- };
- }
- }
- Ok(())
- }
-
#[test]
fn test_min_max() -> Result<()> {
let observed = AggregateFunction::Min.return_type(&[DataType::Utf8])?;
@@ -328,33 +283,6 @@ mod tests {
Ok(())
}
- #[test]
- fn test_avg_return_type() -> Result<()> {
- let observed =
AggregateFunction::Avg.return_type(&[DataType::Float32])?;
- assert_eq!(DataType::Float64, observed);
-
- let observed =
AggregateFunction::Avg.return_type(&[DataType::Float64])?;
- assert_eq!(DataType::Float64, observed);
-
- let observed = AggregateFunction::Avg.return_type(&[DataType::Int32])?;
- assert_eq!(DataType::Float64, observed);
-
- let observed =
- AggregateFunction::Avg.return_type(&[DataType::Decimal128(10,
6)])?;
- assert_eq!(DataType::Decimal128(14, 10), observed);
-
- let observed =
- AggregateFunction::Avg.return_type(&[DataType::Decimal128(36,
6)])?;
- assert_eq!(DataType::Decimal128(38, 10), observed);
- Ok(())
- }
-
- #[test]
- fn test_avg_no_utf8() {
- let observed = AggregateFunction::Avg.return_type(&[DataType::Utf8]);
- assert!(observed.is_err());
- }
-
// Helper function
// Create aggregate expr with type coercion
fn create_physical_agg_expr_for_test(
diff --git a/datafusion/physical-expr/src/aggregate/groups_accumulator/mod.rs
b/datafusion/physical-expr/src/aggregate/groups_accumulator/mod.rs
index 73d810ec05..1944e2b2d4 100644
--- a/datafusion/physical-expr/src/aggregate/groups_accumulator/mod.rs
+++ b/datafusion/physical-expr/src/aggregate/groups_accumulator/mod.rs
@@ -19,6 +19,7 @@ mod adapter;
pub use adapter::GroupsAccumulatorAdapter;
// Backward compatibility
+#[allow(unused_imports)]
pub(crate) mod accumulate {
pub use
datafusion_physical_expr_common::aggregate::groups_accumulator::accumulate::NullState;
}
diff --git a/datafusion/physical-expr/src/aggregate/mod.rs
b/datafusion/physical-expr/src/aggregate/mod.rs
index f64c5b1fb2..7cb50fc252 100644
--- a/datafusion/physical-expr/src/aggregate/mod.rs
+++ b/datafusion/physical-expr/src/aggregate/mod.rs
@@ -20,7 +20,6 @@ pub use
datafusion_physical_expr_common::aggregate::AggregateExpr;
pub(crate) mod array_agg;
pub(crate) mod array_agg_distinct;
pub(crate) mod array_agg_ordered;
-pub(crate) mod average;
pub(crate) mod correlation;
pub(crate) mod covariance;
pub(crate) mod grouping;
diff --git a/datafusion/physical-expr/src/expressions/mod.rs
b/datafusion/physical-expr/src/expressions/mod.rs
index 0020aa5f55..59de4d0874 100644
--- a/datafusion/physical-expr/src/expressions/mod.rs
+++ b/datafusion/physical-expr/src/expressions/mod.rs
@@ -38,8 +38,6 @@ pub mod helpers {
pub use crate::aggregate::array_agg::ArrayAgg;
pub use crate::aggregate::array_agg_distinct::DistinctArrayAgg;
pub use crate::aggregate::array_agg_ordered::OrderSensitiveArrayAgg;
-pub use crate::aggregate::average::Avg;
-pub use crate::aggregate::average::AvgAccumulator;
pub use crate::aggregate::build_in::create_aggregate_expr;
pub use crate::aggregate::correlation::Correlation;
pub use crate::aggregate::grouping::Grouping;
diff --git a/datafusion/physical-plan/src/aggregates/mod.rs
b/datafusion/physical-plan/src/aggregates/mod.rs
index b7d8d60f4f..4c187f03f3 100644
--- a/datafusion/physical-plan/src/aggregates/mod.rs
+++ b/datafusion/physical-plan/src/aggregates/mod.rs
@@ -1177,7 +1177,7 @@ mod tests {
use crate::coalesce_batches::CoalesceBatchesExec;
use crate::coalesce_partitions::CoalescePartitionsExec;
use crate::common;
- use crate::expressions::{col, Avg};
+ use crate::expressions::col;
use crate::memory::MemoryExec;
use crate::test::assert_is_pending;
use crate::test::exec::{assert_strong_count_converges_to_zero,
BlockingExec};
@@ -1194,6 +1194,7 @@ mod tests {
use datafusion_execution::memory_pool::FairSpillPool;
use datafusion_execution::runtime_env::{RuntimeConfig, RuntimeEnv};
use datafusion_expr::expr::Sort;
+ use datafusion_functions_aggregate::average::avg_udaf;
use datafusion_functions_aggregate::count::count_udaf;
use datafusion_functions_aggregate::median::median_udaf;
use datafusion_physical_expr::expressions::{
@@ -1485,11 +1486,17 @@ mod tests {
groups: vec![vec![false]],
};
- let aggregates: Vec<Arc<dyn AggregateExpr>> = vec![Arc::new(Avg::new(
- col("b", &input_schema)?,
- "AVG(b)".to_string(),
- DataType::Float64,
- ))];
+ let aggregates: Vec<Arc<dyn AggregateExpr>> =
vec![create_aggregate_expr(
+ &avg_udaf(),
+ &[col("b", &input_schema)?],
+ &[datafusion_expr::col("b")],
+ &[],
+ &[],
+ &input_schema,
+ "AVG(b)",
+ false,
+ false,
+ )?];
let task_ctx = if spill {
// set to an appropriate value to trigger spill
@@ -1819,11 +1826,17 @@ mod tests {
vec![test_median_agg_expr(&input_schema)?];
// use fast-path in `row_hash.rs`.
- let aggregates_v2: Vec<Arc<dyn AggregateExpr>> =
vec![Arc::new(Avg::new(
- col("b", &input_schema)?,
- "AVG(b)".to_string(),
- DataType::Float64,
- ))];
+ let aggregates_v2: Vec<Arc<dyn AggregateExpr>> =
vec![create_aggregate_expr(
+ &avg_udaf(),
+ &[col("b", &input_schema)?],
+ &[datafusion_expr::col("b")],
+ &[],
+ &[],
+ &input_schema,
+ "AVG(b)",
+ false,
+ false,
+ )?];
for (version, groups, aggregates) in [
(0, groups_none, aggregates_v0),
@@ -1873,15 +1886,21 @@ mod tests {
async fn test_drop_cancel_without_groups() -> Result<()> {
let task_ctx = Arc::new(TaskContext::default());
let schema =
- Arc::new(Schema::new(vec![Field::new("a", DataType::Float32,
true)]));
+ Arc::new(Schema::new(vec![Field::new("a", DataType::Float64,
true)]));
let groups = PhysicalGroupBy::default();
- let aggregates: Vec<Arc<dyn AggregateExpr>> = vec![Arc::new(Avg::new(
- col("a", &schema)?,
- "AVG(a)".to_string(),
- DataType::Float64,
- ))];
+ let aggregates: Vec<Arc<dyn AggregateExpr>> =
vec![create_aggregate_expr(
+ &avg_udaf(),
+ &[col("a", &schema)?],
+ &[datafusion_expr::col("a")],
+ &[],
+ &[],
+ &schema,
+ "AVG(a)",
+ false,
+ false,
+ )?];
let blocking_exec = Arc::new(BlockingExec::new(Arc::clone(&schema),
1));
let refs = blocking_exec.refs();
@@ -1908,18 +1927,24 @@ mod tests {
async fn test_drop_cancel_with_groups() -> Result<()> {
let task_ctx = Arc::new(TaskContext::default());
let schema = Arc::new(Schema::new(vec![
- Field::new("a", DataType::Float32, true),
- Field::new("b", DataType::Float32, true),
+ Field::new("a", DataType::Float64, true),
+ Field::new("b", DataType::Float64, true),
]));
let groups =
PhysicalGroupBy::new_single(vec![(col("a", &schema)?,
"a".to_string())]);
- let aggregates: Vec<Arc<dyn AggregateExpr>> = vec![Arc::new(Avg::new(
- col("b", &schema)?,
- "AVG(b)".to_string(),
- DataType::Float64,
- ))];
+ let aggregates: Vec<Arc<dyn AggregateExpr>> =
vec![create_aggregate_expr(
+ &avg_udaf(),
+ &[col("b", &schema)?],
+ &[datafusion_expr::col("b")],
+ &[],
+ &[],
+ &schema,
+ "AVG(b)",
+ false,
+ false,
+ )?];
let blocking_exec = Arc::new(BlockingExec::new(Arc::clone(&schema),
1));
let refs = blocking_exec.refs();
diff --git a/datafusion/proto/proto/datafusion.proto
b/datafusion/proto/proto/datafusion.proto
index 50356d5b60..8d73643f9c 100644
--- a/datafusion/proto/proto/datafusion.proto
+++ b/datafusion/proto/proto/datafusion.proto
@@ -475,7 +475,7 @@ enum AggregateFunction {
MIN = 0;
MAX = 1;
// SUM = 2;
- AVG = 3;
+ // AVG = 3;
// COUNT = 4;
// APPROX_DISTINCT = 5;
ARRAY_AGG = 6;
diff --git a/datafusion/proto/src/generated/pbjson.rs
b/datafusion/proto/src/generated/pbjson.rs
index 8cca0fe4a8..10d3f54dc8 100644
--- a/datafusion/proto/src/generated/pbjson.rs
+++ b/datafusion/proto/src/generated/pbjson.rs
@@ -534,7 +534,6 @@ impl serde::Serialize for AggregateFunction {
let variant = match self {
Self::Min => "MIN",
Self::Max => "MAX",
- Self::Avg => "AVG",
Self::ArrayAgg => "ARRAY_AGG",
Self::Correlation => "CORRELATION",
Self::Grouping => "GROUPING",
@@ -552,7 +551,6 @@ impl<'de> serde::Deserialize<'de> for AggregateFunction {
const FIELDS: &[&str] = &[
"MIN",
"MAX",
- "AVG",
"ARRAY_AGG",
"CORRELATION",
"GROUPING",
@@ -599,7 +597,6 @@ impl<'de> serde::Deserialize<'de> for AggregateFunction {
match value {
"MIN" => Ok(AggregateFunction::Min),
"MAX" => Ok(AggregateFunction::Max),
- "AVG" => Ok(AggregateFunction::Avg),
"ARRAY_AGG" => Ok(AggregateFunction::ArrayAgg),
"CORRELATION" => Ok(AggregateFunction::Correlation),
"GROUPING" => Ok(AggregateFunction::Grouping),
diff --git a/datafusion/proto/src/generated/prost.rs
b/datafusion/proto/src/generated/prost.rs
index 56f1498292..9504d26d44 100644
--- a/datafusion/proto/src/generated/prost.rs
+++ b/datafusion/proto/src/generated/prost.rs
@@ -1929,7 +1929,7 @@ pub enum AggregateFunction {
Min = 0,
Max = 1,
/// SUM = 2;
- Avg = 3,
+ /// AVG = 3;
/// COUNT = 4;
/// APPROX_DISTINCT = 5;
ArrayAgg = 6,
@@ -1971,7 +1971,6 @@ impl AggregateFunction {
match self {
AggregateFunction::Min => "MIN",
AggregateFunction::Max => "MAX",
- AggregateFunction::Avg => "AVG",
AggregateFunction::ArrayAgg => "ARRAY_AGG",
AggregateFunction::Correlation => "CORRELATION",
AggregateFunction::Grouping => "GROUPING",
@@ -1983,7 +1982,6 @@ impl AggregateFunction {
match value {
"MIN" => Some(Self::Min),
"MAX" => Some(Self::Max),
- "AVG" => Some(Self::Avg),
"ARRAY_AGG" => Some(Self::ArrayAgg),
"CORRELATION" => Some(Self::Correlation),
"GROUPING" => Some(Self::Grouping),
diff --git a/datafusion/proto/src/logical_plan/from_proto.rs
b/datafusion/proto/src/logical_plan/from_proto.rs
index ba0e708218..420e59688d 100644
--- a/datafusion/proto/src/logical_plan/from_proto.rs
+++ b/datafusion/proto/src/logical_plan/from_proto.rs
@@ -139,7 +139,6 @@ impl From<protobuf::AggregateFunction> for
AggregateFunction {
match agg_fun {
protobuf::AggregateFunction::Min => Self::Min,
protobuf::AggregateFunction::Max => Self::Max,
- protobuf::AggregateFunction::Avg => Self::Avg,
protobuf::AggregateFunction::ArrayAgg => Self::ArrayAgg,
protobuf::AggregateFunction::Correlation => Self::Correlation,
protobuf::AggregateFunction::Grouping => Self::Grouping,
diff --git a/datafusion/proto/src/logical_plan/to_proto.rs
b/datafusion/proto/src/logical_plan/to_proto.rs
index 08999effa4..d12bfd9ffd 100644
--- a/datafusion/proto/src/logical_plan/to_proto.rs
+++ b/datafusion/proto/src/logical_plan/to_proto.rs
@@ -110,7 +110,6 @@ impl From<&AggregateFunction> for
protobuf::AggregateFunction {
match value {
AggregateFunction::Min => Self::Min,
AggregateFunction::Max => Self::Max,
- AggregateFunction::Avg => Self::Avg,
AggregateFunction::ArrayAgg => Self::ArrayAgg,
AggregateFunction::Correlation => Self::Correlation,
AggregateFunction::Grouping => Self::Grouping,
@@ -374,7 +373,6 @@ pub fn serialize_expr(
AggregateFunction::ArrayAgg =>
protobuf::AggregateFunction::ArrayAgg,
AggregateFunction::Min => protobuf::AggregateFunction::Min,
AggregateFunction::Max => protobuf::AggregateFunction::Max,
- AggregateFunction::Avg => protobuf::AggregateFunction::Avg,
AggregateFunction::Correlation => {
protobuf::AggregateFunction::Correlation
}
diff --git a/datafusion/proto/src/physical_plan/to_proto.rs
b/datafusion/proto/src/physical_plan/to_proto.rs
index a9d3736dee..4554e529c3 100644
--- a/datafusion/proto/src/physical_plan/to_proto.rs
+++ b/datafusion/proto/src/physical_plan/to_proto.rs
@@ -23,7 +23,7 @@ use datafusion::datasource::file_format::parquet::ParquetSink;
use datafusion::physical_expr::window::{NthValueKind,
SlidingAggregateWindowExpr};
use datafusion::physical_expr::{PhysicalSortExpr, ScalarFunctionExpr};
use datafusion::physical_plan::expressions::{
- ArrayAgg, Avg, BinaryExpr, CaseExpr, CastExpr, Column, Correlation,
CumeDist,
+ ArrayAgg, BinaryExpr, CaseExpr, CastExpr, Column, Correlation, CumeDist,
DistinctArrayAgg, Grouping, InListExpr, IsNotNullExpr, IsNullExpr,
Literal, Max, Min,
NegativeExpr, NotExpr, NthValue, NthValueAgg, Ntile,
OrderSensitiveArrayAgg, Rank,
RankType, RowNumber, TryCastExpr, WindowShift,
@@ -165,21 +165,28 @@ pub fn serialize_physical_window_expr(
} else if let Some(plain_aggr_window_expr) =
expr.downcast_ref::<PlainAggregateWindowExpr>()
{
- let AggrFn { inner, distinct } =
-
aggr_expr_to_aggr_fn(plain_aggr_window_expr.get_aggregate_expr().as_ref())?;
+ let aggr_expr = plain_aggr_window_expr.get_aggregate_expr();
+ if let Some(a) =
aggr_expr.as_any().downcast_ref::<AggregateFunctionExpr>() {
+ physical_window_expr_node::WindowFunction::UserDefinedAggrFunction(
+ a.fun().name().to_string(),
+ )
+ } else {
+ let AggrFn { inner, distinct } = aggr_expr_to_aggr_fn(
+ plain_aggr_window_expr.get_aggregate_expr().as_ref(),
+ )?;
- if distinct {
- // TODO
- return not_impl_err!(
- "Distinct aggregate functions not supported in window
expressions"
- );
- }
+ if distinct {
+ return not_impl_err!(
+ "Distinct aggregate functions not supported in window
expressions"
+ );
+ }
- if !window_frame.start_bound.is_unbounded() {
- return Err(DataFusionError::Internal(format!("Invalid
PlainAggregateWindowExpr = {window_expr:?} with WindowFrame =
{window_frame:?}")));
- }
+ if !window_frame.start_bound.is_unbounded() {
+ return Err(DataFusionError::Internal(format!("Invalid
PlainAggregateWindowExpr = {window_expr:?} with WindowFrame =
{window_frame:?}")));
+ }
- physical_window_expr_node::WindowFunction::AggrFunction(inner as i32)
+ physical_window_expr_node::WindowFunction::AggrFunction(inner as
i32)
+ }
} else if let Some(sliding_aggr_window_expr) =
expr.downcast_ref::<SlidingAggregateWindowExpr>()
{
@@ -251,8 +258,6 @@ fn aggr_expr_to_aggr_fn(expr: &dyn AggregateExpr) ->
Result<AggrFn> {
protobuf::AggregateFunction::Min
} else if aggr_expr.downcast_ref::<Max>().is_some() {
protobuf::AggregateFunction::Max
- } else if aggr_expr.downcast_ref::<Avg>().is_some() {
- protobuf::AggregateFunction::Avg
} else if aggr_expr.downcast_ref::<Correlation>().is_some() {
protobuf::AggregateFunction::Correlation
} else if aggr_expr.downcast_ref::<NthValueAgg>().is_some() {
diff --git a/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
b/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
index b3966c3f02..1d61a65f0b 100644
--- a/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
+++ b/datafusion/proto/tests/cases/roundtrip_logical_plan.rs
@@ -59,6 +59,7 @@ use datafusion_expr::{
TryCast, Volatility, WindowFrame, WindowFrameBound, WindowFrameUnits,
WindowFunctionDefinition, WindowUDF, WindowUDFImpl,
};
+use datafusion_functions_aggregate::average::avg_udaf;
use datafusion_functions_aggregate::expr_fn::{
bit_and, bit_or, bit_xor, bool_and, bool_or,
};
@@ -2163,7 +2164,16 @@ fn roundtrip_window() {
vec![col("col1")],
vec![col("col1")],
vec![col("col2")],
- row_number_frame,
+ row_number_frame.clone(),
+ None,
+ ));
+
+ let text_expr7 = Expr::WindowFunction(expr::WindowFunction::new(
+ WindowFunctionDefinition::AggregateUDF(avg_udaf()),
+ vec![col("col1")],
+ vec![],
+ vec![],
+ row_number_frame.clone(),
None,
));
@@ -2174,5 +2184,6 @@ fn roundtrip_window() {
roundtrip_expr_test(test_expr3, ctx.clone());
roundtrip_expr_test(test_expr4, ctx.clone());
roundtrip_expr_test(test_expr5, ctx.clone());
- roundtrip_expr_test(test_expr6, ctx);
+ roundtrip_expr_test(test_expr6, ctx.clone());
+ roundtrip_expr_test(text_expr7, ctx);
}
diff --git a/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
b/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
index eb33132395..03c72cfc32 100644
--- a/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
+++ b/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
@@ -47,7 +47,7 @@ use datafusion::physical_plan::aggregates::{
use datafusion::physical_plan::analyze::AnalyzeExec;
use datafusion::physical_plan::empty::EmptyExec;
use datafusion::physical_plan::expressions::{
- binary, cast, col, in_list, like, lit, Avg, BinaryExpr, Column, NotExpr,
NthValue,
+ binary, cast, col, in_list, like, lit, BinaryExpr, Column, NotExpr,
NthValue,
PhysicalSortExpr,
};
use datafusion::physical_plan::filter::FilterExec;
@@ -60,6 +60,7 @@ use
datafusion::physical_plan::placeholder_row::PlaceholderRowExec;
use datafusion::physical_plan::projection::ProjectionExec;
use datafusion::physical_plan::repartition::RepartitionExec;
use datafusion::physical_plan::sorts::sort::SortExec;
+use datafusion::physical_plan::udaf::create_aggregate_expr;
use datafusion::physical_plan::union::{InterleaveExec, UnionExec};
use datafusion::physical_plan::windows::{
BuiltInWindowExpr, PlainAggregateWindowExpr, WindowAggExec,
@@ -79,6 +80,7 @@ use datafusion_expr::{
Accumulator, AccumulatorFactoryFunction, AggregateUDF, ColumnarValue,
ScalarUDF,
ScalarUDFImpl, Signature, SimpleAggregateUDF, WindowFrame,
WindowFrameBound,
};
+use datafusion_functions_aggregate::average::avg_udaf;
use datafusion_functions_aggregate::string_agg::StringAgg;
use datafusion_proto::physical_plan::{
AsExecutionPlan, DefaultPhysicalExtensionCodec, PhysicalExtensionCodec,
@@ -282,11 +284,17 @@ fn roundtrip_window() -> Result<()> {
));
let plain_aggr_window_expr = Arc::new(PlainAggregateWindowExpr::new(
- Arc::new(Avg::new(
- cast(col("b", &schema)?, &schema, DataType::Float64)?,
- "AVG(b)".to_string(),
- DataType::Float64,
- )),
+ create_aggregate_expr(
+ &avg_udaf(),
+ &[cast(col("b", &schema)?, &schema, DataType::Float64)?],
+ &[],
+ &[],
+ &[],
+ &schema,
+ "avg(b)",
+ false,
+ false,
+ )?,
&[],
&[],
Arc::new(WindowFrame::new(None)),
@@ -342,11 +350,17 @@ fn rountrip_aggregate() -> Result<()> {
let test_cases: Vec<Vec<Arc<dyn AggregateExpr>>> = vec![
// AVG
- vec![Arc::new(Avg::new(
- cast(col("b", &schema)?, &schema, DataType::Float64)?,
- "AVG(b)".to_string(),
- DataType::Float64,
- ))],
+ vec![create_aggregate_expr(
+ &avg_udaf(),
+ &[col("b", &schema)?],
+ &[],
+ &[],
+ &[],
+ &schema,
+ "AVG(b)",
+ false,
+ false,
+ )?],
// NTH_VALUE
vec![Arc::new(NthValueAgg::new(
col("b", &schema)?,
@@ -398,11 +412,17 @@ fn rountrip_aggregate_with_limit() -> Result<()> {
let groups: Vec<(Arc<dyn PhysicalExpr>, String)> =
vec![(col("a", &schema)?, "unused".to_string())];
- let aggregates: Vec<Arc<dyn AggregateExpr>> = vec![Arc::new(Avg::new(
- cast(col("b", &schema)?, &schema, DataType::Float64)?,
- "AVG(b)".to_string(),
- DataType::Float64,
- ))];
+ let aggregates: Vec<Arc<dyn AggregateExpr>> = vec![create_aggregate_expr(
+ &avg_udaf(),
+ &[col("b", &schema)?],
+ &[],
+ &[],
+ &[],
+ &schema,
+ "AVG(b)",
+ false,
+ false,
+ )?];
let agg = AggregateExec::try_new(
AggregateMode::Final,
diff --git a/datafusion/sql/tests/sql_integration.rs
b/datafusion/sql/tests/sql_integration.rs
index 3905d7d184..f196d71d41 100644
--- a/datafusion/sql/tests/sql_integration.rs
+++ b/datafusion/sql/tests/sql_integration.rs
@@ -37,6 +37,7 @@ use datafusion_sql::{
planner::{ParserOptions, SqlToRel},
};
+use datafusion_functions_aggregate::average::avg_udaf;
use datafusion_functions_aggregate::{
approx_median::approx_median_udaf, count::count_udaf,
};
@@ -2309,10 +2310,10 @@ fn empty_over_plus() {
#[test]
fn empty_over_multiple() {
- let sql = "SELECT order_id, MAX(qty) OVER (), min(qty) over (), aVg(qty)
OVER () from orders";
+ let sql = "SELECT order_id, MAX(qty) OVER (), min(qty) over (), avg(qty)
OVER () from orders";
let expected = "\
- Projection: orders.order_id, MAX(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, MIN(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, AVG(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING\
- \n WindowAggr: windowExpr=[[MAX(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, MIN(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, AVG(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING]]\
+ Projection: orders.order_id, MAX(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, MIN(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, avg(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING\
+ \n WindowAggr: windowExpr=[[MAX(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, MIN(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING, avg(orders.qty) ROWS BETWEEN UNBOUNDED
PRECEDING AND UNBOUNDED FOLLOWING]]\
\n TableScan: orders";
quick_test(sql, expected);
}
@@ -2627,8 +2628,8 @@ fn select_groupby_orderby() {
// expect that this is not an ambiguous reference
let expected =
"Sort: birth_date ASC NULLS LAST\
- \n Projection: AVG(person.age) AS value, date_trunc(Utf8(\"month\"),
person.birth_date) AS birth_date\
- \n Aggregate: groupBy=[[person.birth_date]],
aggr=[[AVG(person.age)]]\
+ \n Projection: avg(person.age) AS value, date_trunc(Utf8(\"month\"),
person.birth_date) AS birth_date\
+ \n Aggregate: groupBy=[[person.birth_date]],
aggr=[[avg(person.age)]]\
\n TableScan: person";
quick_test(sql, expected);
@@ -2705,7 +2706,8 @@ fn logical_plan_with_dialect_and_options(
.with_udf(make_udf("sqrt", vec![DataType::Int64], DataType::Int64))
.with_udaf(sum_udaf())
.with_udaf(approx_median_udaf())
- .with_udaf(count_udaf());
+ .with_udaf(count_udaf())
+ .with_udaf(avg_udaf());
let planner = SqlToRel::new_with_options(&context, options);
let result = DFParser::parse_sql_with_dialect(sql, dialect);
diff --git a/datafusion/sqllogictest/test_files/aggregate.slt
b/datafusion/sqllogictest/test_files/aggregate.slt
index 4090ff8764..552ad6a2a7 100644
--- a/datafusion/sqllogictest/test_files/aggregate.slt
+++ b/datafusion/sqllogictest/test_files/aggregate.slt
@@ -3690,10 +3690,10 @@ X 2 2 2 2
Y 1 1 1 1
# aggregate_timestamps_avg
-statement error DataFusion error: Error during planning: No function matches
the given name and argument types 'AVG\(Timestamp\(Nanosecond, None\)\)'\. You
might need to add explicit type casts\.
+query error
SELECT avg(nanos), avg(micros), avg(millis), avg(secs) FROM t
-statement error DataFusion error: Error during planning: No function matches
the given name and argument types 'AVG\(Timestamp\(Nanosecond, None\)\)'\. You
might need to add explicit type casts\.
+query error
SELECT tag, avg(nanos), avg(micros), avg(millis), avg(secs) FROM t GROUP BY
tag ORDER BY tag;
# aggregate_duration_array_agg
@@ -3790,10 +3790,10 @@ Y 2021-01-01 2021-01-01T00:00:00
# aggregate_timestamps_avg
-statement error DataFusion error: Error during planning: No function matches
the given name and argument types 'AVG\(Date32\)'\. You might need to add
explicit type casts\.
+query error
SELECT avg(date32), avg(date64) FROM t
-statement error DataFusion error: Error during planning: No function matches
the given name and argument types 'AVG\(Date32\)'\. You might need to add
explicit type casts\.
+query error
SELECT tag, avg(date32), avg(date64) FROM t GROUP BY tag ORDER BY tag;
@@ -3888,10 +3888,10 @@ B 21:06:28.247821084 21:06:28.247821 21:06:28.247
21:06:28
# aggregate_times_avg
-statement error DataFusion error: Error during planning: No function matches
the given name and argument types 'AVG\(Time64\(Nanosecond\)\)'\. You might
need to add explicit type casts\.
+query error
SELECT avg(nanos), avg(micros), avg(millis), avg(secs) FROM t
-statement error DataFusion error: Error during planning: No function matches
the given name and argument types 'AVG\(Time64\(Nanosecond\)\)'\. You might
need to add explicit type casts\.
+query error
SELECT tag, avg(nanos), avg(micros), avg(millis), avg(secs) FROM t GROUP BY
tag ORDER BY tag;
statement ok
@@ -4325,7 +4325,7 @@ select avg(distinct x_dict) from value_dict;
----
3
-statement error DataFusion error: This feature is not implemented:
AVG\(DISTINCT\) aggregations are not available
+query error
select avg(x_dict), avg(distinct x_dict) from value_dict;
query I
diff --git a/datafusion/sqllogictest/test_files/errors.slt
b/datafusion/sqllogictest/test_files/errors.slt
index d51c69496d..fa25f00974 100644
--- a/datafusion/sqllogictest/test_files/errors.slt
+++ b/datafusion/sqllogictest/test_files/errors.slt
@@ -108,7 +108,7 @@ query error
select count();
# AggregateFunction with wrong number of arguments
-statement error DataFusion error: Error during planning: No function matches
the given name and argument types 'AVG\(Utf8, Float64\)'\. You might need to
add explicit type casts\.\n\tCandidate
functions:\n\tAVG\(Int8/Int16/Int32/Int64/UInt8/UInt16/UInt32/UInt64/Float32/Float64\)
+query error
select avg(c1, c12) from aggregate_test_100;
# AggregateFunction with wrong argument type
diff --git a/datafusion/sqllogictest/test_files/group_by.slt
b/datafusion/sqllogictest/test_files/group_by.slt
index b08df0e4b3..f7f251e4b9 100644
--- a/datafusion/sqllogictest/test_files/group_by.slt
+++ b/datafusion/sqllogictest/test_files/group_by.slt
@@ -1962,9 +1962,9 @@ GROUP BY ALL;
2 0 13
query IIR rowsort
-SELECT sub.col1, sub.col0, sub."AVG(tab3.col2)" AS avg_col2
+SELECT sub.col1, sub.col0, sub."avg(tab3.col2)" AS avg_col2
FROM (
- SELECT col1, AVG(col2), col0 FROM tab3 GROUP BY ALL
+ SELECT col1, avg(col2), col0 FROM tab3 GROUP BY ALL
) AS sub
GROUP BY ALL;
----
diff --git a/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt
b/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt
index ef77bdca1b..de6a153f58 100644
--- a/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt
+++ b/datafusion/sqllogictest/test_files/optimizer_group_by_constant.slt
@@ -60,8 +60,8 @@ 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)]]
+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]
diff --git a/datafusion/sqllogictest/test_files/predicates.slt
b/datafusion/sqllogictest/test_files/predicates.slt
index 4e8f0eb6ca..ffaae7204e 100644
--- a/datafusion/sqllogictest/test_files/predicates.slt
+++ b/datafusion/sqllogictest/test_files/predicates.slt
@@ -748,7 +748,7 @@ OR
GROUP BY p_partkey;
----
logical_plan
-01)Aggregate: groupBy=[[part.p_partkey]],
aggr=[[sum(lineitem.l_extendedprice), AVG(lineitem.l_discount), count(DISTINCT
partsupp.ps_suppkey)]]
+01)Aggregate: groupBy=[[part.p_partkey]],
aggr=[[sum(lineitem.l_extendedprice), avg(lineitem.l_discount), count(DISTINCT
partsupp.ps_suppkey)]]
02)--Projection: lineitem.l_extendedprice, lineitem.l_discount,
part.p_partkey, partsupp.ps_suppkey
03)----Inner Join: part.p_partkey = partsupp.ps_partkey
04)------Projection: lineitem.l_extendedprice, lineitem.l_discount,
part.p_partkey
@@ -759,7 +759,7 @@ logical_plan
09)--------------TableScan: part projection=[p_partkey, p_brand],
partial_filters=[part.p_brand = Utf8("Brand#12") OR part.p_brand =
Utf8("Brand#23")]
10)------TableScan: partsupp projection=[ps_partkey, ps_suppkey]
physical_plan
-01)AggregateExec: mode=SinglePartitioned, gby=[p_partkey@2 as p_partkey],
aggr=[sum(lineitem.l_extendedprice), AVG(lineitem.l_discount), count(DISTINCT
partsupp.ps_suppkey)]
+01)AggregateExec: mode=SinglePartitioned, gby=[p_partkey@2 as p_partkey],
aggr=[sum(lineitem.l_extendedprice), avg(lineitem.l_discount), count(DISTINCT
partsupp.ps_suppkey)]
02)--CoalesceBatchesExec: target_batch_size=8192
03)----HashJoinExec: mode=Partitioned, join_type=Inner, on=[(p_partkey@2,
ps_partkey@0)], projection=[l_extendedprice@0, l_discount@1, p_partkey@2,
ps_suppkey@4]
04)------CoalesceBatchesExec: target_batch_size=8192
diff --git a/datafusion/sqllogictest/test_files/tpch/q1.slt.part
b/datafusion/sqllogictest/test_files/tpch/q1.slt.part
index f005081b15..6c3e7dd361 100644
--- a/datafusion/sqllogictest/test_files/tpch/q1.slt.part
+++ b/datafusion/sqllogictest/test_files/tpch/q1.slt.part
@@ -41,19 +41,19 @@ explain select
----
logical_plan
01)Sort: lineitem.l_returnflag ASC NULLS LAST, lineitem.l_linestatus ASC NULLS
LAST
-02)--Projection: lineitem.l_returnflag, lineitem.l_linestatus,
sum(lineitem.l_quantity) AS sum_qty, sum(lineitem.l_extendedprice) AS
sum_base_price, sum(lineitem.l_extendedprice * Int64(1) - lineitem.l_discount)
AS sum_disc_price, sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax) AS sum_charge,
AVG(lineitem.l_quantity) AS avg_qty, AVG(lineitem.l_extendedprice) AS
avg_price, AVG(lineitem.l_discount) AS avg_disc, count(*) AS count_order
-03)----Aggregate: groupBy=[[lineitem.l_returnflag, lineitem.l_linestatus]],
aggr=[[sum(lineitem.l_quantity), sum(lineitem.l_extendedprice),
sum(__common_expr_1) AS sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount), sum(__common_expr_1 * (Decimal128(Some(1),20,0) +
lineitem.l_tax)) AS sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax), AVG(lineitem.l_quantity),
AVG(lineitem.l_extendedprice), AVG(lineitem.l_discount), count(Int64(1)) AS
[...]
+02)--Projection: lineitem.l_returnflag, lineitem.l_linestatus,
sum(lineitem.l_quantity) AS sum_qty, sum(lineitem.l_extendedprice) AS
sum_base_price, sum(lineitem.l_extendedprice * Int64(1) - lineitem.l_discount)
AS sum_disc_price, sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax) AS sum_charge,
avg(lineitem.l_quantity) AS avg_qty, avg(lineitem.l_extendedprice) AS
avg_price, avg(lineitem.l_discount) AS avg_disc, count(*) AS count_order
+03)----Aggregate: groupBy=[[lineitem.l_returnflag, lineitem.l_linestatus]],
aggr=[[sum(lineitem.l_quantity), sum(lineitem.l_extendedprice),
sum(__common_expr_1) AS sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount), sum(__common_expr_1 * (Decimal128(Some(1),20,0) +
lineitem.l_tax)) AS sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax), avg(lineitem.l_quantity),
avg(lineitem.l_extendedprice), avg(lineitem.l_discount), count(Int64(1)) AS
[...]
04)------Projection: lineitem.l_extendedprice * (Decimal128(Some(1),20,0) -
lineitem.l_discount) AS __common_expr_1, lineitem.l_quantity,
lineitem.l_extendedprice, lineitem.l_discount, lineitem.l_tax,
lineitem.l_returnflag, lineitem.l_linestatus
05)--------Filter: lineitem.l_shipdate <= Date32("1998-09-02")
06)----------TableScan: lineitem projection=[l_quantity, l_extendedprice,
l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate],
partial_filters=[lineitem.l_shipdate <= Date32("1998-09-02")]
physical_plan
01)SortPreservingMergeExec: [l_returnflag@0 ASC NULLS LAST,l_linestatus@1 ASC
NULLS LAST]
02)--SortExec: expr=[l_returnflag@0 ASC NULLS LAST,l_linestatus@1 ASC NULLS
LAST], preserve_partitioning=[true]
-03)----ProjectionExec: expr=[l_returnflag@0 as l_returnflag, l_linestatus@1 as
l_linestatus, sum(lineitem.l_quantity)@2 as sum_qty,
sum(lineitem.l_extendedprice)@3 as sum_base_price, sum(lineitem.l_extendedprice
* Int64(1) - lineitem.l_discount)@4 as sum_disc_price,
sum(lineitem.l_extendedprice * Int64(1) - lineitem.l_discount * Int64(1) +
lineitem.l_tax)@5 as sum_charge, AVG(lineitem.l_quantity)@6 as avg_qty,
AVG(lineitem.l_extendedprice)@7 as avg_price, AVG(lineitem.l_discount)@8 as av
[...]
-04)------AggregateExec: mode=FinalPartitioned, gby=[l_returnflag@0 as
l_returnflag, l_linestatus@1 as l_linestatus], aggr=[sum(lineitem.l_quantity),
sum(lineitem.l_extendedprice), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax), AVG(lineitem.l_quantity),
AVG(lineitem.l_extendedprice), AVG(lineitem.l_discount), count(*)]
+03)----ProjectionExec: expr=[l_returnflag@0 as l_returnflag, l_linestatus@1 as
l_linestatus, sum(lineitem.l_quantity)@2 as sum_qty,
sum(lineitem.l_extendedprice)@3 as sum_base_price, sum(lineitem.l_extendedprice
* Int64(1) - lineitem.l_discount)@4 as sum_disc_price,
sum(lineitem.l_extendedprice * Int64(1) - lineitem.l_discount * Int64(1) +
lineitem.l_tax)@5 as sum_charge, avg(lineitem.l_quantity)@6 as avg_qty,
avg(lineitem.l_extendedprice)@7 as avg_price, avg(lineitem.l_discount)@8 as av
[...]
+04)------AggregateExec: mode=FinalPartitioned, gby=[l_returnflag@0 as
l_returnflag, l_linestatus@1 as l_linestatus], aggr=[sum(lineitem.l_quantity),
sum(lineitem.l_extendedprice), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax), avg(lineitem.l_quantity),
avg(lineitem.l_extendedprice), avg(lineitem.l_discount), count(*)]
05)--------CoalesceBatchesExec: target_batch_size=8192
06)----------RepartitionExec: partitioning=Hash([l_returnflag@0,
l_linestatus@1], 4), input_partitions=4
-07)------------AggregateExec: mode=Partial, gby=[l_returnflag@5 as
l_returnflag, l_linestatus@6 as l_linestatus], aggr=[sum(lineitem.l_quantity),
sum(lineitem.l_extendedprice), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax), AVG(lineitem.l_quantity),
AVG(lineitem.l_extendedprice), AVG(lineitem.l_discount), count(*)]
+07)------------AggregateExec: mode=Partial, gby=[l_returnflag@5 as
l_returnflag, l_linestatus@6 as l_linestatus], aggr=[sum(lineitem.l_quantity),
sum(lineitem.l_extendedprice), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount), sum(lineitem.l_extendedprice * Int64(1) -
lineitem.l_discount * Int64(1) + lineitem.l_tax), avg(lineitem.l_quantity),
avg(lineitem.l_extendedprice), avg(lineitem.l_discount), count(*)]
08)--------------ProjectionExec: expr=[l_extendedprice@1 * (Some(1),20,0 -
l_discount@2) as __common_expr_1, l_quantity@0 as l_quantity, l_extendedprice@1
as l_extendedprice, l_discount@2 as l_discount, l_tax@3 as l_tax,
l_returnflag@4 as l_returnflag, l_linestatus@5 as l_linestatus]
09)----------------CoalesceBatchesExec: target_batch_size=8192
10)------------------FilterExec: l_shipdate@6 <= 1998-09-02
diff --git a/datafusion/sqllogictest/test_files/tpch/q17.slt.part
b/datafusion/sqllogictest/test_files/tpch/q17.slt.part
index b1562301d9..ecb54e97b9 100644
--- a/datafusion/sqllogictest/test_files/tpch/q17.slt.part
+++ b/datafusion/sqllogictest/test_files/tpch/q17.slt.part
@@ -39,7 +39,7 @@ logical_plan
01)Projection: CAST(sum(lineitem.l_extendedprice) AS Float64) / Float64(7) AS
avg_yearly
02)--Aggregate: groupBy=[[]], aggr=[[sum(lineitem.l_extendedprice)]]
03)----Projection: lineitem.l_extendedprice
-04)------Inner Join: part.p_partkey = __scalar_sq_1.l_partkey Filter:
CAST(lineitem.l_quantity AS Decimal128(30, 15)) < __scalar_sq_1.Float64(0.2) *
AVG(lineitem.l_quantity)
+04)------Inner Join: part.p_partkey = __scalar_sq_1.l_partkey Filter:
CAST(lineitem.l_quantity AS Decimal128(30, 15)) < __scalar_sq_1.Float64(0.2) *
avg(lineitem.l_quantity)
05)--------Projection: lineitem.l_quantity, lineitem.l_extendedprice,
part.p_partkey
06)----------Inner Join: lineitem.l_partkey = part.p_partkey
07)------------TableScan: lineitem projection=[l_partkey, l_quantity,
l_extendedprice]
@@ -47,8 +47,8 @@ logical_plan
09)--------------Filter: part.p_brand = Utf8("Brand#23") AND part.p_container
= Utf8("MED BOX")
10)----------------TableScan: part projection=[p_partkey, p_brand,
p_container], partial_filters=[part.p_brand = Utf8("Brand#23"),
part.p_container = Utf8("MED BOX")]
11)--------SubqueryAlias: __scalar_sq_1
-12)----------Projection: CAST(Float64(0.2) * CAST(AVG(lineitem.l_quantity) AS
Float64) AS Decimal128(30, 15)), lineitem.l_partkey
-13)------------Aggregate: groupBy=[[lineitem.l_partkey]],
aggr=[[AVG(lineitem.l_quantity)]]
+12)----------Projection: CAST(Float64(0.2) * CAST(avg(lineitem.l_quantity) AS
Float64) AS Decimal128(30, 15)), lineitem.l_partkey
+13)------------Aggregate: groupBy=[[lineitem.l_partkey]],
aggr=[[avg(lineitem.l_quantity)]]
14)--------------TableScan: lineitem projection=[l_partkey, l_quantity]
physical_plan
01)ProjectionExec: expr=[CAST(sum(lineitem.l_extendedprice)@0 AS Float64) / 7
as avg_yearly]
@@ -56,7 +56,7 @@ physical_plan
03)----CoalescePartitionsExec
04)------AggregateExec: mode=Partial, gby=[],
aggr=[sum(lineitem.l_extendedprice)]
05)--------CoalesceBatchesExec: target_batch_size=8192
-06)----------HashJoinExec: mode=Partitioned, join_type=Inner,
on=[(p_partkey@2, l_partkey@1)], filter=CAST(l_quantity@0 AS Decimal128(30,
15)) < Float64(0.2) * AVG(lineitem.l_quantity)@1, projection=[l_extendedprice@1]
+06)----------HashJoinExec: mode=Partitioned, join_type=Inner,
on=[(p_partkey@2, l_partkey@1)], filter=CAST(l_quantity@0 AS Decimal128(30,
15)) < Float64(0.2) * avg(lineitem.l_quantity)@1, projection=[l_extendedprice@1]
07)------------CoalesceBatchesExec: target_batch_size=8192
08)--------------HashJoinExec: mode=Partitioned, join_type=Inner,
on=[(l_partkey@0, p_partkey@0)], projection=[l_quantity@1, l_extendedprice@2,
p_partkey@3]
09)----------------CoalesceBatchesExec: target_batch_size=8192
@@ -69,11 +69,11 @@ physical_plan
16)------------------------FilterExec: p_brand@1 = Brand#23 AND p_container@2
= MED BOX
17)--------------------------RepartitionExec: partitioning=RoundRobinBatch(4),
input_partitions=1
18)----------------------------CsvExec: file_groups={1 group:
[[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/part.tbl]]},
projection=[p_partkey, p_brand, p_container], has_header=false
-19)------------ProjectionExec: expr=[CAST(0.2 *
CAST(AVG(lineitem.l_quantity)@1 AS Float64) AS Decimal128(30, 15)) as
Float64(0.2) * AVG(lineitem.l_quantity), l_partkey@0 as l_partkey]
-20)--------------AggregateExec: mode=FinalPartitioned, gby=[l_partkey@0 as
l_partkey], aggr=[AVG(lineitem.l_quantity)]
+19)------------ProjectionExec: expr=[CAST(0.2 *
CAST(avg(lineitem.l_quantity)@1 AS Float64) AS Decimal128(30, 15)) as
Float64(0.2) * avg(lineitem.l_quantity), l_partkey@0 as l_partkey]
+20)--------------AggregateExec: mode=FinalPartitioned, gby=[l_partkey@0 as
l_partkey], aggr=[avg(lineitem.l_quantity)]
21)----------------CoalesceBatchesExec: target_batch_size=8192
22)------------------RepartitionExec: partitioning=Hash([l_partkey@0], 4),
input_partitions=4
-23)--------------------AggregateExec: mode=Partial, gby=[l_partkey@0 as
l_partkey], aggr=[AVG(lineitem.l_quantity)]
+23)--------------------AggregateExec: mode=Partial, gby=[l_partkey@0 as
l_partkey], aggr=[avg(lineitem.l_quantity)]
24)----------------------CsvExec: file_groups={4 groups:
[[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/lineitem.tbl:0..18561749],
[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/lineitem.tbl:18561749..37123498],
[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/lineitem.tbl:37123498..55685247],
[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/lineitem.tbl:55685247..74246996]]},
projection=[l_partkey, l_quantity], has_header=false
diff --git a/datafusion/sqllogictest/test_files/tpch/q22.slt.part
b/datafusion/sqllogictest/test_files/tpch/q22.slt.part
index 5b39c2725a..b3bfc32964 100644
--- a/datafusion/sqllogictest/test_files/tpch/q22.slt.part
+++ b/datafusion/sqllogictest/test_files/tpch/q22.slt.part
@@ -61,7 +61,7 @@ logical_plan
03)----Aggregate: groupBy=[[custsale.cntrycode]], aggr=[[count(Int64(1)) AS
count(*), sum(custsale.c_acctbal)]]
04)------SubqueryAlias: custsale
05)--------Projection: substr(customer.c_phone, Int64(1), Int64(2)) AS
cntrycode, customer.c_acctbal
-06)----------Inner Join: Filter: CAST(customer.c_acctbal AS Decimal128(19,
6)) > __scalar_sq_2.AVG(customer.c_acctbal)
+06)----------Inner Join: Filter: CAST(customer.c_acctbal AS Decimal128(19,
6)) > __scalar_sq_2.avg(customer.c_acctbal)
07)------------Projection: customer.c_phone, customer.c_acctbal
08)--------------LeftAnti Join: customer.c_custkey =
__correlated_sq_1.o_custkey
09)----------------Filter: substr(customer.c_phone, Int64(1), Int64(2)) IN
([Utf8("13"), Utf8("31"), Utf8("23"), Utf8("29"), Utf8("30"), Utf8("18"),
Utf8("17")])
@@ -69,7 +69,7 @@ logical_plan
11)----------------SubqueryAlias: __correlated_sq_1
12)------------------TableScan: orders projection=[o_custkey]
13)------------SubqueryAlias: __scalar_sq_2
-14)--------------Aggregate: groupBy=[[]], aggr=[[AVG(customer.c_acctbal)]]
+14)--------------Aggregate: groupBy=[[]], aggr=[[avg(customer.c_acctbal)]]
15)----------------Projection: customer.c_acctbal
16)------------------Filter: customer.c_acctbal > Decimal128(Some(0),15,2) AND
substr(customer.c_phone, Int64(1), Int64(2)) IN ([Utf8("13"), Utf8("31"),
Utf8("23"), Utf8("29"), Utf8("30"), Utf8("18"), Utf8("17")])
17)--------------------TableScan: customer projection=[c_phone, c_acctbal],
partial_filters=[customer.c_acctbal > Decimal128(Some(0),15,2) AS
customer.c_acctbal > Decimal128(Some(0),30,15), substr(customer.c_phone,
Int64(1), Int64(2)) IN ([Utf8("13"), Utf8("31"), Utf8("23"), Utf8("29"),
Utf8("30"), Utf8("18"), Utf8("17")]), customer.c_acctbal >
Decimal128(Some(0),15,2)]
@@ -83,7 +83,7 @@ physical_plan
07)------------AggregateExec: mode=Partial, gby=[cntrycode@0 as cntrycode],
aggr=[count(*), sum(custsale.c_acctbal)]
08)--------------ProjectionExec: expr=[substr(c_phone@0, 1, 2) as cntrycode,
c_acctbal@1 as c_acctbal]
09)----------------RepartitionExec: partitioning=RoundRobinBatch(4),
input_partitions=1
-10)------------------NestedLoopJoinExec: join_type=Inner,
filter=CAST(c_acctbal@0 AS Decimal128(19, 6)) > AVG(customer.c_acctbal)@1
+10)------------------NestedLoopJoinExec: join_type=Inner,
filter=CAST(c_acctbal@0 AS Decimal128(19, 6)) > avg(customer.c_acctbal)@1
11)--------------------CoalescePartitionsExec
12)----------------------CoalesceBatchesExec: target_batch_size=8192
13)------------------------HashJoinExec: mode=Partitioned, join_type=LeftAnti,
on=[(c_custkey@0, o_custkey@0)], projection=[c_phone@1, c_acctbal@2]
@@ -96,9 +96,9 @@ physical_plan
20)--------------------------CoalesceBatchesExec: target_batch_size=8192
21)----------------------------RepartitionExec:
partitioning=Hash([o_custkey@0], 4), input_partitions=4
22)------------------------------CsvExec: file_groups={4 groups:
[[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/orders.tbl:0..4223281],
[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/orders.tbl:4223281..8446562],
[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/orders.tbl:8446562..12669843],
[WORKSPACE_ROOT/datafusion/sqllogictest/test_files/tpch/data/orders.tbl:12669843..16893122]]},
projection=[o_custkey], has_header=false
-23)--------------------AggregateExec: mode=Final, gby=[],
aggr=[AVG(customer.c_acctbal)]
+23)--------------------AggregateExec: mode=Final, gby=[],
aggr=[avg(customer.c_acctbal)]
24)----------------------CoalescePartitionsExec
-25)------------------------AggregateExec: mode=Partial, gby=[],
aggr=[AVG(customer.c_acctbal)]
+25)------------------------AggregateExec: mode=Partial, gby=[],
aggr=[avg(customer.c_acctbal)]
26)--------------------------ProjectionExec: expr=[c_acctbal@1 as c_acctbal]
27)----------------------------CoalesceBatchesExec: target_batch_size=8192
28)------------------------------FilterExec: c_acctbal@1 > Some(0),15,2 AND
Use substr(c_phone@0, 1, 2) IN (SET) ([Literal { value: Utf8("13") }, Literal {
value: Utf8("31") }, Literal { value: Utf8("23") }, Literal { value: Utf8("29")
}, Literal { value: Utf8("30") }, Literal { value: Utf8("18") }, Literal {
value: Utf8("17") }])
diff --git a/datafusion/sqllogictest/test_files/window.slt
b/datafusion/sqllogictest/test_files/window.slt
index d63917a78e..e6f3e70c1e 100644
--- a/datafusion/sqllogictest/test_files/window.slt
+++ b/datafusion/sqllogictest/test_files/window.slt
@@ -2727,8 +2727,8 @@ EXPLAIN SELECT
MAX(inc_col) OVER(ORDER BY ts DESC RANGE BETWEEN 3 PRECEDING AND UNBOUNDED
FOLLOWING) as max2,
COUNT(inc_col) OVER(ORDER BY ts ASC RANGE BETWEEN UNBOUNDED PRECEDING AND 5
FOLLOWING) as count1,
COUNT(inc_col) OVER(ORDER BY ts DESC RANGE BETWEEN 3 PRECEDING AND UNBOUNDED
FOLLOWING) as count2,
- AVG(inc_col) OVER(ORDER BY ts ASC RANGE BETWEEN UNBOUNDED PRECEDING AND 5
FOLLOWING) as avg1,
- AVG(inc_col) OVER(ORDER BY ts DESC RANGE BETWEEN 3 PRECEDING AND UNBOUNDED
FOLLOWING) as avg2
+ avg(inc_col) OVER(ORDER BY ts ASC RANGE BETWEEN UNBOUNDED PRECEDING AND 5
FOLLOWING) as avg1,
+ avg(inc_col) OVER(ORDER BY ts DESC RANGE BETWEEN 3 PRECEDING AND UNBOUNDED
FOLLOWING) as avg2
FROM annotated_data_finite
ORDER BY inc_col ASC
LIMIT 5
@@ -2737,18 +2737,18 @@ logical_plan
01)Projection: sum1, sum2, min1, min2, max1, max2, count1, count2, avg1, avg2
02)--Limit: skip=0, fetch=5
03)----Sort: annotated_data_finite.inc_col ASC NULLS LAST, fetch=5
-04)------Projection: sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING AS sum1, sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND
UNBOUNDED FOLLOWING AS sum2, MIN(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING AS min1, MIN(annotated_data_finite.inc_col) [...]
-05)--------WindowAggr: windowExpr=[[sum(__common_expr_1 AS
annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts ASC NULLS
LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND 5 FOLLOWING,
MIN(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts ASC NULLS
LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND 5 FOLLOWING,
MAX(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts ASC NULLS
LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND 5 FOLLOWING,
count(annotated_data_finit [...]
-06)----------WindowAggr: windowExpr=[[sum(__common_expr_1 AS
annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts DESC NULLS
FIRST] RANGE BETWEEN 3 PRECEDING AND UNBOUNDED FOLLOWING,
MIN(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts DESC
NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND UNBOUNDED FOLLOWING,
MAX(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts DESC
NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND UNBOUNDED FOLLOWING,
count(annotated_da [...]
+04)------Projection: sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING AS sum1, sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND
UNBOUNDED FOLLOWING AS sum2, MIN(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING AS min1, MIN(annotated_data_finite.inc_col) [...]
+05)--------WindowAggr: windowExpr=[[sum(__common_expr_1 AS
annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts ASC NULLS
LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND 5 FOLLOWING,
MIN(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts ASC NULLS
LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND 5 FOLLOWING,
MAX(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts ASC NULLS
LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND 5 FOLLOWING,
count(annotated_data_finit [...]
+06)----------WindowAggr: windowExpr=[[sum(__common_expr_1 AS
annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts DESC NULLS
FIRST] RANGE BETWEEN 3 PRECEDING AND UNBOUNDED FOLLOWING,
MIN(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts DESC
NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND UNBOUNDED FOLLOWING,
MAX(annotated_data_finite.inc_col) ORDER BY [annotated_data_finite.ts DESC
NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND UNBOUNDED FOLLOWING,
count(annotated_da [...]
07)------------Projection: CAST(annotated_data_finite.inc_col AS Int64) AS
__common_expr_1, CAST(annotated_data_finite.inc_col AS Float64) AS
__common_expr_2, annotated_data_finite.ts, annotated_data_finite.inc_col
08)--------------TableScan: annotated_data_finite projection=[ts, inc_col]
physical_plan
01)ProjectionExec: expr=[sum1@0 as sum1, sum2@1 as sum2, min1@2 as min1,
min2@3 as min2, max1@4 as max1, max2@5 as max2, count1@6 as count1, count2@7 as
count2, avg1@8 as avg1, avg2@9 as avg2]
02)--GlobalLimitExec: skip=0, fetch=5
03)----SortExec: TopK(fetch=5), expr=[inc_col@10 ASC NULLS LAST],
preserve_partitioning=[false]
-04)------ProjectionExec: expr=[sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING@9 as sum1, sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND
UNBOUNDED FOLLOWING@4 as sum2, MIN(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING@10 as min1, MIN(annotated_dat [...]
-05)--------BoundedWindowAggExec: wdw=[sum(annotated_data_finite.inc_col) ORDER
BY [annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING
AND 5 FOLLOWING: Ok(Field { name: "sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING", data_type: Int64, nullable: true, dict_id: 0, dict_is_ordered:
false, metadata: {} }), frame: WindowFrame { units: Range, start_bound:
Preceding(Int32(NULL)), en [...]
-06)----------BoundedWindowAggExec: wdw=[sum(annotated_data_finite.inc_col)
ORDER BY [annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING
AND UNBOUNDED FOLLOWING: Ok(Field { name: "sum(annotated_data_finite.inc_col)
ORDER BY [annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING
AND UNBOUNDED FOLLOWING", data_type: Int64, nullable: true, dict_id: 0,
dict_is_ordered: false, metadata: {} }), frame: WindowFrame { units: Range,
start_bound: Preceding(Int32(NULL [...]
+04)------ProjectionExec: expr=[sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING@9 as sum1, sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING AND
UNBOUNDED FOLLOWING@4 as sum2, MIN(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING@10 as min1, MIN(annotated_dat [...]
+05)--------BoundedWindowAggExec: wdw=[sum(annotated_data_finite.inc_col) ORDER
BY [annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING
AND 5 FOLLOWING: Ok(Field { name: "sum(annotated_data_finite.inc_col) ORDER BY
[annotated_data_finite.ts ASC NULLS LAST] RANGE BETWEEN UNBOUNDED PRECEDING AND
5 FOLLOWING", data_type: Int64, nullable: true, dict_id: 0, dict_is_ordered:
false, metadata: {} }), frame: WindowFrame { units: Range, start_bound:
Preceding(Int32(NULL)), en [...]
+06)----------BoundedWindowAggExec: wdw=[sum(annotated_data_finite.inc_col)
ORDER BY [annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING
AND UNBOUNDED FOLLOWING: Ok(Field { name: "sum(annotated_data_finite.inc_col)
ORDER BY [annotated_data_finite.ts DESC NULLS FIRST] RANGE BETWEEN 3 PRECEDING
AND UNBOUNDED FOLLOWING", data_type: Int64, nullable: true, dict_id: 0,
dict_is_ordered: false, metadata: {} }), frame: WindowFrame { units: Range,
start_bound: Preceding(Int32(NULL [...]
07)------------ProjectionExec: expr=[CAST(inc_col@1 AS Int64) as
__common_expr_1, CAST(inc_col@1 AS Float64) as __common_expr_2, ts@0 as ts,
inc_col@1 as inc_col]
08)--------------CsvExec: file_groups={1 group:
[[WORKSPACE_ROOT/datafusion/core/tests/data/window_1.csv]]}, projection=[ts,
inc_col], output_ordering=[ts@0 ASC NULLS LAST], has_header=true
@@ -3630,7 +3630,7 @@ set datafusion.execution.target_partitions = 2;
# we should still have the orderings [a ASC, b ASC], [c ASC].
query TT
EXPLAIN SELECT *,
- AVG(d) OVER sliding_window AS avg_d
+ avg(d) OVER sliding_window AS avg_d
FROM multiple_ordered_table_inf
WINDOW sliding_window AS (
PARTITION BY d
@@ -3640,13 +3640,13 @@ ORDER BY c
----
logical_plan
01)Sort: multiple_ordered_table_inf.c ASC NULLS LAST
-02)--Projection: multiple_ordered_table_inf.a0, multiple_ordered_table_inf.a,
multiple_ordered_table_inf.b, multiple_ordered_table_inf.c,
multiple_ordered_table_inf.d, AVG(multiple_ordered_table_inf.d) PARTITION BY
[multiple_ordered_table_inf.d] ORDER BY [multiple_ordered_table_inf.a ASC NULLS
LAST] RANGE BETWEEN 10 PRECEDING AND CURRENT ROW AS avg_d
-03)----WindowAggr: windowExpr=[[AVG(CAST(multiple_ordered_table_inf.d AS
Float64)) PARTITION BY [multiple_ordered_table_inf.d] ORDER BY
[multiple_ordered_table_inf.a ASC NULLS LAST] RANGE BETWEEN 10 PRECEDING AND
CURRENT ROW]]
+02)--Projection: multiple_ordered_table_inf.a0, multiple_ordered_table_inf.a,
multiple_ordered_table_inf.b, multiple_ordered_table_inf.c,
multiple_ordered_table_inf.d, avg(multiple_ordered_table_inf.d) PARTITION BY
[multiple_ordered_table_inf.d] ORDER BY [multiple_ordered_table_inf.a ASC NULLS
LAST] RANGE BETWEEN 10 PRECEDING AND CURRENT ROW AS avg_d
+03)----WindowAggr: windowExpr=[[avg(CAST(multiple_ordered_table_inf.d AS
Float64)) PARTITION BY [multiple_ordered_table_inf.d] ORDER BY
[multiple_ordered_table_inf.a ASC NULLS LAST] RANGE BETWEEN 10 PRECEDING AND
CURRENT ROW]]
04)------TableScan: multiple_ordered_table_inf projection=[a0, a, b, c, d]
physical_plan
01)SortPreservingMergeExec: [c@3 ASC NULLS LAST]
-02)--ProjectionExec: expr=[a0@0 as a0, a@1 as a, b@2 as b, c@3 as c, d@4 as d,
AVG(multiple_ordered_table_inf.d) PARTITION BY [multiple_ordered_table_inf.d]
ORDER BY [multiple_ordered_table_inf.a ASC NULLS LAST] RANGE BETWEEN 10
PRECEDING AND CURRENT ROW@5 as avg_d]
-03)----BoundedWindowAggExec: wdw=[AVG(multiple_ordered_table_inf.d) PARTITION
BY [multiple_ordered_table_inf.d] ORDER BY [multiple_ordered_table_inf.a ASC
NULLS LAST] RANGE BETWEEN 10 PRECEDING AND CURRENT ROW: Ok(Field { name:
"AVG(multiple_ordered_table_inf.d) PARTITION BY [multiple_ordered_table_inf.d]
ORDER BY [multiple_ordered_table_inf.a ASC NULLS LAST] RANGE BETWEEN 10
PRECEDING AND CURRENT ROW", data_type: Float64, nullable: true, dict_id: 0,
dict_is_ordered: false, metadata: {} [...]
+02)--ProjectionExec: expr=[a0@0 as a0, a@1 as a, b@2 as b, c@3 as c, d@4 as d,
avg(multiple_ordered_table_inf.d) PARTITION BY [multiple_ordered_table_inf.d]
ORDER BY [multiple_ordered_table_inf.a ASC NULLS LAST] RANGE BETWEEN 10
PRECEDING AND CURRENT ROW@5 as avg_d]
+03)----BoundedWindowAggExec: wdw=[avg(multiple_ordered_table_inf.d) PARTITION
BY [multiple_ordered_table_inf.d] ORDER BY [multiple_ordered_table_inf.a ASC
NULLS LAST] RANGE BETWEEN 10 PRECEDING AND CURRENT ROW: Ok(Field { name:
"avg(multiple_ordered_table_inf.d) PARTITION BY [multiple_ordered_table_inf.d]
ORDER BY [multiple_ordered_table_inf.a ASC NULLS LAST] RANGE BETWEEN 10
PRECEDING AND CURRENT ROW", data_type: Float64, nullable: true, dict_id: 0,
dict_is_ordered: false, metadata: {} [...]
04)------CoalesceBatchesExec: target_batch_size=4096
05)--------RepartitionExec: partitioning=Hash([d@4], 2), input_partitions=2,
preserve_order=true, sort_exprs=a@1 ASC NULLS LAST,b@2 ASC NULLS LAST,c@3 ASC
NULLS LAST
06)----------RepartitionExec: partitioning=RoundRobinBatch(2),
input_partitions=1
diff --git a/datafusion/substrait/tests/cases/consumer_integration.rs
b/datafusion/substrait/tests/cases/consumer_integration.rs
index 975cc150d7..8ea3a69cab 100644
--- a/datafusion/substrait/tests/cases/consumer_integration.rs
+++ b/datafusion/substrait/tests/cases/consumer_integration.rs
@@ -46,9 +46,9 @@ mod tests {
let plan_str = format!("{:?}", plan);
assert_eq!(
plan_str,
- "Projection: FILENAME_PLACEHOLDER_0.l_returnflag AS L_RETURNFLAG,
FILENAME_PLACEHOLDER_0.l_linestatus AS L_LINESTATUS,
sum(FILENAME_PLACEHOLDER_0.l_quantity) AS SUM_QTY,
sum(FILENAME_PLACEHOLDER_0.l_extendedprice) AS SUM_BASE_PRICE,
sum(FILENAME_PLACEHOLDER_0.l_extendedprice * Int32(1) -
FILENAME_PLACEHOLDER_0.l_discount) AS SUM_DISC_PRICE,
sum(FILENAME_PLACEHOLDER_0.l_extendedprice * Int32(1) -
FILENAME_PLACEHOLDER_0.l_discount * Int32(1) + FILENAME_PLACEHOLDER_0.l_tax) AS
S [...]
+ "Projection: FILENAME_PLACEHOLDER_0.l_returnflag AS L_RETURNFLAG,
FILENAME_PLACEHOLDER_0.l_linestatus AS L_LINESTATUS,
sum(FILENAME_PLACEHOLDER_0.l_quantity) AS SUM_QTY,
sum(FILENAME_PLACEHOLDER_0.l_extendedprice) AS SUM_BASE_PRICE,
sum(FILENAME_PLACEHOLDER_0.l_extendedprice * Int32(1) -
FILENAME_PLACEHOLDER_0.l_discount) AS SUM_DISC_PRICE,
sum(FILENAME_PLACEHOLDER_0.l_extendedprice * Int32(1) -
FILENAME_PLACEHOLDER_0.l_discount * Int32(1) + FILENAME_PLACEHOLDER_0.l_tax) AS
S [...]
\n Sort: FILENAME_PLACEHOLDER_0.l_returnflag ASC NULLS LAST,
FILENAME_PLACEHOLDER_0.l_linestatus ASC NULLS LAST\
- \n Aggregate: groupBy=[[FILENAME_PLACEHOLDER_0.l_returnflag,
FILENAME_PLACEHOLDER_0.l_linestatus]],
aggr=[[sum(FILENAME_PLACEHOLDER_0.l_quantity),
sum(FILENAME_PLACEHOLDER_0.l_extendedprice),
sum(FILENAME_PLACEHOLDER_0.l_extendedprice * Int32(1) -
FILENAME_PLACEHOLDER_0.l_discount), sum(FILENAME_PLACEHOLDER_0.l_extendedprice
* Int32(1) - FILENAME_PLACEHOLDER_0.l_discount * Int32(1) +
FILENAME_PLACEHOLDER_0.l_tax), AVG(FILENAME_PLACEHOLDER_0.l_quantity),
AVG(FILENAME_PLACE [...]
+ \n Aggregate: groupBy=[[FILENAME_PLACEHOLDER_0.l_returnflag,
FILENAME_PLACEHOLDER_0.l_linestatus]],
aggr=[[sum(FILENAME_PLACEHOLDER_0.l_quantity),
sum(FILENAME_PLACEHOLDER_0.l_extendedprice),
sum(FILENAME_PLACEHOLDER_0.l_extendedprice * Int32(1) -
FILENAME_PLACEHOLDER_0.l_discount), sum(FILENAME_PLACEHOLDER_0.l_extendedprice
* Int32(1) - FILENAME_PLACEHOLDER_0.l_discount * Int32(1) +
FILENAME_PLACEHOLDER_0.l_tax), avg(FILENAME_PLACEHOLDER_0.l_quantity),
avg(FILENAME_PLACE [...]
\n Projection: FILENAME_PLACEHOLDER_0.l_returnflag,
FILENAME_PLACEHOLDER_0.l_linestatus, FILENAME_PLACEHOLDER_0.l_quantity,
FILENAME_PLACEHOLDER_0.l_extendedprice, FILENAME_PLACEHOLDER_0.l_extendedprice
* (CAST(Int32(1) AS Decimal128(19, 0)) - FILENAME_PLACEHOLDER_0.l_discount),
FILENAME_PLACEHOLDER_0.l_extendedprice * (CAST(Int32(1) AS Decimal128(19, 0)) -
FILENAME_PLACEHOLDER_0.l_discount) * (CAST(Int32(1) AS Decimal128(19, 0)) +
FILENAME_PLACEHOLDER_0.l_tax), FILENAM [...]
\n Filter: FILENAME_PLACEHOLDER_0.l_shipdate <=
Date32(\"1998-12-01\") - IntervalDayTime(\"IntervalDayTime { days: 120,
milliseconds: 0 }\")\
\n TableScan: FILENAME_PLACEHOLDER_0
projection=[l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity,
l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate,
l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment]"
diff --git a/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs
b/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs
index d236d34c9d..922e3e16c8 100644
--- a/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs
+++ b/datafusion/substrait/tests/cases/roundtrip_logical_plan.rs
@@ -239,7 +239,7 @@ async fn aggregate_grouping_sets() -> Result<()> {
async fn aggregate_grouping_rollup() -> Result<()> {
assert_expected_plan(
"SELECT a, c, e, avg(b) FROM data GROUP BY ROLLUP (a, c, e)",
- "Aggregate: groupBy=[[GROUPING SETS ((data.a, data.c, data.e),
(data.a, data.c), (data.a), ())]], aggr=[[AVG(data.b)]]\
+ "Aggregate: groupBy=[[GROUPING SETS ((data.a, data.c, data.e),
(data.a, data.c), (data.a), ())]], aggr=[[avg(data.b)]]\
\n TableScan: data projection=[a, b, c, e]",
true
).await
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]