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