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