sql/statements/
show.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::{self, Display};
16
17use serde::Serialize;
18use sqlparser_derive::{Visit, VisitMut};
19
20use crate::ast::{Expr, Ident, ObjectName};
21
22/// Show kind for SQL expressions like `SHOW DATABASE` or `SHOW TABLE`
23#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
24pub enum ShowKind {
25    All,
26    Like(Ident),
27    Where(Expr),
28}
29
30impl Display for ShowKind {
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        match self {
33            // The `All` is the default kind placeholder, not a valid statement.
34            ShowKind::All => write!(f, ""),
35            ShowKind::Like(ident) => write!(f, "LIKE {ident}"),
36            ShowKind::Where(expr) => write!(f, "WHERE {expr}"),
37        }
38    }
39}
40
41macro_rules! format_kind {
42    ($self: expr, $f: expr) => {
43        if $self.kind != ShowKind::All {
44            write!($f, " {}", &$self.kind)?;
45        }
46    };
47}
48
49#[cfg(feature = "enterprise")]
50pub mod trigger;
51
52/// SQL structure for `SHOW DATABASES`.
53#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
54pub struct ShowDatabases {
55    pub kind: ShowKind,
56    pub full: bool,
57}
58
59/// The SQL `SHOW COLUMNS` statement
60#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
61pub struct ShowColumns {
62    pub kind: ShowKind,
63    pub table: String,
64    pub database: Option<String>,
65    pub full: bool,
66}
67
68impl Display for ShowColumns {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "SHOW ")?;
71        if self.full {
72            write!(f, "FULL ")?;
73        }
74        write!(f, "COLUMNS IN {}", &self.table)?;
75        if let Some(database) = &self.database {
76            write!(f, " IN {database}")?;
77        }
78        format_kind!(self, f);
79        Ok(())
80    }
81}
82
83/// The SQL `SHOW INDEX` statement
84#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
85pub struct ShowIndex {
86    pub kind: ShowKind,
87    pub table: String,
88    pub database: Option<String>,
89}
90
91impl Display for ShowIndex {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        write!(f, "SHOW INDEX IN {}", &self.table)?;
94        if let Some(database) = &self.database {
95            write!(f, " IN {database}")?;
96        }
97        format_kind!(self, f);
98
99        Ok(())
100    }
101}
102
103/// The SQL `SHOW REGION` statement
104#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
105pub struct ShowRegion {
106    pub kind: ShowKind,
107    pub table: String,
108    pub database: Option<String>,
109}
110
111impl Display for ShowRegion {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(f, "SHOW REGION IN {}", &self.table)?;
114        if let Some(database) = &self.database {
115            write!(f, " IN {database}")?;
116        }
117        format_kind!(self, f);
118        Ok(())
119    }
120}
121
122impl ShowDatabases {
123    /// Creates a statement for `SHOW DATABASES`
124    pub fn new(kind: ShowKind, full: bool) -> Self {
125        ShowDatabases { kind, full }
126    }
127}
128
129impl Display for ShowDatabases {
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        if self.full {
132            write!(f, "SHOW FULL DATABASES")?;
133        } else {
134            write!(f, "SHOW DATABASES")?;
135        }
136
137        format_kind!(self, f);
138
139        Ok(())
140    }
141}
142
143/// SQL structure for `SHOW TABLES`.
144#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
145pub struct ShowTables {
146    pub kind: ShowKind,
147    pub database: Option<String>,
148    pub full: bool,
149}
150
151impl Display for ShowTables {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        write!(f, "SHOW ")?;
154        if self.full {
155            write!(f, "FULL ")?;
156        }
157        write!(f, "TABLES")?;
158        if let Some(database) = &self.database {
159            write!(f, " IN {database}")?;
160        }
161        format_kind!(self, f);
162
163        Ok(())
164    }
165}
166
167/// SQL structure for `SHOW TABLE STATUS`.
168#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
169pub struct ShowTableStatus {
170    pub kind: ShowKind,
171    pub database: Option<String>,
172}
173
174impl Display for ShowTableStatus {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        write!(f, "SHOW TABLE STATUS")?;
177        if let Some(database) = &self.database {
178            write!(f, " IN {database}")?;
179        }
180
181        format_kind!(self, f);
182
183        Ok(())
184    }
185}
186
187/// SQL structure for `SHOW CREATE DATABASE`.
188#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
189pub struct ShowCreateDatabase {
190    pub database_name: ObjectName,
191}
192
193impl Display for ShowCreateDatabase {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        let database_name = &self.database_name;
196        write!(f, r#"SHOW CREATE DATABASE {database_name}"#)
197    }
198}
199
200/// SQL structure for `SHOW CREATE TABLE`.
201#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
202pub struct ShowCreateTable {
203    pub table_name: ObjectName,
204    pub variant: ShowCreateTableVariant,
205}
206
207/// Variant of a show create table
208#[derive(Default, Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
209pub enum ShowCreateTableVariant {
210    #[default]
211    Original,
212    PostgresForeignTable,
213}
214
215impl Display for ShowCreateTable {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        let table_name = &self.table_name;
218        write!(f, r#"SHOW CREATE TABLE {table_name}"#)?;
219        if let ShowCreateTableVariant::PostgresForeignTable = self.variant {
220            write!(f, " FOR POSTGRES_FOREIGN_TABLE")?;
221        }
222
223        Ok(())
224    }
225}
226
227/// SQL structure for `SHOW CREATE FLOW`.
228#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
229pub struct ShowCreateFlow {
230    pub flow_name: ObjectName,
231}
232
233impl Display for ShowCreateFlow {
234    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235        let flow_name = &self.flow_name;
236        write!(f, "SHOW CREATE FLOW {flow_name}")
237    }
238}
239
240/// SQL structure for `SHOW FLOWS`.
241#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
242pub struct ShowFlows {
243    pub kind: ShowKind,
244    pub database: Option<String>,
245}
246
247impl Display for ShowFlows {
248    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
249        write!(f, "SHOW FLOWS")?;
250        if let Some(database) = &self.database {
251            write!(f, " IN {database}")?;
252        }
253        format_kind!(self, f);
254
255        Ok(())
256    }
257}
258
259/// SQL structure for `SHOW CREATE VIEW`.
260#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
261pub struct ShowCreateView {
262    pub view_name: ObjectName,
263}
264
265impl Display for ShowCreateView {
266    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267        let view_name = &self.view_name;
268        write!(f, "SHOW CREATE VIEW {view_name}")
269    }
270}
271
272/// SQL structure for `SHOW VIEWS`.
273#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
274pub struct ShowViews {
275    pub kind: ShowKind,
276    pub database: Option<String>,
277}
278
279impl Display for ShowViews {
280    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281        write!(f, "SHOW VIEWS")?;
282        if let Some(database) = &self.database {
283            write!(f, " IN {database}")?;
284        }
285        format_kind!(self, f);
286
287        Ok(())
288    }
289}
290
291/// SQL structure for `SHOW VARIABLES xxx`.
292#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
293pub struct ShowVariables {
294    pub variable: ObjectName,
295}
296
297impl Display for ShowVariables {
298    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299        let variable = &self.variable;
300        write!(f, r#"SHOW VARIABLES {variable}"#)
301    }
302}
303
304/// SQL structure for "SHOW STATUS"
305#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
306pub struct ShowStatus {}
307
308impl Display for ShowStatus {
309    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310        write!(f, "SHOW STATUS")
311    }
312}
313
314/// SQL structure for "SHOW SEARCH_PATH" postgres only
315#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
316pub struct ShowSearchPath {}
317
318impl Display for ShowSearchPath {
319    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320        write!(f, "SHOW SEARCH_PATH")
321    }
322}
323
324/// SQL structure for `SHOW PROCESSLIST`.
325#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
326pub struct ShowProcessList {
327    pub full: bool,
328}
329impl Display for ShowProcessList {
330    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331        if self.full {
332            write!(f, "SHOW FULL PROCESSLIST")?;
333        } else {
334            write!(f, "SHOW PROCESSLIST")?;
335        }
336
337        Ok(())
338    }
339}
340
341#[cfg(test)]
342mod tests {
343    use std::assert_matches::assert_matches;
344
345    use sqlparser::ast::UnaryOperator;
346
347    use super::*;
348    use crate::dialect::GreptimeDbDialect;
349    use crate::parser::{ParseOptions, ParserContext};
350    use crate::statements::statement::Statement;
351
352    #[test]
353    fn test_kind_display() {
354        assert_eq!("", format!("{}", ShowKind::All));
355        assert_eq!(
356            "LIKE test",
357            format!("{}", ShowKind::Like(Ident::new("test")),)
358        );
359        assert_eq!(
360            "WHERE NOT a",
361            format!(
362                "{}",
363                ShowKind::Where(Expr::UnaryOp {
364                    op: UnaryOperator::Not,
365                    expr: Box::new(Expr::Identifier(Ident::new("a"))),
366                })
367            )
368        );
369    }
370
371    #[test]
372    pub fn test_show_database() {
373        let sql = "SHOW DATABASES";
374        let stmts =
375            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
376                .unwrap();
377        assert_eq!(1, stmts.len());
378        assert_matches!(&stmts[0], Statement::ShowDatabases { .. });
379        match &stmts[0] {
380            Statement::ShowDatabases(show) => {
381                assert_eq!(ShowKind::All, show.kind);
382            }
383            _ => {
384                unreachable!();
385            }
386        }
387    }
388
389    #[test]
390    pub fn test_show_create_table() {
391        let sql = "SHOW CREATE TABLE test";
392        let stmts: Vec<Statement> =
393            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
394                .unwrap();
395        assert_eq!(1, stmts.len());
396        assert_matches!(&stmts[0], Statement::ShowCreateTable { .. });
397        match &stmts[0] {
398            Statement::ShowCreateTable(show) => {
399                let table_name = show.table_name.to_string();
400                assert_eq!(table_name, "test");
401                assert_eq!(show.variant, ShowCreateTableVariant::Original);
402            }
403            _ => {
404                unreachable!();
405            }
406        }
407
408        let sql = "SHOW CREATE TABLE test FOR POSTGRES_FOREIGN_TABLE";
409        let stmts: Vec<Statement> =
410            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
411                .unwrap();
412        assert_eq!(1, stmts.len());
413        assert_matches!(&stmts[0], Statement::ShowCreateTable { .. });
414        match &stmts[0] {
415            Statement::ShowCreateTable(show) => {
416                let table_name = show.table_name.to_string();
417                assert_eq!(table_name, "test");
418                assert_eq!(show.variant, ShowCreateTableVariant::PostgresForeignTable);
419            }
420            _ => {
421                unreachable!();
422            }
423        }
424    }
425
426    #[test]
427    pub fn test_show_create_missing_table_name() {
428        let sql = "SHOW CREATE TABLE";
429        assert!(ParserContext::create_with_dialect(
430            sql,
431            &GreptimeDbDialect {},
432            ParseOptions::default()
433        )
434        .is_err());
435    }
436
437    #[test]
438    pub fn test_show_create_unknown_for() {
439        let sql = "SHOW CREATE TABLE t FOR UNKNOWN";
440        assert!(ParserContext::create_with_dialect(
441            sql,
442            &GreptimeDbDialect {},
443            ParseOptions::default()
444        )
445        .is_err());
446    }
447
448    #[test]
449    pub fn test_show_create_flow() {
450        let sql = "SHOW CREATE FLOW test";
451        let stmts: Vec<Statement> =
452            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
453                .unwrap();
454        assert_eq!(1, stmts.len());
455        assert_matches!(&stmts[0], Statement::ShowCreateFlow { .. });
456        match &stmts[0] {
457            Statement::ShowCreateFlow(show) => {
458                let flow_name = show.flow_name.to_string();
459                assert_eq!(flow_name, "test");
460            }
461            _ => {
462                unreachable!();
463            }
464        }
465    }
466    #[test]
467    pub fn test_show_create_missing_flow() {
468        let sql = "SHOW CREATE FLOW";
469        assert!(ParserContext::create_with_dialect(
470            sql,
471            &GreptimeDbDialect {},
472            ParseOptions::default()
473        )
474        .is_err());
475    }
476
477    #[test]
478    fn test_display_show_variables() {
479        let sql = r"show variables v1;";
480        let stmts: Vec<Statement> =
481            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
482                .unwrap();
483        assert_eq!(1, stmts.len());
484        assert_matches!(&stmts[0], Statement::ShowVariables { .. });
485        match &stmts[0] {
486            Statement::ShowVariables(show) => {
487                let new_sql = format!("\n{}", show);
488                assert_eq!(
489                    r#"
490SHOW VARIABLES v1"#,
491                    &new_sql
492                );
493            }
494            _ => {
495                unreachable!();
496            }
497        }
498    }
499
500    #[test]
501    fn test_display_show_create_table() {
502        let sql = r"show create table monitor;";
503        let stmts: Vec<Statement> =
504            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
505                .unwrap();
506        assert_eq!(1, stmts.len());
507        assert_matches!(&stmts[0], Statement::ShowCreateTable { .. });
508        match &stmts[0] {
509            Statement::ShowCreateTable(show) => {
510                let new_sql = format!("\n{}", show);
511                assert_eq!(
512                    r#"
513SHOW CREATE TABLE monitor"#,
514                    &new_sql
515                );
516            }
517            _ => {
518                unreachable!();
519            }
520        }
521    }
522
523    #[test]
524    fn test_display_show_index() {
525        let sql = r"show index from t1 from d1;";
526        let stmts: Vec<Statement> =
527            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
528                .unwrap();
529        assert_eq!(1, stmts.len());
530        assert_matches!(&stmts[0], Statement::ShowIndex { .. });
531        match &stmts[0] {
532            Statement::ShowIndex(show) => {
533                let new_sql = format!("\n{}", show);
534                assert_eq!(
535                    r#"
536SHOW INDEX IN t1 IN d1"#,
537                    &new_sql
538                );
539            }
540            _ => {
541                unreachable!();
542            }
543        }
544    }
545
546    #[test]
547    fn test_display_show_columns() {
548        let sql = r"show full columns in t1 in d1;";
549        let stmts: Vec<Statement> =
550            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
551                .unwrap();
552        assert_eq!(1, stmts.len());
553        assert_matches!(&stmts[0], Statement::ShowColumns { .. });
554        match &stmts[0] {
555            Statement::ShowColumns(show) => {
556                let new_sql = format!("\n{}", show);
557                assert_eq!(
558                    r#"
559SHOW FULL COLUMNS IN t1 IN d1"#,
560                    &new_sql
561                );
562            }
563            _ => {
564                unreachable!();
565            }
566        }
567    }
568
569    #[test]
570    fn test_display_show_tables() {
571        let sql = r"show full tables in d1;";
572        let stmts: Vec<Statement> =
573            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
574                .unwrap();
575        assert_eq!(1, stmts.len());
576        assert_matches!(&stmts[0], Statement::ShowTables { .. });
577        match &stmts[0] {
578            Statement::ShowTables(show) => {
579                let new_sql = format!("\n{}", show);
580                assert_eq!(
581                    r#"
582SHOW FULL TABLES IN d1"#,
583                    &new_sql
584                );
585            }
586            _ => {
587                unreachable!();
588            }
589        }
590
591        let sql = r"show full tables;";
592        let stmts: Vec<Statement> =
593            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
594                .unwrap();
595        assert_eq!(1, stmts.len());
596        assert_matches!(&stmts[0], Statement::ShowTables { .. });
597        match &stmts[0] {
598            Statement::ShowTables(show) => {
599                let new_sql = format!("\n{}", show);
600                assert_eq!(
601                    r#"
602SHOW FULL TABLES"#,
603                    &new_sql
604                );
605            }
606            _ => {
607                unreachable!();
608            }
609        }
610    }
611
612    #[test]
613    fn test_display_show_views() {
614        let sql = r"show views in d1;";
615        let stmts: Vec<Statement> =
616            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
617                .unwrap();
618        assert_eq!(1, stmts.len());
619        assert_matches!(&stmts[0], Statement::ShowViews { .. });
620        match &stmts[0] {
621            Statement::ShowViews(show) => {
622                let new_sql = format!("\n{}", show);
623                assert_eq!(
624                    r#"
625SHOW VIEWS IN d1"#,
626                    &new_sql
627                );
628            }
629            _ => {
630                unreachable!();
631            }
632        }
633
634        let sql = r"show views;";
635        let stmts: Vec<Statement> =
636            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
637                .unwrap();
638        assert_eq!(1, stmts.len());
639        assert_matches!(&stmts[0], Statement::ShowViews { .. });
640        match &stmts[0] {
641            Statement::ShowViews(show) => {
642                let new_sql = format!("\n{}", show);
643                assert_eq!(
644                    r#"
645SHOW VIEWS"#,
646                    &new_sql
647                );
648            }
649            _ => {
650                unreachable!();
651            }
652        }
653    }
654
655    #[test]
656    fn test_display_show_flows() {
657        let sql = r"show flows in d1;";
658        let stmts: Vec<Statement> =
659            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
660                .unwrap();
661        assert_eq!(1, stmts.len());
662        assert_matches!(&stmts[0], Statement::ShowFlows { .. });
663        match &stmts[0] {
664            Statement::ShowFlows(show) => {
665                let new_sql = format!("\n{}", show);
666                assert_eq!(
667                    r#"
668SHOW FLOWS IN d1"#,
669                    &new_sql
670                );
671            }
672            _ => {
673                unreachable!();
674            }
675        }
676
677        let sql = r"show flows;";
678        let stmts: Vec<Statement> =
679            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
680                .unwrap();
681        assert_eq!(1, stmts.len());
682        assert_matches!(&stmts[0], Statement::ShowFlows { .. });
683        match &stmts[0] {
684            Statement::ShowFlows(show) => {
685                let new_sql = format!("\n{}", show);
686                assert_eq!(
687                    r#"
688SHOW FLOWS"#,
689                    &new_sql
690                );
691            }
692            _ => {
693                unreachable!("{:?}", &stmts[0]);
694            }
695        }
696    }
697
698    #[test]
699    fn test_display_show_databases() {
700        let sql = r"show databases;";
701        let stmts: Vec<Statement> =
702            ParserContext::create_with_dialect(sql, &GreptimeDbDialect {}, ParseOptions::default())
703                .unwrap();
704        assert_eq!(1, stmts.len());
705        assert_matches!(&stmts[0], Statement::ShowDatabases { .. });
706        match &stmts[0] {
707            Statement::ShowDatabases(show) => {
708                let new_sql = format!("\n{}", show);
709                assert_eq!(
710                    r#"
711SHOW DATABASES"#,
712                    &new_sql
713                );
714            }
715            _ => {
716                unreachable!();
717            }
718        }
719    }
720}