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