Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions src/query/sql/src/planner/binder/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,12 @@ impl Binder {
pub(super) async fn bind_join(
&mut self,
bind_context: &BindContext,
left_context: BindContext,
right_context: BindContext,
left_child: SExpr,
right_child: SExpr,
join: &common_ast::ast::Join,
) -> Result<(SExpr, BindContext)> {
let (left_child, left_context) =
self.bind_table_reference(bind_context, &join.left).await?;
let (right_child, right_context) =
self.bind_table_reference(bind_context, &join.right).await?;

check_duplicate_join_tables(&left_context, &right_context)?;

let mut bind_context = bind_context.replace();
Expand Down
80 changes: 78 additions & 2 deletions src/query/sql/src/planner/binder/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ use std::collections::HashMap;
use std::default::Default;
use std::sync::Arc;

use async_recursion::async_recursion;
use chrono::TimeZone;
use chrono::Utc;
use common_ast::ast::Indirection;
use common_ast::ast::Join;
use common_ast::ast::SelectStmt;
use common_ast::ast::SelectTarget;
use common_ast::ast::Statement;
Expand Down Expand Up @@ -112,7 +114,8 @@ impl Binder {
.await
}

pub(super) async fn bind_table_reference(
#[async_recursion]
async fn bind_single_table(
&mut self,
bind_context: &BindContext,
table_ref: &TableReference,
Expand Down Expand Up @@ -348,7 +351,6 @@ impl Binder {
}
Ok((s_expr, bind_context))
}
TableReference::Join { span: _, join } => self.bind_join(bind_context, join).await,
TableReference::Subquery {
span: _,
subquery,
Expand Down Expand Up @@ -382,6 +384,7 @@ impl Binder {
self.bind_stage_table(bind_context, stage_info, files_info, alias, None)
.await
}
TableReference::Join { .. } => unreachable!(),
}
}

Expand Down Expand Up @@ -431,6 +434,79 @@ impl Binder {
}
}

pub(super) async fn bind_table_reference(
&mut self,
bind_context: &BindContext,
table_ref: &TableReference,
) -> Result<(SExpr, BindContext)> {
let mut current_ref = table_ref;
let current_ctx = bind_context;

// Stack to keep track of the joins
let mut join_stack: Vec<&Join> = Vec::new();

// Traverse the table reference hierarchy to get to the innermost table
while let TableReference::Join { join, .. } = current_ref {
join_stack.push(join);

// Check whether the right-hand side is a Join or a TableReference
match &*join.right {
TableReference::Join { .. } => {
// Traverse the right-hand side if the right-hand side is a Join
current_ref = &join.right;
}
_ => {
// Traverse the left-hand side if the right-hand side is a TableReference
current_ref = &join.left;
}
}
}

// Bind the innermost table
// current_ref must be left table in its join
let (mut result_expr, mut result_ctx) =
self.bind_single_table(current_ctx, current_ref).await?;

for join in join_stack.iter().rev() {
match &*join.right {
TableReference::Join { .. } => {
let (left_expr, left_ctx) =
self.bind_single_table(current_ctx, &join.left).await?;
let (join_expr, ctx) = self
.bind_join(
current_ctx,
left_ctx,
result_ctx,
left_expr,
result_expr,
join,
)
.await?;
result_expr = join_expr;
result_ctx = ctx;
}
_ => {
let (right_expr, right_ctx) =
self.bind_single_table(current_ctx, &join.right).await?;
let (join_expr, ctx) = self
.bind_join(
current_ctx,
result_ctx,
right_ctx,
result_expr,
right_expr,
join,
)
.await?;
result_expr = join_expr;
result_ctx = ctx;
}
}
}

Ok((result_expr, result_ctx))
}

async fn bind_cte(
&mut self,
bind_context: &BindContext,
Expand Down
2 changes: 0 additions & 2 deletions src/query/sql/src/planner/optimizer/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,8 @@ pub fn optimize_query(

let mut heuristic = HeuristicOptimizer::new(ctx.clone(), bind_context, metadata.clone());
let mut result = heuristic.optimize(s_expr)?;

let mut cascades = CascadesOptimizer::create(ctx.clone(), metadata)?;
result = cascades.optimize(result)?;

// So far, we don't have ability to execute distributed query
// with reading data from local tales(e.g. system tables).
let enable_distributed_query =
Expand Down
67 changes: 67 additions & 0 deletions tests/sqllogictests/suites/mode/standalone/explain/join.test
Original file line number Diff line number Diff line change
Expand Up @@ -547,3 +547,70 @@ drop table t1

statement ok
drop table t2


# https://github.com/datafuselabs/databend/issues/10523
statement ok
create table t1 as select * from numbers(1)

statement ok
set enable_cbo = 0

query I
select t1.number FROM
t1
CROSS JOIN
t1 AS t2,
t1 AS t3,
t1 AS t4,
t1 AS t5,
t1 AS t6,
t1 AS t7,
t1 AS t8,
t1 AS t9,
t1 AS t10,
t1 AS t11,
t1 AS t12,
t1 AS t13,
t1 AS t14,
t1 AS t15,
t1 AS t16,
t1 AS t17,
t1 AS t18,
t1 AS t19,
t1 AS t20
----
0

query I
SELECT t20.number
FROM
((((((((((((((((((
t1 AS t20
CROSS JOIN t1 AS t19)
CROSS JOIN t1 AS t18)
CROSS JOIN t1 AS t17)
CROSS JOIN t1 AS t16)
CROSS JOIN t1 AS t15)
CROSS JOIN t1 AS t14)
CROSS JOIN t1 AS t13)
CROSS JOIN t1 AS t12)
CROSS JOIN t1 AS t11)
CROSS JOIN t1 AS t10)
CROSS JOIN t1 AS t9)
CROSS JOIN t1 AS t8)
CROSS JOIN t1 AS t7)
CROSS JOIN t1 AS t6)
CROSS JOIN t1 AS t5)
CROSS JOIN t1 AS t4)
CROSS JOIN t1 AS t3)
CROSS JOIN t1 AS t2)
CROSS JOIN t1
----
0

statement ok
set enable_cbo = 1

statement ok
drop table t1