Skip to content

Commit c0e80b1

Browse files
authored
feat(query): support explain(DECORRELATED,verbose) (#17518)
* support explain(DECORRELATED,verbose) * test * fix Signed-off-by: coldWater <[email protected]> --------- Signed-off-by: coldWater <[email protected]>
1 parent 39d8c44 commit c0e80b1

File tree

8 files changed

+239
-115
lines changed

8 files changed

+239
-115
lines changed

src/query/ast/src/ast/statements/explain.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ pub enum ExplainKind {
2626
Pipeline,
2727
Fragments,
2828

29-
// `EXPLAIN RAW` and `EXPLAIN OPTIMIZED` will be deprecated in the future,
30-
// use explain options instead
29+
/// `EXPLAIN RAW` will be deprecated in the future, use EXPLAIN(LOGICAL) instead
3130
Raw,
32-
// `EXPLAIN DECORRELATED` will show the plan after subquery decorrelation
31+
/// `EXPLAIN DECORRELATED` will show the plan after subquery decorrelation
32+
/// `EXPLAIN DECORRELATED` will be deprecated in the future, use `EXPLAIN(LOGICAL, DECORRELATED)` instead
3333
Decorrelated,
34+
/// `EXPLAIN OPTIMIZED` will be deprecated in the future, use `EXPLAIN(LOGICAL, OPTIMIZED)` instead
3435
Optimized,
3536

3637
Plan,
@@ -43,9 +44,10 @@ pub enum ExplainKind {
4344
Graphical,
4445
}
4546

46-
#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
47+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Drive, DriveMut)]
4748
pub enum ExplainOption {
4849
Verbose,
4950
Logical,
5051
Optimized,
52+
Decorrelated,
5153
}

src/query/ast/src/ast/statements/statement.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::ast::write_comma_separated_list;
3434
use crate::ast::CreateOption;
3535
use crate::ast::Identifier;
3636
use crate::ast::Query;
37+
use crate::Span;
3738

