Skip to content

Commit 93f32cc

Browse files
committed
Allow to specify join columns in any order
In the joins of the form `SELECT ... FROM L JOIN R ON ...`, `ON L.c1 = R.c2` is now equivalent to `ON R.c2 = L.c1`. Previously, the second syntax returned an error.
1 parent dee333e commit 93f32cc

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

rust/datafusion/src/physical_plan/expressions/column.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ impl Column {
5050
&self.name
5151
}
5252

53+
/// Get the column qualifier
54+
pub fn relation(&self) -> Option<&str> {
55+
self.relation.as_deref()
56+
}
57+
5358
/// Create a new column expression with alias
5459
pub fn new_with_alias(name: &str, relation: Option<String>) -> Self {
5560
Self {

rust/datafusion/src/sql/planner.rs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -390,13 +390,17 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
390390
match constraint {
391391
JoinConstraint::On(sql_expr) => {
392392
let mut keys: Vec<(String, String)> = vec![];
393-
let join_schema = left.schema().join(&right.schema())?;
393+
let left_schema = left.schema();
394+
let right_schema = right.schema();
395+
let join_schema = left_schema.join(right_schema)?;
394396

395397
// parse ON expression
396398
let expr = self.sql_to_rex(sql_expr, &join_schema)?;
397399

398400
// extract join keys
399-
if let Err(e) = extract_join_keys(&expr, &mut keys) {
401+
if let Err(e) =
402+
extract_join_keys(&expr, left_schema, right_schema, &mut keys)
403+
{
400404
// Complex condition, try cross join. We still prefer to **not** allow cross
401405
// joins in general case to avoid abysmal performance.
402406
// However, CubeStore needs this specific form for "rolling window" queries.
@@ -1558,15 +1562,27 @@ fn remove_join_expressions(
15581562
/// foo = bar
15591563
/// foo = bar AND bar = baz AND ...
15601564
///
1561-
fn extract_join_keys(expr: &Expr, accum: &mut Vec<(String, String)>) -> Result<()> {
1565+
fn extract_join_keys(
1566+
expr: &Expr,
1567+
ls: &DFSchema,
1568+
rs: &DFSchema,
1569+
accum: &mut Vec<(String, String)>,
1570+
) -> Result<()> {
15621571
match expr {
15631572
Expr::BinaryExpr { left, op, right } => match op {
15641573
Operator::Eq => match (left.as_ref(), right.as_ref()) {
15651574
(Expr::Column(l, la), Expr::Column(r, ra)) => {
1566-
accum.push((
1567-
Column::new_with_alias(l, la.clone()).full_name(),
1568-
Column::new_with_alias(r, ra.clone()).full_name(),
1569-
));
1575+
let mut lc = Column::new_with_alias(l, la.clone());
1576+
let mut rc = Column::new_with_alias(r, ra.clone());
1577+
// `L = R` and `R = L` are equivalent, handle the latter case.
1578+
if ls.field_with_name(lc.relation(), lc.name()).is_err()
1579+
&& rs.field_with_name(lc.relation(), lc.name()).is_ok()
1580+
{
1581+
// Other cases should result in errors later, e.g. ambiguities in lookup.
1582+
std::mem::swap(&mut lc, &mut rc)
1583+
}
1584+
1585+
accum.push((lc.full_name(), rc.full_name()));
15701586
Ok(())
15711587
}
15721588
other => Err(DataFusionError::SQL(ParserError(format!(
@@ -1575,8 +1591,8 @@ fn extract_join_keys(expr: &Expr, accum: &mut Vec<(String, String)>) -> Result<(
15751591
)))),
15761592
},
15771593
Operator::And => {
1578-
extract_join_keys(left, accum)?;
1579-
extract_join_keys(right, accum)
1594+
extract_join_keys(left, ls, rs, accum)?;
1595+
extract_join_keys(right, ls, rs, accum)
15801596
}
15811597
other => Err(DataFusionError::SQL(ParserError(format!(
15821598
"Unsupported expression '{:?}' in JOIN condition",

0 commit comments

Comments
 (0)