1 | #include "duckdb/planner/joinside.hpp" |
2 | |
3 | #include "duckdb/planner/expression/bound_columnref_expression.hpp" |
4 | #include "duckdb/planner/expression/bound_comparison_expression.hpp" |
5 | #include "duckdb/planner/expression/bound_subquery_expression.hpp" |
6 | #include "duckdb/planner/expression_iterator.hpp" |
7 | |
8 | using namespace duckdb; |
9 | using namespace std; |
10 | |
11 | unique_ptr<Expression> JoinCondition::CreateExpression(JoinCondition cond) { |
12 | return make_unique<BoundComparisonExpression>(cond.comparison, move(cond.left), move(cond.right)); |
13 | } |
14 | |
15 | JoinSide JoinSide::CombineJoinSide(JoinSide left, JoinSide right) { |
16 | if (left == JoinSide::NONE) { |
17 | return right; |
18 | } |
19 | if (right == JoinSide::NONE) { |
20 | return left; |
21 | } |
22 | if (left != right) { |
23 | return JoinSide::BOTH; |
24 | } |
25 | return left; |
26 | } |
27 | |
28 | JoinSide JoinSide::GetJoinSide(idx_t table_binding, unordered_set<idx_t> &left_bindings, |
29 | unordered_set<idx_t> &right_bindings) { |
30 | if (left_bindings.find(table_binding) != left_bindings.end()) { |
31 | // column references table on left side |
32 | assert(right_bindings.find(table_binding) == right_bindings.end()); |
33 | return JoinSide::LEFT; |
34 | } else { |
35 | // column references table on right side |
36 | assert(right_bindings.find(table_binding) != right_bindings.end()); |
37 | return JoinSide::RIGHT; |
38 | } |
39 | } |
40 | |
41 | JoinSide JoinSide::GetJoinSide(Expression &expression, unordered_set<idx_t> &left_bindings, |
42 | unordered_set<idx_t> &right_bindings) { |
43 | if (expression.type == ExpressionType::BOUND_COLUMN_REF) { |
44 | auto &colref = (BoundColumnRefExpression &)expression; |
45 | if (colref.depth > 0) { |
46 | throw Exception("Non-inner join on correlated columns not supported" ); |
47 | } |
48 | return GetJoinSide(colref.binding.table_index, left_bindings, right_bindings); |
49 | } |
50 | assert(expression.type != ExpressionType::BOUND_REF); |
51 | if (expression.type == ExpressionType::SUBQUERY) { |
52 | assert(expression.GetExpressionClass() == ExpressionClass::BOUND_SUBQUERY); |
53 | auto &subquery = (BoundSubqueryExpression &)expression; |
54 | // correlated subquery, check the side of each of correlated columns in the subquery |
55 | JoinSide side = JoinSide::NONE; |
56 | for (auto &corr : subquery.binder->correlated_columns) { |
57 | if (corr.depth > 1) { |
58 | // correlated column has depth > 1 |
59 | // it does not refer to any table in the current set of bindings |
60 | return JoinSide::BOTH; |
61 | } |
62 | auto correlated_side = GetJoinSide(corr.binding.table_index, left_bindings, right_bindings); |
63 | side = CombineJoinSide(side, correlated_side); |
64 | } |
65 | return side; |
66 | } |
67 | JoinSide join_side = JoinSide::NONE; |
68 | ExpressionIterator::EnumerateChildren(expression, [&](Expression &child) { |
69 | auto child_side = GetJoinSide(child, left_bindings, right_bindings); |
70 | join_side = CombineJoinSide(child_side, join_side); |
71 | }); |
72 | return join_side; |
73 | } |
74 | |
75 | JoinSide JoinSide::GetJoinSide(unordered_set<idx_t> bindings, unordered_set<idx_t> &left_bindings, |
76 | unordered_set<idx_t> &right_bindings) { |
77 | JoinSide side = JoinSide::NONE; |
78 | for (auto binding : bindings) { |
79 | side = CombineJoinSide(side, GetJoinSide(binding, left_bindings, right_bindings)); |
80 | } |
81 | return side; |
82 | } |
83 | |