Skip to main content

linkrs_query/executor/expression/functions/builtin/
math.rs

1//! Implementation of mathematical functions
2
3use crate::executor::expression::ExpressionError;
4use linkrs_core::value::NullType;
5use linkrs_core::Value;
6
7define_function_enum! {
8    /// Enumeration of mathematical functions
9    pub enum MathFunction {
10        Abs => {
11            name: "abs",
12            arity: 1,
13            variadic: false,
14            description: "Calculating Absolute Values",
15            handler: execute_abs
16        },
17        Sqrt => {
18            name: "sqrt",
19            arity: 1,
20            variadic: false,
21            description: "square root calculation",
22            handler: execute_sqrt
23        },
24        Pow => {
25            name: "pow",
26            arity: 2,
27            variadic: false,
28            description: "exponentiate (math.)",
29            handler: execute_pow
30        },
31        Log => {
32            name: "log",
33            arity: 2,
34            variadic: false,
35            description: "logarithmic",
36            handler: execute_log
37        },
38        Log10 => {
39            name: "log10",
40            arity: 1,
41            variadic: false,
42            description: "Calculating logarithms with base 10",
43            handler: execute_log10
44        },
45        Sin => {
46            name: "sin",
47            arity: 1,
48            variadic: false,
49            description: "calculate the sine",
50            handler: execute_sin
51        },
52        Cos => {
53            name: "cos",
54            arity: 1,
55            variadic: false,
56            description: "calculate the cosine",
57            handler: execute_cos
58        },
59        Tan => {
60            name: "tan",
61            arity: 1,
62            variadic: false,
63            description: "arithmetic tangent (math.)",
64            handler: execute_tan
65        },
66        Round => {
67            name: "round",
68            arity: 1,
69            variadic: false,
70            description: "discard four, but treat five as whole (of decimal points)",
71            handler: execute_round
72        },
73        Ceil => {
74            name: "ceil",
75            arity: 1,
76            variadic: false,
77            description: "Round up",
78            handler: execute_ceil
79        },
80        Floor => {
81            name: "floor",
82            arity: 1,
83            variadic: false,
84            description: "round down",
85            handler: execute_floor
86        },
87        Asin => {
88            name: "asin",
89            arity: 1,
90            variadic: false,
91            description: "calculate the arcsine",
92            handler: execute_asin
93        },
94        Acos => {
95            name: "acos",
96            arity: 1,
97            variadic: false,
98            description: "Calculate the inverse cosine",
99            handler: execute_acos
100        },
101        Atan => {
102            name: "atan",
103            arity: 1,
104            variadic: false,
105            description: "Compute the arctangent",
106            handler: execute_atan
107        },
108        Cbrt => {
109            name: "cbrt",
110            arity: 1,
111            variadic: false,
112            description: "calculate the cube root",
113            handler: execute_cbrt
114        },
115        Hypot => {
116            name: "hypot",
117            arity: 2,
118            variadic: false,
119            description: "Compute the hypotenuse of a right triangle",
120            handler: execute_hypot
121        },
122        Sign => {
123            name: "sign",
124            arity: 1,
125            variadic: false,
126            description: "Return Value Symbol",
127            handler: execute_sign
128        },
129        Rand => {
130            name: "rand",
131            arity: 0,
132            variadic: false,
133            description: "Generate random floating point numbers",
134            handler: execute_rand
135        },
136        Rand32 => {
137            name: "rand32",
138            arity: 0,
139            variadic: true,
140            description: "Generate 32-bit random integers",
141            handler: execute_rand32
142        },
143        Rand64 => {
144            name: "rand64",
145            arity: 0,
146            variadic: false,
147            description: "Generate 64-bit random integers",
148            handler: execute_rand64
149        },
150        E => {
151            name: "e",
152            arity: 0,
153            variadic: false,
154            description: "Returns the natural constant e",
155            handler: execute_e
156        },
157        Pi => {
158            name: "pi",
159            arity: 0,
160            variadic: false,
161            description: "Return to pi",
162            handler: execute_pi
163        },
164        Exp2 => {
165            name: "exp2",
166            arity: 1,
167            variadic: false,
168            description: "Calculating powers of 2",
169            handler: execute_exp2
170        },
171        Log2 => {
172            name: "log2",
173            arity: 1,
174            variadic: false,
175            description: "Calculating logarithms with a base of 2",
176            handler: execute_log2
177        },
178        Radians => {
179            name: "radians",
180            arity: 1,
181            variadic: false,
182            description: "Angle to radian",
183            handler: execute_radians
184        },
185        BitAnd => {
186            name: "bit_and",
187            arity: 2,
188            variadic: false,
189            description: "compatibility with",
190            handler: execute_bit_and
191        },
192        BitOr => {
193            name: "bit_or",
194            arity: 2,
195            variadic: false,
196            description: "push-button or",
197            handler: execute_bit_or
198        },
199        BitXor => {
200            name: "bit_xor",
201            arity: 2,
202            variadic: false,
203            description: "palindromic or binomial (math.)",
204            handler: execute_bit_xor
205        },
206        Atan2 => {
207            name: "atan2",
208            arity: 2,
209            variadic: false,
210            description: "Compute the arctangent of y/x",
211            handler: execute_atan2
212        },
213        Sinh => {
214            name: "sinh",
215            arity: 1,
216            variadic: false,
217            description: "Calculate the hyperbolic sine",
218            handler: execute_sinh
219        },
220        Cosh => {
221            name: "cosh",
222            arity: 1,
223            variadic: false,
224            description: "Calculate the hyperbolic cosine",
225            handler: execute_cosh
226        },
227        Tanh => {
228            name: "tanh",
229            arity: 1,
230            variadic: false,
231            description: "Calculate the hyperbolic tangent",
232            handler: execute_tanh
233        },
234        Degrees => {
235            name: "degrees",
236            arity: 1,
237            variadic: false,
238            description: "Convert radians to degrees",
239            handler: execute_degrees
240        },
241        Gcd => {
242            name: "gcd",
243            arity: 2,
244            variadic: false,
245            description: "Greatest common divisor",
246            handler: execute_gcd
247        },
248        Lcm => {
249            name: "lcm",
250            arity: 2,
251            variadic: false,
252            description: "Least common multiple",
253            handler: execute_lcm
254        },
255        Factorial => {
256            name: "factorial",
257            arity: 1,
258            variadic: false,
259            description: "Calculate factorial of a number",
260            handler: execute_factorial
261        },
262        Gamma => {
263            name: "gamma",
264            arity: 1,
265            variadic: false,
266            description: "Calculate gamma function",
267            handler: execute_gamma
268        },
269        Lgamma => {
270            name: "lgamma",
271            arity: 1,
272            variadic: false,
273            description: "Calculate natural logarithm of absolute value of gamma function",
274            handler: execute_lgamma
275        },
276        Negate => {
277            name: "negate",
278            arity: 1,
279            variadic: false,
280            description: "Negate a number",
281            handler: execute_negate
282        },
283        Even => {
284            name: "even",
285            arity: 1,
286            variadic: false,
287            description: "Round up to nearest even integer",
288            handler: execute_even
289        },
290        SetSeed => {
291            name: "set_seed",
292            arity: 1,
293            variadic: false,
294            description: "Set random seed",
295            handler: execute_set_seed
296        },
297        BitShiftLeft => {
298            name: "bit_shift_left",
299            arity: 2,
300            variadic: false,
301            description: "Bitwise left shift",
302            handler: execute_bit_shift_left
303        },
304        BitShiftRight => {
305            name: "bit_shift_right",
306            arity: 2,
307            variadic: false,
308            description: "Bitwise right shift",
309            handler: execute_bit_shift_right
310        },
311    }
312}
313
314define_unary_numeric_fn!(
315    execute_abs,
316    int: |i: i32| Ok(Value::Int(i.abs())),
317    float: |f: f32| Ok(Value::Float(f.abs())),
318    "abs"
319);
320
321define_unary_float_fn!(execute_sqrt, |v: f32| v.sqrt(), "sqrt");
322define_unary_float_fn!(execute_sin, |v: f32| v.sin(), "sin");
323define_unary_float_fn!(execute_cos, |v: f32| v.cos(), "cos");
324define_unary_float_fn!(execute_tan, |v: f32| v.tan(), "tan");
325define_unary_float_fn!(execute_log10, |v: f32| v.log10(), "log10");
326
327define_unary_numeric_fn!(
328    execute_round,
329    int: |i: i32| Ok(Value::Int(i)),
330    float: |f: f32| Ok(Value::Float(f.round())),
331    "round"
332);
333
334define_unary_numeric_fn!(
335    execute_ceil,
336    int: |i: i32| Ok(Value::Float(i as f32)),
337    float: |f: f32| Ok(Value::Float(f.ceil())),
338    "ceil"
339);
340
341define_unary_numeric_fn!(
342    execute_floor,
343    int: |i: i32| Ok(Value::Float(i as f32)),
344    float: |f: f32| Ok(Value::Float(f.floor())),
345    "floor"
346);
347
348define_binary_numeric_fn!(
349    execute_pow,
350    |a: f32, b: f32| Ok(Value::Float(a.powf(b))),
351    "pow"
352);
353
354define_binary_numeric_fn!(
355    execute_log,
356    |base: f32, val: f32| Ok(Value::Float(val.log(base))),
357    "log"
358);
359
360// New implementation of mathematical functions
361define_unary_float_fn!(execute_asin, |v: f32| v.asin(), "asin");
362define_unary_float_fn!(execute_acos, |v: f32| v.acos(), "acos");
363define_unary_float_fn!(execute_atan, |v: f32| v.atan(), "atan");
364define_unary_float_fn!(execute_cbrt, |v: f32| v.cbrt(), "cbrt");
365define_unary_float_fn!(execute_exp2, |v: f32| v.exp2(), "exp2");
366define_unary_float_fn!(execute_log2, |v: f32| v.log2(), "log2");
367define_unary_float_fn!(execute_radians, |v: f32| v.to_radians(), "radians");
368
369define_binary_numeric_fn!(
370    execute_hypot,
371    |a: f32, b: f32| Ok(Value::Float(a.hypot(b))),
372    "hypot"
373);
374
375fn execute_sign(args: &[Value]) -> Result<Value, ExpressionError> {
376    match &args[0] {
377        Value::SmallInt(i) => Ok(Value::SmallInt(i.signum())),
378        Value::Int(i) => Ok(Value::Int(i.signum())),
379        Value::BigInt(i) => Ok(Value::BigInt(i.signum())),
380        Value::Float(f) => Ok(Value::Int(f.signum() as i32)),
381        Value::Double(f) => Ok(Value::BigInt(f.signum() as i64)),
382        Value::Null(_) => Ok(Value::Null(NullType::Null)),
383        _ => Err(ExpressionError::type_error(
384            "The sign function requires a numeric type",
385        )),
386    }
387}
388
389fn execute_rand(_args: &[Value]) -> Result<Value, ExpressionError> {
390    use rand::Rng;
391    let mut rng = rand::thread_rng();
392    Ok(Value::Float(rng.gen::<f32>()))
393}
394
395fn execute_rand32(args: &[Value]) -> Result<Value, ExpressionError> {
396    use rand::Rng;
397    let mut rng = rand::thread_rng();
398    let result = match args.len() {
399        0 => rng.gen::<i32>(),
400        1 => match &args[0] {
401            Value::Int(max) => rng.gen_range(0..*max),
402            Value::Null(_) => return Ok(Value::Null(NullType::Null)),
403            _ => {
404                return Err(ExpressionError::type_error(
405                    "The rand32 function takes integer arguments",
406                ))
407            }
408        },
409        2 => match (&args[0], &args[1]) {
410            (Value::Int(min), Value::Int(max)) => rng.gen_range(*min..*max),
411            (Value::Null(_), _) | (_, Value::Null(_)) => return Ok(Value::Null(NullType::Null)),
412            _ => {
413                return Err(ExpressionError::type_error(
414                    "The rand32 function takes integer arguments",
415                ))
416            }
417        },
418        _ => {
419            return Err(ExpressionError::type_error(
420                "The rand32 function takes 0-2 arguments",
421            ))
422        }
423    };
424    Ok(Value::Int(result))
425}
426
427fn execute_rand64(_args: &[Value]) -> Result<Value, ExpressionError> {
428    use rand::Rng;
429    let mut rng = rand::thread_rng();
430    Ok(Value::BigInt(rng.gen::<i64>()))
431}
432
433fn execute_e(_args: &[Value]) -> Result<Value, ExpressionError> {
434    Ok(Value::Float(std::f32::consts::E))
435}
436
437fn execute_pi(_args: &[Value]) -> Result<Value, ExpressionError> {
438    Ok(Value::Float(std::f32::consts::PI))
439}
440
441fn execute_bit_and(args: &[Value]) -> Result<Value, ExpressionError> {
442    match (&args[0], &args[1]) {
443        (Value::SmallInt(a), Value::SmallInt(b)) => Ok(Value::SmallInt(a & b)),
444        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a & b)),
445        (Value::BigInt(a), Value::BigInt(b)) => Ok(Value::BigInt(a & b)),
446        (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
447        _ => Err(ExpressionError::type_error(
448            "The bit_and function takes integer arguments",
449        )),
450    }
451}
452
453fn execute_bit_or(args: &[Value]) -> Result<Value, ExpressionError> {
454    match (&args[0], &args[1]) {
455        (Value::SmallInt(a), Value::SmallInt(b)) => Ok(Value::SmallInt(a | b)),
456        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a | b)),
457        (Value::BigInt(a), Value::BigInt(b)) => Ok(Value::BigInt(a | b)),
458        (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
459        _ => Err(ExpressionError::type_error(
460            "The bit_or function takes integer arguments",
461        )),
462    }
463}
464
465define_binary_numeric_fn!(
466    execute_atan2,
467    |y: f32, x: f32| Ok(Value::Float(y.atan2(x))),
468    "atan2"
469);
470
471define_unary_float_fn!(execute_sinh, |v: f32| v.sinh(), "sinh");
472define_unary_float_fn!(execute_cosh, |v: f32| v.cosh(), "cosh");
473define_unary_float_fn!(execute_tanh, |v: f32| v.tanh(), "tanh");
474define_unary_float_fn!(execute_degrees, |v: f32| v.to_degrees(), "degrees");
475
476fn execute_bit_xor(args: &[Value]) -> Result<Value, ExpressionError> {
477    match (&args[0], &args[1]) {
478        (Value::SmallInt(a), Value::SmallInt(b)) => Ok(Value::SmallInt(a ^ b)),
479        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a ^ b)),
480        (Value::BigInt(a), Value::BigInt(b)) => Ok(Value::BigInt(a ^ b)),
481        (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
482        _ => Err(ExpressionError::type_error(
483            "The bit_xor function takes integer arguments",
484        )),
485    }
486}
487
488fn execute_gcd(args: &[Value]) -> Result<Value, ExpressionError> {
489    match (&args[0], &args[1]) {
490        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(gcd(*a, *b))),
491        (Value::BigInt(a), Value::BigInt(b)) => Ok(Value::BigInt(gcd(*a, *b))),
492        (Value::Int(a), Value::BigInt(b)) => Ok(Value::BigInt(gcd(*a as i64, *b))),
493        (Value::BigInt(a), Value::Int(b)) => Ok(Value::BigInt(gcd(*a, *b as i64))),
494        (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
495        _ => Err(ExpressionError::type_error(
496            "The gcd function requires integer arguments",
497        )),
498    }
499}
500
501fn execute_lcm(args: &[Value]) -> Result<Value, ExpressionError> {
502    match (&args[0], &args[1]) {
503        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(lcm(*a, *b))),
504        (Value::BigInt(a), Value::BigInt(b)) => Ok(Value::BigInt(lcm(*a, *b))),
505        (Value::Int(a), Value::BigInt(b)) => Ok(Value::BigInt(lcm(*a as i64, *b))),
506        (Value::BigInt(a), Value::Int(b)) => Ok(Value::BigInt(lcm(*a, *b as i64))),
507        (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
508        _ => Err(ExpressionError::type_error(
509            "The lcm function requires integer arguments",
510        )),
511    }
512}
513
514fn gcd<
515    T: Copy
516        + std::ops::Rem<Output = T>
517        + PartialEq
518        + From<i8>
519        + std::ops::Neg<Output = T>
520        + PartialOrd,
521>(
522    mut a: T,
523    mut b: T,
524) -> T {
525    let zero: T = T::from(0);
526    if a == zero {
527        return b;
528    }
529    if b == zero {
530        return a;
531    }
532    while b != zero {
533        let temp = b;
534        b = a % b;
535        a = temp;
536    }
537    if a < zero {
538        -a
539    } else {
540        a
541    }
542}
543
544fn lcm<
545    T: Copy
546        + std::ops::Rem<Output = T>
547        + PartialEq
548        + From<i8>
549        + std::ops::Neg<Output = T>
550        + PartialOrd
551        + std::ops::Div<Output = T>
552        + std::ops::Mul<Output = T>,
553>(
554    a: T,
555    b: T,
556) -> T {
557    let zero: T = T::from(0);
558    if a == zero || b == zero {
559        return zero;
560    }
561    let g = gcd(a, b);
562    let abs_a = if a < zero { -a } else { a };
563    let abs_b = if b < zero { -b } else { b };
564    (abs_a / g) * abs_b
565}
566
567fn execute_factorial(args: &[Value]) -> Result<Value, ExpressionError> {
568    match &args[0] {
569        Value::SmallInt(i) => {
570            if *i < 0 {
571                return Err(ExpressionError::type_error(
572                    "factorial requires a non-negative integer",
573                ));
574            }
575            let mut result: i64 = 1;
576            for j in 2..=*i as i64 {
577                result *= j;
578            }
579            Ok(Value::BigInt(result))
580        }
581        Value::Int(i) => {
582            if *i < 0 {
583                return Err(ExpressionError::type_error(
584                    "factorial requires a non-negative integer",
585                ));
586            }
587            let mut result: i64 = 1;
588            for j in 2..=*i as i64 {
589                result *= j;
590            }
591            Ok(Value::BigInt(result))
592        }
593        Value::BigInt(i) => {
594            if *i < 0 {
595                return Err(ExpressionError::type_error(
596                    "factorial requires a non-negative integer",
597                ));
598            }
599            let mut result: i64 = 1;
600            for j in 2..=*i {
601                result *= j;
602            }
603            Ok(Value::BigInt(result))
604        }
605        Value::Float(f) => {
606            if *f < 0.0 {
607                return Err(ExpressionError::type_error(
608                    "factorial requires a non-negative integer",
609                ));
610            }
611            Ok(Value::Float(gamma(*f + 1.0)))
612        }
613        Value::Double(f) => {
614            if *f < 0.0 {
615                return Err(ExpressionError::type_error(
616                    "factorial requires a non-negative integer",
617                ));
618            }
619            Ok(Value::Float(gamma(*f as f32 + 1.0)))
620        }
621        Value::Null(_) => Ok(Value::Null(NullType::Null)),
622        _ => Err(ExpressionError::type_error(
623            "factorial requires a numeric type",
624        )),
625    }
626}
627
628fn gamma(mut x: f32) -> f32 {
629    if x < 0.5 {
630        std::f32::consts::PI / ((std::f32::consts::PI * x).sin() * gamma(1.0 - x))
631    } else {
632        x -= 1.0;
633        let g: usize = 7;
634        let c = [
635            0.999_999_9,
636            676.520_3,
637            -1_259.139_2,
638            771.323_4,
639            -176.615_04,
640            12.507_343,
641            -0.138_571_1,
642            9.984_369e-6,
643            1.505_632_7e-7,
644        ];
645        let mut t = c[0];
646        for (i, val) in c.iter().enumerate().take(g + 2).skip(1) {
647            t += val / (x + i as f32);
648        }
649        let x = x + g as f32 + 0.5;
650        (2.0 * std::f32::consts::PI).sqrt() * x.powf(x - 0.5) * (-x).exp() * t
651    }
652}
653
654fn execute_gamma(args: &[Value]) -> Result<Value, ExpressionError> {
655    match &args[0] {
656        Value::SmallInt(i) => Ok(Value::Float(gamma(*i as f32))),
657        Value::Int(i) => Ok(Value::Float(gamma(*i as f32))),
658        Value::BigInt(i) => Ok(Value::Float(gamma(*i as f32))),
659        Value::Float(f) => Ok(Value::Float(gamma(*f))),
660        Value::Double(f) => Ok(Value::Float(gamma(*f as f32))),
661        Value::Null(_) => Ok(Value::Null(NullType::Null)),
662        _ => Err(ExpressionError::type_error("gamma requires a numeric type")),
663    }
664}
665
666fn execute_lgamma(args: &[Value]) -> Result<Value, ExpressionError> {
667    match &args[0] {
668        Value::SmallInt(i) => Ok(Value::Float(gamma(*i as f32).abs().ln())),
669        Value::Int(i) => Ok(Value::Float(gamma(*i as f32).abs().ln())),
670        Value::BigInt(i) => Ok(Value::Float(gamma(*i as f32).abs().ln())),
671        Value::Float(f) => Ok(Value::Float(gamma(*f).abs().ln())),
672        Value::Double(f) => Ok(Value::Float(gamma(*f as f32).abs().ln())),
673        Value::Null(_) => Ok(Value::Null(NullType::Null)),
674        _ => Err(ExpressionError::type_error(
675            "lgamma requires a numeric type",
676        )),
677    }
678}
679
680fn execute_negate(args: &[Value]) -> Result<Value, ExpressionError> {
681    match &args[0] {
682        Value::SmallInt(i) => Ok(Value::SmallInt(-i)),
683        Value::Int(i) => Ok(Value::Int(-i)),
684        Value::BigInt(i) => Ok(Value::BigInt(-i)),
685        Value::Float(f) => Ok(Value::Float(-f)),
686        Value::Double(f) => Ok(Value::Double(-f)),
687        Value::Null(_) => Ok(Value::Null(NullType::Null)),
688        _ => Err(ExpressionError::type_error(
689            "negate requires a numeric type",
690        )),
691    }
692}
693
694fn execute_even(args: &[Value]) -> Result<Value, ExpressionError> {
695    match &args[0] {
696        Value::SmallInt(i) => Ok(Value::SmallInt(if *i % 2 == 0 { *i } else { *i + 1 })),
697        Value::Int(i) => Ok(Value::Int(if *i % 2 == 0 { *i } else { *i + 1 })),
698        Value::BigInt(i) => Ok(Value::BigInt(if *i % 2 == 0 { *i } else { *i + 1 })),
699        Value::Float(f) => {
700            let rounded = f.round();
701            if rounded % 2.0 == 0.0 {
702                Ok(Value::Float(rounded))
703            } else {
704                Ok(Value::Float(rounded + 1.0))
705            }
706        }
707        Value::Double(f) => {
708            let rounded = f.round();
709            if rounded % 2.0 == 0.0 {
710                Ok(Value::Double(rounded))
711            } else {
712                Ok(Value::Double(rounded + 1.0))
713            }
714        }
715        Value::Null(_) => Ok(Value::Null(NullType::Null)),
716        _ => Err(ExpressionError::type_error("even requires a numeric type")),
717    }
718}
719
720fn execute_set_seed(args: &[Value]) -> Result<Value, ExpressionError> {
721    match &args[0] {
722        Value::SmallInt(_) => Ok(Value::Null(NullType::Null)),
723        Value::Int(_) => Ok(Value::Null(NullType::Null)),
724        Value::BigInt(_) => Ok(Value::Null(NullType::Null)),
725        Value::Float(_) => Ok(Value::Null(NullType::Null)),
726        Value::Double(_) => Ok(Value::Null(NullType::Null)),
727        Value::Null(_) => Ok(Value::Null(NullType::Null)),
728        _ => Err(ExpressionError::type_error(
729            "set_seed requires a numeric type",
730        )),
731    }
732}
733
734fn execute_bit_shift_left(args: &[Value]) -> Result<Value, ExpressionError> {
735    match (&args[0], &args[1]) {
736        (Value::SmallInt(a), Value::SmallInt(b)) => Ok(Value::SmallInt(a << *b)),
737        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a << *b)),
738        (Value::BigInt(a), Value::BigInt(b)) => Ok(Value::BigInt(a << *b)),
739        (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
740        _ => Err(ExpressionError::type_error(
741            "bit_shift_left requires integer arguments",
742        )),
743    }
744}
745
746fn execute_bit_shift_right(args: &[Value]) -> Result<Value, ExpressionError> {
747    match (&args[0], &args[1]) {
748        (Value::SmallInt(a), Value::SmallInt(b)) => Ok(Value::SmallInt(a >> *b)),
749        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a >> *b)),
750        (Value::BigInt(a), Value::BigInt(b)) => Ok(Value::BigInt(a >> *b)),
751        (Value::Null(_), _) | (_, Value::Null(_)) => Ok(Value::Null(NullType::Null)),
752        _ => Err(ExpressionError::type_error(
753            "bit_shift_right requires integer arguments",
754        )),
755    }
756}
757
758#[cfg(test)]
759mod tests;