From a40c2e9286d68f5661d1f554f0e6d2577315d988 Mon Sep 17 00:00:00 2001 From: yaommen Date: Wed, 18 Mar 2026 23:50:53 +0800 Subject: [PATCH] fix: avoid internal errors for OneOf signature mismatches Signed-off-by: yaommen --- .../expr/src/type_coercion/functions.rs | 72 +++++++++++++++---- datafusion/sqllogictest/test_files/array.slt | 8 +-- datafusion/sqllogictest/test_files/errors.slt | 5 +- .../sqllogictest/test_files/functions.slt | 4 +- .../test_files/named_arguments.slt | 2 +- .../test_files/string/string_literal.slt | 4 +- 6 files changed, 72 insertions(+), 23 deletions(-) diff --git a/datafusion/expr/src/type_coercion/functions.rs b/datafusion/expr/src/type_coercion/functions.rs index d5cb98a46ef43..1726034b8ae09 100644 --- a/datafusion/expr/src/type_coercion/functions.rs +++ b/datafusion/expr/src/type_coercion/functions.rs @@ -325,24 +325,20 @@ fn get_valid_types_with_udf( }, TypeSignature::OneOf(signatures) => { let mut res = vec![]; - let mut errors = vec![]; for sig in signatures { - match get_valid_types_with_udf(sig, current_types, func) { - Ok(valid_types) => { - res.extend(valid_types); - } - Err(e) => { - errors.push(e.to_string()); - } + if let Ok(valid_types) = + get_valid_types_with_udf(sig, current_types, func) + { + res.extend(valid_types); } } - // Every signature failed, return the joined error + // Every signature failed, return a neutral planning error rather than + // a branch-specific error that may not match the best overload. if res.is_empty() { - return internal_err!( - "Function '{}' failed to match any signature, errors: {}", - func.name(), - errors.join(",") + return plan_err!( + "Function '{}' failed to match any signature", + func.name() ); } else { res @@ -1223,6 +1219,56 @@ mod tests { Ok(()) } + #[test] + fn test_one_of_uses_generic_plan_error_instead_of_internal_error() { + let current_fields = vec![Arc::new(Field::new("t", DataType::Boolean, true))]; + let signature = Signature::one_of( + vec![ + Signature::coercible( + vec![Coercion::new_exact(TypeSignatureClass::Decimal)], + Volatility::Immutable, + ) + .type_signature + .clone(), + Signature::coercible( + vec![Coercion::new_exact(TypeSignatureClass::Duration)], + Volatility::Immutable, + ) + .type_signature + .clone(), + ], + Volatility::Immutable, + ); + + let err = fields_with_udf(¤t_fields, &MockUdf(signature)).unwrap_err(); + let err = err.to_string(); + + assert_eq!( + err, + "Error during planning: Function 'test' failed to match any signature" + ); + assert!(!err.contains("Internal error")); + assert!(!err.contains("TypeSignatureClass")); + } + + #[test] + fn test_one_of_uses_generic_plan_error_for_arity_mismatch() { + let current_fields = vec![Arc::new(Field::new("t", DataType::Int32, true))]; + let signature = Signature::one_of( + vec![TypeSignature::Any(2), TypeSignature::Any(3)], + Volatility::Immutable, + ); + + let err = fields_with_udf(¤t_fields, &MockUdf(signature)).unwrap_err(); + let err = err.to_string(); + + assert_eq!( + err, + "Error during planning: Function 'test' failed to match any signature" + ); + assert!(!err.contains("Internal error")); + } + #[test] fn test_nested_wildcard_fixed_size_lists() -> Result<()> { let type_into = DataType::FixedSizeList( diff --git a/datafusion/sqllogictest/test_files/array.slt b/datafusion/sqllogictest/test_files/array.slt index 83e9c9cc9c409..37c6aa64cf660 100644 --- a/datafusion/sqllogictest/test_files/array.slt +++ b/datafusion/sqllogictest/test_files/array.slt @@ -7798,17 +7798,17 @@ select generate_series(arrow_cast('2021-01-01T00:00:00', 'Timestamp(Nanosecond, [2021-01-01T00:00:00-05:00, 2021-01-01T01:29:54.500-05:00, 2021-01-01T02:59:49-05:00, 2021-01-01T04:29:43.500-05:00, 2021-01-01T05:59:38-05:00] ## mixing types for timestamps is not supported -query error DataFusion error: Error during planning: Internal error: Function 'generate_series' failed to match any signature +query error DataFusion error: Error during planning: Function 'generate_series' failed to match any signature(.|\n)*generate_series\(Timestamp\(ns, "-05:00"\), Date32, Interval\(MonthDayNano\)\)(.|\n)*Candidate functions: select generate_series(arrow_cast('2021-01-01T00:00:00', 'Timestamp(Nanosecond, Some("-05:00"))'), DATE '2021-01-02', INTERVAL '1' HOUR); ## mixing types not allowed even if an argument is null -query error DataFusion error: Error during planning: Internal error: Function 'generate_series' failed to match any signature +query error DataFusion error: Error during planning: Function 'generate_series' failed to match any signature(.|\n)*generate_series\(Timestamp\(ns\), Date32, Null\)(.|\n)*Candidate functions: select generate_series(TIMESTAMP '1992-09-01', DATE '1993-03-01', NULL); -query error DataFusion error: Error during planning: Internal error: Function 'generate_series' failed to match any signature +query error DataFusion error: Error during planning: Function 'generate_series' failed to match any signature(.|\n)*generate_series\(Int64, Utf8, Utf8\)(.|\n)*Candidate functions: select generate_series(1, '2024-01-01', '2025-01-02'); -query error DataFusion error: Error during planning: Internal error: Function 'generate_series' failed to match any signature +query error DataFusion error: Error during planning: Function 'generate_series' failed to match any signature(.|\n)*generate_series\(Timestamp\(ns\), Utf8, Interval\(MonthDayNano\)\)(.|\n)*Candidate functions: select generate_series('2024-01-01'::timestamp, '2025-01-02', interval '1 day'); ## should return NULL diff --git a/datafusion/sqllogictest/test_files/errors.slt b/datafusion/sqllogictest/test_files/errors.slt index 20c1db5cb1511..2d22875004d00 100644 --- a/datafusion/sqllogictest/test_files/errors.slt +++ b/datafusion/sqllogictest/test_files/errors.slt @@ -125,13 +125,16 @@ from aggregate_test_100 order by c9 # WindowFunction wrong signature -statement error DataFusion error: Error during planning: Internal error: Function 'nth_value' failed to match any signature +statement error DataFusion error: Error during planning: Function 'nth_value' failed to match any signature(.|\n)*nth_value\(Int32, Int64, Int64\)(.|\n)*Candidate functions: select c9, nth_value(c5, 2, 3) over (order by c9) as nv1 from aggregate_test_100 order by c9 +query error DataFusion error: Error during planning: Function 'sum' failed to match any signature(.|\n)*sum\(Boolean\)(.|\n)*Candidate functions: +select sum(bool_col) from (values (true), (false), (null)) as t(bool_col); + # nth_value with wrong name statement error DataFusion error: Error during planning: Invalid function 'nth_vlue'.\nDid you mean 'nth_value'? diff --git a/datafusion/sqllogictest/test_files/functions.slt b/datafusion/sqllogictest/test_files/functions.slt index ee11dc973bbd7..1ed558d3e0361 100644 --- a/datafusion/sqllogictest/test_files/functions.slt +++ b/datafusion/sqllogictest/test_files/functions.slt @@ -208,10 +208,10 @@ SELECT substr('alphabet', NULL, 2) ---- NULL -statement error Function 'substr' failed to match any signature +statement error DataFusion error: Error during planning: Function 'substr' failed to match any signature(.|\n)*Candidate functions: SELECT substr(1, 3) -statement error Function 'substr' failed to match any signature +statement error DataFusion error: Error during planning: Function 'substr' failed to match any signature(.|\n)*Candidate functions: SELECT substr(1, 3, 4) query T diff --git a/datafusion/sqllogictest/test_files/named_arguments.slt b/datafusion/sqllogictest/test_files/named_arguments.slt index 07b6cc6a79a0c..a5cb290eef674 100644 --- a/datafusion/sqllogictest/test_files/named_arguments.slt +++ b/datafusion/sqllogictest/test_files/named_arguments.slt @@ -86,7 +86,7 @@ SELECT substr("STR" => 'hello world', "start_pos" => 7); # Error: wrong number of arguments # This query provides only 1 argument but substr requires 2 or 3 -query error Function 'substr' failed to match any signature +query error DataFusion error: Error during planning: Function 'substr' failed to match any signature(.|\n)*Candidate functions: SELECT substr(str => 'hello world'); ############# diff --git a/datafusion/sqllogictest/test_files/string/string_literal.slt b/datafusion/sqllogictest/test_files/string/string_literal.slt index a07eab3357141..7a372e8d04be5 100644 --- a/datafusion/sqllogictest/test_files/string/string_literal.slt +++ b/datafusion/sqllogictest/test_files/string/string_literal.slt @@ -132,10 +132,10 @@ SELECT substr('Hello🌏世界', 5, 3) ---- o🌏世 -statement error Function 'substr' failed to match any signature +statement error DataFusion error: Error during planning: Function 'substr' failed to match any signature(.|\n)*Candidate functions: SELECT substr(1, 3) -statement error Function 'substr' failed to match any signature +statement error DataFusion error: Error during planning: Function 'substr' failed to match any signature(.|\n)*Candidate functions: SELECT substr(1, 3, 4) statement error Execution error: negative substring length not allowed