mz_expr/scalar/func/impls/
float32.rs1use 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 = false,
20 inverse = NegFloat32,
21 is_monotone = true
22)]
23fn neg_float32(a: f32) -> f32 {
24 -a
25}
26
27#[sqlfunc(sqlname = "abs")]
28fn abs_float32(a: f32) -> f32 {
29 a.abs()
30}
31
32#[sqlfunc(sqlname = "roundf32")]
33fn round_float32(a: f32) -> f32 {
34 a.round_ties_even()
35}
36
37#[sqlfunc(sqlname = "truncf32")]
38fn trunc_float32(a: f32) -> f32 {
39 a.trunc()
40}
41
42#[sqlfunc(sqlname = "ceilf32")]
43fn ceil_float32(a: f32) -> f32 {
44 a.ceil()
45}
46
47#[sqlfunc(sqlname = "floorf32")]
48fn floor_float32(a: f32) -> f32 {
49 a.floor()
50}
51
52#[sqlfunc(
53 sqlname = "real_to_smallint",
54 preserves_uniqueness = false,
55 inverse = super::CastInt16ToFloat32,
56 is_monotone = true
57)]
58fn cast_float32_to_int16(a: f32) -> Result<i16, EvalError> {
59 let f = round_float32(a);
60 #[allow(clippy::as_conversions)]
62 if (f >= (i16::MIN as f32)) && (f < -(i16::MIN as f32)) {
63 Ok(f as i16)
64 } else {
65 Err(EvalError::Int16OutOfRange(f.to_string().into()))
66 }
67}
68
69#[sqlfunc(
70 sqlname = "real_to_integer",
71 preserves_uniqueness = false,
72 inverse = super::CastInt32ToFloat32,
73 is_monotone = true
74)]
75fn cast_float32_to_int32(a: f32) -> Result<i32, EvalError> {
76 let f = round_float32(a);
77 #[allow(clippy::as_conversions)]
83 if (f >= (i32::MIN as f32)) && (f < -(i32::MIN as f32)) {
84 Ok(f as i32)
85 } else {
86 Err(EvalError::Int32OutOfRange(f.to_string().into()))
87 }
88}
89
90#[sqlfunc(
91 sqlname = "real_to_bigint",
92 preserves_uniqueness = false,
93 inverse = super::CastInt64ToFloat32,
94 is_monotone = true
95)]
96fn cast_float32_to_int64(a: f32) -> Result<i64, EvalError> {
97 let f = round_float32(a);
98 #[allow(clippy::as_conversions)]
104 if (f >= (i64::MIN as f32)) && (f < -(i64::MIN as f32)) {
105 Ok(f as i64)
106 } else {
107 Err(EvalError::Int64OutOfRange(f.to_string().into()))
108 }
109}
110
111#[sqlfunc(
112 sqlname = "real_to_double",
113 preserves_uniqueness = false,
114 inverse = super::CastFloat64ToFloat32,
115 is_monotone = true
116)]
117fn cast_float32_to_float64(a: f32) -> f64 {
118 a.into()
119}
120
121#[sqlfunc(
122 sqlname = "real_to_text",
123 preserves_uniqueness = false,
124 inverse = super::CastStringToFloat32
125)]
126fn cast_float32_to_string(a: f32) -> String {
127 let mut s = String::new();
128 strconv::format_float32(&mut s, a);
129 s
130}
131
132#[sqlfunc(
133 sqlname = "real_to_uint2",
134 preserves_uniqueness = false,
135 inverse = super::CastUint16ToFloat32,
136 is_monotone = true
137)]
138fn cast_float32_to_uint16(a: f32) -> Result<u16, EvalError> {
139 let f = round_float32(a);
140 #[allow(clippy::as_conversions)]
142 if (f >= 0.0) && (f <= (u16::MAX as f32)) {
143 Ok(f as u16)
144 } else {
145 Err(EvalError::UInt16OutOfRange(f.to_string().into()))
146 }
147}
148
149#[sqlfunc(
150 sqlname = "real_to_uint4",
151 preserves_uniqueness = false,
152 inverse = super::CastUint32ToFloat32,
153 is_monotone = true
154)]
155fn cast_float32_to_uint32(a: f32) -> Result<u32, EvalError> {
156 let f = round_float32(a);
157 #[allow(clippy::as_conversions)]
162 if (f >= 0.0) && (f < (u32::MAX as f32)) {
163 Ok(f as u32)
164 } else {
165 Err(EvalError::UInt32OutOfRange(f.to_string().into()))
166 }
167}
168
169#[sqlfunc(
170 sqlname = "real_to_uint8",
171 preserves_uniqueness = false,
172 inverse = super::CastUint64ToFloat32,
173 is_monotone = true
174)]
175fn cast_float32_to_uint64(a: f32) -> Result<u64, EvalError> {
176 let f = round_float32(a);
177 #[allow(clippy::as_conversions)]
182 if (f >= 0.0) && (f < (u64::MAX as f32)) {
183 Ok(f as u64)
184 } else {
185 Err(EvalError::UInt64OutOfRange(f.to_string().into()))
186 }
187}
188
189#[derive(
190 Ord,
191 PartialOrd,
192 Clone,
193 Debug,
194 Eq,
195 PartialEq,
196 Serialize,
197 Deserialize,
198 Hash
199)]
200pub struct CastFloat32ToNumeric(pub Option<NumericMaxScale>);
201
202#[sqlfunc(
203 CastFloat32ToNumeric,
204 sqlname = "real_to_numeric",
205 inverse = super::CastNumericToFloat32,
206 is_monotone = true,
207 output_type_expr = SqlScalarType::Numeric { max_scale: self.0 }
208 .nullable(input_type.nullable)
209)]
210fn cast_float32_to_numeric(&self, a: f32) -> Result<Numeric, EvalError> {
211 if a.is_infinite() {
212 return Err(EvalError::InfinityOutOfDomain(
213 "casting real to numeric".into(),
214 ));
215 }
216 let mut a = Numeric::from(a);
217 if let Some(scale) = self.0 {
218 if numeric::rescale(&mut a, scale.into_u8()).is_err() {
219 return Err(EvalError::NumericFieldOverflow);
220 }
221 }
222 numeric::munge_numeric(&mut a).unwrap();
223 Ok(a)
224}