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