Skip to main content

mz_expr/scalar/func/impls/
range.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use 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        // TODO? if typeconv was in expr, we could determine this
69        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// The monotone claim survives this function mapping empty and
88// unbounded-lower ranges to NULL, which the interpreter's endpoint box
89// cannot represent, only because those inputs form a downward-closed
90// prefix of the range ordering (`None` inner sorts below `Some`, and a
91// `None` lower bound sorts below every finite one): a range whose
92// endpoints both yield values contains no NULL-yielding interior. Any
93// change to range ordering or to this function's NULL cases must revisit
94// the claim; see `try_parse_monotonic_iso8601_timestamp` for the
95// SpecialUnary alternative.
96#[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}