1#include "duckdb/planner/expression/bound_cast_expression.hpp"
2#include "duckdb/planner/expression/bound_columnref_expression.hpp"
3#include "duckdb/planner/binder.hpp"
4#include "duckdb/planner/operator/logical_projection.hpp"
5#include "duckdb/planner/operator/logical_set_operation.hpp"
6#include "duckdb/planner/query_node/bound_set_operation_node.hpp"
7
8using namespace duckdb;
9using namespace std;
10
11unique_ptr<LogicalOperator> Binder::CastLogicalOperatorToTypes(vector<SQLType> &source_types,
12 vector<SQLType> &target_types,
13 unique_ptr<LogicalOperator> op) {
14 assert(op);
15 // first check if we even need to cast
16 assert(source_types.size() == target_types.size());
17 if (source_types == target_types) {
18 // source and target types are equal: don't need to cast
19 return op;
20 }
21 // otherwise add casts
22 auto node = op.get();
23 if (node->type == LogicalOperatorType::PROJECTION) {
24 // "node" is a projection; we can just do the casts in there
25 assert(node->expressions.size() == source_types.size());
26 // add the casts to the selection list
27 for (idx_t i = 0; i < target_types.size(); i++) {
28 if (source_types[i] != target_types[i]) {
29 // differing types, have to add a cast
30 string alias = node->expressions[i]->alias;
31 node->expressions[i] = make_unique<BoundCastExpression>(
32 GetInternalType(target_types[i]), move(node->expressions[i]), source_types[i], target_types[i]);
33 node->expressions[i]->alias = alias;
34 }
35 }
36 return op;
37 } else {
38 // found a non-projection operator
39 // push a new projection containing the casts
40
41 // fetch the set of column bindings
42 auto setop_columns = op->GetColumnBindings();
43 assert(setop_columns.size() == source_types.size());
44
45 // now generate the expression list
46 vector<unique_ptr<Expression>> select_list;
47 for (idx_t i = 0; i < target_types.size(); i++) {
48 unique_ptr<Expression> result =
49 make_unique<BoundColumnRefExpression>(GetInternalType(source_types[i]), setop_columns[i]);
50 if (source_types[i] != target_types[i]) {
51 // add a cast only if the source and target types are not equivalent
52 result = make_unique<BoundCastExpression>(GetInternalType(target_types[i]), move(result),
53 source_types[i], target_types[i]);
54 }
55 select_list.push_back(move(result));
56 }
57 auto projection = make_unique<LogicalProjection>(GenerateTableIndex(), move(select_list));
58 projection->children.push_back(move(op));
59 return move(projection);
60 }
61}
62
63unique_ptr<LogicalOperator> Binder::CreatePlan(BoundSetOperationNode &node) {
64 // Generate the logical plan for the left and right sides of the set operation
65 node.left_binder->plan_subquery = plan_subquery;
66 node.right_binder->plan_subquery = plan_subquery;
67
68 auto left_node = node.left_binder->CreatePlan(*node.left);
69 auto right_node = node.right_binder->CreatePlan(*node.right);
70
71 // check if there are any unplanned subqueries left in either child
72 has_unplanned_subqueries =
73 node.left_binder->has_unplanned_subqueries || node.right_binder->has_unplanned_subqueries;
74
75 // for both the left and right sides, cast them to the same types
76 left_node = CastLogicalOperatorToTypes(node.left->types, node.types, move(left_node));
77 right_node = CastLogicalOperatorToTypes(node.right->types, node.types, move(right_node));
78
79 // create actual logical ops for setops
80 LogicalOperatorType logical_type;
81 switch (node.setop_type) {
82 case SetOperationType::UNION:
83 logical_type = LogicalOperatorType::UNION;
84 break;
85 case SetOperationType::EXCEPT:
86 logical_type = LogicalOperatorType::EXCEPT;
87 break;
88 default:
89 assert(node.setop_type == SetOperationType::INTERSECT);
90 logical_type = LogicalOperatorType::INTERSECT;
91 break;
92 }
93 auto root = make_unique<LogicalSetOperation>(node.setop_index, node.types.size(), move(left_node), move(right_node),
94 logical_type);
95
96 return VisitQueryNode(node, move(root));
97}
98