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