1 | #include "duckdb/optimizer/filter_pushdown.hpp" |
2 | |
3 | #include "duckdb/optimizer/filter_combiner.hpp" |
4 | #include "duckdb/planner/operator/logical_filter.hpp" |
5 | #include "duckdb/planner/operator/logical_join.hpp" |
6 | |
7 | using namespace duckdb; |
8 | using namespace std; |
9 | |
10 | using Filter = FilterPushdown::Filter; |
11 | |
12 | unique_ptr<LogicalOperator> FilterPushdown::Rewrite(unique_ptr<LogicalOperator> op) { |
13 | assert(!combiner.HasFilters()); |
14 | switch (op->type) { |
15 | case LogicalOperatorType::AGGREGATE_AND_GROUP_BY: |
16 | return PushdownAggregate(move(op)); |
17 | case LogicalOperatorType::FILTER: |
18 | return PushdownFilter(move(op)); |
19 | case LogicalOperatorType::CROSS_PRODUCT: |
20 | return PushdownCrossProduct(move(op)); |
21 | case LogicalOperatorType::COMPARISON_JOIN: |
22 | case LogicalOperatorType::ANY_JOIN: |
23 | case LogicalOperatorType::DELIM_JOIN: |
24 | return PushdownJoin(move(op)); |
25 | case LogicalOperatorType::PROJECTION: |
26 | return PushdownProjection(move(op)); |
27 | case LogicalOperatorType::INTERSECT: |
28 | case LogicalOperatorType::EXCEPT: |
29 | case LogicalOperatorType::UNION: |
30 | return PushdownSetOperation(move(op)); |
31 | case LogicalOperatorType::DISTINCT: |
32 | case LogicalOperatorType::ORDER_BY: { |
33 | // we can just push directly through these operations without any rewriting |
34 | op->children[0] = Rewrite(move(op->children[0])); |
35 | return op; |
36 | } |
37 | case LogicalOperatorType::GET: |
38 | return PushdownGet(move(op)); |
39 | default: |
40 | return FinishPushdown(move(op)); |
41 | } |
42 | } |
43 | |
44 | unique_ptr<LogicalOperator> FilterPushdown::PushdownJoin(unique_ptr<LogicalOperator> op) { |
45 | assert(op->type == LogicalOperatorType::COMPARISON_JOIN || op->type == LogicalOperatorType::ANY_JOIN || |
46 | op->type == LogicalOperatorType::DELIM_JOIN); |
47 | auto &join = (LogicalJoin &)*op; |
48 | unordered_set<idx_t> left_bindings, right_bindings; |
49 | LogicalJoin::GetTableReferences(*op->children[0], left_bindings); |
50 | LogicalJoin::GetTableReferences(*op->children[1], right_bindings); |
51 | |
52 | switch (join.join_type) { |
53 | case JoinType::INNER: |
54 | return PushdownInnerJoin(move(op), left_bindings, right_bindings); |
55 | case JoinType::LEFT: |
56 | return PushdownLeftJoin(move(op), left_bindings, right_bindings); |
57 | case JoinType::MARK: |
58 | return PushdownMarkJoin(move(op), left_bindings, right_bindings); |
59 | case JoinType::SINGLE: |
60 | return PushdownSingleJoin(move(op), left_bindings, right_bindings); |
61 | default: |
62 | // unsupported join type: stop pushing down |
63 | return FinishPushdown(move(op)); |
64 | } |
65 | } |
66 | void FilterPushdown::PushFilters() { |
67 | for (auto &f : filters) { |
68 | auto result = combiner.AddFilter(move(f->filter)); |
69 | assert(result == FilterResult::SUCCESS); |
70 | } |
71 | filters.clear(); |
72 | } |
73 | FilterResult FilterPushdown::AddFilter(unique_ptr<Expression> expr) { |
74 | PushFilters(); |
75 | // split up the filters by AND predicate |
76 | vector<unique_ptr<Expression>> expressions; |
77 | expressions.push_back(move(expr)); |
78 | LogicalFilter::SplitPredicates(expressions); |
79 | // push the filters into the combiner |
80 | for (auto &expr : expressions) { |
81 | if (combiner.AddFilter(move(expr)) == FilterResult::UNSATISFIABLE) { |
82 | return FilterResult::UNSATISFIABLE; |
83 | } |
84 | } |
85 | return FilterResult::SUCCESS; |
86 | } |
87 | |
88 | void FilterPushdown::GenerateFilters() { |
89 | if (filters.size() > 0) { |
90 | assert(!combiner.HasFilters()); |
91 | return; |
92 | } |
93 | combiner.GenerateFilters([&](unique_ptr<Expression> filter) { |
94 | auto f = make_unique<Filter>(); |
95 | f->filter = move(filter); |
96 | f->ExtractBindings(); |
97 | filters.push_back(move(f)); |
98 | }); |
99 | } |
100 | |
101 | unique_ptr<LogicalOperator> FilterPushdown::FinishPushdown(unique_ptr<LogicalOperator> op) { |
102 | // unhandled type, first perform filter pushdown in its children |
103 | for (idx_t i = 0; i < op->children.size(); i++) { |
104 | FilterPushdown pushdown(optimizer); |
105 | op->children[i] = pushdown.Rewrite(move(op->children[i])); |
106 | } |
107 | // now push any existing filters |
108 | if (filters.size() == 0) { |
109 | // no filters to push |
110 | return op; |
111 | } |
112 | auto filter = make_unique<LogicalFilter>(); |
113 | for (auto &f : filters) { |
114 | filter->expressions.push_back(move(f->filter)); |
115 | } |
116 | filter->children.push_back(move(op)); |
117 | return move(filter); |
118 | } |
119 | |
120 | void FilterPushdown::Filter::() { |
121 | bindings.clear(); |
122 | LogicalJoin::GetExpressionBindings(*filter, bindings); |
123 | } |
124 | |