1macro_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_sql_type(SqlScalarType::Float32.nullable(true)),
57 SqlScalarType::Float32.nullable(true)
58 );
59 assert_eq!(
60 Infallible1.output_sql_type(SqlScalarType::Float32.nullable(false)),
61 SqlScalarType::Float32.nullable(false)
62 );
63
64 assert_eq!(
65 Infallible2.output_sql_type(SqlScalarType::Float32.nullable(true)),
66 SqlScalarType::Float32.nullable(false)
67 );
68 assert_eq!(
69 Infallible2.output_sql_type(SqlScalarType::Float32.nullable(false)),
70 SqlScalarType::Float32.nullable(false)
71 );
72
73 assert_eq!(
74 Infallible3.output_sql_type(SqlScalarType::Float32.nullable(true)),
75 SqlScalarType::Float32.nullable(true)
76 );
77 assert_eq!(
78 Infallible3.output_sql_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_sql_type(SqlScalarType::Float32.nullable(true)),
114 SqlScalarType::Float32.nullable(true)
115 );
116 assert_eq!(
117 Fallible1.output_sql_type(SqlScalarType::Float32.nullable(false)),
118 SqlScalarType::Float32.nullable(false)
119 );
120
121 assert_eq!(
122 Fallible2.output_sql_type(SqlScalarType::Float32.nullable(true)),
123 SqlScalarType::Float32.nullable(false)
124 );
125 assert_eq!(
126 Fallible2.output_sql_type(SqlScalarType::Float32.nullable(false)),
127 SqlScalarType::Float32.nullable(false)
128 );
129
130 assert_eq!(
131 Fallible3.output_sql_type(SqlScalarType::Float32.nullable(true)),
132 SqlScalarType::Float32.nullable(true)
133 );
134 assert_eq!(
135 Fallible3.output_sql_type(SqlScalarType::Float32.nullable(false)),
136 SqlScalarType::Float32.nullable(true)
137 );
138 }
139
140 mod stateful {
143 use mz_expr_derive::sqlfunc;
144 use mz_repr::RowArena;
145
146 use crate::EvalError;
147 use crate::scalar::func::EagerUnaryFunc;
148 use crate::scalar::func::binary::EagerBinaryFunc;
149
150 pub struct AddOffset(i64);
151
152 #[sqlfunc(sqlname = "add_offset")]
153 fn add_offset(&self, a: i64) -> i64 {
154 a + self.0
155 }
156
157 pub struct ScaleSum(i64);
158
159 #[sqlfunc(sqlname = "scale_sum")]
160 fn scale_sum(&self, a: i64, b: i64) -> Result<i64, EvalError> {
161 (a + b)
162 .checked_mul(self.0)
163 .ok_or(EvalError::NumericFieldOverflow)
164 }
165
166 #[mz_ore::test]
167 fn stateful_unary_and_binary_read_their_state() {
168 let arena = RowArena::new();
169 assert_eq!(EagerUnaryFunc::call(&AddOffset(3), 4, &arena), 7);
170 assert_eq!(EagerBinaryFunc::call(&ScaleSum(2), (3, 4), &arena), Ok(14));
171 assert_eq!(format!("{}", AddOffset(3)), "add_offset");
172 assert_eq!(format!("{}", ScaleSum(2)), "scale_sum");
173 }
174 }
175}
176
177macro_rules! derive_unary {
186 (@try_map_payload $f:ident) => { $f.clone() };
189 (@try_map_payload $f:ident $marker:ident) => { $f.try_map_expr()? };
190 (@map_payload $f:ident) => { $f.clone() };
191 (@map_payload $f:ident $marker:ident) => { $f.map_expr() };
192 (@mir_ty $name:ident) => { $name };
195 (@mir_ty $name:ident $marker:ident) => { $name<crate::MirScalarExpr> };
196 ($($name:ident $(($marker:ident))?),* $(,)?) => {
197 #[derive(
198 Ord, PartialOrd, Clone, Debug, Eq, PartialEq,
199 serde::Serialize, serde::Deserialize, Hash,
200 )]
201 pub enum UnaryFunc<E = crate::MirScalarExpr> {
202 $($name($name $(<$marker>)?),)*
203 }
204
205 impl<E: Eval> UnaryFunc<E> {
208 pub fn eval<'a>(
209 &'a self,
210 datums: &[Datum<'a>],
211 temp_storage: &'a RowArena,
212 a: &'a impl Eval,
213 ) -> Result<Datum<'a>, EvalError> {
214 match self {
215 $(Self::$name(f) => f.eval(datums, temp_storage, a),)*
216 }
217 }
218
219 pub fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
220 match self {
221 $(Self::$name(f) => LazyUnaryFunc::output_sql_type(f, input_type),)*
222 }
223 }
224 pub fn output_type(&self, input_type: ReprColumnType) -> ReprColumnType {
225 match self {
226 $(Self::$name(f) => LazyUnaryFunc::output_type(f, input_type),)*
227 }
228 }
229 pub fn propagates_nulls(&self) -> bool {
230 match self {
231 $(Self::$name(f) => LazyUnaryFunc::propagates_nulls(f),)*
232 }
233 }
234 pub fn introduces_nulls(&self) -> bool {
235 match self {
236 $(Self::$name(f) => LazyUnaryFunc::introduces_nulls(f),)*
237 }
238 }
239 pub fn preserves_uniqueness(&self) -> bool {
240 match self {
241 $(Self::$name(f) => LazyUnaryFunc::preserves_uniqueness(f),)*
242 }
243 }
244 pub fn is_monotone(&self) -> bool {
245 match self {
246 $(Self::$name(f) => LazyUnaryFunc::is_monotone(f),)*
247 }
248 }
249 pub fn could_error(&self) -> bool {
250 match self {
251 $(Self::$name(f) => LazyUnaryFunc::could_error(f),)*
252 }
253 }
254 pub fn is_eliminable_cast(&self) -> bool {
255 match self {
256 $(Self::$name(f) => LazyUnaryFunc::is_eliminable_cast(f),)*
257 }
258 }
259 }
260
261 impl<E> UnaryFunc<E> {
262 pub fn variant_name(&self) -> &'static str {
265 match self {
266 $(Self::$name(_) =>
267 <$name $(<$marker>)? as crate::func::FuncName>::NAME,)*
268 }
269 }
270
271 #[cfg(feature = "func-registry")]
274 pub fn sqlfunc_source(&self) -> Option<crate::func::SqlFuncSource> {
275 match self {
276 $(Self::$name(_) =>
277 <$name $(<$marker>)? as crate::func::FuncName>::SQLFUNC,)*
278 }
279 }
280
281 #[cfg(feature = "func-registry")]
283 pub fn sqlfunc_input_types(&self) -> Option<Vec<SqlColumnType>> {
284 match self {
285 $(Self::$name(_) =>
286 <$name $(<$marker>)? as crate::func::FuncName>::sqlfunc_input_types(),)*
287 }
288 }
289
290 pub fn try_map_expr<'a, E2: TryFrom<&'a E>>(
294 &'a self,
295 ) -> Result<UnaryFunc<E2>, E2::Error> {
296 Ok(match self {
297 $(Self::$name(f) => UnaryFunc::$name(
298 derive_unary!(@try_map_payload f $($marker)?),
299 ),)*
300 })
301 }
302
303 pub fn map_expr<'a, E2: From<&'a E>>(&'a self) -> UnaryFunc<E2> {
306 match self {
307 $(Self::$name(f) => UnaryFunc::$name(
308 derive_unary!(@map_payload f $($marker)?),
309 ),)*
310 }
311 }
312 }
313
314 impl UnaryFunc {
318 pub fn inverse(&self) -> Option<UnaryFunc> {
319 match self {
320 $(Self::$name(f) => LazyUnaryFunc::inverse(f),)*
321 }
322 }
323
324 pub fn from_variant_name(name: &str) -> Option<Self> {
336 use crate::func::FuncName;
337 $(
338 if name == <derive_unary!(@mir_ty $name $($marker)?) as FuncName>::NAME {
339 return serde_json::from_value(
340 serde_json::json!({ stringify!($name): null }),
341 )
342 .ok();
343 }
344 )*
345 None
346 }
347
348 pub fn variant_names() -> impl Iterator<Item = &'static str> {
350 use crate::func::FuncName;
351 [$(
352 <derive_unary!(@mir_ty $name $($marker)?) as FuncName>::NAME,
353 )*]
354 .into_iter()
355 }
356 }
357
358 impl<E> fmt::Display for UnaryFunc<E> {
359 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
360 match self {
361 $(Self::$name(func) => func.fmt(f),)*
362 }
363 }
364 }
365
366 $(
367 impl<E> From<$name $(<$marker>)?> for crate::UnaryFunc<E> {
368 fn from(variant: $name $(<$marker>)?) -> Self {
369 Self::$name(variant)
370 }
371 }
372 )*
373 }
374}
375
376macro_rules! derive_variadic {
382 ($($name:ident ( $variant:ident )),* $(,)?) => {
383 #[derive(
384 Ord, PartialOrd, Clone, Debug, Eq, PartialEq,
385 serde::Serialize, serde::Deserialize, Hash,
386 )]
387 pub enum VariadicFunc {
388 $($name($variant),)*
389 }
390
391 impl VariadicFunc {
392 pub fn eval<'a>(
393 &'a self,
394 datums: &[Datum<'a>],
395 temp_storage: &'a RowArena,
396 exprs: &'a [impl Eval],
397 ) -> Result<Datum<'a>, EvalError> {
398 match self {
399 $(Self::$name(f) => f.eval(datums, temp_storage, exprs),)*
400 }
401 }
402
403 pub fn output_sql_type(&self, input_types: Vec<SqlColumnType>) -> SqlColumnType {
404 match self {
405 $(Self::$name(f) => LazyVariadicFunc::output_type(f, &input_types),)*
406 }
407 }
408
409 pub fn output_type(&self, input_types: Vec<ReprColumnType>) -> ReprColumnType {
413 let sql_types = input_types.iter().map(SqlColumnType::from_repr).collect();
414 ReprColumnType::from(&self.output_sql_type(sql_types))
415 }
416
417 pub fn propagates_nulls(&self) -> bool {
418 match self {
419 $(Self::$name(f) => LazyVariadicFunc::propagates_nulls(f),)*
420 }
421 }
422
423 pub fn introduces_nulls(&self) -> bool {
424 match self {
425 $(Self::$name(f) => LazyVariadicFunc::introduces_nulls(f),)*
426 }
427 }
428
429 pub fn could_error(&self) -> bool {
430 match self {
431 $(Self::$name(f) => LazyVariadicFunc::could_error(f),)*
432 }
433 }
434
435 pub fn is_monotone(&self) -> bool {
436 match self {
437 $(Self::$name(f) => LazyVariadicFunc::is_monotone(f),)*
438 }
439 }
440
441 pub fn is_associative(&self) -> bool {
442 match self {
443 $(Self::$name(f) => LazyVariadicFunc::is_associative(f),)*
444 }
445 }
446
447 pub fn is_infix_op(&self) -> bool {
448 match self {
449 $(Self::$name(f) => LazyVariadicFunc::is_infix_op(f),)*
450 }
451 }
452
453 pub fn variant_name(&self) -> &'static str {
456 match self {
457 $(Self::$name(_) => <$variant as crate::func::FuncName>::NAME,)*
458 }
459 }
460
461 #[cfg(feature = "func-registry")]
464 pub fn sqlfunc_source(&self) -> Option<crate::func::SqlFuncSource> {
465 match self {
466 $(Self::$name(_) => <$variant as crate::func::FuncName>::SQLFUNC,)*
467 }
468 }
469
470 #[cfg(feature = "func-registry")]
472 pub fn sqlfunc_input_types(&self) -> Option<Vec<SqlColumnType>> {
473 match self {
474 $(Self::$name(_) =>
475 <$variant as crate::func::FuncName>::sqlfunc_input_types(),)*
476 }
477 }
478
479 pub fn from_variant_name(name: &str) -> Option<Self> {
490 $(
491 if name == <$variant as crate::func::FuncName>::NAME {
492 return serde_json::from_value(
493 serde_json::json!({ stringify!($name): null }),
494 )
495 .ok();
496 }
497 )*
498 None
499 }
500
501 pub fn variant_names() -> impl Iterator<Item = &'static str> {
503 [$(<$variant as crate::func::FuncName>::NAME,)*].into_iter()
504 }
505 }
506
507 impl fmt::Display for VariadicFunc {
508 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
509 match self {
510 $(Self::$name(func) => func.fmt(f),)*
511 }
512 }
513 }
514
515 $(
516 impl From<$variant> for crate::VariadicFunc {
517 fn from(variant: $variant) -> Self {
518 Self::$name(variant)
519 }
520 }
521 )*
522 }
523}
524
525macro_rules! derive_binary {
531 ($($name:ident ( $variant:ident )),* $(,)?) => {
532 #[derive(
533 Ord, PartialOrd, Clone, Debug, Eq, PartialEq,
534 serde::Serialize, serde::Deserialize, Hash,
535 )]
536 pub enum BinaryFunc {
537 $($name($variant),)*
538 }
539
540 impl BinaryFunc {
541 pub fn eval<'a>(
542 &'a self,
543 datums: &[Datum<'a>],
544 temp_storage: &'a RowArena,
545 exprs: &[&'a impl Eval],
546 ) -> Result<Datum<'a>, EvalError> {
547 match self {
548 $(Self::$name(f) => f.eval(datums, temp_storage, exprs),)*
549 }
550 }
551
552 pub fn output_sql_type(&self, input_types: &[SqlColumnType]) -> SqlColumnType {
553 match self {
554 $(Self::$name(f) => {
555 LazyBinaryFunc::output_sql_type(f, input_types)
556 },)*
557 }
558 }
559
560 pub fn output_type(&self, input_types: &[ReprColumnType]) -> ReprColumnType {
561 match self {
562 $(Self::$name(f) => LazyBinaryFunc::output_type(f, input_types),)*
563 }
564 }
565
566 pub fn propagates_nulls(&self) -> bool {
567 match self {
568 $(Self::$name(f) => LazyBinaryFunc::propagates_nulls(f),)*
569 }
570 }
571
572 pub fn introduces_nulls(&self) -> bool {
573 match self {
574 $(Self::$name(f) => LazyBinaryFunc::introduces_nulls(f),)*
575 }
576 }
577
578 pub fn is_infix_op(&self) -> bool {
579 match self {
580 $(Self::$name(f) => LazyBinaryFunc::is_infix_op(f),)*
581 }
582 }
583
584 pub fn negate(&self) -> Option<BinaryFunc> {
585 match self {
586 $(Self::$name(f) => LazyBinaryFunc::negate(f),)*
587 }
588 }
589
590 pub fn could_error(&self) -> bool {
591 match self {
592 $(Self::$name(f) => LazyBinaryFunc::could_error(f),)*
593 }
594 }
595
596 pub fn is_monotone(&self) -> (bool, bool) {
597 match self {
598 $(Self::$name(f) => LazyBinaryFunc::is_monotone(f),)*
599 }
600 }
601
602 pub fn is_infinity_monotone(&self) -> bool {
603 match self {
604 $(Self::$name(f) => LazyBinaryFunc::is_infinity_monotone(f),)*
605 }
606 }
607
608 pub fn variant_name(&self) -> &'static str {
611 match self {
612 $(Self::$name(_) => <$variant as crate::func::FuncName>::NAME,)*
613 }
614 }
615
616 #[cfg(feature = "func-registry")]
619 pub fn sqlfunc_source(&self) -> Option<crate::func::SqlFuncSource> {
620 match self {
621 $(Self::$name(_) => <$variant as crate::func::FuncName>::SQLFUNC,)*
622 }
623 }
624
625 #[cfg(feature = "func-registry")]
627 pub fn sqlfunc_input_types(&self) -> Option<Vec<SqlColumnType>> {
628 match self {
629 $(Self::$name(_) =>
630 <$variant as crate::func::FuncName>::sqlfunc_input_types(),)*
631 }
632 }
633
634 pub fn from_variant_name(name: &str) -> Option<Self> {
645 $(
646 if name == <$variant as crate::func::FuncName>::NAME {
647 return serde_json::from_value(
648 serde_json::json!({ stringify!($name): null }),
649 )
650 .ok();
651 }
652 )*
653 None
654 }
655
656 pub fn variant_names() -> impl Iterator<Item = &'static str> {
658 [$(<$variant as crate::func::FuncName>::NAME,)*].into_iter()
659 }
660 }
661
662 impl fmt::Display for BinaryFunc {
663 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
664 match self {
665 $(Self::$name(func) => func.fmt(f),)*
666 }
667 }
668 }
669
670 $(
671 impl From<$variant> for crate::BinaryFunc {
672 fn from(variant: $variant) -> Self {
673 Self::$name(variant)
674 }
675 }
676 )*
677 }
678}