1//! The PostgreSQL backend
23use 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;
1112/// The PostgreSQL backend
13#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
14pub struct Pg;
1516#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Queryable)]
17pub struct InnerPgTypeMetadata {
18pub(in crate::pg) oid: u32,
19pub(in crate::pg) array_oid: u32,
20}
2122impl From<(u32, u32)> for InnerPgTypeMetadata {
23fn from((oid, array_oid): (u32, u32)) -> Self {
24Self { oid, array_oid }
25 }
26}
2728/// This error indicates that a type lookup for a custom
29/// postgres type failed
30#[derive(Clone, Debug, Hash, PartialEq, 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>>);
3738impl 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")]
42pub fn new(cache_key: PgMetadataCacheKey<'static>) -> Self {
43Self::new_internal(cache_key)
44 }
4546pub(in crate::pg) fn new_internal(cache_key: PgMetadataCacheKey<'static>) -> Self {
47Self(Box::new(cache_key))
48 }
49}
5051impl std::error::Error for FailedToLookupTypeError {}
5253impl std::fmt::Display for FailedToLookupTypeError {
54fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55if let Some(schema) = self.0.schema.as_ref() {
56write!(
57 f,
58"Failed to find a type oid for `{}`.`{}`",
59 schema, self.0.type_name
60 )
61 } else {
62write!(f, "Failed to find a type oid for `{}`", self.0.type_name)
63 }
64 }
65}
6667/// The [OIDs] for a SQL type
68///
69/// [OIDs]: https://www.postgresql.org/docs/current/static/datatype-oid.html
70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71#[must_use]
72pub struct PgTypeMetadata(pub(in crate::pg) Result<InnerPgTypeMetadata, FailedToLookupTypeError>);
7374impl 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
82pub fn new(type_oid: u32, array_oid: u32) -> Self {
83Self(Ok(InnerPgTypeMetadata {
84 oid: type_oid,
85 array_oid,
86 }))
87 }
8889/// 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")]
97pub fn from_result(r: Result<(u32, u32), FailedToLookupTypeError>) -> Self {
98Self(r.map(|(oid, array_oid)| InnerPgTypeMetadata { oid, array_oid }))
99 }
100101/// The [OID] of `T`
102 ///
103 /// [OID]: https://www.postgresql.org/docs/current/static/datatype-oid.html
104pub fn oid(&self) -> Result<u32, impl std::error::Error + Send + Sync> {
105self.0.as_ref().map(|i| i.oid).map_err(Clone::clone)
106 }
107108/// The [OID] of `T[]`
109 ///
110 /// [OID]: https://www.postgresql.org/docs/current/static/datatype-oid.html
111pub fn array_oid(&self) -> Result<u32, impl std::error::Error + Send + Sync> {
112self.0.as_ref().map(|i| i.array_oid).map_err(Clone::clone)
113 }
114}
115116impl Backend for Pg {
117type QueryBuilder = PgQueryBuilder;
118type RawValue<'a> = PgValue<'a>;
119type BindCollector<'a> = RawBytesBindCollector<Pg>;
120}
121122impl TypeMetadata for Pg {
123type TypeMetadata = PgTypeMetadata;
124type MetadataLookup = dyn PgMetadataLookup;
125}
126127impl SqlDialect for Pg {
128type ReturningClause = sql_dialect::returning_clause::PgLikeReturningClause;
129130type OnConflictClause = PgOnConflictClause;
131132type InsertWithDefaultKeyword = sql_dialect::default_keyword_for_insert::IsoSqlDefaultKeyword;
133type BatchInsertSupport = sql_dialect::batch_insert_support::PostgresLikeBatchInsertSupport;
134type ConcatClause = sql_dialect::concat_clause::ConcatWithPipesClause;
135136type DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause;
137138type EmptyFromClauseSyntax = sql_dialect::from_clause_syntax::AnsiSqlFromClauseSyntax;
139type SelectStatementSyntax = sql_dialect::select_statement_syntax::AnsiSqlSelectStatement;
140141type ExistsSyntax = sql_dialect::exists_syntax::AnsiSqlExistsSyntax;
142type ArrayComparison = PgStyleArrayComparison;
143type AliasSyntax = sql_dialect::alias_syntax::AsAliasSyntax;
144}
145146impl DieselReserveSpecialization for Pg {}
147impl TrustedBackend for Pg {}
148149#[derive(Debug, Copy, Clone)]
150pub struct PgOnConflictClause;
151152impl sql_dialect::on_conflict_clause::SupportsOnConflictClause for PgOnConflictClause {}
153impl sql_dialect::on_conflict_clause::SupportsOnConflictClauseWhere for PgOnConflictClause {}
154impl sql_dialect::on_conflict_clause::PgLikeOnConflictClause for PgOnConflictClause {}
155156#[derive(Debug, Copy, Clone)]
157pub struct PgStyleArrayComparison;
158159impl LikeIsAllowedForType<crate::sql_types::Binary> for Pg {}
160161// Using the same field names as tokio-postgres
162/// See Postgres documentation for SQL Commands NOTIFY and LISTEN
163#[derive(Clone, Debug)]
164pub struct PgNotification {
165/// process ID of notifying server process
166pub process_id: i32,
167/// Name of the notification channel
168pub channel: String,
169/// optional data that was submitted with the notification,
170 ///
171 /// This is set to an empty string if no data was submitted
172 ///
173 /// (Postgres unfortunally does not provide a way to differentiate between
174 /// not set and empty here)
175pub payload: String,
176}