1#include "duckdb/optimizer/filter_pushdown.hpp"
2#include "duckdb/optimizer/optimizer.hpp"
3#include "duckdb/planner/binder.hpp"
4#include "duckdb/planner/expression/bound_columnref_expression.hpp"
5#include "duckdb/planner/expression_iterator.hpp"
6#include "duckdb/planner/operator/logical_set_operation.hpp"
7
8using namespace duckdb;
9using namespace std;
10
11using Filter = FilterPushdown::Filter;
12
13static void ReplaceSetOpBindings(vector<ColumnBinding> &bindings, Filter &filter, Expression &expr,
14 LogicalSetOperation &setop) {
15 if (expr.type == ExpressionType::BOUND_COLUMN_REF) {
16 auto &colref = (BoundColumnRefExpression &)expr;
17 assert(colref.binding.table_index == setop.table_index);
18 assert(colref.depth == 0);
19
20 // rewrite the binding by looking into the bound_tables list of the subquery
21 colref.binding = bindings[colref.binding.column_index];
22 filter.bindings.insert(colref.binding.table_index);
23 return;
24 }
25 ExpressionIterator::EnumerateChildren(
26 expr, [&](Expression &child) { ReplaceSetOpBindings(bindings, filter, child, setop); });
27}
28
29unique_ptr<LogicalOperator> FilterPushdown::PushdownSetOperation(unique_ptr<LogicalOperator> op) {
30 assert(op->type == LogicalOperatorType::UNION || op->type == LogicalOperatorType::EXCEPT ||
31 op->type == LogicalOperatorType::INTERSECT);
32 auto &setop = (LogicalSetOperation &)*op;
33
34 assert(op->children.size() == 2);
35 auto left_bindings = op->children[0]->GetColumnBindings();
36 auto right_bindings = op->children[1]->GetColumnBindings();
37
38 // pushdown into set operation, we can duplicate the condition and pushdown the expressions into both sides
39 FilterPushdown left_pushdown(optimizer), right_pushdown(optimizer);
40 for (idx_t i = 0; i < filters.size(); i++) {
41 // first create a copy of the filter
42 auto right_filter = make_unique<Filter>();
43 right_filter->filter = filters[i]->filter->Copy();
44
45 // in the original filter, rewrite references to the result of the union into references to the left_index
46 ReplaceSetOpBindings(left_bindings, *filters[i], *filters[i]->filter, setop);
47 // in the copied filter, rewrite references to the result of the union into references to the right_index
48 ReplaceSetOpBindings(right_bindings, *right_filter, *right_filter->filter, setop);
49
50 // extract bindings again
51 filters[i]->ExtractBindings();
52 right_filter->ExtractBindings();
53
54 // move the filters into the child pushdown nodes
55 left_pushdown.filters.push_back(move(filters[i]));
56 right_pushdown.filters.push_back(move(right_filter));
57 }
58
59 op->children[0] = left_pushdown.Rewrite(move(op->children[0]));
60 op->children[1] = right_pushdown.Rewrite(move(op->children[1]));
61 return op;
62}
63