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