14
14
15
15
//! Filter Push Down optimizer rule ensures that filters are applied as early as possible in the plan
16
16
17
+ use crate :: error:: Result ;
17
18
use crate :: execution:: context:: ExecutionProps ;
18
19
use crate :: logical_expr:: TableProviderFilterPushDown ;
19
20
use crate :: logical_plan:: plan:: { Aggregate , Filter , Join , Projection , Union } ;
20
21
use crate :: logical_plan:: {
21
- and , col, replace_col, Column , CrossJoin , JoinType , Limit , LogicalPlan , TableScan ,
22
+ col, replace_col, Column , CrossJoin , JoinType , Limit , LogicalPlan , TableScan ,
22
23
} ;
23
24
use crate :: logical_plan:: { DFSchema , Expr } ;
24
25
use crate :: optimizer:: optimizer:: OptimizerRule ;
25
26
use crate :: optimizer:: utils;
26
- use crate :: { error:: Result , logical_plan:: Operator } ;
27
- use std:: {
28
- collections:: { HashMap , HashSet } ,
29
- sync:: Arc ,
30
- } ;
27
+ use std:: collections:: { HashMap , HashSet } ;
31
28
32
29
/// Filter Push Down optimizer rule pushes filter clauses down the plan
33
30
/// # Introduction
@@ -95,23 +92,6 @@ fn push_down(state: &State, plan: &LogicalPlan) -> Result<LogicalPlan> {
95
92
utils:: from_plan ( plan, & expr, & new_inputs)
96
93
}
97
94
98
- /// returns a new [LogicalPlan] that wraps `plan` in a [LogicalPlan::Filter] with
99
- /// its predicate be all `predicates` ANDed.
100
- fn add_filter ( plan : LogicalPlan , predicates : & [ & Expr ] ) -> LogicalPlan {
101
- // reduce filters to a single filter with an AND
102
- let predicate = predicates
103
- . iter ( )
104
- . skip ( 1 )
105
- . fold ( predicates[ 0 ] . clone ( ) , |acc, predicate| {
106
- and ( acc, ( * predicate) . to_owned ( ) )
107
- } ) ;
108
-
109
- LogicalPlan :: Filter ( Filter {
110
- predicate,
111
- input : Arc :: new ( plan) ,
112
- } )
113
- }
114
-
115
95
// remove all filters from `filters` that are in `predicate_columns`
116
96
fn remove_filters (
117
97
filters : & [ ( Expr , HashSet < Column > ) ] ,
@@ -150,32 +130,14 @@ fn issue_filters(
150
130
return push_down ( & state, plan) ;
151
131
}
152
132
153
- let plan = add_filter ( plan. clone ( ) , & predicates) ;
133
+ let plan = utils :: add_filter ( plan. clone ( ) , & predicates) ;
154
134
155
135
state. filters = remove_filters ( & state. filters , & predicate_columns) ;
156
136
157
137
// continue optimization over all input nodes by cloning the current state (i.e. each node is independent)
158
138
push_down ( & state, & plan)
159
139
}
160
140
161
- /// converts "A AND B AND C" => [A, B, C]
162
- fn split_members < ' a > ( predicate : & ' a Expr , predicates : & mut Vec < & ' a Expr > ) {
163
- match predicate {
164
- Expr :: BinaryExpr {
165
- right,
166
- op : Operator :: And ,
167
- left,
168
- } => {
169
- split_members ( left, predicates) ;
170
- split_members ( right, predicates) ;
171
- }
172
- Expr :: Alias ( expr, _) => {
173
- split_members ( expr, predicates) ;
174
- }
175
- other => predicates. push ( other) ,
176
- }
177
- }
178
-
179
141
// For a given JOIN logical plan, determine whether each side of the join is preserved.
180
142
// We say a join side is preserved if the join returns all or a subset of the rows from
181
143
// the relevant side, such that each row of the output table directly maps to a row of
@@ -289,7 +251,7 @@ fn optimize_join(
289
251
Ok ( plan)
290
252
} else {
291
253
// wrap the join on the filter whose predicates must be kept
292
- let plan = add_filter ( plan, & to_keep. 0 ) ;
254
+ let plan = utils :: add_filter ( plan, & to_keep. 0 ) ;
293
255
state. filters = remove_filters ( & state. filters , & to_keep. 1 ) ;
294
256
295
257
Ok ( plan)
@@ -305,7 +267,7 @@ fn optimize(plan: &LogicalPlan, mut state: State) -> Result<LogicalPlan> {
305
267
LogicalPlan :: Analyze { .. } => push_down ( & state, plan) ,
306
268
LogicalPlan :: Filter ( Filter { input, predicate } ) => {
307
269
let mut predicates = vec ! [ ] ;
308
- split_members ( predicate, & mut predicates) ;
270
+ utils :: split_conjunction ( predicate, & mut predicates) ;
309
271
310
272
// Predicates without referencing columns (WHERE FALSE, WHERE 1=1, etc.)
311
273
let mut no_col_predicates = vec ! [ ] ;
@@ -328,7 +290,10 @@ fn optimize(plan: &LogicalPlan, mut state: State) -> Result<LogicalPlan> {
328
290
// As those contain only literals, they could be optimized using constant folding
329
291
// and removal of WHERE TRUE / WHERE FALSE
330
292
if !no_col_predicates. is_empty ( ) {
331
- Ok ( add_filter ( optimize ( input, state) ?, & no_col_predicates) )
293
+ Ok ( utils:: add_filter (
294
+ optimize ( input, state) ?,
295
+ & no_col_predicates,
296
+ ) )
332
297
} else {
333
298
optimize ( input, state)
334
299
}
@@ -592,17 +557,18 @@ fn rewrite(expr: &Expr, projection: &HashMap<String, Expr>) -> Result<Expr> {
592
557
593
558
#[ cfg( test) ]
594
559
mod tests {
560
+ use std:: sync:: Arc ;
561
+
595
562
use super :: * ;
596
563
use crate :: datasource:: TableProvider ;
564
+ use crate :: logical_plan:: plan:: provider_as_source;
597
565
use crate :: logical_plan:: {
598
- lit, sum, union_with_alias, DFSchema , Expr , LogicalPlanBuilder , Operator ,
566
+ and, col, lit, sum, union_with_alias, DFSchema , Expr , LogicalPlanBuilder ,
567
+ Operator ,
599
568
} ;
600
569
use crate :: physical_plan:: ExecutionPlan ;
570
+ use crate :: prelude:: JoinType ;
601
571
use crate :: test:: * ;
602
- use crate :: {
603
- logical_plan:: { col, plan:: provider_as_source} ,
604
- prelude:: JoinType ,
605
- } ;
606
572
607
573
use arrow:: datatypes:: SchemaRef ;
608
574
use async_trait:: async_trait;
0 commit comments