duckdb 0.4.1-dev960.0 → 0.5.1-dev2.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/lib/duckdb.js +335 -20
- package/package.json +3 -1
- package/src/connection.cpp +32 -10
- package/src/database.cpp +7 -7
- package/src/duckdb.cpp +33222 -21193
- package/src/duckdb.hpp +4423 -2055
- package/src/duckdb_node.cpp +1 -0
- package/src/duckdb_node.hpp +34 -1
- package/src/parquet-amalgamation.cpp +32940 -32761
- package/src/parquet-amalgamation.hpp +17 -10
- package/src/statement.cpp +147 -23
- package/test/data_type_support.test.js +110 -13
- package/test/extension.test.js +4 -0
- package/test/jsdoc.test.js +60 -0
- package/test/query_result.test.js +23 -0
package/lib/duckdb.js
CHANGED
|
@@ -1,32 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module duckdb
|
|
3
|
+
* @summary these jsdoc annotations are still a work in progress - feedback and suggestions are welcome!
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
var duckdb = require('./duckdb-binding.js');
|
|
2
7
|
module.exports = exports = duckdb;
|
|
3
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Check that errno attribute equals this to check for a duckdb error
|
|
11
|
+
* @constant {number}
|
|
12
|
+
*/
|
|
13
|
+
var ERROR = duckdb.ERROR;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Open database in readonly mode
|
|
17
|
+
* @constant {number}
|
|
18
|
+
*/
|
|
19
|
+
var OPEN_READONLY = duckdb.OPEN_READONLY;
|
|
20
|
+
/**
|
|
21
|
+
* Currently ignored
|
|
22
|
+
* @constant {number}
|
|
23
|
+
*/
|
|
24
|
+
var OPEN_READWRITE = duckdb.OPEN_READWRITE;
|
|
25
|
+
/**
|
|
26
|
+
* Currently ignored
|
|
27
|
+
* @constant {number}
|
|
28
|
+
*/
|
|
29
|
+
var OPEN_CREATE = duckdb.OPEN_CREATE;
|
|
30
|
+
/**
|
|
31
|
+
* Currently ignored
|
|
32
|
+
* @constant {number}
|
|
33
|
+
*/
|
|
34
|
+
var OPEN_FULLMUTEX = duckdb.OPEN_FULLMUTEX;
|
|
35
|
+
/**
|
|
36
|
+
* Currently ignored
|
|
37
|
+
* @constant {number}
|
|
38
|
+
*/
|
|
39
|
+
var OPEN_SHAREDCACHE = duckdb.OPEN_SHAREDCACHE;
|
|
40
|
+
/**
|
|
41
|
+
* Currently ignored
|
|
42
|
+
* @constant {number}
|
|
43
|
+
*/
|
|
44
|
+
var OPEN_PRIVATECACHE = duckdb.OPEN_PRIVATECACHE;
|
|
4
45
|
|
|
5
46
|
// some wrappers for compatibilities sake
|
|
47
|
+
/**
|
|
48
|
+
* Main database interface
|
|
49
|
+
*/
|
|
6
50
|
var Database = duckdb.Database;
|
|
51
|
+
/**
|
|
52
|
+
* @class
|
|
53
|
+
*/
|
|
7
54
|
var Connection = duckdb.Connection;
|
|
55
|
+
/**
|
|
56
|
+
* @class
|
|
57
|
+
*/
|
|
8
58
|
var Statement = duckdb.Statement;
|
|
59
|
+
/**
|
|
60
|
+
* @class
|
|
61
|
+
*/
|
|
62
|
+
var QueryResult = duckdb.QueryResult;
|
|
9
63
|
|
|
64
|
+
/**
|
|
65
|
+
* @method
|
|
66
|
+
* @return data chunk
|
|
67
|
+
*/
|
|
68
|
+
QueryResult.prototype.nextChunk;
|
|
10
69
|
|
|
11
|
-
|
|
70
|
+
/**
|
|
71
|
+
* @name asyncIterator
|
|
72
|
+
* @memberof module:duckdb~QueryResult
|
|
73
|
+
* @method
|
|
74
|
+
* @instance
|
|
75
|
+
* @yields data chunks
|
|
76
|
+
*/
|
|
77
|
+
QueryResult.prototype[Symbol.asyncIterator] = async function*() {
|
|
78
|
+
let prefetch = this.nextChunk();
|
|
79
|
+
while (true) {
|
|
80
|
+
const chunk = await prefetch;
|
|
81
|
+
// Null chunk indicates end of stream
|
|
82
|
+
if (!chunk) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Prefetch the next chunk while we're iterating
|
|
86
|
+
prefetch = this.nextChunk();
|
|
87
|
+
for (const row of chunk) {
|
|
88
|
+
yield row;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Run a SQL statement and trigger a callback when done
|
|
96
|
+
* @arg sql
|
|
97
|
+
* @param {...*} params
|
|
98
|
+
* @param callback
|
|
99
|
+
* @return {void}
|
|
100
|
+
*/
|
|
101
|
+
Connection.prototype.run = function (sql) {
|
|
12
102
|
var statement = new Statement(this, sql);
|
|
13
103
|
return statement.run.apply(statement, arguments);
|
|
14
104
|
}
|
|
15
105
|
|
|
16
|
-
|
|
17
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Run a SQL query and triggers the callback once for all result rows
|
|
108
|
+
* @arg sql
|
|
109
|
+
* @param {...*} params
|
|
110
|
+
* @param callback
|
|
111
|
+
* @return {void}
|
|
112
|
+
*/
|
|
113
|
+
Connection.prototype.all = function (sql) {
|
|
114
|
+
var statement = new Statement(this, sql);
|
|
18
115
|
return statement.all.apply(statement, arguments);
|
|
19
116
|
}
|
|
20
117
|
|
|
21
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Runs a SQL query and triggers the callback for each result row
|
|
120
|
+
* @arg sql
|
|
121
|
+
* @param {...*} params
|
|
122
|
+
* @param callback
|
|
123
|
+
* @return {void}
|
|
124
|
+
*/
|
|
125
|
+
Connection.prototype.each = function (sql) {
|
|
22
126
|
var statement = new Statement(this, sql);
|
|
23
127
|
return statement.each.apply(statement, arguments);
|
|
24
128
|
}
|
|
25
129
|
|
|
26
|
-
|
|
27
|
-
|
|
130
|
+
/**
|
|
131
|
+
* @arg sql
|
|
132
|
+
* @param {...*} params
|
|
133
|
+
* @yields row chunks
|
|
134
|
+
*/
|
|
135
|
+
Connection.prototype.stream = async function* (sql) {
|
|
136
|
+
const statement = new Statement(this, sql);
|
|
137
|
+
const queryResult = await statement.stream.apply(statement, arguments);
|
|
138
|
+
for await (const result of queryResult) {
|
|
139
|
+
yield result;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Register a User Defined Function
|
|
145
|
+
*
|
|
146
|
+
* @arg name
|
|
147
|
+
* @arg return_type
|
|
148
|
+
* @arg fun
|
|
149
|
+
* @return {void}
|
|
150
|
+
* @note this follows the wasm udfs somewhat but is simpler because we can pass data much more cleanly
|
|
151
|
+
*/
|
|
152
|
+
Connection.prototype.register = function (name, return_type, fun) {
|
|
28
153
|
// TODO what if this throws an error somewhere? do we need a try/catch?
|
|
29
|
-
return this.register_bulk(name, return_type, function(desc) {
|
|
154
|
+
return this.register_bulk(name, return_type, function (desc) {
|
|
30
155
|
try {
|
|
31
156
|
// Build an argument resolver
|
|
32
157
|
const buildResolver = (arg) => {
|
|
@@ -126,62 +251,252 @@ Connection.prototype.register = function(name, return_type, fun) {
|
|
|
126
251
|
desc.ret.data[i] = res;
|
|
127
252
|
desc.ret.validity[i] = res === undefined || res === null ? 0 : 1;
|
|
128
253
|
}
|
|
129
|
-
} catch(error) { // work around recently fixed napi bug https://github.com/nodejs/node-addon-api/issues/912
|
|
254
|
+
} catch (error) { // work around recently fixed napi bug https://github.com/nodejs/node-addon-api/issues/912
|
|
130
255
|
console.log(desc.ret);
|
|
131
256
|
msg = error;
|
|
132
257
|
if (typeof error == 'object' && 'message' in error) {
|
|
133
258
|
msg = error.message
|
|
134
259
|
}
|
|
135
|
-
throw {name: 'DuckDB-UDF-Exception', message
|
|
260
|
+
throw { name: 'DuckDB-UDF-Exception', message: msg };
|
|
136
261
|
}
|
|
137
262
|
})
|
|
138
263
|
}
|
|
139
264
|
|
|
140
|
-
|
|
265
|
+
/**
|
|
266
|
+
* Prepare a SQL query for execution
|
|
267
|
+
* @method
|
|
268
|
+
* @arg sql
|
|
269
|
+
* @param {...*} params
|
|
270
|
+
* @param callback
|
|
271
|
+
* @return {Statement}
|
|
272
|
+
*/
|
|
273
|
+
Connection.prototype.prepare;
|
|
274
|
+
/**
|
|
275
|
+
* Execute a SQL query
|
|
276
|
+
* @method
|
|
277
|
+
* @arg sql
|
|
278
|
+
* @param {...*} params
|
|
279
|
+
* @param callback
|
|
280
|
+
* @return {void}
|
|
281
|
+
*/
|
|
282
|
+
Connection.prototype.exec;
|
|
283
|
+
/**
|
|
284
|
+
* Register a User Defined Function
|
|
285
|
+
*
|
|
286
|
+
* @method
|
|
287
|
+
* @arg name
|
|
288
|
+
* @arg return_type
|
|
289
|
+
* @param callback
|
|
290
|
+
* @return {void}
|
|
291
|
+
*/
|
|
292
|
+
Connection.prototype.register_bulk;
|
|
293
|
+
/**
|
|
294
|
+
* Unregister a User Defined Function
|
|
295
|
+
*
|
|
296
|
+
* @method
|
|
297
|
+
* @arg name
|
|
298
|
+
* @arg return_type
|
|
299
|
+
* @param callback
|
|
300
|
+
* @return {void}
|
|
301
|
+
*/
|
|
302
|
+
Connection.prototype.unregister;
|
|
303
|
+
|
|
304
|
+
var default_connection = function (o) {
|
|
141
305
|
if (o.default_connection == undefined) {
|
|
142
306
|
o.default_connection = new duckdb.Connection(o);
|
|
143
307
|
}
|
|
144
|
-
return
|
|
308
|
+
return o.default_connection;
|
|
145
309
|
}
|
|
146
310
|
|
|
147
|
-
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Closes database instance
|
|
314
|
+
* @method
|
|
315
|
+
* @param callback
|
|
316
|
+
* @return {void}
|
|
317
|
+
*/
|
|
318
|
+
Database.prototype.close = function() {
|
|
319
|
+
this.default_connection = null
|
|
320
|
+
this.close_internal.apply(this, arguments);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Internal method. Do not use, call Connection#close instead
|
|
325
|
+
* @method
|
|
326
|
+
* @param callback
|
|
327
|
+
* @return {void}
|
|
328
|
+
*/
|
|
329
|
+
Database.prototype.close_internal;
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Triggers callback when all scheduled database tasks have completed.
|
|
333
|
+
* @method
|
|
334
|
+
* @param callback
|
|
335
|
+
* @return {void}
|
|
336
|
+
*/
|
|
337
|
+
Database.prototype.wait;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* TODO: what does this do?
|
|
341
|
+
* @method
|
|
342
|
+
* @param callback
|
|
343
|
+
* @return {void}
|
|
344
|
+
*/
|
|
345
|
+
Database.prototype.serialize;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* TODO: what does this do?
|
|
349
|
+
* @method
|
|
350
|
+
* @param callback
|
|
351
|
+
* @return {void}
|
|
352
|
+
*/
|
|
353
|
+
Database.prototype.parallelize;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Create a new database connection
|
|
357
|
+
* @method
|
|
358
|
+
* @arg path the database to connect to, either a file path, or `:memory:`
|
|
359
|
+
* @return {Connection}
|
|
360
|
+
*/
|
|
361
|
+
Database.prototype.connect;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Supposedly interrupt queries, but currently does not do anything.
|
|
365
|
+
* @method
|
|
366
|
+
* @param callback
|
|
367
|
+
* @return {void}
|
|
368
|
+
*/
|
|
369
|
+
Database.prototype.interrupt;
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Prepare a SQL query for execution
|
|
373
|
+
* @arg sql
|
|
374
|
+
* @return {Statement}
|
|
375
|
+
*/
|
|
376
|
+
Database.prototype.prepare = function () {
|
|
148
377
|
return default_connection(this).prepare.apply(this.default_connection, arguments);
|
|
149
378
|
}
|
|
150
379
|
|
|
151
|
-
|
|
380
|
+
/**
|
|
381
|
+
* Convenience method for Connection#run using a built-in default connection
|
|
382
|
+
* @arg sql
|
|
383
|
+
* @param {...*} params
|
|
384
|
+
* @param callback
|
|
385
|
+
* @return {void}
|
|
386
|
+
*/
|
|
387
|
+
Database.prototype.run = function () {
|
|
152
388
|
default_connection(this).run.apply(this.default_connection, arguments);
|
|
153
389
|
return this;
|
|
154
390
|
}
|
|
155
391
|
|
|
156
|
-
|
|
392
|
+
/**
|
|
393
|
+
* Convenience method for Connection#each using a built-in default connection
|
|
394
|
+
* @arg sql
|
|
395
|
+
* @param {...*} params
|
|
396
|
+
* @param callback
|
|
397
|
+
* @return {void}
|
|
398
|
+
*/
|
|
399
|
+
Database.prototype.each = function () {
|
|
157
400
|
default_connection(this).each.apply(this.default_connection, arguments);
|
|
158
401
|
return this;
|
|
159
402
|
}
|
|
160
403
|
|
|
161
|
-
|
|
404
|
+
/**
|
|
405
|
+
* Convenience method for Connection#apply using a built-in default connection
|
|
406
|
+
* @arg sql
|
|
407
|
+
* @param {...*} params
|
|
408
|
+
* @param callback
|
|
409
|
+
* @return {void}
|
|
410
|
+
*/
|
|
411
|
+
Database.prototype.all = function () {
|
|
162
412
|
default_connection(this).all.apply(this.default_connection, arguments);
|
|
163
413
|
return this;
|
|
164
414
|
}
|
|
165
415
|
|
|
166
|
-
|
|
416
|
+
/**
|
|
417
|
+
* Convenience method for Connection#exec using a built-in default connection
|
|
418
|
+
* @arg sql
|
|
419
|
+
* @param {...*} params
|
|
420
|
+
* @param callback
|
|
421
|
+
* @return {void}
|
|
422
|
+
*/
|
|
423
|
+
Database.prototype.exec = function () {
|
|
167
424
|
default_connection(this).exec.apply(this.default_connection, arguments);
|
|
168
425
|
return this;
|
|
169
426
|
}
|
|
170
427
|
|
|
171
|
-
|
|
428
|
+
/**
|
|
429
|
+
* Convenience method for Connection#register using a built-in default connection
|
|
430
|
+
* @arg name
|
|
431
|
+
* @arg return_type
|
|
432
|
+
* @arg fun
|
|
433
|
+
* @return {this}
|
|
434
|
+
*/
|
|
435
|
+
Database.prototype.register = function () {
|
|
172
436
|
default_connection(this).register.apply(this.default_connection, arguments);
|
|
173
437
|
return this;
|
|
174
438
|
}
|
|
175
439
|
|
|
176
|
-
|
|
440
|
+
/**
|
|
441
|
+
* Convenience method for Connection#unregister using a built-in default connection
|
|
442
|
+
* @arg name
|
|
443
|
+
* @return {this}
|
|
444
|
+
*/
|
|
445
|
+
Database.prototype.unregister = function () {
|
|
177
446
|
default_connection(this).unregister.apply(this.default_connection, arguments);
|
|
178
447
|
return this;
|
|
179
448
|
}
|
|
180
449
|
|
|
181
|
-
|
|
450
|
+
/**
|
|
451
|
+
* Not implemented
|
|
452
|
+
*/
|
|
453
|
+
Database.prototype.get = function () {
|
|
182
454
|
throw "get() is not implemented because it's evil";
|
|
183
455
|
}
|
|
184
456
|
|
|
185
|
-
|
|
457
|
+
/**
|
|
458
|
+
* Not implemented
|
|
459
|
+
*/
|
|
460
|
+
Statement.prototype.get = function () {
|
|
186
461
|
throw "get() is not implemented because it's evil";
|
|
187
462
|
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* @method
|
|
466
|
+
* @arg sql
|
|
467
|
+
* @param {...*} params
|
|
468
|
+
* @param callback
|
|
469
|
+
* @return {void}
|
|
470
|
+
*/
|
|
471
|
+
Statement.prototype.run;
|
|
472
|
+
/**
|
|
473
|
+
* @method
|
|
474
|
+
* @arg sql
|
|
475
|
+
* @param {...*} params
|
|
476
|
+
* @param callback
|
|
477
|
+
* @return {void}
|
|
478
|
+
*/
|
|
479
|
+
Statement.prototype.all;
|
|
480
|
+
/**
|
|
481
|
+
* @method
|
|
482
|
+
* @arg sql
|
|
483
|
+
* @param {...*} params
|
|
484
|
+
* @param callback
|
|
485
|
+
* @return {void}
|
|
486
|
+
*/
|
|
487
|
+
Statement.prototype.each;
|
|
488
|
+
/**
|
|
489
|
+
* @method
|
|
490
|
+
* @arg sql
|
|
491
|
+
* @param {...*} params
|
|
492
|
+
* @param callback
|
|
493
|
+
* @return {void}
|
|
494
|
+
*/
|
|
495
|
+
Statement.prototype.finalize
|
|
496
|
+
/**
|
|
497
|
+
* @method
|
|
498
|
+
* @arg sql
|
|
499
|
+
* @param {...*} params
|
|
500
|
+
* @yield callback
|
|
501
|
+
*/
|
|
502
|
+
Statement.prototype.stream;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "duckdb",
|
|
3
3
|
"main": "./lib/duckdb.js",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.1-dev2.0",
|
|
5
5
|
"description": "DuckDB node.js API",
|
|
6
6
|
"gypfile": true,
|
|
7
7
|
"dependencies": {
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"aws-sdk": "^2.790.0",
|
|
29
|
+
"chai": "^4.3.6",
|
|
30
|
+
"jsdoc3-parser": "^2.0.0",
|
|
29
31
|
"mocha": "^8.3.0"
|
|
30
32
|
},
|
|
31
33
|
"repository": {
|
package/src/connection.cpp
CHANGED
|
@@ -31,8 +31,29 @@ struct ConnectTask : public Task {
|
|
|
31
31
|
|
|
32
32
|
void DoWork() override {
|
|
33
33
|
auto &connection = Get<Connection>();
|
|
34
|
+
if (!connection.database_ref || !connection.database_ref->database) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
34
37
|
connection.connection = duckdb::make_unique<duckdb::Connection>(*connection.database_ref->database);
|
|
38
|
+
success = true;
|
|
39
|
+
}
|
|
40
|
+
void Callback() override {
|
|
41
|
+
auto &connection = Get<Connection>();
|
|
42
|
+
Napi::Env env = connection.Env();
|
|
43
|
+
|
|
44
|
+
std::vector<napi_value> args;
|
|
45
|
+
if (!success) {
|
|
46
|
+
args.push_back(Utils::CreateError(env, "Invalid database object"));
|
|
47
|
+
} else {
|
|
48
|
+
args.push_back(env.Null());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Napi::HandleScope scope(env);
|
|
52
|
+
|
|
53
|
+
callback.Value().MakeCallback(connection.Value(), args);
|
|
35
54
|
}
|
|
55
|
+
|
|
56
|
+
bool success = false;
|
|
36
57
|
};
|
|
37
58
|
|
|
38
59
|
Connection::Connection(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Connection>(info) {
|
|
@@ -78,7 +99,7 @@ struct JSArgs {
|
|
|
78
99
|
duckdb::DataChunk *args;
|
|
79
100
|
duckdb::Vector *result;
|
|
80
101
|
bool done;
|
|
81
|
-
|
|
102
|
+
duckdb::PreservedError error;
|
|
82
103
|
};
|
|
83
104
|
|
|
84
105
|
void DuckDBNodeUDFLauncher(Napi::Env env, Napi::Function jsudf, std::nullptr_t *, JSArgs *jsargs) {
|
|
@@ -188,8 +209,10 @@ void DuckDBNodeUDFLauncher(Napi::Env env, Napi::Function jsudf, std::nullptr_t *
|
|
|
188
209
|
}
|
|
189
210
|
}
|
|
190
211
|
}
|
|
212
|
+
} catch (const duckdb::Exception &e) {
|
|
213
|
+
jsargs->error = duckdb::PreservedError(e);
|
|
191
214
|
} catch (const std::exception &e) {
|
|
192
|
-
jsargs->error = e
|
|
215
|
+
jsargs->error = duckdb::PreservedError(e);
|
|
193
216
|
}
|
|
194
217
|
jsargs->done = true;
|
|
195
218
|
}
|
|
@@ -219,8 +242,8 @@ struct RegisterTask : public Task {
|
|
|
219
242
|
while (!jsargs.done) {
|
|
220
243
|
std::this_thread::yield();
|
|
221
244
|
}
|
|
222
|
-
if (
|
|
223
|
-
|
|
245
|
+
if (jsargs.error) {
|
|
246
|
+
jsargs.error.Throw();
|
|
224
247
|
}
|
|
225
248
|
};
|
|
226
249
|
|
|
@@ -327,18 +350,17 @@ struct ExecTask : public Task {
|
|
|
327
350
|
return;
|
|
328
351
|
}
|
|
329
352
|
|
|
330
|
-
// thanks Mark
|
|
331
353
|
for (duckdb::idx_t i = 0; i < statements.size(); i++) {
|
|
332
354
|
auto res = connection.connection->Query(move(statements[i]));
|
|
333
|
-
if (
|
|
355
|
+
if (res->HasError()) {
|
|
334
356
|
success = false;
|
|
335
|
-
error = res->
|
|
357
|
+
error = res->GetErrorObject();
|
|
336
358
|
break;
|
|
337
359
|
}
|
|
338
360
|
}
|
|
339
361
|
} catch (duckdb::ParserException &e) {
|
|
340
362
|
success = false;
|
|
341
|
-
error = e
|
|
363
|
+
error = duckdb::PreservedError(e);
|
|
342
364
|
return;
|
|
343
365
|
}
|
|
344
366
|
}
|
|
@@ -346,12 +368,12 @@ struct ExecTask : public Task {
|
|
|
346
368
|
void Callback() override {
|
|
347
369
|
auto env = object.Env();
|
|
348
370
|
Napi::HandleScope scope(env);
|
|
349
|
-
callback.Value().MakeCallback(object.Value(), {success ? env.Null() : Napi::String::New(env, error)});
|
|
371
|
+
callback.Value().MakeCallback(object.Value(), {success ? env.Null() : Napi::String::New(env, error.Message())});
|
|
350
372
|
};
|
|
351
373
|
|
|
352
374
|
std::string sql;
|
|
353
375
|
bool success;
|
|
354
|
-
|
|
376
|
+
duckdb::PreservedError error;
|
|
355
377
|
};
|
|
356
378
|
|
|
357
379
|
Napi::Value Connection::Exec(const Napi::CallbackInfo &info) {
|
package/src/database.cpp
CHANGED
|
@@ -11,7 +11,7 @@ Napi::Object Database::Init(Napi::Env env, Napi::Object exports) {
|
|
|
11
11
|
|
|
12
12
|
Napi::Function t = DefineClass(
|
|
13
13
|
env, "Database",
|
|
14
|
-
{InstanceMethod("
|
|
14
|
+
{InstanceMethod("close_internal", &Database::Close), InstanceMethod("wait", &Database::Wait),
|
|
15
15
|
InstanceMethod("serialize", &Database::Serialize), InstanceMethod("parallelize", &Database::Parallelize),
|
|
16
16
|
InstanceMethod("connect", &Database::Connect), InstanceMethod("interrupt", &Database::Interrupt)});
|
|
17
17
|
|
|
@@ -60,8 +60,10 @@ struct OpenTask : public Task {
|
|
|
60
60
|
extension.Load(*Get<Database>().database);
|
|
61
61
|
success = true;
|
|
62
62
|
|
|
63
|
+
} catch (const duckdb::Exception &ex) {
|
|
64
|
+
error = duckdb::PreservedError(ex);
|
|
63
65
|
} catch (std::exception &ex) {
|
|
64
|
-
error = ex
|
|
66
|
+
error = duckdb::PreservedError(ex);
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -71,7 +73,7 @@ struct OpenTask : public Task {
|
|
|
71
73
|
|
|
72
74
|
std::vector<napi_value> args;
|
|
73
75
|
if (!success) {
|
|
74
|
-
args.push_back(Utils::CreateError(env, error));
|
|
76
|
+
args.push_back(Utils::CreateError(env, error.Message()));
|
|
75
77
|
} else {
|
|
76
78
|
args.push_back(env.Null());
|
|
77
79
|
}
|
|
@@ -83,7 +85,7 @@ struct OpenTask : public Task {
|
|
|
83
85
|
|
|
84
86
|
std::string filename;
|
|
85
87
|
duckdb::DBConfig duckdb_config;
|
|
86
|
-
|
|
88
|
+
duckdb::PreservedError error;
|
|
87
89
|
bool success = false;
|
|
88
90
|
};
|
|
89
91
|
|
|
@@ -141,9 +143,7 @@ static void TaskExecuteCallback(napi_env e, void *data) {
|
|
|
141
143
|
static void TaskCompleteCallback(napi_env e, napi_status status, void *data) {
|
|
142
144
|
std::unique_ptr<TaskHolder> holder((TaskHolder *)data);
|
|
143
145
|
holder->db->TaskComplete(e);
|
|
144
|
-
|
|
145
|
-
holder->task->Callback();
|
|
146
|
-
}
|
|
146
|
+
holder->task->DoCallback();
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
void Database::TaskComplete(Napi::Env env) {
|