mz_expr/scalar/func/impls/
list.rs1use std::fmt;
11
12use mz_expr_derive::sqlfunc;
13use mz_repr::{AsColumnType, Datum, DatumList, Row, RowArena, SqlColumnType, SqlScalarType};
14use serde::{Deserialize, Serialize};
15
16use crate::func::binary::EagerBinaryFunc;
17use crate::scalar::func::{LazyUnaryFunc, stringify_datum};
18use crate::{Eval, EvalError, MirScalarExpr};
19
20#[derive(
21 Ord,
22 PartialOrd,
23 Clone,
24 Debug,
25 Eq,
26 PartialEq,
27 Serialize,
28 Deserialize,
29 Hash
30)]
31pub struct CastListToString {
32 pub ty: SqlScalarType,
33}
34
35impl LazyUnaryFunc for CastListToString {
36 fn eval<'a>(
37 &'a self,
38 datums: &[Datum<'a>],
39 temp_storage: &'a RowArena,
40 a: &'a impl Eval,
41 ) -> Result<Datum<'a>, EvalError> {
42 let a = a.eval(datums, temp_storage)?;
43 if a.is_null() {
44 return Ok(Datum::Null);
45 }
46 let mut buf = String::new();
47 stringify_datum(&mut buf, a, &self.ty)?;
48 Ok(Datum::String(temp_storage.push_string(buf)))
49 }
50
51 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
52 SqlScalarType::String.nullable(input_type.nullable)
53 }
54
55 fn propagates_nulls(&self) -> bool {
56 true
57 }
58
59 fn introduces_nulls(&self) -> bool {
60 false
61 }
62
63 fn preserves_uniqueness(&self) -> bool {
64 true
65 }
66
67 fn inverse(&self) -> Option<crate::UnaryFunc> {
68 None
70 }
71
72 fn is_monotone(&self) -> bool {
73 false
74 }
75
76 fn is_eliminable_cast(&self) -> bool {
77 false
78 }
79}
80
81impl fmt::Display for CastListToString {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 f.write_str("listtostr")
84 }
85}
86
87#[derive(
88 Ord,
89 PartialOrd,
90 Clone,
91 Debug,
92 Eq,
93 PartialEq,
94 Serialize,
95 Deserialize,
96 Hash
97)]
98pub struct CastListToJsonb<E = MirScalarExpr> {
99 pub cast_element: Box<E>,
100}
101
102impl<E: Eval> LazyUnaryFunc for CastListToJsonb<E> {
103 fn eval<'a>(
104 &'a self,
105 datums: &[Datum<'a>],
106 temp_storage: &'a RowArena,
107 a: &'a impl Eval,
108 ) -> Result<Datum<'a>, EvalError> {
109 let a = a.eval(datums, temp_storage)?;
110 if a.is_null() {
111 return Ok(Datum::Null);
112 }
113 let mut row = Row::default();
114 row.packer().push_list_with(|packer| {
115 for elem in a.unwrap_list().iter() {
116 let elem = match self.cast_element.eval(&[elem], temp_storage)? {
117 Datum::Null => Datum::JsonNull,
118 d => d,
119 };
120 packer.push(elem);
121 }
122 Ok::<_, EvalError>(())
123 })?;
124 Ok(temp_storage.push_unary_row(row))
125 }
126
127 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
128 SqlScalarType::Jsonb.nullable(input_type.nullable)
129 }
130
131 fn propagates_nulls(&self) -> bool {
132 true
133 }
134
135 fn introduces_nulls(&self) -> bool {
136 false
137 }
138
139 fn preserves_uniqueness(&self) -> bool {
140 true
141 }
142
143 fn inverse(&self) -> Option<crate::UnaryFunc> {
144 None
147 }
148
149 fn is_monotone(&self) -> bool {
150 false
151 }
152
153 fn is_eliminable_cast(&self) -> bool {
154 false
155 }
156}
157
158impl<E> CastListToJsonb<E> {
159 pub fn try_map_expr<'a, E2: TryFrom<&'a E>>(
162 &'a self,
163 ) -> Result<CastListToJsonb<E2>, E2::Error> {
164 Ok(CastListToJsonb {
165 cast_element: Box::new(E2::try_from(&*self.cast_element)?),
166 })
167 }
168
169 pub fn map_expr<'a, E2: From<&'a E>>(&'a self) -> CastListToJsonb<E2> {
172 CastListToJsonb {
173 cast_element: Box::new(E2::from(&*self.cast_element)),
174 }
175 }
176}
177
178impl<E> fmt::Display for CastListToJsonb<E> {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 f.write_str("listtojsonb")
181 }
182}
183
184#[derive(
187 Ord,
188 PartialOrd,
189 Clone,
190 Debug,
191 Eq,
192 PartialEq,
193 Serialize,
194 Deserialize,
195 Hash
196)]
197pub struct CastList1ToList2<E = MirScalarExpr> {
198 pub return_ty: SqlScalarType,
200 pub cast_expr: Box<E>,
202}
203
204impl<E: Eval> LazyUnaryFunc for CastList1ToList2<E> {
205 fn eval<'a>(
206 &'a self,
207 datums: &[Datum<'a>],
208 temp_storage: &'a RowArena,
209 a: &'a impl Eval,
210 ) -> Result<Datum<'a>, EvalError> {
211 let a = a.eval(datums, temp_storage)?;
212 if a.is_null() {
213 return Ok(Datum::Null);
214 }
215 let mut cast_datums = Vec::new();
216 for el in a.unwrap_list().iter() {
217 cast_datums.push(self.cast_expr.eval(&[el], temp_storage)?);
221 }
222
223 Ok(temp_storage.make_datum(|packer| packer.push_list(cast_datums)))
224 }
225
226 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
227 self.return_ty
228 .without_modifiers()
229 .nullable(input_type.nullable)
230 }
231
232 fn propagates_nulls(&self) -> bool {
233 true
234 }
235
236 fn introduces_nulls(&self) -> bool {
237 false
238 }
239
240 fn preserves_uniqueness(&self) -> bool {
241 false
242 }
243
244 fn inverse(&self) -> Option<crate::UnaryFunc> {
245 None
247 }
248
249 fn is_monotone(&self) -> bool {
250 false
251 }
252
253 fn is_eliminable_cast(&self) -> bool {
254 false
255 }
256}
257
258impl<E> CastList1ToList2<E> {
259 pub fn try_map_expr<'a, E2: TryFrom<&'a E>>(
262 &'a self,
263 ) -> Result<CastList1ToList2<E2>, E2::Error> {
264 Ok(CastList1ToList2 {
265 return_ty: self.return_ty.clone(),
266 cast_expr: Box::new(E2::try_from(&*self.cast_expr)?),
267 })
268 }
269
270 pub fn map_expr<'a, E2: From<&'a E>>(&'a self) -> CastList1ToList2<E2> {
273 CastList1ToList2 {
274 return_ty: self.return_ty.clone(),
275 cast_expr: Box::new(E2::from(&*self.cast_expr)),
276 }
277 }
278}
279
280impl<E> fmt::Display for CastList1ToList2<E> {
281 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
282 f.write_str("list1tolist2")
283 }
284}
285
286#[sqlfunc(sqlname = "list_length")]
287fn list_length<'a>(a: DatumList<'a>) -> Result<i32, EvalError> {
288 let count = a.iter().count();
289 count
290 .try_into()
291 .map_err(|_| EvalError::Int32OutOfRange(count.to_string().into()))
292}
293
294#[derive(
298 Ord,
299 PartialOrd,
300 Clone,
301 Debug,
302 Eq,
303 PartialEq,
304 Serialize,
305 Deserialize,
306 Hash
307)]
308pub struct ListLengthMax {
309 pub max_layer: usize,
311}
312impl EagerBinaryFunc for ListLengthMax {
313 type Input<'a> = (DatumList<'a>, i64);
314 type Output<'a> = Result<Option<i32>, EvalError>;
315 #[allow(clippy::as_conversions)]
317 fn call<'a>(&self, (a, b): Self::Input<'a>, _: &'a RowArena) -> Self::Output<'a> {
318 fn max_len_on_layer(i: DatumList<'_>, on_layer: i64) -> Option<usize> {
319 let i = i.iter();
320 if on_layer > 1 {
321 let mut max_len = None;
322 for d in i {
323 if let Datum::List(i) = d {
324 max_len = std::cmp::max(max_len_on_layer(i, on_layer - 1), max_len);
325 }
326 }
327 max_len
328 } else {
329 Some(i.count())
330 }
331 }
332 if b as usize > self.max_layer || b < 1 {
333 Err(EvalError::InvalidLayer {
334 max_layer: self.max_layer,
335 val: b,
336 })
337 } else {
338 match max_len_on_layer(a, b) {
339 Some(l) => match l.try_into() {
340 Ok(c) => Ok(Some(c)),
341 Err(_) => Err(EvalError::Int32OutOfRange(l.to_string().into())),
342 },
343 None => Ok(None),
344 }
345 }
346 }
347 fn output_sql_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
348 let output = Self::Output::as_column_type();
349 let propagates_nulls = self.propagates_nulls();
350 let nullable = output.nullable;
351 let input_nullable = input_types.iter().any(|t| t.nullable);
352 output.nullable(nullable || (propagates_nulls && input_nullable))
353 }
354}
355impl fmt::Display for ListLengthMax {
356 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
357 f.write_str("list_length_max")
358 }
359}