duckdb 0.8.2-dev2399.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.
- 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/common/http_state.cpp +78 -0
- package/src/duckdb/src/core_functions/function_list.cpp +2 -2
- package/src/duckdb/src/core_functions/scalar/list/array_slice.cpp +314 -82
- 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/http_state.hpp +61 -28
- package/src/duckdb/src/include/duckdb/common/types/value.hpp +4 -1
- package/src/duckdb/src/include/duckdb/core_functions/scalar/list_functions.hpp +4 -4
- 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/operator_expression.hpp +20 -3
- 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/extension/extension_helper.cpp +2 -1
- 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/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_array_access.cpp +13 -4
- 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/include/nodes/parsenodes.hpp +1 -0
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +12855 -12282
- package/src/duckdb/ub_src_common.cpp +2 -0
- package/src/duckdb/ub_src_function_table_arrow.cpp +2 -0
@@ -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>
|
308
|
-
|
309
|
-
|
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
|
-
|
319
|
-
|
318
|
+
auto ¶meter_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 ¶meters) {
|
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
|
-
|
396
|
+
case_insensitive_map_t<Value> owned_values;
|
397
|
+
if (parameters.parameters) {
|
398
|
+
auto ¶ms = *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 ¶meters) {
|
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 ¶meters) {
|
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 ¶meters) {
|
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
|
-
|
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 ¶meters) {
|
608
616
|
// prepare the query for execution
|
609
617
|
auto prepared = CreatePreparedStatement(lock, query, std::move(statement), parameters.parameters);
|
610
|
-
|
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 ¶meters) {
|
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 ¶meters) {
|
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,
|
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,
|
896
|
+
const PendingQueryParameters ¶meters,
|
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)) {
|
@@ -180,7 +180,8 @@ ExtensionLoadResult ExtensionHelper::LoadExtensionInternal(DuckDB &db, const std
|
|
180
180
|
#endif
|
181
181
|
|
182
182
|
#ifdef DUCKDB_EXTENSIONS_TEST_WITH_LOADABLE
|
183
|
-
|
183
|
+
// Note: weird comma's are on purpose to do easy string contains on a list of extension names
|
184
|
+
if (!initial_load && StringUtil::Contains(DUCKDB_EXTENSIONS_TEST_WITH_LOADABLE, "," + extension + ",")) {
|
184
185
|
Connection con(db);
|
185
186
|
auto result = con.Query((string) "LOAD '" + DUCKDB_EXTENSIONS_BUILD_PATH + "/" + extension + "/" + extension +
|
186
187
|
".duckdb_extension'");
|
@@ -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>
|
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(
|
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
|
-
|
59
|
+
case_insensitive_map_t<LogicalType> PreparedStatement::GetExpectedParameterTypes() const {
|
60
60
|
D_ASSERT(data);
|
61
|
-
|
61
|
+
case_insensitive_map_t<LogicalType> expected_types(data->value_map.size());
|
62
62
|
for (auto &it : data->value_map) {
|
63
|
-
|
64
|
-
|
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[
|
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
|
-
|
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 = &
|
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,
|
22
|
-
|
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
|
-
|
37
|
-
|
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(
|
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
|
52
|
-
|
53
|
-
|
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
|
-
|
60
|
+
auto &value = lookup->second;
|
61
|
+
if (!value.DefaultTryCastAs(it.second->return_type)) {
|
57
62
|
throw BinderException(
|
58
|
-
"Type mismatch for binding parameter with
|
59
|
-
it.second->return_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
|
66
|
+
it.second->SetValue(value);
|
62
67
|
}
|
63
68
|
}
|
64
69
|
|
65
|
-
bool PreparedStatementData::TryGetType(
|
66
|
-
auto it = value_map.find(
|
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->
|
78
|
+
result = it->second->GetValue().type();
|
74
79
|
}
|
75
80
|
return true;
|
76
81
|
}
|
77
82
|
|
78
|
-
LogicalType PreparedStatementData::GetType(
|
83
|
+
LogicalType PreparedStatementData::GetType(const string &identifier) {
|
79
84
|
LogicalType result;
|
80
|
-
if (!TryGetType(
|
81
|
-
throw BinderException("Could not find parameter with
|
85
|
+
if (!TryGetType(identifier, result)) {
|
86
|
+
throw BinderException("Could not find parameter identified with: %s", identifier);
|
82
87
|
}
|
83
88
|
return result;
|
84
89
|
}
|
@@ -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
|
|
@@ -27,10 +27,19 @@ unique_ptr<ParsedExpression> Transformer::TransformArrayAccess(duckdb_libpgquery
|
|
27
27
|
children.push_back(std::move(result));
|
28
28
|
if (index->is_slice) {
|
29
29
|
// slice
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
// if either the lower or upper bound is not specified, we use an empty const list so that we can
|
31
|
+
// handle it in the execution
|
32
|
+
unique_ptr<ParsedExpression> lower =
|
33
|
+
index->lidx ? TransformExpression(index->lidx)
|
34
|
+
: make_uniq<ConstantExpression>(Value::LIST(LogicalType::INTEGER, vector<Value>()));
|
35
|
+
children.push_back(std::move(lower));
|
36
|
+
unique_ptr<ParsedExpression> upper =
|
37
|
+
index->uidx ? TransformExpression(index->uidx)
|
38
|
+
: make_uniq<ConstantExpression>(Value::LIST(LogicalType::INTEGER, vector<Value>()));
|
39
|
+
children.push_back(std::move(upper));
|
40
|
+
if (index->step) {
|
41
|
+
children.push_back(TransformExpression(index->step));
|
42
|
+
}
|
34
43
|
result = make_uniq<OperatorExpression>(ExpressionType::ARRAY_SLICE, std::move(children));
|
35
44
|
} else {
|
36
45
|
// array access
|
@@ -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) {
|