mz_repr/
scalar.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::collections::BTreeMap;
11use std::fmt::{self, Debug};
12use std::hash::Hash;
13use std::iter;
14use std::ops::Add;
15use std::sync::LazyLock;
16
17use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
18use dec::OrderedDecimal;
19use enum_kinds::EnumKind;
20use itertools::Itertools;
21use mz_lowertest::MzReflect;
22use mz_ore::Overflowing;
23use mz_ore::cast::CastFrom;
24use mz_ore::str::StrExt;
25use mz_proto::{IntoRustIfSome, ProtoType, RustType, TryFromProtoError};
26use ordered_float::OrderedFloat;
27use proptest::prelude::*;
28use proptest::strategy::Union;
29use serde::{Deserialize, Serialize};
30use uuid::Uuid;
31
32use crate::adt::array::{Array, ArrayDimension};
33use crate::adt::char::{Char, CharLength};
34use crate::adt::date::Date;
35use crate::adt::interval::Interval;
36use crate::adt::jsonb::{Jsonb, JsonbRef};
37use crate::adt::mz_acl_item::{AclItem, AclMode, MzAclItem};
38use crate::adt::numeric::{Numeric, NumericMaxScale};
39use crate::adt::pg_legacy_name::PgLegacyName;
40use crate::adt::range::{Range, RangeLowerBound, RangeUpperBound};
41use crate::adt::system::{Oid, PgLegacyChar, RegClass, RegProc, RegType};
42use crate::adt::timestamp::{
43    CheckedTimestamp, HIGH_DATE, LOW_DATE, TimestampError, TimestampPrecision,
44};
45use crate::adt::varchar::{VarChar, VarCharMaxLength};
46pub use crate::relation_and_scalar::ProtoScalarType;
47pub use crate::relation_and_scalar::proto_scalar_type::ProtoRecordField;
48use crate::role_id::RoleId;
49use crate::row::DatumNested;
50use crate::{CatalogItemId, ColumnName, ColumnType, DatumList, DatumMap, Row, RowArena};
51
52/// A single value.
53///
54/// # Notes
55///
56/// ## Equality
57/// `Datum` must always derive [`Eq`] to enforce equality with `repr::Row`.
58///
59/// ## `Datum`-containing types
60/// Because Rust disallows recursive enums, complex types which need to contain
61/// other `Datum`s instead store bytes representing that data in other structs,
62/// usually prefixed with `Datum` (e.g. `DatumList`). These types perform a form
63/// of ad-hoc deserialization of their inner bytes to `Datum`s via
64/// `crate::row::read_datum`.
65///
66/// To create a new instance of a `Datum`-referencing `Datum`, you need to store
67/// the inner `Datum`'s bytes in a row (so you can in turn borrow those bytes in
68/// the outer `Datum`). The idiom we've devised for this is a series of
69/// functions on `repr::row::RowPacker` prefixed with `push_`.
70///
71#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, EnumKind)]
72#[enum_kind(DatumKind)]
73pub enum Datum<'a> {
74    /// The `false` boolean value.
75    False,
76    /// The `true` boolean value.
77    True,
78    /// A 16-bit signed integer.
79    Int16(i16),
80    /// A 32-bit signed integer.
81    Int32(i32),
82    /// A 64-bit signed integer.
83    Int64(i64),
84    /// An 8-bit unsigned integer.
85    UInt8(u8),
86    /// An 16-bit unsigned integer.
87    UInt16(u16),
88    /// A 32-bit unsigned integer.
89    UInt32(u32),
90    /// A 64-bit unsigned integer.
91    UInt64(u64),
92    /// A 32-bit floating point number.
93    Float32(OrderedFloat<f32>),
94    /// A 64-bit floating point number.
95    Float64(OrderedFloat<f64>),
96    /// A date.
97    Date(Date),
98    /// A time.
99    Time(NaiveTime),
100    /// A date and time, without a timezone.
101    /// Note that this is not [`crate::Timestamp`]! That's in [`Datum::MzTimestamp`].
102    Timestamp(CheckedTimestamp<NaiveDateTime>),
103    /// A date and time, with a timezone.
104    TimestampTz(CheckedTimestamp<DateTime<Utc>>),
105    /// A span of time.
106    Interval(Interval),
107    /// A sequence of untyped bytes.
108    Bytes(&'a [u8]),
109    /// A sequence of Unicode codepoints encoded as UTF-8.
110    String(&'a str),
111    /// Unlike [`Datum::List`], arrays are like tensors and are not permitted to
112    /// be ragged.
113    Array(Array<'a>),
114    /// A sequence of `Datum`s.
115    ///
116    /// Unlike [`Datum::Array`], lists are permitted to be ragged.
117    List(DatumList<'a>),
118    /// A mapping from string keys to `Datum`s.
119    Map(DatumMap<'a>),
120    /// An exact decimal number, possibly with a fractional component, with up
121    /// to 39 digits of precision.
122    Numeric(OrderedDecimal<Numeric>),
123    /// An unknown value within a JSON-typed `Datum`.
124    ///
125    /// This variant is distinct from [`Datum::Null`] as a null datum is
126    /// distinct from a non-null datum that contains the JSON value `null`.
127    JsonNull,
128    /// A universally unique identifier.
129    Uuid(Uuid),
130    MzTimestamp(crate::Timestamp),
131    /// A range of values, e.g. [-1, 1).
132    Range(Range<DatumNested<'a>>),
133    /// A list of privileges granted to a user, that uses [`RoleId`]s for role
134    /// references.
135    MzAclItem(MzAclItem),
136    /// A list of privileges granted to a user that uses [`Oid`]s for role references.
137    /// This type is used primarily for compatibility with PostgreSQL.
138    AclItem(AclItem),
139    /// A placeholder value.
140    ///
141    /// Dummy values are never meant to be observed. Many operations on `Datum`
142    /// panic if called on this variant.
143    ///
144    /// Dummies are useful as placeholders in e.g. a `Vec<Datum>`, where it is
145    /// known that a certain element of the vector is never observed and
146    /// therefore needn't be computed, but where *some* `Datum` must still be
147    /// provided to maintain the shape of the vector. While any valid datum
148    /// could be used for this purpose, having a dedicated variant makes it
149    /// obvious when these optimizations have gone awry. If we used e.g.
150    /// `Datum::Null`, an unexpected `Datum::Null` could indicate any number of
151    /// problems: bad user data, bad function metadata, or a bad optimization.
152    ///
153    // TODO(benesch): get rid of this variant. With a more capable optimizer, I
154    // don't think there would be any need for dummy datums.
155    Dummy,
156    // Keep `Null` last so that calling `<` on Datums sorts nulls last, to
157    // match the default in PostgreSQL. Note that this doesn't have an effect
158    // on ORDER BY, because that is handled by compare_columns. The only
159    // situation it has an effect is array comparisons, e.g.,
160    // `SELECT ARRAY[1] < ARRAY[NULL]::int[]`. In such a situation, we end up
161    // calling `<` on Datums (see `fn lt` in scalar/func.rs).
162    /// An unknown value.
163    Null,
164    // WARNING! DON'T PLACE NEW DATUM VARIANTS HERE!
165    //
166    // This order of variants of this enum determines how nulls sort. We
167    // have decided that nulls should sort last in Materialize, so all
168    // other datum variants should appear before `Null`.
169}
170
171impl TryFrom<Datum<'_>> for bool {
172    type Error = ();
173
174    #[inline]
175    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
176        match from {
177            Datum::False => Ok(false),
178            Datum::True => Ok(true),
179            _ => Err(()),
180        }
181    }
182}
183
184impl TryFrom<Datum<'_>> for Option<bool> {
185    type Error = ();
186
187    #[inline]
188    fn try_from(datum: Datum<'_>) -> Result<Self, Self::Error> {
189        match datum {
190            Datum::Null => Ok(None),
191            Datum::False => Ok(Some(false)),
192            Datum::True => Ok(Some(true)),
193            _ => Err(()),
194        }
195    }
196}
197
198impl TryFrom<Datum<'_>> for f32 {
199    type Error = ();
200
201    #[inline]
202    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
203        match from {
204            Datum::Float32(f) => Ok(*f),
205            _ => Err(()),
206        }
207    }
208}
209
210impl TryFrom<Datum<'_>> for Option<f32> {
211    type Error = ();
212
213    #[inline]
214    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
215        match from {
216            Datum::Null => Ok(None),
217            Datum::Float32(f) => Ok(Some(*f)),
218            _ => Err(()),
219        }
220    }
221}
222
223impl TryFrom<Datum<'_>> for OrderedFloat<f32> {
224    type Error = ();
225
226    #[inline]
227    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
228        match from {
229            Datum::Float32(f) => Ok(f),
230            _ => Err(()),
231        }
232    }
233}
234
235impl TryFrom<Datum<'_>> for Option<OrderedFloat<f32>> {
236    type Error = ();
237
238    #[inline]
239    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
240        match from {
241            Datum::Null => Ok(None),
242            Datum::Float32(f) => Ok(Some(f)),
243            _ => Err(()),
244        }
245    }
246}
247
248impl TryFrom<Datum<'_>> for f64 {
249    type Error = ();
250
251    #[inline]
252    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
253        match from {
254            Datum::Float64(f) => Ok(*f),
255            _ => Err(()),
256        }
257    }
258}
259
260impl TryFrom<Datum<'_>> for Option<f64> {
261    type Error = ();
262
263    #[inline]
264    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
265        match from {
266            Datum::Null => Ok(None),
267            Datum::Float64(f) => Ok(Some(*f)),
268            _ => Err(()),
269        }
270    }
271}
272
273impl TryFrom<Datum<'_>> for OrderedFloat<f64> {
274    type Error = ();
275
276    #[inline]
277    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
278        match from {
279            Datum::Float64(f) => Ok(f),
280            _ => Err(()),
281        }
282    }
283}
284
285impl TryFrom<Datum<'_>> for Option<OrderedFloat<f64>> {
286    type Error = ();
287
288    #[inline]
289    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
290        match from {
291            Datum::Null => Ok(None),
292            Datum::Float64(f) => Ok(Some(f)),
293            _ => Err(()),
294        }
295    }
296}
297
298impl TryFrom<Datum<'_>> for i16 {
299    type Error = ();
300
301    #[inline]
302    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
303        match from {
304            Datum::Int16(i) => Ok(i),
305            _ => Err(()),
306        }
307    }
308}
309
310impl TryFrom<Datum<'_>> for Option<i16> {
311    type Error = ();
312
313    #[inline]
314    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
315        match from {
316            Datum::Null => Ok(None),
317            Datum::Int16(i) => Ok(Some(i)),
318            _ => Err(()),
319        }
320    }
321}
322
323impl TryFrom<Datum<'_>> for i32 {
324    type Error = ();
325
326    #[inline]
327    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
328        match from {
329            Datum::Int32(i) => Ok(i),
330            _ => Err(()),
331        }
332    }
333}
334
335impl TryFrom<Datum<'_>> for Option<i32> {
336    type Error = ();
337
338    #[inline]
339    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
340        match from {
341            Datum::Null => Ok(None),
342            Datum::Int32(i) => Ok(Some(i)),
343            _ => Err(()),
344        }
345    }
346}
347
348impl TryFrom<Datum<'_>> for i64 {
349    type Error = ();
350
351    #[inline]
352    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
353        match from {
354            Datum::Int64(i) => Ok(i),
355            _ => Err(()),
356        }
357    }
358}
359
360impl TryFrom<Datum<'_>> for Option<i64> {
361    type Error = ();
362
363    #[inline]
364    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
365        match from {
366            Datum::Null => Ok(None),
367            Datum::Int64(i) => Ok(Some(i)),
368            _ => Err(()),
369        }
370    }
371}
372
373impl TryFrom<Datum<'_>> for u16 {
374    type Error = ();
375
376    #[inline]
377    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
378        match from {
379            Datum::UInt16(u) => Ok(u),
380            _ => Err(()),
381        }
382    }
383}
384
385impl TryFrom<Datum<'_>> for Option<u16> {
386    type Error = ();
387
388    #[inline]
389    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
390        match from {
391            Datum::Null => Ok(None),
392            Datum::UInt16(u) => Ok(Some(u)),
393            _ => Err(()),
394        }
395    }
396}
397
398impl TryFrom<Datum<'_>> for u32 {
399    type Error = ();
400
401    #[inline]
402    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
403        match from {
404            Datum::UInt32(u) => Ok(u),
405            _ => Err(()),
406        }
407    }
408}
409
410impl TryFrom<Datum<'_>> for Option<u32> {
411    type Error = ();
412
413    #[inline]
414    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
415        match from {
416            Datum::Null => Ok(None),
417            Datum::UInt32(u) => Ok(Some(u)),
418            _ => Err(()),
419        }
420    }
421}
422
423impl TryFrom<Datum<'_>> for u64 {
424    type Error = ();
425
426    #[inline]
427    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
428        match from {
429            Datum::UInt64(u) => Ok(u),
430            _ => Err(()),
431        }
432    }
433}
434
435impl TryFrom<Datum<'_>> for Option<u64> {
436    type Error = ();
437
438    #[inline]
439    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
440        match from {
441            Datum::Null => Ok(None),
442            Datum::UInt64(u) => Ok(Some(u)),
443            _ => Err(()),
444        }
445    }
446}
447
448impl TryFrom<Datum<'_>> for CheckedTimestamp<NaiveDateTime> {
449    type Error = ();
450
451    #[inline]
452    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
453        match from {
454            Datum::Timestamp(dt) => Ok(dt),
455            _ => Err(()),
456        }
457    }
458}
459
460impl TryFrom<Datum<'_>> for CheckedTimestamp<DateTime<Utc>> {
461    type Error = ();
462
463    #[inline]
464    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
465        match from {
466            Datum::TimestampTz(dt_tz) => Ok(dt_tz),
467            _ => Err(()),
468        }
469    }
470}
471
472impl TryFrom<Datum<'_>> for Date {
473    type Error = ();
474
475    #[inline]
476    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
477        match from {
478            Datum::Date(d) => Ok(d),
479            _ => Err(()),
480        }
481    }
482}
483
484impl TryFrom<Datum<'_>> for OrderedDecimal<Numeric> {
485    type Error = ();
486
487    #[inline]
488    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
489        match from {
490            Datum::Numeric(n) => Ok(n),
491            _ => Err(()),
492        }
493    }
494}
495
496impl TryFrom<Datum<'_>> for Option<OrderedDecimal<Numeric>> {
497    type Error = ();
498
499    #[inline]
500    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
501        match from {
502            Datum::Null => Ok(None),
503            Datum::Numeric(n) => Ok(Some(n)),
504            _ => Err(()),
505        }
506    }
507}
508
509impl TryFrom<Datum<'_>> for crate::Timestamp {
510    type Error = ();
511
512    #[inline]
513    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
514        match from {
515            Datum::MzTimestamp(n) => Ok(n),
516            _ => Err(()),
517        }
518    }
519}
520
521impl TryFrom<Datum<'_>> for Option<crate::Timestamp> {
522    type Error = ();
523
524    #[inline]
525    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
526        match from {
527            Datum::Null => Ok(None),
528            Datum::MzTimestamp(n) => Ok(Some(n)),
529            _ => Err(()),
530        }
531    }
532}
533
534impl TryFrom<Datum<'_>> for Interval {
535    type Error = ();
536
537    #[inline]
538    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
539        match from {
540            Datum::Interval(i) => Ok(i),
541            _ => Err(()),
542        }
543    }
544}
545
546impl TryFrom<Datum<'_>> for Option<Interval> {
547    type Error = ();
548
549    #[inline]
550    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
551        match from {
552            Datum::Null => Ok(None),
553            Datum::Interval(i) => Ok(Some(i)),
554            _ => Err(()),
555        }
556    }
557}
558
559impl TryFrom<Datum<'_>> for NaiveTime {
560    type Error = ();
561
562    #[inline]
563    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
564        match from {
565            Datum::Time(t) => Ok(t),
566            _ => Err(()),
567        }
568    }
569}
570
571impl TryFrom<Datum<'_>> for Option<NaiveTime> {
572    type Error = ();
573
574    #[inline]
575    fn try_from(from: Datum<'_>) -> Result<Self, Self::Error> {
576        match from {
577            Datum::Null => Ok(None),
578            Datum::Time(t) => Ok(Some(t)),
579            _ => Err(()),
580        }
581    }
582}
583
584impl<'a> Datum<'a> {
585    /// Reports whether this datum is null (i.e., is [`Datum::Null`]).
586    pub fn is_null(&self) -> bool {
587        matches!(self, Datum::Null)
588    }
589
590    /// Unwraps the boolean value within this datum.
591    ///
592    /// # Panics
593    ///
594    /// Panics if the datum is not [`Datum::False`] or [`Datum::True`].
595    #[track_caller]
596    pub fn unwrap_bool(&self) -> bool {
597        match self {
598            Datum::False => false,
599            Datum::True => true,
600            _ => panic!("Datum::unwrap_bool called on {:?}", self),
601        }
602    }
603
604    /// Unwraps the 16-bit integer value within this datum.
605    ///
606    /// # Panics
607    ///
608    /// Panics if the datum is not [`Datum::Int16`].
609    #[track_caller]
610    pub fn unwrap_int16(&self) -> i16 {
611        match self {
612            Datum::Int16(i) => *i,
613            _ => panic!("Datum::unwrap_int16 called on {:?}", self),
614        }
615    }
616
617    /// Unwraps the 32-bit integer value within this datum.
618    ///
619    /// # Panics
620    ///
621    /// Panics if the datum is not [`Datum::Int32`].
622    #[track_caller]
623    pub fn unwrap_int32(&self) -> i32 {
624        match self {
625            Datum::Int32(i) => *i,
626            _ => panic!("Datum::unwrap_int32 called on {:?}", self),
627        }
628    }
629
630    /// Unwraps the 64-bit integer value within this datum.
631    ///
632    /// # Panics
633    ///
634    /// Panics if the datum is not [`Datum::Int64`].
635    #[track_caller]
636    pub fn unwrap_int64(&self) -> i64 {
637        match self {
638            Datum::Int64(i) => *i,
639            _ => panic!("Datum::unwrap_int64 called on {:?}", self),
640        }
641    }
642
643    /// Unwraps the 8-bit unsigned integer value within this datum.
644    ///
645    /// # Panics
646    ///
647    /// Panics if the datum is not [`Datum::UInt8`].
648    #[track_caller]
649    pub fn unwrap_uint8(&self) -> u8 {
650        match self {
651            Datum::UInt8(u) => *u,
652            _ => panic!("Datum::unwrap_uint8 called on {:?}", self),
653        }
654    }
655
656    /// Unwraps the 16-bit unsigned integer value within this datum.
657    ///
658    /// # Panics
659    ///
660    /// Panics if the datum is not [`Datum::UInt16`].
661    #[track_caller]
662    pub fn unwrap_uint16(&self) -> u16 {
663        match self {
664            Datum::UInt16(u) => *u,
665            _ => panic!("Datum::unwrap_uint16 called on {:?}", self),
666        }
667    }
668
669    /// Unwraps the 32-bit unsigned integer value within this datum.
670    ///
671    /// # Panics
672    ///
673    /// Panics if the datum is not [`Datum::UInt32`].
674    #[track_caller]
675    pub fn unwrap_uint32(&self) -> u32 {
676        match self {
677            Datum::UInt32(u) => *u,
678            _ => panic!("Datum::unwrap_uint32 called on {:?}", self),
679        }
680    }
681
682    /// Unwraps the 64-bit unsigned integer value within this datum.
683    ///
684    /// # Panics
685    ///
686    /// Panics if the datum is not [`Datum::UInt64`].
687    #[track_caller]
688    pub fn unwrap_uint64(&self) -> u64 {
689        match self {
690            Datum::UInt64(u) => *u,
691            _ => panic!("Datum::unwrap_uint64 called on {:?}", self),
692        }
693    }
694
695    #[track_caller]
696    pub fn unwrap_ordered_float32(&self) -> OrderedFloat<f32> {
697        match self {
698            Datum::Float32(f) => *f,
699            _ => panic!("Datum::unwrap_ordered_float32 called on {:?}", self),
700        }
701    }
702
703    #[track_caller]
704    pub fn unwrap_ordered_float64(&self) -> OrderedFloat<f64> {
705        match self {
706            Datum::Float64(f) => *f,
707            _ => panic!("Datum::unwrap_ordered_float64 called on {:?}", self),
708        }
709    }
710
711    /// Unwraps the 32-bit floating-point value within this datum.
712    ///
713    /// # Panics
714    ///
715    /// Panics if the datum is not [`Datum::Float32`].
716    #[track_caller]
717    pub fn unwrap_float32(&self) -> f32 {
718        match self {
719            Datum::Float32(f) => f.into_inner(),
720            _ => panic!("Datum::unwrap_float32 called on {:?}", self),
721        }
722    }
723
724    /// Unwraps the 64-bit floating-point value within this datum.
725    ///
726    /// # Panics
727    ///
728    /// Panics if the datum is not [`Datum::Float64`].
729    #[track_caller]
730    pub fn unwrap_float64(&self) -> f64 {
731        match self {
732            Datum::Float64(f) => f.into_inner(),
733            _ => panic!("Datum::unwrap_float64 called on {:?}", self),
734        }
735    }
736
737    /// Unwraps the date value within this datum.
738    ///
739    /// # Panics
740    ///
741    /// Panics if the datum is not [`Datum::Date`].
742    #[track_caller]
743    pub fn unwrap_date(&self) -> Date {
744        match self {
745            Datum::Date(d) => *d,
746            _ => panic!("Datum::unwrap_date called on {:?}", self),
747        }
748    }
749
750    /// Unwraps the time vaqlue within this datum.
751    ///
752    /// # Panics
753    ///
754    /// Panics if the datum is not [`Datum::Time`].
755    #[track_caller]
756    pub fn unwrap_time(&self) -> chrono::NaiveTime {
757        match self {
758            Datum::Time(t) => *t,
759            _ => panic!("Datum::unwrap_time called on {:?}", self),
760        }
761    }
762
763    /// Unwraps the timestamp value within this datum.
764    ///
765    /// # Panics
766    ///
767    /// Panics if the datum is not [`Datum::Timestamp`].
768    #[track_caller]
769    pub fn unwrap_timestamp(&self) -> CheckedTimestamp<chrono::NaiveDateTime> {
770        match self {
771            Datum::Timestamp(ts) => *ts,
772            _ => panic!("Datum::unwrap_timestamp called on {:?}", self),
773        }
774    }
775
776    /// Unwraps the timestamptz value within this datum.
777    ///
778    /// # Panics
779    ///
780    /// Panics if the datum is not [`Datum::TimestampTz`].
781    #[track_caller]
782    pub fn unwrap_timestamptz(&self) -> CheckedTimestamp<chrono::DateTime<Utc>> {
783        match self {
784            Datum::TimestampTz(ts) => *ts,
785            _ => panic!("Datum::unwrap_timestamptz called on {:?}", self),
786        }
787    }
788
789    /// Unwraps the interval value within this datum.
790    ///
791    /// # Panics
792    ///
793    /// Panics if the datum is not [`Datum::Interval`].
794    #[track_caller]
795    pub fn unwrap_interval(&self) -> Interval {
796        match self {
797            Datum::Interval(iv) => *iv,
798            _ => panic!("Datum::unwrap_interval called on {:?}", self),
799        }
800    }
801
802    /// Unwraps the string value within this datum.
803    ///
804    /// # Panics
805    ///
806    /// Panics if the datum is not [`Datum::String`].
807    #[track_caller]
808    pub fn unwrap_str(&self) -> &'a str {
809        match self {
810            Datum::String(s) => s,
811            _ => panic!("Datum::unwrap_string called on {:?}", self),
812        }
813    }
814
815    /// Unwraps the bytes value within this datum.
816    ///
817    /// # Panics
818    ///
819    /// Panics if the datum is not [`Datum::Bytes`].
820    #[track_caller]
821    pub fn unwrap_bytes(&self) -> &'a [u8] {
822        match self {
823            Datum::Bytes(b) => b,
824            _ => panic!("Datum::unwrap_bytes called on {:?}", self),
825        }
826    }
827
828    /// Unwraps the uuid value within this datum.
829    ///
830    /// # Panics
831    ///
832    /// Panics if the datum is not [`Datum::Uuid`].
833    #[track_caller]
834    pub fn unwrap_uuid(&self) -> Uuid {
835        match self {
836            Datum::Uuid(u) => *u,
837            _ => panic!("Datum::unwrap_uuid called on {:?}", self),
838        }
839    }
840
841    /// Unwraps the array value within this datum.
842    ///
843    /// # Panics
844    ///
845    /// Panics if the datum is not [`Datum::Array`].
846    #[track_caller]
847    pub fn unwrap_array(&self) -> Array<'a> {
848        match self {
849            Datum::Array(array) => *array,
850            _ => panic!("Datum::unwrap_array called on {:?}", self),
851        }
852    }
853
854    /// Unwraps the list value within this datum.
855    ///
856    /// # Panics
857    ///
858    /// Panics if the datum is not [`Datum::List`].
859    #[track_caller]
860    pub fn unwrap_list(&self) -> DatumList<'a> {
861        match self {
862            Datum::List(list) => *list,
863            _ => panic!("Datum::unwrap_list called on {:?}", self),
864        }
865    }
866
867    /// Unwraps the map value within this datum.
868    ///
869    /// # Panics
870    ///
871    /// Panics if the datum is not [`Datum::Map`].
872    #[track_caller]
873    pub fn unwrap_map(&self) -> DatumMap<'a> {
874        match self {
875            Datum::Map(dict) => *dict,
876            _ => panic!("Datum::unwrap_dict called on {:?}", self),
877        }
878    }
879
880    /// Unwraps the numeric value within this datum.
881    ///
882    /// # Panics
883    ///
884    /// Panics if the datum is not [`Datum::Numeric`].
885    #[track_caller]
886    pub fn unwrap_numeric(&self) -> OrderedDecimal<Numeric> {
887        match self {
888            Datum::Numeric(n) => *n,
889            _ => panic!("Datum::unwrap_numeric called on {:?}", self),
890        }
891    }
892
893    /// Unwraps the mz_repr::Timestamp value within this datum.
894    ///
895    /// # Panics
896    ///
897    /// Panics if the datum is not [`Datum::MzTimestamp`].
898    #[track_caller]
899    pub fn unwrap_mz_timestamp(&self) -> crate::Timestamp {
900        match self {
901            Datum::MzTimestamp(t) => *t,
902            _ => panic!("Datum::unwrap_mz_timestamp called on {:?}", self),
903        }
904    }
905
906    /// Unwraps the range value within this datum.
907    ///
908    /// Note that the return type is a range generic over `Datum`, which is
909    /// convenient to work with. However, the type stored in the datum is
910    /// generic over `DatumNested`, which is necessary to avoid needless boxing
911    /// of the inner `Datum`.
912    ///
913    /// # Panics
914    ///
915    /// Panics if the datum is not [`Datum::Range`].
916    #[track_caller]
917    pub fn unwrap_range(&self) -> Range<Datum<'a>> {
918        match self {
919            Datum::Range(range) => range.into_bounds(|b| b.datum()),
920            _ => panic!("Datum::unwrap_range called on {:?}", self),
921        }
922    }
923
924    /// Unwraps the mz_acl_item value within this datum.
925    ///
926    /// # Panics
927    ///
928    /// Panics if the datum is not [`Datum::MzAclItem`].
929    #[track_caller]
930    pub fn unwrap_mz_acl_item(&self) -> MzAclItem {
931        match self {
932            Datum::MzAclItem(mz_acl_item) => *mz_acl_item,
933            _ => panic!("Datum::unwrap_mz_acl_item called on {:?}", self),
934        }
935    }
936
937    /// Unwraps the acl_item value within this datum.
938    ///
939    /// # Panics
940    ///
941    /// Panics if the datum is not [`Datum::AclItem`].
942    #[track_caller]
943    pub fn unwrap_acl_item(&self) -> AclItem {
944        match self {
945            Datum::AclItem(acl_item) => *acl_item,
946            _ => panic!("Datum::unwrap_acl_item called on {:?}", self),
947        }
948    }
949
950    /// Reports whether this datum is an instance of the specified column type.
951    pub fn is_instance_of(self, column_type: &ColumnType) -> bool {
952        fn is_instance_of_scalar(datum: Datum, scalar_type: &ScalarType) -> bool {
953            if let ScalarType::Jsonb = scalar_type {
954                // json type checking
955                match datum {
956                    Datum::Dummy => panic!("Datum::Dummy observed"),
957                    Datum::JsonNull
958                    | Datum::False
959                    | Datum::True
960                    | Datum::Numeric(_)
961                    | Datum::String(_) => true,
962                    Datum::List(list) => list
963                        .iter()
964                        .all(|elem| is_instance_of_scalar(elem, scalar_type)),
965                    Datum::Map(dict) => dict
966                        .iter()
967                        .all(|(_key, val)| is_instance_of_scalar(val, scalar_type)),
968                    _ => false,
969                }
970            } else {
971                // sql type checking
972                match (datum, scalar_type) {
973                    (Datum::Dummy, _) => panic!("Datum::Dummy observed"),
974                    (Datum::Null, _) => false,
975                    (Datum::False, ScalarType::Bool) => true,
976                    (Datum::False, _) => false,
977                    (Datum::True, ScalarType::Bool) => true,
978                    (Datum::True, _) => false,
979                    (Datum::Int16(_), ScalarType::Int16) => true,
980                    (Datum::Int16(_), _) => false,
981                    (Datum::Int32(_), ScalarType::Int32) => true,
982                    (Datum::Int32(_), _) => false,
983                    (Datum::Int64(_), ScalarType::Int64) => true,
984                    (Datum::Int64(_), _) => false,
985                    (Datum::UInt8(_), ScalarType::PgLegacyChar) => true,
986                    (Datum::UInt8(_), _) => false,
987                    (Datum::UInt16(_), ScalarType::UInt16) => true,
988                    (Datum::UInt16(_), _) => false,
989                    (Datum::UInt32(_), ScalarType::Oid) => true,
990                    (Datum::UInt32(_), ScalarType::RegClass) => true,
991                    (Datum::UInt32(_), ScalarType::RegProc) => true,
992                    (Datum::UInt32(_), ScalarType::RegType) => true,
993                    (Datum::UInt32(_), ScalarType::UInt32) => true,
994                    (Datum::UInt32(_), _) => false,
995                    (Datum::UInt64(_), ScalarType::UInt64) => true,
996                    (Datum::UInt64(_), _) => false,
997                    (Datum::Float32(_), ScalarType::Float32) => true,
998                    (Datum::Float32(_), _) => false,
999                    (Datum::Float64(_), ScalarType::Float64) => true,
1000                    (Datum::Float64(_), _) => false,
1001                    (Datum::Date(_), ScalarType::Date) => true,
1002                    (Datum::Date(_), _) => false,
1003                    (Datum::Time(_), ScalarType::Time) => true,
1004                    (Datum::Time(_), _) => false,
1005                    (Datum::Timestamp(_), ScalarType::Timestamp { .. }) => true,
1006                    (Datum::Timestamp(_), _) => false,
1007                    (Datum::TimestampTz(_), ScalarType::TimestampTz { .. }) => true,
1008                    (Datum::TimestampTz(_), _) => false,
1009                    (Datum::Interval(_), ScalarType::Interval) => true,
1010                    (Datum::Interval(_), _) => false,
1011                    (Datum::Bytes(_), ScalarType::Bytes) => true,
1012                    (Datum::Bytes(_), _) => false,
1013                    (Datum::String(_), ScalarType::String)
1014                    | (Datum::String(_), ScalarType::VarChar { .. })
1015                    | (Datum::String(_), ScalarType::Char { .. })
1016                    | (Datum::String(_), ScalarType::PgLegacyName) => true,
1017                    (Datum::String(_), _) => false,
1018                    (Datum::Uuid(_), ScalarType::Uuid) => true,
1019                    (Datum::Uuid(_), _) => false,
1020                    (Datum::Array(array), ScalarType::Array(t)) => {
1021                        array.elements.iter().all(|e| match e {
1022                            Datum::Null => true,
1023                            _ => is_instance_of_scalar(e, t),
1024                        })
1025                    }
1026                    (Datum::Array(array), ScalarType::Int2Vector) => {
1027                        array.dims().len() == 1
1028                            && array
1029                                .elements
1030                                .iter()
1031                                .all(|e| is_instance_of_scalar(e, &ScalarType::Int16))
1032                    }
1033                    (Datum::Array(_), _) => false,
1034                    (Datum::List(list), ScalarType::List { element_type, .. }) => list
1035                        .iter()
1036                        .all(|e| e.is_null() || is_instance_of_scalar(e, element_type)),
1037                    (Datum::List(list), ScalarType::Record { fields, .. }) => {
1038                        list.iter().zip_eq(fields).all(|(e, (_, t))| {
1039                            (e.is_null() && t.nullable) || is_instance_of_scalar(e, &t.scalar_type)
1040                        })
1041                    }
1042                    (Datum::List(_), _) => false,
1043                    (Datum::Map(map), ScalarType::Map { value_type, .. }) => map
1044                        .iter()
1045                        .all(|(_k, v)| v.is_null() || is_instance_of_scalar(v, value_type)),
1046                    (Datum::Map(_), _) => false,
1047                    (Datum::JsonNull, _) => false,
1048                    (Datum::Numeric(_), ScalarType::Numeric { .. }) => true,
1049                    (Datum::Numeric(_), _) => false,
1050                    (Datum::MzTimestamp(_), ScalarType::MzTimestamp) => true,
1051                    (Datum::MzTimestamp(_), _) => false,
1052                    (Datum::Range(Range { inner }), ScalarType::Range { element_type }) => {
1053                        match inner {
1054                            None => true,
1055                            Some(inner) => {
1056                                true && match inner.lower.bound {
1057                                    None => true,
1058                                    Some(b) => is_instance_of_scalar(b.datum(), element_type),
1059                                } && match inner.upper.bound {
1060                                    None => true,
1061                                    Some(b) => is_instance_of_scalar(b.datum(), element_type),
1062                                }
1063                            }
1064                        }
1065                    }
1066                    (Datum::Range(_), _) => false,
1067                    (Datum::MzAclItem(_), ScalarType::MzAclItem) => true,
1068                    (Datum::MzAclItem(_), _) => false,
1069                    (Datum::AclItem(_), ScalarType::AclItem) => true,
1070                    (Datum::AclItem(_), _) => false,
1071                }
1072            }
1073        }
1074        if column_type.nullable {
1075            if let Datum::Null = self {
1076                return true;
1077            }
1078        }
1079        is_instance_of_scalar(self, &column_type.scalar_type)
1080    }
1081}
1082
1083impl<'a> From<bool> for Datum<'a> {
1084    #[inline]
1085    fn from(b: bool) -> Datum<'a> {
1086        if b { Datum::True } else { Datum::False }
1087    }
1088}
1089
1090// TODO: Reconsider whether we want this blanket impl or have precise control
1091//   over the types.
1092impl<'a, T> From<Overflowing<T>> for Datum<'a>
1093where
1094    Datum<'a>: From<T>,
1095{
1096    #[inline]
1097    fn from(i: Overflowing<T>) -> Datum<'a> {
1098        Datum::from(i.into_inner())
1099    }
1100}
1101
1102impl<'a> From<i16> for Datum<'a> {
1103    #[inline]
1104    fn from(i: i16) -> Datum<'a> {
1105        Datum::Int16(i)
1106    }
1107}
1108
1109impl<'a> From<i32> for Datum<'a> {
1110    #[inline]
1111    fn from(i: i32) -> Datum<'a> {
1112        Datum::Int32(i)
1113    }
1114}
1115
1116impl<'a> From<i64> for Datum<'a> {
1117    #[inline]
1118    fn from(i: i64) -> Datum<'a> {
1119        Datum::Int64(i)
1120    }
1121}
1122
1123impl<'a> From<u8> for Datum<'a> {
1124    #[inline]
1125    fn from(u: u8) -> Datum<'a> {
1126        Datum::UInt8(u)
1127    }
1128}
1129
1130impl<'a> From<u16> for Datum<'a> {
1131    #[inline]
1132    fn from(u: u16) -> Datum<'a> {
1133        Datum::UInt16(u)
1134    }
1135}
1136
1137impl<'a> From<u32> for Datum<'a> {
1138    #[inline]
1139    fn from(u: u32) -> Datum<'a> {
1140        Datum::UInt32(u)
1141    }
1142}
1143
1144impl<'a> From<u64> for Datum<'a> {
1145    #[inline]
1146    fn from(u: u64) -> Datum<'a> {
1147        Datum::UInt64(u)
1148    }
1149}
1150
1151impl<'a> From<OrderedFloat<f32>> for Datum<'a> {
1152    #[inline]
1153    fn from(f: OrderedFloat<f32>) -> Datum<'a> {
1154        Datum::Float32(f)
1155    }
1156}
1157
1158impl<'a> From<OrderedFloat<f64>> for Datum<'a> {
1159    #[inline]
1160    fn from(f: OrderedFloat<f64>) -> Datum<'a> {
1161        Datum::Float64(f)
1162    }
1163}
1164
1165impl<'a> From<f32> for Datum<'a> {
1166    #[inline]
1167    fn from(f: f32) -> Datum<'a> {
1168        Datum::Float32(OrderedFloat(f))
1169    }
1170}
1171
1172impl<'a> From<f64> for Datum<'a> {
1173    #[inline]
1174    fn from(f: f64) -> Datum<'a> {
1175        Datum::Float64(OrderedFloat(f))
1176    }
1177}
1178
1179impl<'a> From<i128> for Datum<'a> {
1180    #[inline]
1181    fn from(d: i128) -> Datum<'a> {
1182        Datum::Numeric(OrderedDecimal(Numeric::try_from(d).unwrap()))
1183    }
1184}
1185
1186impl<'a> From<u128> for Datum<'a> {
1187    #[inline]
1188    fn from(d: u128) -> Datum<'a> {
1189        Datum::Numeric(OrderedDecimal(Numeric::try_from(d).unwrap()))
1190    }
1191}
1192
1193impl<'a> From<Numeric> for Datum<'a> {
1194    #[inline]
1195    fn from(n: Numeric) -> Datum<'a> {
1196        Datum::Numeric(OrderedDecimal(n))
1197    }
1198}
1199
1200impl<'a> From<OrderedDecimal<Numeric>> for Datum<'a> {
1201    #[inline]
1202    fn from(n: OrderedDecimal<Numeric>) -> Datum<'a> {
1203        Datum::Numeric(n)
1204    }
1205}
1206
1207impl<'a> From<chrono::Duration> for Datum<'a> {
1208    #[inline]
1209    fn from(duration: chrono::Duration) -> Datum<'a> {
1210        let micros = duration.num_microseconds().unwrap_or(0);
1211        Datum::Interval(Interval::new(0, 0, micros))
1212    }
1213}
1214
1215impl<'a> From<Interval> for Datum<'a> {
1216    #[inline]
1217    fn from(other: Interval) -> Datum<'a> {
1218        Datum::Interval(other)
1219    }
1220}
1221
1222impl<'a> From<&'a str> for Datum<'a> {
1223    #[inline]
1224    fn from(s: &'a str) -> Datum<'a> {
1225        Datum::String(s)
1226    }
1227}
1228
1229impl<'a> From<&'a [u8]> for Datum<'a> {
1230    #[inline]
1231    fn from(b: &'a [u8]) -> Datum<'a> {
1232        Datum::Bytes(b)
1233    }
1234}
1235
1236impl<'a> From<Date> for Datum<'a> {
1237    #[inline]
1238    fn from(d: Date) -> Datum<'a> {
1239        Datum::Date(d)
1240    }
1241}
1242
1243impl<'a> From<NaiveTime> for Datum<'a> {
1244    #[inline]
1245    fn from(t: NaiveTime) -> Datum<'a> {
1246        Datum::Time(t)
1247    }
1248}
1249
1250impl<'a> From<CheckedTimestamp<NaiveDateTime>> for Datum<'a> {
1251    #[inline]
1252    fn from(dt: CheckedTimestamp<NaiveDateTime>) -> Datum<'a> {
1253        Datum::Timestamp(dt)
1254    }
1255}
1256
1257impl<'a> From<CheckedTimestamp<DateTime<Utc>>> for Datum<'a> {
1258    #[inline]
1259    fn from(dt: CheckedTimestamp<DateTime<Utc>>) -> Datum<'a> {
1260        Datum::TimestampTz(dt)
1261    }
1262}
1263
1264impl<'a> TryInto<Datum<'a>> for NaiveDateTime {
1265    type Error = TimestampError;
1266
1267    #[inline]
1268    fn try_into(self) -> Result<Datum<'a>, Self::Error> {
1269        let t = CheckedTimestamp::from_timestamplike(self)?;
1270        Ok(t.into())
1271    }
1272}
1273
1274impl<'a> TryInto<Datum<'a>> for DateTime<Utc> {
1275    type Error = TimestampError;
1276
1277    #[inline]
1278    fn try_into(self) -> Result<Datum<'a>, Self::Error> {
1279        let t = CheckedTimestamp::from_timestamplike(self)?;
1280        Ok(t.into())
1281    }
1282}
1283
1284impl<'a> From<Uuid> for Datum<'a> {
1285    #[inline]
1286    fn from(uuid: Uuid) -> Datum<'a> {
1287        Datum::Uuid(uuid)
1288    }
1289}
1290impl<'a> From<crate::Timestamp> for Datum<'a> {
1291    #[inline]
1292    fn from(ts: crate::Timestamp) -> Datum<'a> {
1293        Datum::MzTimestamp(ts)
1294    }
1295}
1296
1297impl<'a> From<MzAclItem> for Datum<'a> {
1298    #[inline]
1299    fn from(mz_acl_item: MzAclItem) -> Self {
1300        Datum::MzAclItem(mz_acl_item)
1301    }
1302}
1303
1304impl<'a, T> From<Option<T>> for Datum<'a>
1305where
1306    Datum<'a>: From<T>,
1307{
1308    fn from(o: Option<T>) -> Datum<'a> {
1309        match o {
1310            Some(d) => d.into(),
1311            None => Datum::Null,
1312        }
1313    }
1314}
1315
1316fn write_delimited<T, TS, F>(
1317    f: &mut fmt::Formatter,
1318    delimiter: &str,
1319    things: TS,
1320    write: F,
1321) -> fmt::Result
1322where
1323    TS: IntoIterator<Item = T>,
1324    F: Fn(&mut fmt::Formatter, T) -> fmt::Result,
1325{
1326    let mut iter = things.into_iter().peekable();
1327    while let Some(thing) = iter.next() {
1328        write(f, thing)?;
1329        if iter.peek().is_some() {
1330            f.write_str(delimiter)?;
1331        }
1332    }
1333    Ok(())
1334}
1335
1336impl fmt::Display for Datum<'_> {
1337    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1338        match self {
1339            Datum::Null => f.write_str("null"),
1340            Datum::True => f.write_str("true"),
1341            Datum::False => f.write_str("false"),
1342            Datum::Int16(num) => write!(f, "{}", num),
1343            Datum::Int32(num) => write!(f, "{}", num),
1344            Datum::Int64(num) => write!(f, "{}", num),
1345            Datum::UInt8(num) => write!(f, "{}", num),
1346            Datum::UInt16(num) => write!(f, "{}", num),
1347            Datum::UInt32(num) => write!(f, "{}", num),
1348            Datum::UInt64(num) => write!(f, "{}", num),
1349            Datum::Float32(num) => write!(f, "{}", num),
1350            Datum::Float64(num) => write!(f, "{}", num),
1351            Datum::Date(d) => write!(f, "{}", d),
1352            Datum::Time(t) => write!(f, "{}", t),
1353            Datum::Timestamp(t) => write!(f, "{}", t),
1354            Datum::TimestampTz(t) => write!(f, "{}", t),
1355            Datum::Interval(iv) => write!(f, "{}", iv),
1356            Datum::Bytes(dat) => {
1357                f.write_str("0x")?;
1358                for b in dat.iter() {
1359                    write!(f, "{:02x}", b)?;
1360                }
1361                Ok(())
1362            }
1363            Datum::String(s) => {
1364                write!(f, "{}", s.escaped())
1365            }
1366            Datum::Uuid(u) => write!(f, "{}", u),
1367            Datum::Array(array) => {
1368                if array.dims().into_iter().any(|dim| dim.lower_bound != 1) {
1369                    write_delimited(f, "", array.dims().into_iter(), |f, e| {
1370                        let (lower, upper) = e.dimension_bounds();
1371                        write!(f, "[{}:{}]", lower, upper)
1372                    })?;
1373                    f.write_str("=")?;
1374                }
1375                f.write_str("{")?;
1376                write_delimited(f, ", ", &array.elements, |f, e| write!(f, "{}", e))?;
1377                f.write_str("}")
1378            }
1379            Datum::List(list) => {
1380                f.write_str("[")?;
1381                write_delimited(f, ", ", list, |f, e| write!(f, "{}", e))?;
1382                f.write_str("]")
1383            }
1384            Datum::Map(dict) => {
1385                f.write_str("{")?;
1386                write_delimited(f, ", ", dict, |f, (k, v)| write!(f, "{}: {}", k, v))?;
1387                f.write_str("}")
1388            }
1389            Datum::Numeric(n) => write!(f, "{}", n.0.to_standard_notation_string()),
1390            Datum::MzTimestamp(t) => write!(f, "{}", t),
1391            Datum::JsonNull => f.write_str("json_null"),
1392            Datum::Dummy => f.write_str("dummy"),
1393            Datum::Range(i) => write!(f, "{}", i),
1394            Datum::MzAclItem(mz_acl_item) => write!(f, "{mz_acl_item}"),
1395            Datum::AclItem(acl_item) => write!(f, "{acl_item}"),
1396        }
1397    }
1398}
1399
1400/// The type of a [`Datum`].
1401///
1402/// There is a direct correspondence between `Datum` variants and `ScalarType`
1403/// variants.
1404#[derive(
1405    Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd, Hash, EnumKind, MzReflect,
1406)]
1407#[enum_kind(ScalarBaseType, derive(PartialOrd, Ord, Hash))]
1408pub enum ScalarType {
1409    /// The type of [`Datum::True`] and [`Datum::False`].
1410    Bool,
1411    /// The type of [`Datum::Int16`].
1412    Int16,
1413    /// The type of [`Datum::Int32`].
1414    Int32,
1415    /// The type of [`Datum::Int64`].
1416    Int64,
1417    /// The type of [`Datum::UInt16`].
1418    UInt16,
1419    /// The type of [`Datum::UInt32`].
1420    UInt32,
1421    /// The type of [`Datum::UInt64`].
1422    UInt64,
1423    /// The type of [`Datum::Float32`].
1424    Float32,
1425    /// The type of [`Datum::Float64`].
1426    Float64,
1427    /// The type of [`Datum::Numeric`].
1428    ///
1429    /// `Numeric` values cannot exceed [`NUMERIC_DATUM_MAX_PRECISION`] digits of
1430    /// precision.
1431    ///
1432    /// This type additionally specifies the maximum scale of the decimal. The
1433    /// scale specifies the number of digits after the decimal point.
1434    ///
1435    /// [`NUMERIC_DATUM_MAX_PRECISION`]: crate::adt::numeric::NUMERIC_DATUM_MAX_PRECISION
1436    Numeric {
1437        max_scale: Option<NumericMaxScale>,
1438    },
1439    /// The type of [`Datum::Date`].
1440    Date,
1441    /// The type of [`Datum::Time`].
1442    Time,
1443    /// The type of [`Datum::Timestamp`].
1444    Timestamp {
1445        precision: Option<TimestampPrecision>,
1446    },
1447    /// The type of [`Datum::TimestampTz`].
1448    TimestampTz {
1449        precision: Option<TimestampPrecision>,
1450    },
1451    /// The type of [`Datum::Interval`].
1452    Interval,
1453    /// A single byte character type backed by a [`Datum::UInt8`].
1454    ///
1455    /// PostgreSQL calls this type `"char"`. Note the quotes, which distinguish
1456    /// it from the type `ScalarType::Char`.
1457    PgLegacyChar,
1458    /// A character type for storing identifiers of no more than 64 characters
1459    /// in length.
1460    ///
1461    /// PostgreSQL uses this type to represent the names of objects in the
1462    /// system catalog.
1463    PgLegacyName,
1464    /// The type of [`Datum::Bytes`].
1465    Bytes,
1466    /// The type of [`Datum::String`].
1467    String,
1468    /// Stored as [`Datum::String`], but expresses a fixed-width, blank-padded
1469    /// string.
1470    ///
1471    /// Note that a `length` of `None` is used in special cases, such as
1472    /// creating lists.
1473    Char {
1474        length: Option<CharLength>,
1475    },
1476    /// Stored as [`Datum::String`], but can optionally express a limit on the
1477    /// string's length.
1478    VarChar {
1479        max_length: Option<VarCharMaxLength>,
1480    },
1481    /// The type of a datum that may represent any valid JSON value.
1482    ///
1483    /// Valid datum variants for this type are:
1484    ///
1485    ///   * [`Datum::JsonNull`]
1486    ///   * [`Datum::False`]
1487    ///   * [`Datum::True`]
1488    ///   * [`Datum::String`]
1489    ///   * [`Datum::Numeric`]
1490    ///   * [`Datum::List`]
1491    ///   * [`Datum::Map`]
1492    Jsonb,
1493    /// The type of [`Datum::Uuid`].
1494    Uuid,
1495    /// The type of [`Datum::Array`].
1496    ///
1497    /// Elements within the array are of the specified type. It is illegal for
1498    /// the element type to be itself an array type. Array elements may always
1499    /// be [`Datum::Null`].
1500    Array(Box<ScalarType>),
1501    /// The type of [`Datum::List`].
1502    ///
1503    /// Elements within the list are of the specified type. List elements may
1504    /// always be [`Datum::Null`].
1505    List {
1506        element_type: Box<ScalarType>,
1507        custom_id: Option<CatalogItemId>,
1508    },
1509    /// An ordered and named sequence of datums.
1510    Record {
1511        /// The names and types of the fields of the record, in order from left
1512        /// to right.
1513        ///
1514        /// Boxed slice to reduce the size of the enum variant.
1515        fields: Box<[(ColumnName, ColumnType)]>,
1516        custom_id: Option<CatalogItemId>,
1517    },
1518    /// A PostgreSQL object identifier.
1519    Oid,
1520    /// The type of [`Datum::Map`]
1521    ///
1522    /// Keys within the map are always of type [`ScalarType::String`].
1523    /// Values within the map are of the specified type. Values may always
1524    /// be [`Datum::Null`].
1525    Map {
1526        value_type: Box<ScalarType>,
1527        custom_id: Option<CatalogItemId>,
1528    },
1529    /// A PostgreSQL function name.
1530    RegProc,
1531    /// A PostgreSQL type name.
1532    RegType,
1533    /// A PostgreSQL class name.
1534    RegClass,
1535    /// A vector on small ints; this is a legacy type in PG used primarily in
1536    /// the catalog.
1537    Int2Vector,
1538    /// A Materialize timestamp. The type of [`Datum::MzTimestamp`].
1539    MzTimestamp,
1540    Range {
1541        element_type: Box<ScalarType>,
1542    },
1543    /// The type of [`Datum::MzAclItem`]
1544    MzAclItem,
1545    /// The type of [`Datum::AclItem`]
1546    AclItem,
1547}
1548
1549impl RustType<ProtoRecordField> for (ColumnName, ColumnType) {
1550    fn into_proto(&self) -> ProtoRecordField {
1551        ProtoRecordField {
1552            column_name: Some(self.0.into_proto()),
1553            column_type: Some(self.1.into_proto()),
1554        }
1555    }
1556
1557    fn from_proto(proto: ProtoRecordField) -> Result<Self, TryFromProtoError> {
1558        Ok((
1559            proto
1560                .column_name
1561                .into_rust_if_some("ProtoRecordField::column_name")?,
1562            proto
1563                .column_type
1564                .into_rust_if_some("ProtoRecordField::column_type")?,
1565        ))
1566    }
1567}
1568
1569impl RustType<ProtoScalarType> for ScalarType {
1570    fn into_proto(&self) -> ProtoScalarType {
1571        use crate::relation_and_scalar::proto_scalar_type::Kind::*;
1572        use crate::relation_and_scalar::proto_scalar_type::*;
1573
1574        ProtoScalarType {
1575            kind: Some(match self {
1576                ScalarType::Bool => Bool(()),
1577                ScalarType::Int16 => Int16(()),
1578                ScalarType::Int32 => Int32(()),
1579                ScalarType::Int64 => Int64(()),
1580                ScalarType::UInt16 => UInt16(()),
1581                ScalarType::UInt32 => UInt32(()),
1582                ScalarType::UInt64 => UInt64(()),
1583                ScalarType::Float32 => Float32(()),
1584                ScalarType::Float64 => Float64(()),
1585                ScalarType::Date => Date(()),
1586                ScalarType::Time => Time(()),
1587                ScalarType::Timestamp { precision } => Timestamp(ProtoTimestamp {
1588                    precision: precision.into_proto(),
1589                }),
1590                ScalarType::TimestampTz { precision } => TimestampTz(ProtoTimestampTz {
1591                    precision: precision.into_proto(),
1592                }),
1593                ScalarType::Interval => Interval(()),
1594                ScalarType::PgLegacyChar => PgLegacyChar(()),
1595                ScalarType::PgLegacyName => PgLegacyName(()),
1596                ScalarType::Bytes => Bytes(()),
1597                ScalarType::String => String(()),
1598                ScalarType::Jsonb => Jsonb(()),
1599                ScalarType::Uuid => Uuid(()),
1600                ScalarType::Oid => Oid(()),
1601                ScalarType::RegProc => RegProc(()),
1602                ScalarType::RegType => RegType(()),
1603                ScalarType::RegClass => RegClass(()),
1604                ScalarType::Int2Vector => Int2Vector(()),
1605
1606                ScalarType::Numeric { max_scale } => Numeric(max_scale.into_proto()),
1607                ScalarType::Char { length } => Char(ProtoChar {
1608                    length: length.into_proto(),
1609                }),
1610                ScalarType::VarChar { max_length } => VarChar(ProtoVarChar {
1611                    max_length: max_length.into_proto(),
1612                }),
1613
1614                ScalarType::List {
1615                    element_type,
1616                    custom_id,
1617                } => List(Box::new(ProtoList {
1618                    element_type: Some(element_type.into_proto()),
1619                    custom_id: custom_id.map(|id| id.into_proto()),
1620                })),
1621                ScalarType::Record { custom_id, fields } => Record(ProtoRecord {
1622                    custom_id: custom_id.map(|id| id.into_proto()),
1623                    fields: fields.into_proto(),
1624                }),
1625                ScalarType::Array(typ) => Array(typ.into_proto()),
1626                ScalarType::Map {
1627                    value_type,
1628                    custom_id,
1629                } => Map(Box::new(ProtoMap {
1630                    value_type: Some(value_type.into_proto()),
1631                    custom_id: custom_id.map(|id| id.into_proto()),
1632                })),
1633                ScalarType::MzTimestamp => MzTimestamp(()),
1634                ScalarType::Range { element_type } => Range(Box::new(ProtoRange {
1635                    element_type: Some(element_type.into_proto()),
1636                })),
1637                ScalarType::MzAclItem => MzAclItem(()),
1638                ScalarType::AclItem => AclItem(()),
1639            }),
1640        }
1641    }
1642
1643    fn from_proto(proto: ProtoScalarType) -> Result<Self, TryFromProtoError> {
1644        use crate::relation_and_scalar::proto_scalar_type::Kind::*;
1645
1646        let kind = proto
1647            .kind
1648            .ok_or_else(|| TryFromProtoError::missing_field("ProtoScalarType::Kind"))?;
1649
1650        match kind {
1651            Bool(()) => Ok(ScalarType::Bool),
1652            Int16(()) => Ok(ScalarType::Int16),
1653            Int32(()) => Ok(ScalarType::Int32),
1654            Int64(()) => Ok(ScalarType::Int64),
1655            UInt16(()) => Ok(ScalarType::UInt16),
1656            UInt32(()) => Ok(ScalarType::UInt32),
1657            UInt64(()) => Ok(ScalarType::UInt64),
1658            Float32(()) => Ok(ScalarType::Float32),
1659            Float64(()) => Ok(ScalarType::Float64),
1660            Date(()) => Ok(ScalarType::Date),
1661            Time(()) => Ok(ScalarType::Time),
1662            Timestamp(x) => Ok(ScalarType::Timestamp {
1663                precision: x.precision.into_rust()?,
1664            }),
1665            TimestampTz(x) => Ok(ScalarType::TimestampTz {
1666                precision: x.precision.into_rust()?,
1667            }),
1668            Interval(()) => Ok(ScalarType::Interval),
1669            PgLegacyChar(()) => Ok(ScalarType::PgLegacyChar),
1670            PgLegacyName(()) => Ok(ScalarType::PgLegacyName),
1671            Bytes(()) => Ok(ScalarType::Bytes),
1672            String(()) => Ok(ScalarType::String),
1673            Jsonb(()) => Ok(ScalarType::Jsonb),
1674            Uuid(()) => Ok(ScalarType::Uuid),
1675            Oid(()) => Ok(ScalarType::Oid),
1676            RegProc(()) => Ok(ScalarType::RegProc),
1677            RegType(()) => Ok(ScalarType::RegType),
1678            RegClass(()) => Ok(ScalarType::RegClass),
1679            Int2Vector(()) => Ok(ScalarType::Int2Vector),
1680
1681            Numeric(x) => Ok(ScalarType::Numeric {
1682                max_scale: x.into_rust()?,
1683            }),
1684            Char(x) => Ok(ScalarType::Char {
1685                length: x.length.into_rust()?,
1686            }),
1687
1688            VarChar(x) => Ok(ScalarType::VarChar {
1689                max_length: x.max_length.into_rust()?,
1690            }),
1691            Array(x) => Ok(ScalarType::Array({
1692                let st: ScalarType = (*x).into_rust()?;
1693                st.into()
1694            })),
1695            List(x) => Ok(ScalarType::List {
1696                element_type: Box::new(
1697                    x.element_type
1698                        .map(|x| *x)
1699                        .into_rust_if_some("ProtoList::element_type")?,
1700                ),
1701                custom_id: x.custom_id.map(|id| id.into_rust().unwrap()),
1702            }),
1703            Record(x) => Ok(ScalarType::Record {
1704                custom_id: x.custom_id.map(|id| id.into_rust().unwrap()),
1705                fields: x.fields.into_rust()?,
1706            }),
1707            Map(x) => Ok(ScalarType::Map {
1708                value_type: Box::new(
1709                    x.value_type
1710                        .map(|x| *x)
1711                        .into_rust_if_some("ProtoMap::value_type")?,
1712                ),
1713                custom_id: x.custom_id.map(|id| id.into_rust().unwrap()),
1714            }),
1715            MzTimestamp(()) => Ok(ScalarType::MzTimestamp),
1716            Range(x) => Ok(ScalarType::Range {
1717                element_type: Box::new(
1718                    x.element_type
1719                        .map(|x| *x)
1720                        .into_rust_if_some("ProtoRange::element_type")?,
1721                ),
1722            }),
1723            MzAclItem(()) => Ok(ScalarType::MzAclItem),
1724            AclItem(()) => Ok(ScalarType::AclItem),
1725        }
1726    }
1727}
1728
1729/// Types that implement this trait can be stored in an SQL column with the specified ColumnType
1730pub trait AsColumnType {
1731    /// The SQL column type of this Rust type
1732    fn as_column_type() -> ColumnType;
1733}
1734
1735/// A bridge between native Rust types and SQL runtime types represented in Datums
1736pub trait DatumType<'a, E>: Sized {
1737    /// Whether this Rust type can represent NULL values
1738    fn nullable() -> bool;
1739
1740    /// Whether this Rust type can represent errors
1741    fn fallible() -> bool;
1742
1743    /// Try to convert a Result whose Ok variant is a Datum into this native Rust type (Self). If
1744    /// it fails the error variant will contain the original result.
1745    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>>;
1746
1747    /// Convert this Rust type into a Result containing a Datum, or an error
1748    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E>;
1749}
1750
1751/// A new type that wraps a [`Vec`] that is used to differentiate the target [`Datum`] between
1752/// Arrays and Lists. The target of this type is Array.
1753#[derive(Debug)]
1754pub struct ArrayRustType<T>(pub Vec<T>);
1755
1756impl<B: AsColumnType> AsColumnType for Option<B> {
1757    fn as_column_type() -> ColumnType {
1758        B::as_column_type().nullable(true)
1759    }
1760}
1761
1762impl<'a, E, B: DatumType<'a, E>> DatumType<'a, E> for Option<B> {
1763    fn nullable() -> bool {
1764        true
1765    }
1766    fn fallible() -> bool {
1767        false
1768    }
1769    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1770        match res {
1771            Ok(Datum::Null) => Ok(None),
1772            Ok(datum) => B::try_from_result(Ok(datum)).map(Some),
1773            _ => Err(res),
1774        }
1775    }
1776    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1777        match self {
1778            Some(inner) => inner.into_result(temp_storage),
1779            None => Ok(Datum::Null),
1780        }
1781    }
1782}
1783
1784impl<E, B: AsColumnType> AsColumnType for Result<B, E> {
1785    fn as_column_type() -> ColumnType {
1786        B::as_column_type()
1787    }
1788}
1789
1790impl<'a, E, B: DatumType<'a, E>> DatumType<'a, E> for Result<B, E> {
1791    fn nullable() -> bool {
1792        B::nullable()
1793    }
1794    fn fallible() -> bool {
1795        true
1796    }
1797    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1798        B::try_from_result(res).map(Ok)
1799    }
1800    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1801        self.and_then(|inner| inner.into_result(temp_storage))
1802    }
1803}
1804
1805/// Macro to derive DatumType for all Datum variants that are simple Copy types
1806macro_rules! impl_datum_type_copy {
1807    ($lt:lifetime, $native:ty, $variant:ident) => {
1808        impl<$lt> AsColumnType for $native {
1809            fn as_column_type() -> ColumnType {
1810                ScalarType::$variant.nullable(false)
1811            }
1812        }
1813
1814        impl<$lt, E> DatumType<$lt, E> for $native {
1815            fn nullable() -> bool {
1816                false
1817            }
1818
1819            fn fallible() -> bool {
1820                false
1821            }
1822
1823            fn try_from_result(res: Result<Datum<$lt>, E>) -> Result<Self, Result<Datum<$lt>, E>> {
1824                match res {
1825                    Ok(Datum::$variant(f)) => Ok(f.into()),
1826                    _ => Err(res),
1827                }
1828            }
1829
1830            fn into_result(self, _temp_storage: &$lt RowArena) -> Result<Datum<$lt>, E> {
1831                Ok(Datum::$variant(self.into()))
1832            }
1833        }
1834    };
1835    ($native:ty, $variant:ident) => {
1836        impl_datum_type_copy!('a, $native, $variant);
1837    };
1838}
1839
1840impl_datum_type_copy!(f32, Float32);
1841impl_datum_type_copy!(f64, Float64);
1842impl_datum_type_copy!(i16, Int16);
1843impl_datum_type_copy!(i32, Int32);
1844impl_datum_type_copy!(i64, Int64);
1845impl_datum_type_copy!(u16, UInt16);
1846impl_datum_type_copy!(u32, UInt32);
1847impl_datum_type_copy!(u64, UInt64);
1848impl_datum_type_copy!(Interval, Interval);
1849impl_datum_type_copy!(Date, Date);
1850impl_datum_type_copy!(NaiveTime, Time);
1851impl_datum_type_copy!(Uuid, Uuid);
1852impl_datum_type_copy!('a, &'a str, String);
1853impl_datum_type_copy!('a, &'a [u8], Bytes);
1854impl_datum_type_copy!(crate::Timestamp, MzTimestamp);
1855
1856impl<'a, E> DatumType<'a, E> for Datum<'a> {
1857    fn nullable() -> bool {
1858        true
1859    }
1860
1861    fn fallible() -> bool {
1862        false
1863    }
1864
1865    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1866        match res {
1867            Ok(datum) => Ok(datum),
1868            _ => Err(res),
1869        }
1870    }
1871
1872    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1873        Ok(self)
1874    }
1875}
1876
1877impl<'a, E> DatumType<'a, E> for DatumList<'a> {
1878    fn nullable() -> bool {
1879        false
1880    }
1881
1882    fn fallible() -> bool {
1883        false
1884    }
1885
1886    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1887        match res {
1888            Ok(Datum::List(list)) => Ok(list),
1889            _ => Err(res),
1890        }
1891    }
1892
1893    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1894        Ok(Datum::List(self))
1895    }
1896}
1897
1898impl<'a, E> DatumType<'a, E> for DatumMap<'a> {
1899    fn nullable() -> bool {
1900        false
1901    }
1902
1903    fn fallible() -> bool {
1904        false
1905    }
1906
1907    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1908        match res {
1909            Ok(Datum::Map(map)) => Ok(map),
1910            _ => Err(res),
1911        }
1912    }
1913
1914    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1915        Ok(Datum::Map(self))
1916    }
1917}
1918
1919impl<'a, E> DatumType<'a, E> for Range<DatumNested<'a>> {
1920    fn nullable() -> bool {
1921        false
1922    }
1923
1924    fn fallible() -> bool {
1925        false
1926    }
1927
1928    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1929        match res {
1930            Ok(Datum::Range(range)) => Ok(range),
1931            _ => Err(res),
1932        }
1933    }
1934
1935    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1936        Ok(Datum::Range(self))
1937    }
1938}
1939
1940impl<'a, E> DatumType<'a, E> for Range<Datum<'a>> {
1941    fn nullable() -> bool {
1942        false
1943    }
1944
1945    fn fallible() -> bool {
1946        false
1947    }
1948
1949    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1950        match res {
1951            Ok(r @ Datum::Range(..)) => Ok(r.unwrap_range()),
1952            _ => Err(res),
1953        }
1954    }
1955
1956    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1957        let d =
1958            self.into_bounds(|bound| temp_storage.make_datum_nested(|packer| packer.push(bound)));
1959        Ok(Datum::Range(d))
1960    }
1961}
1962
1963impl AsColumnType for bool {
1964    fn as_column_type() -> ColumnType {
1965        ScalarType::Bool.nullable(false)
1966    }
1967}
1968
1969impl<'a, E> DatumType<'a, E> for bool {
1970    fn nullable() -> bool {
1971        false
1972    }
1973
1974    fn fallible() -> bool {
1975        false
1976    }
1977
1978    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
1979        match res {
1980            Ok(Datum::True) => Ok(true),
1981            Ok(Datum::False) => Ok(false),
1982            _ => Err(res),
1983        }
1984    }
1985
1986    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
1987        if self {
1988            Ok(Datum::True)
1989        } else {
1990            Ok(Datum::False)
1991        }
1992    }
1993}
1994
1995impl AsColumnType for String {
1996    fn as_column_type() -> ColumnType {
1997        ScalarType::String.nullable(false)
1998    }
1999}
2000
2001impl<'a, E> DatumType<'a, E> for String {
2002    fn nullable() -> bool {
2003        false
2004    }
2005
2006    fn fallible() -> bool {
2007        false
2008    }
2009
2010    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2011        match res {
2012            Ok(Datum::String(s)) => Ok(s.to_owned()),
2013            _ => Err(res),
2014        }
2015    }
2016
2017    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2018        Ok(Datum::String(temp_storage.push_string(self)))
2019    }
2020}
2021
2022impl AsColumnType for ArrayRustType<String> {
2023    fn as_column_type() -> ColumnType {
2024        ScalarType::Array(Box::new(ScalarType::String)).nullable(false)
2025    }
2026}
2027
2028impl<'a, E> DatumType<'a, E> for ArrayRustType<String> {
2029    fn nullable() -> bool {
2030        false
2031    }
2032
2033    fn fallible() -> bool {
2034        false
2035    }
2036
2037    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2038        match res {
2039            Ok(Datum::Array(arr)) => Ok(ArrayRustType(
2040                arr.elements()
2041                    .into_iter()
2042                    .map(|d| d.unwrap_str().to_string())
2043                    .collect(),
2044            )),
2045            _ => Err(res),
2046        }
2047    }
2048
2049    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2050        Ok(temp_storage.make_datum(|packer| {
2051            packer
2052                .try_push_array(
2053                    &[ArrayDimension {
2054                        lower_bound: 1,
2055                        length: self.0.len(),
2056                    }],
2057                    self.0.iter().map(|elem| Datum::String(elem.as_str())),
2058                )
2059                .expect("self is 1 dimensional, and its length is used for the array length");
2060        }))
2061    }
2062}
2063
2064impl AsColumnType for Vec<u8> {
2065    fn as_column_type() -> ColumnType {
2066        ScalarType::Bytes.nullable(false)
2067    }
2068}
2069
2070impl<'a, E> DatumType<'a, E> for Vec<u8> {
2071    fn nullable() -> bool {
2072        false
2073    }
2074
2075    fn fallible() -> bool {
2076        false
2077    }
2078
2079    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2080        match res {
2081            Ok(Datum::Bytes(b)) => Ok(b.to_owned()),
2082            _ => Err(res),
2083        }
2084    }
2085
2086    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2087        Ok(Datum::Bytes(temp_storage.push_bytes(self)))
2088    }
2089}
2090
2091impl AsColumnType for Numeric {
2092    fn as_column_type() -> ColumnType {
2093        ScalarType::Numeric { max_scale: None }.nullable(false)
2094    }
2095}
2096
2097impl<'a, E> DatumType<'a, E> for Numeric {
2098    fn nullable() -> bool {
2099        false
2100    }
2101
2102    fn fallible() -> bool {
2103        false
2104    }
2105
2106    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2107        match res {
2108            Ok(Datum::Numeric(n)) => Ok(n.into_inner()),
2109            _ => Err(res),
2110        }
2111    }
2112
2113    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2114        Ok(Datum::from(self))
2115    }
2116}
2117
2118impl<'a, E> DatumType<'a, E> for OrderedDecimal<Numeric> {
2119    fn nullable() -> bool {
2120        false
2121    }
2122
2123    fn fallible() -> bool {
2124        false
2125    }
2126
2127    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2128        match res {
2129            Ok(Datum::Numeric(n)) => Ok(n),
2130            _ => Err(res),
2131        }
2132    }
2133
2134    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2135        Ok(Datum::from(self))
2136    }
2137}
2138
2139impl AsColumnType for PgLegacyChar {
2140    fn as_column_type() -> ColumnType {
2141        ScalarType::PgLegacyChar.nullable(false)
2142    }
2143}
2144
2145impl<'a, E> DatumType<'a, E> for PgLegacyChar {
2146    fn nullable() -> bool {
2147        false
2148    }
2149
2150    fn fallible() -> bool {
2151        false
2152    }
2153
2154    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2155        match res {
2156            Ok(Datum::UInt8(a)) => Ok(PgLegacyChar(a)),
2157            _ => Err(res),
2158        }
2159    }
2160
2161    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2162        Ok(Datum::UInt8(self.0))
2163    }
2164}
2165
2166impl<S> AsColumnType for PgLegacyName<S>
2167where
2168    S: AsRef<str>,
2169{
2170    fn as_column_type() -> ColumnType {
2171        ScalarType::PgLegacyName.nullable(false)
2172    }
2173}
2174
2175impl<'a, E> DatumType<'a, E> for PgLegacyName<&'a str> {
2176    fn nullable() -> bool {
2177        false
2178    }
2179
2180    fn fallible() -> bool {
2181        false
2182    }
2183
2184    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2185        match res {
2186            Ok(Datum::String(a)) => Ok(PgLegacyName(a)),
2187            _ => Err(res),
2188        }
2189    }
2190
2191    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2192        Ok(Datum::String(self.0))
2193    }
2194}
2195
2196impl<'a, E> DatumType<'a, E> for PgLegacyName<String> {
2197    fn nullable() -> bool {
2198        false
2199    }
2200
2201    fn fallible() -> bool {
2202        false
2203    }
2204
2205    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2206        match res {
2207            Ok(Datum::String(a)) => Ok(PgLegacyName(a.to_owned())),
2208            _ => Err(res),
2209        }
2210    }
2211
2212    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2213        Ok(Datum::String(temp_storage.push_string(self.0)))
2214    }
2215}
2216
2217impl AsColumnType for Oid {
2218    fn as_column_type() -> ColumnType {
2219        ScalarType::Oid.nullable(false)
2220    }
2221}
2222
2223impl<'a, E> DatumType<'a, E> for Oid {
2224    fn nullable() -> bool {
2225        false
2226    }
2227
2228    fn fallible() -> bool {
2229        false
2230    }
2231
2232    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2233        match res {
2234            Ok(Datum::UInt32(a)) => Ok(Oid(a)),
2235            _ => Err(res),
2236        }
2237    }
2238
2239    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2240        Ok(Datum::UInt32(self.0))
2241    }
2242}
2243
2244impl AsColumnType for RegClass {
2245    fn as_column_type() -> ColumnType {
2246        ScalarType::RegClass.nullable(false)
2247    }
2248}
2249
2250impl<'a, E> DatumType<'a, E> for RegClass {
2251    fn nullable() -> bool {
2252        false
2253    }
2254
2255    fn fallible() -> bool {
2256        false
2257    }
2258
2259    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2260        match res {
2261            Ok(Datum::UInt32(a)) => Ok(RegClass(a)),
2262            _ => Err(res),
2263        }
2264    }
2265
2266    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2267        Ok(Datum::UInt32(self.0))
2268    }
2269}
2270
2271impl AsColumnType for RegProc {
2272    fn as_column_type() -> ColumnType {
2273        ScalarType::RegProc.nullable(false)
2274    }
2275}
2276
2277impl<'a, E> DatumType<'a, E> for RegProc {
2278    fn nullable() -> bool {
2279        false
2280    }
2281
2282    fn fallible() -> bool {
2283        false
2284    }
2285
2286    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2287        match res {
2288            Ok(Datum::UInt32(a)) => Ok(RegProc(a)),
2289            _ => Err(res),
2290        }
2291    }
2292
2293    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2294        Ok(Datum::UInt32(self.0))
2295    }
2296}
2297
2298impl AsColumnType for RegType {
2299    fn as_column_type() -> ColumnType {
2300        ScalarType::RegType.nullable(false)
2301    }
2302}
2303
2304impl<'a, E> DatumType<'a, E> for RegType {
2305    fn nullable() -> bool {
2306        false
2307    }
2308
2309    fn fallible() -> bool {
2310        false
2311    }
2312
2313    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2314        match res {
2315            Ok(Datum::UInt32(a)) => Ok(RegType(a)),
2316            _ => Err(res),
2317        }
2318    }
2319
2320    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2321        Ok(Datum::UInt32(self.0))
2322    }
2323}
2324
2325impl<S> AsColumnType for Char<S>
2326where
2327    S: AsRef<str>,
2328{
2329    fn as_column_type() -> ColumnType {
2330        ScalarType::Char { length: None }.nullable(false)
2331    }
2332}
2333
2334impl<'a, E> DatumType<'a, E> for Char<&'a str> {
2335    fn nullable() -> bool {
2336        false
2337    }
2338
2339    fn fallible() -> bool {
2340        false
2341    }
2342
2343    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2344        match res {
2345            Ok(Datum::String(a)) => Ok(Char(a)),
2346            _ => Err(res),
2347        }
2348    }
2349
2350    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2351        Ok(Datum::String(self.0))
2352    }
2353}
2354
2355impl<'a, E> DatumType<'a, E> for Char<String> {
2356    fn nullable() -> bool {
2357        false
2358    }
2359
2360    fn fallible() -> bool {
2361        false
2362    }
2363
2364    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2365        match res {
2366            Ok(Datum::String(a)) => Ok(Char(a.to_owned())),
2367            _ => Err(res),
2368        }
2369    }
2370
2371    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2372        Ok(Datum::String(temp_storage.push_string(self.0)))
2373    }
2374}
2375
2376impl<S> AsColumnType for VarChar<S>
2377where
2378    S: AsRef<str>,
2379{
2380    fn as_column_type() -> ColumnType {
2381        ScalarType::Char { length: None }.nullable(false)
2382    }
2383}
2384
2385impl<'a, E> DatumType<'a, E> for VarChar<&'a str> {
2386    fn nullable() -> bool {
2387        false
2388    }
2389
2390    fn fallible() -> bool {
2391        false
2392    }
2393
2394    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2395        match res {
2396            Ok(Datum::String(a)) => Ok(VarChar(a)),
2397            _ => Err(res),
2398        }
2399    }
2400
2401    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2402        Ok(Datum::String(self.0))
2403    }
2404}
2405
2406impl<'a, E> DatumType<'a, E> for VarChar<String> {
2407    fn nullable() -> bool {
2408        false
2409    }
2410
2411    fn fallible() -> bool {
2412        false
2413    }
2414
2415    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2416        match res {
2417            Ok(Datum::String(a)) => Ok(VarChar(a.to_owned())),
2418            _ => Err(res),
2419        }
2420    }
2421
2422    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2423        Ok(Datum::String(temp_storage.push_string(self.0)))
2424    }
2425}
2426
2427impl<'a, E> DatumType<'a, E> for Jsonb {
2428    fn nullable() -> bool {
2429        false
2430    }
2431
2432    fn fallible() -> bool {
2433        false
2434    }
2435
2436    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2437        Ok(JsonbRef::try_from_result(res)?.to_owned())
2438    }
2439
2440    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2441        Ok(temp_storage.push_unary_row(self.into_row()))
2442    }
2443}
2444
2445impl AsColumnType for Jsonb {
2446    fn as_column_type() -> ColumnType {
2447        ScalarType::Jsonb.nullable(false)
2448    }
2449}
2450
2451impl<'a, E> DatumType<'a, E> for JsonbRef<'a> {
2452    fn nullable() -> bool {
2453        false
2454    }
2455
2456    fn fallible() -> bool {
2457        false
2458    }
2459
2460    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2461        match res {
2462            Ok(
2463                d @ (Datum::JsonNull
2464                | Datum::True
2465                | Datum::False
2466                | Datum::Numeric(_)
2467                | Datum::String(_)
2468                | Datum::List(_)
2469                | Datum::Map(_)),
2470            ) => Ok(JsonbRef::from_datum(d)),
2471            _ => Err(res),
2472        }
2473    }
2474
2475    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2476        Ok(self.into_datum())
2477    }
2478}
2479
2480impl<'a> AsColumnType for JsonbRef<'a> {
2481    fn as_column_type() -> ColumnType {
2482        ScalarType::Jsonb.nullable(false)
2483    }
2484}
2485
2486impl AsColumnType for MzAclItem {
2487    fn as_column_type() -> ColumnType {
2488        ScalarType::MzAclItem.nullable(false)
2489    }
2490}
2491
2492impl<'a, E> DatumType<'a, E> for MzAclItem {
2493    fn nullable() -> bool {
2494        false
2495    }
2496
2497    fn fallible() -> bool {
2498        false
2499    }
2500
2501    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2502        match res {
2503            Ok(Datum::MzAclItem(mz_acl_item)) => Ok(mz_acl_item),
2504            _ => Err(res),
2505        }
2506    }
2507
2508    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2509        Ok(Datum::MzAclItem(self))
2510    }
2511}
2512
2513impl AsColumnType for AclItem {
2514    fn as_column_type() -> ColumnType {
2515        ScalarType::AclItem.nullable(false)
2516    }
2517}
2518
2519impl<'a, E> DatumType<'a, E> for AclItem {
2520    fn nullable() -> bool {
2521        false
2522    }
2523
2524    fn fallible() -> bool {
2525        false
2526    }
2527
2528    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2529        match res {
2530            Ok(Datum::AclItem(acl_item)) => Ok(acl_item),
2531            _ => Err(res),
2532        }
2533    }
2534
2535    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2536        Ok(Datum::AclItem(self))
2537    }
2538}
2539
2540impl AsColumnType for CheckedTimestamp<NaiveDateTime> {
2541    fn as_column_type() -> ColumnType {
2542        ScalarType::Timestamp { precision: None }.nullable(false)
2543    }
2544}
2545
2546impl<'a, E> DatumType<'a, E> for CheckedTimestamp<NaiveDateTime> {
2547    fn nullable() -> bool {
2548        false
2549    }
2550
2551    fn fallible() -> bool {
2552        false
2553    }
2554
2555    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2556        match res {
2557            Ok(Datum::Timestamp(a)) => Ok(a),
2558            _ => Err(res),
2559        }
2560    }
2561
2562    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2563        Ok(Datum::Timestamp(self))
2564    }
2565}
2566
2567impl AsColumnType for CheckedTimestamp<DateTime<Utc>> {
2568    fn as_column_type() -> ColumnType {
2569        ScalarType::TimestampTz { precision: None }.nullable(false)
2570    }
2571}
2572
2573impl<'a, E> DatumType<'a, E> for CheckedTimestamp<DateTime<Utc>> {
2574    fn nullable() -> bool {
2575        false
2576    }
2577
2578    fn fallible() -> bool {
2579        false
2580    }
2581
2582    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2583        match res {
2584            Ok(Datum::TimestampTz(a)) => Ok(a),
2585            _ => Err(res),
2586        }
2587    }
2588
2589    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2590        Ok(Datum::TimestampTz(self))
2591    }
2592}
2593
2594impl ScalarType {
2595    /// Returns the contained numeric maximum scale.
2596    ///
2597    /// # Panics
2598    ///
2599    /// Panics if the scalar type is not [`ScalarType::Numeric`].
2600    pub fn unwrap_numeric_max_scale(&self) -> Option<NumericMaxScale> {
2601        match self {
2602            ScalarType::Numeric { max_scale } => *max_scale,
2603            _ => panic!("ScalarType::unwrap_numeric_scale called on {:?}", self),
2604        }
2605    }
2606
2607    /// Returns the contained timestamp precision.
2608    ///
2609    /// # Panics
2610    ///
2611    /// Panics if the scalar type is not [`ScalarType::Timestamp`] or
2612    /// [`ScalarType::TimestampTz`].
2613    pub fn unwrap_timestamp_precision(&self) -> Option<TimestampPrecision> {
2614        match self {
2615            ScalarType::Timestamp { precision } | ScalarType::TimestampTz { precision } => {
2616                *precision
2617            }
2618            _ => panic!(
2619                "ScalarType::unwrap_timestamp_precision called on {:?}",
2620                self
2621            ),
2622        }
2623    }
2624
2625    /// Returns the [`ScalarType`] of elements in a [`ScalarType::List`].
2626    ///
2627    /// # Panics
2628    ///
2629    /// Panics if called on anything other than a [`ScalarType::List`].
2630    pub fn unwrap_list_element_type(&self) -> &ScalarType {
2631        match self {
2632            ScalarType::List { element_type, .. } => element_type,
2633            _ => panic!("ScalarType::unwrap_list_element_type called on {:?}", self),
2634        }
2635    }
2636
2637    /// Returns the [`ScalarType`] of elements in the nth layer a
2638    /// [`ScalarType::List`].
2639    ///
2640    /// For example, in an `int list list`, the:
2641    /// - 0th layer is `int list list`
2642    /// - 1st layer is `int list`
2643    /// - 2nd layer is `int`
2644    ///
2645    /// # Panics
2646    ///
2647    /// Panics if the nth-1 layer is anything other than a
2648    /// [`ScalarType::List`].
2649    pub fn unwrap_list_nth_layer_type(&self, layer: usize) -> &ScalarType {
2650        if layer == 0 {
2651            return self;
2652        }
2653        match self {
2654            ScalarType::List { element_type, .. } => {
2655                element_type.unwrap_list_nth_layer_type(layer - 1)
2656            }
2657            _ => panic!(
2658                "ScalarType::unwrap_list_nth_layer_type called on {:?}",
2659                self
2660            ),
2661        }
2662    }
2663
2664    /// Returns vector of [`ScalarType`] elements in a [`ScalarType::Record`].
2665    ///
2666    /// # Panics
2667    ///
2668    /// Panics if called on anything other than a [`ScalarType::Record`].
2669    pub fn unwrap_record_element_type(&self) -> Vec<&ScalarType> {
2670        match self {
2671            ScalarType::Record { fields, .. } => {
2672                fields.iter().map(|(_, t)| &t.scalar_type).collect_vec()
2673            }
2674            _ => panic!(
2675                "ScalarType::unwrap_record_element_type called on {:?}",
2676                self
2677            ),
2678        }
2679    }
2680
2681    /// Returns vector of [`ColumnType`] elements in a [`ScalarType::Record`].
2682    ///
2683    /// # Panics
2684    ///
2685    /// Panics if called on anything other than a [`ScalarType::Record`].
2686    pub fn unwrap_record_element_column_type(&self) -> Vec<&ColumnType> {
2687        match self {
2688            ScalarType::Record { fields, .. } => fields.iter().map(|(_, t)| t).collect_vec(),
2689            _ => panic!(
2690                "ScalarType::unwrap_record_element_column_type called on {:?}",
2691                self
2692            ),
2693        }
2694    }
2695
2696    /// Returns number of dimensions/axes (also known as "rank") on a
2697    /// [`ScalarType::List`].
2698    ///
2699    /// # Panics
2700    ///
2701    /// Panics if called on anything other than a [`ScalarType::List`].
2702    pub fn unwrap_list_n_layers(&self) -> usize {
2703        let mut descender = self.unwrap_list_element_type();
2704        let mut layers = 1;
2705
2706        while let ScalarType::List { element_type, .. } = descender {
2707            layers += 1;
2708            descender = element_type;
2709        }
2710
2711        layers
2712    }
2713
2714    /// Returns `self` with any type modifiers removed.
2715    ///
2716    /// Namely, this should set optional scales or limits to `None`.
2717    pub fn without_modifiers(&self) -> ScalarType {
2718        use ScalarType::*;
2719        match self {
2720            List {
2721                element_type,
2722                custom_id: None,
2723            } => List {
2724                element_type: Box::new(element_type.without_modifiers()),
2725                custom_id: None,
2726            },
2727            Map {
2728                value_type,
2729                custom_id: None,
2730            } => Map {
2731                value_type: Box::new(value_type.without_modifiers()),
2732                custom_id: None,
2733            },
2734            Record {
2735                fields,
2736                custom_id: None,
2737            } => {
2738                let fields = fields
2739                    .iter()
2740                    .map(|(column_name, column_type)| {
2741                        (
2742                            column_name.clone(),
2743                            ColumnType {
2744                                scalar_type: column_type.scalar_type.without_modifiers(),
2745                                nullable: column_type.nullable,
2746                            },
2747                        )
2748                    })
2749                    .collect();
2750                Record {
2751                    fields,
2752                    custom_id: None,
2753                }
2754            }
2755            Array(a) => Array(Box::new(a.without_modifiers())),
2756            Numeric { .. } => Numeric { max_scale: None },
2757            // Char's default length should not be `Some(1)`, but instead `None`
2758            // to support Char values of different lengths in e.g. lists.
2759            Char { .. } => Char { length: None },
2760            VarChar { .. } => VarChar { max_length: None },
2761            Range { element_type } => Range {
2762                element_type: Box::new(element_type.without_modifiers()),
2763            },
2764            v => v.clone(),
2765        }
2766    }
2767
2768    /// Returns the [`ScalarType`] of elements in a [`ScalarType::Array`] or the
2769    /// elements of a vector type, e.g. [`ScalarType::Int16`] for
2770    /// [`ScalarType::Int2Vector`].
2771    ///
2772    /// # Panics
2773    ///
2774    /// Panics if called on anything other than a [`ScalarType::Array`] or
2775    /// [`ScalarType::Int2Vector`].
2776    pub fn unwrap_array_element_type(&self) -> &ScalarType {
2777        match self {
2778            ScalarType::Array(s) => &**s,
2779            ScalarType::Int2Vector => &ScalarType::Int16,
2780            _ => panic!("ScalarType::unwrap_array_element_type called on {:?}", self),
2781        }
2782    }
2783
2784    /// Returns the [`ScalarType`] of elements in a [`ScalarType::Array`],
2785    /// [`ScalarType::Int2Vector`], or [`ScalarType::List`].
2786    ///
2787    /// # Panics
2788    ///
2789    /// Panics if called on anything other than a [`ScalarType::Array`],
2790    /// [`ScalarType::Int2Vector`], or [`ScalarType::List`].
2791    pub fn unwrap_collection_element_type(&self) -> &ScalarType {
2792        match self {
2793            ScalarType::Array(element_type) => element_type,
2794            ScalarType::Int2Vector => &ScalarType::Int16,
2795            ScalarType::List { element_type, .. } => element_type,
2796            _ => panic!(
2797                "ScalarType::unwrap_collection_element_type called on {:?}",
2798                self
2799            ),
2800        }
2801    }
2802
2803    /// Returns the [`ScalarType`] of values in a [`ScalarType::Map`].
2804    ///
2805    /// # Panics
2806    ///
2807    /// Panics if called on anything other than a [`ScalarType::Map`].
2808    pub fn unwrap_map_value_type(&self) -> &ScalarType {
2809        match self {
2810            ScalarType::Map { value_type, .. } => &**value_type,
2811            _ => panic!("ScalarType::unwrap_map_value_type called on {:?}", self),
2812        }
2813    }
2814
2815    /// Returns the length of a [`ScalarType::Char`].
2816    ///
2817    /// # Panics
2818    ///
2819    /// Panics if called on anything other than a [`ScalarType::Char`].
2820    pub fn unwrap_char_length(&self) -> Option<CharLength> {
2821        match self {
2822            ScalarType::Char { length, .. } => *length,
2823            _ => panic!("ScalarType::unwrap_char_length called on {:?}", self),
2824        }
2825    }
2826
2827    /// Returns the max length of a [`ScalarType::VarChar`].
2828    ///
2829    /// # Panics
2830    ///
2831    /// Panics if called on anything other than a [`ScalarType::VarChar`].
2832    pub fn unwrap_varchar_max_length(&self) -> Option<VarCharMaxLength> {
2833        match self {
2834            ScalarType::VarChar { max_length, .. } => *max_length,
2835            _ => panic!("ScalarType::unwrap_varchar_max_length called on {:?}", self),
2836        }
2837    }
2838
2839    /// Returns the [`ScalarType`] of elements in a [`ScalarType::Range`].
2840    ///
2841    /// # Panics
2842    ///
2843    /// Panics if called on anything other than a [`ScalarType::Map`].
2844    pub fn unwrap_range_element_type(&self) -> &ScalarType {
2845        match self {
2846            ScalarType::Range { element_type } => &**element_type,
2847            _ => panic!("ScalarType::unwrap_range_element_type called on {:?}", self),
2848        }
2849    }
2850
2851    /// Returns a "near match" of `self`, which are types that are implicitly
2852    /// castable from `self` and offer a means to leverage Materialize's type
2853    /// system to achieve more reasonable approaches to unifying types.
2854    ///
2855    /// However, it's very important to not blithely accept the `near_match`,
2856    /// which can be suboptimal/unnecessary, e.g. in the case of an already
2857    /// homogeneous group.
2858    ///
2859    /// The feature is preferrable in MZ, but unnecessary in PG because PG's
2860    /// type system offers totally linear progression through the complexity of
2861    /// types. e.g. with numbers, there is a linear progression in the domain
2862    /// each can represent. However, MZ's support for unsigned integers create a
2863    /// non-linear type system, i.e. while the magnitude of `Int32` and
2864    /// `UInt32`'s domains are the same, they are not equal.
2865    ///
2866    /// Without this feature, Materialize will:
2867    /// - Guess that a mixute of the same width of int and uint cannot be
2868    ///   coerced to a homogeneous type.
2869    /// - Select the `Float64` based version of common binary functions (e.g.
2870    ///   `=`), which introduces an unexpected float cast to integer values.
2871    ///
2872    /// Note that if adding any near matches besides unsigned ints, consider
2873    /// extending/generalizing how `guess_best_common_type` uses this function.
2874    pub fn near_match(&self) -> Option<&'static ScalarType> {
2875        match self {
2876            ScalarType::UInt16 => Some(&ScalarType::Int32),
2877            ScalarType::UInt32 => Some(&ScalarType::Int64),
2878            ScalarType::UInt64 => Some(&ScalarType::Numeric { max_scale: None }),
2879            _ => None,
2880        }
2881    }
2882
2883    /// Derives a column type from this scalar type with the specified
2884    /// nullability.
2885    pub const fn nullable(self, nullable: bool) -> ColumnType {
2886        ColumnType {
2887            nullable,
2888            scalar_type: self,
2889        }
2890    }
2891
2892    /// Returns whether or not `self` is a vector-like type, i.e.
2893    /// [`ScalarType::Array`], [`ScalarType::Int2Vector`], or
2894    /// [`ScalarType::List`], irrespective of its element type.
2895    pub fn is_vec(&self) -> bool {
2896        matches!(
2897            self,
2898            ScalarType::Array(_) | ScalarType::Int2Vector | ScalarType::List { .. }
2899        )
2900    }
2901
2902    pub fn is_custom_type(&self) -> bool {
2903        use ScalarType::*;
2904        match self {
2905            List {
2906                element_type: t,
2907                custom_id,
2908            }
2909            | Map {
2910                value_type: t,
2911                custom_id,
2912            } => custom_id.is_some() || t.is_custom_type(),
2913            Record {
2914                fields, custom_id, ..
2915            } => {
2916                custom_id.is_some()
2917                    || fields
2918                        .iter()
2919                        .map(|(_, t)| t)
2920                        .any(|t| t.scalar_type.is_custom_type())
2921            }
2922            _ => false,
2923        }
2924    }
2925
2926    /// Determines equality among scalar types that acknowledges custom OIDs,
2927    /// but ignores other embedded values.
2928    ///
2929    /// In most situations, you want to use `base_eq` rather than `ScalarType`'s
2930    /// implementation of `Eq`. `base_eq` expresses the semantics of direct type
2931    /// interoperability whereas `Eq` expresses an exact comparison between the
2932    /// values.
2933    ///
2934    /// For instance, `base_eq` signals that e.g. two [`ScalarType::Numeric`]
2935    /// values can be added together, irrespective of their embedded scale. In
2936    /// contrast, two `Numeric` values with different scales are never `Eq` to
2937    /// one another.
2938    pub fn base_eq(&self, other: &ScalarType) -> bool {
2939        self.eq_inner(other, false)
2940    }
2941
2942    // Determines equality among scalar types that ignores any custom OIDs or
2943    // embedded values.
2944    pub fn structural_eq(&self, other: &ScalarType) -> bool {
2945        self.eq_inner(other, true)
2946    }
2947
2948    pub fn eq_inner(&self, other: &ScalarType, structure_only: bool) -> bool {
2949        use ScalarType::*;
2950        match (self, other) {
2951            (
2952                List {
2953                    element_type: l,
2954                    custom_id: oid_l,
2955                },
2956                List {
2957                    element_type: r,
2958                    custom_id: oid_r,
2959                },
2960            )
2961            | (
2962                Map {
2963                    value_type: l,
2964                    custom_id: oid_l,
2965                },
2966                Map {
2967                    value_type: r,
2968                    custom_id: oid_r,
2969                },
2970            ) => l.eq_inner(r, structure_only) && (oid_l == oid_r || structure_only),
2971            (Array(a), Array(b)) | (Range { element_type: a }, Range { element_type: b }) => {
2972                a.eq_inner(b, structure_only)
2973            }
2974            (
2975                Record {
2976                    fields: fields_a,
2977                    custom_id: oid_a,
2978                },
2979                Record {
2980                    fields: fields_b,
2981                    custom_id: oid_b,
2982                },
2983            ) => {
2984                (oid_a == oid_b || structure_only)
2985                    && fields_a.len() == fields_b.len()
2986                    && fields_a
2987                        .iter()
2988                        .zip(fields_b)
2989                        // Ignore nullability.
2990                        .all(|(a, b)| {
2991                            (a.0 == b.0 || structure_only)
2992                                && a.1.scalar_type.eq_inner(&b.1.scalar_type, structure_only)
2993                        })
2994            }
2995            (s, o) => ScalarBaseType::from(s) == ScalarBaseType::from(o),
2996        }
2997    }
2998
2999    /// Returns various interesting datums for a ScalarType (max, min, 0 values, etc.).
3000    pub fn interesting_datums(&self) -> impl Iterator<Item = Datum<'static>> {
3001        // TODO: Add datums for the types that have an inner Box'd ScalarType. It'd be best to
3002        // re-use this function to dynamically generate interesting datums of the requested type.
3003        // But the 'static bound makes this either hard or impossible. We might need to remove that
3004        // and return, say, an owned Row. This would require changing lots of dependent test
3005        // functions, some of which also hard code a 'static bound.
3006        static BOOL: LazyLock<Row> =
3007            LazyLock::new(|| Row::pack_slice(&[Datum::True, Datum::False]));
3008        static INT16: LazyLock<Row> = LazyLock::new(|| {
3009            Row::pack_slice(&[
3010                Datum::Int16(0),
3011                Datum::Int16(1),
3012                Datum::Int16(-1),
3013                Datum::Int16(i16::MIN),
3014                Datum::Int16(i16::MIN + 1),
3015                Datum::Int16(i16::MAX),
3016                // The following datums are
3017                // around the boundaries introduced by
3018                // variable-length int encoding
3019                //
3020                // TODO[btv]: Add more datums around
3021                // boundaries in VLE (e.g. negatives) if `test_smoketest_all_builtins` is
3022                // fixed to be faster.
3023                Datum::Int16(127),
3024                Datum::Int16(128),
3025            ])
3026        });
3027        static INT32: LazyLock<Row> = LazyLock::new(|| {
3028            Row::pack_slice(&[
3029                Datum::Int32(0),
3030                Datum::Int32(1),
3031                Datum::Int32(-1),
3032                Datum::Int32(i32::MIN),
3033                Datum::Int32(i32::MIN + 1),
3034                Datum::Int32(i32::MAX),
3035                // The following datums are
3036                // around the boundaries introduced by
3037                // variable-length int encoding
3038                Datum::Int32(32767),
3039                Datum::Int32(32768),
3040            ])
3041        });
3042        static INT64: LazyLock<Row> = LazyLock::new(|| {
3043            Row::pack_slice(&[
3044                Datum::Int64(0),
3045                Datum::Int64(1),
3046                Datum::Int64(-1),
3047                Datum::Int64(i64::MIN),
3048                Datum::Int64(i64::MIN + 1),
3049                Datum::Int64(i64::MAX),
3050                // The following datums are
3051                // around the boundaries introduced by
3052                // variable-length int encoding
3053                Datum::Int64(2147483647),
3054                Datum::Int64(2147483648),
3055            ])
3056        });
3057        static UINT16: LazyLock<Row> = LazyLock::new(|| {
3058            Row::pack_slice(&[
3059                Datum::UInt16(0),
3060                Datum::UInt16(1),
3061                Datum::UInt16(u16::MAX),
3062                // The following datums are
3063                // around the boundaries introduced by
3064                // variable-length int encoding
3065                Datum::UInt16(255),
3066                Datum::UInt16(256),
3067            ])
3068        });
3069        static UINT32: LazyLock<Row> = LazyLock::new(|| {
3070            Row::pack_slice(&[
3071                Datum::UInt32(0),
3072                Datum::UInt32(1),
3073                Datum::UInt32(u32::MAX),
3074                // The following datums are
3075                // around the boundaries introduced by
3076                // variable-length int encoding
3077                Datum::UInt32(32767),
3078                Datum::UInt32(32768),
3079            ])
3080        });
3081        static UINT64: LazyLock<Row> = LazyLock::new(|| {
3082            Row::pack_slice(&[
3083                Datum::UInt64(0),
3084                Datum::UInt64(1),
3085                Datum::UInt64(u64::MAX),
3086                // The following datums are
3087                // around the boundaries introduced by
3088                // variable-length int encoding
3089                Datum::UInt64(2147483647),
3090                Datum::UInt64(2147483648),
3091            ])
3092        });
3093        static FLOAT32: LazyLock<Row> = LazyLock::new(|| {
3094            Row::pack_slice(&[
3095                Datum::Float32(OrderedFloat(0.0)),
3096                Datum::Float32(OrderedFloat(1.0)),
3097                Datum::Float32(OrderedFloat(-1.0)),
3098                Datum::Float32(OrderedFloat(f32::MIN)),
3099                Datum::Float32(OrderedFloat(f32::MIN_POSITIVE)),
3100                Datum::Float32(OrderedFloat(f32::MAX)),
3101                Datum::Float32(OrderedFloat(f32::EPSILON)),
3102                Datum::Float32(OrderedFloat(f32::NAN)),
3103                Datum::Float32(OrderedFloat(f32::INFINITY)),
3104                Datum::Float32(OrderedFloat(f32::NEG_INFINITY)),
3105            ])
3106        });
3107        static FLOAT64: LazyLock<Row> = LazyLock::new(|| {
3108            Row::pack_slice(&[
3109                Datum::Float64(OrderedFloat(0.0)),
3110                Datum::Float64(OrderedFloat(1.0)),
3111                Datum::Float64(OrderedFloat(-1.0)),
3112                Datum::Float64(OrderedFloat(f64::MIN)),
3113                Datum::Float64(OrderedFloat(f64::MIN_POSITIVE)),
3114                Datum::Float64(OrderedFloat(f64::MAX)),
3115                Datum::Float64(OrderedFloat(f64::EPSILON)),
3116                Datum::Float64(OrderedFloat(f64::NAN)),
3117                Datum::Float64(OrderedFloat(f64::INFINITY)),
3118                Datum::Float64(OrderedFloat(f64::NEG_INFINITY)),
3119            ])
3120        });
3121        static NUMERIC: LazyLock<Row> = LazyLock::new(|| {
3122            cfg_if::cfg_if! {
3123                // Numerics can't currently be instantiated under Miri
3124                if #[cfg(miri)] {
3125                    Row::pack_slice(&[])
3126                } else {
3127                    Row::pack_slice(&[
3128                        Datum::Numeric(OrderedDecimal(Numeric::from(0.0))),
3129                        Datum::Numeric(OrderedDecimal(Numeric::from(1.0))),
3130                        Datum::Numeric(OrderedDecimal(Numeric::from(-1.0))),
3131                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MIN))),
3132                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MIN_POSITIVE))),
3133                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MAX))),
3134                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::EPSILON))),
3135                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::NAN))),
3136                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::INFINITY))),
3137                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::NEG_INFINITY))),
3138                    ])
3139                }
3140            }
3141        });
3142        static DATE: LazyLock<Row> = LazyLock::new(|| {
3143            Row::pack_slice(&[
3144                Datum::Date(Date::from_pg_epoch(0).unwrap()),
3145                Datum::Date(Date::from_pg_epoch(Date::LOW_DAYS).unwrap()),
3146                Datum::Date(Date::from_pg_epoch(Date::HIGH_DAYS).unwrap()),
3147            ])
3148        });
3149        static TIME: LazyLock<Row> = LazyLock::new(|| {
3150            Row::pack_slice(&[
3151                Datum::Time(NaiveTime::from_hms_micro_opt(0, 0, 0, 0).unwrap()),
3152                Datum::Time(NaiveTime::from_hms_micro_opt(23, 59, 59, 999_999).unwrap()),
3153            ])
3154        });
3155        static TIMESTAMP: LazyLock<Row> = LazyLock::new(|| {
3156            Row::pack_slice(&[
3157                Datum::Timestamp(
3158                    DateTime::from_timestamp(0, 0)
3159                        .unwrap()
3160                        .naive_utc()
3161                        .try_into()
3162                        .unwrap(),
3163                ),
3164                Datum::Timestamp(
3165                    crate::adt::timestamp::LOW_DATE
3166                        .and_hms_opt(0, 0, 0)
3167                        .unwrap()
3168                        .try_into()
3169                        .unwrap(),
3170                ),
3171                Datum::Timestamp(
3172                    crate::adt::timestamp::HIGH_DATE
3173                        .and_hms_opt(23, 59, 59)
3174                        .unwrap()
3175                        .try_into()
3176                        .unwrap(),
3177                ),
3178                // nano seconds
3179                Datum::Timestamp(
3180                    DateTime::from_timestamp(0, 123456789)
3181                        .unwrap()
3182                        .naive_utc()
3183                        .try_into()
3184                        .unwrap(),
3185                ),
3186                // Leap second
3187                Datum::Timestamp(
3188                    CheckedTimestamp::from_timestamplike(
3189                        NaiveDate::from_isoywd_opt(2019, 30, chrono::Weekday::Wed)
3190                            .unwrap()
3191                            .and_hms_milli_opt(23, 59, 59, 1234)
3192                            .unwrap(),
3193                    )
3194                    .unwrap(),
3195                ),
3196            ])
3197        });
3198        static TIMESTAMPTZ: LazyLock<Row> = LazyLock::new(|| {
3199            Row::pack_slice(&[
3200                Datum::TimestampTz(DateTime::from_timestamp(0, 0).unwrap().try_into().unwrap()),
3201                Datum::TimestampTz(
3202                    DateTime::from_naive_utc_and_offset(
3203                        crate::adt::timestamp::LOW_DATE
3204                            .and_hms_opt(0, 0, 0)
3205                            .unwrap(),
3206                        Utc,
3207                    )
3208                    .try_into()
3209                    .unwrap(),
3210                ),
3211                Datum::TimestampTz(
3212                    DateTime::from_naive_utc_and_offset(
3213                        crate::adt::timestamp::HIGH_DATE
3214                            .and_hms_opt(23, 59, 59)
3215                            .unwrap(),
3216                        Utc,
3217                    )
3218                    .try_into()
3219                    .unwrap(),
3220                ),
3221                // nano seconds
3222                Datum::TimestampTz(
3223                    DateTime::from_timestamp(0, 123456789)
3224                        .unwrap()
3225                        .try_into()
3226                        .unwrap(),
3227                ),
3228            ])
3229        });
3230        static INTERVAL: LazyLock<Row> = LazyLock::new(|| {
3231            Row::pack_slice(&[
3232                Datum::Interval(Interval::new(0, 0, 0)),
3233                Datum::Interval(Interval::new(1, 1, 1)),
3234                Datum::Interval(Interval::new(-1, -1, -1)),
3235                Datum::Interval(Interval::new(1, 0, 0)),
3236                Datum::Interval(Interval::new(0, 1, 0)),
3237                Datum::Interval(Interval::new(0, 0, 1)),
3238                Datum::Interval(Interval::new(-1, 0, 0)),
3239                Datum::Interval(Interval::new(0, -1, 0)),
3240                Datum::Interval(Interval::new(0, 0, -1)),
3241                Datum::Interval(Interval::new(i32::MIN, i32::MIN, i64::MIN)),
3242                Datum::Interval(Interval::new(i32::MAX, i32::MAX, i64::MAX)),
3243                Datum::Interval(Interval::new(i32::MIN, 0, 0)),
3244                Datum::Interval(Interval::new(i32::MAX, 0, 0)),
3245                Datum::Interval(Interval::new(0, i32::MIN, 0)),
3246                Datum::Interval(Interval::new(0, i32::MAX, 0)),
3247                Datum::Interval(Interval::new(0, 0, i64::MIN)),
3248                Datum::Interval(Interval::new(0, 0, i64::MAX)),
3249            ])
3250        });
3251        static PGLEGACYCHAR: LazyLock<Row> =
3252            LazyLock::new(|| Row::pack_slice(&[Datum::UInt8(u8::MIN), Datum::UInt8(u8::MAX)]));
3253        static PGLEGACYNAME: LazyLock<Row> = LazyLock::new(|| {
3254            Row::pack_slice(&[
3255                Datum::String(""),
3256                Datum::String(" "),
3257                Datum::String("'"),
3258                Datum::String("\""),
3259                Datum::String("."),
3260                Datum::String(&"x".repeat(64)),
3261            ])
3262        });
3263        static BYTES: LazyLock<Row> = LazyLock::new(|| {
3264            Row::pack_slice(&[Datum::Bytes(&[]), Datum::Bytes(&[0]), Datum::Bytes(&[255])])
3265        });
3266        static STRING: LazyLock<Row> = LazyLock::new(|| {
3267            Row::pack_slice(&[
3268                Datum::String(""),
3269                Datum::String(" "),
3270                Datum::String("'"),
3271                Datum::String("\""),
3272                Datum::String("."),
3273                Datum::String("2015-09-18T23:56:04.123Z"),
3274                Datum::String(&"x".repeat(100)),
3275                // Valid timezone.
3276                Datum::String("JAPAN"),
3277                Datum::String("1,2,3"),
3278                Datum::String("\r\n"),
3279                Datum::String("\"\""),
3280            ])
3281        });
3282        static CHAR: LazyLock<Row> = LazyLock::new(|| {
3283            Row::pack_slice(&[
3284                Datum::String(" "),
3285                Datum::String("'"),
3286                Datum::String("\""),
3287                Datum::String("."),
3288                Datum::String(","),
3289                Datum::String("\t"),
3290                Datum::String("\n"),
3291                Datum::String("\r"),
3292                Datum::String("\\"),
3293                // Null character.
3294                Datum::String(std::str::from_utf8(b"\x00").unwrap()),
3295                // Start of text.
3296                Datum::String(std::str::from_utf8(b"\x02").unwrap()),
3297                // End of text.
3298                Datum::String(std::str::from_utf8(b"\x03").unwrap()),
3299                // Backspace.
3300                Datum::String(std::str::from_utf8(b"\x08").unwrap()),
3301                // Escape.
3302                Datum::String(std::str::from_utf8(b"\x1B").unwrap()),
3303                // Delete.
3304                Datum::String(std::str::from_utf8(b"\x7F").unwrap()),
3305            ])
3306        });
3307        static JSONB: LazyLock<Row> = LazyLock::new(|| {
3308            let mut datums = vec![Datum::True, Datum::False, Datum::JsonNull];
3309            datums.extend(STRING.iter());
3310            datums.extend(NUMERIC.iter().filter(|n| {
3311                let Datum::Numeric(n) = n else {
3312                    panic!("expected Numeric, found {n:?}");
3313                };
3314                // JSON doesn't support NaN or Infinite numbers.
3315                !(n.0.is_nan() || n.0.is_infinite())
3316            }));
3317            // TODO: Add List, Map.
3318            Row::pack_slice(&datums)
3319        });
3320        static UUID: LazyLock<Row> = LazyLock::new(|| {
3321            Row::pack_slice(&[
3322                Datum::Uuid(Uuid::from_u128(u128::MIN)),
3323                Datum::Uuid(Uuid::from_u128(u128::MAX)),
3324            ])
3325        });
3326        static ARRAY: LazyLock<BTreeMap<&'static ScalarType, Row>> = LazyLock::new(|| {
3327            let generate_row = |inner_type: &ScalarType| {
3328                let datums: Vec<_> = inner_type.interesting_datums().collect();
3329
3330                let mut row = Row::default();
3331                row.packer()
3332                    .try_push_array::<_, Datum<'static>>(
3333                        &[ArrayDimension {
3334                            lower_bound: 1,
3335                            length: 0,
3336                        }],
3337                        [],
3338                    )
3339                    .expect("failed to push empty array");
3340                row.packer()
3341                    .try_push_array(
3342                        &[ArrayDimension {
3343                            lower_bound: 1,
3344                            length: datums.len(),
3345                        }],
3346                        datums,
3347                    )
3348                    .expect("failed to push array");
3349
3350                row
3351            };
3352
3353            ScalarType::enumerate()
3354                .into_iter()
3355                .filter(|ty| !matches!(ty, ScalarType::Array(_)))
3356                .map(|ty| (ty, generate_row(ty)))
3357                .collect()
3358        });
3359        static EMPTY_ARRAY: LazyLock<Row> = LazyLock::new(|| {
3360            let mut row = Row::default();
3361            row.packer()
3362                .try_push_array::<_, Datum<'static>>(
3363                    &[ArrayDimension {
3364                        lower_bound: 1,
3365                        length: 0,
3366                    }],
3367                    [],
3368                )
3369                .expect("failed to push empty array");
3370            row
3371        });
3372        static LIST: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
3373        static RECORD: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
3374        static OID: LazyLock<Row> =
3375            LazyLock::new(|| Row::pack_slice(&[Datum::UInt32(u32::MIN), Datum::UInt32(u32::MAX)]));
3376        static MAP: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
3377        static INT2VECTOR: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
3378        static MZTIMESTAMP: LazyLock<Row> = LazyLock::new(|| {
3379            Row::pack_slice(&[
3380                Datum::MzTimestamp(crate::Timestamp::MIN),
3381                Datum::MzTimestamp(crate::Timestamp::MAX),
3382            ])
3383        });
3384        static RANGE: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
3385        static MZACLITEM: LazyLock<Row> = LazyLock::new(|| {
3386            Row::pack_slice(&[
3387                Datum::MzAclItem(MzAclItem {
3388                    grantee: RoleId::Public,
3389                    grantor: RoleId::Public,
3390                    acl_mode: AclMode::empty(),
3391                }),
3392                Datum::MzAclItem(MzAclItem {
3393                    grantee: RoleId::Public,
3394                    grantor: RoleId::Public,
3395                    acl_mode: AclMode::all(),
3396                }),
3397                Datum::MzAclItem(MzAclItem {
3398                    grantee: RoleId::User(42),
3399                    grantor: RoleId::Public,
3400                    acl_mode: AclMode::empty(),
3401                }),
3402                Datum::MzAclItem(MzAclItem {
3403                    grantee: RoleId::User(42),
3404                    grantor: RoleId::Public,
3405                    acl_mode: AclMode::all(),
3406                }),
3407                Datum::MzAclItem(MzAclItem {
3408                    grantee: RoleId::Public,
3409                    grantor: RoleId::User(42),
3410                    acl_mode: AclMode::empty(),
3411                }),
3412                Datum::MzAclItem(MzAclItem {
3413                    grantee: RoleId::Public,
3414                    grantor: RoleId::User(42),
3415                    acl_mode: AclMode::all(),
3416                }),
3417            ])
3418        });
3419        // aclitem has no binary encoding so we can't test it here.
3420        static ACLITEM: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
3421
3422        let iter: Box<dyn Iterator<Item = Datum<'static>>> = match self {
3423            ScalarType::Bool => Box::new((*BOOL).iter()),
3424            ScalarType::Int16 => Box::new((*INT16).iter()),
3425            ScalarType::Int32 => Box::new((*INT32).iter()),
3426            ScalarType::Int64 => Box::new((*INT64).iter()),
3427            ScalarType::UInt16 => Box::new((*UINT16).iter()),
3428            ScalarType::UInt32 => Box::new((*UINT32).iter()),
3429            ScalarType::UInt64 => Box::new((*UINT64).iter()),
3430            ScalarType::Float32 => Box::new((*FLOAT32).iter()),
3431            ScalarType::Float64 => Box::new((*FLOAT64).iter()),
3432            ScalarType::Numeric { .. } => Box::new((*NUMERIC).iter()),
3433            ScalarType::Date => Box::new((*DATE).iter()),
3434            ScalarType::Time => Box::new((*TIME).iter()),
3435            ScalarType::Timestamp { .. } => Box::new((*TIMESTAMP).iter()),
3436            ScalarType::TimestampTz { .. } => Box::new((*TIMESTAMPTZ).iter()),
3437            ScalarType::Interval => Box::new((*INTERVAL).iter()),
3438            ScalarType::PgLegacyChar => Box::new((*PGLEGACYCHAR).iter()),
3439            ScalarType::PgLegacyName => Box::new((*PGLEGACYNAME).iter()),
3440            ScalarType::Bytes => Box::new((*BYTES).iter()),
3441            ScalarType::String => Box::new((*STRING).iter().chain((*CHAR).iter())),
3442            ScalarType::Char { .. } => Box::new((*CHAR).iter()),
3443            ScalarType::VarChar { .. } => Box::new((*STRING).iter().chain((*CHAR).iter())),
3444            ScalarType::Jsonb => Box::new((*JSONB).iter()),
3445            ScalarType::Uuid => Box::new((*UUID).iter()),
3446            ScalarType::Array(inner_type) => {
3447                if matches!(inner_type.as_ref(), ScalarType::Array(_)) {
3448                    panic!("ScalarType::Array cannot have a nested Array");
3449                }
3450
3451                Box::new(
3452                    (*ARRAY)
3453                        .get(inner_type.as_ref())
3454                        .unwrap_or(&*EMPTY_ARRAY)
3455                        .iter(),
3456                )
3457            }
3458            ScalarType::List { .. } => Box::new((*LIST).iter()),
3459            ScalarType::Record { .. } => Box::new((*RECORD).iter()),
3460            ScalarType::Oid => Box::new((*OID).iter()),
3461            ScalarType::Map { .. } => Box::new((*MAP).iter()),
3462            ScalarType::RegProc => Box::new((*OID).iter()),
3463            ScalarType::RegType => Box::new((*OID).iter()),
3464            ScalarType::RegClass => Box::new((*OID).iter()),
3465            ScalarType::Int2Vector => Box::new((*INT2VECTOR).iter()),
3466            ScalarType::MzTimestamp => Box::new((*MZTIMESTAMP).iter()),
3467            ScalarType::Range { .. } => Box::new((*RANGE).iter()),
3468            ScalarType::MzAclItem { .. } => Box::new((*MZACLITEM).iter()),
3469            ScalarType::AclItem { .. } => Box::new((*ACLITEM).iter()),
3470        };
3471
3472        iter
3473    }
3474
3475    /// Returns all non-parameterized types and some versions of some
3476    /// parameterized types.
3477    pub fn enumerate() -> &'static [Self] {
3478        // TODO: Is there a compile-time way to make sure any new
3479        // non-parameterized types get added here?
3480        &[
3481            ScalarType::Bool,
3482            ScalarType::Int16,
3483            ScalarType::Int32,
3484            ScalarType::Int64,
3485            ScalarType::UInt16,
3486            ScalarType::UInt32,
3487            ScalarType::UInt64,
3488            ScalarType::Float32,
3489            ScalarType::Float64,
3490            ScalarType::Numeric {
3491                max_scale: Some(NumericMaxScale(
3492                    crate::adt::numeric::NUMERIC_DATUM_MAX_PRECISION,
3493                )),
3494            },
3495            ScalarType::Date,
3496            ScalarType::Time,
3497            ScalarType::Timestamp {
3498                precision: Some(TimestampPrecision(crate::adt::timestamp::MAX_PRECISION)),
3499            },
3500            ScalarType::Timestamp {
3501                precision: Some(TimestampPrecision(0)),
3502            },
3503            ScalarType::Timestamp { precision: None },
3504            ScalarType::TimestampTz {
3505                precision: Some(TimestampPrecision(crate::adt::timestamp::MAX_PRECISION)),
3506            },
3507            ScalarType::TimestampTz {
3508                precision: Some(TimestampPrecision(0)),
3509            },
3510            ScalarType::TimestampTz { precision: None },
3511            ScalarType::Interval,
3512            ScalarType::PgLegacyChar,
3513            ScalarType::Bytes,
3514            ScalarType::String,
3515            ScalarType::Char {
3516                length: Some(CharLength(1)),
3517            },
3518            ScalarType::VarChar { max_length: None },
3519            ScalarType::Jsonb,
3520            ScalarType::Uuid,
3521            ScalarType::Oid,
3522            ScalarType::RegProc,
3523            ScalarType::RegType,
3524            ScalarType::RegClass,
3525            ScalarType::Int2Vector,
3526            ScalarType::MzTimestamp,
3527            ScalarType::MzAclItem,
3528            // TODO: Fill in some variants of these.
3529            /*
3530            ScalarType::AclItem,
3531            ScalarType::Array(_),
3532            ScalarType::List {
3533                element_type: todo!(),
3534                custom_id: todo!(),
3535            },
3536            ScalarType::Record {
3537                fields: todo!(),
3538                custom_id: todo!(),
3539            },
3540            ScalarType::Map {
3541                value_type: todo!(),
3542                custom_id: todo!(),
3543            },
3544            ScalarType::Range {
3545                element_type: todo!(),
3546            }
3547            */
3548        ]
3549    }
3550
3551    /// Returns the appropriate element type for making a [`ScalarType::Array`] whose elements are
3552    /// of `self`.
3553    ///
3554    /// If the type is not compatible with making an array, returns in the error position.
3555    pub fn array_of_self_elem_type(self) -> Result<ScalarType, ScalarType> {
3556        match self {
3557            t @ (ScalarType::AclItem
3558            | ScalarType::Bool
3559            | ScalarType::Int16
3560            | ScalarType::Int32
3561            | ScalarType::Int64
3562            | ScalarType::UInt16
3563            | ScalarType::UInt32
3564            | ScalarType::UInt64
3565            | ScalarType::Float32
3566            | ScalarType::Float64
3567            | ScalarType::Numeric { .. }
3568            | ScalarType::Date
3569            | ScalarType::Time
3570            | ScalarType::Timestamp { .. }
3571            | ScalarType::TimestampTz { .. }
3572            | ScalarType::Interval
3573            | ScalarType::PgLegacyChar
3574            | ScalarType::PgLegacyName
3575            | ScalarType::Bytes
3576            | ScalarType::String
3577            | ScalarType::VarChar { .. }
3578            | ScalarType::Jsonb
3579            | ScalarType::Uuid
3580            | ScalarType::Record { .. }
3581            | ScalarType::Oid
3582            | ScalarType::RegProc
3583            | ScalarType::RegType
3584            | ScalarType::RegClass
3585            | ScalarType::Int2Vector
3586            | ScalarType::MzTimestamp
3587            | ScalarType::Range { .. }
3588            | ScalarType::MzAclItem { .. }) => Ok(t),
3589
3590            ScalarType::Array(elem) => Ok(elem.array_of_self_elem_type()?),
3591
3592            // https://github.com/MaterializeInc/database-issues/issues/2360
3593            t @ (ScalarType::Char { .. }
3594            // not sensible to put in arrays
3595            | ScalarType::Map { .. }
3596            | ScalarType::List { .. }) => Err(t),
3597        }
3598    }
3599}
3600
3601// See the chapter "Generating Recurisve Data" from the proptest book:
3602// https://altsysrq.github.io/proptest-book/proptest/tutorial/recursive.html
3603impl Arbitrary for ScalarType {
3604    type Parameters = ();
3605    type Strategy = BoxedStrategy<ScalarType>;
3606
3607    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
3608        // A strategy for generating the leaf cases of ScalarType
3609        let leaf = Union::new(vec![
3610            Just(ScalarType::Bool).boxed(),
3611            Just(ScalarType::UInt16).boxed(),
3612            Just(ScalarType::UInt32).boxed(),
3613            Just(ScalarType::UInt64).boxed(),
3614            Just(ScalarType::Int16).boxed(),
3615            Just(ScalarType::Int32).boxed(),
3616            Just(ScalarType::Int64).boxed(),
3617            Just(ScalarType::Float32).boxed(),
3618            Just(ScalarType::Float64).boxed(),
3619            any::<Option<NumericMaxScale>>()
3620                .prop_map(|max_scale| ScalarType::Numeric { max_scale })
3621                .boxed(),
3622            Just(ScalarType::Date).boxed(),
3623            Just(ScalarType::Time).boxed(),
3624            any::<Option<TimestampPrecision>>()
3625                .prop_map(|precision| ScalarType::Timestamp { precision })
3626                .boxed(),
3627            any::<Option<TimestampPrecision>>()
3628                .prop_map(|precision| ScalarType::TimestampTz { precision })
3629                .boxed(),
3630            Just(ScalarType::MzTimestamp).boxed(),
3631            Just(ScalarType::Interval).boxed(),
3632            Just(ScalarType::PgLegacyChar).boxed(),
3633            Just(ScalarType::Bytes).boxed(),
3634            Just(ScalarType::String).boxed(),
3635            any::<Option<CharLength>>()
3636                .prop_map(|length| ScalarType::Char { length })
3637                .boxed(),
3638            any::<Option<VarCharMaxLength>>()
3639                .prop_map(|max_length| ScalarType::VarChar { max_length })
3640                .boxed(),
3641            Just(ScalarType::PgLegacyName).boxed(),
3642            Just(ScalarType::Jsonb).boxed(),
3643            Just(ScalarType::Uuid).boxed(),
3644            Just(ScalarType::AclItem).boxed(),
3645            Just(ScalarType::MzAclItem).boxed(),
3646            Just(ScalarType::Oid).boxed(),
3647            Just(ScalarType::RegProc).boxed(),
3648            Just(ScalarType::RegType).boxed(),
3649            Just(ScalarType::RegClass).boxed(),
3650            Just(ScalarType::Int2Vector).boxed(),
3651        ])
3652        // None of the leaf ScalarTypes types are really "simpler" than others
3653        // so don't waste time trying to shrink.
3654        .no_shrink()
3655        .boxed();
3656
3657        // There are a limited set of types we support in ranges.
3658        let range_leaf = Union::new(vec![
3659            Just(ScalarType::Int32).boxed(),
3660            Just(ScalarType::Int64).boxed(),
3661            Just(ScalarType::Date).boxed(),
3662            any::<Option<NumericMaxScale>>()
3663                .prop_map(|max_scale| ScalarType::Numeric { max_scale })
3664                .boxed(),
3665            any::<Option<TimestampPrecision>>()
3666                .prop_map(|precision| ScalarType::Timestamp { precision })
3667                .boxed(),
3668            any::<Option<TimestampPrecision>>()
3669                .prop_map(|precision| ScalarType::TimestampTz { precision })
3670                .boxed(),
3671        ]);
3672        let range = range_leaf
3673            .prop_map(|inner_type| ScalarType::Range {
3674                element_type: Box::new(inner_type),
3675            })
3676            .boxed();
3677
3678        // The Array type is not recursive, so we define it separately.
3679        let array = leaf
3680            .clone()
3681            .prop_map(|inner_type| ScalarType::Array(Box::new(inner_type)))
3682            .boxed();
3683
3684        let leaf = Union::new_weighted(vec![(30, leaf), (1, array), (1, range)]);
3685
3686        leaf.prop_recursive(2, 3, 5, |inner| {
3687            Union::new(vec![
3688                // List
3689                (inner.clone(), any::<Option<CatalogItemId>>())
3690                    .prop_map(|(x, id)| ScalarType::List {
3691                        element_type: Box::new(x),
3692                        custom_id: id,
3693                    })
3694                    .boxed(),
3695                // Map
3696                (inner.clone(), any::<Option<CatalogItemId>>())
3697                    .prop_map(|(x, id)| ScalarType::Map {
3698                        value_type: Box::new(x),
3699                        custom_id: id,
3700                    })
3701                    .boxed(),
3702                // Record
3703                {
3704                    // Now we have to use `inner` to create a Record type. First we
3705                    // create strategy that creates ColumnType.
3706                    let column_type_strat =
3707                        (inner, any::<bool>()).prop_map(|(scalar_type, nullable)| ColumnType {
3708                            scalar_type,
3709                            nullable,
3710                        });
3711
3712                    // Then we use that to create the fields of the record case.
3713                    // fields has type vec<(ColumnName,ColumnType)>
3714                    let fields_strat =
3715                        prop::collection::vec((any::<ColumnName>(), column_type_strat), 0..10);
3716
3717                    // Now we combine it with the default strategies to get Records.
3718                    (fields_strat, any::<Option<CatalogItemId>>())
3719                        .prop_map(|(fields, custom_id)| ScalarType::Record {
3720                            fields: fields.into(),
3721                            custom_id,
3722                        })
3723                        .boxed()
3724                },
3725            ])
3726        })
3727        .boxed()
3728    }
3729}
3730
3731static EMPTY_ARRAY_ROW: LazyLock<Row> = LazyLock::new(|| {
3732    let mut row = Row::default();
3733    row.packer()
3734        .try_push_array(&[], iter::empty::<Datum>())
3735        .expect("array known to be valid");
3736    row
3737});
3738
3739static EMPTY_LIST_ROW: LazyLock<Row> = LazyLock::new(|| {
3740    let mut row = Row::default();
3741    row.packer().push_list(iter::empty::<Datum>());
3742    row
3743});
3744
3745static EMPTY_MAP_ROW: LazyLock<Row> = LazyLock::new(|| {
3746    let mut row = Row::default();
3747    row.packer().push_dict(iter::empty::<(_, Datum)>());
3748    row
3749});
3750
3751impl Datum<'_> {
3752    pub fn empty_array() -> Datum<'static> {
3753        EMPTY_ARRAY_ROW.unpack_first()
3754    }
3755
3756    pub fn empty_list() -> Datum<'static> {
3757        EMPTY_LIST_ROW.unpack_first()
3758    }
3759
3760    pub fn empty_map() -> Datum<'static> {
3761        EMPTY_MAP_ROW.unpack_first()
3762    }
3763}
3764
3765/// A mirror type for [`Datum`] that can be proptest-generated.
3766#[derive(Debug, PartialEq, Clone)]
3767pub enum PropDatum {
3768    Null,
3769    Bool(bool),
3770    Int16(i16),
3771    Int32(i32),
3772    Int64(i64),
3773    UInt8(u8),
3774    UInt16(u16),
3775    UInt32(u32),
3776    UInt64(u64),
3777    Float32(f32),
3778    Float64(f64),
3779
3780    Date(Date),
3781    Time(chrono::NaiveTime),
3782    Timestamp(CheckedTimestamp<chrono::NaiveDateTime>),
3783    TimestampTz(CheckedTimestamp<chrono::DateTime<chrono::Utc>>),
3784    MzTimestamp(u64),
3785
3786    Interval(Interval),
3787    Numeric(Numeric),
3788
3789    Bytes(Vec<u8>),
3790    String(String),
3791
3792    Array(PropArray),
3793    List(PropList),
3794    Map(PropDict),
3795    Record(PropDict),
3796    Range(PropRange),
3797
3798    AclItem(AclItem),
3799    MzAclItem(MzAclItem),
3800
3801    JsonNull,
3802    Uuid(Uuid),
3803    Dummy,
3804}
3805
3806impl std::cmp::Eq for PropDatum {}
3807
3808impl PartialOrd for PropDatum {
3809    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
3810        Some(self.cmp(other))
3811    }
3812}
3813
3814impl Ord for PropDatum {
3815    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
3816        Datum::from(self).cmp(&Datum::from(other))
3817    }
3818}
3819
3820/// Generate an arbitrary [`PropDatum`].
3821pub fn arb_datum() -> BoxedStrategy<PropDatum> {
3822    let leaf = Union::new(vec![
3823        Just(PropDatum::Null).boxed(),
3824        any::<bool>().prop_map(PropDatum::Bool).boxed(),
3825        any::<i16>().prop_map(PropDatum::Int16).boxed(),
3826        any::<i32>().prop_map(PropDatum::Int32).boxed(),
3827        any::<i64>().prop_map(PropDatum::Int64).boxed(),
3828        any::<u16>().prop_map(PropDatum::UInt16).boxed(),
3829        any::<u32>().prop_map(PropDatum::UInt32).boxed(),
3830        any::<u64>().prop_map(PropDatum::UInt64).boxed(),
3831        any::<f32>().prop_map(PropDatum::Float32).boxed(),
3832        any::<f64>().prop_map(PropDatum::Float64).boxed(),
3833        arb_date().prop_map(PropDatum::Date).boxed(),
3834        add_arb_duration(chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())
3835            .prop_map(PropDatum::Time)
3836            .boxed(),
3837        arb_naive_date_time()
3838            .prop_map(|t| PropDatum::Timestamp(CheckedTimestamp::from_timestamplike(t).unwrap()))
3839            .boxed(),
3840        arb_utc_date_time()
3841            .prop_map(|t| PropDatum::TimestampTz(CheckedTimestamp::from_timestamplike(t).unwrap()))
3842            .boxed(),
3843        any::<Interval>().prop_map(PropDatum::Interval).boxed(),
3844        arb_numeric().prop_map(PropDatum::Numeric).boxed(),
3845        prop::collection::vec(any::<u8>(), 1024)
3846            .prop_map(PropDatum::Bytes)
3847            .boxed(),
3848        ".*".prop_map(PropDatum::String).boxed(),
3849        Just(PropDatum::JsonNull).boxed(),
3850        any::<[u8; 16]>()
3851            .prop_map(|x| PropDatum::Uuid(Uuid::from_bytes(x)))
3852            .boxed(),
3853        arb_range(arb_range_data())
3854            .prop_map(PropDatum::Range)
3855            .boxed(),
3856        Just(PropDatum::Dummy).boxed(),
3857    ]);
3858    leaf.prop_recursive(3, 8, 16, |inner| {
3859        Union::new(vec![
3860            arb_array(inner.clone()).prop_map(PropDatum::Array).boxed(),
3861            arb_list(inner.clone()).prop_map(PropDatum::List).boxed(),
3862            arb_dict(inner).prop_map(PropDatum::Map).boxed(),
3863        ])
3864    })
3865    .boxed()
3866}
3867
3868/// Generates an arbitrary [`PropDatum`] for the provided [`ColumnType`].
3869pub fn arb_datum_for_column(column_type: ColumnType) -> impl Strategy<Value = PropDatum> {
3870    let strat = arb_datum_for_scalar(column_type.scalar_type);
3871
3872    if column_type.nullable {
3873        Union::new_weighted(vec![(1, Just(PropDatum::Null).boxed()), (5, strat.boxed())]).boxed()
3874    } else {
3875        strat.boxed()
3876    }
3877}
3878
3879/// Generates an arbitrary [`PropDatum`] for the provided [`ScalarType`].
3880pub fn arb_datum_for_scalar(scalar_type: ScalarType) -> impl Strategy<Value = PropDatum> {
3881    match scalar_type {
3882        ScalarType::Bool => any::<bool>().prop_map(PropDatum::Bool).boxed(),
3883        ScalarType::Int16 => any::<i16>().prop_map(PropDatum::Int16).boxed(),
3884        ScalarType::Int32 => any::<i32>().prop_map(PropDatum::Int32).boxed(),
3885        ScalarType::Int64 => any::<i64>().prop_map(PropDatum::Int64).boxed(),
3886        ScalarType::PgLegacyChar => any::<u8>().prop_map(PropDatum::UInt8).boxed(),
3887        ScalarType::UInt16 => any::<u16>().prop_map(PropDatum::UInt16).boxed(),
3888        ScalarType::UInt32
3889        | ScalarType::Oid
3890        | ScalarType::RegClass
3891        | ScalarType::RegProc
3892        | ScalarType::RegType => any::<u32>().prop_map(PropDatum::UInt32).boxed(),
3893        ScalarType::UInt64 => any::<u64>().prop_map(PropDatum::UInt64).boxed(),
3894        ScalarType::Float32 => any::<f32>().prop_map(PropDatum::Float32).boxed(),
3895        ScalarType::Float64 => any::<f64>().prop_map(PropDatum::Float64).boxed(),
3896        ScalarType::Numeric { .. } => arb_numeric().prop_map(PropDatum::Numeric).boxed(),
3897        ScalarType::String
3898        | ScalarType::PgLegacyName
3899        | ScalarType::Char { length: None }
3900        | ScalarType::VarChar { max_length: None } => ".*".prop_map(PropDatum::String).boxed(),
3901        ScalarType::Char {
3902            length: Some(length),
3903        } => {
3904            let max_len = usize::cast_from(length.into_u32()).max(1);
3905            prop::collection::vec(any::<char>(), 0..max_len)
3906                .prop_map(move |chars| {
3907                    // `Char`s are fixed sized strings padded with blanks.
3908                    let num_blanks = max_len - chars.len();
3909                    let s = chars
3910                        .into_iter()
3911                        .chain(std::iter::repeat(' ').take(num_blanks))
3912                        .collect();
3913                    PropDatum::String(s)
3914                })
3915                .boxed()
3916        }
3917        ScalarType::VarChar {
3918            max_length: Some(length),
3919        } => {
3920            let max_len = usize::cast_from(length.into_u32()).max(1);
3921            prop::collection::vec(any::<char>(), 0..max_len)
3922                .prop_map(|chars| PropDatum::String(chars.into_iter().collect()))
3923                .boxed()
3924        }
3925        ScalarType::Bytes => prop::collection::vec(any::<u8>(), 300)
3926            .prop_map(PropDatum::Bytes)
3927            .boxed(),
3928        ScalarType::Date => arb_date().prop_map(PropDatum::Date).boxed(),
3929        ScalarType::Time => add_arb_duration(chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())
3930            .prop_map(PropDatum::Time)
3931            .boxed(),
3932        ScalarType::Timestamp { .. } => arb_naive_date_time()
3933            .prop_map(|t| PropDatum::Timestamp(CheckedTimestamp::from_timestamplike(t).unwrap()))
3934            .boxed(),
3935        ScalarType::TimestampTz { .. } => arb_utc_date_time()
3936            .prop_map(|t| PropDatum::TimestampTz(CheckedTimestamp::from_timestamplike(t).unwrap()))
3937            .boxed(),
3938        ScalarType::MzTimestamp => any::<u64>().prop_map(PropDatum::MzTimestamp).boxed(),
3939        ScalarType::Interval => any::<Interval>().prop_map(PropDatum::Interval).boxed(),
3940        ScalarType::Uuid => any::<[u8; 16]>()
3941            .prop_map(|x| PropDatum::Uuid(Uuid::from_bytes(x)))
3942            .boxed(),
3943        ScalarType::AclItem => any::<AclItem>().prop_map(PropDatum::AclItem).boxed(),
3944        ScalarType::MzAclItem => any::<MzAclItem>().prop_map(PropDatum::MzAclItem).boxed(),
3945        ScalarType::Range { element_type } => {
3946            let data_strat = (
3947                arb_datum_for_scalar(*element_type.clone()),
3948                arb_datum_for_scalar(*element_type),
3949            );
3950            arb_range(data_strat).prop_map(PropDatum::Range).boxed()
3951        }
3952        ScalarType::List { element_type, .. } => arb_list(arb_datum_for_scalar(*element_type))
3953            .prop_map(PropDatum::List)
3954            .boxed(),
3955        ScalarType::Array(element_type) => arb_array(arb_datum_for_scalar(*element_type))
3956            .prop_map(PropDatum::Array)
3957            .boxed(),
3958        ScalarType::Int2Vector => arb_array(any::<i16>().prop_map(PropDatum::Int16).boxed())
3959            .prop_map(PropDatum::Array)
3960            .boxed(),
3961        ScalarType::Map { value_type, .. } => arb_dict(arb_datum_for_scalar(*value_type))
3962            .prop_map(PropDatum::Map)
3963            .boxed(),
3964        ScalarType::Record { fields, .. } => {
3965            let field_strats = fields.iter().map(|(name, ty)| {
3966                (
3967                    name.to_string(),
3968                    arb_datum_for_scalar(ty.scalar_type.clone()),
3969                )
3970            });
3971            arb_record(field_strats).prop_map(PropDatum::Record).boxed()
3972        }
3973        ScalarType::Jsonb => {
3974            let int_value = any::<i128>()
3975                .prop_map(|v| Numeric::try_from(v).unwrap())
3976                .boxed();
3977            // Numerics only support up to 39 digits.
3978            let float_value = (1e-39f64..1e39)
3979                .prop_map(|v| Numeric::try_from(v).unwrap())
3980                .boxed();
3981            // JSON does not support NaN or Infinite numbers, so we can't use
3982            // the normal `arb_numeric` strategy.
3983            let json_number = Union::new(vec![int_value, float_value]);
3984
3985            let json_leaf = Union::new(vec![
3986                any::<()>().prop_map(|_| PropDatum::JsonNull).boxed(),
3987                any::<bool>().prop_map(PropDatum::Bool).boxed(),
3988                json_number.prop_map(PropDatum::Numeric).boxed(),
3989                ".*".prop_map(PropDatum::String).boxed(),
3990            ]);
3991            json_leaf
3992                .prop_recursive(4, 32, 8, |element| {
3993                    Union::new(vec![
3994                        prop::collection::vec(element.clone(), 0..16)
3995                            .prop_map(|elements| {
3996                                let datums: Vec<_> = elements.iter().map(|pd| pd.into()).collect();
3997                                let mut row = Row::default();
3998                                row.packer().push_list(datums.iter());
3999                                PropDatum::List(PropList(row, elements))
4000                            })
4001                            .boxed(),
4002                        prop::collection::hash_map(".*", element, 0..16)
4003                            .prop_map(|elements| {
4004                                let mut elements: Vec<_> = elements.into_iter().collect();
4005                                elements.sort_by_key(|(k, _)| k.clone());
4006                                elements.dedup_by_key(|(k, _)| k.clone());
4007                                let mut row = Row::default();
4008                                let entry_iter =
4009                                    elements.iter().map(|(k, v)| (k.as_str(), Datum::from(v)));
4010                                row.packer().push_dict(entry_iter);
4011                                PropDatum::Map(PropDict(row, elements))
4012                            })
4013                            .boxed(),
4014                    ])
4015                })
4016                .boxed()
4017        }
4018    }
4019}
4020
4021/// Generates an arbitrary [`NaiveDateTime`].
4022pub fn arb_naive_date_time() -> impl Strategy<Value = NaiveDateTime> {
4023    add_arb_duration(chrono::DateTime::from_timestamp(0, 0).unwrap().naive_utc())
4024}
4025
4026/// Generates an arbitrary [`DateTime`] in [`Utc`].
4027pub fn arb_utc_date_time() -> impl Strategy<Value = DateTime<Utc>> {
4028    add_arb_duration(chrono::Utc.timestamp_opt(0, 0).unwrap())
4029}
4030
4031fn arb_array_dimension() -> BoxedStrategy<ArrayDimension> {
4032    (1..4_usize)
4033        .prop_map(|length| ArrayDimension {
4034            lower_bound: 1,
4035            length,
4036        })
4037        .boxed()
4038}
4039
4040#[derive(Debug, PartialEq, Clone)]
4041pub struct PropArray(Row, Vec<PropDatum>);
4042
4043fn arb_array(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropArray> {
4044    // Elements in Arrays can always be Null.
4045    let element_strategy = Union::new_weighted(vec![
4046        (20, element_strategy),
4047        (1, Just(PropDatum::Null).boxed()),
4048    ]);
4049
4050    prop::collection::vec(
4051        arb_array_dimension(),
4052        1..usize::from(crate::adt::array::MAX_ARRAY_DIMENSIONS),
4053    )
4054    .prop_flat_map(move |dimensions| {
4055        let n_elts: usize = dimensions.iter().map(|d| d.length).product();
4056        (
4057            Just(dimensions),
4058            prop::collection::vec(element_strategy.clone(), n_elts),
4059        )
4060    })
4061    .prop_map(|(dimensions, elements)| {
4062        let element_datums: Vec<Datum<'_>> = elements.iter().map(|pd| pd.into()).collect();
4063        let mut row = Row::default();
4064        row.packer()
4065            .try_push_array(&dimensions, element_datums)
4066            .unwrap();
4067        PropArray(row, elements)
4068    })
4069    .boxed()
4070}
4071
4072#[derive(Debug, PartialEq, Clone)]
4073pub struct PropList(Row, Vec<PropDatum>);
4074
4075fn arb_list(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropList> {
4076    // Elements in Lists can always be Null.
4077    let element_strategy = Union::new_weighted(vec![
4078        (20, element_strategy),
4079        (1, Just(PropDatum::Null).boxed()),
4080    ]);
4081
4082    prop::collection::vec(element_strategy, 1..50)
4083        .prop_map(|elements| {
4084            let element_datums: Vec<Datum<'_>> = elements.iter().map(|pd| pd.into()).collect();
4085            let mut row = Row::default();
4086            row.packer().push_list(element_datums.iter());
4087            PropList(row, elements)
4088        })
4089        .boxed()
4090}
4091
4092#[derive(Debug, PartialEq, Clone)]
4093pub struct PropRange(
4094    Row,
4095    Option<(
4096        (Option<Box<PropDatum>>, bool),
4097        (Option<Box<PropDatum>>, bool),
4098    )>,
4099);
4100
4101pub fn arb_range_type() -> Union<BoxedStrategy<ScalarType>> {
4102    Union::new(vec![
4103        Just(ScalarType::Int32).boxed(),
4104        Just(ScalarType::Int64).boxed(),
4105        Just(ScalarType::Date).boxed(),
4106    ])
4107}
4108
4109fn arb_range_data() -> Union<BoxedStrategy<(PropDatum, PropDatum)>> {
4110    Union::new(vec![
4111        (
4112            any::<i32>().prop_map(PropDatum::Int32),
4113            any::<i32>().prop_map(PropDatum::Int32),
4114        )
4115            .boxed(),
4116        (
4117            any::<i64>().prop_map(PropDatum::Int64),
4118            any::<i64>().prop_map(PropDatum::Int64),
4119        )
4120            .boxed(),
4121        (
4122            arb_date().prop_map(PropDatum::Date),
4123            arb_date().prop_map(PropDatum::Date),
4124        )
4125            .boxed(),
4126    ])
4127}
4128
4129fn arb_range(
4130    data: impl Strategy<Value = (PropDatum, PropDatum)> + 'static,
4131) -> BoxedStrategy<PropRange> {
4132    (
4133        any::<u16>(),
4134        any::<bool>(),
4135        any::<bool>(),
4136        any::<bool>(),
4137        any::<bool>(),
4138        data,
4139    )
4140        .prop_map(
4141            |(split, lower_inf, lower_inc, upper_inf, upper_inc, (a, b))| {
4142                let mut row = Row::default();
4143                let mut packer = row.packer();
4144                let r = if split % 32 == 0 {
4145                    packer
4146                        .push_range(Range::new(None))
4147                        .expect("pushing empty ranges never fails");
4148                    None
4149                } else {
4150                    let b_is_lower = Datum::from(&b) < Datum::from(&a);
4151
4152                    let (lower, upper) = if b_is_lower { (b, a) } else { (a, b) };
4153                    let mut range = Range::new(Some((
4154                        RangeLowerBound {
4155                            inclusive: lower_inc,
4156                            bound: if lower_inf {
4157                                None
4158                            } else {
4159                                Some(Datum::from(&lower))
4160                            },
4161                        },
4162                        RangeUpperBound {
4163                            inclusive: upper_inc,
4164                            bound: if upper_inf {
4165                                None
4166                            } else {
4167                                Some(Datum::from(&upper))
4168                            },
4169                        },
4170                    )));
4171
4172                    range.canonicalize().unwrap();
4173
4174                    // Extract canonicalized state; pretend the range was empty
4175                    // if the bounds are rewritten.
4176                    let (empty, lower_inf, lower_inc, upper_inf, upper_inc) = match range.inner {
4177                        None => (true, false, false, false, false),
4178                        Some(inner) => (
4179                            false
4180                                || match inner.lower.bound {
4181                                    Some(b) => b != Datum::from(&lower),
4182                                    None => !lower_inf,
4183                                }
4184                                || match inner.upper.bound {
4185                                    Some(b) => b != Datum::from(&upper),
4186                                    None => !upper_inf,
4187                                },
4188                            inner.lower.bound.is_none(),
4189                            inner.lower.inclusive,
4190                            inner.upper.bound.is_none(),
4191                            inner.upper.inclusive,
4192                        ),
4193                    };
4194
4195                    if empty {
4196                        packer.push_range(Range { inner: None }).unwrap();
4197                        None
4198                    } else {
4199                        packer.push_range(range).unwrap();
4200                        Some((
4201                            (
4202                                if lower_inf {
4203                                    None
4204                                } else {
4205                                    Some(Box::new(lower))
4206                                },
4207                                lower_inc,
4208                            ),
4209                            (
4210                                if upper_inf {
4211                                    None
4212                                } else {
4213                                    Some(Box::new(upper))
4214                                },
4215                                upper_inc,
4216                            ),
4217                        ))
4218                    }
4219                };
4220
4221                PropRange(row, r)
4222            },
4223        )
4224        .boxed()
4225}
4226
4227#[derive(Debug, PartialEq, Clone)]
4228pub struct PropDict(Row, Vec<(String, PropDatum)>);
4229
4230fn arb_dict(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropDict> {
4231    // Elements in Maps can always be Null.
4232    let element_strategy = Union::new_weighted(vec![
4233        (20, element_strategy),
4234        (1, Just(PropDatum::Null).boxed()),
4235    ]);
4236
4237    prop::collection::vec((".*", element_strategy), 1..50)
4238        .prop_map(|mut entries| {
4239            entries.sort_by_key(|(k, _)| k.clone());
4240            entries.dedup_by_key(|(k, _)| k.clone());
4241            let mut row = Row::default();
4242            let entry_iter = entries.iter().map(|(k, v)| (k.as_str(), Datum::from(v)));
4243            row.packer().push_dict(entry_iter);
4244            PropDict(row, entries)
4245        })
4246        .boxed()
4247}
4248
4249fn arb_record(
4250    fields: impl Iterator<Item = (String, BoxedStrategy<PropDatum>)>,
4251) -> BoxedStrategy<PropDict> {
4252    let (names, strategies): (Vec<_>, Vec<_>) = fields.unzip();
4253
4254    strategies
4255        .prop_map(move |x| {
4256            let mut row = Row::default();
4257            row.packer().push_list(x.iter().map(Datum::from));
4258            let entries: Vec<_> = names.clone().into_iter().zip(x).collect();
4259            PropDict(row, entries)
4260        })
4261        .boxed()
4262}
4263
4264fn arb_date() -> BoxedStrategy<Date> {
4265    (Date::LOW_DAYS..Date::HIGH_DAYS)
4266        .prop_map(move |days| Date::from_pg_epoch(days).unwrap())
4267        .boxed()
4268}
4269
4270pub fn add_arb_duration<T: 'static + Copy + Add<chrono::Duration> + std::fmt::Debug>(
4271    to: T,
4272) -> BoxedStrategy<T::Output>
4273where
4274    T::Output: std::fmt::Debug,
4275{
4276    let lower = LOW_DATE
4277        .and_hms_opt(0, 0, 0)
4278        .unwrap()
4279        .and_utc()
4280        .timestamp_micros();
4281    let upper = HIGH_DATE
4282        .and_hms_opt(0, 0, 0)
4283        .unwrap()
4284        .and_utc()
4285        .timestamp_micros();
4286    (lower..upper)
4287        .prop_map(move |v| to + chrono::Duration::microseconds(v))
4288        .boxed()
4289}
4290
4291pub(crate) fn arb_numeric() -> BoxedStrategy<Numeric> {
4292    let int_value = any::<i128>()
4293        .prop_map(|v| Numeric::try_from(v).unwrap())
4294        .boxed();
4295    let float_value = (-1e39f64..1e39)
4296        .prop_map(|v| Numeric::try_from(v).unwrap())
4297        .boxed();
4298
4299    // While these strategies are subsets of the ones above, including them
4300    // helps us generate a more realistic set of values.
4301    let tiny_floats = ((-10.0..10.0), (1u32..10))
4302        .prop_map(|(v, num_digits)| {
4303            // Truncate to a small number of digits.
4304            let num_digits: f64 = 10u32.pow(num_digits).try_into().unwrap();
4305            let trunc = f64::trunc(v * num_digits) / num_digits;
4306            Numeric::try_from(trunc).unwrap()
4307        })
4308        .boxed();
4309    let small_ints = (-1_000_000..1_000_000)
4310        .prop_map(|v| Numeric::try_from(v).unwrap())
4311        .boxed();
4312    let small_floats = (-1_000_000.0..1_000_000.0)
4313        .prop_map(|v| Numeric::try_from(v).unwrap())
4314        .boxed();
4315
4316    Union::new_weighted(vec![
4317        (20, tiny_floats),
4318        (20, small_ints),
4319        (20, small_floats),
4320        (10, int_value),
4321        (10, float_value),
4322        (1, Just(Numeric::infinity()).boxed()),
4323        (1, Just(-Numeric::infinity()).boxed()),
4324        (1, Just(Numeric::nan()).boxed()),
4325        (1, Just(Numeric::zero()).boxed()),
4326    ])
4327    .boxed()
4328}
4329
4330impl<'a> From<&'a PropDatum> for Datum<'a> {
4331    #[inline]
4332    fn from(pd: &'a PropDatum) -> Self {
4333        use PropDatum::*;
4334        match pd {
4335            Null => Datum::Null,
4336            Bool(b) => Datum::from(*b),
4337            Int16(i) => Datum::from(*i),
4338            Int32(i) => Datum::from(*i),
4339            Int64(i) => Datum::from(*i),
4340            UInt8(u) => Datum::from(*u),
4341            UInt16(u) => Datum::from(*u),
4342            UInt32(u) => Datum::from(*u),
4343            UInt64(u) => Datum::from(*u),
4344            Float32(f) => Datum::from(*f),
4345            Float64(f) => Datum::from(*f),
4346            Date(d) => Datum::from(*d),
4347            Time(t) => Datum::from(*t),
4348            Timestamp(t) => Datum::from(*t),
4349            TimestampTz(t) => Datum::from(*t),
4350            MzTimestamp(t) => Datum::MzTimestamp((*t).into()),
4351            Interval(i) => Datum::from(*i),
4352            Numeric(s) => Datum::from(*s),
4353            Bytes(b) => Datum::from(&b[..]),
4354            String(s) => Datum::from(s.as_str()),
4355            Array(PropArray(row, _)) => {
4356                let array = row.unpack_first().unwrap_array();
4357                Datum::Array(array)
4358            }
4359            List(PropList(row, _)) => {
4360                let list = row.unpack_first().unwrap_list();
4361                Datum::List(list)
4362            }
4363            Map(PropDict(row, _)) => {
4364                let map = row.unpack_first().unwrap_map();
4365                Datum::Map(map)
4366            }
4367            Record(PropDict(row, _)) => {
4368                let list = row.unpack_first().unwrap_list();
4369                Datum::List(list)
4370            }
4371            Range(PropRange(row, _)) => {
4372                let d = row.unpack_first();
4373                assert!(matches!(d, Datum::Range(_)));
4374                d
4375            }
4376            AclItem(i) => Datum::AclItem(*i),
4377            MzAclItem(i) => Datum::MzAclItem(*i),
4378            JsonNull => Datum::JsonNull,
4379            Uuid(u) => Datum::from(*u),
4380            Dummy => Datum::Dummy,
4381        }
4382    }
4383}
4384
4385#[mz_ore::test]
4386fn verify_base_eq_record_nullability() {
4387    let s1 = ScalarType::Record {
4388        fields: [(
4389            "c".into(),
4390            ColumnType {
4391                scalar_type: ScalarType::Bool,
4392                nullable: true,
4393            },
4394        )]
4395        .into(),
4396        custom_id: None,
4397    };
4398    let s2 = ScalarType::Record {
4399        fields: [(
4400            "c".into(),
4401            ColumnType {
4402                scalar_type: ScalarType::Bool,
4403                nullable: false,
4404            },
4405        )]
4406        .into(),
4407        custom_id: None,
4408    };
4409    let s3 = ScalarType::Record {
4410        fields: [].into(),
4411        custom_id: None,
4412    };
4413    assert!(s1.base_eq(&s2));
4414    assert!(!s1.base_eq(&s3));
4415}
4416
4417#[cfg(test)]
4418mod tests {
4419    use mz_ore::assert_ok;
4420    use mz_proto::protobuf_roundtrip;
4421
4422    use super::*;
4423
4424    proptest! {
4425       #[mz_ore::test]
4426       #[cfg_attr(miri, ignore)] // too slow
4427        fn scalar_type_protobuf_roundtrip(expect in any::<ScalarType>() ) {
4428            let actual = protobuf_roundtrip::<_, ProtoScalarType>(&expect);
4429            assert_ok!(actual);
4430            assert_eq!(actual.unwrap(), expect);
4431        }
4432    }
4433
4434    proptest! {
4435        #[mz_ore::test]
4436        #[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `decContextDefault` on OS `linux`
4437        fn array_packing_unpacks_correctly(array in arb_array(arb_datum())) {
4438            let PropArray(row, elts) = array;
4439            let datums: Vec<Datum<'_>> = elts.iter().map(|e| e.into()).collect();
4440            let unpacked_datums: Vec<Datum<'_>> = row.unpack_first().unwrap_array().elements().iter().collect();
4441            assert_eq!(unpacked_datums, datums);
4442        }
4443
4444        #[mz_ore::test]
4445        #[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `decContextDefault` on OS `linux`
4446        fn list_packing_unpacks_correctly(array in arb_list(arb_datum())) {
4447            let PropList(row, elts) = array;
4448            let datums: Vec<Datum<'_>> = elts.iter().map(|e| e.into()).collect();
4449            let unpacked_datums: Vec<Datum<'_>> = row.unpack_first().unwrap_list().iter().collect();
4450            assert_eq!(unpacked_datums, datums);
4451        }
4452
4453        #[mz_ore::test]
4454        #[cfg_attr(miri, ignore)] // too slow
4455        fn dict_packing_unpacks_correctly(array in arb_dict(arb_datum())) {
4456            let PropDict(row, elts) = array;
4457            let datums: Vec<(&str, Datum<'_>)> = elts.iter().map(|(k, e)| (k.as_str(), e.into())).collect();
4458            let unpacked_datums: Vec<(&str, Datum<'_>)> = row.unpack_first().unwrap_map().iter().collect();
4459            assert_eq!(unpacked_datums, datums);
4460        }
4461
4462        #[mz_ore::test]
4463        #[cfg_attr(miri, ignore)] // too slow
4464        fn row_packing_roundtrips_single_valued(prop_datums in prop::collection::vec(arb_datum(), 1..100)) {
4465            let datums: Vec<Datum<'_>> = prop_datums.iter().map(|pd| pd.into()).collect();
4466            let row = Row::pack(&datums);
4467            let unpacked = row.unpack();
4468            assert_eq!(datums, unpacked);
4469        }
4470
4471        #[mz_ore::test]
4472        #[cfg_attr(miri, ignore)] // too slow
4473        fn range_packing_unpacks_correctly(range in arb_range(arb_range_data())) {
4474            let PropRange(row, prop_range) = range;
4475            let row = row.unpack_first();
4476            let d = row.unwrap_range();
4477
4478            let (((prop_lower, prop_lower_inc), (prop_upper, prop_upper_inc)), crate::adt::range::RangeInner {lower, upper}) = match (prop_range, d.inner) {
4479                (Some(prop_values), Some(inner_range)) => (prop_values, inner_range),
4480                (None, None) => return Ok(()),
4481                _ => panic!("inequivalent row packing"),
4482            };
4483
4484            for (prop_bound, prop_bound_inc, inner_bound, inner_bound_inc) in [
4485                (prop_lower, prop_lower_inc, lower.bound, lower.inclusive),
4486                (prop_upper, prop_upper_inc, upper.bound, upper.inclusive),
4487            ] {
4488                assert_eq!(prop_bound_inc, inner_bound_inc);
4489                match (prop_bound, inner_bound) {
4490                    (None, None) => continue,
4491                    (Some(p), Some(b)) => {
4492                        assert_eq!(Datum::from(&*p), b);
4493                    }
4494                    _ => panic!("inequivalent row packing"),
4495                }
4496            }
4497        }
4498    }
4499}