Skip to content

Commit d9ebd2b

Browse files
authored
implement rewrite for ExtractEquijoinPredicate and avoid clone in filter (#10165)
* implement rewrite for ExtractEquijoinPredicate and avoid clone in filter * fix clippy * optimize code
1 parent 16369d8 commit d9ebd2b

File tree

1 file changed

+61
-52
lines changed

1 file changed

+61
-52
lines changed

datafusion/optimizer/src/extract_equijoin_predicate.rs

+61-52
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
//! [`ExtractEquijoinPredicate`] identifies equality join (equijoin) predicates
1919
use crate::optimizer::ApplyOrder;
2020
use crate::{OptimizerConfig, OptimizerRule};
21-
use datafusion_common::DFSchema;
21+
use datafusion_common::tree_node::Transformed;
2222
use datafusion_common::Result;
23-
use datafusion_expr::utils::{can_hash, find_valid_equijoin_key_pair, split_conjunction};
23+
use datafusion_common::{internal_err, DFSchema};
24+
use datafusion_expr::utils::split_conjunction_owned;
25+
use datafusion_expr::utils::{can_hash, find_valid_equijoin_key_pair};
2426
use datafusion_expr::{BinaryExpr, Expr, ExprSchemable, Join, LogicalPlan, Operator};
2527
use std::sync::Arc;
26-
2728
// equijoin predicate
2829
type EquijoinPredicate = (Expr, Expr);
2930

@@ -51,82 +52,90 @@ impl ExtractEquijoinPredicate {
5152
impl OptimizerRule for ExtractEquijoinPredicate {
5253
fn try_optimize(
5354
&self,
54-
plan: &LogicalPlan,
55+
_plan: &LogicalPlan,
5556
_config: &dyn OptimizerConfig,
5657
) -> Result<Option<LogicalPlan>> {
58+
internal_err!("Should have called ExtractEquijoinPredicate::rewrite")
59+
}
60+
fn supports_rewrite(&self) -> bool {
61+
true
62+
}
63+
64+
fn name(&self) -> &str {
65+
"extract_equijoin_predicate"
66+
}
67+
68+
fn apply_order(&self) -> Option<ApplyOrder> {
69+
Some(ApplyOrder::BottomUp)
70+
}
71+
72+
fn rewrite(
73+
&self,
74+
plan: LogicalPlan,
75+
_config: &dyn OptimizerConfig,
76+
) -> Result<Transformed<LogicalPlan>> {
5777
match plan {
5878
LogicalPlan::Join(Join {
5979
left,
6080
right,
61-
on,
62-
filter,
81+
mut on,
82+
filter: Some(expr),
6383
join_type,
6484
join_constraint,
6585
schema,
6686
null_equals_null,
6787
}) => {
6888
let left_schema = left.schema();
6989
let right_schema = right.schema();
70-
71-
filter.as_ref().map_or(Result::Ok(None), |expr| {
72-
let (equijoin_predicates, non_equijoin_expr) =
73-
split_eq_and_noneq_join_predicate(
74-
expr,
75-
left_schema,
76-
right_schema,
77-
)?;
78-
79-
let optimized_plan = (!equijoin_predicates.is_empty()).then(|| {
80-
let mut new_on = on.clone();
81-
new_on.extend(equijoin_predicates);
82-
83-
LogicalPlan::Join(Join {
84-
left: left.clone(),
85-
right: right.clone(),
86-
on: new_on,
87-
filter: non_equijoin_expr,
88-
join_type: *join_type,
89-
join_constraint: *join_constraint,
90-
schema: schema.clone(),
91-
null_equals_null: *null_equals_null,
92-
})
93-
});
94-
95-
Ok(optimized_plan)
96-
})
90+
let (equijoin_predicates, non_equijoin_expr) =
91+
split_eq_and_noneq_join_predicate(expr, left_schema, right_schema)?;
92+
93+
if !equijoin_predicates.is_empty() {
94+
on.extend(equijoin_predicates);
95+
Ok(Transformed::yes(LogicalPlan::Join(Join {
96+
left,
97+
right,
98+
on,
99+
filter: non_equijoin_expr,
100+
join_type,
101+
join_constraint,
102+
schema,
103+
null_equals_null,
104+
})))
105+
} else {
106+
Ok(Transformed::no(LogicalPlan::Join(Join {
107+
left,
108+
right,
109+
on,
110+
filter: non_equijoin_expr,
111+
join_type,
112+
join_constraint,
113+
schema,
114+
null_equals_null,
115+
})))
116+
}
97117
}
98-
_ => Ok(None),
118+
_ => Ok(Transformed::no(plan)),
99119
}
100120
}
101-
102-
fn name(&self) -> &str {
103-
"extract_equijoin_predicate"
104-
}
105-
106-
fn apply_order(&self) -> Option<ApplyOrder> {
107-
Some(ApplyOrder::BottomUp)
108-
}
109121
}
110122

111123
fn split_eq_and_noneq_join_predicate(
112-
filter: &Expr,
124+
filter: Expr,
113125
left_schema: &Arc<DFSchema>,
114126
right_schema: &Arc<DFSchema>,
115127
) -> Result<(Vec<EquijoinPredicate>, Option<Expr>)> {
116-
let exprs = split_conjunction(filter);
128+
let exprs = split_conjunction_owned(filter);
117129

118130
let mut accum_join_keys: Vec<(Expr, Expr)> = vec![];
119131
let mut accum_filters: Vec<Expr> = vec![];
120132
for expr in exprs {
121133
match expr {
122134
Expr::BinaryExpr(BinaryExpr {
123-
left,
135+
ref left,
124136
op: Operator::Eq,
125-
right,
137+
ref right,
126138
}) => {
127-
let left = left.as_ref();
128-
let right = right.as_ref();
129-
130139
let join_key_pair = find_valid_equijoin_key_pair(
131140
left,
132141
right,
@@ -141,13 +150,13 @@ fn split_eq_and_noneq_join_predicate(
141150
if can_hash(&left_expr_type) && can_hash(&right_expr_type) {
142151
accum_join_keys.push((left_expr, right_expr));
143152
} else {
144-
accum_filters.push(expr.clone());
153+
accum_filters.push(expr);
145154
}
146155
} else {
147-
accum_filters.push(expr.clone());
156+
accum_filters.push(expr);
148157
}
149158
}
150-
_ => accum_filters.push(expr.clone()),
159+
_ => accum_filters.push(expr),
151160
}
152161
}
153162

0 commit comments

Comments
 (0)