duckdb 0.8.2-dev2509.0 → 0.8.2-dev2673.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/binding.gyp +1 -0
  2. package/package.json +1 -1
  3. package/src/duckdb/extension/icu/icu-datepart.cpp +3 -3
  4. package/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +1 -1
  5. package/src/duckdb/src/catalog/default/default_functions.cpp +5 -0
  6. package/src/duckdb/src/common/enum_util.cpp +35 -1
  7. package/src/duckdb/src/core_functions/aggregate/nested/list.cpp +6 -1
  8. package/src/duckdb/src/core_functions/scalar/list/array_slice.cpp +6 -0
  9. package/src/duckdb/src/execution/expression_executor/execute_parameter.cpp +2 -2
  10. package/src/duckdb/src/execution/index/art/art.cpp +43 -31
  11. package/src/duckdb/src/execution/index/art/leaf.cpp +47 -33
  12. package/src/duckdb/src/execution/index/art/node.cpp +31 -24
  13. package/src/duckdb/src/execution/index/art/prefix.cpp +100 -16
  14. package/src/duckdb/src/execution/operator/schema/physical_create_index.cpp +54 -31
  15. package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +32 -15
  16. package/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp +57 -0
  17. package/src/duckdb/src/function/table/arrow.cpp +95 -92
  18. package/src/duckdb/src/function/table/arrow_conversion.cpp +45 -68
  19. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  20. package/src/duckdb/src/include/duckdb/common/case_insensitive_map.hpp +1 -0
  21. package/src/duckdb/src/include/duckdb/common/enum_util.hpp +8 -0
  22. package/src/duckdb/src/include/duckdb/common/helper.hpp +8 -3
  23. package/src/duckdb/src/include/duckdb/common/types/value.hpp +4 -1
  24. package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +7 -5
  25. package/src/duckdb/src/include/duckdb/execution/index/art/leaf.hpp +6 -6
  26. package/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +6 -0
  27. package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +9 -11
  28. package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_index.hpp +8 -1
  29. package/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp +99 -0
  30. package/src/duckdb/src/include/duckdb/function/table/arrow.hpp +6 -36
  31. package/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp +3 -1
  32. package/src/duckdb/src/include/duckdb/main/client_context.hpp +15 -14
  33. package/src/duckdb/src/include/duckdb/main/prepared_statement.hpp +73 -5
  34. package/src/duckdb/src/include/duckdb/main/prepared_statement_data.hpp +6 -6
  35. package/src/duckdb/src/include/duckdb/parser/expression/parameter_expression.hpp +17 -1
  36. package/src/duckdb/src/include/duckdb/parser/statement/execute_statement.hpp +1 -1
  37. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +5 -3
  38. package/src/duckdb/src/include/duckdb/planner/bound_parameter_map.hpp +2 -1
  39. package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_data.hpp +20 -5
  40. package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_expression.hpp +3 -3
  41. package/src/duckdb/src/include/duckdb/planner/planner.hpp +4 -3
  42. package/src/duckdb/src/include/duckdb/storage/object_cache.hpp +1 -1
  43. package/src/duckdb/src/include/duckdb/verification/prepared_statement_verifier.hpp +1 -1
  44. package/src/duckdb/src/include/duckdb.h +16 -0
  45. package/src/duckdb/src/main/capi/pending-c.cpp +6 -0
  46. package/src/duckdb/src/main/capi/prepared-c.cpp +52 -4
  47. package/src/duckdb/src/main/client_context.cpp +27 -17
  48. package/src/duckdb/src/main/client_verify.cpp +17 -0
  49. package/src/duckdb/src/main/prepared_statement.cpp +38 -11
  50. package/src/duckdb/src/main/prepared_statement_data.cpp +23 -18
  51. package/src/duckdb/src/parallel/executor.cpp +3 -0
  52. package/src/duckdb/src/parser/expression/parameter_expression.cpp +7 -7
  53. package/src/duckdb/src/parser/statement/execute_statement.cpp +2 -2
  54. package/src/duckdb/src/parser/transform/expression/transform_param_ref.cpp +45 -26
  55. package/src/duckdb/src/parser/transform/statement/transform_prepare.cpp +28 -6
  56. package/src/duckdb/src/parser/transformer.cpp +27 -9
  57. package/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp +10 -10
  58. package/src/duckdb/src/planner/binder/statement/bind_execute.cpp +13 -7
  59. package/src/duckdb/src/planner/expression/bound_parameter_expression.cpp +13 -13
  60. package/src/duckdb/src/planner/planner.cpp +7 -6
  61. package/src/duckdb/src/storage/checkpoint_manager.cpp +1 -1
  62. package/src/duckdb/src/storage/serialization/serialize_expression.cpp +3 -3
  63. package/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp +2 -2
  64. package/src/duckdb/src/verification/prepared_statement_verifier.cpp +16 -11
  65. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +9652 -9482
  66. package/src/duckdb/ub_src_function_table_arrow.cpp +2 -0
