Skip to main content

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