Skip to main content

mz_repr/
scalar.rs

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