1#include "duckdb/parser/expression/columnref_expression.hpp"
2#include "duckdb/parser/expression/constant_expression.hpp"
3#include "duckdb/parser/expression_map.hpp"
4#include "duckdb/parser/query_node/select_node.hpp"
5#include "duckdb/parser/query_node/set_operation_node.hpp"
6#include "duckdb/planner/binder.hpp"
7#include "duckdb/planner/expression/bound_columnref_expression.hpp"
8#include "duckdb/planner/query_node/bound_set_operation_node.hpp"
9#include "duckdb/planner/query_node/bound_select_node.hpp"
10#include "duckdb/planner/expression_binder/order_binder.hpp"
11
12using namespace std;
13
14namespace duckdb {
15
16static void GatherAliases(BoundQueryNode &node, unordered_map<string, idx_t> &aliases,
17 expression_map_t<idx_t> &expressions) {
18 if (node.type == QueryNodeType::SET_OPERATION_NODE) {
19 // setop, recurse
20 auto &setop = (BoundSetOperationNode &)node;
21 GatherAliases(*setop.left, aliases, expressions);
22 GatherAliases(*setop.right, aliases, expressions);
23 } else {
24 // query node
25 assert(node.type == QueryNodeType::SELECT_NODE);
26 auto &select = (BoundSelectNode &)node;
27 // fill the alias lists
28 for (idx_t i = 0; i < select.names.size(); i++) {
29 auto &name = select.names[i];
30 auto &expr = select.original_expressions[i];
31 // first check if the alias is already in there
32 auto entry = aliases.find(name);
33 if (entry != aliases.end()) {
34 // the alias already exists
35 // check if there is a conflict
36 if (entry->second != i) {
37 // there is a conflict
38 // we place "-1" in the aliases map at this location
39 // "-1" signifies that there is an ambiguous reference
40 aliases[name] = INVALID_INDEX;
41 }
42 } else {
43 // the alias is not in there yet, just assign it
44 aliases[name] = i;
45 }
46 // now check if the node is already in the set of expressions
47 auto expr_entry = expressions.find(expr.get());
48 if (expr_entry != expressions.end()) {
49 // the node is in there
50 // repeat the same as with the alias: if there is an ambiguity we insert "-1"
51 if (expr_entry->second != i) {
52 expressions[expr.get()] = INVALID_INDEX;
53 }
54 } else {
55 // not in there yet, just place it in there
56 expressions[expr.get()] = i;
57 }
58 }
59 }
60}
61
62unique_ptr<BoundQueryNode> Binder::BindNode(SetOperationNode &statement) {
63 auto result = make_unique<BoundSetOperationNode>();
64 result->setop_type = statement.setop_type;
65
66 // first recursively visit the set operations
67 // both the left and right sides have an independent BindContext and Binder
68 assert(statement.left);
69 assert(statement.right);
70
71 result->setop_index = GenerateTableIndex();
72
73 result->left_binder = make_unique<Binder>(context, this);
74 result->left = result->left_binder->BindNode(*statement.left);
75
76 result->right_binder = make_unique<Binder>(context, this);
77 result->right = result->right_binder->BindNode(*statement.right);
78
79 if (statement.modifiers.size() > 0) {
80 // handle the ORDER BY/DISTINCT clauses
81
82 // we recursively visit the children of this node to extract aliases and expressions that can be referenced in
83 // the ORDER BY
84 unordered_map<string, idx_t> alias_map;
85 expression_map_t<idx_t> expression_map;
86 GatherAliases(*result, alias_map, expression_map);
87
88 // now we perform the actual resolution of the ORDER BY/DISTINCT expressions
89 OrderBinder order_binder({result->left_binder.get(), result->right_binder.get()}, result->setop_index,
90 alias_map, expression_map, statement.left->GetSelectList().size());
91 BindModifiers(order_binder, statement, *result);
92 }
93
94 result->names = result->left->names;
95
96 // move the correlated expressions from the child binders to this binder
97 MoveCorrelatedExpressions(*result->left_binder);
98 MoveCorrelatedExpressions(*result->right_binder);
99
100 // now both sides have been bound we can resolve types
101 if (result->left->types.size() != result->right->types.size()) {
102 throw Exception("Set operations can only apply to expressions with the "
103 "same number of result columns");
104 }
105
106 // figure out the types of the setop result by picking the max of both
107 for (idx_t i = 0; i < result->left->types.size(); i++) {
108 auto result_type = MaxSQLType(result->left->types[i], result->right->types[i]);
109 result->types.push_back(result_type);
110 }
111
112 // finally bind the types of the ORDER/DISTINCT clause expressions
113 BindModifierTypes(*result, result->types, result->setop_index);
114 return move(result);
115}
116
117} // namespace duckdb
118