sea_query/backend/mysql/
query.rs

1use super::*;
2use crate::extension::mysql::*;
3
4impl QueryBuilder for MysqlQueryBuilder {
5    fn values_list_tuple_prefix(&self) -> &str {
6        "ROW"
7    }
8
9    fn prepare_select_distinct(&self, select_distinct: &SelectDistinct, sql: &mut dyn SqlWriter) {
10        match select_distinct {
11            SelectDistinct::All => write!(sql, "ALL").unwrap(),
12            SelectDistinct::Distinct => write!(sql, "DISTINCT").unwrap(),
13            SelectDistinct::DistinctRow => write!(sql, "DISTINCTROW").unwrap(),
14            _ => {}
15        };
16    }
17
18    fn prepare_index_hints(&self, select: &SelectStatement, sql: &mut dyn SqlWriter) {
19        if !select.index_hints.is_empty() {
20            write!(sql, " ").unwrap();
21        }
22        for (i, hint) in select.index_hints.iter().enumerate() {
23            if i != 0 {
24                write!(sql, " ").unwrap()
25            }
26            match hint.r#type {
27                IndexHintType::Use => {
28                    write!(sql, "USE INDEX ",).unwrap();
29                    self.prepare_index_hint_scope(&hint.scope, sql);
30                    write!(sql, "(").unwrap();
31                    hint.index.prepare(sql.as_writer(), self.quote());
32                }
33                IndexHintType::Ignore => {
34                    write!(sql, "IGNORE INDEX ",).unwrap();
35                    self.prepare_index_hint_scope(&hint.scope, sql);
36                    write!(sql, "(").unwrap();
37                    hint.index.prepare(sql.as_writer(), self.quote());
38                }
39                IndexHintType::Force => {
40                    write!(sql, "FORCE INDEX ",).unwrap();
41                    self.prepare_index_hint_scope(&hint.scope, sql);
42                    write!(sql, "(").unwrap();
43                    hint.index.prepare(sql.as_writer(), self.quote());
44                }
45            }
46            write!(sql, ")").unwrap();
47        }
48    }
49
50    fn prepare_query_statement(&self, query: &SubQueryStatement, sql: &mut dyn SqlWriter) {
51        query.prepare_statement(self, sql);
52    }
53
54    fn prepare_with_clause_recursive_options(&self, _: &WithClause, _: &mut dyn SqlWriter) {
55        // MySQL doesn't support sql recursive with query 'SEARCH' and 'CYCLE' options.
56    }
57
58    fn prepare_with_query_clause_materialization(
59        &self,
60        _: &CommonTableExpression,
61        _: &mut dyn SqlWriter,
62    ) {
63        // MySQL doesn't support declaring materialization in SQL for with query.
64    }
65
66    fn prepare_update_join(
67        &self,
68        from: &[TableRef],
69        condition: &ConditionHolder,
70        sql: &mut dyn SqlWriter,
71    ) {
72        if from.is_empty() {
73            return;
74        }
75
76        write!(sql, " JOIN ").unwrap();
77
78        // TODO what if we have multiple from?
79        self.prepare_table_ref(&from[0], sql);
80
81        self.prepare_condition(condition, "ON", sql);
82    }
83
84    fn prepare_update_from(&self, _: &[TableRef], _: &mut dyn SqlWriter) {}
85
86    fn prepare_update_column(
87        &self,
88        table: &Option<Box<TableRef>>,
89        from: &[TableRef],
90        column: &DynIden,
91        sql: &mut dyn SqlWriter,
92    ) {
93        use std::ops::Deref;
94
95        if from.is_empty() {
96            column.prepare(sql.as_writer(), self.quote());
97        } else {
98            if let Some(table) = table {
99                if let TableRef::Table(table) = table.deref() {
100                    self.prepare_column_ref(
101                        &ColumnRef::TableColumn(table.clone(), column.clone()),
102                        sql,
103                    );
104                    return;
105                }
106            }
107            column.prepare(sql.as_writer(), self.quote());
108        }
109    }
110
111    fn prepare_update_condition(
112        &self,
113        from: &[TableRef],
114        condition: &ConditionHolder,
115        sql: &mut dyn SqlWriter,
116    ) {
117        if !from.is_empty() {
118            return;
119        }
120        self.prepare_condition(condition, "WHERE", sql);
121    }
122
123    fn prepare_join_type(&self, join_type: &JoinType, sql: &mut dyn SqlWriter) {
124        match join_type {
125            JoinType::FullOuterJoin => panic!("Mysql does not support FULL OUTER JOIN"),
126            _ => self.prepare_join_type_common(join_type, sql),
127        }
128    }
129
130    fn prepare_order_expr(&self, order_expr: &OrderExpr, sql: &mut dyn SqlWriter) {
131        match order_expr.nulls {
132            None => (),
133            Some(NullOrdering::Last) => {
134                self.prepare_simple_expr(&order_expr.expr, sql);
135                write!(sql, " IS NULL ASC, ").unwrap()
136            }
137            Some(NullOrdering::First) => {
138                self.prepare_simple_expr(&order_expr.expr, sql);
139                write!(sql, " IS NULL DESC, ").unwrap()
140            }
141        }
142        if !matches!(order_expr.order, Order::Field(_)) {
143            self.prepare_simple_expr(&order_expr.expr, sql);
144        }
145        self.prepare_order(order_expr, sql);
146    }
147
148    fn prepare_value(&self, value: &Value, sql: &mut dyn SqlWriter) {
149        sql.push_param(value.clone(), self as _);
150    }
151
152    fn prepare_on_conflict_target(&self, _: &[OnConflictTarget], _: &mut dyn SqlWriter) {
153        // MySQL doesn't support declaring ON CONFLICT target.
154    }
155
156    fn prepare_on_conflict_action(
157        &self,
158        on_conflict_action: &Option<OnConflictAction>,
159        sql: &mut dyn SqlWriter,
160    ) {
161        match on_conflict_action {
162            Some(OnConflictAction::DoNothing(pk_cols)) => {
163                if !pk_cols.is_empty() {
164                    self.prepare_on_conflict_do_update_keywords(sql);
165                    pk_cols.iter().fold(true, |first, pk_col| {
166                        if !first {
167                            write!(sql, ", ").unwrap()
168                        }
169                        pk_col.prepare(sql.as_writer(), self.quote());
170                        write!(sql, " = ").unwrap();
171                        pk_col.prepare(sql.as_writer(), self.quote());
172                        false
173                    });
174                } else {
175                    write!(sql, " IGNORE").unwrap();
176                }
177            }
178            _ => self.prepare_on_conflict_action_common(on_conflict_action, sql),
179        }
180    }
181
182    fn prepare_on_conflict_keywords(&self, sql: &mut dyn SqlWriter) {
183        write!(sql, " ON DUPLICATE KEY").unwrap();
184    }
185
186    fn prepare_on_conflict_do_update_keywords(&self, sql: &mut dyn SqlWriter) {
187        write!(sql, " UPDATE ").unwrap();
188    }
189
190    fn prepare_on_conflict_excluded_table(&self, col: &DynIden, sql: &mut dyn SqlWriter) {
191        write!(sql, "VALUES(").unwrap();
192        col.prepare(sql.as_writer(), self.quote());
193        write!(sql, ")").unwrap();
194    }
195
196    fn prepare_on_conflict_condition(&self, _: &ConditionHolder, _: &mut dyn SqlWriter) {}
197
198    fn prepare_returning(&self, _returning: &Option<ReturningClause>, _sql: &mut dyn SqlWriter) {}
199
200    fn random_function(&self) -> &str {
201        "RAND"
202    }
203
204    fn insert_default_keyword(&self) -> &str {
205        "()"
206    }
207}
208
209impl MysqlQueryBuilder {
210    fn prepare_index_hint_scope(&self, index_hint_scope: &IndexHintScope, sql: &mut dyn SqlWriter) {
211        match index_hint_scope {
212            IndexHintScope::Join => {
213                write!(sql, "FOR JOIN ").unwrap();
214            }
215            IndexHintScope::OrderBy => {
216                write!(sql, "FOR ORDER BY ").unwrap();
217            }
218            IndexHintScope::GroupBy => {
219                write!(sql, "FOR GROUP BY ").unwrap();
220            }
221            IndexHintScope::All => {}
222        }
223    }
224}