mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-01 19:57:30 +00:00
Support EXPLAIN
/ DESCR
/ DESCRIBE
[FORMATTED | EXTENDED]
(#1156)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
991dbab755
commit
ef4668075b
5 changed files with 103 additions and 30 deletions
|
@ -2436,22 +2436,24 @@ pub enum Statement {
|
||||||
id: u64,
|
id: u64,
|
||||||
},
|
},
|
||||||
/// ```sql
|
/// ```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>
|
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/explain.html>
|
||||||
ExplainTable {
|
ExplainTable {
|
||||||
/// If true, query used the MySQL `DESCRIBE` alias for explain
|
/// `EXPLAIN | DESC | DESCRIBE`
|
||||||
describe_alias: bool,
|
describe_alias: DescribeAlias,
|
||||||
|
/// Hive style `FORMATTED | EXTENDED`
|
||||||
|
hive_format: Option<HiveDescribeFormat>,
|
||||||
/// Table name
|
/// Table name
|
||||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||||
table_name: ObjectName,
|
table_name: ObjectName,
|
||||||
},
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// [EXPLAIN | DESCRIBE <select statement>
|
/// [EXPLAIN | DESC | DESCRIBE] <statement>
|
||||||
/// ```
|
/// ```
|
||||||
Explain {
|
Explain {
|
||||||
// If true, query used the MySQL `DESCRIBE` alias for explain
|
/// `EXPLAIN | DESC | DESCRIBE`
|
||||||
describe_alias: bool,
|
describe_alias: DescribeAlias,
|
||||||
/// Carry out the command and show actual run times and other statistics.
|
/// Carry out the command and show actual run times and other statistics.
|
||||||
analyze: bool,
|
analyze: bool,
|
||||||
// Display additional information regarding the plan.
|
// Display additional information regarding the plan.
|
||||||
|
@ -2611,12 +2613,13 @@ impl fmt::Display for Statement {
|
||||||
}
|
}
|
||||||
Statement::ExplainTable {
|
Statement::ExplainTable {
|
||||||
describe_alias,
|
describe_alias,
|
||||||
|
hive_format,
|
||||||
table_name,
|
table_name,
|
||||||
} => {
|
} => {
|
||||||
if *describe_alias {
|
write!(f, "{describe_alias} ")?;
|
||||||
write!(f, "DESCRIBE ")?;
|
|
||||||
} else {
|
if let Some(format) = hive_format {
|
||||||
write!(f, "EXPLAIN ")?;
|
write!(f, "{} ", format)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "{table_name}")
|
write!(f, "{table_name}")
|
||||||
|
@ -2628,11 +2631,7 @@ impl fmt::Display for Statement {
|
||||||
statement,
|
statement,
|
||||||
format,
|
format,
|
||||||
} => {
|
} => {
|
||||||
if *describe_alias {
|
write!(f, "{describe_alias} ")?;
|
||||||
write!(f, "DESCRIBE ")?;
|
|
||||||
} else {
|
|
||||||
write!(f, "EXPLAIN ")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if *analyze {
|
if *analyze {
|
||||||
write!(f, "ANALYZE ")?;
|
write!(f, "ANALYZE ")?;
|
||||||
|
@ -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)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
|
|
@ -303,6 +303,7 @@ define_keywords!(
|
||||||
FORCE_QUOTE,
|
FORCE_QUOTE,
|
||||||
FOREIGN,
|
FOREIGN,
|
||||||
FORMAT,
|
FORMAT,
|
||||||
|
FORMATTED,
|
||||||
FORWARD,
|
FORWARD,
|
||||||
FRAME_ROW,
|
FRAME_ROW,
|
||||||
FREE,
|
FREE,
|
||||||
|
|
|
@ -464,8 +464,9 @@ impl<'a> Parser<'a> {
|
||||||
Token::Word(w) => match w.keyword {
|
Token::Word(w) => match w.keyword {
|
||||||
Keyword::KILL => Ok(self.parse_kill()?),
|
Keyword::KILL => Ok(self.parse_kill()?),
|
||||||
Keyword::FLUSH => Ok(self.parse_flush()?),
|
Keyword::FLUSH => Ok(self.parse_flush()?),
|
||||||
Keyword::DESCRIBE => Ok(self.parse_explain(true)?),
|
Keyword::DESC => Ok(self.parse_explain(DescribeAlias::Desc)?),
|
||||||
Keyword::EXPLAIN => Ok(self.parse_explain(false)?),
|
Keyword::DESCRIBE => Ok(self.parse_explain(DescribeAlias::Describe)?),
|
||||||
|
Keyword::EXPLAIN => Ok(self.parse_explain(DescribeAlias::Explain)?),
|
||||||
Keyword::ANALYZE => Ok(self.parse_analyze()?),
|
Keyword::ANALYZE => Ok(self.parse_analyze()?),
|
||||||
Keyword::SELECT | Keyword::WITH | Keyword::VALUES => {
|
Keyword::SELECT | Keyword::WITH | Keyword::VALUES => {
|
||||||
self.prev_token();
|
self.prev_token();
|
||||||
|
@ -6805,7 +6806,10 @@ impl<'a> Parser<'a> {
|
||||||
Ok(Statement::Kill { modifier, id })
|
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 analyze = self.parse_keyword(Keyword::ANALYZE);
|
||||||
let verbose = self.parse_keyword(Keyword::VERBOSE);
|
let verbose = self.parse_keyword(Keyword::VERBOSE);
|
||||||
let mut format = None;
|
let mut format = None;
|
||||||
|
@ -6825,9 +6829,17 @@ impl<'a> Parser<'a> {
|
||||||
format,
|
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)?;
|
let table_name = self.parse_object_name(false)?;
|
||||||
Ok(Statement::ExplainTable {
|
Ok(Statement::ExplainTable {
|
||||||
describe_alias,
|
describe_alias,
|
||||||
|
hive_format,
|
||||||
table_name,
|
table_name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3932,19 +3932,32 @@ fn run_explain_analyze(
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_explain_table() {
|
fn parse_explain_table() {
|
||||||
let validate_explain = |query: &str, expected_describe_alias: bool| match verified_stmt(query) {
|
let validate_explain =
|
||||||
Statement::ExplainTable {
|
|query: &str, expected_describe_alias: DescribeAlias| match verified_stmt(query) {
|
||||||
describe_alias,
|
Statement::ExplainTable {
|
||||||
table_name,
|
describe_alias,
|
||||||
} => {
|
hive_format,
|
||||||
assert_eq!(describe_alias, expected_describe_alias);
|
table_name,
|
||||||
assert_eq!("test_identifier", table_name.to_string());
|
} => {
|
||||||
}
|
assert_eq!(describe_alias, expected_describe_alias);
|
||||||
_ => panic!("Unexpected Statement, must be ExplainTable"),
|
assert_eq!(hive_format, None);
|
||||||
};
|
assert_eq!("test_identifier", table_name.to_string());
|
||||||
|
}
|
||||||
|
_ => panic!("Unexpected Statement, must be ExplainTable"),
|
||||||
|
};
|
||||||
|
|
||||||
validate_explain("EXPLAIN test_identifier", false);
|
validate_explain("EXPLAIN test_identifier", DescribeAlias::Explain);
|
||||||
validate_explain("DESCRIBE test_identifier", true);
|
validate_explain("DESCRIBE test_identifier", DescribeAlias::Describe);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn explain_describe() {
|
||||||
|
verified_stmt("DESCRIBE test.table");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn explain_desc() {
|
||||||
|
verified_stmt("DESC test.table");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -48,6 +48,16 @@ fn parse_describe() {
|
||||||
generic(None).verified_stmt(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]
|
#[test]
|
||||||
fn parse_insert_overwrite() {
|
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"#;
|
let insert_partitions = r#"INSERT OVERWRITE TABLE db.new_table PARTITION (a = '1', b) SELECT a, b, c FROM db.table"#;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue