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