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