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