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 |