| 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 | |
| 15 | namespace duckdb { |
| 16 | |
| 17 | Planner::Planner(ClientContext &context) : binder(Binder::CreateBinder(context)), context(context) { |
| 18 | } |
| 19 | |
| 20 | static 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 | |
| 29 | void 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 ¶meter_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 | |
| 96 | shared_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 | |
| 111 | void 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 | |
| 145 | static 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 | |
| 154 | void 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 | |