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 7df085e672 Enable user defined display_name for ScalarUDF (#10417)
7df085e672 is described below

commit 7df085e6723d3e2c56b2164a5012c82199810ea9
Author: Junhao Liu <[email protected]>
AuthorDate: Wed May 8 11:09:10 2024 -0600

    Enable user defined display_name for ScalarUDF (#10417)
    
    * enable user defined display_name
    
    * add display_name to get_field
    
    * add physical name
---
 datafusion/core/src/physical_planner.rs   |  5 ++---
 datafusion/expr/src/expr.rs               |  4 ++--
 datafusion/expr/src/udf.rs                | 15 +++++++++++++++
 datafusion/functions/src/core/getfield.rs | 21 +++++++++++++++++++++
 4 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/datafusion/core/src/physical_planner.rs 
b/datafusion/core/src/physical_planner.rs
index dfcda553af..132bc3953c 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<String> {
                 }
             };
         }
-        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 9789dd345f..01ef2571ea 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<Stri
 
 /// Returns a readable name of an expression based on the input schema.
 /// This function recursively transverses the expression for names such as 
"CAST(a > 2)".
-fn create_name(e: &Expr) -> Result<String> {
+pub(crate) fn create_name(e: &Expr) -> Result<String> {
     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<String> {
             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 c9c11a6bbf..29ee4a86e5 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<String> {
+        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<String> {
+        let names: Vec<String> = 
args.iter().map(create_name).collect::<Result<_>>()?;
+        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 a092aac159..50c917548d 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<String> {
+        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
     }


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

Reply via email to