1use std::collections::BTreeMap;
11use std::error::Error;
12use std::{io, str};
13
14use bytes::{BufMut, BytesMut};
15use chrono::{DateTime, NaiveDateTime, NaiveTime, Utc};
16use dec::OrderedDecimal;
17use itertools::Itertools;
18use mz_ore::cast::ReinterpretCast;
19use mz_pgrepr_consts::oid::TYPE_INT2_OID;
20use mz_pgwire_common::Format;
21use mz_repr::adt::array::ArrayDimension;
22use mz_repr::adt::char;
23use mz_repr::adt::date::Date;
24use mz_repr::adt::jsonb::JsonbRef;
25use mz_repr::adt::mz_acl_item::{AclItem, MzAclItem};
26use mz_repr::adt::numeric::{self as mz_repr_numeric, NumericMaxScale, rescale};
27use mz_repr::adt::pg_legacy_name::NAME_MAX_BYTES;
28use mz_repr::adt::range::{Range, RangeInner};
29use mz_repr::adt::timestamp::CheckedTimestamp;
30use mz_repr::strconv::{self, Nestable};
31use mz_repr::{Datum, RowArena, RowPacker, RowRef, SqlRelationType, SqlScalarType};
32use postgres_types::{FromSql, IsNull, ToSql, Type as PgType};
33use uuid::Uuid;
34
35use crate::types::{NumericConstraints, UINT2, UINT4, UINT8};
36use crate::value::error::{IntoDatumError, NulCharacterError};
37use crate::{Interval, Jsonb, Numeric, Type, UInt2, UInt4, UInt8};
38
39pub mod error;
40pub mod interval;
41pub mod jsonb;
42pub mod numeric;
43pub mod record;
44pub mod unsigned;
45
46#[derive(Debug)]
48pub enum Value {
49 Array {
51 dims: Vec<ArrayDimension>,
53 elements: Vec<Option<Value>>,
55 },
56 Bool(bool),
58 Bytea(Vec<u8>),
60 Char(u8),
62 Date(Date),
64 Float4(f32),
66 Float8(f64),
68 Int2(i16),
70 Int4(i32),
72 Int8(i64),
74 UInt2(UInt2),
76 UInt4(UInt4),
78 UInt8(UInt8),
80 Interval(Interval),
82 Jsonb(Jsonb),
84 List(Vec<Option<Value>>),
86 Map(BTreeMap<String, Option<Value>>),
88 Name(String),
90 Numeric(Numeric),
92 Oid(u32),
94 Record(Vec<Option<Value>>),
96 Time(NaiveTime),
98 Timestamp(CheckedTimestamp<NaiveDateTime>),
100 TimestampTz(CheckedTimestamp<DateTime<Utc>>),
102 Text(String),
104 BpChar(String),
106 VarChar(String),
108 Uuid(Uuid),
110 Int2Vector {
112 elements: Vec<Option<Value>>,
114 },
115 MzTimestamp(mz_repr::Timestamp),
117 Range(Range<Box<Value>>),
119 MzAclItem(MzAclItem),
122 AclItem(AclItem),
125}
126
127impl Value {
128 pub fn from_datum(datum: Datum, typ: &SqlScalarType) -> Option<Value> {
133 match (datum, typ) {
134 (Datum::Null, _) => None,
135 (Datum::True, SqlScalarType::Bool) => Some(Value::Bool(true)),
136 (Datum::False, SqlScalarType::Bool) => Some(Value::Bool(false)),
137 (Datum::Int16(i), SqlScalarType::Int16) => Some(Value::Int2(i)),
138 (Datum::Int32(i), SqlScalarType::Int32) => Some(Value::Int4(i)),
139 (Datum::Int64(i), SqlScalarType::Int64) => Some(Value::Int8(i)),
140 (Datum::UInt8(c), SqlScalarType::PgLegacyChar) => Some(Value::Char(c)),
141 (Datum::UInt16(u), SqlScalarType::UInt16) => Some(Value::UInt2(UInt2(u))),
142 (Datum::UInt32(oid), SqlScalarType::Oid) => Some(Value::Oid(oid)),
143 (Datum::UInt32(oid), SqlScalarType::RegClass) => Some(Value::Oid(oid)),
144 (Datum::UInt32(oid), SqlScalarType::RegProc) => Some(Value::Oid(oid)),
145 (Datum::UInt32(oid), SqlScalarType::RegType) => Some(Value::Oid(oid)),
146 (Datum::UInt32(u), SqlScalarType::UInt32) => Some(Value::UInt4(UInt4(u))),
147 (Datum::UInt64(u), SqlScalarType::UInt64) => Some(Value::UInt8(UInt8(u))),
148 (Datum::Float32(f), SqlScalarType::Float32) => Some(Value::Float4(*f)),
149 (Datum::Float64(f), SqlScalarType::Float64) => Some(Value::Float8(*f)),
150 (Datum::Numeric(d), SqlScalarType::Numeric { .. }) => Some(Value::Numeric(Numeric(d))),
151 (Datum::MzTimestamp(t), SqlScalarType::MzTimestamp) => Some(Value::MzTimestamp(t)),
152 (Datum::MzAclItem(mai), SqlScalarType::MzAclItem) => Some(Value::MzAclItem(mai)),
153 (Datum::AclItem(ai), SqlScalarType::AclItem) => Some(Value::AclItem(ai)),
154 (Datum::Date(d), SqlScalarType::Date) => Some(Value::Date(d)),
155 (Datum::Time(t), SqlScalarType::Time) => Some(Value::Time(t)),
156 (Datum::Timestamp(ts), SqlScalarType::Timestamp { .. }) => Some(Value::Timestamp(ts)),
157 (Datum::TimestampTz(ts), SqlScalarType::TimestampTz { .. }) => {
158 Some(Value::TimestampTz(ts))
159 }
160 (Datum::Interval(iv), SqlScalarType::Interval) => Some(Value::Interval(Interval(iv))),
161 (Datum::Bytes(b), SqlScalarType::Bytes) => Some(Value::Bytea(b.to_vec())),
162 (Datum::String(s), SqlScalarType::String) => Some(Value::Text(s.to_owned())),
163 (Datum::String(s), SqlScalarType::VarChar { .. }) => Some(Value::VarChar(s.to_owned())),
164 (Datum::String(s), SqlScalarType::Char { length }) => {
165 Some(Value::BpChar(char::format_str_pad(s, *length)))
166 }
167 (Datum::String(s), SqlScalarType::PgLegacyName) => Some(Value::Name(s.into())),
168 (_, SqlScalarType::Jsonb) => {
169 Some(Value::Jsonb(Jsonb(JsonbRef::from_datum(datum).to_owned())))
170 }
171 (Datum::Uuid(u), SqlScalarType::Uuid) => Some(Value::Uuid(u)),
172 (Datum::Array(array), SqlScalarType::Array(elem_type)) => {
173 let dims = array.dims().into_iter().collect();
174 let elements = array
175 .elements()
176 .iter()
177 .map(|elem| Value::from_datum(elem, elem_type))
178 .collect();
179 Some(Value::Array { dims, elements })
180 }
181 (Datum::Array(array), SqlScalarType::Int2Vector) => {
182 assert!(
183 array.has_int2vector_dims(),
184 "int2vector must be 1 dimensional, or empty"
185 );
186 let elements = array
187 .elements()
188 .iter()
189 .map(|elem| Value::from_datum(elem, &SqlScalarType::Int16))
190 .collect();
191 Some(Value::Int2Vector { elements })
192 }
193 (Datum::List(list), SqlScalarType::List { element_type, .. }) => {
194 let elements = list
195 .iter()
196 .map(|elem| Value::from_datum(elem, element_type))
197 .collect();
198 Some(Value::List(elements))
199 }
200 (Datum::List(record), SqlScalarType::Record { fields, .. }) => {
201 let fields = record
202 .iter()
203 .zip_eq(fields)
204 .map(|(e, (_name, ty))| Value::from_datum(e, &ty.scalar_type))
205 .collect();
206 Some(Value::Record(fields))
207 }
208 (Datum::Map(dict), SqlScalarType::Map { value_type, .. }) => {
209 let entries = dict
210 .iter()
211 .map(|(k, v)| (k.to_owned(), Value::from_datum(v, value_type)))
212 .collect();
213 Some(Value::Map(entries))
214 }
215 (Datum::Range(range), SqlScalarType::Range { element_type }) => {
216 let value_range = range.into_bounds(|b| {
217 Box::new(
218 Value::from_datum(b.datum(), element_type)
219 .expect("RangeBounds never contain Datum::Null"),
220 )
221 });
222 Some(Value::Range(value_range))
223 }
224 _ => panic!("can't serialize {}::{:?}", datum, typ),
225 }
226 }
227
228 pub fn into_datum<'a>(
230 self,
231 buf: &'a RowArena,
232 typ: &Type,
233 ) -> Result<Datum<'a>, IntoDatumError> {
234 Ok(match self {
235 Value::Array { dims, elements } => {
236 let element_pg_type = match typ {
237 Type::Array(t) => &*t,
238 _ => panic!("Value::Array should have type Type::Array. Found {:?}", typ),
239 };
240 let elements: Result<Vec<_>, _> = elements
241 .into_iter()
242 .map(|element| match element {
243 Some(element) => element.into_datum(buf, element_pg_type),
244 None => Ok(Datum::Null),
245 })
246 .collect();
247 let elements = elements?;
248 buf.try_make_datum(|packer| {
249 packer
250 .try_push_array(&dims, elements)
251 .map_err(IntoDatumError::from)
252 })?
253 }
254 Value::Int2Vector { .. } => {
255 unreachable!("into_datum cannot be called on Value::Int2Vector");
258 }
259 Value::Bool(true) => Datum::True,
260 Value::Bool(false) => Datum::False,
261 Value::Bytea(b) => Datum::Bytes(buf.push_bytes(b)),
262 Value::Char(c) => Datum::UInt8(c),
263 Value::Date(d) => Datum::Date(d),
264 Value::Float4(f) => Datum::Float32(f.into()),
265 Value::Float8(f) => Datum::Float64(f.into()),
266 Value::Int2(i) => Datum::Int16(i),
267 Value::Int4(i) => Datum::Int32(i),
268 Value::Int8(i) => Datum::Int64(i),
269 Value::UInt2(u) => Datum::UInt16(u.0),
270 Value::UInt4(u) => Datum::UInt32(u.0),
271 Value::UInt8(u) => Datum::UInt64(u.0),
272 Value::Jsonb(js) => buf.push_unary_row(js.0.into_row()),
273 Value::List(elems) => {
274 let elem_pg_type = match typ {
275 Type::List(t) => &*t,
276 _ => panic!("Value::List should have type Type::List. Found {:?}", typ),
277 };
278 let elems: Result<Vec<_>, _> = elems
279 .into_iter()
280 .map(|elem| match elem {
281 Some(elem) => elem.into_datum(buf, elem_pg_type),
282 None => Ok(Datum::Null),
283 })
284 .collect();
285 let elems = elems?;
286 buf.make_datum(|packer| packer.push_list(elems))
287 }
288 Value::Map(map) => {
289 let elem_pg_type = match typ {
290 Type::Map { value_type } => &*value_type,
291 _ => panic!("Value::Map should have type Type::Map. Found {:?}", typ),
292 };
293 buf.try_make_datum(|packer| {
294 packer.try_push_dict_with(|row| {
295 for (k, v) in map {
296 row.push(Datum::String(buf.push_string(k)));
297 let datum = match v {
298 Some(elem) => elem.into_datum(buf, elem_pg_type)?,
299 None => Datum::Null,
300 };
301 row.push(datum);
302 }
303 Ok::<_, IntoDatumError>(())
304 })
305 })?
306 }
307 Value::Oid(oid) => Datum::UInt32(oid),
308 Value::Record(_) => {
309 unreachable!("into_datum cannot be called on Value::Record");
312 }
313 Value::Time(t) => Datum::Time(t),
314 Value::Timestamp(ts) => Datum::Timestamp(ts),
315 Value::TimestampTz(ts) => Datum::TimestampTz(ts),
316 Value::Interval(iv) => Datum::Interval(iv.0),
317 Value::Text(s) | Value::VarChar(s) | Value::Name(s) => {
318 Datum::String(buf.push_string(s))
319 }
320 Value::BpChar(s) => Datum::String(buf.push_string(s.trim_end().into())),
321 Value::Uuid(u) => Datum::Uuid(u),
322 Value::Numeric(n) => Datum::Numeric(n.0),
323 Value::MzTimestamp(t) => Datum::MzTimestamp(t),
324 Value::Range(range) => {
325 let elem_pg_type = match typ {
326 Type::Range { element_type } => &*element_type,
327 _ => panic!("Value::Range should have type Type::Range. Found {:?}", typ),
328 };
329 let range = range.try_into_bounds(|elem| elem.into_datum(buf, elem_pg_type))?;
330 buf.try_make_datum(|packer| packer.push_range(range).map_err(IntoDatumError::from))?
331 }
332 Value::MzAclItem(mz_acl_item) => Datum::MzAclItem(mz_acl_item),
333 Value::AclItem(acl_item) => Datum::AclItem(acl_item),
334 })
335 }
336
337 pub fn into_datum_decode_error<'a>(
342 self,
343 buf: &'a RowArena,
344 typ: &Type,
345 context: &str,
346 ) -> Result<Datum<'a>, String> {
347 self.into_datum(buf, typ)
348 .map_err(|e| format!("unable to decode {}: {}", context, e))
349 }
350
351 pub fn encode(&self, ty: &Type, format: Format, buf: &mut BytesMut) -> Result<(), io::Error> {
353 match format {
354 Format::Text => {
355 self.encode_text(buf);
356 Ok(())
357 }
358 Format::Binary => self.encode_binary(ty, buf),
359 }
360 }
361
362 pub fn encode_text(&self, buf: &mut BytesMut) -> Nestable {
365 match self {
366 Value::Array { dims, elements } => {
367 strconv::format_array(buf, dims, elements, |buf, elem| match elem {
368 None => Ok::<_, ()>(buf.write_null()),
369 Some(elem) => Ok(elem.encode_text(buf.nonnull_buffer())),
370 })
371 .expect("provided closure never fails")
372 }
373 Value::Int2Vector { elements } => {
374 strconv::format_legacy_vector(buf, elements, |buf, elem| {
375 Ok::<_, ()>(
376 elem.as_ref()
377 .expect("Int2Vector does not support NULL values")
378 .encode_text(buf.nonnull_buffer()),
379 )
380 })
381 .expect("provided closure never fails")
382 }
383 Value::Bool(b) => strconv::format_bool(buf, *b),
384 Value::Bytea(b) => strconv::format_bytes(buf, b),
385 Value::Char(c) => {
386 buf.put_u8(*c);
387 Nestable::MayNeedEscaping
388 }
389 Value::Date(d) => strconv::format_date(buf, *d),
390 Value::Int2(i) => strconv::format_int16(buf, *i),
391 Value::Int4(i) => strconv::format_int32(buf, *i),
392 Value::Int8(i) => strconv::format_int64(buf, *i),
393 Value::UInt2(u) => strconv::format_uint16(buf, u.0),
394 Value::UInt4(u) => strconv::format_uint32(buf, u.0),
395 Value::UInt8(u) => strconv::format_uint64(buf, u.0),
396 Value::Interval(iv) => strconv::format_interval(buf, iv.0),
397 Value::Float4(f) => strconv::format_float32(buf, *f),
398 Value::Float8(f) => strconv::format_float64(buf, *f),
399 Value::Jsonb(js) => strconv::format_jsonb(buf, js.0.as_ref()),
400 Value::List(elems) => strconv::format_list(buf, elems, |buf, elem| match elem {
401 None => Ok::<_, ()>(buf.write_null()),
402 Some(elem) => Ok(elem.encode_text(buf.nonnull_buffer())),
403 })
404 .expect("provided closure never fails"),
405 Value::Map(elems) => strconv::format_map(buf, elems, |buf, value| match value {
406 None => Ok::<_, ()>(buf.write_null()),
407 Some(elem) => Ok(elem.encode_text(buf.nonnull_buffer())),
408 })
409 .expect("provided closure never fails"),
410 Value::Oid(oid) => strconv::format_uint32(buf, *oid),
411 Value::Record(elems) => strconv::format_record(buf, elems, |buf, elem| match elem {
412 None => Ok::<_, ()>(buf.write_null()),
413 Some(elem) => Ok(elem.encode_text(buf.nonnull_buffer())),
414 })
415 .expect("provided closure never fails"),
416 Value::Text(s) | Value::VarChar(s) | Value::BpChar(s) | Value::Name(s) => {
417 strconv::format_string(buf, s)
418 }
419 Value::Time(t) => strconv::format_time(buf, *t),
420 Value::Timestamp(ts) => strconv::format_timestamp(buf, ts),
421 Value::TimestampTz(ts) => strconv::format_timestamptz(buf, ts),
422 Value::Uuid(u) => strconv::format_uuid(buf, *u),
423 Value::Numeric(d) => strconv::format_numeric(buf, &d.0),
424 Value::MzTimestamp(t) => strconv::format_mz_timestamp(buf, *t),
425 Value::Range(range) => strconv::format_range(buf, range, |buf, elem| match elem {
426 Some(elem) => Ok(elem.encode_text(buf.nonnull_buffer())),
427 None => Ok::<_, ()>(buf.write_null()),
428 })
429 .expect("provided closure never fails"),
430 Value::MzAclItem(mz_acl_item) => strconv::format_mz_acl_item(buf, *mz_acl_item),
431 Value::AclItem(acl_item) => strconv::format_acl_item(buf, *acl_item),
432 }
433 }
434
435 pub fn encode_binary(&self, ty: &Type, buf: &mut BytesMut) -> Result<(), io::Error> {
438 let is_null = match self {
441 Value::Array { dims, elements } => {
442 let ndims = pg_len("number of array dimensions", dims.len())?;
443 let has_null = elements.iter().any(|e| e.is_none());
444 let elem_type = match ty {
445 Type::Array(elem_type) => elem_type,
446 _ => unreachable!(),
447 };
448 buf.put_i32(ndims);
449 buf.put_i32(has_null.into());
450 buf.put_u32(elem_type.oid());
451 for dim in dims {
452 buf.put_i32(pg_len("array dimension length", dim.length)?);
453 buf.put_i32(dim.lower_bound.try_into().map_err(|_| {
454 io::Error::new(
455 io::ErrorKind::InvalidData,
456 "array dimension lower bound does not fit into an i32",
457 )
458 })?);
459 }
460 for elem in elements {
461 encode_element(buf, elem.as_ref(), elem_type)?;
462 }
463 Ok(postgres_types::IsNull::No)
464 }
465 Value::Int2Vector { elements } => {
466 let has_null = elements.iter().any(|e| e.is_none());
469 buf.put_i32(1);
470 buf.put_i32(has_null.into());
471 buf.put_u32(TYPE_INT2_OID);
472 buf.put_i32(pg_len("int2vector dimension length", elements.len())?);
473 buf.put_i32(0);
474 for elem in elements {
475 encode_element(buf, elem.as_ref(), &Type::Int2)?;
476 }
477 Ok(postgres_types::IsNull::No)
478 }
479 Value::Bool(b) => b.to_sql(&PgType::BOOL, buf),
480 Value::Bytea(b) => b.to_sql(&PgType::BYTEA, buf),
481 Value::Char(c) => i8::reinterpret_cast(*c).to_sql(&PgType::CHAR, buf),
482 Value::Date(d) => d.pg_epoch_days().to_sql(&PgType::DATE, buf),
483 Value::Float4(f) => f.to_sql(&PgType::FLOAT4, buf),
484 Value::Float8(f) => f.to_sql(&PgType::FLOAT8, buf),
485 Value::Int2(i) => i.to_sql(&PgType::INT2, buf),
486 Value::Int4(i) => i.to_sql(&PgType::INT4, buf),
487 Value::Int8(i) => i.to_sql(&PgType::INT8, buf),
488 Value::UInt2(u) => u.to_sql(&*UINT2, buf),
489 Value::UInt4(u) => u.to_sql(&*UINT4, buf),
490 Value::UInt8(u) => u.to_sql(&*UINT8, buf),
491 Value::Interval(iv) => iv.to_sql(&PgType::INTERVAL, buf),
492 Value::Jsonb(js) => js.to_sql(&PgType::JSONB, buf),
493 Value::List(_) => {
494 Err("binary encoding of list types is not implemented".into())
525 }
526 Value::Map(_) => {
527 Err("binary encoding of map types is not implemented".into())
531 }
532 Value::Name(s) => s.to_sql(&PgType::NAME, buf),
533 Value::Oid(i) => i.to_sql(&PgType::OID, buf),
534 Value::Record(fields) => {
535 let nfields = pg_len("record field length", fields.len())?;
536 buf.put_i32(nfields);
537 let field_types = match ty {
538 Type::Record(fields) => fields,
539 _ => unreachable!(),
540 };
541 for (f, ty) in fields.iter().zip_eq(field_types) {
542 buf.put_u32(ty.oid());
543 encode_element(buf, f.as_ref(), ty)?;
544 }
545 Ok(postgres_types::IsNull::No)
546 }
547 Value::Text(s) => s.to_sql(&PgType::TEXT, buf),
548 Value::BpChar(s) => s.to_sql(&PgType::BPCHAR, buf),
549 Value::VarChar(s) => s.to_sql(&PgType::VARCHAR, buf),
550 Value::Time(t) => t.to_sql(&PgType::TIME, buf),
551 Value::Timestamp(ts) => ts.to_sql(&PgType::TIMESTAMP, buf),
552 Value::TimestampTz(ts) => ts.to_sql(&PgType::TIMESTAMPTZ, buf),
553 Value::Uuid(u) => u.to_sql(&PgType::UUID, buf),
554 Value::Numeric(a) => a.to_sql(&PgType::NUMERIC, buf),
555 Value::MzTimestamp(t) => t.to_string().to_sql(&PgType::TEXT, buf),
556 Value::Range(range) => {
557 buf.put_u8(range.pg_flag_bits());
558
559 let elem_type = match ty {
560 Type::Range { element_type } => element_type,
561 _ => unreachable!(),
562 };
563
564 if let Some(RangeInner { lower, upper }) = &range.inner {
565 for bound in [&lower.bound, &upper.bound] {
566 if let Some(bound) = bound {
567 let base = buf.len();
568 buf.put_i32(0);
569 bound.encode_binary(elem_type, buf)?;
570 let len = pg_len("encoded range bound", buf.len() - base - 4)?;
571 buf[base..base + 4].copy_from_slice(&len.to_be_bytes());
572 }
573 }
574 }
575 Ok(postgres_types::IsNull::No)
576 }
577 Value::MzAclItem(mz_acl_item) => {
578 buf.extend_from_slice(&mz_acl_item.encode_binary());
579 Ok(postgres_types::IsNull::No)
580 }
581 Value::AclItem(_) => Err("aclitem has no binary encoding".into()),
582 }
583 .expect("encode_binary should never trigger a to_sql failure");
584 if let IsNull::Yes = is_null {
585 panic!("encode_binary impossibly called on a null value")
586 }
587 Ok(())
588 }
589
590 pub fn binary_encoding_error(typ: &SqlScalarType) -> Result<(), &'static str> {
604 match typ {
605 SqlScalarType::Bool => Ok(()),
606 SqlScalarType::Int16 => Ok(()),
607 SqlScalarType::Int32 => Ok(()),
608 SqlScalarType::Int64 => Ok(()),
609 SqlScalarType::PgLegacyChar => Ok(()),
610 SqlScalarType::UInt16 => Ok(()),
611 SqlScalarType::Oid => Ok(()),
612 SqlScalarType::RegClass => Ok(()),
613 SqlScalarType::RegProc => Ok(()),
614 SqlScalarType::RegType => Ok(()),
615 SqlScalarType::UInt32 => Ok(()),
616 SqlScalarType::UInt64 => Ok(()),
617 SqlScalarType::Float32 => Ok(()),
618 SqlScalarType::Float64 => Ok(()),
619 SqlScalarType::Numeric { .. } => Ok(()),
620 SqlScalarType::MzTimestamp => Ok(()),
621 SqlScalarType::MzAclItem => Ok(()),
622 SqlScalarType::AclItem => Err("no binary output function available for type aclitem"),
623 SqlScalarType::Date => Ok(()),
624 SqlScalarType::Time => Ok(()),
625 SqlScalarType::Timestamp { .. } => Ok(()),
626 SqlScalarType::TimestampTz { .. } => Ok(()),
627 SqlScalarType::Interval => Ok(()),
628 SqlScalarType::Bytes => Ok(()),
629 SqlScalarType::String => Ok(()),
630 SqlScalarType::VarChar { .. } => Ok(()),
631 SqlScalarType::Char { .. } => Ok(()),
632 SqlScalarType::PgLegacyName => Ok(()),
633 SqlScalarType::Jsonb => Ok(()),
634 SqlScalarType::Uuid => Ok(()),
635 SqlScalarType::Array(elem_type) => Self::binary_encoding_error(elem_type),
636 SqlScalarType::Int2Vector => Ok(()),
637 SqlScalarType::List { .. } => Err("no binary output function available for type list"),
638 SqlScalarType::Map { .. } => Err("no binary output function available for type map"),
639 SqlScalarType::Record { fields, .. } => fields
640 .iter()
641 .try_for_each(|(_, ty)| Self::binary_encoding_error(&ty.scalar_type)),
642 SqlScalarType::Range { element_type } => Self::binary_encoding_error(element_type),
643 }
644 }
645
646 pub fn can_encode_binary(typ: &SqlScalarType) -> bool {
650 Self::binary_encoding_error(typ).is_ok()
651 }
652
653 pub fn decode(
656 format: Format,
657 ty: &Type,
658 raw: &[u8],
659 ) -> Result<Value, Box<dyn Error + Sync + Send>> {
660 match format {
661 Format::Text => Value::decode_text(ty, raw),
662 Format::Binary => Value::decode_binary(ty, raw),
663 }
664 }
665
666 pub fn decode_text<'a>(
669 ty: &'a Type,
670 raw: &'a [u8],
671 ) -> Result<Value, Box<dyn Error + Sync + Send>> {
672 let s = str::from_utf8(raw)?;
673 reject_nul(s)?;
676 Ok(match ty {
677 Type::Array(elem_type) => {
678 let (elements, dims) = strconv::parse_array(
679 s,
680 || None,
681 |elem_text| Value::decode_text(elem_type, elem_text.as_bytes()).map(Some),
682 )?;
683 Value::Array { dims, elements }
684 }
685 Type::Int2Vector { .. } => {
686 return Err("input of Int2Vector types is not implemented".into());
687 }
688 Type::Bool => Value::Bool(strconv::parse_bool(s)?),
689 Type::Bytea => Value::Bytea(strconv::parse_bytes(s)?),
690 Type::Char => Value::Char(raw.get(0).copied().unwrap_or(0)),
691 Type::Date => Value::Date(strconv::parse_date(s)?),
692 Type::Float4 => Value::Float4(strconv::parse_float32(s)?),
693 Type::Float8 => Value::Float8(strconv::parse_float64(s)?),
694 Type::Int2 => Value::Int2(strconv::parse_int16(s)?),
695 Type::Int4 => Value::Int4(strconv::parse_int32(s)?),
696 Type::Int8 => Value::Int8(strconv::parse_int64(s)?),
697 Type::UInt2 => Value::UInt2(UInt2(strconv::parse_uint16(s)?)),
698 Type::UInt4 => Value::UInt4(UInt4(strconv::parse_uint32(s)?)),
699 Type::UInt8 => Value::UInt8(UInt8(strconv::parse_uint64(s)?)),
700 Type::Interval { .. } => Value::Interval(Interval(strconv::parse_interval(s)?)),
701 Type::Json => return Err("input of json types is not implemented".into()),
702 Type::Jsonb => Value::Jsonb(Jsonb(strconv::parse_jsonb(s)?)),
703 Type::List(elem_type) => Value::List(strconv::parse_list(
704 s,
705 matches!(**elem_type, Type::List(..)),
706 || None,
707 |elem_text| Value::decode_text(elem_type, elem_text.as_bytes()).map(Some),
708 )?),
709 Type::Map { value_type } => Value::Map(strconv::parse_map(
710 s,
711 matches!(**value_type, Type::Map { .. }),
712 |elem_text| {
713 elem_text
714 .map(|t| Value::decode_text(value_type, t.as_bytes()))
715 .transpose()
716 },
717 )?),
718 Type::Name => Value::Name(strconv::parse_pg_legacy_name(s)),
719 Type::Numeric { constraints } => Value::Numeric(Numeric(rescale_numeric(
720 strconv::parse_numeric(s)?,
721 constraints.as_ref(),
722 )?)),
723 Type::Oid | Type::RegClass | Type::RegProc | Type::RegType => {
724 Value::Oid(strconv::parse_oid(s)?)
725 }
726 Type::Record(_) => {
727 return Err("input of anonymous composite types is not implemented".into());
728 }
729 Type::Text => Value::Text(s.to_owned()),
730 Type::BpChar { .. } => Value::BpChar(s.to_owned()),
731 Type::VarChar { .. } => Value::VarChar(s.to_owned()),
732 Type::Time { .. } => Value::Time(strconv::parse_time(s)?),
733 Type::TimeTz { .. } => return Err("input of timetz types is not implemented".into()),
734 Type::Timestamp { .. } => Value::Timestamp(strconv::parse_timestamp(s)?),
735 Type::TimestampTz { .. } => Value::TimestampTz(strconv::parse_timestamptz(s)?),
736 Type::Uuid => Value::Uuid(strconv::parse_uuid(s)?),
737 Type::MzTimestamp => Value::MzTimestamp(strconv::parse_mz_timestamp(s)?),
738 Type::Range { element_type } => Value::Range(strconv::parse_range(s, |elem_text| {
739 Value::decode_text(element_type, elem_text.as_bytes()).map(Box::new)
740 })?),
741 Type::MzAclItem => Value::MzAclItem(strconv::parse_mz_acl_item(s)?),
742 Type::AclItem => Value::AclItem(strconv::parse_acl_item(s)?),
743 })
744 }
745
746 pub fn decode_text_into_row<'a>(
748 ty: &'a Type,
749 s: &'a str,
750 packer: &mut RowPacker,
751 ) -> Result<(), Box<dyn Error + Sync + Send>> {
752 reject_nul(s)?;
755 Ok(match ty {
756 Type::Array(elem_type) => {
757 let (elements, dims) =
758 strconv::parse_array(s, || None, |elem_text| Ok::<_, String>(Some(elem_text)))?;
759 unsafe {
761 packer.push_array_with_unchecked(&dims, |packer| {
762 let mut nelements = 0;
763 for element in elements {
764 match element {
765 Some(elem_text) => {
766 Value::decode_text_into_row(elem_type, &elem_text, packer)?
767 }
768
769 None => packer.push(Datum::Null),
770 }
771 nelements += 1;
772 }
773 Ok::<_, Box<dyn Error + Sync + Send>>(nelements)
774 })?
775 }
776 }
777 Type::Int2Vector { .. } => {
778 return Err("input of Int2Vector types is not implemented".into());
779 }
780 Type::Bool => packer.push(Datum::from(strconv::parse_bool(s)?)),
781 Type::Bytea => packer.push(Datum::Bytes(&strconv::parse_bytes(s)?)),
782 Type::Char => packer.push(Datum::UInt8(s.as_bytes().get(0).copied().unwrap_or(0))),
783 Type::Date => packer.push(Datum::Date(strconv::parse_date(s)?)),
784 Type::Float4 => packer.push(Datum::Float32(strconv::parse_float32(s)?.into())),
785 Type::Float8 => packer.push(Datum::Float64(strconv::parse_float64(s)?.into())),
786 Type::Int2 => packer.push(Datum::Int16(strconv::parse_int16(s)?)),
787 Type::Int4 => packer.push(Datum::Int32(strconv::parse_int32(s)?)),
788 Type::Int8 => packer.push(Datum::Int64(strconv::parse_int64(s)?)),
789 Type::UInt2 => packer.push(Datum::UInt16(strconv::parse_uint16(s)?)),
790 Type::UInt4 => packer.push(Datum::UInt32(strconv::parse_uint32(s)?)),
791 Type::UInt8 => packer.push(Datum::UInt64(strconv::parse_uint64(s)?)),
792 Type::Interval { .. } => packer.push(Datum::Interval(strconv::parse_interval(s)?)),
793 Type::Json => return Err("input of json types is not implemented".into()),
794 Type::Jsonb => packer.push(strconv::parse_jsonb(s)?.into_row().unpack_first()),
795 Type::List(elem_type) => {
796 let elems = strconv::parse_list(
797 s,
798 matches!(**elem_type, Type::List(..)),
799 || None,
800 |elem_text| Ok::<_, String>(Some(elem_text)),
801 )?;
802 packer.push_list_with(|packer| {
803 for elem in elems {
804 match elem {
805 Some(elem) => Value::decode_text_into_row(elem_type, &elem, packer)?,
806 None => packer.push(Datum::Null),
807 }
808 }
809 Ok::<_, Box<dyn Error + Sync + Send>>(())
810 })?;
811 }
812 Type::Map { value_type } => {
813 let map =
814 strconv::parse_map(s, matches!(**value_type, Type::Map { .. }), |elem_text| {
815 elem_text.map(Ok::<_, String>).transpose()
816 })?;
817 packer.push_dict_with(|row| {
818 for (k, v) in map {
819 row.push(Datum::String(&k));
820 match v {
821 Some(elem) => Value::decode_text_into_row(value_type, &elem, row)?,
822 None => row.push(Datum::Null),
823 }
824 }
825 Ok::<_, Box<dyn Error + Sync + Send>>(())
826 })?;
827 }
828 Type::Name => packer.push(Datum::String(&strconv::parse_pg_legacy_name(s))),
829 Type::Numeric { constraints } => packer.push(Datum::Numeric(rescale_numeric(
830 strconv::parse_numeric(s)?,
831 constraints.as_ref(),
832 )?)),
833 Type::Oid | Type::RegClass | Type::RegProc | Type::RegType => {
834 packer.push(Datum::UInt32(strconv::parse_oid(s)?))
835 }
836 Type::Record(_) => {
837 return Err("input of anonymous composite types is not implemented".into());
838 }
839 Type::Text => packer.push(Datum::String(s)),
840 Type::BpChar { .. } => packer.push(Datum::String(s.trim_end())),
841 Type::VarChar { .. } => packer.push(Datum::String(s)),
842 Type::Time { .. } => packer.push(Datum::Time(strconv::parse_time(s)?)),
843 Type::TimeTz { .. } => return Err("input of timetz types is not implemented".into()),
844 Type::Timestamp { .. } => packer.push(Datum::Timestamp(strconv::parse_timestamp(s)?)),
845 Type::TimestampTz { .. } => {
846 packer.push(Datum::TimestampTz(strconv::parse_timestamptz(s)?))
847 }
848 Type::Uuid => packer.push(Datum::Uuid(strconv::parse_uuid(s)?)),
849 Type::MzTimestamp => packer.push(Datum::MzTimestamp(strconv::parse_mz_timestamp(s)?)),
850 Type::Range { element_type } => {
851 let range = strconv::parse_range(s, |elem_text| {
852 Value::decode_text(element_type, elem_text.as_bytes()).map(Box::new)
853 })?;
854 let buf = RowArena::new();
857 let range = range
858 .try_into_bounds(|elem| elem.into_datum(&buf, element_type))
859 .map_err(Box::<dyn Error + Sync + Send>::from)?;
860 packer
861 .push_range(range)
862 .map_err(Box::<dyn Error + Sync + Send>::from)?;
863 }
864 Type::MzAclItem => packer.push(Datum::MzAclItem(strconv::parse_mz_acl_item(s)?)),
865 Type::AclItem => packer.push(Datum::AclItem(strconv::parse_acl_item(s)?)),
866 })
867 }
868
869 pub fn decode_binary(ty: &Type, raw: &[u8]) -> Result<Value, Box<dyn Error + Sync + Send>> {
872 match ty {
873 Type::Array(_) => Err("input of array types is not implemented".into()),
874 Type::Int2Vector => Err("input of int2vector types is not implemented".into()),
875 Type::Bool => bool::from_sql(ty.inner(), raw).map(Value::Bool),
876 Type::Bytea => Vec::<u8>::from_sql(ty.inner(), raw).map(Value::Bytea),
877 Type::Char => {
878 i8::from_sql(ty.inner(), raw).map(|c| Value::Char(u8::reinterpret_cast(c)))
879 }
880 Type::Date => {
881 let days = i32::from_sql(ty.inner(), raw)?;
882 Ok(Value::Date(Date::from_pg_epoch(days)?))
883 }
884 Type::Float4 => f32::from_sql(ty.inner(), raw).map(Value::Float4),
885 Type::Float8 => f64::from_sql(ty.inner(), raw).map(Value::Float8),
886 Type::Int2 => i16::from_sql(ty.inner(), raw).map(Value::Int2),
887 Type::Int4 => i32::from_sql(ty.inner(), raw).map(Value::Int4),
888 Type::Int8 => i64::from_sql(ty.inner(), raw).map(Value::Int8),
889 Type::UInt2 => UInt2::from_sql(ty.inner(), raw).map(Value::UInt2),
890 Type::UInt4 => UInt4::from_sql(ty.inner(), raw).map(Value::UInt4),
891 Type::UInt8 => UInt8::from_sql(ty.inner(), raw).map(Value::UInt8),
892 Type::Interval { .. } => Interval::from_sql(ty.inner(), raw).map(Value::Interval),
893 Type::Json => Err("input of json types is not implemented".into()),
894 Type::Jsonb => Jsonb::from_sql(ty.inner(), raw).map(Value::Jsonb),
895 Type::List(_) => Err("binary decoding of list types is not implemented".into()),
896 Type::Map { .. } => Err("binary decoding of map types is not implemented".into()),
897 Type::Name => {
898 let s = String::from_sql(ty.inner(), raw)?;
899 reject_nul(&s)?;
900 if s.len() > NAME_MAX_BYTES {
901 return Err("identifier too long".into());
902 }
903 Ok(Value::Name(s))
904 }
905 Type::Numeric { constraints } => {
906 let n = Numeric::from_sql(ty.inner(), raw)?;
907 Ok(Value::Numeric(Numeric(rescale_numeric(
908 n.0,
909 constraints.as_ref(),
910 )?)))
911 }
912 Type::Oid | Type::RegClass | Type::RegProc | Type::RegType => {
913 u32::from_sql(ty.inner(), raw).map(Value::Oid)
914 }
915 Type::Record(_) => Err("input of anonymous composite types is not implemented".into()),
916 Type::Text => decode_binary_string(ty, raw).map(Value::Text),
917 Type::BpChar { .. } => decode_binary_string(ty, raw).map(Value::BpChar),
918 Type::VarChar { .. } => decode_binary_string(ty, raw).map(Value::VarChar),
919 Type::Time { .. } => NaiveTime::from_sql(ty.inner(), raw).map(Value::Time),
920 Type::TimeTz { .. } => Err("input of timetz types is not implemented".into()),
921 Type::Timestamp { .. } => {
922 let ts = NaiveDateTime::from_sql(ty.inner(), raw)?;
923 Ok(Value::Timestamp(CheckedTimestamp::from_timestamplike(ts)?))
924 }
925 Type::TimestampTz { .. } => {
926 let ts = DateTime::<Utc>::from_sql(ty.inner(), raw)?;
927 Ok(Value::TimestampTz(CheckedTimestamp::from_timestamplike(
928 ts,
929 )?))
930 }
931 Type::Uuid => Uuid::from_sql(ty.inner(), raw).map(Value::Uuid),
932 Type::MzTimestamp => {
933 let s = String::from_sql(ty.inner(), raw)?;
934 let t: mz_repr::Timestamp = s.parse()?;
935 Ok(Value::MzTimestamp(t))
936 }
937 Type::Range { .. } => Err("binary decoding of range types is not implemented".into()),
938 Type::MzAclItem => {
939 let mz_acl_item = MzAclItem::decode_binary(raw)?;
940 Ok(Value::MzAclItem(mz_acl_item))
941 }
942 Type::AclItem => Err("aclitem has no binary encoding".into()),
943 }
944 }
945}
946
947fn reject_nul(s: &str) -> Result<(), Box<dyn Error + Sync + Send>> {
950 if s.contains('\0') {
951 Err(Box::new(NulCharacterError))
952 } else {
953 Ok(())
954 }
955}
956
957fn decode_binary_string(ty: &Type, raw: &[u8]) -> Result<String, Box<dyn Error + Sync + Send>> {
959 let s = String::from_sql(ty.inner(), raw)?;
960 reject_nul(&s)?;
961 Ok(s)
962}
963
964fn rescale_numeric(
966 mut n: OrderedDecimal<mz_repr_numeric::Numeric>,
967 constraints: Option<&NumericConstraints>,
968) -> Result<OrderedDecimal<mz_repr_numeric::Numeric>, Box<dyn Error + Sync + Send>> {
969 if let Some(constraints) = constraints {
970 rescale(
971 &mut n.0,
972 NumericMaxScale::try_from(i64::from(constraints.max_scale()))?.into_u8(),
973 )?;
974 }
975 Ok(n)
976}
977
978fn encode_element(buf: &mut BytesMut, elem: Option<&Value>, ty: &Type) -> Result<(), io::Error> {
979 match elem {
980 None => buf.put_i32(-1),
981 Some(elem) => {
982 let base = buf.len();
983 buf.put_i32(0);
984 elem.encode_binary(ty, buf)?;
985 let len = pg_len("encoded element", buf.len() - base - 4)?;
986 buf[base..base + 4].copy_from_slice(&len.to_be_bytes());
987 }
988 }
989 Ok(())
990}
991
992fn pg_len(what: &str, len: usize) -> Result<i32, io::Error> {
993 len.try_into().map_err(|_| {
994 io::Error::new(
995 io::ErrorKind::InvalidData,
996 format!("{} does not fit into an i32", what),
997 )
998 })
999}
1000
1001pub fn values_from_row(row: &RowRef, typ: &SqlRelationType) -> Vec<Option<Value>> {
1006 row.iter()
1007 .zip_eq(typ.column_types.iter())
1008 .map(|(col, typ)| Value::from_datum(col, &typ.scalar_type))
1009 .collect()
1010}
1011
1012#[cfg(test)]
1013mod tests {
1014 use mz_repr::arb_datum_for_scalar;
1015 use proptest::prelude::*;
1016
1017 use super::*;
1018
1019 #[mz_ore::test]
1027 #[cfg_attr(miri, ignore)] fn proptest_binary_encoding_error_matches_encode_binary() {
1029 let strat =
1030 any::<SqlScalarType>().prop_flat_map(|ty| (Just(ty.clone()), arb_datum_for_scalar(ty)));
1031 proptest!(ProptestConfig::with_cases(256), |((ty, prop_datum) in strat)| {
1032 if Value::binary_encoding_error(&ty).is_err() {
1036 return Ok(());
1037 }
1038 let datum = Datum::from(&prop_datum);
1039 let value = match Value::from_datum(datum, &ty) {
1040 Some(v) => v,
1041 None => return Ok(()),
1043 };
1044 let pg_ty = Type::from(&ty);
1045 let mut buf = BytesMut::new();
1046 value
1047 .encode_binary(&pg_ty, &mut buf)
1048 .expect("encode_binary must succeed when binary_encoding_error returns Ok");
1049 });
1050 }
1051
1052 #[mz_ore::test]
1054 fn decode_text_error_smoke_test() {
1055 let bool_array = Value::Array {
1056 dims: vec![ArrayDimension {
1057 lower_bound: 0,
1058 length: 1,
1059 }],
1060 elements: vec![Some(Value::Bool(true))],
1061 };
1062
1063 let mut buf = BytesMut::new();
1064 bool_array.encode_text(&mut buf);
1065 let buf = buf.to_vec();
1066
1067 let int_array_tpe = Type::Array(Box::new(Type::Int4));
1068 let decoded_int_array = Value::decode_text(&int_array_tpe, &buf);
1069
1070 assert_eq!(
1071 decoded_int_array.map_err(|e| e.to_string()).unwrap_err(),
1072 "invalid input syntax for type array: Specifying array lower bounds is not supported: \"[0:0]={t}\"".to_string()
1073 );
1074 }
1075
1076 #[mz_ore::test]
1082 #[cfg_attr(miri, ignore)] fn decode_numeric_applies_destination_scale() {
1084 let ty = Type::from(&SqlScalarType::Numeric {
1086 max_scale: Some(NumericMaxScale::try_from(2_i64).unwrap()),
1087 });
1088 let expected = strconv::parse_numeric("10.45").unwrap();
1089
1090 let input = Value::Numeric(Numeric(strconv::parse_numeric("10.447").unwrap()));
1093 let mut buf = BytesMut::new();
1094 input
1095 .encode_binary(&ty, &mut buf)
1096 .expect("encoding 10.447 as numeric must succeed");
1097 let Value::Numeric(Numeric(binary)) = Value::decode_binary(&ty, &buf).unwrap() else {
1098 panic!("decode_binary of a numeric must yield Value::Numeric");
1099 };
1100 assert_eq!(binary, expected, "binary decode did not rescale to scale 2");
1101
1102 let Value::Numeric(Numeric(text)) = Value::decode_text(&ty, b"10.447").unwrap() else {
1104 panic!("decode_text of a numeric must yield Value::Numeric");
1105 };
1106 assert_eq!(text, expected, "text decode did not rescale to scale 2");
1107 }
1108
1109 #[mz_ore::test]
1111 fn decode_rejects_nul_in_strings() {
1112 const NUL_ERR: &str = "invalid byte sequence for encoding \"UTF8\": 0x00";
1113 let raw = b"foo\x00bar";
1114
1115 for ty in [
1116 Type::Text,
1117 Type::BpChar { length: None },
1118 Type::VarChar { max_length: None },
1119 Type::Name,
1120 ] {
1121 for format in [Format::Text, Format::Binary] {
1122 let res = Value::decode(format, &ty, raw);
1123 assert_eq!(
1124 res.map(|_| ()).map_err(|e| e.to_string()).unwrap_err(),
1125 NUL_ERR,
1126 "{ty:?} in {format:?} format must reject NUL",
1127 );
1128 }
1129 }
1130
1131 let res = Value::decode_text(&Type::Bytea, b"\\x00\x00");
1133 assert_eq!(
1134 res.map(|_| ()).map_err(|e| e.to_string()).unwrap_err(),
1135 NUL_ERR,
1136 );
1137
1138 let Value::Text(s) = Value::decode(Format::Binary, &Type::Text, b"foobar").unwrap() else {
1140 panic!("decoding a text value must yield Value::Text");
1141 };
1142 assert_eq!(s, "foobar");
1143 }
1144}