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