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