| 1 | #include "duckdb/planner/binder.hpp" |
|---|---|
| 2 | #include "duckdb/parser/statement/execute_statement.hpp" |
| 3 | #include "duckdb/planner/planner.hpp" |
| 4 | #include "duckdb/planner/operator/logical_execute.hpp" |
| 5 | #include "duckdb/planner/expression_binder/constant_binder.hpp" |
| 6 | #include "duckdb/main/client_config.hpp" |
| 7 | #include "duckdb/main/client_data.hpp" |
| 8 | #include "duckdb/execution/expression_executor.hpp" |
| 9 | |
| 10 | namespace duckdb { |
| 11 | |
| 12 | BoundStatement Binder::Bind(ExecuteStatement &stmt) { |
| 13 | auto parameter_count = stmt.n_param; |
| 14 | |
| 15 | // bind the prepared statement |
| 16 | auto &client_data = ClientData::Get(context); |
| 17 | |
| 18 | auto entry = client_data.prepared_statements.find(x: stmt.name); |
| 19 | if (entry == client_data.prepared_statements.end()) { |
| 20 | throw BinderException("Prepared statement \"%s\" does not exist", stmt.name); |
| 21 | } |
| 22 | |
| 23 | // check if we need to rebind the prepared statement |
| 24 | // this happens if the catalog changes, since in this case e.g. tables we relied on may have been deleted |
| 25 | auto prepared = entry->second; |
| 26 | |
| 27 | // bind any supplied parameters |
| 28 | vector<Value> bind_values; |
| 29 | auto constant_binder = Binder::CreateBinder(context); |
| 30 | constant_binder->SetCanContainNulls(true); |
| 31 | for (idx_t i = 0; i < stmt.values.size(); i++) { |
| 32 | ConstantBinder cbinder(*constant_binder, context, "EXECUTE statement"); |
| 33 | auto bound_expr = cbinder.Bind(expr&: stmt.values[i]); |
| 34 | |
| 35 | Value value = ExpressionExecutor::EvaluateScalar(context, expr: *bound_expr, allow_unfoldable: true); |
| 36 | bind_values.push_back(x: std::move(value)); |
| 37 | } |
| 38 | unique_ptr<LogicalOperator> rebound_plan; |
| 39 | if (prepared->RequireRebind(context, values: bind_values)) { |
| 40 | // catalog was modified or statement does not have clear types: rebind the statement before running the execute |
| 41 | Planner prepared_planner(context); |
| 42 | for (idx_t i = 0; i < bind_values.size(); i++) { |
| 43 | prepared_planner.parameter_data.emplace_back(args&: bind_values[i]); |
| 44 | } |
| 45 | prepared = prepared_planner.PrepareSQLStatement(statement: entry->second->unbound_statement->Copy()); |
| 46 | rebound_plan = std::move(prepared_planner.plan); |
| 47 | D_ASSERT(prepared->properties.bound_all_parameters); |
| 48 | this->bound_tables = prepared_planner.binder->bound_tables; |
| 49 | } |
| 50 | // copy the properties of the prepared statement into the planner |
| 51 | this->properties = prepared->properties; |
| 52 | this->properties.parameter_count = parameter_count; |
| 53 | BoundStatement result; |
| 54 | result.names = prepared->names; |
| 55 | result.types = prepared->types; |
| 56 | |
| 57 | prepared->Bind(values: std::move(bind_values)); |
| 58 | if (rebound_plan) { |
| 59 | auto execute_plan = make_uniq<LogicalExecute>(args: std::move(prepared)); |
| 60 | execute_plan->children.push_back(x: std::move(rebound_plan)); |
| 61 | result.plan = std::move(execute_plan); |
| 62 | } else { |
| 63 | result.plan = make_uniq<LogicalExecute>(args: std::move(prepared)); |
| 64 | } |
| 65 | return result; |
| 66 | } |
| 67 | |
| 68 | } // namespace duckdb |
| 69 |