mz_expr/scalar/func/impls/
array.rs1use std::fmt;
11
12use mz_expr_derive::sqlfunc;
13use mz_lowertest::MzReflect;
14use mz_repr::adt::array::{Array, ArrayDimension};
15use mz_repr::{Datum, DatumList, Row, RowArena, RowPacker, SqlColumnType, SqlScalarType};
16use serde::{Deserialize, Serialize};
17
18use crate::scalar::func::{LazyUnaryFunc, stringify_datum};
19use crate::{Eval, EvalError, MirScalarExpr};
20
21#[sqlfunc(sqlname = "arraytolist", introduces_nulls = false)]
25fn cast_array_to_list_one_dim<'a, T>(a: Array<'a, T>) -> Result<DatumList<'a, T>, EvalError> {
26 let ndims = a.dims().ndims();
27 if ndims > 1 {
28 return Err(EvalError::Unsupported {
29 feature: format!(
30 "casting multi-dimensional array to list; got array with {} dimensions",
31 ndims
32 )
33 .into(),
34 discussion_no: None,
35 });
36 }
37 Ok(a.elements())
38}
39
40#[derive(
41 Ord,
42 PartialOrd,
43 Clone,
44 Debug,
45 Eq,
46 PartialEq,
47 Serialize,
48 Deserialize,
49 Hash,
50 MzReflect
51)]
52pub struct CastArrayToString {
53 pub ty: SqlScalarType,
54}
55
56impl LazyUnaryFunc for CastArrayToString {
57 fn eval<'a>(
58 &'a self,
59 datums: &[Datum<'a>],
60 temp_storage: &'a RowArena,
61 a: &'a impl Eval,
62 ) -> Result<Datum<'a>, EvalError> {
63 let a = a.eval(datums, temp_storage)?;
64 if a.is_null() {
65 return Ok(Datum::Null);
66 }
67 let mut buf = String::new();
68 stringify_datum(&mut buf, a, &self.ty)?;
69 Ok(Datum::String(temp_storage.push_string(buf)))
70 }
71
72 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
73 SqlScalarType::String.nullable(input_type.nullable)
74 }
75
76 fn propagates_nulls(&self) -> bool {
77 true
78 }
79
80 fn introduces_nulls(&self) -> bool {
81 false
82 }
83
84 fn preserves_uniqueness(&self) -> bool {
85 true
86 }
87
88 fn inverse(&self) -> Option<crate::UnaryFunc> {
89 None
92 }
93
94 fn is_monotone(&self) -> bool {
95 false
96 }
97
98 fn is_eliminable_cast(&self) -> bool {
99 false
100 }
101}
102
103impl fmt::Display for CastArrayToString {
104 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 f.write_str("arraytostr")
106 }
107}
108
109#[derive(
110 Ord,
111 PartialOrd,
112 Clone,
113 Debug,
114 Eq,
115 PartialEq,
116 Serialize,
117 Deserialize,
118 Hash,
119 MzReflect
120)]
121pub struct CastArrayToJsonb {
122 pub cast_element: Box<MirScalarExpr>,
123}
124
125impl LazyUnaryFunc for CastArrayToJsonb {
126 fn eval<'a>(
127 &'a self,
128 datums: &[Datum<'a>],
129 temp_storage: &'a RowArena,
130 a: &'a impl Eval,
131 ) -> Result<Datum<'a>, EvalError> {
132 fn pack<'a>(
133 temp_storage: &RowArena,
134 elems: &mut impl Iterator<Item = Datum<'a>>,
135 dims: &[ArrayDimension],
136 cast_element: &MirScalarExpr,
137 packer: &mut RowPacker,
138 ) -> Result<(), EvalError> {
139 packer.push_list_with(|packer| match dims {
140 [] => Ok(()),
141 [dim] => {
142 for _ in 0..dim.length {
143 let elem = elems.next().unwrap();
144 let elem = match cast_element.eval(&[elem], temp_storage)? {
145 Datum::Null => Datum::JsonNull,
146 d => d,
147 };
148 packer.push(elem);
149 }
150 Ok(())
151 }
152 [dim, rest @ ..] => {
153 for _ in 0..dim.length {
154 pack(temp_storage, elems, rest, cast_element, packer)?;
155 }
156 Ok(())
157 }
158 })
159 }
160
161 let a = a.eval(datums, temp_storage)?;
162 if a.is_null() {
163 return Ok(Datum::Null);
164 }
165 let a = a.unwrap_array();
166 let elements = a.elements();
167 let dims = a.dims().into_iter().collect::<Vec<_>>();
168 let mut row = Row::default();
169 pack(
170 temp_storage,
171 &mut elements.into_iter(),
172 &dims,
173 &self.cast_element,
174 &mut row.packer(),
175 )?;
176 Ok(temp_storage.push_unary_row(row))
177 }
178
179 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
180 SqlScalarType::Jsonb.nullable(input_type.nullable)
181 }
182
183 fn propagates_nulls(&self) -> bool {
184 true
185 }
186
187 fn introduces_nulls(&self) -> bool {
188 false
189 }
190
191 fn preserves_uniqueness(&self) -> bool {
192 false
197 }
198
199 fn inverse(&self) -> Option<crate::UnaryFunc> {
200 None
203 }
204
205 fn is_monotone(&self) -> bool {
206 false
207 }
208
209 fn is_eliminable_cast(&self) -> bool {
210 false
211 }
212}
213
214impl fmt::Display for CastArrayToJsonb {
215 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
216 f.write_str("arraytojsonb")
217 }
218}
219
220#[derive(
224 Ord,
225 PartialOrd,
226 Clone,
227 Debug,
228 Eq,
229 PartialEq,
230 Serialize,
231 Deserialize,
232 Hash,
233 MzReflect
234)]
235pub struct CastArrayToArray {
236 pub return_ty: SqlScalarType,
237 pub cast_expr: Box<MirScalarExpr>,
238}
239
240impl LazyUnaryFunc for CastArrayToArray {
241 fn eval<'a>(
242 &'a self,
243 datums: &[Datum<'a>],
244 temp_storage: &'a RowArena,
245 a: &'a impl Eval,
246 ) -> Result<Datum<'a>, EvalError> {
247 let a = a.eval(datums, temp_storage)?;
248 if a.is_null() {
249 return Ok(Datum::Null);
250 }
251
252 let arr = a.unwrap_array();
253 let dims = arr.dims().into_iter().collect::<Vec<ArrayDimension>>();
254
255 let casted_datums = arr
256 .elements()
257 .iter()
258 .map(|datum| self.cast_expr.eval(&[datum], temp_storage))
259 .collect::<Result<Vec<Datum<'a>>, EvalError>>()?;
260
261 Ok(temp_storage.try_make_datum(|packer| packer.try_push_array(&dims, casted_datums))?)
262 }
263
264 fn output_sql_type(&self, _input_type: SqlColumnType) -> SqlColumnType {
265 self.return_ty.clone().nullable(true)
266 }
267
268 fn propagates_nulls(&self) -> bool {
269 true
270 }
271
272 fn introduces_nulls(&self) -> bool {
273 false
274 }
275
276 fn preserves_uniqueness(&self) -> bool {
277 false
278 }
279
280 fn inverse(&self) -> Option<crate::UnaryFunc> {
281 None
282 }
283
284 fn is_monotone(&self) -> bool {
285 false
286 }
287
288 fn is_eliminable_cast(&self) -> bool {
289 false
290 }
291}
292
293impl fmt::Display for CastArrayToArray {
294 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
295 f.write_str("arraytoarray")
296 }
297}