mz_expr/scalar/func/impls/
record.rs1use std::fmt;
11
12use itertools::Itertools;
13use mz_repr::{Datum, 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 CastRecordToString {
31 pub ty: SqlScalarType,
32}
33
34impl LazyUnaryFunc for CastRecordToString {
35 fn eval<'a>(
36 &'a self,
37 datums: &[Datum<'a>],
38 temp_storage: &'a RowArena,
39 a: &'a impl Eval,
40 ) -> Result<Datum<'a>, EvalError> {
41 let a = a.eval(datums, temp_storage)?;
42 if a.is_null() {
43 return Ok(Datum::Null);
44 }
45 let mut buf = String::new();
46 stringify_datum(&mut buf, a, &self.ty)?;
47 Ok(Datum::String(temp_storage.push_string(buf)))
48 }
49
50 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
51 SqlScalarType::String.nullable(input_type.nullable)
52 }
53
54 fn propagates_nulls(&self) -> bool {
55 true
56 }
57
58 fn introduces_nulls(&self) -> bool {
59 false
60 }
61
62 fn preserves_uniqueness(&self) -> bool {
63 true
64 }
65
66 fn inverse(&self) -> Option<crate::UnaryFunc> {
67 None
69 }
70
71 fn is_monotone(&self) -> bool {
72 false
73 }
74
75 fn is_eliminable_cast(&self) -> bool {
76 false
77 }
78}
79
80impl fmt::Display for CastRecordToString {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 f.write_str("recordtostr")
83 }
84}
85
86#[derive(
89 Ord,
90 PartialOrd,
91 Clone,
92 Debug,
93 Eq,
94 PartialEq,
95 Serialize,
96 Deserialize,
97 Hash
98)]
99pub struct CastRecord1ToRecord2<E = MirScalarExpr> {
100 pub return_ty: SqlScalarType,
101 pub cast_exprs: Box<[E]>,
102}
103
104impl<E: Eval> LazyUnaryFunc for CastRecord1ToRecord2<E> {
105 fn eval<'a>(
106 &'a self,
107 datums: &[Datum<'a>],
108 temp_storage: &'a RowArena,
109 a: &'a impl Eval,
110 ) -> Result<Datum<'a>, EvalError> {
111 let a = a.eval(datums, temp_storage)?;
112 if a.is_null() {
113 return Ok(Datum::Null);
114 }
115 let mut cast_datums = Vec::new();
116 for (el, cast_expr) in a.unwrap_list().iter().zip_eq(&self.cast_exprs) {
117 cast_datums.push(cast_expr.eval(&[el], temp_storage)?);
118 }
119 Ok(temp_storage.make_datum(|packer| packer.push_list(cast_datums)))
120 }
121
122 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
123 self.return_ty
124 .without_modifiers()
125 .nullable(input_type.nullable)
126 }
127
128 fn propagates_nulls(&self) -> bool {
129 true
130 }
131
132 fn introduces_nulls(&self) -> bool {
133 false
134 }
135
136 fn preserves_uniqueness(&self) -> bool {
137 false
138 }
139
140 fn inverse(&self) -> Option<crate::UnaryFunc> {
141 None
143 }
144
145 fn is_monotone(&self) -> bool {
146 false
150 }
151
152 fn is_eliminable_cast(&self) -> bool {
153 false
154 }
155}
156
157impl<E> CastRecord1ToRecord2<E> {
158 pub fn try_map_expr<'a, E2: TryFrom<&'a E>>(
162 &'a self,
163 ) -> Result<CastRecord1ToRecord2<E2>, E2::Error> {
164 Ok(CastRecord1ToRecord2 {
165 return_ty: self.return_ty.clone(),
166 cast_exprs: self
167 .cast_exprs
168 .iter()
169 .map(E2::try_from)
170 .collect::<Result<Box<[E2]>, _>>()?,
171 })
172 }
173
174 pub fn map_expr<'a, E2: From<&'a E>>(&'a self) -> CastRecord1ToRecord2<E2> {
177 CastRecord1ToRecord2 {
178 return_ty: self.return_ty.clone(),
179 cast_exprs: self.cast_exprs.iter().map(E2::from).collect(),
180 }
181 }
182}
183
184impl<E> fmt::Display for CastRecord1ToRecord2<E> {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 f.write_str("record1torecord2")
187 }
188}
189
190#[derive(
191 Ord,
192 PartialOrd,
193 Clone,
194 Debug,
195 Eq,
196 PartialEq,
197 Serialize,
198 Deserialize,
199 Hash
200)]
201pub struct RecordGet(pub usize);
202
203impl LazyUnaryFunc for RecordGet {
204 fn eval<'a>(
205 &'a self,
206 datums: &[Datum<'a>],
207 temp_storage: &'a RowArena,
208 a: &'a impl Eval,
209 ) -> Result<Datum<'a>, EvalError> {
210 let a = a.eval(datums, temp_storage)?;
211 if a.is_null() {
212 return Ok(Datum::Null);
213 }
214 Ok(a.unwrap_list().iter().nth(self.0).unwrap())
215 }
216
217 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
218 match input_type.scalar_type {
219 SqlScalarType::Record { fields, .. } => {
220 let (_name, ty) = &fields[self.0];
221 let mut ty = ty.clone();
222 ty.nullable = ty.nullable || input_type.nullable;
223 ty
224 }
225 _ => unreachable!(
226 "RecordGet on non-record input: {:?}",
227 input_type.scalar_type
228 ),
229 }
230 }
231
232 fn propagates_nulls(&self) -> bool {
233 true
234 }
235
236 fn introduces_nulls(&self) -> bool {
237 true
239 }
240
241 fn preserves_uniqueness(&self) -> bool {
242 false
243 }
244
245 fn inverse(&self) -> Option<crate::UnaryFunc> {
246 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 fmt::Display for RecordGet {
259 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260 write!(f, "record_get[{}]", self.0)
261 }
262}