From a50cb0868b7f68580523d7632977c890daeeb369 Mon Sep 17 00:00:00 2001 From: Omer Banay Date: Wed, 7 Jun 2023 21:45:20 +0300 Subject: [PATCH 1/3] Prioritize UDF over scalar built-in function in case of function name collision --- datafusion/common/src/config.rs | 2 + datafusion/core/src/execution/context.rs | 2 + .../test_files/information_schema.slt | 1 + datafusion/sql/src/expr/function.rs | 41 ++++++-- datafusion/sql/src/planner.rs | 2 + datafusion/sql/tests/integration_test.rs | 94 ++++++++++++++++++- 6 files changed, 131 insertions(+), 11 deletions(-) diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index c5ce3540fce5..26982bda80f7 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -191,6 +191,8 @@ config_namespace! { /// MySQL, PostgreSQL, Hive, SQLite, Snowflake, Redshift, MsSQL, ClickHouse, BigQuery, and Ansi. pub dialect: String, default = "generic".to_string() + /// Should DataFusion prioritize UDF over built-in scalar function in case of function name conflict. + pub prioritize_udf: bool, default = false } } diff --git a/datafusion/core/src/execution/context.rs b/datafusion/core/src/execution/context.rs index 6b81a39691d6..36f921e3aa56 100644 --- a/datafusion/core/src/execution/context.rs +++ b/datafusion/core/src/execution/context.rs @@ -1793,6 +1793,7 @@ impl SessionState { self.config.options().sql_parser.enable_ident_normalization; let parse_float_as_decimal = self.config.options().sql_parser.parse_float_as_decimal; + let prioritize_udf = self.config.options().sql_parser.prioritize_udf; for reference in references { let table = reference.table(); let resolved = self.resolve_table_ref(&reference); @@ -1810,6 +1811,7 @@ impl SessionState { ParserOptions { parse_float_as_decimal, enable_ident_normalization, + prioritize_udf, }, ); query.statement_to_plan(statement) diff --git a/datafusion/core/tests/sqllogictests/test_files/information_schema.slt b/datafusion/core/tests/sqllogictests/test_files/information_schema.slt index 38f1d2cd05d4..350d55fbedda 100644 --- a/datafusion/core/tests/sqllogictests/test_files/information_schema.slt +++ b/datafusion/core/tests/sqllogictests/test_files/information_schema.slt @@ -174,6 +174,7 @@ datafusion.optimizer.top_down_join_key_reordering true datafusion.sql_parser.dialect generic datafusion.sql_parser.enable_ident_normalization true datafusion.sql_parser.parse_float_as_decimal false +datafusion.sql_parser.prioritize_udf false # show_variable_in_config_options query TT diff --git a/datafusion/sql/src/expr/function.rs b/datafusion/sql/src/expr/function.rs index 0fb6b7554776..de6c4d3ad48a 100644 --- a/datafusion/sql/src/expr/function.rs +++ b/datafusion/sql/src/expr/function.rs @@ -47,6 +47,15 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { crate::utils::normalize_ident(function.name.0[0].clone()) }; + if self.options.prioritize_udf { + // user-defined functions (UDF) + if let Some(udf) = + self.try_sql_fn_to_udf(&name, &function, schema, planner_context)? + { + return Ok(udf); + } + } + // next, scalar built-in if let Ok(fun) = BuiltinScalarFunction::from_str(&name) { let args = @@ -139,14 +148,16 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { ))); }; - // finally, user-defined functions (UDF) and UDAF - if let Some(fm) = self.schema_provider.get_function_meta(&name) { - let args = - self.function_args_to_expr(function.args, schema, planner_context)?; - return Ok(Expr::ScalarUDF(ScalarUDF::new(fm, args))); + if !self.options.prioritize_udf { + // user-defined functions (UDF) + if let Some(udf) = + self.try_sql_fn_to_udf(&name, &function, schema, planner_context)? + { + return Ok(udf); + } } - // User defined aggregate functions + // User defined aggregate functions (UDAF) if let Some(fm) = self.schema_provider.get_aggregate_meta(&name) { let args = self.function_args_to_expr(function.args, schema, planner_context)?; @@ -193,6 +204,24 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { }) } + fn try_sql_fn_to_udf( + &self, + name: &str, + function: &SQLFunction, + schema: &DFSchema, + planner_context: &mut PlannerContext, + ) -> Result> { + if let Some(fm) = self.schema_provider.get_function_meta(name) { + let args = self.function_args_to_expr( + function.args.clone(), + schema, + planner_context, + )?; + return Ok(Some(Expr::ScalarUDF(ScalarUDF::new(fm, args)))); + } + Ok(None) + } + fn sql_fn_arg_to_logical_expr( &self, sql: FunctionArg, diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs index ceec01037425..26def07cfe56 100644 --- a/datafusion/sql/src/planner.rs +++ b/datafusion/sql/src/planner.rs @@ -58,6 +58,7 @@ pub trait ContextProvider { pub struct ParserOptions { pub parse_float_as_decimal: bool, pub enable_ident_normalization: bool, + pub prioritize_udf: bool, } impl Default for ParserOptions { @@ -65,6 +66,7 @@ impl Default for ParserOptions { Self { parse_float_as_decimal: false, enable_ident_normalization: true, + prioritize_udf: false, } } } diff --git a/datafusion/sql/tests/integration_test.rs b/datafusion/sql/tests/integration_test.rs index 7161fa481cbe..9b1b21fb115a 100644 --- a/datafusion/sql/tests/integration_test.rs +++ b/datafusion/sql/tests/integration_test.rs @@ -28,7 +28,8 @@ use datafusion_common::{ }; use datafusion_expr::{ logical_plan::{LogicalPlan, Prepare}, - AggregateUDF, ScalarUDF, TableSource, + AggregateUDF, BuiltinScalarFunction, ColumnarValue, Expr, ReturnTypeFunction, + ScalarFunctionImplementation, ScalarUDF, Signature, TableSource, Volatility, }; use datafusion_sql::{ parser::DFParser, @@ -72,6 +73,7 @@ fn parse_decimals() { ParserOptions { parse_float_as_decimal: true, enable_ident_normalization: false, + prioritize_udf: false, }, ); } @@ -125,12 +127,78 @@ fn parse_ident_normalization() { ParserOptions { parse_float_as_decimal: false, enable_ident_normalization, + prioritize_udf: false, }, ); assert_eq!(expected, format!("{plan:?}")); } } +#[test] +fn parse_prioritize_udf() { + // Create a UDF that has the same name as a builtin function (abs) + let return_type: ReturnTypeFunction = + Arc::new(move |_| Ok(Arc::new(DataType::Int64))); + let fun: ScalarFunctionImplementation = + Arc::new(move |_| Ok(ColumnarValue::Scalar(ScalarValue::Int64(Some(1))))); + let scalar_udf = Arc::new(ScalarUDF::new( + "abs", + &Signature::uniform(1, vec![DataType::Float32], Volatility::Stable), + &return_type, + &fun, + )); + + // Test data + let test_data = [ + ( + "SELECT ABS(-1)", + Expr::ScalarFunction(datafusion_expr::expr::ScalarFunction { + fun: BuiltinScalarFunction::Abs, + args: vec![Expr::Literal(ScalarValue::Int64(Some(-1)))], + }), + false, + ), + ( + "SELECT ABS(-1)", + Expr::ScalarUDF(datafusion_expr::expr::ScalarUDF { + fun: scalar_udf.clone(), + args: vec![Expr::Literal(ScalarValue::Int64(Some(-1)))], + }), + true, + ), + ]; + + for (sql, expected_projected_field, prioritize_udf) in test_data { + let mut udfs = HashMap::new(); + udfs.insert("abs".to_string(), scalar_udf.clone()); + let plan = logical_plan_with_options_and_context( + sql, + ParserOptions { + parse_float_as_decimal: false, + enable_ident_normalization: true, + prioritize_udf, + }, + &MockContextProvider { + udafs: HashMap::default(), + udfs, + options: ConfigOptions::default(), + }, + ); + // Check that the plan is as expected + assert_eq!( + "Ok(Projection: abs(Int64(-1))\n EmptyRelation)", + format!("{:?}", &plan) + ); + // Because a plan with a UDF is displayed exactly the same as a plan with a built-in function, + // we need to check the the projected field to ensure that the plan is correct. + let projected_field = match plan { + Ok(LogicalPlan::Projection(projection)) => projection.expr[0].to_owned(), + _ => panic!("Expected Projection"), + }; + assert_eq!(projected_field, expected_projected_field); + } +} + #[test] fn select_no_relation() { quick_test( @@ -1246,9 +1314,12 @@ fn select_simple_aggregate_with_groupby_column_unselected() { fn select_simple_aggregate_with_groupby_and_column_in_group_by_does_not_exist() { let sql = "SELECT SUM(age) FROM person GROUP BY doesnotexist"; let err = logical_plan(sql).expect_err("query should have failed"); - assert_eq!("Schema error: No field named doesnotexist. Valid fields are \"SUM(person.age)\", \ + assert_eq!( + "Schema error: No field named doesnotexist. Valid fields are \"SUM(person.age)\", \ person.id, person.first_name, person.last_name, person.age, person.state, \ - person.salary, person.birth_date, person.\"😀\".", format!("{err}")); + person.salary, person.birth_date, person.\"😀\".", + format!("{err}") + ); } #[test] @@ -2549,6 +2620,18 @@ fn logical_plan_with_dialect_and_options( planner.statement_to_plan(ast.pop_front().unwrap()) } +fn logical_plan_with_options_and_context( + sql: &str, + options: ParserOptions, + context: &S, +) -> Result { + let dialect = &GenericDialect {}; + let planner = SqlToRel::new_with_options(context, options); + let result = DFParser::parse_sql_with_dialect(sql, dialect); + let mut ast = result?; + planner.statement_to_plan(ast.pop_front().unwrap()) +} + /// Create logical plan, write with formatter, compare to expected output fn quick_test(sql: &str, expected: &str) { let plan = logical_plan(sql).unwrap(); @@ -2596,6 +2679,7 @@ fn prepare_stmt_replace_params_quick_test( struct MockContextProvider { options: ConfigOptions, udafs: HashMap>, + udfs: HashMap>, } impl ContextProvider for MockContextProvider { @@ -2679,8 +2763,8 @@ impl ContextProvider for MockContextProvider { } } - fn get_function_meta(&self, _name: &str) -> Option> { - None + fn get_function_meta(&self, name: &str) -> Option> { + self.udfs.get(name).map(Arc::clone) } fn get_aggregate_meta(&self, name: &str) -> Option> { From 76283c40de121f1e65507ad1d8de45fefa7c48b1 Mon Sep 17 00:00:00 2001 From: Omer Banay Date: Sun, 11 Jun 2023 11:51:28 +0300 Subject: [PATCH 2/3] Remove prioritize_udf config flag (assume true by default) --- datafusion/common/src/config.rs | 2 - datafusion/core/src/execution/context.rs | 2 - .../test_files/information_schema.slt | 1 - datafusion/sql/src/expr/function.rs | 39 +++---------------- datafusion/sql/src/planner.rs | 2 - datafusion/sql/tests/integration_test.rs | 16 +------- 6 files changed, 7 insertions(+), 55 deletions(-) diff --git a/datafusion/common/src/config.rs b/datafusion/common/src/config.rs index 26982bda80f7..c5ce3540fce5 100644 --- a/datafusion/common/src/config.rs +++ b/datafusion/common/src/config.rs @@ -191,8 +191,6 @@ config_namespace! { /// MySQL, PostgreSQL, Hive, SQLite, Snowflake, Redshift, MsSQL, ClickHouse, BigQuery, and Ansi. pub dialect: String, default = "generic".to_string() - /// Should DataFusion prioritize UDF over built-in scalar function in case of function name conflict. - pub prioritize_udf: bool, default = false } } diff --git a/datafusion/core/src/execution/context.rs b/datafusion/core/src/execution/context.rs index 36f921e3aa56..6b81a39691d6 100644 --- a/datafusion/core/src/execution/context.rs +++ b/datafusion/core/src/execution/context.rs @@ -1793,7 +1793,6 @@ impl SessionState { self.config.options().sql_parser.enable_ident_normalization; let parse_float_as_decimal = self.config.options().sql_parser.parse_float_as_decimal; - let prioritize_udf = self.config.options().sql_parser.prioritize_udf; for reference in references { let table = reference.table(); let resolved = self.resolve_table_ref(&reference); @@ -1811,7 +1810,6 @@ impl SessionState { ParserOptions { parse_float_as_decimal, enable_ident_normalization, - prioritize_udf, }, ); query.statement_to_plan(statement) diff --git a/datafusion/core/tests/sqllogictests/test_files/information_schema.slt b/datafusion/core/tests/sqllogictests/test_files/information_schema.slt index 350d55fbedda..38f1d2cd05d4 100644 --- a/datafusion/core/tests/sqllogictests/test_files/information_schema.slt +++ b/datafusion/core/tests/sqllogictests/test_files/information_schema.slt @@ -174,7 +174,6 @@ datafusion.optimizer.top_down_join_key_reordering true datafusion.sql_parser.dialect generic datafusion.sql_parser.enable_ident_normalization true datafusion.sql_parser.parse_float_as_decimal false -datafusion.sql_parser.prioritize_udf false # show_variable_in_config_options query TT diff --git a/datafusion/sql/src/expr/function.rs b/datafusion/sql/src/expr/function.rs index de6c4d3ad48a..0289e804110c 100644 --- a/datafusion/sql/src/expr/function.rs +++ b/datafusion/sql/src/expr/function.rs @@ -47,13 +47,11 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { crate::utils::normalize_ident(function.name.0[0].clone()) }; - if self.options.prioritize_udf { - // user-defined functions (UDF) - if let Some(udf) = - self.try_sql_fn_to_udf(&name, &function, schema, planner_context)? - { - return Ok(udf); - } + // user-defined function (UDF) should have precedence in case it has the same name as a scalar built-in function + if let Some(fm) = self.schema_provider.get_function_meta(&name) { + let args = + self.function_args_to_expr(function.args, schema, planner_context)?; + return Ok(Expr::ScalarUDF(ScalarUDF::new(fm, args))); } // next, scalar built-in @@ -148,15 +146,6 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { ))); }; - if !self.options.prioritize_udf { - // user-defined functions (UDF) - if let Some(udf) = - self.try_sql_fn_to_udf(&name, &function, schema, planner_context)? - { - return Ok(udf); - } - } - // User defined aggregate functions (UDAF) if let Some(fm) = self.schema_provider.get_aggregate_meta(&name) { let args = @@ -204,24 +193,6 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { }) } - fn try_sql_fn_to_udf( - &self, - name: &str, - function: &SQLFunction, - schema: &DFSchema, - planner_context: &mut PlannerContext, - ) -> Result> { - if let Some(fm) = self.schema_provider.get_function_meta(name) { - let args = self.function_args_to_expr( - function.args.clone(), - schema, - planner_context, - )?; - return Ok(Some(Expr::ScalarUDF(ScalarUDF::new(fm, args)))); - } - Ok(None) - } - fn sql_fn_arg_to_logical_expr( &self, sql: FunctionArg, diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs index 26def07cfe56..ceec01037425 100644 --- a/datafusion/sql/src/planner.rs +++ b/datafusion/sql/src/planner.rs @@ -58,7 +58,6 @@ pub trait ContextProvider { pub struct ParserOptions { pub parse_float_as_decimal: bool, pub enable_ident_normalization: bool, - pub prioritize_udf: bool, } impl Default for ParserOptions { @@ -66,7 +65,6 @@ impl Default for ParserOptions { Self { parse_float_as_decimal: false, enable_ident_normalization: true, - prioritize_udf: false, } } } diff --git a/datafusion/sql/tests/integration_test.rs b/datafusion/sql/tests/integration_test.rs index 9b1b21fb115a..05dc7469b1db 100644 --- a/datafusion/sql/tests/integration_test.rs +++ b/datafusion/sql/tests/integration_test.rs @@ -28,7 +28,7 @@ use datafusion_common::{ }; use datafusion_expr::{ logical_plan::{LogicalPlan, Prepare}, - AggregateUDF, BuiltinScalarFunction, ColumnarValue, Expr, ReturnTypeFunction, + AggregateUDF, ColumnarValue, Expr, ReturnTypeFunction, ScalarFunctionImplementation, ScalarUDF, Signature, TableSource, Volatility, }; use datafusion_sql::{ @@ -73,7 +73,6 @@ fn parse_decimals() { ParserOptions { parse_float_as_decimal: true, enable_ident_normalization: false, - prioritize_udf: false, }, ); } @@ -127,7 +126,6 @@ fn parse_ident_normalization() { ParserOptions { parse_float_as_decimal: false, enable_ident_normalization, - prioritize_udf: false, }, ); assert_eq!(expected, format!("{plan:?}")); @@ -150,25 +148,16 @@ fn parse_prioritize_udf() { // Test data let test_data = [ - ( - "SELECT ABS(-1)", - Expr::ScalarFunction(datafusion_expr::expr::ScalarFunction { - fun: BuiltinScalarFunction::Abs, - args: vec![Expr::Literal(ScalarValue::Int64(Some(-1)))], - }), - false, - ), ( "SELECT ABS(-1)", Expr::ScalarUDF(datafusion_expr::expr::ScalarUDF { fun: scalar_udf.clone(), args: vec![Expr::Literal(ScalarValue::Int64(Some(-1)))], }), - true, ), ]; - for (sql, expected_projected_field, prioritize_udf) in test_data { + for (sql, expected_projected_field) in test_data { let mut udfs = HashMap::new(); udfs.insert("abs".to_string(), scalar_udf.clone()); let plan = logical_plan_with_options_and_context( @@ -176,7 +165,6 @@ fn parse_prioritize_udf() { ParserOptions { parse_float_as_decimal: false, enable_ident_normalization: true, - prioritize_udf, }, &MockContextProvider { udafs: HashMap::default(), From 5f325bd718111071861eb93d8d6aef0550076c80 Mon Sep 17 00:00:00 2001 From: Omer Banay Date: Sun, 11 Jun 2023 13:29:23 +0300 Subject: [PATCH 3/3] Add test scalar_udf_override_built_in_scalar_function --- datafusion/core/tests/sql/udf.rs | 33 ++++++++++ datafusion/sql/tests/integration_test.rs | 82 ++---------------------- 2 files changed, 38 insertions(+), 77 deletions(-) diff --git a/datafusion/core/tests/sql/udf.rs b/datafusion/core/tests/sql/udf.rs index a31028fd71cb..0ecd5d0fde86 100644 --- a/datafusion/core/tests/sql/udf.rs +++ b/datafusion/core/tests/sql/udf.rs @@ -179,6 +179,39 @@ async fn scalar_udf_zero_params() -> Result<()> { Ok(()) } +#[tokio::test] +async fn scalar_udf_override_built_in_scalar_function() -> Result<()> { + let schema = Schema::new(vec![Field::new("a", DataType::Int32, false)]); + + let batch = RecordBatch::try_new( + Arc::new(schema.clone()), + vec![Arc::new(Int32Array::from(vec![-100]))], + )?; + let ctx = SessionContext::new(); + + ctx.register_batch("t", batch)?; + // register a UDF that has the same name as a builtin function (abs) and just returns 1 regardless of input + ctx.register_udf(create_udf( + "abs", + vec![DataType::Int32], + Arc::new(DataType::Int32), + Volatility::Immutable, + Arc::new(move |_| Ok(ColumnarValue::Scalar(ScalarValue::Int32(Some(1))))), + )); + + // Make sure that the UDF is used instead of the built-in function + let result = plan_and_collect(&ctx, "select abs(a) a from t").await?; + let expected = vec![ + "+---+", // + "| a |", // + "+---+", // + "| 1 |", // + "+---+", // + ]; + assert_batches_eq!(expected, &result); + Ok(()) +} + /// tests the creation, registration and usage of a UDAF #[tokio::test] async fn simple_udaf() -> Result<()> { diff --git a/datafusion/sql/tests/integration_test.rs b/datafusion/sql/tests/integration_test.rs index 05dc7469b1db..7161fa481cbe 100644 --- a/datafusion/sql/tests/integration_test.rs +++ b/datafusion/sql/tests/integration_test.rs @@ -28,8 +28,7 @@ use datafusion_common::{ }; use datafusion_expr::{ logical_plan::{LogicalPlan, Prepare}, - AggregateUDF, ColumnarValue, Expr, ReturnTypeFunction, - ScalarFunctionImplementation, ScalarUDF, Signature, TableSource, Volatility, + AggregateUDF, ScalarUDF, TableSource, }; use datafusion_sql::{ parser::DFParser, @@ -132,61 +131,6 @@ fn parse_ident_normalization() { } } -#[test] -fn parse_prioritize_udf() { - // Create a UDF that has the same name as a builtin function (abs) - let return_type: ReturnTypeFunction = - Arc::new(move |_| Ok(Arc::new(DataType::Int64))); - let fun: ScalarFunctionImplementation = - Arc::new(move |_| Ok(ColumnarValue::Scalar(ScalarValue::Int64(Some(1))))); - let scalar_udf = Arc::new(ScalarUDF::new( - "abs", - &Signature::uniform(1, vec![DataType::Float32], Volatility::Stable), - &return_type, - &fun, - )); - - // Test data - let test_data = [ - ( - "SELECT ABS(-1)", - Expr::ScalarUDF(datafusion_expr::expr::ScalarUDF { - fun: scalar_udf.clone(), - args: vec![Expr::Literal(ScalarValue::Int64(Some(-1)))], - }), - ), - ]; - - for (sql, expected_projected_field) in test_data { - let mut udfs = HashMap::new(); - udfs.insert("abs".to_string(), scalar_udf.clone()); - let plan = logical_plan_with_options_and_context( - sql, - ParserOptions { - parse_float_as_decimal: false, - enable_ident_normalization: true, - }, - &MockContextProvider { - udafs: HashMap::default(), - udfs, - options: ConfigOptions::default(), - }, - ); - // Check that the plan is as expected - assert_eq!( - "Ok(Projection: abs(Int64(-1))\n EmptyRelation)", - format!("{:?}", &plan) - ); - // Because a plan with a UDF is displayed exactly the same as a plan with a built-in function, - // we need to check the the projected field to ensure that the plan is correct. - let projected_field = match plan { - Ok(LogicalPlan::Projection(projection)) => projection.expr[0].to_owned(), - _ => panic!("Expected Projection"), - }; - assert_eq!(projected_field, expected_projected_field); - } -} - #[test] fn select_no_relation() { quick_test( @@ -1302,12 +1246,9 @@ fn select_simple_aggregate_with_groupby_column_unselected() { fn select_simple_aggregate_with_groupby_and_column_in_group_by_does_not_exist() { let sql = "SELECT SUM(age) FROM person GROUP BY doesnotexist"; let err = logical_plan(sql).expect_err("query should have failed"); - assert_eq!( - "Schema error: No field named doesnotexist. Valid fields are \"SUM(person.age)\", \ + assert_eq!("Schema error: No field named doesnotexist. Valid fields are \"SUM(person.age)\", \ person.id, person.first_name, person.last_name, person.age, person.state, \ - person.salary, person.birth_date, person.\"😀\".", - format!("{err}") - ); + person.salary, person.birth_date, person.\"😀\".", format!("{err}")); } #[test] @@ -2608,18 +2549,6 @@ fn logical_plan_with_dialect_and_options( planner.statement_to_plan(ast.pop_front().unwrap()) } -fn logical_plan_with_options_and_context( - sql: &str, - options: ParserOptions, - context: &S, -) -> Result { - let dialect = &GenericDialect {}; - let planner = SqlToRel::new_with_options(context, options); - let result = DFParser::parse_sql_with_dialect(sql, dialect); - let mut ast = result?; - planner.statement_to_plan(ast.pop_front().unwrap()) -} - /// Create logical plan, write with formatter, compare to expected output fn quick_test(sql: &str, expected: &str) { let plan = logical_plan(sql).unwrap(); @@ -2667,7 +2596,6 @@ fn prepare_stmt_replace_params_quick_test( struct MockContextProvider { options: ConfigOptions, udafs: HashMap>, - udfs: HashMap>, } impl ContextProvider for MockContextProvider { @@ -2751,8 +2679,8 @@ impl ContextProvider for MockContextProvider { } } - fn get_function_meta(&self, name: &str) -> Option> { - self.udfs.get(name).map(Arc::clone) + fn get_function_meta(&self, _name: &str) -> Option> { + None } fn get_aggregate_meta(&self, name: &str) -> Option> {