mz_repr/
scalar.rs

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