Skip to content

Commit cd68f48

Browse files
committed
Adds support for subquery representation in plans
Signed-off-by: coldWater <[email protected]>
1 parent 18ce7dd commit cd68f48

File tree

5 files changed

+148
-4
lines changed

5 files changed

+148
-4
lines changed

src/query/sql/src/planner/format/display.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,40 @@ where
157157
tree.children.extend(stats);
158158
}
159159

160+
let subquerys = op.get_subquery(vec![]);
161+
if !subquerys.is_empty() {
162+
let subquerys = subquerys
163+
.into_iter()
164+
.map(|subquery| {
165+
let children = vec![
166+
subquery
167+
.compare_op
168+
.map(|compare| FormatTreeNode::new(format!("compare_op: {compare:?}"))),
169+
Some(FormatTreeNode::new(format!(
170+
"output_column: {}",
171+
self.id_humanizer
172+
.humanize_column_id(subquery.output_column.index)
173+
))),
174+
subquery.projection_index.map(|id| {
175+
FormatTreeNode::new(format!(
176+
"projection_index: {}",
177+
self.id_humanizer.humanize_column_id(id)
178+
))
179+
}),
180+
Some(subquery.subquery.to_format_tree(self.id_humanizer)?),
181+
];
182+
Ok(FormatTreeNode::with_children(
183+
format!("Subquery ({:?})", subquery.typ),
184+
children.into_iter().filter_map(|x| x).collect(),
185+
))
186+
})
187+
.collect::<Result<Vec<_>>>()?;
188+
tree.children.push(FormatTreeNode::with_children(
189+
"subquerys".to_string(),
190+
subquerys,
191+
));
192+
}
193+
160194
let children = s_expr
161195
.children()
162196
.map(|s_expr| self.humanize_s_expr(s_expr))

src/query/sql/src/planner/optimizer/ir/expr/s_expr.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,7 @@ impl SExpr {
175175
/// Check if contain subquery
176176
#[recursive::recursive]
177177
pub(crate) fn has_subquery(&self) -> bool {
178-
if !self.plan.has_subquery() {
179-
return self.children.iter().any(|child| child.has_subquery());
180-
}
181-
true
178+
self.plan.has_subquery() || self.children.iter().any(|child| child.has_subquery())
182179
}
183180

184181
//

src/query/sql/src/planner/plans/operator.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use databend_common_exception::Result;
2020
use educe::Educe;
2121

2222
use super::MutationSource;
23+
use super::SubqueryExpr;
2324
use crate::optimizer::ir::PhysicalProperty;
2425
use crate::optimizer::ir::RelExpr;
2526
use crate::optimizer::ir::RelationalProperty;
@@ -209,6 +210,76 @@ impl RelOperator {
209210
RelOperator::MutationSource(_) => false,
210211
}
211212
}
213+
214+
pub fn get_subquery(&self, mut result: Vec<SubqueryExpr>) -> Vec<SubqueryExpr> {
215+
match self {
216+
RelOperator::Scan(_)
217+
| RelOperator::Limit(_)
218+
| RelOperator::Exchange(_)
219+
| RelOperator::UnionAll(_)
220+
| RelOperator::Sort(_)
221+
| RelOperator::DummyTableScan(_)
222+
| RelOperator::ConstantTableScan(_)
223+
| RelOperator::ExpressionScan(_)
224+
| RelOperator::CacheScan(_)
225+
| RelOperator::AsyncFunction(_)
226+
| RelOperator::RecursiveCteScan(_)
227+
| RelOperator::Mutation(_)
228+
| RelOperator::CompactBlock(_)
229+
| RelOperator::MutationSource(_) => (),
230+
RelOperator::Join(op) => {
231+
for condition in &op.equi_conditions {
232+
result = condition.left.get_subquery(result);
233+
result = condition.right.get_subquery(result);
234+
}
235+
for expr in &op.non_equi_conditions {
236+
result = expr.get_subquery(result);
237+
}
238+
}
239+
RelOperator::EvalScalar(op) => {
240+
for item in &op.items {
241+
result = item.scalar.get_subquery(result);
242+
}
243+
}
244+
RelOperator::Filter(op) => {
245+
for pred in &op.predicates {
246+
result = pred.get_subquery(result);
247+
}
248+
}
249+
RelOperator::Aggregate(op) => {
250+
for item in &op.group_items {
251+
result = item.scalar.get_subquery(result);
252+
}
253+
for func in &op.aggregate_functions {
254+
result = func.scalar.get_subquery(result);
255+
}
256+
}
257+
RelOperator::Window(op) => {
258+
for order in &op.order_by {
259+
result = order.order_by_item.scalar.get_subquery(result);
260+
}
261+
for expr in &op.partition_by {
262+
result = expr.scalar.get_subquery(result);
263+
}
264+
if let WindowFuncType::Aggregate(agg) = &op.function {
265+
for expr in agg.exprs() {
266+
result = expr.get_subquery(result);
267+
}
268+
}
269+
}
270+
RelOperator::ProjectSet(op) => {
271+
for srf in &op.srfs {
272+
result = srf.scalar.get_subquery(result);
273+
}
274+
}
275+
RelOperator::Udf(op) => {
276+
for item in &op.items {
277+
result = item.scalar.get_subquery(result);
278+
}
279+
}
280+
}
281+
result
282+
}
212283
}
213284

