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