duckdb 0.8.2-dev2509.0 → 0.8.2-dev2669.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 (64) 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/scalar/list/array_slice.cpp +6 -0
  8. package/src/duckdb/src/execution/expression_executor/execute_parameter.cpp +2 -2
  9. package/src/duckdb/src/execution/index/art/art.cpp +43 -31
  10. package/src/duckdb/src/execution/index/art/leaf.cpp +47 -33
  11. package/src/duckdb/src/execution/index/art/node.cpp +31 -24
  12. package/src/duckdb/src/execution/index/art/prefix.cpp +100 -16
  13. package/src/duckdb/src/execution/operator/schema/physical_create_index.cpp +54 -31
  14. package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +32 -15
  15. package/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp +57 -0
  16. package/src/duckdb/src/function/table/arrow.cpp +95 -92
  17. package/src/duckdb/src/function/table/arrow_conversion.cpp +45 -68
  18. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  19. package/src/duckdb/src/include/duckdb/common/case_insensitive_map.hpp +1 -0
  20. package/src/duckdb/src/include/duckdb/common/enum_util.hpp +8 -0
  21. package/src/duckdb/src/include/duckdb/common/helper.hpp +8 -3
  22. package/src/duckdb/src/include/duckdb/common/types/value.hpp +4 -1
  23. package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +7 -5
  24. package/src/duckdb/src/include/duckdb/execution/index/art/leaf.hpp +6 -6
  25. package/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +6 -0
  26. package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +9 -11
  27. package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_index.hpp +8 -1
  28. package/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp +99 -0
  29. package/src/duckdb/src/include/duckdb/function/table/arrow.hpp +6 -36
  30. package/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp +3 -1
  31. package/src/duckdb/src/include/duckdb/main/client_context.hpp +15 -14
  32. package/src/duckdb/src/include/duckdb/main/prepared_statement.hpp +73 -5
  33. package/src/duckdb/src/include/duckdb/main/prepared_statement_data.hpp +6 -6
  34. package/src/duckdb/src/include/duckdb/parser/expression/parameter_expression.hpp +17 -1
  35. package/src/duckdb/src/include/duckdb/parser/statement/execute_statement.hpp +1 -1
  36. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +5 -3
  37. package/src/duckdb/src/include/duckdb/planner/bound_parameter_map.hpp +2 -1
  38. package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_data.hpp +20 -5
  39. package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_expression.hpp +3 -3
  40. package/src/duckdb/src/include/duckdb/planner/planner.hpp +4 -3
  41. package/src/duckdb/src/include/duckdb/storage/object_cache.hpp +1 -1
  42. package/src/duckdb/src/include/duckdb/verification/prepared_statement_verifier.hpp +1 -1
  43. package/src/duckdb/src/include/duckdb.h +16 -0
  44. package/src/duckdb/src/main/capi/pending-c.cpp +6 -0
  45. package/src/duckdb/src/main/capi/prepared-c.cpp +52 -4
  46. package/src/duckdb/src/main/client_context.cpp +27 -17
  47. package/src/duckdb/src/main/client_verify.cpp +17 -0
  48. package/src/duckdb/src/main/prepared_statement.cpp +38 -11
  49. package/src/duckdb/src/main/prepared_statement_data.cpp +23 -18
  50. package/src/duckdb/src/parser/expression/parameter_expression.cpp +7 -7
  51. package/src/duckdb/src/parser/statement/execute_statement.cpp +2 -2
  52. package/src/duckdb/src/parser/transform/expression/transform_param_ref.cpp +45 -26
  53. package/src/duckdb/src/parser/transform/statement/transform_prepare.cpp +28 -6
  54. package/src/duckdb/src/parser/transformer.cpp +27 -9
  55. package/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp +10 -10
  56. package/src/duckdb/src/planner/binder/statement/bind_execute.cpp +13 -7
  57. package/src/duckdb/src/planner/expression/bound_parameter_expression.cpp +13 -13
  58. package/src/duckdb/src/planner/planner.cpp +7 -6
  59. package/src/duckdb/src/storage/checkpoint_manager.cpp +1 -1
  60. package/src/duckdb/src/storage/serialization/serialize_expression.cpp +3 -3
  61. package/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp +2 -2
  62. package/src/duckdb/src/verification/prepared_statement_verifier.cpp +16 -11
  63. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +9652 -9482
  64. package/src/duckdb/ub_src_function_table_arrow.cpp +2 -0
