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.
- package/binding.gyp +1 -0
- package/package.json +1 -1
- package/src/duckdb/extension/icu/icu-datepart.cpp +3 -3
- package/src/duckdb/src/catalog/catalog_entry/duck_table_entry.cpp +1 -1
- package/src/duckdb/src/catalog/default/default_functions.cpp +5 -0
- package/src/duckdb/src/common/enum_util.cpp +35 -1
- package/src/duckdb/src/core_functions/aggregate/nested/list.cpp +6 -1
- package/src/duckdb/src/core_functions/scalar/list/array_slice.cpp +6 -0
- package/src/duckdb/src/execution/expression_executor/execute_parameter.cpp +2 -2
- package/src/duckdb/src/execution/index/art/art.cpp +43 -31
- package/src/duckdb/src/execution/index/art/leaf.cpp +47 -33
- package/src/duckdb/src/execution/index/art/node.cpp +31 -24
- package/src/duckdb/src/execution/index/art/prefix.cpp +100 -16
- package/src/duckdb/src/execution/operator/schema/physical_create_index.cpp +54 -31
- package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +32 -15
- package/src/duckdb/src/function/table/arrow/arrow_duck_schema.cpp +57 -0
- package/src/duckdb/src/function/table/arrow.cpp +95 -92
- package/src/duckdb/src/function/table/arrow_conversion.cpp +45 -68
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/common/case_insensitive_map.hpp +1 -0
- package/src/duckdb/src/include/duckdb/common/enum_util.hpp +8 -0
- package/src/duckdb/src/include/duckdb/common/helper.hpp +8 -3
- package/src/duckdb/src/include/duckdb/common/types/value.hpp +4 -1
- package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +7 -5
- package/src/duckdb/src/include/duckdb/execution/index/art/leaf.hpp +6 -6
- package/src/duckdb/src/include/duckdb/execution/index/art/node.hpp +6 -0
- package/src/duckdb/src/include/duckdb/execution/index/art/prefix.hpp +9 -11
- package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_index.hpp +8 -1
- package/src/duckdb/src/include/duckdb/function/table/arrow/arrow_duck_schema.hpp +99 -0
- package/src/duckdb/src/include/duckdb/function/table/arrow.hpp +6 -36
- package/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp +3 -1
- package/src/duckdb/src/include/duckdb/main/client_context.hpp +15 -14
- package/src/duckdb/src/include/duckdb/main/prepared_statement.hpp +73 -5
- package/src/duckdb/src/include/duckdb/main/prepared_statement_data.hpp +6 -6
- package/src/duckdb/src/include/duckdb/parser/expression/parameter_expression.hpp +17 -1
- package/src/duckdb/src/include/duckdb/parser/statement/execute_statement.hpp +1 -1
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +5 -3
- package/src/duckdb/src/include/duckdb/planner/bound_parameter_map.hpp +2 -1
- package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_data.hpp +20 -5
- package/src/duckdb/src/include/duckdb/planner/expression/bound_parameter_expression.hpp +3 -3
- package/src/duckdb/src/include/duckdb/planner/planner.hpp +4 -3
- package/src/duckdb/src/include/duckdb/storage/object_cache.hpp +1 -1
- package/src/duckdb/src/include/duckdb/verification/prepared_statement_verifier.hpp +1 -1
- package/src/duckdb/src/include/duckdb.h +16 -0
- package/src/duckdb/src/main/capi/pending-c.cpp +6 -0
- package/src/duckdb/src/main/capi/prepared-c.cpp +52 -4
- package/src/duckdb/src/main/client_context.cpp +27 -17
- package/src/duckdb/src/main/client_verify.cpp +17 -0
- package/src/duckdb/src/main/prepared_statement.cpp +38 -11
- package/src/duckdb/src/main/prepared_statement_data.cpp +23 -18
- package/src/duckdb/src/parallel/executor.cpp +3 -0
- package/src/duckdb/src/parser/expression/parameter_expression.cpp +7 -7
- package/src/duckdb/src/parser/statement/execute_statement.cpp +2 -2
- package/src/duckdb/src/parser/transform/expression/transform_param_ref.cpp +45 -26
- package/src/duckdb/src/parser/transform/statement/transform_prepare.cpp +28 -6
- package/src/duckdb/src/parser/transformer.cpp +27 -9
- package/src/duckdb/src/planner/binder/expression/bind_parameter_expression.cpp +10 -10
- package/src/duckdb/src/planner/binder/statement/bind_execute.cpp +13 -7
- package/src/duckdb/src/planner/expression/bound_parameter_expression.cpp +13 -13
- package/src/duckdb/src/planner/planner.cpp +7 -6
- package/src/duckdb/src/storage/checkpoint_manager.cpp +1 -1
- package/src/duckdb/src/storage/serialization/serialize_expression.cpp +3 -3
- package/src/duckdb/src/storage/serialization/serialize_parsed_expression.cpp +2 -2
- package/src/duckdb/src/verification/prepared_statement_verifier.cpp +16 -11
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +9652 -9482
- package/src/duckdb/ub_src_function_table_arrow.cpp +2 -0
@@ -589,6 +589,9 @@ bool Executor::GetPipelinesProgress(double ¤t_progress) { // LCOV_EXCL_STA
|
|
589
589
|
total_cardinality += child_cardinality;
|
590
590
|
}
|
591
591
|
current_progress = 0;
|
592
|
+
if (total_cardinality == 0) {
|
593
|
+
return true;
|
594
|
+
}
|
592
595
|
for (size_t i = 0; i < progress.size(); i++) {
|
593
596
|
current_progress += progress[i] * double(cardinality[i]) / double(total_cardinality);
|
594
597
|
}
|
@@ -11,36 +11,36 @@
|
|
11
11
|
namespace duckdb {
|
12
12
|
|
13
13
|
ParameterExpression::ParameterExpression()
|
14
|
-
: ParsedExpression(ExpressionType::VALUE_PARAMETER, ExpressionClass::PARAMETER)
|
14
|
+
: ParsedExpression(ExpressionType::VALUE_PARAMETER, ExpressionClass::PARAMETER) {
|
15
15
|
}
|
16
16
|
|
17
17
|
string ParameterExpression::ToString() const {
|
18
|
-
return "$" +
|
18
|
+
return "$" + identifier;
|
19
19
|
}
|
20
20
|
|
21
21
|
unique_ptr<ParsedExpression> ParameterExpression::Copy() const {
|
22
22
|
auto copy = make_uniq<ParameterExpression>();
|
23
|
-
copy->
|
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.
|
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(
|
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.
|
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->
|
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 &
|
10
|
-
|
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
|
-
|
8
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
29
|
-
|
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
|
-
|
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
|
-
|
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,
|
33
|
+
TransformExpressionList(*stmt.params, intermediate_values);
|
30
34
|
}
|
31
|
-
|
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
|
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
|
-
|
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
|
-
|
97
|
-
root.
|
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
|
-
|
119
|
+
|
120
|
+
bool Transformer::GetParam(const string &identifier, idx_t &index, PreparedParamType type) {
|
100
121
|
auto &root = RootTransformer();
|
101
|
-
|
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
|
-
|
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
|
15
|
+
auto parameter_id = expr.identifier;
|
17
16
|
// check if a parameter value has already been supplied
|
18
|
-
if (
|
17
|
+
if (binder.parameters->parameter_data.count(parameter_id)) {
|
19
18
|
// it has! emit a constant directly
|
20
|
-
auto &data = binder.parameters->parameter_data[
|
21
|
-
auto constant = make_uniq<BoundConstantExpression>(data.
|
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
|
-
|
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(
|
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[
|
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(
|
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
|
-
|
33
|
+
case_insensitive_map_t<Value> bind_values;
|
29
34
|
auto constant_binder = Binder::CreateBinder(context);
|
30
35
|
constant_binder->SetCanContainNulls(true);
|
31
|
-
for (
|
36
|
+
for (auto &pair : mapped_named_values) {
|
32
37
|
ConstantBinder cbinder(*constant_binder, context, "EXECUTE statement");
|
33
|
-
auto bound_expr = cbinder.Bind(
|
38
|
+
auto bound_expr = cbinder.Bind(pair.second);
|
34
39
|
|
35
40
|
Value value = ExpressionExecutor::EvaluateScalar(context, *bound_expr, true);
|
36
|
-
bind_values.
|
41
|
+
bind_values[pair.first] = std::move(value);
|
37
42
|
}
|
38
43
|
unique_ptr<LogicalOperator> rebound_plan;
|
39
|
-
|
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 (
|
43
|
-
prepared_planner.parameter_data.
|
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(
|
9
|
+
BoundParameterExpression::BoundParameterExpression(const string &identifier)
|
10
10
|
: Expression(ExpressionType::VALUE_PARAMETER, ExpressionClass::BOUND_PARAMETER,
|
11
11
|
LogicalType(LogicalTypeId::UNKNOWN)),
|
12
|
-
|
12
|
+
identifier(identifier) {
|
13
13
|
}
|
14
14
|
|
15
|
-
BoundParameterExpression::BoundParameterExpression(bound_parameter_map_t &global_parameter_set,
|
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
|
-
|
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(
|
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[
|
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 "$" +
|
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
|
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(
|
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>(
|
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.
|
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
|
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,
|
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
|
87
|
-
auto &
|
86
|
+
auto &identifier = kv.first;
|
87
|
+
auto ¶m = kv.second;
|
88
88
|
// check if the type of the parameter could be resolved
|
89
|
-
if (!
|
89
|
+
if (!param->return_type.IsValid()) {
|
90
90
|
properties.bound_all_parameters = false;
|
91
91
|
continue;
|
92
92
|
}
|
93
|
-
|
94
|
-
value_map[
|
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,
|
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("
|
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
|
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 &>(),
|
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("
|
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("
|
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->
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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->
|
69
|
+
parameter->identifier = identifier;
|
65
70
|
parameter->alias = alias;
|
66
71
|
child = std::move(parameter);
|
67
72
|
return;
|