mz_expr/scalar/func/impls/
record.rs1use std::fmt;
11
12use itertools::Itertools;
13use mz_lowertest::MzReflect;
14use mz_repr::{Datum, RowArena, 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 CastRecordToString {
22 pub ty: SqlScalarType,
23}
24
25impl LazyUnaryFunc for CastRecordToString {
26 fn eval<'a>(
27 &'a self,
28 datums: &[Datum<'a>],
29 temp_storage: &'a RowArena,
30 a: &'a MirScalarExpr,
31 ) -> Result<Datum<'a>, EvalError> {
32 let a = a.eval(datums, temp_storage)?;
33 if a.is_null() {
34 return Ok(Datum::Null);
35 }
36 let mut buf = String::new();
37 stringify_datum(&mut buf, a, &self.ty)?;
38 Ok(Datum::String(temp_storage.push_string(buf)))
39 }
40
41 fn output_type(&self, input_type: SqlColumnType) -> SqlColumnType {
42 SqlScalarType::String.nullable(input_type.nullable)
43 }
44
45 fn propagates_nulls(&self) -> bool {
46 true
47 }
48
49 fn introduces_nulls(&self) -> bool {
50 false
51 }
52
53 fn preserves_uniqueness(&self) -> bool {
54 true
55 }
56
57 fn inverse(&self) -> Option<crate::UnaryFunc> {
58 None
60 }
61
62 fn is_monotone(&self) -> bool {
63 false
64 }
65}
66
67impl fmt::Display for CastRecordToString {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 f.write_str("recordtostr")
70 }
71}
72
73#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)]
76pub struct CastRecord1ToRecord2 {
77 pub return_ty: SqlScalarType,
78 pub cast_exprs: Box<[MirScalarExpr]>,
79}
80
81impl LazyUnaryFunc for CastRecord1ToRecord2 {
82 fn eval<'a>(
83 &'a self,
84 datums: &[Datum<'a>],
85 temp_storage: &'a RowArena,
86 a: &'a MirScalarExpr,
87 ) -> Result<Datum<'a>, EvalError> {
88 let a = a.eval(datums, temp_storage)?;
89 if a.is_null() {
90 return Ok(Datum::Null);
91 }
92 let mut cast_datums = Vec::new();
93 for (el, cast_expr) in a.unwrap_list().iter().zip_eq(&self.cast_exprs) {
94 cast_datums.push(cast_expr.eval(&[el], temp_storage)?);
95 }
96 Ok(temp_storage.make_datum(|packer| packer.push_list(cast_datums)))
97 }
98
99 fn output_type(&self, input_type: SqlColumnType) -> SqlColumnType {
100 self.return_ty
101 .without_modifiers()
102 .nullable(input_type.nullable)
103 }
104
105 fn propagates_nulls(&self) -> bool {
106 true
107 }
108
109 fn introduces_nulls(&self) -> bool {
110 false
111 }
112
113 fn preserves_uniqueness(&self) -> bool {
114 false
115 }
116
117 fn inverse(&self) -> Option<crate::UnaryFunc> {
118 None
120 }
121
122 fn is_monotone(&self) -> bool {
123 false
127 }
128}
129
130impl fmt::Display for CastRecord1ToRecord2 {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 f.write_str("record1torecord2")
133 }
134}
135
136#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)]
137pub struct RecordGet(pub usize);
138
139impl LazyUnaryFunc for RecordGet {
140 fn eval<'a>(
141 &'a self,
142 datums: &[Datum<'a>],
143 temp_storage: &'a RowArena,
144 a: &'a MirScalarExpr,
145 ) -> Result<Datum<'a>, EvalError> {
146 let a = a.eval(datums, temp_storage)?;
147 if a.is_null() {
148 return Ok(Datum::Null);
149 }
150 Ok(a.unwrap_list().iter().nth(self.0).unwrap())
151 }
152
153 fn output_type(&self, input_type: SqlColumnType) -> SqlColumnType {
154 match input_type.scalar_type {
155 SqlScalarType::Record { fields, .. } => {
156 let (_name, ty) = &fields[self.0];
157 let mut ty = ty.clone();
158 ty.nullable = ty.nullable || input_type.nullable;
159 ty
160 }
161 _ => unreachable!(
162 "RecordGet on non-record input: {:?}",
163 input_type.scalar_type
164 ),
165 }
166 }
167
168 fn propagates_nulls(&self) -> bool {
169 true
170 }
171
172 fn introduces_nulls(&self) -> bool {
173 true
175 }
176
177 fn preserves_uniqueness(&self) -> bool {
178 false
179 }
180
181 fn inverse(&self) -> Option<crate::UnaryFunc> {
182 None
183 }
184
185 fn is_monotone(&self) -> bool {
186 false
187 }
188}
189
190impl fmt::Display for RecordGet {
191 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192 write!(f, "record_get[{}]", self.0)
193 }
194}