@@ -11,36 +11,36 @@
11
11
  namespace duckdb {
12
12
 
13
13
  ParameterExpression::ParameterExpression()
14
- : ParsedExpression(ExpressionType::VALUE_PARAMETER, ExpressionClass::PARAMETER), parameter_nr(0) {
14
+ : ParsedExpression(ExpressionType::VALUE_PARAMETER, ExpressionClass::PARAMETER) {
15
15
  }
16
16
 
17
17
  string ParameterExpression::ToString() const {
18
- return "$" + to_string(parameter_nr);
18
+ return "$" + identifier;
19
19
  }
20
20
 
21
21
  unique_ptr<ParsedExpression> ParameterExpression::Copy() const {
22
22
  auto copy = make_uniq<ParameterExpression>();
23
- copy->parameter_nr = parameter_nr;
23
+ copy->identifier = identifier;
24
24
  copy->CopyProperties(*this);
25
25
  return std::move(copy);
26
26
  }
27
27
 
28
28
  bool ParameterExpression::Equal(const ParameterExpression &a, const ParameterExpression &b) {
29
- return a.parameter_nr == b.parameter_nr;
29
+ return StringUtil::CIEquals(a.identifier, b.identifier);
30
30
  }
31
31
 
32
32
  hash_t ParameterExpression::Hash() const {
33
33
  hash_t result = ParsedExpression::Hash();
34
- return CombineHash(duckdb::Hash(parameter_nr), result);
34
+ return CombineHash(duckdb::Hash(identifier.c_str(), identifier.size()), result);
35
35
  }
36
36
 
37
37
  void ParameterExpression::Serialize(FieldWriter &writer) const {
38
- writer.WriteField<idx_t>(parameter_nr);
38
+ writer.WriteString(identifier);
39
39
  }
40
40
 
41
41
  unique_ptr<ParsedExpression> ParameterExpression::Deserialize(ExpressionType type, FieldReader &reader) {
42
42
  auto expression = make_uniq<ParameterExpression>();
43
- expression->parameter_nr = reader.ReadRequired<idx_t>();
43
+ expression->identifier = reader.ReadRequired<string>();
44
44
  return std::move(expression);
45
45
  }
46
46
 
@@ -6,8 +6,8 @@ ExecuteStatement::ExecuteStatement() : SQLStatement(StatementType::EXECUTE_STATE
6
6
  }
7
7
 
8
8
  ExecuteStatement::ExecuteStatement(const ExecuteStatement &other) : SQLStatement(other), name(other.name) {
9
- for (const auto &value : other.values) {
10
- values.push_back(value->Copy());
9
+ for (const auto &item : other.named_values) {
10
+ named_values.emplace(std::make_pair(item.first, item.second->Copy()));
11
11
  }
12
12
  }
13
13
 
@@ -4,40 +4,59 @@
4
4
 
5
5
  namespace duckdb {
6
6
 
7
- unique_ptr<ParsedExpression> Transformer::TransformParamRef(duckdb_libpgquery::PGParamRef &node) {
8
- auto expr = make_uniq<ParameterExpression>();
7
+ namespace {
8
+
9
+ struct PreparedParam {
10
+ PreparedParamType type;
11
+ string identifier;
12
+ };
13
+
14
+ } // namespace
15
+
16
+ static PreparedParam GetParameterIdentifier(duckdb_libpgquery::PGParamRef &node) {
17
+ PreparedParam param;
18
+ if (node.name) {
19
+ param.type = PreparedParamType::NAMED;
20
+ param.identifier = node.name;
21
+ return param;
22
+ }
9
23
  if (node.number < 0) {
10
24
  throw ParserException("Parameter numbers cannot be negative");
11
25
  }
26
+ param.identifier = StringUtil::Format("%d", node.number);
27
+ param.type = node.number == 0 ? PreparedParamType::AUTO_INCREMENT : PreparedParamType::POSITIONAL;
28
+ return param;
29
+ }
12
30
 
13
- if (node.name) {
14
- // This is a named parameter, try to find an entry for it
15
- D_ASSERT(node.number == 0);
16
- int32_t index;
17
- if (GetNamedParam(node.name, index)) {
18
- // We've seen this named parameter before and assigned it an index!
19
- node.number = index;
20
- }
21
- }
22
- if (node.number == 0) {
23
- expr->parameter_nr = ParamCount() + 1;
24
- if (node.name && !HasNamedParameters() && ParamCount() != 0) {
25
- // This parameter is named, but there were other parameter before it, and they were not named
26
- throw NotImplementedException("Mixing positional and named parameters is not supported yet");
31
+ unique_ptr<ParsedExpression> Transformer::TransformParamRef(duckdb_libpgquery::PGParamRef &node) {
32
+ auto expr = make_uniq<ParameterExpression>();
33
+
34
+ auto param = GetParameterIdentifier(node);
35
+ idx_t known_param_index = DConstants::INVALID_INDEX;
36
+ // This is a named parameter, try to find an entry for it
37
+ GetParam(param.identifier, known_param_index, param.type);
38
+
39
+ if (known_param_index == DConstants::INVALID_INDEX) {
40
+ // We have not seen this parameter before
41
+ if (node.number != 0) {
42
+ // Preserve the parameter number
43
+ known_param_index = node.number;
44
+ } else {
45
+ known_param_index = ParamCount() + 1;
46
+ if (!node.name) {
47
+ param.identifier = StringUtil::Format("%d", known_param_index);
48
+ }
27
49
  }
28
- if (node.name) {
29
- D_ASSERT(!named_param_map.count(node.name));
50
+
51
+ if (!named_param_map.count(param.identifier)) {
30
52
  // Add it to the named parameter map so we can find it next time it's referenced
31
- SetNamedParam(node.name, expr->parameter_nr);
53
+ SetParam(param.identifier, known_param_index, param.type);
32
54
  }
33
- } else {
34
- if (!node.name && HasNamedParameters()) {
35
- // This parameter does not have a name, but the named param map is not empty
36
- throw NotImplementedException("Mixing positional and named parameters is not supported yet");
37
- }
38
- expr->parameter_nr = node.number;
39
55
  }
40
- SetParamCount(MaxValue<idx_t>(ParamCount(), expr->parameter_nr));
56
+
57
+ expr->identifier = param.identifier;
58
+ idx_t new_param_count = MaxValue<idx_t>(ParamCount(), known_param_index);
59
+ SetParamCount(new_param_count);
41
60
  return std::move(expr);
42
61
  }
43
62
 
@@ -2,6 +2,8 @@
2
2
  #include "duckdb/parser/statement/execute_statement.hpp"
3
3
  #include "duckdb/parser/statement/prepare_statement.hpp"
4
4
  #include "duckdb/parser/transformer.hpp"
5
+ #include "duckdb/parser/expression/comparison_expression.hpp"
6
+ #include "duckdb/parser/expression/columnref_expression.hpp"
5
7
 
6
8
  namespace duckdb {
7
9
 
@@ -13,26 +15,46 @@ unique_ptr<PrepareStatement> Transformer::TransformPrepare(duckdb_libpgquery::PG
13
15
  auto result = make_uniq<PrepareStatement>();
14
16
  result->name = string(stmt.name);
15
17
  result->statement = TransformStatement(*stmt.query);
16
- if (!result->statement->named_param_map.empty()) {
17
- throw NotImplementedException("Named parameters are not supported in this client yet");
18
- }
19
18
  SetParamCount(0);
20
19
 
21
20
  return result;
22
21
  }
23
22
 
23
+ static string NotAcceptedExpressionException() {
24
+ return "Only scalar parameters, named parameters or NULL supported for EXECUTE";
25
+ }
26
+
24
27
  unique_ptr<ExecuteStatement> Transformer::TransformExecute(duckdb_libpgquery::PGExecuteStmt &stmt) {
25
28
  auto result = make_uniq<ExecuteStatement>();
26
29
  result->name = string(stmt.name);
27
30
 
31
+ vector<unique_ptr<ParsedExpression>> intermediate_values;
28
32
  if (stmt.params) {
29
- TransformExpressionList(*stmt.params, result->values);
33
+ TransformExpressionList(*stmt.params, intermediate_values);
30
34
  }
31
- for (auto &expr : result->values) {
35
+
36
+ idx_t param_idx = 0;
37
+ for (idx_t i = 0; i < intermediate_values.size(); i++) {
38
+ auto &expr = intermediate_values[i];
32
39
  if (!expr->IsScalar()) {
33
- throw Exception("Only scalar parameters or NULL supported for EXECUTE");
40
+ throw InvalidInputException(NotAcceptedExpressionException());
41
+ }
42
+ if (!expr->alias.empty() && param_idx != 0) {
43
+ // Found unnamed parameters mixed with named parameters
44
+ throw NotImplementedException("Mixing named parameters and positional parameters is not supported yet");
45
+ }
46
+ auto param_name = expr->alias;
47
+ if (expr->alias.empty()) {
48
+ param_name = std::to_string(param_idx + 1);
49
+ if (param_idx != i) {
50
+ throw NotImplementedException("Mixing named parameters and positional parameters is not supported yet");
51
+ }
52
+ param_idx++;
34
53
  }
54
+ expr->alias.clear();
55
+ result->named_values[param_name] = std::move(expr);
35
56
  }
57
+ intermediate_values.clear();
36
58
  return result;
37
59
  }
38
60
 
@@ -91,24 +91,42 @@ void Transformer::SetParamCount(idx_t new_count) {
91
91
  auto &root = RootTransformer();
92
92
  root.prepared_statement_parameter_index = new_count;
93
93
  }
94
- void Transformer::SetNamedParam(const string &name, int32_t index) {
94
+
95
+ static void ParamTypeCheck(PreparedParamType last_type, PreparedParamType new_type) {
96
+ // Mixing positional/auto-increment and named parameters is not supported
97
+ if (last_type == PreparedParamType::INVALID) {
98
+ return;
99
+ }
100
+ if (last_type == PreparedParamType::NAMED) {
101
+ if (new_type != PreparedParamType::NAMED) {
102
+ throw NotImplementedException("Mixing named and positional parameters is not supported yet");
103
+ }
104
+ }
105
+ if (last_type != PreparedParamType::NAMED) {
106
+ if (new_type == PreparedParamType::NAMED) {
107
+ throw NotImplementedException("Mixing named and positional parameters is not supported yet");
108
+ }
109
+ }
110
+ }
111
+
112
+ void Transformer::SetParam(const string &identifier, idx_t index, PreparedParamType type) {
95
113
  auto &root = RootTransformer();
96
- D_ASSERT(!root.named_param_map.count(name));
97
- root.named_param_map[name] = index;
114
+ ParamTypeCheck(root.last_param_type, type);
115
+ root.last_param_type = type;
116
+ D_ASSERT(!root.named_param_map.count(identifier));
117
+ root.named_param_map[identifier] = index;
98
118
  }
99
- bool Transformer::GetNamedParam(const string &name, int32_t &index) {
119
+
120
+ bool Transformer::GetParam(const string &identifier, idx_t &index, PreparedParamType type) {
100
121
  auto &root = RootTransformer();
101
- auto entry = root.named_param_map.find(name);
122
+ ParamTypeCheck(root.last_param_type, type);
123
+ auto entry = root.named_param_map.find(identifier);
102
124
  if (entry == root.named_param_map.end()) {
103
125
  return false;
104
126
  }
105
127
  index = entry->second;
106
128
  return true;
107
129
  }
108
- bool Transformer::HasNamedParameters() const {
109
- auto &root = RootTransformer();
110
- return !root.named_param_map.empty();
111
- }
112
130
 
113
131
  unique_ptr<SQLStatement> Transformer::TransformStatementInternal(duckdb_libpgquery::PGNode &stmt) {
114
132
  switch (stmt.type) {
@@ -7,34 +7,34 @@
7
7
  namespace duckdb {
8
8
 
9
9
  BindResult ExpressionBinder::BindExpression(ParameterExpression &expr, idx_t depth) {
10
- D_ASSERT(expr.parameter_nr > 0);
11
- auto bound_parameter = make_uniq<BoundParameterExpression>(expr.parameter_nr);
10
+ auto bound_parameter = make_uniq<BoundParameterExpression>(expr.identifier);
12
11
  bound_parameter->alias = expr.alias;
13
12
  if (!binder.parameters) {
14
13
  throw BinderException("Unexpected prepared parameter. This type of statement can't be prepared!");
15
14
  }
16
- auto parameter_idx = expr.parameter_nr;
15
+ auto parameter_id = expr.identifier;
17
16
  // check if a parameter value has already been supplied
18
- if (parameter_idx <= binder.parameters->parameter_data.size()) {
17
+ if (binder.parameters->parameter_data.count(parameter_id)) {
19
18
  // it has! emit a constant directly
20
- auto &data = binder.parameters->parameter_data[parameter_idx - 1];
21
- auto constant = make_uniq<BoundConstantExpression>(data.value);
19
+ auto &data = binder.parameters->parameter_data[parameter_id];
20
+ auto constant = make_uniq<BoundConstantExpression>(data.GetValue());
22
21
  constant->alias = expr.alias;
23
22
  return BindResult(std::move(constant));
24
23
  }
25
- auto entry = binder.parameters->parameters.find(parameter_idx);
24
+
25
+ auto entry = binder.parameters->parameters.find(parameter_id);
26
26
  if (entry == binder.parameters->parameters.end()) {
27
27
  // no entry yet: create a new one
28
28
  auto data = make_shared<BoundParameterData>();
29
- data->return_type = binder.parameters->GetReturnType(parameter_idx - 1);
29
+ data->return_type = binder.parameters->GetReturnType(parameter_id);
30
30
  bound_parameter->return_type = data->return_type;
31
31
  bound_parameter->parameter_data = data;
32
- binder.parameters->parameters[parameter_idx] = std::move(data);
32
+ binder.parameters->parameters[parameter_id] = std::move(data);
33
33
  } else {
34
34
  // a prepared statement with this parameter index was already there: use it
35
35
  auto &data = entry->second;
36
36
  bound_parameter->parameter_data = data;
37
- bound_parameter->return_type = binder.parameters->GetReturnType(parameter_idx - 1);
37
+ bound_parameter->return_type = binder.parameters->GetReturnType(parameter_id);
38
38
  }
39
39
  return BindResult(std::move(bound_parameter));
40
40
  }
@@ -6,6 +6,7 @@
6
6
  #include "duckdb/main/client_config.hpp"
7
7
  #include "duckdb/main/client_data.hpp"
8
8
  #include "duckdb/execution/expression_executor.hpp"
9
+ #include "duckdb/common/case_insensitive_map.hpp"
9
10
 
10
11
  namespace duckdb {
11
12
 
@@ -23,24 +24,29 @@ BoundStatement Binder::Bind(ExecuteStatement &stmt) {
23
24
  // check if we need to rebind the prepared statement
24
25
  // this happens if the catalog changes, since in this case e.g. tables we relied on may have been deleted
25
26
  auto prepared = entry->second;
27
+ auto &named_param_map = prepared->unbound_statement->named_param_map;
26
28
 
29
+ PreparedStatement::VerifyParameters(stmt.named_values, named_param_map);
30
+
31
+ auto &mapped_named_values = stmt.named_values;
27
32
  // bind any supplied parameters
28
- vector<Value> bind_values;
33
+ case_insensitive_map_t<Value> bind_values;
29
34
  auto constant_binder = Binder::CreateBinder(context);
30
35
  constant_binder->SetCanContainNulls(true);
31
- for (idx_t i = 0; i < stmt.values.size(); i++) {
36
+ for (auto &pair : mapped_named_values) {
32
37
  ConstantBinder cbinder(*constant_binder, context, "EXECUTE statement");
33
- auto bound_expr = cbinder.Bind(stmt.values[i]);
38
+ auto bound_expr = cbinder.Bind(pair.second);
34
39
 
35
40
  Value value = ExpressionExecutor::EvaluateScalar(context, *bound_expr, true);
36
- bind_values.push_back(std::move(value));
41
+ bind_values[pair.first] = std::move(value);
37
42
  }
38
43
  unique_ptr<LogicalOperator> rebound_plan;
39
- if (prepared->RequireRebind(context, bind_values)) {
44
+
45
+ if (prepared->RequireRebind(context, &bind_values)) {
40
46
  // catalog was modified or statement does not have clear types: rebind the statement before running the execute
41
47
  Planner prepared_planner(context);
42
- for (idx_t i = 0; i < bind_values.size(); i++) {
43
- prepared_planner.parameter_data.emplace_back(bind_values[i]);
48
+ for (auto &pair : bind_values) {
49
+ prepared_planner.parameter_data.emplace(pair);
44
50
  }
45
51
  prepared = prepared_planner.PrepareSQLStatement(entry->second->unbound_statement->Copy());
46
52
  rebound_plan = std::move(prepared_planner.plan);
@@ -6,22 +6,22 @@
6
6
 
7
7
  namespace duckdb {
8
8
 
9
- BoundParameterExpression::BoundParameterExpression(idx_t parameter_nr)
9
+ BoundParameterExpression::BoundParameterExpression(const string &identifier)
10
10
  : Expression(ExpressionType::VALUE_PARAMETER, ExpressionClass::BOUND_PARAMETER,
11
11
  LogicalType(LogicalTypeId::UNKNOWN)),
12
- parameter_nr(parameter_nr) {
12
+ identifier(identifier) {
13
13
  }
14
14
 
15
- BoundParameterExpression::BoundParameterExpression(bound_parameter_map_t &global_parameter_set, idx_t parameter_nr,
15
+ BoundParameterExpression::BoundParameterExpression(bound_parameter_map_t &global_parameter_set, string identifier,
16
16
  LogicalType return_type,
17
17
  shared_ptr<BoundParameterData> parameter_data)
18
18
  : Expression(ExpressionType::VALUE_PARAMETER, ExpressionClass::BOUND_PARAMETER, std::move(return_type)),
19
- parameter_nr(parameter_nr) {
19
+ identifier(std::move(identifier)) {
20
20
  // check if we have already deserialized a parameter with this number
21
- auto entry = global_parameter_set.find(parameter_nr);
21
+ auto entry = global_parameter_set.find(this->identifier);
22
22
  if (entry == global_parameter_set.end()) {
23
23
  // we have not - store the entry we deserialized from this parameter expression
24
- global_parameter_set[parameter_nr] = parameter_data;
24
+ global_parameter_set[this->identifier] = parameter_data;
25
25
  } else {
26
26
  // we have! use the previously deserialized entry
27
27
  parameter_data = entry->second;
@@ -57,7 +57,7 @@ bool BoundParameterExpression::IsFoldable() const {
57
57
  }
58
58
 
59
59
  string BoundParameterExpression::ToString() const {
60
- return "$" + to_string(parameter_nr);
60
+ return "$" + identifier;
61
61
  }
62
62
 
63
63
  bool BoundParameterExpression::Equals(const BaseExpression &other_p) const {
@@ -65,17 +65,17 @@ bool BoundParameterExpression::Equals(const BaseExpression &other_p) const {
65
65
  return false;
66
66
  }
67
67
  auto &other = other_p.Cast<BoundParameterExpression>();
68
- return parameter_nr == other.parameter_nr;
68
+ return StringUtil::CIEquals(identifier, other.identifier);
69
69
  }
70
70
 
71
71
  hash_t BoundParameterExpression::Hash() const {
72
72
  hash_t result = Expression::Hash();
73
- result = CombineHash(duckdb::Hash(parameter_nr), result);
73
+ result = CombineHash(duckdb::Hash(identifier.c_str(), identifier.size()), result);
74
74
  return result;
75
75
  }
76
76
 
77
77
  unique_ptr<Expression> BoundParameterExpression::Copy() {
78
- auto result = make_uniq<BoundParameterExpression>(parameter_nr);
78
+ auto result = make_uniq<BoundParameterExpression>(identifier);
79
79
  result->parameter_data = parameter_data;
80
80
  result->return_type = return_type;
81
81
  result->CopyProperties(*this);
@@ -83,7 +83,7 @@ unique_ptr<Expression> BoundParameterExpression::Copy() {
83
83
  }
84
84
 
85
85
  void BoundParameterExpression::Serialize(FieldWriter &writer) const {
86
- writer.WriteField(parameter_nr);
86
+ writer.WriteString(identifier);
87
87
  writer.WriteSerializable(return_type);
88
88
  writer.WriteSerializable(*parameter_data);
89
89
  }
@@ -91,11 +91,11 @@ void BoundParameterExpression::Serialize(FieldWriter &writer) const {
91
91
  unique_ptr<Expression> BoundParameterExpression::Deserialize(ExpressionDeserializationState &state,
92
92
  FieldReader &reader) {
93
93
  auto &global_parameter_set = state.gstate.parameter_data;
94
- auto parameter_nr = reader.ReadRequired<idx_t>();
94
+ auto identifier = reader.ReadRequired<string>();
95
95
  auto return_type = reader.ReadRequiredSerializable<LogicalType, LogicalType>();
96
96
  auto parameter_data = reader.ReadRequiredSerializable<BoundParameterData, shared_ptr<BoundParameterData>>();
97
97
  auto result = unique_ptr<BoundParameterExpression>(new BoundParameterExpression(
98
- global_parameter_set, parameter_nr, std::move(return_type), std::move(parameter_data)));
98
+ global_parameter_set, std::move(identifier), std::move(return_type), std::move(parameter_data)));
99
99
  return std::move(result);
100
100
  }
101
101
 
@@ -83,15 +83,15 @@ void Planner::CreatePlan(SQLStatement &statement) {
83
83
 
84
84
  // set up a map of parameter number -> value entries
85
85
  for (auto &kv : bound_parameters.parameters) {
86
- auto parameter_index = kv.first;
87
- auto &parameter_data = kv.second;
86
+ auto &identifier = kv.first;
87
+ auto &param = kv.second;
88
88
  // check if the type of the parameter could be resolved
89
- if (!parameter_data->return_type.IsValid()) {
89
+ if (!param->return_type.IsValid()) {
90
90
  properties.bound_all_parameters = false;
91
91
  continue;
92
92
  }
93
- parameter_data->value = Value(parameter_data->return_type);
94
- value_map[parameter_index] = parameter_data;
93
+ param->SetValue(Value(param->return_type));
94
+ value_map[identifier] = param;
95
95
  }
96
96
  }
97
97
 
@@ -153,7 +153,8 @@ static bool OperatorSupportsSerialization(LogicalOperator &op) {
153
153
  return op.SupportSerialization();
154
154
  }
155
155
 
156
- void Planner::VerifyPlan(ClientContext &context, unique_ptr<LogicalOperator> &op, bound_parameter_map_t *map) {
156
+ void Planner::VerifyPlan(ClientContext &context, unique_ptr<LogicalOperator> &op,
157
+ optional_ptr<bound_parameter_map_t> map) {
157
158
  #ifdef DUCKDB_ALTERNATIVE_VERIFY
158
159
  // if alternate verification is enabled we run the original operator
159
160
  return;
@@ -394,7 +394,7 @@ void CheckpointReader::ReadIndex(ClientContext &context, MetaBlockReader &reader
394
394
  case IndexType::ART: {
395
395
  auto &storage = table_catalog.GetStorage();
396
396
  auto art = make_uniq<ART>(index_info.column_ids, TableIOManager::Get(storage), std::move(unbound_expressions),
397
- index_info.constraint_type, storage.db, root_block_id, root_offset);
397
+ index_info.constraint_type, storage.db, nullptr, root_block_id, root_offset);
398
398
  index_catalog.index = art.get();
399
399
  storage.info->indexes.AddIndex(std::move(art));
400
400
  break;
@@ -241,16 +241,16 @@ unique_ptr<Expression> BoundOperatorExpression::FormatDeserialize(FormatDeserial
241
241
 
242
242
  void BoundParameterExpression::FormatSerialize(FormatSerializer &serializer) const {
243
243
  Expression::FormatSerialize(serializer);
244
- serializer.WriteProperty("parameter_nr", parameter_nr);
244
+ serializer.WriteProperty("identifier", identifier);
245
245
  serializer.WriteProperty("return_type", return_type);
246
246
  serializer.WriteProperty("parameter_data", *parameter_data);
247
247
  }
248
248
 
249
249
  unique_ptr<Expression> BoundParameterExpression::FormatDeserialize(FormatDeserializer &deserializer) {
250
- auto parameter_nr = deserializer.ReadProperty<idx_t>("parameter_nr");
250
+ auto identifier = deserializer.ReadProperty<string>("identifier");
251
251
  auto return_type = deserializer.ReadProperty<LogicalType>("return_type");
252
252
  auto parameter_data = deserializer.ReadProperty<shared_ptr<BoundParameterData>>("parameter_data");
253
- auto result = duckdb::unique_ptr<BoundParameterExpression>(new BoundParameterExpression(deserializer.Get<bound_parameter_map_t &>(), parameter_nr, std::move(return_type), std::move(parameter_data)));
253
+ auto result = duckdb::unique_ptr<BoundParameterExpression>(new BoundParameterExpression(deserializer.Get<bound_parameter_map_t &>(), std::move(identifier), std::move(return_type), std::move(parameter_data)));
254
254
  return std::move(result);
255
255
  }
256
256
 
@@ -246,12 +246,12 @@ unique_ptr<ParsedExpression> OperatorExpression::FormatDeserialize(FormatDeseria
246
246
 
247
247
  void ParameterExpression::FormatSerialize(FormatSerializer &serializer) const {
248
248
  ParsedExpression::FormatSerialize(serializer);
249
- serializer.WriteProperty("parameter_nr", parameter_nr);
249
+ serializer.WriteProperty("identifier", identifier);
250
250
  }
251
251
 
252
252
  unique_ptr<ParsedExpression> ParameterExpression::FormatDeserialize(FormatDeserializer &deserializer) {
253
253
  auto result = duckdb::unique_ptr<ParameterExpression>(new ParameterExpression());
254
- deserializer.ReadProperty("parameter_nr", result->parameter_nr);
254
+ deserializer.ReadProperty("identifier", result->identifier);
255
255
  return std::move(result);
256
256
  }
257
257
 
@@ -23,6 +23,9 @@ void PreparedStatementVerifier::Extract() {
23
23
  ParsedExpressionIterator::EnumerateQueryNodeChildren(
24
24
  *select.node, [&](unique_ptr<ParsedExpression> &child) { ConvertConstants(child); });
25
25
  statement->n_param = values.size();
26
+ for (auto &kv : values) {
27
+ statement->named_param_map[kv.first] = 0;
28
+ }
26
29
  // create the PREPARE and EXECUTE statements
27
30
  string name = "__duckdb_verification_prepared_statement";
28
31
  auto prepare = make_uniq<PrepareStatement>();
@@ -31,7 +34,7 @@ void PreparedStatementVerifier::Extract() {
31
34
 
32
35
  auto execute = make_uniq<ExecuteStatement>();
33
36
  execute->name = name;
34
- execute->values = std::move(values);
37
+ execute->named_values = std::move(values);
35
38
 
36
39
  auto dealloc = make_uniq<DropStatement>();
37
40
  dealloc->info->type = CatalogType::PREPARED_STATEMENT;
@@ -49,19 +52,21 @@ void PreparedStatementVerifier::ConvertConstants(unique_ptr<ParsedExpression> &c
49
52
  child->alias = string();
50
53
  // check if the value already exists
51
54
  idx_t index = values.size();
52
- for (idx_t v_idx = 0; v_idx < values.size(); v_idx++) {
53
- if (values[v_idx]->Equals(*child)) {
54
- // duplicate value! refer to the original value
55
- index = v_idx;
56
- break;
57
- }
58
- }
59
- if (index == values.size()) {
60
- values.push_back(std::move(child));
55
+ auto identifier = std::to_string(index + 1);
56
+ const auto predicate = [&](const std::pair<const string, unique_ptr<ParsedExpression>> &pair) {
57
+ return pair.second->Equals(*child.get());
58
+ };
59
+ auto result = std::find_if(values.begin(), values.end(), predicate);
60
+ if (result == values.end()) {
61
+ // If it doesn't exist yet, add it
62
+ values[identifier] = std::move(child);
63
+ } else {
64
+ identifier = result->first;
61
65
  }
66
+
62
67
  // replace it with an expression
63
68
  auto parameter = make_uniq<ParameterExpression>();
64
- parameter->parameter_nr = index + 1;
69
+ parameter->identifier = identifier;
65
70
  parameter->alias = alias;
66
71
  child = std::move(parameter);
67
72
  return;