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