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 mz_expr_derive::sqlfunc;
11use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale};
12use mz_repr::{SqlScalarType, strconv};
13use serde::{Deserialize, Serialize};
14
15use crate::EvalError;
16
17#[sqlfunc(
18    sqlname = "~",
19    preserves_uniqueness = true,
20    inverse = super::BitNotUint32
21)]
22fn bit_not_uint32(a: u32) -> u32 {
23    !a
24}
25
26#[sqlfunc(
27    sqlname = "uint4_to_real",
28    preserves_uniqueness = false,
29    inverse = super::CastFloat32ToUint32,
30    is_monotone = true
31)]
32fn cast_uint32_to_float32(a: u32) -> f32 {
33    // TODO(benesch): remove potentially dangerous usage of `as`.
34    #[allow(clippy::as_conversions)]
35    {
36        a as f32
37    }
38}
39
40#[sqlfunc(
41    sqlname = "uint4_to_double",
42    preserves_uniqueness = true,
43    inverse = super::CastFloat64ToUint32,
44    is_monotone = true
45)]
46fn cast_uint32_to_float64(a: u32) -> f64 {
47    f64::from(a)
48}
49
50#[sqlfunc(
51    sqlname = "uint4_to_uint2",
52    // Partial: errors for `u32` values above `u16::MAX`. Marking this as
53    // uniqueness-preserving would let cast inversion rewrite `col::uint2 = lit`
54    // into an index lookup on `col`, skipping the cast and dropping its
55    // out-of-range error.
56    preserves_uniqueness = false,
57    inverse = super::CastUint16ToUint32,
58    is_monotone = true
59)]
60fn cast_uint32_to_uint16(a: u32) -> Result<u16, EvalError> {
61    u16::try_from(a).or_else(|_| Err(EvalError::UInt16OutOfRange(a.to_string().into())))
62}
63
64#[sqlfunc(
65    sqlname = "uint4_to_uint8",
66    preserves_uniqueness = true,
67    inverse = super::CastUint64ToUint32,
68    is_monotone = true
69)]
70fn cast_uint32_to_uint64(a: u32) -> u64 {
71    u64::from(a)
72}
73
74#[sqlfunc(
75    sqlname = "uint4_to_smallint",
76    // Partial: errors for `u32` values above `i16::MAX`. See `uint4_to_uint2`.
77    preserves_uniqueness = false,
78    inverse = super::CastInt16ToUint32,
79    is_monotone = true
80)]
81fn cast_uint32_to_int16(a: u32) -> Result<i16, EvalError> {
82    i16::try_from(a).or_else(|_| Err(EvalError::Int16OutOfRange(a.to_string().into())))
83}
84
85#[sqlfunc(
86    sqlname = "uint4_to_integer",
87    // Partial: errors for `u32` values above `i32::MAX`. See `uint4_to_uint2`.
88    preserves_uniqueness = false,
89    inverse = super::CastInt32ToUint32,
90    is_monotone = true
91)]
92fn cast_uint32_to_int32(a: u32) -> Result<i32, EvalError> {
93    i32::try_from(a).or_else(|_| Err(EvalError::Int32OutOfRange(a.to_string().into())))
94}
95
96#[sqlfunc(
97    sqlname = "uint4_to_bigint",
98    preserves_uniqueness = true,
99    inverse = super::CastInt64ToUint32,
100    is_monotone = true
101)]
102fn cast_uint32_to_int64(a: u32) -> i64 {
103    i64::from(a)
104}
105
106#[sqlfunc(
107    sqlname = "uint4_to_text",
108    preserves_uniqueness = true,
109    inverse = super::CastStringToUint32
110)]
111fn cast_uint32_to_string(a: u32) -> String {
112    let mut buf = String::new();
113    strconv::format_uint32(&mut buf, a);
114    buf
115}
116
117#[derive(
118    Ord,
119    PartialOrd,
120    Clone,
121    Debug,
122    Eq,
123    PartialEq,
124    Serialize,
125    Deserialize,
126    Hash
127)]
128pub struct CastUint32ToNumeric(pub Option<NumericMaxScale>);
129
130#[sqlfunc(
131    CastUint32ToNumeric,
132    sqlname = "uint4_to_numeric",
133    could_error = self.0.is_some(),
134    inverse = super::CastNumericToUint32,
135    is_monotone = true,
136    output_type_expr = SqlScalarType::Numeric { max_scale: self.0 }
137        .nullable(input_type.nullable)
138)]
139fn cast_uint32_to_numeric(&self, a: u32) -> Result<Numeric, EvalError> {
140    let mut a = Numeric::from(a);
141    if let Some(scale) = self.0 {
142        if numeric::rescale(&mut a, scale.into_u8()).is_err() {
143            return Err(EvalError::NumericFieldOverflow);
144        }
145    }
146    // Besides `rescale`, cast is infallible.
147    Ok(a)
148}