Skip to main content

mz_expr/scalar/func/impls/
uint32.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::BitNotUint32)
24)]
25fn bit_not_uint32(a: u32) -> u32 {
26    !a
27}
28
29#[sqlfunc(
30    sqlname = "uint4_to_real",
31    preserves_uniqueness = false,
32    inverse = to_unary!(super::CastFloat32ToUint32),
33    is_monotone = true
34)]
35fn cast_uint32_to_float32(a: u32) -> 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 = "uint4_to_double",
45    preserves_uniqueness = true,
46    inverse = to_unary!(super::CastFloat64ToUint32),
47    is_monotone = true
48)]
49fn cast_uint32_to_float64(a: u32) -> f64 {
50    f64::from(a)
51}
52
53#[sqlfunc(
54    sqlname = "uint4_to_uint2",
55    // Partial: errors for `u32` values above `u16::MAX`. Marking this as
56    // uniqueness-preserving would let cast inversion rewrite `col::uint2 = lit`
57    // into an index lookup on `col`, skipping the cast and dropping its
58    // out-of-range error.
59    preserves_uniqueness = false,
60    inverse = to_unary!(super::CastUint16ToUint32),
61    is_monotone = true
62)]
63fn cast_uint32_to_uint16(a: u32) -> Result<u16, EvalError> {
64    u16::try_from(a).or_else(|_| Err(EvalError::UInt16OutOfRange(a.to_string().into())))
65}
66
67#[sqlfunc(
68    sqlname = "uint4_to_uint8",
69    preserves_uniqueness = true,
70    inverse = to_unary!(super::CastUint64ToUint32),
71    is_monotone = true
72)]
73fn cast_uint32_to_uint64(a: u32) -> u64 {
74    u64::from(a)
75}
76
77#[sqlfunc(
78    sqlname = "uint4_to_smallint",
79    // Partial: errors for `u32` values above `i16::MAX`. See `uint4_to_uint2`.
80    preserves_uniqueness = false,
81    inverse = to_unary!(super::CastInt16ToUint32),
82    is_monotone = true
83)]
84fn cast_uint32_to_int16(a: u32) -> Result<i16, EvalError> {
85    i16::try_from(a).or_else(|_| Err(EvalError::Int16OutOfRange(a.to_string().into())))
86}
87
88#[sqlfunc(
89    sqlname = "uint4_to_integer",
90    // Partial: errors for `u32` values above `i32::MAX`. See `uint4_to_uint2`.
91    preserves_uniqueness = false,
92    inverse = to_unary!(super::CastInt32ToUint32),
93    is_monotone = true
94)]
95fn cast_uint32_to_int32(a: u32) -> Result<i32, EvalError> {
96    i32::try_from(a).or_else(|_| Err(EvalError::Int32OutOfRange(a.to_string().into())))
97}
98
99#[sqlfunc(
100    sqlname = "uint4_to_bigint",
101    preserves_uniqueness = true,
102    inverse = to_unary!(super::CastInt64ToUint32),
103    is_monotone = true
104)]
105fn cast_uint32_to_int64(a: u32) -> i64 {
106    i64::from(a)
107}
108
109#[sqlfunc(
110    sqlname = "uint4_to_text",
111    preserves_uniqueness = true,
112    inverse = to_unary!(super::CastStringToUint32)
113)]
114fn cast_uint32_to_string(a: u32) -> String {
115    let mut buf = String::new();
116    strconv::format_uint32(&mut buf, a);
117    buf
118}
119
120#[derive(
121    Ord,
122    PartialOrd,
123    Clone,
124    Debug,
125    Eq,
126    PartialEq,
127    Serialize,
128    Deserialize,
129    Hash
130)]
131pub struct CastUint32ToNumeric(pub Option<NumericMaxScale>);
132
133impl EagerUnaryFunc for CastUint32ToNumeric {
134    type Input<'a> = u32;
135    type Output<'a> = Result<Numeric, EvalError>;
136
137    fn call<'a>(&self, a: Self::Input<'a>) -> Self::Output<'a> {
138        let mut a = Numeric::from(a);
139        if let Some(scale) = self.0 {
140            if numeric::rescale(&mut a, scale.into_u8()).is_err() {
141                return Err(EvalError::NumericFieldOverflow);
142            }
143        }
144        // Besides `rescale`, cast is infallible.
145        Ok(a)
146    }
147
148    fn output_sql_type(&self, input: SqlColumnType) -> SqlColumnType {
149        SqlScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable)
150    }
151
152    fn could_error(&self) -> bool {
153        self.0.is_some()
154    }
155
156    fn inverse(&self) -> Option<crate::UnaryFunc> {
157        to_unary!(super::CastNumericToUint32)
158    }
159
160    fn is_monotone(&self) -> bool {
161        true
162    }
163}
164
165impl fmt::Display for CastUint32ToNumeric {
166    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167        f.write_str("uint4_to_numeric")
168    }
169}