sqlparser_mysql/dds/
create_table.rs

1use core::fmt;
2use std::fmt::{write, Display, Formatter};
3
4use nom::branch::alt;
5use nom::bytes::complete::{tag, tag_no_case, take_until};
6use nom::character::complete::{multispace0, multispace1};
7use nom::combinator::{map, opt};
8use nom::multi::many1;
9use nom::sequence::{delimited, preceded, terminated, tuple};
10use nom::IResult;
11
12use base::column::{Column, ColumnSpecification};
13use base::error::ParseSQLError;
14use base::fulltext_or_spatial_type::FulltextOrSpatialType;
15use base::index_option::IndexOption;
16use base::index_or_key_type::IndexOrKeyType;
17use base::index_type::IndexType;
18use base::table::Table;
19use base::table_option::TableOption;
20use base::{CheckConstraintDefinition, CommonParser, KeyPart, ReferenceDefinition};
21use dms::SelectStatement;
22
23/// **CreateTableStatement**
24/// [MySQL Doc](https://dev.mysql.com/doc/refman/8.0/en/create-table.html)
25///
26/// - Simple Create:
27/// ```sql
28/// CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
29///     (create_definition,...)
30///     [table_options]
31///     [partition_options]
32///```
33/// - Create as Select:
34/// ```sql
35/// CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
36///     [(create_definition,...)]
37///     [table_options]
38///     [partition_options]
39///     [IGNORE | REPLACE]
40///     [AS] query_expression
41///```
42/// - Create Like:
43/// ```sql
44/// CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
45///     { LIKE old_tbl_name | (LIKE old_tbl_name) }
46/// ```
47#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
48pub struct CreateTableStatement {
49    /// `[TEMPORARY]` part
50    pub temporary: bool,
51    /// `[IF NOT EXISTS]` part
52    pub if_not_exists: bool,
53    /// `tbl_name` part
54    pub table: Table,
55    /// simple definition | as select definition | like other table definition
56    pub create_type: CreateTableType,
57}
58
59impl Display for CreateTableStatement {
60    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61        write!(f, "CREATE");
62        if self.temporary {
63            write!(f, " TEMPORARY");
64        }
65        write!(f, " TABLE {}", &self.table);
66        write!(f, " {}", &self.create_type);
67        Ok(())
68    }
69}
70
71impl CreateTableStatement {
72    pub fn parse(i: &str) -> IResult<&str, CreateTableStatement, ParseSQLError<&str>> {
73        alt((
74            CreateTableType::create_simple,
75            CreateTableType::create_as_query,
76            CreateTableType::create_like_old_table,
77        ))(i)
78    }
79}
80
81#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
82pub enum IgnoreOrReplaceType {
83    Ignore,
84    Replace,
85}
86
87impl Display for IgnoreOrReplaceType {
88    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
89        match *self {
90            IgnoreOrReplaceType::Ignore => write!(f, "IGNORE"),
91            IgnoreOrReplaceType::Replace => write!(f, "REPLACE"),
92        }
93    }
94}
95
96impl IgnoreOrReplaceType {
97    fn parse(i: &str) -> IResult<&str, IgnoreOrReplaceType, ParseSQLError<&str>> {
98        alt((
99            map(tag_no_case("IGNORE"), |_| IgnoreOrReplaceType::Ignore),
100            map(tag_no_case("REPLACE"), |_| IgnoreOrReplaceType::Replace),
101        ))(i)
102    }
103}
104
105#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
106pub enum CreateTableType {
107    /// Simple Create
108    /// ```sql
109    /// CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
110    ///     (create_definition,...)
111    ///     [table_options]
112    ///     [partition_options]
113    /// ```
114    Simple {
115        create_definition: Vec<CreateDefinition>, // (create_definition,...)
116        table_options: Option<Vec<TableOption>>,  // [table_options]
117        partition_options: Option<CreatePartitionOption>, // [partition_options]
118    },
119
120    /// Select Create
121    /// ```sql
122    /// CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
123    ///     [(create_definition,...)]
124    ///     [table_options]
125    ///     [partition_options]
126    ///     [IGNORE | REPLACE]
127    ///     [AS] query_expression
128    /// ```
129    AsQuery {
130        create_definition: Option<Vec<CreateDefinition>>, // (create_definition,...)
131        table_options: Option<Vec<TableOption>>,          // [table_options]
132        partition_options: Option<CreatePartitionOption>, // [partition_options]
133        opt_ignore_or_replace: Option<IgnoreOrReplaceType>, // [IGNORE | REPLACE]
134        query_expression: SelectStatement,                // [AS] query_expression
135    },
136
137    /// Like Create
138    /// ```sql
139    /// CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
140    ///     { LIKE old_tbl_name | (LIKE old_tbl_name) }
141    /// ```
142    LikeOldTable { table: Table },
143}
144
145impl Display for CreateTableType {
146    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
147        match *self {
148            CreateTableType::Simple {
149                ref create_definition,
150                ref table_options,
151                ref partition_options,
152            } => {
153                write!(f, " {}", CreateDefinition::format_list(create_definition));
154                if let Some(table_options) = table_options {
155                    write!(f, " {}", TableOption::format_list(table_options));
156                };
157                if let Some(partition_options) = partition_options {
158                    write!(f, " {}", partition_options);
159                };
160                Ok(())
161            }
162            CreateTableType::AsQuery {
163                ref create_definition,
164                ref table_options,
165                ref partition_options,
166                ref opt_ignore_or_replace,
167                ref query_expression,
168            } => {
169                if let Some(create_definition) = create_definition {
170                    write!(f, " {}", CreateDefinition::format_list(create_definition));
171                }
172                if let Some(table_options) = table_options {
173                    write!(f, " {}", TableOption::format_list(table_options));
174                };
175                if let Some(partition_options) = partition_options {
176                    write!(f, " {}", partition_options);
177                };
178                if let Some(opt_ignore_or_replace) = opt_ignore_or_replace {
179                    write!(f, " {}", opt_ignore_or_replace);
180                };
181                write!(f, " {}", query_expression);
182                Ok(())
183            }
184            CreateTableType::LikeOldTable { ref table } => write!(f, "LIKE {}", table),
185        }
186    }
187}
188
189impl CreateTableType {
190    /// parse [CreateTableType::Simple]
191    fn create_simple(i: &str) -> IResult<&str, CreateTableStatement, ParseSQLError<&str>> {
192        map(
193            tuple((
194                Self::create_table_with_name,
195                multispace0,
196                // (create_definition,...)
197                CreateDefinition::create_definition_list,
198                multispace0,
199                // [table_options]
200                opt(Self::create_table_options),
201                multispace0,
202                // [partition_options]
203                opt(CreatePartitionOption::parse),
204                CommonParser::statement_terminator,
205            )),
206            |(x)| {
207                let temporary = x.0 .0;
208                let if_not_exists = x.0 .1;
209                let table = x.0 .2;
210                let create_type = CreateTableType::Simple {
211                    create_definition: x.2,
212                    table_options: x.4,
213                    partition_options: x.6,
214                };
215                CreateTableStatement {
216                    table,
217                    temporary,
218                    if_not_exists,
219                    create_type,
220                }
221            },
222        )(i)
223    }
224
225    /// parse [CreateTableType::AsQuery]
226    fn create_as_query(i: &str) -> IResult<&str, CreateTableStatement, ParseSQLError<&str>> {
227        map(
228            tuple((
229                Self::create_table_with_name,
230                multispace0,
231                // [(create_definition,...)]
232                opt(CreateDefinition::create_definition_list),
233                multispace0,
234                // [table_options]
235                opt(Self::create_table_options),
236                multispace0,
237                // [partition_options]
238                opt(CreatePartitionOption::parse),
239                multispace0,
240                opt(IgnoreOrReplaceType::parse),
241                multispace0,
242                opt(tag_no_case("AS")),
243                multispace0,
244                SelectStatement::parse,
245            )),
246            |(x)| {
247                let table = x.0 .2;
248                let if_not_exists = x.0 .1;
249                let temporary = x.0 .0;
250                let create_type = CreateTableType::AsQuery {
251                    create_definition: x.2,
252                    table_options: x.4,
253                    partition_options: x.6,
254                    opt_ignore_or_replace: x.8,
255                    query_expression: x.12,
256                };
257                CreateTableStatement {
258                    table,
259                    temporary,
260                    if_not_exists,
261                    create_type,
262                }
263            },
264        )(i)
265    }
266
267    /// parse [CreateTableType::LikeOldTable]
268    fn create_like_old_table(i: &str) -> IResult<&str, CreateTableStatement, ParseSQLError<&str>> {
269        map(
270            tuple((
271                Self::create_table_with_name,
272                multispace0,
273                // { LIKE old_tbl_name | (LIKE old_tbl_name) }
274                map(
275                    alt((
276                        map(
277                            tuple((
278                                tag_no_case("LIKE"),
279                                multispace1,
280                                Table::schema_table_reference,
281                            )),
282                            |x| x.2,
283                        ),
284                        map(
285                            delimited(tag("("), Table::schema_table_reference, tag(")")),
286                            |x| x,
287                        ),
288                    )),
289                    |x| CreateTableType::LikeOldTable { table: x },
290                ),
291                CommonParser::statement_terminator,
292            )),
293            |(x, _, create_type, _)| {
294                let table = x.2;
295                let if_not_exists = x.1;
296                let temporary = x.0;
297                CreateTableStatement {
298                    table,
299                    temporary,
300                    if_not_exists,
301                    create_type,
302                }
303            },
304        )(i)
305    }
306
307    /// parse `[table_options]` part
308    fn create_table_options(i: &str) -> IResult<&str, Vec<TableOption>, ParseSQLError<&str>> {
309        map(
310            many1(map(
311                tuple((
312                    TableOption::parse,
313                    multispace0,
314                    opt(CommonParser::ws_sep_comma),
315                )),
316                |x| x.0,
317            )),
318            |x| x,
319        )(i)
320    }
321
322    /// parse `CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name` part:
323    fn create_table_with_name(i: &str) -> IResult<&str, (bool, bool, Table), ParseSQLError<&str>> {
324        map(
325            tuple((
326                tuple((tag_no_case("CREATE"), multispace1)),
327                opt(tag_no_case("TEMPORARY")),
328                multispace0,
329                tuple((tag_no_case("TABLE"), multispace1)),
330                // [IF NOT EXISTS]
331                Self::if_not_exists,
332                multispace0,
333                // tbl_name
334                Table::schema_table_reference,
335            )),
336            |x| (x.1.is_some(), x.4, x.6),
337        )(i)
338    }
339
340    /// parse `[IF NOT EXISTS]` part
341    fn if_not_exists(i: &str) -> IResult<&str, bool, ParseSQLError<&str>> {
342        map(
343            opt(tuple((
344                tag_no_case("IF"),
345                multispace1,
346                tag_no_case("NOT"),
347                multispace1,
348                tag_no_case("EXISTS"),
349            ))),
350            |x| x.is_some(),
351        )(i)
352    }
353}
354
355#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
356pub enum CreateDefinition {
357    /// col_name column_definition
358    ColumnDefinition {
359        column_definition: ColumnSpecification,
360    },
361
362    /// `{INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option] ...`
363    IndexOrKey {
364        index_or_key: IndexOrKeyType,               // {INDEX | KEY}
365        opt_index_name: Option<String>,             // [index_name]
366        opt_index_type: Option<IndexType>,          // [index_type]
367        key_part: Vec<KeyPart>,                     // (key_part,...)
368        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
369    },
370
371    /// `{FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...) [index_option] ...`
372    FulltextOrSpatial {
373        fulltext_or_spatial: FulltextOrSpatialType, // {FULLTEXT | SPATIAL}
374        opt_index_or_key: Option<IndexOrKeyType>,   // {INDEX | KEY}
375        opt_index_name: Option<String>,             // [index_name]
376        key_part: Vec<KeyPart>,                     // (key_part,...)
377        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
378    },
379
380    /// `[CONSTRAINT [symbol]] PRIMARY KEY [index_type] (key_part,...) [index_option] ...`
381    PrimaryKey {
382        opt_symbol: Option<String>,                 // [symbol]
383        opt_index_type: Option<IndexType>,          // [index_type]
384        key_part: Vec<KeyPart>,                     // (key_part,...)
385        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
386    },
387
388    /// `[CONSTRAINT [symbol]] UNIQUE [INDEX | KEY] [index_name] [index_type] (key_part,...) [index_option] ...`
389    Unique {
390        opt_symbol: Option<String>,                 // [symbol]
391        opt_index_or_key: Option<IndexOrKeyType>,   // [INDEX | KEY]
392        opt_index_name: Option<String>,             // [index_name]
393        opt_index_type: Option<IndexType>,          // [index_type]
394        key_part: Vec<KeyPart>,                     // (key_part,...)
395        opt_index_option: Option<Vec<IndexOption>>, // [index_option]
396    },
397
398    /// `[CONSTRAINT [symbol]] FOREIGN KEY [index_name] (col_name,...) reference_definition`
399    ForeignKey {
400        opt_symbol: Option<String>,                // [symbol]
401        opt_index_name: Option<String>,            // [index_name]
402        columns: Vec<String>,                      // (col_name,...)
403        reference_definition: ReferenceDefinition, // reference_definition
404    },
405
406    /// `check_constraint_definition`
407    Check {
408        check_constraint_definition: CheckConstraintDefinition,
409    },
410}
411
412impl Display for CreateDefinition {
413    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
414        match *self {
415            CreateDefinition::ColumnDefinition {
416                ref column_definition,
417            } => write!(f, " {}", column_definition),
418            CreateDefinition::IndexOrKey {
419                ref index_or_key,
420                ref opt_index_name,
421                ref opt_index_type,
422                ref key_part,
423                ref opt_index_option,
424            } => {
425                write!(f, " {}", index_or_key);
426                if let Some(opt_index_name) = opt_index_name {
427                    write!(f, " {}", opt_index_name);
428                }
429                if let Some(opt_index_type) = opt_index_type {
430                    write!(f, " {}", opt_index_type);
431                }
432                write!(f, " {}", KeyPart::format_list(key_part));
433                if let Some(opt_index_option) = opt_index_option {
434                    write!(f, " {}", IndexOption::format_list(opt_index_option));
435                }
436                Ok(())
437            }
438            CreateDefinition::FulltextOrSpatial {
439                ref fulltext_or_spatial,
440                ref opt_index_or_key,
441                ref opt_index_name,
442                ref key_part,
443                ref opt_index_option,
444            } => {
445                write!(f, " {}", fulltext_or_spatial);
446                if let Some(opt_index_or_key) = opt_index_or_key {
447                    write!(f, " {}", opt_index_or_key);
448                }
449                if let Some(opt_index_name) = opt_index_name {
450                    write!(f, " {}", opt_index_name);
451                }
452                write!(f, " {}", KeyPart::format_list(key_part));
453                if let Some(opt_index_option) = opt_index_option {
454                    write!(f, " {}", IndexOption::format_list(opt_index_option));
455                }
456                Ok(())
457            }
458            CreateDefinition::PrimaryKey {
459                ref opt_symbol,
460                ref opt_index_type,
461                ref key_part,
462                ref opt_index_option,
463            } => {
464                if let Some(opt_symbol) = opt_symbol {
465                    write!(f, " CONSTRAINT {}", opt_symbol);
466                }
467                write!(f, " PRIMARY KEY");
468                if let Some(opt_index_type) = opt_index_type {
469                    write!(f, " {}", opt_index_type);
470                }
471                write!(f, " {}", KeyPart::format_list(key_part));
472                if let Some(opt_index_option) = opt_index_option {
473                    write!(f, " {}", IndexOption::format_list(opt_index_option));
474                }
475                Ok(())
476            }
477            CreateDefinition::Unique {
478                ref opt_symbol,
479                ref opt_index_or_key,
480                ref opt_index_name,
481                ref opt_index_type,
482                ref key_part,
483                ref opt_index_option,
484            } => {
485                if let Some(opt_symbol) = opt_symbol {
486                    write!(f, " CONSTRAINT {}", opt_symbol);
487                }
488                write!(f, " UNIQUE");
489                if let Some(opt_index_or_key) = opt_index_or_key {
490                    write!(f, " {}", opt_index_or_key);
491                }
492                if let Some(opt_index_name) = opt_index_name {
493                    write!(f, " {}", opt_index_name);
494                }
495                if let Some(opt_index_type) = opt_index_type {
496                    write!(f, " {}", opt_index_type);
497                }
498                write!(f, " {}", KeyPart::format_list(key_part));
499                if let Some(opt_index_option) = opt_index_option {
500                    write!(f, " {}", IndexOption::format_list(opt_index_option));
501                }
502                Ok(())
503            }
504            CreateDefinition::ForeignKey {
505                ref opt_symbol,
506                ref opt_index_name,
507                ref columns,
508                ref reference_definition,
509            } => {
510                if let Some(opt_symbol) = opt_symbol {
511                    write!(f, " CONSTRAINT {}", opt_symbol);
512                }
513                write!(f, " FOREIGN KEY");
514                if let Some(opt_index_name) = opt_index_name {
515                    write!(f, " {}", opt_index_name);
516                }
517                write!(f, " ({})", columns.join(", "));
518                write!(f, " {}", reference_definition);
519                Ok(())
520            }
521            CreateDefinition::Check {
522                ref check_constraint_definition,
523            } => write!(f, " {}", check_constraint_definition),
524        }
525    }
526}
527
528impl CreateDefinition {
529    /// `create_definition: {
530    ///     col_name column_definition
531    ///   | {INDEX | KEY} [index_name] [index_type] (key_part,...)
532    ///       [index_option] ...
533    ///   | {FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...)
534    ///       [index_option] ...
535    ///   | [CONSTRAINT [symbol]] PRIMARY KEY
536    ///       [index_type] (key_part,...)
537    ///       [index_option] ...
538    ///   | [CONSTRAINT [symbol]] UNIQUE [INDEX | KEY]
539    ///       [index_name] [index_type] (key_part,...)
540    ///       [index_option] ...
541    ///   | [CONSTRAINT [symbol]] FOREIGN KEY
542    ///       [index_name] (col_name,...)
543    ///       reference_definition
544    ///   | check_constraint_definition
545    /// }`
546    pub fn parse(i: &str) -> IResult<&str, CreateDefinition, ParseSQLError<&str>> {
547        alt((
548            map(ColumnSpecification::parse, |x| {
549                CreateDefinition::ColumnDefinition {
550                    column_definition: x,
551                }
552            }),
553            CreateDefinition::index_or_key,
554            CreateDefinition::fulltext_or_spatial,
555            CreateDefinition::primary_key,
556            CreateDefinition::unique,
557            CreateDefinition::foreign_key,
558            CreateDefinition::check_constraint_definition,
559        ))(i)
560    }
561
562    pub fn format_list(list: &[CreateDefinition]) -> String {
563        list.iter()
564            .map(|x| x.to_string())
565            .collect::<Vec<String>>()
566            .join(", ")
567    }
568
569    fn create_definition_list(
570        i: &str,
571    ) -> IResult<&str, Vec<CreateDefinition>, ParseSQLError<&str>> {
572        delimited(
573            tag("("),
574            many1(map(
575                tuple((
576                    multispace0,
577                    CreateDefinition::parse,
578                    multispace0,
579                    opt(CommonParser::ws_sep_comma),
580                    multispace0,
581                )),
582                |x| x.1,
583            )),
584            tag(")"),
585        )(i)
586    }
587
588    /// `{INDEX | KEY} [index_name] [index_type] (key_part,...) [index_option] ...`
589    fn index_or_key(i: &str) -> IResult<&str, CreateDefinition, ParseSQLError<&str>> {
590        map(
591            tuple((
592                // {INDEX | KEY}
593                IndexOrKeyType::parse,
594                // [index_name]
595                CommonParser::opt_index_name,
596                // [index_type]
597                IndexType::opt_index_type,
598                // (key_part,...)
599                KeyPart::parse,
600                // [index_option]
601                IndexOption::opt_index_option,
602            )),
603            |(index_or_key, opt_index_name, opt_index_type, key_part, opt_index_option)| {
604                CreateDefinition::IndexOrKey {
605                    index_or_key,
606                    opt_index_name,
607                    opt_index_type,
608                    key_part,
609                    opt_index_option,
610                }
611            },
612        )(i)
613    }
614
615    /// `{FULLTEXT | SPATIAL} [INDEX | KEY] [index_name] (key_part,...) [index_option] ...`
616    fn fulltext_or_spatial(i: &str) -> IResult<&str, CreateDefinition, ParseSQLError<&str>> {
617        map(
618            tuple((
619                // {FULLTEXT | SPATIAL}
620                FulltextOrSpatialType::parse,
621                // [INDEX | KEY]
622                preceded(multispace1, opt(IndexOrKeyType::parse)),
623                // [index_name]
624                CommonParser::opt_index_name,
625                // (key_part,...)
626                KeyPart::parse,
627                // [index_option]
628                IndexOption::opt_index_option,
629            )),
630            |(fulltext_or_spatial, index_or_key, index_name, key_part, opt_index_option)| {
631                CreateDefinition::FulltextOrSpatial {
632                    fulltext_or_spatial,
633                    opt_index_or_key: index_or_key,
634                    opt_index_name: index_name,
635                    key_part,
636                    opt_index_option,
637                }
638            },
639        )(i)
640    }
641
642    /// `[CONSTRAINT [symbol]] PRIMARY KEY [index_type] (key_part,...) [index_option] ...`
643    fn primary_key(i: &str) -> IResult<&str, CreateDefinition, ParseSQLError<&str>> {
644        map(
645            tuple((
646                Self::opt_constraint_with_opt_symbol, // [CONSTRAINT [symbol]]
647                tuple((
648                    multispace0,
649                    tag_no_case("PRIMARY"),
650                    multispace1,
651                    tag_no_case("KEY"),
652                )), // PRIMARY KEY
653                IndexType::opt_index_type,            // [index_type]
654                KeyPart::parse,                       // (key_part,...)
655                IndexOption::opt_index_option,        // [index_option]
656            )),
657            |(opt_symbol, _, opt_index_type, key_part, opt_index_option)| {
658                CreateDefinition::PrimaryKey {
659                    opt_symbol,
660                    opt_index_type,
661                    key_part,
662                    opt_index_option,
663                }
664            },
665        )(i)
666    }
667
668    /// `[CONSTRAINT [symbol]] UNIQUE [INDEX | KEY] [index_name] [index_type]
669    ///  (key_part,...) [index_option] ...`
670    fn unique(i: &str) -> IResult<&str, CreateDefinition, ParseSQLError<&str>> {
671        map(
672            tuple((
673                Self::opt_constraint_with_opt_symbol, // [CONSTRAINT [symbol]]
674                map(
675                    tuple((
676                        multispace0,
677                        tag_no_case("UNIQUE"),
678                        multispace1,
679                        opt(IndexOrKeyType::parse),
680                    )),
681                    |(_, _, _, value)| value,
682                ), // UNIQUE [INDEX | KEY]
683                CommonParser::opt_index_name,         // [index_name]
684                IndexType::opt_index_type,            // [index_type]
685                KeyPart::parse,                       // (key_part,...)
686                IndexOption::opt_index_option,        // [index_option]
687            )),
688            |(
689                opt_symbol,
690                opt_index_or_key,
691                opt_index_name,
692                opt_index_type,
693                key_part,
694                opt_index_option,
695            )| {
696                CreateDefinition::Unique {
697                    opt_symbol,
698                    opt_index_or_key,
699                    opt_index_name,
700                    opt_index_type,
701                    key_part,
702                    opt_index_option,
703                }
704            },
705        )(i)
706    }
707
708    /// `[CONSTRAINT [symbol]] FOREIGN KEY [index_name] (col_name,...) reference_definition`
709    fn foreign_key(i: &str) -> IResult<&str, CreateDefinition, ParseSQLError<&str>> {
710        map(
711            tuple((
712                // [CONSTRAINT [symbol]]
713                Self::opt_constraint_with_opt_symbol,
714                // FOREIGN KEY
715                tuple((
716                    multispace0,
717                    tag_no_case("FOREIGN"),
718                    multispace1,
719                    tag_no_case("KEY"),
720                )),
721                // [index_name]
722                CommonParser::opt_index_name,
723                // (col_name,...)
724                map(
725                    tuple((
726                        multispace0,
727                        delimited(
728                            tag("("),
729                            delimited(multispace0, Column::index_col_list, multispace0),
730                            tag(")"),
731                        ),
732                        multispace0,
733                    )),
734                    |(_, value, _)| value.iter().map(|x| x.name.clone()).collect(),
735                ),
736                // reference_definition
737                ReferenceDefinition::parse,
738            )),
739            |(opt_symbol, _, opt_index_name, columns, reference_definition)| {
740                CreateDefinition::ForeignKey {
741                    opt_symbol,
742                    opt_index_name,
743                    columns,
744                    reference_definition,
745                }
746            },
747        )(i)
748    }
749
750    /// check_constraint_definition
751    /// `[CONSTRAINT [symbol]] CHECK (expr) [[NOT] ENFORCED]`
752    fn check_constraint_definition(
753        i: &str,
754    ) -> IResult<&str, CreateDefinition, ParseSQLError<&str>> {
755        map(
756            tuple((
757                // [CONSTRAINT [symbol]]
758                Self::opt_constraint_with_opt_symbol,
759                // CHECK
760                tuple((multispace1, tag_no_case("CHECK"), multispace0)),
761                // (expr)
762                delimited(tag("("), take_until(")"), tag(")")),
763                // [[NOT] ENFORCED]
764                opt(tuple((
765                    multispace0,
766                    opt(tag_no_case("NOT")),
767                    multispace1,
768                    tag_no_case("ENFORCED"),
769                    multispace0,
770                ))),
771            )),
772            |(symbol, _, expr, opt_whether_enforced)| {
773                let expr = String::from(expr);
774                let enforced =
775                    opt_whether_enforced.map_or(true, |(_, opt_not, _, _, _)| opt_not.is_none());
776                CreateDefinition::Check {
777                    check_constraint_definition: CheckConstraintDefinition {
778                        symbol,
779                        expr,
780                        enforced,
781                    },
782                }
783            },
784        )(i)
785    }
786
787    /// `[CONSTRAINT [symbol]]`
788    fn opt_constraint_with_opt_symbol(
789        i: &str,
790    ) -> IResult<&str, Option<String>, ParseSQLError<&str>> {
791        map(
792            opt(preceded(
793                tag_no_case("CONSTRAINT"),
794                opt(preceded(multispace1, CommonParser::sql_identifier)),
795            )),
796            |(x)| x.and_then(|inner| inner.map(String::from)),
797        )(i)
798    }
799}
800
801///////////////////// TODO support create partition parser
802#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
803pub enum CreatePartitionOption {
804    None,
805}
806
807impl Display for CreatePartitionOption {
808    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
809        write!(f, "")
810    }
811}
812
813impl CreatePartitionOption {
814    fn parse(i: &str) -> IResult<&str, CreatePartitionOption, ParseSQLError<&str>> {
815        map(tag_no_case(""), |_| CreatePartitionOption::None)(i)
816    }
817}
818///////////////////// TODO support create partition parser
819
820#[cfg(test)]
821mod tests {
822    use base::column::{ColumnConstraint, ColumnSpecification};
823    use base::table_option::TableOption;
824    use base::{
825        Column, DataType, FieldDefinitionExpression, KeyPart, KeyPartType, Literal,
826        ReferenceDefinition,
827    };
828    use dds::create_table::{
829        CreateDefinition, CreatePartitionOption, CreateTableStatement, CreateTableType,
830    };
831    use dms::SelectStatement;
832
833    #[test]
834    fn parse_create_simple() {
835        let sqls = ["create table admin_role \
836            (`role_id` int(10) unsigned NOT NULL Auto_Increment COMMENT 'Role ID',\
837            `role_type` varchar(1) NOT NULL DEFAULT '0' COMMENT 'Role Type',\
838            PRIMARY KEY (`role_id`))\
839            ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Admin Role Table';"];
840        let exp = [
841            CreateTableStatement {
842                temporary: false,
843                if_not_exists: false,
844                table: "admin_role".into(),
845                create_type: CreateTableType::Simple {
846                    create_definition: vec![
847                        CreateDefinition::ColumnDefinition {
848                            column_definition: ColumnSpecification {
849                                column: "role_id".into(),
850                                data_type: DataType::UnsignedInt(10),
851                                constraints: vec![
852                                    ColumnConstraint::NotNull,
853                                    ColumnConstraint::AutoIncrement,
854                                ],
855                                comment: Some("Role ID".to_string()),
856                                position: None,
857                            },
858                        },
859                        CreateDefinition::ColumnDefinition {
860                            column_definition: ColumnSpecification {
861                                column: "role_type".into(),
862                                data_type: DataType::Varchar(1),
863                                constraints: vec![
864                                    ColumnConstraint::NotNull,
865                                    ColumnConstraint::DefaultValue(Literal::String(
866                                        "0".to_string(),
867                                    )),
868                                ],
869                                comment: Some("Role Type".to_string()),
870                                position: None,
871                            },
872                        },
873                        CreateDefinition::PrimaryKey {
874                            opt_symbol: None,
875                            opt_index_type: None,
876                            key_part: vec![KeyPart {
877                                r#type: KeyPartType::ColumnNameWithLength {
878                                    col_name: "role_id".to_string(),
879                                    length: None,
880                                },
881                                order: None,
882                            }],
883                            opt_index_option: None,
884                        },
885                    ],
886                    table_options: Some(vec![
887                        TableOption::Engine("InnoDB".to_string()),
888                        TableOption::DefaultCharset("utf8".to_string()),
889                        TableOption::Comment("Admin Role Table".to_string()),
890                    ]),
891                    partition_options: Some(CreatePartitionOption::None),
892                },
893            },
894            CreateTableStatement {
895                temporary: false,
896                if_not_exists: false,
897                table: "tbl_name".into(),
898                create_type: CreateTableType::LikeOldTable {
899                    table: "old_tbl_name".into(),
900                },
901            },
902        ];
903
904        for i in 0..sqls.len() {
905            let res = CreateTableType::create_simple(sqls[i]);
906            assert!(res.is_ok());
907            assert_eq!(res.unwrap().1, exp[i]);
908        }
909    }
910
911    #[test]
912    fn parse_create_as_query() {
913        let sqls = ["CREATE TABLE tbl_name AS SELECT * from other_tbl_name"];
914        let exp = [CreateTableStatement {
915            temporary: false,
916            if_not_exists: false,
917            table: "tbl_name".into(),
918            create_type: CreateTableType::AsQuery {
919                create_definition: None,
920                table_options: None,
921                partition_options: Some(CreatePartitionOption::None),
922                opt_ignore_or_replace: None,
923                query_expression: SelectStatement {
924                    tables: vec!["other_tbl_name".into()],
925                    distinct: false,
926                    fields: vec![FieldDefinitionExpression::All],
927                    join: vec![],
928                    where_clause: None,
929                    group_by: None,
930                    order: None,
931                    limit: None,
932                },
933            },
934        }];
935        for i in 0..sqls.len() {
936            let res = CreateTableType::create_as_query(sqls[i]);
937            assert!(res.is_ok());
938            assert_eq!(res.unwrap().1, exp[i]);
939        }
940    }
941
942    #[test]
943    fn parse_create_like_old() {
944        let sqls = ["CREATE TABLE tbl_name LIKE old_tbl_name"];
945        let exp = [CreateTableStatement {
946            temporary: false,
947            if_not_exists: false,
948            table: "tbl_name".into(),
949            create_type: CreateTableType::LikeOldTable {
950                table: "old_tbl_name".into(),
951            },
952        }];
953        for i in 0..sqls.len() {
954            let res = CreateTableType::create_like_old_table(sqls[i]);
955            assert!(res.is_ok());
956            assert_eq!(res.unwrap().1, exp[i]);
957        }
958    }
959
960    #[test]
961    fn parse_create_definition_list() {
962        let part = "(order_id INT not null, product_id INT DEFAULT 10,\
963         PRIMARY KEY(order_id, product_id), FOREIGN KEY (product_id) REFERENCES product(id))";
964        let exp = vec![
965            CreateDefinition::ColumnDefinition {
966                column_definition: ColumnSpecification {
967                    column: "order_id".into(),
968                    data_type: DataType::Int(32),
969                    constraints: vec![ColumnConstraint::NotNull],
970                    comment: None,
971                    position: None,
972                },
973            },
974            CreateDefinition::ColumnDefinition {
975                column_definition: ColumnSpecification {
976                    column: "product_id".into(),
977                    data_type: DataType::Int(32),
978                    constraints: vec![ColumnConstraint::DefaultValue(Literal::Integer(10))],
979                    comment: None,
980                    position: None,
981                },
982            },
983            CreateDefinition::PrimaryKey {
984                opt_symbol: None,
985                opt_index_type: None,
986                key_part: vec![
987                    KeyPart {
988                        r#type: KeyPartType::ColumnNameWithLength {
989                            col_name: "order_id".to_string(),
990                            length: None,
991                        },
992                        order: None,
993                    },
994                    KeyPart {
995                        r#type: KeyPartType::ColumnNameWithLength {
996                            col_name: "product_id".to_string(),
997                            length: None,
998                        },
999                        order: None,
1000                    },
1001                ],
1002                opt_index_option: None,
1003            },
1004            CreateDefinition::ForeignKey {
1005                opt_symbol: None,
1006                opt_index_name: None,
1007                columns: vec!["product_id".to_string()],
1008                reference_definition: ReferenceDefinition {
1009                    tbl_name: "product".to_string(),
1010                    key_part: vec![KeyPart {
1011                        r#type: KeyPartType::ColumnNameWithLength {
1012                            col_name: "id".to_string(),
1013                            length: None,
1014                        },
1015                        order: None,
1016                    }],
1017                    match_type: None,
1018                    on_delete: None,
1019                    on_update: None,
1020                },
1021            },
1022        ];
1023        let res = CreateDefinition::create_definition_list(part);
1024        assert!(res.is_ok());
1025        assert_eq!(res.unwrap().1, exp);
1026    }
1027}