mz_expr/scalar/func/
macros.rs1macro_rules! to_unary {
12 ($f:expr) => {
13 Some(crate::UnaryFunc::from($f))
14 };
15}
16
17#[cfg(test)]
18mod test {
19 use mz_expr_derive::sqlfunc;
20 use mz_repr::SqlScalarType;
21
22 use crate::EvalError;
23 use crate::scalar::func::LazyUnaryFunc;
24
25 #[sqlfunc(sqlname = "INFALLIBLE")]
26 fn infallible1(a: f32) -> f32 {
27 a
28 }
29
30 #[sqlfunc]
31 fn infallible2(a: Option<f32>) -> f32 {
32 a.unwrap_or_default()
33 }
34
35 #[sqlfunc]
36 fn infallible3(a: f32) -> Option<f32> {
37 Some(a)
38 }
39
40 #[mz_ore::test]
41 fn elision_rules_infallible() {
42 assert_eq!(format!("{}", Infallible1), "INFALLIBLE");
43 assert!(Infallible1.propagates_nulls());
44 assert!(!Infallible1.introduces_nulls());
45
46 assert!(!Infallible2.propagates_nulls());
47 assert!(!Infallible2.introduces_nulls());
48
49 assert!(Infallible3.propagates_nulls());
50 assert!(Infallible3.introduces_nulls());
51 }
52
53 #[mz_ore::test]
54 fn output_types_infallible() {
55 assert_eq!(
56 Infallible1.output_type(SqlScalarType::Float32.nullable(true)),
57 SqlScalarType::Float32.nullable(true)
58 );
59 assert_eq!(
60 Infallible1.output_type(SqlScalarType::Float32.nullable(false)),
61 SqlScalarType::Float32.nullable(false)
62 );
63
64 assert_eq!(
65 Infallible2.output_type(SqlScalarType::Float32.nullable(true)),
66 SqlScalarType::Float32.nullable(false)
67 );
68 assert_eq!(
69 Infallible2.output_type(SqlScalarType::Float32.nullable(false)),
70 SqlScalarType::Float32.nullable(false)
71 );
72
73 assert_eq!(
74 Infallible3.output_type(SqlScalarType::Float32.nullable(true)),
75 SqlScalarType::Float32.nullable(true)
76 );
77 assert_eq!(
78 Infallible3.output_type(SqlScalarType::Float32.nullable(false)),
79 SqlScalarType::Float32.nullable(true)
80 );
81 }
82
83 #[sqlfunc]
84 fn fallible1(a: f32) -> Result<f32, EvalError> {
85 Ok(a)
86 }
87
88 #[sqlfunc]
89 fn fallible2(a: Option<f32>) -> Result<f32, EvalError> {
90 Ok(a.unwrap_or_default())
91 }
92
93 #[sqlfunc]
94 fn fallible3(a: f32) -> Result<Option<f32>, EvalError> {
95 Ok(Some(a))
96 }
97
98 #[mz_ore::test]
99 fn elision_rules_fallible() {
100 assert!(Fallible1.propagates_nulls());
101 assert!(!Fallible1.introduces_nulls());
102
103 assert!(!Fallible2.propagates_nulls());
104 assert!(!Fallible2.introduces_nulls());
105
106 assert!(Fallible3.propagates_nulls());
107 assert!(Fallible3.introduces_nulls());
108 }
109
110 #[mz_ore::test]
111 fn output_types_fallible() {
112 assert_eq!(
113 Fallible1.output_type(SqlScalarType::Float32.nullable(true)),
114 SqlScalarType::Float32.nullable(true)
115 );
116 assert_eq!(
117 Fallible1.output_type(SqlScalarType::Float32.nullable(false)),
118 SqlScalarType::Float32.nullable(false)
119 );
120
121 assert_eq!(
122 Fallible2.output_type(SqlScalarType::Float32.nullable(true)),
123 SqlScalarType::Float32.nullable(false)
124 );
125 assert_eq!(
126 Fallible2.output_type(SqlScalarType::Float32.nullable(false)),
127 SqlScalarType::Float32.nullable(false)
128 );
129
130 assert_eq!(
131 Fallible3.output_type(SqlScalarType::Float32.nullable(true)),
132 SqlScalarType::Float32.nullable(true)
133 );
134 assert_eq!(
135 Fallible3.output_type(SqlScalarType::Float32.nullable(false)),
136 SqlScalarType::Float32.nullable(true)
137 );
138 }
139}
140
141macro_rules! derive_unary {
147 ($($name:ident),*) => {
148 #[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, Hash, mz_lowertest::MzReflect)]
149 pub enum UnaryFunc {
150 $($name($name),)*
151 }
152
153 impl UnaryFunc {
154 pub fn eval<'a>(
155 &'a self,
156 datums: &[Datum<'a>],
157 temp_storage: &'a RowArena,
158 a: &'a MirScalarExpr,
159 ) -> Result<Datum<'a>, EvalError> {
160 match self {
161 $(Self::$name(f) => f.eval(datums, temp_storage, a),)*
162 }
163 }
164
165 pub fn output_type(&self, input_type: SqlColumnType) -> SqlColumnType {
166 match self {
167 $(Self::$name(f) => LazyUnaryFunc::output_type(f, input_type),)*
168 }
169 }
170 pub fn propagates_nulls(&self) -> bool {
171 match self {
172 $(Self::$name(f) => LazyUnaryFunc::propagates_nulls(f),)*
173 }
174 }
175 pub fn introduces_nulls(&self) -> bool {
176 match self {
177 $(Self::$name(f) => LazyUnaryFunc::introduces_nulls(f),)*
178 }
179 }
180 pub fn preserves_uniqueness(&self) -> bool {
181 match self {
182 $(Self::$name(f) => LazyUnaryFunc::preserves_uniqueness(f),)*
183 }
184 }
185 pub fn inverse(&self) -> Option<UnaryFunc> {
186 match self {
187 $(Self::$name(f) => LazyUnaryFunc::inverse(f),)*
188 }
189 }
190 pub fn is_monotone(&self) -> bool {
191 match self {
192 $(Self::$name(f) => LazyUnaryFunc::is_monotone(f),)*
193 }
194 }
195 pub fn could_error(&self) -> bool {
196 match self {
197 $(Self::$name(f) => LazyUnaryFunc::could_error(f),)*
198 }
199 }
200 }
201
202 impl fmt::Display for UnaryFunc {
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 match self {
205 $(Self::$name(func) => func.fmt(f),)*
206 }
207 }
208 }
209
210 $(
211 impl From<$name> for crate::UnaryFunc {
212 fn from(variant: $name) -> Self {
213 Self::$name(variant)
214 }
215 }
216 )*
217 }
218}
219
220macro_rules! derive_binary_from {
223 ($($name:ident $( ( $variant:ident ) )?),* $(,)?) => {
224 $(
225 derive_binary_from!(from @ $name $( ( $variant ) )?);
226 )*
227 };
228 (from @ $name:ident ( $variant:ident ) ) => {
229 impl From<$variant> for crate::BinaryFunc {
230 fn from(variant: $variant) -> Self {
231 Self::$name(variant)
232 }
233 }
234 };
235 (from @ $name:ident) => {
236 derive_binary_from!(from @ $name ( $name ) );
237 };
238}