datafusion_functions_nested/
string.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! [`ScalarUDFImpl`] definitions for array_to_string and string_to_array functions.
19
20use arrow::array::{
21    Array, ArrayRef, BooleanArray, Float32Array, Float64Array, GenericListArray,
22    Int8Array, Int16Array, Int32Array, Int64Array, LargeStringArray, ListBuilder,
23    OffsetSizeTrait, StringArray, StringBuilder, UInt8Array, UInt16Array, UInt32Array,
24    UInt64Array,
25};
26use arrow::datatypes::{DataType, Field};
27
28use datafusion_common::utils::ListCoercion;
29use datafusion_common::{DataFusionError, Result, not_impl_err};
30
31use std::any::Any;
32
33use crate::utils::make_scalar_function;
34use arrow::array::{
35    GenericStringArray, StringArrayType, StringViewArray,
36    builder::{ArrayBuilder, LargeStringBuilder, StringViewBuilder},
37    cast::AsArray,
38};
39use arrow::compute::cast;
40use arrow::datatypes::DataType::{
41    Dictionary, FixedSizeList, LargeList, LargeUtf8, List, Null, Utf8, Utf8View,
42};
43use datafusion_common::cast::{
44    as_fixed_size_list_array, as_large_list_array, as_list_array,
45};
46use datafusion_common::exec_err;
47use datafusion_common::types::logical_string;
48use datafusion_expr::{
49    ArrayFunctionArgument, ArrayFunctionSignature, Coercion, ColumnarValue,
50    Documentation, ScalarUDFImpl, Signature, TypeSignature, TypeSignatureClass,
51    Volatility,
52};
53use datafusion_functions::downcast_arg;
54use datafusion_macros::user_doc;
55use std::sync::Arc;
56
57macro_rules! call_array_function {
58    ($DATATYPE:expr, false) => {
59        match $DATATYPE {
60            DataType::Utf8 => array_function!(StringArray),
61            DataType::Utf8View => array_function!(StringViewArray),
62            DataType::LargeUtf8 => array_function!(LargeStringArray),
63            DataType::Boolean => array_function!(BooleanArray),
64            DataType::Float32 => array_function!(Float32Array),
65            DataType::Float64 => array_function!(Float64Array),
66            DataType::Int8 => array_function!(Int8Array),
67            DataType::Int16 => array_function!(Int16Array),
68            DataType::Int32 => array_function!(Int32Array),
69            DataType::Int64 => array_function!(Int64Array),
70            DataType::UInt8 => array_function!(UInt8Array),
71            DataType::UInt16 => array_function!(UInt16Array),
72            DataType::UInt32 => array_function!(UInt32Array),
73            DataType::UInt64 => array_function!(UInt64Array),
74            dt => not_impl_err!("Unsupported data type in array_to_string: {dt}"),
75        }
76    };
77    ($DATATYPE:expr, $INCLUDE_LIST:expr) => {{
78        match $DATATYPE {
79            DataType::List(_) => array_function!(ListArray),
80            DataType::Utf8 => array_function!(StringArray),
81            DataType::Utf8View => array_function!(StringViewArray),
82            DataType::LargeUtf8 => array_function!(LargeStringArray),
83            DataType::Boolean => array_function!(BooleanArray),
84            DataType::Float32 => array_function!(Float32Array),
85            DataType::Float64 => array_function!(Float64Array),
86            DataType::Int8 => array_function!(Int8Array),
87            DataType::Int16 => array_function!(Int16Array),
88            DataType::Int32 => array_function!(Int32Array),
89            DataType::Int64 => array_function!(Int64Array),
90            DataType::UInt8 => array_function!(UInt8Array),
91            DataType::UInt16 => array_function!(UInt16Array),
92            DataType::UInt32 => array_function!(UInt32Array),
93            DataType::UInt64 => array_function!(UInt64Array),
94            dt => not_impl_err!("Unsupported data type in array_to_string: {dt}"),
95        }
96    }};
97}
98
99macro_rules! to_string {
100    ($ARG:expr, $ARRAY:expr, $DELIMITER:expr, $NULL_STRING:expr, $WITH_NULL_STRING:expr, $ARRAY_TYPE:ident) => {{
101        let arr = downcast_arg!($ARRAY, $ARRAY_TYPE);
102        for x in arr {
103            match x {
104                Some(x) => {
105                    $ARG.push_str(&x.to_string());
106                    $ARG.push_str($DELIMITER);
107                }
108                None => {
109                    if $WITH_NULL_STRING {
110                        $ARG.push_str($NULL_STRING);
111                        $ARG.push_str($DELIMITER);
112                    }
113                }
114            }
115        }
116        Ok($ARG)
117    }};
118}
119
120// Create static instances of ScalarUDFs for each function
121make_udf_expr_and_func!(
122    ArrayToString,
123    array_to_string,
124    array delimiter, // arg name
125    "converts each element to its text representation.", // doc
126    array_to_string_udf // internal function name
127);
128
129#[user_doc(
130    doc_section(label = "Array Functions"),
131    description = "Converts each element to its text representation.",
132    syntax_example = "array_to_string(array, delimiter[, null_string])",
133    sql_example = r#"```sql
134> select array_to_string([[1, 2, 3, 4], [5, 6, 7, 8]], ',');
135+----------------------------------------------------+
136| array_to_string(List([1,2,3,4,5,6,7,8]),Utf8(",")) |
137+----------------------------------------------------+
138| 1,2,3,4,5,6,7,8                                    |
139+----------------------------------------------------+
140```"#,
141    argument(
142        name = "array",
143        description = "Array expression. Can be a constant, column, or function, and any combination of array operators."
144    ),
145    argument(name = "delimiter", description = "Array element separator."),
146    argument(
147        name = "null_string",
148        description = "Optional. String to replace null values in the array. If not provided, nulls will be handled by default behavior."
149    )
150)]
151#[derive(Debug, PartialEq, Eq, Hash)]
152pub struct ArrayToString {
153    signature: Signature,
154    aliases: Vec<String>,
155}
156
157impl Default for ArrayToString {
158    fn default() -> Self {
159        Self::new()
160    }
161}
162
163impl ArrayToString {
164    pub fn new() -> Self {
165        Self {
166            signature: Signature::one_of(
167                vec![
168                    TypeSignature::ArraySignature(ArrayFunctionSignature::Array {
169                        arguments: vec![
170                            ArrayFunctionArgument::Array,
171                            ArrayFunctionArgument::String,
172                            ArrayFunctionArgument::String,
173                        ],
174                        array_coercion: Some(ListCoercion::FixedSizedListToList),
175                    }),
176                    TypeSignature::ArraySignature(ArrayFunctionSignature::Array {
177                        arguments: vec![
178                            ArrayFunctionArgument::Array,
179                            ArrayFunctionArgument::String,
180                        ],
181                        array_coercion: Some(ListCoercion::FixedSizedListToList),
182                    }),
183                ],
184                Volatility::Immutable,
185            ),
186            aliases: vec![
187                String::from("list_to_string"),
188                String::from("array_join"),
189                String::from("list_join"),
190            ],
191        }
192    }
193}
194
195impl ScalarUDFImpl for ArrayToString {
196    fn as_any(&self) -> &dyn Any {
197        self
198    }
199
200    fn name(&self) -> &str {
201        "array_to_string"
202    }
203
204    fn signature(&self) -> &Signature {
205        &self.signature
206    }
207
208    fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
209        Ok(Utf8)
210    }
211
212    fn invoke_with_args(
213        &self,
214        args: datafusion_expr::ScalarFunctionArgs,
215    ) -> Result<ColumnarValue> {
216        make_scalar_function(array_to_string_inner)(&args.args)
217    }
218
219    fn aliases(&self) -> &[String] {
220        &self.aliases
221    }
222
223    fn documentation(&self) -> Option<&Documentation> {
224        self.doc()
225    }
226}
227
228make_udf_expr_and_func!(
229    StringToArray,
230    string_to_array,
231    string delimiter null_string, // arg name
232    "splits a `string` based on a `delimiter` and returns an array of parts. Any parts matching the optional `null_string` will be replaced with `NULL`", // doc
233    string_to_array_udf // internal function name
234);
235
236#[user_doc(
237    doc_section(label = "Array Functions"),
238    description = "Splits a string into an array of substrings based on a delimiter. Any substrings matching the optional `null_str` argument are replaced with NULL.",
239    syntax_example = "string_to_array(str, delimiter[, null_str])",
240    sql_example = r#"```sql
241> select string_to_array('abc##def', '##');
242+-----------------------------------+
243| string_to_array(Utf8('abc##def'))  |
244+-----------------------------------+
245| ['abc', 'def']                    |
246+-----------------------------------+
247> select string_to_array('abc def', ' ', 'def');
248+---------------------------------------------+
249| string_to_array(Utf8('abc def'), Utf8(' '), Utf8('def')) |
250+---------------------------------------------+
251| ['abc', NULL]                               |
252+---------------------------------------------+
253```"#,
254    argument(name = "str", description = "String expression to split."),
255    argument(name = "delimiter", description = "Delimiter string to split on."),
256    argument(
257        name = "null_str",
258        description = "Substring values to be replaced with `NULL`."
259    )
260)]
261#[derive(Debug, PartialEq, Eq, Hash)]
262pub(super) struct StringToArray {
263    signature: Signature,
264    aliases: Vec<String>,
265}
266
267impl StringToArray {
268    pub fn new() -> Self {
269        Self {
270            signature: Signature::one_of(
271                vec![
272                    TypeSignature::Coercible(vec![
273                        Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
274                        Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
275                    ]),
276                    TypeSignature::Coercible(vec![
277                        Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
278                        Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
279                        Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
280                    ]),
281                ],
282                Volatility::Immutable,
283            ),
284            aliases: vec![String::from("string_to_list")],
285        }
286    }
287}
288
289impl ScalarUDFImpl for StringToArray {
290    fn as_any(&self) -> &dyn Any {
291        self
292    }
293
294    fn name(&self) -> &str {
295        "string_to_array"
296    }
297
298    fn signature(&self) -> &Signature {
299        &self.signature
300    }
301
302    fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
303        Ok(List(Arc::new(Field::new_list_field(
304            arg_types[0].clone(),
305            true,
306        ))))
307    }
308
309    fn invoke_with_args(
310        &self,
311        args: datafusion_expr::ScalarFunctionArgs,
312    ) -> Result<ColumnarValue> {
313        let args = &args.args;
314        match args[0].data_type() {
315            Utf8 | Utf8View => make_scalar_function(string_to_array_inner::<i32>)(args),
316            LargeUtf8 => make_scalar_function(string_to_array_inner::<i64>)(args),
317            other => {
318                exec_err!("unsupported type for string_to_array function as {other:?}")
319            }
320        }
321    }
322
323    fn aliases(&self) -> &[String] {
324        &self.aliases
325    }
326
327    fn documentation(&self) -> Option<&Documentation> {
328        self.doc()
329    }
330}
331
332fn array_to_string_inner(args: &[ArrayRef]) -> Result<ArrayRef> {
333    if args.len() < 2 || args.len() > 3 {
334        return exec_err!("array_to_string expects two or three arguments");
335    }
336
337    let arr = &args[0];
338
339    let delimiters: Vec<Option<&str>> = match args[1].data_type() {
340        Utf8 => args[1].as_string::<i32>().iter().collect(),
341        Utf8View => args[1].as_string_view().iter().collect(),
342        LargeUtf8 => args[1].as_string::<i64>().iter().collect(),
343        other => {
344            return exec_err!(
345                "unsupported type for second argument to array_to_string function as {other:?}"
346            );
347        }
348    };
349
350    let mut null_string = String::from("");
351    let mut with_null_string = false;
352    if args.len() == 3 {
353        null_string = match args[2].data_type() {
354            Utf8 => args[2].as_string::<i32>().value(0).to_string(),
355            Utf8View => args[2].as_string_view().value(0).to_string(),
356            LargeUtf8 => args[2].as_string::<i64>().value(0).to_string(),
357            other => {
358                return exec_err!(
359                    "unsupported type for second argument to array_to_string function as {other:?}"
360                );
361            }
362        };
363        with_null_string = true;
364    }
365
366    /// Creates a single string from single element of a ListArray (which is
367    /// itself another Array)
368    fn compute_array_to_string<'a>(
369        arg: &'a mut String,
370        arr: &ArrayRef,
371        delimiter: String,
372        null_string: String,
373        with_null_string: bool,
374    ) -> Result<&'a mut String> {
375        match arr.data_type() {
376            List(..) => {
377                let list_array = as_list_array(&arr)?;
378                for i in 0..list_array.len() {
379                    if !list_array.is_null(i) {
380                        compute_array_to_string(
381                            arg,
382                            &list_array.value(i),
383                            delimiter.clone(),
384                            null_string.clone(),
385                            with_null_string,
386                        )?;
387                    } else if with_null_string {
388                        arg.push_str(&null_string);
389                        arg.push_str(&delimiter);
390                    }
391                }
392
393                Ok(arg)
394            }
395            FixedSizeList(..) => {
396                let list_array = as_fixed_size_list_array(&arr)?;
397
398                for i in 0..list_array.len() {
399                    if !list_array.is_null(i) {
400                        compute_array_to_string(
401                            arg,
402                            &list_array.value(i),
403                            delimiter.clone(),
404                            null_string.clone(),
405                            with_null_string,
406                        )?;
407                    } else if with_null_string {
408                        arg.push_str(&null_string);
409                        arg.push_str(&delimiter);
410                    }
411                }
412
413                Ok(arg)
414            }
415            LargeList(..) => {
416                let list_array = as_large_list_array(&arr)?;
417                for i in 0..list_array.len() {
418                    if !list_array.is_null(i) {
419                        compute_array_to_string(
420                            arg,
421                            &list_array.value(i),
422                            delimiter.clone(),
423                            null_string.clone(),
424                            with_null_string,
425                        )?;
426                    } else if with_null_string {
427                        arg.push_str(&null_string);
428                        arg.push_str(&delimiter);
429                    }
430                }
431
432                Ok(arg)
433            }
434            Dictionary(_key_type, value_type) => {
435                // Call cast to unwrap the dictionary. This could be optimized if we wanted
436                // to accept the overhead of extra code
437                let values = cast(&arr, value_type.as_ref()).map_err(|e| {
438                    DataFusionError::from(e).context(
439                        "Casting dictionary to values in compute_array_to_string",
440                    )
441                })?;
442                compute_array_to_string(
443                    arg,
444                    &values,
445                    delimiter,
446                    null_string,
447                    with_null_string,
448                )
449            }
450            Null => Ok(arg),
451            data_type => {
452                macro_rules! array_function {
453                    ($ARRAY_TYPE:ident) => {
454                        to_string!(
455                            arg,
456                            arr,
457                            &delimiter,
458                            &null_string,
459                            with_null_string,
460                            $ARRAY_TYPE
461                        )
462                    };
463                }
464                call_array_function!(data_type, false)
465            }
466        }
467    }
468
469    fn generate_string_array<O: OffsetSizeTrait>(
470        list_arr: &GenericListArray<O>,
471        delimiters: &[Option<&str>],
472        null_string: &str,
473        with_null_string: bool,
474    ) -> Result<StringArray> {
475        let mut res: Vec<Option<String>> = Vec::new();
476        for (arr, &delimiter) in list_arr.iter().zip(delimiters.iter()) {
477            if let (Some(arr), Some(delimiter)) = (arr, delimiter) {
478                let mut arg = String::from("");
479                let s = compute_array_to_string(
480                    &mut arg,
481                    &arr,
482                    delimiter.to_string(),
483                    null_string.to_string(),
484                    with_null_string,
485                )?
486                .clone();
487
488                if let Some(s) = s.strip_suffix(delimiter) {
489                    res.push(Some(s.to_string()));
490                } else {
491                    res.push(Some(s));
492                }
493            } else {
494                res.push(None);
495            }
496        }
497
498        Ok(StringArray::from(res))
499    }
500
501    let string_arr = match arr.data_type() {
502        List(_) => {
503            let list_array = as_list_array(&arr)?;
504            generate_string_array::<i32>(
505                list_array,
506                &delimiters,
507                &null_string,
508                with_null_string,
509            )?
510        }
511        LargeList(_) => {
512            let list_array = as_large_list_array(&arr)?;
513            generate_string_array::<i64>(
514                list_array,
515                &delimiters,
516                &null_string,
517                with_null_string,
518            )?
519        }
520        // Signature guards against this arm
521        _ => return exec_err!("array_to_string expects list as first argument"),
522    };
523
524    Ok(Arc::new(string_arr))
525}
526
527/// String_to_array SQL function
528/// Splits string at occurrences of delimiter and returns an array of parts
529/// string_to_array('abc~@~def~@~ghi', '~@~') = '["abc", "def", "ghi"]'
530fn string_to_array_inner<T: OffsetSizeTrait>(args: &[ArrayRef]) -> Result<ArrayRef> {
531    if args.len() < 2 || args.len() > 3 {
532        return exec_err!("string_to_array expects two or three arguments");
533    }
534
535    match args[0].data_type() {
536        Utf8 => {
537            let string_array = args[0].as_string::<T>();
538            let builder = StringBuilder::with_capacity(
539                string_array.len(),
540                string_array.get_buffer_memory_size(),
541            );
542            string_to_array_inner_2::<&GenericStringArray<T>, StringBuilder>(
543                args,
544                &string_array,
545                builder,
546            )
547        }
548        Utf8View => {
549            let string_array = args[0].as_string_view();
550            let builder = StringViewBuilder::with_capacity(string_array.len());
551            string_to_array_inner_2::<&StringViewArray, StringViewBuilder>(
552                args,
553                &string_array,
554                builder,
555            )
556        }
557        LargeUtf8 => {
558            let string_array = args[0].as_string::<T>();
559            let builder = LargeStringBuilder::with_capacity(
560                string_array.len(),
561                string_array.get_buffer_memory_size(),
562            );
563            string_to_array_inner_2::<&GenericStringArray<T>, LargeStringBuilder>(
564                args,
565                &string_array,
566                builder,
567            )
568        }
569        other => exec_err!(
570            "unsupported type for first argument to string_to_array function as {other:?}"
571        ),
572    }
573}
574
575fn string_to_array_inner_2<'a, StringArrType, StringBuilderType>(
576    args: &'a [ArrayRef],
577    string_array: &StringArrType,
578    string_builder: StringBuilderType,
579) -> Result<ArrayRef>
580where
581    StringArrType: StringArrayType<'a>,
582    StringBuilderType: StringArrayBuilderType,
583{
584    match args[1].data_type() {
585        Utf8 => {
586            let delimiter_array = args[1].as_string::<i32>();
587            if args.len() == 2 {
588                string_to_array_impl::<
589                    StringArrType,
590                    &GenericStringArray<i32>,
591                    &StringViewArray,
592                    StringBuilderType,
593                >(string_array, &delimiter_array, None, string_builder)
594            } else {
595                string_to_array_inner_3::<
596                    StringArrType,
597                    &GenericStringArray<i32>,
598                    StringBuilderType,
599                >(args, string_array, &delimiter_array, string_builder)
600            }
601        }
602        Utf8View => {
603            let delimiter_array = args[1].as_string_view();
604
605            if args.len() == 2 {
606                string_to_array_impl::<
607                    StringArrType,
608                    &StringViewArray,
609                    &StringViewArray,
610                    StringBuilderType,
611                >(string_array, &delimiter_array, None, string_builder)
612            } else {
613                string_to_array_inner_3::<
614                    StringArrType,
615                    &StringViewArray,
616                    StringBuilderType,
617                >(args, string_array, &delimiter_array, string_builder)
618            }
619        }
620        LargeUtf8 => {
621            let delimiter_array = args[1].as_string::<i64>();
622            if args.len() == 2 {
623                string_to_array_impl::<
624                    StringArrType,
625                    &GenericStringArray<i64>,
626                    &StringViewArray,
627                    StringBuilderType,
628                >(string_array, &delimiter_array, None, string_builder)
629            } else {
630                string_to_array_inner_3::<
631                    StringArrType,
632                    &GenericStringArray<i64>,
633                    StringBuilderType,
634                >(args, string_array, &delimiter_array, string_builder)
635            }
636        }
637        other => exec_err!(
638            "unsupported type for second argument to string_to_array function as {other:?}"
639        ),
640    }
641}
642
643fn string_to_array_inner_3<'a, StringArrType, DelimiterArrType, StringBuilderType>(
644    args: &'a [ArrayRef],
645    string_array: &StringArrType,
646    delimiter_array: &DelimiterArrType,
647    string_builder: StringBuilderType,
648) -> Result<ArrayRef>
649where
650    StringArrType: StringArrayType<'a>,
651    DelimiterArrType: StringArrayType<'a>,
652    StringBuilderType: StringArrayBuilderType,
653{
654    match args[2].data_type() {
655        Utf8 => {
656            let null_type_array = Some(args[2].as_string::<i32>());
657            string_to_array_impl::<
658                StringArrType,
659                DelimiterArrType,
660                &GenericStringArray<i32>,
661                StringBuilderType,
662            >(
663                string_array,
664                delimiter_array,
665                null_type_array,
666                string_builder,
667            )
668        }
669        Utf8View => {
670            let null_type_array = Some(args[2].as_string_view());
671            string_to_array_impl::<
672                StringArrType,
673                DelimiterArrType,
674                &StringViewArray,
675                StringBuilderType,
676            >(
677                string_array,
678                delimiter_array,
679                null_type_array,
680                string_builder,
681            )
682        }
683        LargeUtf8 => {
684            let null_type_array = Some(args[2].as_string::<i64>());
685            string_to_array_impl::<
686                StringArrType,
687                DelimiterArrType,
688                &GenericStringArray<i64>,
689                StringBuilderType,
690            >(
691                string_array,
692                delimiter_array,
693                null_type_array,
694                string_builder,
695            )
696        }
697        other => {
698            exec_err!("unsupported type for string_to_array function as {other:?}")
699        }
700    }
701}
702
703fn string_to_array_impl<
704    'a,
705    StringArrType,
706    DelimiterArrType,
707    NullValueArrType,
708    StringBuilderType,
709>(
710    string_array: &StringArrType,
711    delimiter_array: &DelimiterArrType,
712    null_value_array: Option<NullValueArrType>,
713    string_builder: StringBuilderType,
714) -> Result<ArrayRef>
715where
716    StringArrType: StringArrayType<'a>,
717    DelimiterArrType: StringArrayType<'a>,
718    NullValueArrType: StringArrayType<'a>,
719    StringBuilderType: StringArrayBuilderType,
720{
721    let mut list_builder = ListBuilder::new(string_builder);
722
723    match null_value_array {
724        None => {
725            string_array.iter().zip(delimiter_array.iter()).for_each(
726                |(string, delimiter)| {
727                    match (string, delimiter) {
728                        (Some(string), Some("")) => {
729                            list_builder.values().append_value(string);
730                            list_builder.append(true);
731                        }
732                        (Some(string), Some(delimiter)) => {
733                            string.split(delimiter).for_each(|s| {
734                                list_builder.values().append_value(s);
735                            });
736                            list_builder.append(true);
737                        }
738                        (Some(string), None) => {
739                            string.chars().map(|c| c.to_string()).for_each(|c| {
740                                list_builder.values().append_value(c.as_str());
741                            });
742                            list_builder.append(true);
743                        }
744                        _ => list_builder.append(false), // null value
745                    }
746                },
747            )
748        }
749        Some(null_value_array) => string_array
750            .iter()
751            .zip(delimiter_array.iter())
752            .zip(null_value_array.iter())
753            .for_each(|((string, delimiter), null_value)| {
754                match (string, delimiter) {
755                    (Some(string), Some("")) => {
756                        if Some(string) == null_value {
757                            list_builder.values().append_null();
758                        } else {
759                            list_builder.values().append_value(string);
760                        }
761                        list_builder.append(true);
762                    }
763                    (Some(string), Some(delimiter)) => {
764                        string.split(delimiter).for_each(|s| {
765                            if Some(s) == null_value {
766                                list_builder.values().append_null();
767                            } else {
768                                list_builder.values().append_value(s);
769                            }
770                        });
771                        list_builder.append(true);
772                    }
773                    (Some(string), None) => {
774                        string.chars().map(|c| c.to_string()).for_each(|c| {
775                            if Some(c.as_str()) == null_value {
776                                list_builder.values().append_null();
777                            } else {
778                                list_builder.values().append_value(c.as_str());
779                            }
780                        });
781                        list_builder.append(true);
782                    }
783                    _ => list_builder.append(false), // null value
784                }
785            }),
786    };
787
788    let list_array = list_builder.finish();
789    Ok(Arc::new(list_array) as ArrayRef)
790}
791
792trait StringArrayBuilderType: ArrayBuilder {
793    fn append_value(&mut self, val: &str);
794
795    fn append_null(&mut self);
796}
797
798impl StringArrayBuilderType for StringBuilder {
799    fn append_value(&mut self, val: &str) {
800        StringBuilder::append_value(self, val);
801    }
802
803    fn append_null(&mut self) {
804        StringBuilder::append_null(self);
805    }
806}
807
808impl StringArrayBuilderType for StringViewBuilder {
809    fn append_value(&mut self, val: &str) {
810        StringViewBuilder::append_value(self, val)
811    }
812
813    fn append_null(&mut self) {
814        StringViewBuilder::append_null(self)
815    }
816}
817
818impl StringArrayBuilderType for LargeStringBuilder {
819    fn append_value(&mut self, val: &str) {
820        LargeStringBuilder::append_value(self, val);
821    }
822
823    fn append_null(&mut self) {
824        LargeStringBuilder::append_null(self);
825    }
826}