1#include "duckdb/planner/binder.hpp"
2#include "duckdb/planner/expression/bound_columnref_expression.hpp"
3#include "duckdb/planner/expression/bound_reference_expression.hpp"
4#include "duckdb/planner/operator/list.hpp"
5#include "duckdb/planner/operator/logical_dummy_scan.hpp"
6#include "duckdb/planner/operator/logical_limit.hpp"
7#include "duckdb/planner/query_node/bound_select_node.hpp"
8
9namespace duckdb {
10
11unique_ptr<LogicalOperator> Binder::PlanFilter(unique_ptr<Expression> condition, unique_ptr<LogicalOperator> root) {
12 PlanSubqueries(expr&: condition, root);
13 auto filter = make_uniq<LogicalFilter>(args: std::move(condition));
14 filter->AddChild(child: std::move(root));
15 return std::move(filter);
16}
17
18unique_ptr<LogicalOperator> Binder::CreatePlan(BoundSelectNode &statement) {
19 unique_ptr<LogicalOperator> root;
20 D_ASSERT(statement.from_table);
21 root = CreatePlan(ref&: *statement.from_table);
22 D_ASSERT(root);
23
24 // plan the sample clause
25 if (statement.sample_options) {
26 root = make_uniq<LogicalSample>(args: std::move(statement.sample_options), args: std::move(root));
27 }
28
29 if (statement.where_clause) {
30 root = PlanFilter(condition: std::move(statement.where_clause), root: std::move(root));
31 }
32
33 if (!statement.aggregates.empty() || !statement.groups.group_expressions.empty()) {
34 if (!statement.groups.group_expressions.empty()) {
35 // visit the groups
36 for (auto &group : statement.groups.group_expressions) {
37 PlanSubqueries(expr&: group, root);
38 }
39 }
40 // now visit all aggregate expressions
41 for (auto &expr : statement.aggregates) {
42 PlanSubqueries(expr, root);
43 }
44 // finally create the aggregate node with the group_index and aggregate_index as obtained from the binder
45 auto aggregate = make_uniq<LogicalAggregate>(args&: statement.group_index, args&: statement.aggregate_index,
46 args: std::move(statement.aggregates));
47 aggregate->groups = std::move(statement.groups.group_expressions);
48 aggregate->groupings_index = statement.groupings_index;
49 aggregate->grouping_sets = std::move(statement.groups.grouping_sets);
50 aggregate->grouping_functions = std::move(statement.grouping_functions);
51
52 aggregate->AddChild(child: std::move(root));
53 root = std::move(aggregate);
54 } else if (!statement.groups.grouping_sets.empty()) {
55 // edge case: we have grouping sets but no groups or aggregates
56 // this can only happen if we have e.g. select 1 from tbl group by ();
57 // just output a dummy scan
58 root = make_uniq_base<LogicalOperator, LogicalDummyScan>(args&: statement.group_index);
59 }
60
61 if (statement.having) {
62 PlanSubqueries(expr&: statement.having, root);
63 auto having = make_uniq<LogicalFilter>(args: std::move(statement.having));
64
65 having->AddChild(child: std::move(root));
66 root = std::move(having);
67 }
68
69 if (!statement.windows.empty()) {
70 auto win = make_uniq<LogicalWindow>(args&: statement.window_index);
71 win->expressions = std::move(statement.windows);
72 // visit the window expressions
73 for (auto &expr : win->expressions) {
74 PlanSubqueries(expr, root);
75 }
76 D_ASSERT(!win->expressions.empty());
77 win->AddChild(child: std::move(root));
78 root = std::move(win);
79 }
80
81 if (statement.qualify) {
82 PlanSubqueries(expr&: statement.qualify, root);
83 auto qualify = make_uniq<LogicalFilter>(args: std::move(statement.qualify));
84
85 qualify->AddChild(child: std::move(root));
86 root = std::move(qualify);
87 }
88
89 for (idx_t i = statement.unnests.size(); i > 0; i--) {
90 auto unnest_level = i - 1;
91 auto entry = statement.unnests.find(x: unnest_level);
92 if (entry == statement.unnests.end()) {
93 throw InternalException("unnests specified at level %d but none were found", unnest_level);
94 }
95 auto &unnest_node = entry->second;
96 auto unnest = make_uniq<LogicalUnnest>(args&: unnest_node.index);
97 unnest->expressions = std::move(unnest_node.expressions);
98 // visit the unnest expressions
99 for (auto &expr : unnest->expressions) {
100 PlanSubqueries(expr, root);
101 }
102 D_ASSERT(!unnest->expressions.empty());
103 unnest->AddChild(child: std::move(root));
104 root = std::move(unnest);
105 }
106
107 for (auto &expr : statement.select_list) {
108 PlanSubqueries(expr, root);
109 }
110
111 auto proj = make_uniq<LogicalProjection>(args&: statement.projection_index, args: std::move(statement.select_list));
112 auto &projection = *proj;
113 proj->AddChild(child: std::move(root));
114 root = std::move(proj);
115
116 // finish the plan by handling the elements of the QueryNode
117 root = VisitQueryNode(node&: statement, root: std::move(root));
118
119 // add a prune node if necessary
120 if (statement.need_prune) {
121 D_ASSERT(root);
122 vector<unique_ptr<Expression>> prune_expressions;
123 for (idx_t i = 0; i < statement.column_count; i++) {
124 prune_expressions.push_back(x: make_uniq<BoundColumnRefExpression>(
125 args&: projection.expressions[i]->return_type, args: ColumnBinding(statement.projection_index, i)));
126 }
127 auto prune = make_uniq<LogicalProjection>(args&: statement.prune_index, args: std::move(prune_expressions));
128 prune->AddChild(child: std::move(root));
129 root = std::move(prune);
130 }
131 return root;
132}
133
134} // namespace duckdb
135