diesel/mysql/query_builder/
query_fragment_impls.rs

1use crate::expression::operators::Concat;
2use crate::mysql::backend::MysqlOnConflictClause;
3use crate::mysql::Mysql;
4use crate::query_builder::insert_statement::DefaultValues;
5use crate::query_builder::locking_clause::{ForShare, ForUpdate, NoModifier, NoWait, SkipLocked};
6use crate::query_builder::nodes::StaticQueryFragment;
7use crate::query_builder::upsert::into_conflict_clause::OnConflictSelectWrapper;
8use crate::query_builder::upsert::on_conflict_actions::{DoNothing, DoUpdate};
9use crate::query_builder::upsert::on_conflict_clause::OnConflictValues;
10use crate::query_builder::upsert::on_conflict_target::{ConflictTarget, OnConflictTarget};
11use crate::query_builder::where_clause::NoWhereClause;
12use crate::query_builder::{AstPass, QueryFragment};
13use crate::result::QueryResult;
14use crate::{Column, Table};
15
16impl QueryFragment<Mysql> for ForUpdate {
17    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
18        out.push_sql(" FOR UPDATE");
19        Ok(())
20    }
21}
22
23impl QueryFragment<Mysql> for ForShare {
24    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
25        out.push_sql(" FOR SHARE");
26        Ok(())
27    }
28}
29
30impl QueryFragment<Mysql> for NoModifier {
31    fn walk_ast<'b>(&'b self, _out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
32        Ok(())
33    }
34}
35
36impl QueryFragment<Mysql> for SkipLocked {
37    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
38        out.push_sql(" SKIP LOCKED");
39        Ok(())
40    }
41}
42
43impl QueryFragment<Mysql> for NoWait {
44    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
45        out.push_sql(" NOWAIT");
46        Ok(())
47    }
48}
49
50impl QueryFragment<Mysql, crate::mysql::backend::MysqlStyleDefaultValueClause> for DefaultValues {
51    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
52        out.push_sql("() VALUES ()");
53        Ok(())
54    }
55}
56
57impl<L, R> QueryFragment<Mysql, crate::mysql::backend::MysqlConcatClause> for Concat<L, R>
58where
59    L: QueryFragment<Mysql>,
60    R: QueryFragment<Mysql>,
61{
62    fn walk_ast<'b>(
63        &'b self,
64        mut out: crate::query_builder::AstPass<'_, 'b, Mysql>,
65    ) -> crate::result::QueryResult<()> {
66        out.push_sql("CONCAT(");
67        self.left.walk_ast(out.reborrow())?;
68        out.push_sql(",");
69        self.right.walk_ast(out.reborrow())?;
70        out.push_sql(")");
71        Ok(())
72    }
73}
74
75impl<T> QueryFragment<Mysql, crate::mysql::backend::MysqlOnConflictClause> for DoNothing<T>
76where
77    T: Table + StaticQueryFragment,
78    T::Component: QueryFragment<Mysql>,
79    T::PrimaryKey: DoNothingClauseHelper,
80{
81    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
82        out.push_sql(" UPDATE ");
83        T::PrimaryKey::walk_ast::<T>(out.reborrow())?;
84        Ok(())
85    }
86}
87
88impl<T, Tab> QueryFragment<Mysql, crate::mysql::backend::MysqlOnConflictClause> for DoUpdate<T, Tab>
89where
90    T: QueryFragment<Mysql>,
91    Tab: Table + StaticQueryFragment,
92    Tab::PrimaryKey: DoNothingClauseHelper,
93    Tab::Component: QueryFragment<Mysql>,
94{
95    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
96        out.unsafe_to_cache_prepared();
97        out.push_sql(" UPDATE ");
98        if self.changeset.is_noop(out.backend())? {
99            Tab::PrimaryKey::walk_ast::<Tab>(out.reborrow())?;
100        } else {
101            self.changeset.walk_ast(out.reborrow())?;
102        }
103        Ok(())
104    }
105}
106
107impl<Values, Target, Action> QueryFragment<Mysql, MysqlOnConflictClause>
108    for OnConflictValues<Values, Target, Action, NoWhereClause>
109where
110    Values: QueryFragment<Mysql>,
111    Target: QueryFragment<Mysql>,
112    Action: QueryFragment<Mysql>,
113    NoWhereClause: QueryFragment<Mysql>,
114{
115    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
116        self.values.walk_ast(out.reborrow())?;
117        out.push_sql(" ON DUPLICATE KEY");
118        self.target.walk_ast(out.reborrow())?;
119        self.action.walk_ast(out.reborrow())?;
120        self.where_clause.walk_ast(out)?;
121        Ok(())
122    }
123}
124
125/// A marker type signaling that the given `ON CONFLICT` clause
126/// uses mysql's `ON DUPLICATE KEY` syntax that triggers on
127/// all unique constraints
128///
129/// See [`InsertStatement::on_conflict`](crate::query_builder::InsertStatement::on_conflict)
130/// for examples
131#[derive(Debug, Copy, Clone)]
132pub struct DuplicatedKeys;
133
134impl<Tab> OnConflictTarget<Tab> for ConflictTarget<DuplicatedKeys> {}
135
136impl QueryFragment<Mysql, MysqlOnConflictClause> for ConflictTarget<DuplicatedKeys> {
137    fn walk_ast<'b>(&'b self, _out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
138        Ok(())
139    }
140}
141
142impl<S> QueryFragment<crate::mysql::Mysql> for OnConflictSelectWrapper<S>
143where
144    S: QueryFragment<crate::mysql::Mysql>,
145{
146    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, crate::mysql::Mysql>) -> QueryResult<()> {
147        self.0.walk_ast(out)
148    }
149}
150
151/// This is a helper trait
152/// that provideds a fake `DO NOTHING` clause
153/// based on reassigning the possible
154/// composite primary key to itself
155trait DoNothingClauseHelper {
156    fn walk_ast<T>(out: AstPass<'_, '_, Mysql>) -> QueryResult<()>
157    where
158        T: StaticQueryFragment,
159        T::Component: QueryFragment<Mysql>;
160}
161
162impl<C> DoNothingClauseHelper for C
163where
164    C: Column,
165{
166    fn walk_ast<T>(mut out: AstPass<'_, '_, Mysql>) -> QueryResult<()>
167    where
168        T: StaticQueryFragment,
169        T::Component: QueryFragment<Mysql>,
170    {
171        T::STATIC_COMPONENT.walk_ast(out.reborrow())?;
172        out.push_sql(".");
173        out.push_identifier(C::NAME)?;
174        out.push_sql(" = ");
175        T::STATIC_COMPONENT.walk_ast(out.reborrow())?;
176        out.push_sql(".");
177        out.push_identifier(C::NAME)?;
178        Ok(())
179    }
180}
181
182macro_rules! do_nothing_for_composite_keys {
183    ($(
184        $Tuple:tt {
185            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
186        }
187    )+) => {
188        $(
189            impl<$($T,)*> DoNothingClauseHelper for ($($T,)*)
190            where $($T: Column,)*
191            {
192                fn walk_ast<Table>(mut out: AstPass<'_, '_, Mysql>) -> QueryResult<()>
193                where
194                    Table: StaticQueryFragment,
195                    Table::Component: QueryFragment<Mysql>,
196                {
197                    let mut first = true;
198                    $(
199                        #[allow(unused_assignments)]
200                        if first {
201                            first = false;
202                        } else {
203                            out.push_sql(", ");
204                        }
205                        Table::STATIC_COMPONENT.walk_ast(out.reborrow())?;
206                        out.push_sql(".");
207                        out.push_identifier($T::NAME)?;
208                        out.push_sql(" = ");
209                        Table::STATIC_COMPONENT.walk_ast(out.reborrow())?;
210                        out.push_sql(".");
211                        out.push_identifier($T::NAME)?;
212                    )*
213                    Ok(())
214                }
215            }
216        )*
217    }
218}
219
220diesel_derives::__diesel_for_each_tuple!(do_nothing_for_composite_keys);