sqlx_postgres/
type_info.rs

1#![allow(dead_code)]
2
3use std::borrow::Cow;
4use std::fmt::{self, Display, Formatter};
5use std::ops::Deref;
6use std::sync::Arc;
7
8use crate::ext::ustr::UStr;
9use crate::types::Oid;
10
11pub(crate) use sqlx_core::type_info::TypeInfo;
12
13/// Type information for a PostgreSQL type.
14///
15/// ### Note: Implementation of `==` ([`PartialEq::eq()`])
16/// Because `==` on [`TypeInfo`]s has been used throughout the SQLx API as a synonym for type compatibility,
17/// e.g. in the default impl of [`Type::compatible()`][sqlx_core::types::Type::compatible],
18/// some concessions have been made in the implementation.
19///
20/// When comparing two `PgTypeInfo`s using the `==` operator ([`PartialEq::eq()`]),
21/// if one was constructed with [`Self::with_oid()`] and the other with [`Self::with_name()`] or
22/// [`Self::array_of()`], `==` will return `true`:
23///
24/// ```
25/// # use sqlx::postgres::{types::Oid, PgTypeInfo};
26/// // Potentially surprising result, this assert will pass:
27/// assert_eq!(PgTypeInfo::with_oid(Oid(1)), PgTypeInfo::with_name("definitely_not_real"));
28/// ```
29///
30/// Since it is not possible in this case to prove the types are _not_ compatible (because
31/// both `PgTypeInfo`s need to be resolved by an active connection to know for sure)
32/// and type compatibility is mainly done as a sanity check anyway,
33/// it was deemed acceptable to fudge equality in this very specific case.
34///
35/// This also applies when querying with the text protocol (not using prepared statements,
36/// e.g. [`sqlx::raw_sql()`][sqlx_core::raw_sql::raw_sql]), as the connection will be unable
37/// to look up the type info like it normally does when preparing a statement: it won't know
38/// what the OIDs of the output columns will be until it's in the middle of reading the result,
39/// and by that time it's too late.
40///
41/// To compare types for exact equality, use [`Self::type_eq()`] instead.
42#[derive(Debug, Clone, PartialEq)]
43#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
44pub struct PgTypeInfo(pub(crate) PgType);
45
46impl Deref for PgTypeInfo {
47    type Target = PgType;
48
49    fn deref(&self) -> &Self::Target {
50        &self.0
51    }
52}
53
54#[derive(Debug, Clone)]
55#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
56#[repr(u32)]
57pub enum PgType {
58    Bool,
59    Bytea,
60    Char,
61    Name,
62    Int8,
63    Int2,
64    Int4,
65    Text,
66    Oid,
67    Json,
68    JsonArray,
69    Point,
70    Lseg,
71    Path,
72    Box,
73    Polygon,
74    Line,
75    LineArray,
76    Cidr,
77    CidrArray,
78    Float4,
79    Float8,
80    Unknown,
81    Circle,
82    CircleArray,
83    Macaddr8,
84    Macaddr8Array,
85    Macaddr,
86    Inet,
87    BoolArray,
88    ByteaArray,
89    CharArray,
90    NameArray,
91    Int2Array,
92    Int4Array,
93    TextArray,
94    BpcharArray,
95    VarcharArray,
96    Int8Array,
97    PointArray,
98    LsegArray,
99    PathArray,
100    BoxArray,
101    Float4Array,
102    Float8Array,
103    PolygonArray,
104    OidArray,
105    MacaddrArray,
106    InetArray,
107    Bpchar,
108    Varchar,
109    Date,
110    Time,
111    Timestamp,
112    TimestampArray,
113    DateArray,
114    TimeArray,
115    Timestamptz,
116    TimestamptzArray,
117    Interval,
118    IntervalArray,
119    NumericArray,
120    Timetz,
121    TimetzArray,
122    Bit,
123    BitArray,
124    Varbit,
125    VarbitArray,
126    Numeric,
127    Record,
128    RecordArray,
129    Uuid,
130    UuidArray,
131    Jsonb,
132    JsonbArray,
133    Int4Range,
134    Int4RangeArray,
135    NumRange,
136    NumRangeArray,
137    TsRange,
138    TsRangeArray,
139    TstzRange,
140    TstzRangeArray,
141    DateRange,
142    DateRangeArray,
143    Int8Range,
144    Int8RangeArray,
145    Jsonpath,
146    JsonpathArray,
147    Money,
148    MoneyArray,
149
150    // https://www.postgresql.org/docs/9.3/datatype-pseudo.html
151    Void,
152
153    // A realized user-defined type. When a connection sees a DeclareXX variant it resolves
154    // into this one before passing it along to `accepts` or inside of `Value` objects.
155    Custom(Arc<PgCustomType>),
156
157    // From [`PgTypeInfo::with_name`]
158    DeclareWithName(UStr),
159
160    // NOTE: Do we want to bring back type declaration by ID? It's notoriously fragile but
161    //       someone may have a user for it
162    DeclareWithOid(Oid),
163
164    DeclareArrayOf(Arc<PgArrayOf>),
165}
166
167#[derive(Debug, Clone)]
168#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
169pub struct PgCustomType {
170    #[cfg_attr(feature = "offline", serde(skip))]
171    pub(crate) oid: Oid,
172    pub(crate) name: UStr,
173    pub(crate) kind: PgTypeKind,
174}
175
176#[derive(Debug, Clone)]
177#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
178pub enum PgTypeKind {
179    Simple,
180    Pseudo,
181    Domain(PgTypeInfo),
182    Composite(Arc<[(String, PgTypeInfo)]>),
183    Array(PgTypeInfo),
184    Enum(Arc<[String]>),
185    Range(PgTypeInfo),
186}
187
188#[derive(Debug)]
189#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
190pub struct PgArrayOf {
191    pub(crate) elem_name: UStr,
192    pub(crate) name: Box<str>,
193}
194
195impl PgTypeInfo {
196    /// Returns the corresponding `PgTypeInfo` if the OID is a built-in type and recognized by SQLx.
197    pub(crate) fn try_from_oid(oid: Oid) -> Option<Self> {
198        PgType::try_from_oid(oid).map(Self)
199    }
200
201    /// Returns the _kind_ (simple, array, enum, etc.) for this type.
202    pub fn kind(&self) -> &PgTypeKind {
203        self.0.kind()
204    }
205
206    /// Returns the OID for this type, if available.
207    ///
208    /// The OID may not be available if SQLx only knows the type by name.
209    /// It will have to be resolved by a `PgConnection` at runtime which
210    /// will yield a new and semantically distinct `TypeInfo` instance.
211    ///
212    /// This method does not perform any such lookup.
213    ///
214    /// ### Note
215    /// With the exception of [the default `pg_type` catalog][pg_type], type OIDs are *not* stable in PostgreSQL.
216    /// If a type is added by an extension, its OID will be assigned when the `CREATE EXTENSION` statement is executed,
217    /// and so can change depending on what extensions are installed and in what order, as well as the exact
218    /// version of PostgreSQL.
219    ///
220    /// [pg_type]: https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
221    pub fn oid(&self) -> Option<Oid> {
222        self.0.try_oid()
223    }
224
225    #[doc(hidden)]
226    pub fn __type_feature_gate(&self) -> Option<&'static str> {
227        if [
228            PgTypeInfo::DATE,
229            PgTypeInfo::TIME,
230            PgTypeInfo::TIMESTAMP,
231            PgTypeInfo::TIMESTAMPTZ,
232            PgTypeInfo::DATE_ARRAY,
233            PgTypeInfo::TIME_ARRAY,
234            PgTypeInfo::TIMESTAMP_ARRAY,
235            PgTypeInfo::TIMESTAMPTZ_ARRAY,
236        ]
237        .contains(self)
238        {
239            Some("time")
240        } else if [PgTypeInfo::UUID, PgTypeInfo::UUID_ARRAY].contains(self) {
241            Some("uuid")
242        } else if [
243            PgTypeInfo::JSON,
244            PgTypeInfo::JSONB,
245            PgTypeInfo::JSON_ARRAY,
246            PgTypeInfo::JSONB_ARRAY,
247        ]
248        .contains(self)
249        {
250            Some("json")
251        } else if [
252            PgTypeInfo::CIDR,
253            PgTypeInfo::INET,
254            PgTypeInfo::CIDR_ARRAY,
255            PgTypeInfo::INET_ARRAY,
256        ]
257        .contains(self)
258        {
259            Some("ipnetwork")
260        } else if [PgTypeInfo::MACADDR].contains(self) {
261            Some("mac_address")
262        } else if [PgTypeInfo::NUMERIC, PgTypeInfo::NUMERIC_ARRAY].contains(self) {
263            Some("bigdecimal")
264        } else {
265            None
266        }
267    }
268
269    /// Create a `PgTypeInfo` from a type name.
270    ///
271    /// The OID for the type will be fetched from Postgres on use of
272    /// a value of this type. The fetched OID will be cached per-connection.
273    ///
274    /// ### Note: Type Names Prefixed with `_`
275    /// In `pg_catalog.pg_type`, Postgres prefixes a type name with `_` to denote an array of that
276    /// type, e.g. `int4[]` actually exists in `pg_type` as `_int4`.
277    ///
278    /// Previously, it was necessary in manual [`PgHasArrayType`][crate::PgHasArrayType] impls
279    /// to return [`PgTypeInfo::with_name()`] with the type name prefixed with `_` to denote
280    /// an array type, but this would not work with schema-qualified names.
281    ///
282    /// As of 0.8, [`PgTypeInfo::array_of()`] is used to declare an array type,
283    /// and the Postgres driver is now able to properly resolve arrays of custom types,
284    /// even in other schemas, which was not previously supported.
285    ///
286    /// It is highly recommended to migrate existing usages to [`PgTypeInfo::array_of()`] where
287    /// applicable.
288    ///
289    /// However, to maintain compatibility, the driver now infers any type name prefixed with `_`
290    /// to be an array of that type. This may introduce some breakages for types which use
291    /// a `_` prefix but which are not arrays.
292    ///
293    /// As a workaround, type names with `_` as a prefix but which are not arrays should be wrapped
294    /// in quotes, e.g.:
295    /// ```
296    /// use sqlx::postgres::PgTypeInfo;
297    /// use sqlx::{Type, TypeInfo};
298    ///
299    /// /// `CREATE TYPE "_foo" AS ENUM ('Bar', 'Baz');`
300    /// #[derive(sqlx::Type)]
301    /// // Will prevent SQLx from inferring `_foo` as an array type.
302    /// #[sqlx(type_name = r#""_foo""#)]
303    /// enum Foo {
304    ///     Bar,
305    ///     Baz
306    /// }
307    ///
308    /// assert_eq!(Foo::type_info().name(), r#""_foo""#);
309    /// ```
310    pub const fn with_name(name: &'static str) -> Self {
311        Self(PgType::DeclareWithName(UStr::Static(name)))
312    }
313
314    /// Create a `PgTypeInfo` of an array from the name of its element type.
315    ///
316    /// The array type OID will be fetched from Postgres on use of a value of this type.
317    /// The fetched OID will be cached per-connection.
318    pub fn array_of(elem_name: &'static str) -> Self {
319        // to satisfy `name()` and `display_name()`, we need to construct strings to return
320        Self(PgType::DeclareArrayOf(Arc::new(PgArrayOf {
321            elem_name: elem_name.into(),
322            name: format!("{elem_name}[]").into(),
323        })))
324    }
325
326    /// Create a `PgTypeInfo` from an OID.
327    ///
328    /// Note that the OID for a type is very dependent on the environment. If you only ever use
329    /// one database or if this is an unhandled built-in type, you should be fine. Otherwise,
330    /// you will be better served using [`Self::with_name()`].
331    ///
332    /// ### Note: Interaction with `==`
333    /// This constructor may give surprising results with `==`.
334    ///
335    /// See [the type-level docs][Self] for details.
336    pub const fn with_oid(oid: Oid) -> Self {
337        Self(PgType::DeclareWithOid(oid))
338    }
339
340    /// Returns `true` if `self` can be compared exactly to `other`.
341    ///
342    /// Unlike `==`, this will return false if
343    pub fn type_eq(&self, other: &Self) -> bool {
344        self.eq_impl(other, false)
345    }
346}
347
348// DEVELOPER PRO TIP: find builtin type OIDs easily by grepping this file
349// https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
350//
351// If you have Postgres running locally you can also try
352// SELECT oid, typarray FROM pg_type where typname = '<type name>'
353
354impl PgType {
355    /// Returns the corresponding `PgType` if the OID is a built-in type and recognized by SQLx.
356    pub(crate) fn try_from_oid(oid: Oid) -> Option<Self> {
357        Some(match oid.0 {
358            16 => PgType::Bool,
359            17 => PgType::Bytea,
360            18 => PgType::Char,
361            19 => PgType::Name,
362            20 => PgType::Int8,
363            21 => PgType::Int2,
364            23 => PgType::Int4,
365            25 => PgType::Text,
366            26 => PgType::Oid,
367            114 => PgType::Json,
368            199 => PgType::JsonArray,
369            600 => PgType::Point,
370            601 => PgType::Lseg,
371            602 => PgType::Path,
372            603 => PgType::Box,
373            604 => PgType::Polygon,
374            628 => PgType::Line,
375            629 => PgType::LineArray,
376            650 => PgType::Cidr,
377            651 => PgType::CidrArray,
378            700 => PgType::Float4,
379            701 => PgType::Float8,
380            705 => PgType::Unknown,
381            718 => PgType::Circle,
382            719 => PgType::CircleArray,
383            774 => PgType::Macaddr8,
384            775 => PgType::Macaddr8Array,
385            790 => PgType::Money,
386            791 => PgType::MoneyArray,
387            829 => PgType::Macaddr,
388            869 => PgType::Inet,
389            1000 => PgType::BoolArray,
390            1001 => PgType::ByteaArray,
391            1002 => PgType::CharArray,
392            1003 => PgType::NameArray,
393            1005 => PgType::Int2Array,
394            1007 => PgType::Int4Array,
395            1009 => PgType::TextArray,
396            1014 => PgType::BpcharArray,
397            1015 => PgType::VarcharArray,
398            1016 => PgType::Int8Array,
399            1017 => PgType::PointArray,
400            1018 => PgType::LsegArray,
401            1019 => PgType::PathArray,
402            1020 => PgType::BoxArray,
403            1021 => PgType::Float4Array,
404            1022 => PgType::Float8Array,
405            1027 => PgType::PolygonArray,
406            1028 => PgType::OidArray,
407            1040 => PgType::MacaddrArray,
408            1041 => PgType::InetArray,
409            1042 => PgType::Bpchar,
410            1043 => PgType::Varchar,
411            1082 => PgType::Date,
412            1083 => PgType::Time,
413            1114 => PgType::Timestamp,
414            1115 => PgType::TimestampArray,
415            1182 => PgType::DateArray,
416            1183 => PgType::TimeArray,
417            1184 => PgType::Timestamptz,
418            1185 => PgType::TimestamptzArray,
419            1186 => PgType::Interval,
420            1187 => PgType::IntervalArray,
421            1231 => PgType::NumericArray,
422            1266 => PgType::Timetz,
423            1270 => PgType::TimetzArray,
424            1560 => PgType::Bit,
425            1561 => PgType::BitArray,
426            1562 => PgType::Varbit,
427            1563 => PgType::VarbitArray,
428            1700 => PgType::Numeric,
429            2278 => PgType::Void,
430            2249 => PgType::Record,
431            2287 => PgType::RecordArray,
432            2950 => PgType::Uuid,
433            2951 => PgType::UuidArray,
434            3802 => PgType::Jsonb,
435            3807 => PgType::JsonbArray,
436            3904 => PgType::Int4Range,
437            3905 => PgType::Int4RangeArray,
438            3906 => PgType::NumRange,
439            3907 => PgType::NumRangeArray,
440            3908 => PgType::TsRange,
441            3909 => PgType::TsRangeArray,
442            3910 => PgType::TstzRange,
443            3911 => PgType::TstzRangeArray,
444            3912 => PgType::DateRange,
445            3913 => PgType::DateRangeArray,
446            3926 => PgType::Int8Range,
447            3927 => PgType::Int8RangeArray,
448            4072 => PgType::Jsonpath,
449            4073 => PgType::JsonpathArray,
450
451            _ => {
452                return None;
453            }
454        })
455    }
456
457    pub(crate) fn oid(&self) -> Oid {
458        match self.try_oid() {
459            Some(oid) => oid,
460            None => unreachable!("(bug) use of unresolved type declaration [oid]"),
461        }
462    }
463
464    pub(crate) fn try_oid(&self) -> Option<Oid> {
465        Some(match self {
466            PgType::Bool => Oid(16),
467            PgType::Bytea => Oid(17),
468            PgType::Char => Oid(18),
469            PgType::Name => Oid(19),
470            PgType::Int8 => Oid(20),
471            PgType::Int2 => Oid(21),
472            PgType::Int4 => Oid(23),
473            PgType::Text => Oid(25),
474            PgType::Oid => Oid(26),
475            PgType::Json => Oid(114),
476            PgType::JsonArray => Oid(199),
477            PgType::Point => Oid(600),
478            PgType::Lseg => Oid(601),
479            PgType::Path => Oid(602),
480            PgType::Box => Oid(603),
481            PgType::Polygon => Oid(604),
482            PgType::Line => Oid(628),
483            PgType::LineArray => Oid(629),
484            PgType::Cidr => Oid(650),
485            PgType::CidrArray => Oid(651),
486            PgType::Float4 => Oid(700),
487            PgType::Float8 => Oid(701),
488            PgType::Unknown => Oid(705),
489            PgType::Circle => Oid(718),
490            PgType::CircleArray => Oid(719),
491            PgType::Macaddr8 => Oid(774),
492            PgType::Macaddr8Array => Oid(775),
493            PgType::Money => Oid(790),
494            PgType::MoneyArray => Oid(791),
495            PgType::Macaddr => Oid(829),
496            PgType::Inet => Oid(869),
497            PgType::BoolArray => Oid(1000),
498            PgType::ByteaArray => Oid(1001),
499            PgType::CharArray => Oid(1002),
500            PgType::NameArray => Oid(1003),
501            PgType::Int2Array => Oid(1005),
502            PgType::Int4Array => Oid(1007),
503            PgType::TextArray => Oid(1009),
504            PgType::BpcharArray => Oid(1014),
505            PgType::VarcharArray => Oid(1015),
506            PgType::Int8Array => Oid(1016),
507            PgType::PointArray => Oid(1017),
508            PgType::LsegArray => Oid(1018),
509            PgType::PathArray => Oid(1019),
510            PgType::BoxArray => Oid(1020),
511            PgType::Float4Array => Oid(1021),
512            PgType::Float8Array => Oid(1022),
513            PgType::PolygonArray => Oid(1027),
514            PgType::OidArray => Oid(1028),
515            PgType::MacaddrArray => Oid(1040),
516            PgType::InetArray => Oid(1041),
517            PgType::Bpchar => Oid(1042),
518            PgType::Varchar => Oid(1043),
519            PgType::Date => Oid(1082),
520            PgType::Time => Oid(1083),
521            PgType::Timestamp => Oid(1114),
522            PgType::TimestampArray => Oid(1115),
523            PgType::DateArray => Oid(1182),
524            PgType::TimeArray => Oid(1183),
525            PgType::Timestamptz => Oid(1184),
526            PgType::TimestamptzArray => Oid(1185),
527            PgType::Interval => Oid(1186),
528            PgType::IntervalArray => Oid(1187),
529            PgType::NumericArray => Oid(1231),
530            PgType::Timetz => Oid(1266),
531            PgType::TimetzArray => Oid(1270),
532            PgType::Bit => Oid(1560),
533            PgType::BitArray => Oid(1561),
534            PgType::Varbit => Oid(1562),
535            PgType::VarbitArray => Oid(1563),
536            PgType::Numeric => Oid(1700),
537            PgType::Void => Oid(2278),
538            PgType::Record => Oid(2249),
539            PgType::RecordArray => Oid(2287),
540            PgType::Uuid => Oid(2950),
541            PgType::UuidArray => Oid(2951),
542            PgType::Jsonb => Oid(3802),
543            PgType::JsonbArray => Oid(3807),
544            PgType::Int4Range => Oid(3904),
545            PgType::Int4RangeArray => Oid(3905),
546            PgType::NumRange => Oid(3906),
547            PgType::NumRangeArray => Oid(3907),
548            PgType::TsRange => Oid(3908),
549            PgType::TsRangeArray => Oid(3909),
550            PgType::TstzRange => Oid(3910),
551            PgType::TstzRangeArray => Oid(3911),
552            PgType::DateRange => Oid(3912),
553            PgType::DateRangeArray => Oid(3913),
554            PgType::Int8Range => Oid(3926),
555            PgType::Int8RangeArray => Oid(3927),
556            PgType::Jsonpath => Oid(4072),
557            PgType::JsonpathArray => Oid(4073),
558
559            PgType::Custom(ty) => ty.oid,
560
561            PgType::DeclareWithOid(oid) => *oid,
562            PgType::DeclareWithName(_) => {
563                return None;
564            }
565            PgType::DeclareArrayOf(_) => {
566                return None;
567            }
568        })
569    }
570
571    pub(crate) fn display_name(&self) -> &str {
572        match self {
573            PgType::Bool => "BOOL",
574            PgType::Bytea => "BYTEA",
575            PgType::Char => "\"CHAR\"",
576            PgType::Name => "NAME",
577            PgType::Int8 => "INT8",
578            PgType::Int2 => "INT2",
579            PgType::Int4 => "INT4",
580            PgType::Text => "TEXT",
581            PgType::Oid => "OID",
582            PgType::Json => "JSON",
583            PgType::JsonArray => "JSON[]",
584            PgType::Point => "POINT",
585            PgType::Lseg => "LSEG",
586            PgType::Path => "PATH",
587            PgType::Box => "BOX",
588            PgType::Polygon => "POLYGON",
589            PgType::Line => "LINE",
590            PgType::LineArray => "LINE[]",
591            PgType::Cidr => "CIDR",
592            PgType::CidrArray => "CIDR[]",
593            PgType::Float4 => "FLOAT4",
594            PgType::Float8 => "FLOAT8",
595            PgType::Unknown => "UNKNOWN",
596            PgType::Circle => "CIRCLE",
597            PgType::CircleArray => "CIRCLE[]",
598            PgType::Macaddr8 => "MACADDR8",
599            PgType::Macaddr8Array => "MACADDR8[]",
600            PgType::Macaddr => "MACADDR",
601            PgType::Inet => "INET",
602            PgType::BoolArray => "BOOL[]",
603            PgType::ByteaArray => "BYTEA[]",
604            PgType::CharArray => "\"CHAR\"[]",
605            PgType::NameArray => "NAME[]",
606            PgType::Int2Array => "INT2[]",
607            PgType::Int4Array => "INT4[]",
608            PgType::TextArray => "TEXT[]",
609            PgType::BpcharArray => "CHAR[]",
610            PgType::VarcharArray => "VARCHAR[]",
611            PgType::Int8Array => "INT8[]",
612            PgType::PointArray => "POINT[]",
613            PgType::LsegArray => "LSEG[]",
614            PgType::PathArray => "PATH[]",
615            PgType::BoxArray => "BOX[]",
616            PgType::Float4Array => "FLOAT4[]",
617            PgType::Float8Array => "FLOAT8[]",
618            PgType::PolygonArray => "POLYGON[]",
619            PgType::OidArray => "OID[]",
620            PgType::MacaddrArray => "MACADDR[]",
621            PgType::InetArray => "INET[]",
622            PgType::Bpchar => "CHAR",
623            PgType::Varchar => "VARCHAR",
624            PgType::Date => "DATE",
625            PgType::Time => "TIME",
626            PgType::Timestamp => "TIMESTAMP",
627            PgType::TimestampArray => "TIMESTAMP[]",
628            PgType::DateArray => "DATE[]",
629            PgType::TimeArray => "TIME[]",
630            PgType::Timestamptz => "TIMESTAMPTZ",
631            PgType::TimestamptzArray => "TIMESTAMPTZ[]",
632            PgType::Interval => "INTERVAL",
633            PgType::IntervalArray => "INTERVAL[]",
634            PgType::NumericArray => "NUMERIC[]",
635            PgType::Timetz => "TIMETZ",
636            PgType::TimetzArray => "TIMETZ[]",
637            PgType::Bit => "BIT",
638            PgType::BitArray => "BIT[]",
639            PgType::Varbit => "VARBIT",
640            PgType::VarbitArray => "VARBIT[]",
641            PgType::Numeric => "NUMERIC",
642            PgType::Record => "RECORD",
643            PgType::RecordArray => "RECORD[]",
644            PgType::Uuid => "UUID",
645            PgType::UuidArray => "UUID[]",
646            PgType::Jsonb => "JSONB",
647            PgType::JsonbArray => "JSONB[]",
648            PgType::Int4Range => "INT4RANGE",
649            PgType::Int4RangeArray => "INT4RANGE[]",
650            PgType::NumRange => "NUMRANGE",
651            PgType::NumRangeArray => "NUMRANGE[]",
652            PgType::TsRange => "TSRANGE",
653            PgType::TsRangeArray => "TSRANGE[]",
654            PgType::TstzRange => "TSTZRANGE",
655            PgType::TstzRangeArray => "TSTZRANGE[]",
656            PgType::DateRange => "DATERANGE",
657            PgType::DateRangeArray => "DATERANGE[]",
658            PgType::Int8Range => "INT8RANGE",
659            PgType::Int8RangeArray => "INT8RANGE[]",
660            PgType::Jsonpath => "JSONPATH",
661            PgType::JsonpathArray => "JSONPATH[]",
662            PgType::Money => "MONEY",
663            PgType::MoneyArray => "MONEY[]",
664            PgType::Void => "VOID",
665            PgType::Custom(ty) => &ty.name,
666            PgType::DeclareWithOid(_) => "?",
667            PgType::DeclareWithName(name) => name,
668            PgType::DeclareArrayOf(array) => &array.name,
669        }
670    }
671
672    pub(crate) fn name(&self) -> &str {
673        match self {
674            PgType::Bool => "bool",
675            PgType::Bytea => "bytea",
676            PgType::Char => "char",
677            PgType::Name => "name",
678            PgType::Int8 => "int8",
679            PgType::Int2 => "int2",
680            PgType::Int4 => "int4",
681            PgType::Text => "text",
682            PgType::Oid => "oid",
683            PgType::Json => "json",
684            PgType::JsonArray => "_json",
685            PgType::Point => "point",
686            PgType::Lseg => "lseg",
687            PgType::Path => "path",
688            PgType::Box => "box",
689            PgType::Polygon => "polygon",
690            PgType::Line => "line",
691            PgType::LineArray => "_line",
692            PgType::Cidr => "cidr",
693            PgType::CidrArray => "_cidr",
694            PgType::Float4 => "float4",
695            PgType::Float8 => "float8",
696            PgType::Unknown => "unknown",
697            PgType::Circle => "circle",
698            PgType::CircleArray => "_circle",
699            PgType::Macaddr8 => "macaddr8",
700            PgType::Macaddr8Array => "_macaddr8",
701            PgType::Macaddr => "macaddr",
702            PgType::Inet => "inet",
703            PgType::BoolArray => "_bool",
704            PgType::ByteaArray => "_bytea",
705            PgType::CharArray => "_char",
706            PgType::NameArray => "_name",
707            PgType::Int2Array => "_int2",
708            PgType::Int4Array => "_int4",
709            PgType::TextArray => "_text",
710            PgType::BpcharArray => "_bpchar",
711            PgType::VarcharArray => "_varchar",
712            PgType::Int8Array => "_int8",
713            PgType::PointArray => "_point",
714            PgType::LsegArray => "_lseg",
715            PgType::PathArray => "_path",
716            PgType::BoxArray => "_box",
717            PgType::Float4Array => "_float4",
718            PgType::Float8Array => "_float8",
719            PgType::PolygonArray => "_polygon",
720            PgType::OidArray => "_oid",
721            PgType::MacaddrArray => "_macaddr",
722            PgType::InetArray => "_inet",
723            PgType::Bpchar => "bpchar",
724            PgType::Varchar => "varchar",
725            PgType::Date => "date",
726            PgType::Time => "time",
727            PgType::Timestamp => "timestamp",
728            PgType::TimestampArray => "_timestamp",
729            PgType::DateArray => "_date",
730            PgType::TimeArray => "_time",
731            PgType::Timestamptz => "timestamptz",
732            PgType::TimestamptzArray => "_timestamptz",
733            PgType::Interval => "interval",
734            PgType::IntervalArray => "_interval",
735            PgType::NumericArray => "_numeric",
736            PgType::Timetz => "timetz",
737            PgType::TimetzArray => "_timetz",
738            PgType::Bit => "bit",
739            PgType::BitArray => "_bit",
740            PgType::Varbit => "varbit",
741            PgType::VarbitArray => "_varbit",
742            PgType::Numeric => "numeric",
743            PgType::Record => "record",
744            PgType::RecordArray => "_record",
745            PgType::Uuid => "uuid",
746            PgType::UuidArray => "_uuid",
747            PgType::Jsonb => "jsonb",
748            PgType::JsonbArray => "_jsonb",
749            PgType::Int4Range => "int4range",
750            PgType::Int4RangeArray => "_int4range",
751            PgType::NumRange => "numrange",
752            PgType::NumRangeArray => "_numrange",
753            PgType::TsRange => "tsrange",
754            PgType::TsRangeArray => "_tsrange",
755            PgType::TstzRange => "tstzrange",
756            PgType::TstzRangeArray => "_tstzrange",
757            PgType::DateRange => "daterange",
758            PgType::DateRangeArray => "_daterange",
759            PgType::Int8Range => "int8range",
760            PgType::Int8RangeArray => "_int8range",
761            PgType::Jsonpath => "jsonpath",
762            PgType::JsonpathArray => "_jsonpath",
763            PgType::Money => "money",
764            PgType::MoneyArray => "_money",
765            PgType::Void => "void",
766            PgType::Custom(ty) => &ty.name,
767            PgType::DeclareWithOid(_) => "?",
768            PgType::DeclareWithName(name) => name,
769            PgType::DeclareArrayOf(array) => &array.name,
770        }
771    }
772
773    pub(crate) fn kind(&self) -> &PgTypeKind {
774        match self {
775            PgType::Bool => &PgTypeKind::Simple,
776            PgType::Bytea => &PgTypeKind::Simple,
777            PgType::Char => &PgTypeKind::Simple,
778            PgType::Name => &PgTypeKind::Simple,
779            PgType::Int8 => &PgTypeKind::Simple,
780            PgType::Int2 => &PgTypeKind::Simple,
781            PgType::Int4 => &PgTypeKind::Simple,
782            PgType::Text => &PgTypeKind::Simple,
783            PgType::Oid => &PgTypeKind::Simple,
784            PgType::Json => &PgTypeKind::Simple,
785            PgType::JsonArray => &PgTypeKind::Array(PgTypeInfo(PgType::Json)),
786            PgType::Point => &PgTypeKind::Simple,
787            PgType::Lseg => &PgTypeKind::Simple,
788            PgType::Path => &PgTypeKind::Simple,
789            PgType::Box => &PgTypeKind::Simple,
790            PgType::Polygon => &PgTypeKind::Simple,
791            PgType::Line => &PgTypeKind::Simple,
792            PgType::LineArray => &PgTypeKind::Array(PgTypeInfo(PgType::Line)),
793            PgType::Cidr => &PgTypeKind::Simple,
794            PgType::CidrArray => &PgTypeKind::Array(PgTypeInfo(PgType::Cidr)),
795            PgType::Float4 => &PgTypeKind::Simple,
796            PgType::Float8 => &PgTypeKind::Simple,
797            PgType::Unknown => &PgTypeKind::Simple,
798            PgType::Circle => &PgTypeKind::Simple,
799            PgType::CircleArray => &PgTypeKind::Array(PgTypeInfo(PgType::Circle)),
800            PgType::Macaddr8 => &PgTypeKind::Simple,
801            PgType::Macaddr8Array => &PgTypeKind::Array(PgTypeInfo(PgType::Macaddr8)),
802            PgType::Macaddr => &PgTypeKind::Simple,
803            PgType::Inet => &PgTypeKind::Simple,
804            PgType::BoolArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bool)),
805            PgType::ByteaArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bytea)),
806            PgType::CharArray => &PgTypeKind::Array(PgTypeInfo(PgType::Char)),
807            PgType::NameArray => &PgTypeKind::Array(PgTypeInfo(PgType::Name)),
808            PgType::Int2Array => &PgTypeKind::Array(PgTypeInfo(PgType::Int2)),
809            PgType::Int4Array => &PgTypeKind::Array(PgTypeInfo(PgType::Int4)),
810            PgType::TextArray => &PgTypeKind::Array(PgTypeInfo(PgType::Text)),
811            PgType::BpcharArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bpchar)),
812            PgType::VarcharArray => &PgTypeKind::Array(PgTypeInfo(PgType::Varchar)),
813            PgType::Int8Array => &PgTypeKind::Array(PgTypeInfo(PgType::Int8)),
814            PgType::PointArray => &PgTypeKind::Array(PgTypeInfo(PgType::Point)),
815            PgType::LsegArray => &PgTypeKind::Array(PgTypeInfo(PgType::Lseg)),
816            PgType::PathArray => &PgTypeKind::Array(PgTypeInfo(PgType::Path)),
817            PgType::BoxArray => &PgTypeKind::Array(PgTypeInfo(PgType::Box)),
818            PgType::Float4Array => &PgTypeKind::Array(PgTypeInfo(PgType::Float4)),
819            PgType::Float8Array => &PgTypeKind::Array(PgTypeInfo(PgType::Float8)),
820            PgType::PolygonArray => &PgTypeKind::Array(PgTypeInfo(PgType::Polygon)),
821            PgType::OidArray => &PgTypeKind::Array(PgTypeInfo(PgType::Oid)),
822            PgType::MacaddrArray => &PgTypeKind::Array(PgTypeInfo(PgType::Macaddr)),
823            PgType::InetArray => &PgTypeKind::Array(PgTypeInfo(PgType::Inet)),
824            PgType::Bpchar => &PgTypeKind::Simple,
825            PgType::Varchar => &PgTypeKind::Simple,
826            PgType::Date => &PgTypeKind::Simple,
827            PgType::Time => &PgTypeKind::Simple,
828            PgType::Timestamp => &PgTypeKind::Simple,
829            PgType::TimestampArray => &PgTypeKind::Array(PgTypeInfo(PgType::Timestamp)),
830            PgType::DateArray => &PgTypeKind::Array(PgTypeInfo(PgType::Date)),
831            PgType::TimeArray => &PgTypeKind::Array(PgTypeInfo(PgType::Time)),
832            PgType::Timestamptz => &PgTypeKind::Simple,
833            PgType::TimestamptzArray => &PgTypeKind::Array(PgTypeInfo(PgType::Timestamptz)),
834            PgType::Interval => &PgTypeKind::Simple,
835            PgType::IntervalArray => &PgTypeKind::Array(PgTypeInfo(PgType::Interval)),
836            PgType::NumericArray => &PgTypeKind::Array(PgTypeInfo(PgType::Numeric)),
837            PgType::Timetz => &PgTypeKind::Simple,
838            PgType::TimetzArray => &PgTypeKind::Array(PgTypeInfo(PgType::Timetz)),
839            PgType::Bit => &PgTypeKind::Simple,
840            PgType::BitArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bit)),
841            PgType::Varbit => &PgTypeKind::Simple,
842            PgType::VarbitArray => &PgTypeKind::Array(PgTypeInfo(PgType::Varbit)),
843            PgType::Numeric => &PgTypeKind::Simple,
844            PgType::Record => &PgTypeKind::Simple,
845            PgType::RecordArray => &PgTypeKind::Array(PgTypeInfo(PgType::Record)),
846            PgType::Uuid => &PgTypeKind::Simple,
847            PgType::UuidArray => &PgTypeKind::Array(PgTypeInfo(PgType::Uuid)),
848            PgType::Jsonb => &PgTypeKind::Simple,
849            PgType::JsonbArray => &PgTypeKind::Array(PgTypeInfo(PgType::Jsonb)),
850            PgType::Int4Range => &PgTypeKind::Range(PgTypeInfo::INT4),
851            PgType::Int4RangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::Int4Range)),
852            PgType::NumRange => &PgTypeKind::Range(PgTypeInfo::NUMERIC),
853            PgType::NumRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::NumRange)),
854            PgType::TsRange => &PgTypeKind::Range(PgTypeInfo::TIMESTAMP),
855            PgType::TsRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::TsRange)),
856            PgType::TstzRange => &PgTypeKind::Range(PgTypeInfo::TIMESTAMPTZ),
857            PgType::TstzRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::TstzRange)),
858            PgType::DateRange => &PgTypeKind::Range(PgTypeInfo::DATE),
859            PgType::DateRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::DateRange)),
860            PgType::Int8Range => &PgTypeKind::Range(PgTypeInfo::INT8),
861            PgType::Int8RangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::Int8Range)),
862            PgType::Jsonpath => &PgTypeKind::Simple,
863            PgType::JsonpathArray => &PgTypeKind::Array(PgTypeInfo(PgType::Jsonpath)),
864            PgType::Money => &PgTypeKind::Simple,
865            PgType::MoneyArray => &PgTypeKind::Array(PgTypeInfo(PgType::Money)),
866
867            PgType::Void => &PgTypeKind::Pseudo,
868
869            PgType::Custom(ty) => &ty.kind,
870
871            PgType::DeclareWithOid(oid) => {
872                unreachable!("(bug) use of unresolved type declaration [oid={}]", oid.0);
873            }
874            PgType::DeclareWithName(name) => {
875                unreachable!("(bug) use of unresolved type declaration [name={name}]");
876            }
877            PgType::DeclareArrayOf(array) => {
878                unreachable!(
879                    "(bug) use of unresolved type declaration [array of={}]",
880                    array.elem_name
881                );
882            }
883        }
884    }
885
886    /// If `self` is an array type, return the type info for its element.
887    pub(crate) fn try_array_element(&self) -> Option<Cow<'_, PgTypeInfo>> {
888        // We explicitly match on all the `None` cases to ensure an exhaustive match.
889        match self {
890            PgType::Bool => None,
891            PgType::BoolArray => Some(Cow::Owned(PgTypeInfo(PgType::Bool))),
892            PgType::Bytea => None,
893            PgType::ByteaArray => Some(Cow::Owned(PgTypeInfo(PgType::Bytea))),
894            PgType::Char => None,
895            PgType::CharArray => Some(Cow::Owned(PgTypeInfo(PgType::Char))),
896            PgType::Name => None,
897            PgType::NameArray => Some(Cow::Owned(PgTypeInfo(PgType::Name))),
898            PgType::Int8 => None,
899            PgType::Int8Array => Some(Cow::Owned(PgTypeInfo(PgType::Int8))),
900            PgType::Int2 => None,
901            PgType::Int2Array => Some(Cow::Owned(PgTypeInfo(PgType::Int2))),
902            PgType::Int4 => None,
903            PgType::Int4Array => Some(Cow::Owned(PgTypeInfo(PgType::Int4))),
904            PgType::Text => None,
905            PgType::TextArray => Some(Cow::Owned(PgTypeInfo(PgType::Text))),
906            PgType::Oid => None,
907            PgType::OidArray => Some(Cow::Owned(PgTypeInfo(PgType::Oid))),
908            PgType::Json => None,
909            PgType::JsonArray => Some(Cow::Owned(PgTypeInfo(PgType::Json))),
910            PgType::Point => None,
911            PgType::PointArray => Some(Cow::Owned(PgTypeInfo(PgType::Point))),
912            PgType::Lseg => None,
913            PgType::LsegArray => Some(Cow::Owned(PgTypeInfo(PgType::Lseg))),
914            PgType::Path => None,
915            PgType::PathArray => Some(Cow::Owned(PgTypeInfo(PgType::Path))),
916            PgType::Box => None,
917            PgType::BoxArray => Some(Cow::Owned(PgTypeInfo(PgType::Box))),
918            PgType::Polygon => None,
919            PgType::PolygonArray => Some(Cow::Owned(PgTypeInfo(PgType::Polygon))),
920            PgType::Line => None,
921            PgType::LineArray => Some(Cow::Owned(PgTypeInfo(PgType::Line))),
922            PgType::Cidr => None,
923            PgType::CidrArray => Some(Cow::Owned(PgTypeInfo(PgType::Cidr))),
924            PgType::Float4 => None,
925            PgType::Float4Array => Some(Cow::Owned(PgTypeInfo(PgType::Float4))),
926            PgType::Float8 => None,
927            PgType::Float8Array => Some(Cow::Owned(PgTypeInfo(PgType::Float8))),
928            PgType::Circle => None,
929            PgType::CircleArray => Some(Cow::Owned(PgTypeInfo(PgType::Circle))),
930            PgType::Macaddr8 => None,
931            PgType::Macaddr8Array => Some(Cow::Owned(PgTypeInfo(PgType::Macaddr8))),
932            PgType::Money => None,
933            PgType::MoneyArray => Some(Cow::Owned(PgTypeInfo(PgType::Money))),
934            PgType::Macaddr => None,
935            PgType::MacaddrArray => Some(Cow::Owned(PgTypeInfo(PgType::Macaddr))),
936            PgType::Inet => None,
937            PgType::InetArray => Some(Cow::Owned(PgTypeInfo(PgType::Inet))),
938            PgType::Bpchar => None,
939            PgType::BpcharArray => Some(Cow::Owned(PgTypeInfo(PgType::Bpchar))),
940            PgType::Varchar => None,
941            PgType::VarcharArray => Some(Cow::Owned(PgTypeInfo(PgType::Varchar))),
942            PgType::Date => None,
943            PgType::DateArray => Some(Cow::Owned(PgTypeInfo(PgType::Date))),
944            PgType::Time => None,
945            PgType::TimeArray => Some(Cow::Owned(PgTypeInfo(PgType::Time))),
946            PgType::Timestamp => None,
947            PgType::TimestampArray => Some(Cow::Owned(PgTypeInfo(PgType::Timestamp))),
948            PgType::Timestamptz => None,
949            PgType::TimestamptzArray => Some(Cow::Owned(PgTypeInfo(PgType::Timestamptz))),
950            PgType::Interval => None,
951            PgType::IntervalArray => Some(Cow::Owned(PgTypeInfo(PgType::Interval))),
952            PgType::Timetz => None,
953            PgType::TimetzArray => Some(Cow::Owned(PgTypeInfo(PgType::Timetz))),
954            PgType::Bit => None,
955            PgType::BitArray => Some(Cow::Owned(PgTypeInfo(PgType::Bit))),
956            PgType::Varbit => None,
957            PgType::VarbitArray => Some(Cow::Owned(PgTypeInfo(PgType::Varbit))),
958            PgType::Numeric => None,
959            PgType::NumericArray => Some(Cow::Owned(PgTypeInfo(PgType::Numeric))),
960            PgType::Record => None,
961            PgType::RecordArray => Some(Cow::Owned(PgTypeInfo(PgType::Record))),
962            PgType::Uuid => None,
963            PgType::UuidArray => Some(Cow::Owned(PgTypeInfo(PgType::Uuid))),
964            PgType::Jsonb => None,
965            PgType::JsonbArray => Some(Cow::Owned(PgTypeInfo(PgType::Jsonb))),
966            PgType::Int4Range => None,
967            PgType::Int4RangeArray => Some(Cow::Owned(PgTypeInfo(PgType::Int4Range))),
968            PgType::NumRange => None,
969            PgType::NumRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::NumRange))),
970            PgType::TsRange => None,
971            PgType::TsRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::TsRange))),
972            PgType::TstzRange => None,
973            PgType::TstzRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::TstzRange))),
974            PgType::DateRange => None,
975            PgType::DateRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::DateRange))),
976            PgType::Int8Range => None,
977            PgType::Int8RangeArray => Some(Cow::Owned(PgTypeInfo(PgType::Int8Range))),
978            PgType::Jsonpath => None,
979            PgType::JsonpathArray => Some(Cow::Owned(PgTypeInfo(PgType::Jsonpath))),
980            // There is no `UnknownArray`
981            PgType::Unknown => None,
982            // There is no `VoidArray`
983            PgType::Void => None,
984
985            PgType::Custom(ty) => match &ty.kind {
986                PgTypeKind::Simple => None,
987                PgTypeKind::Pseudo => None,
988                PgTypeKind::Domain(_) => None,
989                PgTypeKind::Composite(_) => None,
990                PgTypeKind::Array(ref elem_type_info) => Some(Cow::Borrowed(elem_type_info)),
991                PgTypeKind::Enum(_) => None,
992                PgTypeKind::Range(_) => None,
993            },
994            PgType::DeclareWithOid(_) => None,
995            PgType::DeclareWithName(name) => {
996                // LEGACY: infer the array element name from a `_` prefix
997                UStr::strip_prefix(name, "_")
998                    .map(|elem| Cow::Owned(PgTypeInfo(PgType::DeclareWithName(elem))))
999            }
1000            PgType::DeclareArrayOf(array) => Some(Cow::Owned(PgTypeInfo(PgType::DeclareWithName(
1001                array.elem_name.clone(),
1002            )))),
1003        }
1004    }
1005
1006    /// Returns `true` if this type cannot be matched by name.
1007    fn is_declare_with_oid(&self) -> bool {
1008        matches!(self, Self::DeclareWithOid(_))
1009    }
1010
1011    /// Compare two `PgType`s, first by OID, then by array element, then by name.
1012    ///
1013    /// If `soft_eq` is true and `self` or `other` is `DeclareWithOid` but not both, return `true`
1014    /// before checking names.
1015    fn eq_impl(&self, other: &Self, soft_eq: bool) -> bool {
1016        if let (Some(a), Some(b)) = (self.try_oid(), other.try_oid()) {
1017            // If there are OIDs available, use OIDs to perform a direct match
1018            return a == b;
1019        }
1020
1021        if soft_eq && (self.is_declare_with_oid() || other.is_declare_with_oid()) {
1022            // If we get to this point, one instance is `DeclareWithOid()` and the other is
1023            // `DeclareArrayOf()` or `DeclareWithName()`, which means we can't compare the two.
1024            //
1025            // Since this is only likely to occur when using the text protocol where we can't
1026            // resolve type names before executing a query, we can just opt out of typechecking.
1027            return true;
1028        }
1029
1030        if let (Some(elem_a), Some(elem_b)) = (self.try_array_element(), other.try_array_element())
1031        {
1032            return elem_a == elem_b;
1033        }
1034
1035        // Otherwise, perform a match on the name
1036        name_eq(self.name(), other.name())
1037    }
1038}
1039
1040impl TypeInfo for PgTypeInfo {
1041    fn name(&self) -> &str {
1042        self.0.display_name()
1043    }
1044
1045    fn is_null(&self) -> bool {
1046        false
1047    }
1048
1049    fn is_void(&self) -> bool {
1050        matches!(self.0, PgType::Void)
1051    }
1052
1053    fn type_compatible(&self, other: &Self) -> bool
1054    where
1055        Self: Sized,
1056    {
1057        self == other
1058    }
1059}
1060
1061impl PartialEq<PgCustomType> for PgCustomType {
1062    fn eq(&self, other: &PgCustomType) -> bool {
1063        other.oid == self.oid
1064    }
1065}
1066
1067impl PgTypeInfo {
1068    // boolean, state of true or false
1069    pub(crate) const BOOL: Self = Self(PgType::Bool);
1070    pub(crate) const BOOL_ARRAY: Self = Self(PgType::BoolArray);
1071
1072    // binary data types, variable-length binary string
1073    pub(crate) const BYTEA: Self = Self(PgType::Bytea);
1074    pub(crate) const BYTEA_ARRAY: Self = Self(PgType::ByteaArray);
1075
1076    // uuid
1077    pub(crate) const UUID: Self = Self(PgType::Uuid);
1078    pub(crate) const UUID_ARRAY: Self = Self(PgType::UuidArray);
1079
1080    // record
1081    pub(crate) const RECORD: Self = Self(PgType::Record);
1082    pub(crate) const RECORD_ARRAY: Self = Self(PgType::RecordArray);
1083
1084    //
1085    // JSON types
1086    // https://www.postgresql.org/docs/current/datatype-json.html
1087    //
1088
1089    pub(crate) const JSON: Self = Self(PgType::Json);
1090    pub(crate) const JSON_ARRAY: Self = Self(PgType::JsonArray);
1091
1092    pub(crate) const JSONB: Self = Self(PgType::Jsonb);
1093    pub(crate) const JSONB_ARRAY: Self = Self(PgType::JsonbArray);
1094
1095    pub(crate) const JSONPATH: Self = Self(PgType::Jsonpath);
1096    pub(crate) const JSONPATH_ARRAY: Self = Self(PgType::JsonpathArray);
1097
1098    //
1099    // network address types
1100    // https://www.postgresql.org/docs/current/datatype-net-types.html
1101    //
1102
1103    pub(crate) const CIDR: Self = Self(PgType::Cidr);
1104    pub(crate) const CIDR_ARRAY: Self = Self(PgType::CidrArray);
1105
1106    pub(crate) const INET: Self = Self(PgType::Inet);
1107    pub(crate) const INET_ARRAY: Self = Self(PgType::InetArray);
1108
1109    pub(crate) const MACADDR: Self = Self(PgType::Macaddr);
1110    pub(crate) const MACADDR_ARRAY: Self = Self(PgType::MacaddrArray);
1111
1112    pub(crate) const MACADDR8: Self = Self(PgType::Macaddr8);
1113    pub(crate) const MACADDR8_ARRAY: Self = Self(PgType::Macaddr8Array);
1114
1115    //
1116    // character types
1117    // https://www.postgresql.org/docs/current/datatype-character.html
1118    //
1119
1120    // internal type for object names
1121    pub(crate) const NAME: Self = Self(PgType::Name);
1122    pub(crate) const NAME_ARRAY: Self = Self(PgType::NameArray);
1123
1124    // character type, fixed-length, blank-padded
1125    pub(crate) const BPCHAR: Self = Self(PgType::Bpchar);
1126    pub(crate) const BPCHAR_ARRAY: Self = Self(PgType::BpcharArray);
1127
1128    // character type, variable-length with limit
1129    pub(crate) const VARCHAR: Self = Self(PgType::Varchar);
1130    pub(crate) const VARCHAR_ARRAY: Self = Self(PgType::VarcharArray);
1131
1132    // character type, variable-length
1133    pub(crate) const TEXT: Self = Self(PgType::Text);
1134    pub(crate) const TEXT_ARRAY: Self = Self(PgType::TextArray);
1135
1136    // unknown type, transmitted as text
1137    pub(crate) const UNKNOWN: Self = Self(PgType::Unknown);
1138
1139    //
1140    // numeric types
1141    // https://www.postgresql.org/docs/current/datatype-numeric.html
1142    //
1143
1144    // single-byte internal type
1145    pub(crate) const CHAR: Self = Self(PgType::Char);
1146    pub(crate) const CHAR_ARRAY: Self = Self(PgType::CharArray);
1147
1148    // internal type for type ids
1149    pub(crate) const OID: Self = Self(PgType::Oid);
1150    pub(crate) const OID_ARRAY: Self = Self(PgType::OidArray);
1151
1152    // small-range integer; -32768 to +32767
1153    pub(crate) const INT2: Self = Self(PgType::Int2);
1154    pub(crate) const INT2_ARRAY: Self = Self(PgType::Int2Array);
1155
1156    // typical choice for integer; -2147483648 to +2147483647
1157    pub(crate) const INT4: Self = Self(PgType::Int4);
1158    pub(crate) const INT4_ARRAY: Self = Self(PgType::Int4Array);
1159
1160    // large-range integer; -9223372036854775808 to +9223372036854775807
1161    pub(crate) const INT8: Self = Self(PgType::Int8);
1162    pub(crate) const INT8_ARRAY: Self = Self(PgType::Int8Array);
1163
1164    // variable-precision, inexact, 6 decimal digits precision
1165    pub(crate) const FLOAT4: Self = Self(PgType::Float4);
1166    pub(crate) const FLOAT4_ARRAY: Self = Self(PgType::Float4Array);
1167
1168    // variable-precision, inexact, 15 decimal digits precision
1169    pub(crate) const FLOAT8: Self = Self(PgType::Float8);
1170    pub(crate) const FLOAT8_ARRAY: Self = Self(PgType::Float8Array);
1171
1172    // user-specified precision, exact
1173    pub(crate) const NUMERIC: Self = Self(PgType::Numeric);
1174    pub(crate) const NUMERIC_ARRAY: Self = Self(PgType::NumericArray);
1175
1176    // user-specified precision, exact
1177    pub(crate) const MONEY: Self = Self(PgType::Money);
1178    pub(crate) const MONEY_ARRAY: Self = Self(PgType::MoneyArray);
1179
1180    //
1181    // date/time types
1182    // https://www.postgresql.org/docs/current/datatype-datetime.html
1183    //
1184
1185    // both date and time (no time zone)
1186    pub(crate) const TIMESTAMP: Self = Self(PgType::Timestamp);
1187    pub(crate) const TIMESTAMP_ARRAY: Self = Self(PgType::TimestampArray);
1188
1189    // both date and time (with time zone)
1190    pub(crate) const TIMESTAMPTZ: Self = Self(PgType::Timestamptz);
1191    pub(crate) const TIMESTAMPTZ_ARRAY: Self = Self(PgType::TimestamptzArray);
1192
1193    // date (no time of day)
1194    pub(crate) const DATE: Self = Self(PgType::Date);
1195    pub(crate) const DATE_ARRAY: Self = Self(PgType::DateArray);
1196
1197    // time of day (no date)
1198    pub(crate) const TIME: Self = Self(PgType::Time);
1199    pub(crate) const TIME_ARRAY: Self = Self(PgType::TimeArray);
1200
1201    // time of day (no date), with time zone
1202    pub(crate) const TIMETZ: Self = Self(PgType::Timetz);
1203    pub(crate) const TIMETZ_ARRAY: Self = Self(PgType::TimetzArray);
1204
1205    // time interval
1206    pub(crate) const INTERVAL: Self = Self(PgType::Interval);
1207    pub(crate) const INTERVAL_ARRAY: Self = Self(PgType::IntervalArray);
1208
1209    //
1210    // geometric types
1211    // https://www.postgresql.org/docs/current/datatype-geometric.html
1212    //
1213
1214    // point on a plane
1215    pub(crate) const POINT: Self = Self(PgType::Point);
1216    pub(crate) const POINT_ARRAY: Self = Self(PgType::PointArray);
1217
1218    // infinite line
1219    pub(crate) const LINE: Self = Self(PgType::Line);
1220    pub(crate) const LINE_ARRAY: Self = Self(PgType::LineArray);
1221
1222    // finite line segment
1223    pub(crate) const LSEG: Self = Self(PgType::Lseg);
1224    pub(crate) const LSEG_ARRAY: Self = Self(PgType::LsegArray);
1225
1226    // rectangular box
1227    pub(crate) const BOX: Self = Self(PgType::Box);
1228    pub(crate) const BOX_ARRAY: Self = Self(PgType::BoxArray);
1229
1230    // open or closed path
1231    pub(crate) const PATH: Self = Self(PgType::Path);
1232    pub(crate) const PATH_ARRAY: Self = Self(PgType::PathArray);
1233
1234    // polygon
1235    pub(crate) const POLYGON: Self = Self(PgType::Polygon);
1236    pub(crate) const POLYGON_ARRAY: Self = Self(PgType::PolygonArray);
1237
1238    // circle
1239    pub(crate) const CIRCLE: Self = Self(PgType::Circle);
1240    pub(crate) const CIRCLE_ARRAY: Self = Self(PgType::CircleArray);
1241
1242    //
1243    // bit string types
1244    // https://www.postgresql.org/docs/current/datatype-bit.html
1245    //
1246
1247    pub(crate) const BIT: Self = Self(PgType::Bit);
1248    pub(crate) const BIT_ARRAY: Self = Self(PgType::BitArray);
1249
1250    pub(crate) const VARBIT: Self = Self(PgType::Varbit);
1251    pub(crate) const VARBIT_ARRAY: Self = Self(PgType::VarbitArray);
1252
1253    //
1254    // range types
1255    // https://www.postgresql.org/docs/current/rangetypes.html
1256    //
1257
1258    pub(crate) const INT4_RANGE: Self = Self(PgType::Int4Range);
1259    pub(crate) const INT4_RANGE_ARRAY: Self = Self(PgType::Int4RangeArray);
1260
1261    pub(crate) const NUM_RANGE: Self = Self(PgType::NumRange);
1262    pub(crate) const NUM_RANGE_ARRAY: Self = Self(PgType::NumRangeArray);
1263
1264    pub(crate) const TS_RANGE: Self = Self(PgType::TsRange);
1265    pub(crate) const TS_RANGE_ARRAY: Self = Self(PgType::TsRangeArray);
1266
1267    pub(crate) const TSTZ_RANGE: Self = Self(PgType::TstzRange);
1268    pub(crate) const TSTZ_RANGE_ARRAY: Self = Self(PgType::TstzRangeArray);
1269
1270    pub(crate) const DATE_RANGE: Self = Self(PgType::DateRange);
1271    pub(crate) const DATE_RANGE_ARRAY: Self = Self(PgType::DateRangeArray);
1272
1273    pub(crate) const INT8_RANGE: Self = Self(PgType::Int8Range);
1274    pub(crate) const INT8_RANGE_ARRAY: Self = Self(PgType::Int8RangeArray);
1275
1276    //
1277    // pseudo types
1278    // https://www.postgresql.org/docs/9.3/datatype-pseudo.html
1279    //
1280
1281    pub(crate) const VOID: Self = Self(PgType::Void);
1282}
1283
1284impl Display for PgTypeInfo {
1285    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1286        f.pad(self.name())
1287    }
1288}
1289
1290impl PartialEq<PgType> for PgType {
1291    fn eq(&self, other: &PgType) -> bool {
1292        self.eq_impl(other, true)
1293    }
1294}
1295
1296/// Check type names for equality, respecting Postgres' case sensitivity rules for identifiers.
1297///
1298/// https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
1299fn name_eq(name1: &str, name2: &str) -> bool {
1300    // Cop-out of processing Unicode escapes by just using string equality.
1301    if name1.starts_with("U&") {
1302        // If `name2` doesn't start with `U&` this will automatically be `false`.
1303        return name1 == name2;
1304    }
1305
1306    let mut chars1 = identifier_chars(name1);
1307    let mut chars2 = identifier_chars(name2);
1308
1309    while let (Some(a), Some(b)) = (chars1.next(), chars2.next()) {
1310        if !a.eq(&b) {
1311            return false;
1312        }
1313    }
1314
1315    chars1.next().is_none() && chars2.next().is_none()
1316}
1317
1318struct IdentifierChar {
1319    ch: char,
1320    case_sensitive: bool,
1321}
1322
1323impl IdentifierChar {
1324    fn eq(&self, other: &Self) -> bool {
1325        if self.case_sensitive || other.case_sensitive {
1326            self.ch == other.ch
1327        } else {
1328            self.ch.eq_ignore_ascii_case(&other.ch)
1329        }
1330    }
1331}
1332
1333/// Return an iterator over all significant characters of an identifier.
1334///
1335/// Ignores non-escaped quotation marks.
1336fn identifier_chars(ident: &str) -> impl Iterator<Item = IdentifierChar> + '_ {
1337    let mut case_sensitive = false;
1338    let mut last_char_quote = false;
1339
1340    ident.chars().filter_map(move |ch| {
1341        if ch == '"' {
1342            if last_char_quote {
1343                last_char_quote = false;
1344            } else {
1345                last_char_quote = true;
1346                return None;
1347            }
1348        } else if last_char_quote {
1349            last_char_quote = false;
1350            case_sensitive = !case_sensitive;
1351        }
1352
1353        Some(IdentifierChar { ch, case_sensitive })
1354    })
1355}
1356
1357#[test]
1358fn test_name_eq() {
1359    let test_values = [
1360        ("foo", "foo", true),
1361        ("foo", "Foo", true),
1362        ("foo", "FOO", true),
1363        ("foo", r#""foo""#, true),
1364        ("foo", r#""Foo""#, false),
1365        ("foo", "foo.foo", false),
1366        ("foo.foo", "foo.foo", true),
1367        ("foo.foo", "foo.Foo", true),
1368        ("foo.foo", "foo.FOO", true),
1369        ("foo.foo", "Foo.foo", true),
1370        ("foo.foo", "Foo.Foo", true),
1371        ("foo.foo", "FOO.FOO", true),
1372        ("foo.foo", "foo", false),
1373        ("foo.foo", r#"foo."foo""#, true),
1374        ("foo.foo", r#"foo."Foo""#, false),
1375        ("foo.foo", r#"foo."FOO""#, false),
1376    ];
1377
1378    for (left, right, eq) in test_values {
1379        assert_eq!(
1380            name_eq(left, right),
1381            eq,
1382            "failed check for name_eq({left:?}, {right:?})"
1383        );
1384        assert_eq!(
1385            name_eq(right, left),
1386            eq,
1387            "failed check for name_eq({right:?}, {left:?})"
1388        );
1389    }
1390}