1use super::*;
2use crate::write_int;
3
4impl TableBuilder for MysqlQueryBuilder {
5 fn prepare_table_opt(&self, create: &TableCreateStatement, sql: &mut impl SqlWriter) {
6 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 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}