3839
// SQL statement
3940
#[allow(clippy::large_enum_variant)]
@@ -46,7 +47,7 @@ pub enum Statement {
4647
},
4748
Explain {
4849
kind: ExplainKind,
49-
options: Vec<ExplainOption>,
50+
options: (Span, Vec<ExplainOption>),
5051
query: Box<Statement>,
5152
},
5253
ExplainAnalyze {
@@ -586,7 +587,7 @@ impl Display for Statement {
586587
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
587588
match self {
588589
Statement::Explain {
589-
options,
590+
options: (_, options),
590591
kind,
591592
query,
592593
} => {
@@ -602,6 +603,7 @@ impl Display for Statement {
602603
ExplainOption::Verbose => "VERBOSE",
603604
ExplainOption::Logical => "LOGICAL",
604605
ExplainOption::Optimized => "OPTIMIZED",
606+
ExplainOption::Decorrelated => "DECORRELATED",
605607
}
606608
})
607609
.join(", ")

src/query/ast/src/parser/statement.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use crate::parser::stream::stream_table;
4040
use crate::parser::token::*;
4141
use crate::parser::Error;
4242
use crate::parser::ErrorKind;
43+
use crate::span::merge_span;
4344

4445
pub enum ShowGrantOption {
4546
PrincipalIdentity(PrincipalIdentity),
@@ -78,7 +79,9 @@ pub fn statement_body(i: Input) -> IResult<Statement> {
7879
None => ExplainKind::Plan,
7980
_ => unreachable!(),
8081
},
81-
options: options.as_ref().map_or(vec![], |(_, opts, _)| opts.clone()),
82+
options: options
83+
.map(|(a, opts, b)| (merge_span(Some(a.span), Some(b.span)), opts))
84+
.unwrap_or_default(),
8285
query: Box::new(statement.stmt),
8386
})
8487
},
@@ -4796,12 +4799,13 @@ pub fn alter_password_action(i: Input) -> IResult<AlterPasswordAction> {
47964799
pub fn explain_option(i: Input) -> IResult<ExplainOption> {
47974800
map(
47984801
rule! {
4799-
VERBOSE | LOGICAL | OPTIMIZED
4802+
VERBOSE | LOGICAL | OPTIMIZED | DECORRELATED
48004803
},
48014804
|opt| match &opt.kind {
48024805
VERBOSE => ExplainOption::Verbose,
48034806
LOGICAL => ExplainOption::Logical,
48044807
OPTIMIZED => ExplainOption::Optimized,
4808+
DECORRELATED => ExplainOption::Decorrelated,
48054809
_ => unreachable!(),
48064810
},
48074811
)(i)

src/query/ast/tests/it/testdata/stmt.txt

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,10 @@ EXPLAIN PIPELINE SELECT a FROM b
745745
---------- AST ------------
746746
Explain {
747747
kind: Pipeline,
748-
options: [],
748+
options: (
749+
None,
750+
[],
751+
),
749752
query: Query(
750753
Query {
751754
span: Some(
@@ -830,7 +833,10 @@ EXPLAIN REPLACE INTO test ON CONFLICT (c) SELECT sum(c) AS c FROM source GROUP B
830833
---------- AST ------------
831834
Explain {
832835
kind: Plan,
833-
options: [],
836+
options: (
837+
None,
838+
[],
839+
),
834840
query: Replace(
835841
ReplaceStmt {
836842
hints: None,
@@ -996,7 +1002,10 @@ EXPLAIN PIPELINE SELECT a FROM t1 IGNORE_RESULT
9961002
---------- AST ------------
9971003
Explain {
9981004
kind: Pipeline,
999-
options: [],
1005+
options: (
1006+
None,
1007+
[],
1008+
),
10001009
query: Query(
10011010
Query {
10021011
span: Some(
@@ -1081,11 +1090,16 @@ EXPLAIN(VERBOSE, LOGICAL, OPTIMIZED) SELECT * FROM t WHERE a = 1
10811090
---------- AST ------------
10821091
Explain {
10831092
kind: Plan,
1084-
options: [
1085-
Verbose,
1086-
Logical,
1087-
Optimized,
1088-
],
1093+
options: (
1094+
Some(
1095+
7..36,
1096+
),
1097+
[
1098+
Verbose,
1099+
Logical,
1100+
Optimized,
1101+
],
1102+
),
10891103
query: Query(
10901104
Query {
10911105
span: Some(

src/query/service/src/interpreters/interpreter_explain.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,6 @@ impl Interpreter for ExplainInterpreter {
9090
#[async_backtrace::framed]
9191
async fn execute2(&self) -> Result<PipelineBuildResult> {
9292
let blocks = match &self.kind {
93-
ExplainKind::Raw | ExplainKind::Optimized | ExplainKind::Decorrelated => {
94-
self.explain_plan(&self.plan)?
95-
}
9693
ExplainKind::Plan if self.config.logical => self.explain_plan(&self.plan)?,
9794
ExplainKind::Plan => match &self.plan {
9895
Plan::Query {
@@ -263,6 +260,10 @@ impl Interpreter for ExplainInterpreter {
263260
let column = StringType::from_data(line_split_result);
264261
vec![DataBlock::new_from_columns(vec![column])]
265262
}
263+
264+
ExplainKind::Raw | ExplainKind::Optimized | ExplainKind::Decorrelated => {
265+
unreachable!()
266+
}
266267
};
267268

268269
PipelineBuildResult::from_blocks(blocks)

src/query/sql/src/planner/binder/explain.rs

Lines changed: 80 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use databend_common_ast::ast::ExplainKind;
1616
use databend_common_ast::ast::ExplainOption;
1717
use databend_common_ast::ast::Statement;
18+
use databend_common_ast::Span;
1819
use databend_common_exception::ErrorCode;
1920
use databend_common_exception::Result;
2021

@@ -28,31 +29,65 @@ pub struct ExplainConfig {
2829
pub verbose: bool,
2930
pub logical: bool,
3031
pub optimized: bool,
32+
pub decorrelated: bool,
3133
}
3234

35+
impl ExplainConfig {
36+
fn validate(&self, span: Span, kind: &ExplainKind) -> Result<()> {
37+
if self.logical
38+
&& !matches!(
39+
kind,
40+
ExplainKind::Plan
41+
| ExplainKind::Raw
42+
| ExplainKind::Optimized
43+
| ExplainKind::Decorrelated
44+
)
45+
{
46+
return Err(ErrorCode::SyntaxException(
47+
"This EXPLAIN statement does not support LOGICAL options".to_string(),
48+
)
49+
.set_span(span));
50+
}
51+
52+
if self.decorrelated && !matches!(kind, ExplainKind::Plan | ExplainKind::Decorrelated) {
53+
return Err(ErrorCode::SyntaxException(
54+
"This EXPLAIN statement does not support DECORRELATED options".to_string(),
55+
)
56+
.set_span(span));
57+
}
58+
59+
if self.optimized && !matches!(kind, ExplainKind::Plan | ExplainKind::Optimized) {
60+
return Err(ErrorCode::SyntaxException(
61+
"This EXPLAIN statement does not support OPTIMIZED option".to_string(),
62+
)
63+
.set_span(span));
64+
}
65+
66+
Ok(())
67+
}
68+
}
69+
70+
#[derive(Default)]
3371
struct ExplainConfigBuilder {
3472
verbose: bool,
3573
logical: bool,
3674
optimized: bool,
75+
decorrelated: bool,
3776
}
3877

3978
impl ExplainConfigBuilder {
40-
pub fn new() -> Self {
41-
ExplainConfigBuilder {
42-
verbose: false,
43-
logical: false,
44-
optimized: false,
45-
}
46-
}
47-
48-
pub fn add_option(mut self, option: &ExplainOption) -> Self {
79+
pub fn add_option(mut self, option: ExplainOption) -> Self {
4980
match option {
5081
ExplainOption::Verbose => self.verbose = true,
5182
ExplainOption::Logical => self.logical = true,
5283
ExplainOption::Optimized => {
5384
self.logical = true;
5485
self.optimized = true;
5586
}
87+
ExplainOption::Decorrelated => {
88+
self.logical = true;
89+
self.decorrelated = true;
90+
}
5691
}
5792

5893
self
@@ -63,6 +98,7 @@ impl ExplainConfigBuilder {
6398
verbose: self.verbose,
6499
logical: self.logical,
65100
optimized: self.optimized,
101+
decorrelated: self.decorrelated,
66102
}
67103
}
68104
}
@@ -72,82 +108,56 @@ impl Binder {
72108
&mut self,
73109
bind_context: &mut BindContext,
74110
kind: &ExplainKind,
75-
options: &[ExplainOption],
111+
(span, options): &(Span, Vec<ExplainOption>),
76112
inner: &Statement,
77113
) -> Result<Plan> {
78-
let mut builder = ExplainConfigBuilder::new();
114+
let mut builder = ExplainConfigBuilder::default();
79115
if let Statement::Explain { .. } | Statement::ExplainAnalyze { .. } = inner {
80116
return Err(ErrorCode::SyntaxException("Invalid statement"));
81117
}
82118

83-
// Rewrite `EXPLAIN RAW` to `EXPLAIN(LOGICAL)`
84-
if matches!(kind, ExplainKind::Raw) {
85-
builder = builder.add_option(&ExplainOption::Logical);
86-
}
87-
88-
// Rewrite `EXPLAIN OPTIMIZED` to `EXPLAIN(LOGICAL, OPTIMIZED)`
89-
if matches!(kind, ExplainKind::Optimized) {
90-
builder = builder.add_option(&ExplainOption::Logical);
91-
builder = builder.add_option(&ExplainOption::Optimized);
92-
}
93-
94119
for option in options {
95-
builder = builder.add_option(option);
120+
builder = builder.add_option(*option);
96121
}
97122

98-
let config = builder.build();
123+
match kind {
124+
ExplainKind::Raw => {
125+
// Rewrite `EXPLAIN RAW` to `EXPLAIN(LOGICAL)`
126+
builder = builder.add_option(ExplainOption::Logical);
127+
}
128+
ExplainKind::Decorrelated => {
129+
// Rewrite `EXPLAIN DECORRELATED` to `EXPLAIN(LOGICAL, DECORRELATED)`
130+
builder = builder.add_option(ExplainOption::Decorrelated);
131+
}
132+
ExplainKind::Optimized => {
133+
// Rewrite `EXPLAIN OPTIMIZED` to `EXPLAIN(LOGICAL, OPTIMIZED)`
134+
builder = builder.add_option(ExplainOption::Optimized);
135+
}
136+
_ => {}
137+
};
99138

100-
// Validate the configuration
101-
validate_explain_config(kind, &config)?;
139+
let config = builder.build();
140+
config.validate(span.to_owned(), kind)?;
102141

103-
let plan = match kind {
104-
ExplainKind::Ast(formatted_stmt) => Plan::ExplainAst {
142+
match kind {
143+
ExplainKind::Ast(formatted_stmt) => Ok(Plan::ExplainAst {
105144
formatted_string: formatted_stmt.clone(),
106-
},
107-
ExplainKind::Syntax(formatted_sql) => Plan::ExplainSyntax {
145+
}),
146+
ExplainKind::Syntax(formatted_sql) => Ok(Plan::ExplainSyntax {
108147
formatted_sql: formatted_sql.clone(),
109-
},
110-
_ => Plan::Explain {
148+
}),
149+
ExplainKind::Raw | ExplainKind::Decorrelated | ExplainKind::Optimized => {
150+
Ok(Plan::Explain {
151+
kind: ExplainKind::Plan,
152+
config,
153+
plan: Box::new(self.bind_statement(bind_context, inner).await?),
154+
})
155+
}
156+
_ => Ok(Plan::Explain {
111157
kind: kind.clone(),
112158
config,
113159
plan: Box::new(self.bind_statement(bind_context, inner).await?),
114-
},
115-
};
116-
117-
Ok(plan)
118-
}
119-
}
120-
121-
fn validate_explain_config(kind: &ExplainKind, config: &ExplainConfig) -> Result<()> {
122-
if !matches!(
123-
kind,
124-
ExplainKind::Plan | ExplainKind::Raw | ExplainKind::Optimized
125-
) && config.logical
126-
{
127-
return Err(ErrorCode::SyntaxException(
128-
"LOGICAL option is only supported for EXPLAIN SELECT statement".to_string(),
129-
));
130-
}
131-
132-
if !matches!(
133-
kind,
134-
ExplainKind::Plan | ExplainKind::Raw | ExplainKind::Optimized
135-
) && config.optimized
136-
{
137-
return Err(ErrorCode::SyntaxException(
138-
"OPTIMIZED option is only supported for EXPLAIN SELECT statement".to_string(),
139-
));
140-
}
141-
142-
if !matches!(
143-
kind,
144-
ExplainKind::Plan | ExplainKind::Raw | ExplainKind::Optimized
145-
) && config.verbose
146-
{
147-
return Err(ErrorCode::SyntaxException(
148-
"VERBOSE option is only supported for EXPLAIN SELECT statement".to_string(),
149-
));
160+
}),
161+
}
150162
}
151-
152-
Ok(())
153163
}

0 commit comments

Comments
 (0)