@@ -26,8 +26,9 @@ use datafusion_common::{
2626 utils:: { coerced_fixed_size_list_to_list, list_ndims} ,
2727 Result ,
2828} ;
29- use datafusion_expr_common:: signature:: {
30- ArrayFunctionSignature , FIXED_SIZE_LIST_WILDCARD , TIMEZONE_WILDCARD ,
29+ use datafusion_expr_common:: {
30+ signature:: { ArrayFunctionSignature , FIXED_SIZE_LIST_WILDCARD , TIMEZONE_WILDCARD } ,
31+ type_coercion:: binary:: string_coercion,
3132} ;
3233use std:: sync:: Arc ;
3334
@@ -176,6 +177,7 @@ fn is_well_supported_signature(type_signature: &TypeSignature) -> bool {
176177 type_signature,
177178 TypeSignature :: UserDefined
178179 | TypeSignature :: Numeric ( _)
180+ | TypeSignature :: String ( _)
179181 | TypeSignature :: Coercible ( _)
180182 | TypeSignature :: Any ( _)
181183 )
@@ -381,6 +383,67 @@ fn get_valid_types(
381383 . iter ( )
382384 . map ( |valid_type| current_types. iter ( ) . map ( |_| valid_type. clone ( ) ) . collect ( ) )
383385 . collect ( ) ,
386+ TypeSignature :: String ( number) => {
387+ if * number < 1 {
388+ return plan_err ! (
389+ "The signature expected at least one argument but received {}" ,
390+ current_types. len( )
391+ ) ;
392+ }
393+ if * number != current_types. len ( ) {
394+ return plan_err ! (
395+ "The signature expected {} arguments but received {}" ,
396+ number,
397+ current_types. len( )
398+ ) ;
399+ }
400+
401+ fn coercion_rule (
402+ lhs_type : & DataType ,
403+ rhs_type : & DataType ,
404+ ) -> Result < DataType > {
405+ match ( lhs_type, rhs_type) {
406+ ( DataType :: Null , DataType :: Null ) => Ok ( DataType :: Utf8 ) ,
407+ ( DataType :: Null , data_type) | ( data_type, DataType :: Null ) => {
408+ coercion_rule ( data_type, & DataType :: Utf8 )
409+ }
410+ ( DataType :: Dictionary ( _, lhs) , DataType :: Dictionary ( _, rhs) ) => {
411+ coercion_rule ( lhs, rhs)
412+ }
413+ ( DataType :: Dictionary ( _, v) , other)
414+ | ( other, DataType :: Dictionary ( _, v) ) => coercion_rule ( v, other) ,
415+ _ => {
416+ if let Some ( coerced_type) = string_coercion ( lhs_type, rhs_type) {
417+ Ok ( coerced_type)
418+ } else {
419+ plan_err ! (
420+ "{} and {} are not coercible to a common string type" ,
421+ lhs_type,
422+ rhs_type
423+ )
424+ }
425+ }
426+ }
427+ }
428+
429+ // Length checked above, safe to unwrap
430+ let mut coerced_type = current_types. first ( ) . unwrap ( ) . to_owned ( ) ;
431+ for t in current_types. iter ( ) . skip ( 1 ) {
432+ coerced_type = coercion_rule ( & coerced_type, t) ?;
433+ }
434+
435+ fn base_type_or_default_type ( data_type : & DataType ) -> DataType {
436+ if data_type. is_null ( ) {
437+ DataType :: Utf8
438+ } else if let DataType :: Dictionary ( _, v) = data_type {
439+ base_type_or_default_type ( v)
440+ } else {
441+ data_type. to_owned ( )
442+ }
443+ }
444+
445+ vec ! [ vec![ base_type_or_default_type( & coerced_type) ; * number] ]
446+ }
384447 TypeSignature :: Numeric ( number) => {
385448 if * number < 1 {
386449 return plan_err ! (
0 commit comments