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