diesel/query_builder/insert_statement/
mod.rs

1pub(crate) mod batch_insert;
2mod column_list;
3mod insert_from_select;
4
5pub(crate) use self::batch_insert::BatchInsert;
6pub(crate) use self::column_list::ColumnList;
7pub(crate) use self::insert_from_select::InsertFromSelect;
8#[diesel_derives::__diesel_public_if(
9    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
10)]
11pub(crate) use self::private::{Insert, InsertOrIgnore, Replace};
12
13use super::returning_clause::*;
14use crate::backend::{sql_dialect, DieselReserveSpecialization, SqlDialect};
15use crate::expression::grouped::Grouped;
16use crate::expression::operators::Eq;
17use crate::expression::{Expression, NonAggregate, SelectableExpression};
18use crate::query_builder::*;
19use crate::query_dsl::RunQueryDsl;
20use crate::query_source::{Column, Table};
21use crate::{insertable::*, QuerySource};
22use std::marker::PhantomData;
23
24pub(crate) use self::private::InsertAutoTypeHelper;
25
26#[cfg(feature = "sqlite")]
27mod insert_with_default_for_sqlite;
28
29/// The structure returned by [`insert_into`].
30///
31/// The provided methods [`values`] and [`default_values`] will insert
32/// data into the targeted table.
33///
34/// [`insert_into`]: crate::insert_into()
35/// [`values`]: IncompleteInsertStatement::values()
36/// [`default_values`]: IncompleteInsertStatement::default_values()
37#[derive(Debug, Clone, Copy)]
38#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
39pub struct IncompleteInsertStatement<T, Op = Insert> {
40    target: T,
41    operator: Op,
42}
43
44/// Represents the return type of [`diesel::insert_or_ignore_into`](crate::insert_or_ignore_into)
45pub type IncompleteInsertOrIgnoreStatement<T> = IncompleteInsertStatement<T, InsertOrIgnore>;
46
47/// Represents a complete `INSERT OR IGNORE` statement.
48pub type InsertOrIgnoreStatement<T, U, Ret = NoReturningClause> =
49    InsertStatement<T, U, InsertOrIgnore, Ret>;
50
51/// Represents the return type of [`diesel::replace_into`](crate::replace_into)
52pub type IncompleteReplaceStatement<T> = IncompleteInsertStatement<T, Replace>;
53
54/// Represents a complete `INSERT OR REPLACE` statement.
55pub type ReplaceStatement<T, U, Ret = NoReturningClause> = InsertStatement<T, U, Replace, Ret>;
56
57impl<T, Op> IncompleteInsertStatement<T, Op>
58where
59    T: QuerySource,
60{
61    pub(crate) fn new(target: T, operator: Op) -> Self {
62        IncompleteInsertStatement { target, operator }
63    }
64
65    /// Inserts `DEFAULT VALUES` into the targeted table.
66    ///
67    /// ```rust
68    /// # include!("../../doctest_setup.rs");
69    /// #
70    /// # table! {
71    /// #     users (name) {
72    /// #         name -> Text,
73    /// #         hair_color -> Text,
74    /// #     }
75    /// # }
76    /// #
77    /// # fn main() {
78    /// #     run_test();
79    /// # }
80    /// #
81    /// # fn run_test() -> QueryResult<()> {
82    /// #     use diesel::insert_into;
83    /// #     use self::users::dsl::*;
84    /// #     let connection = &mut connection_no_data();
85    /// diesel::sql_query("CREATE TABLE users (
86    ///     name VARCHAR(255) NOT NULL DEFAULT 'Sean',
87    ///     hair_color VARCHAR(255) NOT NULL DEFAULT 'Green'
88    /// )").execute(connection)?;
89    ///
90    /// insert_into(users)
91    ///     .default_values()
92    ///     .execute(connection)
93    ///     .unwrap();
94    /// let inserted_user = users.first(connection)?;
95    /// let expected_data = (String::from("Sean"), String::from("Green"));
96    ///
97    /// assert_eq!(expected_data, inserted_user);
98    /// #     Ok(())
99    /// # }
100    /// ```
101    pub fn default_values(self) -> InsertStatement<T, DefaultValues, Op> {
102        self.values(DefaultValues)
103    }
104
105    /// Inserts the given values into the table passed to `insert_into`.
106    ///
107    /// See the documentation of [`insert_into`] for
108    /// usage examples.
109    ///
110    /// This method can sometimes produce extremely opaque error messages due to
111    /// limitations of the Rust language. If you receive an error about
112    /// "overflow evaluating requirement" as a result of calling this method,
113    /// you may need an `&` in front of the argument to this method.
114    ///
115    /// [`insert_into`]: crate::insert_into()
116    pub fn values<U>(self, records: U) -> InsertStatement<T, U::Values, Op>
117    where
118        U: Insertable<T>,
119    {
120        InsertStatement::new(
121            self.target,
122            records.values(),
123            self.operator,
124            NoReturningClause,
125        )
126    }
127}
128
129/// A fully constructed insert statement.
130///
131/// The parameters of this struct represent:
132///
133/// - `T`: The table we are inserting into
134/// - `U`: The data being inserted
135/// - `Op`: The operation being performed. The specific types used to represent
136///   this are private, but correspond to SQL such as `INSERT` or `REPLACE`.
137///   You can safely rely on the default type representing `INSERT`
138/// - `Ret`: The `RETURNING` clause of the query. The specific types used to
139///   represent this are private. You can safely rely on the default type
140///   representing a query without a `RETURNING` clause.
141#[diesel_derives::__diesel_public_if(
142    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
143    public_fields(operator, target, records, returning)
144)]
145#[derive(Debug, Copy, Clone)]
146#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
147pub struct InsertStatement<T: QuerySource, U, Op = Insert, Ret = NoReturningClause> {
148    /// The operator used by this InsertStatement
149    ///
150    /// Corresponds to either `Insert` or `Replace`
151    operator: Op,
152    /// The table we are inserting into
153    target: T,
154    /// The data which should be inserted
155    records: U,
156    /// An optional returning clause
157    returning: Ret,
158    into_clause: T::FromClause,
159}
160
161impl<T, U, Op, Ret> QueryId for InsertStatement<T, U, Op, Ret>
162where
163    T: QuerySource + QueryId + 'static,
164    U: QueryId,
165    Op: QueryId,
166    Ret: QueryId,
167{
168    type QueryId = InsertStatement<T, U::QueryId, Op::QueryId, Ret::QueryId>;
169
170    const HAS_STATIC_QUERY_ID: bool = T::HAS_STATIC_QUERY_ID
171        && U::HAS_STATIC_QUERY_ID
172        && Op::HAS_STATIC_QUERY_ID
173        && Ret::HAS_STATIC_QUERY_ID;
174}
175
176impl<T: QuerySource, U, Op, Ret> InsertStatement<T, U, Op, Ret> {
177    /// Create a new InsertStatement instance
178    #[diesel_derives::__diesel_public_if(
179        feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
180    )]
181    pub(crate) fn new(target: T, records: U, operator: Op, returning: Ret) -> Self {
182        InsertStatement {
183            into_clause: target.from_clause(),
184            operator,
185            target,
186            records,
187            returning,
188        }
189    }
190
191    pub(crate) fn replace_values<F, V>(self, f: F) -> InsertStatement<T, V, Op, Ret>
192    where
193        F: FnOnce(U) -> V,
194    {
195        InsertStatement::new(self.target, f(self.records), self.operator, self.returning)
196    }
197}
198
199impl<T: QuerySource, U, C, Op, Ret> InsertStatement<T, InsertFromSelect<U, C>, Op, Ret> {
200    /// Set the column list when inserting from a select statement
201    ///
202    /// See the documentation for [`insert_into`] for usage examples.
203    ///
204    /// [`insert_into`]: crate::insert_into()
205    pub fn into_columns<C2>(
206        self,
207        columns: C2,
208    ) -> InsertStatement<T, InsertFromSelect<U, C2>, Op, Ret>
209    where
210        C2: ColumnList<Table = T> + Expression,
211        U: Query<SqlType = C2::SqlType>,
212    {
213        InsertStatement::new(
214            self.target,
215            self.records.with_columns(columns),
216            self.operator,
217            self.returning,
218        )
219    }
220}
221
222impl<T, U, Op, Ret, DB> QueryFragment<DB> for InsertStatement<T, U, Op, Ret>
223where
224    DB: Backend + DieselReserveSpecialization,
225    T: Table,
226    T::FromClause: QueryFragment<DB>,
227    U: QueryFragment<DB> + CanInsertInSingleQuery<DB>,
228    Op: QueryFragment<DB>,
229    Ret: QueryFragment<DB>,
230{
231    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
232        if self.records.rows_to_insert() == Some(0) {
233            out.push_sql("SELECT 1 FROM ");
234            self.into_clause.walk_ast(out.reborrow())?;
235            out.push_sql(" WHERE 1=0");
236            return Ok(());
237        }
238
239        self.operator.walk_ast(out.reborrow())?;
240        out.push_sql(" INTO ");
241        self.into_clause.walk_ast(out.reborrow())?;
242        out.push_sql(" ");
243        self.records.walk_ast(out.reborrow())?;
244        self.returning.walk_ast(out.reborrow())?;
245        Ok(())
246    }
247}
248
249impl<T, U, Op> AsQuery for InsertStatement<T, U, Op, NoReturningClause>
250where
251    T: Table,
252    InsertStatement<T, U, Op, ReturningClause<T::AllColumns>>: Query,
253{
254    type SqlType = <Self::Query as Query>::SqlType;
255    type Query = InsertStatement<T, U, Op, ReturningClause<T::AllColumns>>;
256
257    fn as_query(self) -> Self::Query {
258        self.returning(T::all_columns())
259    }
260}
261
262impl<T, U, Op, Ret> Query for InsertStatement<T, U, Op, ReturningClause<Ret>>
263where
264    T: QuerySource,
265    Ret: Expression + SelectableExpression<T> + NonAggregate,
266{
267    type SqlType = Ret::SqlType;
268}
269
270impl<T: QuerySource, U, Op, Ret, Conn> RunQueryDsl<Conn> for InsertStatement<T, U, Op, Ret> {}
271
272impl<T: QuerySource, U, Op> InsertStatement<T, U, Op> {
273    /// Specify what expression is returned after execution of the `insert`.
274    /// # Examples
275    ///
276    /// ### Inserting records:
277    ///
278    /// ```rust
279    /// # include!("../../doctest_setup.rs");
280    /// #
281    /// # #[cfg(feature = "postgres")]
282    /// # fn main() {
283    /// #     use schema::users::dsl::*;
284    /// #     let connection = &mut establish_connection();
285    /// let inserted_names = diesel::insert_into(users)
286    ///     .values(&vec![name.eq("Timmy"), name.eq("Jimmy")])
287    ///     .returning(name)
288    ///     .get_results(connection)
289    ///     .unwrap();
290    /// // Note that the returned order is not guaranteed to be preserved
291    /// assert_eq!(inserted_names.len(), 2);
292    /// assert!(inserted_names.contains(&"Timmy".to_string()));
293    /// assert!(inserted_names.contains(&"Jimmy".to_string()));
294    /// # }
295    /// # #[cfg(not(feature = "postgres"))]
296    /// # fn main() {}
297    /// ```
298    pub fn returning<E>(self, returns: E) -> InsertStatement<T, U, Op, ReturningClause<E>>
299    where
300        InsertStatement<T, U, Op, ReturningClause<E>>: Query,
301    {
302        InsertStatement::new(
303            self.target,
304            self.records,
305            self.operator,
306            ReturningClause(returns),
307        )
308    }
309}
310
311/// Marker trait to indicate that no additional operations have been added
312/// to a record for insert.
313///
314/// This is used to prevent things like
315/// `.on_conflict_do_nothing().on_conflict_do_nothing()`
316/// from compiling.
317#[cfg_attr(
318    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
319    cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
320)]
321pub trait UndecoratedInsertRecord<Table> {}
322
323impl<T, Tab> UndecoratedInsertRecord<Tab> for &T where T: ?Sized + UndecoratedInsertRecord<Tab> {}
324
325impl<T, U> UndecoratedInsertRecord<T::Table> for ColumnInsertValue<T, U> where T: Column {}
326
327impl<T, U> UndecoratedInsertRecord<T::Table>
328    for DefaultableColumnInsertValue<ColumnInsertValue<T, U>>
329where
330    T: Column,
331{
332}
333
334impl<T, Table> UndecoratedInsertRecord<Table> for [T] where T: UndecoratedInsertRecord<Table> {}
335
336impl<T, Table, QId, const STATIC_QUERY_ID: bool> UndecoratedInsertRecord<Table>
337    for BatchInsert<T, Table, QId, STATIC_QUERY_ID>
338where
339    T: UndecoratedInsertRecord<Table>,
340{
341}
342
343impl<T, Table> UndecoratedInsertRecord<Table> for Vec<T> where [T]: UndecoratedInsertRecord<Table> {}
344
345impl<Lhs, Rhs> UndecoratedInsertRecord<Lhs::Table> for Eq<Lhs, Rhs> where Lhs: Column {}
346
347impl<Lhs, Rhs, Tab> UndecoratedInsertRecord<Tab> for Option<Eq<Lhs, Rhs>> where
348    Eq<Lhs, Rhs>: UndecoratedInsertRecord<Tab>
349{
350}
351
352impl<Lhs, Rhs> UndecoratedInsertRecord<Lhs::Table> for Grouped<Eq<Lhs, Rhs>> where Lhs: Column {}
353
354impl<Lhs, Rhs, Tab> UndecoratedInsertRecord<Tab> for Option<Grouped<Eq<Lhs, Rhs>>> where
355    Eq<Lhs, Rhs>: UndecoratedInsertRecord<Tab>
356{
357}
358
359impl<T, Table> UndecoratedInsertRecord<Table> for ValuesClause<T, Table> where
360    T: UndecoratedInsertRecord<Table>
361{
362}
363
364#[derive(Debug, Clone, Copy, QueryId)]
365#[doc(hidden)]
366pub struct DefaultValues;
367
368impl<DB: Backend> CanInsertInSingleQuery<DB> for DefaultValues {
369    fn rows_to_insert(&self) -> Option<usize> {
370        Some(1)
371    }
372}
373
374impl<Tab> Insertable<Tab> for DefaultValues {
375    type Values = DefaultValues;
376
377    fn values(self) -> Self::Values {
378        self
379    }
380}
381
382impl<Tab> Insertable<Tab> for &DefaultValues {
383    type Values = DefaultValues;
384
385    fn values(self) -> Self::Values {
386        *self
387    }
388}
389
390impl<DB> QueryFragment<DB> for DefaultValues
391where
392    DB: Backend,
393    Self: QueryFragment<DB, DB::DefaultValueClauseForInsert>,
394{
395    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
396        <Self as QueryFragment<DB, DB::DefaultValueClauseForInsert>>::walk_ast(self, pass)
397    }
398}
399
400impl<DB> QueryFragment<DB, sql_dialect::default_value_clause::AnsiDefaultValueClause>
401    for DefaultValues
402where
403    DB: Backend
404        + SqlDialect<
405            DefaultValueClauseForInsert = sql_dialect::default_value_clause::AnsiDefaultValueClause,
406        >,
407{
408    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
409        out.push_sql("DEFAULT VALUES");
410        Ok(())
411    }
412}
413
414/// This type represents a values clause used as part of insert statements
415///
416/// Diesel exposes this type for third party backends so that
417/// they can implement batch insert support
418#[cfg_attr(
419    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
420    cfg(feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes")
421)]
422#[derive(Debug, Clone, Copy, QueryId)]
423pub struct ValuesClause<T, Tab> {
424    /// Values to insert
425    pub values: T,
426    _marker: PhantomData<Tab>,
427}
428
429impl<T: Default, Tab> Default for ValuesClause<T, Tab> {
430    fn default() -> Self {
431        Self::new(T::default())
432    }
433}
434
435impl<T, Tab> ValuesClause<T, Tab> {
436    pub(crate) fn new(values: T) -> Self {
437        Self {
438            values,
439            _marker: PhantomData,
440        }
441    }
442}
443
444impl<T, Tab, DB> CanInsertInSingleQuery<DB> for ValuesClause<T, Tab>
445where
446    DB: Backend,
447    T: CanInsertInSingleQuery<DB>,
448{
449    fn rows_to_insert(&self) -> Option<usize> {
450        self.values.rows_to_insert()
451    }
452}
453
454impl<T, Tab, DB> QueryFragment<DB> for ValuesClause<T, Tab>
455where
456    DB: Backend,
457    Tab: Table,
458    T: InsertValues<DB, Tab>,
459    DefaultValues: QueryFragment<DB>,
460{
461    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
462        if self.values.is_noop(out.backend())? {
463            DefaultValues.walk_ast(out)?;
464        } else {
465            out.push_sql("(");
466            self.values.column_names(out.reborrow())?;
467            out.push_sql(") VALUES (");
468            self.values.walk_ast(out.reborrow())?;
469            out.push_sql(")");
470        }
471        Ok(())
472    }
473}
474
475mod private {
476    use crate::backend::{Backend, DieselReserveSpecialization};
477    use crate::query_builder::{AstPass, QueryFragment, QueryId};
478    use crate::QueryResult;
479
480    #[derive(Debug, Copy, Clone, QueryId)]
481    pub struct Insert;
482
483    impl<DB> QueryFragment<DB> for Insert
484    where
485        DB: Backend + DieselReserveSpecialization,
486    {
487        fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
488            out.push_sql("INSERT");
489            Ok(())
490        }
491    }
492
493    /// A marker type for insert or ignore statements
494    #[derive(Debug, Copy, Clone, QueryId)]
495    pub struct InsertOrIgnore;
496
497    #[cfg(feature = "sqlite")]
498    impl QueryFragment<crate::sqlite::Sqlite> for InsertOrIgnore {
499        fn walk_ast<'b>(
500            &'b self,
501            mut out: AstPass<'_, 'b, crate::sqlite::Sqlite>,
502        ) -> QueryResult<()> {
503            out.push_sql("INSERT OR IGNORE");
504            Ok(())
505        }
506    }
507
508    #[cfg(feature = "mysql_backend")]
509    impl QueryFragment<crate::mysql::Mysql> for InsertOrIgnore {
510        fn walk_ast<'b>(
511            &'b self,
512            mut out: AstPass<'_, 'b, crate::mysql::Mysql>,
513        ) -> QueryResult<()> {
514            out.push_sql("INSERT IGNORE");
515            Ok(())
516        }
517    }
518
519    /// A marker type for replace statements
520    #[derive(Debug, Copy, Clone, QueryId)]
521    pub struct Replace;
522
523    #[cfg(feature = "sqlite")]
524    impl QueryFragment<crate::sqlite::Sqlite> for Replace {
525        fn walk_ast<'b>(
526            &'b self,
527            mut out: AstPass<'_, 'b, crate::sqlite::Sqlite>,
528        ) -> QueryResult<()> {
529            out.push_sql("REPLACE");
530            Ok(())
531        }
532    }
533
534    #[cfg(feature = "mysql_backend")]
535    impl QueryFragment<crate::mysql::Mysql> for Replace {
536        fn walk_ast<'b>(
537            &'b self,
538            mut out: AstPass<'_, 'b, crate::mysql::Mysql>,
539        ) -> QueryResult<()> {
540            out.push_sql("REPLACE");
541            Ok(())
542        }
543    }
544
545    // otherwise rustc complains at a different location that this trait is more private than the other item that uses it
546    #[allow(unreachable_pub)]
547    pub trait InsertAutoTypeHelper {
548        type Table;
549        type Op;
550    }
551
552    impl<T, Op> InsertAutoTypeHelper for crate::query_builder::IncompleteInsertStatement<T, Op> {
553        type Table = T;
554        type Op = Op;
555    }
556}