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