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
8using namespace duckdb;
9using namespace std;
10
11unique_ptr<Expression> JoinCondition::CreateExpression(JoinCondition cond) {
12 return make_unique<BoundComparisonExpression>(cond.comparison, move(cond.left), move(cond.right));
13}
14
15JoinSide 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
28JoinSide 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
41JoinSide 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
75JoinSide 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