diesel/
backend.rs

1//! Types which represent various database backends
2
3use crate::query_builder::QueryBuilder;
4use crate::sql_types::{self, HasSqlType, TypeMetadata};
5
6#[cfg_attr(
7    not(any(
8        feature = "postgres_backend",
9        feature = "mysql_backend",
10        feature = "sqlite",
11        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
12    )),
13    allow(unused_imports)
14)]
15#[doc(inline)]
16#[diesel_derives::__diesel_public_if(
17    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
18)]
19pub(crate) use self::private::{DieselReserveSpecialization, TrustedBackend};
20
21/// A database backend
22///
23/// This trait represents the concept of a backend (e.g. "MySQL" vs "SQLite").
24/// It is separate from a [`Connection`](crate::connection::Connection)
25/// to that backend.
26/// One backend may have multiple concrete connection implementations.
27///
28/// # Implementing a custom backend
29///
30/// Implementing a custom backend requires enabling the
31/// `i-implement-a-third-party-backend-and-opt-into-breaking-changes` crate feature
32/// to get access to all necessary type and trait implementations.
33///
34/// Implementations of this trait should not assume details about how the
35/// connection is implemented.
36/// For example, the `Pg` backend does not assume that `libpq` is being used.
37/// Implementations of this trait can and should care about details of the wire
38/// protocol used to communicate with the database.
39///
40/// Implementing support for a new backend is a complex topic and depends on the
41/// details how the newly implemented backend may communicate with diesel. As of this,
42/// we cannot provide concrete examples here and only present a general outline of
43/// the required steps. Existing backend implementations provide a good starting point
44/// to see how certain things are solved for other backend implementations.
45///
46/// Types implementing `Backend` should generally be zero sized structs.
47///
48/// To implement the `Backend` trait, you need to:
49///
50/// * Specify how a query should be build from string parts by providing a [`QueryBuilder`]
51/// matching your backend
52/// * Specify the bind value format used by your database connection library by providing
53/// a [`BindCollector`](crate::query_builder::bind_collector::BindCollector) matching your backend
54/// * Specify how values are received from the database by providing a corresponding raw value
55/// definition
56/// * Control sql dialect specific parts of diesels query dsl implementation by providing a
57/// matching [`SqlDialect`] implementation
58/// * Implement [`TypeMetadata`] to specify how your backend identifies types
59/// * Specify support for common datatypes by implementing [`HasSqlType`] for the following sql types:
60///     + [`SmallInt`](sql_types::SmallInt)
61///     + [`Integer`](sql_types::Integer)
62///     + [`BigInt`](sql_types::BigInt)
63///     + [`Float`](sql_types::Float)
64///     + [`Double`](sql_types::Double)
65///     + [`Text`](sql_types::Text)
66///     + [`Binary`](sql_types::Binary)
67///     + [`Date`](sql_types::Date)
68///     + [`Time`](sql_types::Time)
69///     + [`Timestamp`](sql_types::Timestamp)
70///
71/// Additionally to the listed required trait bounds you may want to implement
72#[cfg_attr(
73    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
74    doc = "[`DieselReserveSpecialization`]"
75)]
76#[cfg_attr(
77    not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
78    doc = "`DieselReserveSpecialization`"
79)]
80/// to opt in existing wild card [`QueryFragment`] impls for large parts of the dsl.
81///
82/// [`QueryFragment`]: crate::query_builder::QueryFragment
83pub trait Backend
84where
85    Self: Sized + SqlDialect + TypeMetadata,
86    Self: HasSqlType<sql_types::SmallInt>,
87    Self: HasSqlType<sql_types::Integer>,
88    Self: HasSqlType<sql_types::BigInt>,
89    Self: HasSqlType<sql_types::Float>,
90    Self: HasSqlType<sql_types::Double>,
91    Self: HasSqlType<sql_types::Text>,
92    Self: HasSqlType<sql_types::Binary>,
93    Self: HasSqlType<sql_types::Date>,
94    Self: HasSqlType<sql_types::Time>,
95    Self: HasSqlType<sql_types::Timestamp>,
96{
97    /// The concrete [`QueryBuilder`] implementation for this backend.
98    type QueryBuilder: QueryBuilder<Self>;
99
100    /// The actual type given to [`FromSql`], with lifetimes applied. This type
101    /// should not be used directly.
102    ///
103    /// [`FromSql`]: crate::deserialize::FromSql
104    type RawValue<'a>;
105
106    /// The concrete [`BindCollector`](crate::query_builder::bind_collector::BindCollector)
107    /// implementation for this backend.
108    ///
109    /// Most backends should use [`RawBytesBindCollector`].
110    ///
111    /// [`RawBytesBindCollector`]: crate::query_builder::bind_collector::RawBytesBindCollector
112    type BindCollector<'a>: crate::query_builder::bind_collector::BindCollector<'a, Self> + 'a;
113}
114
115#[doc(hidden)]
116#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
117#[deprecated(note = "Use `Backend::RawValue` directly")]
118pub type RawValue<'a, DB> = <DB as Backend>::RawValue<'a>;
119
120#[doc(hidden)]
121#[cfg(all(feature = "with-deprecated", not(feature = "without-deprecated")))]
122#[deprecated(note = "Use `Backend::BindCollector` directly")]
123pub type BindCollector<'a, DB> = <DB as Backend>::BindCollector<'a>;
124
125/// This trait provides various options to configure the
126/// generated SQL for a specific backend.
127///
128/// Accessing anything from this trait is considered to be part of the
129/// public API. Implementing this trait is not considered to be part of
130/// diesel's public API, as future versions of diesel may add additional
131/// associated constants here.
132///
133/// Each associated type is used to configure the behaviour
134/// of one or more [`QueryFragment`](crate::query_builder::QueryFragment)
135/// implementations by providing
136/// a custom `QueryFragment<YourBackend, YourSpecialSyntaxType>` implementation
137/// to specialize on generic `QueryFragment<DB, DB::AssociatedType>` implementations.
138///
139#[cfg_attr(
140    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
141    doc = "See the [`sql_dialect`] module for options provided by diesel out of the box."
142)]
143pub trait SqlDialect: self::private::TrustedBackend {
144    /// Configures how this backend supports `RETURNING` clauses
145    ///
146    /// This allows backends to opt in `RETURNING` clause support and to
147    /// provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
148    #[cfg_attr(
149        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
150        doc = "implementation for [`ReturningClause`](crate::query_builder::ReturningClause)"
151    )]
152    #[cfg_attr(
153        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
154        doc = "implementation for `ReturningClause`"
155    )]
156    ///
157    #[cfg_attr(
158        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
159        doc = "See [`sql_dialect::returning_clause`] for provided default implementations"
160    )]
161    type ReturningClause;
162    /// Configures how this backend supports `ON CONFLICT` clauses
163    ///
164    /// This allows backends to opt in `ON CONFLICT` clause support
165    ///
166    #[cfg_attr(
167        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
168        doc = "See [`sql_dialect::on_conflict_clause`] for provided default implementations"
169    )]
170    type OnConflictClause;
171    /// Configures how this backend handles the bare `DEFAULT` keyword for
172    /// inserting the default value in a `INSERT INTO` `VALUES` clause
173    ///
174    /// This allows backends to opt in support for `DEFAULT` value expressions
175    /// for insert statements
176    ///
177    #[cfg_attr(
178        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
179        doc = "See [`sql_dialect::default_keyword_for_insert`] for provided default implementations"
180    )]
181    type InsertWithDefaultKeyword;
182    /// Configures how this backend handles Batch insert statements
183    ///
184    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
185    #[cfg_attr(
186        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
187        doc = "implementation for [`BatchInsert`](crate::query_builder::BatchInsert)"
188    )]
189    #[cfg_attr(
190        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
191        doc = "implementation for `BatchInsert`"
192    )]
193    ///
194    #[cfg_attr(
195        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
196        doc = "See [`sql_dialect::batch_insert_support`] for provided default implementations"
197    )]
198    type BatchInsertSupport;
199    /// Configures how this backend handles the Concat clauses in
200    /// select statements.
201    ///
202    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
203    #[cfg_attr(
204        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
205        doc = "implementation for [`Concat`](crate::expression::Concat)"
206    )]
207    #[cfg_attr(
208        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
209        doc = "implementation for `Concat`"
210    )]
211    ///
212    #[cfg_attr(
213        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
214        doc = "See [`sql_dialect::concat_clause`] for provided default implementations"
215    )]
216    type ConcatClause;
217    /// Configures how this backend handles the `DEFAULT VALUES` clause for
218    /// insert statements.
219    ///
220    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
221    #[cfg_attr(
222        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
223        doc = "implementation for [`DefaultValues`](crate::query_builder::DefaultValues)"
224    )]
225    #[cfg_attr(
226        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
227        doc = "implementation for `DefaultValues`"
228    )]
229    ///
230    #[cfg_attr(
231        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
232        doc = "See [`sql_dialect::default_value_clause`] for provided default implementations"
233    )]
234    type DefaultValueClauseForInsert;
235    /// Configures how this backend handles empty `FROM` clauses for select statements.
236    ///
237    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
238    #[cfg_attr(
239        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
240        doc = "implementation for [`NoFromClause`](crate::query_builder::NoFromClause)"
241    )]
242    #[cfg_attr(
243        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
244        doc = "implementation for `NoFromClause`"
245    )]
246    ///
247    #[cfg_attr(
248        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
249        doc = "See [`sql_dialect::from_clause_syntax`] for provided default implementations"
250    )]
251    type EmptyFromClauseSyntax;
252    /// Configures how this backend handles `EXISTS()` expressions.
253    ///
254    /// This allows backends to provide a custom [`QueryFragment`](crate::query_builder::QueryFragment)
255    #[cfg_attr(
256        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
257        doc = "implementation for [`Exists`](crate::expression::exists::Exists)"
258    )]
259    #[cfg_attr(
260        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
261        doc = "implementation for `Exists`"
262    )]
263    ///
264    #[cfg_attr(
265        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
266        doc = "See [`sql_dialect::exists_syntax`] for provided default implementations"
267    )]
268    type ExistsSyntax;
269
270    /// Configures how this backend handles `IN()` and `NOT IN()` expressions.
271    ///
272    /// This allows backends to provide custom [`QueryFragment`](crate::query_builder::QueryFragment)
273    #[cfg_attr(
274        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
275        doc = "implementations for [`In`](crate::expression::array_comparison::In),
276    [`NotIn`](crate::expression::array_comparison::NotIn) and
277    [`Many`](crate::expression::array_comparison::Many)"
278    )]
279    #[cfg_attr(
280        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
281        doc = "implementations for `In`, `NotIn` and `Many`"
282    )]
283    ///
284    #[cfg_attr(
285        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
286        doc = "See [`sql_dialect::array_comparison`] for provided default implementations"
287    )]
288    type ArrayComparison;
289
290    /// Configures how this backend structures `SELECT` queries
291    ///
292    /// This allows backends to provide custom [`QueryFragment`](crate::query_builder::QueryFragment)
293    /// implementations for
294    #[cfg_attr(
295        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
296        doc = "`SelectStatement` and `BoxedSelectStatement`"
297    )]
298    #[cfg_attr(
299        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
300        doc = "[`SelectStatement`](crate::query_builder::SelectStatement) and
301               [`BoxedSelectStatement`](crate::query_builder::BoxedSelectStatement)"
302    )]
303    ///
304    #[cfg_attr(
305        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
306        doc = "See [`sql_dialect::select_statement_syntax`] for provided default implementations"
307    )]
308    type SelectStatementSyntax;
309
310    /// Configures how this backend structures `SELECT` queries
311    ///
312    /// This allows backends to provide custom [`QueryFragment`](crate::query_builder::QueryFragment)
313    /// implementations for [`Alias<T>`](crate::query_source::Alias)
314    ///
315    #[cfg_attr(
316        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
317        doc = "See [`sql_dialect::alias_syntax`] for provided default implementations"
318    )]
319    type AliasSyntax;
320}
321
322/// This module contains all options provided by diesel to configure the [`SqlDialect`] trait.
323// This module is only public behind the unstable feature flag, as we may want to change SqlDialect
324// implementations of existing backends because of:
325// * The backend gained support for previously unsupported SQL operations
326// * The backend fixed/introduced a bug that requires special handling
327// * We got some edge case wrong with sharing the implementation between backends
328//
329// By not exposing these types publicly we are able to change the exact definitions later on
330// as users cannot write trait bounds that ensure that a specific type is used in place of
331// an existing associated type.
332#[diesel_derives::__diesel_public_if(
333    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
334)]
335pub(crate) mod sql_dialect {
336    #![cfg_attr(
337        not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
338        // Otherwise there are false positives
339        // because the lint seems to believe that these pub statements
340        // are not required, but they are required through the various backend impls
341        allow(unreachable_pub)
342    )]
343    #[cfg(doc)]
344    use super::SqlDialect;
345
346    /// This module contains all diesel provided reusable options to
347    /// configure [`SqlDialect::OnConflictClause`]
348    #[diesel_derives::__diesel_public_if(
349        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
350    )]
351    pub mod on_conflict_clause {
352        /// A marker trait indicating if a `ON CONFLICT` clause is supported or not
353        ///
354        /// If you use a custom type to specify specialized support for `ON CONFLICT` clauses
355        /// implementing this trait opts into reusing diesels existing `ON CONFLICT`
356        /// `QueryFragment` implementations
357        pub trait SupportsOnConflictClause {}
358
359        /// A marker trait indicating if a `ON CONFLICT (...) DO UPDATE ... [WHERE ...]` clause is supported or not
360        pub trait SupportsOnConflictClauseWhere {}
361
362        /// A marker trait indicating whether the on conflict clause implementation
363        /// is mostly like postgresql
364        pub trait PgLikeOnConflictClause: SupportsOnConflictClause {}
365
366        /// This marker type indicates that `ON CONFLICT` clauses are not supported for this backend
367        #[derive(Debug, Copy, Clone)]
368        pub struct DoesNotSupportOnConflictClause;
369    }
370
371    /// This module contains all reusable options to configure
372    /// [`SqlDialect::ReturningClause`]
373    #[diesel_derives::__diesel_public_if(
374        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
375    )]
376    pub mod returning_clause {
377        /// A marker trait indicating if a `RETURNING` clause is supported or not
378        ///
379        /// If you use a custom type to specify specialized support for `RETURNING` clauses
380        /// implementing this trait opts in supporting `RETURNING` clause syntax
381        pub trait SupportsReturningClause {}
382
383        /// Indicates that a backend provides support for `RETURNING` clauses
384        /// using the postgresql `RETURNING` syntax
385        #[derive(Debug, Copy, Clone)]
386        pub struct PgLikeReturningClause;
387
388        /// Indicates that a backend does not support `RETURNING` clauses
389        #[derive(Debug, Copy, Clone)]
390        pub struct DoesNotSupportReturningClause;
391
392        impl SupportsReturningClause for PgLikeReturningClause {}
393    }
394
395    /// This module contains all reusable options to configure
396    /// [`SqlDialect::InsertWithDefaultKeyword`]
397    #[diesel_derives::__diesel_public_if(
398        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
399    )]
400    pub mod default_keyword_for_insert {
401        /// A marker trait indicating if a `DEFAULT` like expression
402        /// is supported as part of `INSERT INTO` clauses to indicate
403        /// that a default value should be inserted at a specific position
404        ///
405        /// If you use a custom type to specify specialized support for `DEFAULT`
406        /// expressions implementing this trait opts in support for `DEFAULT`
407        /// value expressions for inserts. Otherwise diesel will emulate this
408        /// behaviour.
409        pub trait SupportsDefaultKeyword {}
410
411        /// Indicates that a backend support `DEFAULT` value expressions
412        /// for `INSERT INTO` statements based on the ISO SQL standard
413        #[derive(Debug, Copy, Clone)]
414        pub struct IsoSqlDefaultKeyword;
415
416        /// Indicates that a backend does not support `DEFAULT` value
417        /// expressions for `INSERT INTO` statements
418        #[derive(Debug, Copy, Clone)]
419        pub struct DoesNotSupportDefaultKeyword;
420
421        impl SupportsDefaultKeyword for IsoSqlDefaultKeyword {}
422    }
423
424    /// This module contains all reusable options to configure
425    /// [`SqlDialect::BatchInsertSupport`]
426    #[diesel_derives::__diesel_public_if(
427        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
428    )]
429    pub mod batch_insert_support {
430        /// A marker trait indicating if batch insert statements
431        /// are supported for this backend or not
432        pub trait SupportsBatchInsert {}
433
434        /// Indicates that this backend does not support batch
435        /// insert statements.
436        /// In this case diesel will emulate batch insert support
437        /// by inserting each row on its own
438        #[derive(Debug, Copy, Clone)]
439        pub struct DoesNotSupportBatchInsert;
440
441        /// Indicates that this backend supports postgres style
442        /// batch insert statements to insert multiple rows using one
443        /// insert statement
444        #[derive(Debug, Copy, Clone)]
445        pub struct PostgresLikeBatchInsertSupport;
446
447        impl SupportsBatchInsert for PostgresLikeBatchInsertSupport {}
448    }
449    /// This module contains all reusable options to configure
450    /// [`SqlDialect::ConcatClause`]
451    #[diesel_derives::__diesel_public_if(
452        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
453    )]
454    pub mod concat_clause {
455
456        /// Indicates that this backend uses the
457        /// `||` operator to select a concatenation
458        /// of two variables or strings
459        #[derive(Debug, Clone, Copy)]
460        pub struct ConcatWithPipesClause;
461    }
462
463    /// This module contains all reusable options to configure
464    /// [`SqlDialect::DefaultValueClauseForInsert`]
465    #[diesel_derives::__diesel_public_if(
466        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
467    )]
468    pub mod default_value_clause {
469
470        /// Indicates that this backend uses the
471        /// `DEFAULT VALUES` syntax to specify
472        /// that a row consisting only of default
473        /// values should be inserted
474        #[derive(Debug, Clone, Copy)]
475        pub struct AnsiDefaultValueClause;
476    }
477
478    /// This module contains all reusable options to configure
479    /// [`SqlDialect::EmptyFromClauseSyntax`]
480    #[diesel_derives::__diesel_public_if(
481        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
482    )]
483    pub(crate) mod from_clause_syntax {
484
485        /// Indicates that this backend skips
486        /// the `FROM` clause in `SELECT` statements
487        /// if no table/view is queried
488        #[derive(Debug, Copy, Clone)]
489        pub struct AnsiSqlFromClauseSyntax;
490    }
491
492    /// This module contains all reusable options to configure
493    /// [`SqlDialect::ExistsSyntax`]
494    #[diesel_derives::__diesel_public_if(
495        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
496    )]
497    pub mod exists_syntax {
498
499        /// Indicates that this backend
500        /// treats `EXIST()` as function
501        /// like expression
502        #[derive(Debug, Copy, Clone)]
503        pub struct AnsiSqlExistsSyntax;
504    }
505
506    /// This module contains all reusable options to configure
507    /// [`SqlDialect::ArrayComparison`]
508    #[diesel_derives::__diesel_public_if(
509        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
510    )]
511    pub mod array_comparison {
512
513        /// Indicates that this backend requires a single bind
514        /// per array element in `IN()` and `NOT IN()` expression
515        #[derive(Debug, Copy, Clone)]
516        pub struct AnsiSqlArrayComparison;
517    }
518
519    /// This module contains all reusable options to configure
520    /// [`SqlDialect::SelectStatementSyntax`]
521    #[diesel_derives::__diesel_public_if(
522        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
523    )]
524    pub mod select_statement_syntax {
525        /// Indicates that this backend uses the default
526        /// ANSI select statement structure
527        #[derive(Debug, Copy, Clone)]
528        pub struct AnsiSqlSelectStatement;
529    }
530
531    /// This module contains all reusable options to configure
532    /// [`SqlDialect::AliasSyntax`]
533    #[diesel_derives::__diesel_public_if(
534        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
535    )]
536    pub mod alias_syntax {
537        /// Indicates that this backend uses `table AS alias` for
538        /// defining table aliases
539        #[derive(Debug, Copy, Clone)]
540        pub struct AsAliasSyntax;
541    }
542}
543
544// These traits are not part of the public API
545// because we want to replace them by with an associated type
546// in the child trait later if GAT's are finally stable
547pub(crate) mod private {
548
549    /// This is a marker trait which indicates that
550    /// diesel may specialize a certain [`QueryFragment`]
551    /// impl in a later version. If you as a user encounter, where rustc
552    /// suggests adding this a bound to a type implementing `Backend`
553    /// consider adding the following bound instead
554    /// `YourQueryType: QueryFragment<DB>` (the concrete bound
555    /// is likely mentioned by rustc as part of a `note: …`)
556    ///
557    /// For any user implementing a custom backend: You likely want to implement
558    /// this trait for your custom backend type to opt in the existing [`QueryFragment`] impls in diesel.
559    /// As indicated by the `i-implement-a-third-party-backend-and-opt-into-breaking-changes` feature
560    /// diesel reserves the right to specialize any generic [`QueryFragment`](crate::query_builder::QueryFragment)
561    /// impl via [`SqlDialect`](super::SqlDialect) in a later minor version release
562    ///
563    /// [`QueryFragment`]: crate::query_builder::QueryFragment
564    #[cfg_attr(
565        docsrs,
566        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
567    )]
568    pub trait DieselReserveSpecialization {}
569
570    /// This trait just indicates that none implements
571    /// [`SqlDialect`](super::SqlDialect) without enabling the
572    /// `i-implement-a-third-party-backend-and-opt-into-breaking-changes`
573    /// feature flag.
574    #[cfg_attr(
575        docsrs,
576        doc(cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))
577    )]
578    pub trait TrustedBackend {}
579}