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, separated};
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/// Trait for SQL container types whose element/value type can be extracted
1937/// from or wrapped into a [`SqlScalarType`].
1938///
1939/// Implemented by [`DatumList`], [`Array`], [`DatumMap`], and [`Range`].
1940/// The `#[sqlfunc]` proc macro emits calls to these associated functions so
1941/// that Rust's type system resolves the correct unwrap/wrap behavior at compile
1942/// time, instead of relying on string-matching type names in the AST.
1943///
1944/// The methods are deliberately associated functions (no `&self`) because they
1945/// operate on [`SqlScalarType`] metadata, not on container values.
1946pub trait SqlContainerType {
1947    /// Extract the element type from a container scalar type.
1948    fn unwrap_element_type(container: &SqlScalarType) -> &SqlScalarType;
1949    /// Construct a container scalar type from an element type.
1950    fn wrap_element_type(element: SqlScalarType) -> SqlScalarType;
1951}
1952
1953/// Types that implement this trait can be stored in an SQL column with the specified SqlColumnType
1954pub trait AsColumnType {
1955    /// The SQL column type of this Rust type
1956    fn as_column_type() -> SqlColumnType;
1957}
1958
1959/// A bridge between native Rust types and SQL runtime types represented in Datums
1960pub trait InputDatumType<'a, E>: Sized {
1961    /// Whether this Rust type can represent NULL values
1962    fn nullable() -> bool;
1963
1964    /// Whether ALL components of this input accept NULL values.
1965    ///
1966    /// For single-element types this equals `nullable()`. For tuples, this is
1967    /// the AND of all components' `nullable()` values. Used by `output_type` to
1968    /// detect implicit null propagation from non-nullable parameter positions.
1969    fn all_nullable() -> bool {
1970        Self::nullable()
1971    }
1972
1973    /// Try to convert a Result whose Ok variant is a Datum into this native Rust type (Self). If
1974    /// it fails the error variant will contain the original result.
1975    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>>;
1976
1977    /// Try to convert a number of datums to a Result whose Ok variant is a native Rust type (Self)
1978    /// representing a number of datums obtained from the iterator.
1979    fn try_from_iter(
1980        iter: &mut impl Iterator<Item = Result<Datum<'a>, E>>,
1981    ) -> Result<Self, Result<Option<Datum<'a>>, E>> {
1982        // TODO: Consider removing default implementation, only relevant for single-element datum
1983        //   types.
1984        match iter.next() {
1985            Some(next) => Self::try_from_result(next).map_err(|e| e.map(Some)),
1986            None => Err(Ok(None)),
1987        }
1988    }
1989}
1990
1991/// A bridge between native Rust types and SQL runtime types represented in Datums
1992pub trait OutputDatumType<'a, E>: Sized {
1993    /// Whether this Rust type can represent NULL values
1994    fn nullable() -> bool;
1995
1996    /// Whether this Rust type can represent errors
1997    fn fallible() -> bool;
1998
1999    /// Convert this Rust type into a Result containing a Datum, or an error
2000    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E>;
2001}
2002
2003/// A new type that wraps a [`Vec`] that is used to differentiate the target [`Datum`] between
2004/// Arrays and Lists. The target of this type is Array.
2005#[derive(Debug)]
2006pub struct ArrayRustType<T>(pub Vec<T>);
2007
2008impl<T> From<Vec<T>> for ArrayRustType<T> {
2009    fn from(v: Vec<T>) -> Self {
2010        Self(v)
2011    }
2012}
2013
2014// We define `AsColumnType` in terms of the owned type of `B`.
2015impl<B: ToOwned<Owned: AsColumnType> + ?Sized> AsColumnType for Cow<'_, B> {
2016    fn as_column_type() -> SqlColumnType {
2017        <B::Owned>::as_column_type()
2018    }
2019}
2020
2021impl<'a, E, B: ToOwned + ?Sized> InputDatumType<'a, E> for Cow<'a, B>
2022where
2023    for<'b> B::Owned: InputDatumType<'b, E>,
2024    for<'b> &'b B: InputDatumType<'b, E>,
2025{
2026    fn nullable() -> bool {
2027        B::Owned::nullable()
2028    }
2029    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2030        <&B>::try_from_result(res).map(|b| Cow::Borrowed(b))
2031    }
2032}
2033
2034impl<'a, E, B: ToOwned + ?Sized> OutputDatumType<'a, E> for Cow<'a, B>
2035where
2036    for<'b> B::Owned: OutputDatumType<'b, E>,
2037    for<'b> &'b B: OutputDatumType<'b, E>,
2038{
2039    fn nullable() -> bool {
2040        B::Owned::nullable()
2041    }
2042    fn fallible() -> bool {
2043        B::Owned::fallible()
2044    }
2045    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2046        match self {
2047            Cow::Owned(b) => b.into_result(temp_storage),
2048            Cow::Borrowed(b) => b.into_result(temp_storage),
2049        }
2050    }
2051}
2052
2053impl<B: AsColumnType> AsColumnType for Option<B> {
2054    fn as_column_type() -> SqlColumnType {
2055        B::as_column_type().nullable(true)
2056    }
2057}
2058
2059impl<'a, E, B: InputDatumType<'a, E>> InputDatumType<'a, E> for Option<B> {
2060    fn nullable() -> bool {
2061        true
2062    }
2063    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2064        match res {
2065            Ok(Datum::Null) => Ok(None),
2066            Ok(datum) => B::try_from_result(Ok(datum)).map(Some),
2067            _ => Err(res),
2068        }
2069    }
2070}
2071
2072impl<'a, E, B: OutputDatumType<'a, E>> OutputDatumType<'a, E> for Option<B> {
2073    fn nullable() -> bool {
2074        true
2075    }
2076    fn fallible() -> bool {
2077        false
2078    }
2079    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2080        match self {
2081            Some(inner) => inner.into_result(temp_storage),
2082            None => Ok(Datum::Null),
2083        }
2084    }
2085}
2086
2087impl<E, B: AsColumnType> AsColumnType for Result<B, E> {
2088    fn as_column_type() -> SqlColumnType {
2089        B::as_column_type()
2090    }
2091}
2092
2093impl<'a, E, B: InputDatumType<'a, E>> InputDatumType<'a, E> for Result<B, E> {
2094    fn nullable() -> bool {
2095        B::nullable()
2096    }
2097    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2098        B::try_from_result(res).map(Ok)
2099    }
2100    fn try_from_iter(
2101        iter: &mut impl Iterator<Item = Result<Datum<'a>, E>>,
2102    ) -> Result<Self, Result<Option<Datum<'a>>, E>> {
2103        B::try_from_iter(iter).map(Ok)
2104    }
2105}
2106
2107impl<'a, E, B: OutputDatumType<'a, E>> OutputDatumType<'a, E> for Result<B, E> {
2108    fn nullable() -> bool {
2109        B::nullable()
2110    }
2111    fn fallible() -> bool {
2112        true
2113    }
2114    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2115        self.and_then(|inner| inner.into_result(temp_storage))
2116    }
2117}
2118
2119macro_rules! impl_tuple_input_datum_type {
2120    ($($T:ident),+) => {
2121        #[allow(non_snake_case)]
2122        impl<'a, E, $($T: InputDatumType<'a, E>),+> InputDatumType<'a, E> for ($($T,)+) {
2123            fn try_from_result(_res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2124                unimplemented!("Not possible")
2125            }
2126            fn try_from_iter(
2127                iter: &mut impl Iterator<Item = Result<Datum<'a>, E>>,
2128            ) -> Result<Self, Result<Option<Datum<'a>>, E>> {
2129                // Eagerly evaluate all arguments before checking for errors.
2130                // Each `$T` repetition expands to a separate variable, so we
2131                // first collect all results and then unpack them in priority
2132                // order: internal errors, then eval errors, then null
2133                // propagation. Doing it in one pass per `$T` would short-
2134                // circuit on the first error and skip evaluating later args.
2135                $(
2136                    let $T = <$T>::try_from_iter(iter);
2137                )+
2138                // Handle internal errors
2139                $(
2140                    let $T = match $T {
2141                        Err(Ok(None)) => return Err(Ok(None)),
2142                        Err(Ok(Some(datum))) if !datum.is_null() => return Err(Ok(Some(datum))),
2143                        els => els,
2144                    };
2145                )+
2146                // Handle eval errors
2147                $(
2148                    let $T = match $T {
2149                        Err(Err(err)) => return Err(Err(err)),
2150                        els => els,
2151                    };
2152                )+
2153                // Handle null propagation
2154                $(
2155                    let $T = $T?;
2156                )+
2157                Ok(($($T,)+))
2158            }
2159            fn nullable() -> bool {
2160                // OR: the tuple "accepts NULL" if any component does.
2161                // Used by the default `propagates_nulls` (`!nullable()`): when
2162                // every component rejects NULL, the function propagates nulls
2163                // for ALL inputs — safe for the optimizer to replace with NULL.
2164                $( <$T>::nullable() )||+
2165            }
2166            fn all_nullable() -> bool {
2167                // AND: true only when every component accepts NULL. When false,
2168                // at least one parameter position rejects NULL at runtime
2169                // (via `try_from_iter`), making the output potentially nullable
2170                // even if `propagates_nulls` is false.
2171                $( <$T>::nullable() )&&+
2172            }
2173        }
2174    }
2175}
2176
2177impl_tuple_input_datum_type!(T0);
2178impl_tuple_input_datum_type!(T0, T1);
2179impl_tuple_input_datum_type!(T0, T1, T2);
2180impl_tuple_input_datum_type!(T0, T1, T2, T3);
2181impl_tuple_input_datum_type!(T0, T1, T2, T3, T4);
2182impl_tuple_input_datum_type!(T0, T1, T2, T3, T4, T5);
2183
2184/// A wrapper type for variadic arguments that consumes the remaining iterator.
2185#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2186pub struct Variadic<T>(pub Vec<T>);
2187
2188impl<T> From<Vec<T>> for Variadic<T> {
2189    #[inline(always)]
2190    fn from(v: Vec<T>) -> Self {
2191        Self(v)
2192    }
2193}
2194
2195impl<T> std::ops::Deref for Variadic<T> {
2196    type Target = Vec<T>;
2197
2198    #[inline(always)]
2199    fn deref(&self) -> &Self::Target {
2200        &self.0
2201    }
2202}
2203
2204impl<T> IntoIterator for Variadic<T> {
2205    type Item = T;
2206    type IntoIter = std::vec::IntoIter<T>;
2207
2208    #[inline(always)]
2209    fn into_iter(self) -> Self::IntoIter {
2210        self.0.into_iter()
2211    }
2212}
2213
2214impl<'a, T> IntoIterator for &'a Variadic<T> {
2215    type Item = &'a T;
2216    type IntoIter = std::slice::Iter<'a, T>;
2217
2218    #[inline(always)]
2219    fn into_iter(self) -> Self::IntoIter {
2220        (&self.0).into_iter()
2221    }
2222}
2223
2224impl<'a, E, T: InputDatumType<'a, E>> InputDatumType<'a, E> for Variadic<T> {
2225    fn nullable() -> bool {
2226        T::nullable()
2227    }
2228    #[inline]
2229    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2230        Ok(vec![T::try_from_result(res)?].into())
2231    }
2232    #[inline]
2233    fn try_from_iter(
2234        iter: &mut impl Iterator<Item = Result<Datum<'a>, E>>,
2235    ) -> Result<Self, Result<Option<Datum<'a>>, E>> {
2236        let mut res = Vec::with_capacity(iter.size_hint().0);
2237        loop {
2238            match T::try_from_iter(iter) {
2239                Ok(t) => res.push(t),
2240                Err(Ok(None)) => break,
2241                Err(err) => return Err(err),
2242            }
2243        }
2244        Ok(Self(res))
2245    }
2246}
2247
2248/// Wrapper to distinguish "argument may not be present" from `Option<T>` (nullable).
2249#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
2250pub struct OptionalArg<T>(pub Option<T>);
2251
2252impl<T> std::ops::Deref for OptionalArg<T> {
2253    type Target = Option<T>;
2254
2255    #[inline(always)]
2256    fn deref(&self) -> &Self::Target {
2257        &self.0
2258    }
2259}
2260
2261impl<T> From<Option<T>> for OptionalArg<T> {
2262    #[inline(always)]
2263    fn from(opt: Option<T>) -> Self {
2264        Self(opt)
2265    }
2266}
2267
2268impl<'a, E, T: InputDatumType<'a, E>> InputDatumType<'a, E> for OptionalArg<T> {
2269    fn nullable() -> bool {
2270        T::nullable()
2271    }
2272    #[inline]
2273    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2274        Ok(Some(T::try_from_result(res)?).into())
2275    }
2276    #[inline]
2277    fn try_from_iter(
2278        iter: &mut impl Iterator<Item = Result<Datum<'a>, E>>,
2279    ) -> Result<Self, Result<Option<Datum<'a>>, E>> {
2280        match iter.next() {
2281            Some(datum) => {
2282                let val = T::try_from_result(datum).map_err(|r| r.map(Some))?;
2283                Ok(Some(val).into())
2284            }
2285            None => Ok(None.into()),
2286        }
2287    }
2288}
2289
2290/// A wrapper type that excludes `NULL` values, even if `B` allows them.
2291///
2292/// The wrapper allows for using types that can represent `NULL` values in contexts where
2293/// `NULL` values are not allowed, enforcing the non-null constraint at the type level.
2294/// For example, functions that propagate `NULL` values can use this type to ensure that
2295/// their inputs are non-null, even if the type could represent `NULL` values.
2296#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2297pub struct ExcludeNull<B>(B);
2298
2299impl<B: AsColumnType> AsColumnType for ExcludeNull<B> {
2300    fn as_column_type() -> SqlColumnType {
2301        B::as_column_type().nullable(false)
2302    }
2303}
2304
2305impl<'a, E, B: InputDatumType<'a, E>> InputDatumType<'a, E> for ExcludeNull<B> {
2306    fn nullable() -> bool {
2307        false
2308    }
2309    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2310        match res {
2311            Ok(Datum::Null) => Err(Ok(Datum::Null)),
2312            _ => B::try_from_result(res).map(ExcludeNull),
2313        }
2314    }
2315}
2316
2317impl<'a, E, B: OutputDatumType<'a, E>> OutputDatumType<'a, E> for ExcludeNull<B> {
2318    fn nullable() -> bool {
2319        false
2320    }
2321    fn fallible() -> bool {
2322        B::fallible()
2323    }
2324    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2325        self.0.into_result(temp_storage)
2326    }
2327}
2328
2329impl<B> std::ops::Deref for ExcludeNull<B> {
2330    type Target = B;
2331
2332    fn deref(&self) -> &Self::Target {
2333        &self.0
2334    }
2335}
2336
2337/// Macro to derive InputDatumType and OutputDatumType for all Datum variants that are simple Copy types
2338macro_rules! impl_datum_type_copy {
2339    ($lt:lifetime, $native:ty, $variant:ident) => {
2340        #[allow(unused_lifetimes)]
2341        impl<$lt> AsColumnType for $native {
2342            fn as_column_type() -> SqlColumnType {
2343                SqlScalarType::$variant.nullable(false)
2344            }
2345        }
2346
2347        impl<$lt, E> InputDatumType<$lt, E> for $native {
2348            fn nullable() -> bool {
2349                false
2350            }
2351
2352            fn try_from_result(res: Result<Datum<$lt>, E>) -> Result<Self, Result<Datum<$lt>, E>> {
2353                match res {
2354                    Ok(Datum::$variant(f)) => Ok(f.into()),
2355                    _ => Err(res),
2356                }
2357            }
2358        }
2359
2360        impl<$lt, E> OutputDatumType<$lt, E> for $native {
2361            fn nullable() -> bool {
2362                false
2363            }
2364
2365            fn fallible() -> bool {
2366                false
2367            }
2368
2369            fn into_result(self, _temp_storage: &$lt RowArena) -> Result<Datum<$lt>, E> {
2370                Ok(Datum::$variant(self.into()))
2371            }
2372        }
2373    };
2374    ($native:ty, $variant:ident) => {
2375        impl_datum_type_copy!('a, $native, $variant);
2376    };
2377}
2378
2379impl_datum_type_copy!(f32, Float32);
2380impl_datum_type_copy!(f64, Float64);
2381impl_datum_type_copy!(i16, Int16);
2382impl_datum_type_copy!(i32, Int32);
2383impl_datum_type_copy!(i64, Int64);
2384impl_datum_type_copy!(u16, UInt16);
2385impl_datum_type_copy!(u32, UInt32);
2386impl_datum_type_copy!(u64, UInt64);
2387impl_datum_type_copy!(Interval, Interval);
2388impl_datum_type_copy!(Date, Date);
2389impl_datum_type_copy!(NaiveTime, Time);
2390impl_datum_type_copy!(Uuid, Uuid);
2391impl_datum_type_copy!('a, &'a str, String);
2392impl_datum_type_copy!('a, &'a [u8], Bytes);
2393impl_datum_type_copy!(crate::Timestamp, MzTimestamp);
2394
2395impl<'a, E> InputDatumType<'a, E> for Datum<'a> {
2396    fn nullable() -> bool {
2397        true
2398    }
2399
2400    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2401        match res {
2402            Ok(datum) => Ok(datum),
2403            _ => Err(res),
2404        }
2405    }
2406}
2407
2408impl<'a, E> OutputDatumType<'a, E> for Datum<'a> {
2409    fn nullable() -> bool {
2410        true
2411    }
2412
2413    fn fallible() -> bool {
2414        false
2415    }
2416
2417    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2418        Ok(self)
2419    }
2420}
2421
2422impl<'a, E> InputDatumType<'a, E> for DatumList<'a> {
2423    fn nullable() -> bool {
2424        false
2425    }
2426
2427    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2428        match res {
2429            Ok(Datum::List(list)) => Ok(list),
2430            _ => Err(res),
2431        }
2432    }
2433}
2434
2435impl<'a, E> OutputDatumType<'a, E> for DatumList<'a> {
2436    fn nullable() -> bool {
2437        false
2438    }
2439
2440    fn fallible() -> bool {
2441        false
2442    }
2443
2444    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2445        Ok(Datum::List(self))
2446    }
2447}
2448
2449impl<'a, E> InputDatumType<'a, E> for Array<'a> {
2450    fn nullable() -> bool {
2451        false
2452    }
2453
2454    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2455        match res {
2456            Ok(Datum::Array(array)) => Ok(array),
2457            _ => Err(res),
2458        }
2459    }
2460}
2461
2462impl<'a, E> OutputDatumType<'a, E> for Array<'a> {
2463    fn nullable() -> bool {
2464        false
2465    }
2466
2467    fn fallible() -> bool {
2468        false
2469    }
2470
2471    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2472        Ok(Datum::Array(self))
2473    }
2474}
2475
2476/// A wrapper around [`Array`] that represents a PostgreSQL `int2vector` value.
2477///
2478/// This exists to allow distinguishing between `int2vector` and regular array
2479/// values in the type system, which enables `#[sqlfunc]` conversions.
2480#[derive(Debug)]
2481pub struct Int2Vector<'a>(pub Array<'a>);
2482
2483impl AsColumnType for Int2Vector<'_> {
2484    fn as_column_type() -> SqlColumnType {
2485        SqlScalarType::Int2Vector.nullable(false)
2486    }
2487}
2488
2489impl<'a, E> InputDatumType<'a, E> for Int2Vector<'a> {
2490    fn nullable() -> bool {
2491        false
2492    }
2493
2494    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2495        match res {
2496            Ok(Datum::Array(array)) => Ok(Int2Vector(array)),
2497            _ => Err(res),
2498        }
2499    }
2500}
2501
2502impl<'a, E> OutputDatumType<'a, E> for Int2Vector<'a> {
2503    fn nullable() -> bool {
2504        false
2505    }
2506
2507    fn fallible() -> bool {
2508        false
2509    }
2510
2511    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2512        Ok(Datum::Array(self.0))
2513    }
2514}
2515
2516impl<'a, E> InputDatumType<'a, E> for DatumMap<'a> {
2517    fn nullable() -> bool {
2518        false
2519    }
2520
2521    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2522        match res {
2523            Ok(Datum::Map(map)) => Ok(map),
2524            _ => Err(res),
2525        }
2526    }
2527}
2528
2529impl<'a, E> OutputDatumType<'a, E> for DatumMap<'a> {
2530    fn nullable() -> bool {
2531        false
2532    }
2533
2534    fn fallible() -> bool {
2535        false
2536    }
2537
2538    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2539        Ok(Datum::Map(self))
2540    }
2541}
2542
2543impl<'a, E> InputDatumType<'a, E> for Range<DatumNested<'a>> {
2544    fn nullable() -> bool {
2545        false
2546    }
2547
2548    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2549        match res {
2550            Ok(Datum::Range(range)) => Ok(range),
2551            _ => Err(res),
2552        }
2553    }
2554}
2555
2556impl<'a, E> OutputDatumType<'a, E> for Range<DatumNested<'a>> {
2557    fn nullable() -> bool {
2558        false
2559    }
2560
2561    fn fallible() -> bool {
2562        false
2563    }
2564
2565    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2566        Ok(Datum::Range(self))
2567    }
2568}
2569
2570impl<'a, E> InputDatumType<'a, E> for Range<Datum<'a>> {
2571    fn nullable() -> bool {
2572        false
2573    }
2574
2575    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2576        match res {
2577            Ok(r @ Datum::Range(..)) => Ok(r.unwrap_range()),
2578            _ => Err(res),
2579        }
2580    }
2581}
2582
2583impl<'a, E> OutputDatumType<'a, E> for Range<Datum<'a>> {
2584    fn nullable() -> bool {
2585        false
2586    }
2587
2588    fn fallible() -> bool {
2589        false
2590    }
2591
2592    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2593        let d =
2594            self.into_bounds(|bound| temp_storage.make_datum_nested(|packer| packer.push(bound)));
2595        Ok(Datum::Range(d))
2596    }
2597}
2598
2599impl AsColumnType for bool {
2600    fn as_column_type() -> SqlColumnType {
2601        SqlScalarType::Bool.nullable(false)
2602    }
2603}
2604
2605impl<'a, E> InputDatumType<'a, E> for bool {
2606    fn nullable() -> bool {
2607        false
2608    }
2609
2610    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2611        match res {
2612            Ok(Datum::True) => Ok(true),
2613            Ok(Datum::False) => Ok(false),
2614            _ => Err(res),
2615        }
2616    }
2617}
2618
2619impl<'a, E> OutputDatumType<'a, E> for bool {
2620    fn nullable() -> bool {
2621        false
2622    }
2623
2624    fn fallible() -> bool {
2625        false
2626    }
2627
2628    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2629        if self {
2630            Ok(Datum::True)
2631        } else {
2632            Ok(Datum::False)
2633        }
2634    }
2635}
2636
2637impl AsColumnType for String {
2638    fn as_column_type() -> SqlColumnType {
2639        SqlScalarType::String.nullable(false)
2640    }
2641}
2642
2643impl<'a, E> InputDatumType<'a, E> for String {
2644    fn nullable() -> bool {
2645        false
2646    }
2647
2648    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2649        match res {
2650            Ok(Datum::String(s)) => Ok(s.to_owned()),
2651            _ => Err(res),
2652        }
2653    }
2654}
2655
2656impl<'a, E> OutputDatumType<'a, E> for String {
2657    fn nullable() -> bool {
2658        false
2659    }
2660
2661    fn fallible() -> bool {
2662        false
2663    }
2664
2665    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2666        Ok(Datum::String(temp_storage.push_string(self)))
2667    }
2668}
2669
2670impl<T: AsColumnType> AsColumnType for ArrayRustType<T> {
2671    fn as_column_type() -> SqlColumnType {
2672        let inner = T::as_column_type();
2673        SqlScalarType::Array(Box::new(inner.scalar_type)).nullable(false)
2674    }
2675}
2676
2677impl<'a, T, E> InputDatumType<'a, E> for ArrayRustType<T>
2678where
2679    T: InputDatumType<'a, E>,
2680{
2681    fn nullable() -> bool {
2682        false
2683    }
2684
2685    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2686        if let Ok(Datum::Array(arr)) = &res {
2687            let result = arr
2688                .elements()
2689                .into_iter()
2690                .map(|d| T::try_from_result(Ok(d)))
2691                .collect::<Result<_, _>>();
2692            if let Ok(elements) = result {
2693                return Ok(ArrayRustType(elements));
2694            }
2695        }
2696
2697        // The `try_from_result` contract requires we return the original `res` on error.
2698        Err(res)
2699    }
2700}
2701
2702impl<'a, T, E> OutputDatumType<'a, E> for ArrayRustType<T>
2703where
2704    T: OutputDatumType<'a, E>,
2705{
2706    fn nullable() -> bool {
2707        false
2708    }
2709
2710    fn fallible() -> bool {
2711        T::fallible()
2712    }
2713
2714    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2715        let dimensions = ArrayDimension {
2716            lower_bound: 1,
2717            length: self.0.len(),
2718        };
2719        let iter = self
2720            .0
2721            .into_iter()
2722            .map(|elem| elem.into_result(temp_storage));
2723        temp_storage.try_make_datum(|packer| {
2724            packer
2725                .try_push_array_fallible(&[dimensions], iter)
2726                .expect("self is 1 dimensional, and its length is used for the array length")
2727        })
2728    }
2729}
2730
2731impl AsColumnType for Vec<u8> {
2732    fn as_column_type() -> SqlColumnType {
2733        SqlScalarType::Bytes.nullable(false)
2734    }
2735}
2736
2737impl<'a, E> InputDatumType<'a, E> for Vec<u8> {
2738    fn nullable() -> bool {
2739        false
2740    }
2741
2742    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2743        match res {
2744            Ok(Datum::Bytes(b)) => Ok(b.to_owned()),
2745            _ => Err(res),
2746        }
2747    }
2748}
2749
2750impl<'a, E> OutputDatumType<'a, E> for Vec<u8> {
2751    fn nullable() -> bool {
2752        false
2753    }
2754
2755    fn fallible() -> bool {
2756        false
2757    }
2758
2759    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2760        Ok(Datum::Bytes(temp_storage.push_bytes(self)))
2761    }
2762}
2763
2764impl AsColumnType for Numeric {
2765    fn as_column_type() -> SqlColumnType {
2766        SqlScalarType::Numeric { max_scale: None }.nullable(false)
2767    }
2768}
2769
2770impl<'a, E> InputDatumType<'a, E> for Numeric {
2771    fn nullable() -> bool {
2772        false
2773    }
2774
2775    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2776        match res {
2777            Ok(Datum::Numeric(n)) => Ok(n.into_inner()),
2778            _ => Err(res),
2779        }
2780    }
2781}
2782
2783impl<'a, E> OutputDatumType<'a, E> for Numeric {
2784    fn nullable() -> bool {
2785        false
2786    }
2787
2788    fn fallible() -> bool {
2789        false
2790    }
2791
2792    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2793        Ok(Datum::from(self))
2794    }
2795}
2796
2797impl<'a, E> InputDatumType<'a, E> for OrderedDecimal<Numeric> {
2798    fn nullable() -> bool {
2799        false
2800    }
2801
2802    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2803        match res {
2804            Ok(Datum::Numeric(n)) => Ok(n),
2805            _ => Err(res),
2806        }
2807    }
2808}
2809
2810impl<'a, E> OutputDatumType<'a, E> for OrderedDecimal<Numeric> {
2811    fn nullable() -> bool {
2812        false
2813    }
2814
2815    fn fallible() -> bool {
2816        false
2817    }
2818
2819    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2820        Ok(Datum::from(self))
2821    }
2822}
2823
2824impl AsColumnType for PgLegacyChar {
2825    fn as_column_type() -> SqlColumnType {
2826        SqlScalarType::PgLegacyChar.nullable(false)
2827    }
2828}
2829
2830impl<'a, E> InputDatumType<'a, E> for PgLegacyChar {
2831    fn nullable() -> bool {
2832        false
2833    }
2834
2835    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2836        match res {
2837            Ok(Datum::UInt8(a)) => Ok(PgLegacyChar(a)),
2838            _ => Err(res),
2839        }
2840    }
2841}
2842
2843impl<'a, E> OutputDatumType<'a, E> for PgLegacyChar {
2844    fn nullable() -> bool {
2845        false
2846    }
2847
2848    fn fallible() -> bool {
2849        false
2850    }
2851
2852    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2853        Ok(Datum::UInt8(self.0))
2854    }
2855}
2856
2857impl<S> AsColumnType for PgLegacyName<S>
2858where
2859    S: AsRef<str>,
2860{
2861    fn as_column_type() -> SqlColumnType {
2862        SqlScalarType::PgLegacyName.nullable(false)
2863    }
2864}
2865
2866impl<'a, E> InputDatumType<'a, E> for PgLegacyName<&'a str> {
2867    fn nullable() -> bool {
2868        false
2869    }
2870
2871    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2872        match res {
2873            Ok(Datum::String(a)) => Ok(PgLegacyName(a)),
2874            _ => Err(res),
2875        }
2876    }
2877}
2878
2879impl<'a, E> OutputDatumType<'a, E> for PgLegacyName<&'a str> {
2880    fn nullable() -> bool {
2881        false
2882    }
2883
2884    fn fallible() -> bool {
2885        false
2886    }
2887
2888    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2889        Ok(Datum::String(self.0))
2890    }
2891}
2892
2893impl<'a, E> InputDatumType<'a, E> for PgLegacyName<String> {
2894    fn nullable() -> bool {
2895        false
2896    }
2897
2898    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2899        match res {
2900            Ok(Datum::String(a)) => Ok(PgLegacyName(a.to_owned())),
2901            _ => Err(res),
2902        }
2903    }
2904}
2905
2906impl<'a, E> OutputDatumType<'a, E> for PgLegacyName<String> {
2907    fn nullable() -> bool {
2908        false
2909    }
2910
2911    fn fallible() -> bool {
2912        false
2913    }
2914
2915    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2916        Ok(Datum::String(temp_storage.push_string(self.0)))
2917    }
2918}
2919
2920impl AsColumnType for Oid {
2921    fn as_column_type() -> SqlColumnType {
2922        SqlScalarType::Oid.nullable(false)
2923    }
2924}
2925
2926impl<'a, E> InputDatumType<'a, E> for Oid {
2927    fn nullable() -> bool {
2928        false
2929    }
2930
2931    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2932        match res {
2933            Ok(Datum::UInt32(a)) => Ok(Oid(a)),
2934            _ => Err(res),
2935        }
2936    }
2937}
2938
2939impl<'a, E> OutputDatumType<'a, E> for Oid {
2940    fn nullable() -> bool {
2941        false
2942    }
2943
2944    fn fallible() -> bool {
2945        false
2946    }
2947
2948    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2949        Ok(Datum::UInt32(self.0))
2950    }
2951}
2952
2953impl AsColumnType for RegClass {
2954    fn as_column_type() -> SqlColumnType {
2955        SqlScalarType::RegClass.nullable(false)
2956    }
2957}
2958
2959impl<'a, E> InputDatumType<'a, E> for RegClass {
2960    fn nullable() -> bool {
2961        false
2962    }
2963
2964    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2965        match res {
2966            Ok(Datum::UInt32(a)) => Ok(RegClass(a)),
2967            _ => Err(res),
2968        }
2969    }
2970}
2971
2972impl<'a, E> OutputDatumType<'a, E> for RegClass {
2973    fn nullable() -> bool {
2974        false
2975    }
2976
2977    fn fallible() -> bool {
2978        false
2979    }
2980
2981    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
2982        Ok(Datum::UInt32(self.0))
2983    }
2984}
2985
2986impl AsColumnType for RegProc {
2987    fn as_column_type() -> SqlColumnType {
2988        SqlScalarType::RegProc.nullable(false)
2989    }
2990}
2991
2992impl<'a, E> InputDatumType<'a, E> for RegProc {
2993    fn nullable() -> bool {
2994        false
2995    }
2996
2997    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
2998        match res {
2999            Ok(Datum::UInt32(a)) => Ok(RegProc(a)),
3000            _ => Err(res),
3001        }
3002    }
3003}
3004
3005impl<'a, E> OutputDatumType<'a, E> for RegProc {
3006    fn nullable() -> bool {
3007        false
3008    }
3009
3010    fn fallible() -> bool {
3011        false
3012    }
3013
3014    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3015        Ok(Datum::UInt32(self.0))
3016    }
3017}
3018
3019impl AsColumnType for RegType {
3020    fn as_column_type() -> SqlColumnType {
3021        SqlScalarType::RegType.nullable(false)
3022    }
3023}
3024
3025impl<'a, E> InputDatumType<'a, E> for RegType {
3026    fn nullable() -> bool {
3027        false
3028    }
3029
3030    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3031        match res {
3032            Ok(Datum::UInt32(a)) => Ok(RegType(a)),
3033            _ => Err(res),
3034        }
3035    }
3036}
3037
3038impl<'a, E> OutputDatumType<'a, E> for RegType {
3039    fn nullable() -> bool {
3040        false
3041    }
3042
3043    fn fallible() -> bool {
3044        false
3045    }
3046
3047    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3048        Ok(Datum::UInt32(self.0))
3049    }
3050}
3051
3052impl<S> AsColumnType for Char<S>
3053where
3054    S: AsRef<str>,
3055{
3056    fn as_column_type() -> SqlColumnType {
3057        SqlScalarType::Char { length: None }.nullable(false)
3058    }
3059}
3060
3061impl<'a, E> InputDatumType<'a, E> for Char<&'a str> {
3062    fn nullable() -> bool {
3063        false
3064    }
3065
3066    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3067        match res {
3068            Ok(Datum::String(a)) => Ok(Char(a)),
3069            _ => Err(res),
3070        }
3071    }
3072}
3073
3074impl<'a, E> OutputDatumType<'a, E> for Char<&'a str> {
3075    fn nullable() -> bool {
3076        false
3077    }
3078
3079    fn fallible() -> bool {
3080        false
3081    }
3082
3083    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3084        Ok(Datum::String(self.0))
3085    }
3086}
3087
3088impl<'a, E> InputDatumType<'a, E> for Char<String> {
3089    fn nullable() -> bool {
3090        false
3091    }
3092
3093    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3094        match res {
3095            Ok(Datum::String(a)) => Ok(Char(a.to_owned())),
3096            _ => Err(res),
3097        }
3098    }
3099}
3100
3101impl<'a, E> OutputDatumType<'a, E> for Char<String> {
3102    fn nullable() -> bool {
3103        false
3104    }
3105
3106    fn fallible() -> bool {
3107        false
3108    }
3109
3110    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3111        Ok(Datum::String(temp_storage.push_string(self.0)))
3112    }
3113}
3114
3115impl<S> AsColumnType for VarChar<S>
3116where
3117    S: AsRef<str>,
3118{
3119    fn as_column_type() -> SqlColumnType {
3120        SqlScalarType::Char { length: None }.nullable(false)
3121    }
3122}
3123
3124impl<'a, E> InputDatumType<'a, E> for VarChar<&'a str> {
3125    fn nullable() -> bool {
3126        false
3127    }
3128
3129    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3130        match res {
3131            Ok(Datum::String(a)) => Ok(VarChar(a)),
3132            _ => Err(res),
3133        }
3134    }
3135}
3136
3137impl<'a, E> OutputDatumType<'a, E> for VarChar<&'a str> {
3138    fn nullable() -> bool {
3139        false
3140    }
3141
3142    fn fallible() -> bool {
3143        false
3144    }
3145
3146    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3147        Ok(Datum::String(self.0))
3148    }
3149}
3150
3151impl<'a, E> InputDatumType<'a, E> for VarChar<String> {
3152    fn nullable() -> bool {
3153        false
3154    }
3155
3156    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3157        match res {
3158            Ok(Datum::String(a)) => Ok(VarChar(a.to_owned())),
3159            _ => Err(res),
3160        }
3161    }
3162}
3163
3164impl<'a, E> OutputDatumType<'a, E> for VarChar<String> {
3165    fn nullable() -> bool {
3166        false
3167    }
3168
3169    fn fallible() -> bool {
3170        false
3171    }
3172
3173    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3174        Ok(Datum::String(temp_storage.push_string(self.0)))
3175    }
3176}
3177
3178impl<'a, E> InputDatumType<'a, E> for Jsonb {
3179    fn nullable() -> bool {
3180        false
3181    }
3182
3183    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3184        Ok(JsonbRef::try_from_result(res)?.to_owned())
3185    }
3186}
3187
3188impl<'a, E> OutputDatumType<'a, E> for Jsonb {
3189    fn nullable() -> bool {
3190        false
3191    }
3192
3193    fn fallible() -> bool {
3194        false
3195    }
3196
3197    fn into_result(self, temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3198        Ok(temp_storage.push_unary_row(self.into_row()))
3199    }
3200}
3201
3202impl AsColumnType for Jsonb {
3203    fn as_column_type() -> SqlColumnType {
3204        SqlScalarType::Jsonb.nullable(false)
3205    }
3206}
3207
3208impl<'a, E> InputDatumType<'a, E> for JsonbRef<'a> {
3209    fn nullable() -> bool {
3210        false
3211    }
3212
3213    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3214        match res {
3215            Ok(
3216                d @ (Datum::JsonNull
3217                | Datum::True
3218                | Datum::False
3219                | Datum::Numeric(_)
3220                | Datum::String(_)
3221                | Datum::List(_)
3222                | Datum::Map(_)),
3223            ) => Ok(JsonbRef::from_datum(d)),
3224            _ => Err(res),
3225        }
3226    }
3227}
3228
3229impl<'a, E> OutputDatumType<'a, E> for JsonbRef<'a> {
3230    fn nullable() -> bool {
3231        false
3232    }
3233
3234    fn fallible() -> bool {
3235        false
3236    }
3237
3238    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3239        Ok(self.into_datum())
3240    }
3241}
3242
3243impl<'a> AsColumnType for JsonbRef<'a> {
3244    fn as_column_type() -> SqlColumnType {
3245        SqlScalarType::Jsonb.nullable(false)
3246    }
3247}
3248
3249impl AsColumnType for MzAclItem {
3250    fn as_column_type() -> SqlColumnType {
3251        SqlScalarType::MzAclItem.nullable(false)
3252    }
3253}
3254
3255impl<'a, E> InputDatumType<'a, E> for MzAclItem {
3256    fn nullable() -> bool {
3257        false
3258    }
3259
3260    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3261        match res {
3262            Ok(Datum::MzAclItem(mz_acl_item)) => Ok(mz_acl_item),
3263            _ => Err(res),
3264        }
3265    }
3266}
3267
3268impl<'a, E> OutputDatumType<'a, E> for MzAclItem {
3269    fn nullable() -> bool {
3270        false
3271    }
3272
3273    fn fallible() -> bool {
3274        false
3275    }
3276
3277    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3278        Ok(Datum::MzAclItem(self))
3279    }
3280}
3281
3282impl AsColumnType for AclItem {
3283    fn as_column_type() -> SqlColumnType {
3284        SqlScalarType::AclItem.nullable(false)
3285    }
3286}
3287
3288impl<'a, E> InputDatumType<'a, E> for AclItem {
3289    fn nullable() -> bool {
3290        false
3291    }
3292
3293    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3294        match res {
3295            Ok(Datum::AclItem(acl_item)) => Ok(acl_item),
3296            _ => Err(res),
3297        }
3298    }
3299}
3300
3301impl<'a, E> OutputDatumType<'a, E> for AclItem {
3302    fn nullable() -> bool {
3303        false
3304    }
3305
3306    fn fallible() -> bool {
3307        false
3308    }
3309
3310    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3311        Ok(Datum::AclItem(self))
3312    }
3313}
3314
3315impl AsColumnType for CheckedTimestamp<NaiveDateTime> {
3316    fn as_column_type() -> SqlColumnType {
3317        SqlScalarType::Timestamp { precision: None }.nullable(false)
3318    }
3319}
3320
3321impl<'a, E> InputDatumType<'a, E> for CheckedTimestamp<NaiveDateTime> {
3322    fn nullable() -> bool {
3323        false
3324    }
3325
3326    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3327        match res {
3328            Ok(Datum::Timestamp(a)) => Ok(a),
3329            _ => Err(res),
3330        }
3331    }
3332}
3333
3334impl<'a, E> OutputDatumType<'a, E> for CheckedTimestamp<NaiveDateTime> {
3335    fn nullable() -> bool {
3336        false
3337    }
3338
3339    fn fallible() -> bool {
3340        false
3341    }
3342
3343    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3344        Ok(Datum::Timestamp(self))
3345    }
3346}
3347
3348impl AsColumnType for CheckedTimestamp<DateTime<Utc>> {
3349    fn as_column_type() -> SqlColumnType {
3350        SqlScalarType::TimestampTz { precision: None }.nullable(false)
3351    }
3352}
3353
3354impl<'a, E> InputDatumType<'a, E> for CheckedTimestamp<DateTime<Utc>> {
3355    fn nullable() -> bool {
3356        false
3357    }
3358
3359    fn try_from_result(res: Result<Datum<'a>, E>) -> Result<Self, Result<Datum<'a>, E>> {
3360        match res {
3361            Ok(Datum::TimestampTz(a)) => Ok(a),
3362            _ => Err(res),
3363        }
3364    }
3365}
3366
3367impl<'a, E> OutputDatumType<'a, E> for CheckedTimestamp<DateTime<Utc>> {
3368    fn nullable() -> bool {
3369        false
3370    }
3371
3372    fn fallible() -> bool {
3373        false
3374    }
3375
3376    fn into_result(self, _temp_storage: &'a RowArena) -> Result<Datum<'a>, E> {
3377        Ok(Datum::TimestampTz(self))
3378    }
3379}
3380
3381impl SqlScalarType {
3382    /// Returns the contained numeric maximum scale.
3383    ///
3384    /// # Panics
3385    ///
3386    /// Panics if the scalar type is not [`SqlScalarType::Numeric`].
3387    pub fn unwrap_numeric_max_scale(&self) -> Option<NumericMaxScale> {
3388        match self {
3389            SqlScalarType::Numeric { max_scale } => *max_scale,
3390            _ => panic!("SqlScalarType::unwrap_numeric_scale called on {:?}", self),
3391        }
3392    }
3393
3394    /// Returns the contained timestamp precision.
3395    ///
3396    /// # Panics
3397    ///
3398    /// Panics if the scalar type is not [`SqlScalarType::Timestamp`] or
3399    /// [`SqlScalarType::TimestampTz`].
3400    pub fn unwrap_timestamp_precision(&self) -> Option<TimestampPrecision> {
3401        match self {
3402            SqlScalarType::Timestamp { precision } | SqlScalarType::TimestampTz { precision } => {
3403                *precision
3404            }
3405            _ => panic!(
3406                "SqlScalarType::unwrap_timestamp_precision called on {:?}",
3407                self
3408            ),
3409        }
3410    }
3411
3412    /// Returns the [`SqlScalarType`] of elements in a [`SqlScalarType::List`].
3413    ///
3414    /// # Panics
3415    ///
3416    /// Panics if called on anything other than a [`SqlScalarType::List`].
3417    pub fn unwrap_list_element_type(&self) -> &SqlScalarType {
3418        match self {
3419            SqlScalarType::List { element_type, .. } => element_type,
3420            _ => panic!(
3421                "SqlScalarType::unwrap_list_element_type called on {:?}",
3422                self
3423            ),
3424        }
3425    }
3426
3427    /// Returns the [`SqlScalarType`] of elements in the nth layer a
3428    /// [`SqlScalarType::List`].
3429    ///
3430    /// For example, in an `int list list`, the:
3431    /// - 0th layer is `int list list`
3432    /// - 1st layer is `int list`
3433    /// - 2nd layer is `int`
3434    ///
3435    /// # Panics
3436    ///
3437    /// Panics if the nth-1 layer is anything other than a
3438    /// [`SqlScalarType::List`].
3439    pub fn unwrap_list_nth_layer_type(&self, layer: usize) -> &SqlScalarType {
3440        if layer == 0 {
3441            return self;
3442        }
3443        match self {
3444            SqlScalarType::List { element_type, .. } => {
3445                element_type.unwrap_list_nth_layer_type(layer - 1)
3446            }
3447            _ => panic!(
3448                "SqlScalarType::unwrap_list_nth_layer_type called on {:?}",
3449                self
3450            ),
3451        }
3452    }
3453
3454    /// Returns a vector of [`SqlScalarType`] elements in a [`SqlScalarType::Record`].
3455    ///
3456    /// # Panics
3457    ///
3458    /// Panics if called on anything other than a [`SqlScalarType::Record`].
3459    pub fn unwrap_record_element_type(&self) -> Vec<&SqlScalarType> {
3460        match self {
3461            SqlScalarType::Record { fields, .. } => {
3462                fields.iter().map(|(_, t)| &t.scalar_type).collect_vec()
3463            }
3464            _ => panic!(
3465                "SqlScalarType::unwrap_record_element_type called on {:?}",
3466                self
3467            ),
3468        }
3469    }
3470
3471    /// Returns vector of [`SqlColumnType`] 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_column_type(&self) -> Vec<&SqlColumnType> {
3477        match self {
3478            SqlScalarType::Record { fields, .. } => fields.iter().map(|(_, t)| t).collect_vec(),
3479            _ => panic!(
3480                "SqlScalarType::unwrap_record_element_column_type called on {:?}",
3481                self
3482            ),
3483        }
3484    }
3485
3486    /// Returns number of dimensions/axes (also known as "rank") on a
3487    /// [`SqlScalarType::List`].
3488    ///
3489    /// # Panics
3490    ///
3491    /// Panics if called on anything other than a [`SqlScalarType::List`].
3492    pub fn unwrap_list_n_layers(&self) -> usize {
3493        let mut descender = self.unwrap_list_element_type();
3494        let mut layers = 1;
3495
3496        while let SqlScalarType::List { element_type, .. } = descender {
3497            layers += 1;
3498            descender = element_type;
3499        }
3500
3501        layers
3502    }
3503
3504    /// Returns `self` with any type modifiers removed.
3505    ///
3506    /// Namely, this should set optional scales or limits to `None`.
3507    pub fn without_modifiers(&self) -> SqlScalarType {
3508        use SqlScalarType::*;
3509        match self {
3510            List {
3511                element_type,
3512                custom_id: None,
3513            } => List {
3514                element_type: Box::new(element_type.without_modifiers()),
3515                custom_id: None,
3516            },
3517            Map {
3518                value_type,
3519                custom_id: None,
3520            } => Map {
3521                value_type: Box::new(value_type.without_modifiers()),
3522                custom_id: None,
3523            },
3524            Record {
3525                fields,
3526                custom_id: None,
3527            } => {
3528                let fields = fields
3529                    .iter()
3530                    .map(|(column_name, column_type)| {
3531                        (
3532                            column_name.clone(),
3533                            SqlColumnType {
3534                                scalar_type: column_type.scalar_type.without_modifiers(),
3535                                nullable: column_type.nullable,
3536                            },
3537                        )
3538                    })
3539                    .collect();
3540                Record {
3541                    fields,
3542                    custom_id: None,
3543                }
3544            }
3545            Array(a) => Array(Box::new(a.without_modifiers())),
3546            Numeric { .. } => Numeric { max_scale: None },
3547            // Char's default length should not be `Some(1)`, but instead `None`
3548            // to support Char values of different lengths in e.g. lists.
3549            Char { .. } => Char { length: None },
3550            VarChar { .. } => VarChar { max_length: None },
3551            Range { element_type } => Range {
3552                element_type: Box::new(element_type.without_modifiers()),
3553            },
3554            v => v.clone(),
3555        }
3556    }
3557
3558    /// Returns the [`SqlScalarType`] of elements in a [`SqlScalarType::Array`] or the
3559    /// elements of a vector type, e.g. [`SqlScalarType::Int16`] for
3560    /// [`SqlScalarType::Int2Vector`].
3561    ///
3562    /// # Panics
3563    ///
3564    /// Panics if called on anything other than a [`SqlScalarType::Array`] or
3565    /// [`SqlScalarType::Int2Vector`].
3566    pub fn unwrap_array_element_type(&self) -> &SqlScalarType {
3567        match self {
3568            SqlScalarType::Array(s) => &**s,
3569            SqlScalarType::Int2Vector => &SqlScalarType::Int16,
3570            _ => panic!(
3571                "SqlScalarType::unwrap_array_element_type called on {:?}",
3572                self
3573            ),
3574        }
3575    }
3576
3577    /// Returns the [`SqlScalarType`] of elements in a [`SqlScalarType::Array`],
3578    /// [`SqlScalarType::Int2Vector`], or [`SqlScalarType::List`].
3579    ///
3580    /// # Panics
3581    ///
3582    /// Panics if called on anything other than a [`SqlScalarType::Array`],
3583    /// [`SqlScalarType::Int2Vector`], or [`SqlScalarType::List`].
3584    pub fn unwrap_collection_element_type(&self) -> &SqlScalarType {
3585        match self {
3586            SqlScalarType::Array(element_type) => element_type,
3587            SqlScalarType::Int2Vector => &SqlScalarType::Int16,
3588            SqlScalarType::List { element_type, .. } => element_type,
3589            _ => panic!(
3590                "SqlScalarType::unwrap_collection_element_type called on {:?}",
3591                self
3592            ),
3593        }
3594    }
3595
3596    /// Returns the [`SqlScalarType`] of values in a [`SqlScalarType::Map`].
3597    ///
3598    /// # Panics
3599    ///
3600    /// Panics if called on anything other than a [`SqlScalarType::Map`].
3601    pub fn unwrap_map_value_type(&self) -> &SqlScalarType {
3602        match self {
3603            SqlScalarType::Map { value_type, .. } => &**value_type,
3604            _ => panic!("SqlScalarType::unwrap_map_value_type called on {:?}", self),
3605        }
3606    }
3607
3608    /// Returns the length of a [`SqlScalarType::Char`].
3609    ///
3610    /// # Panics
3611    ///
3612    /// Panics if called on anything other than a [`SqlScalarType::Char`].
3613    pub fn unwrap_char_length(&self) -> Option<CharLength> {
3614        match self {
3615            SqlScalarType::Char { length, .. } => *length,
3616            _ => panic!("SqlScalarType::unwrap_char_length called on {:?}", self),
3617        }
3618    }
3619
3620    /// Returns the max length of a [`SqlScalarType::VarChar`].
3621    ///
3622    /// # Panics
3623    ///
3624    /// Panics if called on anything other than a [`SqlScalarType::VarChar`].
3625    pub fn unwrap_varchar_max_length(&self) -> Option<VarCharMaxLength> {
3626        match self {
3627            SqlScalarType::VarChar { max_length, .. } => *max_length,
3628            _ => panic!(
3629                "SqlScalarType::unwrap_varchar_max_length called on {:?}",
3630                self
3631            ),
3632        }
3633    }
3634
3635    /// Returns the [`SqlScalarType`] of elements in a [`SqlScalarType::Range`].
3636    ///
3637    /// # Panics
3638    ///
3639    /// Panics if called on anything other than a [`SqlScalarType::Map`].
3640    pub fn unwrap_range_element_type(&self) -> &SqlScalarType {
3641        match self {
3642            SqlScalarType::Range { element_type } => &**element_type,
3643            _ => panic!(
3644                "SqlScalarType::unwrap_range_element_type called on {:?}",
3645                self
3646            ),
3647        }
3648    }
3649
3650    /// Returns a "near match" of `self`, which are types that are implicitly
3651    /// castable from `self` and offer a means to leverage Materialize's type
3652    /// system to achieve more reasonable approaches to unifying types.
3653    ///
3654    /// However, it's very important to not blithely accept the `near_match`,
3655    /// which can be suboptimal/unnecessary, e.g. in the case of an already
3656    /// homogeneous group.
3657    ///
3658    /// The feature is preferrable in MZ, but unnecessary in PG because PG's
3659    /// type system offers totally linear progression through the complexity of
3660    /// types. e.g. with numbers, there is a linear progression in the domain
3661    /// each can represent. However, MZ's support for unsigned integers create a
3662    /// non-linear type system, i.e. while the magnitude of `Int32` and
3663    /// `UInt32`'s domains are the same, they are not equal.
3664    ///
3665    /// Without this feature, Materialize will:
3666    /// - Guess that a mixute of the same width of int and uint cannot be
3667    ///   coerced to a homogeneous type.
3668    /// - Select the `Float64` based version of common binary functions (e.g.
3669    ///   `=`), which introduces an unexpected float cast to integer values.
3670    ///
3671    /// Note that if adding any near matches besides unsigned ints, consider
3672    /// extending/generalizing how `guess_best_common_type` uses this function.
3673    pub fn near_match(&self) -> Option<&'static SqlScalarType> {
3674        match self {
3675            SqlScalarType::UInt16 => Some(&SqlScalarType::Int32),
3676            SqlScalarType::UInt32 => Some(&SqlScalarType::Int64),
3677            SqlScalarType::UInt64 => Some(&SqlScalarType::Numeric { max_scale: None }),
3678            _ => None,
3679        }
3680    }
3681
3682    /// Derives a column type from this scalar type with the specified
3683    /// nullability.
3684    pub const fn nullable(self, nullable: bool) -> SqlColumnType {
3685        SqlColumnType {
3686            nullable,
3687            scalar_type: self,
3688        }
3689    }
3690
3691    /// Returns whether or not `self` is a vector-like type, i.e.
3692    /// [`SqlScalarType::Array`], [`SqlScalarType::Int2Vector`], or
3693    /// [`SqlScalarType::List`], irrespective of its element type.
3694    pub fn is_vec(&self) -> bool {
3695        matches!(
3696            self,
3697            SqlScalarType::Array(_) | SqlScalarType::Int2Vector | SqlScalarType::List { .. }
3698        )
3699    }
3700
3701    pub fn is_custom_type(&self) -> bool {
3702        use SqlScalarType::*;
3703        match self {
3704            List {
3705                element_type: t,
3706                custom_id,
3707            }
3708            | Map {
3709                value_type: t,
3710                custom_id,
3711            } => custom_id.is_some() || t.is_custom_type(),
3712            Record {
3713                fields, custom_id, ..
3714            } => {
3715                custom_id.is_some()
3716                    || fields
3717                        .iter()
3718                        .map(|(_, t)| t)
3719                        .any(|t| t.scalar_type.is_custom_type())
3720            }
3721            _ => false,
3722        }
3723    }
3724
3725    /// Determines equality among scalar types that acknowledges custom OIDs,
3726    /// but ignores other embedded values.
3727    ///
3728    /// In most situations, you want to use `base_eq` rather than `SqlScalarType`'s
3729    /// implementation of `Eq`. `base_eq` expresses the semantics of direct type
3730    /// interoperability whereas `Eq` expresses an exact comparison between the
3731    /// values.
3732    ///
3733    /// For instance, `base_eq` signals that e.g. two [`SqlScalarType::Numeric`]
3734    /// values can be added together, irrespective of their embedded scale. In
3735    /// contrast, two `Numeric` values with different scales are never `Eq` to
3736    /// one another.
3737    pub fn base_eq(&self, other: &SqlScalarType) -> bool {
3738        self.eq_inner(other, false)
3739    }
3740
3741    // Determines equality among scalar types that ignores any custom OIDs or
3742    // embedded values.
3743    pub fn structural_eq(&self, other: &SqlScalarType) -> bool {
3744        self.eq_inner(other, true)
3745    }
3746
3747    pub fn eq_inner(&self, other: &SqlScalarType, structure_only: bool) -> bool {
3748        use SqlScalarType::*;
3749        match (self, other) {
3750            (
3751                List {
3752                    element_type: l,
3753                    custom_id: oid_l,
3754                },
3755                List {
3756                    element_type: r,
3757                    custom_id: oid_r,
3758                },
3759            )
3760            | (
3761                Map {
3762                    value_type: l,
3763                    custom_id: oid_l,
3764                },
3765                Map {
3766                    value_type: r,
3767                    custom_id: oid_r,
3768                },
3769            ) => l.eq_inner(r, structure_only) && (oid_l == oid_r || structure_only),
3770            (Array(a), Array(b)) | (Range { element_type: a }, Range { element_type: b }) => {
3771                a.eq_inner(b, structure_only)
3772            }
3773            (
3774                Record {
3775                    fields: fields_a,
3776                    custom_id: oid_a,
3777                },
3778                Record {
3779                    fields: fields_b,
3780                    custom_id: oid_b,
3781                },
3782            ) => {
3783                (oid_a == oid_b || structure_only)
3784                    && fields_a.len() == fields_b.len()
3785                    && fields_a
3786                        .iter()
3787                        .zip_eq(fields_b)
3788                        // Ignore nullability.
3789                        .all(|(a, b)| {
3790                            (a.0 == b.0 || structure_only)
3791                                && a.1.scalar_type.eq_inner(&b.1.scalar_type, structure_only)
3792                        })
3793            }
3794            (s, o) => SqlScalarBaseType::from(s) == SqlScalarBaseType::from(o),
3795        }
3796    }
3797
3798    /// Adopts the nullability from another [`SqlScalarType`].
3799    /// Traverses deeply into structured types.
3800    pub fn backport_nullability(&mut self, backport_typ: &ReprScalarType) {
3801        match (self, backport_typ) {
3802            (
3803                SqlScalarType::List { element_type, .. },
3804                ReprScalarType::List {
3805                    element_type: backport_element_type,
3806                    ..
3807                },
3808            ) => {
3809                element_type.backport_nullability(backport_element_type);
3810            }
3811            (
3812                SqlScalarType::Map { value_type, .. },
3813                ReprScalarType::Map {
3814                    value_type: backport_value_type,
3815                    ..
3816                },
3817            ) => {
3818                value_type.backport_nullability(backport_value_type);
3819            }
3820            (
3821                SqlScalarType::Record { fields, .. },
3822                ReprScalarType::Record {
3823                    fields: backport_fields,
3824                    ..
3825                },
3826            ) => {
3827                assert_eq!(
3828                    fields.len(),
3829                    backport_fields.len(),
3830                    "HIR and MIR types should have the same number of fields"
3831                );
3832                fields
3833                    .iter_mut()
3834                    .zip_eq(backport_fields)
3835                    .for_each(|(field, backport_field)| {
3836                        field.1.backport_nullability(backport_field);
3837                    });
3838            }
3839            (SqlScalarType::Array(a), ReprScalarType::Array(b)) => {
3840                a.backport_nullability(b);
3841            }
3842            (
3843                SqlScalarType::Range { element_type },
3844                ReprScalarType::Range {
3845                    element_type: backport_element_type,
3846                },
3847            ) => {
3848                element_type.backport_nullability(backport_element_type);
3849            }
3850            _ => (),
3851        }
3852    }
3853
3854    /// Returns various interesting datums for a SqlScalarType (max, min, 0 values, etc.).
3855    pub fn interesting_datums(&self) -> impl Iterator<Item = Datum<'static>> {
3856        // TODO: Add datums for the types that have an inner Box'd SqlScalarType. It'd be best to
3857        // re-use this function to dynamically generate interesting datums of the requested type.
3858        // But the 'static bound makes this either hard or impossible. We might need to remove that
3859        // and return, say, an owned Row. This would require changing lots of dependent test
3860        // functions, some of which also hard code a 'static bound.
3861        static BOOL: LazyLock<Row> =
3862            LazyLock::new(|| Row::pack_slice(&[Datum::True, Datum::False]));
3863        static INT16: LazyLock<Row> = LazyLock::new(|| {
3864            Row::pack_slice(&[
3865                Datum::Int16(0),
3866                Datum::Int16(1),
3867                Datum::Int16(-1),
3868                Datum::Int16(i16::MIN),
3869                Datum::Int16(i16::MIN + 1),
3870                Datum::Int16(i16::MAX),
3871                // The following datums are
3872                // around the boundaries introduced by
3873                // variable-length int encoding
3874                //
3875                // TODO[btv]: Add more datums around
3876                // boundaries in VLE (e.g. negatives) if `test_smoketest_all_builtins` is
3877                // fixed to be faster.
3878                Datum::Int16(127),
3879                Datum::Int16(128),
3880            ])
3881        });
3882        static INT32: LazyLock<Row> = LazyLock::new(|| {
3883            Row::pack_slice(&[
3884                Datum::Int32(0),
3885                Datum::Int32(1),
3886                Datum::Int32(-1),
3887                Datum::Int32(i32::MIN),
3888                Datum::Int32(i32::MIN + 1),
3889                Datum::Int32(i32::MAX),
3890                // The following datums are
3891                // around the boundaries introduced by
3892                // variable-length int encoding
3893                Datum::Int32(32767),
3894                Datum::Int32(32768),
3895            ])
3896        });
3897        static INT64: LazyLock<Row> = LazyLock::new(|| {
3898            Row::pack_slice(&[
3899                Datum::Int64(0),
3900                Datum::Int64(1),
3901                Datum::Int64(-1),
3902                Datum::Int64(i64::MIN),
3903                Datum::Int64(i64::MIN + 1),
3904                Datum::Int64(i64::MAX),
3905                // The following datums are
3906                // around the boundaries introduced by
3907                // variable-length int encoding
3908                Datum::Int64(2147483647),
3909                Datum::Int64(2147483648),
3910            ])
3911        });
3912        static UINT16: LazyLock<Row> = LazyLock::new(|| {
3913            Row::pack_slice(&[
3914                Datum::UInt16(0),
3915                Datum::UInt16(1),
3916                Datum::UInt16(u16::MAX),
3917                // The following datums are
3918                // around the boundaries introduced by
3919                // variable-length int encoding
3920                Datum::UInt16(255),
3921                Datum::UInt16(256),
3922            ])
3923        });
3924        static UINT32: LazyLock<Row> = LazyLock::new(|| {
3925            Row::pack_slice(&[
3926                Datum::UInt32(0),
3927                Datum::UInt32(1),
3928                Datum::UInt32(u32::MAX),
3929                // The following datums are
3930                // around the boundaries introduced by
3931                // variable-length int encoding
3932                Datum::UInt32(32767),
3933                Datum::UInt32(32768),
3934            ])
3935        });
3936        static UINT64: LazyLock<Row> = LazyLock::new(|| {
3937            Row::pack_slice(&[
3938                Datum::UInt64(0),
3939                Datum::UInt64(1),
3940                Datum::UInt64(u64::MAX),
3941                // The following datums are
3942                // around the boundaries introduced by
3943                // variable-length int encoding
3944                Datum::UInt64(2147483647),
3945                Datum::UInt64(2147483648),
3946            ])
3947        });
3948        static FLOAT32: LazyLock<Row> = LazyLock::new(|| {
3949            Row::pack_slice(&[
3950                Datum::Float32(OrderedFloat(0.0)),
3951                Datum::Float32(OrderedFloat(1.0)),
3952                Datum::Float32(OrderedFloat(-1.0)),
3953                Datum::Float32(OrderedFloat(f32::MIN)),
3954                Datum::Float32(OrderedFloat(f32::MIN_POSITIVE)),
3955                Datum::Float32(OrderedFloat(f32::MAX)),
3956                Datum::Float32(OrderedFloat(f32::EPSILON)),
3957                Datum::Float32(OrderedFloat(f32::NAN)),
3958                Datum::Float32(OrderedFloat(f32::INFINITY)),
3959                Datum::Float32(OrderedFloat(f32::NEG_INFINITY)),
3960            ])
3961        });
3962        static FLOAT64: LazyLock<Row> = LazyLock::new(|| {
3963            Row::pack_slice(&[
3964                Datum::Float64(OrderedFloat(0.0)),
3965                Datum::Float64(OrderedFloat(1.0)),
3966                Datum::Float64(OrderedFloat(-1.0)),
3967                Datum::Float64(OrderedFloat(f64::MIN)),
3968                Datum::Float64(OrderedFloat(f64::MIN_POSITIVE)),
3969                Datum::Float64(OrderedFloat(f64::MAX)),
3970                Datum::Float64(OrderedFloat(f64::EPSILON)),
3971                Datum::Float64(OrderedFloat(f64::NAN)),
3972                Datum::Float64(OrderedFloat(f64::INFINITY)),
3973                Datum::Float64(OrderedFloat(f64::NEG_INFINITY)),
3974            ])
3975        });
3976        static NUMERIC: LazyLock<Row> = LazyLock::new(|| {
3977            cfg_if::cfg_if! {
3978                // Numerics can't currently be instantiated under Miri
3979                if #[cfg(miri)] {
3980                    Row::pack_slice(&[])
3981                } else {
3982                    Row::pack_slice(&[
3983                        Datum::Numeric(OrderedDecimal(Numeric::from(0.0))),
3984                        Datum::Numeric(OrderedDecimal(Numeric::from(1.0))),
3985                        Datum::Numeric(OrderedDecimal(Numeric::from(-1.0))),
3986                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MIN))),
3987                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MIN_POSITIVE))),
3988                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MAX))),
3989                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::EPSILON))),
3990                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::NAN))),
3991                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::INFINITY))),
3992                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::NEG_INFINITY))),
3993                    ])
3994                }
3995            }
3996        });
3997        static DATE: LazyLock<Row> = LazyLock::new(|| {
3998            Row::pack_slice(&[
3999                Datum::Date(Date::from_pg_epoch(0).unwrap()),
4000                Datum::Date(Date::from_pg_epoch(Date::LOW_DAYS).unwrap()),
4001                Datum::Date(Date::from_pg_epoch(Date::HIGH_DAYS).unwrap()),
4002            ])
4003        });
4004        static TIME: LazyLock<Row> = LazyLock::new(|| {
4005            Row::pack_slice(&[
4006                Datum::Time(NaiveTime::from_hms_micro_opt(0, 0, 0, 0).unwrap()),
4007                Datum::Time(NaiveTime::from_hms_micro_opt(23, 59, 59, 999_999).unwrap()),
4008            ])
4009        });
4010        static TIMESTAMP: LazyLock<Row> = LazyLock::new(|| {
4011            Row::pack_slice(&[
4012                Datum::Timestamp(
4013                    DateTime::from_timestamp(0, 0)
4014                        .unwrap()
4015                        .naive_utc()
4016                        .try_into()
4017                        .unwrap(),
4018                ),
4019                Datum::Timestamp(
4020                    crate::adt::timestamp::LOW_DATE
4021                        .and_hms_opt(0, 0, 0)
4022                        .unwrap()
4023                        .try_into()
4024                        .unwrap(),
4025                ),
4026                Datum::Timestamp(
4027                    crate::adt::timestamp::HIGH_DATE
4028                        .and_hms_opt(23, 59, 59)
4029                        .unwrap()
4030                        .try_into()
4031                        .unwrap(),
4032                ),
4033                // nano seconds
4034                Datum::Timestamp(
4035                    DateTime::from_timestamp(0, 123456789)
4036                        .unwrap()
4037                        .naive_utc()
4038                        .try_into()
4039                        .unwrap(),
4040                ),
4041                // Leap second
4042                Datum::Timestamp(
4043                    CheckedTimestamp::from_timestamplike(
4044                        NaiveDate::from_isoywd_opt(2019, 30, chrono::Weekday::Wed)
4045                            .unwrap()
4046                            .and_hms_milli_opt(23, 59, 59, 1234)
4047                            .unwrap(),
4048                    )
4049                    .unwrap(),
4050                ),
4051            ])
4052        });
4053        static TIMESTAMPTZ: LazyLock<Row> = LazyLock::new(|| {
4054            Row::pack_slice(&[
4055                Datum::TimestampTz(DateTime::from_timestamp(0, 0).unwrap().try_into().unwrap()),
4056                Datum::TimestampTz(
4057                    DateTime::from_naive_utc_and_offset(
4058                        crate::adt::timestamp::LOW_DATE
4059                            .and_hms_opt(0, 0, 0)
4060                            .unwrap(),
4061                        Utc,
4062                    )
4063                    .try_into()
4064                    .unwrap(),
4065                ),
4066                Datum::TimestampTz(
4067                    DateTime::from_naive_utc_and_offset(
4068                        crate::adt::timestamp::HIGH_DATE
4069                            .and_hms_opt(23, 59, 59)
4070                            .unwrap(),
4071                        Utc,
4072                    )
4073                    .try_into()
4074                    .unwrap(),
4075                ),
4076                // nano seconds
4077                Datum::TimestampTz(
4078                    DateTime::from_timestamp(0, 123456789)
4079                        .unwrap()
4080                        .try_into()
4081                        .unwrap(),
4082                ),
4083            ])
4084        });
4085        static INTERVAL: LazyLock<Row> = LazyLock::new(|| {
4086            Row::pack_slice(&[
4087                Datum::Interval(Interval::new(0, 0, 0)),
4088                Datum::Interval(Interval::new(1, 1, 1)),
4089                Datum::Interval(Interval::new(-1, -1, -1)),
4090                Datum::Interval(Interval::new(1, 0, 0)),
4091                Datum::Interval(Interval::new(0, 1, 0)),
4092                Datum::Interval(Interval::new(0, 0, 1)),
4093                Datum::Interval(Interval::new(-1, 0, 0)),
4094                Datum::Interval(Interval::new(0, -1, 0)),
4095                Datum::Interval(Interval::new(0, 0, -1)),
4096                Datum::Interval(Interval::new(i32::MIN, i32::MIN, i64::MIN)),
4097                Datum::Interval(Interval::new(i32::MAX, i32::MAX, i64::MAX)),
4098                Datum::Interval(Interval::new(i32::MIN, 0, 0)),
4099                Datum::Interval(Interval::new(i32::MAX, 0, 0)),
4100                Datum::Interval(Interval::new(0, i32::MIN, 0)),
4101                Datum::Interval(Interval::new(0, i32::MAX, 0)),
4102                Datum::Interval(Interval::new(0, 0, i64::MIN)),
4103                Datum::Interval(Interval::new(0, 0, i64::MAX)),
4104            ])
4105        });
4106        static PGLEGACYCHAR: LazyLock<Row> =
4107            LazyLock::new(|| Row::pack_slice(&[Datum::UInt8(u8::MIN), Datum::UInt8(u8::MAX)]));
4108        static PGLEGACYNAME: LazyLock<Row> = LazyLock::new(|| {
4109            Row::pack_slice(&[
4110                Datum::String(""),
4111                Datum::String(" "),
4112                Datum::String("'"),
4113                Datum::String("\""),
4114                Datum::String("."),
4115                Datum::String(&"x".repeat(64)),
4116            ])
4117        });
4118        static BYTES: LazyLock<Row> = LazyLock::new(|| {
4119            Row::pack_slice(&[Datum::Bytes(&[]), Datum::Bytes(&[0]), Datum::Bytes(&[255])])
4120        });
4121        static STRING: LazyLock<Row> = LazyLock::new(|| {
4122            Row::pack_slice(&[
4123                Datum::String(""),
4124                Datum::String(" "),
4125                Datum::String("'"),
4126                Datum::String("\""),
4127                Datum::String("."),
4128                Datum::String("2015-09-18T23:56:04.123Z"),
4129                Datum::String(&"x".repeat(100)),
4130                // Valid timezone.
4131                Datum::String("JAPAN"),
4132                Datum::String("1,2,3"),
4133                Datum::String("\r\n"),
4134                Datum::String("\"\""),
4135            ])
4136        });
4137        static CHAR: LazyLock<Row> = LazyLock::new(|| {
4138            Row::pack_slice(&[
4139                Datum::String(" "),
4140                Datum::String("'"),
4141                Datum::String("\""),
4142                Datum::String("."),
4143                Datum::String(","),
4144                Datum::String("\t"),
4145                Datum::String("\n"),
4146                Datum::String("\r"),
4147                Datum::String("\\"),
4148                // Null character.
4149                Datum::String(std::str::from_utf8(b"\x00").unwrap()),
4150                // Start of text.
4151                Datum::String(std::str::from_utf8(b"\x02").unwrap()),
4152                // End of text.
4153                Datum::String(std::str::from_utf8(b"\x03").unwrap()),
4154                // Backspace.
4155                Datum::String(std::str::from_utf8(b"\x08").unwrap()),
4156                // Escape.
4157                Datum::String(std::str::from_utf8(b"\x1B").unwrap()),
4158                // Delete.
4159                Datum::String(std::str::from_utf8(b"\x7F").unwrap()),
4160            ])
4161        });
4162        static JSONB: LazyLock<Row> = LazyLock::new(|| {
4163            let mut datums = vec![Datum::True, Datum::False, Datum::JsonNull];
4164            datums.extend(STRING.iter());
4165            datums.extend(NUMERIC.iter().filter(|n| {
4166                let Datum::Numeric(n) = n else {
4167                    panic!("expected Numeric, found {n:?}");
4168                };
4169                // JSON doesn't support NaN or Infinite numbers.
4170                !(n.0.is_nan() || n.0.is_infinite())
4171            }));
4172            // TODO: Add List, Map.
4173            Row::pack_slice(&datums)
4174        });
4175        static UUID: LazyLock<Row> = LazyLock::new(|| {
4176            Row::pack_slice(&[
4177                Datum::Uuid(Uuid::from_u128(u128::MIN)),
4178                Datum::Uuid(Uuid::from_u128(u128::MAX)),
4179            ])
4180        });
4181        static ARRAY: LazyLock<BTreeMap<&'static SqlScalarType, Row>> = LazyLock::new(|| {
4182            let generate_row = |inner_type: &SqlScalarType| {
4183                let datums: Vec<_> = inner_type.interesting_datums().collect();
4184
4185                let mut row = Row::default();
4186                row.packer()
4187                    .try_push_array::<_, Datum<'static>>(
4188                        &[ArrayDimension {
4189                            lower_bound: 1,
4190                            length: 0,
4191                        }],
4192                        [],
4193                    )
4194                    .expect("failed to push empty array");
4195                row.packer()
4196                    .try_push_array(
4197                        &[ArrayDimension {
4198                            lower_bound: 1,
4199                            length: datums.len(),
4200                        }],
4201                        datums,
4202                    )
4203                    .expect("failed to push array");
4204
4205                row
4206            };
4207
4208            SqlScalarType::enumerate()
4209                .into_iter()
4210                .filter(|ty| !matches!(ty, SqlScalarType::Array(_)))
4211                .map(|ty| (ty, generate_row(ty)))
4212                .collect()
4213        });
4214        static EMPTY_ARRAY: LazyLock<Row> = LazyLock::new(|| {
4215            let mut row = Row::default();
4216            row.packer()
4217                .try_push_array::<_, Datum<'static>>(
4218                    &[ArrayDimension {
4219                        lower_bound: 1,
4220                        length: 0,
4221                    }],
4222                    [],
4223                )
4224                .expect("failed to push empty array");
4225            row
4226        });
4227        static LIST: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4228        static RECORD: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4229        static OID: LazyLock<Row> =
4230            LazyLock::new(|| Row::pack_slice(&[Datum::UInt32(u32::MIN), Datum::UInt32(u32::MAX)]));
4231        static MAP: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4232        static INT2VECTOR: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4233        static MZTIMESTAMP: LazyLock<Row> = LazyLock::new(|| {
4234            Row::pack_slice(&[
4235                Datum::MzTimestamp(crate::Timestamp::MIN),
4236                Datum::MzTimestamp(crate::Timestamp::MAX),
4237            ])
4238        });
4239        static RANGE: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4240        static MZACLITEM: LazyLock<Row> = LazyLock::new(|| {
4241            Row::pack_slice(&[
4242                Datum::MzAclItem(MzAclItem {
4243                    grantee: RoleId::Public,
4244                    grantor: RoleId::Public,
4245                    acl_mode: AclMode::empty(),
4246                }),
4247                Datum::MzAclItem(MzAclItem {
4248                    grantee: RoleId::Public,
4249                    grantor: RoleId::Public,
4250                    acl_mode: AclMode::all(),
4251                }),
4252                Datum::MzAclItem(MzAclItem {
4253                    grantee: RoleId::User(42),
4254                    grantor: RoleId::Public,
4255                    acl_mode: AclMode::empty(),
4256                }),
4257                Datum::MzAclItem(MzAclItem {
4258                    grantee: RoleId::User(42),
4259                    grantor: RoleId::Public,
4260                    acl_mode: AclMode::all(),
4261                }),
4262                Datum::MzAclItem(MzAclItem {
4263                    grantee: RoleId::Public,
4264                    grantor: RoleId::User(42),
4265                    acl_mode: AclMode::empty(),
4266                }),
4267                Datum::MzAclItem(MzAclItem {
4268                    grantee: RoleId::Public,
4269                    grantor: RoleId::User(42),
4270                    acl_mode: AclMode::all(),
4271                }),
4272            ])
4273        });
4274        // aclitem has no binary encoding so we can't test it here.
4275        static ACLITEM: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4276
4277        let iter: Box<dyn Iterator<Item = Datum<'static>>> = match self {
4278            SqlScalarType::Bool => Box::new((*BOOL).iter()),
4279            SqlScalarType::Int16 => Box::new((*INT16).iter()),
4280            SqlScalarType::Int32 => Box::new((*INT32).iter()),
4281            SqlScalarType::Int64 => Box::new((*INT64).iter()),
4282            SqlScalarType::UInt16 => Box::new((*UINT16).iter()),
4283            SqlScalarType::UInt32 => Box::new((*UINT32).iter()),
4284            SqlScalarType::UInt64 => Box::new((*UINT64).iter()),
4285            SqlScalarType::Float32 => Box::new((*FLOAT32).iter()),
4286            SqlScalarType::Float64 => Box::new((*FLOAT64).iter()),
4287            SqlScalarType::Numeric { .. } => Box::new((*NUMERIC).iter()),
4288            SqlScalarType::Date => Box::new((*DATE).iter()),
4289            SqlScalarType::Time => Box::new((*TIME).iter()),
4290            SqlScalarType::Timestamp { .. } => Box::new((*TIMESTAMP).iter()),
4291            SqlScalarType::TimestampTz { .. } => Box::new((*TIMESTAMPTZ).iter()),
4292            SqlScalarType::Interval => Box::new((*INTERVAL).iter()),
4293            SqlScalarType::PgLegacyChar => Box::new((*PGLEGACYCHAR).iter()),
4294            SqlScalarType::PgLegacyName => Box::new((*PGLEGACYNAME).iter()),
4295            SqlScalarType::Bytes => Box::new((*BYTES).iter()),
4296            SqlScalarType::String => Box::new((*STRING).iter().chain((*CHAR).iter())),
4297            SqlScalarType::Char { .. } => Box::new((*CHAR).iter()),
4298            SqlScalarType::VarChar { .. } => Box::new((*STRING).iter().chain((*CHAR).iter())),
4299            SqlScalarType::Jsonb => Box::new((*JSONB).iter()),
4300            SqlScalarType::Uuid => Box::new((*UUID).iter()),
4301            SqlScalarType::Array(inner_type) => {
4302                if matches!(inner_type.as_ref(), SqlScalarType::Array(_)) {
4303                    panic!("SqlScalarType::Array cannot have a nested Array");
4304                }
4305
4306                Box::new(
4307                    (*ARRAY)
4308                        .get(inner_type.as_ref())
4309                        .unwrap_or(&*EMPTY_ARRAY)
4310                        .iter(),
4311                )
4312            }
4313            SqlScalarType::List { .. } => Box::new((*LIST).iter()),
4314            SqlScalarType::Record { .. } => Box::new((*RECORD).iter()),
4315            SqlScalarType::Oid => Box::new((*OID).iter()),
4316            SqlScalarType::Map { .. } => Box::new((*MAP).iter()),
4317            SqlScalarType::RegProc => Box::new((*OID).iter()),
4318            SqlScalarType::RegType => Box::new((*OID).iter()),
4319            SqlScalarType::RegClass => Box::new((*OID).iter()),
4320            SqlScalarType::Int2Vector => Box::new((*INT2VECTOR).iter()),
4321            SqlScalarType::MzTimestamp => Box::new((*MZTIMESTAMP).iter()),
4322            SqlScalarType::Range { .. } => Box::new((*RANGE).iter()),
4323            SqlScalarType::MzAclItem { .. } => Box::new((*MZACLITEM).iter()),
4324            SqlScalarType::AclItem { .. } => Box::new((*ACLITEM).iter()),
4325        };
4326
4327        iter
4328    }
4329
4330    /// Returns all non-parameterized types and some versions of some
4331    /// parameterized types.
4332    pub fn enumerate() -> &'static [Self] {
4333        // TODO: Is there a compile-time way to make sure any new
4334        // non-parameterized types get added here?
4335        &[
4336            SqlScalarType::Bool,
4337            SqlScalarType::Int16,
4338            SqlScalarType::Int32,
4339            SqlScalarType::Int64,
4340            SqlScalarType::UInt16,
4341            SqlScalarType::UInt32,
4342            SqlScalarType::UInt64,
4343            SqlScalarType::Float32,
4344            SqlScalarType::Float64,
4345            SqlScalarType::Numeric {
4346                max_scale: Some(NumericMaxScale(
4347                    crate::adt::numeric::NUMERIC_DATUM_MAX_PRECISION,
4348                )),
4349            },
4350            SqlScalarType::Date,
4351            SqlScalarType::Time,
4352            SqlScalarType::Timestamp {
4353                precision: Some(TimestampPrecision(crate::adt::timestamp::MAX_PRECISION)),
4354            },
4355            SqlScalarType::Timestamp {
4356                precision: Some(TimestampPrecision(0)),
4357            },
4358            SqlScalarType::Timestamp { precision: None },
4359            SqlScalarType::TimestampTz {
4360                precision: Some(TimestampPrecision(crate::adt::timestamp::MAX_PRECISION)),
4361            },
4362            SqlScalarType::TimestampTz {
4363                precision: Some(TimestampPrecision(0)),
4364            },
4365            SqlScalarType::TimestampTz { precision: None },
4366            SqlScalarType::Interval,
4367            SqlScalarType::PgLegacyChar,
4368            SqlScalarType::Bytes,
4369            SqlScalarType::String,
4370            SqlScalarType::Char {
4371                length: Some(CharLength(1)),
4372            },
4373            SqlScalarType::VarChar { max_length: None },
4374            SqlScalarType::Jsonb,
4375            SqlScalarType::Uuid,
4376            SqlScalarType::Oid,
4377            SqlScalarType::RegProc,
4378            SqlScalarType::RegType,
4379            SqlScalarType::RegClass,
4380            SqlScalarType::Int2Vector,
4381            SqlScalarType::MzTimestamp,
4382            SqlScalarType::MzAclItem,
4383            // TODO: Fill in some variants of these.
4384            /*
4385            SqlScalarType::AclItem,
4386            SqlScalarType::Array(_),
4387            SqlScalarType::List {
4388                element_type: todo!(),
4389                custom_id: todo!(),
4390            },
4391            SqlScalarType::Record {
4392                fields: todo!(),
4393                custom_id: todo!(),
4394            },
4395            SqlScalarType::Map {
4396                value_type: todo!(),
4397                custom_id: todo!(),
4398            },
4399            SqlScalarType::Range {
4400                element_type: todo!(),
4401            }
4402            */
4403        ]
4404    }
4405
4406    /// Returns the appropriate element type for making a [`SqlScalarType::Array`] whose elements are
4407    /// of `self`.
4408    ///
4409    /// If the type is not compatible with making an array, returns in the error position.
4410    pub fn array_of_self_elem_type(self) -> Result<SqlScalarType, SqlScalarType> {
4411        match self {
4412            t @ (SqlScalarType::AclItem
4413            | SqlScalarType::Bool
4414            | SqlScalarType::Int16
4415            | SqlScalarType::Int32
4416            | SqlScalarType::Int64
4417            | SqlScalarType::UInt16
4418            | SqlScalarType::UInt32
4419            | SqlScalarType::UInt64
4420            | SqlScalarType::Float32
4421            | SqlScalarType::Float64
4422            | SqlScalarType::Numeric { .. }
4423            | SqlScalarType::Date
4424            | SqlScalarType::Time
4425            | SqlScalarType::Timestamp { .. }
4426            | SqlScalarType::TimestampTz { .. }
4427            | SqlScalarType::Interval
4428            | SqlScalarType::PgLegacyChar
4429            | SqlScalarType::PgLegacyName
4430            | SqlScalarType::Bytes
4431            | SqlScalarType::String
4432            | SqlScalarType::VarChar { .. }
4433            | SqlScalarType::Jsonb
4434            | SqlScalarType::Uuid
4435            | SqlScalarType::Record { .. }
4436            | SqlScalarType::Oid
4437            | SqlScalarType::RegProc
4438            | SqlScalarType::RegType
4439            | SqlScalarType::RegClass
4440            | SqlScalarType::Int2Vector
4441            | SqlScalarType::MzTimestamp
4442            | SqlScalarType::Range { .. }
4443            | SqlScalarType::MzAclItem { .. }) => Ok(t),
4444
4445            SqlScalarType::Array(elem) => Ok(elem.array_of_self_elem_type()?),
4446
4447            // https://github.com/MaterializeInc/database-issues/issues/2360
4448            t @ (SqlScalarType::Char { .. }
4449            // not sensible to put in arrays
4450            | SqlScalarType::Map { .. }
4451            | SqlScalarType::List { .. }) => Err(t),
4452        }
4453    }
4454}
4455
4456// See the chapter "Generating Recurisve Data" from the proptest book:
4457// https://altsysrq.github.io/proptest-book/proptest/tutorial/recursive.html
4458impl Arbitrary for SqlScalarType {
4459    type Parameters = ();
4460    type Strategy = BoxedStrategy<SqlScalarType>;
4461
4462    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
4463        // A strategy for generating the leaf cases of SqlScalarType
4464        let leaf = Union::new(vec![
4465            Just(SqlScalarType::Bool).boxed(),
4466            Just(SqlScalarType::UInt16).boxed(),
4467            Just(SqlScalarType::UInt32).boxed(),
4468            Just(SqlScalarType::UInt64).boxed(),
4469            Just(SqlScalarType::Int16).boxed(),
4470            Just(SqlScalarType::Int32).boxed(),
4471            Just(SqlScalarType::Int64).boxed(),
4472            Just(SqlScalarType::Float32).boxed(),
4473            Just(SqlScalarType::Float64).boxed(),
4474            any::<Option<NumericMaxScale>>()
4475                .prop_map(|max_scale| SqlScalarType::Numeric { max_scale })
4476                .boxed(),
4477            Just(SqlScalarType::Date).boxed(),
4478            Just(SqlScalarType::Time).boxed(),
4479            any::<Option<TimestampPrecision>>()
4480                .prop_map(|precision| SqlScalarType::Timestamp { precision })
4481                .boxed(),
4482            any::<Option<TimestampPrecision>>()
4483                .prop_map(|precision| SqlScalarType::TimestampTz { precision })
4484                .boxed(),
4485            Just(SqlScalarType::MzTimestamp).boxed(),
4486            Just(SqlScalarType::Interval).boxed(),
4487            Just(SqlScalarType::PgLegacyChar).boxed(),
4488            Just(SqlScalarType::Bytes).boxed(),
4489            Just(SqlScalarType::String).boxed(),
4490            any::<Option<CharLength>>()
4491                .prop_map(|length| SqlScalarType::Char { length })
4492                .boxed(),
4493            any::<Option<VarCharMaxLength>>()
4494                .prop_map(|max_length| SqlScalarType::VarChar { max_length })
4495                .boxed(),
4496            Just(SqlScalarType::PgLegacyName).boxed(),
4497            Just(SqlScalarType::Jsonb).boxed(),
4498            Just(SqlScalarType::Uuid).boxed(),
4499            Just(SqlScalarType::AclItem).boxed(),
4500            Just(SqlScalarType::MzAclItem).boxed(),
4501            Just(SqlScalarType::Oid).boxed(),
4502            Just(SqlScalarType::RegProc).boxed(),
4503            Just(SqlScalarType::RegType).boxed(),
4504            Just(SqlScalarType::RegClass).boxed(),
4505            Just(SqlScalarType::Int2Vector).boxed(),
4506        ])
4507        // None of the leaf SqlScalarTypes types are really "simpler" than others
4508        // so don't waste time trying to shrink.
4509        .no_shrink()
4510        .boxed();
4511
4512        // There are a limited set of types we support in ranges.
4513        let range_leaf = Union::new(vec![
4514            Just(SqlScalarType::Int32).boxed(),
4515            Just(SqlScalarType::Int64).boxed(),
4516            Just(SqlScalarType::Date).boxed(),
4517            any::<Option<NumericMaxScale>>()
4518                .prop_map(|max_scale| SqlScalarType::Numeric { max_scale })
4519                .boxed(),
4520            any::<Option<TimestampPrecision>>()
4521                .prop_map(|precision| SqlScalarType::Timestamp { precision })
4522                .boxed(),
4523            any::<Option<TimestampPrecision>>()
4524                .prop_map(|precision| SqlScalarType::TimestampTz { precision })
4525                .boxed(),
4526        ]);
4527        let range = range_leaf
4528            .prop_map(|inner_type| SqlScalarType::Range {
4529                element_type: Box::new(inner_type),
4530            })
4531            .boxed();
4532
4533        // The Array type is not recursive, so we define it separately.
4534        let array = leaf
4535            .clone()
4536            .prop_map(|inner_type| SqlScalarType::Array(Box::new(inner_type)))
4537            .boxed();
4538
4539        let leaf = Union::new_weighted(vec![(30, leaf), (1, array), (1, range)]);
4540
4541        leaf.prop_recursive(2, 3, 5, |inner| {
4542            Union::new(vec![
4543                // List
4544                (inner.clone(), any::<Option<CatalogItemId>>())
4545                    .prop_map(|(x, id)| SqlScalarType::List {
4546                        element_type: Box::new(x),
4547                        custom_id: id,
4548                    })
4549                    .boxed(),
4550                // Map
4551                (inner.clone(), any::<Option<CatalogItemId>>())
4552                    .prop_map(|(x, id)| SqlScalarType::Map {
4553                        value_type: Box::new(x),
4554                        custom_id: id,
4555                    })
4556                    .boxed(),
4557                // Record
4558                {
4559                    // Now we have to use `inner` to create a Record type. First we
4560                    // create strategy that creates SqlColumnType.
4561                    let column_type_strat =
4562                        (inner, any::<bool>()).prop_map(|(scalar_type, nullable)| SqlColumnType {
4563                            scalar_type,
4564                            nullable,
4565                        });
4566
4567                    // Then we use that to create the fields of the record case.
4568                    // fields has type vec<(ColumnName,SqlColumnType)>
4569                    let fields_strat =
4570                        prop::collection::vec((any::<ColumnName>(), column_type_strat), 0..10);
4571
4572                    // Now we combine it with the default strategies to get Records.
4573                    (fields_strat, any::<Option<CatalogItemId>>())
4574                        .prop_map(|(fields, custom_id)| SqlScalarType::Record {
4575                            fields: fields.into(),
4576                            custom_id,
4577                        })
4578                        .boxed()
4579                },
4580            ])
4581        })
4582        .boxed()
4583    }
4584}
4585
4586impl Arbitrary for ReprScalarType {
4587    type Parameters = ();
4588    type Strategy = BoxedStrategy<ReprScalarType>;
4589
4590    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
4591        // A strategy for generating the leaf cases of ReprScalarType
4592        let leaf = Union::new(vec![
4593            Just(ReprScalarType::Bool).boxed(),
4594            Just(ReprScalarType::UInt8).boxed(),
4595            Just(ReprScalarType::UInt16).boxed(),
4596            Just(ReprScalarType::UInt32).boxed(),
4597            Just(ReprScalarType::UInt64).boxed(),
4598            Just(ReprScalarType::Int16).boxed(),
4599            Just(ReprScalarType::Int32).boxed(),
4600            Just(ReprScalarType::Int64).boxed(),
4601            Just(ReprScalarType::Float32).boxed(),
4602            Just(ReprScalarType::Float64).boxed(),
4603            Just(ReprScalarType::Numeric).boxed(),
4604            Just(ReprScalarType::Date).boxed(),
4605            Just(ReprScalarType::Time).boxed(),
4606            Just(ReprScalarType::Timestamp).boxed(),
4607            Just(ReprScalarType::TimestampTz).boxed(),
4608            Just(ReprScalarType::MzTimestamp).boxed(),
4609            Just(ReprScalarType::Interval).boxed(),
4610            Just(ReprScalarType::Bytes).boxed(),
4611            Just(ReprScalarType::String).boxed(),
4612            Just(ReprScalarType::Jsonb).boxed(),
4613            Just(ReprScalarType::Uuid).boxed(),
4614            Just(ReprScalarType::AclItem).boxed(),
4615            Just(ReprScalarType::MzAclItem).boxed(),
4616            Just(ReprScalarType::Int2Vector).boxed(),
4617        ])
4618        // None of the leaf ReprScalarTypes types are really "simpler" than others
4619        // so don't waste time trying to shrink.
4620        .no_shrink()
4621        .boxed();
4622
4623        // There are a limited set of types we support in ranges.
4624        let range_leaf = Union::new(vec![
4625            Just(ReprScalarType::Int32).boxed(),
4626            Just(ReprScalarType::Int64).boxed(),
4627            Just(ReprScalarType::Date).boxed(),
4628            Just(ReprScalarType::Numeric).boxed(),
4629            Just(ReprScalarType::Timestamp).boxed(),
4630            Just(ReprScalarType::TimestampTz).boxed(),
4631        ]);
4632        let range = range_leaf
4633            .prop_map(|inner_type| ReprScalarType::Range {
4634                element_type: Box::new(inner_type),
4635            })
4636            .boxed();
4637
4638        // The Array type is not recursive, so we define it separately.
4639        let array = leaf
4640            .clone()
4641            .prop_map(|inner_type| ReprScalarType::Array(Box::new(inner_type)))
4642            .boxed();
4643
4644        let leaf = Union::new_weighted(vec![(30, leaf), (1, array), (1, range)]);
4645
4646        leaf.prop_recursive(2, 3, 5, |inner| {
4647            Union::new(vec![
4648                // List
4649                inner
4650                    .clone()
4651                    .prop_map(|x| ReprScalarType::List {
4652                        element_type: Box::new(x),
4653                    })
4654                    .boxed(),
4655                // Map
4656                inner
4657                    .clone()
4658                    .prop_map(|x| ReprScalarType::Map {
4659                        value_type: Box::new(x),
4660                    })
4661                    .boxed(),
4662                // Record
4663                {
4664                    // Now we have to use `inner` to create a Record type. First we
4665                    // create strategy that creates SqlColumnType.
4666                    let column_type_strat =
4667                        (inner.clone(), any::<bool>()).prop_map(|(scalar_type, nullable)| {
4668                            ReprColumnType {
4669                                scalar_type,
4670                                nullable,
4671                            }
4672                        });
4673
4674                    // Then we use that to create the fields of the record case.
4675                    // fields has type vec<(ColumnName,SqlColumnType)>
4676                    let fields_strat = prop::collection::vec(column_type_strat, 0..10);
4677
4678                    // Now we combine it with the default strategies to get Records.
4679                    fields_strat
4680                        .prop_map(|fields| ReprScalarType::Record {
4681                            fields: fields.into_boxed_slice(),
4682                        })
4683                        .boxed()
4684                },
4685            ])
4686        })
4687        .boxed()
4688    }
4689}
4690
4691/// The type of a [`Datum`] as it is represented.
4692///
4693/// Each variant here corresponds to one or more variants of [`SqlScalarType`].
4694///
4695/// There is a direct correspondence between `Datum` variants and `ReprScalarType`
4696/// variants: every `Datum` variant corresponds to exactly one `ReprScalarType` variant
4697/// (with an exception for `Datum::Array`, which could be both an `Int2Vector` and an `Array`).
4698///
4699/// It is important that any new variants for this enum be added to the `Arbitrary` instance
4700/// and the `union` method.
4701#[derive(Clone, Debug, EnumKind, Serialize, Deserialize, MzReflect)]
4702#[enum_kind(ReprScalarBaseType, derive(PartialOrd, Ord, Hash))]
4703pub enum ReprScalarType {
4704    Bool,
4705    Int16,
4706    Int32,
4707    Int64,
4708    UInt8, // also includes SqlScalarType::PgLegacyChar
4709    UInt16,
4710    UInt32, // also includes SqlScalarType::{Oid,RegClass,RegProc,RegType}
4711    UInt64,
4712    Float32,
4713    Float64,
4714    Numeric,
4715    Date,
4716    Time,
4717    Timestamp,
4718    TimestampTz,
4719    MzTimestamp,
4720    Interval,
4721    Bytes,
4722    Jsonb,
4723    String, // also includes SqlScalarType::{VarChar,Char,PgLegacyName}
4724    Uuid,
4725    Array(Box<ReprScalarType>),
4726    Int2Vector, // differs from Array enough to stick around
4727    List { element_type: Box<ReprScalarType> },
4728    Record { fields: Box<[ReprColumnType]> },
4729    Map { value_type: Box<ReprScalarType> },
4730    Range { element_type: Box<ReprScalarType> },
4731    MzAclItem,
4732    AclItem,
4733}
4734
4735impl PartialEq for ReprScalarType {
4736    fn eq(&self, other: &Self) -> bool {
4737        match (self, other) {
4738            (ReprScalarType::Array(a), ReprScalarType::Array(b)) => a.eq(b),
4739            (
4740                ReprScalarType::List { element_type: a },
4741                ReprScalarType::List { element_type: b },
4742            ) => a.eq(b),
4743            (ReprScalarType::Record { fields: a }, ReprScalarType::Record { fields: b }) => {
4744                a.len() == b.len()
4745                    && a.iter()
4746                        .zip_eq(b.iter())
4747                        .all(|(af, bf)| af.scalar_type.eq(&bf.scalar_type))
4748            }
4749            (ReprScalarType::Map { value_type: a }, ReprScalarType::Map { value_type: b }) => {
4750                a.eq(b)
4751            }
4752            (
4753                ReprScalarType::Range { element_type: a },
4754                ReprScalarType::Range { element_type: b },
4755            ) => a.eq(b),
4756            _ => ReprScalarBaseType::from(self) == ReprScalarBaseType::from(other),
4757        }
4758    }
4759}
4760impl Eq for ReprScalarType {}
4761
4762impl Hash for ReprScalarType {
4763    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
4764        match self {
4765            ReprScalarType::Array(a) => a.hash(state),
4766            ReprScalarType::List { element_type: a } => a.hash(state),
4767            ReprScalarType::Record { fields: a } => {
4768                for field in a {
4769                    field.scalar_type.hash(state);
4770                }
4771            }
4772            ReprScalarType::Map { value_type: a } => a.hash(state),
4773            ReprScalarType::Range { element_type: a } => a.hash(state),
4774            _ => ReprScalarBaseType::from(self).hash(state),
4775        }
4776    }
4777}
4778
4779impl PartialOrd for ReprScalarType {
4780    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
4781        Some(self.cmp(other))
4782    }
4783}
4784
4785impl Ord for ReprScalarType {
4786    fn cmp(&self, other: &Self) -> Ordering {
4787        match (self, other) {
4788            (ReprScalarType::Array(a), ReprScalarType::Array(b)) => a.cmp(b),
4789            (
4790                ReprScalarType::List { element_type: a },
4791                ReprScalarType::List { element_type: b },
4792            ) => a.cmp(b),
4793            (ReprScalarType::Record { fields: a }, ReprScalarType::Record { fields: b }) => {
4794                let len_ordering = a.len().cmp(&b.len());
4795                if len_ordering != Ordering::Equal {
4796                    return len_ordering;
4797                }
4798
4799                // NB ignoring nullability
4800                for (af, bf) in a.iter().zip_eq(b.iter()) {
4801                    let scalar_type_ordering = af.scalar_type.cmp(&bf.scalar_type);
4802                    if scalar_type_ordering != Ordering::Equal {
4803                        return scalar_type_ordering;
4804                    }
4805                }
4806
4807                Ordering::Equal
4808            }
4809            (ReprScalarType::Map { value_type: a }, ReprScalarType::Map { value_type: b }) => {
4810                a.cmp(b)
4811            }
4812            (
4813                ReprScalarType::Range { element_type: a },
4814                ReprScalarType::Range { element_type: b },
4815            ) => a.cmp(b),
4816            _ => ReprScalarBaseType::from(self).cmp(&ReprScalarBaseType::from(other)),
4817        }
4818    }
4819}
4820
4821impl std::fmt::Display for ReprScalarType {
4822    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4823        match self {
4824            ReprScalarType::Bool => write!(f, "r_bool"),
4825            ReprScalarType::Int16 => write!(f, "r_int16"),
4826            ReprScalarType::Int32 => write!(f, "r_int32"),
4827            ReprScalarType::Int64 => write!(f, "r_int64"),
4828            ReprScalarType::UInt8 => write!(f, "r_uint8"),
4829            ReprScalarType::UInt16 => write!(f, "r_uint16"),
4830            ReprScalarType::UInt32 => write!(f, "r_uint32"),
4831            ReprScalarType::UInt64 => write!(f, "r_uint64"),
4832            ReprScalarType::Float32 => write!(f, "r_float32"),
4833            ReprScalarType::Float64 => write!(f, "r_float64"),
4834            ReprScalarType::Numeric => write!(f, "r_numeric"),
4835            ReprScalarType::Date => write!(f, "r_date"),
4836            ReprScalarType::Time => write!(f, "r_time"),
4837            ReprScalarType::Timestamp => write!(f, "r_timestamp"),
4838            ReprScalarType::TimestampTz => write!(f, "r_timestamptz"),
4839            ReprScalarType::MzTimestamp => write!(f, "r_mz_timestamp"),
4840            ReprScalarType::Interval => write!(f, "r_interval"),
4841            ReprScalarType::Bytes => write!(f, "r_bytes"),
4842            ReprScalarType::Jsonb => write!(f, "r_jsonb"),
4843            ReprScalarType::String => write!(f, "r_string"),
4844            ReprScalarType::Uuid => write!(f, "r_uuid"),
4845            ReprScalarType::Array(element_type) => write!(f, "r_array({element_type})"),
4846            ReprScalarType::Int2Vector => write!(f, "r_int2vector"),
4847            ReprScalarType::List { element_type } => write!(f, "r_list({element_type})"),
4848            ReprScalarType::Record { fields } => {
4849                let fields = separated(", ", fields.iter());
4850                write!(f, "r_record({fields})")
4851            }
4852            ReprScalarType::Map { value_type } => write!(f, "r_map({value_type})"),
4853            ReprScalarType::Range { element_type } => write!(f, "r_range({element_type})"),
4854            ReprScalarType::MzAclItem => write!(f, "r_mz_acl_item"),
4855            ReprScalarType::AclItem => write!(f, "r_acl_item"),
4856        }
4857    }
4858}
4859
4860impl ReprScalarType {
4861    /// Returns a [`ReprColumnType`] with the given nullability.
4862    pub fn nullable(self, nullable: bool) -> ReprColumnType {
4863        ReprColumnType {
4864            scalar_type: self,
4865            nullable,
4866        }
4867    }
4868
4869    /// Returns the union of two `ReprScalarType` or an error.
4870    ///
4871    /// Errors can only occur if the two types are built somewhere using different constructors.
4872    /// Note that `ReprScalarType::Record` holds a `ReprColumnType`, and so nullability information
4873    /// is unioned.
4874    pub fn union(&self, scalar_type: &ReprScalarType) -> Result<Self, anyhow::Error> {
4875        match (self, scalar_type) {
4876            (ReprScalarType::Bool, ReprScalarType::Bool) => Ok(ReprScalarType::Bool),
4877            (ReprScalarType::Int16, ReprScalarType::Int16) => Ok(ReprScalarType::Int16),
4878            (ReprScalarType::Int32, ReprScalarType::Int32) => Ok(ReprScalarType::Int32),
4879            (ReprScalarType::Int64, ReprScalarType::Int64) => Ok(ReprScalarType::Int64),
4880            (ReprScalarType::UInt8, ReprScalarType::UInt8) => Ok(ReprScalarType::UInt8),
4881            (ReprScalarType::UInt16, ReprScalarType::UInt16) => Ok(ReprScalarType::UInt16),
4882            (ReprScalarType::UInt32, ReprScalarType::UInt32) => Ok(ReprScalarType::UInt32),
4883            (ReprScalarType::UInt64, ReprScalarType::UInt64) => Ok(ReprScalarType::UInt64),
4884            (ReprScalarType::Float32, ReprScalarType::Float32) => Ok(ReprScalarType::Float32),
4885            (ReprScalarType::Float64, ReprScalarType::Float64) => Ok(ReprScalarType::Float64),
4886            (ReprScalarType::Numeric, ReprScalarType::Numeric) => Ok(ReprScalarType::Numeric),
4887            (ReprScalarType::Date, ReprScalarType::Date) => Ok(ReprScalarType::Date),
4888            (ReprScalarType::Time, ReprScalarType::Time) => Ok(ReprScalarType::Time),
4889            (ReprScalarType::Timestamp, ReprScalarType::Timestamp) => Ok(ReprScalarType::Timestamp),
4890            (ReprScalarType::TimestampTz, ReprScalarType::TimestampTz) => {
4891                Ok(ReprScalarType::TimestampTz)
4892            }
4893            (ReprScalarType::MzTimestamp, ReprScalarType::MzTimestamp) => {
4894                Ok(ReprScalarType::MzTimestamp)
4895            }
4896            (ReprScalarType::AclItem, ReprScalarType::AclItem) => Ok(ReprScalarType::AclItem),
4897            (ReprScalarType::MzAclItem, ReprScalarType::MzAclItem) => Ok(ReprScalarType::MzAclItem),
4898            (ReprScalarType::Interval, ReprScalarType::Interval) => Ok(ReprScalarType::Interval),
4899            (ReprScalarType::Bytes, ReprScalarType::Bytes) => Ok(ReprScalarType::Bytes),
4900            (ReprScalarType::Jsonb, ReprScalarType::Jsonb) => Ok(ReprScalarType::Jsonb),
4901            (ReprScalarType::String, ReprScalarType::String) => Ok(ReprScalarType::String),
4902            (ReprScalarType::Uuid, ReprScalarType::Uuid) => Ok(ReprScalarType::Uuid),
4903            (ReprScalarType::Array(element_type), ReprScalarType::Array(other_element_type)) => Ok(
4904                ReprScalarType::Array(Box::new(element_type.union(other_element_type)?)),
4905            ),
4906            (ReprScalarType::Int2Vector, ReprScalarType::Int2Vector) => {
4907                Ok(ReprScalarType::Int2Vector)
4908            }
4909            (
4910                ReprScalarType::List { element_type },
4911                ReprScalarType::List {
4912                    element_type: other_element_type,
4913                },
4914            ) => Ok(ReprScalarType::List {
4915                element_type: Box::new(element_type.union(other_element_type)?),
4916            }),
4917            (
4918                ReprScalarType::Record { fields },
4919                ReprScalarType::Record {
4920                    fields: other_fields,
4921                },
4922            ) => {
4923                if fields.len() != other_fields.len() {
4924                    bail!("Can't union record types: {:?} and {:?}", self, scalar_type);
4925                }
4926
4927                let mut union_fields = Vec::with_capacity(fields.len());
4928                for (field, other_field) in fields.iter().zip_eq(other_fields.iter()) {
4929                    union_fields.push(field.union(other_field)?);
4930                }
4931                Ok(ReprScalarType::Record {
4932                    fields: union_fields.into_boxed_slice(),
4933                })
4934            }
4935            (
4936                ReprScalarType::Map { value_type },
4937                ReprScalarType::Map {
4938                    value_type: other_value_type,
4939                },
4940            ) => Ok(ReprScalarType::Map {
4941                value_type: Box::new(value_type.union(other_value_type)?),
4942            }),
4943            (
4944                ReprScalarType::Range { element_type },
4945                ReprScalarType::Range {
4946                    element_type: other_element_type,
4947                },
4948            ) => Ok(ReprScalarType::Range {
4949                element_type: Box::new(element_type.union(other_element_type)?),
4950            }),
4951            (_, _) => bail!("Can't union scalar types: {:?} and {:?}", self, scalar_type),
4952        }
4953    }
4954
4955    /// Returns the [`ReprScalarType`] of elements in a [`ReprScalarType::List`].
4956    ///
4957    /// # Panics
4958    ///
4959    /// Panics if called on anything other than a [`ReprScalarType::List`].
4960    pub fn unwrap_list_element_type(&self) -> &ReprScalarType {
4961        match self {
4962            ReprScalarType::List { element_type, .. } => element_type,
4963            _ => panic!(
4964                "ReprScalarType::unwrap_list_element_type called on {:?}",
4965                self
4966            ),
4967        }
4968    }
4969
4970    /// Returns a vector of [`ReprScalarType`] elements in a [`ReprScalarType::Record`].
4971    ///
4972    /// # Panics
4973    ///
4974    /// Panics if called on anything other than a [`ReprScalarType::Record`].
4975    pub fn unwrap_record_element_type(&self) -> Vec<&ReprScalarType> {
4976        match self {
4977            ReprScalarType::Record { fields, .. } => {
4978                fields.iter().map(|t| &t.scalar_type).collect_vec()
4979            }
4980            _ => panic!(
4981                "SqlScalarType::unwrap_record_element_type called on {:?}",
4982                self
4983            ),
4984        }
4985    }
4986}
4987
4988impl From<&SqlScalarType> for ReprScalarType {
4989    fn from(typ: &SqlScalarType) -> Self {
4990        match typ {
4991            SqlScalarType::Bool => ReprScalarType::Bool,
4992            SqlScalarType::Int16 => ReprScalarType::Int16,
4993            SqlScalarType::Int32 => ReprScalarType::Int32,
4994            SqlScalarType::Int64 => ReprScalarType::Int64,
4995            SqlScalarType::UInt16 => ReprScalarType::UInt16,
4996            SqlScalarType::UInt32 => ReprScalarType::UInt32,
4997            SqlScalarType::UInt64 => ReprScalarType::UInt64,
4998            SqlScalarType::Float32 => ReprScalarType::Float32,
4999            SqlScalarType::Float64 => ReprScalarType::Float64,
5000            SqlScalarType::Numeric { max_scale: _ } => ReprScalarType::Numeric,
5001            SqlScalarType::Date => ReprScalarType::Date,
5002            SqlScalarType::Time => ReprScalarType::Time,
5003            SqlScalarType::Timestamp { precision: _ } => ReprScalarType::Timestamp,
5004            SqlScalarType::TimestampTz { precision: _ } => ReprScalarType::TimestampTz,
5005            SqlScalarType::Interval => ReprScalarType::Interval,
5006            SqlScalarType::PgLegacyChar => ReprScalarType::UInt8,
5007            SqlScalarType::PgLegacyName => ReprScalarType::String,
5008            SqlScalarType::Bytes => ReprScalarType::Bytes,
5009            SqlScalarType::String => ReprScalarType::String,
5010            SqlScalarType::Char { length: _ } => ReprScalarType::String,
5011            SqlScalarType::VarChar { max_length: _ } => ReprScalarType::String,
5012            SqlScalarType::Jsonb => ReprScalarType::Jsonb,
5013            SqlScalarType::Uuid => ReprScalarType::Uuid,
5014            SqlScalarType::Array(element_type) => {
5015                ReprScalarType::Array(Box::new(element_type.as_ref().into()))
5016            }
5017            SqlScalarType::List {
5018                element_type,
5019                custom_id: _,
5020            } => ReprScalarType::List {
5021                element_type: Box::new(element_type.as_ref().into()),
5022            },
5023            SqlScalarType::Record {
5024                fields,
5025                custom_id: _,
5026            } => ReprScalarType::Record {
5027                fields: fields.into_iter().map(|(_, typ)| typ.into()).collect(),
5028            },
5029            SqlScalarType::Oid => ReprScalarType::UInt32,
5030            SqlScalarType::Map {
5031                value_type,
5032                custom_id: _,
5033            } => ReprScalarType::Map {
5034                value_type: Box::new(value_type.as_ref().into()),
5035            },
5036            SqlScalarType::RegProc => ReprScalarType::UInt32,
5037            SqlScalarType::RegType => ReprScalarType::UInt32,
5038            SqlScalarType::RegClass => ReprScalarType::UInt32,
5039            SqlScalarType::Int2Vector => ReprScalarType::Int2Vector,
5040            SqlScalarType::MzTimestamp => ReprScalarType::MzTimestamp,
5041            SqlScalarType::Range { element_type } => ReprScalarType::Range {
5042                element_type: Box::new(element_type.as_ref().into()),
5043            },
5044            SqlScalarType::MzAclItem => ReprScalarType::MzAclItem,
5045            SqlScalarType::AclItem => ReprScalarType::AclItem,
5046        }
5047    }
5048}
5049
5050impl SqlScalarType {
5051    /// Lossily translates a [`ReprScalarType`] back to a [`SqlScalarType`].
5052    ///
5053    /// NB that `ReprScalarType::from` is a left inverse of this function, but
5054    /// not a right inverse.
5055    ///
5056    /// Here is an example: `SqlScalarType::VarChar` maps to `ReprScalarType::String`,
5057    /// which maps back to `SqlScalarType::String`.
5058    ///
5059    /// ```
5060    /// use mz_repr::{ReprScalarType, SqlScalarType};
5061    ///
5062    /// let sql = SqlScalarType::VarChar { max_length: None };
5063    /// let repr = ReprScalarType::from(&sql);
5064    /// assert_eq!(repr, ReprScalarType::String);
5065    ///
5066    /// let sql_rt = SqlScalarType::from_repr(&repr);
5067    /// assert_ne!(sql_rt, sql);
5068    /// assert_eq!(sql_rt, SqlScalarType::String);
5069    /// ```
5070    pub fn from_repr(repr: &ReprScalarType) -> Self {
5071        match repr {
5072            ReprScalarType::Bool => SqlScalarType::Bool,
5073            ReprScalarType::Int16 => SqlScalarType::Int16,
5074            ReprScalarType::Int32 => SqlScalarType::Int32,
5075            ReprScalarType::Int64 => SqlScalarType::Int64,
5076            ReprScalarType::UInt8 => SqlScalarType::PgLegacyChar,
5077            ReprScalarType::UInt16 => SqlScalarType::UInt16,
5078            ReprScalarType::UInt32 => SqlScalarType::UInt32,
5079            ReprScalarType::UInt64 => SqlScalarType::UInt64,
5080            ReprScalarType::Float32 => SqlScalarType::Float32,
5081            ReprScalarType::Float64 => SqlScalarType::Float64,
5082            ReprScalarType::Numeric => SqlScalarType::Numeric { max_scale: None },
5083            ReprScalarType::Date => SqlScalarType::Date,
5084            ReprScalarType::Time => SqlScalarType::Time,
5085            ReprScalarType::Timestamp => SqlScalarType::Timestamp { precision: None },
5086            ReprScalarType::TimestampTz => SqlScalarType::TimestampTz { precision: None },
5087            ReprScalarType::MzTimestamp => SqlScalarType::MzTimestamp,
5088            ReprScalarType::Interval => SqlScalarType::Interval,
5089            ReprScalarType::Bytes => SqlScalarType::Bytes,
5090            ReprScalarType::Jsonb => SqlScalarType::Jsonb,
5091            ReprScalarType::String => SqlScalarType::String,
5092            ReprScalarType::Uuid => SqlScalarType::Uuid,
5093            ReprScalarType::Array(element_type) => {
5094                SqlScalarType::Array(Box::new(SqlScalarType::from_repr(element_type)))
5095            }
5096            ReprScalarType::Int2Vector => SqlScalarType::Int2Vector,
5097            ReprScalarType::List { element_type } => SqlScalarType::List {
5098                element_type: Box::new(SqlScalarType::from_repr(element_type)),
5099                custom_id: None,
5100            },
5101            ReprScalarType::Record { fields } => SqlScalarType::Record {
5102                fields: fields
5103                    .iter()
5104                    .enumerate()
5105                    .map(|typ| {
5106                        (
5107                            ColumnName::from(format!("field_{}", typ.0)),
5108                            SqlColumnType::from_repr(typ.1),
5109                        )
5110                    })
5111                    .collect::<Vec<_>>()
5112                    .into_boxed_slice(),
5113                custom_id: None,
5114            },
5115            ReprScalarType::Map { value_type } => SqlScalarType::Map {
5116                value_type: Box::new(SqlScalarType::from_repr(value_type)),
5117                custom_id: None,
5118            },
5119            ReprScalarType::Range { element_type } => SqlScalarType::Range {
5120                element_type: Box::new(SqlScalarType::from_repr(element_type)),
5121            },
5122            ReprScalarType::MzAclItem => SqlScalarType::MzAclItem,
5123            ReprScalarType::AclItem => SqlScalarType::AclItem,
5124        }
5125    }
5126}
5127
5128static EMPTY_ARRAY_ROW: LazyLock<Row> = LazyLock::new(|| {
5129    let mut row = Row::default();
5130    row.packer()
5131        .try_push_array(&[], iter::empty::<Datum>())
5132        .expect("array known to be valid");
5133    row
5134});
5135
5136static EMPTY_LIST_ROW: LazyLock<Row> = LazyLock::new(|| {
5137    let mut row = Row::default();
5138    row.packer().push_list(iter::empty::<Datum>());
5139    row
5140});
5141
5142static EMPTY_MAP_ROW: LazyLock<Row> = LazyLock::new(|| {
5143    let mut row = Row::default();
5144    row.packer().push_dict(iter::empty::<(_, Datum)>());
5145    row
5146});
5147
5148impl Datum<'_> {
5149    pub fn empty_array() -> Datum<'static> {
5150        EMPTY_ARRAY_ROW.unpack_first()
5151    }
5152
5153    pub fn empty_list() -> Datum<'static> {
5154        EMPTY_LIST_ROW.unpack_first()
5155    }
5156
5157    pub fn empty_map() -> Datum<'static> {
5158        EMPTY_MAP_ROW.unpack_first()
5159    }
5160
5161    pub fn contains_dummy(&self) -> bool {
5162        match self {
5163            Datum::Dummy => true,
5164            Datum::List(list) => list.iter().any(|d| d.contains_dummy()),
5165            Datum::Map(map) => map.iter().any(|(_, d)| d.contains_dummy()),
5166            Datum::Array(array) => array.elements().iter().any(|d| d.contains_dummy()),
5167            Datum::Range(range) => range.inner.map_or(false, |range| {
5168                range
5169                    .lower
5170                    .bound
5171                    .map_or(false, |d| d.datum().contains_dummy())
5172                    || range
5173                        .upper
5174                        .bound
5175                        .map_or(false, |d| d.datum().contains_dummy())
5176            }),
5177            _ => false,
5178        }
5179    }
5180}
5181
5182/// A mirror type for [`Datum`] that can be proptest-generated.
5183#[derive(Debug, PartialEq, Clone)]
5184pub enum PropDatum {
5185    Null,
5186    Bool(bool),
5187    Int16(i16),
5188    Int32(i32),
5189    Int64(i64),
5190    UInt8(u8),
5191    UInt16(u16),
5192    UInt32(u32),
5193    UInt64(u64),
5194    Float32(f32),
5195    Float64(f64),
5196
5197    Date(Date),
5198    Time(chrono::NaiveTime),
5199    Timestamp(CheckedTimestamp<chrono::NaiveDateTime>),
5200    TimestampTz(CheckedTimestamp<chrono::DateTime<chrono::Utc>>),
5201    MzTimestamp(u64),
5202
5203    Interval(Interval),
5204    Numeric(Numeric),
5205
5206    Bytes(Vec<u8>),
5207    String(String),
5208
5209    Array(PropArray),
5210    List(PropList),
5211    Map(PropDict),
5212    Record(PropDict),
5213    Range(PropRange),
5214
5215    AclItem(AclItem),
5216    MzAclItem(MzAclItem),
5217
5218    JsonNull,
5219    Uuid(Uuid),
5220    Dummy,
5221}
5222
5223impl std::cmp::Eq for PropDatum {}
5224
5225impl PartialOrd for PropDatum {
5226    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
5227        Some(self.cmp(other))
5228    }
5229}
5230
5231impl Ord for PropDatum {
5232    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
5233        Datum::from(self).cmp(&Datum::from(other))
5234    }
5235}
5236
5237/// Generate an arbitrary [`PropDatum`].
5238pub fn arb_datum(allow_dummy: bool) -> BoxedStrategy<PropDatum> {
5239    let mut leaf_options = vec![
5240        any::<bool>().prop_map(PropDatum::Bool).boxed(),
5241        any::<i16>().prop_map(PropDatum::Int16).boxed(),
5242        any::<i32>().prop_map(PropDatum::Int32).boxed(),
5243        any::<i64>().prop_map(PropDatum::Int64).boxed(),
5244        any::<u16>().prop_map(PropDatum::UInt16).boxed(),
5245        any::<u32>().prop_map(PropDatum::UInt32).boxed(),
5246        any::<u64>().prop_map(PropDatum::UInt64).boxed(),
5247        any::<f32>().prop_map(PropDatum::Float32).boxed(),
5248        any::<f64>().prop_map(PropDatum::Float64).boxed(),
5249        arb_date().prop_map(PropDatum::Date).boxed(),
5250        add_arb_duration(chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())
5251            .prop_map(PropDatum::Time)
5252            .boxed(),
5253        arb_naive_date_time()
5254            .prop_map(|t| PropDatum::Timestamp(CheckedTimestamp::from_timestamplike(t).unwrap()))
5255            .boxed(),
5256        arb_utc_date_time()
5257            .prop_map(|t| PropDatum::TimestampTz(CheckedTimestamp::from_timestamplike(t).unwrap()))
5258            .boxed(),
5259        any::<Interval>().prop_map(PropDatum::Interval).boxed(),
5260        arb_numeric().prop_map(PropDatum::Numeric).boxed(),
5261        prop::collection::vec(any::<u8>(), 1024)
5262            .prop_map(PropDatum::Bytes)
5263            .boxed(),
5264        ".*".prop_map(PropDatum::String).boxed(),
5265        Just(PropDatum::JsonNull).boxed(),
5266        any::<[u8; 16]>()
5267            .prop_map(|x| PropDatum::Uuid(Uuid::from_bytes(x)))
5268            .boxed(),
5269        arb_range(arb_range_data())
5270            .prop_map(PropDatum::Range)
5271            .boxed(),
5272    ];
5273
5274    if allow_dummy {
5275        leaf_options.push(Just(PropDatum::Dummy).boxed());
5276    }
5277    let leaf = Union::new(leaf_options);
5278
5279    leaf.prop_recursive(3, 8, 16, |inner| {
5280        Union::new(vec![
5281            arb_array(inner.clone()).prop_map(PropDatum::Array).boxed(),
5282            arb_list(inner.clone()).prop_map(PropDatum::List).boxed(),
5283            arb_dict(inner).prop_map(PropDatum::Map).boxed(),
5284        ])
5285    })
5286    .boxed()
5287}
5288
5289/// Generates an arbitrary [`PropDatum`] for the provided [`SqlColumnType`].
5290pub fn arb_datum_for_column(column_type: SqlColumnType) -> impl Strategy<Value = PropDatum> {
5291    let strat = arb_datum_for_scalar(column_type.scalar_type);
5292
5293    if column_type.nullable {
5294        Union::new_weighted(vec![(1, Just(PropDatum::Null).boxed()), (5, strat.boxed())]).boxed()
5295    } else {
5296        strat.boxed()
5297    }
5298}
5299
5300/// Generates an arbitrary [`PropDatum`] for the provided [`SqlScalarType`].
5301pub fn arb_datum_for_scalar(scalar_type: SqlScalarType) -> impl Strategy<Value = PropDatum> {
5302    match scalar_type {
5303        SqlScalarType::Bool => any::<bool>().prop_map(PropDatum::Bool).boxed(),
5304        SqlScalarType::Int16 => any::<i16>().prop_map(PropDatum::Int16).boxed(),
5305        SqlScalarType::Int32 => any::<i32>().prop_map(PropDatum::Int32).boxed(),
5306        SqlScalarType::Int64 => any::<i64>().prop_map(PropDatum::Int64).boxed(),
5307        SqlScalarType::PgLegacyChar => any::<u8>().prop_map(PropDatum::UInt8).boxed(),
5308        SqlScalarType::UInt16 => any::<u16>().prop_map(PropDatum::UInt16).boxed(),
5309        SqlScalarType::UInt32
5310        | SqlScalarType::Oid
5311        | SqlScalarType::RegClass
5312        | SqlScalarType::RegProc
5313        | SqlScalarType::RegType => any::<u32>().prop_map(PropDatum::UInt32).boxed(),
5314        SqlScalarType::UInt64 => any::<u64>().prop_map(PropDatum::UInt64).boxed(),
5315        SqlScalarType::Float32 => any::<f32>().prop_map(PropDatum::Float32).boxed(),
5316        SqlScalarType::Float64 => any::<f64>().prop_map(PropDatum::Float64).boxed(),
5317        SqlScalarType::Numeric { .. } => arb_numeric().prop_map(PropDatum::Numeric).boxed(),
5318        SqlScalarType::String
5319        | SqlScalarType::PgLegacyName
5320        | SqlScalarType::Char { length: None }
5321        | SqlScalarType::VarChar { max_length: None } => ".*".prop_map(PropDatum::String).boxed(),
5322        SqlScalarType::Char {
5323            length: Some(length),
5324        } => {
5325            let max_len = usize::cast_from(length.into_u32()).max(1);
5326            prop::collection::vec(any::<char>(), 0..max_len)
5327                .prop_map(move |chars| {
5328                    // `Char`s are fixed sized strings padded with blanks.
5329                    let num_blanks = max_len - chars.len();
5330                    let s = chars
5331                        .into_iter()
5332                        .chain(std::iter::repeat(' ').take(num_blanks))
5333                        .collect();
5334                    PropDatum::String(s)
5335                })
5336                .boxed()
5337        }
5338        SqlScalarType::VarChar {
5339            max_length: Some(length),
5340        } => {
5341            let max_len = usize::cast_from(length.into_u32()).max(1);
5342            prop::collection::vec(any::<char>(), 0..max_len)
5343                .prop_map(|chars| PropDatum::String(chars.into_iter().collect()))
5344                .boxed()
5345        }
5346        SqlScalarType::Bytes => prop::collection::vec(any::<u8>(), 300)
5347            .prop_map(PropDatum::Bytes)
5348            .boxed(),
5349        SqlScalarType::Date => arb_date().prop_map(PropDatum::Date).boxed(),
5350        SqlScalarType::Time => add_arb_duration(chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())
5351            .prop_map(PropDatum::Time)
5352            .boxed(),
5353        SqlScalarType::Timestamp { .. } => arb_naive_date_time()
5354            .prop_map(|t| PropDatum::Timestamp(CheckedTimestamp::from_timestamplike(t).unwrap()))
5355            .boxed(),
5356        SqlScalarType::TimestampTz { .. } => arb_utc_date_time()
5357            .prop_map(|t| PropDatum::TimestampTz(CheckedTimestamp::from_timestamplike(t).unwrap()))
5358            .boxed(),
5359        SqlScalarType::MzTimestamp => any::<u64>().prop_map(PropDatum::MzTimestamp).boxed(),
5360        SqlScalarType::Interval => any::<Interval>().prop_map(PropDatum::Interval).boxed(),
5361        SqlScalarType::Uuid => any::<[u8; 16]>()
5362            .prop_map(|x| PropDatum::Uuid(Uuid::from_bytes(x)))
5363            .boxed(),
5364        SqlScalarType::AclItem => any::<AclItem>().prop_map(PropDatum::AclItem).boxed(),
5365        SqlScalarType::MzAclItem => any::<MzAclItem>().prop_map(PropDatum::MzAclItem).boxed(),
5366        SqlScalarType::Range { element_type } => {
5367            let data_strat = (
5368                arb_datum_for_scalar(*element_type.clone()),
5369                arb_datum_for_scalar(*element_type),
5370            );
5371            arb_range(data_strat).prop_map(PropDatum::Range).boxed()
5372        }
5373        SqlScalarType::List { element_type, .. } => arb_list(arb_datum_for_scalar(*element_type))
5374            .prop_map(PropDatum::List)
5375            .boxed(),
5376        SqlScalarType::Array(element_type) => arb_array(arb_datum_for_scalar(*element_type))
5377            .prop_map(PropDatum::Array)
5378            .boxed(),
5379        SqlScalarType::Int2Vector => arb_array(any::<i16>().prop_map(PropDatum::Int16).boxed())
5380            .prop_map(PropDatum::Array)
5381            .boxed(),
5382        SqlScalarType::Map { value_type, .. } => arb_dict(arb_datum_for_scalar(*value_type))
5383            .prop_map(PropDatum::Map)
5384            .boxed(),
5385        SqlScalarType::Record { fields, .. } => {
5386            let field_strats = fields.iter().map(|(name, ty)| {
5387                (
5388                    name.to_string(),
5389                    arb_datum_for_scalar(ty.scalar_type.clone()),
5390                )
5391            });
5392            arb_record(field_strats).prop_map(PropDatum::Record).boxed()
5393        }
5394        SqlScalarType::Jsonb => {
5395            let int_value = any::<i128>()
5396                .prop_map(|v| Numeric::try_from(v).unwrap())
5397                .boxed();
5398            // Numerics only support up to 39 digits.
5399            let float_value = (1e-39f64..1e39)
5400                .prop_map(|v| Numeric::try_from(v).unwrap())
5401                .boxed();
5402            // JSON does not support NaN or Infinite numbers, so we can't use
5403            // the normal `arb_numeric` strategy.
5404            let json_number = Union::new(vec![int_value, float_value]);
5405
5406            let json_leaf = Union::new(vec![
5407                any::<()>().prop_map(|_| PropDatum::JsonNull).boxed(),
5408                any::<bool>().prop_map(PropDatum::Bool).boxed(),
5409                json_number.prop_map(PropDatum::Numeric).boxed(),
5410                ".*".prop_map(PropDatum::String).boxed(),
5411            ]);
5412            json_leaf
5413                .prop_recursive(4, 32, 8, |element| {
5414                    Union::new(vec![
5415                        prop::collection::vec(element.clone(), 0..16)
5416                            .prop_map(|elements| {
5417                                let datums: Vec<_> = elements.iter().map(|pd| pd.into()).collect();
5418                                let mut row = Row::default();
5419                                row.packer().push_list(datums.iter());
5420                                PropDatum::List(PropList(row, elements))
5421                            })
5422                            .boxed(),
5423                        prop::collection::hash_map(".*", element, 0..16)
5424                            .prop_map(|elements| {
5425                                let mut elements: Vec<_> = elements.into_iter().collect();
5426                                elements.sort_by_key(|(k, _)| k.clone());
5427                                elements.dedup_by_key(|(k, _)| k.clone());
5428                                let mut row = Row::default();
5429                                let entry_iter =
5430                                    elements.iter().map(|(k, v)| (k.as_str(), Datum::from(v)));
5431                                row.packer().push_dict(entry_iter);
5432                                PropDatum::Map(PropDict(row, elements))
5433                            })
5434                            .boxed(),
5435                    ])
5436                })
5437                .boxed()
5438        }
5439    }
5440}
5441
5442/// Generates an arbitrary [`NaiveDateTime`].
5443pub fn arb_naive_date_time() -> impl Strategy<Value = NaiveDateTime> {
5444    add_arb_duration(chrono::DateTime::from_timestamp(0, 0).unwrap().naive_utc())
5445}
5446
5447/// Generates an arbitrary [`DateTime`] in [`Utc`].
5448pub fn arb_utc_date_time() -> impl Strategy<Value = DateTime<Utc>> {
5449    add_arb_duration(chrono::Utc.timestamp_opt(0, 0).unwrap())
5450}
5451
5452fn arb_array_dimension() -> BoxedStrategy<ArrayDimension> {
5453    (1..4_usize)
5454        .prop_map(|length| ArrayDimension {
5455            lower_bound: 1,
5456            length,
5457        })
5458        .boxed()
5459}
5460
5461#[derive(Debug, PartialEq, Clone)]
5462pub struct PropArray(Row, Vec<PropDatum>);
5463
5464fn arb_array(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropArray> {
5465    // Elements in Arrays can always be Null.
5466    let element_strategy = Union::new_weighted(vec![
5467        (20, element_strategy),
5468        (1, Just(PropDatum::Null).boxed()),
5469    ]);
5470
5471    prop::collection::vec(
5472        arb_array_dimension(),
5473        1..usize::from(crate::adt::array::MAX_ARRAY_DIMENSIONS),
5474    )
5475    .prop_flat_map(move |dimensions| {
5476        let n_elts: usize = dimensions.iter().map(|d| d.length).product();
5477        (
5478            Just(dimensions),
5479            prop::collection::vec(element_strategy.clone(), n_elts),
5480        )
5481    })
5482    .prop_map(|(dimensions, elements)| {
5483        let element_datums: Vec<Datum<'_>> = elements.iter().map(|pd| pd.into()).collect();
5484        let mut row = Row::default();
5485        row.packer()
5486            .try_push_array(&dimensions, element_datums)
5487            .unwrap();
5488        PropArray(row, elements)
5489    })
5490    .boxed()
5491}
5492
5493#[derive(Debug, PartialEq, Clone)]
5494pub struct PropList(Row, Vec<PropDatum>);
5495
5496fn arb_list(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropList> {
5497    // Elements in Lists can always be Null.
5498    let element_strategy = Union::new_weighted(vec![
5499        (20, element_strategy),
5500        (1, Just(PropDatum::Null).boxed()),
5501    ]);
5502
5503    prop::collection::vec(element_strategy, 1..50)
5504        .prop_map(|elements| {
5505            let element_datums: Vec<Datum<'_>> = elements.iter().map(|pd| pd.into()).collect();
5506            let mut row = Row::default();
5507            row.packer().push_list(element_datums.iter());
5508            PropList(row, elements)
5509        })
5510        .boxed()
5511}
5512
5513#[derive(Debug, PartialEq, Clone)]
5514pub struct PropRange(
5515    Row,
5516    Option<(
5517        (Option<Box<PropDatum>>, bool),
5518        (Option<Box<PropDatum>>, bool),
5519    )>,
5520);
5521
5522pub fn arb_range_type() -> Union<BoxedStrategy<SqlScalarType>> {
5523    Union::new(vec![
5524        Just(SqlScalarType::Int32).boxed(),
5525        Just(SqlScalarType::Int64).boxed(),
5526        Just(SqlScalarType::Date).boxed(),
5527    ])
5528}
5529
5530fn arb_range_data() -> Union<BoxedStrategy<(PropDatum, PropDatum)>> {
5531    Union::new(vec![
5532        (
5533            any::<i32>().prop_map(PropDatum::Int32),
5534            any::<i32>().prop_map(PropDatum::Int32),
5535        )
5536            .boxed(),
5537        (
5538            any::<i64>().prop_map(PropDatum::Int64),
5539            any::<i64>().prop_map(PropDatum::Int64),
5540        )
5541            .boxed(),
5542        (
5543            arb_date().prop_map(PropDatum::Date),
5544            arb_date().prop_map(PropDatum::Date),
5545        )
5546            .boxed(),
5547    ])
5548}
5549
5550fn arb_range(
5551    data: impl Strategy<Value = (PropDatum, PropDatum)> + 'static,
5552) -> BoxedStrategy<PropRange> {
5553    (
5554        any::<u16>(),
5555        any::<bool>(),
5556        any::<bool>(),
5557        any::<bool>(),
5558        any::<bool>(),
5559        data,
5560    )
5561        .prop_map(
5562            |(split, lower_inf, lower_inc, upper_inf, upper_inc, (a, b))| {
5563                let mut row = Row::default();
5564                let mut packer = row.packer();
5565                let r = if split % 32 == 0 {
5566                    packer
5567                        .push_range(Range::new(None))
5568                        .expect("pushing empty ranges never fails");
5569                    None
5570                } else {
5571                    let b_is_lower = Datum::from(&b) < Datum::from(&a);
5572
5573                    let (lower, upper) = if b_is_lower { (b, a) } else { (a, b) };
5574                    let mut range = Range::new(Some((
5575                        RangeLowerBound {
5576                            inclusive: lower_inc,
5577                            bound: if lower_inf {
5578                                None
5579                            } else {
5580                                Some(Datum::from(&lower))
5581                            },
5582                        },
5583                        RangeUpperBound {
5584                            inclusive: upper_inc,
5585                            bound: if upper_inf {
5586                                None
5587                            } else {
5588                                Some(Datum::from(&upper))
5589                            },
5590                        },
5591                    )));
5592
5593                    range.canonicalize().unwrap();
5594
5595                    // Extract canonicalized state; pretend the range was empty
5596                    // if the bounds are rewritten.
5597                    let (empty, lower_inf, lower_inc, upper_inf, upper_inc) = match range.inner {
5598                        None => (true, false, false, false, false),
5599                        Some(inner) => (
5600                            false
5601                                || match inner.lower.bound {
5602                                    Some(b) => b != Datum::from(&lower),
5603                                    None => !lower_inf,
5604                                }
5605                                || match inner.upper.bound {
5606                                    Some(b) => b != Datum::from(&upper),
5607                                    None => !upper_inf,
5608                                },
5609                            inner.lower.bound.is_none(),
5610                            inner.lower.inclusive,
5611                            inner.upper.bound.is_none(),
5612                            inner.upper.inclusive,
5613                        ),
5614                    };
5615
5616                    if empty {
5617                        packer.push_range(Range { inner: None }).unwrap();
5618                        None
5619                    } else {
5620                        packer.push_range(range).unwrap();
5621                        Some((
5622                            (
5623                                if lower_inf {
5624                                    None
5625                                } else {
5626                                    Some(Box::new(lower))
5627                                },
5628                                lower_inc,
5629                            ),
5630                            (
5631                                if upper_inf {
5632                                    None
5633                                } else {
5634                                    Some(Box::new(upper))
5635                                },
5636                                upper_inc,
5637                            ),
5638                        ))
5639                    }
5640                };
5641
5642                PropRange(row, r)
5643            },
5644        )
5645        .boxed()
5646}
5647
5648#[derive(Debug, PartialEq, Clone)]
5649pub struct PropDict(Row, Vec<(String, PropDatum)>);
5650
5651fn arb_dict(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropDict> {
5652    // Elements in Maps can always be Null.
5653    let element_strategy = Union::new_weighted(vec![
5654        (20, element_strategy),
5655        (1, Just(PropDatum::Null).boxed()),
5656    ]);
5657
5658    prop::collection::vec((".*", element_strategy), 1..50)
5659        .prop_map(|mut entries| {
5660            entries.sort_by_key(|(k, _)| k.clone());
5661            entries.dedup_by_key(|(k, _)| k.clone());
5662            let mut row = Row::default();
5663            let entry_iter = entries.iter().map(|(k, v)| (k.as_str(), Datum::from(v)));
5664            row.packer().push_dict(entry_iter);
5665            PropDict(row, entries)
5666        })
5667        .boxed()
5668}
5669
5670fn arb_record(
5671    fields: impl Iterator<Item = (String, BoxedStrategy<PropDatum>)>,
5672) -> BoxedStrategy<PropDict> {
5673    let (names, strategies): (Vec<_>, Vec<_>) = fields.unzip();
5674
5675    strategies
5676        .prop_map(move |x| {
5677            let mut row = Row::default();
5678            row.packer().push_list(x.iter().map(Datum::from));
5679            let entries: Vec<_> = names.clone().into_iter().zip_eq(x).collect();
5680            PropDict(row, entries)
5681        })
5682        .boxed()
5683}
5684
5685fn arb_date() -> BoxedStrategy<Date> {
5686    (Date::LOW_DAYS..Date::HIGH_DAYS)
5687        .prop_map(move |days| Date::from_pg_epoch(days).unwrap())
5688        .boxed()
5689}
5690
5691pub fn add_arb_duration<T: 'static + Copy + Add<chrono::Duration> + std::fmt::Debug>(
5692    to: T,
5693) -> BoxedStrategy<T::Output>
5694where
5695    T::Output: std::fmt::Debug,
5696{
5697    let lower = LOW_DATE
5698        .and_hms_opt(0, 0, 0)
5699        .unwrap()
5700        .and_utc()
5701        .timestamp_micros();
5702    let upper = HIGH_DATE
5703        .and_hms_opt(0, 0, 0)
5704        .unwrap()
5705        .and_utc()
5706        .timestamp_micros();
5707    (lower..upper)
5708        .prop_map(move |v| to + chrono::Duration::microseconds(v))
5709        .boxed()
5710}
5711
5712pub(crate) fn arb_numeric() -> BoxedStrategy<Numeric> {
5713    let int_value = any::<i128>()
5714        .prop_map(|v| Numeric::try_from(v).unwrap())
5715        .boxed();
5716    let float_value = (-1e39f64..1e39)
5717        .prop_map(|v| Numeric::try_from(v).unwrap())
5718        .boxed();
5719
5720    // While these strategies are subsets of the ones above, including them
5721    // helps us generate a more realistic set of values.
5722    let tiny_floats = ((-10.0..10.0), (1u32..10))
5723        .prop_map(|(v, num_digits)| {
5724            // Truncate to a small number of digits.
5725            let num_digits: f64 = 10u32.pow(num_digits).try_into().unwrap();
5726            let trunc = f64::trunc(v * num_digits) / num_digits;
5727            Numeric::try_from(trunc).unwrap()
5728        })
5729        .boxed();
5730    let small_ints = (-1_000_000..1_000_000)
5731        .prop_map(|v| Numeric::try_from(v).unwrap())
5732        .boxed();
5733    let small_floats = (-1_000_000.0..1_000_000.0)
5734        .prop_map(|v| Numeric::try_from(v).unwrap())
5735        .boxed();
5736
5737    Union::new_weighted(vec![
5738        (20, tiny_floats),
5739        (20, small_ints),
5740        (20, small_floats),
5741        (10, int_value),
5742        (10, float_value),
5743        (1, Just(Numeric::infinity()).boxed()),
5744        (1, Just(-Numeric::infinity()).boxed()),
5745        (1, Just(Numeric::nan()).boxed()),
5746        (1, Just(Numeric::zero()).boxed()),
5747    ])
5748    .boxed()
5749}
5750
5751impl<'a> From<&'a PropDatum> for Datum<'a> {
5752    #[inline]
5753    fn from(pd: &'a PropDatum) -> Self {
5754        use PropDatum::*;
5755        match pd {
5756            Null => Datum::Null,
5757            Bool(b) => Datum::from(*b),
5758            Int16(i) => Datum::from(*i),
5759            Int32(i) => Datum::from(*i),
5760            Int64(i) => Datum::from(*i),
5761            UInt8(u) => Datum::from(*u),
5762            UInt16(u) => Datum::from(*u),
5763            UInt32(u) => Datum::from(*u),
5764            UInt64(u) => Datum::from(*u),
5765            Float32(f) => Datum::from(*f),
5766            Float64(f) => Datum::from(*f),
5767            Date(d) => Datum::from(*d),
5768            Time(t) => Datum::from(*t),
5769            Timestamp(t) => Datum::from(*t),
5770            TimestampTz(t) => Datum::from(*t),
5771            MzTimestamp(t) => Datum::MzTimestamp((*t).into()),
5772            Interval(i) => Datum::from(*i),
5773            Numeric(s) => Datum::from(*s),
5774            Bytes(b) => Datum::from(&b[..]),
5775            String(s) => Datum::from(s.as_str()),
5776            Array(PropArray(row, _)) => {
5777                let array = row.unpack_first().unwrap_array();
5778                Datum::Array(array)
5779            }
5780            List(PropList(row, _)) => {
5781                let list = row.unpack_first().unwrap_list();
5782                Datum::List(list)
5783            }
5784            Map(PropDict(row, _)) => {
5785                let map = row.unpack_first().unwrap_map();
5786                Datum::Map(map)
5787            }
5788            Record(PropDict(row, _)) => {
5789                let list = row.unpack_first().unwrap_list();
5790                Datum::List(list)
5791            }
5792            Range(PropRange(row, _)) => {
5793                let d = row.unpack_first();
5794                assert!(matches!(d, Datum::Range(_)));
5795                d
5796            }
5797            AclItem(i) => Datum::AclItem(*i),
5798            MzAclItem(i) => Datum::MzAclItem(*i),
5799            JsonNull => Datum::JsonNull,
5800            Uuid(u) => Datum::from(*u),
5801            Dummy => Datum::Dummy,
5802        }
5803    }
5804}
5805
5806#[mz_ore::test]
5807fn verify_base_eq_record_nullability() {
5808    let s1 = SqlScalarType::Record {
5809        fields: [(
5810            "c".into(),
5811            SqlColumnType {
5812                scalar_type: SqlScalarType::Bool,
5813                nullable: true,
5814            },
5815        )]
5816        .into(),
5817        custom_id: None,
5818    };
5819    let s2 = SqlScalarType::Record {
5820        fields: [(
5821            "c".into(),
5822            SqlColumnType {
5823                scalar_type: SqlScalarType::Bool,
5824                nullable: false,
5825            },
5826        )]
5827        .into(),
5828        custom_id: None,
5829    };
5830    let s3 = SqlScalarType::Record {
5831        fields: [].into(),
5832        custom_id: None,
5833    };
5834    assert!(s1.base_eq(&s2));
5835    assert!(!s1.base_eq(&s3));
5836}
5837
5838#[cfg(test)]
5839mod tests {
5840    use mz_ore::assert_ok;
5841    use mz_proto::protobuf_roundtrip;
5842
5843    use super::*;
5844
5845    proptest! {
5846       #[mz_ore::test]
5847       #[cfg_attr(miri, ignore)] // too slow
5848        fn scalar_type_protobuf_roundtrip(expect in any::<SqlScalarType>() ) {
5849            let actual = protobuf_roundtrip::<_, ProtoScalarType>(&expect);
5850            assert_ok!(actual);
5851            assert_eq!(actual.unwrap(), expect);
5852        }
5853    }
5854
5855    proptest! {
5856        #[mz_ore::test]
5857        #[cfg_attr(miri, ignore)]
5858        fn sql_repr_types_agree_on_valid_data(
5859            (src, datum) in any::<SqlColumnType>()
5860                .prop_flat_map(|src| {
5861                    let datum = arb_datum_for_column(src.clone());
5862                    (Just(src), datum)
5863                }),
5864        ) {
5865            let tgt = ReprColumnType::from(&src);
5866            let datum = Datum::from(&datum);
5867            assert_eq!(
5868                datum.is_instance_of_sql(&src),
5869                datum.is_instance_of(&tgt),
5870                "translated to repr type {tgt:#?}",
5871            );
5872        }
5873    }
5874
5875    proptest! {
5876        // We run many cases because the data are _random_, and we want to be sure
5877        // that we have covered sufficient cases.
5878        #![proptest_config(ProptestConfig::with_cases(10000))]
5879        #[mz_ore::test]
5880        #[cfg_attr(miri, ignore)]
5881        fn sql_repr_types_agree_on_random_data(
5882            src in any::<SqlColumnType>(),
5883            datum in arb_datum(true),
5884        ) {
5885            let tgt = ReprColumnType::from(&src);
5886            let datum = Datum::from(&datum);
5887
5888            assert_eq!(
5889                datum.is_instance_of_sql(&src),
5890                datum.is_instance_of(&tgt),
5891                "translated to repr type {tgt:#?}",
5892            );
5893        }
5894    }
5895
5896    proptest! {
5897        #![proptest_config(ProptestConfig::with_cases(10000))]
5898        #[mz_ore::test]
5899        #[cfg_attr(miri, ignore)]
5900        fn repr_type_to_sql_type_roundtrip(repr_type in any::<ReprScalarType>()) {
5901            // ReprScalarType::from is a left inverse of SqlScalarType::from.
5902            //
5903            // It is _not_ a right inverse, because SqlScalarType::from is lossy.
5904            // For example, many SqlScalarType variants map to ReprScalarType::String.
5905            let sql_type = SqlScalarType::from_repr(&repr_type);
5906            assert_eq!(repr_type, ReprScalarType::from(&sql_type));
5907        }
5908    }
5909
5910    proptest! {
5911        #![proptest_config(ProptestConfig::with_cases(10000))]
5912        #[mz_ore::test]
5913        #[cfg_attr(miri, ignore)]
5914        fn sql_type_base_eq_implies_repr_type_eq(
5915            sql_type1 in any::<SqlScalarType>(),
5916            sql_type2 in any::<SqlScalarType>(),
5917        ) {
5918            let repr_type1 = ReprScalarType::from(&sql_type1);
5919            let repr_type2 = ReprScalarType::from(&sql_type2);
5920            if sql_type1.base_eq(&sql_type2) {
5921                assert_eq!(repr_type1, repr_type2);
5922            }
5923        }
5924    }
5925
5926    proptest! {
5927        #![proptest_config(ProptestConfig::with_cases(10000))]
5928        #[mz_ore::test]
5929        #[cfg_attr(miri, ignore)]
5930        fn repr_type_self_union(repr_type in any::<ReprScalarType>()) {
5931            let union = repr_type.union(&repr_type);
5932            assert_ok!(
5933                union,
5934                "every type should self-union \
5935                 (update ReprScalarType::union to handle this)",
5936            );
5937            assert_eq!(
5938                union.unwrap(), repr_type,
5939                "every type should self-union to itself",
5940            );
5941        }
5942    }
5943
5944    proptest! {
5945        #[mz_ore::test]
5946        #[cfg_attr(miri, ignore)] // can't call foreign function `decContextDefault`
5947        fn array_packing_unpacks_correctly(array in arb_array(arb_datum(true))) {
5948            let PropArray(row, elts) = array;
5949            let datums: Vec<Datum<'_>> = elts.iter().map(|e| e.into()).collect();
5950            let unpacked_datums: Vec<Datum<'_>> = row
5951                .unpack_first().unwrap_array().elements().iter().collect();
5952            assert_eq!(unpacked_datums, datums);
5953        }
5954
5955        #[mz_ore::test]
5956        #[cfg_attr(miri, ignore)] // can't call foreign function `decContextDefault`
5957        fn list_packing_unpacks_correctly(array in arb_list(arb_datum(true))) {
5958            let PropList(row, elts) = array;
5959            let datums: Vec<Datum<'_>> = elts.iter().map(|e| e.into()).collect();
5960            let unpacked_datums: Vec<Datum<'_>> = row
5961                .unpack_first().unwrap_list().iter().collect();
5962            assert_eq!(unpacked_datums, datums);
5963        }
5964
5965        #[mz_ore::test]
5966        #[cfg_attr(miri, ignore)] // too slow
5967        fn dict_packing_unpacks_correctly(array in arb_dict(arb_datum(true))) {
5968            let PropDict(row, elts) = array;
5969            let datums: Vec<(&str, Datum<'_>)> = elts.iter()
5970                .map(|(k, e)| (k.as_str(), e.into())).collect();
5971            let unpacked_datums: Vec<(&str, Datum<'_>)> = row
5972                .unpack_first().unwrap_map().iter().collect();
5973            assert_eq!(unpacked_datums, datums);
5974        }
5975
5976        #[mz_ore::test]
5977        #[cfg_attr(miri, ignore)] // too slow
5978        fn row_packing_roundtrips_single_valued(
5979            prop_datums in prop::collection::vec(arb_datum(true), 1..100),
5980        ) {
5981            let datums: Vec<Datum<'_>> = prop_datums.iter().map(|pd| pd.into()).collect();
5982            let row = Row::pack(&datums);
5983            let unpacked = row.unpack();
5984            assert_eq!(datums, unpacked);
5985        }
5986
5987        #[mz_ore::test]
5988        #[cfg_attr(miri, ignore)] // too slow
5989        fn range_packing_unpacks_correctly(range in arb_range(arb_range_data())) {
5990            let PropRange(row, prop_range) = range;
5991            let row = row.unpack_first();
5992            let d = row.unwrap_range();
5993
5994            let (
5995                ((prop_lower, prop_lower_inc), (prop_upper, prop_upper_inc)),
5996                crate::adt::range::RangeInner { lower, upper },
5997            ) = match (prop_range, d.inner) {
5998                (Some(prop_values), Some(inner_range)) => (prop_values, inner_range),
5999                (None, None) => return Ok(()),
6000                _ => panic!("inequivalent row packing"),
6001            };
6002
6003            for (prop_bound, prop_bound_inc, inner_bound, inner_bound_inc) in [
6004                (prop_lower, prop_lower_inc, lower.bound, lower.inclusive),
6005                (prop_upper, prop_upper_inc, upper.bound, upper.inclusive),
6006            ] {
6007                assert_eq!(prop_bound_inc, inner_bound_inc);
6008                match (prop_bound, inner_bound) {
6009                    (None, None) => continue,
6010                    (Some(p), Some(b)) => {
6011                        assert_eq!(Datum::from(&*p), b);
6012                    }
6013                    _ => panic!("inequivalent row packing"),
6014                }
6015            }
6016        }
6017    }
6018}