diff --git a/src/dialect/clickhouse.rs b/src/dialect/clickhouse.rs index 155b827e1..34940467a 100644 --- a/src/dialect/clickhouse.rs +++ b/src/dialect/clickhouse.rs @@ -33,4 +33,8 @@ impl Dialect for ClickHouseDialect { fn supports_select_wildcard_except(&self) -> bool { true } + + fn describe_requires_table_keyword(&self) -> bool { + true + } } diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 4c7572af0..df3022adc 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -485,9 +485,20 @@ pub trait Dialect: Debug + Any { } } + /// Returns the precedence when the precedence is otherwise unknown fn prec_unknown(&self) -> u8 { 0 } + + /// Returns true if this dialect requires the `TABLE` keyword after `DESCRIBE` + /// + /// Defaults to false. + /// + /// If true, the following statement is valid: `DESCRIBE TABLE my_table` + /// If false, the following statements are valid: `DESCRIBE my_table` and `DESCRIBE table` + fn describe_requires_table_keyword(&self) -> bool { + false + } } /// This represents the operators for which precedence must be defined diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index b22eb236f..89508c3bb 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -154,6 +154,10 @@ impl Dialect for SnowflakeDialect { _ => None, } } + + fn describe_requires_table_keyword(&self) -> bool { + true + } } /// Parse snowflake create table statement. diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 900ad9081..2632d807a 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -8185,15 +8185,20 @@ impl<'a> Parser<'a> { format, }), _ => { - let mut hive_format = None; - match self.parse_one_of_keywords(&[Keyword::EXTENDED, Keyword::FORMATTED]) { - Some(Keyword::EXTENDED) => hive_format = Some(HiveDescribeFormat::Extended), - Some(Keyword::FORMATTED) => hive_format = Some(HiveDescribeFormat::Formatted), - _ => {} - } + let hive_format = + match self.parse_one_of_keywords(&[Keyword::EXTENDED, Keyword::FORMATTED]) { + Some(Keyword::EXTENDED) => Some(HiveDescribeFormat::Extended), + Some(Keyword::FORMATTED) => Some(HiveDescribeFormat::Formatted), + _ => None, + }; + + let has_table_keyword = if self.dialect.describe_requires_table_keyword() { + // only allow to use TABLE keyword for DESC|DESCRIBE statement + self.parse_keyword(Keyword::TABLE) + } else { + false + }; - // only allow to use TABLE keyword for DESC|DESCRIBE statement - let has_table_keyword = self.parse_keyword(Keyword::TABLE); let table_name = self.parse_object_name(false)?; Ok(Statement::ExplainTable { describe_alias, diff --git a/tests/sqlparser_clickhouse.rs b/tests/sqlparser_clickhouse.rs index 4c96febab..931899ff9 100644 --- a/tests/sqlparser_clickhouse.rs +++ b/tests/sqlparser_clickhouse.rs @@ -1376,6 +1376,36 @@ fn parse_select_table_function_settings() { } } +#[test] +fn explain_describe() { + clickhouse().verified_stmt("DESCRIBE test.table"); + clickhouse().verified_stmt("DESCRIBE TABLE test.table"); +} + +#[test] +fn explain_desc() { + clickhouse().verified_stmt("DESC test.table"); + clickhouse().verified_stmt("DESC TABLE test.table"); +} + +#[test] +fn parse_explain_table() { + match clickhouse().verified_stmt("EXPLAIN TABLE test_identifier") { + Statement::ExplainTable { + describe_alias, + hive_format, + has_table_keyword, + table_name, + } => { + pretty_assertions::assert_eq!(describe_alias, DescribeAlias::Explain); + pretty_assertions::assert_eq!(hive_format, None); + pretty_assertions::assert_eq!(has_table_keyword, true); + pretty_assertions::assert_eq!("test_identifier", table_name.to_string()); + } + _ => panic!("Unexpected Statement, must be ExplainTable"), + } +} + fn clickhouse() -> TestedDialects { TestedDialects { dialects: vec![Box::new(ClickHouseDialect {})], diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 896a043c4..517e978b4 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -4301,29 +4301,16 @@ fn parse_explain_table() { validate_explain("EXPLAIN test_identifier", DescribeAlias::Explain, false); validate_explain("DESCRIBE test_identifier", DescribeAlias::Describe, false); validate_explain("DESC test_identifier", DescribeAlias::Desc, false); - validate_explain( - "EXPLAIN TABLE test_identifier", - DescribeAlias::Explain, - true, - ); - validate_explain( - "DESCRIBE TABLE test_identifier", - DescribeAlias::Describe, - true, - ); - validate_explain("DESC TABLE test_identifier", DescribeAlias::Desc, true); } #[test] fn explain_describe() { verified_stmt("DESCRIBE test.table"); - verified_stmt("DESCRIBE TABLE test.table"); } #[test] fn explain_desc() { verified_stmt("DESC test.table"); - verified_stmt("DESC TABLE test.table"); } #[test] diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index 5f0b9f575..157dad060 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -21,7 +21,7 @@ use sqlparser::ast::{ UnaryOperator, Value, }; use sqlparser::dialect::{GenericDialect, HiveDialect, MsSqlDialect}; -use sqlparser::parser::{ParserError, ParserOptions}; +use sqlparser::parser::ParserError; use sqlparser::test_utils::*; #[test] @@ -35,18 +35,11 @@ fn parse_table_create() { hive().verified_stmt(serdeproperties); } -fn generic(options: Option) -> TestedDialects { - TestedDialects { - dialects: vec![Box::new(GenericDialect {})], - options, - } -} - #[test] fn parse_describe() { - let describe = r#"DESCRIBE namespace.`table`"#; - hive().verified_stmt(describe); - generic(None).verified_stmt(describe); + hive_and_generic().verified_stmt(r#"DESCRIBE namespace.`table`"#); + hive_and_generic().verified_stmt(r#"DESCRIBE namespace.table"#); + hive_and_generic().verified_stmt(r#"DESCRIBE table"#); } #[test] @@ -414,3 +407,10 @@ fn hive() -> TestedDialects { options: None, } } + +fn hive_and_generic() -> TestedDialects { + TestedDialects { + dialects: vec![Box::new(HiveDialect {}), Box::new(GenericDialect {})], + options: None, + } +} diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index a331c7df9..a4f29c04f 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -2292,3 +2292,33 @@ fn test_parse_position() { snowflake().verified_query("SELECT position('an', 'banana', 1)"); snowflake().verified_query("SELECT n, h, POSITION(n IN h) FROM pos"); } + +#[test] +fn explain_describe() { + snowflake().verified_stmt("DESCRIBE test.table"); + snowflake().verified_stmt("DESCRIBE TABLE test.table"); +} + +#[test] +fn explain_desc() { + snowflake().verified_stmt("DESC test.table"); + snowflake().verified_stmt("DESC TABLE test.table"); +} + +#[test] +fn parse_explain_table() { + match snowflake().verified_stmt("EXPLAIN TABLE test_identifier") { + Statement::ExplainTable { + describe_alias, + hive_format, + has_table_keyword, + table_name, + } => { + assert_eq!(describe_alias, DescribeAlias::Explain); + assert_eq!(hive_format, None); + assert_eq!(has_table_keyword, true); + assert_eq!("test_identifier", table_name.to_string()); + } + _ => panic!("Unexpected Statement, must be ExplainTable"), + } +}