From 4e67a52f067fd07b0822c68bad9b4c561728268c Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Sat, 26 Oct 2024 20:05:21 +0200 Subject: [PATCH 1/6] Added support for SHOW DATABASES/SCHEMAS/VIEWS and extended SHOW TABLES for hive dialect --- src/ast/mod.rs | 68 +++++++++++++++++++++++++++++++++++++--- src/keywords.rs | 3 ++ src/parser/mod.rs | 55 +++++++++++++++++++++++++++++--- tests/sqlparser_hive.rs | 14 +++++++++ tests/sqlparser_mysql.rs | 10 +++++- 5 files changed, 140 insertions(+), 10 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 0573240a2..d3262bf70 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -73,8 +73,9 @@ pub use self::value::{ TrimWhereField, Value, }; -use crate::ast::helpers::stmt_data_loading::{ - DataLoadingOptions, StageLoadSelectItem, StageParamsObject, +use crate::{ + ast::helpers::stmt_data_loading::{DataLoadingOptions, StageLoadSelectItem, StageParamsObject}, + keywords::Keyword, }; #[cfg(feature = "visitor")] pub use visitor::*; @@ -2782,12 +2783,30 @@ pub enum Statement { filter: Option, }, /// ```sql + /// SHOW DATABASES [LIKE 'pattern'] + /// ``` + ShowDatabases { pattern: Option }, + /// ```sql + /// SHOW SCHEMAS [LIKE 'pattern'] + /// ``` + ShowSchemas { pattern: Option }, + /// ```sql /// SHOW TABLES /// ``` - /// Note: this is a MySQL-specific statement. ShowTables { extended: bool, full: bool, + // The keyword used to indicate the DB name (IN/FROM) + db_name_keyword: Option, + db_name: Option, + filter: Option, + }, + /// ```sql + /// SHOW VIEWS + /// ``` + ShowViews { + // The keyword used to indicate the DB name (IN/FROM) + db_name_keyword: Option, db_name: Option, filter: Option, }, @@ -4363,9 +4382,24 @@ impl fmt::Display for Statement { } Ok(()) } + Statement::ShowDatabases { pattern } => { + write!(f, "SHOW DATABASES")?; + if let Some(pattern) = pattern { + write!(f, " LIKE '{}'", pattern)?; + } + Ok(()) + } + Statement::ShowSchemas { pattern } => { + write!(f, "SHOW SCHEMAS")?; + if let Some(pattern) = pattern { + write!(f, " LIKE '{}'", pattern)?; + } + Ok(()) + } Statement::ShowTables { extended, full, + db_name_keyword, db_name, filter, } => { @@ -4376,7 +4410,31 @@ impl fmt::Display for Statement { full = if *full { "FULL " } else { "" }, )?; if let Some(db_name) = db_name { - write!(f, " FROM {db_name}")?; + let keyword = match &db_name_keyword { + Some(Keyword::FROM) => "FROM", + Some(Keyword::IN) => "IN", + _ => "", // unexpected + }; + write!(f, " {} {db_name}", keyword)?; + } + if let Some(filter) = filter { + write!(f, " {filter}")?; + } + Ok(()) + } + Statement::ShowViews { + db_name_keyword, + db_name, + filter + } => { + write!(f, "SHOW VIEWS")?; + if let Some(db_name) = db_name { + let keyword = match &db_name_keyword { + Some(Keyword::FROM) => "FROM", + Some(Keyword::IN) => "IN", + _ => "", // unexpected + }; + write!(f, " {} {db_name}", keyword)?; } if let Some(filter) = filter { write!(f, " {filter}")?; @@ -6057,6 +6115,7 @@ pub enum ShowStatementFilter { Like(String), ILike(String), Where(Expr), + NoKeyword(String), } impl fmt::Display for ShowStatementFilter { @@ -6066,6 +6125,7 @@ impl fmt::Display for ShowStatementFilter { Like(pattern) => write!(f, "LIKE '{}'", value::escape_single_quote_string(pattern)), ILike(pattern) => write!(f, "ILIKE {}", value::escape_single_quote_string(pattern)), Where(expr) => write!(f, "WHERE {expr}"), + NoKeyword(pattern) => write!(f, "'{}'", value::escape_single_quote_string(pattern)), } } } diff --git a/src/keywords.rs b/src/keywords.rs index 6182ae176..e98309681 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -217,6 +217,7 @@ define_keywords!( CYCLE, DATA, DATABASE, + DATABASES, DATA_RETENTION_TIME_IN_DAYS, DATE, DATE32, @@ -662,6 +663,7 @@ define_keywords!( SAFE_CAST, SAVEPOINT, SCHEMA, + SCHEMAS, SCOPE, SCROLL, SEARCH, @@ -822,6 +824,7 @@ define_keywords!( VERSION, VERSIONING, VIEW, + VIEWS, VIRTUAL, VOLATILE, WAREHOUSE, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a9a5b1df4..67b717f2d 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9579,6 +9579,8 @@ impl<'a> Parser<'a> { Ok(self.parse_show_columns(extended, full)?) } else if self.parse_keyword(Keyword::TABLES) { Ok(self.parse_show_tables(extended, full)?) + } else if self.parse_keyword(Keyword::VIEWS) { + Ok(self.parse_show_views()?) } else if self.parse_keyword(Keyword::FUNCTIONS) { Ok(self.parse_show_functions()?) } else if extended || full { @@ -9605,6 +9607,10 @@ impl<'a> Parser<'a> { session, global, }) + } else if self.parse_keyword(Keyword::DATABASES) { + self.parse_show_databases() + } else if self.parse_keyword(Keyword::SCHEMAS) { + self.parse_show_schemas() } else { Ok(Statement::ShowVariable { variable: self.parse_identifiers()?, @@ -9612,6 +9618,24 @@ impl<'a> Parser<'a> { } } + fn parse_show_databases(&mut self) -> Result { + let pattern = if self.parse_keyword(Keyword::LIKE) { + Some(self.parse_literal_string()?) + } else { + None + }; + Ok(Statement::ShowDatabases { pattern }) + } + + fn parse_show_schemas(&mut self) -> Result { + let pattern = if self.parse_keyword(Keyword::LIKE) { + Some(self.parse_literal_string()?) + } else { + None + }; + Ok(Statement::ShowSchemas { pattern }) + } + pub fn parse_show_create(&mut self) -> Result { let obj_type = match self.expect_one_of_keywords(&[ Keyword::TABLE, @@ -9667,14 +9691,30 @@ impl<'a> Parser<'a> { extended: bool, full: bool, ) -> Result { - let db_name = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { - Some(_) => Some(self.parse_identifier(false)?), - None => None, - }; + let (db_name_keyword, db_name) = + match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { + Some(keyword) => (Some(keyword), Some(self.parse_identifier(false)?)), + None => (None, None), + }; let filter = self.parse_show_statement_filter()?; Ok(Statement::ShowTables { extended, full, + db_name_keyword, + db_name, + filter, + }) + } + + fn parse_show_views(&mut self) -> Result { + let (db_name_keyword, db_name) = + match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { + Some(keyword) => (Some(keyword), Some(self.parse_identifier(false)?)), + None => (None, None), + }; + let filter = self.parse_show_statement_filter()?; + Ok(Statement::ShowViews { + db_name_keyword, db_name, filter, }) @@ -9704,7 +9744,12 @@ impl<'a> Parser<'a> { } else if self.parse_keyword(Keyword::WHERE) { Ok(Some(ShowStatementFilter::Where(self.parse_expr()?))) } else { - Ok(None) + match self.peek_token().token { + Token::SingleQuotedString(_) | Token::DoubleQuotedString(_) => Ok(Some( + ShowStatementFilter::NoKeyword(self.parse_literal_string()?), + )), + _ => Ok(None), + } } } diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index 10bd374c0..10dda4175 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -534,6 +534,20 @@ fn parse_use() { ); } +#[test] +fn test_show() { + hive().verified_stmt("SHOW DATABASES"); + hive().verified_stmt("SHOW DATABASES LIKE '%abc'"); + hive().verified_stmt("SHOW SCHEMAS"); + hive().verified_stmt("SHOW SCHEMAS LIKE '%abc'"); + hive().verified_stmt("SHOW TABLES"); + hive().verified_stmt("SHOW TABLES IN db1"); + hive().verified_stmt("SHOW TABLES IN db1 'abc'"); + hive().verified_stmt("SHOW VIEWS"); + hive().verified_stmt("SHOW VIEWS IN db1"); + hive().verified_stmt("SHOW VIEWS IN db1 'abc'"); +} + fn hive() -> TestedDialects { TestedDialects::new(vec![Box::new(HiveDialect {})]) } diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index db5b9ec8d..a5e5b5120 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -24,6 +24,7 @@ use matches::assert_matches; use sqlparser::ast::MysqlInsertPriority::{Delayed, HighPriority, LowPriority}; use sqlparser::ast::*; use sqlparser::dialect::{GenericDialect, MySqlDialect}; +use sqlparser::keywords::Keyword; use sqlparser::parser::{ParserError, ParserOptions}; use sqlparser::tokenizer::Token; use test_utils::*; @@ -329,6 +330,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, + db_name_keyword: None, db_name: None, filter: None, } @@ -338,6 +340,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, + db_name_keyword: Some(Keyword::FROM), db_name: Some(Ident::new("mydb")), filter: None, } @@ -347,6 +350,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: true, full: false, + db_name_keyword: None, db_name: None, filter: None, } @@ -356,6 +360,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: true, + db_name_keyword: None, db_name: None, filter: None, } @@ -365,6 +370,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, + db_name_keyword: None, db_name: None, filter: Some(ShowStatementFilter::Like("pattern".into())), } @@ -374,13 +380,15 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, + db_name_keyword: None, db_name: None, filter: Some(ShowStatementFilter::Where( mysql_and_generic().verified_expr("1 = 2") )), } ); - mysql_and_generic().one_statement_parses_to("SHOW TABLES IN mydb", "SHOW TABLES FROM mydb"); + mysql_and_generic().verified_stmt("SHOW TABLES IN mydb"); + mysql_and_generic().verified_stmt( "SHOW TABLES FROM mydb"); } #[test] From a5edbb74017446069ac8f50576dbb189539dc70c Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Wed, 30 Oct 2024 07:25:11 +0200 Subject: [PATCH 2/6] Improve parsing for optional literal string without a keyword indication --- src/parser/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 67b717f2d..596c44557 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9744,12 +9744,12 @@ impl<'a> Parser<'a> { } else if self.parse_keyword(Keyword::WHERE) { Ok(Some(ShowStatementFilter::Where(self.parse_expr()?))) } else { - match self.peek_token().token { - Token::SingleQuotedString(_) | Token::DoubleQuotedString(_) => Ok(Some( - ShowStatementFilter::NoKeyword(self.parse_literal_string()?), - )), - _ => Ok(None), - } + self.maybe_parse(|parser| -> Result { + parser.parse_literal_string() + })? + .map_or(Ok(None), |filter| { + Ok(Some(ShowStatementFilter::NoKeyword(filter))) + }) } } From 9249aa30ca39bb27bb503f188f812098b2d3d90e Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Wed, 30 Oct 2024 07:47:36 +0200 Subject: [PATCH 3/6] Code review comments --- src/ast/mod.rs | 12 ++++++------ tests/sqlparser_hive.rs | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d3262bf70..24cdc9115 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4413,7 +4413,7 @@ impl fmt::Display for Statement { let keyword = match &db_name_keyword { Some(Keyword::FROM) => "FROM", Some(Keyword::IN) => "IN", - _ => "", // unexpected + _ => unreachable!(), }; write!(f, " {} {db_name}", keyword)?; } @@ -4422,17 +4422,17 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::ShowViews { - db_name_keyword, - db_name, - filter + Statement::ShowViews { + db_name_keyword, + db_name, + filter, } => { write!(f, "SHOW VIEWS")?; if let Some(db_name) = db_name { let keyword = match &db_name_keyword { Some(Keyword::FROM) => "FROM", Some(Keyword::IN) => "IN", - _ => "", // unexpected + _ => unreachable!(), }; write!(f, " {} {db_name}", keyword)?; } diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index 10dda4175..027c109e4 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -536,16 +536,16 @@ fn parse_use() { #[test] fn test_show() { - hive().verified_stmt("SHOW DATABASES"); - hive().verified_stmt("SHOW DATABASES LIKE '%abc'"); - hive().verified_stmt("SHOW SCHEMAS"); - hive().verified_stmt("SHOW SCHEMAS LIKE '%abc'"); - hive().verified_stmt("SHOW TABLES"); - hive().verified_stmt("SHOW TABLES IN db1"); - hive().verified_stmt("SHOW TABLES IN db1 'abc'"); - hive().verified_stmt("SHOW VIEWS"); - hive().verified_stmt("SHOW VIEWS IN db1"); - hive().verified_stmt("SHOW VIEWS IN db1 'abc'"); + hive_and_generic().verified_stmt("SHOW DATABASES"); + hive_and_generic().verified_stmt("SHOW DATABASES LIKE '%abc'"); + hive_and_generic().verified_stmt("SHOW SCHEMAS"); + hive_and_generic().verified_stmt("SHOW SCHEMAS LIKE '%abc'"); + hive_and_generic().verified_stmt("SHOW TABLES"); + hive_and_generic().verified_stmt("SHOW TABLES IN db1"); + hive_and_generic().verified_stmt("SHOW TABLES IN db1 'abc'"); + hive_and_generic().verified_stmt("SHOW VIEWS"); + hive_and_generic().verified_stmt("SHOW VIEWS IN db1"); + hive_and_generic().verified_stmt("SHOW VIEWS IN db1 'abc'"); } fn hive() -> TestedDialects { From febab0b5300b8c83b90758470e64abda1b1b2930 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Wed, 30 Oct 2024 08:03:32 +0200 Subject: [PATCH 4/6] Remove redundant whitespace --- tests/sqlparser_mysql.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index a5e5b5120..ee7c4d49a 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -388,7 +388,7 @@ fn parse_show_tables() { } ); mysql_and_generic().verified_stmt("SHOW TABLES IN mydb"); - mysql_and_generic().verified_stmt( "SHOW TABLES FROM mydb"); + mysql_and_generic().verified_stmt("SHOW TABLES FROM mydb"); } #[test] From 407003ac013091ace8b43f4a29ff31f98e891c97 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Thu, 31 Oct 2024 23:34:37 +0100 Subject: [PATCH 5/6] Code review comments, also added support for materialized views --- src/ast/mod.rs | 73 +++++++++++++++++++++++---------------- src/parser/mod.rs | 51 ++++++++++++++------------- tests/sqlparser_common.rs | 21 +++++++++++ tests/sqlparser_hive.rs | 14 -------- tests/sqlparser_mysql.rs | 13 ++++--- 5 files changed, 95 insertions(+), 77 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 24cdc9115..e250c9b30 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -73,9 +73,8 @@ pub use self::value::{ TrimWhereField, Value, }; -use crate::{ - ast::helpers::stmt_data_loading::{DataLoadingOptions, StageLoadSelectItem, StageParamsObject}, - keywords::Keyword, +use crate::ast::helpers::stmt_data_loading::{ + DataLoadingOptions, StageLoadSelectItem, StageParamsObject, }; #[cfg(feature = "visitor")] pub use visitor::*; @@ -2785,19 +2784,18 @@ pub enum Statement { /// ```sql /// SHOW DATABASES [LIKE 'pattern'] /// ``` - ShowDatabases { pattern: Option }, + ShowDatabases { filter: Option }, /// ```sql /// SHOW SCHEMAS [LIKE 'pattern'] /// ``` - ShowSchemas { pattern: Option }, + ShowSchemas { filter: Option }, /// ```sql /// SHOW TABLES /// ``` ShowTables { extended: bool, full: bool, - // The keyword used to indicate the DB name (IN/FROM) - db_name_keyword: Option, + clause: Option, db_name: Option, filter: Option, }, @@ -2805,8 +2803,8 @@ pub enum Statement { /// SHOW VIEWS /// ``` ShowViews { - // The keyword used to indicate the DB name (IN/FROM) - db_name_keyword: Option, + materialized: bool, + clause: Option, db_name: Option, filter: Option, }, @@ -4382,24 +4380,24 @@ impl fmt::Display for Statement { } Ok(()) } - Statement::ShowDatabases { pattern } => { + Statement::ShowDatabases { filter } => { write!(f, "SHOW DATABASES")?; - if let Some(pattern) = pattern { - write!(f, " LIKE '{}'", pattern)?; + if let Some(filter) = filter { + write!(f, " {filter}")?; } Ok(()) } - Statement::ShowSchemas { pattern } => { + Statement::ShowSchemas { filter } => { write!(f, "SHOW SCHEMAS")?; - if let Some(pattern) = pattern { - write!(f, " LIKE '{}'", pattern)?; + if let Some(filter) = filter { + write!(f, " {filter}")?; } Ok(()) } Statement::ShowTables { extended, full, - db_name_keyword, + clause: show_clause, db_name, filter, } => { @@ -4409,13 +4407,11 @@ impl fmt::Display for Statement { extended = if *extended { "EXTENDED " } else { "" }, full = if *full { "FULL " } else { "" }, )?; + if let Some(show_clause) = show_clause { + write!(f, " {show_clause}")?; + } if let Some(db_name) = db_name { - let keyword = match &db_name_keyword { - Some(Keyword::FROM) => "FROM", - Some(Keyword::IN) => "IN", - _ => unreachable!(), - }; - write!(f, " {} {db_name}", keyword)?; + write!(f, " {db_name}")?; } if let Some(filter) = filter { write!(f, " {filter}")?; @@ -4423,18 +4419,17 @@ impl fmt::Display for Statement { Ok(()) } Statement::ShowViews { - db_name_keyword, + materialized, + clause: show_clause, db_name, filter, } => { - write!(f, "SHOW VIEWS")?; + write!(f, "SHOW {}VIEWS", if *materialized { "MATERIALIZED " } else { "" })?; + if let Some(show_clause) = show_clause { + write!(f, " {show_clause}")?; + } if let Some(db_name) = db_name { - let keyword = match &db_name_keyword { - Some(Keyword::FROM) => "FROM", - Some(Keyword::IN) => "IN", - _ => unreachable!(), - }; - write!(f, " {} {db_name}", keyword)?; + write!(f, " {db_name}")?; } if let Some(filter) = filter { write!(f, " {filter}")?; @@ -6130,6 +6125,24 @@ impl fmt::Display for ShowStatementFilter { } } +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub enum ShowClause { + IN, + FROM, +} + +impl fmt::Display for ShowClause { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use ShowClause::*; + match self { + FROM => write!(f, "FROM"), + IN => write!(f, "IN"), + } + } +} + /// Sqlite specific syntax /// /// See [Sqlite documentation](https://sqlite.org/lang_conflict.html) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 596c44557..7e5749c44 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9579,8 +9579,10 @@ impl<'a> Parser<'a> { Ok(self.parse_show_columns(extended, full)?) } else if self.parse_keyword(Keyword::TABLES) { Ok(self.parse_show_tables(extended, full)?) + } else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEWS]) { + Ok(self.parse_show_views(true)?) } else if self.parse_keyword(Keyword::VIEWS) { - Ok(self.parse_show_views()?) + Ok(self.parse_show_views(false)?) } else if self.parse_keyword(Keyword::FUNCTIONS) { Ok(self.parse_show_functions()?) } else if extended || full { @@ -9619,21 +9621,15 @@ impl<'a> Parser<'a> { } fn parse_show_databases(&mut self) -> Result { - let pattern = if self.parse_keyword(Keyword::LIKE) { - Some(self.parse_literal_string()?) - } else { - None - }; - Ok(Statement::ShowDatabases { pattern }) + Ok(Statement::ShowDatabases { + filter: self.parse_show_statement_filter()?, + }) } fn parse_show_schemas(&mut self) -> Result { - let pattern = if self.parse_keyword(Keyword::LIKE) { - Some(self.parse_literal_string()?) - } else { - None - }; - Ok(Statement::ShowSchemas { pattern }) + Ok(Statement::ShowSchemas { + filter: self.parse_show_statement_filter()?, + }) } pub fn parse_show_create(&mut self) -> Result { @@ -9691,30 +9687,33 @@ impl<'a> Parser<'a> { extended: bool, full: bool, ) -> Result { - let (db_name_keyword, db_name) = - match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { - Some(keyword) => (Some(keyword), Some(self.parse_identifier(false)?)), - None => (None, None), - }; + let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) + { + Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)), + Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)), + _ => (None, None), + }; let filter = self.parse_show_statement_filter()?; Ok(Statement::ShowTables { extended, full, - db_name_keyword, + clause, db_name, filter, }) } - fn parse_show_views(&mut self) -> Result { - let (db_name_keyword, db_name) = - match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { - Some(keyword) => (Some(keyword), Some(self.parse_identifier(false)?)), - None => (None, None), - }; + fn parse_show_views(&mut self, materialized: bool) -> Result { + let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) + { + Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)), + Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)), + _ => (None, None), + }; let filter = self.parse_show_statement_filter()?; Ok(Statement::ShowViews { - db_name_keyword, + materialized, + clause, db_name, filter, }) diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index a2eb5070d..20d709bd1 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -11378,3 +11378,24 @@ fn test_try_convert() { all_dialects_where(|d| d.supports_try_convert() && !d.convert_type_before_value()); dialects.verified_expr("TRY_CONVERT('foo', VARCHAR(MAX))"); } + +#[test] +fn test_show_dbs_schemas_tables_views() { + verified_stmt("SHOW DATABASES"); + verified_stmt("SHOW DATABASES LIKE '%abc'"); + verified_stmt("SHOW SCHEMAS"); + verified_stmt("SHOW SCHEMAS LIKE '%abc'"); + verified_stmt("SHOW TABLES"); + verified_stmt("SHOW TABLES IN db1"); + verified_stmt("SHOW TABLES IN db1 'abc'"); + verified_stmt("SHOW VIEWS"); + verified_stmt("SHOW VIEWS IN db1"); + verified_stmt("SHOW VIEWS IN db1 'abc'"); + verified_stmt("SHOW VIEWS FROM db1"); + verified_stmt("SHOW VIEWS FROM db1 'abc'"); + verified_stmt("SHOW MATERIALIZED VIEWS"); + verified_stmt("SHOW MATERIALIZED VIEWS IN db1"); + verified_stmt("SHOW MATERIALIZED VIEWS IN db1 'abc'"); + verified_stmt("SHOW MATERIALIZED VIEWS FROM db1"); + verified_stmt("SHOW MATERIALIZED VIEWS FROM db1 'abc'"); +} \ No newline at end of file diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index 027c109e4..10bd374c0 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -534,20 +534,6 @@ fn parse_use() { ); } -#[test] -fn test_show() { - hive_and_generic().verified_stmt("SHOW DATABASES"); - hive_and_generic().verified_stmt("SHOW DATABASES LIKE '%abc'"); - hive_and_generic().verified_stmt("SHOW SCHEMAS"); - hive_and_generic().verified_stmt("SHOW SCHEMAS LIKE '%abc'"); - hive_and_generic().verified_stmt("SHOW TABLES"); - hive_and_generic().verified_stmt("SHOW TABLES IN db1"); - hive_and_generic().verified_stmt("SHOW TABLES IN db1 'abc'"); - hive_and_generic().verified_stmt("SHOW VIEWS"); - hive_and_generic().verified_stmt("SHOW VIEWS IN db1"); - hive_and_generic().verified_stmt("SHOW VIEWS IN db1 'abc'"); -} - fn hive() -> TestedDialects { TestedDialects::new(vec![Box::new(HiveDialect {})]) } diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index ee7c4d49a..4b9354e85 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -24,7 +24,6 @@ use matches::assert_matches; use sqlparser::ast::MysqlInsertPriority::{Delayed, HighPriority, LowPriority}; use sqlparser::ast::*; use sqlparser::dialect::{GenericDialect, MySqlDialect}; -use sqlparser::keywords::Keyword; use sqlparser::parser::{ParserError, ParserOptions}; use sqlparser::tokenizer::Token; use test_utils::*; @@ -330,7 +329,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, - db_name_keyword: None, + clause: None, db_name: None, filter: None, } @@ -340,7 +339,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, - db_name_keyword: Some(Keyword::FROM), + clause: Some(ShowClause::FROM), db_name: Some(Ident::new("mydb")), filter: None, } @@ -350,7 +349,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: true, full: false, - db_name_keyword: None, + clause: None, db_name: None, filter: None, } @@ -360,7 +359,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: true, - db_name_keyword: None, + clause: None, db_name: None, filter: None, } @@ -370,7 +369,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, - db_name_keyword: None, + clause: None, db_name: None, filter: Some(ShowStatementFilter::Like("pattern".into())), } @@ -380,7 +379,7 @@ fn parse_show_tables() { Statement::ShowTables { extended: false, full: false, - db_name_keyword: None, + clause: None, db_name: None, filter: Some(ShowStatementFilter::Where( mysql_and_generic().verified_expr("1 = 2") From 07a651ae432fed267bbb07e2da1fa28564e9c128 Mon Sep 17 00:00:00 2001 From: Yoav Cohen Date: Fri, 1 Nov 2024 17:32:50 +0100 Subject: [PATCH 6/6] formatting --- src/ast/mod.rs | 6 +++++- src/parser/mod.rs | 6 ++---- tests/sqlparser_common.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e250c9b30..b2672552e 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -4424,7 +4424,11 @@ impl fmt::Display for Statement { db_name, filter, } => { - write!(f, "SHOW {}VIEWS", if *materialized { "MATERIALIZED " } else { "" })?; + write!( + f, + "SHOW {}VIEWS", + if *materialized { "MATERIALIZED " } else { "" } + )?; if let Some(show_clause) = show_clause { write!(f, " {show_clause}")?; } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 7e5749c44..c4b92ba4e 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9687,8 +9687,7 @@ impl<'a> Parser<'a> { extended: bool, full: bool, ) -> Result { - let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) - { + let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)), Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)), _ => (None, None), @@ -9704,8 +9703,7 @@ impl<'a> Parser<'a> { } fn parse_show_views(&mut self, materialized: bool) -> Result { - let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) - { + let (clause, db_name) = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { Some(Keyword::FROM) => (Some(ShowClause::FROM), Some(self.parse_identifier(false)?)), Some(Keyword::IN) => (Some(ShowClause::IN), Some(self.parse_identifier(false)?)), _ => (None, None), diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 20d709bd1..4016e5a69 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -11398,4 +11398,4 @@ fn test_show_dbs_schemas_tables_views() { verified_stmt("SHOW MATERIALIZED VIEWS IN db1 'abc'"); verified_stmt("SHOW MATERIALIZED VIEWS FROM db1"); verified_stmt("SHOW MATERIALIZED VIEWS FROM db1 'abc'"); -} \ No newline at end of file +}