Skip to main content

mz_repr/
scalar.rs

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