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#[derive(Default, Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
21pub struct DropTableStatement {
22 pub if_temporary: bool,
23 pub if_exists: bool,
24 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}