Skip to main content

diesel/pg/
backend.rs

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