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    #[allow(dead_code)]
177    fn infallible1(a: f32, b: f32) -> f32 {
178        a + b
179    }
180
181    #[sqlfunc]
182    #[allow(dead_code)]
183    fn infallible2(a: Option<f32>, b: Option<f32>) -> f32 {
184        a.unwrap_or_default() + b.unwrap_or_default()
185    }
186
187    #[sqlfunc]
188    #[allow(dead_code)]
189    fn infallible3(a: f32, b: f32) -> Option<f32> {
190        Some(a + b)
191    }
192
193    #[mz_ore::test]
194    fn elision_rules_infallible() {
195        assert_eq!(format!("{}", Infallible1), "INFALLIBLE");
196        assert!(Infallible1.propagates_nulls());
197        assert!(!Infallible1.introduces_nulls());
198
199        assert!(!Infallible2.propagates_nulls());
200        assert!(!Infallible2.introduces_nulls());
201
202        assert!(Infallible3.propagates_nulls());
203        assert!(Infallible3.introduces_nulls());
204    }
205
206    #[mz_ore::test]
207    fn output_types_infallible() {
208        assert_eq!(
209            Infallible1.output_type(
210                ScalarType::Float32.nullable(true),
211                ScalarType::Float32.nullable(true)
212            ),
213            ScalarType::Float32.nullable(true)
214        );
215        assert_eq!(
216            Infallible1.output_type(
217                ScalarType::Float32.nullable(true),
218                ScalarType::Float32.nullable(false)
219            ),
220            ScalarType::Float32.nullable(true)
221        );
222        assert_eq!(
223            Infallible1.output_type(
224                ScalarType::Float32.nullable(false),
225                ScalarType::Float32.nullable(true)
226            ),
227            ScalarType::Float32.nullable(true)
228        );
229        assert_eq!(
230            Infallible1.output_type(
231                ScalarType::Float32.nullable(false),
232                ScalarType::Float32.nullable(false)
233            ),
234            ScalarType::Float32.nullable(false)
235        );
236
237        assert_eq!(
238            Infallible2.output_type(
239                ScalarType::Float32.nullable(true),
240                ScalarType::Float32.nullable(true)
241            ),
242            ScalarType::Float32.nullable(false)
243        );
244        assert_eq!(
245            Infallible2.output_type(
246                ScalarType::Float32.nullable(true),
247                ScalarType::Float32.nullable(false)
248            ),
249            ScalarType::Float32.nullable(false)
250        );
251        assert_eq!(
252            Infallible2.output_type(
253                ScalarType::Float32.nullable(false),
254                ScalarType::Float32.nullable(true)
255            ),
256            ScalarType::Float32.nullable(false)
257        );
258        assert_eq!(
259            Infallible2.output_type(
260                ScalarType::Float32.nullable(false),
261                ScalarType::Float32.nullable(false)
262            ),
263            ScalarType::Float32.nullable(false)
264        );
265
266        assert_eq!(
267            Infallible3.output_type(
268                ScalarType::Float32.nullable(true),
269                ScalarType::Float32.nullable(true)
270            ),
271            ScalarType::Float32.nullable(true)
272        );
273        assert_eq!(
274            Infallible3.output_type(
275                ScalarType::Float32.nullable(true),
276                ScalarType::Float32.nullable(false)
277            ),
278            ScalarType::Float32.nullable(true)
279        );
280        assert_eq!(
281            Infallible3.output_type(
282                ScalarType::Float32.nullable(false),
283                ScalarType::Float32.nullable(true)
284            ),
285            ScalarType::Float32.nullable(true)
286        );
287        assert_eq!(
288            Infallible3.output_type(
289                ScalarType::Float32.nullable(false),
290                ScalarType::Float32.nullable(false)
291            ),
292            ScalarType::Float32.nullable(true)
293        );
294    }
295
296    #[sqlfunc]
297    #[allow(dead_code)]
298    fn fallible1(a: f32, b: f32) -> Result<f32, EvalError> {
299        Ok(a + b)
300    }
301
302    #[sqlfunc]
303    #[allow(dead_code)]
304    fn fallible2(a: Option<f32>, b: Option<f32>) -> Result<f32, EvalError> {
305        Ok(a.unwrap_or_default() + b.unwrap_or_default())
306    }
307
308    #[sqlfunc]
309    #[allow(dead_code)]
310    fn fallible3(a: f32, b: f32) -> Result<Option<f32>, EvalError> {
311        Ok(Some(a + b))
312    }
313
314    #[mz_ore::test]
315    fn elision_rules_fallible() {
316        assert!(Fallible1.propagates_nulls());
317        assert!(!Fallible1.introduces_nulls());
318
319        assert!(!Fallible2.propagates_nulls());
320        assert!(!Fallible2.introduces_nulls());
321
322        assert!(Fallible3.propagates_nulls());
323        assert!(Fallible3.introduces_nulls());
324    }
325
326    #[mz_ore::test]
327    fn output_types_fallible() {
328        assert_eq!(
329            Fallible1.output_type(
330                ScalarType::Float32.nullable(true),
331                ScalarType::Float32.nullable(true)
332            ),
333            ScalarType::Float32.nullable(true)
334        );
335        assert_eq!(
336            Fallible1.output_type(
337                ScalarType::Float32.nullable(true),
338                ScalarType::Float32.nullable(false)
339            ),
340            ScalarType::Float32.nullable(true)
341        );
342        assert_eq!(
343            Fallible1.output_type(
344                ScalarType::Float32.nullable(false),
345                ScalarType::Float32.nullable(true)
346            ),
347            ScalarType::Float32.nullable(true)
348        );
349        assert_eq!(
350            Fallible1.output_type(
351                ScalarType::Float32.nullable(false),
352                ScalarType::Float32.nullable(false)
353            ),
354            ScalarType::Float32.nullable(false)
355        );
356
357        assert_eq!(
358            Fallible2.output_type(
359                ScalarType::Float32.nullable(true),
360                ScalarType::Float32.nullable(true)
361            ),
362            ScalarType::Float32.nullable(false)
363        );
364        assert_eq!(
365            Fallible2.output_type(
366                ScalarType::Float32.nullable(true),
367                ScalarType::Float32.nullable(false)
368            ),
369            ScalarType::Float32.nullable(false)
370        );
371        assert_eq!(
372            Fallible2.output_type(
373                ScalarType::Float32.nullable(false),
374                ScalarType::Float32.nullable(true)
375            ),
376            ScalarType::Float32.nullable(false)
377        );
378        assert_eq!(
379            Fallible2.output_type(
380                ScalarType::Float32.nullable(false),
381                ScalarType::Float32.nullable(false)
382            ),
383            ScalarType::Float32.nullable(false)
384        );
385
386        assert_eq!(
387            Fallible3.output_type(
388                ScalarType::Float32.nullable(true),
389                ScalarType::Float32.nullable(true)
390            ),
391            ScalarType::Float32.nullable(true)
392        );
393        assert_eq!(
394            Fallible3.output_type(
395                ScalarType::Float32.nullable(true),
396                ScalarType::Float32.nullable(false)
397            ),
398            ScalarType::Float32.nullable(true)
399        );
400        assert_eq!(
401            Fallible3.output_type(
402                ScalarType::Float32.nullable(false),
403                ScalarType::Float32.nullable(true)
404            ),
405            ScalarType::Float32.nullable(true)
406        );
407        assert_eq!(
408            Fallible3.output_type(
409                ScalarType::Float32.nullable(false),
410                ScalarType::Float32.nullable(false)
411            ),
412            ScalarType::Float32.nullable(true)
413        );
414    }
415
416    #[mz_ore::test]
417    fn test_equivalence_nullable() {
418        test_equivalence_inner(true);
419    }
420
421    #[mz_ore::test]
422    fn test_equivalence_non_nullable() {
423        test_equivalence_inner(false);
424    }
425
426    /// Test the equivalence of the binary functions in the `func` module with their
427    /// derived sqlfunc implementation. The `input_nullable` parameter determines
428    /// whether the input colum is marked nullable or not.
429    fn test_equivalence_inner(input_nullable: bool) {
430        #[track_caller]
431        fn check<T: LazyBinaryFunc + std::fmt::Display + std::fmt::Debug>(
432            new: T,
433            old: BinaryFunc,
434            column_a_ty: &ColumnType,
435            column_b_ty: &ColumnType,
436        ) {
437            assert_eq!(
438                new.propagates_nulls(),
439                old.propagates_nulls(),
440                "{new:?} propagates_nulls mismatch"
441            );
442            assert_eq!(
443                new.introduces_nulls(),
444                old.introduces_nulls(),
445                "{new:?} introduces_nulls mismatch"
446            );
447            assert_eq!(
448                new.could_error(),
449                old.could_error(),
450                "{new:?} could_error mismatch"
451            );
452            assert_eq!(
453                new.is_monotone(),
454                old.is_monotone(),
455                "{new:?} is_monotone mismatch"
456            );
457            assert_eq!(
458                new.is_infix_op(),
459                old.is_infix_op(),
460                "{new:?} is_infix_op mismatch"
461            );
462            assert_eq!(
463                new.output_type(column_a_ty.clone(), column_b_ty.clone()),
464                old.output_type(column_a_ty.clone(), column_b_ty.clone()),
465                "{new:?} output_type mismatch"
466            );
467            assert_eq!(
468                format!("{}", new),
469                format!("{}", old),
470                "{new:?} format mismatch"
471            );
472        }
473
474        let i32_ty = ColumnType {
475            nullable: input_nullable,
476            scalar_type: ScalarType::Int32,
477        };
478        let ts_tz_ty = ColumnType {
479            nullable: input_nullable,
480            scalar_type: ScalarType::TimestampTz { precision: None },
481        };
482        let time_ty = ColumnType {
483            nullable: input_nullable,
484            scalar_type: ScalarType::Time,
485        };
486        let interval_ty = ColumnType {
487            nullable: input_nullable,
488            scalar_type: ScalarType::Interval,
489        };
490        let i32_map_ty = ColumnType {
491            nullable: input_nullable,
492            scalar_type: ScalarType::Map {
493                value_type: Box::new(ScalarType::Int32),
494                custom_id: None,
495            },
496        };
497
498        use BinaryFunc as BF;
499
500        // TODO: We're passing unexpected column types to the functions here,
501        //   which works because most don't look at the type. We should fix this
502        //   and pass expected column types.
503
504        check(func::AddInt16, BF::AddInt16, &i32_ty, &i32_ty);
505        check(func::AddInt32, BF::AddInt32, &i32_ty, &i32_ty);
506        check(func::AddInt64, BF::AddInt64, &i32_ty, &i32_ty);
507        check(func::AddUint16, BF::AddUInt16, &i32_ty, &i32_ty);
508        check(func::AddUint32, BF::AddUInt32, &i32_ty, &i32_ty);
509        check(func::AddUint64, BF::AddUInt64, &i32_ty, &i32_ty);
510        check(func::AddFloat32, BF::AddFloat32, &i32_ty, &i32_ty);
511        check(func::AddFloat64, BF::AddFloat64, &i32_ty, &i32_ty);
512        check(func::AddDateTime, BF::AddDateTime, &i32_ty, &i32_ty);
513        check(func::AddDateInterval, BF::AddDateInterval, &i32_ty, &i32_ty);
514        check(
515            func::AddTimeInterval,
516            BF::AddTimeInterval,
517            &ts_tz_ty,
518            &i32_ty,
519        );
520        check(func::RoundNumericBinary, BF::RoundNumeric, &i32_ty, &i32_ty);
521        check(func::ConvertFrom, BF::ConvertFrom, &i32_ty, &i32_ty);
522        check(func::Left, BF::Left, &i32_ty, &i32_ty);
523        check(func::Right, BF::Right, &i32_ty, &i32_ty);
524        check(func::Trim, BF::Trim, &i32_ty, &i32_ty);
525        check(func::TrimLeading, BF::TrimLeading, &i32_ty, &i32_ty);
526        check(func::TrimTrailing, BF::TrimTrailing, &i32_ty, &i32_ty);
527        check(func::Encode, BF::Encode, &i32_ty, &i32_ty);
528        check(func::Decode, BF::Decode, &i32_ty, &i32_ty);
529        check(
530            func::EncodedBytesCharLength,
531            BF::EncodedBytesCharLength,
532            &i32_ty,
533            &i32_ty,
534        );
535        check(func::AddNumeric, BF::AddNumeric, &i32_ty, &i32_ty);
536        check(func::AddInterval, BF::AddInterval, &i32_ty, &i32_ty);
537        check(func::BitAndInt16, BF::BitAndInt16, &i32_ty, &i32_ty);
538        check(func::BitAndInt32, BF::BitAndInt32, &i32_ty, &i32_ty);
539        check(func::BitAndInt64, BF::BitAndInt64, &i32_ty, &i32_ty);
540        check(func::BitAndUint16, BF::BitAndUInt16, &i32_ty, &i32_ty);
541        check(func::BitAndUint32, BF::BitAndUInt32, &i32_ty, &i32_ty);
542        check(func::BitAndUint64, BF::BitAndUInt64, &i32_ty, &i32_ty);
543        check(func::BitOrInt16, BF::BitOrInt16, &i32_ty, &i32_ty);
544        check(func::BitOrInt32, BF::BitOrInt32, &i32_ty, &i32_ty);
545        check(func::BitOrInt64, BF::BitOrInt64, &i32_ty, &i32_ty);
546        check(func::BitOrUint16, BF::BitOrUInt16, &i32_ty, &i32_ty);
547        check(func::BitOrUint32, BF::BitOrUInt32, &i32_ty, &i32_ty);
548        check(func::BitOrUint64, BF::BitOrUInt64, &i32_ty, &i32_ty);
549        check(func::BitXorInt16, BF::BitXorInt16, &i32_ty, &i32_ty);
550        check(func::BitXorInt32, BF::BitXorInt32, &i32_ty, &i32_ty);
551        check(func::BitXorInt64, BF::BitXorInt64, &i32_ty, &i32_ty);
552        check(func::BitXorUint16, BF::BitXorUInt16, &i32_ty, &i32_ty);
553        check(func::BitXorUint32, BF::BitXorUInt32, &i32_ty, &i32_ty);
554        check(func::BitXorUint64, BF::BitXorUInt64, &i32_ty, &i32_ty);
555
556        check(
557            func::BitShiftLeftInt16,
558            BF::BitShiftLeftInt16,
559            &i32_ty,
560            &i32_ty,
561        );
562        check(
563            func::BitShiftLeftInt32,
564            BF::BitShiftLeftInt32,
565            &i32_ty,
566            &i32_ty,
567        );
568        check(
569            func::BitShiftLeftInt64,
570            BF::BitShiftLeftInt64,
571            &i32_ty,
572            &i32_ty,
573        );
574        check(
575            func::BitShiftLeftUint16,
576            BF::BitShiftLeftUInt16,
577            &i32_ty,
578            &i32_ty,
579        );
580        check(
581            func::BitShiftLeftUint32,
582            BF::BitShiftLeftUInt32,
583            &i32_ty,
584            &i32_ty,
585        );
586        check(
587            func::BitShiftLeftUint64,
588            BF::BitShiftLeftUInt64,
589            &i32_ty,
590            &i32_ty,
591        );
592
593        check(
594            func::BitShiftRightInt16,
595            BF::BitShiftRightInt16,
596            &i32_ty,
597            &i32_ty,
598        );
599        check(
600            func::BitShiftRightInt32,
601            BF::BitShiftRightInt32,
602            &i32_ty,
603            &i32_ty,
604        );
605        check(
606            func::BitShiftRightInt64,
607            BF::BitShiftRightInt64,
608            &i32_ty,
609            &i32_ty,
610        );
611        check(
612            func::BitShiftRightUint16,
613            BF::BitShiftRightUInt16,
614            &i32_ty,
615            &i32_ty,
616        );
617        check(
618            func::BitShiftRightUint32,
619            BF::BitShiftRightUInt32,
620            &i32_ty,
621            &i32_ty,
622        );
623        check(
624            func::BitShiftRightUint64,
625            BF::BitShiftRightUInt64,
626            &i32_ty,
627            &i32_ty,
628        );
629
630        check(func::SubInt16, BF::SubInt16, &i32_ty, &i32_ty);
631        check(func::SubInt32, BF::SubInt32, &i32_ty, &i32_ty);
632        check(func::SubInt64, BF::SubInt64, &i32_ty, &i32_ty);
633        check(func::SubUint16, BF::SubUInt16, &i32_ty, &i32_ty);
634        check(func::SubUint32, BF::SubUInt32, &i32_ty, &i32_ty);
635        check(func::SubUint64, BF::SubUInt64, &i32_ty, &i32_ty);
636        check(func::SubFloat32, BF::SubFloat32, &i32_ty, &i32_ty);
637        check(func::SubFloat64, BF::SubFloat64, &i32_ty, &i32_ty);
638        check(func::SubNumeric, BF::SubNumeric, &i32_ty, &i32_ty);
639
640        check(func::AgeTimestamp, BF::AgeTimestamp, &i32_ty, &i32_ty);
641        check(func::AgeTimestamptz, BF::AgeTimestampTz, &i32_ty, &i32_ty);
642
643        check(func::SubTimestamp, BF::SubTimestamp, &ts_tz_ty, &i32_ty);
644        check(func::SubTimestamptz, BF::SubTimestampTz, &ts_tz_ty, &i32_ty);
645        check(func::SubDate, BF::SubDate, &i32_ty, &i32_ty);
646        check(func::SubTime, BF::SubTime, &i32_ty, &i32_ty);
647        check(func::SubInterval, BF::SubInterval, &i32_ty, &i32_ty);
648        check(func::SubDateInterval, BF::SubDateInterval, &i32_ty, &i32_ty);
649        check(
650            func::SubTimeInterval,
651            BF::SubTimeInterval,
652            &time_ty,
653            &interval_ty,
654        );
655
656        check(func::MulInt16, BF::MulInt16, &i32_ty, &i32_ty);
657        check(func::MulInt32, BF::MulInt32, &i32_ty, &i32_ty);
658        check(func::MulInt64, BF::MulInt64, &i32_ty, &i32_ty);
659        check(func::MulUint16, BF::MulUInt16, &i32_ty, &i32_ty);
660        check(func::MulUint32, BF::MulUInt32, &i32_ty, &i32_ty);
661        check(func::MulUint64, BF::MulUInt64, &i32_ty, &i32_ty);
662        check(func::MulFloat32, BF::MulFloat32, &i32_ty, &i32_ty);
663        check(func::MulFloat64, BF::MulFloat64, &i32_ty, &i32_ty);
664        check(func::MulNumeric, BF::MulNumeric, &i32_ty, &i32_ty);
665        check(func::MulInterval, BF::MulInterval, &i32_ty, &i32_ty);
666
667        check(func::DivInt16, BF::DivInt16, &i32_ty, &i32_ty);
668        check(func::DivInt32, BF::DivInt32, &i32_ty, &i32_ty);
669        check(func::DivInt64, BF::DivInt64, &i32_ty, &i32_ty);
670        check(func::DivUint16, BF::DivUInt16, &i32_ty, &i32_ty);
671        check(func::DivUint32, BF::DivUInt32, &i32_ty, &i32_ty);
672        check(func::DivUint64, BF::DivUInt64, &i32_ty, &i32_ty);
673        check(func::DivFloat32, BF::DivFloat32, &i32_ty, &i32_ty);
674        check(func::DivFloat64, BF::DivFloat64, &i32_ty, &i32_ty);
675        check(func::DivNumeric, BF::DivNumeric, &i32_ty, &i32_ty);
676        check(func::DivInterval, BF::DivInterval, &i32_ty, &i32_ty);
677
678        check(func::ModInt16, BF::ModInt16, &i32_ty, &i32_ty);
679        check(func::ModInt32, BF::ModInt32, &i32_ty, &i32_ty);
680        check(func::ModInt64, BF::ModInt64, &i32_ty, &i32_ty);
681        check(func::ModUint16, BF::ModUInt16, &i32_ty, &i32_ty);
682        check(func::ModUint32, BF::ModUInt32, &i32_ty, &i32_ty);
683        check(func::ModUint64, BF::ModUInt64, &i32_ty, &i32_ty);
684        check(func::ModFloat32, BF::ModFloat32, &i32_ty, &i32_ty);
685        check(func::ModFloat64, BF::ModFloat64, &i32_ty, &i32_ty);
686        check(func::ModNumeric, BF::ModNumeric, &i32_ty, &i32_ty);
687
688        check(func::LogBaseNumeric, BF::LogNumeric, &i32_ty, &i32_ty);
689        check(func::Power, BF::Power, &i32_ty, &i32_ty);
690        check(func::PowerNumeric, BF::PowerNumeric, &i32_ty, &i32_ty);
691
692        check(func::UuidGenerateV5, BF::UuidGenerateV5, &i32_ty, &i32_ty);
693
694        check(func::GetBit, BF::GetBit, &i32_ty, &i32_ty);
695        check(func::GetByte, BF::GetByte, &i32_ty, &i32_ty);
696
697        check(
698            func::ConstantTimeEqBytes,
699            BF::ConstantTimeEqBytes,
700            &i32_ty,
701            &i32_ty,
702        );
703        check(
704            func::ConstantTimeEqString,
705            BF::ConstantTimeEqString,
706            &i32_ty,
707            &i32_ty,
708        );
709
710        check(
711            func::RangeContainsI32,
712            BF::RangeContainsElem {
713                elem_type: ScalarType::Int32,
714                rev: false,
715            },
716            &i32_ty,
717            &i32_ty,
718        );
719        check(
720            func::RangeContainsI64,
721            BF::RangeContainsElem {
722                elem_type: ScalarType::Int64,
723                rev: false,
724            },
725            &i32_ty,
726            &i32_ty,
727        );
728        check(
729            func::RangeContainsDate,
730            BF::RangeContainsElem {
731                elem_type: ScalarType::Date,
732                rev: false,
733            },
734            &i32_ty,
735            &i32_ty,
736        );
737        check(
738            func::RangeContainsNumeric,
739            BF::RangeContainsElem {
740                elem_type: ScalarType::Numeric { max_scale: None },
741                rev: false,
742            },
743            &i32_ty,
744            &i32_ty,
745        );
746        check(
747            func::RangeContainsTimestamp,
748            BF::RangeContainsElem {
749                elem_type: ScalarType::Timestamp { precision: None },
750                rev: false,
751            },
752            &i32_ty,
753            &i32_ty,
754        );
755        check(
756            func::RangeContainsTimestampTz,
757            BF::RangeContainsElem {
758                elem_type: ScalarType::TimestampTz { precision: None },
759                rev: false,
760            },
761            &i32_ty,
762            &i32_ty,
763        );
764        check(
765            func::RangeContainsI32Rev,
766            BF::RangeContainsElem {
767                elem_type: ScalarType::Int32,
768                rev: true,
769            },
770            &i32_ty,
771            &i32_ty,
772        );
773        check(
774            func::RangeContainsI64Rev,
775            BF::RangeContainsElem {
776                elem_type: ScalarType::Int64,
777                rev: true,
778            },
779            &i32_ty,
780            &i32_ty,
781        );
782        check(
783            func::RangeContainsDateRev,
784            BF::RangeContainsElem {
785                elem_type: ScalarType::Date,
786                rev: true,
787            },
788            &i32_ty,
789            &i32_ty,
790        );
791        check(
792            func::RangeContainsNumericRev,
793            BF::RangeContainsElem {
794                elem_type: ScalarType::Numeric { max_scale: None },
795                rev: true,
796            },
797            &i32_ty,
798            &i32_ty,
799        );
800        check(
801            func::RangeContainsTimestampRev,
802            BF::RangeContainsElem {
803                elem_type: ScalarType::Timestamp { precision: None },
804                rev: true,
805            },
806            &i32_ty,
807            &i32_ty,
808        );
809        check(
810            func::RangeContainsTimestampTzRev,
811            BF::RangeContainsElem {
812                elem_type: ScalarType::TimestampTz { precision: None },
813                rev: true,
814            },
815            &i32_ty,
816            &i32_ty,
817        );
818
819        check(
820            func::RangeContainsRange,
821            BF::RangeContainsRange { rev: false },
822            &i32_ty,
823            &i32_ty,
824        );
825        check(
826            func::RangeContainsRangeRev,
827            BF::RangeContainsRange { rev: true },
828            &i32_ty,
829            &i32_ty,
830        );
831        check(func::RangeOverlaps, BF::RangeOverlaps, &i32_ty, &i32_ty);
832        check(func::RangeAfter, BF::RangeAfter, &i32_ty, &i32_ty);
833        check(func::RangeBefore, BF::RangeBefore, &i32_ty, &i32_ty);
834        check(func::RangeOverleft, BF::RangeOverleft, &i32_ty, &i32_ty);
835        check(func::RangeOverright, BF::RangeOverright, &i32_ty, &i32_ty);
836        check(func::RangeAdjacent, BF::RangeAdjacent, &i32_ty, &i32_ty);
837
838        check(func::RangeUnion, BF::RangeUnion, &i32_ty, &i32_ty);
839        check(
840            func::RangeIntersection,
841            BF::RangeIntersection,
842            &i32_ty,
843            &i32_ty,
844        );
845        check(func::RangeDifference, BF::RangeDifference, &i32_ty, &i32_ty);
846
847        check(func::Eq, BF::Eq, &i32_ty, &i32_ty);
848        check(func::NotEq, BF::NotEq, &i32_ty, &i32_ty);
849        check(func::Lt, BF::Lt, &i32_ty, &i32_ty);
850        check(func::Lte, BF::Lte, &i32_ty, &i32_ty);
851        check(func::Gt, BF::Gt, &i32_ty, &i32_ty);
852        check(func::Gte, BF::Gte, &i32_ty, &i32_ty);
853
854        check(func::LikeEscape, BF::LikeEscape, &i32_ty, &i32_ty);
855        check(func::TimezoneOffset, BF::TimezoneOffset, &i32_ty, &i32_ty);
856        check(func::TextConcatBinary, BF::TextConcat, &i32_ty, &i32_ty);
857
858        check(
859            func::ToCharTimestampFormat,
860            BF::ToCharTimestamp,
861            &i32_ty,
862            &i32_ty,
863        );
864        check(
865            func::ToCharTimestampTzFormat,
866            BF::ToCharTimestampTz,
867            &i32_ty,
868            &i32_ty,
869        );
870
871        // JsonbGet* have a `stringify` parameter that doesn't work with the sqlfunc macro.
872        // check(func::JsonbGetInt64, BF::JsonbGetInt64, &i32_ty, &i32_ty);
873        // check(func::JsonbGetString, BF::JsonbGetString, &i32_ty, &i32_ty);
874        // check(func::JsonbGetPath, BF::JsonbGetPath, &i32_ty, &i32_ty);
875        check(
876            func::JsonbContainsString,
877            BF::JsonbContainsString,
878            &i32_ty,
879            &i32_ty,
880        );
881        check(func::MapContainsKey, BF::MapContainsKey, &i32_ty, &i32_ty);
882        check(
883            func::MapContainsAllKeys,
884            BF::MapContainsAllKeys,
885            &i32_ty,
886            &i32_ty,
887        );
888        check(
889            func::MapContainsAnyKeys,
890            BF::MapContainsAnyKeys,
891            &i32_ty,
892            &i32_ty,
893        );
894        check(func::MapContainsMap, BF::MapContainsMap, &i32_ty, &i32_ty);
895        check(func::MapGetValue, BF::MapGetValue, &i32_map_ty, &i32_ty);
896        check(
897            func::ListContainsList,
898            BF::ListContainsList { rev: false },
899            &i32_ty,
900            &i32_ty,
901        );
902        check(
903            func::ListContainsListRev,
904            BF::ListContainsList { rev: true },
905            &i32_ty,
906            &i32_ty,
907        );
908
909        check(
910            func::JsonbContainsJsonb,
911            BF::JsonbContainsJsonb,
912            &i32_ty,
913            &i32_ty,
914        );
915        check(func::JsonbConcat, BF::JsonbConcat, &i32_ty, &i32_ty);
916        check(
917            func::JsonbDeleteInt64,
918            BF::JsonbDeleteInt64,
919            &i32_ty,
920            &i32_ty,
921        );
922        check(
923            func::JsonbDeleteString,
924            BF::JsonbDeleteString,
925            &i32_ty,
926            &i32_ty,
927        );
928
929        check(
930            func::DateBinTimestamp,
931            BF::DateBinTimestamp,
932            &i32_ty,
933            &i32_ty,
934        );
935        check(
936            func::DateBinTimestampTz,
937            BF::DateBinTimestampTz,
938            &i32_ty,
939            &i32_ty,
940        );
941        check(
942            func::DatePartIntervalNumeric,
943            BF::ExtractInterval,
944            &i32_ty,
945            &i32_ty,
946        );
947        check(func::DatePartTimeNumeric, BF::ExtractTime, &i32_ty, &i32_ty);
948        check(
949            func::DatePartTimestampTimestampNumeric,
950            BF::ExtractTimestamp,
951            &i32_ty,
952            &i32_ty,
953        );
954        check(
955            func::DatePartTimestampTimestampTzNumeric,
956            BF::ExtractTimestampTz,
957            &i32_ty,
958            &i32_ty,
959        );
960        check(
961            func::DatePartIntervalF64,
962            BF::DatePartInterval,
963            &i32_ty,
964            &i32_ty,
965        );
966        check(func::DatePartTimeF64, BF::DatePartTime, &i32_ty, &i32_ty);
967        check(
968            func::DatePartTimestampTimestampF64,
969            BF::DatePartTimestamp,
970            &i32_ty,
971            &i32_ty,
972        );
973        check(
974            func::DatePartTimestampTimestampTzF64,
975            BF::DatePartTimestampTz,
976            &i32_ty,
977            &i32_ty,
978        );
979
980        check(func::ExtractDateUnits, BF::ExtractDate, &i32_ty, &i32_ty);
981        check(
982            func::DateTruncUnitsTimestamp,
983            BF::DateTruncTimestamp,
984            &i32_ty,
985            &i32_ty,
986        );
987        check(
988            func::DateTruncUnitsTimestampTz,
989            BF::DateTruncTimestampTz,
990            &i32_ty,
991            &i32_ty,
992        );
993        check(
994            func::DateTruncInterval,
995            BF::DateTruncInterval,
996            &i32_ty,
997            &i32_ty,
998        );
999
1000        check(func::ArrayLength, BF::ArrayLength, &i32_ty, &i32_ty);
1001        check(func::ArrayLower, BF::ArrayLower, &i32_ty, &i32_ty);
1002        check(func::ArrayRemove, BF::ArrayRemove, &i32_ty, &i32_ty);
1003        check(func::ArrayUpper, BF::ArrayUpper, &i32_ty, &i32_ty);
1004        // check(func::ListLength, BF::ListLength, &i32_ty, &i32_ty);
1005        check(func::ArrayContains, BF::ArrayContains, &i32_ty, &i32_ty);
1006        check(
1007            func::ArrayContainsArray,
1008            BF::ArrayContainsArray { rev: false },
1009            &i32_ty,
1010            &i32_ty,
1011        );
1012        check(
1013            func::ArrayContainsArrayRev,
1014            BF::ArrayContainsArray { rev: true },
1015            &i32_ty,
1016            &i32_ty,
1017        );
1018        check(
1019            func::ArrayArrayConcat,
1020            BF::ArrayArrayConcat,
1021            &i32_ty,
1022            &i32_ty,
1023        );
1024        check(func::ListListConcat, BF::ListListConcat, &i32_ty, &i32_ty);
1025        check(
1026            func::ListElementConcat,
1027            BF::ListElementConcat,
1028            &i32_ty,
1029            &i32_ty,
1030        );
1031        check(
1032            func::ElementListConcat,
1033            BF::ElementListConcat,
1034            &i32_ty,
1035            &i32_ty,
1036        );
1037        check(func::ListRemove, BF::ListRemove, &i32_ty, &i32_ty);
1038        check(func::DigestString, BF::DigestString, &i32_ty, &i32_ty);
1039        check(func::DigestBytes, BF::DigestBytes, &i32_ty, &i32_ty);
1040        check(func::MzRenderTypmod, BF::MzRenderTypmod, &i32_ty, &i32_ty);
1041        check(
1042            func::MzAclItemContainsPrivilege,
1043            BF::MzAclItemContainsPrivilege,
1044            &i32_ty,
1045            &i32_ty,
1046        );
1047        check(func::ParseIdent, BF::ParseIdent, &i32_ty, &i32_ty);
1048        check(func::StartsWith, BF::StartsWith, &i32_ty, &i32_ty);
1049        check(func::PrettySql, BF::PrettySql, &i32_ty, &i32_ty);
1050    }
1051}