mz_expr/scalar/func/impls/
range.rs1use std::fmt;
11
12use mz_expr_derive::sqlfunc;
13use mz_lowertest::MzReflect;
14use mz_repr::adt::range::Range;
15use mz_repr::{Datum, RowArena, SqlColumnType, SqlScalarType};
16use serde::{Deserialize, Serialize};
17
18use crate::scalar::func::{LazyUnaryFunc, stringify_datum};
19use crate::{EvalError, MirScalarExpr};
20
21#[derive(
22 Ord,
23 PartialOrd,
24 Clone,
25 Debug,
26 Eq,
27 PartialEq,
28 Serialize,
29 Deserialize,
30 Hash,
31 MzReflect
32)]
33pub struct CastRangeToString {
34 pub ty: SqlScalarType,
35}
36
37impl LazyUnaryFunc for CastRangeToString {
38 fn eval<'a>(
39 &'a self,
40 datums: &[Datum<'a>],
41 temp_storage: &'a RowArena,
42 a: &'a MirScalarExpr,
43 ) -> Result<Datum<'a>, EvalError> {
44 let a = a.eval(datums, temp_storage)?;
45 if a.is_null() {
46 return Ok(Datum::Null);
47 }
48 let mut buf = String::new();
49 stringify_datum(&mut buf, a, &self.ty)?;
50 Ok(Datum::String(temp_storage.push_string(buf)))
51 }
52
53 fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType {
54 SqlScalarType::String.nullable(input_type.nullable)
55 }
56
57 fn propagates_nulls(&self) -> bool {
58 true
59 }
60
61 fn introduces_nulls(&self) -> bool {
62 false
63 }
64
65 fn preserves_uniqueness(&self) -> bool {
66 true
67 }
68
69 fn inverse(&self) -> Option<crate::UnaryFunc> {
70 None
72 }
73
74 fn is_monotone(&self) -> bool {
75 false
76 }
77
78 fn is_eliminable_cast(&self) -> bool {
79 false
80 }
81}
82
83impl fmt::Display for CastRangeToString {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 f.write_str("rangetostr")
86 }
87}
88
89#[sqlfunc(sqlname = "rangelower", is_monotone = true)]
90fn range_lower<T>(a: Range<T>) -> Option<T> {
91 a.inner.map(|inner| inner.lower.bound).flatten()
92}
93
94#[sqlfunc(sqlname = "rangeupper")]
95fn range_upper<T>(a: Range<T>) -> Option<T> {
96 a.inner.map(|inner| inner.upper.bound).flatten()
97}
98
99#[sqlfunc(sqlname = "range_empty")]
100fn range_empty<T>(a: Range<T>) -> bool {
101 a.inner.is_none()
102}
103
104#[sqlfunc(sqlname = "range_lower_inc")]
105fn range_lower_inc<T>(a: Range<T>) -> bool {
106 match a.inner {
107 None => false,
108 Some(inner) => inner.lower.inclusive,
109 }
110}
111
112#[sqlfunc(sqlname = "range_upper_inc")]
113fn range_upper_inc<T>(a: Range<T>) -> bool {
114 match a.inner {
115 None => false,
116 Some(inner) => inner.upper.inclusive,
117 }
118}
119
120#[sqlfunc(sqlname = "range_lower_inf")]
121fn range_lower_inf<T>(a: Range<T>) -> bool {
122 match a.inner {
123 None => false,
124 Some(inner) => inner.lower.bound.is_none(),
125 }
126}
127
128#[sqlfunc(sqlname = "range_upper_inf")]
129fn range_upper_inf<T>(a: Range<T>) -> bool {
130 match a.inner {
131 None => false,
132 Some(inner) => inner.upper.bound.is_none(),
133 }
134}