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