| 1 | #include "duckdb/execution/operator/aggregate/physical_hash_aggregate.hpp" |
| 2 | #include "duckdb/execution/operator/projection/physical_projection.hpp" |
| 3 | #include "duckdb/execution/physical_plan_generator.hpp" |
| 4 | #include "duckdb/function/aggregate/distributive_functions.hpp" |
| 5 | #include "duckdb/planner/expression/bound_aggregate_expression.hpp" |
| 6 | #include "duckdb/planner/expression/bound_columnref_expression.hpp" |
| 7 | #include "duckdb/planner/expression/bound_reference_expression.hpp" |
| 8 | #include "duckdb/planner/operator/logical_distinct.hpp" |
| 9 | |
| 10 | using namespace duckdb; |
| 11 | using namespace std; |
| 12 | |
| 13 | unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreateDistinct(unique_ptr<PhysicalOperator> child) { |
| 14 | assert(child); |
| 15 | // create a PhysicalHashAggregate that groups by the input columns |
| 16 | auto &types = child->GetTypes(); |
| 17 | vector<unique_ptr<Expression>> groups, expressions; |
| 18 | for (idx_t i = 0; i < types.size(); i++) { |
| 19 | groups.push_back(make_unique<BoundReferenceExpression>(types[i], i)); |
| 20 | } |
| 21 | |
| 22 | auto groupby = |
| 23 | make_unique<PhysicalHashAggregate>(types, move(expressions), move(groups), PhysicalOperatorType::DISTINCT); |
| 24 | groupby->children.push_back(move(child)); |
| 25 | return move(groupby); |
| 26 | } |
| 27 | |
| 28 | unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreateDistinctOn(unique_ptr<PhysicalOperator> child, |
| 29 | vector<unique_ptr<Expression>> distinct_targets) { |
| 30 | assert(child); |
| 31 | assert(distinct_targets.size() > 0); |
| 32 | |
| 33 | auto &types = child->GetTypes(); |
| 34 | vector<unique_ptr<Expression>> groups, aggregates, projections; |
| 35 | // creates one group per distinct_target |
| 36 | for (auto &target : distinct_targets) { |
| 37 | groups.push_back(move(target)); |
| 38 | } |
| 39 | // we need to create one aggregate per column in the select_list |
| 40 | for (idx_t i = 0; i < types.size(); ++i) { |
| 41 | // first we create an aggregate that returns the FIRST element |
| 42 | auto bound = make_unique<BoundReferenceExpression>(types[i], i); |
| 43 | auto first_aggregate = make_unique<BoundAggregateExpression>( |
| 44 | types[i], FirstFun::GetFunction(SQLTypeFromInternalType(types[i])), false); |
| 45 | first_aggregate->children.push_back(move(bound)); |
| 46 | // and push it to the list of aggregates |
| 47 | aggregates.push_back(move(first_aggregate)); |
| 48 | projections.push_back(make_unique<BoundReferenceExpression>(types[i], i)); |
| 49 | } |
| 50 | |
| 51 | // we add a physical hash aggregation in the plan to select the distinct groups |
| 52 | auto groupby = |
| 53 | make_unique<PhysicalHashAggregate>(types, move(aggregates), move(groups), PhysicalOperatorType::DISTINCT); |
| 54 | groupby->children.push_back(move(child)); |
| 55 | |
| 56 | // we add a physical projection on top of the aggregation to project all members in the select list |
| 57 | auto aggr_projection = make_unique<PhysicalProjection>(types, move(projections)); |
| 58 | aggr_projection->children.push_back(move(groupby)); |
| 59 | |
| 60 | return move(aggr_projection); |
| 61 | } |
| 62 | |
| 63 | unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreatePlan(LogicalDistinct &op) { |
| 64 | assert(op.children.size() == 1); |
| 65 | auto plan = CreatePlan(*op.children[0]); |
| 66 | if (op.distinct_targets.size() > 0) { |
| 67 | return CreateDistinctOn(move(plan), move(op.distinct_targets)); |
| 68 | } else { |
| 69 | return CreateDistinct(move(plan)); |
| 70 | } |
| 71 | } |
| 72 | |