sqlparser_mysql/dds/
drop_table.rs

1use core::fmt;
2use std::fmt::Formatter;
3use std::str;
4
5use nom::bytes::complete::tag_no_case;
6use nom::character::complete::multispace0;
7use nom::character::complete::multispace1;
8use nom::combinator::opt;
9use nom::multi::many0;
10use nom::sequence::{delimited, terminated, tuple};
11use nom::IResult;
12
13use base::error::ParseSQLError;
14use base::table::Table;
15use base::CommonParser;
16
17/// parse `DROP [TEMPORARY] TABLE [IF EXISTS]
18///     tbl_name [, tbl_name] ...
19///     [RESTRICT | CASCADE]`
20#[derive(Default, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
21pub struct DropTableStatement {
22    pub if_temporary: bool,
23    pub if_exists: bool,
24    /// A name of a table, view, custom type, etc., possibly multipart, i.e. db.schema.obj
25    pub tables: Vec<Table>,
26    pub if_restrict: bool,
27    pub if_cascade: bool,
28}
29
30impl DropTableStatement {
31    pub fn parse(i: &str) -> IResult<&str, DropTableStatement, ParseSQLError<&str>> {
32        let mut parser = tuple((
33            tag_no_case("DROP "),
34            opt(delimited(
35                multispace0,
36                tag_no_case("TEMPORARY"),
37                multispace0,
38            )),
39            multispace0,
40            tag_no_case("TABLE "),
41            CommonParser::parse_if_exists,
42            multispace0,
43            many0(terminated(
44                Table::without_alias,
45                opt(CommonParser::ws_sep_comma),
46            )),
47            opt(delimited(multispace1, tag_no_case("RESTRICT"), multispace0)),
48            opt(delimited(multispace1, tag_no_case("CASCADE"), multispace0)),
49            CommonParser::statement_terminator,
50        ));
51        let (
52            remaining_input,
53            (
54                _,
55                opt_if_temporary,
56                _,
57                _,
58                opt_if_exists,
59                _,
60                tables,
61                opt_if_restrict,
62                opt_if_cascade,
63                _,
64            ),
65        ) = parser(i)?;
66
67        Ok((
68            remaining_input,
69            DropTableStatement {
70                if_temporary: opt_if_temporary.is_some(),
71                tables,
72                if_exists: opt_if_exists.is_some(),
73                if_restrict: opt_if_restrict.is_some(),
74                if_cascade: opt_if_cascade.is_some(),
75            },
76        ))
77    }
78}
79
80impl fmt::Display for DropTableStatement {
81    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
82        write!(f, "DROP")?;
83        if self.if_temporary {
84            write!(f, "TEMPORARY ")?;
85        }
86        write!(f, " TABLE")?;
87        if self.if_exists {
88            write!(f, " IF EXISTS")?;
89        }
90
91        let table_name = self
92            .tables
93            .iter()
94            .map(|x| x.name.clone())
95            .collect::<Vec<String>>()
96            .join(", ");
97        write!(f, " {}", table_name)?;
98
99        if self.if_restrict {
100            write!(f, " RESTRICT")?;
101        }
102        if self.if_cascade {
103            write!(f, " CASCADE")?;
104        }
105        Ok(())
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use base::table::Table;
112    use dds::drop_table::DropTableStatement;
113
114    #[test]
115    fn parse_drop_table() {
116        let sqls = vec![
117            "DROP  TABLE tbl_name;",
118            "DROP TABLE  foo.tbl_name1, tbl_name2;",
119            "DROP TEMPORARY  TABLE  bar.tbl_name",
120            "DROP TEMPORARY TABLE tbl_name1, tbl_name2;",
121            "DROP  TABLE  IF EXISTS  tbl_name;",
122            "DROP TABLE IF EXISTS tbl_name1, foo.tbl_name2;",
123            "DROP  TEMPORARY TABLE IF    EXISTS tbl_name;",
124            "DROP TEMPORARY TABLE  IF EXISTS foo.tbl_name1, bar.tbl_name2;",
125            "DROP  TABLE tbl_name RESTRICT",
126            "DROP TABLE IF EXISTS tbl_name RESTRICT;",
127            "DROP TEMPORARY TABLE tbl_name RESTRICT;",
128            "DROP TEMPORARY  TABLE  IF  EXISTS tbl_name RESTRICT;",
129            "DROP TABLE tbl_name1, tbl_name2 RESTRICT;",
130            "DROP TABLE IF EXISTS tbl_name1, tbl_name2 RESTRICT;",
131            "DROP TEMPORARY TABLE tbl_name1, tbl_name2 RESTRICT",
132            "DROP TEMPORARY TABLE IF EXISTS tbl_name1, tbl_name2 RESTRICT;",
133            "DROP TABLE tbl_name CASCADE",
134            "DROP TABLE IF EXISTS tbl_name CASCADE;",
135            "DROP TEMPORARY TABLE tbl_name CASCADE",
136            "DROP TEMPORARY TABLE IF EXISTS tbl_name CASCADE;",
137            "DROP TABLE tbl_name1, tbl_name2 CASCADE;",
138            "DROP TABLE IF EXISTS tbl_name1, tbl_name2 CASCADE;",
139            "DROP TEMPORARY TABLE tbl_name1, tbl_name2 CASCADE",
140            "DROP TEMPORARY TABLE IF EXISTS tbl_name1, tbl_name2 CASCADE;",
141        ];
142
143        let one_table = vec![Table::from("tbl_name")];
144        let two_tables = vec![Table::from("tbl_name1"), Table::from("tbl_name2")];
145
146        let exp_statements = vec![
147            DropTableStatement {
148                tables: one_table.clone(),
149                ..DropTableStatement::default()
150            },
151            DropTableStatement {
152                tables: vec![Table::from(("foo", "tbl_name1")), Table::from("tbl_name2")],
153                ..DropTableStatement::default()
154            },
155            DropTableStatement {
156                if_temporary: true,
157                tables: vec![Table::from(("bar", "tbl_name"))],
158                ..DropTableStatement::default()
159            },
160            DropTableStatement {
161                if_temporary: true,
162                tables: two_tables.clone(),
163                ..DropTableStatement::default()
164            },
165            DropTableStatement {
166                if_exists: true,
167                tables: one_table.clone(),
168                ..DropTableStatement::default()
169            },
170            DropTableStatement {
171                if_exists: true,
172                tables: vec![Table::from("tbl_name1"), Table::from(("foo", "tbl_name2"))],
173                ..DropTableStatement::default()
174            },
175            DropTableStatement {
176                if_temporary: true,
177                if_exists: true,
178                tables: one_table.clone(),
179                ..DropTableStatement::default()
180            },
181            DropTableStatement {
182                if_temporary: true,
183                if_exists: true,
184                tables: vec![
185                    Table::from(("foo", "tbl_name1")),
186                    Table::from(("bar", "tbl_name2")),
187                ],
188                ..DropTableStatement::default()
189            },
190            DropTableStatement {
191                if_restrict: true,
192                tables: one_table.clone(),
193                ..DropTableStatement::default()
194            },
195            DropTableStatement {
196                if_exists: true,
197                if_restrict: true,
198                tables: one_table.clone(),
199                ..DropTableStatement::default()
200            },
201            DropTableStatement {
202                if_temporary: true,
203                if_restrict: true,
204                tables: one_table.clone(),
205                ..DropTableStatement::default()
206            },
207            DropTableStatement {
208                if_temporary: true,
209                if_exists: true,
210                if_restrict: true,
211                tables: one_table.clone(),
212                ..DropTableStatement::default()
213            },
214            DropTableStatement {
215                if_restrict: true,
216                tables: two_tables.clone(),
217                ..DropTableStatement::default()
218            },
219            DropTableStatement {
220                if_exists: true,
221                if_restrict: true,
222                tables: two_tables.clone(),
223                ..DropTableStatement::default()
224            },
225            DropTableStatement {
226                if_temporary: true,
227                if_restrict: true,
228                tables: two_tables.clone(),
229                ..DropTableStatement::default()
230            },
231            DropTableStatement {
232                if_temporary: true,
233                if_exists: true,
234                if_restrict: true,
235                tables: two_tables.clone(),
236                ..DropTableStatement::default()
237            },
238            DropTableStatement {
239                if_cascade: true,
240                tables: one_table.clone(),
241                ..DropTableStatement::default()
242            },
243            DropTableStatement {
244                if_exists: true,
245                if_cascade: true,
246                tables: one_table.clone(),
247                ..DropTableStatement::default()
248            },
249            DropTableStatement {
250                if_temporary: true,
251                if_cascade: true,
252                tables: one_table.clone(),
253                ..DropTableStatement::default()
254            },
255            DropTableStatement {
256                if_temporary: true,
257                if_exists: true,
258                if_cascade: true,
259                tables: one_table.clone(),
260                ..DropTableStatement::default()
261            },
262            DropTableStatement {
263                if_cascade: true,
264                tables: two_tables.clone(),
265                ..DropTableStatement::default()
266            },
267            DropTableStatement {
268                if_exists: true,
269                if_cascade: true,
270                tables: two_tables.clone(),
271                ..DropTableStatement::default()
272            },
273            DropTableStatement {
274                if_temporary: true,
275                if_cascade: true,
276                tables: two_tables.clone(),
277                ..DropTableStatement::default()
278            },
279            DropTableStatement {
280                if_temporary: true,
281                if_exists: true,
282                if_cascade: true,
283                tables: two_tables.clone(),
284                ..DropTableStatement::default()
285            },
286        ];
287
288        for i in 0..sqls.len() {
289            let res = DropTableStatement::parse(sqls[i]);
290            assert!(res.is_ok());
291            assert_eq!(res.unwrap().1, exp_statements[i]);
292        }
293    }
294}