LCOV - code coverage report
Current view: top level - libs/proxy/postgres-types2/src - lib.rs (source / functions) Coverage Total Hit
Test: 1e20c4f2b28aa592527961bb32170ebbd2c9172f.info Lines: 2.3 % 130 3
Test Date: 2025-07-16 12:29:03 Functions: 2.2 % 46 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              : #![warn(clippy::all, missing_docs)]
       6              : 
       7              : use std::any::type_name;
       8              : use std::error::Error;
       9              : use std::fmt;
      10              : use std::sync::Arc;
      11              : 
      12              : use fallible_iterator::FallibleIterator;
      13              : #[doc(inline)]
      14              : pub use postgres_protocol2::Oid;
      15              : use postgres_protocol2::types;
      16              : 
      17              : use crate::type_gen::{Inner, Other};
      18              : 
      19              : /// Generates a simple implementation of `ToSql::accepts` which accepts the
      20              : /// types passed to it.
      21              : macro_rules! accepts {
      22              :     ($($expected:ident),+) => (
      23            0 :         fn accepts(ty: &$crate::Type) -> bool {
      24            0 :             matches!(*ty, $($crate::Type::$expected)|+)
      25            0 :         }
      26              :     )
      27              : }
      28              : 
      29              : // mod pg_lsn;
      30              : #[doc(hidden)]
      31              : pub mod private;
      32              : // mod special;
      33              : mod type_gen;
      34              : 
      35              : /// A Postgres type.
      36              : #[derive(PartialEq, Eq, Clone, Hash)]
      37              : pub struct Type(Inner);
      38              : 
      39              : impl fmt::Debug for Type {
      40            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
      41            0 :         fmt::Debug::fmt(&self.0, fmt)
      42            0 :     }
      43              : }
      44              : 
      45              : impl fmt::Display for Type {
      46            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
      47            0 :         match self.schema() {
      48            0 :             "public" | "pg_catalog" => {}
      49            0 :             schema => write!(fmt, "{schema}.")?,
      50              :         }
      51            0 :         fmt.write_str(self.name())
      52            0 :     }
      53              : }
      54              : 
      55              : impl Type {
      56              :     /// Creates a new `Type`.
      57            0 :     pub fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Type {
      58            0 :         Type(Inner::Other(Arc::new(Other {
      59            0 :             name,
      60            0 :             oid,
      61            0 :             kind,
      62            0 :             schema,
      63            0 :         })))
      64            0 :     }
      65              : 
      66              :     /// Returns the `Type` corresponding to the provided `Oid` if it
      67              :     /// corresponds to a built-in type.
      68            0 :     pub fn from_oid(oid: Oid) -> Option<Type> {
      69            0 :         Inner::from_oid(oid).map(Type)
      70            0 :     }
      71              : 
      72              :     /// Returns the OID of the `Type`.
      73            0 :     pub fn oid(&self) -> Oid {
      74            0 :         self.0.oid()
      75            0 :     }
      76              : 
      77              :     /// Returns the kind of this type.
      78           76 :     pub fn kind(&self) -> &Kind {
      79           76 :         self.0.kind()
      80           76 :     }
      81              : 
      82              :     /// Returns the schema of this type.
      83            0 :     pub fn schema(&self) -> &str {
      84            0 :         match self.0 {
      85            0 :             Inner::Other(ref u) => &u.schema,
      86            0 :             _ => "pg_catalog",
      87              :         }
      88            0 :     }
      89              : 
      90              :     /// Returns the name of this type.
      91            0 :     pub fn name(&self) -> &str {
      92            0 :         self.0.name()
      93            0 :     }
      94              : }
      95              : 
      96              : /// Represents the kind of a Postgres type.
      97              : #[derive(Debug, Clone, PartialEq, Eq, Hash)]
      98              : #[non_exhaustive]
      99              : pub enum Kind {
     100              :     /// A simple type like `VARCHAR` or `INTEGER`.
     101              :     Simple,
     102              :     /// An enumerated type.
     103              :     Enum,
     104              :     /// A pseudo-type.
     105              :     Pseudo,
     106              :     /// An array type along with the type of its elements.
     107              :     Array(Type),
     108              :     /// A range type along with the type of its elements.
     109              :     Range(Oid),
     110              :     /// A multirange type along with the type of its elements.
     111              :     Multirange(Type),
     112              :     /// A domain type along with its underlying type.
     113              :     Domain(Oid),
     114              :     /// A composite type.
     115              :     Composite(Oid),
     116              : }
     117              : 
     118              : /// Information about a field of a composite type.
     119              : #[derive(Debug, Clone, PartialEq, Eq, Hash)]
     120              : pub struct Field {
     121              :     name: String,
     122              :     type_: Type,
     123              : }
     124              : 
     125              : impl Field {
     126              :     /// Creates a new `Field`.
     127            0 :     pub fn new(name: String, type_: Type) -> Field {
     128            0 :         Field { name, type_ }
     129            0 :     }
     130              : 
     131              :     /// Returns the name of the field.
     132            0 :     pub fn name(&self) -> &str {
     133            0 :         &self.name
     134            0 :     }
     135              : 
     136              :     /// Returns the type of the field.
     137            0 :     pub fn type_(&self) -> &Type {
     138            0 :         &self.type_
     139            0 :     }
     140              : }
     141              : 
     142              : /// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
     143              : /// implementation that does not support `NULL` values.
     144              : #[derive(Debug, Clone, Copy)]
     145              : pub struct WasNull;
     146              : 
     147              : impl fmt::Display for WasNull {
     148            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     149            0 :         fmt.write_str("a Postgres value was `NULL`")
     150            0 :     }
     151              : }
     152              : 
     153              : impl Error for WasNull {}
     154              : 
     155              : /// An error indicating that a conversion was attempted between incompatible
     156              : /// Rust and Postgres types.
     157              : #[derive(Debug)]
     158              : pub struct WrongType {
     159              :     postgres: Type,
     160              :     rust: &'static str,
     161              : }
     162              : 
     163              : impl fmt::Display for WrongType {
     164            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     165            0 :         write!(
     166            0 :             fmt,
     167            0 :             "cannot convert between the Rust type `{}` and the Postgres type `{}`",
     168              :             self.rust, self.postgres,
     169              :         )
     170            0 :     }
     171              : }
     172              : 
     173              : impl Error for WrongType {}
     174              : 
     175              : impl WrongType {
     176              :     /// Creates a new `WrongType` error.
     177            0 :     pub fn new<T>(ty: Type) -> WrongType {
     178            0 :         WrongType {
     179            0 :             postgres: ty,
     180            0 :             rust: type_name::<T>(),
     181            0 :         }
     182            0 :     }
     183              : }
     184              : 
     185              : /// An error indicating that a as_text conversion was attempted on a binary
     186              : /// result.
     187              : #[derive(Debug)]
     188              : pub struct WrongFormat {}
     189              : 
     190              : impl Error for WrongFormat {}
     191              : 
     192              : impl fmt::Display for WrongFormat {
     193            0 :     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
     194            0 :         write!(
     195            0 :             fmt,
     196            0 :             "cannot read column as text while it is in binary format"
     197              :         )
     198            0 :     }
     199              : }
     200              : 
     201              : /// A trait for types that can be created from a Postgres value.
     202              : pub trait FromSql<'a>: Sized {
     203              :     /// Creates a new value of this type from a buffer of data of the specified
     204              :     /// Postgres `Type` in its binary format.
     205              :     ///
     206              :     /// The caller of this method is responsible for ensuring that this type
     207              :     /// is compatible with the Postgres `Type`.
     208              :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>>;
     209              : 
     210              :     /// Creates a new value of this type from a `NULL` SQL value.
     211              :     ///
     212              :     /// The caller of this method is responsible for ensuring that this type
     213              :     /// is compatible with the Postgres `Type`.
     214              :     ///
     215              :     /// The default implementation returns `Err(Box::new(WasNull))`.
     216              :     #[allow(unused_variables)]
     217            0 :     fn from_sql_null(ty: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
     218            0 :         Err(Box::new(WasNull))
     219            0 :     }
     220              : 
     221              :     /// A convenience function that delegates to `from_sql` and `from_sql_null` depending on the
     222              :     /// value of `raw`.
     223            0 :     fn from_sql_nullable(
     224            0 :         ty: &Type,
     225            0 :         raw: Option<&'a [u8]>,
     226            0 :     ) -> Result<Self, Box<dyn Error + Sync + Send>> {
     227            0 :         match raw {
     228            0 :             Some(raw) => Self::from_sql(ty, raw),
     229            0 :             None => Self::from_sql_null(ty),
     230              :         }
     231            0 :     }
     232              : 
     233              :     /// Determines if a value of this type can be created from the specified
     234              :     /// Postgres `Type`.
     235              :     fn accepts(ty: &Type) -> bool;
     236              : }
     237              : 
     238              : /// A trait for types which can be created from a Postgres value without borrowing any data.
     239              : ///
     240              : /// This is primarily useful for trait bounds on functions.
     241              : pub trait FromSqlOwned: for<'a> FromSql<'a> {}
     242              : 
     243              : impl<T> FromSqlOwned for T where T: for<'a> FromSql<'a> {}
     244              : 
     245              : impl<'a, T: FromSql<'a>> FromSql<'a> for Option<T> {
     246            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
     247            0 :         <T as FromSql>::from_sql(ty, raw).map(Some)
     248            0 :     }
     249              : 
     250            0 :     fn from_sql_null(_: &Type) -> Result<Option<T>, Box<dyn Error + Sync + Send>> {
     251            0 :         Ok(None)
     252            0 :     }
     253              : 
     254            0 :     fn accepts(ty: &Type) -> bool {
     255            0 :         <T as FromSql>::accepts(ty)
     256            0 :     }
     257              : }
     258              : 
     259              : impl<'a, T: FromSql<'a>> FromSql<'a> for Vec<T> {
     260            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Vec<T>, Box<dyn Error + Sync + Send>> {
     261            0 :         let member_type = match *ty.kind() {
     262            0 :             Kind::Array(ref member) => member,
     263            0 :             _ => panic!("expected array type"),
     264              :         };
     265              : 
     266            0 :         let array = types::array_from_sql(raw)?;
     267            0 :         if array.dimensions().count()? > 1 {
     268            0 :             return Err("array contains too many dimensions".into());
     269            0 :         }
     270              : 
     271            0 :         array
     272            0 :             .values()
     273            0 :             .map(|v| T::from_sql_nullable(member_type, v))
     274            0 :             .collect()
     275            0 :     }
     276              : 
     277            0 :     fn accepts(ty: &Type) -> bool {
     278            0 :         match *ty.kind() {
     279            0 :             Kind::Array(ref inner) => T::accepts(inner),
     280            0 :             _ => false,
     281              :         }
     282            0 :     }
     283              : }
     284              : 
     285              : impl<'a> FromSql<'a> for String {
     286            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<String, Box<dyn Error + Sync + Send>> {
     287            0 :         <&str as FromSql>::from_sql(ty, raw).map(ToString::to_string)
     288            0 :     }
     289              : 
     290            0 :     fn accepts(ty: &Type) -> bool {
     291            0 :         <&str as FromSql>::accepts(ty)
     292            0 :     }
     293              : }
     294              : 
     295              : impl<'a> FromSql<'a> for &'a str {
     296            0 :     fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box<dyn Error + Sync + Send>> {
     297            0 :         match *ty {
     298            0 :             ref ty if ty.name() == "ltree" => types::ltree_from_sql(raw),
     299            0 :             ref ty if ty.name() == "lquery" => types::lquery_from_sql(raw),
     300            0 :             ref ty if ty.name() == "ltxtquery" => types::ltxtquery_from_sql(raw),
     301            0 :             _ => types::text_from_sql(raw),
     302              :         }
     303            0 :     }
     304              : 
     305            0 :     fn accepts(ty: &Type) -> bool {
     306            0 :         match *ty {
     307            0 :             Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true,
     308            0 :             ref ty
     309            0 :                 if (ty.name() == "citext"
     310            0 :                     || ty.name() == "ltree"
     311            0 :                     || ty.name() == "lquery"
     312            0 :                     || ty.name() == "ltxtquery") =>
     313              :             {
     314            0 :                 true
     315              :             }
     316            0 :             _ => false,
     317              :         }
     318            0 :     }
     319              : }
     320              : 
     321              : macro_rules! simple_from {
     322              :     ($t:ty, $f:ident, $($expected:ident),+) => {
     323              :         impl<'a> FromSql<'a> for $t {
     324            0 :             fn from_sql(_: &Type, raw: &'a [u8]) -> Result<$t, Box<dyn Error + Sync + Send>> {
     325            0 :                 types::$f(raw)
     326            0 :             }
     327              : 
     328              :             accepts!($($expected),+);
     329              :         }
     330              :     }
     331              : }
     332              : 
     333              : simple_from!(i8, char_from_sql, CHAR);
     334              : simple_from!(u32, oid_from_sql, OID);
     335              : 
     336              : /// An enum representing the nullability of a Postgres value.
     337              : pub enum IsNull {
     338              :     /// The value is NULL.
     339              :     Yes,
     340              :     /// The value is not NULL.
     341              :     No,
     342              : }
     343              : 
     344              : /// Supported Postgres message format types
     345              : ///
     346              : /// Using Text format in a message assumes a Postgres `SERVER_ENCODING` of `UTF8`
     347              : #[derive(Clone, Copy, Debug, PartialEq)]
     348              : pub enum Format {
     349              :     /// Text format (UTF-8)
     350              :     Text,
     351              :     /// Compact, typed binary format
     352              :     Binary,
     353              : }
        

Generated by: LCOV version 2.1-beta