@@ -22,9 +22,8 @@ use datafusion_common::tree_node::Transformed;
2222use datafusion_common:: DFSchema ;
2323use datafusion_common:: Result ;
2424use datafusion_expr:: utils:: split_conjunction_owned;
25- use datafusion_expr:: utils:: { can_hash, find_valid_equijoin_key_pair, is_inferred_alias } ;
25+ use datafusion_expr:: utils:: { can_hash, find_valid_equijoin_key_pair} ;
2626use datafusion_expr:: { BinaryExpr , Expr , ExprSchemable , Join , LogicalPlan , Operator } ;
27- use std:: collections:: HashSet ;
2827// equijoin predicate
2928type EquijoinPredicate = ( Expr , Expr ) ;
3029
@@ -82,17 +81,14 @@ impl OptimizerRule for ExtractEquijoinPredicate {
8281 let right_schema = right. schema ( ) ;
8382 let ( equijoin_predicates, non_equijoin_expr) =
8483 split_eq_and_noneq_join_predicate ( expr, left_schema, right_schema) ?;
85- let has_new_keys = !equijoin_predicates. is_empty ( ) ;
8684
87- on. extend ( equijoin_predicates) ;
88- let filter = residual_minus_on ( non_equijoin_expr, & on) ;
89-
90- if has_new_keys {
85+ if !equijoin_predicates. is_empty ( ) {
86+ on. extend ( equijoin_predicates) ;
9187 Ok ( Transformed :: yes ( LogicalPlan :: Join ( Join {
9288 left,
9389 right,
9490 on,
95- filter,
91+ filter : non_equijoin_expr ,
9692 join_type,
9793 join_constraint,
9894 schema,
@@ -103,7 +99,7 @@ impl OptimizerRule for ExtractEquijoinPredicate {
10399 left,
104100 right,
105101 on,
106- filter,
102+ filter : non_equijoin_expr ,
107103 join_type,
108104 join_constraint,
109105 schema,
@@ -126,10 +122,6 @@ fn split_eq_and_noneq_join_predicate(
126122 let mut accum_join_keys: Vec < ( Expr , Expr ) > = vec ! [ ] ;
127123 let mut accum_filters: Vec < Expr > = vec ! [ ] ;
128124 for expr in exprs {
129- if is_inferred_alias ( & expr) {
130- accum_filters. push ( expr) ;
131- continue ;
132- }
133125 match expr {
134126 Expr :: BinaryExpr ( BinaryExpr {
135127 ref left,
@@ -160,77 +152,17 @@ fn split_eq_and_noneq_join_predicate(
160152 Ok ( ( accum_join_keys, result_filter) )
161153}
162154
163- fn residual_minus_on ( filter : Option < Expr > , on : & [ ( Expr , Expr ) ] ) -> Option < Expr > {
164- let filter = filter?;
165- let exprs = split_conjunction_owned ( filter) ;
166-
167- let mut on_set: HashSet < ( String , String ) > = HashSet :: new ( ) ;
168- for ( l, r) in on {
169- let ( a, b) = canonical_pair ( l, r) ;
170- on_set. insert ( ( a. clone ( ) , b. clone ( ) ) ) ;
171- }
172-
173- let remaining: Vec < Expr > = exprs
174- . into_iter ( )
175- . filter ( |e| !is_self_equality ( e) )
176- . filter ( |e| {
177- let inner = match e {
178- Expr :: Alias ( alias) => alias. expr . as_ref ( ) ,
179- _ => e,
180- } ;
181- if let Expr :: BinaryExpr ( BinaryExpr { left, op : Operator :: Eq , right } ) = inner {
182- let ( a, b) = canonical_pair ( left, right) ;
183- !on_set. contains ( & ( a, b) )
184- } else {
185- true
186- }
187- } )
188- . collect ( ) ;
189-
190- remaining. into_iter ( ) . reduce ( Expr :: and)
191- }
192-
193- fn canonical_pair ( left : & Expr , right : & Expr ) -> ( String , String ) {
194- let l = canonical_str ( left) ;
195- let r = canonical_str ( right) ;
196- if l <= r { ( l, r) } else { ( r, l) }
197- }
198-
199- fn canonical_str ( expr : & Expr ) -> String {
200- match expr {
201- Expr :: Alias ( alias) => canonical_str ( & alias. expr ) ,
202- _ => format ! ( "{}" , expr) ,
203- }
204- }
205-
206- fn is_self_equality ( expr : & Expr ) -> bool {
207- let inner = match expr {
208- Expr :: Alias ( alias) => alias. expr . as_ref ( ) ,
209- _ => expr,
210- } ;
211- match inner {
212- Expr :: BinaryExpr ( BinaryExpr { left, op : Operator :: Eq , right } ) => left. as_ref ( ) == right. as_ref ( ) ,
213- _ => false ,
214- }
215- }
216-
217-
218155#[ cfg( test) ]
219156mod tests {
220157 use super :: * ;
221158 use crate :: assert_optimized_plan_eq_display_indent_snapshot;
222159 use crate :: test:: * ;
223- use crate :: { Optimizer , OptimizerContext } ;
224160 use arrow:: datatypes:: DataType ;
225- use datafusion_common:: NullEquality ;
226161 use datafusion_expr:: {
227162 col, lit, logical_plan:: builder:: LogicalPlanBuilder , JoinType ,
228- logical_plan:: JoinConstraint ,
229163 } ;
230164 use std:: sync:: Arc ;
231165
232- fn observe ( _plan : & LogicalPlan , _rule : & dyn OptimizerRule ) { }
233-
234166 macro_rules! assert_optimized_plan_equal {
235167 (
236168 $plan: expr,
@@ -287,31 +219,6 @@ mod tests {
287219 )
288220 }
289221
290- #[ test]
291- fn residual_minus_on_removes_symmetric_dup ( ) -> Result < ( ) > {
292- let left = test_table_scan_with_name ( "l" ) ?;
293- let right = test_table_scan_with_name ( "r" ) ?;
294- let on = vec ! [ ( col( "l.a" ) , col( "r.a" ) ) ] ;
295- let filter = Some ( col ( "r.a" ) . eq ( col ( "l.a" ) ) . and ( col ( "l.a" ) . eq ( col ( "l.a" ) ) ) ) ;
296- let join = Join :: try_new (
297- Arc :: new ( left) ,
298- Arc :: new ( right) ,
299- on,
300- filter,
301- JoinType :: Inner ,
302- JoinConstraint :: On ,
303- NullEquality :: NullEqualsNull ,
304- ) ?;
305- let optimizer = Optimizer :: with_rules ( vec ! [ Arc :: new( ExtractEquijoinPredicate :: new( ) ) ] ) ;
306- let optimized = optimizer. optimize ( LogicalPlan :: Join ( join) , & OptimizerContext :: new ( ) , observe) ?;
307- if let LogicalPlan :: Join ( j) = optimized {
308- assert ! ( j. filter. is_none( ) ) ;
309- } else {
310- panic ! ( "expected join" ) ;
311- }
312- Ok ( ( ) )
313- }
314-
315222 #[ test]
316223 fn join_with_only_none_equi_predicate ( ) -> Result < ( ) > {
317224 let t1 = test_table_scan_with_name ( "t1" ) ?;
0 commit comments