Skip to main content

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