| 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 | |
| 9 | namespace duckdb { |
| 10 | |
| 11 | unique_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 | |
| 18 | unique_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 | |