mz_expr/scalar/func/impls/
map.rs1use std::fmt;
11
12use itertools::Itertools;
13use mz_expr_derive::sqlfunc;
14use mz_lowertest::MzReflect;
15use mz_repr::{Datum, DatumMap, 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 CastMapToString {
34 pub ty: SqlScalarType,
35}
36
37impl LazyUnaryFunc for CastMapToString {
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 CastMapToString {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 f.write_str("maptostr")
86 }
87}
88
89#[sqlfunc(sqlname = "map_length")]
90fn map_length<'a>(a: DatumMap<'a>) -> Result<i32, EvalError> {
91 let count = a.iter().count();
92 count
93 .try_into()
94 .map_err(|_| EvalError::Int32OutOfRange(count.to_string().into()))
95}
96
97#[derive(
98 Ord,
99 PartialOrd,
100 Clone,
101 Debug,
102 Eq,
103 PartialEq,
104 Serialize,
105 Deserialize,
106 Hash,
107 MzReflect
108)]
109pub struct MapBuildFromRecordList {
110 pub value_type: SqlScalarType,
111}
112
113impl LazyUnaryFunc for MapBuildFromRecordList {
114 fn eval<'a>(
115 &'a self,
116 datums: &[Datum<'a>],
117 temp_storage: &'a RowArena,
118 a: &'a MirScalarExpr,
119 ) -> Result<Datum<'a>, EvalError> {
120 let a = a.eval(datums, temp_storage)?;
121 if a.is_null() {
122 return Ok(Datum::Null);
123 }
124 let list = a.unwrap_list();
125 let mut map = std::collections::BTreeMap::new();
126
127 for i in list.iter() {
128 if i.is_null() {
129 continue;
130 }
131
132 for (k, v) in i.unwrap_list().iter().tuples() {
133 if k.is_null() {
134 continue;
135 }
136 map.insert(k.unwrap_str(), v);
137 }
138 }
139
140 let map = temp_storage.make_datum(|packer| packer.push_dict(map));
141 Ok(map)
142 }
143
144 fn output_sql_type(&self, _input_type: SqlColumnType) -> SqlColumnType {
145 SqlScalarType::Map {
146 value_type: Box::new(self.value_type.clone()),
147 custom_id: None,
148 }
149 .nullable(true)
150 }
151
152 fn propagates_nulls(&self) -> bool {
153 true
154 }
155
156 fn introduces_nulls(&self) -> bool {
157 true
158 }
159
160 fn preserves_uniqueness(&self) -> bool {
161 false
162 }
163
164 fn inverse(&self) -> Option<crate::UnaryFunc> {
165 None
166 }
167
168 fn is_monotone(&self) -> bool {
169 false
170 }
171
172 fn is_eliminable_cast(&self) -> bool {
173 false
174 }
175}
176
177impl fmt::Display for MapBuildFromRecordList {
178 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179 f.write_str("map_build")
180 }
181}