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}