mz_expr/scalar/func/impls/
float32.rs
1use std::fmt;
11
12use mz_lowertest::MzReflect;
13use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale};
14use mz_repr::{ColumnType, ScalarType, strconv};
15use serde::{Deserialize, Serialize};
16
17use crate::EvalError;
18use crate::scalar::func::EagerUnaryFunc;
19
20sqlfunc!(
21 #[sqlname = "-"]
22 #[preserves_uniqueness = false]
23 #[inverse = to_unary!(NegFloat32)]
24 #[is_monotone = true]
25 fn neg_float32(a: f32) -> f32 {
26 -a
27 }
28);
29
30sqlfunc!(
31 #[sqlname = "abs"]
32 fn abs_float32(a: f32) -> f32 {
33 a.abs()
34 }
35);
36
37sqlfunc!(
38 #[sqlname = "roundf32"]
39 fn round_float32(a: f32) -> f32 {
40 a.round_ties_even()
41 }
42);
43
44sqlfunc!(
45 #[sqlname = "truncf32"]
46 fn trunc_float32(a: f32) -> f32 {
47 a.trunc()
48 }
49);
50
51sqlfunc!(
52 #[sqlname = "ceilf32"]
53 fn ceil_float32(a: f32) -> f32 {
54 a.ceil()
55 }
56);
57
58sqlfunc!(
59 #[sqlname = "floorf32"]
60 fn floor_float32(a: f32) -> f32 {
61 a.floor()
62 }
63);
64
65sqlfunc!(
66 #[sqlname = "real_to_smallint"]
67 #[preserves_uniqueness = false]
68 #[inverse = to_unary!(super::CastInt16ToFloat32)]
69 #[is_monotone = true]
70 fn cast_float32_to_int16(a: f32) -> Result<i16, EvalError> {
71 let f = round_float32(a);
72 #[allow(clippy::as_conversions)]
74 if (f >= (i16::MIN as f32)) && (f < -(i16::MIN as f32)) {
75 Ok(f as i16)
76 } else {
77 Err(EvalError::Int16OutOfRange(f.to_string().into()))
78 }
79 }
80);
81
82sqlfunc!(
83 #[sqlname = "real_to_integer"]
84 #[preserves_uniqueness = false]
85 #[inverse = to_unary!(super::CastInt32ToFloat32)]
86 #[is_monotone = true]
87 fn cast_float32_to_int32(a: f32) -> Result<i32, EvalError> {
88 let f = round_float32(a);
89 #[allow(clippy::as_conversions)]
95 if (f >= (i32::MIN as f32)) && (f < -(i32::MIN as f32)) {
96 Ok(f as i32)
97 } else {
98 Err(EvalError::Int32OutOfRange(f.to_string().into()))
99 }
100 }
101);
102
103sqlfunc!(
104 #[sqlname = "real_to_bigint"]
105 #[preserves_uniqueness = false]
106 #[inverse = to_unary!(super::CastInt64ToFloat32)]
107 #[is_monotone = true]
108 fn cast_float32_to_int64(a: f32) -> Result<i64, EvalError> {
109 let f = round_float32(a);
110 #[allow(clippy::as_conversions)]
116 if (f >= (i64::MIN as f32)) && (f < -(i64::MIN as f32)) {
117 Ok(f as i64)
118 } else {
119 Err(EvalError::Int64OutOfRange(f.to_string().into()))
120 }
121 }
122);
123
124sqlfunc!(
125 #[sqlname = "real_to_double"]
126 #[preserves_uniqueness = false]
127 #[inverse = to_unary!(super::CastFloat64ToFloat32)]
128 #[is_monotone = true]
129 fn cast_float32_to_float64(a: f32) -> f64 {
130 a.into()
131 }
132);
133
134sqlfunc!(
135 #[sqlname = "real_to_text"]
136 #[preserves_uniqueness = false]
137 #[inverse = to_unary!(super::CastStringToFloat32)]
138 fn cast_float32_to_string(a: f32) -> String {
139 let mut s = String::new();
140 strconv::format_float32(&mut s, a);
141 s
142 }
143);
144
145sqlfunc!(
146 #[sqlname = "real_to_uint2"]
147 #[preserves_uniqueness = false]
148 #[inverse = to_unary!(super::CastUint16ToFloat32)]
149 #[is_monotone = true]
150 fn cast_float32_to_uint16(a: f32) -> Result<u16, EvalError> {
151 let f = round_float32(a);
152 #[allow(clippy::as_conversions)]
154 if (f >= 0.0) && (f <= (u16::MAX as f32)) {
155 Ok(f as u16)
156 } else {
157 Err(EvalError::UInt16OutOfRange(f.to_string().into()))
158 }
159 }
160);
161
162sqlfunc!(
163 #[sqlname = "real_to_uint4"]
164 #[preserves_uniqueness = false]
165 #[inverse = to_unary!(super::CastUint32ToFloat32)]
166 #[is_monotone = true]
167 fn cast_float32_to_uint32(a: f32) -> Result<u32, EvalError> {
168 let f = round_float32(a);
169 #[allow(clippy::as_conversions)]
171 if (f >= 0.0) && (f <= (u32::MAX as f32)) {
172 Ok(f as u32)
173 } else {
174 Err(EvalError::UInt32OutOfRange(f.to_string().into()))
175 }
176 }
177);
178
179sqlfunc!(
180 #[sqlname = "real_to_uint8"]
181 #[preserves_uniqueness = false]
182 #[inverse = to_unary!(super::CastUint64ToFloat32)]
183 #[is_monotone = true]
184 fn cast_float32_to_uint64(a: f32) -> Result<u64, EvalError> {
185 let f = round_float32(a);
186 #[allow(clippy::as_conversions)]
188 if (f >= 0.0) && (f <= (u64::MAX as f32)) {
189 Ok(f as u64)
190 } else {
191 Err(EvalError::UInt64OutOfRange(f.to_string().into()))
192 }
193 }
194);
195
196#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)]
197pub struct CastFloat32ToNumeric(pub Option<NumericMaxScale>);
198
199impl<'a> EagerUnaryFunc<'a> for CastFloat32ToNumeric {
200 type Input = f32;
201 type Output = Result<Numeric, EvalError>;
202
203 fn call(&self, a: f32) -> Result<Numeric, EvalError> {
204 if a.is_infinite() {
205 return Err(EvalError::InfinityOutOfDomain(
206 "casting real to numeric".into(),
207 ));
208 }
209 let mut a = Numeric::from(a);
210 if let Some(scale) = self.0 {
211 if numeric::rescale(&mut a, scale.into_u8()).is_err() {
212 return Err(EvalError::NumericFieldOverflow);
213 }
214 }
215 numeric::munge_numeric(&mut a).unwrap();
216 Ok(a)
217 }
218
219 fn output_type(&self, input: ColumnType) -> ColumnType {
220 ScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable)
221 }
222
223 fn inverse(&self) -> Option<crate::UnaryFunc> {
224 to_unary!(super::CastNumericToFloat32)
225 }
226
227 fn is_monotone(&self) -> bool {
228 true
229 }
230}
231
232impl fmt::Display for CastFloat32ToNumeric {
233 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234 f.write_str("real_to_numeric")
235 }
236}