sqlmath 2023.9.25 → 2023.10.25
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/CHANGELOG.md +19 -2
- package/README.md +29 -10
- package/jslint.mjs +2 -2
- package/package.json +3 -3
- package/sqlmath.mjs +507 -498
package/sqlmath.mjs
CHANGED
|
@@ -25,20 +25,28 @@
|
|
|
25
25
|
/*global FinalizationRegistry*/
|
|
26
26
|
"use strict";
|
|
27
27
|
|
|
28
|
-
let
|
|
29
|
-
let
|
|
30
|
-
let
|
|
28
|
+
let JSBATON_ARGC = 8;
|
|
29
|
+
let JSBATON_OFFSET_ALL = 256;
|
|
30
|
+
let JSBATON_OFFSET_ARGV = 128;
|
|
31
|
+
let JSBATON_OFFSET_BUFV = 192;
|
|
32
|
+
let JSBATON_OFFSET_FUNCNAME = 8;
|
|
33
|
+
let JS_MAX_SAFE_INTEGER = 0x1f_ffff_ffff_ffff;
|
|
34
|
+
let JS_MIN_SAFE_INTEGER = -0x1f_ffff_ffff_ffff;
|
|
35
|
+
let SIZEOF_BLOB_MAX = 1_000_000_000;
|
|
36
|
+
let SIZEOF_FUNCNAME = 16;
|
|
31
37
|
let SQLITE_DATATYPE_BLOB = 0x04;
|
|
38
|
+
let SQLITE_DATATYPE_EXTERNALBUFFER = 0x71;
|
|
32
39
|
let SQLITE_DATATYPE_FLOAT = 0x02;
|
|
33
40
|
let SQLITE_DATATYPE_INTEGER = 0x01;
|
|
34
|
-
let SQLITE_DATATYPE_INTEGER_0 =
|
|
41
|
+
let SQLITE_DATATYPE_INTEGER_0 = 0x00;
|
|
35
42
|
let SQLITE_DATATYPE_INTEGER_1 = 0x21;
|
|
36
43
|
let SQLITE_DATATYPE_NULL = 0x05;
|
|
37
|
-
let SQLITE_DATATYPE_OFFSET = 768;
|
|
38
|
-
let SQLITE_DATATYPE_SHAREDARRAYBUFFER = 0x71;
|
|
39
44
|
let SQLITE_DATATYPE_TEXT = 0x03;
|
|
40
45
|
let SQLITE_DATATYPE_TEXT_0 = 0x13;
|
|
41
|
-
let
|
|
46
|
+
let SQLITE_RESPONSETYPE_LASTBLOB = 1;
|
|
47
|
+
|
|
48
|
+
let FILENAME_DBTMP = "/tmp/__dbtmp1"; //jslint-ignore-line
|
|
49
|
+
let IS_BROWSER;
|
|
42
50
|
let SQLITE_OPEN_AUTOPROXY = 0x00000020; /* VFS only */
|
|
43
51
|
let SQLITE_OPEN_CREATE = 0x00000004; /* Ok for sqlite3_open_v2() */
|
|
44
52
|
let SQLITE_OPEN_DELETEONCLOSE = 0x00000008; /* VFS only */
|
|
@@ -63,7 +71,6 @@ let SQLITE_OPEN_WAL = 0x00080000; /* VFS only */
|
|
|
63
71
|
let cModule;
|
|
64
72
|
let cModulePath;
|
|
65
73
|
let consoleError = console.error;
|
|
66
|
-
let dbDict = new WeakMap(); // private-dict of sqlite-database-connections
|
|
67
74
|
let dbFinalizationRegistry;
|
|
68
75
|
// init debugInline
|
|
69
76
|
let debugInline = (function () {
|
|
@@ -97,7 +104,20 @@ let {
|
|
|
97
104
|
let sqlMessageDict = {}; // dict of web-worker-callbacks
|
|
98
105
|
let sqlMessageId = 0;
|
|
99
106
|
let sqlWorker;
|
|
100
|
-
let version = "v2023.
|
|
107
|
+
let version = "v2023.10.25";
|
|
108
|
+
|
|
109
|
+
function assertInt64(val) {
|
|
110
|
+
// This function will assert <val> is within range of c99-signed-long-long.
|
|
111
|
+
val = BigInt(val);
|
|
112
|
+
if (!(
|
|
113
|
+
-9_223_372_036_854_775_808n <= val && val <= 9_223_372_036_854_775_807n
|
|
114
|
+
)) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
`integer ${val} outside signed-64-bit inclusive-range`
|
|
117
|
+
+ " -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807"
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
101
121
|
|
|
102
122
|
function assertJsonEqual(aa, bb, message) {
|
|
103
123
|
|
|
@@ -148,97 +168,6 @@ function assertOrThrow(condition, message) {
|
|
|
148
168
|
}
|
|
149
169
|
}
|
|
150
170
|
|
|
151
|
-
async function cCallAsync(baton, cFuncName, ...argList) {
|
|
152
|
-
|
|
153
|
-
// This function will serialize <argList> to a c <baton>,
|
|
154
|
-
// suitable for passing into napi.
|
|
155
|
-
|
|
156
|
-
let argi = 0;
|
|
157
|
-
let errStack;
|
|
158
|
-
assertOrThrow(
|
|
159
|
-
argList.length < 16,
|
|
160
|
-
"cCallAsync - argList.length must be less than than 16"
|
|
161
|
-
);
|
|
162
|
-
baton = baton || jsbatonCreate();
|
|
163
|
-
// pad argList to length JSBATON_ARGC
|
|
164
|
-
while (argList.length < 2 * JSBATON_ARGC) {
|
|
165
|
-
argList.push(0n);
|
|
166
|
-
}
|
|
167
|
-
// serialize js-value to c-value
|
|
168
|
-
argList = argList.map(function (value, ii) {
|
|
169
|
-
argi = ii;
|
|
170
|
-
switch (typeof value) {
|
|
171
|
-
case "bigint":
|
|
172
|
-
case "boolean":
|
|
173
|
-
baton.setBigInt64(8 + argi * 8, BigInt(value), true);
|
|
174
|
-
return value;
|
|
175
|
-
case "number":
|
|
176
|
-
// check for min/max safe-integer
|
|
177
|
-
assertOrThrow(
|
|
178
|
-
(
|
|
179
|
-
-9_007_199_254_740_991 <= value
|
|
180
|
-
&& value <= 9_007_199_254_740_991
|
|
181
|
-
),
|
|
182
|
-
(
|
|
183
|
-
"non-bigint integer must be within inclusive-range"
|
|
184
|
-
+ " -9,007,199,254,740,991 to 9,007,199,254,740,991"
|
|
185
|
-
)
|
|
186
|
-
);
|
|
187
|
-
baton.setBigInt64(8 + argi * 8, BigInt(value), true);
|
|
188
|
-
return value;
|
|
189
|
-
// case "object":
|
|
190
|
-
// break;
|
|
191
|
-
case "string":
|
|
192
|
-
baton = jsbatonValuePush({
|
|
193
|
-
argi,
|
|
194
|
-
baton,
|
|
195
|
-
value: (
|
|
196
|
-
value.endsWith("\u0000")
|
|
197
|
-
? value
|
|
198
|
-
// append null-terminator to string
|
|
199
|
-
: value + "\u0000"
|
|
200
|
-
)
|
|
201
|
-
});
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
if (ArrayBuffer.isView(value)) {
|
|
205
|
-
return new DataView(
|
|
206
|
-
value.buffer,
|
|
207
|
-
value.byteOffset,
|
|
208
|
-
value.byteLength
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
if (isExternalBuffer(value)) {
|
|
212
|
-
return value;
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
// encode cFuncName into baton
|
|
216
|
-
argi += 1;
|
|
217
|
-
baton = jsbatonValuePush({
|
|
218
|
-
argi,
|
|
219
|
-
baton,
|
|
220
|
-
value: cFuncName + "\u0000"
|
|
221
|
-
});
|
|
222
|
-
// prepend baton, cFuncName to argList
|
|
223
|
-
argList = [
|
|
224
|
-
baton, cFuncName, ...argList
|
|
225
|
-
];
|
|
226
|
-
// preserve stack-trace
|
|
227
|
-
errStack = new Error().stack.replace((
|
|
228
|
-
/.*$/m
|
|
229
|
-
), "");
|
|
230
|
-
try {
|
|
231
|
-
return (
|
|
232
|
-
IS_BROWSER
|
|
233
|
-
? await sqlMessagePost(...argList)
|
|
234
|
-
: await cModule[cFuncName](argList)
|
|
235
|
-
);
|
|
236
|
-
} catch (err) {
|
|
237
|
-
err.stack += errStack;
|
|
238
|
-
assertOrThrow(undefined, err);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
171
|
async function childProcessSpawn2(command, args, option) {
|
|
243
172
|
|
|
244
173
|
// This function will run child_process.spawn as a promise.
|
|
@@ -360,11 +289,18 @@ async function ciBuildExt1NodejsConfigure({
|
|
|
360
289
|
consoleError(`ciBuildExt1Nodejs - configure binding.gyp`);
|
|
361
290
|
await fsWriteFileUnlessTest("binding.gyp", JSON.stringify({
|
|
362
291
|
"target_defaults": {
|
|
363
|
-
"cflags": [
|
|
292
|
+
"cflags": [
|
|
293
|
+
"-Wextra",
|
|
294
|
+
"-std=c11"
|
|
295
|
+
],
|
|
364
296
|
"conditions": [
|
|
365
297
|
[
|
|
366
|
-
"OS ==
|
|
367
|
-
{
|
|
298
|
+
"OS == 'win'",
|
|
299
|
+
{
|
|
300
|
+
"defines": [
|
|
301
|
+
"WIN32"
|
|
302
|
+
]
|
|
303
|
+
}
|
|
368
304
|
]
|
|
369
305
|
],
|
|
370
306
|
// https://github.com/nodejs/node-gyp/blob/v9.3.1/gyp/pylib/gyp/MSVSSettings.py
|
|
@@ -373,29 +309,45 @@ async function ciBuildExt1NodejsConfigure({
|
|
|
373
309
|
"WarningLevel": 3
|
|
374
310
|
}
|
|
375
311
|
},
|
|
376
|
-
"xcode_settings": {
|
|
312
|
+
"xcode_settings": {
|
|
313
|
+
"OTHER_CFLAGS": [
|
|
314
|
+
"-Wextra",
|
|
315
|
+
"-std=c11"
|
|
316
|
+
]
|
|
317
|
+
}
|
|
377
318
|
},
|
|
378
319
|
"targets": [
|
|
379
320
|
{
|
|
380
321
|
"cflags": cflagsNowarning,
|
|
322
|
+
"defines": [
|
|
323
|
+
"SRC_SQLITE_BASE_C2"
|
|
324
|
+
],
|
|
381
325
|
"sources": [
|
|
382
|
-
"
|
|
383
|
-
"
|
|
384
|
-
"
|
|
326
|
+
"sqlmath_base.c",
|
|
327
|
+
"sqlmath_external_pcre2.c",
|
|
328
|
+
"sqlmath_external_sqlite.c",
|
|
329
|
+
"sqlmath_external_zlib.c"
|
|
385
330
|
],
|
|
386
331
|
"target_name": "SRC_SQLITE_BASE",
|
|
387
332
|
"type": "static_library",
|
|
388
|
-
"xcode_settings": {
|
|
333
|
+
"xcode_settings": {
|
|
334
|
+
"OTHER_CFLAGS": cflagsNowarning
|
|
335
|
+
}
|
|
389
336
|
},
|
|
390
337
|
{
|
|
338
|
+
"defines": [
|
|
339
|
+
"SQLMATH_CUSTOM"
|
|
340
|
+
],
|
|
391
341
|
"sources": [
|
|
392
|
-
"
|
|
342
|
+
"sqlmath_custom.c"
|
|
393
343
|
],
|
|
394
344
|
"target_name": "SQLMATH_CUSTOM",
|
|
395
345
|
"type": "static_library"
|
|
396
346
|
},
|
|
397
347
|
{
|
|
398
|
-
"defines": [
|
|
348
|
+
"defines": [
|
|
349
|
+
"SQLMATH_NODEJS_C2"
|
|
350
|
+
],
|
|
399
351
|
"dependencies": [
|
|
400
352
|
"SQLMATH_CUSTOM",
|
|
401
353
|
"SRC_SQLITE_BASE"
|
|
@@ -408,19 +360,20 @@ async function ciBuildExt1NodejsConfigure({
|
|
|
408
360
|
{
|
|
409
361
|
"cflags": cflagsNowarning,
|
|
410
362
|
"defines": [
|
|
411
|
-
"
|
|
363
|
+
"SRC_SQLITE_SHELL_C2"
|
|
412
364
|
],
|
|
413
365
|
"dependencies": [
|
|
414
366
|
"SQLMATH_CUSTOM",
|
|
415
367
|
"SRC_SQLITE_BASE"
|
|
416
368
|
],
|
|
417
369
|
"sources": [
|
|
418
|
-
"
|
|
419
|
-
"build/SRC_SQLITE_SHELL.c"
|
|
370
|
+
"sqlmath_external_sqlite.c"
|
|
420
371
|
],
|
|
421
372
|
"target_name": "shell",
|
|
422
373
|
"type": "executable",
|
|
423
|
-
"xcode_settings": {
|
|
374
|
+
"xcode_settings": {
|
|
375
|
+
"OTHER_CFLAGS": cflagsNowarning
|
|
376
|
+
}
|
|
424
377
|
}
|
|
425
378
|
]
|
|
426
379
|
}, undefined, 4) + "\n");
|
|
@@ -482,62 +435,178 @@ async function ciBuildExt2NodejsBuild({
|
|
|
482
435
|
);
|
|
483
436
|
}
|
|
484
437
|
|
|
485
|
-
function dbCallAsync(baton,
|
|
438
|
+
async function dbCallAsync(baton, argList, mode) {
|
|
486
439
|
|
|
487
|
-
// This function will call
|
|
440
|
+
// This function will call c-function dbXxx() with given <funcname>
|
|
441
|
+
// and return [<baton>, ...argList].
|
|
488
442
|
|
|
489
|
-
let
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
443
|
+
let db;
|
|
444
|
+
let errStack;
|
|
445
|
+
let funcname;
|
|
446
|
+
let id;
|
|
447
|
+
let result;
|
|
448
|
+
let timeElapsed;
|
|
449
|
+
// If argList contains <db>, then mark it as busy.
|
|
450
|
+
if (mode === "modeDb") {
|
|
451
|
+
// init db
|
|
452
|
+
db = argList[0];
|
|
453
|
+
assertOrThrow(
|
|
454
|
+
db.busy >= 0,
|
|
455
|
+
`dbCallAsync - invalid db.busy = ${db.busy}`
|
|
456
|
+
);
|
|
457
|
+
db.ii = (db.ii + 1) % db.connPool.length;
|
|
458
|
+
db.ptr = db.connPool[db.ii][0];
|
|
459
|
+
// increment db.busy
|
|
460
|
+
db.busy += 1;
|
|
461
|
+
try {
|
|
462
|
+
return await dbCallAsync(baton, [db.ptr, ...argList.slice(1)]);
|
|
463
|
+
} finally {
|
|
464
|
+
// decrement db.busy
|
|
465
|
+
db.busy -= 1;
|
|
466
|
+
assertOrThrow(
|
|
467
|
+
db.busy >= 0,
|
|
468
|
+
`dbCallAsync - invalid db.busy = ${db.busy}`
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
// copy argList to avoid side-effect
|
|
473
|
+
argList = [...argList];
|
|
474
|
+
assertOrThrow(
|
|
475
|
+
argList.length <= JSBATON_ARGC,
|
|
476
|
+
`dbCallAsync - argList.length must be less than than ${JSBATON_ARGC}`
|
|
477
|
+
);
|
|
478
|
+
// pad argList to length JSBATON_ARGC
|
|
479
|
+
while (argList.length < JSBATON_ARGC) {
|
|
480
|
+
argList.push(0n);
|
|
481
|
+
}
|
|
482
|
+
// serialize js-value to c-value
|
|
483
|
+
argList = argList.map(function (val, argi) {
|
|
484
|
+
if (val === null || val === undefined) {
|
|
485
|
+
val = 0;
|
|
486
|
+
}
|
|
487
|
+
switch (typeof val) {
|
|
488
|
+
case "bigint":
|
|
489
|
+
case "boolean":
|
|
490
|
+
case "number":
|
|
491
|
+
// check for min/max safe-integer
|
|
492
|
+
assertOrThrow(
|
|
493
|
+
(
|
|
494
|
+
(JS_MIN_SAFE_INTEGER <= val && val <= JS_MAX_SAFE_INTEGER)
|
|
495
|
+
|| typeof val === "bigint"
|
|
496
|
+
),
|
|
497
|
+
(
|
|
498
|
+
"dbCallAsync - "
|
|
499
|
+
+ "non-bigint-integer must be within inclusive-range"
|
|
500
|
+
+ ` ${JS_MIN_SAFE_INTEGER} to ${JS_MAX_SAFE_INTEGER}`
|
|
501
|
+
)
|
|
502
|
+
);
|
|
503
|
+
val = BigInt(val);
|
|
504
|
+
assertInt64(val);
|
|
505
|
+
baton.setBigInt64(JSBATON_OFFSET_ARGV + argi * 8, val, true);
|
|
506
|
+
return val;
|
|
507
|
+
// case "object":
|
|
508
|
+
// break;
|
|
509
|
+
case "string":
|
|
510
|
+
baton = jsbatonSetValue(baton, argi, (
|
|
511
|
+
val.endsWith("\u0000")
|
|
512
|
+
? val
|
|
513
|
+
// append null-terminator to string
|
|
514
|
+
: val + "\u0000"
|
|
515
|
+
));
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
assertOrThrow(
|
|
519
|
+
!ArrayBuffer.isView(val) || val.byteOffset === 0,
|
|
520
|
+
(
|
|
521
|
+
"dbCallAsync - argList cannot contain arraybuffer-views"
|
|
522
|
+
+ " with non-zero byteOffset"
|
|
523
|
+
)
|
|
524
|
+
);
|
|
525
|
+
if (isExternalBuffer(val)) {
|
|
526
|
+
return val;
|
|
527
|
+
}
|
|
528
|
+
throw new Error(`dbCallAsync - invalid arg-type "${typeof val}"`);
|
|
529
|
+
});
|
|
530
|
+
// assert byteOffset === 0
|
|
531
|
+
[baton, ...argList].forEach(function (arg) {
|
|
532
|
+
assertOrThrow(!ArrayBuffer.isView(arg) || arg.byteOffset === 0, arg);
|
|
501
533
|
});
|
|
534
|
+
// extract funcname
|
|
535
|
+
funcname = new TextDecoder().decode(
|
|
536
|
+
new DataView(baton.buffer, JSBATON_OFFSET_FUNCNAME, SIZEOF_FUNCNAME)
|
|
537
|
+
).replace((/\u0000/g), "");
|
|
538
|
+
// preserve stack-trace
|
|
539
|
+
errStack = new Error().stack.replace((/.*$/m), "");
|
|
540
|
+
try {
|
|
541
|
+
|
|
542
|
+
// Dispatch to nodejs-napi.
|
|
543
|
+
|
|
544
|
+
if (!IS_BROWSER) {
|
|
545
|
+
await cModule._jspromiseCreate(baton.buffer, argList, funcname);
|
|
546
|
+
// prepend baton to argList
|
|
547
|
+
return [baton, ...argList];
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Dispatch to web-worker.
|
|
551
|
+
|
|
552
|
+
// increment sqlMessageId
|
|
553
|
+
sqlMessageId += 1;
|
|
554
|
+
id = sqlMessageId;
|
|
555
|
+
// postMessage to web-worker
|
|
556
|
+
sqlWorker.postMessage(
|
|
557
|
+
{
|
|
558
|
+
FILENAME_DBTMP,
|
|
559
|
+
JSBATON_OFFSET_ALL,
|
|
560
|
+
JSBATON_OFFSET_BUFV,
|
|
561
|
+
argList,
|
|
562
|
+
baton,
|
|
563
|
+
funcname,
|
|
564
|
+
id
|
|
565
|
+
},
|
|
566
|
+
// transfer arraybuffer without copying
|
|
567
|
+
[baton.buffer, ...argList.filter(isExternalBuffer)]
|
|
568
|
+
);
|
|
569
|
+
// init timeElapsed
|
|
570
|
+
timeElapsed = Date.now();
|
|
571
|
+
// await result from web-worker
|
|
572
|
+
result = await new Promise(function (resolve) {
|
|
573
|
+
sqlMessageDict[id] = resolve;
|
|
574
|
+
});
|
|
575
|
+
// cleanup sqlMessageDict
|
|
576
|
+
delete sqlMessageDict[id];
|
|
577
|
+
// debug slow postMessage
|
|
578
|
+
timeElapsed = Date.now() - timeElapsed;
|
|
579
|
+
if (timeElapsed > 500 || funcname === "testTimeElapsed") {
|
|
580
|
+
consoleError(
|
|
581
|
+
"sqlMessagePost - "
|
|
582
|
+
+ JSON.stringify({funcname, timeElapsed})
|
|
583
|
+
+ errStack
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
assertOrThrow(!result.errmsg, result.errmsg);
|
|
587
|
+
// prepend baton to argList
|
|
588
|
+
return [result.baton, ...result.argList];
|
|
589
|
+
} catch (err) {
|
|
590
|
+
err.stack += errStack;
|
|
591
|
+
assertOrThrow(undefined, err);
|
|
592
|
+
}
|
|
502
593
|
}
|
|
503
594
|
|
|
504
|
-
async function dbCloseAsync({
|
|
505
|
-
db
|
|
506
|
-
}) {
|
|
595
|
+
async function dbCloseAsync(db) {
|
|
507
596
|
|
|
508
597
|
// This function will close sqlite-database-connection <db>.
|
|
509
598
|
|
|
510
|
-
let __db = dbDeref(db);
|
|
511
599
|
// prevent segfault - do not close db if actions are pending
|
|
512
600
|
assertOrThrow(
|
|
513
|
-
|
|
514
|
-
|
|
601
|
+
db.busy === 0,
|
|
602
|
+
`dbCloseAsync - cannot close db with ${db.busy} actions pending`
|
|
515
603
|
);
|
|
516
604
|
// cleanup connPool
|
|
517
|
-
await Promise.all(
|
|
605
|
+
await Promise.all(db.connPool.map(async function (ptr) {
|
|
518
606
|
let val = ptr[0];
|
|
519
607
|
ptr[0] = 0n;
|
|
520
|
-
await
|
|
521
|
-
undefined,
|
|
522
|
-
"_dbClose",
|
|
523
|
-
val,
|
|
524
|
-
__db.filename
|
|
525
|
-
);
|
|
608
|
+
await dbCallAsync(jsbatonCreate("_dbClose"), [val, db.filename]);
|
|
526
609
|
}));
|
|
527
|
-
dbDict.delete(db);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function dbDeref(db) {
|
|
531
|
-
|
|
532
|
-
// This function will get private-object mapped to <db>.
|
|
533
|
-
|
|
534
|
-
let __db = dbDict.get(db);
|
|
535
|
-
assertOrThrow(__db?.connPool[0] > 0, "invalid or closed db");
|
|
536
|
-
assertOrThrow(__db.busy >= 0, "invalid db.busy " + __db.busy);
|
|
537
|
-
__db.ii = (__db.ii + 1) % __db.connPool.length;
|
|
538
|
-
__db.ptr = __db.connPool[__db.ii][0];
|
|
539
|
-
assertOrThrow(__db.ptr > 0n, "invalid or closed db");
|
|
540
|
-
return __db;
|
|
541
610
|
}
|
|
542
611
|
|
|
543
612
|
function dbExecAndReturnLastBlobAsync({
|
|
@@ -552,7 +621,7 @@ function dbExecAndReturnLastBlobAsync({
|
|
|
552
621
|
return dbExecAsync({
|
|
553
622
|
bindList,
|
|
554
623
|
db,
|
|
555
|
-
responseType: "
|
|
624
|
+
responseType: "lastblob",
|
|
556
625
|
sql
|
|
557
626
|
});
|
|
558
627
|
}
|
|
@@ -560,92 +629,83 @@ function dbExecAndReturnLastBlobAsync({
|
|
|
560
629
|
async function dbExecAsync({
|
|
561
630
|
bindList = [],
|
|
562
631
|
db,
|
|
563
|
-
modeRetry,
|
|
564
632
|
responseType,
|
|
565
633
|
sql
|
|
566
634
|
}) {
|
|
567
635
|
|
|
568
636
|
// This function will exec <sql> in <db> and return <result>.
|
|
569
637
|
|
|
570
|
-
let baton;
|
|
571
|
-
let bindByKey;
|
|
572
|
-
let
|
|
573
|
-
let
|
|
638
|
+
let baton = jsbatonCreate("_dbExec");
|
|
639
|
+
let bindByKey = !Array.isArray(bindList);
|
|
640
|
+
let bufi = [0];
|
|
641
|
+
let referenceList = [];
|
|
574
642
|
let result;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
assertOrThrow(modeRetry > 0, err);
|
|
585
|
-
consoleError(err);
|
|
586
|
-
consoleError(
|
|
587
|
-
"dbExecAsync - retry failed sql-query with "
|
|
588
|
-
+ modeRetry
|
|
589
|
-
+ " remaining retries"
|
|
643
|
+
if (bindByKey) {
|
|
644
|
+
Object.entries(bindList).forEach(function ([key, val]) {
|
|
645
|
+
baton = jsbatonSetValue(baton, undefined, `:${key}\u0000`);
|
|
646
|
+
baton = jsbatonSetValue(
|
|
647
|
+
baton,
|
|
648
|
+
undefined,
|
|
649
|
+
val,
|
|
650
|
+
bufi,
|
|
651
|
+
referenceList
|
|
590
652
|
);
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
baton = jsbatonCreate();
|
|
598
|
-
bindByKey = !Array.isArray(bindList);
|
|
599
|
-
bindListLength = (
|
|
600
|
-
Array.isArray(bindList)
|
|
601
|
-
? bindList.length
|
|
602
|
-
: Object.keys(bindList).length
|
|
603
|
-
);
|
|
604
|
-
externalbufferList = [];
|
|
605
|
-
Object.entries(bindList).forEach(function ([
|
|
606
|
-
key, val
|
|
607
|
-
]) {
|
|
608
|
-
if (bindByKey) {
|
|
609
|
-
baton = jsbatonValuePush({
|
|
653
|
+
});
|
|
654
|
+
} else {
|
|
655
|
+
bindList.forEach(function (val) {
|
|
656
|
+
baton = jsbatonSetValue(
|
|
610
657
|
baton,
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
externalbufferList,
|
|
617
|
-
value: val
|
|
658
|
+
undefined,
|
|
659
|
+
val,
|
|
660
|
+
bufi,
|
|
661
|
+
referenceList
|
|
662
|
+
);
|
|
618
663
|
});
|
|
619
|
-
}
|
|
620
|
-
result = await dbCallAsync(
|
|
664
|
+
}
|
|
665
|
+
[baton, ...result] = await dbCallAsync(
|
|
621
666
|
baton,
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
667
|
+
[
|
|
668
|
+
// 0. db
|
|
669
|
+
db,
|
|
670
|
+
// 1. sql
|
|
671
|
+
String(sql) + "\n;\nPRAGMA noop",
|
|
672
|
+
// 2. bindList.length
|
|
673
|
+
(
|
|
674
|
+
bindByKey
|
|
675
|
+
? Object.keys(bindList).length
|
|
676
|
+
: bindList.length
|
|
677
|
+
),
|
|
678
|
+
// 3. bindByKey
|
|
679
|
+
bindByKey,
|
|
680
|
+
// 4. responseType
|
|
681
|
+
(
|
|
682
|
+
responseType === "lastblob"
|
|
683
|
+
? SQLITE_RESPONSETYPE_LASTBLOB
|
|
684
|
+
: 0
|
|
685
|
+
)
|
|
686
|
+
],
|
|
687
|
+
"modeDb"
|
|
636
688
|
);
|
|
637
|
-
result = result[
|
|
689
|
+
result = result[0];
|
|
690
|
+
if (!IS_BROWSER) {
|
|
691
|
+
result = cModule._jsbatonStealCbuffer(
|
|
692
|
+
baton.buffer,
|
|
693
|
+
0,
|
|
694
|
+
Number(
|
|
695
|
+
responseType !== "arraybuffer" && responseType !== "lastblob"
|
|
696
|
+
)
|
|
697
|
+
);
|
|
698
|
+
}
|
|
638
699
|
switch (responseType) {
|
|
639
700
|
case "arraybuffer":
|
|
640
|
-
case "
|
|
701
|
+
case "lastblob":
|
|
641
702
|
return result;
|
|
642
703
|
case "list":
|
|
643
|
-
return
|
|
704
|
+
return jsonParseArraybuffer(result);
|
|
644
705
|
default:
|
|
645
|
-
result
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
return rowList.map(function (row) {
|
|
706
|
+
return jsonParseArraybuffer(result).map(function (table) {
|
|
707
|
+
let colList = table.shift();
|
|
708
|
+
return table.map(function (row) {
|
|
649
709
|
let dict = {};
|
|
650
710
|
colList.forEach(function (key, ii) {
|
|
651
711
|
dict[key] = row[ii];
|
|
@@ -656,15 +716,15 @@ async function dbExecAsync({
|
|
|
656
716
|
}
|
|
657
717
|
}
|
|
658
718
|
|
|
659
|
-
async function
|
|
719
|
+
async function dbFileLoadAsync({
|
|
660
720
|
db,
|
|
661
721
|
dbData,
|
|
662
722
|
filename,
|
|
663
|
-
|
|
664
|
-
|
|
723
|
+
modeNoop,
|
|
724
|
+
modeSave = 0
|
|
665
725
|
}) {
|
|
666
726
|
|
|
667
|
-
// This function will
|
|
727
|
+
// This function will load <filename> to <db>.
|
|
668
728
|
|
|
669
729
|
if (modeNoop) {
|
|
670
730
|
return;
|
|
@@ -676,38 +736,46 @@ async function dbFileExportAsync({
|
|
|
676
736
|
typeof filename === "string" && filename,
|
|
677
737
|
`invalid filename ${filename}`
|
|
678
738
|
);
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
739
|
+
dbData = await dbCallAsync(
|
|
740
|
+
jsbatonCreate("_dbFileLoad"),
|
|
741
|
+
[
|
|
742
|
+
// 0. sqlite3 * pInMemory
|
|
743
|
+
db,
|
|
744
|
+
// 1. char *zFilename
|
|
745
|
+
filename,
|
|
746
|
+
// 2. const int isSave
|
|
747
|
+
modeSave,
|
|
748
|
+
// 3. undefined
|
|
749
|
+
undefined,
|
|
750
|
+
// 4. dbData - same position as dbOpenAsync
|
|
751
|
+
dbData
|
|
752
|
+
],
|
|
753
|
+
"modeDb"
|
|
687
754
|
);
|
|
755
|
+
return dbData[1 + 0];
|
|
688
756
|
}
|
|
689
757
|
|
|
690
|
-
async function
|
|
758
|
+
async function dbFileSaveAsync({
|
|
691
759
|
db,
|
|
692
760
|
dbData,
|
|
693
761
|
filename
|
|
694
762
|
}) {
|
|
695
763
|
|
|
696
|
-
// This function will
|
|
764
|
+
// This function will save <db> to <filename>.
|
|
697
765
|
|
|
698
|
-
await
|
|
766
|
+
return await dbFileLoadAsync({
|
|
699
767
|
db,
|
|
700
768
|
dbData,
|
|
701
769
|
filename,
|
|
702
|
-
|
|
770
|
+
modeSave: 1
|
|
703
771
|
});
|
|
704
772
|
}
|
|
705
773
|
|
|
706
774
|
async function dbNoopAsync(...argList) {
|
|
707
775
|
|
|
708
|
-
// This function will do nothing except return argList
|
|
776
|
+
// This function will do nothing except return <argList>.
|
|
709
777
|
|
|
710
|
-
return await
|
|
778
|
+
return await dbCallAsync(jsbatonCreate("_dbNoop"), argList);
|
|
711
779
|
}
|
|
712
780
|
|
|
713
781
|
async function dbOpenAsync({
|
|
@@ -727,13 +795,8 @@ async function dbOpenAsync({
|
|
|
727
795
|
// const char *zVfs /* Name of VFS module to use */
|
|
728
796
|
// );
|
|
729
797
|
let connPool;
|
|
730
|
-
let db = {
|
|
731
|
-
|
|
732
|
-
};
|
|
733
|
-
assertOrThrow(
|
|
734
|
-
typeof filename === "string",
|
|
735
|
-
`invalid filename ${filename}`
|
|
736
|
-
);
|
|
798
|
+
let db = {busy: 0, filename, ii: 0};
|
|
799
|
+
assertOrThrow(typeof filename === "string", `invalid filename ${filename}`);
|
|
737
800
|
assertOrThrow(
|
|
738
801
|
!dbData || isExternalBuffer(dbData),
|
|
739
802
|
"dbData must be ArrayBuffer"
|
|
@@ -741,37 +804,28 @@ async function dbOpenAsync({
|
|
|
741
804
|
connPool = await Promise.all(Array.from(new Array(
|
|
742
805
|
threadCount
|
|
743
806
|
), async function () {
|
|
744
|
-
let ptr = await
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
807
|
+
let [ptr] = await dbCallAsync(
|
|
808
|
+
jsbatonCreate("_dbOpen"),
|
|
809
|
+
[
|
|
810
|
+
// 0. const char *filename, Database filename (UTF-8)
|
|
811
|
+
filename,
|
|
812
|
+
// 1. sqlite3 **ppDb, OUT: SQLite db handle
|
|
813
|
+
undefined,
|
|
814
|
+
// 2. int flags, Flags
|
|
815
|
+
flags ?? (
|
|
816
|
+
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI
|
|
817
|
+
),
|
|
818
|
+
// 3. const char *zVfs Name of VFS module to use
|
|
819
|
+
undefined,
|
|
820
|
+
// 4. wasm-only - arraybuffer of raw sqlite-database
|
|
821
|
+
dbData
|
|
822
|
+
]
|
|
759
823
|
);
|
|
760
|
-
ptr = [
|
|
761
|
-
|
|
762
|
-
];
|
|
763
|
-
dbFinalizationRegistry.register(db, {
|
|
764
|
-
afterFinalization,
|
|
765
|
-
ptr
|
|
766
|
-
});
|
|
824
|
+
ptr = [ptr.getBigInt64(JSBATON_OFFSET_ARGV + 0, true)];
|
|
825
|
+
dbFinalizationRegistry.register(db, {afterFinalization, ptr});
|
|
767
826
|
return ptr;
|
|
768
827
|
}));
|
|
769
|
-
|
|
770
|
-
busy: 0,
|
|
771
|
-
connPool,
|
|
772
|
-
filename,
|
|
773
|
-
ii: 0
|
|
774
|
-
});
|
|
828
|
+
db.connPool = connPool;
|
|
775
829
|
return db;
|
|
776
830
|
}
|
|
777
831
|
|
|
@@ -825,35 +879,50 @@ async function fsWriteFileUnlessTest(file, data, mode) {
|
|
|
825
879
|
|
|
826
880
|
function isExternalBuffer(buf) {
|
|
827
881
|
|
|
828
|
-
// This function will check if <buf> is ArrayBuffer
|
|
882
|
+
// This function will check if <buf> is ArrayBuffer.
|
|
829
883
|
|
|
830
|
-
return buf &&
|
|
831
|
-
buf.constructor === ArrayBuffer
|
|
832
|
-
|| (
|
|
833
|
-
typeof SharedArrayBuffer === "function"
|
|
834
|
-
&& buf.constructor === SharedArrayBuffer
|
|
835
|
-
)
|
|
836
|
-
);
|
|
884
|
+
return buf && buf.constructor === ArrayBuffer;
|
|
837
885
|
}
|
|
838
886
|
|
|
839
|
-
function jsbatonCreate() {
|
|
887
|
+
function jsbatonCreate(funcname) {
|
|
840
888
|
|
|
841
889
|
// This function will create buffer <baton>.
|
|
842
890
|
|
|
843
|
-
let baton = new DataView(new ArrayBuffer(
|
|
844
|
-
//
|
|
845
|
-
baton.setInt32(4,
|
|
891
|
+
let baton = new DataView(new ArrayBuffer(JSBATON_OFFSET_ALL));
|
|
892
|
+
// init nallc, nused
|
|
893
|
+
baton.setInt32(4, JSBATON_OFFSET_ALL, true);
|
|
894
|
+
// copy funcname into baton
|
|
895
|
+
new Uint8Array(
|
|
896
|
+
baton.buffer,
|
|
897
|
+
baton.byteOffset + JSBATON_OFFSET_FUNCNAME,
|
|
898
|
+
SIZEOF_FUNCNAME - 1
|
|
899
|
+
).set(new TextEncoder().encode(funcname));
|
|
846
900
|
return baton;
|
|
847
901
|
}
|
|
848
902
|
|
|
849
|
-
function
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
}
|
|
903
|
+
function jsbatonGetInt64(baton, argi) {
|
|
904
|
+
|
|
905
|
+
// This function will return int64-value from <baton> at <argi>.
|
|
906
|
+
|
|
907
|
+
return baton.getBigInt64(JSBATON_OFFSET_ARGV + argi * 8, true);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
function jsbatonGetString(baton, argi) {
|
|
911
|
+
|
|
912
|
+
// This function will return string-value from <baton> at <argi>.
|
|
913
|
+
|
|
914
|
+
let offset = baton.getInt32(JSBATON_OFFSET_ARGV + argi * 8, true);
|
|
915
|
+
return new TextDecoder().decode(new Uint8Array(
|
|
916
|
+
baton.buffer,
|
|
917
|
+
baton.byteOffset + offset + 1 + 4,
|
|
918
|
+
// remove null-terminator from string
|
|
919
|
+
baton.getInt32(offset + 1, true) - 1
|
|
920
|
+
));
|
|
921
|
+
}
|
|
855
922
|
|
|
856
|
-
|
|
923
|
+
function jsbatonSetValue(baton, argi, val, bufi, referenceList) {
|
|
924
|
+
|
|
925
|
+
// This function will set <val> to buffer <baton>.
|
|
857
926
|
|
|
858
927
|
let nn;
|
|
859
928
|
let nused;
|
|
@@ -862,126 +931,130 @@ function jsbatonValuePush({
|
|
|
862
931
|
let vtype;
|
|
863
932
|
/*
|
|
864
933
|
#define SQLITE_DATATYPE_BLOB 0x04
|
|
934
|
+
#define SQLITE_DATATYPE_EXTERNALBUFFER 0x71
|
|
865
935
|
#define SQLITE_DATATYPE_FLOAT 0x02
|
|
866
936
|
#define SQLITE_DATATYPE_INTEGER 0x01
|
|
867
|
-
#define SQLITE_DATATYPE_INTEGER_0
|
|
937
|
+
#define SQLITE_DATATYPE_INTEGER_0 0x00
|
|
868
938
|
#define SQLITE_DATATYPE_INTEGER_1 0x21
|
|
869
939
|
#define SQLITE_DATATYPE_NULL 0x05
|
|
870
|
-
#define SQLITE_DATATYPE_OFFSET 768
|
|
871
|
-
#define SQLITE_DATATYPE_SHAREDARRAYBUFFER 0x71
|
|
872
940
|
#define SQLITE_DATATYPE_TEXT 0x03
|
|
873
941
|
#define SQLITE_DATATYPE_TEXT_0 0x13
|
|
874
|
-
// 1.
|
|
875
|
-
// 2.
|
|
876
|
-
// 3.
|
|
877
|
-
// 4.
|
|
878
|
-
// 5.
|
|
879
|
-
// 6.
|
|
880
|
-
// 7.
|
|
881
|
-
// 8.
|
|
882
|
-
// 9.
|
|
883
|
-
// 10.
|
|
884
|
-
// 11.
|
|
885
|
-
// 12.
|
|
886
|
-
// 13.
|
|
887
|
-
// 14.
|
|
888
|
-
// 15.
|
|
889
|
-
// 16.
|
|
890
|
-
// 17.
|
|
891
|
-
// 18.
|
|
942
|
+
// 1. 0.bigint
|
|
943
|
+
// 2. 0.boolean
|
|
944
|
+
// 3. 0.function
|
|
945
|
+
// 4. 0.number
|
|
946
|
+
// 5. 0.object
|
|
947
|
+
// 6. 0.string
|
|
948
|
+
// 7. 0.symbol
|
|
949
|
+
// 8. 0.undefined
|
|
950
|
+
// 9. 1.bigint
|
|
951
|
+
// 10. 1.boolean
|
|
952
|
+
// 11. 1.function
|
|
953
|
+
// 12. 1.number
|
|
954
|
+
// 13. 1.object
|
|
955
|
+
// 14. 1.string
|
|
956
|
+
// 15. 1.symbol
|
|
957
|
+
// 16. 1.undefined
|
|
958
|
+
// 17. 1.buffer
|
|
959
|
+
// 18. 1.externalbuffer
|
|
892
960
|
*/
|
|
893
|
-
// 10.
|
|
894
|
-
if (
|
|
895
|
-
|
|
961
|
+
// 10. 1.boolean
|
|
962
|
+
if (val === 1 || val === 1n) {
|
|
963
|
+
val = true;
|
|
896
964
|
}
|
|
897
|
-
switch (
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
//
|
|
903
|
-
case "
|
|
965
|
+
switch (
|
|
966
|
+
val
|
|
967
|
+
? "1." + typeof(val)
|
|
968
|
+
: "0." + typeof(val)
|
|
969
|
+
) {
|
|
970
|
+
// 1. 0.bigint
|
|
971
|
+
case "0.bigint":
|
|
972
|
+
// 2. 0.boolean
|
|
973
|
+
case "0.boolean":
|
|
974
|
+
// 4. 0.number
|
|
975
|
+
case "0.number":
|
|
976
|
+
if (Number.isNaN(val)) {
|
|
977
|
+
vtype = SQLITE_DATATYPE_NULL;
|
|
978
|
+
vsize = 0;
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
904
981
|
vtype = SQLITE_DATATYPE_INTEGER_0;
|
|
905
982
|
vsize = 0;
|
|
906
983
|
break;
|
|
907
|
-
// 3.
|
|
908
|
-
// case "
|
|
909
|
-
// 5.
|
|
910
|
-
case "
|
|
911
|
-
// 7.
|
|
912
|
-
case "
|
|
913
|
-
// 8.
|
|
914
|
-
case "
|
|
915
|
-
// 11.
|
|
916
|
-
case "
|
|
917
|
-
// 15.
|
|
918
|
-
case "
|
|
919
|
-
// 16.
|
|
920
|
-
// case "
|
|
984
|
+
// 3. 0.function
|
|
985
|
+
// case "0.function":
|
|
986
|
+
// 5. 0.object
|
|
987
|
+
case "0.object":
|
|
988
|
+
// 7. 0.symbol
|
|
989
|
+
case "0.symbol":
|
|
990
|
+
// 8. 0.undefined
|
|
991
|
+
case "0.undefined":
|
|
992
|
+
// 11. 1.function
|
|
993
|
+
case "1.function":
|
|
994
|
+
// 15. 1.symbol
|
|
995
|
+
case "1.symbol":
|
|
996
|
+
// 16. 1.undefined
|
|
997
|
+
// case "1.undefined":
|
|
921
998
|
vtype = SQLITE_DATATYPE_NULL;
|
|
922
999
|
vsize = 0;
|
|
923
1000
|
break;
|
|
924
|
-
// 6.
|
|
925
|
-
case "
|
|
1001
|
+
// 6. 0.string
|
|
1002
|
+
case "0.string":
|
|
926
1003
|
vtype = SQLITE_DATATYPE_TEXT_0;
|
|
927
1004
|
vsize = 0;
|
|
928
1005
|
break;
|
|
929
|
-
// 9.
|
|
930
|
-
case "
|
|
1006
|
+
// 9. 1.bigint
|
|
1007
|
+
case "1.bigint":
|
|
931
1008
|
vtype = SQLITE_DATATYPE_INTEGER;
|
|
932
1009
|
vsize = 8;
|
|
933
1010
|
break;
|
|
934
|
-
// 10.
|
|
935
|
-
case "
|
|
1011
|
+
// 10. 1.boolean
|
|
1012
|
+
case "1.boolean":
|
|
936
1013
|
vtype = SQLITE_DATATYPE_INTEGER_1;
|
|
937
1014
|
vsize = 0;
|
|
938
1015
|
break;
|
|
939
|
-
// 12.
|
|
940
|
-
case "
|
|
1016
|
+
// 12. 1.number
|
|
1017
|
+
case "1.number":
|
|
941
1018
|
vtype = SQLITE_DATATYPE_FLOAT;
|
|
942
1019
|
vsize = 8;
|
|
943
1020
|
break;
|
|
944
|
-
//
|
|
945
|
-
|
|
1021
|
+
// 14. 1.string
|
|
1022
|
+
case "1.string":
|
|
1023
|
+
val = new TextEncoder().encode(val);
|
|
1024
|
+
vtype = SQLITE_DATATYPE_TEXT;
|
|
1025
|
+
vsize = 4 + val.byteLength;
|
|
1026
|
+
break;
|
|
1027
|
+
// 13. 1.object
|
|
946
1028
|
default:
|
|
947
|
-
// 18.
|
|
948
|
-
if (
|
|
1029
|
+
// 18. 1.externalbuffer
|
|
1030
|
+
if (val.constructor === ArrayBuffer) {
|
|
949
1031
|
assertOrThrow(
|
|
950
1032
|
!IS_BROWSER,
|
|
951
1033
|
"external ArrayBuffer cannot be passed directly to wasm"
|
|
952
1034
|
);
|
|
953
|
-
|
|
954
|
-
externalbufferList.length <= 8,
|
|
955
|
-
"externalbufferList.length must be less than 8"
|
|
956
|
-
);
|
|
957
|
-
externalbufferList.push(new DataView(value));
|
|
958
|
-
vtype = SQLITE_DATATYPE_SHAREDARRAYBUFFER;
|
|
1035
|
+
vtype = SQLITE_DATATYPE_EXTERNALBUFFER;
|
|
959
1036
|
vsize = 4;
|
|
960
1037
|
break;
|
|
961
1038
|
}
|
|
962
|
-
// 17.
|
|
963
|
-
if (ArrayBuffer.isView(
|
|
964
|
-
if (
|
|
1039
|
+
// 17. 1.buffer
|
|
1040
|
+
if (ArrayBuffer.isView(val)) {
|
|
1041
|
+
if (val.byteLength === 0) {
|
|
965
1042
|
vtype = SQLITE_DATATYPE_NULL;
|
|
966
1043
|
vsize = 0;
|
|
967
1044
|
break;
|
|
968
1045
|
}
|
|
969
1046
|
vtype = SQLITE_DATATYPE_BLOB;
|
|
970
|
-
vsize = 4 +
|
|
1047
|
+
vsize = 4 + val.byteLength;
|
|
971
1048
|
break;
|
|
972
1049
|
}
|
|
973
|
-
// 13.
|
|
974
|
-
|
|
975
|
-
typeof
|
|
976
|
-
?
|
|
977
|
-
:
|
|
978
|
-
? value.toJSON()
|
|
979
|
-
: JSON.stringify(value)
|
|
1050
|
+
// 13. 1.object
|
|
1051
|
+
val = new TextEncoder().encode(
|
|
1052
|
+
typeof val.toJSON === "function"
|
|
1053
|
+
? val.toJSON()
|
|
1054
|
+
: JSON.stringify(val)
|
|
980
1055
|
);
|
|
981
|
-
// 14. true.string
|
|
982
|
-
value = new TextEncoder().encode(value);
|
|
983
1056
|
vtype = SQLITE_DATATYPE_TEXT;
|
|
984
|
-
vsize = 4 +
|
|
1057
|
+
vsize = 4 + val.byteLength;
|
|
985
1058
|
}
|
|
986
1059
|
nused = baton.getInt32(4, true);
|
|
987
1060
|
nn = nused + 1 + vsize;
|
|
@@ -995,16 +1068,14 @@ function jsbatonValuePush({
|
|
|
995
1068
|
baton = new DataView(new ArrayBuffer(
|
|
996
1069
|
Math.min(2 ** Math.ceil(Math.log2(nn)), 0x7fff_ffff)
|
|
997
1070
|
));
|
|
998
|
-
// update
|
|
1071
|
+
// update nallc
|
|
999
1072
|
baton.setInt32(0, baton.byteLength, true);
|
|
1000
|
-
// copy
|
|
1001
|
-
new Uint8Array(
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
nused
|
|
1005
|
-
).set(new Uint8Array(tmp.buffer, tmp.byteOffset, nused), 0);
|
|
1073
|
+
// copy old-baton into new-baton
|
|
1074
|
+
new Uint8Array(baton.buffer, baton.byteOffset, nused).set(
|
|
1075
|
+
new Uint8Array(tmp.buffer, tmp.byteOffset, nused)
|
|
1076
|
+
);
|
|
1006
1077
|
}
|
|
1007
|
-
// push vtype
|
|
1078
|
+
// push vtype - 1-byte
|
|
1008
1079
|
baton.setUint8(nused, vtype);
|
|
1009
1080
|
// update nused
|
|
1010
1081
|
baton.setInt32(4, nused + 1 + vsize, true);
|
|
@@ -1014,70 +1085,69 @@ function jsbatonValuePush({
|
|
|
1014
1085
|
case SQLITE_DATATYPE_TEXT:
|
|
1015
1086
|
// set argv[ii] to blob/text location
|
|
1016
1087
|
if (argi !== undefined) {
|
|
1017
|
-
baton.setInt32(
|
|
1088
|
+
baton.setInt32(JSBATON_OFFSET_ARGV + argi * 8, nused, true);
|
|
1018
1089
|
}
|
|
1019
1090
|
vsize -= 4;
|
|
1020
|
-
// push vsize
|
|
1021
1091
|
assertOrThrow(
|
|
1022
|
-
0 <= vsize && vsize <=
|
|
1092
|
+
0 <= vsize && vsize <= SIZEOF_BLOB_MAX,
|
|
1023
1093
|
(
|
|
1024
1094
|
"sqlite-blob byte-length must be within inclusive-range"
|
|
1025
|
-
+
|
|
1095
|
+
+ ` 0 to ${SIZEOF_BLOB_MAX}`
|
|
1026
1096
|
)
|
|
1027
1097
|
);
|
|
1098
|
+
// push vsize - 4-byte
|
|
1028
1099
|
baton.setInt32(nused + 1, vsize, true);
|
|
1100
|
+
// push SQLITE-BLOB/TEXT - vsize-byte
|
|
1029
1101
|
new Uint8Array(
|
|
1030
1102
|
baton.buffer,
|
|
1031
|
-
nused + 1 + 4,
|
|
1103
|
+
baton.byteOffset + nused + 1 + 4,
|
|
1032
1104
|
vsize
|
|
1033
|
-
).set(new Uint8Array(
|
|
1034
|
-
break;
|
|
1035
|
-
case SQLITE_DATATYPE_FLOAT:
|
|
1036
|
-
baton.setFloat64(nused + 1, value, true);
|
|
1105
|
+
).set(new Uint8Array(val.buffer, val.byteOffset, vsize));
|
|
1037
1106
|
break;
|
|
1038
|
-
case
|
|
1107
|
+
case SQLITE_DATATYPE_EXTERNALBUFFER:
|
|
1108
|
+
vsize = val.byteLength;
|
|
1039
1109
|
assertOrThrow(
|
|
1110
|
+
0 <= vsize && vsize <= SIZEOF_BLOB_MAX,
|
|
1040
1111
|
(
|
|
1041
|
-
-
|
|
1042
|
-
|
|
1043
|
-
),
|
|
1044
|
-
(
|
|
1045
|
-
"sqlite-integer must be within inclusive-range "
|
|
1046
|
-
+ "-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807"
|
|
1112
|
+
"sqlite-blob byte-length must be within inclusive-range"
|
|
1113
|
+
+ ` 0 to ${SIZEOF_BLOB_MAX}`
|
|
1047
1114
|
)
|
|
1048
1115
|
);
|
|
1049
|
-
baton.setBigInt64(nused + 1, value, true);
|
|
1050
|
-
break;
|
|
1051
|
-
case SQLITE_DATATYPE_SHAREDARRAYBUFFER:
|
|
1052
|
-
vsize = value.byteLength;
|
|
1053
|
-
// push vsize
|
|
1054
1116
|
assertOrThrow(
|
|
1055
|
-
0
|
|
1056
|
-
|
|
1057
|
-
"sqlite-blob byte-length must be within inclusive-range"
|
|
1058
|
-
+ " 0 to 1,000,000,000"
|
|
1059
|
-
)
|
|
1117
|
+
bufi[0] < JSBATON_ARGC,
|
|
1118
|
+
`cannot pass more than ${JSBATON_ARGC} arraybuffers`
|
|
1060
1119
|
);
|
|
1061
|
-
|
|
1120
|
+
// push externalbuffer - 4-byte
|
|
1121
|
+
baton.setInt32(nused + 1, bufi[0], true);
|
|
1122
|
+
// set buffer
|
|
1123
|
+
cModule._jsbatonSetArraybuffer(baton.buffer, bufi[0], val);
|
|
1124
|
+
// increment bufi
|
|
1125
|
+
bufi[0] += 1;
|
|
1126
|
+
// add buffer to reference_list to prevent gc during db_call.
|
|
1127
|
+
referenceList.push(val);
|
|
1128
|
+
break;
|
|
1129
|
+
case SQLITE_DATATYPE_FLOAT:
|
|
1130
|
+
// push SQLITE-REAL - 8-byte
|
|
1131
|
+
baton.setFloat64(nused + 1, val, true);
|
|
1132
|
+
break;
|
|
1133
|
+
case SQLITE_DATATYPE_INTEGER:
|
|
1134
|
+
assertInt64(val);
|
|
1135
|
+
// push SQLITE-INTEGER - 8-byte
|
|
1136
|
+
baton.setBigInt64(nused + 1, val, true);
|
|
1062
1137
|
break;
|
|
1063
1138
|
}
|
|
1064
1139
|
return baton;
|
|
1065
1140
|
}
|
|
1066
1141
|
|
|
1067
|
-
function
|
|
1068
|
-
argi,
|
|
1069
|
-
baton
|
|
1070
|
-
}) {
|
|
1142
|
+
function jsonParseArraybuffer(buf) {
|
|
1071
1143
|
|
|
1072
|
-
// This function will
|
|
1144
|
+
// This function will JSON.parse arraybuffer <buf>.
|
|
1073
1145
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
baton.getInt32(offset + 1, true) - 1
|
|
1080
|
-
));
|
|
1146
|
+
return JSON.parse(
|
|
1147
|
+
IS_BROWSER
|
|
1148
|
+
? new TextDecoder().decode(buf)
|
|
1149
|
+
: buf
|
|
1150
|
+
);
|
|
1081
1151
|
}
|
|
1082
1152
|
|
|
1083
1153
|
async function moduleFsInit() {
|
|
@@ -1149,59 +1219,6 @@ function objectDeepCopyWithKeysSorted(obj) {
|
|
|
1149
1219
|
return sorted;
|
|
1150
1220
|
}
|
|
1151
1221
|
|
|
1152
|
-
async function sqlMessagePost(baton, cFuncName, ...argList) {
|
|
1153
|
-
|
|
1154
|
-
// This function will post msg to <sqlWorker> and return result.
|
|
1155
|
-
|
|
1156
|
-
let errStack;
|
|
1157
|
-
let id;
|
|
1158
|
-
let result;
|
|
1159
|
-
let timeElapsed = Date.now();
|
|
1160
|
-
// increment sqlMessageId
|
|
1161
|
-
sqlMessageId += 1;
|
|
1162
|
-
id = sqlMessageId;
|
|
1163
|
-
// postMessage to web-worker
|
|
1164
|
-
sqlWorker.postMessage(
|
|
1165
|
-
{
|
|
1166
|
-
argList,
|
|
1167
|
-
baton,
|
|
1168
|
-
cFuncName,
|
|
1169
|
-
id
|
|
1170
|
-
},
|
|
1171
|
-
// transfer arraybuffer without copying
|
|
1172
|
-
[
|
|
1173
|
-
baton.buffer,
|
|
1174
|
-
...argList.filter(function (elem) {
|
|
1175
|
-
return elem && elem.constructor === ArrayBuffer;
|
|
1176
|
-
})
|
|
1177
|
-
]
|
|
1178
|
-
);
|
|
1179
|
-
// preserve stack-trace
|
|
1180
|
-
errStack = new Error().stack.replace((
|
|
1181
|
-
/.*$/m
|
|
1182
|
-
), "");
|
|
1183
|
-
// await result from web-worker
|
|
1184
|
-
result = await new Promise(function (resolve) {
|
|
1185
|
-
sqlMessageDict[id] = resolve;
|
|
1186
|
-
});
|
|
1187
|
-
// cleanup sqlMessageDict
|
|
1188
|
-
delete sqlMessageDict[id];
|
|
1189
|
-
// debug slow postMessage
|
|
1190
|
-
timeElapsed = Date.now() - timeElapsed;
|
|
1191
|
-
if (timeElapsed > 500 || cFuncName === "testTimeElapsed") {
|
|
1192
|
-
consoleError(
|
|
1193
|
-
"sqlMessagePost - " + JSON.stringify({
|
|
1194
|
-
cFuncName,
|
|
1195
|
-
timeElapsed
|
|
1196
|
-
}) + errStack
|
|
1197
|
-
);
|
|
1198
|
-
}
|
|
1199
|
-
assertOrThrow(!result.errmsg, result.errmsg);
|
|
1200
|
-
return [
|
|
1201
|
-
result.baton, result.cFuncName, ...result.argList
|
|
1202
|
-
];
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
1222
|
async function sqlmathInit() {
|
|
1206
1223
|
|
|
1207
1224
|
// This function will init sqlmath.
|
|
@@ -1209,15 +1226,12 @@ async function sqlmathInit() {
|
|
|
1209
1226
|
let moduleModule;
|
|
1210
1227
|
dbFinalizationRegistry = (
|
|
1211
1228
|
dbFinalizationRegistry
|
|
1212
|
-
) || new FinalizationRegistry(function ({
|
|
1213
|
-
afterFinalization,
|
|
1214
|
-
ptr
|
|
1215
|
-
}) {
|
|
1229
|
+
) || new FinalizationRegistry(function ({afterFinalization, ptr}) {
|
|
1216
1230
|
|
|
1217
1231
|
// This function will auto-close any open sqlite3-db-pointer,
|
|
1218
1232
|
// after its js-wrapper has been garbage-collected.
|
|
1219
1233
|
|
|
1220
|
-
|
|
1234
|
+
dbCallAsync(jsbatonCreate("_dbClose"), [ptr[0]]);
|
|
1221
1235
|
if (afterFinalization) {
|
|
1222
1236
|
afterFinalization();
|
|
1223
1237
|
}
|
|
@@ -1226,10 +1240,8 @@ async function sqlmathInit() {
|
|
|
1226
1240
|
// Feature-detect nodejs.
|
|
1227
1241
|
|
|
1228
1242
|
if (
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
&& typeof process?.versions?.node === "string"
|
|
1232
|
-
)
|
|
1243
|
+
typeof process !== "object"
|
|
1244
|
+
|| typeof process?.versions?.node !== "string"
|
|
1233
1245
|
|| cModule
|
|
1234
1246
|
) {
|
|
1235
1247
|
return;
|
|
@@ -1316,19 +1328,15 @@ function sqlmathWebworkerInit({
|
|
|
1316
1328
|
if (modeTest) {
|
|
1317
1329
|
sqlWorker.postMessage = function (data) {
|
|
1318
1330
|
setTimeout(function () {
|
|
1319
|
-
sqlWorker.onmessage({
|
|
1320
|
-
data
|
|
1321
|
-
});
|
|
1331
|
+
sqlWorker.onmessage({data});
|
|
1322
1332
|
});
|
|
1323
1333
|
};
|
|
1324
|
-
// test
|
|
1325
|
-
|
|
1326
|
-
// test
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
modeTest
|
|
1331
|
-
});
|
|
1334
|
+
// test dbCallAsync handling-behavior
|
|
1335
|
+
dbCallAsync(jsbatonCreate("testTimeElapsed"), [true]);
|
|
1336
|
+
// test dbFileLoadAsync handling-behavior
|
|
1337
|
+
dbFileLoadAsync({db, filename: "aa", modeTest});
|
|
1338
|
+
// test jsonParseArraybuffer handling-behavior
|
|
1339
|
+
jsonParseArraybuffer(new TextEncoder().encode("0"));
|
|
1332
1340
|
// revert IS_BROWSER
|
|
1333
1341
|
IS_BROWSER = undefined;
|
|
1334
1342
|
}
|
|
@@ -1339,7 +1347,6 @@ await sqlmathInit();
|
|
|
1339
1347
|
sqlmathInit(); // coverage-hack
|
|
1340
1348
|
|
|
1341
1349
|
export {
|
|
1342
|
-
SQLITE_MAX_LENGTH2,
|
|
1343
1350
|
SQLITE_OPEN_AUTOPROXY,
|
|
1344
1351
|
SQLITE_OPEN_CREATE,
|
|
1345
1352
|
SQLITE_OPEN_DELETEONCLOSE,
|
|
@@ -1361,6 +1368,7 @@ export {
|
|
|
1361
1368
|
SQLITE_OPEN_TRANSIENT_DB,
|
|
1362
1369
|
SQLITE_OPEN_URI,
|
|
1363
1370
|
SQLITE_OPEN_WAL,
|
|
1371
|
+
assertInt64,
|
|
1364
1372
|
assertJsonEqual,
|
|
1365
1373
|
assertNumericalEqual,
|
|
1366
1374
|
assertOrThrow,
|
|
@@ -1369,8 +1377,8 @@ export {
|
|
|
1369
1377
|
dbCloseAsync,
|
|
1370
1378
|
dbExecAndReturnLastBlobAsync,
|
|
1371
1379
|
dbExecAsync,
|
|
1372
|
-
|
|
1373
|
-
|
|
1380
|
+
dbFileLoadAsync,
|
|
1381
|
+
dbFileSaveAsync,
|
|
1374
1382
|
dbNoopAsync,
|
|
1375
1383
|
dbOpenAsync,
|
|
1376
1384
|
debugInline,
|
|
@@ -1378,7 +1386,8 @@ export {
|
|
|
1378
1386
|
fsExistsUnlessTest,
|
|
1379
1387
|
fsReadFileUnlessTest,
|
|
1380
1388
|
fsWriteFileUnlessTest,
|
|
1381
|
-
|
|
1389
|
+
jsbatonGetInt64,
|
|
1390
|
+
jsbatonGetString,
|
|
1382
1391
|
noop,
|
|
1383
1392
|
objectDeepCopyWithKeysSorted,
|
|
1384
1393
|
sqlmathWebworkerInit,
|