duckdb 0.7.1-dev240.0 → 0.7.1-dev320.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/README.md +1 -1
- package/package.json +3 -3
- package/src/duckdb/extension/json/json_scan.cpp +1 -4
- package/src/duckdb/extension/parquet/column_reader.cpp +7 -0
- package/src/duckdb/extension/parquet/include/column_reader.hpp +1 -0
- package/src/duckdb/extension/parquet/parquet-extension.cpp +2 -10
- package/src/duckdb/src/catalog/catalog.cpp +62 -13
- package/src/duckdb/src/catalog/catalog_entry/index_catalog_entry.cpp +8 -7
- package/src/duckdb/src/catalog/default/default_views.cpp +1 -1
- package/src/duckdb/src/common/file_system.cpp +23 -9
- package/src/duckdb/src/common/local_file_system.cpp +4 -4
- package/src/duckdb/src/execution/index/art/art.cpp +117 -67
- package/src/duckdb/src/execution/index/art/art_key.cpp +24 -12
- package/src/duckdb/src/execution/index/art/leaf.cpp +7 -8
- package/src/duckdb/src/execution/index/art/node.cpp +13 -27
- package/src/duckdb/src/execution/index/art/node16.cpp +5 -8
- package/src/duckdb/src/execution/index/art/node256.cpp +3 -5
- package/src/duckdb/src/execution/index/art/node4.cpp +4 -7
- package/src/duckdb/src/execution/index/art/node48.cpp +5 -8
- package/src/duckdb/src/execution/index/art/prefix.cpp +2 -3
- package/src/duckdb/src/execution/operator/helper/physical_reset.cpp +1 -9
- package/src/duckdb/src/execution/operator/helper/physical_set.cpp +1 -9
- package/src/duckdb/src/function/pragma/pragma_queries.cpp +2 -2
- package/src/duckdb/src/function/scalar/generic/current_setting.cpp +2 -2
- package/src/duckdb/src/function/table/read_csv.cpp +3 -5
- package/src/duckdb/src/function/table/table_scan.cpp +3 -0
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/catalog.hpp +7 -1
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry/duck_index_entry.hpp +1 -1
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry/index_catalog_entry.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/enums/wal_type.hpp +3 -0
- package/src/duckdb/src/include/duckdb/common/file_system.hpp +1 -1
- package/src/duckdb/src/include/duckdb/execution/index/art/art.hpp +37 -41
- package/src/duckdb/src/include/duckdb/execution/index/art/art_key.hpp +8 -11
- package/src/duckdb/src/include/duckdb/main/{extension_functions.hpp → extension_entries.hpp} +26 -5
- package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +3 -0
- package/src/duckdb/src/include/duckdb/planner/binder.hpp +3 -0
- package/src/duckdb/src/include/duckdb/planner/expression_binder/index_binder.hpp +10 -3
- package/src/duckdb/src/include/duckdb/storage/data_table.hpp +7 -1
- package/src/duckdb/src/include/duckdb/storage/index.hpp +47 -38
- package/src/duckdb/src/include/duckdb/storage/write_ahead_log.hpp +7 -0
- package/src/duckdb/src/main/database.cpp +4 -2
- package/src/duckdb/src/main/extension/extension_load.cpp +22 -3
- package/src/duckdb/src/parser/parsed_data/create_index_info.cpp +3 -0
- package/src/duckdb/src/planner/binder/statement/bind_create_table.cpp +13 -0
- package/src/duckdb/src/planner/expression_binder/index_binder.cpp +32 -1
- package/src/duckdb/src/storage/buffer_manager.cpp +30 -3
- package/src/duckdb/src/storage/compression/bitpacking.cpp +16 -7
- package/src/duckdb/src/storage/data_table.cpp +66 -3
- package/src/duckdb/src/storage/index.cpp +1 -1
- package/src/duckdb/src/storage/local_storage.cpp +1 -1
- package/src/duckdb/src/storage/table_index_list.cpp +1 -2
- package/src/duckdb/src/storage/wal_replay.cpp +68 -0
- package/src/duckdb/src/storage/write_ahead_log.cpp +21 -1
- package/src/duckdb/src/transaction/commit_state.cpp +5 -2
- package/src/duckdb/third_party/concurrentqueue/blockingconcurrentqueue.h +2 -2
- package/src/statement.cpp +46 -12
- package/test/arrow.test.ts +3 -3
- package/test/prepare.test.ts +39 -1
- package/test/typescript_decls.test.ts +1 -1
|
@@ -1144,15 +1144,78 @@ void DataTable::UpdateColumn(TableCatalogEntry &table, ClientContext &context, V
|
|
|
1144
1144
|
}
|
|
1145
1145
|
|
|
1146
1146
|
//===--------------------------------------------------------------------===//
|
|
1147
|
-
//
|
|
1147
|
+
// Index Scan
|
|
1148
1148
|
//===--------------------------------------------------------------------===//
|
|
1149
|
-
void DataTable::
|
|
1149
|
+
void DataTable::InitializeWALCreateIndexScan(CreateIndexScanState &state, const vector<column_t> &column_ids) {
|
|
1150
1150
|
// we grab the append lock to make sure nothing is appended until AFTER we finish the index scan
|
|
1151
1151
|
state.append_lock = std::unique_lock<mutex>(append_lock);
|
|
1152
|
-
row_groups->InitializeCreateIndexScan(state);
|
|
1153
1152
|
InitializeScan(state, column_ids);
|
|
1154
1153
|
}
|
|
1155
1154
|
|
|
1155
|
+
void DataTable::WALAddIndex(ClientContext &context, unique_ptr<Index> index,
|
|
1156
|
+
const vector<unique_ptr<Expression>> &expressions) {
|
|
1157
|
+
|
|
1158
|
+
// if the data table is empty
|
|
1159
|
+
if (row_groups->IsEmpty()) {
|
|
1160
|
+
info->indexes.AddIndex(std::move(index));
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
auto &allocator = Allocator::Get(db);
|
|
1165
|
+
|
|
1166
|
+
DataChunk result;
|
|
1167
|
+
result.Initialize(allocator, index->logical_types);
|
|
1168
|
+
|
|
1169
|
+
DataChunk intermediate;
|
|
1170
|
+
vector<LogicalType> intermediate_types;
|
|
1171
|
+
auto column_ids = index->column_ids;
|
|
1172
|
+
column_ids.push_back(COLUMN_IDENTIFIER_ROW_ID);
|
|
1173
|
+
for (auto &id : index->column_ids) {
|
|
1174
|
+
auto &col = column_definitions[id];
|
|
1175
|
+
intermediate_types.push_back(col.Type());
|
|
1176
|
+
}
|
|
1177
|
+
intermediate_types.emplace_back(LogicalType::ROW_TYPE);
|
|
1178
|
+
intermediate.Initialize(allocator, intermediate_types);
|
|
1179
|
+
|
|
1180
|
+
// initialize an index scan
|
|
1181
|
+
CreateIndexScanState state;
|
|
1182
|
+
InitializeWALCreateIndexScan(state, column_ids);
|
|
1183
|
+
|
|
1184
|
+
if (!is_root) {
|
|
1185
|
+
throw InternalException("Error during WAL replay. Cannot add an index to a table that has been altered.");
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// now start incrementally building the index
|
|
1189
|
+
{
|
|
1190
|
+
IndexLock lock;
|
|
1191
|
+
index->InitializeLock(lock);
|
|
1192
|
+
|
|
1193
|
+
while (true) {
|
|
1194
|
+
intermediate.Reset();
|
|
1195
|
+
result.Reset();
|
|
1196
|
+
// scan a new chunk from the table to index
|
|
1197
|
+
CreateIndexScan(state, intermediate, TableScanType::TABLE_SCAN_COMMITTED_ROWS_OMIT_PERMANENTLY_DELETED);
|
|
1198
|
+
if (intermediate.size() == 0) {
|
|
1199
|
+
// finished scanning for index creation
|
|
1200
|
+
// release all locks
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
// resolve the expressions for this chunk
|
|
1204
|
+
index->ExecuteExpressions(intermediate, result);
|
|
1205
|
+
|
|
1206
|
+
// insert into the index
|
|
1207
|
+
if (!index->Insert(lock, result, intermediate.data[intermediate.ColumnCount() - 1])) {
|
|
1208
|
+
throw InternalException("Error during WAL replay. Can't create unique index, table contains "
|
|
1209
|
+
"duplicate data on indexed column(s).");
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
info->indexes.AddIndex(std::move(index));
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
//===--------------------------------------------------------------------===//
|
|
1217
|
+
// Statistics
|
|
1218
|
+
//===--------------------------------------------------------------------===//
|
|
1156
1219
|
unique_ptr<BaseStatistics> DataTable::GetStatistics(ClientContext &context, column_t column_id) {
|
|
1157
1220
|
if (column_id == COLUMN_IDENTIFIER_ROW_ID) {
|
|
1158
1221
|
return nullptr;
|
|
@@ -86,7 +86,7 @@ bool Index::IndexIsUpdated(const vector<PhysicalIndex> &column_ids) const {
|
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
BlockPointer Index::Serialize(
|
|
89
|
+
BlockPointer Index::Serialize(MetaBlockWriter &writer) {
|
|
90
90
|
throw NotImplementedException("The implementation of this index serialization does not exist.");
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -127,7 +127,7 @@ LocalTableStorage::LocalTableStorage(DataTable &table)
|
|
|
127
127
|
unbound_expressions.push_back(expr->Copy());
|
|
128
128
|
}
|
|
129
129
|
indexes.AddIndex(make_unique<ART>(art.column_ids, art.table_io_manager, std::move(unbound_expressions),
|
|
130
|
-
art.constraint_type, art.db,
|
|
130
|
+
art.constraint_type, art.db, true));
|
|
131
131
|
}
|
|
132
132
|
return false;
|
|
133
133
|
});
|
|
@@ -60,8 +60,7 @@ void TableIndexList::VerifyForeignKey(const vector<PhysicalIndex> &fk_keys, Data
|
|
|
60
60
|
throw InternalException("Internal Foreign Key error: could not find index to verify...");
|
|
61
61
|
}
|
|
62
62
|
conflict_manager.SetIndexCount(1);
|
|
63
|
-
|
|
64
|
-
index->LookupValues(chunk, conflict_manager);
|
|
63
|
+
index->CheckConstraintsForChunk(chunk, conflict_manager);
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
vector<column_t> TableIndexList::GetRequiredColumns() {
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
#include "duckdb/storage/write_ahead_log.hpp"
|
|
19
19
|
#include "duckdb/storage/storage_manager.hpp"
|
|
20
20
|
#include "duckdb/main/attached_database.hpp"
|
|
21
|
+
#include "duckdb/execution/index/art/art.hpp"
|
|
22
|
+
#include "duckdb/catalog/catalog_entry/duck_index_entry.hpp"
|
|
21
23
|
|
|
22
24
|
namespace duckdb {
|
|
23
25
|
|
|
@@ -154,6 +156,12 @@ void ReplayState::ReplayEntry(WALType entry_type) {
|
|
|
154
156
|
case WALType::DROP_TABLE_MACRO:
|
|
155
157
|
ReplayDropTableMacro();
|
|
156
158
|
break;
|
|
159
|
+
case WALType::CREATE_INDEX:
|
|
160
|
+
ReplayCreateIndex();
|
|
161
|
+
break;
|
|
162
|
+
case WALType::DROP_INDEX:
|
|
163
|
+
ReplayDropIndex();
|
|
164
|
+
break;
|
|
157
165
|
case WALType::USE_TABLE:
|
|
158
166
|
ReplayUseTable();
|
|
159
167
|
break;
|
|
@@ -379,6 +387,66 @@ void ReplayState::ReplayDropTableMacro() {
|
|
|
379
387
|
catalog.DropEntry(context, &info);
|
|
380
388
|
}
|
|
381
389
|
|
|
390
|
+
//===--------------------------------------------------------------------===//
|
|
391
|
+
// Replay Index
|
|
392
|
+
//===--------------------------------------------------------------------===//
|
|
393
|
+
void ReplayState::ReplayCreateIndex() {
|
|
394
|
+
|
|
395
|
+
auto info = IndexCatalogEntry::Deserialize(source, context);
|
|
396
|
+
if (deserialize_only) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// get the physical table to which we'll add the index
|
|
401
|
+
auto table = catalog.GetEntry<TableCatalogEntry>(context, info->schema, info->table->table_name);
|
|
402
|
+
auto &data_table = table->GetStorage();
|
|
403
|
+
|
|
404
|
+
// bind the parsed expressions
|
|
405
|
+
if (info->expressions.empty()) {
|
|
406
|
+
for (auto &parsed_expr : info->parsed_expressions) {
|
|
407
|
+
info->expressions.push_back(parsed_expr->Copy());
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
auto binder = Binder::CreateBinder(context);
|
|
411
|
+
auto expressions = binder->BindCreateIndexExpressions(table, info.get());
|
|
412
|
+
|
|
413
|
+
// create the empty index
|
|
414
|
+
unique_ptr<Index> index;
|
|
415
|
+
switch (info->index_type) {
|
|
416
|
+
case IndexType::ART: {
|
|
417
|
+
index = make_unique<ART>(info->column_ids, TableIOManager::Get(data_table), expressions, info->constraint_type,
|
|
418
|
+
data_table.db, true);
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
default:
|
|
422
|
+
throw InternalException("Unimplemented index type");
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// add the index to the catalog
|
|
426
|
+
auto index_entry = (DuckIndexEntry *)catalog.CreateIndex(context, info.get());
|
|
427
|
+
index_entry->index = index.get();
|
|
428
|
+
index_entry->info = data_table.info;
|
|
429
|
+
for (auto &parsed_expr : info->parsed_expressions) {
|
|
430
|
+
index_entry->parsed_expressions.push_back(parsed_expr->Copy());
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// physically add the index to the data table storage
|
|
434
|
+
data_table.WALAddIndex(context, std::move(index), expressions);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
void ReplayState::ReplayDropIndex() {
|
|
438
|
+
|
|
439
|
+
DropInfo info;
|
|
440
|
+
info.type = CatalogType::INDEX_ENTRY;
|
|
441
|
+
info.schema = source.Read<string>();
|
|
442
|
+
info.name = source.Read<string>();
|
|
443
|
+
if (deserialize_only) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
catalog.DropEntry(context, &info);
|
|
448
|
+
}
|
|
449
|
+
|
|
382
450
|
//===--------------------------------------------------------------------===//
|
|
383
451
|
// Replay Data
|
|
384
452
|
//===--------------------------------------------------------------------===//
|
|
@@ -119,7 +119,7 @@ void WriteAheadLog::WriteSequenceValue(SequenceCatalogEntry *entry, SequenceValu
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
//===--------------------------------------------------------------------===//
|
|
122
|
-
//
|
|
122
|
+
// MACROS
|
|
123
123
|
//===--------------------------------------------------------------------===//
|
|
124
124
|
void WriteAheadLog::WriteCreateMacro(ScalarMacroCatalogEntry *entry) {
|
|
125
125
|
if (skip_writing) {
|
|
@@ -155,6 +155,26 @@ void WriteAheadLog::WriteDropTableMacro(TableMacroCatalogEntry *entry) {
|
|
|
155
155
|
writer->WriteString(entry->name);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
//===--------------------------------------------------------------------===//
|
|
159
|
+
// Indexes
|
|
160
|
+
//===--------------------------------------------------------------------===//
|
|
161
|
+
void WriteAheadLog::WriteCreateIndex(IndexCatalogEntry *entry) {
|
|
162
|
+
if (skip_writing) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
writer->Write<WALType>(WALType::CREATE_INDEX);
|
|
166
|
+
entry->Serialize(*writer);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
void WriteAheadLog::WriteDropIndex(IndexCatalogEntry *entry) {
|
|
170
|
+
if (skip_writing) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
writer->Write<WALType>(WALType::DROP_INDEX);
|
|
174
|
+
writer->WriteString(entry->schema->name);
|
|
175
|
+
writer->WriteString(entry->name);
|
|
176
|
+
}
|
|
177
|
+
|
|
158
178
|
//===--------------------------------------------------------------------===//
|
|
159
179
|
// Custom Types
|
|
160
180
|
//===--------------------------------------------------------------------===//
|
|
@@ -87,7 +87,9 @@ void CommitState::WriteCatalogEntry(CatalogEntry *entry, data_ptr_t dataptr) {
|
|
|
87
87
|
case CatalogType::TABLE_MACRO_ENTRY:
|
|
88
88
|
log->WriteCreateTableMacro((TableMacroCatalogEntry *)parent);
|
|
89
89
|
break;
|
|
90
|
-
|
|
90
|
+
case CatalogType::INDEX_ENTRY:
|
|
91
|
+
log->WriteCreateIndex((IndexCatalogEntry *)parent);
|
|
92
|
+
break;
|
|
91
93
|
case CatalogType::TYPE_ENTRY:
|
|
92
94
|
log->WriteCreateType((TypeCatalogEntry *)parent);
|
|
93
95
|
break;
|
|
@@ -119,6 +121,8 @@ void CommitState::WriteCatalogEntry(CatalogEntry *entry, data_ptr_t dataptr) {
|
|
|
119
121
|
log->WriteDropType((TypeCatalogEntry *)entry);
|
|
120
122
|
break;
|
|
121
123
|
case CatalogType::INDEX_ENTRY:
|
|
124
|
+
log->WriteDropIndex((IndexCatalogEntry *)entry);
|
|
125
|
+
break;
|
|
122
126
|
case CatalogType::PREPARED_STATEMENT:
|
|
123
127
|
case CatalogType::SCALAR_FUNCTION_ENTRY:
|
|
124
128
|
// do nothing, indexes/prepared statements/functions aren't persisted to disk
|
|
@@ -127,7 +131,6 @@ void CommitState::WriteCatalogEntry(CatalogEntry *entry, data_ptr_t dataptr) {
|
|
|
127
131
|
throw InternalException("Don't know how to drop this type!");
|
|
128
132
|
}
|
|
129
133
|
break;
|
|
130
|
-
case CatalogType::INDEX_ENTRY:
|
|
131
134
|
case CatalogType::PREPARED_STATEMENT:
|
|
132
135
|
case CatalogType::AGGREGATE_FUNCTION_ENTRY:
|
|
133
136
|
case CatalogType::SCALAR_FUNCTION_ENTRY:
|
|
@@ -24,8 +24,8 @@ template<typename T, typename Traits = ConcurrentQueueDefaultTraits>
|
|
|
24
24
|
class BlockingConcurrentQueue
|
|
25
25
|
{
|
|
26
26
|
private:
|
|
27
|
-
typedef ::
|
|
28
|
-
typedef ::
|
|
27
|
+
typedef ::duckdb_moodycamel::ConcurrentQueue<T, Traits> ConcurrentQueue;
|
|
28
|
+
typedef ::duckdb_moodycamel::LightweightSemaphore LightweightSemaphore;
|
|
29
29
|
|
|
30
30
|
public:
|
|
31
31
|
typedef typename ConcurrentQueue::producer_token_t producer_token_t;
|
package/src/statement.cpp
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
#include <string>
|
|
9
9
|
#include <regex>
|
|
10
10
|
|
|
11
|
+
using std::unique_ptr;
|
|
12
|
+
|
|
11
13
|
namespace node_duckdb {
|
|
12
14
|
|
|
13
15
|
Napi::FunctionReference Statement::constructor;
|
|
@@ -28,13 +30,45 @@ Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) {
|
|
|
28
30
|
return exports;
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
static unique_ptr<duckdb::PreparedStatement> PrepareManyInternal(Statement &statement) {
|
|
34
|
+
auto &connection = statement.connection_ref->connection;
|
|
35
|
+
std::vector<unique_ptr<duckdb::SQLStatement>> statements;
|
|
36
|
+
try {
|
|
37
|
+
if (connection == nullptr) {
|
|
38
|
+
throw duckdb::ConnectionException("Connection was never established or has been closed already");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Prepare all statements
|
|
42
|
+
statements = connection->ExtractStatements(statement.sql);
|
|
43
|
+
if (statements.empty()) {
|
|
44
|
+
throw duckdb::InvalidInputException("No statement to prepare!");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// if there are multiple statements, we directly execute the statements besides the last one
|
|
48
|
+
// we only return the result of the last statement to the user, unless one of the previous statements fails
|
|
49
|
+
for (idx_t i = 0; i + 1 < statements.size(); i++) {
|
|
50
|
+
auto pending_query = connection->PendingQuery(std::move(statements[i]));
|
|
51
|
+
auto res = pending_query->Execute();
|
|
52
|
+
if (res->HasError()) {
|
|
53
|
+
return duckdb::make_unique<duckdb::PreparedStatement>(res->GetErrorObject());
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return connection->Prepare(std::move(statements.back()));
|
|
58
|
+
} catch (const duckdb::Exception &ex) {
|
|
59
|
+
return duckdb::make_unique<duckdb::PreparedStatement>(duckdb::PreservedError(ex));
|
|
60
|
+
} catch (std::exception &ex) {
|
|
61
|
+
return duckdb::make_unique<duckdb::PreparedStatement>(duckdb::PreservedError(ex));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
31
65
|
struct PrepareTask : public Task {
|
|
32
66
|
PrepareTask(Statement &statement, Napi::Function callback) : Task(statement, callback) {
|
|
33
67
|
}
|
|
34
68
|
|
|
35
69
|
void DoWork() override {
|
|
36
70
|
auto &statement = Get<Statement>();
|
|
37
|
-
statement.statement =
|
|
71
|
+
statement.statement = PrepareManyInternal(statement);
|
|
38
72
|
}
|
|
39
73
|
|
|
40
74
|
void Callback() override {
|
|
@@ -221,7 +255,7 @@ struct StatementParam {
|
|
|
221
255
|
};
|
|
222
256
|
|
|
223
257
|
struct RunPreparedTask : public Task {
|
|
224
|
-
RunPreparedTask(Statement &statement,
|
|
258
|
+
RunPreparedTask(Statement &statement, unique_ptr<StatementParam> params, RunType run_type)
|
|
225
259
|
: Task(statement, params->callback), params(std::move(params)), run_type(run_type) {
|
|
226
260
|
}
|
|
227
261
|
|
|
@@ -366,13 +400,13 @@ struct RunPreparedTask : public Task {
|
|
|
366
400
|
} break;
|
|
367
401
|
}
|
|
368
402
|
}
|
|
369
|
-
|
|
370
|
-
|
|
403
|
+
unique_ptr<duckdb::QueryResult> result;
|
|
404
|
+
unique_ptr<StatementParam> params;
|
|
371
405
|
RunType run_type;
|
|
372
406
|
};
|
|
373
407
|
|
|
374
408
|
struct RunQueryTask : public Task {
|
|
375
|
-
RunQueryTask(Statement &statement,
|
|
409
|
+
RunQueryTask(Statement &statement, unique_ptr<StatementParam> params, Napi::Promise::Deferred deferred)
|
|
376
410
|
: Task(statement), deferred(deferred), params(std::move(params)) {
|
|
377
411
|
}
|
|
378
412
|
|
|
@@ -406,11 +440,11 @@ struct RunQueryTask : public Task {
|
|
|
406
440
|
}
|
|
407
441
|
|
|
408
442
|
Napi::Promise::Deferred deferred;
|
|
409
|
-
|
|
410
|
-
|
|
443
|
+
unique_ptr<duckdb::QueryResult> result;
|
|
444
|
+
unique_ptr<StatementParam> params;
|
|
411
445
|
};
|
|
412
446
|
|
|
413
|
-
|
|
447
|
+
unique_ptr<StatementParam> Statement::HandleArgs(const Napi::CallbackInfo &info) {
|
|
414
448
|
size_t start_idx = ignore_first_param ? 1 : 0;
|
|
415
449
|
auto params = duckdb::make_unique<StatementParam>();
|
|
416
450
|
|
|
@@ -541,7 +575,7 @@ struct GetChunkTask : public Task {
|
|
|
541
575
|
}
|
|
542
576
|
|
|
543
577
|
Napi::Promise::Deferred deferred;
|
|
544
|
-
|
|
578
|
+
unique_ptr<duckdb::DataChunk> chunk;
|
|
545
579
|
};
|
|
546
580
|
|
|
547
581
|
struct GetNextArrowIpcTask : public Task {
|
|
@@ -571,10 +605,10 @@ struct GetNextArrowIpcTask : public Task {
|
|
|
571
605
|
duckdb::string_t blob = *(duckdb::string_t *)(chunk->data[0].GetData());
|
|
572
606
|
|
|
573
607
|
// Transfer ownership and Construct ArrayBuffer
|
|
574
|
-
auto data_chunk_ptr = new
|
|
608
|
+
auto data_chunk_ptr = new unique_ptr<duckdb::DataChunk>();
|
|
575
609
|
*data_chunk_ptr = std::move(chunk);
|
|
576
610
|
auto deleter = [](Napi::Env, void *finalizeData, void *hint) {
|
|
577
|
-
delete static_cast<
|
|
611
|
+
delete static_cast<unique_ptr<duckdb::DataChunk> *>(hint);
|
|
578
612
|
};
|
|
579
613
|
auto array_buffer =
|
|
580
614
|
Napi::ArrayBuffer::New(env, (void *)blob.GetDataUnsafe(), blob.GetSize(), deleter, data_chunk_ptr);
|
|
@@ -583,7 +617,7 @@ struct GetNextArrowIpcTask : public Task {
|
|
|
583
617
|
}
|
|
584
618
|
|
|
585
619
|
Napi::Promise::Deferred deferred;
|
|
586
|
-
|
|
620
|
+
unique_ptr<duckdb::DataChunk> chunk;
|
|
587
621
|
};
|
|
588
622
|
|
|
589
623
|
Napi::Value QueryResult::NextChunk(const Napi::CallbackInfo &info) {
|
package/test/arrow.test.ts
CHANGED
|
@@ -20,13 +20,13 @@ describe('arrow IPC API fails neatly when extension not loaded', function() {
|
|
|
20
20
|
db.arrowIPCStream(query).then(
|
|
21
21
|
() => Promise.reject(new Error('Expected method to reject.')),
|
|
22
22
|
err => {
|
|
23
|
-
assert.ok(err.message.includes("
|
|
23
|
+
assert.ok(err.message.includes("arrow"))
|
|
24
24
|
}
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
db.arrowIPCAll(`SELECT * FROM ipc_table`, function (err: null | Error, result: ArrowArray) {
|
|
28
28
|
if (err) {
|
|
29
|
-
assert.ok(err.message.includes("
|
|
29
|
+
assert.ok(err.message.includes("arrow"))
|
|
30
30
|
} else {
|
|
31
31
|
assert.fail("Expected error");
|
|
32
32
|
}
|
|
@@ -39,7 +39,7 @@ describe('arrow IPC API fails neatly when extension not loaded', function() {
|
|
|
39
39
|
it('register buffer should be disabled currently', function(done) {
|
|
40
40
|
db.register_buffer("test", [new Uint8Array(new ArrayBuffer(10))], true, (err: null | Error) => {
|
|
41
41
|
assert.ok(err)
|
|
42
|
-
assert.ok(err.toString().includes("
|
|
42
|
+
assert.ok(err.toString().includes("arrow"));
|
|
43
43
|
done()
|
|
44
44
|
});
|
|
45
45
|
});
|
package/test/prepare.test.ts
CHANGED
|
@@ -66,7 +66,6 @@ describe('prepare', function() {
|
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
|
|
70
69
|
it('should prepare a statement and return values again', function(done) {
|
|
71
70
|
var stmt = db.prepare("SELECT txt, num, flt, blb FROM foo ORDER BY num", function(err: null | Error) {
|
|
72
71
|
if (err) throw err;
|
|
@@ -343,6 +342,45 @@ describe('prepare', function() {
|
|
|
343
342
|
after(function(done) { db.close(done); });
|
|
344
343
|
});
|
|
345
344
|
|
|
345
|
+
describe('prepare multiple statements', function() {
|
|
346
|
+
var db: sqlite3.Database;
|
|
347
|
+
before(function(done) { db = new sqlite3.Database(':memory:',
|
|
348
|
+
function(err) {
|
|
349
|
+
db.run("CREATE TABLE foo (a integer)", done)
|
|
350
|
+
}
|
|
351
|
+
); });
|
|
352
|
+
|
|
353
|
+
it('should directly execute first statements', function(done) {
|
|
354
|
+
db.prepare("insert into foo values (3); insert into foo values (4); select * from foo")
|
|
355
|
+
.all(function(err: null | Error, rows: TableData) {
|
|
356
|
+
if (err) throw err;
|
|
357
|
+
assert.equal(rows[0].a, 3);
|
|
358
|
+
assert.equal(rows[1].a, 4);
|
|
359
|
+
})
|
|
360
|
+
.finalize(done);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('should fail in prepare, when executing the first statement', function(done) {
|
|
364
|
+
let prepared = db.prepare("SELECT * FROM non_existent_table; SELECT 42", function(err: null | Error) {
|
|
365
|
+
if (err) {
|
|
366
|
+
done();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it('should fail in prepare, when preparing the first statement', function(done) {
|
|
373
|
+
let prepared = db.prepare("SELCET * FROM foo; SELECT 42", function(err: null | Error) {
|
|
374
|
+
if (err) {
|
|
375
|
+
done();
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
after(function(done) { db.close(done); });
|
|
382
|
+
});
|
|
383
|
+
|
|
346
384
|
describe('all()', function() {
|
|
347
385
|
var db: sqlite3.Database;
|
|
348
386
|
before(function(done) { db = new sqlite3.Database(':memory:',
|
|
@@ -2,7 +2,7 @@ import * as duckdb from "..";
|
|
|
2
2
|
import assert from "assert";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
|
|
5
|
-
describe("TypeScript
|
|
5
|
+
describe("TypeScript declarations", function () {
|
|
6
6
|
var db: duckdb.Database;
|
|
7
7
|
before(function (done) {
|
|
8
8
|
db = new duckdb.Database(":memory:", duckdb.OPEN_READWRITE, done);
|