| 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 |  | 
|---|
| 8 | using namespace duckdb; | 
|---|
| 9 | using namespace std; | 
|---|
| 10 |  | 
|---|
| 11 | unique_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 |  | 
|---|
| 63 | unique_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 |  | 
|---|