diff --git a/datafusion/functions-nested/src/string.rs b/datafusion/functions-nested/src/string.rs index 1c8d58fca..c296f1969 100644 --- a/datafusion/functions-nested/src/string.rs +++ b/datafusion/functions-nested/src/string.rs @@ -347,21 +347,20 @@ fn array_to_string_inner(args: &[ArrayRef]) -> Result { } }; - let mut null_string = String::from(""); - let mut with_null_string = false; - if args.len() == 3 { - null_string = match args[2].data_type() { - Utf8 => args[2].as_string::().value(0).to_string(), - Utf8View => args[2].as_string_view().value(0).to_string(), - LargeUtf8 => args[2].as_string::().value(0).to_string(), + let null_strings = if args.len() == 3 { + Some(match args[2].data_type() { + Utf8 => args[2].as_string::().iter().collect(), + Utf8View => args[2].as_string_view().iter().collect(), + LargeUtf8 => args[2].as_string::().iter().collect(), other => { return exec_err!( - "unsupported type for second argument to array_to_string function as {other:?}" + "unsupported type for third argument to array_to_string function as {other:?}" ); } - }; - with_null_string = true; - } + }) + } else { + None + }; /// Creates a single string from single element of a ListArray (which is /// itself another Array) @@ -469,18 +468,24 @@ fn array_to_string_inner(args: &[ArrayRef]) -> Result { fn generate_string_array( list_arr: &GenericListArray, delimiters: &[Option<&str>], - null_string: &str, - with_null_string: bool, + null_strings: &Option>>, ) -> Result { let mut res: Vec> = Vec::new(); - for (arr, &delimiter) in list_arr.iter().zip(delimiters.iter()) { + for (i, (arr, &delimiter)) in list_arr.iter().zip(delimiters.iter()).enumerate() { if let (Some(arr), Some(delimiter)) = (arr, delimiter) { + let (null_string, with_null_string) = match null_strings { + Some(ns) => match ns[i] { + Some(s) => (s.to_string(), true), + None => (String::new(), false), + }, + None => (String::new(), false), + }; let mut arg = String::from(""); let s = compute_array_to_string( &mut arg, &arr, delimiter.to_string(), - null_string.to_string(), + null_string, with_null_string, )? .clone(); @@ -501,21 +506,11 @@ fn array_to_string_inner(args: &[ArrayRef]) -> Result { let string_arr = match arr.data_type() { List(_) => { let list_array = as_list_array(&arr)?; - generate_string_array::( - list_array, - &delimiters, - &null_string, - with_null_string, - )? + generate_string_array::(list_array, &delimiters, &null_strings)? } LargeList(_) => { let list_array = as_large_list_array(&arr)?; - generate_string_array::( - list_array, - &delimiters, - &null_string, - with_null_string, - )? + generate_string_array::(list_array, &delimiters, &null_strings)? } // Signature guards against this arm _ => return exec_err!("array_to_string expects list as first argument"), diff --git a/datafusion/sqllogictest/test_files/array.slt b/datafusion/sqllogictest/test_files/array.slt index 889106c08..5113b9718 100644 --- a/datafusion/sqllogictest/test_files/array.slt +++ b/datafusion/sqllogictest/test_files/array.slt @@ -5248,6 +5248,25 @@ NULL 1.2.3 51_52_*_54_55_56_57_58_59_60 1.2.3 61_62_63_64_65_66_67_68_69_70 1.2.3 +# array_to_string with per-row null_string column +statement ok +CREATE TABLE test_null_str_col AS VALUES + (make_array(1, NULL, 3), ',', 'N/A'), + (make_array(NULL, 5, NULL), ',', 'MISSING'), + (make_array(10, NULL, 12), '-', 'X'), + (make_array(20, NULL, 21), '-', NULL); + +query T +SELECT array_to_string(column1, column2, column3) FROM test_null_str_col; +---- +1,N/A,3 +MISSING,5,MISSING +10-X-12 +20-21 + +statement ok +DROP TABLE test_null_str_col; + ## cardinality # cardinality scalar function