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