Skip to main content

diesel/query_builder/
mod.rs

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.
6
7#[macro_use]
8mod query_id;
9#[macro_use]
10mod clause_macro;
11
12pub(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;
36
37#[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::{BoxedDeleteStatement, DeleteStatement};
47#[doc(inline)]
48pub use self::insert_statement::{
49    IncompleteInsertOrIgnoreStatement, IncompleteInsertStatement, IncompleteReplaceStatement,
50    InsertOrIgnoreStatement, InsertStatement, ReplaceStatement,
51};
52#[doc(inline)]
53pub use self::query_id::QueryId;
54#[doc(inline)]
55pub use self::sql_query::{BoxedSqlQuery, SqlQuery};
56#[doc(inline)]
57pub use self::upsert::into_conflict_clause::IntoConflictValueClause;
58#[doc(inline)]
59pub use self::upsert::on_conflict_target::{ConflictTarget, OnConflictTarget};
60#[doc(inline)]
61pub use self::upsert::on_conflict_target_decorations::DecoratableTarget;
62
63#[doc(inline)]
64pub use self::update_statement::changeset::AsChangeset;
65#[doc(inline)]
66pub use self::update_statement::target::{IntoUpdateTarget, UpdateTarget};
67#[doc(inline)]
68pub use self::update_statement::{BoxedUpdateStatement, UpdateStatement};
69
70#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
71pub use self::combination_clause::{
72    All, Distinct, Except, Intersect, ParenthesisWrapper, SupportsCombinationClause, Union,
73};
74#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
75pub use self::limit_clause::{LimitClause, NoLimitClause};
76#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
77pub use self::limit_offset_clause::{BoxedLimitOffsetClause, LimitOffsetClause};
78#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
79pub use self::offset_clause::{NoOffsetClause, OffsetClause};
80#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
81pub use self::order_clause::{NoOrderClause, OrderClause};
82
83#[doc(inline)]
pub use self::insert_statement::batch_insert::BatchInsert;#[diesel_derives::__diesel_public_if(
84    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
85)]
86#[doc(inline)]
87pub(crate) use self::insert_statement::batch_insert::BatchInsert;
88pub use self::insert_statement::{UndecoratedInsertRecord, ValuesClause};#[diesel_derives::__diesel_public_if(
89    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
90)]
91pub(crate) use self::insert_statement::{UndecoratedInsertRecord, ValuesClause};
92
93#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
94#[doc(inline)]
95pub use self::insert_statement::{DefaultValues, InsertOrIgnore, Replace};
96
97#[cfg(not(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"))]
98pub(crate) mod returning;
99#[cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")]
100pub mod returning;
101
102#[doc(inline)]
103#[doc(inline)]
pub use self::ast_pass::AstPassToSqlOptions;#[diesel_derives::__diesel_public_if(
104    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
105)]
106pub(crate) use self::ast_pass::AstPassToSqlOptions;
107
108#[doc(inline)]
109#[doc(inline)]
pub use self::select_clause::SelectClauseExpression;#[diesel_derives::__diesel_public_if(
110    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
111)]
112pub(crate) use self::select_clause::SelectClauseExpression;
113
114#[doc(inline)]
115#[doc(inline)]
pub use self::from_clause::{FromClause, NoFromClause};#[diesel_derives::__diesel_public_if(
116    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
117)]
118pub(crate) use self::from_clause::{FromClause, NoFromClause};
119#[doc(inline)]
pub use self::select_statement::BoxedSelectStatement;#[diesel_derives::__diesel_public_if(
120    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
121)]
122#[doc(inline)]
123pub(crate) use self::select_statement::BoxedSelectStatement;
124
125#[doc(inline)]
pub use self::select_statement::SelectStatement;#[diesel_derives::__diesel_public_if(
126    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
127)]
128#[doc(inline)]
129pub(crate) use self::select_statement::SelectStatement;
130
131pub(crate) use self::insert_statement::ColumnList;
132
133#[cfg(feature = "postgres_backend")]
134pub use crate::pg::query_builder::only::Only;
135
136#[cfg(feature = "postgres_backend")]
137pub use crate::pg::query_builder::tablesample::{Tablesample, TablesampleMethod};
138
139#[cfg(feature = "postgres_backend")]
140pub(crate) use self::bind_collector::ByteWrapper;
141use crate::backend::Backend;
142use crate::result::QueryResult;
143use alloc::boxed::Box;
144use alloc::string::String;
145use alloc::vec::Vec;
146use core::error::Error;
147
148pub(crate) use self::private::NotSpecialized;
149
150#[doc(hidden)]
151pub type Binds = Vec<Option<Vec<u8>>>;
152/// A specialized Result type used with the query builder.
153pub type BuildQueryResult = Result<(), Box<dyn Error + Send + Sync>>;
154
155/// Constructs a SQL query from a Diesel AST.
156///
157/// The only reason you should ever need to interact with this trait is if you
158/// are extending Diesel with support for a new backend. Plugins which extend
159/// the query builder with new capabilities will interact with [`AstPass`]
160/// instead.
161pub trait QueryBuilder<DB: Backend> {
162    /// Add `sql` to the end of the query being constructed.
163    fn push_sql(&mut self, sql: &str);
164
165    /// Quote `identifier`, and add it to the end of the query being
166    /// constructed.
167    fn push_identifier(&mut self, identifier: &str) -> QueryResult<()>;
168
169    /// Add a placeholder for a bind parameter to the end of the query being
170    /// constructed.
171    fn push_bind_param(&mut self);
172
173    /// Increases the internal counter for bind parameters without adding the
174    /// bind parameter itself to the query
175    fn push_bind_param_value_only(&mut self) {}
176
177    /// Returns the constructed SQL query.
178    fn finish(self) -> String;
179}
180
181/// A complete SQL query with a return type.
182///
183/// This can be a select statement, or a command such as `update` or `insert`
184/// with a `RETURNING` clause. Unlike [`Expression`], types implementing this
185/// trait are guaranteed to be executable on their own.
186///
187/// A type which doesn't implement this trait may still represent a complete SQL
188/// query. For example, an `INSERT` statement without a `RETURNING` clause will
189/// not implement this trait, but can still be executed.
190///
191/// [`Expression`]: crate::expression::Expression
192pub trait Query {
193    /// The SQL type that this query represents.
194    ///
195    /// This is the SQL type of the `SELECT` clause for select statements, and
196    /// the SQL type of the `RETURNING` clause for insert, update, or delete
197    /// statements.
198    type SqlType;
199}
200
201impl<T: Query> Query for &T {
202    type SqlType = T::SqlType;
203}
204
205/// Indicates that a type is a `SELECT` statement.
206///
207/// This trait differs from `Query` in two ways:
208/// - It is implemented only for select statements, rather than all queries
209///   which return a value.
210/// - It has looser constraints. A type implementing `SelectQuery` is known to
211///   be potentially valid if used as a subselect, but it is not necessarily
212///   able to be executed.
213pub trait SelectQuery {
214    /// The SQL type of the `SELECT` clause
215    type SqlType;
216}
217
218/// An untyped fragment of SQL.
219///
220/// This may be a complete SQL command (such as an update statement without a
221/// `RETURNING` clause), or a subsection (such as our internal types used to
222/// represent a `WHERE` clause). Implementations of [`ExecuteDsl`] and
223/// [`LoadQuery`] will generally require that this trait be implemented.
224///
225/// [`ExecuteDsl`]: crate::query_dsl::methods::ExecuteDsl
226/// [`LoadQuery`]: crate::query_dsl::methods::LoadQuery
227#[diagnostic::on_unimplemented(
228    message = "`{Self}` is no valid SQL fragment for the `{DB}` backend",
229    note = "this usually means that the `{DB}` database system does not support \n\
230            this SQL syntax"
231)]
232pub trait QueryFragment<DB: Backend, SP = self::private::NotSpecialized> {
233    /// Walk over this `QueryFragment` for all passes.
234    ///
235    /// This method is where the actual behavior of an AST node is implemented.
236    /// This method will contain the behavior required for all possible AST
237    /// passes. See [`AstPass`] for more details.
238    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()>;
239
240    /// Converts this `QueryFragment` to its SQL representation.
241    ///
242    /// This method should only be called by implementations of `Connection`.
243    #[diesel_derives::__diesel_public_if(
244        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
245    )]
246    fn to_sql(&self, out: &mut DB::QueryBuilder, backend: &DB) -> QueryResult<()> {
247        let mut options = AstPassToSqlOptions::default();
248        self.walk_ast(AstPass::to_sql(out, &mut options, backend))
249    }
250
251    /// Serializes all bind parameters in this query.
252    ///
253    /// A bind parameter is a value which is sent separately from the query
254    /// itself. It is represented in SQL with a placeholder such as `?` or `$1`.
255    ///
256    /// This method should only be called by implementations of `Connection`.
257    #[diesel_derives::__diesel_public_if(
258        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
259    )]
260    fn collect_binds<'b>(
261        &'b self,
262        out: &mut DB::BindCollector<'b>,
263        metadata_lookup: &mut DB::MetadataLookup,
264        backend: &'b DB,
265    ) -> QueryResult<()> {
266        self.walk_ast(AstPass::collect_binds(out, metadata_lookup, backend))
267    }
268
269    /// Is this query safe to store in the prepared statement cache?
270    ///
271    /// In order to keep our prepared statement cache at a reasonable size, we
272    /// avoid caching any queries which represent a potentially unbounded number
273    /// of SQL queries. Generally this will only return `true` for queries for
274    /// which `to_sql` will always construct exactly identical SQL.
275    ///
276    /// Some examples of where this method will return `false` are:
277    ///
278    /// - `SqlLiteral` (We don't know if the SQL was constructed dynamically, so
279    ///   we must assume that it was)
280    /// - `In` and `NotIn` (Each value requires a separate bind param
281    ///   placeholder)
282    ///
283    /// This method should only be called by implementations of `Connection`.
284    #[diesel_derives::__diesel_public_if(
285        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
286    )]
287    fn is_safe_to_cache_prepared(&self, backend: &DB) -> QueryResult<bool> {
288        let mut result = true;
289        self.walk_ast(AstPass::is_safe_to_cache_prepared(&mut result, backend))?;
290        Ok(result)
291    }
292
293    /// Does walking this AST have any effect?
294    #[diesel_derives::__diesel_public_if(
295        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
296    )]
297    fn is_noop(&self, backend: &DB) -> QueryResult<bool> {
298        let mut result = true;
299        self.walk_ast(AstPass::is_noop(&mut result, backend))?;
300        Ok(result)
301    }
302}
303
304impl<T: ?Sized, DB> QueryFragment<DB> for Box<T>
305where
306    DB: Backend,
307    T: QueryFragment<DB>,
308{
309    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
310        QueryFragment::walk_ast(&**self, pass)
311    }
312}
313
314impl<T: ?Sized, DB> QueryFragment<DB> for alloc::rc::Rc<T>
315where
316    DB: Backend,
317    T: QueryFragment<DB>,
318{
319    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
320        QueryFragment::walk_ast(&**self, pass)
321    }
322}
323
324impl<T: ?Sized, DB> QueryFragment<DB> for alloc::sync::Arc<T>
325where
326    DB: Backend,
327    T: QueryFragment<DB>,
328{
329    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
330        QueryFragment::walk_ast(&**self, pass)
331    }
332}
333
334impl<T: ?Sized, DB> QueryFragment<DB> for &T
335where
336    DB: Backend,
337    T: QueryFragment<DB>,
338{
339    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
340        QueryFragment::walk_ast(&**self, pass)
341    }
342}
343
344impl<DB: Backend> QueryFragment<DB> for () {
345    fn walk_ast<'b>(&'b self, _: AstPass<'_, 'b, DB>) -> QueryResult<()> {
346        Ok(())
347    }
348}
349
350impl<T, DB> QueryFragment<DB> for Option<T>
351where
352    DB: Backend,
353    T: QueryFragment<DB>,
354{
355    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
356        match *self {
357            Some(ref c) => c.walk_ast(out),
358            None => Ok(()),
359        }
360    }
361}
362
363/// A trait used to construct type erased boxed variant of the current query node
364///
365/// Mainly useful for implementing third party backends
366#[diagnostic::on_unimplemented(
367    note = "this usually means that `{Self}` is no valid SQL for `{DB}`"
368)]
369pub trait IntoBoxedClause<'a, DB> {
370    /// Resulting type
371    type BoxedClause;
372
373    /// Convert the given query node in it's boxed representation
374    fn into_boxed(self) -> Self::BoxedClause;
375}
376
377/// Types that can be converted into a complete, typed SQL query.
378///
379/// This is used internally to automatically add the right select clause when
380/// none is specified, or to automatically add `RETURNING *` in certain contexts.
381///
382/// A type which implements this trait is guaranteed to be valid for execution.
383pub trait AsQuery {
384    /// The SQL type of `Self::Query`
385    type SqlType;
386
387    /// What kind of query does this type represent?
388    type Query: Query<SqlType = Self::SqlType>;
389
390    /// Converts a type which semantically represents a SQL query into the
391    /// actual query being executed. See the trait level docs for more.
392    // This method is part of our public API,
393    // so we won't change the name to just appease clippy
394    // (Also the trait is literally named `AsQuery` so
395    // naming the method similarity is fine)
396    #[allow(clippy::wrong_self_convention)]
397    fn as_query(self) -> Self::Query;
398}
399
400impl<T: Query> AsQuery for T {
401    type SqlType = <T as Query>::SqlType;
402    type Query = T;
403
404    fn as_query(self) -> <T as AsQuery>::Query {
405        self
406    }
407}
408
409/// Takes a query `QueryFragment` expression as an argument and returns a type
410/// that implements `fmt::Display` and `fmt::Debug` to show the query.
411///
412/// The `Display` implementation will show the exact query being sent to the
413/// server, with a comment showing the values of the bind parameters. The
414/// `Debug` implementation will include the same information in a more
415/// structured form, and respects pretty printing.
416///
417/// # Example
418///
419/// ### Returning SQL from a count statement:
420///
421/// ```rust
422/// # include!("../doctest_setup.rs");
423/// #
424/// # use diesel::*;
425/// # use schema::*;
426/// #
427/// # fn main() {
428/// #   use schema::users::dsl::*;
429/// let sql = debug_query::<DB, _>(&users.count()).to_string();
430/// # if cfg!(feature = "postgres") {
431/// #     assert_eq!(sql, r#"SELECT COUNT(*) FROM "users" -- binds: []"#);
432/// # } else {
433/// assert_eq!(sql, "SELECT COUNT(*) FROM `users` -- binds: []");
434/// # }
435///
436/// let query = users.find(1);
437/// let debug = debug_query::<DB, _>(&query);
438/// # if cfg!(feature = "postgres") {
439/// #     assert_eq!(debug.to_string(), "SELECT \"users\".\"id\", \"users\".\"name\" \
440/// #         FROM \"users\" WHERE (\"users\".\"id\" = $1) -- binds: [1]");
441/// # } else {
442/// assert_eq!(
443///     debug.to_string(),
444///     "SELECT `users`.`id`, `users`.`name` FROM `users` \
445///     WHERE (`users`.`id` = ?) -- binds: [1]"
446/// );
447/// # }
448///
449/// let debug = format!("{:?}", debug);
450/// # if !cfg!(feature = "postgres") { // Escaping that string is a pain
451/// let expected = "Query { \
452///     sql: \"SELECT `users`.`id`, `users`.`name` FROM `users` WHERE \
453///         (`users`.`id` = ?)\", \
454///     binds: [1] \
455/// }";
456/// assert_eq!(debug, expected);
457/// # }
458/// # }
459/// ```
460pub fn debug_query<DB, T>(query: &T) -> DebugQuery<'_, T, DB> {
461    DebugQuery::new(query)
462}
463
464mod private {
465    #[allow(missing_debug_implementations, missing_copy_implementations)]
466    pub struct NotSpecialized;
467}
468
469pub(crate) mod has_query;