@@ -23,6 +23,7 @@
23
23
  #include "nodes/parsenodes.hpp"
24
24
  #include "nodes/primnodes.hpp"
25
25
  #include "pg_definitions.hpp"
26
+ #include "duckdb/parser/expression/parameter_expression.hpp"
26
27
 
27
28
  namespace duckdb {
28
29
 
@@ -67,6 +68,8 @@ private:
67
68
  idx_t prepared_statement_parameter_index = 0;
68
69
  //! Map from named parameter to parameter index;
69
70
  case_insensitive_map_t<idx_t> named_param_map;
71
+ //! Last parameter type
72
+ PreparedParamType last_param_type = PreparedParamType::INVALID;
70
73
  //! Holds window expressions defined by name. We need those when transforming the expressions referring to them.
71
74
  unordered_map<string, duckdb_libpgquery::PGWindowDef *> window_clauses;
72
75
  //! The set of pivot entries to create
@@ -82,9 +85,8 @@ private:
82
85
  Transformer &RootTransformer();
83
86
  const Transformer &RootTransformer() const;
84
87
  void SetParamCount(idx_t new_count);
85
- void SetNamedParam(const string &name, int32_t index);
86
- bool GetNamedParam(const string &name, int32_t &index);
87
- bool HasNamedParameters() const;
88
+ void SetParam(const string &name, idx_t index, PreparedParamType type);
89
+ bool GetParam(const string &name, idx_t &index, PreparedParamType type);
88
90
 
89
91
  void AddPivotEntry(string enum_name, unique_ptr<SelectNode> source, unique_ptr<ParsedExpression> column,
90
92
  unique_ptr<QueryNode> subquery);
@@ -10,11 +10,12 @@
10
10
 
11
11
  #include "duckdb/common/types.hpp"
12
12
  #include "duckdb/common/unordered_map.hpp"
13
+ #include "duckdb/common/case_insensitive_map.hpp"
13
14
 
14
15
  namespace duckdb {
15
16
 
16
17
  struct BoundParameterData;
17
18
 
18
- using bound_parameter_map_t = unordered_map<idx_t, shared_ptr<BoundParameterData>>;
19
+ using bound_parameter_map_t = case_insensitive_map_t<shared_ptr<BoundParameterData>>;
19
20
 
20
21
  } // namespace duckdb
@@ -11,19 +11,32 @@
11
11
  #include "duckdb/common/types/value.hpp"
12
12
  #include "duckdb/planner/bound_parameter_map.hpp"
13
13
  #include "duckdb/common/field_writer.hpp"
14
+ #include "duckdb/common/case_insensitive_map.hpp"
14
15
 
15
16
  namespace duckdb {
16
17
 
17
18
  struct BoundParameterData {
19
+ public:
18
20
  BoundParameterData() {
19
21
  }
20
22
  explicit BoundParameterData(Value val) : value(std::move(val)), return_type(value.type()) {
21
23
  }
22
24
 
25
+ private:
23
26
  Value value;
27
+
28
+ public:
24
29
  LogicalType return_type;
25
30
 
26
31
  public:
32
+ void SetValue(Value val) {
33
+ value = std::move(val);
34
+ }
35
+
36
+ const Value &GetValue() const {
37
+ return value;
38
+ }
39
+
27
40
  void Serialize(Serializer &serializer) const {
28
41
  FieldWriter writer(serializer);
29
42
  value.Serialize(writer.GetSerializer());
@@ -45,17 +58,19 @@ public:
45
58
  };
46
59
 
47
60
  struct BoundParameterMap {
48
- explicit BoundParameterMap(vector<BoundParameterData> &parameter_data) : parameter_data(parameter_data) {
61
+ explicit BoundParameterMap(case_insensitive_map_t<BoundParameterData> &parameter_data)
62
+ : parameter_data(parameter_data) {
49
63
  }
50
64
 
51
65
  bound_parameter_map_t parameters;
52
- vector<BoundParameterData> &parameter_data;
66
+ case_insensitive_map_t<BoundParameterData> &parameter_data;
53
67
 
54
- LogicalType GetReturnType(idx_t index) {
55
- if (index >= parameter_data.size()) {
68
+ LogicalType GetReturnType(const string &identifier) {
69
+ auto it = parameter_data.find(identifier);
70
+ if (it == parameter_data.end()) {
56
71
  return LogicalTypeId::UNKNOWN;
57
72
  }
58
- return parameter_data[index].return_type;
73
+ return it->second.return_type;
59
74
  }
60
75
  };
61
76
 
@@ -18,9 +18,9 @@ public:
18
18
  static constexpr const ExpressionClass TYPE = ExpressionClass::BOUND_PARAMETER;
19
19
 
20
20
  public:
21
- explicit BoundParameterExpression(idx_t parameter_nr);
21
+ explicit BoundParameterExpression(const string &identifier);
22
22
 
23
- idx_t parameter_nr;
23
+ string identifier;
24
24
  shared_ptr<BoundParameterData> parameter_data;
25
25
 
26
26
  public:
@@ -47,7 +47,7 @@ public:
47
47
  static unique_ptr<Expression> FormatDeserialize(FormatDeserializer &deserializer);
48
48
 
49
49
  private:
50
- BoundParameterExpression(bound_parameter_map_t &global_parameter_set, idx_t parameter_nr, LogicalType return_type,
50
+ BoundParameterExpression(bound_parameter_map_t &global_parameter_set, string identifier, LogicalType return_type,
51
51
  shared_ptr<BoundParameterData> parameter_data);
52
52
  };
53
53
 
@@ -25,21 +25,22 @@ class Planner {
25
25
  public:
26
26
  explicit Planner(ClientContext &context);
27
27
 
28
+ public:
28
29
  unique_ptr<LogicalOperator> plan;
29
30
  vector<string> names;
30
31
  vector<LogicalType> types;
31
- bound_parameter_map_t value_map;
32
- vector<BoundParameterData> parameter_data;
32
+ case_insensitive_map_t<BoundParameterData> parameter_data;
33
33
 
34
34
  shared_ptr<Binder> binder;
35
35
  ClientContext &context;
36
36
 
37
37
  StatementProperties properties;
38
+ bound_parameter_map_t value_map;
38
39
 
39
40
  public:
40
41
  void CreatePlan(unique_ptr<SQLStatement> statement);
41
42
  static void VerifyPlan(ClientContext &context, unique_ptr<LogicalOperator> &op,
42
- bound_parameter_map_t *map = nullptr);
43
+ optional_ptr<bound_parameter_map_t> map = nullptr);
43
44
 
44
45
  private:
45
46
  void CreatePlan(SQLStatement &statement);
@@ -48,7 +48,7 @@ public:
48
48
  }
49
49
 
50
50
  template <class T, class... Args>
51
- shared_ptr<T> GetOrCreate(const string &key, Args &&... args) {
51
+ shared_ptr<T> GetOrCreate(const string &key, Args &&...args) {
52
52
  lock_guard<mutex> glock(lock);
53
53
 
54
54
  auto entry = cache.find(key);
@@ -21,7 +21,7 @@ public:
21
21
  const std::function<unique_ptr<QueryResult>(const string &, unique_ptr<SQLStatement>)> &run) override;
22
22
 
23
23
  private:
24
- vector<unique_ptr<ParsedExpression>> values;
24
+ case_insensitive_map_t<unique_ptr<ParsedExpression>> values;
25
25
  unique_ptr<SQLStatement> prepare_statement;
26
26
  unique_ptr<SQLStatement> execute_statement;
27
27
  unique_ptr<SQLStatement> dealloc_statement;
@@ -944,6 +944,16 @@ Returns 0 if the query was not successfully prepared.
944
944
  */
945
945
  DUCKDB_API idx_t duckdb_nparams(duckdb_prepared_statement prepared_statement);
946
946
 
947
+ /*!
948
+ Returns the name used to identify the parameter
949
+ The returned string should be freed using `duckdb_free`.
950
+
951
+ Returns NULL if the index is out of range for the provided prepared statement.
952
+
953
+ * prepared_statement: The prepared statement for which to get the parameter name from.
954
+ */
955
+ const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, idx_t index);
956
+
947
957
  /*!
948
958
  Returns the parameter type for the parameter at the given index.
949
959
 
@@ -960,6 +970,12 @@ Clear the params bind to the prepared statement.
960
970
  */
961
971
  DUCKDB_API duckdb_state duckdb_clear_bindings(duckdb_prepared_statement prepared_statement);
962
972
 
973
+ /*!
974
+ Retrieve the index of the parameter for the prepared statement, identified by name
975
+ */
976
+ DUCKDB_API duckdb_state duckdb_bind_parameter_index(duckdb_prepared_statement prepared_statement, idx_t *param_idx_out,
977
+ const char *name);
978
+
963
979
  /*!
964
980
  Binds a bool value to the prepared statement at the specified index.
965
981
  */
@@ -2,12 +2,17 @@
2
2
  #include "duckdb/main/query_result.hpp"
3
3
  #include "duckdb/main/pending_query_result.hpp"
4
4
  #include "duckdb/common/preserved_error.hpp"
5
+ #include "duckdb/common/case_insensitive_map.hpp"
6
+ #include "duckdb/common/optional_ptr.hpp"
5
7
 
8
+ using duckdb::case_insensitive_map_t;
6
9
  using duckdb::make_uniq;
10
+ using duckdb::optional_ptr;
7
11
  using duckdb::PendingExecutionResult;
8
12
  using duckdb::PendingQueryResult;
9
13
  using duckdb::PendingStatementWrapper;
10
14
  using duckdb::PreparedStatementWrapper;
15
+ using duckdb::Value;
11
16
 
12
17
  duckdb_state duckdb_pending_prepared_internal(duckdb_prepared_statement prepared_statement,
13
18
  duckdb_pending_result *out_result, bool allow_streaming) {
@@ -17,6 +22,7 @@ duckdb_state duckdb_pending_prepared_internal(duckdb_prepared_statement prepared
17
22
  auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement);
18
23
  auto result = new PendingStatementWrapper();
19
24
  result->allow_streaming = allow_streaming;
25
+
20
26
  try {
21
27
  result->statement = wrapper->statement->PendingQuery(wrapper->values, allow_streaming);
22
28
  } catch (const duckdb::Exception &ex) {
@@ -2,7 +2,10 @@
2
2
  #include "duckdb/main/query_result.hpp"
3
3
  #include "duckdb/main/prepared_statement_data.hpp"
4
4
  #include "duckdb/common/types/decimal.hpp"
5
+ #include "duckdb/common/optional_ptr.hpp"
6
+ #include "duckdb/common/case_insensitive_map.hpp"
5
7
 
8
+ using duckdb::case_insensitive_map_t;
6
9
  using duckdb::Connection;
7
10
  using duckdb::date_t;
8
11
  using duckdb::dtime_t;
@@ -10,8 +13,10 @@ using duckdb::ExtractStatementsWrapper;
10
13
  using duckdb::hugeint_t;
11
14
  using duckdb::LogicalType;
12
15
  using duckdb::MaterializedQueryResult;
16
+ using duckdb::optional_ptr;
13
17
  using duckdb::PreparedStatementWrapper;
14
18
  using duckdb::QueryResultType;
19
+ using duckdb::StringUtil;
15
20
  using duckdb::timestamp_t;
16
21
  using duckdb::Value;
17
22
 
@@ -84,13 +89,42 @@ idx_t duckdb_nparams(duckdb_prepared_statement prepared_statement) {
84
89
  return wrapper->statement->n_param;
85
90
  }
86
91
 
92
+ static duckdb::string duckdb_parameter_name_internal(duckdb_prepared_statement prepared_statement, idx_t index) {
93
+ auto wrapper = (PreparedStatementWrapper *)prepared_statement;
94
+ if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
95
+ return duckdb::string();
96
+ }
97
+ if (index > wrapper->statement->n_param) {
98
+ return duckdb::string();
99
+ }
100
+ for (auto &item : wrapper->statement->named_param_map) {
101
+ auto &identifier = item.first;
102
+ auto &param_idx = item.second;
103
+ if (param_idx == index) {
104
+ // Found the matching parameter
105
+ return identifier;
106
+ }
107
+ }
108
+ // No parameter was found with this index
109
+ return duckdb::string();
110
+ }
111
+
112
+ const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, idx_t index) {
113
+ auto identifier = duckdb_parameter_name_internal(prepared_statement, index);
114
+ if (identifier == duckdb::string()) {
115
+ return NULL;
116
+ }
117
+ return strdup(identifier.c_str());
118
+ }
119
+
87
120
  duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) {
88
121
  auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement);
89
122
  if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
90
123
  return DUCKDB_TYPE_INVALID;
91
124
  }
92
125
  LogicalType param_type;
93
- if (!wrapper->statement->data->TryGetType(param_idx, param_type)) {
126
+ auto identifier = std::to_string(param_idx);
127
+ if (!wrapper->statement->data->TryGetType(identifier, param_type)) {
94
128
  return DUCKDB_TYPE_INVALID;
95
129
  }
96
130
  return ConvertCPPTypeToC(param_type);
@@ -113,10 +147,23 @@ static duckdb_state duckdb_bind_value(duckdb_prepared_statement prepared_stateme
113
147
  if (param_idx <= 0 || param_idx > wrapper->statement->n_param) {
114
148
  return DuckDBError;
115
149
  }
116
- if (param_idx > wrapper->values.size()) {
117
- wrapper->values.resize(param_idx);
150
+ auto identifier = duckdb_parameter_name_internal(prepared_statement, param_idx);
151
+ wrapper->values[identifier] = val;
152
+ return DuckDBSuccess;
153
+ }
154
+
155
+ duckdb_state duckdb_bind_parameter_index(duckdb_prepared_statement prepared_statement, idx_t *param_idx_out,
156
+ const char *name) {
157
+ auto wrapper = (PreparedStatementWrapper *)prepared_statement;
158
+ if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
159
+ return DuckDBError;
160
+ }
161
+ auto &statement = wrapper->statement;
162
+ auto entry = statement->named_param_map.find(name);
163
+ if (entry == statement->named_param_map.end()) {
164
+ return DuckDBError;
118
165
  }
119
- wrapper->values[param_idx - 1] = val;
166
+ *param_idx_out = entry->second;
120
167
  return DuckDBSuccess;
121
168
  }
122
169
 
@@ -232,6 +279,7 @@ duckdb_state duckdb_execute_prepared(duckdb_prepared_statement prepared_statemen
232
279
  if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
233
280
  return DuckDBError;
234
281
  }
282
+
235
283
  auto result = wrapper->statement->Execute(wrapper->values, false);
236
284
  return duckdb_translate_result(std::move(result), out_result);
237
285
  }
@@ -304,9 +304,9 @@ static bool IsExplainAnalyze(SQLStatement *statement) {
304
304
  return explain.explain_type == ExplainType::EXPLAIN_ANALYZE;
305
305
  }
306
306
 
307
- shared_ptr<PreparedStatementData> ClientContext::CreatePreparedStatement(ClientContextLock &lock, const string &query,
308
- unique_ptr<SQLStatement> statement,
309
- vector<Value> *values) {
307
+ shared_ptr<PreparedStatementData>
308
+ ClientContext::CreatePreparedStatement(ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement,
309
+ optional_ptr<case_insensitive_map_t<Value>> values) {
310
310
  StatementType statement_type = statement->type;
311
311
  auto result = make_shared<PreparedStatementData>(statement_type);
312
312
 
@@ -315,8 +315,9 @@ shared_ptr<PreparedStatementData> ClientContext::CreatePreparedStatement(ClientC
315
315
  profiler.StartPhase("planner");
316
316
  Planner planner(*this);
317
317
  if (values) {
318
- for (auto &value : *values) {
319
- planner.parameter_data.emplace_back(value);
318
+ auto &parameter_values = *values;
319
+ for (auto &value : parameter_values) {
320
+ planner.parameter_data.emplace(value);
320
321
  }
321
322
  }
322
323
 
@@ -370,7 +371,7 @@ double ClientContext::GetProgress() {
370
371
 
371
372
  unique_ptr<PendingQueryResult> ClientContext::PendingPreparedStatement(ClientContextLock &lock,
372
373
  shared_ptr<PreparedStatementData> statement_p,
373
- PendingQueryParameters parameters) {
374
+ const PendingQueryParameters &parameters) {
374
375
  D_ASSERT(active_query);
375
376
  auto &statement = *statement_p;
376
377
  if (ValidChecker::IsInvalidated(ActiveTransaction()) && statement.properties.requires_valid_transaction) {
@@ -392,7 +393,14 @@ unique_ptr<PendingQueryResult> ClientContext::PendingPreparedStatement(ClientCon
392
393
  }
393
394
 
394
395
  // bind the bound values before execution
395
- statement.Bind(parameters.parameters ? *parameters.parameters : vector<Value>());
396
+ case_insensitive_map_t<Value> owned_values;
397
+ if (parameters.parameters) {
398
+ auto &params = *parameters.parameters;
399
+ for (auto &val : params) {
400
+ owned_values.emplace(val);
401
+ }
402
+ }
403
+ statement.Bind(std::move(owned_values));
396
404
 
397
405
  active_query->executor = make_uniq<Executor>(*this);
398
406
  auto &executor = *active_query->executor;
@@ -566,7 +574,7 @@ unique_ptr<PreparedStatement> ClientContext::Prepare(const string &query) {
566
574
 
567
575
  unique_ptr<PendingQueryResult> ClientContext::PendingQueryPreparedInternal(ClientContextLock &lock, const string &query,
568
576
  shared_ptr<PreparedStatementData> &prepared,
569
- PendingQueryParameters parameters) {
577
+ const PendingQueryParameters &parameters) {
570
578
  try {
571
579
  InitialCleanup(lock);
572
580
  } catch (const Exception &ex) {
@@ -579,13 +587,13 @@ unique_ptr<PendingQueryResult> ClientContext::PendingQueryPreparedInternal(Clien
579
587
 
580
588
  unique_ptr<PendingQueryResult> ClientContext::PendingQuery(const string &query,
581
589
  shared_ptr<PreparedStatementData> &prepared,
582
- PendingQueryParameters parameters) {
590
+ const PendingQueryParameters &parameters) {
583
591
  auto lock = LockContext();
584
592
  return PendingQueryPreparedInternal(*lock, query, prepared, parameters);
585
593
  }
586
594
 
587
595
  unique_ptr<QueryResult> ClientContext::Execute(const string &query, shared_ptr<PreparedStatementData> &prepared,
588
- PendingQueryParameters parameters) {
596
+ const PendingQueryParameters &parameters) {
589
597
  auto lock = LockContext();
590
598
  auto pending = PendingQueryPreparedInternal(*lock, query, prepared, parameters);
591
599
  if (pending->HasError()) {
@@ -595,7 +603,7 @@ unique_ptr<QueryResult> ClientContext::Execute(const string &query, shared_ptr<P
595
603
  }
596
604
 
597
605
  unique_ptr<QueryResult> ClientContext::Execute(const string &query, shared_ptr<PreparedStatementData> &prepared,
598
- vector<Value> &values, bool allow_stream_result) {
606
+ case_insensitive_map_t<Value> &values, bool allow_stream_result) {
599
607
  PendingQueryParameters parameters;
600
608
  parameters.parameters = &values;
601
609
  parameters.allow_stream_result = allow_stream_result;
@@ -604,10 +612,11 @@ unique_ptr<QueryResult> ClientContext::Execute(const string &query, shared_ptr<P
604
612
 
605
613
  unique_ptr<PendingQueryResult> ClientContext::PendingStatementInternal(ClientContextLock &lock, const string &query,
606
614
  unique_ptr<SQLStatement> statement,
607
- PendingQueryParameters parameters) {
615
+ const PendingQueryParameters &parameters) {
608
616
  // prepare the query for execution
609
617
  auto prepared = CreatePreparedStatement(lock, query, std::move(statement), parameters.parameters);
610
- if (prepared->properties.parameter_count > 0 && !parameters.parameters) {
618
+ idx_t parameter_count = !parameters.parameters ? 0 : parameters.parameters->size();
619
+ if (prepared->properties.parameter_count > 0 && parameter_count == 0) {
611
620
  string error_message = StringUtil::Format("Expected %lld parameters, but none were supplied",
612
621
  prepared->properties.parameter_count);
613
622
  return make_uniq<PendingQueryResult>(PreservedError(error_message));
@@ -640,7 +649,7 @@ bool ClientContext::IsActiveResult(ClientContextLock &lock, BaseQueryResult *res
640
649
 
641
650
  unique_ptr<PendingQueryResult> ClientContext::PendingStatementOrPreparedStatementInternal(
642
651
  ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement,
643
- shared_ptr<PreparedStatementData> &prepared, PendingQueryParameters parameters) {
652
+ shared_ptr<PreparedStatementData> &prepared, const PendingQueryParameters &parameters) {
644
653
  // check if we are on AutoCommit. In this case we should start a transaction.
645
654
  if (statement && config.AnyVerification()) {
646
655
  // query verification is enabled
@@ -697,7 +706,7 @@ unique_ptr<PendingQueryResult> ClientContext::PendingStatementOrPreparedStatemen
697
706
 
698
707
  unique_ptr<PendingQueryResult> ClientContext::PendingStatementOrPreparedStatement(
699
708
  ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement,
700
- shared_ptr<PreparedStatementData> &prepared, PendingQueryParameters parameters) {
709
+ shared_ptr<PreparedStatementData> &prepared, const PendingQueryParameters &parameters) {
701
710
  unique_ptr<PendingQueryResult> result;
702
711
 
703
712
  try {
@@ -722,7 +731,7 @@ unique_ptr<PendingQueryResult> ClientContext::PendingStatementOrPreparedStatemen
722
731
  if (statement) {
723
732
  result = PendingStatementInternal(lock, query, std::move(statement), parameters);
724
733
  } else {
725
- if (prepared->RequireRebind(*this, *parameters.parameters)) {
734
+ if (prepared->RequireRebind(*this, parameters.parameters)) {
726
735
  // catalog was modified: rebind the statement before execution
727
736
  auto new_prepared =
728
737
  CreatePreparedStatement(lock, query, prepared->unbound_statement->Copy(), parameters.parameters);
@@ -884,7 +893,8 @@ unique_ptr<PendingQueryResult> ClientContext::PendingQuery(unique_ptr<SQLStateme
884
893
 
885
894
  unique_ptr<PendingQueryResult> ClientContext::PendingQueryInternal(ClientContextLock &lock,
886
895
  unique_ptr<SQLStatement> statement,
887
- PendingQueryParameters parameters, bool verify) {
896
+ const PendingQueryParameters &parameters,
897
+ bool verify) {
888
898
  auto query = statement->query;
889
899
  shared_ptr<PreparedStatementData> prepared;
890
900
  if (verify) {
@@ -7,6 +7,20 @@
7
7
 
8
8
  namespace duckdb {
9
9
 
10
+ static void ThrowIfExceptionIsInternal(StatementVerifier &verifier) {
11
+ if (!verifier.materialized_result) {
12
+ return;
13
+ }
14
+ auto &result = *verifier.materialized_result;
15
+ if (!result.HasError()) {
16
+ return;
17
+ }
18
+ auto &error = result.GetErrorObject();
19
+ if (error.Type() == ExceptionType::INTERNAL) {
20
+ error.Throw();
21
+ }
22
+ }
23
+
10
24
  PreservedError ClientContext::VerifyQuery(ClientContextLock &lock, const string &query,
11
25
  unique_ptr<SQLStatement> statement) {
12
26
  D_ASSERT(statement->type == StatementType::SELECT_STATEMENT);
@@ -81,6 +95,9 @@ PreservedError ClientContext::VerifyQuery(ClientContextLock &lock, const string
81
95
  if (!failed) {
82
96
  // PreparedStatementVerifier fails if it runs into a ParameterNotAllowedException, which is OK
83
97
  statement_verifiers.push_back(std::move(prepared_statement_verifier));
98
+ } else {
99
+ // If it does fail, let's make sure it's not an internal exception
100
+ ThrowIfExceptionIsInternal(*prepared_statement_verifier);
84
101
  }
85
102
  } else {
86
103
  if (ValidChecker::IsInvalidated(*db)) {
@@ -6,9 +6,9 @@
6
6
  namespace duckdb {
7
7
 
8
8
  PreparedStatement::PreparedStatement(shared_ptr<ClientContext> context, shared_ptr<PreparedStatementData> data_p,
9
- string query, idx_t n_param, case_insensitive_map_t<idx_t> named_param_pam_p)
9
+ string query, idx_t n_param, case_insensitive_map_t<idx_t> named_param_map_p)
10
10
  : context(std::move(context)), data(std::move(data_p)), query(std::move(query)), success(true), n_param(n_param),
11
- named_param_map(std::move(named_param_pam_p)) {
11
+ named_param_map(std::move(named_param_map_p)) {
12
12
  D_ASSERT(data || !success);
13
13
  }
14
14
 
@@ -56,19 +56,27 @@ const vector<string> &PreparedStatement::GetNames() {
56
56
  return data->names;
57
57
  }
58
58
 
59
- vector<LogicalType> PreparedStatement::GetExpectedParameterTypes() const {
59
+ case_insensitive_map_t<LogicalType> PreparedStatement::GetExpectedParameterTypes() const {
60
60
  D_ASSERT(data);
61
- vector<LogicalType> expected_types(data->value_map.size());
61
+ case_insensitive_map_t<LogicalType> expected_types(data->value_map.size());
62
62
  for (auto &it : data->value_map) {
63
- D_ASSERT(it.first >= 1);
64
- idx_t param_index = it.first - 1;
65
- D_ASSERT(param_index < expected_types.size());
63
+ auto &identifier = it.first;
64
+ D_ASSERT(data->value_map.count(identifier));
66
65
  D_ASSERT(it.second);
67
- expected_types[param_index] = it.second->value.type();
66
+ expected_types[identifier] = it.second->GetValue().type();
68
67
  }
69
68
  return expected_types;
70
69
  }
71
70
 
71
+ unique_ptr<QueryResult> PreparedStatement::Execute(case_insensitive_map_t<Value> &named_values,
72
+ bool allow_stream_result) {
73
+ auto pending = PendingQuery(named_values, allow_stream_result);
74
+ if (pending->HasError()) {
75
+ return make_uniq<MaterializedQueryResult>(pending->GetErrorObject());
76
+ }
77
+ return pending->Execute();
78
+ }
79
+
72
80
  unique_ptr<QueryResult> PreparedStatement::Execute(vector<Value> &values, bool allow_stream_result) {
73
81
  auto pending = PendingQuery(values, allow_stream_result);
74
82
  if (pending->HasError()) {
@@ -78,14 +86,33 @@ unique_ptr<QueryResult> PreparedStatement::Execute(vector<Value> &values, bool a
78
86
  }
79
87
 
80
88
  unique_ptr<PendingQueryResult> PreparedStatement::PendingQuery(vector<Value> &values, bool allow_stream_result) {
89
+ case_insensitive_map_t<Value> named_values;
90
+ for (idx_t i = 0; i < values.size(); i++) {
91
+ auto &val = values[i];
92
+ named_values[std::to_string(i + 1)] = val;
93
+ }
94
+ return PendingQuery(named_values, allow_stream_result);
95
+ }
96
+
97
+ unique_ptr<PendingQueryResult> PreparedStatement::PendingQuery(case_insensitive_map_t<Value> &named_values,
98
+ bool allow_stream_result) {
81
99
  if (!success) {
82
- throw InvalidInputException("Attempting to execute an unsuccessfully prepared statement!");
100
+ auto exception = InvalidInputException("Attempting to execute an unsuccessfully prepared statement!");
101
+ return make_uniq<PendingQueryResult>(PreservedError(exception));
83
102
  }
84
- D_ASSERT(data);
85
103
  PendingQueryParameters parameters;
86
- parameters.parameters = &values;
104
+ parameters.parameters = &named_values;
105
+
106
+ try {
107
+ VerifyParameters(named_values, named_param_map);
108
+ } catch (const Exception &ex) {
109
+ return make_uniq<PendingQueryResult>(PreservedError(ex));
110
+ }
111
+
112
+ D_ASSERT(data);
87
113
  parameters.allow_stream_result = allow_stream_result && data->properties.allow_stream_result;
88
114
  auto result = context->PendingQuery(query, data, parameters);
115
+ // The result should not contain any reference to the 'vector<Value> parameters.parameters'
89
116
  return result;
90
117
  }
91
118
 
@@ -18,8 +18,9 @@ void PreparedStatementData::CheckParameterCount(idx_t parameter_count) {
18
18
  }
19
19
  }
20
20
 
21
- bool PreparedStatementData::RequireRebind(ClientContext &context, const vector<Value> &values) {
22
- CheckParameterCount(values.size());
21
+ bool PreparedStatementData::RequireRebind(ClientContext &context, optional_ptr<case_insensitive_map_t<Value>> values) {
22
+ idx_t count = values ? values->size() : 0;
23
+ CheckParameterCount(count);
23
24
  if (!unbound_statement) {
24
25
  // no unbound statement!? cannot rebind?
25
26
  return false;
@@ -33,52 +34,56 @@ bool PreparedStatementData::RequireRebind(ClientContext &context, const vector<V
33
34
  return true;
34
35
  }
35
36
  for (auto &it : value_map) {
36
- const idx_t i = it.first - 1;
37
- if (values[i].type() != it.second->return_type) {
37
+ auto &identifier = it.first;
38
+ auto lookup = values->find(identifier);
39
+ D_ASSERT(lookup != values->end());
40
+ if (lookup->second.type() != it.second->return_type) {
38
41
  return true;
39
42
  }
40
43
  }
41
44
  return false;
42
45
  }
43
46
 
44
- void PreparedStatementData::Bind(vector<Value> values) {
47
+ void PreparedStatementData::Bind(case_insensitive_map_t<Value> values) {
45
48
  // set parameters
46
49
  D_ASSERT(!unbound_statement || unbound_statement->n_param == properties.parameter_count);
47
50
  CheckParameterCount(values.size());
48
51
 
49
52
  // bind the required values
50
53
  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
+ const string &identifier = it.first;
55
+ auto lookup = values.find(identifier);
56
+ if (lookup == values.end()) {
57
+ throw BinderException("Could not find parameter with identifier %s", identifier);
54
58
  }
55
59
  D_ASSERT(it.second);
56
- if (!values[i].DefaultTryCastAs(it.second->return_type)) {
60
+ auto &value = lookup->second;
61
+ if (!value.DefaultTryCastAs(it.second->return_type)) {
57
62
  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());
63
+ "Type mismatch for binding parameter with identifier %s, expected type %s but got type %s", identifier,
64
+ it.second->return_type.ToString().c_str(), value.type().ToString().c_str());
60
65
  }
61
- it.second->value = values[i];
66
+ it.second->SetValue(value);
62
67
  }
63
68
  }
64
69
 
65
- bool PreparedStatementData::TryGetType(idx_t param_idx, LogicalType &result) {
66
- auto it = value_map.find(param_idx);
70
+ bool PreparedStatementData::TryGetType(const string &identifier, LogicalType &result) {
71
+ auto it = value_map.find(identifier);
67
72
  if (it == value_map.end()) {
68
73
  return false;
69
74
  }
70
75
  if (it->second->return_type.id() != LogicalTypeId::INVALID) {
71
76
  result = it->second->return_type;
72
77
  } else {
73
- result = it->second->value.type();
78
+ result = it->second->GetValue().type();
74
79
  }
75
80
  return true;
76
81
  }
77
82
 
78
- LogicalType PreparedStatementData::GetType(idx_t param_idx) {
83
+ LogicalType PreparedStatementData::GetType(const string &identifier) {
79
84
  LogicalType result;
80
- if (!TryGetType(param_idx, result)) {
81
- throw BinderException("Could not find parameter with index %llu", param_idx);
85
+ if (!TryGetType(identifier, result)) {
86
+ throw BinderException("Could not find parameter identified with: %s", identifier);
82
87
  }
83
88
  return result;
84
89
  }