Skip to main content

sea_query/backend/mysql/
table.rs

1use super::*;
2use crate::write_int;
3
4impl TableBuilder for MysqlQueryBuilder {
5    fn prepare_table_opt(&self, create: &TableCreateStatement, sql: &mut impl SqlWriter) {
6        // comment
7        if let Some(comment) = &create.comment {
8            sql.write_str(" COMMENT '").unwrap();
9            self.write_escaped(sql, comment);
10            sql.write_str("'").unwrap();
11        }
12        self.prepare_table_opt_def(create, sql)
13    }
14
15    fn prepare_column_def(&self, column_def: &ColumnDef, sql: &mut impl SqlWriter) {
16        self.prepare_iden(&column_def.name, sql);
17
18        if let Some(column_type) = &column_def.types {
19            sql.write_str(" ").unwrap();
20            self.prepare_column_type(column_type, sql);
21        }
22
23        self.prepare_column_spec(&column_def.spec, sql);
24    }
25
26    fn prepare_column_type(&self, column_type: &ColumnType, sql: &mut impl SqlWriter) {
27        match column_type {
28            ColumnType::Char(length) => match length {
29                Some(length) => {
30                    sql.write_str("char(").unwrap();
31                    write_int(sql, *length);
32                    sql.write_str(")")
33                }
34                None => sql.write_str("char"),
35            },
36            ColumnType::String(length) => match length {
37                StringLen::N(length) => {
38                    sql.write_str("varchar(").unwrap();
39                    write_int(sql, *length);
40                    sql.write_char(')')
41                }
42                StringLen::None => sql.write_str("varchar(255)"),
43                StringLen::Max => sql.write_str("varchar(65535)"),
44            },
45            ColumnType::Text => sql.write_str("text"),
46            ColumnType::TinyInteger | ColumnType::TinyUnsigned => sql.write_str("tinyint"),
47            ColumnType::SmallInteger | ColumnType::SmallUnsigned => sql.write_str("smallint"),
48            ColumnType::Integer | ColumnType::Unsigned => sql.write_str("int"),
49            ColumnType::BigInteger | ColumnType::BigUnsigned => sql.write_str("bigint"),
50            ColumnType::Float => sql.write_str("float"),
51            ColumnType::Double => sql.write_str("double"),
52            ColumnType::Decimal(precision) => match precision {
53                Some((precision, scale)) => {
54                    sql.write_str("decimal(").unwrap();
55                    write_int(sql, *precision);
56                    sql.write_str(", ").unwrap();
57                    write_int(sql, *scale);
58                    sql.write_char(')')
59                }
60                None => sql.write_str("decimal"),
61            },
62            ColumnType::DateTime => sql.write_str("datetime"),
63            ColumnType::Timestamp => sql.write_str("timestamp"),
64            ColumnType::TimestampWithTimeZone => sql.write_str("timestamp"),
65            ColumnType::Time => sql.write_str("time"),
66            ColumnType::Date => sql.write_str("date"),
67            ColumnType::Year => sql.write_str("year"),
68            ColumnType::Interval(_, _) => sql.write_str("unsupported"),
69            ColumnType::Binary(length) => {
70                sql.write_str("binary(").unwrap();
71                write_int(sql, *length);
72                sql.write_char(')')
73            }
74            ColumnType::VarBinary(length) => match length {
75                StringLen::N(length) => {
76                    sql.write_str("varbinary(").unwrap();
77                    write_int(sql, *length);
78                    sql.write_char(')')
79                }
80                StringLen::None => sql.write_str("varbinary(255)"),
81                StringLen::Max => sql.write_str("varbinary(65535)"),
82            },
83            ColumnType::Blob => sql.write_str("blob"),
84            ColumnType::Bit(length) => match length {
85                Some(length) => {
86                    sql.write_str("bit(").unwrap();
87                    write_int(sql, *length);
88                    sql.write_char(')')
89                }
90                None => sql.write_str("bit"),
91            },
92            ColumnType::VarBit(length) => {
93                sql.write_str("bit(").unwrap();
94                write_int(sql, *length);
95                sql.write_char(')')
96            }
97            ColumnType::Boolean => sql.write_str("bool"),
98            ColumnType::Money(precision) => match precision {
99                Some((precision, scale)) => {
100                    sql.write_str("decimal(").unwrap();
101                    write_int(sql, *precision);
102                    sql.write_str(", ").unwrap();
103                    write_int(sql, *scale);
104                    sql.write_char(')')
105                }
106                None => sql.write_str("decimal"),
107            },
108            ColumnType::Json => sql.write_str("json"),
109            ColumnType::JsonBinary => sql.write_str("json"),
110            ColumnType::Uuid => sql.write_str("binary(16)"),
111            ColumnType::Custom(iden) => sql.write_str(&format!("{iden}")),
112            ColumnType::Enum { variants, .. } => {
113                sql.write_str("ENUM('").unwrap();
114
115                let mut viter = variants.iter();
116                join_io!(
117                    viter,
118                    variant,
119                    join {
120                        sql.write_str("', '").unwrap();
121                    },
122                    do {
123                        sql.write_str(&variant.0).unwrap();
124                    }
125                );
126
127                sql.write_str("')")
128            }
129            ColumnType::Array(_) => unimplemented!("Array is not available in MySQL."),
130            ColumnType::Vector(_) => unimplemented!("Vector is not available in MySQL."),
131            ColumnType::Cidr => unimplemented!("Cidr is not available in MySQL."),
132            ColumnType::Inet => unimplemented!("Inet is not available in MySQL."),
133            ColumnType::MacAddr => unimplemented!("MacAddr is not available in MySQL."),
134            ColumnType::LTree => unimplemented!("LTree is not available in MySQL."),
135        }
136        .unwrap();
137
138        if matches!(
139            column_type,
140            ColumnType::TinyUnsigned
141                | ColumnType::SmallUnsigned
142                | ColumnType::Unsigned
143                | ColumnType::BigUnsigned
144        ) {
145            sql.write_str(" UNSIGNED").unwrap();
146        }
147    }
148
149    fn column_spec_auto_increment_keyword(&self) -> &str {
150        " AUTO_INCREMENT"
151    }
152
153    fn prepare_table_alter_statement(&self, alter: &TableAlterStatement, sql: &mut impl SqlWriter) {
154        if alter.options.is_empty() {
155            panic!("No alter option found")
156        };
157        sql.write_str("ALTER TABLE ").unwrap();
158        if let Some(table) = &alter.table {
159            self.prepare_table_ref_table_stmt(table, sql);
160            sql.write_str(" ").unwrap();
161        }
162
163        let mut opts = alter.options.iter();
164
165        join_io!(
166            opts,
167            opt,
168            join {
169                sql.write_str(", ").unwrap();
170            },
171            do {
172                match opt {
173                    TableAlterOption::AddColumn(AddColumnOption {
174                        column,
175                        if_not_exists,
176                    }) => {
177                        sql.write_str("ADD COLUMN ").unwrap();
178                        if *if_not_exists {
179                            sql.write_str("IF NOT EXISTS ").unwrap();
180                        }
181                        self.prepare_column_def(column, sql);
182                    }
183                    TableAlterOption::ModifyColumn(column_def) => {
184                        sql.write_str("MODIFY COLUMN ").unwrap();
185                        self.prepare_column_def(column_def, sql);
186                    }
187                    TableAlterOption::RenameColumn(from_name, to_name) => {
188                        sql.write_str("RENAME COLUMN ").unwrap();
189                        self.prepare_iden(from_name, sql);
190                        sql.write_str(" TO ").unwrap();
191                        self.prepare_iden(to_name, sql);
192                    }
193                    TableAlterOption::DropColumn(DropColumnOption { column_name, .. }) => {
194                        sql.write_str("DROP COLUMN ").unwrap();
195                        self.prepare_iden(column_name, sql);
196                    }
197                    TableAlterOption::DropForeignKey(name) => {
198                        let mut foreign_key = TableForeignKey::new();
199                        foreign_key.name(name.to_string());
200                        let drop = ForeignKeyDropStatement {
201                            foreign_key,
202                            table: None,
203                        };
204                        self.prepare_foreign_key_drop_statement_internal(
205                            &drop,
206                            sql,
207                            Mode::TableAlter,
208                        );
209                    }
210                    TableAlterOption::AddForeignKey(foreign_key) => {
211                        let create = ForeignKeyCreateStatement {
212                            foreign_key: foreign_key.to_owned(),
213                        };
214                        self.prepare_foreign_key_create_statement_internal(
215                            &create,
216                            sql,
217                            Mode::TableAlter,
218                        );
219                    }
220                    TableAlterOption::DropConstraint(name) => {
221                        sql.write_str("DROP CONSTRAINT ").unwrap();
222                        self.prepare_iden(name, sql);
223                    }
224                };
225            }
226        );
227    }
228
229    fn prepare_table_rename_statement(
230        &self,
231        rename: &TableRenameStatement,
232        sql: &mut impl SqlWriter,
233    ) {
234        sql.write_str("RENAME TABLE ").unwrap();
235        if let Some(from_name) = &rename.from_name {
236            self.prepare_table_ref_table_stmt(from_name, sql);
237        }
238        sql.write_str(" TO ").unwrap();
239        if let Some(to_name) = &rename.to_name {
240            self.prepare_table_ref_table_stmt(to_name, sql);
241        }
242    }
243
244    fn prepare_partition_by(&self, partition_by: &PartitionBy, sql: &mut impl SqlWriter) {
245        match partition_by {
246            PartitionBy::Range(cols) => {
247                sql.write_str("RANGE (").unwrap();
248                self.prepare_partition_cols(cols, sql);
249                sql.write_char(')').unwrap();
250            }
251            PartitionBy::List(cols) => {
252                sql.write_str("LIST (").unwrap();
253                self.prepare_partition_cols(cols, sql);
254                sql.write_char(')').unwrap();
255            }
256            PartitionBy::Hash(cols) => {
257                sql.write_str("HASH (").unwrap();
258                self.prepare_partition_cols(cols, sql);
259                sql.write_char(')').unwrap();
260            }
261            PartitionBy::Key(cols) => {
262                sql.write_str("KEY (").unwrap();
263                self.prepare_partition_cols(cols, sql);
264                sql.write_char(')').unwrap();
265            }
266        }
267    }
268
269    fn prepare_partition_definition(
270        &self,
271        name: &DynIden,
272        values: Option<&PartitionValues>,
273        sql: &mut impl SqlWriter,
274    ) {
275        sql.write_str("PARTITION ").unwrap();
276        self.prepare_iden(name, sql);
277        if let Some(values) = values {
278            sql.write_str(" ").unwrap();
279            self.prepare_partition_values(values, sql);
280        }
281    }
282
283    fn prepare_partition_values(
284        &self,
285        partition_values: &PartitionValues,
286        sql: &mut impl SqlWriter,
287    ) {
288        match partition_values {
289            PartitionValues::In(values) => {
290                sql.write_str("VALUES IN (").unwrap();
291                self.prepare_partition_exprs(values, sql);
292                sql.write_char(')').unwrap();
293            }
294            PartitionValues::FromTo(_, _) => panic!("MySQL does not support VALUES FROM ... TO"),
295            PartitionValues::LessThan(values) => {
296                sql.write_str("VALUES LESS THAN (").unwrap();
297                self.prepare_partition_exprs(values, sql);
298                sql.write_char(')').unwrap();
299            }
300            PartitionValues::With(_, _) => panic!("MySQL does not support VALUES WITH"),
301        }
302    }
303
304    /// column comment
305    fn column_comment(&self, comment: &str, sql: &mut impl SqlWriter) {
306        sql.write_str(" COMMENT '").unwrap();
307        self.write_escaped(sql, comment);
308        sql.write_str("'").unwrap();
309    }
310}
311
312impl MysqlQueryBuilder {
313    fn prepare_partition_cols(&self, cols: &[DynIden], sql: &mut impl SqlWriter) {
314        let mut first = true;
315        for col in cols {
316            if !first {
317                sql.write_str(", ").unwrap();
318            }
319            self.prepare_iden(col, sql);
320            first = false;
321        }
322    }
323
324    fn prepare_partition_exprs(&self, exprs: &[Expr], sql: &mut impl SqlWriter) {
325        let mut first = true;
326        for expr in exprs {
327            if !first {
328                sql.write_str(", ").unwrap();
329            }
330            self.prepare_expr(expr, sql);
331            first = false;
332        }
333    }
334}