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
7using namespace duckdb;
8using namespace std;
9
10using Filter = FilterPushdown::Filter;
11
12unique_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
44unique_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}
66void 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}
73FilterResult 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
88void 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
101unique_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
120void FilterPushdown::Filter::ExtractBindings() {
121 bindings.clear();
122 LogicalJoin::GetExpressionBindings(*filter, bindings);
123}
124