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
10namespace duckdb {
11
12BoundStatement 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