risingwave_expr_impl/scalar/
array_to_string.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![allow(clippy::unit_arg)]
16
17use risingwave_common::array::*;
18use risingwave_common::types::ToText;
19use risingwave_expr::expr::Context;
20use risingwave_expr::function;
21
22/// Converts each array element to its text representation, and concatenates those
23/// separated by the delimiter string. If `null_string` is given and is not NULL,
24/// then NULL array entries are represented by that string; otherwise, they are omitted.
25///
26/// ```sql
27/// array_to_string ( array anyarray, delimiter text [, null_string text ] ) → text
28/// ```
29///
30/// Examples:
31///
32/// ```slt
33/// query T
34/// select array_to_string(array[1, 2, 3, NULL, 5], ',')
35/// ----
36/// 1,2,3,5
37///
38/// query T
39/// select array_to_string(array[1, 2, 3, NULL, 5], ',', '*')
40/// ----
41/// 1,2,3,*,5
42///
43/// query T
44/// select array_to_string(array[null,'foo',null], ',', '*');
45/// ----
46/// *,foo,*
47///
48/// query T
49/// select array_to_string(array['2023-02-20 17:35:25'::timestamp, null,'2023-02-19 13:01:30'::timestamp], ',', '*');
50/// ----
51/// 2023-02-20 17:35:25,*,2023-02-19 13:01:30
52///
53/// query T
54/// with t as (
55///   select array[1,null,2,3] as arr, ',' as d union all
56///   select array[4,5,6,null,7] as arr, '|')
57/// select array_to_string(arr, d) from t;
58/// ----
59/// 1,2,3
60/// 4|5|6|7
61///
62/// # `array` or `delimiter` are required. Otherwise, returns null.
63/// query T
64/// select array_to_string(array[1,2], NULL);
65/// ----
66/// NULL
67///
68/// query error polymorphic type
69/// select array_to_string(null, ',');
70///
71/// # multidimensional array
72/// query T
73/// select array_to_string(array[array['one', null], array['three', 'four']]::text[][], ',');
74/// ----
75/// one,three,four
76///
77/// query T
78/// select array_to_string(array[array['one', null], array['three', 'four']]::text[][], ',', '*');
79/// ----
80/// one,*,three,four
81/// ```
82#[function("array_to_string(anyarray, varchar) -> varchar")]
83fn array_to_string(
84    array: ListRef<'_>,
85    delimiter: &str,
86    ctx: &Context,
87    writer: &mut impl std::fmt::Write,
88) {
89    let element_data_type = ctx.arg_types[0].unnest_list();
90    let mut first = true;
91    for element in array.flatten().iter() {
92        let Some(element) = element else { continue };
93        if !first {
94            write!(writer, "{}", delimiter).unwrap();
95        } else {
96            first = false;
97        }
98        element.write_with_type(element_data_type, writer).unwrap();
99    }
100}
101
102#[function("array_to_string(anyarray, varchar, varchar) -> varchar")]
103fn array_to_string_with_null(
104    array: ListRef<'_>,
105    delimiter: &str,
106    null_string: &str,
107    ctx: &Context,
108    writer: &mut impl std::fmt::Write,
109) {
110    let element_data_type = ctx.arg_types[0].unnest_list();
111    let mut first = true;
112    for element in array.flatten().iter() {
113        if !first {
114            write!(writer, "{}", delimiter).unwrap();
115        } else {
116            first = false;
117        }
118        match element {
119            Some(s) => s.write_with_type(element_data_type, writer).unwrap(),
120            None => write!(writer, "{}", null_string).unwrap(),
121        }
122    }
123}