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(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(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(vec![Ident::new("my_schema"), Ident::new("foo")])],
209                false
210            ))
211        );
212
213        let sql = "DROP TABLE my_catalog.my_schema.foo";
214        let result =
215            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
216        let mut stmts = result.unwrap();
217        assert_eq!(
218            stmts.pop().unwrap(),
219            Statement::DropTable(DropTable::new(
220                vec![ObjectName(vec![
221                    Ident::new("my_catalog"),
222                    Ident::new("my_schema"),
223                    Ident::new("foo")
224                ])],
225                false
226            ))
227        )
228    }
229
230    #[test]
231    pub fn test_drop_database() {
232        let sql = "DROP DATABASE public";
233        let result =
234            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
235        let mut stmts = result.unwrap();
236        assert_eq!(
237            stmts.pop().unwrap(),
238            Statement::DropDatabase(DropDatabase::new(
239                ObjectName(vec![Ident::new("public")]),
240                false
241            ))
242        );
243
244        let sql = "DROP DATABASE IF EXISTS public";
245        let result =
246            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
247        let mut stmts = result.unwrap();
248        assert_eq!(
249            stmts.pop().unwrap(),
250            Statement::DropDatabase(DropDatabase::new(
251                ObjectName(vec![Ident::new("public")]),
252                true
253            ))
254        );
255
256        let sql = "DROP DATABASE `fOo`";
257        let result =
258            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
259        let mut stmts = result.unwrap();
260        assert_eq!(
261            stmts.pop().unwrap(),
262            Statement::DropDatabase(DropDatabase::new(
263                ObjectName(vec![Ident::with_quote('`', "fOo"),]),
264                false
265            ))
266        );
267    }
268
269    #[test]
270    pub fn test_drop_flow() {
271        let sql = "DROP FLOW foo";
272        let result =
273            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
274        let mut stmts: Vec<Statement> = result.unwrap();
275        assert_eq!(
276            stmts.pop().unwrap(),
277            Statement::DropFlow(DropFlow::new(ObjectName(vec![Ident::new("foo")]), false))
278        );
279
280        let sql = "DROP FLOW IF EXISTS foo";
281        let result =
282            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
283        let mut stmts = result.unwrap();
284        assert_eq!(
285            stmts.pop().unwrap(),
286            Statement::DropFlow(DropFlow::new(ObjectName(vec![Ident::new("foo")]), true))
287        );
288
289        let sql = "DROP FLOW my_schema.foo";
290        let result =
291            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
292        let mut stmts = result.unwrap();
293        assert_eq!(
294            stmts.pop().unwrap(),
295            Statement::DropFlow(DropFlow::new(
296                ObjectName(vec![Ident::new("my_schema"), Ident::new("foo")]),
297                false
298            ))
299        );
300
301        let sql = "DROP FLOW my_catalog.my_schema.foo";
302        let result =
303            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
304        let mut stmts = result.unwrap();
305        assert_eq!(
306            stmts.pop().unwrap(),
307            Statement::DropFlow(DropFlow::new(
308                ObjectName(vec![
309                    Ident::new("my_catalog"),
310                    Ident::new("my_schema"),
311                    Ident::new("foo")
312                ]),
313                false
314            ))
315        )
316    }
317
318    #[test]
319    pub fn test_drop_view() {
320        let sql = "DROP VIEW foo";
321        let result =
322            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
323        let mut stmts: Vec<Statement> = result.unwrap();
324        let stmt = stmts.pop().unwrap();
325        assert_eq!(
326            stmt,
327            Statement::DropView(DropView {
328                view_name: ObjectName(vec![Ident::new("foo")]),
329                drop_if_exists: false,
330            })
331        );
332        assert_eq!(sql, stmt.to_string());
333
334        let sql = "DROP VIEW greptime.public.foo";
335        let result =
336            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
337        let mut stmts: Vec<Statement> = result.unwrap();
338        let stmt = stmts.pop().unwrap();
339        assert_eq!(
340            stmt,
341            Statement::DropView(DropView {
342                view_name: ObjectName(vec![
343                    Ident::new("greptime"),
344                    Ident::new("public"),
345                    Ident::new("foo")
346                ]),
347                drop_if_exists: false,
348            })
349        );
350        assert_eq!(sql, stmt.to_string());
351
352        let sql = "DROP VIEW IF EXISTS foo";
353        let result =
354            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
355        let mut stmts: Vec<Statement> = result.unwrap();
356        let stmt = stmts.pop().unwrap();
357        assert_eq!(
358            stmt,
359            Statement::DropView(DropView {
360                view_name: ObjectName(vec![Ident::new("foo")]),
361                drop_if_exists: true,
362            })
363        );
364        assert_eq!(sql, stmt.to_string());
365    }
366}