1 | #include "duckdb/parser/tableref/joinref.hpp" |
2 | #include "duckdb/planner/binder.hpp" |
3 | #include "duckdb/planner/expression_binder/where_binder.hpp" |
4 | #include "duckdb/planner/tableref/bound_joinref.hpp" |
5 | #include "duckdb/parser/expression/columnref_expression.hpp" |
6 | #include "duckdb/parser/expression/comparison_expression.hpp" |
7 | #include "duckdb/parser/expression/conjunction_expression.hpp" |
8 | |
9 | using namespace duckdb; |
10 | using namespace std; |
11 | |
12 | unique_ptr<BoundTableRef> Binder::Bind(JoinRef &ref) { |
13 | auto result = make_unique<BoundJoinRef>(); |
14 | result->type = ref.type; |
15 | if (ref.using_columns.size() > 0) { |
16 | // USING columns |
17 | assert(!result->condition); |
18 | vector<string> left_join_bindings; |
19 | vector<unordered_set<string>> matching_left_bindings; |
20 | |
21 | result->left = Bind(*ref.left); |
22 | for (auto &using_column : ref.using_columns) { |
23 | // for each using column, get the matching binding |
24 | auto left_bindings = bind_context.GetMatchingBindings(using_column); |
25 | if (left_bindings.size() == 0) { |
26 | throw BinderException("Column \"%s\" does not exist on left side of join!" , using_column.c_str()); |
27 | } |
28 | // find the join binding |
29 | string left_binding; |
30 | for (auto &binding : left_bindings) { |
31 | if (!bind_context.BindingIsHidden(binding, using_column)) { |
32 | if (!left_binding.empty()) { |
33 | string error = "Column name \"" + using_column + |
34 | "\" is ambiguous: it exists more than once on left side of join.\nCandidates:" ; |
35 | for (auto &binding : left_bindings) { |
36 | error += "\n\t" + binding + "." + using_column; |
37 | } |
38 | throw BinderException(error); |
39 | } else { |
40 | left_binding = binding; |
41 | } |
42 | } |
43 | } |
44 | left_join_bindings.push_back(left_binding); |
45 | matching_left_bindings.push_back(move(left_bindings)); |
46 | } |
47 | result->right = Bind(*ref.right); |
48 | for (idx_t i = 0; i < ref.using_columns.size(); i++) { |
49 | auto &using_column = ref.using_columns[i]; |
50 | auto &left_bindings = matching_left_bindings[i]; |
51 | auto left_binding = left_join_bindings[i]; |
52 | |
53 | auto all_bindings = bind_context.GetMatchingBindings(using_column); |
54 | string right_binding; |
55 | for (auto &binding : all_bindings) { |
56 | if (left_bindings.find(binding) == left_bindings.end()) { |
57 | assert(right_binding.empty()); |
58 | right_binding = binding; |
59 | } |
60 | } |
61 | if (right_binding.empty()) { |
62 | throw BinderException("Column \"%s\" does not exist on right side of join!" , using_column.c_str()); |
63 | } |
64 | assert(!left_binding.empty()); |
65 | auto left_expr = make_unique<ColumnRefExpression>(using_column, left_binding); |
66 | auto right_expr = make_unique<ColumnRefExpression>(using_column, right_binding); |
67 | bind_context.hidden_columns.insert(right_expr->table_name + "." + right_expr->column_name); |
68 | auto comp_expr = |
69 | make_unique<ComparisonExpression>(ExpressionType::COMPARE_EQUAL, move(left_expr), move(right_expr)); |
70 | if (!ref.condition) { |
71 | ref.condition = move(comp_expr); |
72 | } else { |
73 | ref.condition = make_unique<ConjunctionExpression>(ExpressionType::CONJUNCTION_AND, move(ref.condition), |
74 | move(comp_expr)); |
75 | } |
76 | } |
77 | } else { |
78 | result->left = Bind(*ref.left); |
79 | result->right = Bind(*ref.right); |
80 | } |
81 | if (ref.condition) { |
82 | WhereBinder binder(*this, context); |
83 | result->condition = binder.Bind(ref.condition); |
84 | } |
85 | return move(result); |
86 | } |
87 | |