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