| 1 | #include "duckdb/main/prepared_statement_data.hpp" |
| 2 | #include "duckdb/execution/physical_operator.hpp" |
| 3 | #include "duckdb/parser/sql_statement.hpp" |
| 4 | |
| 5 | namespace duckdb { |
| 6 | |
| 7 | PreparedStatementData::PreparedStatementData(StatementType type) : statement_type(type) { |
| 8 | } |
| 9 | |
| 10 | PreparedStatementData::~PreparedStatementData() { |
| 11 | } |
| 12 | |
| 13 | void PreparedStatementData::CheckParameterCount(idx_t parameter_count) { |
| 14 | const auto required = properties.parameter_count; |
| 15 | if (parameter_count != required) { |
| 16 | throw BinderException("Parameter/argument count mismatch for prepared statement. Expected %llu, got %llu" , |
| 17 | required, parameter_count); |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | bool PreparedStatementData::RequireRebind(ClientContext &context, const vector<Value> &values) { |
| 22 | CheckParameterCount(parameter_count: values.size()); |
| 23 | if (!unbound_statement) { |
| 24 | // no unbound statement!? cannot rebind? |
| 25 | return false; |
| 26 | } |
| 27 | if (!properties.bound_all_parameters) { |
| 28 | // parameters not yet bound: query always requires a rebind |
| 29 | return true; |
| 30 | } |
| 31 | if (Catalog::GetSystemCatalog(context).GetCatalogVersion() != catalog_version) { |
| 32 | //! context is out of bounds |
| 33 | return true; |
| 34 | } |
| 35 | for (auto &it : value_map) { |
| 36 | const idx_t i = it.first - 1; |
| 37 | if (values[i].type() != it.second->return_type) { |
| 38 | return true; |
| 39 | } |
| 40 | } |
| 41 | return false; |
| 42 | } |
| 43 | |
| 44 | void PreparedStatementData::Bind(vector<Value> values) { |
| 45 | // set parameters |
| 46 | D_ASSERT(!unbound_statement || unbound_statement->n_param == properties.parameter_count); |
| 47 | CheckParameterCount(parameter_count: values.size()); |
| 48 | |
| 49 | // bind the required values |
| 50 | for (auto &it : value_map) { |
| 51 | const idx_t i = it.first - 1; |
| 52 | if (i >= values.size()) { |
| 53 | throw BinderException("Could not find parameter with index %llu" , i + 1); |
| 54 | } |
| 55 | D_ASSERT(it.second); |
| 56 | if (!values[i].DefaultTryCastAs(target_type: it.second->return_type)) { |
| 57 | throw BinderException( |
| 58 | "Type mismatch for binding parameter with index %llu, expected type %s but got type %s" , i + 1, |
| 59 | it.second->return_type.ToString().c_str(), values[i].type().ToString().c_str()); |
| 60 | } |
| 61 | it.second->value = values[i]; |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | bool PreparedStatementData::TryGetType(idx_t param_idx, LogicalType &result) { |
| 66 | auto it = value_map.find(x: param_idx); |
| 67 | if (it == value_map.end()) { |
| 68 | return false; |
| 69 | } |
| 70 | if (it->second->return_type.id() != LogicalTypeId::INVALID) { |
| 71 | result = it->second->return_type; |
| 72 | } else { |
| 73 | result = it->second->value.type(); |
| 74 | } |
| 75 | return true; |
| 76 | } |
| 77 | |
| 78 | LogicalType PreparedStatementData::GetType(idx_t param_idx) { |
| 79 | LogicalType result; |
| 80 | if (!TryGetType(param_idx, result)) { |
| 81 | throw BinderException("Could not find parameter with index %llu" , param_idx); |
| 82 | } |
| 83 | return result; |
| 84 | } |
| 85 | |
| 86 | } // namespace duckdb |
| 87 | |