mz_catalog_decode/
durable.rs1use mz_repr::Datum;
15use mz_repr::adt::interval::Interval;
16use mz_repr::adt::jsonb::JsonbRef;
17use mz_repr::adt::mz_acl_item::{AclMode, MzAclItem};
18use mz_repr::adt::numeric;
19use mz_repr::role_id::RoleId;
20use mz_sql_parser::ast::{DateTimeField, IntervalValue};
21
22fn jsonb_datum_to_u64<'a>(d: Datum<'a>) -> Result<u64, String> {
24 let Datum::Numeric(n) = d else {
25 return Err("expected numeric value".into());
26 };
27
28 let mut cx = numeric::cx_datum();
29 cx.try_into_u64(n.0)
30 .map_err(|_| format!("number out of u64 range: {n}"))
31}
32
33fn jsonb_datum_to_acl_mode(d: Datum) -> Result<AclMode, String> {
39 let Datum::Map(dict) = d else {
40 return Err(format!("unexpected acl_mode: {d}"));
41 };
42 let mut bits = None;
43 for (key, val) in dict.iter() {
44 match key {
45 "bitflags" => bits = Some(jsonb_datum_to_u64(val)?),
46 other => return Err(format!("unexpected acl_mode field: {other}")),
47 }
48 }
49 let bits = bits.ok_or_else(|| "missing acl_mode bitflags".to_string())?;
50 AclMode::from_bits(bits).ok_or_else(|| format!("invalid acl_mode bitflags: {bits}"))
51}
52
53fn jsonb_datum_to_role_id(d: Datum) -> Result<RoleId, String> {
55 match d {
56 Datum::String("Public") => Ok(RoleId::Public),
57 Datum::String(other) => Err(format!("unexpected role ID variant: {other}")),
58 Datum::Map(dict) => {
59 let (key, val) = dict.iter().next().ok_or_else(|| "empty".to_string())?;
60 let n = jsonb_datum_to_u64(val)?;
61 match key {
62 "User" => Ok(RoleId::User(n)),
63 "System" => Ok(RoleId::System(n)),
64 "Predefined" => Ok(RoleId::Predefined(n)),
65 other => Err(format!("unexpected role ID variant: {other}")),
66 }
67 }
68 _ => Err("expected string or object".into()),
69 }
70}
71
72pub fn catalog_id(a: JsonbRef<'_>) -> Result<String, String> {
76 match a.into_datum() {
77 Datum::String(variant) => match variant {
79 "Explain" => Ok("e".to_string()),
80 "Public" => Ok("p".to_string()),
81 other => Err(format!("unexpected ID variant: {other}")),
82 },
83 Datum::Map(dict) => {
85 let (key, val) = dict.iter().next().ok_or_else(|| "empty".to_string())?;
86 let prefix = match key {
87 "IntrospectionSourceIndex" => "si",
88 "Predefined" => "g",
89 "System" => "s",
90 "Transient" => "t",
91 "User" => "u",
92 other => return Err(format!("unexpected ID variant: {other}")),
93 };
94 let n = jsonb_datum_to_u64(val)?;
95 Ok(format!("{prefix}{n}"))
96 }
97 _ => Err("expected string or object".into()),
98 }
99}
100
101pub fn privileges(a: JsonbRef<'_>) -> Result<Vec<MzAclItem>, String> {
103 let parse_one = |datum| match datum {
104 Datum::Map(dict) => {
105 let mut grantee = None;
106 let mut grantor = None;
107 let mut acl_mode = None;
108 for (key, val) in dict.iter() {
109 match key {
110 "grantee" => {
111 let id = jsonb_datum_to_role_id(val)?;
112 grantee = Some(id);
113 }
114 "grantor" => {
115 let id = jsonb_datum_to_role_id(val)?;
116 grantor = Some(id);
117 }
118 "acl_mode" => {
119 acl_mode = Some(jsonb_datum_to_acl_mode(val)?);
120 }
121 other => return Err(format!("unexpected privilege field: {other}")),
122 }
123 }
124 Ok(MzAclItem {
125 grantee: grantee.ok_or_else(|| format!("missing grantee: {dict:?}"))?,
126 grantor: grantor.ok_or_else(|| "missing grantor in privilege".to_string())?,
127 acl_mode: acl_mode.ok_or_else(|| "missing acl_mode in privilege".to_string())?,
128 })
129 }
130 other => Err(format!("expected object in array, found: {other}")),
131 };
132
133 match a.into_datum() {
134 Datum::List(list) => {
135 let mut result = Vec::new();
136 for item in list.iter() {
137 result.push(parse_one(item)?);
138 }
139 Ok(result)
140 }
141 _ => Err("expected array".to_string()),
142 }
143}
144
145pub fn acl_mode(a: JsonbRef<'_>) -> Result<AclMode, String> {
148 jsonb_datum_to_acl_mode(a.into_datum())
149}
150
151pub(crate) fn interval_literal(literal: &IntervalValue) -> Result<Interval, String> {
155 Interval::from_literal(
156 &literal.value,
157 date_time_field(literal.precision_high),
158 date_time_field(literal.precision_low),
159 literal.fsec_max_precision,
160 )
161 .map_err(|e| e.to_string())
162}
163
164fn date_time_field(field: DateTimeField) -> mz_repr::adt::datetime::DateTimeField {
165 use mz_repr::adt::datetime::DateTimeField as Repr;
166 match field {
167 DateTimeField::Millennium => Repr::Millennium,
168 DateTimeField::Century => Repr::Century,
169 DateTimeField::Decade => Repr::Decade,
170 DateTimeField::Year => Repr::Year,
171 DateTimeField::Month => Repr::Month,
172 DateTimeField::Day => Repr::Day,
173 DateTimeField::Hour => Repr::Hour,
174 DateTimeField::Minute => Repr::Minute,
175 DateTimeField::Second => Repr::Second,
176 DateTimeField::Milliseconds => Repr::Milliseconds,
177 DateTimeField::Microseconds => Repr::Microseconds,
178 }
179}