mz_expr/scalar/func/impls/
uint64.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
10use std::fmt;
11
12use mz_lowertest::MzReflect;
13use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale};
14use mz_repr::{ColumnType, ScalarType, strconv};
15use serde::{Deserialize, Serialize};
16
17use crate::EvalError;
18use crate::scalar::func::EagerUnaryFunc;
19
20sqlfunc!(
21    #[sqlname = "~"]
22    #[preserves_uniqueness = true]
23    #[inverse = to_unary!(super::BitNotUint64)]
24    fn bit_not_uint64(a: u64) -> u64 {
25        !a
26    }
27);
28
29sqlfunc!(
30    #[sqlname = "uint8_to_real"]
31    #[preserves_uniqueness = false]
32    #[inverse = to_unary!(super::CastFloat32ToUint64)]
33    #[is_monotone = true]
34    fn cast_uint64_to_float32(a: u64) -> f32 {
35        // TODO(benesch): remove potentially dangerous usage of `as`.
36        #[allow(clippy::as_conversions)]
37        {
38            a as f32
39        }
40    }
41);
42
43sqlfunc!(
44    #[sqlname = "uint8_to_double"]
45    #[preserves_uniqueness = false]
46    #[inverse = to_unary!(super::CastFloat64ToUint64)]
47    #[is_monotone = true]
48    fn cast_uint64_to_float64(a: u64) -> f64 {
49        // TODO(benesch): remove potentially dangerous usage of `as`.
50        #[allow(clippy::as_conversions)]
51        {
52            a as f64
53        }
54    }
55);
56
57sqlfunc!(
58    #[sqlname = "uint8_to_uint2"]
59    #[preserves_uniqueness = true]
60    #[inverse = to_unary!(super::CastUint16ToUint64)]
61    #[is_monotone = true]
62    fn cast_uint64_to_uint16(a: u64) -> Result<u16, EvalError> {
63        u16::try_from(a).or_else(|_| Err(EvalError::UInt16OutOfRange(a.to_string().into())))
64    }
65);
66
67sqlfunc!(
68    #[sqlname = "uint8_to_uint4"]
69    #[preserves_uniqueness = true]
70    #[inverse = to_unary!(super::CastUint32ToUint64)]
71    #[is_monotone = true]
72    fn cast_uint64_to_uint32(a: u64) -> Result<u32, EvalError> {
73        u32::try_from(a).or_else(|_| Err(EvalError::UInt32OutOfRange(a.to_string().into())))
74    }
75);
76
77sqlfunc!(
78    #[sqlname = "uint8_to_smallint"]
79    #[preserves_uniqueness = true]
80    #[inverse = to_unary!(super::CastInt16ToUint64)]
81    #[is_monotone = true]
82    fn cast_uint64_to_int16(a: u64) -> Result<i16, EvalError> {
83        i16::try_from(a).or_else(|_| Err(EvalError::Int16OutOfRange(a.to_string().into())))
84    }
85);
86
87sqlfunc!(
88    #[sqlname = "uint8_to_integer"]
89    #[preserves_uniqueness = true]
90    #[inverse = to_unary!(super::CastInt32ToUint64)]
91    #[is_monotone = true]
92    fn cast_uint64_to_int32(a: u64) -> Result<i32, EvalError> {
93        i32::try_from(a).or_else(|_| Err(EvalError::Int32OutOfRange(a.to_string().into())))
94    }
95);
96
97sqlfunc!(
98    #[sqlname = "uint8_to_bigint"]
99    #[preserves_uniqueness = true]
100    #[inverse = to_unary!(super::CastInt64ToUint64)]
101    #[is_monotone = true]
102    fn cast_uint64_to_int64(a: u64) -> Result<i64, EvalError> {
103        i64::try_from(a).or_else(|_| Err(EvalError::Int64OutOfRange(a.to_string().into())))
104    }
105);
106
107sqlfunc!(
108    #[sqlname = "uint8_to_text"]
109    #[preserves_uniqueness = true]
110    #[inverse = to_unary!(super::CastStringToUint64)]
111    fn cast_uint64_to_string(a: u64) -> String {
112        let mut buf = String::new();
113        strconv::format_uint64(&mut buf, a);
114        buf
115    }
116);
117
118#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)]
119pub struct CastUint64ToNumeric(pub Option<NumericMaxScale>);
120
121impl<'a> EagerUnaryFunc<'a> for CastUint64ToNumeric {
122    type Input = u64;
123    type Output = Result<Numeric, EvalError>;
124
125    fn call(&self, a: u64) -> Result<Numeric, EvalError> {
126        let mut a = Numeric::from(a);
127        if let Some(scale) = self.0 {
128            if numeric::rescale(&mut a, scale.into_u8()).is_err() {
129                return Err(EvalError::NumericFieldOverflow);
130            }
131        }
132        // Besides `rescale`, cast is infallible.
133        Ok(a)
134    }
135
136    fn output_type(&self, input: ColumnType) -> ColumnType {
137        ScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable)
138    }
139
140    fn could_error(&self) -> bool {
141        self.0.is_some()
142    }
143
144    fn inverse(&self) -> Option<crate::UnaryFunc> {
145        to_unary!(super::CastNumericToUint64)
146    }
147
148    fn is_monotone(&self) -> bool {
149        true
150    }
151}
152
153impl fmt::Display for CastUint64ToNumeric {
154    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155        f.write_str("uint8_to_numeric")
156    }
157}