mz_expr/scalar/func/impls/
range.rs
1use std::fmt;
11
12use mz_lowertest::MzReflect;
13use mz_repr::adt::range::Range;
14use mz_repr::{ColumnType, Datum, RowArena, ScalarType};
15use proptest_derive::Arbitrary;
16use serde::{Deserialize, Serialize};
17
18use crate::scalar::func::{LazyUnaryFunc, stringify_datum};
19use crate::{EvalError, MirScalarExpr};
20
21#[derive(
22 Arbitrary, Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect,
23)]
24pub struct CastRangeToString {
25 pub ty: ScalarType,
26}
27
28impl LazyUnaryFunc for CastRangeToString {
29 fn eval<'a>(
30 &'a self,
31 datums: &[Datum<'a>],
32 temp_storage: &'a RowArena,
33 a: &'a MirScalarExpr,
34 ) -> Result<Datum<'a>, EvalError> {
35 let a = a.eval(datums, temp_storage)?;
36 if a.is_null() {
37 return Ok(Datum::Null);
38 }
39 let mut buf = String::new();
40 stringify_datum(&mut buf, a, &self.ty)?;
41 Ok(Datum::String(temp_storage.push_string(buf)))
42 }
43
44 fn output_type(&self, input_type: ColumnType) -> ColumnType {
45 ScalarType::String.nullable(input_type.nullable)
46 }
47
48 fn propagates_nulls(&self) -> bool {
49 true
50 }
51
52 fn introduces_nulls(&self) -> bool {
53 false
54 }
55
56 fn preserves_uniqueness(&self) -> bool {
57 true
58 }
59
60 fn inverse(&self) -> Option<crate::UnaryFunc> {
61 None
63 }
64
65 fn is_monotone(&self) -> bool {
66 false
67 }
68}
69
70impl fmt::Display for CastRangeToString {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 f.write_str("rangetostr")
73 }
74}
75
76#[derive(
77 Arbitrary, Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect,
78)]
79pub struct RangeLower;
80
81impl LazyUnaryFunc for RangeLower {
82 fn eval<'a>(
83 &'a self,
84 datums: &[Datum<'a>],
85 temp_storage: &'a RowArena,
86 a: &'a MirScalarExpr,
87 ) -> Result<Datum<'a>, EvalError> {
88 let a = a.eval(datums, temp_storage)?;
89 if a.is_null() {
90 return Ok(Datum::Null);
91 }
92 let r = a.unwrap_range();
93 Ok(Datum::from(
94 r.inner.map(|inner| inner.lower.bound).flatten(),
95 ))
96 }
97
98 fn output_type(&self, input_type: ColumnType) -> ColumnType {
99 input_type
100 .scalar_type
101 .unwrap_range_element_type()
102 .clone()
103 .nullable(true)
104 }
105
106 fn propagates_nulls(&self) -> bool {
107 true
108 }
109
110 fn introduces_nulls(&self) -> bool {
111 true
112 }
113
114 fn preserves_uniqueness(&self) -> bool {
115 false
116 }
117
118 fn inverse(&self) -> Option<crate::UnaryFunc> {
119 None
120 }
121
122 fn is_monotone(&self) -> bool {
123 true }
125}
126
127impl fmt::Display for RangeLower {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 f.write_str("rangelower")
130 }
131}
132
133#[derive(
134 Arbitrary, Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect,
135)]
136pub struct RangeUpper;
137
138impl LazyUnaryFunc for RangeUpper {
139 fn eval<'a>(
140 &'a self,
141 datums: &[Datum<'a>],
142 temp_storage: &'a RowArena,
143 a: &'a MirScalarExpr,
144 ) -> Result<Datum<'a>, EvalError> {
145 let a = a.eval(datums, temp_storage)?;
146 if a.is_null() {
147 return Ok(Datum::Null);
148 }
149 let r = a.unwrap_range();
150 Ok(Datum::from(
151 r.inner.map(|inner| inner.upper.bound).flatten(),
152 ))
153 }
154
155 fn output_type(&self, input_type: ColumnType) -> ColumnType {
156 input_type
157 .scalar_type
158 .unwrap_range_element_type()
159 .clone()
160 .nullable(true)
161 }
162
163 fn propagates_nulls(&self) -> bool {
164 true
165 }
166
167 fn introduces_nulls(&self) -> bool {
168 true
169 }
170
171 fn preserves_uniqueness(&self) -> bool {
172 false
173 }
174
175 fn inverse(&self) -> Option<crate::UnaryFunc> {
176 None
177 }
178
179 fn is_monotone(&self) -> bool {
180 false
181 }
182}
183
184impl fmt::Display for RangeUpper {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 f.write_str("rangeupper")
187 }
188}
189
190sqlfunc!(
191 #[sqlname = "range_empty"]
192 fn range_empty(a: Range<Datum<'a>>) -> bool {
193 a.inner.is_none()
194 }
195);
196
197sqlfunc!(
198 #[sqlname = "range_lower_inc"]
199 fn range_lower_inc(a: Range<Datum<'a>>) -> bool {
200 match a.inner {
201 None => false,
202 Some(inner) => inner.lower.inclusive,
203 }
204 }
205);
206
207sqlfunc!(
208 #[sqlname = "range_upper_inc"]
209 fn range_upper_inc(a: Range<Datum<'a>>) -> bool {
210 match a.inner {
211 None => false,
212 Some(inner) => inner.upper.inclusive,
213 }
214 }
215);
216
217sqlfunc!(
218 #[sqlname = "range_lower_inf"]
219 fn range_lower_inf(a: Range<Datum<'a>>) -> bool {
220 match a.inner {
221 None => false,
222 Some(inner) => inner.lower.bound.is_none(),
223 }
224 }
225);
226
227sqlfunc!(
228 #[sqlname = "range_upper_inf"]
229 fn range_upper_inf(a: Range<Datum<'a>>) -> bool {
230 match a.inner {
231 None => false,
232 Some(inner) => inner.upper.bound.is_none(),
233 }
234 }
235);