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