Skip to main content

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