mz_expr/scalar/func/impls/
list.rs1use std::fmt;
11
12use mz_expr_derive::sqlfunc;
13use mz_repr::{Datum, DatumList, ExcludeNull, Row, RowArena, SqlColumnType, SqlScalarType};
14use serde::{Deserialize, Serialize};
15
16use crate::scalar::func::{LazyUnaryFunc, stringify_datum};
17use crate::{Eval, EvalError, MirScalarExpr};
18
19#[derive(
20 Ord,
21 PartialOrd,
22 Clone,
23 Debug,
24 Eq,
25 PartialEq,
26 Serialize,
27 Deserialize,
28 Hash
29)]
30pub struct CastListToString {
31 pub ty: SqlScalarType,
32}
33
34#[sqlfunc(CastListToString, sqlname = "listtostr", preserves_uniqueness = true)]
36fn cast_list_to_string<'a>(&self, a: ExcludeNull<Datum<'a>>) -> Result<String, EvalError> {
37 let mut buf = String::new();
38 stringify_datum(&mut buf, *a, &self.ty)?;
39 Ok(buf)
40}
41
42#[derive(
43 Ord,
44 PartialOrd,
45 Clone,
46 Debug,
47 Eq,
48 PartialEq,
49 Serialize,
50 Deserialize,
51 Hash
52)]
53pub struct CastListToJsonb<E = MirScalarExpr> {
54 pub cast_element: Box<E>,
55}
56
57impl<E: Eval> LazyUnaryFunc for CastListToJsonb<E> {
58 fn eval<'a>(
59 &'a self,
60 datums: &[Datum<'a>],
61 temp_storage: &'a RowArena,
62 a: &'a impl Eval,
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 row = Row::default();
69 row.packer().push_list_with(|packer| {
70 for elem in a.unwrap_list().iter() {
71 let elem = match self.cast_element.eval(&[elem], temp_storage)? {
72 Datum::Null => Datum::JsonNull,
73 d => d,
74 };
75 packer.push(elem);
76 }
77 Ok::<_, EvalError>(())
78 })?;
79 Ok(temp_storage.push_unary_row(row))
80 }
81
82 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
83 SqlScalarType::Jsonb.nullable(input_type.nullable)
84 }
85
86 fn propagates_nulls(&self) -> bool {
87 true
88 }
89
90 fn introduces_nulls(&self) -> bool {
91 false
92 }
93
94 fn preserves_uniqueness(&self) -> bool {
95 true
96 }
97
98 fn inverse(&self) -> Option<crate::UnaryFunc> {
99 None
102 }
103
104 fn is_monotone(&self) -> bool {
105 false
106 }
107
108 fn is_eliminable_cast(&self) -> bool {
109 false
110 }
111}
112
113impl<E> CastListToJsonb<E> {
114 pub fn try_map_expr<'a, E2: TryFrom<&'a E>>(
117 &'a self,
118 ) -> Result<CastListToJsonb<E2>, E2::Error> {
119 Ok(CastListToJsonb {
120 cast_element: Box::new(E2::try_from(&*self.cast_element)?),
121 })
122 }
123
124 pub fn map_expr<'a, E2: From<&'a E>>(&'a self) -> CastListToJsonb<E2> {
127 CastListToJsonb {
128 cast_element: Box::new(E2::from(&*self.cast_element)),
129 }
130 }
131}
132
133impl<E> fmt::Display for CastListToJsonb<E> {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 f.write_str("listtojsonb")
136 }
137}
138
139#[derive(
142 Ord,
143 PartialOrd,
144 Clone,
145 Debug,
146 Eq,
147 PartialEq,
148 Serialize,
149 Deserialize,
150 Hash
151)]
152pub struct CastList1ToList2<E = MirScalarExpr> {
153 pub return_ty: SqlScalarType,
155 pub cast_expr: Box<E>,
157}
158
159impl<E: Eval> LazyUnaryFunc for CastList1ToList2<E> {
160 fn eval<'a>(
161 &'a self,
162 datums: &[Datum<'a>],
163 temp_storage: &'a RowArena,
164 a: &'a impl Eval,
165 ) -> Result<Datum<'a>, EvalError> {
166 let a = a.eval(datums, temp_storage)?;
167 if a.is_null() {
168 return Ok(Datum::Null);
169 }
170 let mut cast_datums = Vec::new();
171 for el in a.unwrap_list().iter() {
172 cast_datums.push(self.cast_expr.eval(&[el], temp_storage)?);
176 }
177
178 Ok(temp_storage.make_datum(|packer| packer.push_list(cast_datums)))
179 }
180
181 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
182 self.return_ty
183 .without_modifiers()
184 .nullable(input_type.nullable)
185 }
186
187 fn propagates_nulls(&self) -> bool {
188 true
189 }
190
191 fn introduces_nulls(&self) -> bool {
192 false
193 }
194
195 fn preserves_uniqueness(&self) -> bool {
196 false
197 }
198
199 fn inverse(&self) -> Option<crate::UnaryFunc> {
200 None
202 }
203
204 fn is_monotone(&self) -> bool {
205 false
206 }
207
208 fn is_eliminable_cast(&self) -> bool {
209 false
210 }
211}
212
213impl<E> CastList1ToList2<E> {
214 pub fn try_map_expr<'a, E2: TryFrom<&'a E>>(
217 &'a self,
218 ) -> Result<CastList1ToList2<E2>, E2::Error> {
219 Ok(CastList1ToList2 {
220 return_ty: self.return_ty.clone(),
221 cast_expr: Box::new(E2::try_from(&*self.cast_expr)?),
222 })
223 }
224
225 pub fn map_expr<'a, E2: From<&'a E>>(&'a self) -> CastList1ToList2<E2> {
228 CastList1ToList2 {
229 return_ty: self.return_ty.clone(),
230 cast_expr: Box::new(E2::from(&*self.cast_expr)),
231 }
232 }
233}
234
235impl<E> fmt::Display for CastList1ToList2<E> {
236 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237 f.write_str("list1tolist2")
238 }
239}
240
241#[sqlfunc(sqlname = "list_length")]
242fn list_length<'a>(a: DatumList<'a>) -> Result<i32, EvalError> {
243 let count = a.iter().count();
244 count
245 .try_into()
246 .map_err(|_| EvalError::Int32OutOfRange(count.to_string().into()))
247}
248
249#[derive(
251 Ord,
252 PartialOrd,
253 Clone,
254 Debug,
255 Eq,
256 PartialEq,
257 Serialize,
258 Deserialize,
259 Hash
260)]
261pub struct ListLengthMax {
262 pub max_layer: usize,
264}
265#[sqlfunc(ListLengthMax)]
266#[allow(clippy::as_conversions)]
268fn list_length_max<'a>(&self, a: DatumList<'a>, b: i64) -> Result<Option<i32>, EvalError> {
269 fn max_len_on_layer(i: DatumList<'_>, on_layer: i64) -> Option<usize> {
270 let i = i.iter();
271 if on_layer > 1 {
272 let mut max_len = None;
273 for d in i {
274 if let Datum::List(i) = d {
275 max_len = std::cmp::max(max_len_on_layer(i, on_layer - 1), max_len);
276 }
277 }
278 max_len
279 } else {
280 Some(i.count())
281 }
282 }
283 if b as usize > self.max_layer || b < 1 {
284 Err(EvalError::InvalidLayer {
285 max_layer: self.max_layer,
286 val: b,
287 })
288 } else {
289 match max_len_on_layer(a, b) {
290 Some(l) => match l.try_into() {
291 Ok(c) => Ok(Some(c)),
292 Err(_) => Err(EvalError::Int32OutOfRange(l.to_string().into())),
293 },
294 None => Ok(None),
295 }
296 }
297}