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_join_type(&self, join_type: &JoinType, sql: &mut dyn SqlWriter) {
67        match join_type {
68            JoinType::FullOuterJoin => panic!("Mysql does not support FULL OUTER JOIN"),
69            _ => self.prepare_join_type_common(join_type, sql),
70        }
71    }
72
73    fn prepare_order_expr(&self, order_expr: &OrderExpr, sql: &mut dyn SqlWriter) {
74        match order_expr.nulls {
75            None => (),
76            Some(NullOrdering::Last) => {
77                self.prepare_simple_expr(&order_expr.expr, sql);
78                write!(sql, " IS NULL ASC, ").unwrap()
79            }
80            Some(NullOrdering::First) => {
81                self.prepare_simple_expr(&order_expr.expr, sql);
82                write!(sql, " IS NULL DESC, ").unwrap()
83            }
84        }
85        if !matches!(order_expr.order, Order::Field(_)) {
86            self.prepare_simple_expr(&order_expr.expr, sql);
87        }
88        self.prepare_order(order_expr, sql);
89    }
90
91    fn prepare_value(&self, value: &Value, sql: &mut dyn SqlWriter) {
92        sql.push_param(value.clone(), self as _);
93    }
94
95    fn prepare_on_conflict_target(&self, _: &[OnConflictTarget], _: &mut dyn SqlWriter) {
96        // MySQL doesn't support declaring ON CONFLICT target.
97    }
98
99    fn prepare_on_conflict_action(
100        &self,
101        on_conflict_action: &Option<OnConflictAction>,
102        sql: &mut dyn SqlWriter,
103    ) {
104        match on_conflict_action {
105            Some(OnConflictAction::DoNothing(pk_cols)) => {
106                if !pk_cols.is_empty() {
107                    self.prepare_on_conflict_do_update_keywords(sql);
108                    pk_cols.iter().fold(true, |first, pk_col| {
109                        if !first {
110                            write!(sql, ", ").unwrap()
111                        }
112                        pk_col.prepare(sql.as_writer(), self.quote());
113                        write!(sql, " = ").unwrap();
114                        pk_col.prepare(sql.as_writer(), self.quote());
115                        false
116                    });
117                } else {
118                    write!(sql, " IGNORE").unwrap();
119                }
120            }
121            _ => self.prepare_on_conflict_action_common(on_conflict_action, sql),
122        }
123    }
124
125    fn prepare_on_conflict_keywords(&self, sql: &mut dyn SqlWriter) {
126        write!(sql, " ON DUPLICATE KEY").unwrap();
127    }
128
129    fn prepare_on_conflict_do_update_keywords(&self, sql: &mut dyn SqlWriter) {
130        write!(sql, " UPDATE ").unwrap();
131    }
132
133    fn prepare_on_conflict_excluded_table(&self, col: &DynIden, sql: &mut dyn SqlWriter) {
134        write!(sql, "VALUES(").unwrap();
135        col.prepare(sql.as_writer(), self.quote());
136        write!(sql, ")").unwrap();
137    }
138
139    fn prepare_on_conflict_condition(&self, _: &ConditionHolder, _: &mut dyn SqlWriter) {}
140
141    fn prepare_returning(&self, _returning: &Option<ReturningClause>, _sql: &mut dyn SqlWriter) {}
142
143    fn random_function(&self) -> &str {
144        "RAND"
145    }
146
147    fn insert_default_keyword(&self) -> &str {
148        "()"
149    }
150}
151
152impl MysqlQueryBuilder {
153    fn prepare_index_hint_scope(&self, index_hint_scope: &IndexHintScope, sql: &mut dyn SqlWriter) {
154        match index_hint_scope {
155            IndexHintScope::Join => {
156                write!(sql, "FOR JOIN ").unwrap();
157            }
158            IndexHintScope::OrderBy => {
159                write!(sql, "FOR ORDER BY ").unwrap();
160            }
161            IndexHintScope::GroupBy => {
162                write!(sql, "FOR GROUP BY ").unwrap();
163            }
164            IndexHintScope::All => {}
165        }
166    }
167}