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