1#include "duckdb/planner/planner.hpp"
2
3#include "duckdb/common/serializer.hpp"
4#include "duckdb/common/serializer/buffered_deserializer.hpp"
5#include "duckdb/execution/expression_executor.hpp"
6#include "duckdb/main/client_context.hpp"
7#include "duckdb/main/client_data.hpp"
8#include "duckdb/main/database.hpp"
9#include "duckdb/main/prepared_statement_data.hpp"
10#include "duckdb/main/query_profiler.hpp"
11#include "duckdb/planner/binder.hpp"
12#include "duckdb/planner/expression/bound_parameter_expression.hpp"
13#include "duckdb/transaction/meta_transaction.hpp"
14
15namespace duckdb {
16
17Planner::Planner(ClientContext &context) : binder(Binder::CreateBinder(context)), context(context) {
18}
19
20static void CheckTreeDepth(const LogicalOperator &op, idx_t max_depth, idx_t depth = 0) {
21 if (depth >= max_depth) {
22 throw ParserException("Maximum tree depth of %lld exceeded in logical planner", max_depth);
23 }
24 for (auto &child : op.children) {
25 CheckTreeDepth(op: *child, max_depth, depth: depth + 1);
26 }
27}
28
29void Planner::CreatePlan(SQLStatement &statement) {
30 auto &profiler = QueryProfiler::Get(context);
31 auto parameter_count = statement.n_param;
32
33 BoundParameterMap bound_parameters(parameter_data);
34
35 // first bind the tables and columns to the catalog
36 bool parameters_resolved = true;
37 try {
38 profiler.StartPhase(phase: "binder");
39 binder->parameters = &bound_parameters;
40 auto bound_statement = binder->Bind(statement);
41 profiler.EndPhase();
42
43 this->names = bound_statement.names;
44 this->types = bound_statement.types;
45 this->plan = std::move(bound_statement.plan);
46
47 auto max_tree_depth = ClientConfig::GetConfig(context).max_expression_depth;
48 CheckTreeDepth(op: *plan, max_depth: max_tree_depth);
49 } catch (const ParameterNotResolvedException &ex) {
50 // parameter types could not be resolved
51 this->names = {"unknown"};
52 this->types = {LogicalTypeId::UNKNOWN};
53 this->plan = nullptr;
54 parameters_resolved = false;
55 } catch (const Exception &ex) {
56 auto &config = DBConfig::GetConfig(context);
57
58 this->plan = nullptr;
59 for (auto &extension_op : config.operator_extensions) {
60 auto bound_statement =
61 extension_op->Bind(context, *this->binder, extension_op->operator_info.get(), statement);
62 if (bound_statement.plan != nullptr) {
63 this->names = bound_statement.names;
64 this->types = bound_statement.types;
65 this->plan = std::move(bound_statement.plan);
66 break;
67 }
68 }
69
70 if (!this->plan) {
71 throw;
72 }
73 } catch (std::exception &ex) {
74 throw;
75 }
76 this->properties = binder->properties;
77 this->properties.parameter_count = parameter_count;
78 properties.bound_all_parameters = parameters_resolved;
79
80 Planner::VerifyPlan(context, op&: plan, map: &bound_parameters.parameters);
81
82 // set up a map of parameter number -> value entries
83 for (auto &kv : bound_parameters.parameters) {
84 auto parameter_index = kv.first;
85 auto &parameter_data = kv.second;
86 // check if the type of the parameter could be resolved
87 if (!parameter_data->return_type.IsValid()) {
88 properties.bound_all_parameters = false;
89 continue;
90 }
91 parameter_data->value = Value(parameter_data->return_type);
92 value_map[parameter_index] = parameter_data;
93 }
94}
95
96shared_ptr<PreparedStatementData> Planner::PrepareSQLStatement(unique_ptr<SQLStatement> statement) {
97 auto copied_statement = statement->Copy();
98 // create a plan of the underlying statement
99 CreatePlan(statement: std::move(statement));
100 // now create the logical prepare
101 auto prepared_data = make_shared<PreparedStatementData>(args&: copied_statement->type);
102 prepared_data->unbound_statement = std::move(copied_statement);
103 prepared_data->names = names;
104 prepared_data->types = types;
105 prepared_data->value_map = std::move(value_map);
106 prepared_data->properties = properties;
107 prepared_data->catalog_version = MetaTransaction::Get(context).catalog_version;
108 return prepared_data;
109}
110
111void Planner::CreatePlan(unique_ptr<SQLStatement> statement) {
112 D_ASSERT(statement);
113 switch (statement->type) {
114 case StatementType::SELECT_STATEMENT:
115 case StatementType::INSERT_STATEMENT:
116 case StatementType::COPY_STATEMENT:
117 case StatementType::DELETE_STATEMENT:
118 case StatementType::UPDATE_STATEMENT:
119 case StatementType::CREATE_STATEMENT:
120 case StatementType::DROP_STATEMENT:
121 case StatementType::ALTER_STATEMENT:
122 case StatementType::TRANSACTION_STATEMENT:
123 case StatementType::EXPLAIN_STATEMENT:
124 case StatementType::VACUUM_STATEMENT:
125 case StatementType::RELATION_STATEMENT:
126 case StatementType::CALL_STATEMENT:
127 case StatementType::EXPORT_STATEMENT:
128 case StatementType::PRAGMA_STATEMENT:
129 case StatementType::SHOW_STATEMENT:
130 case StatementType::SET_STATEMENT:
131 case StatementType::LOAD_STATEMENT:
132 case StatementType::EXTENSION_STATEMENT:
133 case StatementType::PREPARE_STATEMENT:
134 case StatementType::EXECUTE_STATEMENT:
135 case StatementType::LOGICAL_PLAN_STATEMENT:
136 case StatementType::ATTACH_STATEMENT:
137 case StatementType::DETACH_STATEMENT:
138 CreatePlan(statement&: *statement);
139 break;
140 default:
141 throw NotImplementedException("Cannot plan statement of type %s!", StatementTypeToString(type: statement->type));
142 }
143}
144
145static bool OperatorSupportsSerialization(LogicalOperator &op) {
146 for (auto &child : op.children) {
147 if (!OperatorSupportsSerialization(op&: *child)) {
148 return false;
149 }
150 }
151 return op.SupportSerialization();
152}
153
154void Planner::VerifyPlan(ClientContext &context, unique_ptr<LogicalOperator> &op, bound_parameter_map_t *map) {
155#ifdef DUCKDB_ALTERNATIVE_VERIFY
156 // if alternate verification is enabled we run the original operator
157 return;
158#endif
159 if (!op || !ClientConfig::GetConfig(context).verify_serializer) {
160 return;
161 }
162 //! SELECT only for now
163 if (!OperatorSupportsSerialization(op&: *op)) {
164 return;
165 }
166
167 BufferedSerializer serializer;
168 serializer.is_query_plan = true;
169 try {
170 op->Serialize(serializer);
171 } catch (NotImplementedException &ex) {
172 // ignore for now (FIXME)
173 return;
174 }
175 auto data = serializer.GetData();
176 auto deserializer = BufferedContextDeserializer(context, data.data.get(), data.size);
177
178 PlanDeserializationState state(context);
179 auto new_plan = LogicalOperator::Deserialize(deserializer, gstate&: state);
180 if (map) {
181 *map = std::move(state.parameter_data);
182 }
183 op = std::move(new_plan);
184}
185
186} // namespace duckdb
187