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