This is an automated email from the ASF dual-hosted git repository.
jayzhan 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 bf51babc9c Optionally create name of aggregate expression from
expressions (#11776)
bf51babc9c is described below
commit bf51babc9c7dc3e95476f84169646b4452fb9799
Author: 张林伟 <[email protected]>
AuthorDate: Tue Aug 6 13:05:55 2024 +0800
Optionally create name of aggregate expression from expressions (#11776)
* Optionally create name of aggregate expression from expressions
* Fix test
* name -> alias
* keep trying to create aggr expr's display name first
---
.../combine_partial_final_agg.rs | 4 +-
datafusion/core/src/physical_planner.rs | 272 +--------------------
datafusion/core/src/test_util/mod.rs | 2 +-
datafusion/core/tests/fuzz_cases/aggregate_fuzz.rs | 2 +-
datafusion/expr/src/expr.rs | 262 +++++++++++++++++++-
.../physical-expr-common/src/aggregate/mod.rs | 40 ++-
datafusion/physical-plan/src/aggregates/mod.rs | 52 ++--
datafusion/physical-plan/src/windows/mod.rs | 2 +-
datafusion/proto/src/physical_plan/mod.rs | 2 +-
.../proto/tests/cases/roundtrip_physical_plan.rs | 20 +-
10 files changed, 337 insertions(+), 321 deletions(-)
diff --git
a/datafusion/core/src/physical_optimizer/combine_partial_final_agg.rs
b/datafusion/core/src/physical_optimizer/combine_partial_final_agg.rs
index 6f3274820c..843efcc7b0 100644
--- a/datafusion/core/src/physical_optimizer/combine_partial_final_agg.rs
+++ b/datafusion/core/src/physical_optimizer/combine_partial_final_agg.rs
@@ -280,7 +280,7 @@ mod tests {
) -> Arc<dyn AggregateExpr> {
AggregateExprBuilder::new(count_udaf(), vec![expr])
.schema(Arc::new(schema.clone()))
- .name(name)
+ .alias(name)
.build()
.unwrap()
}
@@ -364,7 +364,7 @@ mod tests {
vec![
AggregateExprBuilder::new(sum_udaf(), vec![col("b", &schema)?])
.schema(Arc::clone(&schema))
- .name("Sum(b)")
+ .alias("Sum(b)")
.build()
.unwrap(),
];
diff --git a/datafusion/core/src/physical_planner.rs
b/datafusion/core/src/physical_planner.rs
index 378a892111..65cdbf9fe6 100644
--- a/datafusion/core/src/physical_planner.rs
+++ b/datafusion/core/src/physical_planner.rs
@@ -19,7 +19,6 @@
use std::borrow::Cow;
use std::collections::HashMap;
-use std::fmt::Write;
use std::sync::Arc;
use crate::datasource::file_format::file_type_to_format;
@@ -74,11 +73,9 @@ use datafusion_common::{
};
use datafusion_expr::dml::CopyTo;
use datafusion_expr::expr::{
- self, AggregateFunction, Alias, Between, BinaryExpr, Cast, GroupingSet,
InList, Like,
- TryCast, WindowFunction,
+ self, physical_name, AggregateFunction, Alias, GroupingSet, WindowFunction,
};
use datafusion_expr::expr_rewriter::unnormalize_cols;
-use datafusion_expr::expr_vec_fmt;
use
datafusion_expr::logical_plan::builder::wrap_projection_for_join_if_necessary;
use datafusion_expr::{
DescribeTable, DmlStatement, Extension, Filter, RecursiveQuery,
StringifiedPlan,
@@ -97,265 +94,6 @@ use log::{debug, trace};
use sqlparser::ast::NullTreatment;
use tokio::sync::Mutex;
-fn create_function_physical_name(
- fun: &str,
- distinct: bool,
- args: &[Expr],
- order_by: Option<&Vec<Expr>>,
-) -> Result<String> {
- let names: Vec<String> = args
- .iter()
- .map(|e| create_physical_name(e, false))
- .collect::<Result<_>>()?;
-
- let distinct_str = match distinct {
- true => "DISTINCT ",
- false => "",
- };
-
- let phys_name = format!("{}({}{})", fun, distinct_str, names.join(","));
-
- Ok(order_by
- .map(|order_by| format!("{} ORDER BY [{}]", phys_name,
expr_vec_fmt!(order_by)))
- .unwrap_or(phys_name))
-}
-
-fn physical_name(e: &Expr) -> Result<String> {
- create_physical_name(e, true)
-}
-
-fn create_physical_name(e: &Expr, is_first_expr: bool) -> Result<String> {
- match e {
- Expr::Unnest(_) => {
- internal_err!(
- "Expr::Unnest should have been converted to
LogicalPlan::Unnest"
- )
- }
- Expr::Column(c) => {
- if is_first_expr {
- Ok(c.name.clone())
- } else {
- Ok(c.flat_name())
- }
- }
- Expr::Alias(Alias { name, .. }) => Ok(name.clone()),
- Expr::ScalarVariable(_, variable_names) =>
Ok(variable_names.join(".")),
- Expr::Literal(value) => Ok(format!("{value:?}")),
- Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
- let left = create_physical_name(left, false)?;
- let right = create_physical_name(right, false)?;
- Ok(format!("{left} {op} {right}"))
- }
- Expr::Case(case) => {
- let mut name = "CASE ".to_string();
- if let Some(e) = &case.expr {
- let _ = write!(name, "{} ", create_physical_name(e, false)?);
- }
- for (w, t) in &case.when_then_expr {
- let _ = write!(
- name,
- "WHEN {} THEN {} ",
- create_physical_name(w, false)?,
- create_physical_name(t, false)?
- );
- }
- if let Some(e) = &case.else_expr {
- let _ = write!(name, "ELSE {} ", create_physical_name(e,
false)?);
- }
- name += "END";
- Ok(name)
- }
- Expr::Cast(Cast { expr, .. }) => {
- // CAST does not change the expression name
- create_physical_name(expr, false)
- }
- Expr::TryCast(TryCast { expr, .. }) => {
- // CAST does not change the expression name
- create_physical_name(expr, false)
- }
- Expr::Not(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("NOT {expr}"))
- }
- Expr::Negative(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("(- {expr})"))
- }
- Expr::IsNull(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS NULL"))
- }
- Expr::IsNotNull(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS NOT NULL"))
- }
- Expr::IsTrue(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS TRUE"))
- }
- Expr::IsFalse(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS FALSE"))
- }
- Expr::IsUnknown(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS UNKNOWN"))
- }
- Expr::IsNotTrue(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS NOT TRUE"))
- }
- Expr::IsNotFalse(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS NOT FALSE"))
- }
- Expr::IsNotUnknown(expr) => {
- let expr = create_physical_name(expr, false)?;
- Ok(format!("{expr} IS NOT UNKNOWN"))
- }
- Expr::ScalarFunction(fun) => fun.func.display_name(&fun.args),
- Expr::WindowFunction(WindowFunction {
- fun,
- args,
- order_by,
- ..
- }) => {
- create_function_physical_name(&fun.to_string(), false, args,
Some(order_by))
- }
- Expr::AggregateFunction(AggregateFunction {
- func,
- distinct,
- args,
- filter: _,
- order_by,
- null_treatment: _,
- }) => {
- create_function_physical_name(func.name(), *distinct, args,
order_by.as_ref())
- }
- Expr::GroupingSet(grouping_set) => match grouping_set {
- GroupingSet::Rollup(exprs) => Ok(format!(
- "ROLLUP ({})",
- exprs
- .iter()
- .map(|e| create_physical_name(e, false))
- .collect::<Result<Vec<_>>>()?
- .join(", ")
- )),
- GroupingSet::Cube(exprs) => Ok(format!(
- "CUBE ({})",
- exprs
- .iter()
- .map(|e| create_physical_name(e, false))
- .collect::<Result<Vec<_>>>()?
- .join(", ")
- )),
- GroupingSet::GroupingSets(lists_of_exprs) => {
- let mut strings = vec![];
- for exprs in lists_of_exprs {
- let exprs_str = exprs
- .iter()
- .map(|e| create_physical_name(e, false))
- .collect::<Result<Vec<_>>>()?
- .join(", ");
- strings.push(format!("({exprs_str})"));
- }
- Ok(format!("GROUPING SETS ({})", strings.join(", ")))
- }
- },
-
- Expr::InList(InList {
- expr,
- list,
- negated,
- }) => {
- let expr = create_physical_name(expr, false)?;
- let list = list.iter().map(|expr| create_physical_name(expr,
false));
- if *negated {
- Ok(format!("{expr} NOT IN ({list:?})"))
- } else {
- Ok(format!("{expr} IN ({list:?})"))
- }
- }
- Expr::Exists { .. } => {
- not_impl_err!("EXISTS is not yet supported in the physical plan")
- }
- Expr::InSubquery(_) => {
- not_impl_err!("IN subquery is not yet supported in the physical
plan")
- }
- Expr::ScalarSubquery(_) => {
- not_impl_err!("Scalar subqueries are not yet supported in the
physical plan")
- }
- Expr::Between(Between {
- expr,
- negated,
- low,
- high,
- }) => {
- let expr = create_physical_name(expr, false)?;
- let low = create_physical_name(low, false)?;
- let high = create_physical_name(high, false)?;
- if *negated {
- Ok(format!("{expr} NOT BETWEEN {low} AND {high}"))
- } else {
- Ok(format!("{expr} BETWEEN {low} AND {high}"))
- }
- }
- Expr::Like(Like {
- negated,
- expr,
- pattern,
- escape_char,
- case_insensitive,
- }) => {
- let expr = create_physical_name(expr, false)?;
- let pattern = create_physical_name(pattern, false)?;
- let op_name = if *case_insensitive { "ILIKE" } else { "LIKE" };
- let escape = if let Some(char) = escape_char {
- format!("CHAR '{char}'")
- } else {
- "".to_string()
- };
- if *negated {
- Ok(format!("{expr} NOT {op_name} {pattern}{escape}"))
- } else {
- Ok(format!("{expr} {op_name} {pattern}{escape}"))
- }
- }
- Expr::SimilarTo(Like {
- negated,
- expr,
- pattern,
- escape_char,
- case_insensitive: _,
- }) => {
- let expr = create_physical_name(expr, false)?;
- let pattern = create_physical_name(pattern, false)?;
- let escape = if let Some(char) = escape_char {
- format!("CHAR '{char}'")
- } else {
- "".to_string()
- };
- if *negated {
- Ok(format!("{expr} NOT SIMILAR TO {pattern}{escape}"))
- } else {
- Ok(format!("{expr} SIMILAR TO {pattern}{escape}"))
- }
- }
- Expr::Sort { .. } => {
- internal_err!("Create physical name does not support sort
expression")
- }
- Expr::Wildcard { .. } => {
- internal_err!("Create physical name does not support wildcard")
- }
- Expr::Placeholder(_) => {
- internal_err!("Create physical name does not support placeholder")
- }
- Expr::OuterReferenceColumn(_, _) => {
- internal_err!("Create physical name does not support
OuterReferenceColumn")
- }
- }
-}
-
/// Physical query planner that converts a `LogicalPlan` to an
/// `ExecutionPlan` suitable for execution.
#[async_trait]
@@ -1807,7 +1545,7 @@ type AggregateExprWithOptionalArgs = (
/// Create an aggregate expression with a name from a logical expression
pub fn create_aggregate_expr_with_name_and_maybe_filter(
e: &Expr,
- name: impl Into<String>,
+ name: Option<String>,
logical_input_schema: &DFSchema,
_physical_input_schema: &Schema,
execution_props: &ExecutionProps,
@@ -1881,9 +1619,9 @@ pub fn create_aggregate_expr_and_maybe_filter(
) -> Result<AggregateExprWithOptionalArgs> {
// unpack (nested) aliased logical expressions, e.g. "sum(col) as total"
let (name, e) = match e {
- Expr::Alias(Alias { expr, name, .. }) => (name.clone(), expr.as_ref()),
- Expr::AggregateFunction(_) =>
(e.display_name().unwrap_or(physical_name(e)?), e),
- _ => (physical_name(e)?, e),
+ Expr::Alias(Alias { expr, name, .. }) => (Some(name.clone()),
expr.as_ref()),
+ Expr::AggregateFunction(_) => (e.display_name().ok(), e),
+ _ => (None, e),
};
create_aggregate_expr_with_name_and_maybe_filter(
diff --git a/datafusion/core/src/test_util/mod.rs
b/datafusion/core/src/test_util/mod.rs
index 6eb82dece3..9610a7f203 100644
--- a/datafusion/core/src/test_util/mod.rs
+++ b/datafusion/core/src/test_util/mod.rs
@@ -432,7 +432,7 @@ impl TestAggregate {
pub fn count_expr(&self, schema: &Schema) -> Arc<dyn AggregateExpr> {
AggregateExprBuilder::new(count_udaf(), vec![self.column()])
.schema(Arc::new(schema.clone()))
- .name(self.column_name())
+ .alias(self.column_name())
.build()
.unwrap()
}
diff --git a/datafusion/core/tests/fuzz_cases/aggregate_fuzz.rs
b/datafusion/core/tests/fuzz_cases/aggregate_fuzz.rs
index 6f286c9aeb..4cecb0b693 100644
--- a/datafusion/core/tests/fuzz_cases/aggregate_fuzz.rs
+++ b/datafusion/core/tests/fuzz_cases/aggregate_fuzz.rs
@@ -107,7 +107,7 @@ async fn run_aggregate_test(input1: Vec<RecordBatch>,
group_by_columns: Vec<&str
vec![
AggregateExprBuilder::new(sum_udaf(), vec![col("d",
&schema).unwrap()])
.schema(Arc::clone(&schema))
- .name("sum1")
+ .alias("sum1")
.build()
.unwrap(),
];
diff --git a/datafusion/expr/src/expr.rs b/datafusion/expr/src/expr.rs
index 1a51c181f4..edf45a244e 100644
--- a/datafusion/expr/src/expr.rs
+++ b/datafusion/expr/src/expr.rs
@@ -38,7 +38,8 @@ use datafusion_common::tree_node::{
Transformed, TransformedResult, TreeNode, TreeNodeRecursion,
};
use datafusion_common::{
- internal_err, plan_err, Column, DFSchema, Result, ScalarValue,
TableReference,
+ internal_err, not_impl_err, plan_err, Column, DFSchema, Result,
ScalarValue,
+ TableReference,
};
use sqlparser::ast::NullTreatment;
@@ -2277,6 +2278,265 @@ fn write_names_join<W: Write>(w: &mut W, exprs:
&[Expr], sep: &str) -> Result<()
Ok(())
}
+pub fn create_function_physical_name(
+ fun: &str,
+ distinct: bool,
+ args: &[Expr],
+ order_by: Option<&Vec<Expr>>,
+) -> Result<String> {
+ let names: Vec<String> = args
+ .iter()
+ .map(|e| create_physical_name(e, false))
+ .collect::<Result<_>>()?;
+
+ let distinct_str = match distinct {
+ true => "DISTINCT ",
+ false => "",
+ };
+
+ let phys_name = format!("{}({}{})", fun, distinct_str, names.join(","));
+
+ Ok(order_by
+ .map(|order_by| format!("{} ORDER BY [{}]", phys_name,
expr_vec_fmt!(order_by)))
+ .unwrap_or(phys_name))
+}
+
+pub fn physical_name(e: &Expr) -> Result<String> {
+ create_physical_name(e, true)
+}
+
+fn create_physical_name(e: &Expr, is_first_expr: bool) -> Result<String> {
+ match e {
+ Expr::Unnest(_) => {
+ internal_err!(
+ "Expr::Unnest should have been converted to
LogicalPlan::Unnest"
+ )
+ }
+ Expr::Column(c) => {
+ if is_first_expr {
+ Ok(c.name.clone())
+ } else {
+ Ok(c.flat_name())
+ }
+ }
+ Expr::Alias(Alias { name, .. }) => Ok(name.clone()),
+ Expr::ScalarVariable(_, variable_names) =>
Ok(variable_names.join(".")),
+ Expr::Literal(value) => Ok(format!("{value:?}")),
+ Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
+ let left = create_physical_name(left, false)?;
+ let right = create_physical_name(right, false)?;
+ Ok(format!("{left} {op} {right}"))
+ }
+ Expr::Case(case) => {
+ let mut name = "CASE ".to_string();
+ if let Some(e) = &case.expr {
+ let _ = write!(name, "{} ", create_physical_name(e, false)?);
+ }
+ for (w, t) in &case.when_then_expr {
+ let _ = write!(
+ name,
+ "WHEN {} THEN {} ",
+ create_physical_name(w, false)?,
+ create_physical_name(t, false)?
+ );
+ }
+ if let Some(e) = &case.else_expr {
+ let _ = write!(name, "ELSE {} ", create_physical_name(e,
false)?);
+ }
+ name += "END";
+ Ok(name)
+ }
+ Expr::Cast(Cast { expr, .. }) => {
+ // CAST does not change the expression name
+ create_physical_name(expr, false)
+ }
+ Expr::TryCast(TryCast { expr, .. }) => {
+ // CAST does not change the expression name
+ create_physical_name(expr, false)
+ }
+ Expr::Not(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("NOT {expr}"))
+ }
+ Expr::Negative(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("(- {expr})"))
+ }
+ Expr::IsNull(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS NULL"))
+ }
+ Expr::IsNotNull(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS NOT NULL"))
+ }
+ Expr::IsTrue(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS TRUE"))
+ }
+ Expr::IsFalse(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS FALSE"))
+ }
+ Expr::IsUnknown(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS UNKNOWN"))
+ }
+ Expr::IsNotTrue(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS NOT TRUE"))
+ }
+ Expr::IsNotFalse(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS NOT FALSE"))
+ }
+ Expr::IsNotUnknown(expr) => {
+ let expr = create_physical_name(expr, false)?;
+ Ok(format!("{expr} IS NOT UNKNOWN"))
+ }
+ Expr::ScalarFunction(fun) => fun.func.display_name(&fun.args),
+ Expr::WindowFunction(WindowFunction {
+ fun,
+ args,
+ order_by,
+ ..
+ }) => {
+ create_function_physical_name(&fun.to_string(), false, args,
Some(order_by))
+ }
+ Expr::AggregateFunction(AggregateFunction {
+ func,
+ distinct,
+ args,
+ filter: _,
+ order_by,
+ null_treatment: _,
+ }) => {
+ create_function_physical_name(func.name(), *distinct, args,
order_by.as_ref())
+ }
+ Expr::GroupingSet(grouping_set) => match grouping_set {
+ GroupingSet::Rollup(exprs) => Ok(format!(
+ "ROLLUP ({})",
+ exprs
+ .iter()
+ .map(|e| create_physical_name(e, false))
+ .collect::<Result<Vec<_>>>()?
+ .join(", ")
+ )),
+ GroupingSet::Cube(exprs) => Ok(format!(
+ "CUBE ({})",
+ exprs
+ .iter()
+ .map(|e| create_physical_name(e, false))
+ .collect::<Result<Vec<_>>>()?
+ .join(", ")
+ )),
+ GroupingSet::GroupingSets(lists_of_exprs) => {
+ let mut strings = vec![];
+ for exprs in lists_of_exprs {
+ let exprs_str = exprs
+ .iter()
+ .map(|e| create_physical_name(e, false))
+ .collect::<Result<Vec<_>>>()?
+ .join(", ");
+ strings.push(format!("({exprs_str})"));
+ }
+ Ok(format!("GROUPING SETS ({})", strings.join(", ")))
+ }
+ },
+
+ Expr::InList(InList {
+ expr,
+ list,
+ negated,
+ }) => {
+ let expr = create_physical_name(expr, false)?;
+ let list = list.iter().map(|expr| create_physical_name(expr,
false));
+ if *negated {
+ Ok(format!("{expr} NOT IN ({list:?})"))
+ } else {
+ Ok(format!("{expr} IN ({list:?})"))
+ }
+ }
+ Expr::Exists { .. } => {
+ not_impl_err!("EXISTS is not yet supported in the physical plan")
+ }
+ Expr::InSubquery(_) => {
+ not_impl_err!("IN subquery is not yet supported in the physical
plan")
+ }
+ Expr::ScalarSubquery(_) => {
+ not_impl_err!("Scalar subqueries are not yet supported in the
physical plan")
+ }
+ Expr::Between(Between {
+ expr,
+ negated,
+ low,
+ high,
+ }) => {
+ let expr = create_physical_name(expr, false)?;
+ let low = create_physical_name(low, false)?;
+ let high = create_physical_name(high, false)?;
+ if *negated {
+ Ok(format!("{expr} NOT BETWEEN {low} AND {high}"))
+ } else {
+ Ok(format!("{expr} BETWEEN {low} AND {high}"))
+ }
+ }
+ Expr::Like(Like {
+ negated,
+ expr,
+ pattern,
+ escape_char,
+ case_insensitive,
+ }) => {
+ let expr = create_physical_name(expr, false)?;
+ let pattern = create_physical_name(pattern, false)?;
+ let op_name = if *case_insensitive { "ILIKE" } else { "LIKE" };
+ let escape = if let Some(char) = escape_char {
+ format!("CHAR '{char}'")
+ } else {
+ "".to_string()
+ };
+ if *negated {
+ Ok(format!("{expr} NOT {op_name} {pattern}{escape}"))
+ } else {
+ Ok(format!("{expr} {op_name} {pattern}{escape}"))
+ }
+ }
+ Expr::SimilarTo(Like {
+ negated,
+ expr,
+ pattern,
+ escape_char,
+ case_insensitive: _,
+ }) => {
+ let expr = create_physical_name(expr, false)?;
+ let pattern = create_physical_name(pattern, false)?;
+ let escape = if let Some(char) = escape_char {
+ format!("CHAR '{char}'")
+ } else {
+ "".to_string()
+ };
+ if *negated {
+ Ok(format!("{expr} NOT SIMILAR TO {pattern}{escape}"))
+ } else {
+ Ok(format!("{expr} SIMILAR TO {pattern}{escape}"))
+ }
+ }
+ Expr::Sort { .. } => {
+ internal_err!("Create physical name does not support sort
expression")
+ }
+ Expr::Wildcard { .. } => {
+ internal_err!("Create physical name does not support wildcard")
+ }
+ Expr::Placeholder(_) => {
+ internal_err!("Create physical name does not support placeholder")
+ }
+ Expr::OuterReferenceColumn(_, _) => {
+ internal_err!("Create physical name does not support
OuterReferenceColumn")
+ }
+ }
+}
+
#[cfg(test)]
mod test {
use crate::expr_fn::col;
diff --git a/datafusion/physical-expr-common/src/aggregate/mod.rs
b/datafusion/physical-expr-common/src/aggregate/mod.rs
index 665cdd7083..350023352b 100644
--- a/datafusion/physical-expr-common/src/aggregate/mod.rs
+++ b/datafusion/physical-expr-common/src/aggregate/mod.rs
@@ -22,6 +22,7 @@ use arrow::datatypes::{DataType, Field, Schema, SchemaRef};
use datafusion_common::exec_err;
use datafusion_common::{internal_err, not_impl_err, DFSchema, Result};
+use datafusion_expr::expr::create_function_physical_name;
use datafusion_expr::function::StateFieldsArgs;
use datafusion_expr::type_coercion::aggregates::check_arg_count;
use datafusion_expr::utils::AggregateOrderSensitivity;
@@ -67,7 +68,7 @@ pub fn create_aggregate_expr(
sort_exprs: &[Expr],
ordering_req: &[PhysicalSortExpr],
schema: &Schema,
- name: impl Into<String>,
+ name: Option<String>,
ignore_nulls: bool,
is_distinct: bool,
) -> Result<Arc<dyn AggregateExpr>> {
@@ -77,7 +78,9 @@ pub fn create_aggregate_expr(
builder = builder.order_by(ordering_req.to_vec());
builder = builder.logical_exprs(input_exprs.to_vec());
builder = builder.schema(Arc::new(schema.clone()));
- builder = builder.name(name);
+ if let Some(name) = name {
+ builder = builder.alias(name);
+ }
if ignore_nulls {
builder = builder.ignore_nulls();
@@ -98,7 +101,7 @@ pub fn create_aggregate_expr_with_dfschema(
sort_exprs: &[Expr],
ordering_req: &[PhysicalSortExpr],
dfschema: &DFSchema,
- name: impl Into<String>,
+ alias: Option<String>,
ignore_nulls: bool,
is_distinct: bool,
is_reversed: bool,
@@ -111,7 +114,9 @@ pub fn create_aggregate_expr_with_dfschema(
builder = builder.dfschema(dfschema.clone());
let schema: Schema = dfschema.into();
builder = builder.schema(Arc::new(schema));
- builder = builder.name(name);
+ if let Some(alias) = alias {
+ builder = builder.alias(alias);
+ }
if ignore_nulls {
builder = builder.ignore_nulls();
@@ -137,7 +142,7 @@ pub struct AggregateExprBuilder {
args: Vec<Arc<dyn PhysicalExpr>>,
/// Logical expressions of the aggregate function, it will be deprecated
in <https://github.com/apache/datafusion/issues/11359>
logical_args: Vec<Expr>,
- name: String,
+ alias: Option<String>,
/// Arrow Schema for the aggregate function
schema: SchemaRef,
/// Datafusion Schema for the aggregate function
@@ -160,7 +165,7 @@ impl AggregateExprBuilder {
fun,
args,
logical_args: vec![],
- name: String::new(),
+ alias: None,
schema: Arc::new(Schema::empty()),
dfschema: DFSchema::empty(),
sort_exprs: vec![],
@@ -176,7 +181,7 @@ impl AggregateExprBuilder {
fun,
args,
logical_args,
- name,
+ alias,
schema,
dfschema,
sort_exprs,
@@ -213,6 +218,19 @@ impl AggregateExprBuilder {
)?;
let data_type = fun.return_type(&input_exprs_types)?;
+ let name = match alias {
+ None => create_function_physical_name(
+ fun.name(),
+ is_distinct,
+ &logical_args,
+ if sort_exprs.is_empty() {
+ None
+ } else {
+ Some(&sort_exprs)
+ },
+ )?,
+ Some(alias) => alias,
+ };
Ok(Arc::new(AggregateFunctionExpr {
fun: Arc::unwrap_or_clone(fun),
@@ -232,8 +250,8 @@ impl AggregateExprBuilder {
}))
}
- pub fn name(mut self, name: impl Into<String>) -> Self {
- self.name = name.into();
+ pub fn alias(mut self, alias: impl Into<String>) -> Self {
+ self.alias = Some(alias.into());
self
}
@@ -680,7 +698,7 @@ impl AggregateExpr for AggregateFunctionExpr {
&self.sort_exprs,
&self.ordering_req,
&self.dfschema,
- self.name(),
+ Some(self.name().to_string()),
self.ignore_nulls,
self.is_distinct,
self.is_reversed,
@@ -721,7 +739,7 @@ impl AggregateExpr for AggregateFunctionExpr {
&reverse_sort_exprs,
&reverse_ordering_req,
&self.dfschema,
- name,
+ Some(name),
self.ignore_nulls,
self.is_distinct,
!self.is_reversed,
diff --git a/datafusion/physical-plan/src/aggregates/mod.rs
b/datafusion/physical-plan/src/aggregates/mod.rs
index 8941418c12..d72da9b300 100644
--- a/datafusion/physical-plan/src/aggregates/mod.rs
+++ b/datafusion/physical-plan/src/aggregates/mod.rs
@@ -1362,7 +1362,7 @@ mod tests {
let aggregates = vec![AggregateExprBuilder::new(count_udaf(),
vec![lit(1i8)])
.schema(Arc::clone(&input_schema))
- .name("COUNT(1)")
+ .alias("COUNT(1)")
.logical_exprs(vec![datafusion_expr::lit(1i8)])
.build()?];
@@ -1507,7 +1507,7 @@ mod tests {
vec![
AggregateExprBuilder::new(avg_udaf(), vec![col("b",
&input_schema)?])
.schema(Arc::clone(&input_schema))
- .name("AVG(b)")
+ .alias("AVG(b)")
.build()?,
];
@@ -1803,7 +1803,7 @@ mod tests {
fn test_median_agg_expr(schema: SchemaRef) -> Result<Arc<dyn
AggregateExpr>> {
AggregateExprBuilder::new(median_udaf(), vec![col("a", &schema)?])
.schema(schema)
- .name("MEDIAN(a)")
+ .alias("MEDIAN(a)")
.build()
}
@@ -1834,7 +1834,7 @@ mod tests {
vec![
AggregateExprBuilder::new(avg_udaf(), vec![col("b",
&input_schema)?])
.schema(Arc::clone(&input_schema))
- .name("AVG(b)")
+ .alias("AVG(b)")
.build()?,
];
@@ -1894,7 +1894,7 @@ mod tests {
vec![
AggregateExprBuilder::new(avg_udaf(), vec![col("a", &schema)?])
.schema(Arc::clone(&schema))
- .name("AVG(a)")
+ .alias("AVG(a)")
.build()?,
];
@@ -1934,7 +1934,7 @@ mod tests {
vec![
AggregateExprBuilder::new(avg_udaf(), vec![col("b", &schema)?])
.schema(Arc::clone(&schema))
- .name("AVG(b)")
+ .alias("AVG(b)")
.build()?,
];
@@ -2002,7 +2002,7 @@ mod tests {
&sort_exprs,
&ordering_req,
dfschema,
- "FIRST_VALUE(b)",
+ None,
false,
false,
false,
@@ -2034,7 +2034,7 @@ mod tests {
&sort_exprs,
&ordering_req,
dfschema,
- "LAST_VALUE(b)",
+ None,
false,
false,
false,
@@ -2130,24 +2130,24 @@ mod tests {
let result = crate::collect(aggregate_final, task_ctx).await?;
if is_first_acc {
let expected = [
- "+---+----------------+",
- "| a | FIRST_VALUE(b) |",
- "+---+----------------+",
- "| 2 | 0.0 |",
- "| 3 | 1.0 |",
- "| 4 | 3.0 |",
- "+---+----------------+",
+ "+---+--------------------------------------------+",
+ "| a | first_value(b) ORDER BY [b ASC NULLS LAST] |",
+ "+---+--------------------------------------------+",
+ "| 2 | 0.0 |",
+ "| 3 | 1.0 |",
+ "| 4 | 3.0 |",
+ "+---+--------------------------------------------+",
];
assert_batches_eq!(expected, &result);
} else {
let expected = [
- "+---+---------------+",
- "| a | LAST_VALUE(b) |",
- "+---+---------------+",
- "| 2 | 3.0 |",
- "| 3 | 5.0 |",
- "| 4 | 6.0 |",
- "+---+---------------+",
+ "+---+-------------------------------------------+",
+ "| a | last_value(b) ORDER BY [b ASC NULLS LAST] |",
+ "+---+-------------------------------------------+",
+ "| 2 | 3.0 |",
+ "| 3 | 5.0 |",
+ "| 4 | 6.0 |",
+ "+---+-------------------------------------------+",
];
assert_batches_eq!(expected, &result);
};
@@ -2267,7 +2267,7 @@ mod tests {
&sort_exprs,
&ordering_req,
&test_df_schema,
- "array_agg",
+ None,
false,
false,
false,
@@ -2363,7 +2363,7 @@ mod tests {
let aggregates: Vec<Arc<dyn AggregateExpr>> =
vec![AggregateExprBuilder::new(count_udaf(), vec![lit(1)])
.schema(Arc::clone(&schema))
- .name("1")
+ .alias("1")
.build()?];
let input_batches = (0..4)
@@ -2427,7 +2427,7 @@ mod tests {
&[],
&[],
&df_schema,
- "COUNT(val)",
+ Some("COUNT(val)".to_string()),
false,
false,
false,
@@ -2515,7 +2515,7 @@ mod tests {
&[],
&[],
&df_schema,
- "COUNT(val)",
+ Some("COUNT(val)".to_string()),
false,
false,
false,
diff --git a/datafusion/physical-plan/src/windows/mod.rs
b/datafusion/physical-plan/src/windows/mod.rs
index 65cef28efc..b41f3ad71b 100644
--- a/datafusion/physical-plan/src/windows/mod.rs
+++ b/datafusion/physical-plan/src/windows/mod.rs
@@ -128,7 +128,7 @@ pub fn create_window_expr(
let aggregate = AggregateExprBuilder::new(Arc::clone(fun),
args.to_vec())
.schema(Arc::new(input_schema.clone()))
- .name(name)
+ .alias(name)
.order_by(order_by.to_vec())
.sort_exprs(sort_exprs)
.with_ignore_nulls(ignore_nulls)
diff --git a/datafusion/proto/src/physical_plan/mod.rs
b/datafusion/proto/src/physical_plan/mod.rs
index aefa1d87a2..59db791c75 100644
--- a/datafusion/proto/src/physical_plan/mod.rs
+++ b/datafusion/proto/src/physical_plan/mod.rs
@@ -492,7 +492,7 @@ impl AsExecutionPlan for protobuf::PhysicalPlanNode {
//
https://github.com/apache/datafusion/issues/11804
AggregateExprBuilder::new(agg_udf,
input_phy_expr)
.schema(Arc::clone(&physical_schema))
- .name(name)
+ .alias(name)
.with_ignore_nulls(agg_node.ignore_nulls)
.with_distinct(agg_node.distinct)
.build()
diff --git a/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
b/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
index 0e2bc9cbb3..712182791b 100644
--- a/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
+++ b/datafusion/proto/tests/cases/roundtrip_physical_plan.rs
@@ -296,7 +296,7 @@ fn roundtrip_window() -> Result<()> {
vec![cast(col("b", &schema)?, &schema, DataType::Float64)?],
)
.schema(Arc::clone(&schema))
- .name("avg(b)")
+ .alias("avg(b)")
.build()?,
&[],
&[],
@@ -312,7 +312,7 @@ fn roundtrip_window() -> Result<()> {
let args = vec![cast(col("a", &schema)?, &schema, DataType::Float64)?];
let sum_expr = AggregateExprBuilder::new(sum_udaf(), args)
.schema(Arc::clone(&schema))
- .name("SUM(a) RANGE BETWEEN CURRENT ROW AND UNBOUNDED PRECEEDING")
+ .alias("SUM(a) RANGE BETWEEN CURRENT ROW AND UNBOUNDED PRECEEDING")
.build()?;
let sliding_aggr_window_expr = Arc::new(SlidingAggregateWindowExpr::new(
@@ -346,17 +346,17 @@ fn rountrip_aggregate() -> Result<()> {
let avg_expr = AggregateExprBuilder::new(avg_udaf(), vec![col("b",
&schema)?])
.schema(Arc::clone(&schema))
- .name("AVG(b)")
+ .alias("AVG(b)")
.build()?;
let nth_expr =
AggregateExprBuilder::new(nth_value_udaf(), vec![col("b", &schema)?,
lit(1u64)])
.schema(Arc::clone(&schema))
- .name("NTH_VALUE(b, 1)")
+ .alias("NTH_VALUE(b, 1)")
.build()?;
let str_agg_expr =
AggregateExprBuilder::new(string_agg_udaf(), vec![col("b", &schema)?,
lit(1u64)])
.schema(Arc::clone(&schema))
- .name("NTH_VALUE(b, 1)")
+ .alias("NTH_VALUE(b, 1)")
.build()?;
let test_cases: Vec<Vec<Arc<dyn AggregateExpr>>> = vec![
@@ -396,7 +396,7 @@ fn rountrip_aggregate_with_limit() -> Result<()> {
vec![
AggregateExprBuilder::new(avg_udaf(), vec![col("b", &schema)?])
.schema(Arc::clone(&schema))
- .name("AVG(b)")
+ .alias("AVG(b)")
.build()?,
];
@@ -463,7 +463,7 @@ fn roundtrip_aggregate_udaf() -> Result<()> {
vec![
AggregateExprBuilder::new(Arc::new(udaf), vec![col("b", &schema)?])
.schema(Arc::clone(&schema))
- .name("example_agg")
+ .alias("example_agg")
.build()?,
];
@@ -914,7 +914,7 @@ fn roundtrip_scalar_udf_extension_codec() -> Result<()> {
vec![udf_expr.clone() as Arc<dyn PhysicalExpr>],
)
.schema(schema.clone())
- .name("max")
+ .alias("max")
.build()?;
let window = Arc::new(WindowAggExec::try_new(
@@ -965,7 +965,7 @@ fn roundtrip_aggregate_udf_extension_codec() -> Result<()> {
let aggr_expr = AggregateExprBuilder::new(Arc::clone(&udaf),
aggr_args.clone())
.schema(Arc::clone(&schema))
- .name("aggregate_udf")
+ .alias("aggregate_udf")
.build()?;
let filter = Arc::new(FilterExec::try_new(
@@ -990,7 +990,7 @@ fn roundtrip_aggregate_udf_extension_codec() -> Result<()> {
let aggr_expr = AggregateExprBuilder::new(udaf, aggr_args.clone())
.schema(Arc::clone(&schema))
- .name("aggregate_udf")
+ .alias("aggregate_udf")
.distinct()
.ignore_nulls()
.build()?;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]