| 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 | |