@@ -29,25 +29,17 @@ use datafusion_expr::expr::Cast;
2929use std:: sync:: Arc ;
3030
3131#[ derive( Default ) ]
32- pub struct ReduceOuterJoin ;
32+ pub struct EliminateOuterJoin ;
3333
34- impl ReduceOuterJoin {
34+ impl EliminateOuterJoin {
3535 #[ allow( missing_docs) ]
3636 pub fn new ( ) -> Self {
3737 Self { }
3838 }
3939}
4040
41- /// Attempt to eliminate outer joins to inner joins.
42- /// for query: select ... from a left join b on ... where b.xx = 100;
43- /// if b.xx is null, and b.xx = 100 returns false, filtered those null rows.
44- /// Therefore, there is no need to produce null rows for output, we can use
45- /// inner join instead of left join.
46- ///
47- /// Generally, an outer join can be eliminated to inner join if equals from where
48- /// return false while any inputs are null and columns of those equals are come from
49- /// nullable side of outer join.
50- impl OptimizerRule for ReduceOuterJoin {
41+ /// Attempt to eliminate outer joins.
42+ impl OptimizerRule for EliminateOuterJoin {
5143 fn optimize (
5244 & self ,
5345 plan : & LogicalPlan ,
@@ -56,36 +48,35 @@ impl OptimizerRule for ReduceOuterJoin {
5648 match plan {
5749 LogicalPlan :: Filter ( filter) => match filter. input ( ) . as_ref ( ) {
5850 LogicalPlan :: Join ( join) => {
59- let mut nonnullable_cols : Vec < Column > = vec ! [ ] ;
51+ let mut non_nullable_cols : Vec < Column > = vec ! [ ] ;
6052
61- extract_nonnullable_columns (
53+ extract_non_nullable_columns (
6254 filter. predicate ( ) ,
63- & mut nonnullable_cols ,
55+ & mut non_nullable_cols ,
6456 join. left . schema ( ) ,
6557 join. right . schema ( ) ,
6658 true ,
6759 ) ?;
6860
6961 let new_join_type = if join. join_type . is_outer ( ) {
70- let mut left_nonnullable = false ;
71- let mut right_nonnullable = false ;
72- for col in nonnullable_cols . iter ( ) {
62+ let mut left_non_nullable = false ;
63+ let mut right_non_nullable = false ;
64+ for col in non_nullable_cols . iter ( ) {
7365 if join. left . schema ( ) . field_from_column ( col) . is_ok ( ) {
74- left_nonnullable = true ;
66+ left_non_nullable = true ;
7567 }
7668 if join. right . schema ( ) . field_from_column ( col) . is_ok ( ) {
77- right_nonnullable = true ;
69+ right_non_nullable = true ;
7870 }
7971 }
8072 eliminate_outer (
8173 join. join_type ,
82- left_nonnullable ,
83- right_nonnullable ,
74+ left_non_nullable ,
75+ right_non_nullable ,
8476 )
8577 } else {
8678 join. join_type
8779 } ;
88-
8980 let new_join = LogicalPlan :: Join ( Join {
9081 left : Arc :: new ( ( * join. left ) . clone ( ) ) ,
9182 right : Arc :: new ( ( * join. right ) . clone ( ) ) ,
@@ -112,27 +103,27 @@ impl OptimizerRule for ReduceOuterJoin {
112103
113104pub fn eliminate_outer (
114105 join_type : JoinType ,
115- left_nonnullable : bool ,
116- right_nonnullable : bool ,
106+ left_non_nullable : bool ,
107+ right_non_nullable : bool ,
117108) -> JoinType {
118109 let mut new_join_type = join_type;
119110 match join_type {
120111 JoinType :: Left => {
121- if right_nonnullable {
112+ if right_non_nullable {
122113 new_join_type = JoinType :: Inner ;
123114 }
124115 }
125116 JoinType :: Right => {
126- if left_nonnullable {
117+ if left_non_nullable {
127118 new_join_type = JoinType :: Inner ;
128119 }
129120 }
130121 JoinType :: Full => {
131- if left_nonnullable && right_nonnullable {
122+ if left_non_nullable && right_non_nullable {
132123 new_join_type = JoinType :: Inner ;
133- } else if left_nonnullable {
124+ } else if left_non_nullable {
134125 new_join_type = JoinType :: Left ;
135- } else if right_nonnullable {
126+ } else if right_non_nullable {
136127 new_join_type = JoinType :: Right ;
137128 }
138129 }
@@ -142,23 +133,23 @@ pub fn eliminate_outer(
142133}
143134
144135/// Recursively traverses expr, if expr returns false when
145- /// any inputs are null, treats columns of both sides as nonnullable columns.
136+ /// any inputs are null, treats columns of both sides as non_nullable columns.
146137///
147138/// For and/or expr, extracts from all sub exprs and merges the columns.
148139/// For or expr, if one of sub exprs returns true, discards all columns from or expr.
149140/// For IS NOT NULL/NOT expr, always returns false for NULL input.
150141/// extracts columns from these exprs.
151142/// For all other exprs, fall through
152- fn extract_nonnullable_columns (
143+ fn extract_non_nullable_columns (
153144 expr : & Expr ,
154- nonnullable_cols : & mut Vec < Column > ,
145+ non_nullable_cols : & mut Vec < Column > ,
155146 left_schema : & Arc < DFSchema > ,
156147 right_schema : & Arc < DFSchema > ,
157148 top_level : bool ,
158149) -> Result < ( ) > {
159150 match expr {
160151 Expr :: Column ( col) => {
161- nonnullable_cols . push ( col. clone ( ) ) ;
152+ non_nullable_cols . push ( col. clone ( ) ) ;
162153 Ok ( ( ) )
163154 }
164155 Expr :: BinaryExpr ( BinaryExpr { left, op, right } ) => match op {
@@ -169,16 +160,16 @@ fn extract_nonnullable_columns(
169160 | Operator :: LtEq
170161 | Operator :: Gt
171162 | Operator :: GtEq => {
172- extract_nonnullable_columns (
163+ extract_non_nullable_columns (
173164 left,
174- nonnullable_cols ,
165+ non_nullable_cols ,
175166 left_schema,
176167 right_schema,
177168 false ,
178169 ) ?;
179- extract_nonnullable_columns (
170+ extract_non_nullable_columns (
180171 right,
181- nonnullable_cols ,
172+ non_nullable_cols ,
182173 left_schema,
183174 right_schema,
184175 false ,
@@ -188,36 +179,36 @@ fn extract_nonnullable_columns(
188179 // treat And as Or if does not from top level, such as
189180 // not (c1 < 10 and c2 > 100)
190181 if top_level && * op == Operator :: And {
191- extract_nonnullable_columns (
182+ extract_non_nullable_columns (
192183 left,
193- nonnullable_cols ,
184+ non_nullable_cols ,
194185 left_schema,
195186 right_schema,
196187 top_level,
197188 ) ?;
198- extract_nonnullable_columns (
189+ extract_non_nullable_columns (
199190 right,
200- nonnullable_cols ,
191+ non_nullable_cols ,
201192 left_schema,
202193 right_schema,
203194 top_level,
204195 ) ?;
205196 return Ok ( ( ) ) ;
206197 }
207198
208- let mut left_nonnullable_cols : Vec < Column > = vec ! [ ] ;
209- let mut right_nonnullable_cols : Vec < Column > = vec ! [ ] ;
199+ let mut left_non_nullable_cols : Vec < Column > = vec ! [ ] ;
200+ let mut right_non_nullable_cols : Vec < Column > = vec ! [ ] ;
210201
211- extract_nonnullable_columns (
202+ extract_non_nullable_columns (
212203 left,
213- & mut left_nonnullable_cols ,
204+ & mut left_non_nullable_cols ,
214205 left_schema,
215206 right_schema,
216207 top_level,
217208 ) ?;
218- extract_nonnullable_columns (
209+ extract_non_nullable_columns (
219210 right,
220- & mut right_nonnullable_cols ,
211+ & mut right_non_nullable_cols ,
221212 left_schema,
222213 right_schema,
223214 top_level,
@@ -229,16 +220,17 @@ fn extract_nonnullable_columns(
229220 // this can not be eliminated.
230221 // If columns of relation exist in both sub exprs, any columns of this relation
231222 // can be added to non nullable columns.
232- if !left_nonnullable_cols. is_empty ( ) && !right_nonnullable_cols. is_empty ( )
223+ if !left_non_nullable_cols. is_empty ( )
224+ && !right_non_nullable_cols. is_empty ( )
233225 {
234- for left_col in & left_nonnullable_cols {
235- for right_col in & right_nonnullable_cols {
226+ for left_col in & left_non_nullable_cols {
227+ for right_col in & right_non_nullable_cols {
236228 if ( left_schema. field_from_column ( left_col) . is_ok ( )
237229 && left_schema. field_from_column ( right_col) . is_ok ( ) )
238230 || ( right_schema. field_from_column ( left_col) . is_ok ( )
239231 && right_schema. field_from_column ( right_col) . is_ok ( ) )
240232 {
241- nonnullable_cols . push ( left_col. clone ( ) ) ;
233+ non_nullable_cols . push ( left_col. clone ( ) ) ;
242234 break ;
243235 }
244236 }
@@ -248,9 +240,9 @@ fn extract_nonnullable_columns(
248240 }
249241 _ => Ok ( ( ) ) ,
250242 } ,
251- Expr :: Not ( arg) => extract_nonnullable_columns (
243+ Expr :: Not ( arg) => extract_non_nullable_columns (
252244 arg,
253- nonnullable_cols ,
245+ non_nullable_cols ,
254246 left_schema,
255247 right_schema,
256248 false ,
@@ -259,18 +251,18 @@ fn extract_nonnullable_columns(
259251 if !top_level {
260252 return Ok ( ( ) ) ;
261253 }
262- extract_nonnullable_columns (
254+ extract_non_nullable_columns (
263255 arg,
264- nonnullable_cols ,
256+ non_nullable_cols ,
265257 left_schema,
266258 right_schema,
267259 false ,
268260 )
269261 }
270262 Expr :: Cast ( Cast { expr, data_type : _ } )
271- | Expr :: TryCast { expr, data_type : _ } => extract_nonnullable_columns (
263+ | Expr :: TryCast { expr, data_type : _ } => extract_non_nullable_columns (
272264 expr,
273- nonnullable_cols ,
265+ non_nullable_cols ,
274266 left_schema,
275267 right_schema,
276268 false ,
@@ -292,7 +284,7 @@ mod tests {
292284 } ;
293285
294286 fn assert_optimized_plan_eq ( plan : & LogicalPlan , expected : & str ) {
295- let rule = ReduceOuterJoin :: new ( ) ;
287+ let rule = EliminateOuterJoin :: new ( ) ;
296288 let optimized_plan = rule
297289 . optimize ( plan, & mut OptimizerConfig :: new ( ) )
298290 . expect ( "failed to optimize plan" ) ;
0 commit comments