diesel/pg/
backend.rs

1//! The PostgreSQL backend
2
3use super::query_builder::PgQueryBuilder;
4use super::{PgMetadataLookup, PgValue};
5use crate::backend::*;
6use crate::deserialize::Queryable;
7use crate::expression::operators::LikeIsAllowedForType;
8use crate::pg::metadata_lookup::PgMetadataCacheKey;
9use crate::query_builder::bind_collector::RawBytesBindCollector;
10use crate::sql_types::TypeMetadata;
11
12/// The PostgreSQL backend
13#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Pg {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "Pg")
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for Pg {
    #[inline]
    fn clone(&self) -> Pg { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Pg { }Copy, #[automatically_derived]
impl ::core::hash::Hash for Pg {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for Pg {
    #[inline]
    fn eq(&self, other: &Pg) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Pg {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {}
}Eq, #[automatically_derived]
impl ::core::default::Default for Pg {
    #[inline]
    fn default() -> Pg { Pg {} }
}Default)]
14pub struct Pg;
15
16#[derive(#[automatically_derived]
impl ::core::fmt::Debug for InnerPgTypeMetadata {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "InnerPgTypeMetadata", "oid", &self.oid, "array_oid",
            &&self.array_oid)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for InnerPgTypeMetadata {
    #[inline]
    fn clone(&self) -> InnerPgTypeMetadata {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for InnerPgTypeMetadata { }Copy, #[automatically_derived]
impl ::core::hash::Hash for InnerPgTypeMetadata {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.oid, state);
        ::core::hash::Hash::hash(&self.array_oid, state)
    }
}Hash, #[automatically_derived]
impl ::core::cmp::PartialEq for InnerPgTypeMetadata {
    #[inline]
    fn eq(&self, other: &InnerPgTypeMetadata) -> bool {
        self.oid == other.oid && self.array_oid == other.array_oid
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for InnerPgTypeMetadata {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<u32>;
    }
}Eq, const _: () =
    {
        use diesel;
        use diesel::row::{Row as _, Field as _};
        impl<__DB: diesel::backend::Backend, __ST0, __ST1>
            diesel::deserialize::Queryable<(__ST0, __ST1), __DB> for
            InnerPgTypeMetadata where
            (u32,
            u32): diesel::deserialize::FromStaticSqlRow<(__ST0, __ST1), __DB>
            {
            type Row = (u32, u32);
            fn build(row: (u32, u32)) -> diesel::deserialize::Result<Self> {
                use std::convert::TryInto;
                diesel::deserialize::Result::Ok(Self {
                        oid: row.0.try_into()?,
                        array_oid: row.1.try_into()?,
                    })
            }
        }
    };Queryable)]
17pub struct InnerPgTypeMetadata {
18    pub(in crate::pg) oid: u32,
19    pub(in crate::pg) array_oid: u32,
20}
21
22impl From<(u32, u32)> for InnerPgTypeMetadata {
23    fn from((oid, array_oid): (u32, u32)) -> Self {
24        Self { oid, array_oid }
25    }
26}
27
28/// This error indicates that a type lookup for a custom
29/// postgres type failed
30#[derive(#[automatically_derived]
#[allow(unreachable_pub)]
impl ::core::clone::Clone for FailedToLookupTypeError {
    #[inline]
    fn clone(&self) -> FailedToLookupTypeError {
        FailedToLookupTypeError(::core::clone::Clone::clone(&self.0))
    }
}Clone, #[automatically_derived]
#[allow(unreachable_pub)]
impl ::core::fmt::Debug for FailedToLookupTypeError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "FailedToLookupTypeError", &&self.0)
    }
}Debug, #[automatically_derived]
#[allow(unreachable_pub)]
impl ::core::hash::Hash for FailedToLookupTypeError {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, #[automatically_derived]
#[allow(unreachable_pub)]
impl ::core::cmp::PartialEq for FailedToLookupTypeError {
    #[inline]
    fn eq(&self, other: &FailedToLookupTypeError) -> bool {
        self.0 == other.0
    }
}PartialEq, #[automatically_derived]
#[allow(unreachable_pub)]
impl ::core::cmp::Eq for FailedToLookupTypeError {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _: ::core::cmp::AssertParamIsEq<Box<PgMetadataCacheKey<'static>>>;
    }
}Eq)]
31#[cfg_attr(
32    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
33    cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
34)]
35#[allow(unreachable_pub)]
36pub struct FailedToLookupTypeError(Box<PgMetadataCacheKey<'static>>);
37
38impl FailedToLookupTypeError {
39    /// Construct a new instance of this error type
40    /// containing information about which type lookup failed
41    #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
42    pub fn new(cache_key: PgMetadataCacheKey<'static>) -> Self {
43        Self::new_internal(cache_key)
44    }
45
46    pub(in crate::pg) fn new_internal(cache_key: PgMetadataCacheKey<'static>) -> Self {
47        Self(Box::new(cache_key))
48    }
49}
50
51impl std::error::Error for FailedToLookupTypeError {}
52
53impl std::fmt::Display for FailedToLookupTypeError {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        if let Some(schema) = self.0.schema.as_ref() {
56            f.write_fmt(format_args!("Failed to find a type oid for `{0}`.`{1}`", schema,
        self.0.type_name))write!(
57                f,
58                "Failed to find a type oid for `{}`.`{}`",
59                schema, self.0.type_name
60            )
61        } else {
62            f.write_fmt(format_args!("Failed to find a type oid for `{0}`",
        self.0.type_name))write!(f, "Failed to find a type oid for `{}`", self.0.type_name)
63        }
64    }
65}
66
67/// The [OIDs] for a SQL type
68///
69/// [OIDs]: https://www.postgresql.org/docs/current/static/datatype-oid.html
70#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PgTypeMetadata {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PgTypeMetadata",
            &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for PgTypeMetadata {
    #[inline]
    fn clone(&self) -> PgTypeMetadata {
        PgTypeMetadata(::core::clone::Clone::clone(&self.0))
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for PgTypeMetadata {
    #[inline]
    fn eq(&self, other: &PgTypeMetadata) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PgTypeMetadata {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) -> () {
        let _:
                ::core::cmp::AssertParamIsEq<Result<InnerPgTypeMetadata,
                FailedToLookupTypeError>>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for PgTypeMetadata {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash)]
71#[must_use]
72pub struct PgTypeMetadata(pub(in crate::pg) Result<InnerPgTypeMetadata, FailedToLookupTypeError>);
73
74impl PgTypeMetadata {
75    /// Create a new instance of this type based on known constant [OIDs].
76    ///
77    /// Please refer to [PgMetadataLookup] for a way to query [OIDs]
78    /// of custom types at run time
79    ///
80    /// [OIDs]: https://www.postgresql.org/docs/current/static/datatype-oid.html
81    /// [PgMetadataLookup]: struct.PgMetadataLookup.html
82    pub fn new(type_oid: u32, array_oid: u32) -> Self {
83        Self(Ok(InnerPgTypeMetadata {
84            oid: type_oid,
85            array_oid,
86        }))
87    }
88
89    /// Create a new instance of this type based on dynamically lookup information
90    ///
91    /// This function is useful for third party crates that may implement a custom
92    /// postgres connection type and want to bring their own lookup mechanism.
93    ///
94    /// Otherwise refer to [PgMetadataLookup] for a way to automatically
95    /// implement the corresponding lookup functionality
96    #[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
97    pub fn from_result(r: Result<(u32, u32), FailedToLookupTypeError>) -> Self {
98        Self(r.map(|(oid, array_oid)| InnerPgTypeMetadata { oid, array_oid }))
99    }
100
101    /// The [OID] of `T`
102    ///
103    /// [OID]: https://www.postgresql.org/docs/current/static/datatype-oid.html
104    pub fn oid(&self) -> Result<u32, impl std::error::Error + Send + Sync + use<>> {
105        self.0.as_ref().map(|i| i.oid).map_err(Clone::clone)
106    }
107
108    /// The [OID] of `T[]`
109    ///
110    /// [OID]: https://www.postgresql.org/docs/current/static/datatype-oid.html
111    pub fn array_oid(&self) -> Result<u32, impl std::error::Error + Send + Sync + use<>> {
112        self.0.as_ref().map(|i| i.array_oid).map_err(Clone::clone)
113    }
114}
115
116impl Backend for Pg {
117    type QueryBuilder = PgQueryBuilder;
118    type RawValue<'a> = PgValue<'a>;
119    type BindCollector<'a> = RawBytesBindCollector<Pg>;
120}
121
122impl TypeMetadata for Pg {
123    type TypeMetadata = PgTypeMetadata;
124    type MetadataLookup = dyn PgMetadataLookup;
125}
126
127impl SqlDialect for Pg {
128    type ReturningClause = sql_dialect::returning_clause::PgLikeReturningClause;
129
130    type OnConflictClause = PgOnConflictClause;
131
132    type InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword;
133    type BatchInsertSupport = sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport;
134    type ConcatClause = sql_dialect::concat_clause::ConcatWithPipesClause;
135
136    type DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause;
137
138    type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
139    type SelectStatementSyntax = sql_dialect::select_statement_syntax::AnsiSqlSelectStatement;
140
141    type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
142    type ArrayComparison = PgStyleArrayComparison;
143    type AliasSyntax = sql_dialect::alias_syntax::AsAliasSyntax;
144    type WindowFrameClauseGroupSupport =
145        sql_dialect::window_frame_clause_group_support::IsoGroupWindowFrameUnit;
146    type WindowFrameExclusionSupport =
147        sql_dialect::window_frame_exclusion_support::FrameExclusionSupport;
148    type AggregateFunctionExpressions =
149        sql_dialect::aggregate_function_expressions::PostgresLikeAggregateFunctionExpressions;
150
151    type BuiltInWindowFunctionRequireOrder =
152        sql_dialect::built_in_window_function_require_order::NoOrderRequired;
153}
154
155impl DieselReserveSpecialization for Pg {}
156impl TrustedBackend for Pg {}
157
158#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PgOnConflictClause {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "PgOnConflictClause")
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for PgOnConflictClause { }Copy, #[automatically_derived]
impl ::core::clone::Clone for PgOnConflictClause {
    #[inline]
    fn clone(&self) -> PgOnConflictClause { *self }
}Clone)]
159pub struct PgOnConflictClause;
160
161impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for PgOnConflictClause {}
162impl sql_dialect::on_conflict_clause::SupportsOnConflictClauseWhere for PgOnConflictClause {}
163impl sql_dialect::on_conflict_clause::PgLikeOnConflictClause for PgOnConflictClause {}
164
165#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PgStyleArrayComparison {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "PgStyleArrayComparison")
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for PgStyleArrayComparison { }Copy, #[automatically_derived]
impl ::core::clone::Clone for PgStyleArrayComparison {
    #[inline]
    fn clone(&self) -> PgStyleArrayComparison { *self }
}Clone)]
166pub struct PgStyleArrayComparison;
167
168impl LikeIsAllowedForType<crate::sql_types::Binary> for Pg {}
169
170// Using the same field names as tokio-postgres
171/// See Postgres documentation for SQL Commands NOTIFY and LISTEN
172#[derive(#[automatically_derived]
impl ::core::clone::Clone for PgNotification {
    #[inline]
    fn clone(&self) -> PgNotification {
        PgNotification {
            process_id: ::core::clone::Clone::clone(&self.process_id),
            channel: ::core::clone::Clone::clone(&self.channel),
            payload: ::core::clone::Clone::clone(&self.payload),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for PgNotification {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "PgNotification", "process_id", &self.process_id, "channel",
            &self.channel, "payload", &&self.payload)
    }
}Debug)]
173pub struct PgNotification {
174    /// process ID of notifying server process
175    pub process_id: i32,
176    /// Name of the notification channel
177    pub channel: String,
178    /// optional data that was submitted with the notification,
179    ///
180    /// This is set to an empty string if no data was submitted
181    ///
182    /// (Postgres unfortunally does not provide a way to differentiate between
183    /// not set and empty here)
184    pub payload: String,
185}