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