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_owned_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                // NOTE: -NaN and -0.0 have distinct bit patterns from NaN and
4057                // 0.0 but compare equal under `OrderedFloat`. Orderings that
4058                // look at the representation (e.g. arrow's total order, where
4059                // -NaN < -Infinity) can disagree with `OrderedFloat` on them.
4060                Datum::Float32(OrderedFloat(-f32::NAN)),
4061                Datum::Float32(OrderedFloat(-0.0)),
4062                Datum::Float32(OrderedFloat(f32::INFINITY)),
4063                Datum::Float32(OrderedFloat(f32::NEG_INFINITY)),
4064            ])
4065        });
4066        static FLOAT64: LazyLock<Row> = LazyLock::new(|| {
4067            Row::pack_slice(&[
4068                Datum::Float64(OrderedFloat(0.0)),
4069                Datum::Float64(OrderedFloat(1.0)),
4070                Datum::Float64(OrderedFloat(-1.0)),
4071                Datum::Float64(OrderedFloat(f64::MIN)),
4072                Datum::Float64(OrderedFloat(f64::MIN_POSITIVE)),
4073                Datum::Float64(OrderedFloat(f64::MAX)),
4074                Datum::Float64(OrderedFloat(f64::EPSILON)),
4075                Datum::Float64(OrderedFloat(f64::NAN)),
4076                // See the FLOAT32 note on -NaN and -0.0.
4077                Datum::Float64(OrderedFloat(-f64::NAN)),
4078                Datum::Float64(OrderedFloat(-0.0)),
4079                Datum::Float64(OrderedFloat(f64::INFINITY)),
4080                Datum::Float64(OrderedFloat(f64::NEG_INFINITY)),
4081            ])
4082        });
4083        static NUMERIC: LazyLock<Row> = LazyLock::new(|| {
4084            cfg_if::cfg_if! {
4085                // Numerics can't currently be instantiated under Miri
4086                if #[cfg(miri)] {
4087                    Row::pack_slice(&[])
4088                } else {
4089                    Row::pack_slice(&[
4090                        Datum::Numeric(OrderedDecimal(Numeric::from(0.0))),
4091                        Datum::Numeric(OrderedDecimal(Numeric::from(1.0))),
4092                        Datum::Numeric(OrderedDecimal(Numeric::from(-1.0))),
4093                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MIN))),
4094                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MIN_POSITIVE))),
4095                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::MAX))),
4096                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::EPSILON))),
4097                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::NAN))),
4098                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::INFINITY))),
4099                        Datum::Numeric(OrderedDecimal(Numeric::from(f64::NEG_INFINITY))),
4100                    ])
4101                }
4102            }
4103        });
4104        static DATE: LazyLock<Row> = LazyLock::new(|| {
4105            Row::pack_slice(&[
4106                Datum::Date(Date::from_pg_epoch(0).unwrap()),
4107                Datum::Date(Date::from_pg_epoch(Date::LOW_DAYS).unwrap()),
4108                Datum::Date(Date::from_pg_epoch(Date::HIGH_DAYS).unwrap()),
4109            ])
4110        });
4111        static TIME: LazyLock<Row> = LazyLock::new(|| {
4112            Row::pack_slice(&[
4113                Datum::Time(NaiveTime::from_hms_micro_opt(0, 0, 0, 0).unwrap()),
4114                Datum::Time(NaiveTime::from_hms_micro_opt(23, 59, 59, 999_999).unwrap()),
4115                // Leap second: chrono represents it as a fractional part of
4116                // one second or more. `TIME '23:59:60'` is the largest value
4117                // parsing admits, since fractional leap seconds are rejected,
4118                // and it encodes to exactly PostgreSQL's 24:00:00 bound. A
4119                // fractional leap second here would leave the type's
4120                // PostgreSQL wire domain.
4121                Datum::Time(NaiveTime::from_hms_micro_opt(23, 59, 59, 1_000_000).unwrap()),
4122            ])
4123        });
4124        static TIMESTAMP: LazyLock<Row> = LazyLock::new(|| {
4125            Row::pack_slice(&[
4126                Datum::Timestamp(
4127                    DateTime::from_timestamp(0, 0)
4128                        .unwrap()
4129                        .naive_utc()
4130                        .try_into()
4131                        .unwrap(),
4132                ),
4133                Datum::Timestamp(
4134                    crate::adt::timestamp::LOW_DATE
4135                        .and_hms_opt(0, 0, 0)
4136                        .unwrap()
4137                        .try_into()
4138                        .unwrap(),
4139                ),
4140                Datum::Timestamp(
4141                    crate::adt::timestamp::HIGH_DATE
4142                        .and_hms_opt(23, 59, 59)
4143                        .unwrap()
4144                        .try_into()
4145                        .unwrap(),
4146                ),
4147                // nano seconds
4148                Datum::Timestamp(
4149                    DateTime::from_timestamp(0, 123456789)
4150                        .unwrap()
4151                        .naive_utc()
4152                        .try_into()
4153                        .unwrap(),
4154                ),
4155                // Leap second
4156                Datum::Timestamp(
4157                    CheckedTimestamp::from_timestamplike(
4158                        NaiveDate::from_isoywd_opt(2019, 30, chrono::Weekday::Wed)
4159                            .unwrap()
4160                            .and_hms_milli_opt(23, 59, 59, 1234)
4161                            .unwrap(),
4162                    )
4163                    .unwrap(),
4164                ),
4165            ])
4166        });
4167        static TIMESTAMPTZ: LazyLock<Row> = LazyLock::new(|| {
4168            Row::pack_slice(&[
4169                Datum::TimestampTz(DateTime::from_timestamp(0, 0).unwrap().try_into().unwrap()),
4170                Datum::TimestampTz(
4171                    DateTime::from_naive_utc_and_offset(
4172                        crate::adt::timestamp::LOW_DATE
4173                            .and_hms_opt(0, 0, 0)
4174                            .unwrap(),
4175                        Utc,
4176                    )
4177                    .try_into()
4178                    .unwrap(),
4179                ),
4180                Datum::TimestampTz(
4181                    DateTime::from_naive_utc_and_offset(
4182                        crate::adt::timestamp::HIGH_DATE
4183                            .and_hms_opt(23, 59, 59)
4184                            .unwrap(),
4185                        Utc,
4186                    )
4187                    .try_into()
4188                    .unwrap(),
4189                ),
4190                // nano seconds
4191                Datum::TimestampTz(
4192                    DateTime::from_timestamp(0, 123456789)
4193                        .unwrap()
4194                        .try_into()
4195                        .unwrap(),
4196                ),
4197            ])
4198        });
4199        static INTERVAL: LazyLock<Row> = LazyLock::new(|| {
4200            Row::pack_slice(&[
4201                Datum::Interval(Interval::new(0, 0, 0)),
4202                Datum::Interval(Interval::new(1, 1, 1)),
4203                Datum::Interval(Interval::new(-1, -1, -1)),
4204                Datum::Interval(Interval::new(1, 0, 0)),
4205                Datum::Interval(Interval::new(0, 1, 0)),
4206                Datum::Interval(Interval::new(0, 0, 1)),
4207                Datum::Interval(Interval::new(-1, 0, 0)),
4208                Datum::Interval(Interval::new(0, -1, 0)),
4209                Datum::Interval(Interval::new(0, 0, -1)),
4210                Datum::Interval(Interval::new(i32::MIN, i32::MIN, i64::MIN)),
4211                Datum::Interval(Interval::new(i32::MAX, i32::MAX, i64::MAX)),
4212                Datum::Interval(Interval::new(i32::MIN, 0, 0)),
4213                Datum::Interval(Interval::new(i32::MAX, 0, 0)),
4214                Datum::Interval(Interval::new(0, i32::MIN, 0)),
4215                Datum::Interval(Interval::new(0, i32::MAX, 0)),
4216                Datum::Interval(Interval::new(0, 0, i64::MIN)),
4217                Datum::Interval(Interval::new(0, 0, i64::MAX)),
4218            ])
4219        });
4220        static PGLEGACYCHAR: LazyLock<Row> =
4221            LazyLock::new(|| Row::pack_slice(&[Datum::UInt8(u8::MIN), Datum::UInt8(u8::MAX)]));
4222        static PGLEGACYNAME: LazyLock<Row> = LazyLock::new(|| {
4223            Row::pack_slice(&[
4224                Datum::String(""),
4225                Datum::String(" "),
4226                Datum::String("'"),
4227                Datum::String("\""),
4228                Datum::String("."),
4229                Datum::String(&"x".repeat(64)),
4230            ])
4231        });
4232        static BYTES: LazyLock<Row> = LazyLock::new(|| {
4233            Row::pack_slice(&[Datum::Bytes(&[]), Datum::Bytes(&[0]), Datum::Bytes(&[255])])
4234        });
4235        static STRING: 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("2015-09-18T23:56:04.123Z"),
4243                Datum::String(&"x".repeat(100)),
4244                // Persist stats truncate string bounds to 100 bytes: cover a
4245                // string past that limit, one whose truncated upper bound
4246                // cannot be incremented (every char is char::MAX), and one
4247                // with a multibyte char straddling the truncation boundary.
4248                Datum::String(&"x".repeat(101)),
4249                Datum::String(&"\u{10FFFF}".repeat(101)),
4250                Datum::String(&format!("{}\u{1F600}", "x".repeat(99))),
4251                // Valid timezone.
4252                Datum::String("JAPAN"),
4253                Datum::String("1,2,3"),
4254                Datum::String("\r\n"),
4255                Datum::String("\"\""),
4256            ])
4257        });
4258        static CHAR: LazyLock<Row> = LazyLock::new(|| {
4259            Row::pack_slice(&[
4260                Datum::String(" "),
4261                Datum::String("'"),
4262                Datum::String("\""),
4263                Datum::String("."),
4264                Datum::String(","),
4265                Datum::String("\t"),
4266                Datum::String("\n"),
4267                Datum::String("\r"),
4268                Datum::String("\\"),
4269                // Null character.
4270                Datum::String(std::str::from_utf8(b"\x00").unwrap()),
4271                // Start of text.
4272                Datum::String(std::str::from_utf8(b"\x02").unwrap()),
4273                // End of text.
4274                Datum::String(std::str::from_utf8(b"\x03").unwrap()),
4275                // Backspace.
4276                Datum::String(std::str::from_utf8(b"\x08").unwrap()),
4277                // Escape.
4278                Datum::String(std::str::from_utf8(b"\x1B").unwrap()),
4279                // Delete.
4280                Datum::String(std::str::from_utf8(b"\x7F").unwrap()),
4281            ])
4282        });
4283        static JSONB: LazyLock<Row> = LazyLock::new(|| {
4284            let mut datums = vec![Datum::True, Datum::False, Datum::JsonNull];
4285            datums.extend(STRING.iter());
4286            datums.extend(NUMERIC.iter().filter(|n| {
4287                let Datum::Numeric(n) = n else {
4288                    panic!("expected Numeric, found {n:?}");
4289                };
4290                // JSON doesn't support NaN or Infinite numbers.
4291                !(n.0.is_nan() || n.0.is_infinite())
4292            }));
4293            let mut row = Row::default();
4294            let mut packer = row.packer();
4295            for datum in datums {
4296                packer.push(datum);
4297            }
4298            // Maps, including ones with disjoint key sets. Persist keeps
4299            // per-key statistics for JSON maps, so a collection mixing maps
4300            // where a key is present in one and absent in another exercises
4301            // the absent-key handling in stats and their consumers.
4302            packer.push_dict([("x", Datum::String("a"))]);
4303            packer.push_dict([("y", Datum::String("b"))]);
4304            packer.push_dict([("x", Datum::True), ("y", Datum::JsonNull)]);
4305            packer.push_dict(std::iter::empty::<(&str, Datum)>());
4306            // JSON map keys are not truncated in persist stats, unlike SQL
4307            // string columns, so cover one past the string truncation limit.
4308            let long_key = "k".repeat(101);
4309            packer.push_dict([(long_key.as_str(), Datum::True)]);
4310            packer.push_dict_with(|packer| {
4311                packer.push(Datum::String("nested"));
4312                packer.push_dict([("x", Datum::String("a"))]);
4313            });
4314            // Lists, including a heterogeneous one.
4315            packer.push_list([Datum::True, Datum::JsonNull, Datum::String("a")]);
4316            packer.push_list(std::iter::empty::<Datum>());
4317            row
4318        });
4319        static UUID: LazyLock<Row> = LazyLock::new(|| {
4320            Row::pack_slice(&[
4321                Datum::Uuid(Uuid::from_u128(u128::MIN)),
4322                Datum::Uuid(Uuid::from_u128(u128::MAX)),
4323            ])
4324        });
4325        static ARRAY: LazyLock<BTreeMap<&'static SqlScalarType, Row>> = LazyLock::new(|| {
4326            let generate_row = |inner_type: &SqlScalarType| {
4327                let datums: Vec<_> = inner_type.interesting_datums().collect();
4328
4329                let mut row = Row::default();
4330                row.packer()
4331                    .try_push_array::<_, Datum<'static>>(
4332                        &[ArrayDimension {
4333                            lower_bound: 1,
4334                            length: 0,
4335                        }],
4336                        [],
4337                    )
4338                    .expect("failed to push empty array");
4339                row.packer()
4340                    .try_push_array(
4341                        &[ArrayDimension {
4342                            lower_bound: 1,
4343                            length: datums.len(),
4344                        }],
4345                        datums,
4346                    )
4347                    .expect("failed to push array");
4348
4349                row
4350            };
4351
4352            SqlScalarType::enumerate()
4353                .into_iter()
4354                .filter(|ty| !matches!(ty, SqlScalarType::Array(_)))
4355                .map(|ty| (ty, generate_row(ty)))
4356                .collect()
4357        });
4358        static EMPTY_ARRAY: LazyLock<Row> = LazyLock::new(|| {
4359            let mut row = Row::default();
4360            row.packer()
4361                .try_push_array::<_, Datum<'static>>(
4362                    &[ArrayDimension {
4363                        lower_bound: 1,
4364                        length: 0,
4365                    }],
4366                    [],
4367                )
4368                .expect("failed to push empty array");
4369            row
4370        });
4371        static LIST: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4372        static RECORD: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4373        static OID: LazyLock<Row> =
4374            LazyLock::new(|| Row::pack_slice(&[Datum::UInt32(u32::MIN), Datum::UInt32(u32::MAX)]));
4375        static MAP: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4376        static INT2VECTOR: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4377        static MZTIMESTAMP: LazyLock<Row> = LazyLock::new(|| {
4378            Row::pack_slice(&[
4379                Datum::MzTimestamp(crate::Timestamp::MIN),
4380                Datum::MzTimestamp(crate::Timestamp::MAX),
4381            ])
4382        });
4383        static RANGE: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4384        static MZACLITEM: LazyLock<Row> = LazyLock::new(|| {
4385            Row::pack_slice(&[
4386                Datum::MzAclItem(MzAclItem {
4387                    grantee: RoleId::Public,
4388                    grantor: RoleId::Public,
4389                    acl_mode: AclMode::empty(),
4390                }),
4391                Datum::MzAclItem(MzAclItem {
4392                    grantee: RoleId::Public,
4393                    grantor: RoleId::Public,
4394                    acl_mode: AclMode::all(),
4395                }),
4396                Datum::MzAclItem(MzAclItem {
4397                    grantee: RoleId::User(42),
4398                    grantor: RoleId::Public,
4399                    acl_mode: AclMode::empty(),
4400                }),
4401                Datum::MzAclItem(MzAclItem {
4402                    grantee: RoleId::User(42),
4403                    grantor: RoleId::Public,
4404                    acl_mode: AclMode::all(),
4405                }),
4406                Datum::MzAclItem(MzAclItem {
4407                    grantee: RoleId::Public,
4408                    grantor: RoleId::User(42),
4409                    acl_mode: AclMode::empty(),
4410                }),
4411                Datum::MzAclItem(MzAclItem {
4412                    grantee: RoleId::Public,
4413                    grantor: RoleId::User(42),
4414                    acl_mode: AclMode::all(),
4415                }),
4416            ])
4417        });
4418        // aclitem has no binary encoding so we can't test it here.
4419        static ACLITEM: LazyLock<Row> = LazyLock::new(|| Row::pack_slice(&[]));
4420
4421        let iter: Box<dyn Iterator<Item = Datum<'static>>> = match self {
4422            SqlScalarType::Bool => Box::new((*BOOL).iter()),
4423            SqlScalarType::Int16 => Box::new((*INT16).iter()),
4424            SqlScalarType::Int32 => Box::new((*INT32).iter()),
4425            SqlScalarType::Int64 => Box::new((*INT64).iter()),
4426            SqlScalarType::UInt16 => Box::new((*UINT16).iter()),
4427            SqlScalarType::UInt32 => Box::new((*UINT32).iter()),
4428            SqlScalarType::UInt64 => Box::new((*UINT64).iter()),
4429            SqlScalarType::Float32 => Box::new((*FLOAT32).iter()),
4430            SqlScalarType::Float64 => Box::new((*FLOAT64).iter()),
4431            SqlScalarType::Numeric { .. } => Box::new((*NUMERIC).iter()),
4432            SqlScalarType::Date => Box::new((*DATE).iter()),
4433            SqlScalarType::Time => Box::new((*TIME).iter()),
4434            SqlScalarType::Timestamp { .. } => Box::new((*TIMESTAMP).iter()),
4435            SqlScalarType::TimestampTz { .. } => Box::new((*TIMESTAMPTZ).iter()),
4436            SqlScalarType::Interval => Box::new((*INTERVAL).iter()),
4437            SqlScalarType::PgLegacyChar => Box::new((*PGLEGACYCHAR).iter()),
4438            SqlScalarType::PgLegacyName => Box::new((*PGLEGACYNAME).iter()),
4439            SqlScalarType::Bytes => Box::new((*BYTES).iter()),
4440            SqlScalarType::String => Box::new((*STRING).iter().chain((*CHAR).iter())),
4441            SqlScalarType::Char { .. } => Box::new((*CHAR).iter()),
4442            SqlScalarType::VarChar { .. } => Box::new((*STRING).iter().chain((*CHAR).iter())),
4443            SqlScalarType::Jsonb => Box::new((*JSONB).iter()),
4444            SqlScalarType::Uuid => Box::new((*UUID).iter()),
4445            SqlScalarType::Array(inner_type) => {
4446                if matches!(inner_type.as_ref(), SqlScalarType::Array(_)) {
4447                    panic!("SqlScalarType::Array cannot have a nested Array");
4448                }
4449
4450                Box::new(
4451                    (*ARRAY)
4452                        .get(inner_type.as_ref())
4453                        .unwrap_or(&*EMPTY_ARRAY)
4454                        .iter(),
4455                )
4456            }
4457            SqlScalarType::List { .. } => Box::new((*LIST).iter()),
4458            SqlScalarType::Record { .. } => Box::new((*RECORD).iter()),
4459            SqlScalarType::Oid => Box::new((*OID).iter()),
4460            SqlScalarType::Map { .. } => Box::new((*MAP).iter()),
4461            SqlScalarType::RegProc => Box::new((*OID).iter()),
4462            SqlScalarType::RegType => Box::new((*OID).iter()),
4463            SqlScalarType::RegClass => Box::new((*OID).iter()),
4464            SqlScalarType::Int2Vector => Box::new((*INT2VECTOR).iter()),
4465            SqlScalarType::MzTimestamp => Box::new((*MZTIMESTAMP).iter()),
4466            SqlScalarType::Range { .. } => Box::new((*RANGE).iter()),
4467            SqlScalarType::MzAclItem { .. } => Box::new((*MZACLITEM).iter()),
4468            SqlScalarType::AclItem { .. } => Box::new((*ACLITEM).iter()),
4469        };
4470
4471        iter
4472    }
4473
4474    /// Returns all non-parameterized types and some versions of some
4475    /// parameterized types.
4476    pub fn enumerate() -> &'static [Self] {
4477        // TODO: Is there a compile-time way to make sure any new
4478        // non-parameterized types get added here?
4479        &[
4480            SqlScalarType::Bool,
4481            SqlScalarType::Int16,
4482            SqlScalarType::Int32,
4483            SqlScalarType::Int64,
4484            SqlScalarType::UInt16,
4485            SqlScalarType::UInt32,
4486            SqlScalarType::UInt64,
4487            SqlScalarType::Float32,
4488            SqlScalarType::Float64,
4489            SqlScalarType::Numeric {
4490                max_scale: Some(NumericMaxScale(
4491                    crate::adt::numeric::NUMERIC_DATUM_MAX_PRECISION,
4492                )),
4493            },
4494            SqlScalarType::Date,
4495            SqlScalarType::Time,
4496            SqlScalarType::Timestamp {
4497                precision: Some(TimestampPrecision(crate::adt::timestamp::MAX_PRECISION)),
4498            },
4499            SqlScalarType::Timestamp {
4500                precision: Some(TimestampPrecision(0)),
4501            },
4502            SqlScalarType::Timestamp { precision: None },
4503            SqlScalarType::TimestampTz {
4504                precision: Some(TimestampPrecision(crate::adt::timestamp::MAX_PRECISION)),
4505            },
4506            SqlScalarType::TimestampTz {
4507                precision: Some(TimestampPrecision(0)),
4508            },
4509            SqlScalarType::TimestampTz { precision: None },
4510            SqlScalarType::Interval,
4511            SqlScalarType::PgLegacyChar,
4512            SqlScalarType::Bytes,
4513            SqlScalarType::String,
4514            SqlScalarType::Char {
4515                length: Some(CharLength(1)),
4516            },
4517            SqlScalarType::VarChar { max_length: None },
4518            SqlScalarType::Jsonb,
4519            SqlScalarType::Uuid,
4520            SqlScalarType::Oid,
4521            SqlScalarType::RegProc,
4522            SqlScalarType::RegType,
4523            SqlScalarType::RegClass,
4524            SqlScalarType::Int2Vector,
4525            SqlScalarType::MzTimestamp,
4526            SqlScalarType::MzAclItem,
4527            // TODO: Fill in some variants of these.
4528            /*
4529            SqlScalarType::AclItem,
4530            SqlScalarType::Array(_),
4531            SqlScalarType::List {
4532                element_type: todo!(),
4533                custom_id: todo!(),
4534            },
4535            SqlScalarType::Record {
4536                fields: todo!(),
4537                custom_id: todo!(),
4538            },
4539            SqlScalarType::Map {
4540                value_type: todo!(),
4541                custom_id: todo!(),
4542            },
4543            SqlScalarType::Range {
4544                element_type: todo!(),
4545            }
4546            */
4547        ]
4548    }
4549
4550    /// Returns the appropriate element type for making a [`SqlScalarType::Array`] whose elements are
4551    /// of `self`.
4552    ///
4553    /// If the type is not compatible with making an array, returns in the error position.
4554    pub fn array_of_self_elem_type(self) -> Result<SqlScalarType, SqlScalarType> {
4555        match self {
4556            t @ (SqlScalarType::AclItem
4557            | SqlScalarType::Bool
4558            | SqlScalarType::Int16
4559            | SqlScalarType::Int32
4560            | SqlScalarType::Int64
4561            | SqlScalarType::UInt16
4562            | SqlScalarType::UInt32
4563            | SqlScalarType::UInt64
4564            | SqlScalarType::Float32
4565            | SqlScalarType::Float64
4566            | SqlScalarType::Numeric { .. }
4567            | SqlScalarType::Date
4568            | SqlScalarType::Time
4569            | SqlScalarType::Timestamp { .. }
4570            | SqlScalarType::TimestampTz { .. }
4571            | SqlScalarType::Interval
4572            | SqlScalarType::PgLegacyChar
4573            | SqlScalarType::PgLegacyName
4574            | SqlScalarType::Bytes
4575            | SqlScalarType::String
4576            | SqlScalarType::VarChar { .. }
4577            | SqlScalarType::Jsonb
4578            | SqlScalarType::Uuid
4579            | SqlScalarType::Record { .. }
4580            | SqlScalarType::Oid
4581            | SqlScalarType::RegProc
4582            | SqlScalarType::RegType
4583            | SqlScalarType::RegClass
4584            | SqlScalarType::Int2Vector
4585            | SqlScalarType::MzTimestamp
4586            | SqlScalarType::Range { .. }
4587            | SqlScalarType::MzAclItem { .. }) => Ok(t),
4588
4589            SqlScalarType::Array(elem) => Ok(elem.array_of_self_elem_type()?),
4590
4591            // https://github.com/MaterializeInc/database-issues/issues/2360
4592            t @ (SqlScalarType::Char { .. }
4593            // not sensible to put in arrays
4594            | SqlScalarType::Map { .. }
4595            | SqlScalarType::List { .. }) => Err(t),
4596        }
4597    }
4598}
4599
4600// See the chapter "Generating Recurisve Data" from the proptest book:
4601// https://altsysrq.github.io/proptest-book/proptest/tutorial/recursive.html
4602#[cfg(any(test, feature = "proptest"))]
4603impl Arbitrary for SqlScalarType {
4604    type Parameters = ();
4605    type Strategy = BoxedStrategy<SqlScalarType>;
4606
4607    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
4608        // A strategy for generating the leaf cases of SqlScalarType
4609        let leaf = Union::new(vec![
4610            Just(SqlScalarType::Bool).boxed(),
4611            Just(SqlScalarType::UInt16).boxed(),
4612            Just(SqlScalarType::UInt32).boxed(),
4613            Just(SqlScalarType::UInt64).boxed(),
4614            Just(SqlScalarType::Int16).boxed(),
4615            Just(SqlScalarType::Int32).boxed(),
4616            Just(SqlScalarType::Int64).boxed(),
4617            Just(SqlScalarType::Float32).boxed(),
4618            Just(SqlScalarType::Float64).boxed(),
4619            any::<Option<NumericMaxScale>>()
4620                .prop_map(|max_scale| SqlScalarType::Numeric { max_scale })
4621                .boxed(),
4622            Just(SqlScalarType::Date).boxed(),
4623            Just(SqlScalarType::Time).boxed(),
4624            any::<Option<TimestampPrecision>>()
4625                .prop_map(|precision| SqlScalarType::Timestamp { precision })
4626                .boxed(),
4627            any::<Option<TimestampPrecision>>()
4628                .prop_map(|precision| SqlScalarType::TimestampTz { precision })
4629                .boxed(),
4630            Just(SqlScalarType::MzTimestamp).boxed(),
4631            Just(SqlScalarType::Interval).boxed(),
4632            Just(SqlScalarType::PgLegacyChar).boxed(),
4633            Just(SqlScalarType::Bytes).boxed(),
4634            Just(SqlScalarType::String).boxed(),
4635            any::<Option<CharLength>>()
4636                .prop_map(|length| SqlScalarType::Char { length })
4637                .boxed(),
4638            any::<Option<VarCharMaxLength>>()
4639                .prop_map(|max_length| SqlScalarType::VarChar { max_length })
4640                .boxed(),
4641            Just(SqlScalarType::PgLegacyName).boxed(),
4642            Just(SqlScalarType::Jsonb).boxed(),
4643            Just(SqlScalarType::Uuid).boxed(),
4644            Just(SqlScalarType::AclItem).boxed(),
4645            Just(SqlScalarType::MzAclItem).boxed(),
4646            Just(SqlScalarType::Oid).boxed(),
4647            Just(SqlScalarType::RegProc).boxed(),
4648            Just(SqlScalarType::RegType).boxed(),
4649            Just(SqlScalarType::RegClass).boxed(),
4650            Just(SqlScalarType::Int2Vector).boxed(),
4651        ])
4652        // None of the leaf SqlScalarTypes types are really "simpler" than others
4653        // so don't waste time trying to shrink.
4654        .no_shrink()
4655        .boxed();
4656
4657        // There are a limited set of types we support in ranges.
4658        let range_leaf = Union::new(vec![
4659            Just(SqlScalarType::Int32).boxed(),
4660            Just(SqlScalarType::Int64).boxed(),
4661            Just(SqlScalarType::Date).boxed(),
4662            any::<Option<NumericMaxScale>>()
4663                .prop_map(|max_scale| SqlScalarType::Numeric { max_scale })
4664                .boxed(),
4665            any::<Option<TimestampPrecision>>()
4666                .prop_map(|precision| SqlScalarType::Timestamp { precision })
4667                .boxed(),
4668            any::<Option<TimestampPrecision>>()
4669                .prop_map(|precision| SqlScalarType::TimestampTz { precision })
4670                .boxed(),
4671        ]);
4672        let range = range_leaf
4673            .prop_map(|inner_type| SqlScalarType::Range {
4674                element_type: Box::new(inner_type),
4675            })
4676            .boxed();
4677
4678        // The Array type is not recursive, so we define it separately.
4679        let array = leaf
4680            .clone()
4681            .prop_map(|inner_type| SqlScalarType::Array(Box::new(inner_type)))
4682            .boxed();
4683
4684        let leaf = Union::new_weighted(vec![(30, leaf), (1, array), (1, range)]);
4685
4686        leaf.prop_recursive(2, 3, 5, |inner| {
4687            Union::new(vec![
4688                // List
4689                (inner.clone(), any::<Option<CatalogItemId>>())
4690                    .prop_map(|(x, id)| SqlScalarType::List {
4691                        element_type: Box::new(x),
4692                        custom_id: id,
4693                    })
4694                    .boxed(),
4695                // Map
4696                (inner.clone(), any::<Option<CatalogItemId>>())
4697                    .prop_map(|(x, id)| SqlScalarType::Map {
4698                        value_type: Box::new(x),
4699                        custom_id: id,
4700                    })
4701                    .boxed(),
4702                // Record
4703                {
4704                    // Now we have to use `inner` to create a Record type. First we
4705                    // create strategy that creates SqlColumnType.
4706                    let column_type_strat =
4707                        (inner, any::<bool>()).prop_map(|(scalar_type, nullable)| SqlColumnType {
4708                            scalar_type,
4709                            nullable,
4710                        });
4711
4712                    // Then we use that to create the fields of the record case.
4713                    // fields has type vec<(ColumnName,SqlColumnType)>
4714                    let fields_strat =
4715                        prop::collection::vec((any::<ColumnName>(), column_type_strat), 0..10);
4716
4717                    // Now we combine it with the default strategies to get Records.
4718                    (fields_strat, any::<Option<CatalogItemId>>())
4719                        .prop_map(|(fields, custom_id)| SqlScalarType::Record {
4720                            fields: fields.into(),
4721                            custom_id,
4722                        })
4723                        .boxed()
4724                },
4725            ])
4726        })
4727        .boxed()
4728    }
4729}
4730
4731#[cfg(any(test, feature = "proptest"))]
4732impl Arbitrary for ReprScalarType {
4733    type Parameters = ();
4734    type Strategy = BoxedStrategy<ReprScalarType>;
4735
4736    fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
4737        // A strategy for generating the leaf cases of ReprScalarType
4738        let leaf = Union::new(vec![
4739            Just(ReprScalarType::Bool).boxed(),
4740            Just(ReprScalarType::UInt8).boxed(),
4741            Just(ReprScalarType::UInt16).boxed(),
4742            Just(ReprScalarType::UInt32).boxed(),
4743            Just(ReprScalarType::UInt64).boxed(),
4744            Just(ReprScalarType::Int16).boxed(),
4745            Just(ReprScalarType::Int32).boxed(),
4746            Just(ReprScalarType::Int64).boxed(),
4747            Just(ReprScalarType::Float32).boxed(),
4748            Just(ReprScalarType::Float64).boxed(),
4749            Just(ReprScalarType::Numeric).boxed(),
4750            Just(ReprScalarType::Date).boxed(),
4751            Just(ReprScalarType::Time).boxed(),
4752            Just(ReprScalarType::Timestamp).boxed(),
4753            Just(ReprScalarType::TimestampTz).boxed(),
4754            Just(ReprScalarType::MzTimestamp).boxed(),
4755            Just(ReprScalarType::Interval).boxed(),
4756            Just(ReprScalarType::Bytes).boxed(),
4757            Just(ReprScalarType::String).boxed(),
4758            Just(ReprScalarType::Jsonb).boxed(),
4759            Just(ReprScalarType::Uuid).boxed(),
4760            Just(ReprScalarType::AclItem).boxed(),
4761            Just(ReprScalarType::MzAclItem).boxed(),
4762            Just(ReprScalarType::Int2Vector).boxed(),
4763        ])
4764        // None of the leaf ReprScalarTypes types are really "simpler" than others
4765        // so don't waste time trying to shrink.
4766        .no_shrink()
4767        .boxed();
4768
4769        // There are a limited set of types we support in ranges.
4770        let range_leaf = Union::new(vec![
4771            Just(ReprScalarType::Int32).boxed(),
4772            Just(ReprScalarType::Int64).boxed(),
4773            Just(ReprScalarType::Date).boxed(),
4774            Just(ReprScalarType::Numeric).boxed(),
4775            Just(ReprScalarType::Timestamp).boxed(),
4776            Just(ReprScalarType::TimestampTz).boxed(),
4777        ]);
4778        let range = range_leaf
4779            .prop_map(|inner_type| ReprScalarType::Range {
4780                element_type: Box::new(inner_type),
4781            })
4782            .boxed();
4783
4784        // The Array type is not recursive, so we define it separately.
4785        let array = leaf
4786            .clone()
4787            .prop_map(|inner_type| ReprScalarType::Array(Box::new(inner_type)))
4788            .boxed();
4789
4790        let leaf = Union::new_weighted(vec![(30, leaf), (1, array), (1, range)]);
4791
4792        leaf.prop_recursive(2, 3, 5, |inner| {
4793            Union::new(vec![
4794                // List
4795                inner
4796                    .clone()
4797                    .prop_map(|x| ReprScalarType::List {
4798                        element_type: Box::new(x),
4799                    })
4800                    .boxed(),
4801                // Map
4802                inner
4803                    .clone()
4804                    .prop_map(|x| ReprScalarType::Map {
4805                        value_type: Box::new(x),
4806                    })
4807                    .boxed(),
4808                // Record
4809                {
4810                    // Now we have to use `inner` to create a Record type. First we
4811                    // create strategy that creates SqlColumnType.
4812                    let column_type_strat =
4813                        (inner.clone(), any::<bool>()).prop_map(|(scalar_type, nullable)| {
4814                            ReprColumnType {
4815                                scalar_type,
4816                                nullable,
4817                            }
4818                        });
4819
4820                    // Then we use that to create the fields of the record case.
4821                    // fields has type vec<(ColumnName,SqlColumnType)>
4822                    let fields_strat = prop::collection::vec(column_type_strat, 0..10);
4823
4824                    // Now we combine it with the default strategies to get Records.
4825                    fields_strat
4826                        .prop_map(|fields| ReprScalarType::Record {
4827                            fields: fields.into_boxed_slice(),
4828                        })
4829                        .boxed()
4830                },
4831            ])
4832        })
4833        .boxed()
4834    }
4835}
4836
4837/// The type of a [`Datum`] as it is represented.
4838///
4839/// Each variant here corresponds to one or more variants of [`SqlScalarType`].
4840///
4841/// There is a direct correspondence between `Datum` variants and `ReprScalarType`
4842/// variants: every `Datum` variant corresponds to exactly one `ReprScalarType` variant
4843/// (with an exception for `Datum::Array`, which could be both an `Int2Vector` and an `Array`).
4844///
4845/// It is important that any new variants for this enum be added to the `Arbitrary` instance
4846/// and the `union` method.
4847#[derive(Clone, Debug, EnumKind, Serialize, Deserialize)]
4848#[enum_kind(ReprScalarBaseType, derive(PartialOrd, Ord, Hash))]
4849pub enum ReprScalarType {
4850    Bool,
4851    Int16,
4852    Int32,
4853    Int64,
4854    UInt8, // also includes SqlScalarType::PgLegacyChar
4855    UInt16,
4856    UInt32, // also includes SqlScalarType::{Oid,RegClass,RegProc,RegType}
4857    UInt64,
4858    Float32,
4859    Float64,
4860    Numeric,
4861    Date,
4862    Time,
4863    Timestamp,
4864    TimestampTz,
4865    MzTimestamp,
4866    Interval,
4867    Bytes,
4868    Jsonb,
4869    String, // also includes SqlScalarType::{VarChar,Char,PgLegacyName}
4870    Uuid,
4871    Array(Box<ReprScalarType>),
4872    Int2Vector, // See [`Int2Vector`] for why this is separate from `Array`.
4873    List { element_type: Box<ReprScalarType> },
4874    Record { fields: Box<[ReprColumnType]> },
4875    Map { value_type: Box<ReprScalarType> },
4876    Range { element_type: Box<ReprScalarType> },
4877    MzAclItem,
4878    AclItem,
4879}
4880
4881impl PartialEq for ReprScalarType {
4882    fn eq(&self, other: &Self) -> bool {
4883        match (self, other) {
4884            (ReprScalarType::Array(a), ReprScalarType::Array(b)) => a.eq(b),
4885            (
4886                ReprScalarType::List { element_type: a },
4887                ReprScalarType::List { element_type: b },
4888            ) => a.eq(b),
4889            (ReprScalarType::Record { fields: a }, ReprScalarType::Record { fields: b }) => {
4890                a.len() == b.len()
4891                    && a.iter()
4892                        .zip_eq(b.iter())
4893                        .all(|(af, bf)| af.scalar_type.eq(&bf.scalar_type))
4894            }
4895            (ReprScalarType::Map { value_type: a }, ReprScalarType::Map { value_type: b }) => {
4896                a.eq(b)
4897            }
4898            (
4899                ReprScalarType::Range { element_type: a },
4900                ReprScalarType::Range { element_type: b },
4901            ) => a.eq(b),
4902            _ => ReprScalarBaseType::from(self) == ReprScalarBaseType::from(other),
4903        }
4904    }
4905}
4906impl Eq for ReprScalarType {}
4907
4908impl Hash for ReprScalarType {
4909    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
4910        match self {
4911            ReprScalarType::Array(a) => a.hash(state),
4912            ReprScalarType::List { element_type: a } => a.hash(state),
4913            ReprScalarType::Record { fields: a } => {
4914                for field in a {
4915                    field.scalar_type.hash(state);
4916                }
4917            }
4918            ReprScalarType::Map { value_type: a } => a.hash(state),
4919            ReprScalarType::Range { element_type: a } => a.hash(state),
4920            _ => ReprScalarBaseType::from(self).hash(state),
4921        }
4922    }
4923}
4924
4925impl PartialOrd for ReprScalarType {
4926    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
4927        Some(self.cmp(other))
4928    }
4929}
4930
4931impl Ord for ReprScalarType {
4932    fn cmp(&self, other: &Self) -> Ordering {
4933        match (self, other) {
4934            (ReprScalarType::Array(a), ReprScalarType::Array(b)) => a.cmp(b),
4935            (
4936                ReprScalarType::List { element_type: a },
4937                ReprScalarType::List { element_type: b },
4938            ) => a.cmp(b),
4939            (ReprScalarType::Record { fields: a }, ReprScalarType::Record { fields: b }) => {
4940                let len_ordering = a.len().cmp(&b.len());
4941                if len_ordering != Ordering::Equal {
4942                    return len_ordering;
4943                }
4944
4945                // NB ignoring nullability
4946                for (af, bf) in a.iter().zip_eq(b.iter()) {
4947                    let scalar_type_ordering = af.scalar_type.cmp(&bf.scalar_type);
4948                    if scalar_type_ordering != Ordering::Equal {
4949                        return scalar_type_ordering;
4950                    }
4951                }
4952
4953                Ordering::Equal
4954            }
4955            (ReprScalarType::Map { value_type: a }, ReprScalarType::Map { value_type: b }) => {
4956                a.cmp(b)
4957            }
4958            (
4959                ReprScalarType::Range { element_type: a },
4960                ReprScalarType::Range { element_type: b },
4961            ) => a.cmp(b),
4962            _ => ReprScalarBaseType::from(self).cmp(&ReprScalarBaseType::from(other)),
4963        }
4964    }
4965}
4966
4967impl std::fmt::Display for ReprScalarType {
4968    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4969        match self {
4970            ReprScalarType::Bool => write!(f, "r_bool"),
4971            ReprScalarType::Int16 => write!(f, "r_int16"),
4972            ReprScalarType::Int32 => write!(f, "r_int32"),
4973            ReprScalarType::Int64 => write!(f, "r_int64"),
4974            ReprScalarType::UInt8 => write!(f, "r_uint8"),
4975            ReprScalarType::UInt16 => write!(f, "r_uint16"),
4976            ReprScalarType::UInt32 => write!(f, "r_uint32"),
4977            ReprScalarType::UInt64 => write!(f, "r_uint64"),
4978            ReprScalarType::Float32 => write!(f, "r_float32"),
4979            ReprScalarType::Float64 => write!(f, "r_float64"),
4980            ReprScalarType::Numeric => write!(f, "r_numeric"),
4981            ReprScalarType::Date => write!(f, "r_date"),
4982            ReprScalarType::Time => write!(f, "r_time"),
4983            ReprScalarType::Timestamp => write!(f, "r_timestamp"),
4984            ReprScalarType::TimestampTz => write!(f, "r_timestamptz"),
4985            ReprScalarType::MzTimestamp => write!(f, "r_mz_timestamp"),
4986            ReprScalarType::Interval => write!(f, "r_interval"),
4987            ReprScalarType::Bytes => write!(f, "r_bytes"),
4988            ReprScalarType::Jsonb => write!(f, "r_jsonb"),
4989            ReprScalarType::String => write!(f, "r_string"),
4990            ReprScalarType::Uuid => write!(f, "r_uuid"),
4991            ReprScalarType::Array(element_type) => write!(f, "r_array({element_type})"),
4992            ReprScalarType::Int2Vector => write!(f, "r_int2vector"),
4993            ReprScalarType::List { element_type } => write!(f, "r_list({element_type})"),
4994            ReprScalarType::Record { fields } => {
4995                let fields = separated(", ", fields.iter());
4996                write!(f, "r_record({fields})")
4997            }
4998            ReprScalarType::Map { value_type } => write!(f, "r_map({value_type})"),
4999            ReprScalarType::Range { element_type } => write!(f, "r_range({element_type})"),
5000            ReprScalarType::MzAclItem => write!(f, "r_mz_acl_item"),
5001            ReprScalarType::AclItem => write!(f, "r_acl_item"),
5002        }
5003    }
5004}
5005
5006impl ReprScalarType {
5007    /// Returns a [`ReprColumnType`] with the given nullability.
5008    pub fn nullable(self, nullable: bool) -> ReprColumnType {
5009        ReprColumnType {
5010            scalar_type: self,
5011            nullable,
5012        }
5013    }
5014
5015    /// Returns the union of two `ReprScalarType` or an error.
5016    ///
5017    /// Errors can only occur if the two types are built somewhere using different constructors.
5018    /// Note that `ReprScalarType::Record` holds a `ReprColumnType`, and so nullability information
5019    /// is unioned.
5020    pub fn union(&self, scalar_type: &ReprScalarType) -> Result<Self, anyhow::Error> {
5021        match (self, scalar_type) {
5022            (ReprScalarType::Bool, ReprScalarType::Bool) => Ok(ReprScalarType::Bool),
5023            (ReprScalarType::Int16, ReprScalarType::Int16) => Ok(ReprScalarType::Int16),
5024            (ReprScalarType::Int32, ReprScalarType::Int32) => Ok(ReprScalarType::Int32),
5025            (ReprScalarType::Int64, ReprScalarType::Int64) => Ok(ReprScalarType::Int64),
5026            (ReprScalarType::UInt8, ReprScalarType::UInt8) => Ok(ReprScalarType::UInt8),
5027            (ReprScalarType::UInt16, ReprScalarType::UInt16) => Ok(ReprScalarType::UInt16),
5028            (ReprScalarType::UInt32, ReprScalarType::UInt32) => Ok(ReprScalarType::UInt32),
5029            (ReprScalarType::UInt64, ReprScalarType::UInt64) => Ok(ReprScalarType::UInt64),
5030            (ReprScalarType::Float32, ReprScalarType::Float32) => Ok(ReprScalarType::Float32),
5031            (ReprScalarType::Float64, ReprScalarType::Float64) => Ok(ReprScalarType::Float64),
5032            (ReprScalarType::Numeric, ReprScalarType::Numeric) => Ok(ReprScalarType::Numeric),
5033            (ReprScalarType::Date, ReprScalarType::Date) => Ok(ReprScalarType::Date),
5034            (ReprScalarType::Time, ReprScalarType::Time) => Ok(ReprScalarType::Time),
5035            (ReprScalarType::Timestamp, ReprScalarType::Timestamp) => Ok(ReprScalarType::Timestamp),
5036            (ReprScalarType::TimestampTz, ReprScalarType::TimestampTz) => {
5037                Ok(ReprScalarType::TimestampTz)
5038            }
5039            (ReprScalarType::MzTimestamp, ReprScalarType::MzTimestamp) => {
5040                Ok(ReprScalarType::MzTimestamp)
5041            }
5042            (ReprScalarType::AclItem, ReprScalarType::AclItem) => Ok(ReprScalarType::AclItem),
5043            (ReprScalarType::MzAclItem, ReprScalarType::MzAclItem) => Ok(ReprScalarType::MzAclItem),
5044            (ReprScalarType::Interval, ReprScalarType::Interval) => Ok(ReprScalarType::Interval),
5045            (ReprScalarType::Bytes, ReprScalarType::Bytes) => Ok(ReprScalarType::Bytes),
5046            (ReprScalarType::Jsonb, ReprScalarType::Jsonb) => Ok(ReprScalarType::Jsonb),
5047            (ReprScalarType::String, ReprScalarType::String) => Ok(ReprScalarType::String),
5048            (ReprScalarType::Uuid, ReprScalarType::Uuid) => Ok(ReprScalarType::Uuid),
5049            (ReprScalarType::Array(element_type), ReprScalarType::Array(other_element_type)) => Ok(
5050                ReprScalarType::Array(Box::new(element_type.union(other_element_type)?)),
5051            ),
5052            (ReprScalarType::Int2Vector, ReprScalarType::Int2Vector) => {
5053                Ok(ReprScalarType::Int2Vector)
5054            }
5055            (
5056                ReprScalarType::List { element_type },
5057                ReprScalarType::List {
5058                    element_type: other_element_type,
5059                },
5060            ) => Ok(ReprScalarType::List {
5061                element_type: Box::new(element_type.union(other_element_type)?),
5062            }),
5063            (
5064                ReprScalarType::Record { fields },
5065                ReprScalarType::Record {
5066                    fields: other_fields,
5067                },
5068            ) => {
5069                if fields.len() != other_fields.len() {
5070                    bail!("Can't union record types: {:?} and {:?}", self, scalar_type);
5071                }
5072
5073                let mut union_fields = Vec::with_capacity(fields.len());
5074                for (field, other_field) in fields.iter().zip_eq(other_fields.iter()) {
5075                    union_fields.push(field.union(other_field)?);
5076                }
5077                Ok(ReprScalarType::Record {
5078                    fields: union_fields.into_boxed_slice(),
5079                })
5080            }
5081            (
5082                ReprScalarType::Map { value_type },
5083                ReprScalarType::Map {
5084                    value_type: other_value_type,
5085                },
5086            ) => Ok(ReprScalarType::Map {
5087                value_type: Box::new(value_type.union(other_value_type)?),
5088            }),
5089            (
5090                ReprScalarType::Range { element_type },
5091                ReprScalarType::Range {
5092                    element_type: other_element_type,
5093                },
5094            ) => Ok(ReprScalarType::Range {
5095                element_type: Box::new(element_type.union(other_element_type)?),
5096            }),
5097            (_, _) => bail!("Can't union scalar types: {:?} and {:?}", self, scalar_type),
5098        }
5099    }
5100
5101    /// Returns the [`ReprScalarType`] of elements in a [`ReprScalarType::List`].
5102    ///
5103    /// # Panics
5104    ///
5105    /// Panics if called on anything other than a [`ReprScalarType::List`].
5106    pub fn unwrap_list_element_type(&self) -> &ReprScalarType {
5107        match self {
5108            ReprScalarType::List { element_type, .. } => element_type,
5109            _ => panic!(
5110                "ReprScalarType::unwrap_list_element_type called on {:?}",
5111                self
5112            ),
5113        }
5114    }
5115
5116    /// Returns a vector of [`ReprScalarType`] elements in a [`ReprScalarType::Record`].
5117    ///
5118    /// # Panics
5119    ///
5120    /// Panics if called on anything other than a [`ReprScalarType::Record`].
5121    pub fn unwrap_record_element_type(&self) -> Vec<&ReprScalarType> {
5122        match self {
5123            ReprScalarType::Record { fields, .. } => {
5124                fields.iter().map(|t| &t.scalar_type).collect_vec()
5125            }
5126            _ => panic!(
5127                "SqlScalarType::unwrap_record_element_type called on {:?}",
5128                self
5129            ),
5130        }
5131    }
5132}
5133
5134impl From<&SqlScalarType> for ReprScalarType {
5135    fn from(typ: &SqlScalarType) -> Self {
5136        match typ {
5137            SqlScalarType::Bool => ReprScalarType::Bool,
5138            SqlScalarType::Int16 => ReprScalarType::Int16,
5139            SqlScalarType::Int32 => ReprScalarType::Int32,
5140            SqlScalarType::Int64 => ReprScalarType::Int64,
5141            SqlScalarType::UInt16 => ReprScalarType::UInt16,
5142            SqlScalarType::UInt32 => ReprScalarType::UInt32,
5143            SqlScalarType::UInt64 => ReprScalarType::UInt64,
5144            SqlScalarType::Float32 => ReprScalarType::Float32,
5145            SqlScalarType::Float64 => ReprScalarType::Float64,
5146            SqlScalarType::Numeric { max_scale: _ } => ReprScalarType::Numeric,
5147            SqlScalarType::Date => ReprScalarType::Date,
5148            SqlScalarType::Time => ReprScalarType::Time,
5149            SqlScalarType::Timestamp { precision: _ } => ReprScalarType::Timestamp,
5150            SqlScalarType::TimestampTz { precision: _ } => ReprScalarType::TimestampTz,
5151            SqlScalarType::Interval => ReprScalarType::Interval,
5152            SqlScalarType::PgLegacyChar => ReprScalarType::UInt8,
5153            SqlScalarType::PgLegacyName => ReprScalarType::String,
5154            SqlScalarType::Bytes => ReprScalarType::Bytes,
5155            SqlScalarType::String => ReprScalarType::String,
5156            SqlScalarType::Char { length: _ } => ReprScalarType::String,
5157            SqlScalarType::VarChar { max_length: _ } => ReprScalarType::String,
5158            SqlScalarType::Jsonb => ReprScalarType::Jsonb,
5159            SqlScalarType::Uuid => ReprScalarType::Uuid,
5160            SqlScalarType::Array(element_type) => {
5161                ReprScalarType::Array(Box::new(element_type.as_ref().into()))
5162            }
5163            SqlScalarType::List {
5164                element_type,
5165                custom_id: _,
5166            } => ReprScalarType::List {
5167                element_type: Box::new(element_type.as_ref().into()),
5168            },
5169            SqlScalarType::Record {
5170                fields,
5171                custom_id: _,
5172            } => ReprScalarType::Record {
5173                fields: fields.into_iter().map(|(_, typ)| typ.into()).collect(),
5174            },
5175            SqlScalarType::Oid => ReprScalarType::UInt32,
5176            SqlScalarType::Map {
5177                value_type,
5178                custom_id: _,
5179            } => ReprScalarType::Map {
5180                value_type: Box::new(value_type.as_ref().into()),
5181            },
5182            SqlScalarType::RegProc => ReprScalarType::UInt32,
5183            SqlScalarType::RegType => ReprScalarType::UInt32,
5184            SqlScalarType::RegClass => ReprScalarType::UInt32,
5185            SqlScalarType::Int2Vector => ReprScalarType::Int2Vector,
5186            SqlScalarType::MzTimestamp => ReprScalarType::MzTimestamp,
5187            SqlScalarType::Range { element_type } => ReprScalarType::Range {
5188                element_type: Box::new(element_type.as_ref().into()),
5189            },
5190            SqlScalarType::MzAclItem => ReprScalarType::MzAclItem,
5191            SqlScalarType::AclItem => ReprScalarType::AclItem,
5192        }
5193    }
5194}
5195
5196impl SqlScalarType {
5197    /// Lossily translates a [`ReprScalarType`] back to a [`SqlScalarType`].
5198    ///
5199    /// NB that `ReprScalarType::from` is a left inverse of this function, but
5200    /// not a right inverse.
5201    ///
5202    /// Here is an example: `SqlScalarType::VarChar` maps to `ReprScalarType::String`,
5203    /// which maps back to `SqlScalarType::String`.
5204    ///
5205    /// ```
5206    /// use mz_repr::{ReprScalarType, SqlScalarType};
5207    ///
5208    /// let sql = SqlScalarType::VarChar { max_length: None };
5209    /// let repr = ReprScalarType::from(&sql);
5210    /// assert_eq!(repr, ReprScalarType::String);
5211    ///
5212    /// let sql_rt = SqlScalarType::from_repr(&repr);
5213    /// assert_ne!(sql_rt, sql);
5214    /// assert_eq!(sql_rt, SqlScalarType::String);
5215    /// ```
5216    pub fn from_repr(repr: &ReprScalarType) -> Self {
5217        match repr {
5218            ReprScalarType::Bool => SqlScalarType::Bool,
5219            ReprScalarType::Int16 => SqlScalarType::Int16,
5220            ReprScalarType::Int32 => SqlScalarType::Int32,
5221            ReprScalarType::Int64 => SqlScalarType::Int64,
5222            ReprScalarType::UInt8 => SqlScalarType::PgLegacyChar,
5223            ReprScalarType::UInt16 => SqlScalarType::UInt16,
5224            ReprScalarType::UInt32 => SqlScalarType::UInt32,
5225            ReprScalarType::UInt64 => SqlScalarType::UInt64,
5226            ReprScalarType::Float32 => SqlScalarType::Float32,
5227            ReprScalarType::Float64 => SqlScalarType::Float64,
5228            ReprScalarType::Numeric => SqlScalarType::Numeric { max_scale: None },
5229            ReprScalarType::Date => SqlScalarType::Date,
5230            ReprScalarType::Time => SqlScalarType::Time,
5231            ReprScalarType::Timestamp => SqlScalarType::Timestamp { precision: None },
5232            ReprScalarType::TimestampTz => SqlScalarType::TimestampTz { precision: None },
5233            ReprScalarType::MzTimestamp => SqlScalarType::MzTimestamp,
5234            ReprScalarType::Interval => SqlScalarType::Interval,
5235            ReprScalarType::Bytes => SqlScalarType::Bytes,
5236            ReprScalarType::Jsonb => SqlScalarType::Jsonb,
5237            ReprScalarType::String => SqlScalarType::String,
5238            ReprScalarType::Uuid => SqlScalarType::Uuid,
5239            ReprScalarType::Array(element_type) => {
5240                SqlScalarType::Array(Box::new(SqlScalarType::from_repr(element_type)))
5241            }
5242            ReprScalarType::Int2Vector => SqlScalarType::Int2Vector,
5243            ReprScalarType::List { element_type } => SqlScalarType::List {
5244                element_type: Box::new(SqlScalarType::from_repr(element_type)),
5245                custom_id: None,
5246            },
5247            ReprScalarType::Record { fields } => SqlScalarType::Record {
5248                fields: fields
5249                    .iter()
5250                    .enumerate()
5251                    .map(|typ| {
5252                        (
5253                            ColumnName::from(format!("field_{}", typ.0)),
5254                            SqlColumnType::from_repr(typ.1),
5255                        )
5256                    })
5257                    .collect::<Vec<_>>()
5258                    .into_boxed_slice(),
5259                custom_id: None,
5260            },
5261            ReprScalarType::Map { value_type } => SqlScalarType::Map {
5262                value_type: Box::new(SqlScalarType::from_repr(value_type)),
5263                custom_id: None,
5264            },
5265            ReprScalarType::Range { element_type } => SqlScalarType::Range {
5266                element_type: Box::new(SqlScalarType::from_repr(element_type)),
5267            },
5268            ReprScalarType::MzAclItem => SqlScalarType::MzAclItem,
5269            ReprScalarType::AclItem => SqlScalarType::AclItem,
5270        }
5271    }
5272}
5273
5274static EMPTY_ARRAY_ROW: LazyLock<Row> = LazyLock::new(|| {
5275    let mut row = Row::default();
5276    row.packer()
5277        .try_push_array(&[], iter::empty::<Datum>())
5278        .expect("array known to be valid");
5279    row
5280});
5281
5282static EMPTY_LIST_ROW: LazyLock<Row> = LazyLock::new(|| {
5283    let mut row = Row::default();
5284    row.packer().push_list(iter::empty::<Datum>());
5285    row
5286});
5287
5288static EMPTY_MAP_ROW: LazyLock<Row> = LazyLock::new(|| {
5289    let mut row = Row::default();
5290    row.packer().push_dict(iter::empty::<(_, Datum)>());
5291    row
5292});
5293
5294impl Datum<'_> {
5295    pub fn empty_array() -> Datum<'static> {
5296        EMPTY_ARRAY_ROW.unpack_first()
5297    }
5298
5299    pub fn empty_list() -> Datum<'static> {
5300        EMPTY_LIST_ROW.unpack_first()
5301    }
5302
5303    pub fn empty_map() -> Datum<'static> {
5304        EMPTY_MAP_ROW.unpack_first()
5305    }
5306
5307    pub fn contains_dummy(&self) -> bool {
5308        match self {
5309            Datum::Dummy => true,
5310            Datum::List(list) => list.iter().any(|d| d.contains_dummy()),
5311            Datum::Map(map) => map.iter().any(|(_, d)| d.contains_dummy()),
5312            Datum::Array(array) => array.elements().iter().any(|d| d.contains_dummy()),
5313            Datum::Range(range) => range.inner.map_or(false, |range| {
5314                range
5315                    .lower
5316                    .bound
5317                    .map_or(false, |d| d.datum().contains_dummy())
5318                    || range
5319                        .upper
5320                        .bound
5321                        .map_or(false, |d| d.datum().contains_dummy())
5322            }),
5323            _ => false,
5324        }
5325    }
5326}
5327
5328/// A mirror type for [`Datum`] that can be proptest-generated.
5329#[derive(Debug, PartialEq, Clone)]
5330#[cfg(any(test, feature = "proptest"))]
5331pub enum PropDatum {
5332    Null,
5333    Bool(bool),
5334    Int16(i16),
5335    Int32(i32),
5336    Int64(i64),
5337    UInt8(u8),
5338    UInt16(u16),
5339    UInt32(u32),
5340    UInt64(u64),
5341    Float32(f32),
5342    Float64(f64),
5343
5344    Date(Date),
5345    Time(chrono::NaiveTime),
5346    Timestamp(CheckedTimestamp<chrono::NaiveDateTime>),
5347    TimestampTz(CheckedTimestamp<chrono::DateTime<chrono::Utc>>),
5348    MzTimestamp(u64),
5349
5350    Interval(Interval),
5351    Numeric(Numeric),
5352
5353    Bytes(Vec<u8>),
5354    String(String),
5355
5356    Array(PropArray),
5357    List(PropList),
5358    Map(PropDict),
5359    Record(PropDict),
5360    Range(PropRange),
5361
5362    AclItem(AclItem),
5363    MzAclItem(MzAclItem),
5364
5365    JsonNull,
5366    Uuid(Uuid),
5367    Dummy,
5368}
5369
5370#[cfg(any(test, feature = "proptest"))]
5371impl std::cmp::Eq for PropDatum {}
5372
5373#[cfg(any(test, feature = "proptest"))]
5374impl PartialOrd for PropDatum {
5375    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
5376        Some(self.cmp(other))
5377    }
5378}
5379
5380#[cfg(any(test, feature = "proptest"))]
5381impl Ord for PropDatum {
5382    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
5383        Datum::from(self).cmp(&Datum::from(other))
5384    }
5385}
5386
5387/// Generate an arbitrary [`PropDatum`].
5388#[cfg(any(test, feature = "proptest"))]
5389pub fn arb_datum(allow_dummy: bool) -> BoxedStrategy<PropDatum> {
5390    let mut leaf_options = vec![
5391        any::<bool>().prop_map(PropDatum::Bool).boxed(),
5392        any::<i16>().prop_map(PropDatum::Int16).boxed(),
5393        any::<i32>().prop_map(PropDatum::Int32).boxed(),
5394        any::<i64>().prop_map(PropDatum::Int64).boxed(),
5395        any::<u16>().prop_map(PropDatum::UInt16).boxed(),
5396        any::<u32>().prop_map(PropDatum::UInt32).boxed(),
5397        any::<u64>().prop_map(PropDatum::UInt64).boxed(),
5398        any::<f32>().prop_map(PropDatum::Float32).boxed(),
5399        any::<f64>().prop_map(PropDatum::Float64).boxed(),
5400        arb_date().prop_map(PropDatum::Date).boxed(),
5401        add_arb_duration(chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())
5402            .prop_map(PropDatum::Time)
5403            .boxed(),
5404        arb_naive_date_time()
5405            .prop_map(|t| PropDatum::Timestamp(CheckedTimestamp::from_timestamplike(t).unwrap()))
5406            .boxed(),
5407        arb_utc_date_time()
5408            .prop_map(|t| PropDatum::TimestampTz(CheckedTimestamp::from_timestamplike(t).unwrap()))
5409            .boxed(),
5410        any::<Interval>().prop_map(PropDatum::Interval).boxed(),
5411        arb_numeric().prop_map(PropDatum::Numeric).boxed(),
5412        prop::collection::vec(any::<u8>(), 1024)
5413            .prop_map(PropDatum::Bytes)
5414            .boxed(),
5415        ".*".prop_map(PropDatum::String).boxed(),
5416        Just(PropDatum::JsonNull).boxed(),
5417        any::<[u8; 16]>()
5418            .prop_map(|x| PropDatum::Uuid(Uuid::from_bytes(x)))
5419            .boxed(),
5420        arb_range(arb_range_data())
5421            .prop_map(PropDatum::Range)
5422            .boxed(),
5423    ];
5424
5425    if allow_dummy {
5426        leaf_options.push(Just(PropDatum::Dummy).boxed());
5427    }
5428    let leaf = Union::new(leaf_options);
5429
5430    leaf.prop_recursive(3, 8, 16, |inner| {
5431        Union::new(vec![
5432            arb_array(inner.clone()).prop_map(PropDatum::Array).boxed(),
5433            arb_list(inner.clone()).prop_map(PropDatum::List).boxed(),
5434            arb_dict(inner).prop_map(PropDatum::Map).boxed(),
5435        ])
5436    })
5437    .boxed()
5438}
5439
5440/// Generates an arbitrary [`PropDatum`] for the provided [`SqlColumnType`].
5441#[cfg(any(test, feature = "proptest"))]
5442pub fn arb_datum_for_column(column_type: SqlColumnType) -> impl Strategy<Value = PropDatum> {
5443    let strat = arb_datum_for_scalar(column_type.scalar_type);
5444
5445    if column_type.nullable {
5446        Union::new_weighted(vec![(1, Just(PropDatum::Null).boxed()), (5, strat.boxed())]).boxed()
5447    } else {
5448        strat.boxed()
5449    }
5450}
5451
5452/// Generates an arbitrary [`PropDatum`] for the provided [`SqlScalarType`].
5453#[cfg(any(test, feature = "proptest"))]
5454pub fn arb_datum_for_scalar(scalar_type: SqlScalarType) -> impl Strategy<Value = PropDatum> {
5455    match scalar_type {
5456        SqlScalarType::Bool => any::<bool>().prop_map(PropDatum::Bool).boxed(),
5457        SqlScalarType::Int16 => any::<i16>().prop_map(PropDatum::Int16).boxed(),
5458        SqlScalarType::Int32 => any::<i32>().prop_map(PropDatum::Int32).boxed(),
5459        SqlScalarType::Int64 => any::<i64>().prop_map(PropDatum::Int64).boxed(),
5460        SqlScalarType::PgLegacyChar => any::<u8>().prop_map(PropDatum::UInt8).boxed(),
5461        SqlScalarType::UInt16 => any::<u16>().prop_map(PropDatum::UInt16).boxed(),
5462        SqlScalarType::UInt32
5463        | SqlScalarType::Oid
5464        | SqlScalarType::RegClass
5465        | SqlScalarType::RegProc
5466        | SqlScalarType::RegType => any::<u32>().prop_map(PropDatum::UInt32).boxed(),
5467        SqlScalarType::UInt64 => any::<u64>().prop_map(PropDatum::UInt64).boxed(),
5468        SqlScalarType::Float32 => any::<f32>().prop_map(PropDatum::Float32).boxed(),
5469        SqlScalarType::Float64 => any::<f64>().prop_map(PropDatum::Float64).boxed(),
5470        SqlScalarType::Numeric { .. } => arb_numeric().prop_map(PropDatum::Numeric).boxed(),
5471        SqlScalarType::String
5472        | SqlScalarType::PgLegacyName
5473        | SqlScalarType::Char { length: None }
5474        | SqlScalarType::VarChar { max_length: None } => ".*".prop_map(PropDatum::String).boxed(),
5475        SqlScalarType::Char {
5476            length: Some(length),
5477        } => {
5478            let max_len = usize::cast_from(length.into_u32()).max(1);
5479            prop::collection::vec(any::<char>(), 0..max_len)
5480                .prop_map(move |chars| {
5481                    // `Char`s are fixed sized strings padded with blanks.
5482                    let num_blanks = max_len - chars.len();
5483                    let s = chars
5484                        .into_iter()
5485                        .chain(std::iter::repeat(' ').take(num_blanks))
5486                        .collect();
5487                    PropDatum::String(s)
5488                })
5489                .boxed()
5490        }
5491        SqlScalarType::VarChar {
5492            max_length: Some(length),
5493        } => {
5494            let max_len = usize::cast_from(length.into_u32()).max(1);
5495            prop::collection::vec(any::<char>(), 0..max_len)
5496                .prop_map(|chars| PropDatum::String(chars.into_iter().collect()))
5497                .boxed()
5498        }
5499        SqlScalarType::Bytes => prop::collection::vec(any::<u8>(), 300)
5500            .prop_map(PropDatum::Bytes)
5501            .boxed(),
5502        SqlScalarType::Date => arb_date().prop_map(PropDatum::Date).boxed(),
5503        SqlScalarType::Time => add_arb_duration(chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap())
5504            .prop_map(PropDatum::Time)
5505            .boxed(),
5506        SqlScalarType::Timestamp { .. } => arb_naive_date_time()
5507            .prop_map(|t| PropDatum::Timestamp(CheckedTimestamp::from_timestamplike(t).unwrap()))
5508            .boxed(),
5509        SqlScalarType::TimestampTz { .. } => arb_utc_date_time()
5510            .prop_map(|t| PropDatum::TimestampTz(CheckedTimestamp::from_timestamplike(t).unwrap()))
5511            .boxed(),
5512        SqlScalarType::MzTimestamp => any::<u64>().prop_map(PropDatum::MzTimestamp).boxed(),
5513        SqlScalarType::Interval => any::<Interval>().prop_map(PropDatum::Interval).boxed(),
5514        SqlScalarType::Uuid => any::<[u8; 16]>()
5515            .prop_map(|x| PropDatum::Uuid(Uuid::from_bytes(x)))
5516            .boxed(),
5517        SqlScalarType::AclItem => any::<AclItem>().prop_map(PropDatum::AclItem).boxed(),
5518        SqlScalarType::MzAclItem => any::<MzAclItem>().prop_map(PropDatum::MzAclItem).boxed(),
5519        SqlScalarType::Range { element_type } => {
5520            let data_strat = (
5521                arb_datum_for_scalar(*element_type.clone()),
5522                arb_datum_for_scalar(*element_type),
5523            );
5524            arb_range(data_strat).prop_map(PropDatum::Range).boxed()
5525        }
5526        SqlScalarType::List { element_type, .. } => arb_list(arb_datum_for_scalar(*element_type))
5527            .prop_map(PropDatum::List)
5528            .boxed(),
5529        SqlScalarType::Array(element_type) => arb_array(arb_datum_for_scalar(*element_type))
5530            .prop_map(PropDatum::Array)
5531            .boxed(),
5532        SqlScalarType::Int2Vector => {
5533            // `int2vector` is, by definition, a 1-dimensional array of `int2`
5534            // values (matching PostgreSQL's `int2vector` and Materialize's
5535            // `Value::from_datum`, which asserts on multi-dimensional arrays).
5536            // The generic `arb_array` strategy can produce multi-dimensional
5537            // arrays, so we hand-roll a 1-D variant here.
5538            let element_strategy = any::<i16>().prop_map(PropDatum::Int16).boxed();
5539            prop::collection::vec(element_strategy, 0..16)
5540                .prop_map(|elements| {
5541                    let dims = [ArrayDimension {
5542                        lower_bound: 1,
5543                        length: elements.len(),
5544                    }];
5545                    let element_datums: Vec<Datum<'_>> =
5546                        elements.iter().map(|pd| pd.into()).collect();
5547                    let mut row = Row::default();
5548                    row.packer().try_push_array(&dims, element_datums).unwrap();
5549                    PropDatum::Array(PropArray(row, elements))
5550                })
5551                .boxed()
5552        }
5553        SqlScalarType::Map { value_type, .. } => arb_dict(arb_datum_for_scalar(*value_type))
5554            .prop_map(PropDatum::Map)
5555            .boxed(),
5556        SqlScalarType::Record { fields, .. } => {
5557            let field_strats = fields.iter().map(|(name, ty)| {
5558                (
5559                    name.to_string(),
5560                    arb_datum_for_scalar(ty.scalar_type.clone()),
5561                )
5562            });
5563            arb_record(field_strats).prop_map(PropDatum::Record).boxed()
5564        }
5565        SqlScalarType::Jsonb => {
5566            let int_value = any::<i128>()
5567                .prop_map(|v| Numeric::try_from(v).unwrap())
5568                .boxed();
5569            // Numerics only support up to 39 digits.
5570            let float_value = (1e-39f64..1e39)
5571                .prop_map(|v| Numeric::try_from(v).unwrap())
5572                .boxed();
5573            // JSON does not support NaN or Infinite numbers, so we can't use
5574            // the normal `arb_numeric` strategy.
5575            let json_number = Union::new(vec![int_value, float_value]);
5576
5577            let json_leaf = Union::new(vec![
5578                any::<()>().prop_map(|_| PropDatum::JsonNull).boxed(),
5579                any::<bool>().prop_map(PropDatum::Bool).boxed(),
5580                json_number.prop_map(PropDatum::Numeric).boxed(),
5581                ".*".prop_map(PropDatum::String).boxed(),
5582            ]);
5583            json_leaf
5584                .prop_recursive(4, 32, 8, |element| {
5585                    Union::new(vec![
5586                        prop::collection::vec(element.clone(), 0..16)
5587                            .prop_map(|elements| {
5588                                let datums: Vec<_> = elements.iter().map(|pd| pd.into()).collect();
5589                                let mut row = Row::default();
5590                                row.packer().push_list(datums.iter());
5591                                PropDatum::List(PropList(row, elements))
5592                            })
5593                            .boxed(),
5594                        prop::collection::hash_map(".*", element, 0..16)
5595                            .prop_map(|elements| {
5596                                let mut elements: Vec<_> = elements.into_iter().collect();
5597                                elements.sort_by_key(|(k, _)| k.clone());
5598                                elements.dedup_by_key(|(k, _)| k.clone());
5599                                let mut row = Row::default();
5600                                let entry_iter =
5601                                    elements.iter().map(|(k, v)| (k.as_str(), Datum::from(v)));
5602                                row.packer().push_dict(entry_iter);
5603                                PropDatum::Map(PropDict(row, elements))
5604                            })
5605                            .boxed(),
5606                    ])
5607                })
5608                .boxed()
5609        }
5610    }
5611}
5612
5613/// Generates an arbitrary [`NaiveDateTime`].
5614#[cfg(any(test, feature = "proptest"))]
5615pub fn arb_naive_date_time() -> impl Strategy<Value = NaiveDateTime> {
5616    add_arb_duration(chrono::DateTime::from_timestamp(0, 0).unwrap().naive_utc())
5617}
5618
5619/// Generates an arbitrary [`DateTime`] in [`Utc`].
5620#[cfg(any(test, feature = "proptest"))]
5621pub fn arb_utc_date_time() -> impl Strategy<Value = DateTime<Utc>> {
5622    add_arb_duration(chrono::Utc.timestamp_opt(0, 0).unwrap())
5623}
5624
5625#[cfg(any(test, feature = "proptest"))]
5626fn arb_array_dimension() -> BoxedStrategy<ArrayDimension> {
5627    (1..4_usize)
5628        .prop_map(|length| ArrayDimension {
5629            lower_bound: 1,
5630            length,
5631        })
5632        .boxed()
5633}
5634
5635#[derive(Debug, PartialEq, Clone)]
5636#[cfg(any(test, feature = "proptest"))]
5637pub struct PropArray(Row, Vec<PropDatum>);
5638
5639#[cfg(any(test, feature = "proptest"))]
5640fn arb_array(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropArray> {
5641    // Elements in Arrays can always be Null.
5642    let element_strategy = Union::new_weighted(vec![
5643        (20, element_strategy),
5644        (1, Just(PropDatum::Null).boxed()),
5645    ]);
5646
5647    prop::collection::vec(
5648        arb_array_dimension(),
5649        1..usize::from(crate::adt::array::MAX_ARRAY_DIMENSIONS),
5650    )
5651    .prop_flat_map(move |dimensions| {
5652        let n_elts: usize = dimensions.iter().map(|d| d.length).product();
5653        (
5654            Just(dimensions),
5655            prop::collection::vec(element_strategy.clone(), n_elts),
5656        )
5657    })
5658    .prop_map(|(dimensions, elements)| {
5659        let element_datums: Vec<Datum<'_>> = elements.iter().map(|pd| pd.into()).collect();
5660        let mut row = Row::default();
5661        row.packer()
5662            .try_push_array(&dimensions, element_datums)
5663            .unwrap();
5664        PropArray(row, elements)
5665    })
5666    .boxed()
5667}
5668
5669#[derive(Debug, PartialEq, Clone)]
5670#[cfg(any(test, feature = "proptest"))]
5671pub struct PropList(Row, Vec<PropDatum>);
5672
5673#[cfg(any(test, feature = "proptest"))]
5674fn arb_list(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropList> {
5675    // Elements in Lists can always be Null.
5676    let element_strategy = Union::new_weighted(vec![
5677        (20, element_strategy),
5678        (1, Just(PropDatum::Null).boxed()),
5679    ]);
5680
5681    prop::collection::vec(element_strategy, 1..50)
5682        .prop_map(|elements| {
5683            let element_datums: Vec<Datum<'_>> = elements.iter().map(|pd| pd.into()).collect();
5684            let mut row = Row::default();
5685            row.packer().push_list(element_datums.iter());
5686            PropList(row, elements)
5687        })
5688        .boxed()
5689}
5690
5691#[derive(Debug, PartialEq, Clone)]
5692#[cfg(any(test, feature = "proptest"))]
5693pub struct PropRange(
5694    Row,
5695    Option<(
5696        (Option<Box<PropDatum>>, bool),
5697        (Option<Box<PropDatum>>, bool),
5698    )>,
5699);
5700
5701#[cfg(any(test, feature = "proptest"))]
5702pub fn arb_range_type() -> Union<BoxedStrategy<SqlScalarType>> {
5703    Union::new(vec![
5704        Just(SqlScalarType::Int32).boxed(),
5705        Just(SqlScalarType::Int64).boxed(),
5706        Just(SqlScalarType::Date).boxed(),
5707    ])
5708}
5709
5710#[cfg(any(test, feature = "proptest"))]
5711fn arb_range_data() -> Union<BoxedStrategy<(PropDatum, PropDatum)>> {
5712    Union::new(vec![
5713        (
5714            any::<i32>().prop_map(PropDatum::Int32),
5715            any::<i32>().prop_map(PropDatum::Int32),
5716        )
5717            .boxed(),
5718        (
5719            any::<i64>().prop_map(PropDatum::Int64),
5720            any::<i64>().prop_map(PropDatum::Int64),
5721        )
5722            .boxed(),
5723        (
5724            arb_date().prop_map(PropDatum::Date),
5725            arb_date().prop_map(PropDatum::Date),
5726        )
5727            .boxed(),
5728    ])
5729}
5730
5731#[cfg(any(test, feature = "proptest"))]
5732fn arb_range(
5733    data: impl Strategy<Value = (PropDatum, PropDatum)> + 'static,
5734) -> BoxedStrategy<PropRange> {
5735    (
5736        any::<u16>(),
5737        any::<bool>(),
5738        any::<bool>(),
5739        any::<bool>(),
5740        any::<bool>(),
5741        data,
5742    )
5743        .prop_map(
5744            |(split, lower_inf, lower_inc, upper_inf, upper_inc, (a, b))| {
5745                let mut row = Row::default();
5746                let mut packer = row.packer();
5747                let r = if split % 32 == 0 {
5748                    packer
5749                        .push_range(Range::new(None))
5750                        .expect("pushing empty ranges never fails");
5751                    None
5752                } else {
5753                    let b_is_lower = Datum::from(&b) < Datum::from(&a);
5754
5755                    let (lower, upper) = if b_is_lower { (b, a) } else { (a, b) };
5756                    let mut range = Range::new(Some((
5757                        RangeLowerBound {
5758                            inclusive: lower_inc,
5759                            bound: if lower_inf {
5760                                None
5761                            } else {
5762                                Some(Datum::from(&lower))
5763                            },
5764                        },
5765                        RangeUpperBound {
5766                            inclusive: upper_inc,
5767                            bound: if upper_inf {
5768                                None
5769                            } else {
5770                                Some(Datum::from(&upper))
5771                            },
5772                        },
5773                    )));
5774
5775                    range.canonicalize().unwrap();
5776
5777                    // Extract canonicalized state; pretend the range was empty
5778                    // if the bounds are rewritten.
5779                    let (empty, lower_inf, lower_inc, upper_inf, upper_inc) = match range.inner {
5780                        None => (true, false, false, false, false),
5781                        Some(inner) => (
5782                            false
5783                                || match inner.lower.bound {
5784                                    Some(b) => b != Datum::from(&lower),
5785                                    None => !lower_inf,
5786                                }
5787                                || match inner.upper.bound {
5788                                    Some(b) => b != Datum::from(&upper),
5789                                    None => !upper_inf,
5790                                },
5791                            inner.lower.bound.is_none(),
5792                            inner.lower.inclusive,
5793                            inner.upper.bound.is_none(),
5794                            inner.upper.inclusive,
5795                        ),
5796                    };
5797
5798                    if empty {
5799                        packer.push_range(Range { inner: None }).unwrap();
5800                        None
5801                    } else {
5802                        packer.push_range(range).unwrap();
5803                        Some((
5804                            (
5805                                if lower_inf {
5806                                    None
5807                                } else {
5808                                    Some(Box::new(lower))
5809                                },
5810                                lower_inc,
5811                            ),
5812                            (
5813                                if upper_inf {
5814                                    None
5815                                } else {
5816                                    Some(Box::new(upper))
5817                                },
5818                                upper_inc,
5819                            ),
5820                        ))
5821                    }
5822                };
5823
5824                PropRange(row, r)
5825            },
5826        )
5827        .boxed()
5828}
5829
5830#[derive(Debug, PartialEq, Clone)]
5831#[cfg(any(test, feature = "proptest"))]
5832pub struct PropDict(Row, Vec<(String, PropDatum)>);
5833
5834#[cfg(any(test, feature = "proptest"))]
5835fn arb_dict(element_strategy: BoxedStrategy<PropDatum>) -> BoxedStrategy<PropDict> {
5836    // Elements in Maps can always be Null.
5837    let element_strategy = Union::new_weighted(vec![
5838        (20, element_strategy),
5839        (1, Just(PropDatum::Null).boxed()),
5840    ]);
5841
5842    prop::collection::vec((".*", element_strategy), 1..50)
5843        .prop_map(|mut entries| {
5844            entries.sort_by_key(|(k, _)| k.clone());
5845            entries.dedup_by_key(|(k, _)| k.clone());
5846            let mut row = Row::default();
5847            let entry_iter = entries.iter().map(|(k, v)| (k.as_str(), Datum::from(v)));
5848            row.packer().push_dict(entry_iter);
5849            PropDict(row, entries)
5850        })
5851        .boxed()
5852}
5853
5854#[cfg(any(test, feature = "proptest"))]
5855fn arb_record(
5856    fields: impl Iterator<Item = (String, BoxedStrategy<PropDatum>)>,
5857) -> BoxedStrategy<PropDict> {
5858    let (names, strategies): (Vec<_>, Vec<_>) = fields.unzip();
5859
5860    strategies
5861        .prop_map(move |x| {
5862            let mut row = Row::default();
5863            row.packer().push_list(x.iter().map(Datum::from));
5864            let entries: Vec<_> = names.clone().into_iter().zip_eq(x).collect();
5865            PropDict(row, entries)
5866        })
5867        .boxed()
5868}
5869
5870#[cfg(any(test, feature = "proptest"))]
5871fn arb_date() -> BoxedStrategy<Date> {
5872    (Date::LOW_DAYS..Date::HIGH_DAYS)
5873        .prop_map(move |days| Date::from_pg_epoch(days).unwrap())
5874        .boxed()
5875}
5876
5877#[cfg(any(test, feature = "proptest"))]
5878pub fn add_arb_duration<T: 'static + Copy + Add<chrono::Duration> + std::fmt::Debug>(
5879    to: T,
5880) -> BoxedStrategy<T::Output>
5881where
5882    T::Output: std::fmt::Debug,
5883{
5884    let lower = LOW_DATE
5885        .and_hms_opt(0, 0, 0)
5886        .unwrap()
5887        .and_utc()
5888        .timestamp_micros();
5889    let upper = HIGH_DATE
5890        .and_hms_opt(0, 0, 0)
5891        .unwrap()
5892        .and_utc()
5893        .timestamp_micros();
5894    (lower..upper)
5895        .prop_map(move |v| to + chrono::Duration::microseconds(v))
5896        .boxed()
5897}
5898
5899#[cfg(any(test, feature = "proptest"))]
5900pub(crate) fn arb_numeric() -> BoxedStrategy<Numeric> {
5901    let int_value = any::<i128>()
5902        .prop_map(|v| Numeric::try_from(v).unwrap())
5903        .boxed();
5904    let float_value = (-1e39f64..1e39)
5905        .prop_map(|v| Numeric::try_from(v).unwrap())
5906        .boxed();
5907
5908    // While these strategies are subsets of the ones above, including them
5909    // helps us generate a more realistic set of values.
5910    let tiny_floats = ((-10.0..10.0), (1u32..10))
5911        .prop_map(|(v, num_digits)| {
5912            // Truncate to a small number of digits.
5913            let num_digits: f64 = 10u32.pow(num_digits).try_into().unwrap();
5914            let trunc = f64::trunc(v * num_digits) / num_digits;
5915            Numeric::try_from(trunc).unwrap()
5916        })
5917        .boxed();
5918    let small_ints = (-1_000_000..1_000_000)
5919        .prop_map(|v| Numeric::try_from(v).unwrap())
5920        .boxed();
5921    let small_floats = (-1_000_000.0..1_000_000.0)
5922        .prop_map(|v| Numeric::try_from(v).unwrap())
5923        .boxed();
5924
5925    Union::new_weighted(vec![
5926        (20, tiny_floats),
5927        (20, small_ints),
5928        (20, small_floats),
5929        (10, int_value),
5930        (10, float_value),
5931        (1, Just(Numeric::infinity()).boxed()),
5932        (1, Just(-Numeric::infinity()).boxed()),
5933        (1, Just(Numeric::nan()).boxed()),
5934        (1, Just(Numeric::zero()).boxed()),
5935    ])
5936    .boxed()
5937}
5938
5939#[cfg(any(test, feature = "proptest"))]
5940impl<'a> From<&'a PropDatum> for Datum<'a> {
5941    #[inline]
5942    fn from(pd: &'a PropDatum) -> Self {
5943        use PropDatum::*;
5944        match pd {
5945            Null => Datum::Null,
5946            Bool(b) => Datum::from(*b),
5947            Int16(i) => Datum::from(*i),
5948            Int32(i) => Datum::from(*i),
5949            Int64(i) => Datum::from(*i),
5950            UInt8(u) => Datum::from(*u),
5951            UInt16(u) => Datum::from(*u),
5952            UInt32(u) => Datum::from(*u),
5953            UInt64(u) => Datum::from(*u),
5954            Float32(f) => Datum::from(*f),
5955            Float64(f) => Datum::from(*f),
5956            Date(d) => Datum::from(*d),
5957            Time(t) => Datum::from(*t),
5958            Timestamp(t) => Datum::from(*t),
5959            TimestampTz(t) => Datum::from(*t),
5960            MzTimestamp(t) => Datum::MzTimestamp((*t).into()),
5961            Interval(i) => Datum::from(*i),
5962            Numeric(s) => Datum::from(*s),
5963            Bytes(b) => Datum::from(&b[..]),
5964            String(s) => Datum::from(s.as_str()),
5965            Array(PropArray(row, _)) => {
5966                let array = row.unpack_first().unwrap_array();
5967                Datum::Array(array)
5968            }
5969            List(PropList(row, _)) => {
5970                let list = row.unpack_first().unwrap_list();
5971                Datum::List(list)
5972            }
5973            Map(PropDict(row, _)) => {
5974                let map = row.unpack_first().unwrap_map();
5975                Datum::Map(map)
5976            }
5977            Record(PropDict(row, _)) => {
5978                let list = row.unpack_first().unwrap_list();
5979                Datum::List(list)
5980            }
5981            Range(PropRange(row, _)) => {
5982                let d = row.unpack_first();
5983                assert!(matches!(d, Datum::Range(_)));
5984                d
5985            }
5986            AclItem(i) => Datum::AclItem(*i),
5987            MzAclItem(i) => Datum::MzAclItem(*i),
5988            JsonNull => Datum::JsonNull,
5989            Uuid(u) => Datum::from(*u),
5990            Dummy => Datum::Dummy,
5991        }
5992    }
5993}
5994
5995#[mz_ore::test]
5996fn verify_base_eq_record_nullability() {
5997    let s1 = SqlScalarType::Record {
5998        fields: [(
5999            "c".into(),
6000            SqlColumnType {
6001                scalar_type: SqlScalarType::Bool,
6002                nullable: true,
6003            },
6004        )]
6005        .into(),
6006        custom_id: None,
6007    };
6008    let s2 = SqlScalarType::Record {
6009        fields: [(
6010            "c".into(),
6011            SqlColumnType {
6012                scalar_type: SqlScalarType::Bool,
6013                nullable: false,
6014            },
6015        )]
6016        .into(),
6017        custom_id: None,
6018    };
6019    let s3 = SqlScalarType::Record {
6020        fields: [].into(),
6021        custom_id: None,
6022    };
6023    assert!(s1.base_eq(&s2));
6024    assert!(!s1.base_eq(&s3));
6025}
6026
6027#[cfg(test)]
6028mod tests {
6029    use mz_ore::assert_ok;
6030    use mz_proto::protobuf_roundtrip;
6031
6032    use super::*;
6033
6034    proptest! {
6035       #[mz_ore::test]
6036       #[cfg_attr(miri, ignore)] // too slow
6037        fn scalar_type_protobuf_roundtrip(expect in any::<SqlScalarType>() ) {
6038            let actual = protobuf_roundtrip::<_, ProtoScalarType>(&expect);
6039            assert_ok!(actual);
6040            assert_eq!(actual.unwrap(), expect);
6041        }
6042    }
6043
6044    proptest! {
6045        #[mz_ore::test]
6046        #[cfg_attr(miri, ignore)]
6047        fn sql_repr_types_agree_on_valid_data(
6048            (src, datum) in any::<SqlColumnType>()
6049                .prop_flat_map(|src| {
6050                    let datum = arb_datum_for_column(src.clone());
6051                    (Just(src), datum)
6052                }),
6053        ) {
6054            let tgt = ReprColumnType::from(&src);
6055            let datum = Datum::from(&datum);
6056            assert_eq!(
6057                datum.is_instance_of_sql(&src),
6058                datum.is_instance_of(&tgt),
6059                "translated to repr type {tgt:#?}",
6060            );
6061        }
6062    }
6063
6064    proptest! {
6065        // We run many cases because the data are _random_, and we want to be sure
6066        // that we have covered sufficient cases.
6067        #![proptest_config(ProptestConfig::with_cases(10000))]
6068        #[mz_ore::test]
6069        #[cfg_attr(miri, ignore)]
6070        fn sql_repr_types_agree_on_random_data(
6071            src in any::<SqlColumnType>(),
6072            datum in arb_datum(true),
6073        ) {
6074            let tgt = ReprColumnType::from(&src);
6075            let datum = Datum::from(&datum);
6076
6077            assert_eq!(
6078                datum.is_instance_of_sql(&src),
6079                datum.is_instance_of(&tgt),
6080                "translated to repr type {tgt:#?}",
6081            );
6082        }
6083    }
6084
6085    proptest! {
6086        #![proptest_config(ProptestConfig::with_cases(10000))]
6087        #[mz_ore::test]
6088        #[cfg_attr(miri, ignore)]
6089        fn repr_type_to_sql_type_roundtrip(repr_type in any::<ReprScalarType>()) {
6090            // ReprScalarType::from is a left inverse of SqlScalarType::from.
6091            //
6092            // It is _not_ a right inverse, because SqlScalarType::from is lossy.
6093            // For example, many SqlScalarType variants map to ReprScalarType::String.
6094            let sql_type = SqlScalarType::from_repr(&repr_type);
6095            assert_eq!(repr_type, ReprScalarType::from(&sql_type));
6096        }
6097    }
6098
6099    proptest! {
6100        #![proptest_config(ProptestConfig::with_cases(10000))]
6101        #[mz_ore::test]
6102        #[cfg_attr(miri, ignore)]
6103        fn sql_type_base_eq_implies_repr_type_eq(
6104            sql_type1 in any::<SqlScalarType>(),
6105            sql_type2 in any::<SqlScalarType>(),
6106        ) {
6107            let repr_type1 = ReprScalarType::from(&sql_type1);
6108            let repr_type2 = ReprScalarType::from(&sql_type2);
6109            if sql_type1.base_eq(&sql_type2) {
6110                assert_eq!(repr_type1, repr_type2);
6111            }
6112        }
6113    }
6114
6115    proptest! {
6116        #![proptest_config(ProptestConfig::with_cases(10000))]
6117        #[mz_ore::test]
6118        #[cfg_attr(miri, ignore)]
6119        fn repr_type_self_union(repr_type in any::<ReprScalarType>()) {
6120            let union = repr_type.union(&repr_type);
6121            assert_ok!(
6122                union,
6123                "every type should self-union \
6124                 (update ReprScalarType::union to handle this)",
6125            );
6126            assert_eq!(
6127                union.unwrap(), repr_type,
6128                "every type should self-union to itself",
6129            );
6130        }
6131    }
6132
6133    proptest! {
6134        #[mz_ore::test]
6135        #[cfg_attr(miri, ignore)] // can't call foreign function `decContextDefault`
6136        fn array_packing_unpacks_correctly(array in arb_array(arb_datum(true))) {
6137            let PropArray(row, elts) = array;
6138            let datums: Vec<Datum<'_>> = elts.iter().map(|e| e.into()).collect();
6139            let unpacked_datums: Vec<Datum<'_>> = row
6140                .unpack_first().unwrap_array().elements().iter().collect();
6141            assert_eq!(unpacked_datums, datums);
6142        }
6143
6144        #[mz_ore::test]
6145        #[cfg_attr(miri, ignore)] // can't call foreign function `decContextDefault`
6146        fn list_packing_unpacks_correctly(array in arb_list(arb_datum(true))) {
6147            let PropList(row, elts) = array;
6148            let datums: Vec<Datum<'_>> = elts.iter().map(|e| e.into()).collect();
6149            let unpacked_datums: Vec<Datum<'_>> = row
6150                .unpack_first().unwrap_list().iter().collect();
6151            assert_eq!(unpacked_datums, datums);
6152        }
6153
6154        #[mz_ore::test]
6155        #[cfg_attr(miri, ignore)] // too slow
6156        fn dict_packing_unpacks_correctly(array in arb_dict(arb_datum(true))) {
6157            let PropDict(row, elts) = array;
6158            let datums: Vec<(&str, Datum<'_>)> = elts.iter()
6159                .map(|(k, e)| (k.as_str(), e.into())).collect();
6160            let unpacked_datums: Vec<(&str, Datum<'_>)> = row
6161                .unpack_first().unwrap_map().iter().collect();
6162            assert_eq!(unpacked_datums, datums);
6163        }
6164
6165        #[mz_ore::test]
6166        #[cfg_attr(miri, ignore)] // too slow
6167        fn row_packing_roundtrips_single_valued(
6168            prop_datums in prop::collection::vec(arb_datum(true), 1..100),
6169        ) {
6170            let datums: Vec<Datum<'_>> = prop_datums.iter().map(|pd| pd.into()).collect();
6171            let row = Row::pack(&datums);
6172            let unpacked = row.unpack();
6173            assert_eq!(datums, unpacked);
6174        }
6175
6176        #[mz_ore::test]
6177        #[cfg_attr(miri, ignore)] // too slow
6178        fn range_packing_unpacks_correctly(range in arb_range(arb_range_data())) {
6179            let PropRange(row, prop_range) = range;
6180            let row = row.unpack_first();
6181            let d = row.unwrap_range();
6182
6183            let (
6184                ((prop_lower, prop_lower_inc), (prop_upper, prop_upper_inc)),
6185                crate::adt::range::RangeInner { lower, upper },
6186            ) = match (prop_range, d.inner) {
6187                (Some(prop_values), Some(inner_range)) => (prop_values, inner_range),
6188                (None, None) => return Ok(()),
6189                _ => panic!("inequivalent row packing"),
6190            };
6191
6192            for (prop_bound, prop_bound_inc, inner_bound, inner_bound_inc) in [
6193                (prop_lower, prop_lower_inc, lower.bound, lower.inclusive),
6194                (prop_upper, prop_upper_inc, upper.bound, upper.inclusive),
6195            ] {
6196                assert_eq!(prop_bound_inc, inner_bound_inc);
6197                match (prop_bound, inner_bound) {
6198                    (None, None) => continue,
6199                    (Some(p), Some(b)) => {
6200                        assert_eq!(Datum::from(&*p), b);
6201                    }
6202                    _ => panic!("inequivalent row packing"),
6203                }
6204            }
6205        }
6206    }
6207}