mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-17 10:42:55 +00:00
feat: explain custom statement (#7058)
* feat: explain tql cte Signed-off-by: discord9 <discord9@163.com> * chore: unused Signed-off-by: discord9 <discord9@163.com> * fix: analyze format Signed-off-by: discord9 <discord9@163.com> * Update src/sql/src/statements/statement.rs Co-authored-by: Yingwen <realevenyag@gmail.com> Signed-off-by: discord9 <discord9@163.com> * test: sqlness Signed-off-by: discord9 <discord9@163.com> * pcr Signed-off-by: discord9 <discord9@163.com> --------- Signed-off-by: discord9 <discord9@163.com> Co-authored-by: Yingwen <realevenyag@gmail.com>
This commit is contained in:
@@ -13,37 +13,47 @@
|
||||
// limitations under the License.
|
||||
|
||||
use snafu::ResultExt;
|
||||
use sqlparser::ast::DescribeAlias;
|
||||
use sqlparser::keywords::Keyword;
|
||||
|
||||
use crate::error::{self, Result};
|
||||
use crate::parser::ParserContext;
|
||||
use crate::statements::explain::Explain;
|
||||
use crate::statements::explain::ExplainStatement;
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
/// EXPLAIN statement parser implementation
|
||||
impl ParserContext<'_> {
|
||||
/// explain that support use our own parser to parse the inner statement
|
||||
pub(crate) fn parse_explain(&mut self) -> Result<Statement> {
|
||||
let explain_statement = self
|
||||
.parser
|
||||
.parse_explain(DescribeAlias::Explain)
|
||||
.with_context(|_| error::UnexpectedSnafu {
|
||||
expected: "a query statement",
|
||||
actual: self.peek_token_as_string(),
|
||||
})?;
|
||||
let analyze = self.parser.parse_keyword(Keyword::ANALYZE);
|
||||
let verbose = self.parser.parse_keyword(Keyword::VERBOSE);
|
||||
let format =
|
||||
if self.parser.parse_keyword(Keyword::FORMAT) {
|
||||
Some(self.parser.parse_analyze_format().with_context(|_| {
|
||||
error::UnexpectedSnafu {
|
||||
expected: "analyze format",
|
||||
actual: self.peek_token_as_string(),
|
||||
}
|
||||
})?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Statement::Explain(Box::new(Explain::try_from(
|
||||
explain_statement,
|
||||
)?)))
|
||||
let statement = self.parse_statement()?;
|
||||
|
||||
let explain = ExplainStatement {
|
||||
analyze,
|
||||
verbose,
|
||||
format,
|
||||
statement: Box::new(statement),
|
||||
};
|
||||
Ok(Statement::Explain(Box::new(explain)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sqlparser::ast::helpers::attached_token::AttachedToken;
|
||||
use sqlparser::ast::{
|
||||
GroupByExpr, Query as SpQuery, SelectFlavor, Statement as SpStatement,
|
||||
WildcardAdditionalOptions,
|
||||
};
|
||||
use sqlparser::ast::{GroupByExpr, Query as SpQuery, SelectFlavor, WildcardAdditionalOptions};
|
||||
|
||||
use super::*;
|
||||
use crate::dialect::GreptimeDbDialect;
|
||||
@@ -97,31 +107,30 @@ mod tests {
|
||||
flavor: SelectFlavor::Standard,
|
||||
};
|
||||
|
||||
let sp_statement = SpStatement::Query(Box::new(SpQuery {
|
||||
with: None,
|
||||
body: Box::new(sqlparser::ast::SetExpr::Select(Box::new(select))),
|
||||
order_by: None,
|
||||
limit: None,
|
||||
limit_by: vec![],
|
||||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
settings: None,
|
||||
format_clause: None,
|
||||
}));
|
||||
let sp_query = Box::new(
|
||||
SpQuery {
|
||||
with: None,
|
||||
body: Box::new(sqlparser::ast::SetExpr::Select(Box::new(select))),
|
||||
order_by: None,
|
||||
limit: None,
|
||||
limit_by: vec![],
|
||||
offset: None,
|
||||
fetch: None,
|
||||
locks: vec![],
|
||||
for_clause: None,
|
||||
settings: None,
|
||||
format_clause: None,
|
||||
}
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let explain = Explain::try_from(SpStatement::Explain {
|
||||
describe_alias: DescribeAlias::Explain,
|
||||
let explain = ExplainStatement {
|
||||
analyze: false,
|
||||
verbose: false,
|
||||
statement: Box::new(sp_statement),
|
||||
format: None,
|
||||
query_plan: false,
|
||||
options: None,
|
||||
estimate: false,
|
||||
})
|
||||
.unwrap();
|
||||
statement: Box::new(Statement::Query(sp_query)),
|
||||
};
|
||||
|
||||
assert_eq!(stmts[0], Statement::Explain(Box::new(explain)))
|
||||
}
|
||||
|
||||
@@ -15,36 +15,44 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use serde::Serialize;
|
||||
use sqlparser::ast::{AnalyzeFormat, Statement as SpStatement};
|
||||
use sqlparser::ast::AnalyzeFormat;
|
||||
use sqlparser_derive::{Visit, VisitMut};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::statements::statement::Statement;
|
||||
|
||||
/// Explain statement.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Visit, VisitMut, Serialize)]
|
||||
pub struct Explain {
|
||||
pub inner: SpStatement,
|
||||
pub struct ExplainStatement {
|
||||
/// `EXPLAIN ANALYZE ..`
|
||||
pub analyze: bool,
|
||||
/// `EXPLAIN .. VERBOSE ..`
|
||||
pub verbose: bool,
|
||||
/// `EXPLAIN .. FORMAT `
|
||||
pub format: Option<AnalyzeFormat>,
|
||||
/// The statement to analyze. Note this is a Greptime [`Statement`] (not a
|
||||
/// [`sqlparser::ast::Statement`] so that we can use
|
||||
/// Greptime specific statements
|
||||
pub statement: Box<Statement>,
|
||||
}
|
||||
|
||||
impl Explain {
|
||||
impl ExplainStatement {
|
||||
pub fn format(&self) -> Option<AnalyzeFormat> {
|
||||
match self.inner {
|
||||
SpStatement::Explain { format, .. } => format,
|
||||
_ => None,
|
||||
}
|
||||
self.format
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SpStatement> for Explain {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: SpStatement) -> Result<Self, Self::Error> {
|
||||
Ok(Explain { inner: value })
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Explain {
|
||||
impl Display for ExplainStatement {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.inner)
|
||||
write!(f, "EXPLAIN")?;
|
||||
if self.analyze {
|
||||
write!(f, " ANALYZE")?;
|
||||
}
|
||||
if self.verbose {
|
||||
write!(f, " VERBOSE")?;
|
||||
}
|
||||
if let Some(format) = &self.format {
|
||||
write!(f, " FORMAT {}", format)?;
|
||||
}
|
||||
write!(f, " {}", self.statement)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use crate::statements::cursor::{CloseCursor, DeclareCursor, FetchCursor};
|
||||
use crate::statements::delete::Delete;
|
||||
use crate::statements::describe::DescribeTable;
|
||||
use crate::statements::drop::{DropDatabase, DropFlow, DropTable, DropView};
|
||||
use crate::statements::explain::Explain;
|
||||
use crate::statements::explain::ExplainStatement;
|
||||
use crate::statements::insert::Insert;
|
||||
use crate::statements::kill::Kill;
|
||||
use crate::statements::query::Query;
|
||||
@@ -126,7 +126,7 @@ pub enum Statement {
|
||||
// DESCRIBE TABLE
|
||||
DescribeTable(DescribeTable),
|
||||
// EXPLAIN QUERY
|
||||
Explain(Box<Explain>),
|
||||
Explain(Box<ExplainStatement>),
|
||||
// COPY
|
||||
Copy(Copy),
|
||||
// Telemetry Query Language
|
||||
@@ -301,7 +301,6 @@ impl TryFrom<&Statement> for DfStatement {
|
||||
fn try_from(s: &Statement) -> Result<Self, Self::Error> {
|
||||
let s = match s {
|
||||
Statement::Query(query) => SpStatement::Query(Box::new(query.inner.clone())),
|
||||
Statement::Explain(explain) => explain.inner.clone(),
|
||||
Statement::Insert(insert) => insert.inner.clone(),
|
||||
Statement::Delete(delete) => delete.inner.clone(),
|
||||
_ => {
|
||||
|
||||
Reference in New Issue
Block a user