gaussdb_types/
lib.rs

1//! Conversions to and from Postgres types.
2//!
3//! This crate is used by the `tokio-postgres` and `postgres` crates. You normally don't need to depend directly on it
4//! unless you want to define your own `ToSql` or `FromSql` definitions.
5//!
6//! # Derive
7//!
8//! If the `derive` cargo feature is enabled, you can derive `ToSql` and `FromSql` implementations for custom Postgres
9//! types. Explicitly, modify your `Cargo.toml` file to include the following:
10//!
11//! ```toml
12//! [dependencies]
13//! postgres-types = { version = "0.X.X", features = ["derive"] }
14//! ```
15//!
16//! ## Enums
17//!
18//! Postgres enums correspond to C-like enums in Rust:
19//!
20//! ```sql
21//! CREATE TYPE "Mood" AS ENUM (
22//!     'Sad',
23//!     'Ok',
24//!     'Happy'
25//! );
26//! ```
27//!
28//! ```rust
29//! # #[cfg(feature = "derive")]
30//! use gaussdb_types::{ToSql, FromSql};
31//!
32//! # #[cfg(feature = "derive")]
33//! #[derive(Debug, ToSql, FromSql)]
34//! enum Mood {
35//!     Sad,
36//!     Ok,
37//!     Happy,
38//! }
39//! ```
40//!
41//! ## Domains
42//!
43//! Postgres domains correspond to tuple structs with one member in Rust:
44//!
45//! ```sql
46//! CREATE DOMAIN "SessionId" AS BYTEA CHECK(octet_length(VALUE) = 16);
47//! ```
48//!
49//! ```rust
50//! # #[cfg(feature = "derive")]
51//! use gaussdb_types::{ToSql, FromSql};
52//!
53//! # #[cfg(feature = "derive")]
54//! #[derive(Debug, ToSql, FromSql)]
55//! struct SessionId(Vec<u8>);
56//! ```
57//!
58//! ## Newtypes
59//!
60//! The `#[gaussdb(transparent)]` attribute can be used on a single-field tuple struct to create a
61//! Rust-only wrapper type that will use the [`ToSql`] & [`FromSql`] implementation of the inner
62//! value :
63//! ```rust
64//! # #[cfg(feature = "derive")]
65//! use gaussdb_types::{ToSql, FromSql};
66//!
67//! # #[cfg(feature = "derive")]
68//! #[derive(Debug, ToSql, FromSql)]
69//! #[gaussdb(transparent)]
70//! struct UserId(i32);
71//! ```
72//!
73//! ## Composites
74//!
75//! Postgres composite types correspond to structs in Rust:
76//!
77//! ```sql
78//! CREATE TYPE "InventoryItem" AS (
79//!     name TEXT,
80//!     supplier_id INT,
81//!     price DOUBLE PRECISION
82//! );
83//! ```
84//!
85//! ```rust
86//! # #[cfg(feature = "derive")]
87//! use gaussdb_types::{ToSql, FromSql};
88//!
89//! # #[cfg(feature = "derive")]
90//! #[derive(Debug, ToSql, FromSql)]
91//! struct InventoryItem {
92//!     name: String,
93//!     supplier_id: i32,
94//!     price: Option<f64>,
95//! }
96//! ```
97//!
98//! ## Naming
99//!
100//! The derived implementations will enforce exact matches of type, field, and variant names between the Rust and
101//! Postgres types. The `#[gaussdb(name = "...")]` attribute can be used to adjust the name on a type, variant, or
102//! field:
103//!
104//! ```sql
105//! CREATE TYPE mood AS ENUM (
106//!     'sad',
107//!     'ok',
108//!     'happy'
109//! );
110//! ```
111//!
112//! ```rust
113//! # #[cfg(feature = "derive")]
114//! use gaussdb_types::{ToSql, FromSql};
115//!
116//! # #[cfg(feature = "derive")]
117//! #[derive(Debug, ToSql, FromSql)]
118//! #[gaussdb(name = "mood")]
119//! enum Mood {
120//!     #[gaussdb(name = "sad")]
121//!     Sad,
122//!     #[gaussdb(name = "ok")]
123//!     Ok,
124//!     #[gaussdb(name = "happy")]
125//!     Happy,
126//! }
127//! ```
128//!
129//! Alternatively, the `#[gaussdb(rename_all = "...")]` attribute can be used to rename all fields or variants
130//! with the chosen casing convention. This will not affect the struct or enum's type name. Note that
131//! `#[gaussdb(name = "...")]` takes precendence when used in conjunction with `#[gaussdb(rename_all = "...")]`:
132//!
133//! ```rust
134//! # #[cfg(feature = "derive")]
135//! use gaussdb_types::{ToSql, FromSql};
136//!
137//! # #[cfg(feature = "derive")]
138//! #[derive(Debug, ToSql, FromSql)]
139//! #[gaussdb(name = "mood", rename_all = "snake_case")]
140//! enum Mood {
141//!     #[gaussdb(name = "ok")]
142//!     Ok,             // ok
143//!     VeryHappy,      // very_happy
144//! }
145//! ```
146//!
147//! The following case conventions are supported:
148//! - `"lowercase"`
149//! - `"UPPERCASE"`
150//! - `"PascalCase"`
151//! - `"camelCase"`
152//! - `"snake_case"`
153//! - `"SCREAMING_SNAKE_CASE"`
154//! - `"kebab-case"`
155//! - `"SCREAMING-KEBAB-CASE"`
156//! - `"Train-Case"`
157//!
158//! ## Allowing Enum Mismatches
159//!
160//! By default the generated implementation of [`ToSql`] & [`FromSql`] for enums will require an exact match of the enum
161//! variants between the Rust and Postgres types.
162//! To allow mismatches, the `#[gaussdb(allow_mismatch)]` attribute can be used on the enum definition:
163//!
164//! ```sql
165//! CREATE TYPE mood AS ENUM (
166//!   'Sad',
167//!   'Ok',
168//!   'Happy'
169//! );
170//! ```
171//!
172//! ```rust
173//! # #[cfg(feature = "derive")]
174//! use gaussdb_types::{ToSql, FromSql};
175//!
176//! # #[cfg(feature = "derive")]
177//! #[derive(Debug, ToSql, FromSql)]
178//! #[gaussdb(allow_mismatch)]
179//! enum Mood {
180//!    Happy,
181//!    Meh,
182//! }
183//! ```
184#![warn(clippy::all, rust_2018_idioms, missing_docs)]
185use fallible_iterator::FallibleIterator;
186use gaussdb_protocol::types::{self, ArrayDimension};
187use std::any::type_name;
188use std::borrow::Cow;
189use std::collections::HashMap;
190use std::error::Error;
191use std::fmt;
192use std::hash::BuildHasher;
193use std::net::IpAddr;
194use std::sync::Arc;
195use std::time::{Duration, SystemTime, UNIX_EPOCH};
196
197#[cfg(feature = "derive")]
198pub use gaussdb_derive::{FromSql, ToSql};
199
200#[cfg(feature = "with-serde_json-1")]
201pub use crate::serde_json_1::Json;
202use crate::type_gen::{Inner, Other};
203
204#[doc(inline)]
205pub use gaussdb_protocol::Oid;
206
207#[doc(inline)]
208pub use pg_lsn::PgLsn;
209
210pub use crate::special::{Date, Timestamp};
211use bytes::BytesMut;
212
213// Number of seconds from 1970-01-01 to 2000-01-01
214const TIME_SEC_CONVERSION: u64 = 946_684_800;
215const USEC_PER_SEC: u64 = 1_000_000;
216const NSEC_PER_USEC: u64 = 1_000;
217
218/// Generates a simple implementation of `ToSql::accepts` which accepts the
219/// types passed to it.
220#[macro_export]
221macro_rules! accepts {
222    ($($expected:ident),+) => (
223        fn accepts(ty: &$crate::Type) -> bool {
224            matches!(*ty, $($crate::Type::$expected)|+)
225        }
226    )
227}
228
229/// Generates an implementation of `ToSql::to_sql_checked`.
230///
231/// All `ToSql` implementations should use this macro.
232#[macro_export]
233macro_rules! to_sql_checked {
234    () => {
235        fn to_sql_checked(
236            &self,
237            ty: &$crate::Type,
238            out: &mut $crate::private::BytesMut,
239        ) -> ::std::result::Result<
240            $crate::IsNull,
241            Box<dyn ::std::error::Error + ::std::marker::Sync + ::std::marker::Send>,
242        > {
243            $crate::__to_sql_checked(self, ty, out)
244        }
245    };
246}
247
248// WARNING: this function is not considered part of this crate's public API.
249// It is subject to change at any time.
250#[doc(hidden)]
251pub fn __to_sql_checked<T>(
252    v: &T,
253    ty: &Type,
254    out: &mut BytesMut,
255) -> Result<IsNull, Box<dyn Error + Sync + Send>>
256where
257    T: ToSql,
258{
259    if !T::accepts(ty) {
260        return Err(Box::new(WrongType::new::<T>(ty.clone())));
261    }
262    v.to_sql(ty, out)
263}
264
265#[cfg(feature = "with-bit-vec-0_6")]
266mod bit_vec_06;
267#[cfg(feature = "with-chrono-0_4")]
268mod chrono_04;
269#[cfg(feature = "with-cidr-0_2")]
270mod cidr_02;
271#[cfg(feature = "with-cidr-0_3")]
272mod cidr_03;
273#[cfg(feature = "with-eui48-0_4")]
274mod eui48_04;
275#[cfg(feature = "with-eui48-1")]
276mod eui48_1;
277#[cfg(feature = "with-geo-types-0_6")]
278mod geo_types_06;
279#[cfg(feature = "with-geo-types-0_7")]
280mod geo_types_07;
281#[cfg(feature = "with-jiff-0_1")]
282mod jiff_01;
283#[cfg(feature = "with-jiff-0_2")]
284mod jiff_02;
285#[cfg(feature = "with-serde_json-1")]
286mod serde_json_1;
287#[cfg(feature = "with-smol_str-01")]
288mod smol_str_01;
289#[cfg(feature = "with-time-0_2")]
290mod time_02;
291#[cfg(feature = "with-time-0_3")]
292mod time_03;
293#[cfg(feature = "with-uuid-0_8")]
294mod uuid_08;
295#[cfg(feature = "with-uuid-1")]
296mod uuid_1;
297
298// The time::{date, time} macros produce compile errors if the crate package is renamed.
299#[cfg(feature = "with-time-0_2")]
300extern crate time_02 as time;
301
302mod pg_lsn;
303#[doc(hidden)]
304pub mod private;
305mod special;
306mod type_gen;
307
308/// A Postgres type.
309#[derive(PartialEq, Eq, Clone, Hash)]
310pub struct Type(Inner);
311
312impl fmt::Debug for Type {
313    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
314        fmt::Debug::fmt(&self.0, fmt)
315    }
316}
317
318impl fmt::Display for Type {
319    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
320        match self.schema() {
321            "public" | "pg_catalog" => {}
322            schema => write!(fmt, "{}.", schema)?,
323        }
324        fmt.write_str(self.name())
325    }
326}
327
328impl Type {
329    /// Creates a new `Type`.
330    pub fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Type {
331        Type(Inner::Other(Arc::new(Other {
332            name,
333            oid,
334            kind,
335            schema,
336        })))
337    }
338
339    /// Returns the `Type` corresponding to the provided `Oid` if it
340    /// corresponds to a built-in type.
341    pub fn from_oid(oid: Oid) -> Option<Type> {
342        Inner::from_oid(oid).map(Type)
343    }
344
345    /// Returns the OID of the `Type`.
346    pub fn oid(&self) -> Oid {
347        self.0.oid()
348    }
349
350    /// Returns the kind of this type.
351    pub fn kind(&self) -> &Kind {
352        self.0.kind()
353    }
354
355    /// Returns the schema of this type.
356    pub fn schema(&self) -> &str {
357        match self.0 {
358            Inner::Other(ref u) => &u.schema,
359            _ => "pg_catalog",
360        }
361    }
362
363    /// Returns the name of this type.
364    pub fn name(&self) -> &str {
365        self.0.name()
366    }
367}
368
369/// Represents the kind of a Postgres type.
370#[derive(Debug, Clone, PartialEq, Eq, Hash)]
371#[non_exhaustive]
372pub enum Kind {
373    /// A simple type like `VARCHAR` or `INTEGER`.
374    Simple,
375    /// An enumerated type along with its variants.
376    Enum(Vec<String>),
377    /// A pseudo-type.
378    Pseudo,
379    /// An array type along with the type of its elements.
380    Array(Type),
381    /// A range type along with the type of its elements.
382    Range(Type),
383    /// A multirange type along with the type of its elements.
384    Multirange(Type),
385    /// A domain type along with its underlying type.
386    Domain(Type),
387    /// A composite type along with information about its fields.
388    Composite(Vec<Field>),
389}
390
391/// Information about a field of a composite type.
392#[derive(Debug, Clone, PartialEq, Eq, Hash)]
393pub struct Field {
394    name: String,
395    type_: Type,
396}
397
398impl Field {
399    /// Creates a new `Field`.
400    pub fn new(name: String, type_: Type) -> Field {
401        Field { name, type_ }
402    }
403
404    /// Returns the name of the field.
405    pub fn name(&self) -> &str {
406        &self.name
407    }
408
409    /// Returns the type of the field.
410    pub fn type_(&self) -> &Type {
411        &self.type_
412    }
413}
414
415/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
416/// implementation that does not support `NULL` values.
417#[derive(Debug, Clone, Copy)]
418pub struct WasNull;
419
420impl fmt::Display for WasNull {
421    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
422        fmt.write_str("a Postgres value was `NULL`")
423    }
424}
425
426impl Error for WasNull {}
427
428/// An error indicating that a conversion was attempted between incompatible
429/// Rust and Postgres types.
430#[derive(Debug)]
431pub struct WrongType {
432    postgres: Type,
433    rust: &'static str,
434}
435
436impl fmt::Display for WrongType {
437    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
438        write!(
439            fmt,
440            "cannot convert between the Rust type `{}` and the Postgres type `{}`",
441            self.rust, self.postgres,
442        )
443    }
444}
445
446impl Error for WrongType {}
447
448impl WrongType {
449    /// Creates a new `WrongType` error.
450    pub fn new<T>(ty: Type) -> WrongType {
451        WrongType {
452            postgres: ty,
453            rust: type_name::<T>(),
454        }
455    }
456}
457
458/// A trait for types that can be created from a Postgres value.
459///
460/// # Types
461///
462/// The following implementations are provided by this crate, along with the
463/// corresponding Postgres types:
464///
465/// | Rust type                         | Postgres type(s)                              |
466/// |-----------------------------------|-----------------------------------------------|
467/// | `bool`                            | BOOL                                          |
468/// | `i8`                              | "char"                                        |
469/// | `i16`                             | SMALLINT, SMALLSERIAL                         |
470/// | `i32`                             | INT, SERIAL                                   |
471/// | `u32`                             | OID                                           |
472/// | `i64`                             | BIGINT, BIGSERIAL                             |
473/// | `f32`                             | REAL                                          |
474/// | `f64`                             | DOUBLE PRECISION                              |
475/// | `&str`/`String`                   | VARCHAR, CHAR(n), TEXT, CITEXT, NAME, UNKNOWN |
476/// |                                   | LTREE, LQUERY, LTXTQUERY                      |
477/// | `&[u8]`/`Vec<u8>`                 | BYTEA                                         |
478/// | `HashMap<String, Option<String>>` | HSTORE                                        |
479/// | `SystemTime`                      | TIMESTAMP, TIMESTAMP WITH TIME ZONE           |
480/// | `IpAddr`                          | INET                                          |
481///
482/// In addition, some implementations are provided for types in third party
483/// crates. These are disabled by default; to opt into one of these
484/// implementations, activate the Cargo feature corresponding to the crate's
485/// name prefixed by `with-`. For example, the `with-serde_json-1` feature enables
486/// the implementation for the `serde_json::Value` type.
487///
488/// | Rust type                       | Postgres type(s)                    |
489/// |---------------------------------|-------------------------------------|
490/// | `chrono::NaiveDateTime`         | TIMESTAMP                           |
491/// | `chrono::DateTime<Utc>`         | TIMESTAMP WITH TIME ZONE            |
492/// | `chrono::DateTime<Local>`       | TIMESTAMP WITH TIME ZONE            |
493/// | `chrono::DateTime<FixedOffset>` | TIMESTAMP WITH TIME ZONE            |
494/// | `chrono::NaiveDate`             | DATE                                |
495/// | `chrono::NaiveTime`             | TIME                                |
496/// | `cidr::IpCidr`                  | CIDR                                |
497/// | `cidr::IpInet`                  | INET                                |
498/// | `time::PrimitiveDateTime`       | TIMESTAMP                           |
499/// | `time::OffsetDateTime`          | TIMESTAMP WITH TIME ZONE            |
500/// | `time::Date`                    | DATE                                |
501/// | `time::Time`                    | TIME                                |
502/// | `jiff::civil::Date`             | DATE                                |
503/// | `jiff::civil::DateTime`         | TIMESTAMP                           |
504/// | `jiff::civil::Time`             | TIME                                |
505/// | `jiff::Timestamp`               | TIMESTAMP WITH TIME ZONE            |
506/// | `eui48::MacAddress`             | MACADDR                             |
507/// | `geo_types::Point<f64>`         | POINT                               |
508/// | `geo_types::Rect<f64>`          | BOX                                 |
509/// | `geo_types::LineString<f64>`    | PATH                                |
510/// | `serde_json::Value`             | JSON, JSONB                         |
511/// | `uuid::Uuid`                    | UUID                                |
512/// | `bit_vec::BitVec`               | BIT, VARBIT                         |
513/// | `eui48::MacAddress`             | MACADDR                             |
514/// | `cidr::InetCidr`                | CIDR                                |
515/// | `cidr::InetAddr`                | INET                                |
516/// | `smol_str::SmolStr`             | VARCHAR, CHAR(n), TEXT, CITEXT,     |
517/// |                                 | NAME, UNKNOWN, LTREE, LQUERY,       |
518/// |                                 | LTXTQUERY                           |
519///
520/// # Nullability
521///
522/// In addition to the types listed above, `FromSql` is implemented for
523/// `Option<T>` where `T` implements `FromSql`. An `Option<T>` represents a
524/// nullable Postgres value.
525///
526/// # Arrays
527///
528/// `FromSql` is implemented for `Vec<T>`, `Box<[T]>` and `[T; N]` where `T`
529/// implements `FromSql`, and corresponds to one-dimensional Postgres arrays.
530///
531/// **Note:** the impl for arrays only exist when the Cargo feature `array-impls`
532/// is enabled.
533pub trait FromSql<'a>: Sized {
534    /// Creates a new value of this type from a buffer of data of the specified
535    /// Postgres `Type` in its binary format.
536    ///
537    /// The caller of this method is responsible for ensuring that this type
538    /// is compatible with the Postgres `Type`.
539    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>>;
540
541    /// Creates a new value of this type from a `NULL` SQL value.
542    ///
543    /// The caller of this method is responsible for ensuring that this type
544    /// is compatible with the Postgres `Type`.
545    ///
546    /// The default implementation returns `Err(Box::new(WasNull))`.
547    #[allow(unused_variables)]
548    fn from_sql_null(ty: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
549        Err(Box::new(WasNull))
550    }
551
552    /// A convenience function that delegates to `from_sql` and `from_sql_null` depending on the
553    /// value of `raw`.
554    fn from_sql_nullable(
555        ty: &Type,
556        raw: Option<&'a [u8]>,
557    ) -> Result<Self, Box<dyn Error + Sync + Send>> {
558        match raw {
559            Some(raw) => Self::from_sql(ty, raw),
560            None => Self::from_sql_null(ty),
561        }
562    }
563
564    /// Determines if a value of this type can be created from the specified
565    /// Postgres `Type`.
566    fn accepts(ty: &Type) -> bool;
567}
568
569/// A trait for types which can be created from a Postgres value without borrowing any data.
570///
571/// This is primarily useful for trait bounds on functions.
572pub trait FromSqlOwned: for<'a> FromSql<'a> {}
573
574impl<T> FromSqlOwned for T where T: for<'a> FromSql<'a> {}
575
576impl<'a, T: FromSql<'a>> FromSql<'a> for Option<T> {
577    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
578        <T as FromSql>::from_sql(ty, raw).map(Some)
579    }
580
581    fn from_sql_null(_: &Type) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
582        Ok(None)
583    }
584
585    fn accepts(ty: &Type) -> bool {
586        <T as FromSql>::accepts(ty)
587    }
588}
589
590impl<'a, T: FromSql<'a>> FromSql<'a> for Vec<T> {
591    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Vec<T>, Box<dyn Error + Sync + Send>> {
592        let member_type = match *ty.kind() {
593            Kind::Array(ref member) => member,
594            _ => panic!("expected array type"),
595        };
596
597        let array = types::array_from_sql(raw)?;
598        if array.dimensions().count()? > 1 {
599            return Err("array contains too many dimensions".into());
600        }
601
602        array
603            .values()
604            .map(|v| T::from_sql_nullable(member_type, v))
605            .collect()
606    }
607
608    fn accepts(ty: &Type) -> bool {
609        match *ty.kind() {
610            Kind::Array(ref inner) => T::accepts(inner),
611            _ => false,
612        }
613    }
614}
615
616#[cfg(feature = "array-impls")]
617impl<'a, T: FromSql<'a>, const N: usize> FromSql<'a> for [T; N] {
618    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
619        let member_type = match *ty.kind() {
620            Kind::Array(ref member) => member,
621            _ => panic!("expected array type"),
622        };
623
624        let array = types::array_from_sql(raw)?;
625        if array.dimensions().count()? > 1 {
626            return Err("array contains too many dimensions".into());
627        }
628
629        let mut values = array.values();
630        let out = array_init::try_array_init(|i| {
631            let v = values
632                .next()?
633                .ok_or_else(|| -> Box<dyn Error + Sync + Send> {
634                    format!("too few elements in array (expected {}, got {})", N, i).into()
635                })?;
636            T::from_sql_nullable(member_type, v)
637        })?;
638        if values.next()?.is_some() {
639            return Err(format!(
640                "excess elements in array (expected {}, got more than that)",
641                N,
642            )
643            .into());
644        }
645
646        Ok(out)
647    }
648
649    fn accepts(ty: &Type) -> bool {
650        match *ty.kind() {
651            Kind::Array(ref inner) => T::accepts(inner),
652            _ => false,
653        }
654    }
655}
656
657impl<'a, T: FromSql<'a>> FromSql<'a> for Box<[T]> {
658    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
659        Vec::<T>::from_sql(ty, raw).map(Vec::into_boxed_slice)
660    }
661
662    fn accepts(ty: &Type) -> bool {
663        Vec::<T>::accepts(ty)
664    }
665}
666
667impl<'a> FromSql<'a> for Vec<u8> {
668    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>> {
669        Ok(types::bytea_from_sql(raw).to_owned())
670    }
671
672    accepts!(BYTEA);
673}
674
675impl<'a> FromSql<'a> for &'a [u8] {
676    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a [u8], Box<dyn Error + Sync + Send>> {
677        Ok(types::bytea_from_sql(raw))
678    }
679
680    accepts!(BYTEA);
681}
682
683impl<'a> FromSql<'a> for String {
684    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<String, Box<dyn Error + Sync + Send>> {
685        <&str as FromSql>::from_sql(ty, raw).map(ToString::to_string)
686    }
687
688    fn accepts(ty: &Type) -> bool {
689        <&str as FromSql>::accepts(ty)
690    }
691}
692
693impl<'a> FromSql<'a> for Box<str> {
694    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Box<str>, Box<dyn Error + Sync + Send>> {
695        <&str as FromSql>::from_sql(ty, raw)
696            .map(ToString::to_string)
697            .map(String::into_boxed_str)
698    }
699
700    fn accepts(ty: &Type) -> bool {
701        <&str as FromSql>::accepts(ty)
702    }
703}
704
705impl<'a> FromSql<'a> for &'a str {
706    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
707        match *ty {
708            ref ty if ty.name() == "ltree" => types::ltree_from_sql(raw),
709            ref ty if ty.name() == "lquery" => types::lquery_from_sql(raw),
710            ref ty if ty.name() == "ltxtquery" => types::ltxtquery_from_sql(raw),
711            _ => types::text_from_sql(raw),
712        }
713    }
714
715    fn accepts(ty: &Type) -> bool {
716        match *ty {
717            Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
718            ref ty
719                if (ty.name() == "citext"
720                    || ty.name() == "ltree"
721                    || ty.name() == "lquery"
722                    || ty.name() == "ltxtquery") =>
723            {
724                true
725            }
726            _ => false,
727        }
728    }
729}
730
731macro_rules! simple_from {
732    ($t:ty, $f:ident, $($expected:ident),+) => {
733        impl<'a> FromSql<'a> for $t {
734            fn from_sql(_: &Type, raw: &'a [u8]) -> Result<$t, Box<dyn Error + Sync + Send>> {
735                types::$f(raw)
736            }
737
738            accepts!($($expected),+);
739        }
740    }
741}
742
743simple_from!(bool, bool_from_sql, BOOL);
744simple_from!(i8, char_from_sql, CHAR);
745simple_from!(i16, int2_from_sql, INT2);
746simple_from!(i32, int4_from_sql, INT4);
747simple_from!(u32, oid_from_sql, OID);
748simple_from!(i64, int8_from_sql, INT8);
749simple_from!(f32, float4_from_sql, FLOAT4);
750simple_from!(f64, float8_from_sql, FLOAT8);
751
752impl<'a, S> FromSql<'a> for HashMap<String, Option<String>, S>
753where
754    S: Default + BuildHasher,
755{
756    fn from_sql(
757        _: &Type,
758        raw: &'a [u8],
759    ) -> Result<HashMap<String, Option<String>, S>, Box<dyn Error + Sync + Send>> {
760        types::hstore_from_sql(raw)?
761            .map(|(k, v)| Ok((k.to_owned(), v.map(str::to_owned))))
762            .collect()
763    }
764
765    fn accepts(ty: &Type) -> bool {
766        ty.name() == "hstore"
767    }
768}
769
770impl<'a> FromSql<'a> for SystemTime {
771    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<SystemTime, Box<dyn Error + Sync + Send>> {
772        let time = types::timestamp_from_sql(raw)?;
773        let epoch = UNIX_EPOCH + Duration::from_secs(TIME_SEC_CONVERSION);
774
775        let negative = time < 0;
776        let time = time.unsigned_abs();
777
778        let secs = time / USEC_PER_SEC;
779        let nsec = (time % USEC_PER_SEC) * NSEC_PER_USEC;
780        let offset = Duration::new(secs, nsec as u32);
781
782        let time = if negative {
783            epoch - offset
784        } else {
785            epoch + offset
786        };
787
788        Ok(time)
789    }
790
791    accepts!(TIMESTAMP, TIMESTAMPTZ);
792}
793
794impl<'a> FromSql<'a> for IpAddr {
795    fn from_sql(_: &Type, raw: &'a [u8]) -> Result<IpAddr, Box<dyn Error + Sync + Send>> {
796        let inet = types::inet_from_sql(raw)?;
797        Ok(inet.addr())
798    }
799
800    accepts!(INET);
801}
802
803/// An enum representing the nullability of a Postgres value.
804pub enum IsNull {
805    /// The value is NULL.
806    Yes,
807    /// The value is not NULL.
808    No,
809}
810
811/// A trait for types that can be converted into Postgres values.
812///
813/// # Types
814///
815/// The following implementations are provided by this crate, along with the
816/// corresponding Postgres types:
817///
818/// | Rust type                         | Postgres type(s)                     |
819/// |-----------------------------------|--------------------------------------|
820/// | `bool`                            | BOOL                                 |
821/// | `i8`                              | "char"                               |
822/// | `i16`                             | SMALLINT, SMALLSERIAL                |
823/// | `i32`                             | INT, SERIAL                          |
824/// | `u32`                             | OID                                  |
825/// | `i64`                             | BIGINT, BIGSERIAL                    |
826/// | `f32`                             | REAL                                 |
827/// | `f64`                             | DOUBLE PRECISION                     |
828/// | `&str`/`String`                   | VARCHAR, CHAR(n), TEXT, CITEXT, NAME |
829/// |                                   | LTREE, LQUERY, LTXTQUERY             |
830/// | `&[u8]`/`Vec<u8>`/`[u8; N]`       | BYTEA                                |
831/// | `HashMap<String, Option<String>>` | HSTORE                               |
832/// | `SystemTime`                      | TIMESTAMP, TIMESTAMP WITH TIME ZONE  |
833/// | `IpAddr`                          | INET                                 |
834///
835/// In addition, some implementations are provided for types in third party
836/// crates. These are disabled by default; to opt into one of these
837/// implementations, activate the Cargo feature corresponding to the crate's
838/// name prefixed by `with-`. For example, the `with-serde_json-1` feature enables
839/// the implementation for the `serde_json::Value` type.
840///
841/// | Rust type                       | Postgres type(s)                    |
842/// |---------------------------------|-------------------------------------|
843/// | `chrono::NaiveDateTime`         | TIMESTAMP                           |
844/// | `chrono::DateTime<Utc>`         | TIMESTAMP WITH TIME ZONE            |
845/// | `chrono::DateTime<Local>`       | TIMESTAMP WITH TIME ZONE            |
846/// | `chrono::DateTime<FixedOffset>` | TIMESTAMP WITH TIME ZONE            |
847/// | `chrono::NaiveDate`             | DATE                                |
848/// | `chrono::NaiveTime`             | TIME                                |
849/// | `cidr::IpCidr`                  | CIDR                                |
850/// | `cidr::IpInet`                  | INET                                |
851/// | `time::PrimitiveDateTime`       | TIMESTAMP                           |
852/// | `time::OffsetDateTime`          | TIMESTAMP WITH TIME ZONE            |
853/// | `time::Date`                    | DATE                                |
854/// | `time::Time`                    | TIME                                |
855/// | `eui48::MacAddress`             | MACADDR                             |
856/// | `geo_types::Point<f64>`         | POINT                               |
857/// | `geo_types::Rect<f64>`          | BOX                                 |
858/// | `geo_types::LineString<f64>`    | PATH                                |
859/// | `serde_json::Value`             | JSON, JSONB                         |
860/// | `uuid::Uuid`                    | UUID                                |
861/// | `bit_vec::BitVec`               | BIT, VARBIT                         |
862/// | `eui48::MacAddress`             | MACADDR                             |
863///
864/// # Nullability
865///
866/// In addition to the types listed above, `ToSql` is implemented for
867/// `Option<T>` where `T` implements `ToSql`. An `Option<T>` represents a
868/// nullable Postgres value.
869///
870/// # Arrays
871///
872/// `ToSql` is implemented for `[u8; N]`, `Vec<T>`, `&[T]`, `Box<[T]>` and `[T; N]`
873/// where `T` implements `ToSql` and `N` is const usize, and corresponds to one-dimensional
874/// Postgres arrays with an index offset of 1.
875///
876/// **Note:** the impl for arrays only exist when the Cargo feature `array-impls`
877/// is enabled.
878pub trait ToSql: fmt::Debug {
879    /// Converts the value of `self` into the binary format of the specified
880    /// Postgres `Type`, appending it to `out`.
881    ///
882    /// The caller of this method is responsible for ensuring that this type
883    /// is compatible with the Postgres `Type`.
884    ///
885    /// The return value indicates if this value should be represented as
886    /// `NULL`. If this is the case, implementations **must not** write
887    /// anything to `out`.
888    fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
889    where
890        Self: Sized;
891
892    /// Determines if a value of this type can be converted to the specified
893    /// Postgres `Type`.
894    fn accepts(ty: &Type) -> bool
895    where
896        Self: Sized;
897
898    /// An adaptor method used internally by Rust-Postgres.
899    ///
900    /// *All* implementations of this method should be generated by the
901    /// `to_sql_checked!()` macro.
902    fn to_sql_checked(
903        &self,
904        ty: &Type,
905        out: &mut BytesMut,
906    ) -> Result<IsNull, Box<dyn Error + Sync + Send>>;
907
908    /// Specify the encode format
909    fn encode_format(&self, _ty: &Type) -> Format {
910        Format::Binary
911    }
912}
913
914/// Supported Postgres message format types
915///
916/// Using Text format in a message assumes a Postgres `SERVER_ENCODING` of `UTF8`
917#[derive(Clone, Copy, Debug)]
918pub enum Format {
919    /// Text format (UTF-8)
920    Text,
921    /// Compact, typed binary format
922    Binary,
923}
924
925impl<T> ToSql for &T
926where
927    T: ToSql,
928{
929    fn to_sql(
930        &self,
931        ty: &Type,
932        out: &mut BytesMut,
933    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
934        (*self).to_sql(ty, out)
935    }
936
937    fn accepts(ty: &Type) -> bool {
938        T::accepts(ty)
939    }
940
941    fn encode_format(&self, ty: &Type) -> Format {
942        (*self).encode_format(ty)
943    }
944
945    to_sql_checked!();
946}
947
948impl<T: ToSql> ToSql for Option<T> {
949    fn to_sql(
950        &self,
951        ty: &Type,
952        out: &mut BytesMut,
953    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
954        match *self {
955            Some(ref val) => val.to_sql(ty, out),
956            None => Ok(IsNull::Yes),
957        }
958    }
959
960    fn accepts(ty: &Type) -> bool {
961        <T as ToSql>::accepts(ty)
962    }
963
964    fn encode_format(&self, ty: &Type) -> Format {
965        match self {
966            Some(val) => val.encode_format(ty),
967            None => Format::Binary,
968        }
969    }
970
971    to_sql_checked!();
972}
973
974impl<T: ToSql> ToSql for &[T] {
975    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
976        let member_type = match *ty.kind() {
977            Kind::Array(ref member) => member,
978            _ => panic!("expected array type"),
979        };
980
981        // Arrays are normally one indexed by default but oidvector and int2vector *require* zero indexing
982        let lower_bound = match *ty {
983            Type::OID_VECTOR | Type::INT2_VECTOR => 0,
984            _ => 1,
985        };
986
987        let dimension = ArrayDimension {
988            len: downcast(self.len())?,
989            lower_bound,
990        };
991
992        types::array_to_sql(
993            Some(dimension),
994            member_type.oid(),
995            self.iter(),
996            |e, w| match e.to_sql(member_type, w)? {
997                IsNull::No => Ok(gaussdb_protocol::IsNull::No),
998                IsNull::Yes => Ok(gaussdb_protocol::IsNull::Yes),
999            },
1000            w,
1001        )?;
1002        Ok(IsNull::No)
1003    }
1004
1005    fn accepts(ty: &Type) -> bool {
1006        match *ty.kind() {
1007            Kind::Array(ref member) => T::accepts(member),
1008            _ => false,
1009        }
1010    }
1011
1012    to_sql_checked!();
1013}
1014
1015impl ToSql for &[u8] {
1016    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1017        types::bytea_to_sql(self, w);
1018        Ok(IsNull::No)
1019    }
1020
1021    accepts!(BYTEA);
1022
1023    to_sql_checked!();
1024}
1025
1026#[cfg(feature = "array-impls")]
1027impl<const N: usize> ToSql for [u8; N] {
1028    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1029        types::bytea_to_sql(&self[..], w);
1030        Ok(IsNull::No)
1031    }
1032
1033    accepts!(BYTEA);
1034
1035    to_sql_checked!();
1036}
1037
1038#[cfg(feature = "array-impls")]
1039impl<T: ToSql, const N: usize> ToSql for [T; N] {
1040    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1041        <&[T] as ToSql>::to_sql(&&self[..], ty, w)
1042    }
1043
1044    fn accepts(ty: &Type) -> bool {
1045        <&[T] as ToSql>::accepts(ty)
1046    }
1047
1048    to_sql_checked!();
1049}
1050
1051impl<T: ToSql> ToSql for Vec<T> {
1052    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1053        <&[T] as ToSql>::to_sql(&&**self, ty, w)
1054    }
1055
1056    fn accepts(ty: &Type) -> bool {
1057        <&[T] as ToSql>::accepts(ty)
1058    }
1059
1060    to_sql_checked!();
1061}
1062
1063impl<T: ToSql> ToSql for Box<[T]> {
1064    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1065        <&[T] as ToSql>::to_sql(&&**self, ty, w)
1066    }
1067
1068    fn accepts(ty: &Type) -> bool {
1069        <&[T] as ToSql>::accepts(ty)
1070    }
1071
1072    to_sql_checked!();
1073}
1074
1075impl ToSql for Cow<'_, [u8]> {
1076    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1077        <&[u8] as ToSql>::to_sql(&self.as_ref(), ty, w)
1078    }
1079
1080    fn accepts(ty: &Type) -> bool {
1081        <&[u8] as ToSql>::accepts(ty)
1082    }
1083
1084    to_sql_checked!();
1085}
1086
1087impl ToSql for Vec<u8> {
1088    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1089        <&[u8] as ToSql>::to_sql(&&**self, ty, w)
1090    }
1091
1092    fn accepts(ty: &Type) -> bool {
1093        <&[u8] as ToSql>::accepts(ty)
1094    }
1095
1096    to_sql_checked!();
1097}
1098
1099impl ToSql for &str {
1100    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1101        match ty.name() {
1102            "ltree" => types::ltree_to_sql(self, w),
1103            "lquery" => types::lquery_to_sql(self, w),
1104            "ltxtquery" => types::ltxtquery_to_sql(self, w),
1105            _ => types::text_to_sql(self, w),
1106        }
1107        Ok(IsNull::No)
1108    }
1109
1110    fn accepts(ty: &Type) -> bool {
1111        matches!(
1112            *ty,
1113            Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN
1114        ) || matches!(ty.name(), "citext" | "ltree" | "lquery" | "ltxtquery")
1115    }
1116
1117    to_sql_checked!();
1118}
1119
1120impl ToSql for Cow<'_, str> {
1121    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1122        <&str as ToSql>::to_sql(&self.as_ref(), ty, w)
1123    }
1124
1125    fn accepts(ty: &Type) -> bool {
1126        <&str as ToSql>::accepts(ty)
1127    }
1128
1129    to_sql_checked!();
1130}
1131
1132impl ToSql for String {
1133    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1134        <&str as ToSql>::to_sql(&&**self, ty, w)
1135    }
1136
1137    fn accepts(ty: &Type) -> bool {
1138        <&str as ToSql>::accepts(ty)
1139    }
1140
1141    to_sql_checked!();
1142}
1143
1144impl ToSql for Box<str> {
1145    fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1146        <&str as ToSql>::to_sql(&&**self, ty, w)
1147    }
1148
1149    fn accepts(ty: &Type) -> bool {
1150        <&str as ToSql>::accepts(ty)
1151    }
1152
1153    to_sql_checked!();
1154}
1155
1156macro_rules! simple_to {
1157    ($t:ty, $f:ident, $($expected:ident),+) => {
1158        impl ToSql for $t {
1159            fn to_sql(&self,
1160                      _: &Type,
1161                      w: &mut BytesMut)
1162                      -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1163                types::$f(*self, w);
1164                Ok(IsNull::No)
1165            }
1166
1167            accepts!($($expected),+);
1168
1169            to_sql_checked!();
1170        }
1171    }
1172}
1173
1174simple_to!(bool, bool_to_sql, BOOL);
1175simple_to!(i8, char_to_sql, CHAR);
1176simple_to!(i16, int2_to_sql, INT2);
1177simple_to!(i32, int4_to_sql, INT4);
1178simple_to!(u32, oid_to_sql, OID);
1179simple_to!(i64, int8_to_sql, INT8);
1180simple_to!(f32, float4_to_sql, FLOAT4);
1181simple_to!(f64, float8_to_sql, FLOAT8);
1182
1183impl<H> ToSql for HashMap<String, Option<String>, H>
1184where
1185    H: BuildHasher,
1186{
1187    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1188        types::hstore_to_sql(
1189            self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))),
1190            w,
1191        )?;
1192        Ok(IsNull::No)
1193    }
1194
1195    fn accepts(ty: &Type) -> bool {
1196        ty.name() == "hstore"
1197    }
1198
1199    to_sql_checked!();
1200}
1201
1202impl ToSql for SystemTime {
1203    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1204        let epoch = UNIX_EPOCH + Duration::from_secs(TIME_SEC_CONVERSION);
1205
1206        let to_usec =
1207            |d: Duration| d.as_secs() * USEC_PER_SEC + u64::from(d.subsec_nanos()) / NSEC_PER_USEC;
1208
1209        let time = match self.duration_since(epoch) {
1210            Ok(duration) => to_usec(duration) as i64,
1211            Err(e) => -(to_usec(e.duration()) as i64),
1212        };
1213
1214        types::timestamp_to_sql(time, w);
1215        Ok(IsNull::No)
1216    }
1217
1218    accepts!(TIMESTAMP, TIMESTAMPTZ);
1219
1220    to_sql_checked!();
1221}
1222
1223impl ToSql for IpAddr {
1224    fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
1225        let netmask = match self {
1226            IpAddr::V4(_) => 32,
1227            IpAddr::V6(_) => 128,
1228        };
1229        types::inet_to_sql(*self, netmask, w);
1230        Ok(IsNull::No)
1231    }
1232
1233    accepts!(INET);
1234
1235    to_sql_checked!();
1236}
1237
1238fn downcast(len: usize) -> Result<i32, Box<dyn Error + Sync + Send>> {
1239    if len > i32::MAX as usize {
1240        Err("value too large to transmit".into())
1241    } else {
1242        Ok(len as i32)
1243    }
1244}
1245
1246mod sealed {
1247    pub trait Sealed {}
1248}
1249
1250/// A trait used by clients to abstract over `&dyn ToSql` and `T: ToSql`.
1251///
1252/// This cannot be implemented outside of this crate.
1253pub trait BorrowToSql: sealed::Sealed {
1254    /// Returns a reference to `self` as a `ToSql` trait object.
1255    fn borrow_to_sql(&self) -> &dyn ToSql;
1256}
1257
1258impl sealed::Sealed for &dyn ToSql {}
1259
1260impl BorrowToSql for &dyn ToSql {
1261    #[inline]
1262    fn borrow_to_sql(&self) -> &dyn ToSql {
1263        *self
1264    }
1265}
1266
1267impl sealed::Sealed for Box<dyn ToSql + Sync + '_> {}
1268
1269impl BorrowToSql for Box<dyn ToSql + Sync + '_> {
1270    #[inline]
1271    fn borrow_to_sql(&self) -> &dyn ToSql {
1272        self.as_ref()
1273    }
1274}
1275
1276impl sealed::Sealed for Box<dyn ToSql + Sync + Send + '_> {}
1277impl BorrowToSql for Box<dyn ToSql + Sync + Send + '_> {
1278    #[inline]
1279    fn borrow_to_sql(&self) -> &dyn ToSql {
1280        self.as_ref()
1281    }
1282}
1283
1284impl sealed::Sealed for &(dyn ToSql + Sync) {}
1285
1286/// In async contexts it is sometimes necessary to have the additional
1287/// Sync requirement on parameters for queries since this enables the
1288/// resulting Futures to be Send, hence usable in, e.g., tokio::spawn.
1289/// This instance is provided for those cases.
1290impl BorrowToSql for &(dyn ToSql + Sync) {
1291    #[inline]
1292    fn borrow_to_sql(&self) -> &dyn ToSql {
1293        *self
1294    }
1295}
1296
1297impl<T> sealed::Sealed for T where T: ToSql {}
1298
1299impl<T> BorrowToSql for T
1300where
1301    T: ToSql,
1302{
1303    #[inline]
1304    fn borrow_to_sql(&self) -> &dyn ToSql {
1305        self
1306    }
1307}