sqlparser_mysql/dds/
alter_table.rs

1use core::fmt;
2use std::fmt::{write, Display, Formatter};
3use std::str::FromStr;
4
5use nom::branch::alt;
6use nom::bytes::complete::{tag, tag_no_case, take_until};
7use nom::character::complete::{alphanumeric1, anychar, digit1, multispace0, multispace1};
8use nom::combinator::{map, opt, recognize};
9use nom::error::ParseError;
10use nom::multi::{many0, many1};
11use nom::sequence::{delimited, preceded, terminated, tuple};
12use nom::{IResult, Parser};
13
14use base::algorithm_type::AlgorithmType;
15use base::column::{Column, ColumnSpecification};
16use base::fulltext_or_spatial_type::FulltextOrSpatialType;
17use base::index_option::IndexOption;
18use base::index_or_key_type::IndexOrKeyType;
19use base::index_type::IndexType;
20use base::lock_type::LockType;
21use base::table::Table;
22use base::table_option::TableOption;
23use base::visible_type::VisibleType;
24use base::{
25    CheckConstraintDefinition, CommonParser, KeyPart, ParseSQLError, PartitionDefinition,
26    ReferenceDefinition,
27};
28
29/// parse `ALTER TABLE tbl_name [alter_option [, alter_option] ...] [partition_options]`
30#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
31pub struct AlterTableStatement {
32    pub table: Table,
33    pub alter_options: Option<Vec<AlterTableOption>>,
34    pub partition_options: Option<Vec<AlterPartitionOption>>,
35}
36
37impl Display for AlterTableStatement {
38    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39        write!(f, "ALTER TABLE {}", &self.table);
40        if let Some(alter_options) = &self.alter_options {
41            write!(f, " {}", AlterTableOption::format_list(alter_options));
42        }
43        if let Some(partition_options) = &self.partition_options {
44            write!(
45                f,
46                " {}",
47                AlterPartitionOption::format_list(partition_options)
48            );
49        }
50        Ok(())
51    }
52}
53
54impl AlterTableStatement {
55    pub fn parse(i: &str) -> IResult<&str, AlterTableStatement, ParseSQLError<&str>> {
56        let mut parser = tuple((
57            tuple((
58                tag_no_case("ALTER "),
59                multispace0,
60                tag_no_case("TABLE "),
61                multispace0,
62            )),
63            // tbl_name
64            Table::without_alias,
65            multispace0,
66            //
67            opt(many0(map(
68                tuple((
69                    AlterTableOption::parse,
70                    opt(CommonParser::ws_sep_comma),
71                    multispace0,
72                )),
73                |x| x.0,
74            ))),
75            opt(many0(terminated(
76                AlterPartitionOption::parse,
77                opt(CommonParser::ws_sep_comma),
78            ))),
79            CommonParser::statement_terminator,
80        ));
81        let (remaining_input, (_, table, _, alter_options, partition_options, _)) = parser(i)?;
82        Ok((
83            remaining_input,
84            AlterTableStatement {
85                table,
86                alter_options,
87                partition_options,
88            },
89        ))
90    }
91}
92/////// Alter Table Option
93
94/// {CHECK | CONSTRAINT}
95#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
96pub enum CheckOrConstraintType {
97    Check,
98    Constraint,
99}
100
101impl Display for CheckOrConstraintType {
102    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
103        match *self {
104            CheckOrConstraintType::Check => write!(f, "CHECK"),
105            CheckOrConstraintType::Constraint => write!(f, "CONSTRAINT"),
106        }
107    }
108}
109
110impl CheckOrConstraintType {
111    fn parse(i: &str) -> IResult<&str, CheckOrConstraintType, ParseSQLError<&str>> {
112        alt((
113            map(tag_no_case("CHECK"), |_| CheckOrConstraintType::Check),
114            map(tag_no_case("CONSTRAINT"), |_| {
115                CheckOrConstraintType::Constraint
116            }),
117        ))(i)
118    }
119}
120
121#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
122pub enum AlterTableOption {
123    /// table_options
124    TableOptions { table_options: Vec<TableOption> },
125
126    /// `ADD [COLUMN] col_name column_definition
127    ///     [FIRST | AFTER col_name]`
128    /// `ADD [COLUMN] (col_name column_definition,...)`
129    AddColumn {
130        opt_column: bool, // [COLUMN]
131        columns: Vec<ColumnSpecification>,
132    },
133
134    /// `ADD {INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option] ...`
135    AddIndexOrKey {
136        index_or_key: IndexOrKeyType,               // {INDEX | KEY}
137        opt_index_name: Option<String>,             // [index_name]
138        opt_index_type: Option<IndexType>,          // [index_type]
139        key_part: Vec<KeyPart>,                     // (key_part,...)
140        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
141    },
142
143    /// `ADD {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...) [index_option] ...`
144    AddFulltextOrSpatial {
145        fulltext_or_spatial: FulltextOrSpatialType, // {FULLTEXT | SPATIAL}
146        opt_index_or_key: Option<IndexOrKeyType>,   // {INDEX | KEY}
147        opt_index_name: Option<String>,             // [index_name]
148        key_part: Vec<KeyPart>,                     // (key_part,...)
149        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
150    },
151
152    /// `ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (key_part,...) [index_option] ...`
153    AddPrimaryKey {
154        opt_symbol: Option<String>,                 // [symbol]
155        opt_index_type: Option<IndexType>,          // [index_type]
156        key_part: Vec<KeyPart>,                     // (key_part,...)
157        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
158    },
159
160    /// `ADD [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY]
161    ///     [index_name] [index_type] (key_part,...) [index_option] ...`
162    AddUnique {
163        opt_symbol: Option<String>,                 // [symbol]
164        opt_index_or_key: Option<IndexOrKeyType>,   // [INDEX | KEY]
165        opt_index_name: Option<String>,             // [index_name]
166        opt_index_type: Option<IndexType>,          // [index_type]
167        key_part: Vec<KeyPart>,                     // (key_part,...)
168        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
169    },
170
171    /// `ADD [CONSTRAINT [symbol]] FOREIGN KEY
172    ///     [index_name] (col_name,...) reference_definition`
173    AddForeignKey {
174        opt_symbol: Option<String>,                // [symbol]
175        opt_index_name: Option<String>,            // [index_name]
176        columns: Vec<String>,                      // (col_name,...)
177        reference_definition: ReferenceDefinition, // reference_definition
178    },
179
180    /// `ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]`
181    AddCheck {
182        check_constraint: CheckConstraintDefinition,
183    },
184
185    /// `DROP {CHECK | CONSTRAINT} symbol`
186    DropCheckOrConstraint {
187        check_or_constraint: CheckOrConstraintType,
188        symbol: String,
189    },
190
191    /// `ALTER {CHECK | CONSTRAINT} symbol [NOT] ENFORCED`
192    AlterCheckOrConstraintEnforced {
193        check_or_constraint: CheckOrConstraintType,
194        symbol: String,
195        enforced: bool,
196    },
197
198    /// `ALGORITHM [=] {DEFAULT | INSTANT | INPLACE | COPY}`
199    Algorithm { algorithm: AlgorithmType },
200
201    /// `ALTER [COLUMN] col_name
202    /// { SET DEFAULT {literal | (expr)} | SET {VISIBLE | INVISIBLE} | DROP DEFAULT }`
203    AlterColumn {
204        col_name: String,
205        alter_column_operation: AlertColumnOperation,
206    },
207
208    /// `ALTER INDEX index_name {VISIBLE | INVISIBLE}`
209    AlterIndexVisibility {
210        index_name: String,
211        visible: VisibleType,
212    },
213
214    /// `CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST | AFTER col_name]`
215    ChangeColumn {
216        old_col_name: String,
217        column_definition: ColumnSpecification,
218    },
219
220    /// `[DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]`
221    DefaultCharacterSet {
222        charset_name: String,
223        collation_name: Option<String>,
224    },
225
226    /// `CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]`
227    ConvertToCharacterSet {
228        charset_name: String,
229        collation_name: Option<String>,
230    },
231
232    /// `{DISABLE | ENABLE} KEYS`
233    DisableKeys,
234
235    /// `{DISABLE | ENABLE} KEYS`
236    EnableKeys,
237
238    /// `{DISCARD | IMPORT} TABLESPACE`
239    DiscardTablespace,
240
241    /// `{DISCARD | IMPORT} TABLESPACE`
242    ImportTablespace,
243
244    /// `DROP [COLUMN] col_name`
245    DropColumn { col_name: String },
246
247    /// `DROP {INDEX | KEY} index_name`
248    DropIndexOrKey {
249        index_or_key: IndexOrKeyType,
250        index_name: String,
251    },
252
253    /// `DROP PRIMARY KEY`
254    DropPrimaryKey,
255
256    /// `DROP FOREIGN KEY fk_symbol`
257    DropForeignKey { fk_symbol: String },
258
259    /// FORCE
260    Force,
261
262    /// `LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}`
263    Lock { lock_type: LockType },
264
265    /// `MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name]`
266    ModifyColumn {
267        column_definition: ColumnSpecification,
268    },
269
270    /// `ORDER BY col_name [, col_name] ...`
271    OrderBy { columns: Vec<String> },
272
273    /// `RENAME COLUMN old_col_name TO new_col_name`
274    RenameColumn {
275        old_col_name: String,
276        new_col_name: String,
277    },
278
279    /// `RENAME {INDEX | KEY} old_index_name TO new_index_name`
280    RenameIndexOrKey {
281        index_or_key: IndexOrKeyType,
282        old_index_name: String,
283        new_index_name: String,
284    },
285
286    /// `RENAME [TO | AS] new_tbl_name`
287    RenameTable { new_tbl_name: String },
288
289    /// `{WITHOUT | WITH} VALIDATION`
290    Validation { with_validation: bool },
291}
292
293impl Display for AlterTableOption {
294    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
295        match *self {
296            AlterTableOption::TableOptions { ref table_options } => {
297                write!(f, " {}", TableOption::format_list(table_options))
298            }
299            AlterTableOption::AddColumn {
300                ref opt_column,
301                ref columns,
302            } => {
303                if *opt_column {
304                    write!(f, " ADD COLUMN");
305                }
306                let columns = columns
307                    .iter()
308                    .map(|x| x.to_string())
309                    .collect::<Vec<String>>()
310                    .join(", ");
311                write!(f, " ({})", columns);
312                Ok(())
313            }
314            AlterTableOption::AddIndexOrKey {
315                ref index_or_key,
316                ref opt_index_name,
317                ref opt_index_type,
318                ref key_part,
319                ref opt_index_option,
320            } => {
321                write!(f, " ADD {}", index_or_key);
322                if let Some(opt_index_name) = opt_index_name {
323                    write!(f, " {}", opt_index_name);
324                }
325                if let Some(opt_index_type) = opt_index_type {
326                    write!(f, " {}", opt_index_type);
327                }
328                write!(f, " {}", KeyPart::format_list(key_part));
329                if let Some(opt_index_option) = opt_index_option {
330                    write!(f, " {}", IndexOption::format_list(opt_index_option));
331                }
332                Ok(())
333            }
334            AlterTableOption::AddFulltextOrSpatial {
335                ref fulltext_or_spatial,
336                ref opt_index_or_key,
337                ref opt_index_name,
338                ref key_part,
339                ref opt_index_option,
340            } => {
341                write!(f, " ADD {}", fulltext_or_spatial);
342                if let Some(opt_index_or_key) = opt_index_or_key {
343                    write!(f, " {}", opt_index_or_key);
344                }
345                if let Some(opt_index_name) = opt_index_name {
346                    write!(f, " {}", opt_index_name);
347                }
348                write!(f, " {}", KeyPart::format_list(key_part));
349                if let Some(opt_index_option) = opt_index_option {
350                    write!(f, " {}", IndexOption::format_list(opt_index_option));
351                }
352                Ok(())
353            }
354            AlterTableOption::AddPrimaryKey {
355                ref opt_symbol,
356                ref opt_index_type,
357                ref key_part,
358                ref opt_index_option,
359            } => {
360                write!(f, "ADD");
361                if let Some(opt_symbol) = opt_symbol {
362                    write!(f, " CONSTRAINT {}", opt_symbol);
363                }
364                write!(f, " PRIMARY KEY");
365                if let Some(opt_index_type) = opt_index_type {
366                    write!(f, " {}", opt_index_type);
367                }
368                write!(f, " {}", KeyPart::format_list(key_part));
369                if let Some(opt_index_option) = opt_index_option {
370                    write!(f, " {}", IndexOption::format_list(opt_index_option));
371                }
372                Ok(())
373            }
374            AlterTableOption::AddUnique {
375                ref opt_symbol,
376                ref opt_index_or_key,
377                ref opt_index_name,
378                ref opt_index_type,
379                ref key_part,
380                ref opt_index_option,
381            } => {
382                write!(f, "ADD");
383                if let Some(opt_symbol) = opt_symbol {
384                    write!(f, " CONSTRAINT {}", opt_symbol);
385                }
386                write!(f, " UNIQUE");
387                if let Some(opt_index_or_key) = opt_index_or_key {
388                    write!(f, " {}", opt_index_or_key);
389                }
390                if let Some(opt_index_name) = opt_index_name {
391                    write!(f, " {}", opt_index_name);
392                }
393                if let Some(opt_index_type) = opt_index_type {
394                    write!(f, " {}", opt_index_type);
395                }
396                write!(f, " {}", KeyPart::format_list(key_part));
397                if let Some(opt_index_option) = opt_index_option {
398                    write!(f, " {}", IndexOption::format_list(opt_index_option));
399                }
400                Ok(())
401            }
402            AlterTableOption::AddForeignKey {
403                ref opt_symbol,
404                ref opt_index_name,
405                ref columns,
406                ref reference_definition,
407            } => {
408                write!(f, "ADD");
409                if let Some(opt_symbol) = opt_symbol {
410                    write!(f, " CONSTRAINT {}", opt_symbol);
411                }
412                write!(f, " FOREIGN KEY");
413                if let Some(opt_index_name) = opt_index_name {
414                    write!(f, " {}", opt_index_name);
415                }
416                write!(f, " ({})", columns.join(", "));
417                write!(f, " {}", reference_definition);
418                Ok(())
419            }
420            AlterTableOption::AddCheck {
421                ref check_constraint,
422            } => {
423                write!(f, " ADD {}", check_constraint)
424            }
425            AlterTableOption::DropCheckOrConstraint {
426                ref check_or_constraint,
427                ref symbol,
428            } => {
429                write!(f, "DROP {} {}", &check_or_constraint, &symbol)
430            }
431            AlterTableOption::AlterCheckOrConstraintEnforced {
432                ref check_or_constraint,
433                ref symbol,
434                ref enforced,
435            } => {
436                write!(f, "DROP {} {}", &check_or_constraint, &symbol);
437                if !*enforced {
438                    write!(f, " NOT");
439                }
440                write!(f, " ENFORCED");
441                Ok(())
442            }
443            AlterTableOption::Algorithm { ref algorithm } => {
444                write!(f, " {}", algorithm)
445            }
446            AlterTableOption::AlterColumn {
447                ref col_name,
448                ref alter_column_operation,
449            } => {
450                write!(f, " ALTER {} {}", col_name, alter_column_operation)
451            }
452            AlterTableOption::AlterIndexVisibility {
453                ref index_name,
454                ref visible,
455            } => {
456                write!(f, " ALTER INDEX {} {}", index_name, visible)
457            }
458            AlterTableOption::ChangeColumn {
459                ref old_col_name,
460                ref column_definition,
461            } => {
462                write!(f, " CHANGE {} {}", old_col_name, column_definition)
463            }
464            AlterTableOption::DefaultCharacterSet {
465                ref charset_name,
466                ref collation_name,
467            } => {
468                write!(f, " CHARACTER SET {}", charset_name);
469                if let Some(collation_name) = collation_name {
470                    write!(f, " COLLATE {}", collation_name);
471                }
472                Ok(())
473            }
474            AlterTableOption::ConvertToCharacterSet {
475                ref charset_name,
476                ref collation_name,
477            } => {
478                write!(f, " CONVERT TO CHARACTER SET {}", charset_name);
479                if let Some(collation_name) = collation_name {
480                    write!(f, " COLLATE {}", collation_name);
481                }
482                Ok(())
483            }
484            AlterTableOption::DisableKeys => {
485                write!(f, " DISABLE KEYS")
486            }
487            AlterTableOption::EnableKeys => {
488                write!(f, " ENABLE KEYS")
489            }
490            AlterTableOption::DiscardTablespace => {
491                write!(f, " DISCARD TABLESPACE")
492            }
493            AlterTableOption::ImportTablespace => {
494                write!(f, " IMPORT TABLESPACE")
495            }
496            AlterTableOption::DropColumn { ref col_name } => {
497                write!(f, " DROP {}", col_name)
498            }
499            AlterTableOption::DropIndexOrKey {
500                ref index_or_key,
501                ref index_name,
502            } => {
503                write!(f, " DROP {} {}", index_or_key, index_name)
504            }
505            AlterTableOption::DropPrimaryKey => {
506                write!(f, " DROP PRIMARY KEY")
507            }
508            AlterTableOption::DropForeignKey { ref fk_symbol } => {
509                write!(f, " DROP FOREIGN KEY {}", fk_symbol)
510            }
511            AlterTableOption::Force => {
512                write!(f, " FORCE")
513            }
514            AlterTableOption::Lock { ref lock_type } => {
515                write!(f, " LOCK {}", lock_type)
516            }
517            AlterTableOption::ModifyColumn {
518                ref column_definition,
519            } => {
520                write!(f, " MODIFY {}", column_definition)
521            }
522            AlterTableOption::OrderBy { ref columns } => {
523                let columns = columns.join(", ");
524                write!(f, " ORDER BY {}", columns)
525            }
526            AlterTableOption::RenameColumn {
527                ref old_col_name,
528                ref new_col_name,
529            } => {
530                write!(f, " RENAME COLUMN {} {}", old_col_name, new_col_name)
531            }
532            AlterTableOption::RenameIndexOrKey {
533                ref index_or_key,
534                ref old_index_name,
535                ref new_index_name,
536            } => {
537                write!(
538                    f,
539                    " RENAME {} {} TO {}",
540                    index_or_key, old_index_name, new_index_name
541                )
542            }
543            AlterTableOption::RenameTable { ref new_tbl_name } => {
544                write!(f, " RENAME TO {}", new_tbl_name)
545            }
546            AlterTableOption::Validation {
547                ref with_validation,
548            } => {
549                if *with_validation {
550                    write!(f, " WITH");
551                } else {
552                    write!(f, " WITHOUT");
553                }
554                write!(f, " VALIDATION");
555                Ok(())
556            }
557        }
558    }
559}
560
561impl AlterTableOption {
562    fn parse(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
563        let mut parser = alt((
564            Self::alter_table_options,
565            Self::alter_option_part_1,
566            Self::alter_option_part_2,
567        ));
568        let (remaining_input, res) = parser(i)?;
569        Ok((remaining_input, res))
570    }
571
572    pub fn format_list(list: &[AlterTableOption]) -> String {
573        list.iter()
574            .map(|x| x.to_string())
575            .collect::<Vec<String>>()
576            .join(", ")
577    }
578
579    /// `table_options:
580    ///     table_option [[,] table_option] ...`
581    pub fn alter_table_options(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
582        map(
583            many1(terminated(
584                TableOption::parse,
585                opt(CommonParser::ws_sep_comma),
586            )),
587            |table_options| AlterTableOption::TableOptions { table_options },
588        )(i)
589    }
590
591    fn alter_option_part_1(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
592        alt((
593            Self::add_column,
594            Self::add_index_or_key,
595            Self::add_fulltext_or_spatial,
596            Self::add_primary_key,
597            Self::add_unique,
598            Self::add_foreign_key,
599            Self::add_check,
600            Self::drop_check_or_constraint,
601            Self::alter_check_or_constraint_enforced,
602            map(AlgorithmType::parse, |x| AlterTableOption::Algorithm {
603                algorithm: x,
604            }),
605            Self::alter_column,
606            Self::alter_index_visibility,
607            Self::change_column,
608            Self::default_character_set,
609        ))(i)
610    }
611
612    fn alter_option_part_2(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
613        alt((
614            Self::convert_to_character_set,
615            Self::disable_or_enable_keys,
616            Self::discard_or_import_tablespace,
617            Self::drop_column,
618            Self::drop_index_or_key,
619            Self::drop_primary_key,
620            Self::drop_foreign_key,
621            Self::force,
622            Self::lock,
623            Self::modify_column,
624            Self::order_by,
625            Self::rename_column,
626            Self::rename_index_or_key,
627            Self::rename_table,
628            Self::without_or_with_validation,
629        ))(i)
630    }
631
632    /// `[CONSTRAINT [symbol]]`
633    fn opt_constraint_with_opt_symbol_and_operation(
634        i: &str,
635    ) -> IResult<&str, Option<String>, ParseSQLError<&str>> {
636        map(
637            tuple((
638                tag_no_case("ADD"),
639                opt(preceded(
640                    tuple((multispace1, tag_no_case("CONSTRAINT"))),
641                    opt(preceded(multispace1, CommonParser::sql_identifier)),
642                )),
643            )),
644            |(_, x)| x.and_then(|inner| inner.map(String::from)),
645        )(i)
646    }
647
648    /// `ADD [COLUMN] col_name column_definition
649    ///     [FIRST | AFTER col_name]`
650    /// `ADD [COLUMN] (col_name column_definition,...)`
651    fn add_column(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
652        map(
653            tuple((
654                tag_no_case("ADD"),
655                alt((
656                    map(
657                        tuple((
658                            multispace1,
659                            tag_no_case("COLUMN"),
660                            multispace1,
661                            ColumnSpecification::parse,
662                            multispace0,
663                        )),
664                        |x| (true, vec![x.3]),
665                    ),
666                    map(
667                        tuple((
668                            multispace1,
669                            tag_no_case("COLUMN"),
670                            multispace0,
671                            tag("("),
672                            multispace0,
673                            many1(ColumnSpecification::parse),
674                            multispace0,
675                            tag(")"),
676                        )),
677                        |x| (true, x.5),
678                    ),
679                    map(tuple((multispace0, ColumnSpecification::parse)), |x| {
680                        (false, vec![x.1])
681                    }),
682                    map(
683                        tuple((
684                            multispace0,
685                            tag("("),
686                            multispace0,
687                            many1(ColumnSpecification::parse),
688                            multispace0,
689                            tag(")"),
690                        )),
691                        |x| (false, x.3),
692                    ),
693                )),
694            )),
695            |(_, (opt_column, columns))| AlterTableOption::AddColumn {
696                opt_column,
697                columns,
698            },
699        )(i)
700    }
701
702    /// `ADD {INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option] ...`
703    fn add_index_or_key(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
704        map(
705            tuple((
706                tuple((tag_no_case("ADD"), multispace1)),
707                // {INDEX | KEY}
708                IndexOrKeyType::parse,
709                // [index_name]
710                CommonParser::opt_index_name,
711                // [index_type]
712                IndexType::opt_index_type,
713                // (key_part,...)
714                KeyPart::parse,
715                // [index_option]
716                IndexOption::opt_index_option,
717            )),
718            |(_, index_or_key, opt_index_name, opt_index_type, key_part, opt_index_option)| {
719                AlterTableOption::AddIndexOrKey {
720                    index_or_key,
721                    opt_index_name,
722                    opt_index_type,
723                    key_part,
724                    opt_index_option,
725                }
726            },
727        )(i)
728    }
729
730    /// `ADD {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...) [index_option] ...`
731    fn add_fulltext_or_spatial(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
732        map(
733            tuple((
734                tuple((tag_no_case("ADD"), multispace1)),
735                // {FULLTEXT | SPATIAL}
736                FulltextOrSpatialType::parse,
737                // [INDEX | KEY]
738                preceded(multispace1, opt(IndexOrKeyType::parse)),
739                // [index_name]
740                CommonParser::opt_index_name,
741                // (key_part,...)
742                KeyPart::parse,
743                // [index_option]
744                IndexOption::opt_index_option,
745            )),
746            |(_, fulltext_or_spatial, index_or_key, opt_index_name, key_part, opt_index_option)| {
747                AlterTableOption::AddFulltextOrSpatial {
748                    fulltext_or_spatial,
749                    opt_index_or_key: index_or_key,
750                    opt_index_name,
751                    key_part,
752                    opt_index_option,
753                }
754            },
755        )(i)
756    }
757
758    /// `ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (key_part,...) [index_option] ...`
759    fn add_primary_key(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
760        map(
761            tuple((
762                // [CONSTRAINT [symbol]]
763                Self::opt_constraint_with_opt_symbol_and_operation,
764                // PRIMARY KEY
765                tuple((
766                    multispace0,
767                    tag_no_case("PRIMARY"),
768                    multispace1,
769                    tag_no_case("KEY"),
770                )),
771                // [index_type]
772                IndexType::opt_index_type,
773                // (key_part,...)
774                KeyPart::parse,
775                // [index_option]
776                IndexOption::opt_index_option,
777            )),
778            |(opt_symbol, _, opt_index_type, key_part, opt_index_option)| {
779                AlterTableOption::AddPrimaryKey {
780                    opt_symbol,
781                    opt_index_type,
782                    key_part,
783                    opt_index_option,
784                }
785            },
786        )(i)
787    }
788
789    /// `ADD [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY]
790    ///     [index_name] [index_type] (key_part,...) [index_option] ...`
791    fn add_unique(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
792        map(
793            tuple((
794                // [CONSTRAINT [symbol]]
795                Self::opt_constraint_with_opt_symbol_and_operation,
796                // UNIQUE [INDEX | KEY]
797                map(
798                    tuple((
799                        multispace0,
800                        tag_no_case("UNIQUE"),
801                        multispace1,
802                        opt(alt((
803                            map(tag_no_case("INDEX"), |_| IndexOrKeyType::Index),
804                            map(tag_no_case("KEY"), |_| IndexOrKeyType::Key),
805                        ))),
806                    )),
807                    |(_, _, _, value)| value,
808                ),
809                // [index_name]
810                CommonParser::opt_index_name,
811                // [index_type]
812                IndexType::opt_index_type,
813                // (key_part,...)
814                KeyPart::parse,
815                // [index_option]
816                IndexOption::opt_index_option,
817            )),
818            |(
819                opt_symbol,
820                opt_index_or_key,
821                opt_index_name,
822                opt_index_type,
823                key_part,
824                opt_index_option,
825            )| {
826                AlterTableOption::AddUnique {
827                    opt_symbol,
828                    opt_index_or_key,
829                    opt_index_name,
830                    opt_index_type,
831                    key_part,
832                    opt_index_option,
833                }
834            },
835        )(i)
836    }
837
838    /// `ADD [CONSTRAINT [symbol]] FOREIGN KEY
839    ///     [index_name] (col_name,...) reference_definition`
840    fn add_foreign_key(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
841        map(
842            tuple((
843                // [CONSTRAINT [symbol]]
844                Self::opt_constraint_with_opt_symbol_and_operation,
845                // FOREIGN KEY
846                tuple((
847                    multispace0,
848                    tag_no_case("FOREIGN"),
849                    multispace1,
850                    tag_no_case("KEY"),
851                )),
852                // [index_name]
853                CommonParser::opt_index_name,
854                // (col_name,...)
855                map(
856                    tuple((
857                        multispace0,
858                        delimited(
859                            tag("("),
860                            delimited(multispace0, Column::index_col_list, multispace0),
861                            tag(")"),
862                        ),
863                    )),
864                    |(_, value)| value.iter().map(|x| x.name.clone()).collect(),
865                ),
866                // reference_definition
867                ReferenceDefinition::parse,
868            )),
869            |(opt_symbol, _, opt_index_name, columns, reference_definition)| {
870                AlterTableOption::AddForeignKey {
871                    opt_symbol,
872                    opt_index_name,
873                    columns,
874                    reference_definition,
875                }
876            },
877        )(i)
878    }
879
880    /// `ADD [CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]`
881    fn add_check(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
882        map(
883            tuple((
884                // [CONSTRAINT [symbol]]
885                Self::opt_constraint_with_opt_symbol_and_operation,
886                // CHECK
887                tuple((multispace1, tag_no_case("CHECK"), multispace0)),
888                // (expr)
889                map(delimited(tag("("), take_until(")"), tag(")")), |expr| {
890                    String::from(expr)
891                }),
892                // [[NOT] ENFORCED]
893                map(
894                    opt(tuple((
895                        multispace0,
896                        opt(tag_no_case("NOT")),
897                        multispace1,
898                        tag_no_case("ENFORCED"),
899                        multispace0,
900                    ))),
901                    |x| x.map_or(true, |(_, opt_not, _, _, _)| opt_not.is_none()),
902                ),
903            )),
904            |(symbol, _, expr, enforced)| AlterTableOption::AddCheck {
905                check_constraint: CheckConstraintDefinition {
906                    symbol,
907                    expr,
908                    enforced,
909                },
910            },
911        )(i)
912    }
913
914    /// `DROP {CHECK | CONSTRAINT} symbol`
915    fn drop_check_or_constraint(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
916        map(
917            tuple((
918                tuple((tag_no_case("DROP"), multispace1)),
919                // {CHECK | CONSTRAINT}
920                CheckOrConstraintType::parse,
921                // symbol
922                map(
923                    tuple((multispace1, CommonParser::sql_identifier, multispace0)),
924                    |(_, symbol, _)| String::from(symbol),
925                ),
926            )),
927            |(_, check_or_constraint, symbol)| AlterTableOption::DropCheckOrConstraint {
928                check_or_constraint,
929                symbol,
930            },
931        )(i)
932    }
933
934    /// `ALTER {CHECK | CONSTRAINT} symbol [NOT] ENFORCED`
935    fn alter_check_or_constraint_enforced(
936        i: &str,
937    ) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
938        map(
939            tuple((
940                tuple((tag_no_case("ALTER"), multispace1)),
941                // {CHECK | CONSTRAINT}
942                CheckOrConstraintType::parse,
943                // symbol
944                map(
945                    tuple((multispace1, CommonParser::sql_identifier, multispace1)),
946                    |(_, symbol, _)| String::from(symbol),
947                ),
948                opt(tag_no_case("NOT ")),
949                tuple((multispace0, tag_no_case("ENFORCED"))),
950            )),
951            |(_, check_or_constraint, symbol, opt_not, _)| {
952                AlterTableOption::AlterCheckOrConstraintEnforced {
953                    check_or_constraint,
954                    symbol,
955                    enforced: opt_not.is_none(),
956                }
957            },
958        )(i)
959    }
960
961    /// `ALTER [COLUMN] col_name {
962    ///   SET DEFAULT {literal | (expr)}
963    ///   | SET {VISIBLE | INVISIBLE}
964    ///   | DROP DEFAULT
965    /// }`
966    fn alter_column(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
967        map(
968            tuple((
969                tag_no_case("ALTER "),
970                multispace0,
971                opt(tag_no_case("COLUMN ")),
972                // col_name
973                map(
974                    tuple((multispace0, CommonParser::sql_identifier, multispace1)),
975                    |(_, col_name, _)| String::from(col_name),
976                ),
977                AlertColumnOperation::parse,
978                multispace0,
979            )),
980            |(_, _, _, col_name, alter_column_operation, _)| AlterTableOption::AlterColumn {
981                col_name,
982                alter_column_operation,
983            },
984        )(i)
985    }
986
987    /// `ALTER INDEX index_name {VISIBLE | INVISIBLE}`
988    fn alter_index_visibility(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
989        map(
990            tuple((
991                tag_no_case("ALTER "),
992                multispace0,
993                opt(tag_no_case("INDEX ")),
994                // index_name
995                map(
996                    tuple((multispace0, CommonParser::sql_identifier, multispace1)),
997                    |(_, col_name, _)| String::from(col_name),
998                ),
999                VisibleType::parse,
1000                multispace0,
1001            )),
1002            |(_, _, _, index_name, visible, _)| AlterTableOption::AlterIndexVisibility {
1003                index_name,
1004                visible,
1005            },
1006        )(i)
1007    }
1008
1009    /// `CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST | AFTER col_name]`
1010    fn change_column(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1011        map(
1012            tuple((
1013                tag_no_case("CHANGE "),
1014                multispace0,
1015                opt(tag_no_case("COLUMN ")),
1016                multispace0,
1017                // old_col_name
1018                map(CommonParser::sql_identifier, String::from),
1019                multispace1,
1020                ColumnSpecification::parse,
1021                multispace0,
1022            )),
1023            |(_, _, _, _, old_col_name, _, column_definition, _)| AlterTableOption::ChangeColumn {
1024                old_col_name,
1025                column_definition,
1026            },
1027        )(i)
1028    }
1029
1030    /// `[DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]`
1031    fn default_character_set(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1032        map(
1033            tuple((
1034                opt(tag_no_case("DEFAULT ")),
1035                multispace0,
1036                tuple((
1037                    multispace0,
1038                    tag_no_case("CHARACTER"),
1039                    multispace1,
1040                    tag_no_case("SET"),
1041                    multispace0,
1042                    opt(tag("=")),
1043                    multispace0,
1044                )),
1045                map(CommonParser::sql_identifier, String::from),
1046                multispace0,
1047                opt(map(
1048                    tuple((
1049                        multispace0,
1050                        tag_no_case("COLLATE"),
1051                        multispace1,
1052                        CommonParser::sql_identifier,
1053                    )),
1054                    |(_, _, _, collation_name)| String::from(collation_name),
1055                )),
1056            )),
1057            |(_, _, _, charset_name, _, collation_name)| AlterTableOption::DefaultCharacterSet {
1058                charset_name,
1059                collation_name,
1060            },
1061        )(i)
1062    }
1063
1064    /// `CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]`
1065    fn convert_to_character_set(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1066        let prefix = tuple((
1067            tag_no_case("CONVERT"),
1068            multispace1,
1069            tag_no_case("TO"),
1070            multispace1,
1071            tag_no_case("CHARACTER"),
1072            multispace1,
1073            tag_no_case("SET"),
1074            multispace1,
1075        ));
1076        map(
1077            tuple((
1078                // CONVERT TO CHARACTER SET
1079                prefix,
1080                map(CommonParser::sql_identifier, String::from),
1081                multispace0,
1082                opt(map(
1083                    tuple((
1084                        multispace0,
1085                        tag_no_case("COLLATE"),
1086                        multispace1,
1087                        CommonParser::sql_identifier,
1088                    )),
1089                    |(_, _, _, collation_name)| String::from(collation_name),
1090                )),
1091            )),
1092            |(_, charset_name, _, collation_name)| AlterTableOption::ConvertToCharacterSet {
1093                charset_name,
1094                collation_name,
1095            },
1096        )(i)
1097    }
1098
1099    /// `{DISCARD | IMPORT} TABLESPACE`
1100    fn disable_or_enable_keys(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1101        map(
1102            tuple((
1103                alt((
1104                    map(tag_no_case("DISABLE"), |_| AlterTableOption::DisableKeys),
1105                    map(tag_no_case("ENABLE"), |_| AlterTableOption::EnableKeys),
1106                )),
1107                multispace1,
1108                tag_no_case("KEYS"),
1109                multispace0,
1110            )),
1111            |(operation, _, _, _)| operation,
1112        )(i)
1113    }
1114
1115    /// `{DISCARD | IMPORT} TABLESPACE`
1116    fn discard_or_import_tablespace(
1117        i: &str,
1118    ) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1119        map(
1120            tuple((
1121                alt((
1122                    map(tag_no_case("DISCARD"), |_| {
1123                        AlterTableOption::DiscardTablespace
1124                    }),
1125                    map(tag_no_case("IMPORT"), |_| {
1126                        AlterTableOption::ImportTablespace
1127                    }),
1128                )),
1129                multispace1,
1130                tag_no_case("TABLESPACE"),
1131                multispace0,
1132            )),
1133            |(operation, _, _, _)| operation,
1134        )(i)
1135    }
1136
1137    /// `DROP [COLUMN] col_name`
1138    fn drop_column(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1139        map(
1140            tuple((
1141                tag_no_case("DROP "),
1142                multispace0,
1143                opt(tag_no_case("COLUMN ")),
1144                // col_name
1145                map(
1146                    tuple((multispace0, CommonParser::sql_identifier, multispace0)),
1147                    |(_, col_name, _)| String::from(col_name),
1148                ),
1149                multispace0,
1150            )),
1151            |(_, _, _, col_name, _)| AlterTableOption::DropColumn { col_name },
1152        )(i)
1153    }
1154
1155    /// `DROP {INDEX | KEY} index_name`
1156    fn drop_index_or_key(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1157        map(
1158            tuple((
1159                tuple((tag_no_case("DROP"), multispace1)),
1160                // {INDEX | KEY}
1161                IndexOrKeyType::parse,
1162                // [index_name]
1163                map(
1164                    tuple((multispace1, CommonParser::sql_identifier, multispace0)),
1165                    |(_, index_name, _)| String::from(index_name),
1166                ),
1167                multispace0,
1168            )),
1169            |(_, index_or_key, index_name, _)| AlterTableOption::DropIndexOrKey {
1170                index_or_key,
1171                index_name,
1172            },
1173        )(i)
1174    }
1175
1176    /// `DROP PRIMARY KEY`
1177    fn drop_primary_key(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1178        map(
1179            tuple((
1180                tag_no_case("DROP"),
1181                multispace1,
1182                tag_no_case("PRIMARY"),
1183                multispace1,
1184                tag_no_case("KEY"),
1185                multispace0,
1186            )),
1187            |_| AlterTableOption::DropPrimaryKey,
1188        )(i)
1189    }
1190
1191    /// `DROP FOREIGN KEY fk_symbol`
1192    fn drop_foreign_key(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1193        map(
1194            tuple((
1195                tag_no_case("DROP"),
1196                multispace1,
1197                tag_no_case("FOREIGN"),
1198                multispace1,
1199                tag_no_case("KEY"),
1200                multispace1,
1201                map(CommonParser::sql_identifier, String::from),
1202                multispace0,
1203            )),
1204            |x| AlterTableOption::DropForeignKey { fk_symbol: x.6 },
1205        )(i)
1206    }
1207
1208    /// `FORCE`
1209    fn force(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1210        map(tuple((tag_no_case("FORCE"), multispace0)), |_| {
1211            AlterTableOption::Force
1212        })(i)
1213    }
1214
1215    /// `LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}`
1216    fn lock(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1217        map(LockType::parse, |(lock_type)| AlterTableOption::Lock {
1218            lock_type,
1219        })(i)
1220    }
1221
1222    /// `MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name]`
1223    fn modify_column(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1224        map(
1225            tuple((
1226                tag_no_case("MODIFY "),
1227                multispace0,
1228                opt(tag_no_case("COLUMN ")),
1229                multispace0,
1230                ColumnSpecification::parse,
1231                multispace0,
1232            )),
1233            |(_, _, _, _, column_definition, _)| AlterTableOption::ModifyColumn {
1234                column_definition,
1235            },
1236        )(i)
1237    }
1238
1239    /// `ORDER BY col_name [, col_name] ...`
1240    fn order_by(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1241        map(
1242            tuple((
1243                tag_no_case("ORDER"),
1244                multispace1,
1245                tag_no_case("BY"),
1246                multispace1,
1247                many0(map(
1248                    terminated(Column::without_alias, opt(CommonParser::ws_sep_comma)),
1249                    |e| e.name,
1250                )),
1251                multispace0,
1252            )),
1253            |(_, _, _, _, columns, _)| AlterTableOption::OrderBy { columns },
1254        )(i)
1255    }
1256
1257    /// `RENAME COLUMN old_col_name TO new_col_name`
1258    fn rename_column(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1259        map(
1260            tuple((
1261                tag_no_case("RENAME "),
1262                multispace0,
1263                opt(tag_no_case("COLUMN ")),
1264                multispace0,
1265                // old_col_name
1266                map(CommonParser::sql_identifier, String::from),
1267                multispace1,
1268                tag_no_case("TO"),
1269                multispace1,
1270                // new_col_name
1271                map(CommonParser::sql_identifier, String::from),
1272                multispace0,
1273            )),
1274            |(_, _, _, _, old_col_name, _, _, _, new_col_name, _)| AlterTableOption::RenameColumn {
1275                old_col_name,
1276                new_col_name,
1277            },
1278        )(i)
1279    }
1280
1281    /// `RENAME {INDEX | KEY} old_index_name TO new_index_name`
1282    fn rename_index_or_key(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1283        map(
1284            tuple((
1285                tuple((tag_no_case("RENAME"), multispace1)),
1286                // {INDEX | KEY}
1287                IndexOrKeyType::parse,
1288                // old_index_name
1289                map(
1290                    tuple((multispace1, CommonParser::sql_identifier, multispace1)),
1291                    |(_, index_name, _)| String::from(index_name),
1292                ),
1293                tuple((multispace1, tag_no_case("TO"))),
1294                // new_index_name
1295                map(
1296                    tuple((multispace1, CommonParser::sql_identifier, multispace1)),
1297                    |(_, index_name, _)| String::from(index_name),
1298                ),
1299                multispace0,
1300            )),
1301            |(_, index_or_key, old_index_name, _, new_index_name, _)| {
1302                AlterTableOption::RenameIndexOrKey {
1303                    index_or_key,
1304                    old_index_name,
1305                    new_index_name,
1306                }
1307            },
1308        )(i)
1309    }
1310
1311    /// `RENAME [TO | AS] new_tbl_name`
1312    fn rename_table(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1313        map(
1314            tuple((
1315                tuple((tag_no_case("RENAME"), multispace1)),
1316                // {INDEX | KEY}
1317                alt((tag_no_case("TO"), tag_no_case("AS"))),
1318                // new_tbl_name
1319                map(
1320                    tuple((multispace1, CommonParser::sql_identifier, multispace0)),
1321                    |(_, index_name, _)| String::from(index_name),
1322                ),
1323                multispace0,
1324            )),
1325            |x| AlterTableOption::RenameTable { new_tbl_name: x.2 },
1326        )(i)
1327    }
1328
1329    /// `{WITHOUT | WITH} VALIDATION`
1330    fn without_or_with_validation(i: &str) -> IResult<&str, AlterTableOption, ParseSQLError<&str>> {
1331        map(
1332            tuple((
1333                // {WITHOUT | WITH}
1334                alt((
1335                    map(tag_no_case("WITHOUT"), |_| false),
1336                    map(tag_no_case("WITH"), |_| true),
1337                )),
1338                multispace1,
1339                tag_no_case("VALIDATION"),
1340                multispace0,
1341            )),
1342            |x| AlterTableOption::Validation {
1343                with_validation: x.0,
1344            },
1345        )(i)
1346    }
1347}
1348
1349/// { SET DEFAULT {literal | (expr)} | SET {VISIBLE | INVISIBLE} | DROP DEFAULT }
1350#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
1351pub enum AlertColumnOperation {
1352    SetDefaultLiteral(String),
1353    SetDefaultExpr(String),
1354    SetVisible(VisibleType),
1355    DropDefault,
1356}
1357
1358impl Display for AlertColumnOperation {
1359    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1360        match *self {
1361            AlertColumnOperation::SetDefaultLiteral(ref val) => write!(f, "SET DEFAULT {}", val),
1362            AlertColumnOperation::SetDefaultExpr(ref val) => write!(f, "SET DEFAULT ({})", val),
1363            AlertColumnOperation::SetVisible(ref val) => write!(f, "SET {}", val),
1364            AlertColumnOperation::DropDefault => write!(f, "DROP DEFAULT"),
1365        }
1366    }
1367}
1368
1369impl AlertColumnOperation {
1370    fn parse(i: &str) -> IResult<&str, AlertColumnOperation, ParseSQLError<&str>> {
1371        alt((
1372            map(
1373                tuple((
1374                    tag_no_case("SET"),
1375                    multispace1,
1376                    tag_no_case("DEFAULT"),
1377                    multispace1,
1378                    alt((
1379                        map(
1380                            alt((recognize(tuple((opt(tag("-")), digit1))), alphanumeric1)),
1381                            |x| AlertColumnOperation::SetDefaultLiteral(String::from(x)),
1382                        ),
1383                        map(
1384                            delimited(tag("("), recognize(many1(anychar)), tag(")")),
1385                            |x| AlertColumnOperation::SetDefaultExpr(String::from(x)),
1386                        ),
1387                    )),
1388                    multispace0,
1389                )),
1390                |x| x.4,
1391            ),
1392            map(
1393                tuple((
1394                    tag_no_case("SET"),
1395                    multispace1,
1396                    VisibleType::parse,
1397                    multispace0,
1398                )),
1399                |x| AlertColumnOperation::SetVisible(x.2),
1400            ),
1401            map(
1402                tuple((
1403                    tag_no_case("DROP"),
1404                    multispace1,
1405                    tag_no_case("DEFAULT"),
1406                    multispace0,
1407                )),
1408                |_| AlertColumnOperation::DropDefault,
1409            ),
1410        ))(i)
1411    }
1412}
1413
1414////////////// TODO support alter partition parser
1415#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
1416pub enum AlterPartitionOption {
1417    None,
1418    AddPartition(PartitionDefinition),
1419    DropPartition(String),
1420    DiscardPartition,
1421    ImportPartition,
1422    TruncatePartition,
1423    CoalescePartition,
1424    ReorganizePartitionInto,
1425    ExchangePartitionWithTable,
1426    AnalyzePartition,
1427    CheckPartition,
1428    OptimizePartition,
1429    RebuildPartition,
1430    RepairPartition,
1431    RemovePartitioning,
1432}
1433
1434impl AlterPartitionOption {
1435    fn format_list(list: &[AlterPartitionOption]) -> String {
1436        list.iter()
1437            .map(|x| x.to_string())
1438            .collect::<Vec<String>>()
1439            .join("")
1440    }
1441}
1442
1443impl Display for AlterPartitionOption {
1444    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1445        write!(f, "")
1446    }
1447}
1448
1449impl AlterPartitionOption {
1450    pub fn parse(i: &str) -> IResult<&str, AlterPartitionOption, ParseSQLError<&str>> {
1451        map(tag_no_case(""), |_| AlterPartitionOption::None)(i)
1452    }
1453}
1454////////////// TODO support alter partition parser
1455
1456#[cfg(test)]
1457mod tests {
1458    use base::column::{ColumnConstraint, ColumnPosition, ColumnSpecification};
1459    use base::fulltext_or_spatial_type::FulltextOrSpatialType;
1460    use base::index_option::IndexOption;
1461    use base::index_or_key_type::IndexOrKeyType;
1462    use base::visible_type::VisibleType;
1463    use base::{CheckConstraintDefinition, DataType, KeyPart, KeyPartType, Literal};
1464    use dds::alter_table::AlterTableOption;
1465
1466    #[test]
1467    fn parse_add_column() {
1468        let parts = [
1469            "ADD COLUMN column7 ENUM('small', 'medium', 'large') FIRST",
1470            "ADD COLUMN new_column5 TEXT COMMENT 'This is a comment' AFTER existing_column;",
1471            "ADD column6 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;",
1472        ];
1473        let exps = [
1474            AlterTableOption::AddColumn {
1475                opt_column: true,
1476                columns: vec![ColumnSpecification {
1477                    column: "column7".into(),
1478                    data_type: DataType::Enum(vec![
1479                        Literal::String("small".to_string()),
1480                        Literal::String("medium".to_string()),
1481                        Literal::String("large".to_string()),
1482                    ]),
1483                    constraints: vec![],
1484                    comment: None,
1485                    position: Some(ColumnPosition::First),
1486                }],
1487            },
1488            AlterTableOption::AddColumn {
1489                opt_column: true,
1490                columns: vec![ColumnSpecification {
1491                    column: "new_column5".into(),
1492                    data_type: DataType::Text,
1493                    constraints: vec![],
1494                    comment: Some("This is a comment".to_string()),
1495                    position: Some(ColumnPosition::After("existing_column".into())),
1496                }],
1497            },
1498            AlterTableOption::AddColumn {
1499                opt_column: false,
1500                columns: vec![ColumnSpecification {
1501                    column: "column6".into(),
1502                    data_type: DataType::Timestamp,
1503                    constraints: vec![
1504                        ColumnConstraint::DefaultValue(Literal::CurrentTimestamp),
1505                        ColumnConstraint::OnUpdate(Literal::CurrentTimestamp),
1506                    ],
1507                    comment: None,
1508                    position: None,
1509                }],
1510            },
1511        ];
1512        for i in 0..parts.len() {
1513            let res = AlterTableOption::add_column(parts[i]);
1514            assert!(res.is_ok());
1515            assert_eq!(res.unwrap().1, exps[i])
1516        }
1517    }
1518
1519    #[test]
1520    fn parse_add_index_or_key() {
1521        let parts = [
1522            "ADD INDEX index_name (column_name);",
1523            "ADD KEY index_name (column_name) INVISIBLE COMMENT 'This is an index comment';",
1524        ];
1525        let exps = [
1526            AlterTableOption::AddIndexOrKey {
1527                index_or_key: IndexOrKeyType::Index,
1528                opt_index_name: Some("index_name".to_string()),
1529                opt_index_type: None,
1530                key_part: vec![KeyPart {
1531                    r#type: KeyPartType::ColumnNameWithLength {
1532                        col_name: "column_name".to_string(),
1533                        length: None,
1534                    },
1535                    order: None,
1536                }],
1537                opt_index_option: None,
1538            },
1539            AlterTableOption::AddIndexOrKey {
1540                index_or_key: IndexOrKeyType::Key,
1541                opt_index_name: Some("index_name".to_string()),
1542                opt_index_type: None,
1543                key_part: vec![KeyPart {
1544                    r#type: KeyPartType::ColumnNameWithLength {
1545                        col_name: "column_name".to_string(),
1546                        length: None,
1547                    },
1548                    order: None,
1549                }],
1550                opt_index_option: Some(vec![
1551                    IndexOption::VisibleType(VisibleType::Invisible),
1552                    IndexOption::Comment("This is an index comment".to_string()),
1553                ]),
1554            },
1555        ];
1556        for i in 0..parts.len() {
1557            let res = AlterTableOption::add_index_or_key(parts[i]);
1558            assert!(res.is_ok());
1559            assert_eq!(res.unwrap().1, exps[i]);
1560        }
1561    }
1562
1563    #[test]
1564    fn parse_add_fulltext_or_spatial() {
1565        let parts = [
1566            "ADD FULLTEXT INDEX ft_index_name (column_name);",
1567            "ADD FULLTEXT INDEX ft_index_name (column_name) \
1568            KEY_BLOCK_SIZE=1024 COMMENT 'Fulltext index on column_name' WITH PARSER ngram VISIBLE;",
1569        ];
1570        let exps = [
1571            AlterTableOption::AddFulltextOrSpatial {
1572                fulltext_or_spatial: FulltextOrSpatialType::Fulltext,
1573                opt_index_or_key: Some(IndexOrKeyType::Index),
1574                opt_index_name: Some("ft_index_name".to_string()),
1575                key_part: vec![KeyPart {
1576                    r#type: KeyPartType::ColumnNameWithLength {
1577                        col_name: "column_name".to_string(),
1578                        length: None,
1579                    },
1580                    order: None,
1581                }],
1582                opt_index_option: None,
1583            },
1584            AlterTableOption::AddFulltextOrSpatial {
1585                fulltext_or_spatial: FulltextOrSpatialType::Fulltext,
1586                opt_index_or_key: Some(IndexOrKeyType::Index),
1587                opt_index_name: Some("ft_index_name".to_string()),
1588                key_part: vec![KeyPart {
1589                    r#type: KeyPartType::ColumnNameWithLength {
1590                        col_name: "column_name".to_string(),
1591                        length: None,
1592                    },
1593                    order: None,
1594                }],
1595                opt_index_option: Some(vec![
1596                    IndexOption::KeyBlockSize(1024),
1597                    IndexOption::Comment("Fulltext index on column_name".to_string()),
1598                    IndexOption::WithParser("ngram".to_string()),
1599                    IndexOption::VisibleType(VisibleType::Visible),
1600                ]),
1601            },
1602        ];
1603        for i in 0..parts.len() {
1604            let res = AlterTableOption::add_fulltext_or_spatial(parts[i]);
1605            assert!(res.is_ok());
1606            assert_eq!(res.unwrap().1, exps[i]);
1607        }
1608    }
1609
1610    #[test]
1611    fn parse_add_unique() {
1612        let parts = ["ADD CONSTRAINT UNIQUE (col_19)"];
1613        let exps = [AlterTableOption::AddUnique {
1614            opt_symbol: None,
1615            opt_index_or_key: None,
1616            opt_index_name: None,
1617            opt_index_type: None,
1618            key_part: vec![KeyPart {
1619                r#type: KeyPartType::ColumnNameWithLength {
1620                    col_name: "col_19".to_string(),
1621                    length: None,
1622                },
1623                order: None,
1624            }],
1625            opt_index_option: None,
1626        }];
1627        for i in 0..parts.len() {
1628            let res = AlterTableOption::add_unique(parts[i]);
1629            assert!(res.is_ok());
1630            assert_eq!(res.unwrap().1, exps[i]);
1631        }
1632    }
1633
1634    #[test]
1635    fn parse_convert_to_character_set() {
1636        let parts = ["CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"];
1637        let exps = [AlterTableOption::ConvertToCharacterSet {
1638            charset_name: "utf8mb4".to_string(),
1639            collation_name: Some("utf8mb4_unicode_ci".to_string()),
1640        }];
1641        for i in 0..parts.len() {
1642            let res = AlterTableOption::convert_to_character_set(parts[i]);
1643            assert!(res.is_ok());
1644            assert_eq!(res.unwrap().1, exps[i]);
1645        }
1646    }
1647
1648    #[test]
1649    fn parse_add_primary_key() {
1650        let parts = ["ADD PRIMARY KEY (new_column)"];
1651        let exps = [AlterTableOption::AddPrimaryKey {
1652            opt_symbol: None,
1653            opt_index_option: None,
1654            key_part: vec![KeyPart {
1655                r#type: KeyPartType::ColumnNameWithLength {
1656                    col_name: "new_column".to_string(),
1657                    length: None,
1658                },
1659                order: None,
1660            }],
1661            opt_index_type: None,
1662        }];
1663        for i in 0..parts.len() {
1664            let res = AlterTableOption::add_primary_key(parts[i]);
1665            assert!(res.is_ok());
1666            assert_eq!(res.unwrap().1, exps[i]);
1667        }
1668    }
1669
1670    #[test]
1671    fn parse_add_check() {
1672        let parts = ["ADD CONSTRAINT chk_column CHECK (new_column > 0) NOT ENFORCED;"];
1673        let exps = [AlterTableOption::AddCheck {
1674            check_constraint: CheckConstraintDefinition {
1675                symbol: Some("chk_column".to_string()),
1676                expr: "new_column > 0".to_string(),
1677                enforced: false,
1678            },
1679        }];
1680        for i in 0..parts.len() {
1681            let res = AlterTableOption::add_check(parts[i]);
1682            assert!(res.is_ok());
1683            assert_eq!(res.unwrap().1, exps[i]);
1684        }
1685    }
1686
1687    #[test]
1688    fn parse_modify_column() {
1689        let parts = ["MODIFY COLUMN another_column VARCHAR(255) FIRST;"];
1690        let exps = [AlterTableOption::ModifyColumn {
1691            column_definition: ColumnSpecification {
1692                column: "another_column".into(),
1693                data_type: DataType::Varchar(255),
1694                constraints: vec![],
1695                comment: None,
1696                position: Some(ColumnPosition::First),
1697            },
1698        }];
1699        for i in 0..parts.len() {
1700            let res = AlterTableOption::modify_column(parts[i]);
1701            assert!(res.is_ok());
1702            assert_eq!(res.unwrap().1, exps[i]);
1703        }
1704    }
1705}