mz_expr/scalar/func/
binary.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Utilities for binary functions.
11
12use mz_repr::{ColumnType, Datum, DatumType, RowArena};
13
14use crate::{EvalError, MirScalarExpr};
15
16/// A description of an SQL binary function that has the ability to lazy evaluate its arguments
17// This trait will eventually be annotated with #[enum_dispatch] to autogenerate the UnaryFunc enum
18#[allow(unused)]
19pub(crate) trait LazyBinaryFunc {
20    fn eval<'a>(
21        &'a self,
22        datums: &[Datum<'a>],
23        temp_storage: &'a RowArena,
24        a: &'a MirScalarExpr,
25        b: &'a MirScalarExpr,
26    ) -> Result<Datum<'a>, EvalError>;
27
28    /// The output ColumnType of this function.
29    fn output_type(&self, input_type_a: ColumnType, input_type_b: ColumnType) -> ColumnType;
30
31    /// Whether this function will produce NULL on NULL input.
32    fn propagates_nulls(&self) -> bool;
33
34    /// Whether this function will produce NULL on non-NULL input.
35    fn introduces_nulls(&self) -> bool;
36
37    /// Whether this function might error on non-error input.
38    fn could_error(&self) -> bool {
39        // NB: override this for functions that never error.
40        true
41    }
42
43    /// Returns the negation of the function, if one exists.
44    fn negate(&self) -> Option<crate::BinaryFunc>;
45
46    /// Returns true if the function is monotone. (Non-strict; either increasing or decreasing.)
47    /// Monotone functions map ranges to ranges: ie. given a range of possible inputs, we can
48    /// determine the range of possible outputs just by mapping the endpoints.
49    ///
50    /// This describes the *pointwise* behaviour of the function:
51    /// ie. the behaviour of any specific argument as the others are held constant. (For example, `a - b` is
52    /// monotone in the first argument because for any particular value of `b`, increasing `a` will
53    /// always cause the result to increase... and in the second argument because for any specific `a`,
54    /// increasing `b` will always cause the result to _decrease_.)
55    ///
56    /// This property describes the behaviour of the function over ranges where the function is defined:
57    /// ie. the arguments and the result are non-error datums.
58    fn is_monotone(&self) -> (bool, bool);
59
60    /// Yep, I guess this returns true for infix operators.
61    fn is_infix_op(&self) -> bool;
62}
63
64#[allow(unused)]
65pub(crate) trait EagerBinaryFunc<'a> {
66    type Input1: DatumType<'a, EvalError>;
67    type Input2: DatumType<'a, EvalError>;
68    type Output: DatumType<'a, EvalError>;
69
70    fn call(&self, a: Self::Input1, b: Self::Input2, temp_storage: &'a RowArena) -> Self::Output;
71
72    /// The output ColumnType of this function
73    fn output_type(&self, input_type_a: ColumnType, input_type_b: ColumnType) -> ColumnType;
74
75    /// Whether this function will produce NULL on NULL input
76    fn propagates_nulls(&self) -> bool {
77        // If the inputs are not nullable then nulls are propagated
78        !Self::Input1::nullable() && !Self::Input2::nullable()
79    }
80
81    /// Whether this function will produce NULL on non-NULL input
82    fn introduces_nulls(&self) -> bool {
83        // If the output is nullable then nulls can be introduced
84        Self::Output::nullable()
85    }
86
87    /// Whether this function could produce an error
88    fn could_error(&self) -> bool {
89        Self::Output::fallible()
90    }
91
92    /// Returns the negation of the given binary function, if it exists.
93    fn negate(&self) -> Option<crate::BinaryFunc> {
94        None
95    }
96
97    fn is_monotone(&self) -> (bool, bool) {
98        (false, false)
99    }
100
101    fn is_infix_op(&self) -> bool {
102        false
103    }
104}
105
106impl<T: for<'a> EagerBinaryFunc<'a>> LazyBinaryFunc for T {
107    fn eval<'a>(
108        &'a self,
109        datums: &[Datum<'a>],
110        temp_storage: &'a RowArena,
111        a: &'a MirScalarExpr,
112        b: &'a MirScalarExpr,
113    ) -> Result<Datum<'a>, EvalError> {
114        let a = match T::Input1::try_from_result(a.eval(datums, temp_storage)) {
115            // If we can convert to the input type then we call the function
116            Ok(input) => input,
117            // If we can't and we got a non-null datum something went wrong in the planner
118            Err(Ok(datum)) if !datum.is_null() => {
119                return Err(EvalError::Internal("invalid input type".into()));
120            }
121            // Otherwise we just propagate NULLs and errors
122            Err(res) => return res,
123        };
124        let b = match T::Input2::try_from_result(b.eval(datums, temp_storage)) {
125            // If we can convert to the input type then we call the function
126            Ok(input) => input,
127            // If we can't and we got a non-null datum something went wrong in the planner
128            Err(Ok(datum)) if !datum.is_null() => {
129                return Err(EvalError::Internal("invalid input type".into()));
130            }
131            // Otherwise we just propagate NULLs and errors
132            Err(res) => return res,
133        };
134        self.call(a, b, temp_storage).into_result(temp_storage)
135    }
136
137    fn output_type(&self, input_type_a: ColumnType, input_type_b: ColumnType) -> ColumnType {
138        self.output_type(input_type_a, input_type_b)
139    }
140
141    fn propagates_nulls(&self) -> bool {
142        self.propagates_nulls()
143    }
144
145    fn introduces_nulls(&self) -> bool {
146        self.introduces_nulls()
147    }
148
149    fn could_error(&self) -> bool {
150        self.could_error()
151    }
152
153    fn negate(&self) -> Option<crate::BinaryFunc> {
154        self.negate()
155    }
156
157    fn is_monotone(&self) -> (bool, bool) {
158        self.is_monotone()
159    }
160
161    fn is_infix_op(&self) -> bool {
162        self.is_infix_op()
163    }
164}
165
166#[cfg(test)]
167mod test {
168    use mz_expr_derive::sqlfunc;
169    use mz_repr::ColumnType;
170    use mz_repr::ScalarType;
171
172    use crate::scalar::func::binary::LazyBinaryFunc;
173    use crate::{BinaryFunc, EvalError, func};
174
175    #[sqlfunc(sqlname = "INFALLIBLE", is_infix_op = true)]
176    fn infallible1(a: f32, b: f32) -> f32 {
177        a + b
178    }
179
180    #[sqlfunc]
181    fn infallible2(a: Option<f32>, b: Option<f32>) -> f32 {
182        a.unwrap_or_default() + b.unwrap_or_default()
183    }
184
185    #[sqlfunc]
186    fn infallible3(a: f32, b: f32) -> Option<f32> {
187        Some(a + b)
188    }
189
190    #[mz_ore::test]
191    fn elision_rules_infallible() {
192        assert_eq!(format!("{}", Infallible1), "INFALLIBLE");
193        assert!(Infallible1.propagates_nulls());
194        assert!(!Infallible1.introduces_nulls());
195
196        assert!(!Infallible2.propagates_nulls());
197        assert!(!Infallible2.introduces_nulls());
198
199        assert!(Infallible3.propagates_nulls());
200        assert!(Infallible3.introduces_nulls());
201    }
202
203    #[mz_ore::test]
204    fn output_types_infallible() {
205        assert_eq!(
206            Infallible1.output_type(
207                ScalarType::Float32.nullable(true),
208                ScalarType::Float32.nullable(true)
209            ),
210            ScalarType::Float32.nullable(true)
211        );
212        assert_eq!(
213            Infallible1.output_type(
214                ScalarType::Float32.nullable(true),
215                ScalarType::Float32.nullable(false)
216            ),
217            ScalarType::Float32.nullable(true)
218        );
219        assert_eq!(
220            Infallible1.output_type(
221                ScalarType::Float32.nullable(false),
222                ScalarType::Float32.nullable(true)
223            ),
224            ScalarType::Float32.nullable(true)
225        );
226        assert_eq!(
227            Infallible1.output_type(
228                ScalarType::Float32.nullable(false),
229                ScalarType::Float32.nullable(false)
230            ),
231            ScalarType::Float32.nullable(false)
232        );
233
234        assert_eq!(
235            Infallible2.output_type(
236                ScalarType::Float32.nullable(true),
237                ScalarType::Float32.nullable(true)
238            ),
239            ScalarType::Float32.nullable(false)
240        );
241        assert_eq!(
242            Infallible2.output_type(
243                ScalarType::Float32.nullable(true),
244                ScalarType::Float32.nullable(false)
245            ),
246            ScalarType::Float32.nullable(false)
247        );
248        assert_eq!(
249            Infallible2.output_type(
250                ScalarType::Float32.nullable(false),
251                ScalarType::Float32.nullable(true)
252            ),
253            ScalarType::Float32.nullable(false)
254        );
255        assert_eq!(
256            Infallible2.output_type(
257                ScalarType::Float32.nullable(false),
258                ScalarType::Float32.nullable(false)
259            ),
260            ScalarType::Float32.nullable(false)
261        );
262
263        assert_eq!(
264            Infallible3.output_type(
265                ScalarType::Float32.nullable(true),
266                ScalarType::Float32.nullable(true)
267            ),
268            ScalarType::Float32.nullable(true)
269        );
270        assert_eq!(
271            Infallible3.output_type(
272                ScalarType::Float32.nullable(true),
273                ScalarType::Float32.nullable(false)
274            ),
275            ScalarType::Float32.nullable(true)
276        );
277        assert_eq!(
278            Infallible3.output_type(
279                ScalarType::Float32.nullable(false),
280                ScalarType::Float32.nullable(true)
281            ),
282            ScalarType::Float32.nullable(true)
283        );
284        assert_eq!(
285            Infallible3.output_type(
286                ScalarType::Float32.nullable(false),
287                ScalarType::Float32.nullable(false)
288            ),
289            ScalarType::Float32.nullable(true)
290        );
291    }
292
293    #[sqlfunc]
294    fn fallible1(a: f32, b: f32) -> Result<f32, EvalError> {
295        Ok(a + b)
296    }
297
298    #[sqlfunc]
299    fn fallible2(a: Option<f32>, b: Option<f32>) -> Result<f32, EvalError> {
300        Ok(a.unwrap_or_default() + b.unwrap_or_default())
301    }
302
303    #[sqlfunc]
304    fn fallible3(a: f32, b: f32) -> Result<Option<f32>, EvalError> {
305        Ok(Some(a + b))
306    }
307
308    #[mz_ore::test]
309    fn elision_rules_fallible() {
310        assert!(Fallible1.propagates_nulls());
311        assert!(!Fallible1.introduces_nulls());
312
313        assert!(!Fallible2.propagates_nulls());
314        assert!(!Fallible2.introduces_nulls());
315
316        assert!(Fallible3.propagates_nulls());
317        assert!(Fallible3.introduces_nulls());
318    }
319
320    #[mz_ore::test]
321    fn output_types_fallible() {
322        assert_eq!(
323            Fallible1.output_type(
324                ScalarType::Float32.nullable(true),
325                ScalarType::Float32.nullable(true)
326            ),
327            ScalarType::Float32.nullable(true)
328        );
329        assert_eq!(
330            Fallible1.output_type(
331                ScalarType::Float32.nullable(true),
332                ScalarType::Float32.nullable(false)
333            ),
334            ScalarType::Float32.nullable(true)
335        );
336        assert_eq!(
337            Fallible1.output_type(
338                ScalarType::Float32.nullable(false),
339                ScalarType::Float32.nullable(true)
340            ),
341            ScalarType::Float32.nullable(true)
342        );
343        assert_eq!(
344            Fallible1.output_type(
345                ScalarType::Float32.nullable(false),
346                ScalarType::Float32.nullable(false)
347            ),
348            ScalarType::Float32.nullable(false)
349        );
350
351        assert_eq!(
352            Fallible2.output_type(
353                ScalarType::Float32.nullable(true),
354                ScalarType::Float32.nullable(true)
355            ),
356            ScalarType::Float32.nullable(false)
357        );
358        assert_eq!(
359            Fallible2.output_type(
360                ScalarType::Float32.nullable(true),
361                ScalarType::Float32.nullable(false)
362            ),
363            ScalarType::Float32.nullable(false)
364        );
365        assert_eq!(
366            Fallible2.output_type(
367                ScalarType::Float32.nullable(false),
368                ScalarType::Float32.nullable(true)
369            ),
370            ScalarType::Float32.nullable(false)
371        );
372        assert_eq!(
373            Fallible2.output_type(
374                ScalarType::Float32.nullable(false),
375                ScalarType::Float32.nullable(false)
376            ),
377            ScalarType::Float32.nullable(false)
378        );
379
380        assert_eq!(
381            Fallible3.output_type(
382                ScalarType::Float32.nullable(true),
383                ScalarType::Float32.nullable(true)
384            ),
385            ScalarType::Float32.nullable(true)
386        );
387        assert_eq!(
388            Fallible3.output_type(
389                ScalarType::Float32.nullable(true),
390                ScalarType::Float32.nullable(false)
391            ),
392            ScalarType::Float32.nullable(true)
393        );
394        assert_eq!(
395            Fallible3.output_type(
396                ScalarType::Float32.nullable(false),
397                ScalarType::Float32.nullable(true)
398            ),
399            ScalarType::Float32.nullable(true)
400        );
401        assert_eq!(
402            Fallible3.output_type(
403                ScalarType::Float32.nullable(false),
404                ScalarType::Float32.nullable(false)
405            ),
406            ScalarType::Float32.nullable(true)
407        );
408    }
409
410    #[mz_ore::test]
411    fn test_equivalence_nullable() {
412        test_equivalence_inner(true);
413    }
414
415    #[mz_ore::test]
416    fn test_equivalence_non_nullable() {
417        test_equivalence_inner(false);
418    }
419
420    /// Test the equivalence of the binary functions in the `func` module with their
421    /// derived sqlfunc implementation. The `input_nullable` parameter determines
422    /// whether the input colum is marked nullable or not.
423    fn test_equivalence_inner(input_nullable: bool) {
424        #[track_caller]
425        fn check<T: LazyBinaryFunc + std::fmt::Display + std::fmt::Debug>(
426            new: T,
427            old: BinaryFunc,
428            column_a_ty: &ColumnType,
429            column_b_ty: &ColumnType,
430        ) {
431            assert_eq!(
432                new.propagates_nulls(),
433                old.propagates_nulls(),
434                "{new:?} propagates_nulls mismatch"
435            );
436            assert_eq!(
437                new.introduces_nulls(),
438                old.introduces_nulls(),
439                "{new:?} introduces_nulls mismatch"
440            );
441            assert_eq!(
442                new.could_error(),
443                old.could_error(),
444                "{new:?} could_error mismatch"
445            );
446            assert_eq!(
447                new.is_monotone(),
448                old.is_monotone(),
449                "{new:?} is_monotone mismatch"
450            );
451            assert_eq!(
452                new.is_infix_op(),
453                old.is_infix_op(),
454                "{new:?} is_infix_op mismatch"
455            );
456            assert_eq!(
457                new.output_type(column_a_ty.clone(), column_b_ty.clone()),
458                old.output_type(column_a_ty.clone(), column_b_ty.clone()),
459                "{new:?} output_type mismatch"
460            );
461            assert_eq!(
462                format!("{}", new),
463                format!("{}", old),
464                "{new:?} format mismatch"
465            );
466        }
467
468        let i32_ty = ColumnType {
469            nullable: input_nullable,
470            scalar_type: ScalarType::Int32,
471        };
472        let ts_tz_ty = ColumnType {
473            nullable: input_nullable,
474            scalar_type: ScalarType::TimestampTz { precision: None },
475        };
476        let time_ty = ColumnType {
477            nullable: input_nullable,
478            scalar_type: ScalarType::Time,
479        };
480        let interval_ty = ColumnType {
481            nullable: input_nullable,
482            scalar_type: ScalarType::Interval,
483        };
484        let i32_map_ty = ColumnType {
485            nullable: input_nullable,
486            scalar_type: ScalarType::Map {
487                value_type: Box::new(ScalarType::Int32),
488                custom_id: None,
489            },
490        };
491
492        use BinaryFunc as BF;
493
494        // TODO: We're passing unexpected column types to the functions here,
495        //   which works because most don't look at the type. We should fix this
496        //   and pass expected column types.
497
498        check(func::AddInt16, BF::AddInt16, &i32_ty, &i32_ty);
499        check(func::AddInt32, BF::AddInt32, &i32_ty, &i32_ty);
500        check(func::AddInt64, BF::AddInt64, &i32_ty, &i32_ty);
501        check(func::AddUint16, BF::AddUInt16, &i32_ty, &i32_ty);
502        check(func::AddUint32, BF::AddUInt32, &i32_ty, &i32_ty);
503        check(func::AddUint64, BF::AddUInt64, &i32_ty, &i32_ty);
504        check(func::AddFloat32, BF::AddFloat32, &i32_ty, &i32_ty);
505        check(func::AddFloat64, BF::AddFloat64, &i32_ty, &i32_ty);
506        check(func::AddDateTime, BF::AddDateTime, &i32_ty, &i32_ty);
507        check(func::AddDateInterval, BF::AddDateInterval, &i32_ty, &i32_ty);
508        check(
509            func::AddTimeInterval,
510            BF::AddTimeInterval,
511            &ts_tz_ty,
512            &i32_ty,
513        );
514        check(func::RoundNumericBinary, BF::RoundNumeric, &i32_ty, &i32_ty);
515        check(func::ConvertFrom, BF::ConvertFrom, &i32_ty, &i32_ty);
516        check(func::Left, BF::Left, &i32_ty, &i32_ty);
517        check(func::Right, BF::Right, &i32_ty, &i32_ty);
518        check(func::Trim, BF::Trim, &i32_ty, &i32_ty);
519        check(func::TrimLeading, BF::TrimLeading, &i32_ty, &i32_ty);
520        check(func::TrimTrailing, BF::TrimTrailing, &i32_ty, &i32_ty);
521        check(func::Encode, BF::Encode, &i32_ty, &i32_ty);
522        check(func::Decode, BF::Decode, &i32_ty, &i32_ty);
523        check(
524            func::EncodedBytesCharLength,
525            BF::EncodedBytesCharLength,
526            &i32_ty,
527            &i32_ty,
528        );
529        check(func::AddNumeric, BF::AddNumeric, &i32_ty, &i32_ty);
530        check(func::AddInterval, BF::AddInterval, &i32_ty, &i32_ty);
531        check(func::BitAndInt16, BF::BitAndInt16, &i32_ty, &i32_ty);
532        check(func::BitAndInt32, BF::BitAndInt32, &i32_ty, &i32_ty);
533        check(func::BitAndInt64, BF::BitAndInt64, &i32_ty, &i32_ty);
534        check(func::BitAndUint16, BF::BitAndUInt16, &i32_ty, &i32_ty);
535        check(func::BitAndUint32, BF::BitAndUInt32, &i32_ty, &i32_ty);
536        check(func::BitAndUint64, BF::BitAndUInt64, &i32_ty, &i32_ty);
537        check(func::BitOrInt16, BF::BitOrInt16, &i32_ty, &i32_ty);
538        check(func::BitOrInt32, BF::BitOrInt32, &i32_ty, &i32_ty);
539        check(func::BitOrInt64, BF::BitOrInt64, &i32_ty, &i32_ty);
540        check(func::BitOrUint16, BF::BitOrUInt16, &i32_ty, &i32_ty);
541        check(func::BitOrUint32, BF::BitOrUInt32, &i32_ty, &i32_ty);
542        check(func::BitOrUint64, BF::BitOrUInt64, &i32_ty, &i32_ty);
543        check(func::BitXorInt16, BF::BitXorInt16, &i32_ty, &i32_ty);
544        check(func::BitXorInt32, BF::BitXorInt32, &i32_ty, &i32_ty);
545        check(func::BitXorInt64, BF::BitXorInt64, &i32_ty, &i32_ty);
546        check(func::BitXorUint16, BF::BitXorUInt16, &i32_ty, &i32_ty);
547        check(func::BitXorUint32, BF::BitXorUInt32, &i32_ty, &i32_ty);
548        check(func::BitXorUint64, BF::BitXorUInt64, &i32_ty, &i32_ty);
549
550        check(
551            func::BitShiftLeftInt16,
552            BF::BitShiftLeftInt16,
553            &i32_ty,
554            &i32_ty,
555        );
556        check(
557            func::BitShiftLeftInt32,
558            BF::BitShiftLeftInt32,
559            &i32_ty,
560            &i32_ty,
561        );
562        check(
563            func::BitShiftLeftInt64,
564            BF::BitShiftLeftInt64,
565            &i32_ty,
566            &i32_ty,
567        );
568        check(
569            func::BitShiftLeftUint16,
570            BF::BitShiftLeftUInt16,
571            &i32_ty,
572            &i32_ty,
573        );
574        check(
575            func::BitShiftLeftUint32,
576            BF::BitShiftLeftUInt32,
577            &i32_ty,
578            &i32_ty,
579        );
580        check(
581            func::BitShiftLeftUint64,
582            BF::BitShiftLeftUInt64,
583            &i32_ty,
584            &i32_ty,
585        );
586
587        check(
588            func::BitShiftRightInt16,
589            BF::BitShiftRightInt16,
590            &i32_ty,
591            &i32_ty,
592        );
593        check(
594            func::BitShiftRightInt32,
595            BF::BitShiftRightInt32,
596            &i32_ty,
597            &i32_ty,
598        );
599        check(
600            func::BitShiftRightInt64,
601            BF::BitShiftRightInt64,
602            &i32_ty,
603            &i32_ty,
604        );
605        check(
606            func::BitShiftRightUint16,
607            BF::BitShiftRightUInt16,
608            &i32_ty,
609            &i32_ty,
610        );
611        check(
612            func::BitShiftRightUint32,
613            BF::BitShiftRightUInt32,
614            &i32_ty,
615            &i32_ty,
616        );
617        check(
618            func::BitShiftRightUint64,
619            BF::BitShiftRightUInt64,
620            &i32_ty,
621            &i32_ty,
622        );
623
624        check(func::SubInt16, BF::SubInt16, &i32_ty, &i32_ty);
625        check(func::SubInt32, BF::SubInt32, &i32_ty, &i32_ty);
626        check(func::SubInt64, BF::SubInt64, &i32_ty, &i32_ty);
627        check(func::SubUint16, BF::SubUInt16, &i32_ty, &i32_ty);
628        check(func::SubUint32, BF::SubUInt32, &i32_ty, &i32_ty);
629        check(func::SubUint64, BF::SubUInt64, &i32_ty, &i32_ty);
630        check(func::SubFloat32, BF::SubFloat32, &i32_ty, &i32_ty);
631        check(func::SubFloat64, BF::SubFloat64, &i32_ty, &i32_ty);
632        check(func::SubNumeric, BF::SubNumeric, &i32_ty, &i32_ty);
633
634        check(func::AgeTimestamp, BF::AgeTimestamp, &i32_ty, &i32_ty);
635        check(func::AgeTimestamptz, BF::AgeTimestampTz, &i32_ty, &i32_ty);
636
637        check(func::SubTimestamp, BF::SubTimestamp, &ts_tz_ty, &i32_ty);
638        check(func::SubTimestamptz, BF::SubTimestampTz, &ts_tz_ty, &i32_ty);
639        check(func::SubDate, BF::SubDate, &i32_ty, &i32_ty);
640        check(func::SubTime, BF::SubTime, &i32_ty, &i32_ty);
641        check(func::SubInterval, BF::SubInterval, &i32_ty, &i32_ty);
642        check(func::SubDateInterval, BF::SubDateInterval, &i32_ty, &i32_ty);
643        check(
644            func::SubTimeInterval,
645            BF::SubTimeInterval,
646            &time_ty,
647            &interval_ty,
648        );
649
650        check(func::MulInt16, BF::MulInt16, &i32_ty, &i32_ty);
651        check(func::MulInt32, BF::MulInt32, &i32_ty, &i32_ty);
652        check(func::MulInt64, BF::MulInt64, &i32_ty, &i32_ty);
653        check(func::MulUint16, BF::MulUInt16, &i32_ty, &i32_ty);
654        check(func::MulUint32, BF::MulUInt32, &i32_ty, &i32_ty);
655        check(func::MulUint64, BF::MulUInt64, &i32_ty, &i32_ty);
656        check(func::MulFloat32, BF::MulFloat32, &i32_ty, &i32_ty);
657        check(func::MulFloat64, BF::MulFloat64, &i32_ty, &i32_ty);
658        check(func::MulNumeric, BF::MulNumeric, &i32_ty, &i32_ty);
659        check(func::MulInterval, BF::MulInterval, &i32_ty, &i32_ty);
660
661        check(func::DivInt16, BF::DivInt16, &i32_ty, &i32_ty);
662        check(func::DivInt32, BF::DivInt32, &i32_ty, &i32_ty);
663        check(func::DivInt64, BF::DivInt64, &i32_ty, &i32_ty);
664        check(func::DivUint16, BF::DivUInt16, &i32_ty, &i32_ty);
665        check(func::DivUint32, BF::DivUInt32, &i32_ty, &i32_ty);
666        check(func::DivUint64, BF::DivUInt64, &i32_ty, &i32_ty);
667        check(func::DivFloat32, BF::DivFloat32, &i32_ty, &i32_ty);
668        check(func::DivFloat64, BF::DivFloat64, &i32_ty, &i32_ty);
669        check(func::DivNumeric, BF::DivNumeric, &i32_ty, &i32_ty);
670        check(func::DivInterval, BF::DivInterval, &i32_ty, &i32_ty);
671
672        check(func::ModInt16, BF::ModInt16, &i32_ty, &i32_ty);
673        check(func::ModInt32, BF::ModInt32, &i32_ty, &i32_ty);
674        check(func::ModInt64, BF::ModInt64, &i32_ty, &i32_ty);
675        check(func::ModUint16, BF::ModUInt16, &i32_ty, &i32_ty);
676        check(func::ModUint32, BF::ModUInt32, &i32_ty, &i32_ty);
677        check(func::ModUint64, BF::ModUInt64, &i32_ty, &i32_ty);
678        check(func::ModFloat32, BF::ModFloat32, &i32_ty, &i32_ty);
679        check(func::ModFloat64, BF::ModFloat64, &i32_ty, &i32_ty);
680        check(func::ModNumeric, BF::ModNumeric, &i32_ty, &i32_ty);
681
682        check(func::LogBaseNumeric, BF::LogNumeric, &i32_ty, &i32_ty);
683        check(func::Power, BF::Power, &i32_ty, &i32_ty);
684        check(func::PowerNumeric, BF::PowerNumeric, &i32_ty, &i32_ty);
685
686        check(func::UuidGenerateV5, BF::UuidGenerateV5, &i32_ty, &i32_ty);
687
688        check(func::GetBit, BF::GetBit, &i32_ty, &i32_ty);
689        check(func::GetByte, BF::GetByte, &i32_ty, &i32_ty);
690
691        check(
692            func::ConstantTimeEqBytes,
693            BF::ConstantTimeEqBytes,
694            &i32_ty,
695            &i32_ty,
696        );
697        check(
698            func::ConstantTimeEqString,
699            BF::ConstantTimeEqString,
700            &i32_ty,
701            &i32_ty,
702        );
703
704        check(
705            func::RangeContainsI32,
706            BF::RangeContainsElem {
707                elem_type: ScalarType::Int32,
708                rev: false,
709            },
710            &i32_ty,
711            &i32_ty,
712        );
713        check(
714            func::RangeContainsI64,
715            BF::RangeContainsElem {
716                elem_type: ScalarType::Int64,
717                rev: false,
718            },
719            &i32_ty,
720            &i32_ty,
721        );
722        check(
723            func::RangeContainsDate,
724            BF::RangeContainsElem {
725                elem_type: ScalarType::Date,
726                rev: false,
727            },
728            &i32_ty,
729            &i32_ty,
730        );
731        check(
732            func::RangeContainsNumeric,
733            BF::RangeContainsElem {
734                elem_type: ScalarType::Numeric { max_scale: None },
735                rev: false,
736            },
737            &i32_ty,
738            &i32_ty,
739        );
740        check(
741            func::RangeContainsTimestamp,
742            BF::RangeContainsElem {
743                elem_type: ScalarType::Timestamp { precision: None },
744                rev: false,
745            },
746            &i32_ty,
747            &i32_ty,
748        );
749        check(
750            func::RangeContainsTimestampTz,
751            BF::RangeContainsElem {
752                elem_type: ScalarType::TimestampTz { precision: None },
753                rev: false,
754            },
755            &i32_ty,
756            &i32_ty,
757        );
758        check(
759            func::RangeContainsI32Rev,
760            BF::RangeContainsElem {
761                elem_type: ScalarType::Int32,
762                rev: true,
763            },
764            &i32_ty,
765            &i32_ty,
766        );
767        check(
768            func::RangeContainsI64Rev,
769            BF::RangeContainsElem {
770                elem_type: ScalarType::Int64,
771                rev: true,
772            },
773            &i32_ty,
774            &i32_ty,
775        );
776        check(
777            func::RangeContainsDateRev,
778            BF::RangeContainsElem {
779                elem_type: ScalarType::Date,
780                rev: true,
781            },
782            &i32_ty,
783            &i32_ty,
784        );
785        check(
786            func::RangeContainsNumericRev,
787            BF::RangeContainsElem {
788                elem_type: ScalarType::Numeric { max_scale: None },
789                rev: true,
790            },
791            &i32_ty,
792            &i32_ty,
793        );
794        check(
795            func::RangeContainsTimestampRev,
796            BF::RangeContainsElem {
797                elem_type: ScalarType::Timestamp { precision: None },
798                rev: true,
799            },
800            &i32_ty,
801            &i32_ty,
802        );
803        check(
804            func::RangeContainsTimestampTzRev,
805            BF::RangeContainsElem {
806                elem_type: ScalarType::TimestampTz { precision: None },
807                rev: true,
808            },
809            &i32_ty,
810            &i32_ty,
811        );
812
813        check(
814            func::RangeContainsRange,
815            BF::RangeContainsRange { rev: false },
816            &i32_ty,
817            &i32_ty,
818        );
819        check(
820            func::RangeContainsRangeRev,
821            BF::RangeContainsRange { rev: true },
822            &i32_ty,
823            &i32_ty,
824        );
825        check(func::RangeOverlaps, BF::RangeOverlaps, &i32_ty, &i32_ty);
826        check(func::RangeAfter, BF::RangeAfter, &i32_ty, &i32_ty);
827        check(func::RangeBefore, BF::RangeBefore, &i32_ty, &i32_ty);
828        check(func::RangeOverleft, BF::RangeOverleft, &i32_ty, &i32_ty);
829        check(func::RangeOverright, BF::RangeOverright, &i32_ty, &i32_ty);
830        check(func::RangeAdjacent, BF::RangeAdjacent, &i32_ty, &i32_ty);
831
832        check(func::RangeUnion, BF::RangeUnion, &i32_ty, &i32_ty);
833        check(
834            func::RangeIntersection,
835            BF::RangeIntersection,
836            &i32_ty,
837            &i32_ty,
838        );
839        check(func::RangeDifference, BF::RangeDifference, &i32_ty, &i32_ty);
840
841        check(func::Eq, BF::Eq, &i32_ty, &i32_ty);
842        check(func::NotEq, BF::NotEq, &i32_ty, &i32_ty);
843        check(func::Lt, BF::Lt, &i32_ty, &i32_ty);
844        check(func::Lte, BF::Lte, &i32_ty, &i32_ty);
845        check(func::Gt, BF::Gt, &i32_ty, &i32_ty);
846        check(func::Gte, BF::Gte, &i32_ty, &i32_ty);
847
848        check(func::LikeEscape, BF::LikeEscape, &i32_ty, &i32_ty);
849        check(func::TimezoneOffset, BF::TimezoneOffset, &i32_ty, &i32_ty);
850        check(func::TextConcatBinary, BF::TextConcat, &i32_ty, &i32_ty);
851
852        check(
853            func::ToCharTimestampFormat,
854            BF::ToCharTimestamp,
855            &i32_ty,
856            &i32_ty,
857        );
858        check(
859            func::ToCharTimestampTzFormat,
860            BF::ToCharTimestampTz,
861            &i32_ty,
862            &i32_ty,
863        );
864
865        // JsonbGet* have a `stringify` parameter that doesn't work with the sqlfunc macro.
866        // check(func::JsonbGetInt64, BF::JsonbGetInt64, &i32_ty, &i32_ty);
867        // check(func::JsonbGetString, BF::JsonbGetString, &i32_ty, &i32_ty);
868        // check(func::JsonbGetPath, BF::JsonbGetPath, &i32_ty, &i32_ty);
869        check(
870            func::JsonbContainsString,
871            BF::JsonbContainsString,
872            &i32_ty,
873            &i32_ty,
874        );
875        check(func::MapContainsKey, BF::MapContainsKey, &i32_ty, &i32_ty);
876        check(
877            func::MapContainsAllKeys,
878            BF::MapContainsAllKeys,
879            &i32_ty,
880            &i32_ty,
881        );
882        check(
883            func::MapContainsAnyKeys,
884            BF::MapContainsAnyKeys,
885            &i32_ty,
886            &i32_ty,
887        );
888        check(func::MapContainsMap, BF::MapContainsMap, &i32_ty, &i32_ty);
889        check(func::MapGetValue, BF::MapGetValue, &i32_map_ty, &i32_ty);
890        check(
891            func::ListContainsList,
892            BF::ListContainsList { rev: false },
893            &i32_ty,
894            &i32_ty,
895        );
896        check(
897            func::ListContainsListRev,
898            BF::ListContainsList { rev: true },
899            &i32_ty,
900            &i32_ty,
901        );
902
903        check(
904            func::JsonbContainsJsonb,
905            BF::JsonbContainsJsonb,
906            &i32_ty,
907            &i32_ty,
908        );
909        check(func::JsonbConcat, BF::JsonbConcat, &i32_ty, &i32_ty);
910        check(
911            func::JsonbDeleteInt64,
912            BF::JsonbDeleteInt64,
913            &i32_ty,
914            &i32_ty,
915        );
916        check(
917            func::JsonbDeleteString,
918            BF::JsonbDeleteString,
919            &i32_ty,
920            &i32_ty,
921        );
922
923        check(
924            func::DateBinTimestamp,
925            BF::DateBinTimestamp,
926            &i32_ty,
927            &i32_ty,
928        );
929        check(
930            func::DateBinTimestampTz,
931            BF::DateBinTimestampTz,
932            &i32_ty,
933            &i32_ty,
934        );
935        check(
936            func::DatePartIntervalNumeric,
937            BF::ExtractInterval,
938            &i32_ty,
939            &i32_ty,
940        );
941        check(func::DatePartTimeNumeric, BF::ExtractTime, &i32_ty, &i32_ty);
942        check(
943            func::DatePartTimestampTimestampNumeric,
944            BF::ExtractTimestamp,
945            &i32_ty,
946            &i32_ty,
947        );
948        check(
949            func::DatePartTimestampTimestampTzNumeric,
950            BF::ExtractTimestampTz,
951            &i32_ty,
952            &i32_ty,
953        );
954        check(
955            func::DatePartIntervalF64,
956            BF::DatePartInterval,
957            &i32_ty,
958            &i32_ty,
959        );
960        check(func::DatePartTimeF64, BF::DatePartTime, &i32_ty, &i32_ty);
961        check(
962            func::DatePartTimestampTimestampF64,
963            BF::DatePartTimestamp,
964            &i32_ty,
965            &i32_ty,
966        );
967        check(
968            func::DatePartTimestampTimestampTzF64,
969            BF::DatePartTimestampTz,
970            &i32_ty,
971            &i32_ty,
972        );
973
974        check(func::ExtractDateUnits, BF::ExtractDate, &i32_ty, &i32_ty);
975        check(
976            func::DateTruncUnitsTimestamp,
977            BF::DateTruncTimestamp,
978            &i32_ty,
979            &i32_ty,
980        );
981        check(
982            func::DateTruncUnitsTimestampTz,
983            BF::DateTruncTimestampTz,
984            &i32_ty,
985            &i32_ty,
986        );
987        check(
988            func::DateTruncInterval,
989            BF::DateTruncInterval,
990            &i32_ty,
991            &i32_ty,
992        );
993
994        check(func::ArrayLength, BF::ArrayLength, &i32_ty, &i32_ty);
995        check(func::ArrayLower, BF::ArrayLower, &i32_ty, &i32_ty);
996        check(func::ArrayRemove, BF::ArrayRemove, &i32_ty, &i32_ty);
997        check(func::ArrayUpper, BF::ArrayUpper, &i32_ty, &i32_ty);
998        // check(func::ListLength, BF::ListLength, &i32_ty, &i32_ty);
999        check(func::ArrayContains, BF::ArrayContains, &i32_ty, &i32_ty);
1000        check(
1001            func::ArrayContainsArray,
1002            BF::ArrayContainsArray { rev: false },
1003            &i32_ty,
1004            &i32_ty,
1005        );
1006        check(
1007            func::ArrayContainsArrayRev,
1008            BF::ArrayContainsArray { rev: true },
1009            &i32_ty,
1010            &i32_ty,
1011        );
1012        check(
1013            func::ArrayArrayConcat,
1014            BF::ArrayArrayConcat,
1015            &i32_ty,
1016            &i32_ty,
1017        );
1018        check(func::ListListConcat, BF::ListListConcat, &i32_ty, &i32_ty);
1019        check(
1020            func::ListElementConcat,
1021            BF::ListElementConcat,
1022            &i32_ty,
1023            &i32_ty,
1024        );
1025        check(
1026            func::ElementListConcat,
1027            BF::ElementListConcat,
1028            &i32_ty,
1029            &i32_ty,
1030        );
1031        check(func::ListRemove, BF::ListRemove, &i32_ty, &i32_ty);
1032        check(func::DigestString, BF::DigestString, &i32_ty, &i32_ty);
1033        check(func::DigestBytes, BF::DigestBytes, &i32_ty, &i32_ty);
1034        check(func::MzRenderTypmod, BF::MzRenderTypmod, &i32_ty, &i32_ty);
1035        check(
1036            func::MzAclItemContainsPrivilege,
1037            BF::MzAclItemContainsPrivilege,
1038            &i32_ty,
1039            &i32_ty,
1040        );
1041        check(func::ParseIdent, BF::ParseIdent, &i32_ty, &i32_ty);
1042        check(func::StartsWith, BF::StartsWith, &i32_ty, &i32_ty);
1043        check(func::PrettySql, BF::PrettySql, &i32_ty, &i32_ty);
1044    }
1045}