sql/parsers/
show_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::keywords::Keyword;
17use sqlparser::tokenizer::Token;
18
19use crate::error::{
20    self, InvalidDatabaseNameSnafu, InvalidFlowNameSnafu, InvalidTableNameSnafu, Result,
21};
22use crate::parser::ParserContext;
23use crate::statements::show::{
24    ShowColumns, ShowCreateDatabase, ShowCreateFlow, ShowCreateTable, ShowCreateTableVariant,
25    ShowCreateView, ShowDatabases, ShowFlows, ShowIndex, ShowKind, ShowRegion, ShowSearchPath,
26    ShowStatus, ShowTableStatus, ShowTables, ShowVariables, ShowViews,
27};
28use crate::statements::statement::Statement;
29
30/// SHOW statement parser implementation
31impl ParserContext<'_> {
32    /// Parses SHOW statements
33    /// todo(hl) support `show settings`/`show create`/`show users` etc.
34    pub(crate) fn parse_show(&mut self) -> Result<Statement> {
35        if self.consume_token("DATABASES") || self.consume_token("SCHEMAS") {
36            self.parse_show_databases(false)
37        } else if self.matches_keyword(Keyword::TABLES) {
38            self.parser.next_token();
39            self.parse_show_tables(false)
40        } else if self.matches_keyword(Keyword::TABLE) {
41            self.parser.next_token();
42            if self.matches_keyword(Keyword::STATUS) {
43                self.parser.next_token();
44                self.parse_show_table_status()
45            } else {
46                self.unsupported(self.peek_token_as_string())
47            }
48        } else if self.consume_token("VIEWS") {
49            self.parse_show_views()
50        } else if self.consume_token("FLOWS") {
51            self.parse_show_flows()
52        } else if self.matches_keyword(Keyword::CHARSET) {
53            self.parser.next_token();
54            Ok(Statement::ShowCharset(self.parse_show_kind()?))
55        } else if self.matches_keyword(Keyword::CHARACTER) {
56            self.parser.next_token();
57
58            if self.matches_keyword(Keyword::SET) {
59                self.parser.next_token();
60                Ok(Statement::ShowCharset(self.parse_show_kind()?))
61            } else {
62                self.unsupported(self.peek_token_as_string())
63            }
64        } else if self.matches_keyword(Keyword::COLLATION) {
65            self.parser.next_token();
66            Ok(Statement::ShowCollation(self.parse_show_kind()?))
67        } else if self.matches_keyword(Keyword::COLUMNS) || self.matches_keyword(Keyword::FIELDS) {
68            // SHOW {COLUMNS | FIELDS}
69            self.parser.next_token();
70            self.parse_show_columns(false)
71        } else if self.consume_token("INDEX")
72            || self.consume_token("INDEXES")
73            || self.consume_token("KEYS")
74        {
75            // SHOW {INDEX | INDEXES | KEYS}
76            self.parse_show_index()
77        } else if self.consume_token("REGIONS") || self.consume_token("REGION") {
78            // SHOW REGIONS
79            self.parse_show_regions()
80        } else if self.consume_token("CREATE") {
81            if self.consume_token("DATABASE") || self.consume_token("SCHEMA") {
82                self.parse_show_create_database()
83            } else if self.consume_token("TABLE") {
84                self.parse_show_create_table()
85            } else if self.consume_token("FLOW") {
86                self.parse_show_create_flow()
87            } else if self.consume_token("VIEW") {
88                self.parse_show_create_view()
89            } else {
90                self.unsupported(self.peek_token_as_string())
91            }
92        } else if self.consume_token("FULL") {
93            if self.consume_token("TABLES") {
94                self.parse_show_tables(true)
95            } else if self.consume_token("COLUMNS") || self.consume_token("FIELDS") {
96                // SHOW {COLUMNS | FIELDS}
97                self.parse_show_columns(true)
98            } else if self.consume_token("DATABASES") || self.consume_token("SCHEMAS") {
99                self.parse_show_databases(true)
100            } else {
101                self.unsupported(self.peek_token_as_string())
102            }
103        } else if self.consume_token("VARIABLES") {
104            let variable = self
105                .parse_object_name()
106                .with_context(|_| error::UnexpectedSnafu {
107                    expected: "a variable name",
108                    actual: self.peek_token_as_string(),
109                })?;
110            Ok(Statement::ShowVariables(ShowVariables { variable }))
111        } else if self.consume_token("STATUS") {
112            Ok(Statement::ShowStatus(ShowStatus {}))
113        } else if self.consume_token("SEARCH_PATH") {
114            Ok(Statement::ShowSearchPath(ShowSearchPath {}))
115        } else {
116            self.unsupported(self.peek_token_as_string())
117        }
118    }
119
120    fn parse_show_create_database(&mut self) -> Result<Statement> {
121        let raw_database_name =
122            self.parse_object_name()
123                .with_context(|_| error::UnexpectedSnafu {
124                    expected: "a database name",
125                    actual: self.peek_token_as_string(),
126                })?;
127        let database_name = Self::canonicalize_object_name(raw_database_name);
128        ensure!(
129            !database_name.0.is_empty(),
130            InvalidDatabaseNameSnafu {
131                name: database_name.to_string(),
132            }
133        );
134        Ok(Statement::ShowCreateDatabase(ShowCreateDatabase {
135            database_name,
136        }))
137    }
138
139    /// Parse SHOW CREATE TABLE statement
140    fn parse_show_create_table(&mut self) -> Result<Statement> {
141        let raw_table_name = self
142            .parse_object_name()
143            .with_context(|_| error::UnexpectedSnafu {
144                expected: "a table name",
145                actual: self.peek_token_as_string(),
146            })?;
147        let table_name = Self::canonicalize_object_name(raw_table_name);
148        ensure!(
149            !table_name.0.is_empty(),
150            InvalidTableNameSnafu {
151                name: table_name.to_string(),
152            }
153        );
154        let mut variant = ShowCreateTableVariant::Original;
155        if self.consume_token("FOR") {
156            if self.consume_token("POSTGRES_FOREIGN_TABLE") {
157                variant = ShowCreateTableVariant::PostgresForeignTable;
158            } else {
159                self.unsupported(self.peek_token_as_string())?;
160            }
161        }
162
163        Ok(Statement::ShowCreateTable(ShowCreateTable {
164            table_name,
165            variant,
166        }))
167    }
168
169    fn parse_show_create_flow(&mut self) -> Result<Statement> {
170        let raw_flow_name = self
171            .parse_object_name()
172            .with_context(|_| error::UnexpectedSnafu {
173                expected: "a flow name",
174                actual: self.peek_token_as_string(),
175            })?;
176        let flow_name = Self::canonicalize_object_name(raw_flow_name);
177        ensure!(
178            !flow_name.0.is_empty(),
179            InvalidFlowNameSnafu {
180                name: flow_name.to_string(),
181            }
182        );
183        Ok(Statement::ShowCreateFlow(ShowCreateFlow { flow_name }))
184    }
185
186    fn parse_show_create_view(&mut self) -> Result<Statement> {
187        let raw_view_name = self
188            .parse_object_name()
189            .with_context(|_| error::UnexpectedSnafu {
190                expected: "a view name",
191                actual: self.peek_token_as_string(),
192            })?;
193        let view_name = Self::canonicalize_object_name(raw_view_name);
194        ensure!(
195            !view_name.0.is_empty(),
196            InvalidTableNameSnafu {
197                name: view_name.to_string(),
198            }
199        );
200        Ok(Statement::ShowCreateView(ShowCreateView { view_name }))
201    }
202
203    fn parse_show_table_name(&mut self) -> Result<String> {
204        self.parser.next_token();
205        let table_name = self
206            .parse_object_name()
207            .with_context(|_| error::UnexpectedSnafu {
208                expected: "a table name",
209                actual: self.peek_token_as_string(),
210            })?;
211
212        ensure!(
213            table_name.0.len() == 1,
214            InvalidDatabaseNameSnafu {
215                name: table_name.to_string(),
216            }
217        );
218
219        // Safety: already checked above
220        Ok(Self::canonicalize_object_name(table_name).0[0]
221            .value
222            .clone())
223    }
224
225    fn parse_db_name(&mut self) -> Result<Option<String>> {
226        self.parser.next_token();
227        let db_name = self
228            .parse_object_name()
229            .with_context(|_| error::UnexpectedSnafu {
230                expected: "a database name",
231                actual: self.peek_token_as_string(),
232            })?;
233
234        ensure!(
235            db_name.0.len() == 1,
236            InvalidDatabaseNameSnafu {
237                name: db_name.to_string(),
238            }
239        );
240
241        // Safety: already checked above
242        Ok(Some(
243            Self::canonicalize_object_name(db_name).0[0].value.clone(),
244        ))
245    }
246
247    fn parse_show_columns(&mut self, full: bool) -> Result<Statement> {
248        let table = match self.parser.peek_token().token {
249            // SHOW columns {in | FROM} TABLE
250            Token::Word(w) if matches!(w.keyword, Keyword::IN | Keyword::FROM) => {
251                self.parse_show_table_name()?
252            }
253            _ => {
254                return error::UnexpectedTokenSnafu {
255                    expected: "{FROM | IN} table",
256                    actual: self.peek_token_as_string(),
257                }
258                .fail();
259            }
260        };
261
262        let database = match self.parser.peek_token().token {
263            Token::EOF | Token::SemiColon => {
264                return Ok(Statement::ShowColumns(ShowColumns {
265                    kind: ShowKind::All,
266                    table,
267                    database: None,
268                    full,
269                }));
270            }
271
272            // SHOW columns {In | FROM} TABLE {In | FROM} DATABASE
273            Token::Word(w) => match w.keyword {
274                Keyword::IN | Keyword::FROM => self.parse_db_name()?,
275
276                _ => None,
277            },
278            _ => None,
279        };
280
281        let kind = self.parse_show_kind()?;
282
283        Ok(Statement::ShowColumns(ShowColumns {
284            kind,
285            database,
286            table,
287            full,
288        }))
289    }
290
291    fn parse_show_kind(&mut self) -> Result<ShowKind> {
292        match self.parser.peek_token().token {
293            Token::EOF | Token::SemiColon => Ok(ShowKind::All),
294            Token::Word(w) => match w.keyword {
295                Keyword::LIKE => {
296                    self.parser.next_token();
297                    Ok(ShowKind::Like(
298                        self.parser.parse_identifier().with_context(|_| {
299                            error::UnexpectedSnafu {
300                                expected: "LIKE",
301                                actual: self.peek_token_as_string(),
302                            }
303                        })?,
304                    ))
305                }
306                Keyword::WHERE => {
307                    self.parser.next_token();
308                    Ok(ShowKind::Where(self.parser.parse_expr().with_context(
309                        |_| error::UnexpectedSnafu {
310                            expected: "some valid expression",
311                            actual: self.peek_token_as_string(),
312                        },
313                    )?))
314                }
315                _ => self.unsupported(self.peek_token_as_string()),
316            },
317            _ => self.unsupported(self.peek_token_as_string()),
318        }
319    }
320
321    fn parse_show_index(&mut self) -> Result<Statement> {
322        let table = match self.parser.peek_token().token {
323            // SHOW INDEX {in | FROM} TABLE
324            Token::Word(w) if matches!(w.keyword, Keyword::IN | Keyword::FROM) => {
325                self.parse_show_table_name()?
326            }
327            _ => {
328                return error::UnexpectedTokenSnafu {
329                    expected: "{FROM | IN} table",
330                    actual: self.peek_token_as_string(),
331                }
332                .fail();
333            }
334        };
335
336        let database = match self.parser.peek_token().token {
337            Token::EOF | Token::SemiColon => {
338                return Ok(Statement::ShowIndex(ShowIndex {
339                    kind: ShowKind::All,
340                    table,
341                    database: None,
342                }));
343            }
344
345            // SHOW INDEX {In | FROM} TABLE {In | FROM} DATABASE
346            Token::Word(w) => match w.keyword {
347                Keyword::IN | Keyword::FROM => self.parse_db_name()?,
348
349                _ => None,
350            },
351            _ => None,
352        };
353
354        let kind = match self.parser.peek_token().token {
355            Token::EOF | Token::SemiColon => ShowKind::All,
356            // SHOW INDEX [WHERE] [EXPR]
357            Token::Word(w) => match w.keyword {
358                Keyword::WHERE => {
359                    self.parser.next_token();
360                    ShowKind::Where(self.parser.parse_expr().with_context(|_| {
361                        error::UnexpectedSnafu {
362                            expected: "some valid expression",
363                            actual: self.peek_token_as_string(),
364                        }
365                    })?)
366                }
367                _ => return self.unsupported(self.peek_token_as_string()),
368            },
369            _ => return self.unsupported(self.peek_token_as_string()),
370        };
371
372        Ok(Statement::ShowIndex(ShowIndex {
373            kind,
374            database,
375            table,
376        }))
377    }
378
379    fn parse_show_regions(&mut self) -> Result<Statement> {
380        let table = match self.parser.peek_token().token {
381            // SHOW REGION {in | FROM} TABLE
382            Token::Word(w) if matches!(w.keyword, Keyword::IN | Keyword::FROM) => {
383                self.parse_show_table_name()?
384            }
385            _ => {
386                return error::UnexpectedTokenSnafu {
387                    expected: "{FROM | IN} table",
388                    actual: self.peek_token_as_string(),
389                }
390                .fail();
391            }
392        };
393
394        let database = match self.parser.peek_token().token {
395            Token::EOF | Token::SemiColon => {
396                return Ok(Statement::ShowRegion(ShowRegion {
397                    kind: ShowKind::All,
398                    table,
399                    database: None,
400                }));
401            }
402
403            // SHOW REGION {In | FROM} TABLE {In | FROM} DATABASE
404            Token::Word(w) => match w.keyword {
405                Keyword::IN | Keyword::FROM => self.parse_db_name()?,
406
407                _ => None,
408            },
409            _ => None,
410        };
411
412        let kind = match self.parser.peek_token().token {
413            Token::EOF | Token::SemiColon => ShowKind::All,
414            // SHOW REGION [WHERE] [EXPR]
415            Token::Word(w) => match w.keyword {
416                Keyword::WHERE => {
417                    self.parser.next_token();
418                    ShowKind::Where(self.parser.parse_expr().with_context(|_| {
419                        error::UnexpectedSnafu {
420                            expected: "some valid expression",
421                            actual: self.peek_token_as_string(),
422                        }
423                    })?)
424                }
425                _ => return self.unsupported(self.peek_token_as_string()),
426            },
427            _ => return self.unsupported(self.peek_token_as_string()),
428        };
429
430        Ok(Statement::ShowRegion(ShowRegion {
431            kind,
432            database,
433            table,
434        }))
435    }
436
437    fn parse_show_tables(&mut self, full: bool) -> Result<Statement> {
438        let database = match self.parser.peek_token().token {
439            Token::EOF | Token::SemiColon => {
440                return Ok(Statement::ShowTables(ShowTables {
441                    kind: ShowKind::All,
442                    database: None,
443                    full,
444                }));
445            }
446
447            // SHOW TABLES [in | FROM] [DATABASE]
448            Token::Word(w) => match w.keyword {
449                Keyword::IN | Keyword::FROM => self.parse_db_name()?,
450
451                _ => None,
452            },
453            _ => None,
454        };
455
456        let kind = self.parse_show_kind()?;
457
458        Ok(Statement::ShowTables(ShowTables {
459            kind,
460            database,
461            full,
462        }))
463    }
464
465    fn parse_show_table_status(&mut self) -> Result<Statement> {
466        let database = match self.parser.peek_token().token {
467            Token::EOF | Token::SemiColon => {
468                return Ok(Statement::ShowTableStatus(ShowTableStatus {
469                    kind: ShowKind::All,
470                    database: None,
471                }));
472            }
473
474            // SHOW TABLE STATUS [in | FROM] [DATABASE]
475            Token::Word(w) => match w.keyword {
476                Keyword::IN | Keyword::FROM => self.parse_db_name()?,
477
478                _ => None,
479            },
480            _ => None,
481        };
482
483        let kind = self.parse_show_kind()?;
484
485        Ok(Statement::ShowTableStatus(ShowTableStatus {
486            kind,
487            database,
488        }))
489    }
490
491    /// Parses `SHOW DATABASES` statement.
492    pub fn parse_show_databases(&mut self, full: bool) -> Result<Statement> {
493        let tok = self.parser.next_token().token;
494        match &tok {
495            Token::EOF | Token::SemiColon => Ok(Statement::ShowDatabases(ShowDatabases::new(
496                ShowKind::All,
497                full,
498            ))),
499            Token::Word(w) => match w.keyword {
500                Keyword::LIKE => Ok(Statement::ShowDatabases(ShowDatabases::new(
501                    ShowKind::Like(self.parser.parse_identifier().with_context(|_| {
502                        error::UnexpectedSnafu {
503                            expected: "LIKE",
504                            actual: tok.to_string(),
505                        }
506                    })?),
507                    full,
508                ))),
509                Keyword::WHERE => Ok(Statement::ShowDatabases(ShowDatabases::new(
510                    ShowKind::Where(self.parser.parse_expr().with_context(|_| {
511                        error::UnexpectedSnafu {
512                            expected: "some valid expression",
513                            actual: self.peek_token_as_string(),
514                        }
515                    })?),
516                    full,
517                ))),
518                _ => self.unsupported(self.peek_token_as_string()),
519            },
520            _ => self.unsupported(self.peek_token_as_string()),
521        }
522    }
523
524    fn parse_show_views(&mut self) -> Result<Statement> {
525        let database = match self.parser.peek_token().token {
526            Token::EOF | Token::SemiColon => {
527                return Ok(Statement::ShowViews(ShowViews {
528                    kind: ShowKind::All,
529                    database: None,
530                }));
531            }
532
533            // SHOW FLOWS [in | FROM] [DATABASE]
534            Token::Word(w) => match w.keyword {
535                Keyword::IN | Keyword::FROM => self.parse_db_name()?,
536                _ => None,
537            },
538            _ => None,
539        };
540
541        let kind = self.parse_show_kind()?;
542
543        Ok(Statement::ShowViews(ShowViews { kind, database }))
544    }
545
546    fn parse_show_flows(&mut self) -> Result<Statement> {
547        let database = match self.parser.peek_token().token {
548            Token::EOF | Token::SemiColon => {
549                return Ok(Statement::ShowFlows(ShowFlows {
550                    kind: ShowKind::All,
551                    database: None,
552                }));
553            }
554
555            // SHOW FLOWS [in | FROM] [DATABASE]
556            Token::Word(w) => match w.keyword {
557                Keyword::IN | Keyword::FROM => self.parse_db_name()?,
558                _ => None,
559            },
560            _ => None,
561        };
562
563        let kind = self.parse_show_kind()?;
564
565        Ok(Statement::ShowFlows(ShowFlows { kind, database }))
566    }
567}
568
569#[cfg(test)]
570mod tests {
571    use std::assert_matches::assert_matches;
572
573    use sqlparser::ast::{Ident, ObjectName};
574
575    use super::*;
576    use crate::dialect::GreptimeDbDialect;
577    use crate::parser::ParseOptions;
578    use crate::statements::show::ShowDatabases;
579
580    #[test]
581    pub fn test_show_database_all() {
582        let sql = "SHOW DATABASES";
583        let result =
584            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
585        let stmts = result.unwrap();
586        assert_eq!(1, stmts.len());
587
588        assert_matches!(
589            &stmts[0],
590            Statement::ShowDatabases(ShowDatabases {
591                kind: ShowKind::All,
592                full: false,
593            })
594        );
595    }
596
597    #[test]
598    pub fn test_show_full_databases() {
599        let sql = "SHOW FULL DATABASES";
600        let result =
601            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
602        let stmts = result.unwrap();
603        assert_eq!(1, stmts.len());
604
605        assert_matches!(
606            &stmts[0],
607            Statement::ShowDatabases(ShowDatabases {
608                kind: ShowKind::All,
609                full: true,
610            })
611        );
612
613        let sql = "SHOW FULL DATABASES LIKE 'test%'";
614        let result =
615            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
616        let stmts = result.unwrap();
617        assert_eq!(1, stmts.len());
618
619        assert_matches!(
620            &stmts[0],
621            Statement::ShowDatabases(ShowDatabases {
622                kind: ShowKind::Like(_),
623                full: true,
624            })
625        );
626    }
627
628    #[test]
629    pub fn test_show_database_like() {
630        let sql = "SHOW DATABASES LIKE test_database";
631        let result =
632            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
633        let stmts = result.unwrap();
634        assert_eq!(1, stmts.len());
635
636        assert_matches!(
637            &stmts[0],
638            Statement::ShowDatabases(ShowDatabases {
639                kind: ShowKind::Like(sqlparser::ast::Ident {
640                    value: _,
641                    quote_style: None,
642                    span: _,
643                }),
644                ..
645            })
646        );
647    }
648
649    #[test]
650    pub fn test_show_database_where() {
651        let sql = "SHOW DATABASES WHERE Database LIKE '%whatever1%' OR Database LIKE '%whatever2%'";
652        let result =
653            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
654        let stmts = result.unwrap();
655        assert_eq!(1, stmts.len());
656
657        assert_matches!(
658            &stmts[0],
659            Statement::ShowDatabases(ShowDatabases {
660                kind: ShowKind::Where(sqlparser::ast::Expr::BinaryOp {
661                    left: _,
662                    right: _,
663                    op: sqlparser::ast::BinaryOperator::Or,
664                }),
665                ..
666            })
667        );
668    }
669
670    #[test]
671    pub fn test_show_tables_all() {
672        let sql = "SHOW TABLES";
673        let result =
674            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
675        let stmts = result.unwrap();
676        assert_eq!(1, stmts.len());
677
678        assert_matches!(
679            &stmts[0],
680            Statement::ShowTables(ShowTables {
681                kind: ShowKind::All,
682                database: None,
683                full: false
684            })
685        );
686    }
687
688    #[test]
689    pub fn test_show_tables_like() {
690        let sql = "SHOW TABLES LIKE test_table";
691        let result =
692            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
693        let stmts = result.unwrap();
694        assert_eq!(1, stmts.len());
695
696        assert_matches!(
697            &stmts[0],
698            Statement::ShowTables(ShowTables {
699                kind: ShowKind::Like(sqlparser::ast::Ident {
700                    value: _,
701                    quote_style: None,
702                    span: _,
703                }),
704                database: None,
705                full: false
706            })
707        );
708
709        let sql = "SHOW TABLES in test_db LIKE test_table";
710        let result =
711            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
712        let stmts = result.unwrap();
713        assert_eq!(1, stmts.len());
714
715        assert_matches!(
716            &stmts[0],
717            Statement::ShowTables(ShowTables {
718                kind: ShowKind::Like(sqlparser::ast::Ident {
719                    value: _,
720                    quote_style: None,
721                    span: _,
722                }),
723                database: Some(_),
724                full: false
725            })
726        );
727    }
728
729    #[test]
730    pub fn test_show_tables_where() {
731        let sql = "SHOW TABLES where name like test_table";
732        let result =
733            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
734        let stmts = result.unwrap();
735        assert_eq!(1, stmts.len());
736
737        assert_matches!(
738            &stmts[0],
739            Statement::ShowTables(ShowTables {
740                kind: ShowKind::Where(sqlparser::ast::Expr::Like { .. }),
741                database: None,
742                full: false
743            })
744        );
745
746        let sql = "SHOW TABLES in test_db where name LIKE test_table";
747        let result =
748            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
749        let stmts = result.unwrap();
750        assert_eq!(1, stmts.len());
751
752        assert_matches!(
753            &stmts[0],
754            Statement::ShowTables(ShowTables {
755                kind: ShowKind::Where(sqlparser::ast::Expr::Like { .. }),
756                database: Some(_),
757                full: false
758            })
759        );
760    }
761
762    #[test]
763    pub fn test_show_full_tables() {
764        let sql = "SHOW FULL TABLES";
765        let stmts =
766            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
767                .unwrap();
768        assert_eq!(1, stmts.len());
769        assert_matches!(&stmts[0], Statement::ShowTables { .. });
770        match &stmts[0] {
771            Statement::ShowTables(show) => {
772                assert!(show.full);
773            }
774            _ => {
775                unreachable!();
776            }
777        }
778    }
779
780    #[test]
781    pub fn test_show_full_tables_where() {
782        let sql = "SHOW FULL TABLES IN test_db WHERE Tables LIKE test_table";
783        let stmts =
784            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
785                .unwrap();
786        assert_eq!(1, stmts.len());
787
788        assert_matches!(
789            &stmts[0],
790            Statement::ShowTables(ShowTables {
791                kind: ShowKind::Where(sqlparser::ast::Expr::Like { .. }),
792                database: Some(_),
793                full: true
794            })
795        );
796    }
797
798    #[test]
799    pub fn test_show_full_tables_like() {
800        let sql = "SHOW FULL TABLES LIKE test_table";
801        let result =
802            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
803        let stmts = result.unwrap();
804        assert_eq!(1, stmts.len());
805
806        assert_matches!(
807            &stmts[0],
808            Statement::ShowTables(ShowTables {
809                kind: ShowKind::Like(sqlparser::ast::Ident {
810                    value: _,
811                    quote_style: None,
812                    span: _,
813                }),
814                database: None,
815                full: true
816            })
817        );
818
819        let sql = "SHOW FULL TABLES in test_db LIKE test_table";
820        let result =
821            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
822        let stmts = result.unwrap();
823        assert_eq!(1, stmts.len());
824
825        assert_matches!(
826            &stmts[0],
827            Statement::ShowTables(ShowTables {
828                kind: ShowKind::Like(sqlparser::ast::Ident {
829                    value: _,
830                    quote_style: None,
831                    span: _,
832                }),
833                database: Some(_),
834                full: true
835            })
836        );
837    }
838
839    #[test]
840    pub fn test_show_variables() {
841        let sql = "SHOW VARIABLES system_time_zone";
842        let result =
843            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
844        let stmts = result.unwrap();
845        assert_eq!(1, stmts.len());
846        assert_eq!(
847            stmts[0],
848            Statement::ShowVariables(ShowVariables {
849                variable: ObjectName(vec![Ident::new("system_time_zone")]),
850            })
851        );
852    }
853
854    #[test]
855    pub fn test_show_columns() {
856        let sql = "SHOW COLUMNS";
857        let result =
858            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
859        let error = result.unwrap_err();
860        assert_eq!("Unexpected token while parsing SQL statement, expected: '{FROM | IN} table', found: EOF", error.to_string());
861
862        let sql = "SHOW COLUMNS from test";
863        let result =
864            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
865        let stmts = result.unwrap();
866        assert_eq!(1, stmts.len());
867        assert!(matches!(&stmts[0],
868                         Statement::ShowColumns(ShowColumns {
869                             table,
870                             database,
871                             full,
872                             ..
873
874                         }) if table == "test" && database.is_none() && !full));
875
876        let sql = "SHOW FULL COLUMNS from test from public";
877        let result =
878            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
879        let stmts = result.unwrap();
880        assert_eq!(1, stmts.len());
881        assert!(matches!(&stmts[0],
882                         Statement::ShowColumns(ShowColumns {
883                             table,
884                             database: Some(database),
885                             full,
886                             ..
887                         }) if table == "test" && database == "public" && *full));
888
889        let sql = "SHOW COLUMNS from test like 'disk%'";
890        let result =
891            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
892        let stmts = result.unwrap();
893        assert_eq!(1, stmts.len());
894        assert!(matches!(&stmts[0],
895                         Statement::ShowColumns(ShowColumns {
896                             table,
897                             kind: ShowKind::Like(ident),
898                             ..
899                         }) if table == "test" && ident.to_string() == "'disk%'"));
900
901        let sql = "SHOW COLUMNS from test where Field = 'disk'";
902        let result =
903            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
904        let stmts = result.unwrap();
905        assert_eq!(1, stmts.len());
906        assert!(matches!(&stmts[0],
907                         Statement::ShowColumns(ShowColumns {
908                             table,
909                             kind: ShowKind::Where(expr),
910                             ..
911                         }) if table == "test" && expr.to_string() == "Field = 'disk'"));
912    }
913
914    #[test]
915    pub fn test_show_index() {
916        let sql = "SHOW INDEX";
917        let result =
918            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
919        let error = result.unwrap_err();
920        assert_eq!("Unexpected token while parsing SQL statement, expected: '{FROM | IN} table', found: EOF", error.to_string());
921
922        let sql = "SHOW INDEX from test";
923        let result =
924            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
925        let stmts = result.unwrap();
926        assert_eq!(1, stmts.len());
927        assert!(matches!(&stmts[0],
928                         Statement::ShowIndex(ShowIndex {
929                             table,
930                             database,
931                             ..
932
933                         }) if table == "test" && database.is_none()));
934
935        let sql = "SHOW INDEX from test from public";
936        let result =
937            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
938        let stmts = result.unwrap();
939        assert_eq!(1, stmts.len());
940        assert!(matches!(&stmts[0],
941                         Statement::ShowIndex(ShowIndex {
942                             table,
943                             database: Some(database),
944                             ..
945                         }) if table == "test" && database == "public"));
946
947        // SHOW INDEX deosn't support like
948        let sql = "SHOW INDEX from test like 'disk%'";
949        let result =
950            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
951        let error = result.unwrap_err();
952        assert_eq!(
953            "SQL statement is not supported, keyword: like",
954            error.to_string()
955        );
956
957        let sql = "SHOW INDEX from test where Field = 'disk'";
958        let result =
959            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
960        let stmts = result.unwrap();
961        assert_eq!(1, stmts.len());
962        assert!(matches!(&stmts[0],
963                         Statement::ShowIndex(ShowIndex {
964                             table,
965                             kind: ShowKind::Where(expr),
966                             ..
967                         }) if table == "test" && expr.to_string() == "Field = 'disk'"));
968    }
969
970    #[test]
971    fn test_show_region() {
972        let sql = "SHOW REGION";
973        let result =
974            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
975        let error = result.unwrap_err();
976        assert_eq!("Unexpected token while parsing SQL statement, expected: '{FROM | IN} table', found: EOF", error.to_string());
977
978        let sql = "SHOW REGION from test";
979        let result =
980            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
981        let stmts = result.unwrap();
982        assert_eq!(1, stmts.len());
983        assert!(matches!(&stmts[0],
984                         Statement::ShowRegion(ShowRegion {
985                             table,
986                             database,
987                             ..
988
989                         }) if table == "test" && database.is_none()));
990
991        let sql = "SHOW REGION from test from public";
992        let result =
993            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
994        let stmts = result.unwrap();
995        assert_eq!(1, stmts.len());
996        assert!(matches!(&stmts[0],
997                         Statement::ShowRegion(ShowRegion {
998                             table,
999                             database: Some(database),
1000                             ..
1001                         }) if table == "test" && database == "public"));
1002
1003        // SHOW REGION deosn't support like
1004        let sql = "SHOW REGION from test like 'disk%'";
1005        let result =
1006            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1007        let error = result.unwrap_err();
1008        assert_eq!(
1009            "SQL statement is not supported, keyword: like",
1010            error.to_string()
1011        );
1012
1013        let sql = "SHOW REGION from test where Field = 'disk'";
1014        let result =
1015            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1016        let stmts = result.unwrap();
1017        assert_eq!(1, stmts.len());
1018        assert!(matches!(&stmts[0],
1019                         Statement::ShowRegion(ShowRegion {
1020                             table,
1021                             kind: ShowKind::Where(expr),
1022                             ..
1023                         }) if table == "test" && expr.to_string() == "Field = 'disk'"));
1024    }
1025
1026    #[test]
1027    fn parse_show_collation() {
1028        let sql = "SHOW COLLATION";
1029        let result =
1030            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1031        assert!(matches!(
1032            result.unwrap()[0],
1033            Statement::ShowCollation(ShowKind::All)
1034        ));
1035
1036        let sql = "SHOW COLLATION WHERE Charset = 'latin1'";
1037        let result =
1038            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1039        assert!(matches!(
1040            result.unwrap()[0],
1041            Statement::ShowCollation(ShowKind::Where(_))
1042        ));
1043
1044        let sql = "SHOW COLLATION LIKE 'latin1'";
1045        let result =
1046            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1047        assert!(matches!(
1048            result.unwrap()[0],
1049            Statement::ShowCollation(ShowKind::Like(_))
1050        ));
1051    }
1052
1053    #[test]
1054    fn parse_show_charset() {
1055        let sql = "SHOW CHARSET";
1056        let result =
1057            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1058        assert!(matches!(
1059            result.unwrap()[0],
1060            Statement::ShowCharset(ShowKind::All)
1061        ));
1062
1063        let sql = "SHOW CHARACTER SET";
1064        let result =
1065            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1066        assert!(matches!(
1067            result.unwrap()[0],
1068            Statement::ShowCharset(ShowKind::All)
1069        ));
1070
1071        let sql = "SHOW CHARSET WHERE Charset = 'latin1'";
1072        let result =
1073            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1074        assert!(matches!(
1075            result.unwrap()[0],
1076            Statement::ShowCharset(ShowKind::Where(_))
1077        ));
1078
1079        let sql = "SHOW CHARACTER SET LIKE 'latin1'";
1080        let result =
1081            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1082        assert!(matches!(
1083            result.unwrap()[0],
1084            Statement::ShowCharset(ShowKind::Like(_))
1085        ));
1086    }
1087
1088    fn parse_show_table_status(sql: &str) -> ShowTableStatus {
1089        let result =
1090            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1091        let mut stmts = result.unwrap();
1092        assert_eq!(1, stmts.len());
1093
1094        match stmts.remove(0) {
1095            Statement::ShowTableStatus(stmt) => stmt,
1096            _ => panic!("Failed to parse show table status"),
1097        }
1098    }
1099
1100    #[test]
1101    pub fn test_show_table_status() {
1102        let sql = "SHOW TABLE STATUS";
1103        let stmt = parse_show_table_status(sql);
1104        assert!(stmt.database.is_none());
1105        assert_eq!(sql, stmt.to_string());
1106
1107        let sql = "SHOW TABLE STATUS IN test";
1108        let stmt = parse_show_table_status(sql);
1109        assert_eq!("test", stmt.database.as_ref().unwrap());
1110        assert_eq!(sql, stmt.to_string());
1111
1112        let sql = "SHOW TABLE STATUS LIKE '%monitor'";
1113        let stmt = parse_show_table_status(sql);
1114        assert!(stmt.database.is_none());
1115        assert!(matches!(stmt.kind, ShowKind::Like(_)));
1116        assert_eq!(sql, stmt.to_string());
1117
1118        let sql = "SHOW TABLE STATUS IN test WHERE Name = 'monitor'";
1119        let stmt = parse_show_table_status(sql);
1120        assert_eq!("test", stmt.database.as_ref().unwrap());
1121        assert!(matches!(stmt.kind, ShowKind::Where(_)));
1122        assert_eq!(sql, stmt.to_string());
1123    }
1124
1125    #[test]
1126    pub fn test_show_create_view() {
1127        let sql = "SHOW CREATE VIEW test";
1128        let result =
1129            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1130        let stmts = result.unwrap();
1131        assert_eq!(1, stmts.len());
1132        assert_eq!(
1133            stmts[0],
1134            Statement::ShowCreateView(ShowCreateView {
1135                view_name: ObjectName(vec![Ident::new("test")]),
1136            })
1137        );
1138        assert_eq!(sql, stmts[0].to_string());
1139    }
1140
1141    #[test]
1142    pub fn test_show_views() {
1143        let sql = "SHOW VIEWS";
1144        let result =
1145            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1146        let stmts = result.unwrap();
1147        assert_eq!(1, stmts.len());
1148        assert_eq!(
1149            stmts[0],
1150            Statement::ShowViews(ShowViews {
1151                kind: ShowKind::All,
1152                database: None,
1153            })
1154        );
1155        assert_eq!(sql, stmts[0].to_string());
1156    }
1157
1158    #[test]
1159    pub fn test_show_views_in_db() {
1160        let sql = "SHOW VIEWS IN d1";
1161        let result =
1162            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1163        let stmts = result.unwrap();
1164        assert_eq!(1, stmts.len());
1165        assert_eq!(
1166            stmts[0],
1167            Statement::ShowViews(ShowViews {
1168                kind: ShowKind::All,
1169                database: Some("d1".to_string()),
1170            })
1171        );
1172        assert_eq!(sql, stmts[0].to_string());
1173    }
1174
1175    #[test]
1176    pub fn test_show_flows() {
1177        let sql = "SHOW FLOWS";
1178        let result =
1179            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1180        let stmts = result.unwrap();
1181        assert_eq!(1, stmts.len());
1182        assert_eq!(
1183            stmts[0],
1184            Statement::ShowFlows(ShowFlows {
1185                kind: ShowKind::All,
1186                database: None,
1187            })
1188        );
1189        assert_eq!(sql, stmts[0].to_string());
1190    }
1191
1192    #[test]
1193    pub fn test_show_flows_in_db() {
1194        let sql = "SHOW FLOWS IN d1";
1195        let result =
1196            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default());
1197        let stmts = result.unwrap();
1198        assert_eq!(1, stmts.len());
1199        assert_eq!(
1200            stmts[0],
1201            Statement::ShowFlows(ShowFlows {
1202                kind: ShowKind::All,
1203                database: Some("d1".to_string()),
1204            })
1205        );
1206        assert_eq!(sql, stmts[0].to_string());
1207    }
1208}