diff --git a/src/ast/mod.rs b/src/ast/mod.rs index b2dcc655d..e7c202046 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2776,9 +2776,7 @@ pub enum Statement { ShowColumns { extended: bool, full: bool, - show_in: Option, - filter: Option, - filter_position: ShowStatementFilterPosition, + show_options: ShowStatementOptions, }, /// ```sql /// SHOW DATABASES @@ -2786,11 +2784,7 @@ pub enum Statement { ShowDatabases { terse: bool, history: bool, - filter: Option, - show_in: Option, - starts_with: Option, - limit: Option, - from: Option, + show_options: ShowStatementOptions, }, /// ```sql /// SHOW SCHEMAS @@ -2798,11 +2792,7 @@ pub enum Statement { ShowSchemas { terse: bool, history: bool, - filter: Option, - show_in: Option, - starts_with: Option, - limit: Option, - from: Option, + show_options: ShowStatementOptions, }, /// ```sql /// SHOW TABLES @@ -2813,12 +2803,7 @@ pub enum Statement { extended: bool, full: bool, external: bool, - filter: Option, - show_in: Option, - starts_with: Option, - limit: Option, - from: Option, - filter_position: ShowStatementFilterPosition, + show_options: ShowStatementOptions, }, /// ```sql /// SHOW VIEWS @@ -2826,12 +2811,7 @@ pub enum Statement { ShowViews { terse: bool, materialized: bool, - filter: Option, - show_in: Option, - starts_with: Option, - limit: Option, - from: Option, - filter_position: ShowStatementFilterPosition, + show_options: ShowStatementOptions, }, /// ```sql /// SHOW COLLATION @@ -4411,113 +4391,39 @@ impl fmt::Display for Statement { Statement::ShowColumns { extended, full, - show_in, - filter, - filter_position, + show_options, } => { write!( f, - "SHOW {extended}{full}COLUMNS", + "SHOW {extended}{full}COLUMNS{show_options}", extended = if *extended { "EXTENDED " } else { "" }, full = if *full { "FULL " } else { "" }, )?; - if filter_position == &ShowStatementFilterPosition::InTheMiddle { - if let Some(filter) = filter { - write!(f, " {filter}")?; - } - if let Some(show_in) = show_in { - write!(f, " {show_in}")?; - } - } - if filter_position == &ShowStatementFilterPosition::AtTheEnd { - if let Some(show_in) = show_in { - write!(f, " {show_in}")?; - } - if let Some(filter) = filter { - write!(f, " {filter}")?; - } - } Ok(()) } Statement::ShowDatabases { terse, history, - filter, - show_in, - starts_with, - limit, - from, + show_options, } => { write!( f, - "SHOW {terse}DATABASES", - terse = if *terse { "TERSE " } else { "" } - )?; - write!( - f, - "{history}{filter}{show_in}{starts_with}{limit}{from}", + "SHOW {terse}DATABASES{history}{show_options}", + terse = if *terse { "TERSE " } else { "" }, history = if *history { " HISTORY" } else { "" }, - filter = match filter.as_ref() { - Some(l) => format!(" {l}"), - None => String::new(), - }, - show_in = match show_in { - Some(i) => format!(" {i}"), - None => String::new(), - }, - starts_with = match starts_with.as_ref() { - Some(s) => format!(" STARTS WITH {s}"), - None => String::new(), - }, - limit = match limit.as_ref() { - Some(l) => format!(" LIMIT {l}"), - None => String::new(), - }, - from = match from.as_ref() { - Some(f) => format!(" FROM {f}"), - None => String::new(), - } )?; Ok(()) } Statement::ShowSchemas { terse, history, - filter, - show_in, - starts_with, - limit, - from, + show_options, } => { write!( f, - "SHOW {terse}SCHEMAS", - terse = if *terse { "TERSE " } else { "" } - )?; - write!( - f, - "{history}{filter}{show_in}{starts_with}{limit}{from}", + "SHOW {terse}SCHEMAS{history}{show_options}", + terse = if *terse { "TERSE " } else { "" }, history = if *history { " HISTORY" } else { "" }, - filter = match filter.as_ref() { - Some(l) => format!(" {l}"), - None => String::new(), - }, - show_in = match show_in { - Some(i) => format!(" {i}"), - None => String::new(), - }, - starts_with = match starts_with.as_ref() { - Some(s) => format!(" STARTS WITH {s}"), - None => String::new(), - }, - limit = match limit.as_ref() { - Some(l) => format!(" LIMIT {l}"), - None => String::new(), - }, - from = match from.as_ref() { - Some(f) => format!(" FROM {f}"), - None => String::new(), - } )?; Ok(()) } @@ -4527,110 +4433,30 @@ impl fmt::Display for Statement { extended, full, external, - filter, - show_in, - starts_with, - limit, - from, - filter_position, + show_options, } => { write!( f, - "SHOW {terse}{extended}{full}{external}TABLES", + "SHOW {terse}{extended}{full}{external}TABLES{history}{show_options}", terse = if *terse { "TERSE " } else { "" }, extended = if *extended { "EXTENDED " } else { "" }, full = if *full { "FULL " } else { "" }, external = if *external { "EXTERNAL " } else { "" }, - )?; - write!( - f, - "{history}{like_in_the_middle}{show_in}{starts_with}{limit}{from}{like_at_the_end}", history = if *history { " HISTORY" } else { "" }, - like_in_the_middle = if *filter_position - == ShowStatementFilterPosition::InTheMiddle - && filter.is_some() - { - format!(" {}", filter.as_ref().unwrap()) - } else { - String::new() - }, - show_in = match show_in { - Some(i) => format!(" {i}"), - None => String::new(), - }, - starts_with = match starts_with.as_ref() { - Some(s) => format!(" STARTS WITH {s}"), - None => String::new(), - }, - limit = match limit.as_ref() { - Some(l) => format!(" LIMIT {l}"), - None => String::new(), - }, - from = match from.as_ref() { - Some(f) => format!(" FROM {f}"), - None => String::new(), - }, - like_at_the_end = if *filter_position - == ShowStatementFilterPosition::AtTheEnd - && filter.is_some() - { - format!(" {}", filter.as_ref().unwrap()) - } else { - String::new() - }, - ) + )?; + Ok(()) } Statement::ShowViews { terse, materialized, - filter, - show_in, - starts_with, - limit, - from, - filter_position, + show_options, } => { write!( f, - "SHOW {terse}{materialized}VIEWS", + "SHOW {terse}{materialized}VIEWS{show_options}", terse = if *terse { "TERSE " } else { "" }, materialized = if *materialized { "MATERIALIZED " } else { "" } )?; - write!( - f, - "{like_in_the_middle}{show_in}{starts_with}{limit}{from}{like_at_the_end}", - like_in_the_middle = if *filter_position - == ShowStatementFilterPosition::InTheMiddle - && filter.is_some() - { - format!(" {}", filter.as_ref().unwrap()) - } else { - String::new() - }, - show_in = match show_in { - Some(i) => format!(" {i}"), - None => String::new(), - }, - starts_with = match starts_with.as_ref() { - Some(s) => format!(" STARTS WITH {s}"), - None => String::new(), - }, - limit = match limit.as_ref() { - Some(l) => format!(" LIMIT {l}"), - None => String::new(), - }, - from = match from.as_ref() { - Some(f) => format!(" FROM {f}"), - None => String::new(), - }, - like_at_the_end = if *filter_position == ShowStatementFilterPosition::AtTheEnd - && filter.is_some() - { - format!(" {}", filter.as_ref().unwrap()) - } else { - String::new() - } - )?; Ok(()) } Statement::ShowFunctions { filter } => { @@ -7528,10 +7354,54 @@ impl Display for UtilityOption { } } +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +pub struct ShowStatementOptions { + pub show_in: Option, + pub starts_with: Option, + pub limit: Option, + pub limit_from: Option, + pub filter_position: Option, +} + +impl Display for ShowStatementOptions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (life_in_infix, like_in_suffix) = match &self.filter_position { + Some(ShowStatementFilterPosition::Infix(filter)) => { + (format!(" {filter}"), "".to_string()) + } + Some(ShowStatementFilterPosition::Suffix(filter)) => { + ("".to_string(), format!(" {filter}")) + } + None => ("".to_string(), "".to_string()), + }; + write!( + f, + "{life_in_infix}{show_in}{starts_with}{limit}{from}{like_in_suffix}", + show_in = match &self.show_in { + Some(i) => format!(" {i}"), + None => String::new(), + }, + starts_with = match &self.starts_with { + Some(s) => format!(" STARTS WITH {s}"), + None => String::new(), + }, + limit = match &self.limit { + Some(l) => format!(" LIMIT {l}"), + None => String::new(), + }, + from = match &self.limit_from { + Some(f) => format!(" FROM {f}"), + None => String::new(), + } + )?; + Ok(()) + } +} + #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] pub enum ShowStatementFilterPosition { - InTheMiddle, // Snowflake like - AtTheEnd, // MySQL like + Infix(ShowStatementFilter), // For example: SHOW COLUMNS LIKE '%name%' IN TABLE tbl + Suffix(ShowStatementFilter), // For example: SHOW COLUMNS IN tbl LIKE '%name%' } #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] diff --git a/src/parser/mod.rs b/src/parser/mod.rs index cd0fddc2b..2234af6de 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9647,37 +9647,21 @@ impl<'a> Parser<'a> { fn parse_show_databases(&mut self, terse: bool) -> Result { let history = self.parse_keyword(Keyword::HISTORY); - let filter = self.parse_show_statement_filter()?; - let show_in = self.parse_show_opt_in()?; - let starts_with = self.parse_show_opt_starts_with()?; - let limit = self.parse_show_opt_limit()?; - let from = self.parse_show_opt_from()?; + let show_options = self.parse_show_stmt_options()?; Ok(Statement::ShowDatabases { terse, history, - filter, - show_in, - starts_with, - limit, - from, + show_options, }) } fn parse_show_schemas(&mut self, terse: bool) -> Result { let history = self.parse_keyword(Keyword::HISTORY); - let filter = self.parse_show_statement_filter()?; - let show_in = self.parse_show_opt_in()?; - let starts_with = self.parse_show_opt_starts_with()?; - let limit = self.parse_show_opt_limit()?; - let from = self.parse_show_opt_from()?; + let show_options = self.parse_show_stmt_options()?; Ok(Statement::ShowSchemas { terse, history, - filter, - show_in, - starts_with, - limit, - from, + show_options, }) } @@ -9711,24 +9695,11 @@ impl<'a> Parser<'a> { extended: bool, full: bool, ) -> Result { - let filter; - let filter_position; - let show_in; - if self.dialect.supports_show_like_before_in() { - filter = self.parse_show_statement_filter()?; - filter_position = ShowStatementFilterPosition::InTheMiddle; - show_in = self.parse_show_opt_in()?; - } else { - show_in = self.parse_show_opt_in()?; - filter = self.parse_show_statement_filter()?; - filter_position = ShowStatementFilterPosition::AtTheEnd; - } + let show_options = self.parse_show_stmt_options()?; Ok(Statement::ShowColumns { extended, full, - show_in, - filter, - filter_position, + show_options, }) } @@ -9740,34 +9711,14 @@ impl<'a> Parser<'a> { external: bool, ) -> Result { let history = !external && self.parse_keyword(Keyword::HISTORY); - let filter; - let show_in; - let filter_position; - if self.dialect.supports_show_like_before_in() { - filter = self.parse_show_statement_filter()?; - //YOAV: here we have a problem, the hint is DB-dependent (table in a schemas or some other object) - show_in = self.parse_show_opt_in()?; - filter_position = ShowStatementFilterPosition::InTheMiddle; - } else { - show_in = self.parse_show_opt_in()?; - filter = self.parse_show_statement_filter()?; - filter_position = ShowStatementFilterPosition::AtTheEnd; - } - let starts_with = self.parse_show_opt_starts_with()?; - let limit = self.parse_show_opt_limit()?; - let from = self.parse_show_opt_from()?; + let show_options = self.parse_show_stmt_options()?; Ok(Statement::ShowTables { terse, history, extended, full, external, - filter, - show_in, - starts_with, - limit, - from, - filter_position, + show_options, }) } @@ -9776,30 +9727,11 @@ impl<'a> Parser<'a> { terse: bool, materialized: bool, ) -> Result { - let filter; - let show_in; - let filter_position; - if self.dialect.supports_show_like_before_in() { - filter = self.parse_show_statement_filter()?; - show_in = self.parse_show_opt_in()?; - filter_position = ShowStatementFilterPosition::InTheMiddle; - } else { - show_in = self.parse_show_opt_in()?; - filter = self.parse_show_statement_filter()?; - filter_position = ShowStatementFilterPosition::AtTheEnd; - } - let starts_with = self.parse_show_opt_starts_with()?; - let limit = self.parse_show_opt_limit()?; - let from = self.parse_show_opt_from()?; + let show_options = self.parse_show_stmt_options()?; Ok(Statement::ShowViews { materialized, terse, - filter, - filter_position, - show_in, - starts_with, - limit, - from, + show_options, }) } @@ -12379,134 +12311,121 @@ impl<'a> Parser<'a> { false } - /// Look for an expected keyword, without consuming it - fn peek_keyword(&self, expected: Keyword) -> bool { - match self.peek_token().token { - Token::Word(w) => expected == w.keyword, - _ => false, + /// Look for all of the expected keywords in sequence, without consuming them + fn peek_keywords(&mut self, expected: &[Keyword]) -> bool { + let index = self.index; + for kw in expected { + if !self.parse_keyword(*kw) { + self.index = index; + return false; + } } + self.index = index; + true } - /// Look for one of expected keyword, without consuming it - fn peek_keywords(&self, expected: &[Keyword]) -> bool { - for kw in expected { - if self.peek_keyword(*kw) { - return true; + fn parse_show_stmt_options(&mut self) -> Result { + let show_in; + let mut filter_position = None; + if self.dialect.supports_show_like_before_in() { + if let Some(filter) = self.parse_show_statement_filter()? { + filter_position = Some(ShowStatementFilterPosition::Infix(filter)); + } + show_in = self.maybe_parse_show_stmt_in()?; + } else { + show_in = self.maybe_parse_show_stmt_in()?; + if let Some(filter) = self.parse_show_statement_filter()? { + filter_position = Some(ShowStatementFilterPosition::Suffix(filter)); } } - false + let starts_with = self.maybe_parse_show_stmt_starts_with()?; + let limit = self.maybe_parse_show_stmt_limit()?; + let from = self.maybe_parse_show_stmt_from()?; + Ok(ShowStatementOptions { + filter_position, + show_in, + starts_with, + limit, + limit_from: from, + }) } - fn parse_show_opt_in(&mut self) -> Result, ParserError> { + fn maybe_parse_show_stmt_in(&mut self) -> Result, ParserError> { let clause = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) { Some(Keyword::FROM) => ShowStatementInClause::FROM, Some(Keyword::IN) => ShowStatementInClause::IN, _ => return Ok(None), }; - if self.parse_keyword(Keyword::DATABASE) { - if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) { - Ok(Some(ShowStatementIn { - clause, - parent_type: Some(ShowStatementInParentType::Database), - parent_name: None, - })) - } else { - let parent_name = match self.parse_object_name(false) { - Ok(n) => Some(n), - Err(_) => None, - }; - Ok(Some(ShowStatementIn { - clause, - parent_type: Some(ShowStatementInParentType::Database), - parent_name, - })) + let (parent_type, parent_name) = match self.parse_one_of_keywords(&[ + Keyword::ACCOUNT, + Keyword::DATABASE, + Keyword::SCHEMA, + Keyword::TABLE, + Keyword::VIEW, + ]) { + Some(Keyword::DATABASE) if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) => { + (Some(ShowStatementInParentType::Database), None) } - } else if self.parse_keyword(Keyword::SCHEMA) { - if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) { - Ok(Some(ShowStatementIn { - clause, - parent_type: Some(ShowStatementInParentType::Schema), - parent_name: None, - })) - } else { + Some(Keyword::SCHEMA) if self.peek_keywords(&[Keyword::STARTS, Keyword::WITH]) => { + (Some(ShowStatementInParentType::Schema), None) + } + Some(parent_kw) => { let parent_name = match self.parse_object_name(false) { Ok(n) => Some(n), - Err(_) => None, + _ => None, }; - Ok(Some(ShowStatementIn { - clause, - parent_type: Some(ShowStatementInParentType::Schema), - parent_name, - })) + match parent_kw { + Keyword::ACCOUNT => (Some(ShowStatementInParentType::Account), parent_name), + Keyword::DATABASE => (Some(ShowStatementInParentType::Database), parent_name), + Keyword::SCHEMA => (Some(ShowStatementInParentType::Schema), parent_name), + Keyword::TABLE => (Some(ShowStatementInParentType::Table), parent_name), + Keyword::VIEW => (Some(ShowStatementInParentType::View), parent_name), + _ => unreachable!(), + } } - } else if self.parse_keyword(Keyword::ACCOUNT) { - let parent_name = match self.parse_object_name(false) { - Ok(n) => Some(n), - Err(_) => None, - }; - Ok(Some(ShowStatementIn { - clause, - parent_type: Some(ShowStatementInParentType::Account), - parent_name, - })) - } else if self.parse_keyword(Keyword::TABLE) { - let parent_name = match self.parse_object_name(false) { - Ok(n) => Some(n), - Err(_) => None, - }; - Ok(Some(ShowStatementIn { - clause, - parent_type: Some(ShowStatementInParentType::Table), - parent_name, - })) - } else if self.parse_keyword(Keyword::VIEW) { - let parent_name = match self.parse_object_name(false) { - Ok(n) => Some(n), - Err(_) => None, - }; - Ok(Some(ShowStatementIn { - clause, - parent_type: Some(ShowStatementInParentType::View), - parent_name, - })) - } else { - // Parsing MySQL style FROM tbl_name FROM db_name - // which is equivalent to FROM tbl_name.db_name - let mut parent_name = self.parse_object_name(false)?; - if self - .parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) - .is_some() - { - parent_name.0.insert(0, self.parse_identifier(false)?); + None => { + // Parsing MySQL style FROM tbl_name FROM db_name + // which is equivalent to FROM tbl_name.db_name + let mut parent_name = self.parse_object_name(false)?; + if self + .parse_one_of_keywords(&[Keyword::FROM, Keyword::IN]) + .is_some() + { + parent_name.0.insert(0, self.parse_identifier(false)?); + } + (None, Some(parent_name)) } + }; - Ok(Some(ShowStatementIn { - clause, - parent_type: None, - parent_name: Some(parent_name), - })) - } + Ok(Some(ShowStatementIn { + clause, + parent_type, + parent_name, + })) } - fn parse_show_opt_starts_with(&mut self) -> Result, ParserError> { - match self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) { - true => Ok(Some(self.parse_value()?)), - false => Ok(None), + fn maybe_parse_show_stmt_starts_with(&mut self) -> Result, ParserError> { + if self.parse_keywords(&[Keyword::STARTS, Keyword::WITH]) { + Ok(Some(self.parse_value()?)) + } else { + Ok(None) } } - fn parse_show_opt_limit(&mut self) -> Result, ParserError> { - match self.parse_keyword(Keyword::LIMIT) { - true => Ok(self.parse_limit()?), - false => Ok(None), + fn maybe_parse_show_stmt_limit(&mut self) -> Result, ParserError> { + if self.parse_keyword(Keyword::LIMIT) { + Ok(self.parse_limit()?) + } else { + Ok(None) } } - fn parse_show_opt_from(&mut self) -> Result, ParserError> { - match self.parse_keyword(Keyword::FROM) { - true => Ok(Some(self.parse_value()?)), - false => Ok(None), + fn maybe_parse_show_stmt_from(&mut self) -> Result, ParserError> { + if self.parse_keyword(Keyword::FROM) { + Ok(Some(self.parse_value()?)) + } else { + Ok(None) } } } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index d9d39aec0..65eb2b0c6 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -11428,47 +11428,43 @@ fn test_try_convert() { #[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'"); - - // SHOW is parsed the same by all dialects except the position of the LIKE option - all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt("SHOW TABLES"); - all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt("SHOW TABLES"); - all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt("SHOW TABLES IN db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt("SHOW TABLES IN db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW TABLES IN db1 'abc'"); - - all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt("SHOW VIEWS"); - all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt("SHOW VIEWS"); - all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt("SHOW VIEWS IN db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW VIEWS IN db1 'abc'"); - all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt("SHOW VIEWS FROM db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt("SHOW VIEWS FROM db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW VIEWS FROM db1 'abc'"); - - all_dialects_where(|d| d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS"); - all_dialects_where(|d| d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS IN db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS IN db1"); - all_dialects_where(|d| d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS FROM db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS FROM db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS IN db1 'abc'"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS FROM db1"); - all_dialects_where(|d| !d.supports_show_like_before_in()) - .verified_stmt("SHOW MATERIALIZED VIEWS FROM db1 'abc'"); + // These statements are parsed the same by all dialects + let stmts = vec![ + "SHOW DATABASES", + "SHOW SCHEMAS", + "SHOW TABLES", + "SHOW VIEWS", + "SHOW TABLES IN db1", + "SHOW VIEWS FROM db1", + "SHOW MATERIALIZED VIEWS", + "SHOW MATERIALIZED VIEWS IN db1", + "SHOW MATERIALIZED VIEWS FROM db1", + ]; + for stmt in stmts { + verified_stmt(stmt); + } + + // These statements are parsed the same by all dialects + // except for how the parser interprets the location of + // LIKE option (infix/suffix) + let stmts = vec!["SHOW DATABASES LIKE '%abc'", "SHOW SCHEMAS LIKE '%abc'"]; + for stmt in stmts { + all_dialects_where(|d| d.supports_show_like_before_in()).verified_stmt(stmt); + all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt(stmt); + } + + // These statements are only parsed by dialects that + // support the LIKE option in the suffix + let stmts = vec![ + "SHOW TABLES IN db1 'abc'", + "SHOW VIEWS IN db1 'abc'", + "SHOW VIEWS FROM db1 'abc'", + "SHOW MATERIALIZED VIEWS IN db1 'abc'", + "SHOW MATERIALIZED VIEWS FROM db1 'abc'", + ]; + for stmt in stmts { + all_dialects_where(|d| !d.supports_show_like_before_in()).verified_stmt(stmt); + } } #[test] diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 9cb326b92..8bdf63ae2 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -228,13 +228,17 @@ fn parse_show_columns() { Statement::ShowColumns { extended: false, full: false, - show_in: Some(ShowStatementIn { - clause: ShowStatementInClause::FROM, - parent_type: None, - parent_name: Some(ObjectName(vec![Ident::new("mytable")])), - }), - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd, + show_options: ShowStatementOptions { + show_in: Some(ShowStatementIn { + clause: ShowStatementInClause::FROM, + parent_type: None, + parent_name: Some(ObjectName(vec![Ident::new("mytable")])), + }), + filter_position: None, + limit_from: None, + limit: None, + starts_with: None, + } } ); assert_eq!( @@ -242,13 +246,17 @@ fn parse_show_columns() { Statement::ShowColumns { extended: false, full: false, - show_in: Some(ShowStatementIn { - clause: ShowStatementInClause::FROM, - parent_type: None, - parent_name: Some(ObjectName(vec![Ident::new("mydb"), Ident::new("mytable")])), - }), - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd, + show_options: ShowStatementOptions { + show_in: Some(ShowStatementIn { + clause: ShowStatementInClause::FROM, + parent_type: None, + parent_name: Some(ObjectName(vec![Ident::new("mydb"), Ident::new("mytable")])), + }), + filter_position: None, + limit_from: None, + limit: None, + starts_with: None, + } } ); assert_eq!( @@ -256,13 +264,17 @@ fn parse_show_columns() { Statement::ShowColumns { extended: true, full: false, - show_in: Some(ShowStatementIn { - clause: ShowStatementInClause::FROM, - parent_type: None, - parent_name: Some(ObjectName(vec![Ident::new("mytable")])), - }), - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd, + show_options: ShowStatementOptions { + show_in: Some(ShowStatementIn { + clause: ShowStatementInClause::FROM, + parent_type: None, + parent_name: Some(ObjectName(vec![Ident::new("mytable")])), + }), + filter_position: None, + limit_from: None, + limit: None, + starts_with: None, + } } ); assert_eq!( @@ -270,13 +282,17 @@ fn parse_show_columns() { Statement::ShowColumns { extended: false, full: true, - show_in: Some(ShowStatementIn { - clause: ShowStatementInClause::FROM, - parent_type: None, - parent_name: Some(ObjectName(vec![Ident::new("mytable")])), - }), - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd, + show_options: ShowStatementOptions { + show_in: Some(ShowStatementIn { + clause: ShowStatementInClause::FROM, + parent_type: None, + parent_name: Some(ObjectName(vec![Ident::new("mytable")])), + }), + filter_position: None, + limit_from: None, + limit: None, + starts_with: None, + } } ); assert_eq!( @@ -284,13 +300,19 @@ fn parse_show_columns() { Statement::ShowColumns { extended: false, full: false, - show_in: Some(ShowStatementIn { - clause: ShowStatementInClause::FROM, - parent_type: None, - parent_name: Some(ObjectName(vec![Ident::new("mytable")])), - }), - filter: Some(ShowStatementFilter::Like("pattern".into())), - filter_position: ShowStatementFilterPosition::AtTheEnd, + show_options: ShowStatementOptions { + show_in: Some(ShowStatementIn { + clause: ShowStatementInClause::FROM, + parent_type: None, + parent_name: Some(ObjectName(vec![Ident::new("mytable")])), + }), + filter_position: Some(ShowStatementFilterPosition::Suffix( + ShowStatementFilter::Like("pattern".into()) + )), + limit_from: None, + limit: None, + starts_with: None, + } } ); assert_eq!( @@ -298,15 +320,19 @@ fn parse_show_columns() { Statement::ShowColumns { extended: false, full: false, - show_in: Some(ShowStatementIn { - clause: ShowStatementInClause::FROM, - parent_type: None, - parent_name: Some(ObjectName(vec![Ident::new("mytable")])), - }), - filter: Some(ShowStatementFilter::Where( - mysql_and_generic().verified_expr("1 = 2") - )), - filter_position: ShowStatementFilterPosition::AtTheEnd, + show_options: ShowStatementOptions { + show_in: Some(ShowStatementIn { + clause: ShowStatementInClause::FROM, + parent_type: None, + parent_name: Some(ObjectName(vec![Ident::new("mytable")])), + }), + filter_position: Some(ShowStatementFilterPosition::Suffix( + ShowStatementFilter::Where(mysql_and_generic().verified_expr("1 = 2")) + )), + limit_from: None, + limit: None, + starts_with: None, + } } ); mysql_and_generic() @@ -361,12 +387,13 @@ fn parse_show_tables() { extended: false, full: false, external: false, - starts_with: None, - limit: None, - from: None, - show_in: None, - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd + show_options: ShowStatementOptions { + starts_with: None, + limit: None, + limit_from: None, + show_in: None, + filter_position: None + } } ); assert_eq!( @@ -377,16 +404,17 @@ fn parse_show_tables() { extended: false, full: false, external: false, - starts_with: None, - limit: None, - from: None, - show_in: Some(ShowStatementIn { - clause: ShowStatementInClause::FROM, - parent_type: None, - parent_name: Some(ObjectName(vec![Ident::new("mydb")])), - }), - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd + show_options: ShowStatementOptions { + starts_with: None, + limit: None, + limit_from: None, + show_in: Some(ShowStatementIn { + clause: ShowStatementInClause::FROM, + parent_type: None, + parent_name: Some(ObjectName(vec![Ident::new("mydb")])), + }), + filter_position: None + } } ); assert_eq!( @@ -397,12 +425,13 @@ fn parse_show_tables() { extended: true, full: false, external: false, - starts_with: None, - limit: None, - from: None, - show_in: None, - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd + show_options: ShowStatementOptions { + starts_with: None, + limit: None, + limit_from: None, + show_in: None, + filter_position: None + } } ); assert_eq!( @@ -413,12 +442,13 @@ fn parse_show_tables() { extended: false, full: true, external: false, - starts_with: None, - limit: None, - from: None, - show_in: None, - filter: None, - filter_position: ShowStatementFilterPosition::AtTheEnd + show_options: ShowStatementOptions { + starts_with: None, + limit: None, + limit_from: None, + show_in: None, + filter_position: None + } } ); assert_eq!( @@ -429,12 +459,15 @@ fn parse_show_tables() { extended: false, full: false, external: false, - starts_with: None, - limit: None, - from: None, - show_in: None, - filter: Some(ShowStatementFilter::Like("pattern".into())), - filter_position: ShowStatementFilterPosition::AtTheEnd + show_options: ShowStatementOptions { + starts_with: None, + limit: None, + limit_from: None, + show_in: None, + filter_position: Some(ShowStatementFilterPosition::Suffix( + ShowStatementFilter::Like("pattern".into()) + )) + } } ); assert_eq!( @@ -445,14 +478,15 @@ fn parse_show_tables() { extended: false, full: false, external: false, - starts_with: None, - limit: None, - from: None, - show_in: None, - filter: Some(ShowStatementFilter::Where( - mysql_and_generic().verified_expr("1 = 2") - )), - filter_position: ShowStatementFilterPosition::AtTheEnd + show_options: ShowStatementOptions { + starts_with: None, + limit: None, + limit_from: None, + show_in: None, + filter_position: Some(ShowStatementFilterPosition::Suffix( + ShowStatementFilter::Where(mysql_and_generic().verified_expr("1 = 2")) + )) + } } ); mysql_and_generic().verified_stmt("SHOW TABLES IN mydb");