1//! Contains traits responsible for the actual construction of SQL statements
2//!
3//! The types in this module are part of Diesel's public API, but are generally
4//! only useful for implementing Diesel plugins. Applications should generally
5//! not need to care about the types inside of this module.
67#[macro_use]
8mod query_id;
9#[macro_use]
10mod clause_macro;
1112pub(crate) mod ast_pass;
13pub mod bind_collector;
14mod collected_query;
15pub(crate) mod combination_clause;
16mod debug_query;
17mod delete_statement;
18mod distinct_clause;
19pub(crate) mod from_clause;
20pub(crate) mod functions;
21pub(crate) mod group_by_clause;
22mod having_clause;
23pub(crate) mod insert_statement;
24pub(crate) mod limit_clause;
25pub(crate) mod limit_offset_clause;
26pub(crate) mod locking_clause;
27pub(crate) mod nodes;
28pub(crate) mod offset_clause;
29pub(crate) mod order_clause;
30pub(crate) mod select_clause;
31pub(crate) mod select_statement;
32mod sql_query;
33pub(crate) mod update_statement;
34pub(crate) mod upsert;
35pub(crate) mod where_clause;
3637#[doc(inline)]
38pub use self::ast_pass::AstPass;
39#[doc(inline)]
40pub use self::bind_collector::{BindCollector, MoveableBindCollector};
41#[doc(inline)]
42pub use self::collected_query::CollectedQuery;
43#[doc(inline)]
44pub use self::debug_query::DebugQuery;
45#[doc(inline)]
46pub use self::delete_statement::{
47BoxedCloneDeleteStatement, BoxedDeleteStatement, DeleteStatement,
48};
49#[cfg(any(feature = "mysql_backend", feature = "mariadb_backend"))]
50#[doc(inline)]
51pub use self::insert_statement::SingleRowInsertValues;
52#[doc(inline)]
53pub use self::insert_statement::{
54IncompleteInsertOrIgnoreStatement, IncompleteInsertStatement, IncompleteReplaceStatement,
55InsertOrIgnoreStatement, InsertStatement, ReplaceStatement,
56};
57#[doc(inline)]
58pub use self::query_id::QueryId;
59#[doc(inline)]
60pub use self::sql_query::{BoxedCloneSqlQuery, BoxedSqlQuery, SqlQuery};
61#[doc(inline)]
62pub use self::upsert::into_conflict_clause::IntoConflictValueClause;
63#[doc(inline)]
64pub use self::upsert::on_conflict_target::{ConflictTarget, OnConflictTarget};
65#[doc(inline)]
66pub use self::upsert::on_conflict_target_decorations::DecoratableTarget;
6768#[doc(inline)]
69pub use self::update_statement::changeset::AsChangeset;
70#[doc(inline)]
71pub use self::update_statement::target::{IntoUpdateTarget, UpdateTarget};
72#[doc(inline)]
73pub use self::update_statement::{
74BoxedCloneUpdateStatement, BoxedUpdateStatement, UpdateStatement,
75};
7677#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
78pub use self::combination_clause::{
79All, Distinct, Except, Intersect, ParenthesisWrapper, SupportsCombinationClause, Union,
80};
81#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
82pub use self::limit_clause::{LimitClause, NoLimitClause};
83#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
84pub use self::limit_offset_clause::{
85BoxedCloneLimitOffsetClause, BoxedLimitOffsetClause, LimitOffsetClause,
86};
87#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
88pub use self::offset_clause::{NoOffsetClause, OffsetClause};
89#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
90pub use self::order_clause::{NoOrderClause, OrderClause};
9192#[doc(inline)]
pub use self::insert_statement::batch_insert::BatchInsert;#[diesel_derives::__diesel_public_if(
93 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
94)]95#[doc(inline)]
96pub(crate) use self::insert_statement::batch_insert::BatchInsert;
97pub use self::insert_statement::{UndecoratedInsertRecord, ValuesClause};#[diesel_derives::__diesel_public_if(
98 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
99)]100pub(crate) use self::insert_statement::{UndecoratedInsertRecord, ValuesClause};
101102#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
103#[doc(inline)]
104pub use self::insert_statement::{DefaultValues, InsertOrIgnore, Replace};
105106#[cfg(not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))]
107pub(crate) mod returning;
108#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
109pub mod returning;
110111#[doc(inline)]
112#[doc(inline)]
pub use self::ast_pass::AstPassToSqlOptions;#[diesel_derives::__diesel_public_if(
113 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
114)]115pub(crate) use self::ast_pass::AstPassToSqlOptions;
116117#[doc(inline)]
118#[doc(inline)]
pub use self::select_clause::SelectClauseExpression;#[diesel_derives::__diesel_public_if(
119 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
120)]121pub(crate) use self::select_clause::SelectClauseExpression;
122123#[doc(inline)]
124#[doc(inline)]
pub use self::from_clause::{FromClause, NoFromClause};#[diesel_derives::__diesel_public_if(
125 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
126)]127pub(crate) use self::from_clause::{FromClause, NoFromClause};
128#[cfg_attr(
129 not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"),
130 allow(unused_imports)
131)]
132#[doc(inline)]
pub use self::group_by_clause::{GroupByClause, NoGroupByClause};#[diesel_derives::__diesel_public_if(
133 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
134)]135#[doc(inline)]
136pub(crate) use self::group_by_clause::{GroupByClause, NoGroupByClause};
137#[doc(inline)]
pub use self::select_statement::BoxedCloneSelectStatement;#[diesel_derives::__diesel_public_if(
138 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
139)]140#[doc(inline)]
141pub(crate) use self::select_statement::BoxedCloneSelectStatement;
142#[doc(inline)]
pub use self::select_statement::BoxedSelectStatement;#[diesel_derives::__diesel_public_if(
143 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
144)]145#[doc(inline)]
146pub(crate) use self::select_statement::BoxedSelectStatement;
147148#[doc(inline)]
pub use self::select_statement::SelectStatement;#[diesel_derives::__diesel_public_if(
149 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
150)]151#[doc(inline)]
152pub(crate) use self::select_statement::SelectStatement;
153154pub(crate) use self::insert_statement::ColumnList;
155156#[cfg(feature = "postgres_backend")]
157pub use crate::pg::query_builder::only::Only;
158159#[cfg(feature = "postgres_backend")]
160pub use crate::pg::query_builder::tablesample::{Tablesample, TablesampleMethod};
161162pub(crate) use self::bind_collector::BindData;
163#[cfg(feature = "postgres_backend")]
164pub(crate) use self::bind_collector::ByteWrapper;
165use crate::backend::Backend;
166use crate::result::QueryResult;
167use alloc::boxed::Box;
168use alloc::string::String;
169use alloc::vec::Vec;
170use core::error::Error;
171172pub(crate) use self::private::NotSpecialized;
173174#[doc(hidden)]
175pub type Binds = Vec<Option<Vec<u8>>>;
176/// A specialized Result type used with the query builder.
177pub type BuildQueryResult = Result<(), Box<dyn Error + Send + Sync>>;
178179/// Constructs a SQL query from a Diesel AST.
180///
181/// The only reason you should ever need to interact with this trait is if you
182/// are extending Diesel with support for a new backend. Plugins which extend
183/// the query builder with new capabilities will interact with [`AstPass`]
184/// instead.
185pub trait QueryBuilder<DB: Backend> {
186/// Add `sql` to the end of the query being constructed.
187fn push_sql(&mut self, sql: &str);
188189/// Quote `identifier`, and add it to the end of the query being
190 /// constructed.
191fn push_identifier(&mut self, identifier: &str) -> QueryResult<()>;
192193/// Add a placeholder for a bind parameter to the end of the query being
194 /// constructed.
195fn push_bind_param(&mut self);
196197/// Increases the internal counter for bind parameters without adding the
198 /// bind parameter itself to the query
199fn push_bind_param_value_only(&mut self) {}
200201/// Returns the constructed SQL query.
202fn finish(self) -> String;
203}
204205/// A complete SQL query with a return type.
206///
207/// This can be a select statement, or a command such as `update` or `insert`
208/// with a `RETURNING` clause. Unlike [`Expression`], types implementing this
209/// trait are guaranteed to be executable on their own.
210///
211/// A type which doesn't implement this trait may still represent a complete SQL
212/// query. For example, an `INSERT` statement without a `RETURNING` clause will
213/// not implement this trait, but can still be executed.
214///
215/// [`Expression`]: crate::expression::Expression
216pub trait Query {
217/// The SQL type that this query represents.
218 ///
219 /// This is the SQL type of the `SELECT` clause for select statements, and
220 /// the SQL type of the `RETURNING` clause for insert, update, or delete
221 /// statements.
222type SqlType;
223}
224225impl<T: Query> Queryfor &T {
226type SqlType = T::SqlType;
227}
228229/// Indicates that a type is a `SELECT` statement.
230///
231/// This trait differs from `Query` in two ways:
232/// - It is implemented only for select statements, rather than all queries
233/// which return a value.
234/// - It has looser constraints. A type implementing `SelectQuery` is known to
235/// be potentially valid if used as a subselect, but it is not necessarily
236/// able to be executed.
237pub trait SelectQuery {
238/// The SQL type of the `SELECT` clause
239type SqlType;
240}
241242/// An untyped fragment of SQL.
243///
244/// This may be a complete SQL command (such as an update statement without a
245/// `RETURNING` clause), or a subsection (such as our internal types used to
246/// represent a `WHERE` clause). Implementations of [`ExecuteDsl`] and
247/// [`LoadQuery`] will generally require that this trait be implemented.
248///
249/// [`ExecuteDsl`]: crate::query_dsl::methods::ExecuteDsl
250/// [`LoadQuery`]: crate::query_dsl::methods::LoadQuery
251#[diagnostic::on_unimplemented(
252 message = "`{Self}` is no valid SQL fragment for the `{DB}` backend",
253 note = "this usually means that the `{DB}` database system does not support \n\
254 this SQL syntax"
255)]
256pub trait QueryFragment<DB: Backend, SP = self::private::NotSpecialized> {
257/// Walk over this `QueryFragment` for all passes.
258 ///
259 /// This method is where the actual behavior of an AST node is implemented.
260 /// This method will contain the behavior required for all possible AST
261 /// passes. See [`AstPass`] for more details.
262fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()>;
263264/// Converts this `QueryFragment` to its SQL representation.
265 ///
266 /// This method should only be called by implementations of `Connection`.
267#[diesel_derives::__diesel_public_if(
268 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
269)]
270fn to_sql(&self, out: &mut DB::QueryBuilder, backend: &DB) -> QueryResult<()> {
271let mut options = AstPassToSqlOptions::default();
272self.walk_ast(AstPass::to_sql(out, &mut options, backend))
273 }
274275/// Serializes all bind parameters in this query.
276 ///
277 /// A bind parameter is a value which is sent separately from the query
278 /// itself. It is represented in SQL with a placeholder such as `?` or `$1`.
279 ///
280 /// This method should only be called by implementations of `Connection`.
281#[diesel_derives::__diesel_public_if(
282 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
283)]
284fn collect_binds<'b>(
285&'b self,
286 out: &mut DB::BindCollector<'b>,
287 metadata_lookup: &mut DB::MetadataLookup,
288 backend: &'b DB,
289 ) -> QueryResult<()> {
290self.walk_ast(AstPass::collect_binds(out, metadata_lookup, backend))
291 }
292293/// Is this query safe to store in the prepared statement cache?
294 ///
295 /// In order to keep our prepared statement cache at a reasonable size, we
296 /// avoid caching any queries which represent a potentially unbounded number
297 /// of SQL queries. Generally this will only return `true` for queries for
298 /// which `to_sql` will always construct exactly identical SQL.
299 ///
300 /// Some examples of where this method will return `false` are:
301 ///
302 /// - `SqlLiteral` (We don't know if the SQL was constructed dynamically, so
303 /// we must assume that it was)
304 /// - `In` and `NotIn` (Each value requires a separate bind param
305 /// placeholder)
306 ///
307 /// This method should only be called by implementations of `Connection`.
308#[diesel_derives::__diesel_public_if(
309 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
310)]
311fn is_safe_to_cache_prepared(&self, backend: &DB) -> QueryResult<bool> {
312let mut result = true;
313self.walk_ast(AstPass::is_safe_to_cache_prepared(&mut result, backend))?;
314Ok(result)
315 }
316317/// Does walking this AST have any effect?
318#[diesel_derives::__diesel_public_if(
319 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
320)]
321fn is_noop(&self, backend: &DB) -> QueryResult<bool> {
322let mut result = true;
323self.walk_ast(AstPass::is_noop(&mut result, backend))?;
324Ok(result)
325 }
326327/// Count the number of binds in a given prepared statement
328#[diesel_derives::__diesel_public_if(
329 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
330)]
331fn count_binds(&self, backend: &DB) -> QueryResult<usize> {
332let mut count = 0;
333self.walk_ast(AstPass::count_binds(&mut count, backend))?;
334Ok(count)
335 }
336}
337338impl<T: ?Sized, DB> QueryFragment<DB> for Box<T>
339where
340DB: Backend,
341 T: QueryFragment<DB>,
342{
343fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
344 QueryFragment::walk_ast(&**self, pass)
345 }
346}
347348impl<T: ?Sized, DB> QueryFragment<DB> for alloc::rc::Rc<T>
349where
350DB: Backend,
351 T: QueryFragment<DB>,
352{
353fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
354 QueryFragment::walk_ast(&**self, pass)
355 }
356}
357358impl<T: ?Sized, DB> QueryFragment<DB> for alloc::sync::Arc<T>
359where
360DB: Backend,
361 T: QueryFragment<DB>,
362{
363fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
364 QueryFragment::walk_ast(&**self, pass)
365 }
366}
367368impl<T: ?Sized, DB> QueryFragment<DB> for &T
369where
370DB: Backend,
371 T: QueryFragment<DB>,
372{
373fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
374 QueryFragment::walk_ast(&**self, pass)
375 }
376}
377378impl<DB: Backend> QueryFragment<DB> for () {
379fn walk_ast<'b>(&'b self, _: AstPass<'_, 'b, DB>) -> QueryResult<()> {
380Ok(())
381 }
382}
383384impl<T, DB> QueryFragment<DB> for Option<T>
385where
386DB: Backend,
387 T: QueryFragment<DB>,
388{
389fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
390match *self {
391Some(ref c) => c.walk_ast(out),
392None => Ok(()),
393 }
394 }
395}
396397/// A trait used to construct type erased boxed variant of the current query node
398///
399/// Mainly useful for implementing third party backends
400#[diagnostic::on_unimplemented(
401 note = "this usually means that `{Self}` is no valid SQL for `{DB}`"
402)]
403pub trait IntoBoxedClause<'a, DB> {
404/// Resulting type
405type BoxedClause;
406407/// Convert the given query node in it's boxed representation
408fn into_boxed(self) -> Self::BoxedClause;
409}
410411/// A trait used to construct type erased boxed cloneable variant of the current query node
412///
413/// Mainly useful for implementing third party backends
414#[diagnostic::on_unimplemented(
415 note = "this usually means that `{Self}` is no valid SQL for `{DB}`"
416)]
417pub trait IntoBoxedCloneClause<'a, DB> {
418/// Resulting type
419type BoxedCloneClause;
420421/// Convert the given query node in it's boxed cloneable representation
422fn into_boxed_clone(self) -> Self::BoxedCloneClause;
423}
424425/// Types that can be converted into a complete, typed SQL query.
426///
427/// This is used internally to automatically add the right select clause when
428/// none is specified, or to automatically add `RETURNING *` in certain contexts.
429///
430/// A type which implements this trait is guaranteed to be valid for execution.
431pub trait AsQuery {
432/// The SQL type of `Self::Query`
433type SqlType;
434435/// What kind of query does this type represent?
436type Query: Query<SqlType = Self::SqlType>;
437438/// Converts a type which semantically represents a SQL query into the
439 /// actual query being executed. See the trait level docs for more.
440// This method is part of our public API,
441 // so we won't change the name to just appease clippy
442 // (Also the trait is literally named `AsQuery` so
443 // naming the method similarity is fine)
444#[allow(clippy::wrong_self_convention)]
445fn as_query(self) -> Self::Query;
446}
447448impl<T: Query> AsQueryfor T {
449type SqlType = <T as Query>::SqlType;
450type Query = T;
451452fn as_query(self) -> <T as AsQuery>::Query {
453self454 }
455}
456457/// Takes a query `QueryFragment` expression as an argument and returns a type
458/// that implements `fmt::Display` and `fmt::Debug` to show the query.
459///
460/// The `Display` implementation will show the exact query being sent to the
461/// server, with a comment showing the values of the bind parameters. The
462/// `Debug` implementation will include the same information in a more
463/// structured form, and respects pretty printing.
464///
465/// # Example
466///
467/// ### Returning SQL from a count statement:
468///
469/// ```rust
470/// # include!("../doctest_setup.rs");
471/// #
472/// # use diesel::*;
473/// # use schema::*;
474/// #
475/// # fn main() {
476/// # use schema::users::dsl::*;
477/// let sql = debug_query::<DB, _>(&users.count()).to_string();
478/// # if cfg!(feature = "postgres") {
479/// # assert_eq!(sql, r#"SELECT COUNT(*) FROM "users" -- binds: []"#);
480/// # } else {
481/// assert_eq!(sql, "SELECT COUNT(*) FROM `users` -- binds: []");
482/// # }
483///
484/// let query = users.find(1);
485/// let debug = debug_query::<DB, _>(&query);
486/// # if cfg!(feature = "postgres") {
487/// # assert_eq!(debug.to_string(), "SELECT \"users\".\"id\", \"users\".\"name\" \
488/// # FROM \"users\" WHERE (\"users\".\"id\" = $1) -- binds: [1]");
489/// # } else {
490/// assert_eq!(
491/// debug.to_string(),
492/// "SELECT `users`.`id`, `users`.`name` FROM `users` \
493/// WHERE (`users`.`id` = ?) -- binds: [1]"
494/// );
495/// # }
496///
497/// let debug = format!("{:?}", debug);
498/// # if !cfg!(feature = "postgres") { // Escaping that string is a pain
499/// let expected = "Query { \
500/// sql: \"SELECT `users`.`id`, `users`.`name` FROM `users` WHERE \
501/// (`users`.`id` = ?)\", \
502/// binds: [1] \
503/// }";
504/// assert_eq!(debug, expected);
505/// # }
506/// # }
507/// ```
508pub fn debug_query<DB, T>(query: &T) -> DebugQuery<'_, T, DB> {
509DebugQuery::new(query)
510}
511512mod private {
513#[allow(missing_debug_implementations, missing_copy_implementations)]
514pub struct NotSpecialized;
515}
516517pub(crate) mod has_query;