LCOV - code coverage report
Current view: top level - libs/proxy/postgres-types2/src - lib.rs (source / functions) Coverage Total Hit
Test: bb45db3982713bfd5bec075773079136e362195e.info Lines: 1.6 % 188 3
Test Date: 2024-12-11 15:53:32 Functions: 1.8 % 56 1

            Line data    Source code
       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              : #![doc(html_root_url = "https://docs.rs/postgres-types/0.2")]
       6              : #![warn(clippy::all, rust_2018_idioms, missing_docs)]
       7              : 
       8              : use fallible_iterator::FallibleIterator;
       9              : use postgres_protocol2::types;
      10              : use std::any::type_name;
      11              : use std::error::Error;
      12              : use std::fmt;
      13              : use std::sync::Arc;
      14              : 
      15              : use crate::type_gen::{Inner, Other};
      16              : 
      17              : #[doc(inline)]
      18              : pub use postgres_protocol2::Oid;
      19              : 
      20              : use bytes::BytesMut;
      21              : 
      22              : /// Generates a simple implementation of `ToSql::accepts` which accepts the
      23              : /// types passed to it.
      24              : macro_rules! accepts {
      25              :     ($($expected:ident),+) => (
      26            0 :         fn accepts(ty: &$crate::Type) -> bool {
      27            0 :             matches!(*ty, $($crate::Type::$expected)|+)
      28            0 :         }
      29              :     )
      30              : }
      31              : 
      32              : /// Generates an implementation of `ToSql::to_sql_checked`.
      33              : ///
      34              : /// All `ToSql` implementations should use this macro.
      35              : macro_rules! to_sql_checked {
      36              :     () => {
      37            0 :         fn to_sql_checked(
      38            0 :             &self,
      39            0 :             ty: &$crate::Type,
      40            0 :             out: &mut $crate::private::BytesMut,
      41            0 :         ) -> ::std::result::Result<
      42            0 :             $crate::IsNull,
      43            0 :             Box<dyn ::std::error::Error + ::std::marker::Sync + ::std::marker::Send>,
      44            0 :         > {
      45            0 :             $crate::__to_sql_checked(self, ty, out)
      46            0 :         }
      47              :     };
      48              : }
      49              : 
      50              : // WARNING: this function is not considered part of this crate's public API.
      51              : // It is subject to change at any time.
      52              : #[doc(hidden)]
      53            0 : pub fn __to_sql_checked<T>(
      54            0 :     v: &T,
      55            0 :     ty: &Type,
      56            0 :     out: &mut BytesMut,
      57            0 : ) -> Result<IsNull, Box<dyn Error + Sync + Send>>
      58            0 : where
      59            0 :     T: ToSql,
      60            0 : {
      61            0 :     if !T::accepts(ty) {
      62            0 :         return Err(Box::new(WrongType::new::<T>(ty.clone())));
      63            0 :     }
      64            0 :     v.to_sql(ty, out)
      65            0 : }
      66              : 
      67              : // mod pg_lsn;
      68              : #[doc(hidden)]
      69              : pub mod private;
      70              : // mod special;
      71              : mod type_gen;
      72              : 
      73              : /// A Postgres type.
      74              : #[derive(PartialEq, Eq, Clone, Hash)]
      75              : pub struct Type(Inner);
      76              : 
      77              : impl fmt::Debug for Type {
      78            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
      79            0 :         fmt::Debug::fmt(&self.0, fmt)
      80            0 :     }
      81              : }
      82              : 
      83              : impl fmt::Display for Type {
      84            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
      85            0 :         match self.schema() {
      86            0 :             "public" | "pg_catalog" => {}
      87            0 :             schema => write!(fmt, "{}.", schema)?,
      88              :         }
      89            0 :         fmt.write_str(self.name())
      90            0 :     }
      91              : }
      92              : 
      93              : impl Type {
      94              :     /// Creates a new `Type`.
      95            0 :     pub fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Type {
      96            0 :         Type(Inner::Other(Arc::new(Other {
      97            0 :             name,
      98            0 :             oid,
      99            0 :             kind,
     100            0 :             schema,
     101            0 :         })))
     102            0 :     }
     103              : 
     104              :     /// Returns the `Type` corresponding to the provided `Oid` if it
     105              :     /// corresponds to a built-in type.
     106            0 :     pub fn from_oid(oid: Oid) -> Option<Type> {
     107            0 :         Inner::from_oid(oid).map(Type)
     108            0 :     }
     109              : 
     110              :     /// Returns the OID of the `Type`.
     111            0 :     pub fn oid(&self) -> Oid {
     112            0 :         self.0.oid()
     113            0 :     }
     114              : 
     115              :     /// Returns the kind of this type.
     116           76 :     pub fn kind(&self) -> &Kind {
     117           76 :         self.0.kind()
     118           76 :     }
     119              : 
     120              :     /// Returns the schema of this type.
     121            0 :     pub fn schema(&self) -> &str {
     122            0 :         match self.0 {
     123            0 :             Inner::Other(ref u) => &u.schema,
     124            0 :             _ => "pg_catalog",
     125              :         }
     126            0 :     }
     127              : 
     128              :     /// Returns the name of this type.
     129            0 :     pub fn name(&self) -> &str {
     130            0 :         self.0.name()
     131            0 :     }
     132              : }
     133              : 
     134              : /// Represents the kind of a Postgres type.
     135              : #[derive(Debug, Clone, PartialEq, Eq, Hash)]
     136              : #[non_exhaustive]
     137              : pub enum Kind {
     138              :     /// A simple type like `VARCHAR` or `INTEGER`.
     139              :     Simple,
     140              :     /// An enumerated type along with its variants.
     141              :     Enum(Vec<String>),
     142              :     /// A pseudo-type.
     143              :     Pseudo,
     144              :     /// An array type along with the type of its elements.
     145              :     Array(Type),
     146              :     /// A range type along with the type of its elements.
     147              :     Range(Type),
     148              :     /// A multirange type along with the type of its elements.
     149              :     Multirange(Type),
     150              :     /// A domain type along with its underlying type.
     151              :     Domain(Type),
     152              :     /// A composite type along with information about its fields.
     153              :     Composite(Vec<Field>),
     154              : }
     155              : 
     156              : /// Information about a field of a composite type.
     157              : #[derive(Debug, Clone, PartialEq, Eq, Hash)]
     158              : pub struct Field {
     159              :     name: String,
     160              :     type_: Type,
     161              : }
     162              : 
     163              : impl Field {
     164              :     /// Creates a new `Field`.
     165            0 :     pub fn new(name: String, type_: Type) -> Field {
     166            0 :         Field { name, type_ }
     167            0 :     }
     168              : 
     169              :     /// Returns the name of the field.
     170            0 :     pub fn name(&self) -> &str {
     171            0 :         &self.name
     172            0 :     }
     173              : 
     174              :     /// Returns the type of the field.
     175            0 :     pub fn type_(&self) -> &Type {
     176            0 :         &self.type_
     177            0 :     }
     178              : }
     179              : 
     180              : /// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
     181              : /// implementation that does not support `NULL` values.
     182              : #[derive(Debug, Clone, Copy)]
     183              : pub struct WasNull;
     184              : 
     185              : impl fmt::Display for WasNull {
     186            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     187            0 :         fmt.write_str("a Postgres value was `NULL`")
     188            0 :     }
     189              : }
     190              : 
     191              : impl Error for WasNull {}
     192              : 
     193              : /// An error indicating that a conversion was attempted between incompatible
     194              : /// Rust and Postgres types.
     195              : #[derive(Debug)]
     196              : pub struct WrongType {
     197              :     postgres: Type,
     198              :     rust: &'static str,
     199              : }
     200              : 
     201              : impl fmt::Display for WrongType {
     202            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     203            0 :         write!(
     204            0 :             fmt,
     205            0 :             "cannot convert between the Rust type `{}` and the Postgres type `{}`",
     206            0 :             self.rust, self.postgres,
     207            0 :         )
     208            0 :     }
     209              : }
     210              : 
     211              : impl Error for WrongType {}
     212              : 
     213              : impl WrongType {
     214              :     /// Creates a new `WrongType` error.
     215            0 :     pub fn new<T>(ty: Type) -> WrongType {
     216            0 :         WrongType {
     217            0 :             postgres: ty,
     218            0 :             rust: type_name::<T>(),
     219            0 :         }
     220            0 :     }
     221              : }
     222              : 
     223              : /// An error indicating that a as_text conversion was attempted on a binary
     224              : /// result.
     225              : #[derive(Debug)]
     226              : pub struct WrongFormat {}
     227              : 
     228              : impl Error for WrongFormat {}
     229              : 
     230              : impl fmt::Display for WrongFormat {
     231            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     232            0 :         write!(
     233            0 :             fmt,
     234            0 :             "cannot read column as text while it is in binary format"
     235            0 :         )
     236            0 :     }
     237              : }
     238              : 
     239              : /// A trait for types that can be created from a Postgres value.
     240              : pub trait FromSql<'a>: Sized {
     241              :     /// Creates a new value of this type from a buffer of data of the specified
     242              :     /// Postgres `Type` in its binary format.
     243              :     ///
     244              :     /// The caller of this method is responsible for ensuring that this type
     245              :     /// is compatible with the Postgres `Type`.
     246              :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>>;
     247              : 
     248              :     /// Creates a new value of this type from a `NULL` SQL value.
     249              :     ///
     250              :     /// The caller of this method is responsible for ensuring that this type
     251              :     /// is compatible with the Postgres `Type`.
     252              :     ///
     253              :     /// The default implementation returns `Err(Box::new(WasNull))`.
     254              :     #[allow(unused_variables)]
     255            0 :     fn from_sql_null(ty: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
     256            0 :         Err(Box::new(WasNull))
     257            0 :     }
     258              : 
     259              :     /// A convenience function that delegates to `from_sql` and `from_sql_null` depending on the
     260              :     /// value of `raw`.
     261            0 :     fn from_sql_nullable(
     262            0 :         ty: &Type,
     263            0 :         raw: Option<&'a [u8]>,
     264            0 :     ) -> Result<Self, Box<dyn Error + Sync + Send>> {
     265            0 :         match raw {
     266            0 :             Some(raw) => Self::from_sql(ty, raw),
     267            0 :             None => Self::from_sql_null(ty),
     268              :         }
     269            0 :     }
     270              : 
     271              :     /// Determines if a value of this type can be created from the specified
     272              :     /// Postgres `Type`.
     273              :     fn accepts(ty: &Type) -> bool;
     274              : }
     275              : 
     276              : /// A trait for types which can be created from a Postgres value without borrowing any data.
     277              : ///
     278              : /// This is primarily useful for trait bounds on functions.
     279              : pub trait FromSqlOwned: for<'a> FromSql<'a> {}
     280              : 
     281              : impl<T> FromSqlOwned for T where T: for<'a> FromSql<'a> {}
     282              : 
     283              : impl<'a, T: FromSql<'a>> FromSql<'a> for Option<T> {
     284            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
     285            0 :         <T as FromSql>::from_sql(ty, raw).map(Some)
     286            0 :     }
     287              : 
     288            0 :     fn from_sql_null(_: &Type) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
     289            0 :         Ok(None)
     290            0 :     }
     291              : 
     292            0 :     fn accepts(ty: &Type) -> bool {
     293            0 :         <T as FromSql>::accepts(ty)
     294            0 :     }
     295              : }
     296              : 
     297              : impl<'a, T: FromSql<'a>> FromSql<'a> for Vec<T> {
     298            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Vec<T>, Box<dyn Error + Sync + Send>> {
     299            0 :         let member_type = match *ty.kind() {
     300            0 :             Kind::Array(ref member) => member,
     301            0 :             _ => panic!("expected array type"),
     302              :         };
     303              : 
     304            0 :         let array = types::array_from_sql(raw)?;
     305            0 :         if array.dimensions().count()? > 1 {
     306            0 :             return Err("array contains too many dimensions".into());
     307            0 :         }
     308            0 : 
     309            0 :         array
     310            0 :             .values()
     311            0 :             .map(|v| T::from_sql_nullable(member_type, v))
     312            0 :             .collect()
     313            0 :     }
     314              : 
     315            0 :     fn accepts(ty: &Type) -> bool {
     316            0 :         match *ty.kind() {
     317            0 :             Kind::Array(ref inner) => T::accepts(inner),
     318            0 :             _ => false,
     319              :         }
     320            0 :     }
     321              : }
     322              : 
     323              : impl<'a> FromSql<'a> for String {
     324            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<String, Box<dyn Error + Sync + Send>> {
     325            0 :         <&str as FromSql>::from_sql(ty, raw).map(ToString::to_string)
     326            0 :     }
     327              : 
     328            0 :     fn accepts(ty: &Type) -> bool {
     329            0 :         <&str as FromSql>::accepts(ty)
     330            0 :     }
     331              : }
     332              : 
     333              : impl<'a> FromSql<'a> for &'a str {
     334            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
     335            0 :         match *ty {
     336            0 :             ref ty if ty.name() == "ltree" => types::ltree_from_sql(raw),
     337            0 :             ref ty if ty.name() == "lquery" => types::lquery_from_sql(raw),
     338            0 :             ref ty if ty.name() == "ltxtquery" => types::ltxtquery_from_sql(raw),
     339            0 :             _ => types::text_from_sql(raw),
     340              :         }
     341            0 :     }
     342              : 
     343            0 :     fn accepts(ty: &Type) -> bool {
     344            0 :         match *ty {
     345            0 :             Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
     346            0 :             ref ty
     347            0 :                 if (ty.name() == "citext"
     348            0 :                     || ty.name() == "ltree"
     349            0 :                     || ty.name() == "lquery"
     350            0 :                     || ty.name() == "ltxtquery") =>
     351            0 :             {
     352            0 :                 true
     353              :             }
     354            0 :             _ => false,
     355              :         }
     356            0 :     }
     357              : }
     358              : 
     359              : macro_rules! simple_from {
     360              :     ($t:ty, $f:ident, $($expected:ident),+) => {
     361              :         impl<'a> FromSql<'a> for $t {
     362            0 :             fn from_sql(_: &Type, raw: &'a [u8]) -> Result<$t, Box<dyn Error + Sync + Send>> {
     363            0 :                 types::$f(raw)
     364            0 :             }
     365              : 
     366              :             accepts!($($expected),+);
     367              :         }
     368              :     }
     369              : }
     370              : 
     371              : simple_from!(i8, char_from_sql, CHAR);
     372              : simple_from!(u32, oid_from_sql, OID);
     373              : 
     374              : /// An enum representing the nullability of a Postgres value.
     375              : pub enum IsNull {
     376              :     /// The value is NULL.
     377              :     Yes,
     378              :     /// The value is not NULL.
     379              :     No,
     380              : }
     381              : 
     382              : /// A trait for types that can be converted into Postgres values.
     383              : pub trait ToSql: fmt::Debug {
     384              :     /// Converts the value of `self` into the binary format of the specified
     385              :     /// Postgres `Type`, appending it to `out`.
     386              :     ///
     387              :     /// The caller of this method is responsible for ensuring that this type
     388              :     /// is compatible with the Postgres `Type`.
     389              :     ///
     390              :     /// The return value indicates if this value should be represented as
     391              :     /// `NULL`. If this is the case, implementations **must not** write
     392              :     /// anything to `out`.
     393              :     fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
     394              :     where
     395              :         Self: Sized;
     396              : 
     397              :     /// Determines if a value of this type can be converted to the specified
     398              :     /// Postgres `Type`.
     399              :     fn accepts(ty: &Type) -> bool
     400              :     where
     401              :         Self: Sized;
     402              : 
     403              :     /// An adaptor method used internally by Rust-Postgres.
     404              :     ///
     405              :     /// *All* implementations of this method should be generated by the
     406              :     /// `to_sql_checked!()` macro.
     407              :     fn to_sql_checked(
     408              :         &self,
     409              :         ty: &Type,
     410              :         out: &mut BytesMut,
     411              :     ) -> Result<IsNull, Box<dyn Error + Sync + Send>>;
     412              : 
     413              :     /// Specify the encode format
     414            0 :     fn encode_format(&self, _ty: &Type) -> Format {
     415            0 :         Format::Binary
     416            0 :     }
     417              : }
     418              : 
     419              : /// Supported Postgres message format types
     420              : ///
     421              : /// Using Text format in a message assumes a Postgres `SERVER_ENCODING` of `UTF8`
     422              : #[derive(Clone, Copy, Debug, PartialEq)]
     423              : pub enum Format {
     424              :     /// Text format (UTF-8)
     425              :     Text,
     426              :     /// Compact, typed binary format
     427              :     Binary,
     428              : }
     429              : 
     430              : impl ToSql for &str {
     431            0 :     fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
     432            0 :         match *ty {
     433            0 :             ref ty if ty.name() == "ltree" => types::ltree_to_sql(self, w),
     434            0 :             ref ty if ty.name() == "lquery" => types::lquery_to_sql(self, w),
     435            0 :             ref ty if ty.name() == "ltxtquery" => types::ltxtquery_to_sql(self, w),
     436            0 :             _ => types::text_to_sql(self, w),
     437              :         }
     438            0 :         Ok(IsNull::No)
     439            0 :     }
     440              : 
     441            0 :     fn accepts(ty: &Type) -> bool {
     442            0 :         match *ty {
     443            0 :             Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
     444            0 :             ref ty
     445            0 :                 if (ty.name() == "citext"
     446            0 :                     || ty.name() == "ltree"
     447            0 :                     || ty.name() == "lquery"
     448            0 :                     || ty.name() == "ltxtquery") =>
     449            0 :             {
     450            0 :                 true
     451              :             }
     452            0 :             _ => false,
     453              :         }
     454            0 :     }
     455              : 
     456              :     to_sql_checked!();
     457              : }
     458              : 
     459              : macro_rules! simple_to {
     460              :     ($t:ty, $f:ident, $($expected:ident),+) => {
     461              :         impl ToSql for $t {
     462            0 :             fn to_sql(&self,
     463            0 :                       _: &Type,
     464            0 :                       w: &mut BytesMut)
     465            0 :                       -> Result<IsNull, Box<dyn Error + Sync + Send>> {
     466            0 :                 types::$f(*self, w);
     467            0 :                 Ok(IsNull::No)
     468            0 :             }
     469              : 
     470              :             accepts!($($expected),+);
     471              : 
     472              :             to_sql_checked!();
     473              :         }
     474              :     }
     475              : }
     476              : 
     477              : simple_to!(u32, oid_to_sql, OID);
        

Generated by: LCOV version 2.1-beta