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};
21use crate::statements::drop::{DropDatabase, DropFlow, DropTable, DropView};
22use crate::statements::statement::Statement;
23
24/// DROP statement parser implementation
25impl ParserContext<'_> {
26    pub(crate) fn parse_drop(&mut self) -> Result<Statement> {
27        let _ = self.parser.next_token();
28        match self.parser.peek_token().token {
29            Token::Word(w) => match w.keyword {
30                Keyword::TABLE => self.parse_drop_table(),
31                Keyword::VIEW => self.parse_drop_view(),
32                Keyword::SCHEMA | Keyword::DATABASE => self.parse_drop_database(),
33                Keyword::NoKeyword => {
34                    let uppercase = w.value.to_uppercase();
35                    match uppercase.as_str() {
36                        FLOW => self.parse_drop_flow(),
37                        _ => self.unsupported(w.to_string()),
38                    }
39                }
40                _ => self.unsupported(w.to_string()),
41            },
42            unexpected => self.unsupported(unexpected.to_string()),
43        }
44    }
45
46    fn parse_drop_view(&mut self) -> Result<Statement> {
47        let _ = self.parser.next_token();
48
49        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
50        let raw_view_ident = self
51            .parse_object_name()
52            .with_context(|_| error::UnexpectedSnafu {
53                expected: "a view name",
54                actual: self.peek_token_as_string(),
55            })?;
56        let view_ident = Self::canonicalize_object_name(raw_view_ident);
57        ensure!(
58            !view_ident.0.is_empty(),
59            InvalidTableNameSnafu {
60                name: view_ident.to_string()
61            }
62        );
63
64        Ok(Statement::DropView(DropView {
65            view_name: view_ident,
66            drop_if_exists: if_exists,
67        }))
68    }
69
70    fn parse_drop_flow(&mut self) -> Result<Statement> {
71        let _ = self.parser.next_token();
72
73        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
74        let raw_flow_ident = self
75            .parse_object_name()
76            .with_context(|_| error::UnexpectedSnafu {
77                expected: "a flow name",
78                actual: self.peek_token_as_string(),
79            })?;
80        let flow_ident = Self::canonicalize_object_name(raw_flow_ident);
81        ensure!(
82            !flow_ident.0.is_empty(),
83            InvalidFlowNameSnafu {
84                name: flow_ident.to_string()
85            }
86        );
87
88        Ok(Statement::DropFlow(DropFlow::new(flow_ident, if_exists)))
89    }
90
91    fn parse_drop_table(&mut self) -> Result<Statement> {
92        let _ = self.parser.next_token();
93
94        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
95        let mut table_names = Vec::with_capacity(1);
96        loop {
97            let raw_table_ident =
98                self.parse_object_name()
99                    .with_context(|_| error::UnexpectedSnafu {
100                        expected: "a table name",
101                        actual: self.peek_token_as_string(),
102                    })?;
103            let table_ident = Self::canonicalize_object_name(raw_table_ident);
104            ensure!(
105                !table_ident.0.is_empty(),
106                InvalidTableNameSnafu {
107                    name: table_ident.to_string()
108                }
109            );
110            table_names.push(table_ident);
111            if !self.parser.consume_token(&Token::Comma) {
112                break;
113            }
114        }
115
116        Ok(Statement::DropTable(DropTable::new(table_names, if_exists)))
117    }
118
119    fn parse_drop_database(&mut self) -> Result<Statement> {
120        let _ = self.parser.next_token();
121
122        let if_exists = self.parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
123        let database_name = self
124            .parse_object_name()
125            .with_context(|_| error::UnexpectedSnafu {
126                expected: "a database name",
127                actual: self.peek_token_as_string(),
128            })?;
129        let database_name = Self::canonicalize_object_name(database_name);
130
131        Ok(Statement::DropDatabase(DropDatabase::new(
132            database_name,
133            if_exists,
134        )))
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use sqlparser::ast::{Ident, ObjectName};
141
142    use super::*;
143    use crate::dialect::GreptimeDbDialect;
144    use crate::parser::ParseOptions;
145
146    #[test]
147    pub fn test_drop_table() {
148        let sql = "DROP TABLE foo";
149        let result =
150            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
151        let mut stmts = result.unwrap();
152        assert_eq!(
153            stmts.pop().unwrap(),
154            Statement::DropTable(DropTable::new(
155                vec![ObjectName(vec![Ident::new("foo")])],
156                false
157            ))
158        );
159
160        let sql = "DROP TABLE IF EXISTS foo";
161        let result =
162            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
163        let mut stmts = result.unwrap();
164        assert_eq!(
165            stmts.pop().unwrap(),
166            Statement::DropTable(DropTable::new(
167                vec![ObjectName(vec![Ident::new("foo")])],
168                true
169            ))
170        );
171
172        let sql = "DROP TABLE my_schema.foo";
173        let result =
174            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
175        let mut stmts = result.unwrap();
176        assert_eq!(
177            stmts.pop().unwrap(),
178            Statement::DropTable(DropTable::new(
179                vec![ObjectName(vec![Ident::new("my_schema"), Ident::new("foo")])],
180                false
181            ))
182        );
183
184        let sql = "DROP TABLE my_catalog.my_schema.foo";
185        let result =
186            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
187        let mut stmts = result.unwrap();
188        assert_eq!(
189            stmts.pop().unwrap(),
190            Statement::DropTable(DropTable::new(
191                vec![ObjectName(vec![
192                    Ident::new("my_catalog"),
193                    Ident::new("my_schema"),
194                    Ident::new("foo")
195                ])],
196                false
197            ))
198        )
199    }
200
201    #[test]
202    pub fn test_drop_database() {
203        let sql = "DROP DATABASE public";
204        let result =
205            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
206        let mut stmts = result.unwrap();
207        assert_eq!(
208            stmts.pop().unwrap(),
209            Statement::DropDatabase(DropDatabase::new(
210                ObjectName(vec![Ident::new("public")]),
211                false
212            ))
213        );
214
215        let sql = "DROP DATABASE IF EXISTS public";
216        let result =
217            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
218        let mut stmts = result.unwrap();
219        assert_eq!(
220            stmts.pop().unwrap(),
221            Statement::DropDatabase(DropDatabase::new(
222                ObjectName(vec![Ident::new("public")]),
223                true
224            ))
225        );
226
227        let sql = "DROP DATABASE `fOo`";
228        let result =
229            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
230        let mut stmts = result.unwrap();
231        assert_eq!(
232            stmts.pop().unwrap(),
233            Statement::DropDatabase(DropDatabase::new(
234                ObjectName(vec![Ident::with_quote('`', "fOo"),]),
235                false
236            ))
237        );
238    }
239
240    #[test]
241    pub fn test_drop_flow() {
242        let sql = "DROP FLOW foo";
243        let result =
244            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
245        let mut stmts: Vec<Statement> = result.unwrap();
246        assert_eq!(
247            stmts.pop().unwrap(),
248            Statement::DropFlow(DropFlow::new(ObjectName(vec![Ident::new("foo")]), false))
249        );
250
251        let sql = "DROP FLOW IF EXISTS foo";
252        let result =
253            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
254        let mut stmts = result.unwrap();
255        assert_eq!(
256            stmts.pop().unwrap(),
257            Statement::DropFlow(DropFlow::new(ObjectName(vec![Ident::new("foo")]), true))
258        );
259
260        let sql = "DROP FLOW my_schema.foo";
261        let result =
262            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
263        let mut stmts = result.unwrap();
264        assert_eq!(
265            stmts.pop().unwrap(),
266            Statement::DropFlow(DropFlow::new(
267                ObjectName(vec![Ident::new("my_schema"), Ident::new("foo")]),
268                false
269            ))
270        );
271
272        let sql = "DROP FLOW my_catalog.my_schema.foo";
273        let result =
274            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
275        let mut stmts = result.unwrap();
276        assert_eq!(
277            stmts.pop().unwrap(),
278            Statement::DropFlow(DropFlow::new(
279                ObjectName(vec![
280                    Ident::new("my_catalog"),
281                    Ident::new("my_schema"),
282                    Ident::new("foo")
283                ]),
284                false
285            ))
286        )
287    }
288
289    #[test]
290    pub fn test_drop_view() {
291        let sql = "DROP VIEW foo";
292        let result =
293            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
294        let mut stmts: Vec<Statement> = result.unwrap();
295        let stmt = stmts.pop().unwrap();
296        assert_eq!(
297            stmt,
298            Statement::DropView(DropView {
299                view_name: ObjectName(vec![Ident::new("foo")]),
300                drop_if_exists: false,
301            })
302        );
303        assert_eq!(sql, stmt.to_string());
304
305        let sql = "DROP VIEW greptime.public.foo";
306        let result =
307            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
308        let mut stmts: Vec<Statement> = result.unwrap();
309        let stmt = stmts.pop().unwrap();
310        assert_eq!(
311            stmt,
312            Statement::DropView(DropView {
313                view_name: ObjectName(vec![
314                    Ident::new("greptime"),
315                    Ident::new("public"),
316                    Ident::new("foo")
317                ]),
318                drop_if_exists: false,
319            })
320        );
321        assert_eq!(sql, stmt.to_string());
322
323        let sql = "DROP VIEW IF EXISTS foo";
324        let result =
325            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
326        let mut stmts: Vec<Statement> = result.unwrap();
327        let stmt = stmts.pop().unwrap();
328        assert_eq!(
329            stmt,
330            Statement::DropView(DropView {
331                view_name: ObjectName(vec![Ident::new("foo")]),
332                drop_if_exists: true,
333            })
334        );
335        assert_eq!(sql, stmt.to_string());
336    }
337}