mz_expr/scalar/func/impls/
int32.rs1use std::fmt;
11
12use mz_expr_derive::sqlfunc;
13use mz_lowertest::MzReflect;
14use mz_ore::cast::ReinterpretCast;
15use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale};
16use mz_repr::adt::system::{Oid, PgLegacyChar};
17use mz_repr::{SqlColumnType, SqlScalarType, strconv};
18use serde::{Deserialize, Serialize};
19
20use crate::EvalError;
21use crate::scalar::func::EagerUnaryFunc;
22
23#[sqlfunc(
24 sqlname = "-",
25 preserves_uniqueness = true,
26 inverse = to_unary!(NegInt32),
27 is_monotone = true
28)]
29fn neg_int32(a: i32) -> Result<i32, EvalError> {
30 a.checked_neg()
31 .ok_or_else(|| EvalError::Int32OutOfRange(a.to_string().into()))
32}
33
34#[sqlfunc(
35 sqlname = "~",
36 preserves_uniqueness = true,
37 inverse = to_unary!(BitNotInt32)
38)]
39fn bit_not_int32(a: i32) -> i32 {
40 !a
41}
42
43#[sqlfunc(sqlname = "abs")]
44fn abs_int32(a: i32) -> Result<i32, EvalError> {
45 a.checked_abs()
46 .ok_or_else(|| EvalError::Int32OutOfRange(a.to_string().into()))
47}
48
49#[sqlfunc(
50 sqlname = "integer_to_boolean",
51 preserves_uniqueness = false,
52 inverse = to_unary!(super::CastBoolToInt32)
53)]
54fn cast_int32_to_bool(a: i32) -> bool {
55 a != 0
56}
57
58#[sqlfunc(
59 sqlname = "integer_to_real",
60 preserves_uniqueness = false,
61 inverse = to_unary!(super::CastFloat32ToInt32),
62 is_monotone = true
63)]
64fn cast_int32_to_float32(a: i32) -> f32 {
65 #[allow(clippy::as_conversions)]
67 {
68 a as f32
69 }
70}
71
72#[sqlfunc(
73 sqlname = "integer_to_double",
74 preserves_uniqueness = true,
75 inverse = to_unary!(super::CastFloat64ToInt32),
76 is_monotone = true
77)]
78fn cast_int32_to_float64(a: i32) -> f64 {
79 f64::from(a)
80}
81
82#[sqlfunc(
83 sqlname = "integer_to_smallint",
84 preserves_uniqueness = true,
85 inverse = to_unary!(super::CastInt16ToInt32),
86 is_monotone = true
87)]
88fn cast_int32_to_int16(a: i32) -> Result<i16, EvalError> {
89 i16::try_from(a).or_else(|_| Err(EvalError::Int16OutOfRange(a.to_string().into())))
90}
91
92#[sqlfunc(
93 sqlname = "integer_to_bigint",
94 preserves_uniqueness = true,
95 inverse = to_unary!(super::CastInt64ToInt32),
96 is_monotone = true
97)]
98fn cast_int32_to_int64(a: i32) -> i64 {
99 i64::from(a)
100}
101
102#[sqlfunc(
103 sqlname = "integer_to_text",
104 preserves_uniqueness = true,
105 inverse = to_unary!(super::CastStringToInt32)
106)]
107fn cast_int32_to_string(a: i32) -> String {
108 let mut buf = String::new();
109 strconv::format_int32(&mut buf, a);
110 buf
111}
112
113#[sqlfunc(
114 sqlname = "integer_to_uint2",
115 preserves_uniqueness = true,
116 inverse = to_unary!(super::CastUint16ToInt32),
117 is_monotone = true
118)]
119fn cast_int32_to_uint16(a: i32) -> Result<u16, EvalError> {
120 u16::try_from(a).or_else(|_| Err(EvalError::UInt16OutOfRange(a.to_string().into())))
121}
122
123#[sqlfunc(
124 sqlname = "integer_to_uint4",
125 preserves_uniqueness = true,
126 inverse = to_unary!(super::CastUint32ToInt32),
127 is_monotone = true
128)]
129fn cast_int32_to_uint32(a: i32) -> Result<u32, EvalError> {
130 u32::try_from(a).or_else(|_| Err(EvalError::UInt32OutOfRange(a.to_string().into())))
131}
132
133#[sqlfunc(
134 sqlname = "integer_to_uint8",
135 preserves_uniqueness = true,
136 inverse = to_unary!(super::CastUint64ToInt32),
137 is_monotone = true
138)]
139fn cast_int32_to_uint64(a: i32) -> Result<u64, EvalError> {
140 u64::try_from(a).or_else(|_| Err(EvalError::UInt64OutOfRange(a.to_string().into())))
141}
142
143#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)]
144pub struct CastInt32ToNumeric(pub Option<NumericMaxScale>);
145
146impl<'a> EagerUnaryFunc<'a> for CastInt32ToNumeric {
147 type Input = i32;
148 type Output = Result<Numeric, EvalError>;
149
150 fn call(&self, a: i32) -> Result<Numeric, EvalError> {
151 let mut a = Numeric::from(a);
152 if let Some(scale) = self.0 {
153 if numeric::rescale(&mut a, scale.into_u8()).is_err() {
154 return Err(EvalError::NumericFieldOverflow);
155 }
156 }
157 Ok(a)
159 }
160
161 fn output_type(&self, input: SqlColumnType) -> SqlColumnType {
162 SqlScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable)
163 }
164
165 fn could_error(&self) -> bool {
166 self.0.is_some()
167 }
168
169 fn inverse(&self) -> Option<crate::UnaryFunc> {
170 to_unary!(super::CastNumericToInt32)
171 }
172
173 fn is_monotone(&self) -> bool {
174 true
175 }
176}
177
178impl fmt::Display for CastInt32ToNumeric {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 f.write_str("integer_to_numeric")
181 }
182}
183
184#[sqlfunc(
185 sqlname = "integer_to_oid",
186 preserves_uniqueness = true,
187 inverse = to_unary!(super::CastOidToInt32)
188)]
189fn cast_int32_to_oid(a: i32) -> Oid {
190 Oid(u32::reinterpret_cast(a))
198}
199
200#[sqlfunc(
201 sqlname = "integer_to_\"char\"",
202 preserves_uniqueness = true,
203 inverse = to_unary!(super::CastPgLegacyCharToInt32)
204)]
205fn cast_int32_to_pg_legacy_char(a: i32) -> Result<PgLegacyChar, EvalError> {
206 let a = i8::try_from(a).map_err(|_| EvalError::CharOutOfRange)?;
210 Ok(PgLegacyChar(u8::reinterpret_cast(a)))
211}
212
213#[sqlfunc]
214fn chr(a: i32) -> Result<String, EvalError> {
215 let codepoint = u32::try_from(a).map_err(|_| EvalError::CharacterTooLargeForEncoding(a))?;
218 if codepoint == 0 {
219 Err(EvalError::NullCharacterNotPermitted)
220 } else if 0xd800 <= codepoint && codepoint < 0xe000 {
221 Err(EvalError::CharacterNotValidForEncoding(a))
223 } else {
224 char::from_u32(codepoint)
225 .map(|u| u.to_string())
226 .ok_or(EvalError::CharacterTooLargeForEncoding(a))
227 }
228}