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
10using namespace duckdb;
11using namespace std;
12
13unique_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
28unique_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
63unique_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