214285
impl Operator for RelOperator {

src/query/sql/src/planner/plans/scalar_expr.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,23 @@ impl ScalarExpr {
420420
has_subquery.visit(self).unwrap();
421421
has_subquery.has_subquery
422422
}
423+
424+
pub fn get_subquery(&self, result: Vec<SubqueryExpr>) -> Vec<SubqueryExpr> {
425+
struct GetSubquery {
426+
subquerys: Vec<SubqueryExpr>,
427+
}
428+
429+
impl<'a> Visitor<'a> for GetSubquery {
430+
fn visit_subquery(&mut self, subquery: &'a SubqueryExpr) -> Result<()> {
431+
self.subquerys.push(subquery.clone());
432+
Ok(())
433+
}
434+
}
435+
436+
let mut get_subquery = GetSubquery { subquerys: result };
437+
get_subquery.visit(self).unwrap();
438+
get_subquery.subquerys
439+
}
423440
}
424441

425442
impl From<BoundColumnRef> for ScalarExpr {

tests/sqllogictests/suites/mode/standalone/explain/subquery.test

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,31 @@ HashJoin
296296
├── push downs: [filters: [], limit: NONE]
297297
└── estimated rows: 1.00
298298

299+
query T
300+
explain raw select * from numbers(1) as t where exists (select number as a from numbers(1) where number = t.number)
301+
----
302+
EvalScalar
303+
├── scalars: [t.number (#0) AS (#0)]
304+
└── Filter
305+
├── filters: [SUBQUERY]
306+
├── subquerys
307+
│ └── Subquery (Exists)
308+
│ ├── output_column: system.numbers.number (#1)
309+
│ └── EvalScalar
310+
│ ├── scalars: [numbers.number (#1) AS (#1)]
311+
│ └── Filter
312+
│ ├── filters: [eq(numbers.number (#1), t.number (#0))]
313+
│ └── Scan
314+
│ ├── table: system.numbers (#1)
315+
│ ├── filters: []
316+
│ ├── order by: []
317+
│ └── limit: NONE
318+
└── Scan
319+
├── table: system.numbers (#0)
320+
├── filters: []
321+
├── order by: []
322+
└── limit: NONE
323+
299324
query T
300325
explain select t.number from numbers(1) as t where exists (select * from numbers(1) where number = t.number and number = 0 and t.number < 10)
301326
----

0 commit comments

Comments
 (0)