Skip to content

Commit

Permalink
Support EXPLAIN / DESCR / DESCRIBE [FORMATTED | EXTENDED] (#1156
Browse files Browse the repository at this point in the history
)

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
  • Loading branch information
jonathanlehto and alamb authored Mar 1, 2024
1 parent 991dbab commit ef46680
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 30 deletions.
67 changes: 52 additions & 15 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2436,22 +2436,24 @@ pub enum Statement {
id: u64,
},
/// ```sql
/// EXPLAIN TABLE
/// [EXPLAIN | DESC | DESCRIBE] TABLE
/// ```
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/explain.html>
ExplainTable {
/// If true, query used the MySQL `DESCRIBE` alias for explain
describe_alias: bool,
/// `EXPLAIN | DESC | DESCRIBE`
describe_alias: DescribeAlias,
/// Hive style `FORMATTED | EXTENDED`
hive_format: Option<HiveDescribeFormat>,
/// Table name
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
table_name: ObjectName,
},
/// ```sql
/// [EXPLAIN | DESCRIBE <select statement>
/// [EXPLAIN | DESC | DESCRIBE] <statement>
/// ```
Explain {
// If true, query used the MySQL `DESCRIBE` alias for explain
describe_alias: bool,
/// `EXPLAIN | DESC | DESCRIBE`
describe_alias: DescribeAlias,
/// Carry out the command and show actual run times and other statistics.
analyze: bool,
// Display additional information regarding the plan.
Expand Down Expand Up @@ -2611,12 +2613,13 @@ impl fmt::Display for Statement {
}
Statement::ExplainTable {
describe_alias,
hive_format,
table_name,
} => {
if *describe_alias {
write!(f, "DESCRIBE ")?;
} else {
write!(f, "EXPLAIN ")?;
write!(f, "{describe_alias} ")?;

if let Some(format) = hive_format {
write!(f, "{} ", format)?;
}

write!(f, "{table_name}")
Expand All @@ -2628,11 +2631,7 @@ impl fmt::Display for Statement {
statement,
format,
} => {
if *describe_alias {
write!(f, "DESCRIBE ")?;
} else {
write!(f, "EXPLAIN ")?;
}
write!(f, "{describe_alias} ")?;

if *analyze {
write!(f, "ANALYZE ")?;
Expand Down Expand Up @@ -4925,6 +4924,44 @@ impl fmt::Display for HiveDelimiter {
}
}

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum HiveDescribeFormat {
Extended,
Formatted,
}

impl fmt::Display for HiveDescribeFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use HiveDescribeFormat::*;
f.write_str(match self {
Extended => "EXTENDED",
Formatted => "FORMATTED",
})
}
}

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum DescribeAlias {
Describe,
Explain,
Desc,
}

impl fmt::Display for DescribeAlias {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use DescribeAlias::*;
f.write_str(match self {
Describe => "DESCRIBE",
Explain => "EXPLAIN",
Desc => "DESC",
})
}
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
Expand Down
1 change: 1 addition & 0 deletions src/keywords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ define_keywords!(
FORCE_QUOTE,
FOREIGN,
FORMAT,
FORMATTED,
FORWARD,
FRAME_ROW,
FREE,
Expand Down
18 changes: 15 additions & 3 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,9 @@ impl<'a> Parser<'a> {
Token::Word(w) => match w.keyword {
Keyword::KILL => Ok(self.parse_kill()?),
Keyword::FLUSH => Ok(self.parse_flush()?),
Keyword::DESCRIBE => Ok(self.parse_explain(true)?),
Keyword::EXPLAIN => Ok(self.parse_explain(false)?),
Keyword::DESC => Ok(self.parse_explain(DescribeAlias::Desc)?),
Keyword::DESCRIBE => Ok(self.parse_explain(DescribeAlias::Describe)?),
Keyword::EXPLAIN => Ok(self.parse_explain(DescribeAlias::Explain)?),
Keyword::ANALYZE => Ok(self.parse_analyze()?),
Keyword::SELECT | Keyword::WITH | Keyword::VALUES => {
self.prev_token();
Expand Down Expand Up @@ -6805,7 +6806,10 @@ impl<'a> Parser<'a> {
Ok(Statement::Kill { modifier, id })
}

pub fn parse_explain(&mut self, describe_alias: bool) -> Result<Statement, ParserError> {
pub fn parse_explain(
&mut self,
describe_alias: DescribeAlias,
) -> Result<Statement, ParserError> {
let analyze = self.parse_keyword(Keyword::ANALYZE);
let verbose = self.parse_keyword(Keyword::VERBOSE);
let mut format = None;
Expand All @@ -6825,9 +6829,17 @@ 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 table_name = self.parse_object_name(false)?;
Ok(Statement::ExplainTable {
describe_alias,
hive_format,
table_name,
})
}
Expand Down
37 changes: 25 additions & 12 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3932,19 +3932,32 @@ fn run_explain_analyze(

#[test]
fn parse_explain_table() {
let validate_explain = |query: &str, expected_describe_alias: bool| match verified_stmt(query) {
Statement::ExplainTable {
describe_alias,
table_name,
} => {
assert_eq!(describe_alias, expected_describe_alias);
assert_eq!("test_identifier", table_name.to_string());
}
_ => panic!("Unexpected Statement, must be ExplainTable"),
};
let validate_explain =
|query: &str, expected_describe_alias: DescribeAlias| match verified_stmt(query) {
Statement::ExplainTable {
describe_alias,
hive_format,
table_name,
} => {
assert_eq!(describe_alias, expected_describe_alias);
assert_eq!(hive_format, None);
assert_eq!("test_identifier", table_name.to_string());
}
_ => panic!("Unexpected Statement, must be ExplainTable"),
};

validate_explain("EXPLAIN test_identifier", DescribeAlias::Explain);
validate_explain("DESCRIBE test_identifier", DescribeAlias::Describe);
}

validate_explain("EXPLAIN test_identifier", false);
validate_explain("DESCRIBE test_identifier", true);
#[test]
fn explain_describe() {
verified_stmt("DESCRIBE test.table");
}

#[test]
fn explain_desc() {
verified_stmt("DESC test.table");
}

#[test]
Expand Down
10 changes: 10 additions & 0 deletions tests/sqlparser_hive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ fn parse_describe() {
generic(None).verified_stmt(describe);
}

#[test]
fn explain_describe_formatted() {
hive().verified_stmt("DESCRIBE FORMATTED test.table");
}

#[test]
fn explain_describe_extended() {
hive().verified_stmt("DESCRIBE EXTENDED test.table");
}

#[test]
fn parse_insert_overwrite() {
let insert_partitions = r#"INSERT OVERWRITE TABLE db.new_table PARTITION (a = '1', b) SELECT a, b, c FROM db.table"#;
Expand Down

0 comments on commit ef46680

Please sign in to comment.