diff --git a/datafusion/core/src/physical_planner.rs b/datafusion/core/src/physical_planner.rs index dfcda553af7de..132bc3953cd3d 100644 --- a/datafusion/core/src/physical_planner.rs +++ b/datafusion/core/src/physical_planner.rs @@ -239,9 +239,7 @@ fn create_physical_name(e: &Expr, is_first_expr: bool) -> Result { } }; } - Expr::ScalarFunction(fun) => { - create_function_physical_name(fun.name(), false, &fun.args, None) - } + Expr::ScalarFunction(fun) => fun.func.display_name(&fun.args), Expr::WindowFunction(WindowFunction { fun, args, @@ -491,6 +489,7 @@ impl PhysicalPlanner for DefaultPhysicalPlanner { let plan = self .create_initial_plan(logical_plan, session_state) .await?; + self.optimize_internal(plan, session_state, |_, _| {}) } } diff --git a/datafusion/expr/src/expr.rs b/datafusion/expr/src/expr.rs index 9789dd345faa5..01ef2571ea822 100644 --- a/datafusion/expr/src/expr.rs +++ b/datafusion/expr/src/expr.rs @@ -1637,7 +1637,7 @@ fn create_function_name(fun: &str, distinct: bool, args: &[Expr]) -> Result 2)". -fn create_name(e: &Expr) -> Result { +pub(crate) fn create_name(e: &Expr) -> Result { match e { Expr::Alias(Alias { name, .. }) => Ok(name.clone()), Expr::Column(c) => Ok(c.flat_name()), @@ -1793,7 +1793,7 @@ fn create_name(e: &Expr) -> Result { let expr_name = create_name(expr)?; Ok(format!("unnest({expr_name})")) } - Expr::ScalarFunction(fun) => create_function_name(fun.name(), false, &fun.args), + Expr::ScalarFunction(fun) => fun.func.display_name(&fun.args), Expr::WindowFunction(WindowFunction { fun, args, diff --git a/datafusion/expr/src/udf.rs b/datafusion/expr/src/udf.rs index c9c11a6bbfeac..29ee4a86e57dc 100644 --- a/datafusion/expr/src/udf.rs +++ b/datafusion/expr/src/udf.rs @@ -17,6 +17,7 @@ //! [`ScalarUDF`]: Scalar User Defined Functions +use crate::expr::create_name; use crate::simplify::{ExprSimplifyResult, SimplifyInfo}; use crate::{ ColumnarValue, Expr, FuncMonotonicity, ReturnTypeFunction, @@ -133,6 +134,13 @@ impl ScalarUDF { self.inner.name() } + /// Returns this function's display_name. + /// + /// See [`ScalarUDFImpl::display_name`] for more details + pub fn display_name(&self, args: &[Expr]) -> Result { + self.inner.display_name(args) + } + /// Returns the aliases for this function. /// /// See [`ScalarUDF::with_aliases`] for more details @@ -274,6 +282,13 @@ pub trait ScalarUDFImpl: Debug + Send + Sync { /// Returns this function's name fn name(&self) -> &str; + /// Returns the user-defined display name of the UDF given the arguments + /// + fn display_name(&self, args: &[Expr]) -> Result { + let names: Vec = args.iter().map(create_name).collect::>()?; + Ok(format!("{}({})", self.name(), names.join(","))) + } + /// Returns the function's [`Signature`] for information about what input /// types are accepted and the function's Volatility. fn signature(&self) -> &Signature; diff --git a/datafusion/functions/src/core/getfield.rs b/datafusion/functions/src/core/getfield.rs index a092aac159bbf..50c917548d740 100644 --- a/datafusion/functions/src/core/getfield.rs +++ b/datafusion/functions/src/core/getfield.rs @@ -50,10 +50,31 @@ impl ScalarUDFImpl for GetFieldFunc { fn as_any(&self) -> &dyn Any { self } + fn name(&self) -> &str { "get_field" } + fn display_name(&self, args: &[Expr]) -> Result { + if args.len() != 2 { + return exec_err!( + "get_field function requires 2 arguments, got {}", + args.len() + ); + } + + let name = match &args[1] { + Expr::Literal(name) => name, + _ => { + return exec_err!( + "get_field function requires the argument field_name to be a string" + ); + } + }; + + Ok(format!("{}[{}]", args[0].display_name()?, name)) + } + fn signature(&self) -> &Signature { &self.signature }