sql/parsers/
drop_parser.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use snafu::{ensure, ResultExt};
16use sqlparser::dialect::keywords::Keyword;
17use sqlparser::tokenizer::Token;
18
19use crate::error::{self, InvalidFlowNameSnafu, InvalidTableNameSnafu, Result};
20use crate::parser::{ParserContext, FLOW};
21#[cfg(feature = "enterprise")]
22use crate::statements::drop::trigger::DropTrigger;
23use crate::statements::drop::{DropDatabase, DropFlow, DropTable, DropView};
24use crate::statements::statement::Statement;
25
26/// DROP statement parser implementation
27impl ParserContext<'_> {
28    pub(crate) fn parse_drop(&mut self) -> Result<Statement> {
29        let _ = self.parser.next_token();
30        match self.parser.peek_token().token {
31            Token::Word(w) => match w.keyword {
32                Keyword::TABLE => self.parse_drop_table(),
33                Keyword::VIEW => self.parse_drop_view(),
34                #[cfg(feature = "enterprise")]
35                Keyword::TRIGGER => self.parse_drop_trigger(),
36                Keyword::SCHEMA | Keyword::DATABASE => self.parse_drop_database(),
37                Keyword::NoKeyword => {
38                    let uppercase = w.value.to_uppercase();
39                    match uppercase.as_str() {
40                        FLOW => self.parse_drop_flow(),
41                        _ => self.unsupported(w.to_string()),
42                    }
43                }
44                _ => self.unsupported(w.to_string()),
45            },
46            unexpected => self.unsupported(unexpected.to_string()),
47        }
48    }
49
50    #[cfg(feature = "enterprise")]
51    fn parse_drop_trigger(&mut self) -> Result<Statement> {
52        let _ = self.parser.next_token();
53
54        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
55        let raw_trigger_ident =
56            self.parse_object_name()
57                .with_context(|_| error::UnexpectedSnafu {
58                    expected: "a trigger name",
59                    actual: self.peek_token_as_string(),
60                })?;
61        let trigger_ident = Self::canonicalize_object_name(raw_trigger_ident);
62        ensure!(
63            !trigger_ident.0.is_empty(),
64            error::InvalidTriggerNameSnafu {
65                name: trigger_ident.to_string()
66            }
67        );
68
69        Ok(Statement::DropTrigger(DropTrigger::new(
70            trigger_ident,
71            if_exists,
72        )))
73    }
74
75    fn parse_drop_view(&mut self) -> Result<Statement> {
76        let _ = self.parser.next_token();
77
78        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
79        let raw_view_ident = self
80            .parse_object_name()
81            .with_context(|_| error::UnexpectedSnafu {
82                expected: "a view name",
83                actual: self.peek_token_as_string(),
84            })?;
85        let view_ident = Self::canonicalize_object_name(raw_view_ident);
86        ensure!(
87            !view_ident.0.is_empty(),
88            InvalidTableNameSnafu {
89                name: view_ident.to_string()
90            }
91        );
92
93        Ok(Statement::DropView(DropView {
94            view_name: view_ident,
95            drop_if_exists: if_exists,
96        }))
97    }
98
99    fn parse_drop_flow(&mut self) -> Result<Statement> {
100        let _ = self.parser.next_token();
101
102        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
103        let raw_flow_ident = self
104            .parse_object_name()
105            .with_context(|_| error::UnexpectedSnafu {
106                expected: "a flow name",
107                actual: self.peek_token_as_string(),
108            })?;
109        let flow_ident = Self::canonicalize_object_name(raw_flow_ident);
110        ensure!(
111            !flow_ident.0.is_empty(),
112            InvalidFlowNameSnafu {
113                name: flow_ident.to_string()
114            }
115        );
116
117        Ok(Statement::DropFlow(DropFlow::new(flow_ident, if_exists)))
118    }
119
120    fn parse_drop_table(&mut self) -> Result<Statement> {
121        let _ = self.parser.next_token();
122
123        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
124        let mut table_names = Vec::with_capacity(1);
125        loop {
126            let raw_table_ident =
127                self.parse_object_name()
128                    .with_context(|_| error::UnexpectedSnafu {
129                        expected: "a table name",
130                        actual: self.peek_token_as_string(),
131                    })?;
132            let table_ident = Self::canonicalize_object_name(raw_table_ident);
133            ensure!(
134                !table_ident.0.is_empty(),
135                InvalidTableNameSnafu {
136                    name: table_ident.to_string()
137                }
138            );
139            table_names.push(table_ident);
140            if !self.parser.consume_token(&Token::Comma) {
141                break;
142            }
143        }
144
145        Ok(Statement::DropTable(DropTable::new(table_names, if_exists)))
146    }
147
148    fn parse_drop_database(&mut self) -> Result<Statement> {
149        let _ = self.parser.next_token();
150
151        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
152        let database_name = self
153            .parse_object_name()
154            .with_context(|_| error::UnexpectedSnafu {
155                expected: "a database name",
156                actual: self.peek_token_as_string(),
157            })?;
158        let database_name = Self::canonicalize_object_name(database_name);
159
160        Ok(Statement::DropDatabase(DropDatabase::new(
161            database_name,
162            if_exists,
163        )))
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use sqlparser::ast::{Ident, ObjectName};
170
171    use super::*;
172    use crate::dialect::GreptimeDbDialect;
173    use crate::parser::ParseOptions;
174
175    #[test]
176    pub fn test_drop_table() {
177        let sql = "DROP TABLE foo";
178        let result =
179            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
180        let mut stmts = result.unwrap();
181        assert_eq!(
182            stmts.pop().unwrap(),
183            Statement::DropTable(DropTable::new(
184                vec![ObjectName::from(vec![Ident::new("foo")])],
185                false
186            ))
187        );
188
189        let sql = "DROP TABLE IF EXISTS foo";
190        let result =
191            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
192        let mut stmts = result.unwrap();
193        assert_eq!(
194            stmts.pop().unwrap(),
195            Statement::DropTable(DropTable::new(
196                vec![ObjectName::from(vec![Ident::new("foo")])],
197                true
198            ))
199        );
200
201        let sql = "DROP TABLE my_schema.foo";
202        let result =
203            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
204        let mut stmts = result.unwrap();
205        assert_eq!(
206            stmts.pop().unwrap(),
207            Statement::DropTable(DropTable::new(
208                vec![ObjectName::from(vec![
209                    Ident::new("my_schema"),
210                    Ident::new("foo")
211                ])],
212                false
213            ))
214        );
215
216        let sql = "DROP TABLE my_catalog.my_schema.foo";
217        let result =
218            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
219        let mut stmts = result.unwrap();
220        assert_eq!(
221            stmts.pop().unwrap(),
222            Statement::DropTable(DropTable::new(
223                vec![ObjectName::from(vec![
224                    Ident::new("my_catalog"),
225                    Ident::new("my_schema"),
226                    Ident::new("foo")
227                ])],
228                false
229            ))
230        )
231    }
232
233    #[test]
234    pub fn test_drop_database() {
235        let sql = "DROP DATABASE public";
236        let result =
237            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
238        let mut stmts = result.unwrap();
239        assert_eq!(
240            stmts.pop().unwrap(),
241            Statement::DropDatabase(DropDatabase::new(
242                ObjectName::from(vec![Ident::new("public")]),
243                false
244            ))
245        );
246
247        let sql = "DROP DATABASE IF EXISTS public";
248        let result =
249            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
250        let mut stmts = result.unwrap();
251        assert_eq!(
252            stmts.pop().unwrap(),
253            Statement::DropDatabase(DropDatabase::new(
254                ObjectName::from(vec![Ident::new("public")]),
255                true
256            ))
257        );
258
259        let sql = "DROP DATABASE `fOo`";
260        let result =
261            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
262        let mut stmts = result.unwrap();
263        assert_eq!(
264            stmts.pop().unwrap(),
265            Statement::DropDatabase(DropDatabase::new(
266                ObjectName::from(vec![Ident::with_quote('`', "fOo"),]),
267                false
268            ))
269        );
270    }
271
272    #[test]
273    pub fn test_drop_flow() {
274        let sql = "DROP FLOW foo";
275        let result =
276            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
277        let mut stmts: Vec<Statement> = result.unwrap();
278        assert_eq!(
279            stmts.pop().unwrap(),
280            Statement::DropFlow(DropFlow::new(
281                ObjectName::from(vec![Ident::new("foo")]),
282                false
283            ))
284        );
285
286        let sql = "DROP FLOW IF EXISTS foo";
287        let result =
288            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
289        let mut stmts = result.unwrap();
290        assert_eq!(
291            stmts.pop().unwrap(),
292            Statement::DropFlow(DropFlow::new(
293                ObjectName::from(vec![Ident::new("foo")]),
294                true
295            ))
296        );
297
298        let sql = "DROP FLOW my_schema.foo";
299        let result =
300            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
301        let mut stmts = result.unwrap();
302        assert_eq!(
303            stmts.pop().unwrap(),
304            Statement::DropFlow(DropFlow::new(
305                ObjectName::from(vec![Ident::new("my_schema"), Ident::new("foo")]),
306                false
307            ))
308        );
309
310        let sql = "DROP FLOW my_catalog.my_schema.foo";
311        let result =
312            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
313        let mut stmts = result.unwrap();
314        assert_eq!(
315            stmts.pop().unwrap(),
316            Statement::DropFlow(DropFlow::new(
317                ObjectName::from(vec![
318                    Ident::new("my_catalog"),
319                    Ident::new("my_schema"),
320                    Ident::new("foo")
321                ]),
322                false
323            ))
324        )
325    }
326
327    #[test]
328    pub fn test_drop_view() {
329        let sql = "DROP VIEW foo";
330        let result =
331            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
332        let mut stmts: Vec<Statement> = result.unwrap();
333        let stmt = stmts.pop().unwrap();
334        assert_eq!(
335            stmt,
336            Statement::DropView(DropView {
337                view_name: ObjectName::from(vec![Ident::new("foo")]),
338                drop_if_exists: false,
339            })
340        );
341        assert_eq!(sql, stmt.to_string());
342
343        let sql = "DROP VIEW greptime.public.foo";
344        let result =
345            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
346        let mut stmts: Vec<Statement> = result.unwrap();
347        let stmt = stmts.pop().unwrap();
348        assert_eq!(
349            stmt,
350            Statement::DropView(DropView {
351                view_name: ObjectName::from(vec![
352                    Ident::new("greptime"),
353                    Ident::new("public"),
354                    Ident::new("foo")
355                ]),
356                drop_if_exists: false,
357            })
358        );
359        assert_eq!(sql, stmt.to_string());
360
361        let sql = "DROP VIEW IF EXISTS foo";
362        let result =
363            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
364        let mut stmts: Vec<Statement> = result.unwrap();
365        let stmt = stmts.pop().unwrap();
366        assert_eq!(
367            stmt,
368            Statement::DropView(DropView {
369                view_name: ObjectName::from(vec![Ident::new("foo")]),
370                drop_if_exists: true,
371            })
372        );
373        assert_eq!(sql, stmt.to_string());
374    }
375}