sqlmath 2022.3.5 → 2022.6.30
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/.npmignore +2 -0
- package/CHANGELOG.md +75 -0
- package/LICENSE +2 -2
- package/README.md +25 -3
- package/_binary_sqlmath_napi8_darwin_x64.node +0 -0
- package/_binary_sqlmath_napi8_linux_x64.node +0 -0
- package/_binary_sqlmath_napi8_win32_x64.node +0 -0
- package/_binary_sqlmath_shell_darwin_x64 +0 -0
- package/_binary_sqlmath_shell_linux_x64 +0 -0
- package/_binary_sqlmath_shell_win32_x64.exe +0 -0
- package/jslint.mjs +647 -291
- package/package.json +6 -6
- package/sqlmath.mjs +845 -1761
- package/sqlmath_custom.mjs +4 -0
package/sqlmath.mjs
CHANGED
|
@@ -1,17 +1,112 @@
|
|
|
1
|
+
// MIT License
|
|
2
|
+
//
|
|
3
|
+
// Copyright (c) 2021 Kai Zhu
|
|
4
|
+
//
|
|
5
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
// in the Software without restriction, including without limitation the rights
|
|
8
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
// furnished to do so, subject to the following conditions:
|
|
11
|
+
//
|
|
12
|
+
// The above copyright notice and this permission notice shall be included in
|
|
13
|
+
// all copies or substantial portions of the Software.
|
|
14
|
+
//
|
|
15
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
// SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
1
24
|
/*jslint beta, bitwise, name, node*/
|
|
25
|
+
/*global FinalizationRegistry*/
|
|
2
26
|
"use strict";
|
|
3
|
-
import {createRequire} from "module";
|
|
4
|
-
import jslint from "./jslint.mjs";
|
|
5
27
|
|
|
6
|
-
let
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
let
|
|
28
|
+
let FILENAME_DBTMP = "/tmp/__dbtmp1";
|
|
29
|
+
let IS_BROWSER;
|
|
30
|
+
let JSBATON_ARGC = 16;
|
|
31
|
+
let SQLITE_DATATYPE_BLOB = 0x04;
|
|
32
|
+
// let SQLITE_DATATYPE_BLOB_0 = 0x14;
|
|
33
|
+
let SQLITE_DATATYPE_EXTERNALBUFFER = -0x01;
|
|
34
|
+
let SQLITE_DATATYPE_FLOAT = 0x02;
|
|
35
|
+
// let SQLITE_DATATYPE_FLOAT_0 = 0x12;
|
|
36
|
+
let SQLITE_DATATYPE_INTEGER = 0x01;
|
|
37
|
+
let SQLITE_DATATYPE_INTEGER_0 = 0x11;
|
|
38
|
+
let SQLITE_DATATYPE_INTEGER_1 = 0x21;
|
|
39
|
+
let SQLITE_DATATYPE_NULL = 0x05;
|
|
40
|
+
let SQLITE_DATATYPE_OFFSET = 768;
|
|
41
|
+
let SQLITE_DATATYPE_TEXT = 0x03;
|
|
42
|
+
let SQLITE_DATATYPE_TEXT_0 = 0x13;
|
|
43
|
+
let SQLITE_MAX_LENGTH2 = 1_000_000_000;
|
|
44
|
+
let SQLITE_OPEN_AUTOPROXY = 0x00000020; /* VFS only */
|
|
45
|
+
let SQLITE_OPEN_CREATE = 0x00000004; /* Ok for sqlite3_open_v2() */
|
|
46
|
+
let SQLITE_OPEN_DELETEONCLOSE = 0x00000008; /* VFS only */
|
|
47
|
+
let SQLITE_OPEN_EXCLUSIVE = 0x00000010; /* VFS only */
|
|
48
|
+
let SQLITE_OPEN_FULLMUTEX = 0x00010000; /* Ok for sqlite3_open_v2() */
|
|
49
|
+
let SQLITE_OPEN_MAIN_DB = 0x00000100; /* VFS only */
|
|
50
|
+
let SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; /* VFS only */
|
|
51
|
+
let SQLITE_OPEN_MEMORY = 0x00000080; /* Ok for sqlite3_open_v2() */
|
|
52
|
+
let SQLITE_OPEN_NOFOLLOW = 0x01000000; /* Ok for sqlite3_open_v2() */
|
|
53
|
+
let SQLITE_OPEN_NOMUTEX = 0x00008000; /* Ok for sqlite3_open_v2() */
|
|
54
|
+
let SQLITE_OPEN_PRIVATECACHE = 0x00040000; /* Ok for sqlite3_open_v2() */
|
|
55
|
+
let SQLITE_OPEN_READONLY = 0x00000001; /* Ok for sqlite3_open_v2() */
|
|
56
|
+
let SQLITE_OPEN_READWRITE = 0x00000002; /* Ok for sqlite3_open_v2() */
|
|
57
|
+
let SQLITE_OPEN_SHAREDCACHE = 0x00020000; /* Ok for sqlite3_open_v2() */
|
|
58
|
+
let SQLITE_OPEN_SUBJOURNAL = 0x00002000; /* VFS only */
|
|
59
|
+
let SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; /* VFS only */
|
|
60
|
+
let SQLITE_OPEN_TEMP_DB = 0x00000200; /* VFS only */
|
|
61
|
+
let SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; /* VFS only */
|
|
62
|
+
let SQLITE_OPEN_TRANSIENT_DB = 0x00000400; /* VFS only */
|
|
63
|
+
let SQLITE_OPEN_URI = 0x00000040; /* Ok for sqlite3_open_v2() */
|
|
64
|
+
let SQLITE_OPEN_WAL = 0x00080000; /* VFS only */
|
|
65
|
+
let cModule;
|
|
66
|
+
let consoleError = console.error;
|
|
67
|
+
let dbDict = new WeakMap(); // private-dict of sqlite-database-connections
|
|
68
|
+
let dbFinalizationRegistry;
|
|
69
|
+
// init debugInline
|
|
70
|
+
let debugInline = (function () {
|
|
71
|
+
let __consoleError = function () {
|
|
72
|
+
return;
|
|
73
|
+
};
|
|
74
|
+
function debug(...argv) {
|
|
75
|
+
|
|
76
|
+
// This function will print <argv> to stderr and then return <argv>[0].
|
|
77
|
+
|
|
78
|
+
__consoleError("\n\ndebugInline");
|
|
79
|
+
__consoleError(...argv);
|
|
80
|
+
__consoleError("\n");
|
|
81
|
+
return argv[0];
|
|
82
|
+
}
|
|
83
|
+
debug(); // Coverage-hack.
|
|
84
|
+
__consoleError = console.error;
|
|
85
|
+
return debug;
|
|
86
|
+
}());
|
|
87
|
+
let sqlMessageDict = {}; // dict of web-worker-callbacks
|
|
88
|
+
let sqlMessageId = 0;
|
|
89
|
+
let sqlWorker;
|
|
90
|
+
|
|
91
|
+
function assertJsonEqual(aa, bb, message) {
|
|
92
|
+
|
|
93
|
+
// This function will assert JSON.stringify(<aa>) === JSON.stringify(<bb>).
|
|
94
|
+
|
|
95
|
+
aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa), undefined, 1);
|
|
96
|
+
bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb), undefined, 1);
|
|
97
|
+
if (aa !== bb) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
"\n" + aa + "\n!==\n" + bb
|
|
100
|
+
+ (
|
|
101
|
+
typeof message === "string"
|
|
102
|
+
? " - " + message
|
|
103
|
+
: message
|
|
104
|
+
? " - " + JSON.stringify(message)
|
|
105
|
+
: ""
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
15
110
|
|
|
16
111
|
function assertNumericalEqual(aa, bb, message) {
|
|
17
112
|
|
|
@@ -29,293 +124,324 @@ function assertNumericalEqual(aa, bb, message) {
|
|
|
29
124
|
}
|
|
30
125
|
}
|
|
31
126
|
|
|
127
|
+
function assertOrThrow(condition, message) {
|
|
32
128
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
let SQLITE_OPEN_EXCLUSIVE = 0x00000010; /* VFS only */
|
|
44
|
-
let SQLITE_OPEN_FULLMUTEX = 0x00010000; /* Ok for sqlite3_open_v2() */
|
|
45
|
-
let SQLITE_OPEN_MAIN_DB = 0x00000100; /* VFS only */
|
|
46
|
-
let SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; /* VFS only */
|
|
47
|
-
let SQLITE_OPEN_MEMORY = 0x00000080; /* Ok for sqlite3_open_v2() */
|
|
48
|
-
let SQLITE_OPEN_NOFOLLOW = 0x01000000; /* Ok for sqlite3_open_v2() */
|
|
49
|
-
let SQLITE_OPEN_NOMUTEX = 0x00008000; /* Ok for sqlite3_open_v2() */
|
|
50
|
-
let SQLITE_OPEN_PRIVATECACHE = 0x00040000; /* Ok for sqlite3_open_v2() */
|
|
51
|
-
let SQLITE_OPEN_READONLY = 0x00000001; /* Ok for sqlite3_open_v2() */
|
|
52
|
-
let SQLITE_OPEN_READWRITE = 0x00000002; /* Ok for sqlite3_open_v2() */
|
|
53
|
-
let SQLITE_OPEN_SHAREDCACHE = 0x00020000; /* Ok for sqlite3_open_v2() */
|
|
54
|
-
let SQLITE_OPEN_SUBJOURNAL = 0x00002000; /* VFS only */
|
|
55
|
-
let SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; /* VFS only */
|
|
56
|
-
let SQLITE_OPEN_TEMP_DB = 0x00000200; /* VFS only */
|
|
57
|
-
let SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; /* VFS only */
|
|
58
|
-
let SQLITE_OPEN_TRANSIENT_DB = 0x00000400; /* VFS only */
|
|
59
|
-
let SQLITE_OPEN_URI = 0x00000040; /* Ok for sqlite3_open_v2() */
|
|
60
|
-
let SQLITE_OPEN_WAL = 0x00080000; /* VFS only */
|
|
61
|
-
let addon;
|
|
62
|
-
let consoleError = console.error;
|
|
63
|
-
let dbDict = new WeakMap(); // private map of sqlite-database-connections
|
|
64
|
-
let requireCjs = createRequire(import.meta.url);
|
|
65
|
-
let testList;
|
|
129
|
+
// This function will throw <message> if <condition> is falsy.
|
|
130
|
+
|
|
131
|
+
if (!condition) {
|
|
132
|
+
throw (
|
|
133
|
+
(!message || typeof message === "string")
|
|
134
|
+
? new Error(String(message).slice(0, 2048))
|
|
135
|
+
: message
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
66
139
|
|
|
67
|
-
|
|
140
|
+
async function cCallAsync(baton, cFuncName, ...argList) {
|
|
68
141
|
// this function will serialize <argList> to a c <baton>,
|
|
69
142
|
// suitable for passing into napi
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
err.stack += errStack;
|
|
116
|
-
throw err;
|
|
143
|
+
let argi = 0;
|
|
144
|
+
let errStack;
|
|
145
|
+
assertOrThrow(
|
|
146
|
+
argList.length < 16,
|
|
147
|
+
"cCallAsync - argList.length must be less than than 16"
|
|
148
|
+
);
|
|
149
|
+
baton = baton || jsbatonCreate();
|
|
150
|
+
// pad argList to length JSBATON_ARGC
|
|
151
|
+
while (argList.length < 2 * JSBATON_ARGC) {
|
|
152
|
+
argList.push(0n);
|
|
153
|
+
}
|
|
154
|
+
// serialize js-value to c-value
|
|
155
|
+
argList = argList.map(function (value, ii) {
|
|
156
|
+
argi = ii;
|
|
157
|
+
switch (typeof value) {
|
|
158
|
+
case "bigint":
|
|
159
|
+
case "boolean":
|
|
160
|
+
baton.setBigInt64(8 + argi * 8, BigInt(value), true);
|
|
161
|
+
return value;
|
|
162
|
+
case "number":
|
|
163
|
+
// check for min/max safe-integer
|
|
164
|
+
assertOrThrow(
|
|
165
|
+
(
|
|
166
|
+
-9_007_199_254_740_991 <= value
|
|
167
|
+
&& value <= 9_007_199_254_740_991
|
|
168
|
+
),
|
|
169
|
+
(
|
|
170
|
+
"non-bigint integer must be within inclusive-range"
|
|
171
|
+
+ " -9,007,199,254,740,991 to 9,007,199,254,740,991"
|
|
172
|
+
)
|
|
173
|
+
);
|
|
174
|
+
baton.setBigInt64(8 + argi * 8, BigInt(value), true);
|
|
175
|
+
return value;
|
|
176
|
+
// case "object":
|
|
177
|
+
// break;
|
|
178
|
+
case "string":
|
|
179
|
+
baton = jsbatonValuePush({
|
|
180
|
+
argi,
|
|
181
|
+
baton,
|
|
182
|
+
value: (
|
|
183
|
+
value.endsWith("\u0000")
|
|
184
|
+
? value
|
|
185
|
+
// append null-terminator to string
|
|
186
|
+
: value + "\u0000"
|
|
187
|
+
)
|
|
117
188
|
});
|
|
189
|
+
return;
|
|
118
190
|
}
|
|
119
|
-
|
|
191
|
+
if (ArrayBuffer.isView(value)) {
|
|
192
|
+
return new DataView(
|
|
193
|
+
value.buffer,
|
|
194
|
+
value.byteOffset,
|
|
195
|
+
value.byteLength
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
if (isExternalBuffer(value)) {
|
|
199
|
+
return value;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
// encode cFuncName into baton
|
|
203
|
+
argi += 1;
|
|
204
|
+
baton = jsbatonValuePush({
|
|
205
|
+
argi,
|
|
206
|
+
baton,
|
|
207
|
+
value: cFuncName + "\u0000"
|
|
208
|
+
});
|
|
209
|
+
// prepend baton, cFuncName to argList
|
|
210
|
+
argList = [
|
|
211
|
+
baton, cFuncName, ...argList
|
|
212
|
+
];
|
|
213
|
+
// preserve stack-trace
|
|
214
|
+
errStack = new Error().stack.replace((
|
|
215
|
+
/.*$/m
|
|
216
|
+
), "");
|
|
217
|
+
try {
|
|
218
|
+
return (
|
|
219
|
+
IS_BROWSER
|
|
220
|
+
? await sqlMessagePost(...argList)
|
|
221
|
+
: await cModule[cFuncName](argList)
|
|
222
|
+
);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
err.stack += errStack;
|
|
225
|
+
assertOrThrow(undefined, err);
|
|
120
226
|
}
|
|
227
|
+
}
|
|
121
228
|
|
|
122
|
-
|
|
123
|
-
// this function will call <
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
229
|
+
function dbCallAsync(baton, cFuncName, db, ...argList) {
|
|
230
|
+
// this function will call <cFuncName> using db <argList>[0]
|
|
231
|
+
let __db = dbDeref(db);
|
|
232
|
+
// increment __db.busy
|
|
233
|
+
__db.busy += 1;
|
|
234
|
+
return cCallAsync(
|
|
235
|
+
baton,
|
|
236
|
+
cFuncName,
|
|
237
|
+
__db.ptr,
|
|
238
|
+
...argList
|
|
239
|
+
).finally(function () {
|
|
240
|
+
// decrement __db.busy
|
|
241
|
+
__db.busy -= 1;
|
|
242
|
+
assertOrThrow(__db.busy >= 0, `invalid __db.busy ${__db.busy}`);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
135
245
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
246
|
+
async function dbCloseAsync({
|
|
247
|
+
db
|
|
248
|
+
}) {
|
|
139
249
|
// this function will close sqlite-database-connection <db>
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
250
|
+
let __db = dbDeref(db);
|
|
251
|
+
// prevent segfault - do not close db if actions are pending
|
|
252
|
+
assertOrThrow(
|
|
253
|
+
__db.busy === 0,
|
|
254
|
+
"db cannot close with " + __db.busy + " actions pending"
|
|
255
|
+
);
|
|
256
|
+
// cleanup connPool
|
|
257
|
+
await Promise.all(__db.connPool.map(async function (ptr) {
|
|
258
|
+
let val = ptr[0];
|
|
259
|
+
ptr[0] = 0n;
|
|
260
|
+
await cCallAsync(
|
|
261
|
+
undefined,
|
|
262
|
+
"_dbClose",
|
|
263
|
+
val,
|
|
264
|
+
__db.filename
|
|
145
265
|
);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
ptr[0] = 0n;
|
|
150
|
-
await cCall("__dbCloseAsync", [
|
|
151
|
-
val
|
|
152
|
-
]);
|
|
153
|
-
}));
|
|
154
|
-
dbDict.delete(db);
|
|
155
|
-
}
|
|
266
|
+
}));
|
|
267
|
+
dbDict.delete(db);
|
|
268
|
+
}
|
|
156
269
|
|
|
157
|
-
|
|
270
|
+
function dbDeref(db) {
|
|
158
271
|
// this function will get private-object mapped to <db>
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
272
|
+
let __db = dbDict.get(db);
|
|
273
|
+
assertOrThrow(__db?.connPool[0] > 0, "invalid or closed db");
|
|
274
|
+
assertOrThrow(__db.busy >= 0, "invalid db.busy " + __db.busy);
|
|
275
|
+
__db.ii = (__db.ii + 1) % __db.connPool.length;
|
|
276
|
+
__db.ptr = __db.connPool[__db.ii][0];
|
|
277
|
+
assertOrThrow(__db.ptr > 0n, "invalid or closed db");
|
|
278
|
+
return __db;
|
|
279
|
+
}
|
|
167
280
|
|
|
168
|
-
|
|
169
|
-
|
|
281
|
+
function dbExecAndReturnLastBlobAsync({
|
|
282
|
+
bindList = [],
|
|
283
|
+
db,
|
|
284
|
+
sql
|
|
285
|
+
}) {
|
|
286
|
+
// this function will exec <sql> in <db> and return last value retrieved
|
|
287
|
+
// from execution as raw blob/buffer
|
|
288
|
+
return dbExecAsync({
|
|
289
|
+
bindList,
|
|
170
290
|
db,
|
|
171
|
-
responseType,
|
|
172
|
-
sql
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
291
|
+
responseType: "lastBlob",
|
|
292
|
+
sql
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function dbExecAsync({
|
|
297
|
+
bindList = [],
|
|
298
|
+
db,
|
|
299
|
+
modeRetry,
|
|
300
|
+
responseType,
|
|
301
|
+
sql
|
|
302
|
+
}) {
|
|
179
303
|
// this function will exec <sql> in <db> and return <result>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
await dbTableInsertAsync({
|
|
190
|
-
colList: tmpColList,
|
|
191
|
-
colListPriority: tmpColListPriority,
|
|
192
|
-
csv: tmpCsv,
|
|
304
|
+
let baton;
|
|
305
|
+
let bindByKey;
|
|
306
|
+
let bindListLength;
|
|
307
|
+
let externalbufferList;
|
|
308
|
+
let result;
|
|
309
|
+
while (modeRetry > 0) {
|
|
310
|
+
try {
|
|
311
|
+
return await dbExecAsync({
|
|
312
|
+
bindList,
|
|
193
313
|
db,
|
|
194
|
-
|
|
195
|
-
|
|
314
|
+
responseType,
|
|
315
|
+
sql
|
|
196
316
|
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
bindListLength,
|
|
209
|
-
serialize.bufResult,
|
|
210
|
-
bindByKey,
|
|
211
|
-
(
|
|
212
|
-
responseType === "lastBlob"
|
|
213
|
-
? 1
|
|
214
|
-
: responseType === "lastMatrixDouble"
|
|
215
|
-
? 2
|
|
216
|
-
: 0
|
|
217
|
-
)
|
|
218
|
-
].concat(serialize.bufSharedList));
|
|
219
|
-
result = result[1];
|
|
220
|
-
switch (responseType) {
|
|
221
|
-
case "arraybuffer":
|
|
222
|
-
case "lastBlob":
|
|
223
|
-
return result;
|
|
224
|
-
case "lastMatrixDouble":
|
|
225
|
-
return new Float64Array(result);
|
|
226
|
-
case "list":
|
|
227
|
-
return JSON.parse(new TextDecoder().decode(result));
|
|
228
|
-
default:
|
|
229
|
-
result = JSON.parse(new TextDecoder().decode(result));
|
|
230
|
-
return result.map(function (rowList) {
|
|
231
|
-
let colList = rowList.shift();
|
|
232
|
-
return rowList.map(function (row) {
|
|
233
|
-
let dict = {};
|
|
234
|
-
colList.forEach(function (key, ii) {
|
|
235
|
-
dict[key] = row[ii];
|
|
236
|
-
});
|
|
237
|
-
return dict;
|
|
238
|
-
});
|
|
317
|
+
} catch (err) {
|
|
318
|
+
assertOrThrow(modeRetry > 0, err);
|
|
319
|
+
consoleError(err);
|
|
320
|
+
consoleError(
|
|
321
|
+
"dbExecAsync - retry failed sql-query with "
|
|
322
|
+
+ modeRetry
|
|
323
|
+
+ " remaining retries"
|
|
324
|
+
);
|
|
325
|
+
modeRetry -= 1;
|
|
326
|
+
await new Promise(function (resolve) {
|
|
327
|
+
setTimeout(resolve, 50);
|
|
239
328
|
});
|
|
240
329
|
}
|
|
241
330
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
331
|
+
baton = jsbatonCreate();
|
|
332
|
+
bindByKey = !Array.isArray(bindList);
|
|
333
|
+
bindListLength = (
|
|
334
|
+
Array.isArray(bindList)
|
|
335
|
+
? bindList.length
|
|
336
|
+
: Object.keys(bindList).length
|
|
337
|
+
);
|
|
338
|
+
externalbufferList = [];
|
|
339
|
+
Object.entries(bindList).forEach(function ([
|
|
340
|
+
key, val
|
|
341
|
+
]) {
|
|
342
|
+
if (bindByKey) {
|
|
343
|
+
baton = jsbatonValuePush({
|
|
344
|
+
baton,
|
|
345
|
+
value: ":" + key + "\u0000"
|
|
346
|
+
});
|
|
259
347
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
db,
|
|
265
|
-
sql
|
|
266
|
-
}) {
|
|
267
|
-
// this function will exec <sql> in <db> and return last value retrieved
|
|
268
|
-
// from execution as raw blob/buffer
|
|
269
|
-
return dbExecAsync({
|
|
270
|
-
bindList,
|
|
271
|
-
db,
|
|
272
|
-
responseType: "lastBlob",
|
|
273
|
-
sql
|
|
348
|
+
baton = jsbatonValuePush({
|
|
349
|
+
baton,
|
|
350
|
+
externalbufferList,
|
|
351
|
+
value: val
|
|
274
352
|
});
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
db,
|
|
280
|
-
sql
|
|
281
|
-
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
353
|
+
});
|
|
354
|
+
result = await dbCallAsync(
|
|
355
|
+
baton,
|
|
356
|
+
"_dbExec",
|
|
357
|
+
db, // 0
|
|
358
|
+
String(sql) + "\n;\nPRAGMA noop", // 1
|
|
359
|
+
bindListLength, // 2
|
|
360
|
+
bindByKey, // 3
|
|
361
|
+
( // 4
|
|
362
|
+
responseType === "lastBlob"
|
|
363
|
+
? 1
|
|
364
|
+
: 0
|
|
365
|
+
),
|
|
366
|
+
undefined, // 5
|
|
367
|
+
undefined, // 6
|
|
368
|
+
undefined, // 7 - response
|
|
369
|
+
...externalbufferList // 8
|
|
370
|
+
);
|
|
371
|
+
result = result[2 + 7];
|
|
372
|
+
switch (responseType) {
|
|
373
|
+
case "arraybuffer":
|
|
374
|
+
case "lastBlob":
|
|
375
|
+
return result;
|
|
376
|
+
case "list":
|
|
377
|
+
return JSON.parse(new TextDecoder().decode(result));
|
|
378
|
+
default:
|
|
379
|
+
result = JSON.parse(new TextDecoder().decode(result));
|
|
380
|
+
return result.map(function (rowList) {
|
|
381
|
+
let colList = rowList.shift();
|
|
382
|
+
return rowList.map(function (row) {
|
|
383
|
+
let dict = {};
|
|
384
|
+
colList.forEach(function (key, ii) {
|
|
385
|
+
dict[key] = row[ii];
|
|
386
|
+
});
|
|
387
|
+
return dict;
|
|
388
|
+
});
|
|
289
389
|
});
|
|
290
390
|
}
|
|
391
|
+
}
|
|
291
392
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
393
|
+
async function dbFileExportAsync({
|
|
394
|
+
db,
|
|
395
|
+
dbData,
|
|
396
|
+
filename,
|
|
397
|
+
modeExport = 1
|
|
398
|
+
}) {
|
|
399
|
+
// This function will export <db> to <filename>
|
|
400
|
+
if (IS_BROWSER) {
|
|
401
|
+
filename = FILENAME_DBTMP;
|
|
301
402
|
}
|
|
403
|
+
assertOrThrow(
|
|
404
|
+
typeof filename === "string" && filename,
|
|
405
|
+
`invalid filename ${filename}`
|
|
406
|
+
);
|
|
407
|
+
return await dbCallAsync(
|
|
408
|
+
undefined,
|
|
409
|
+
"_dbFileImportOrExport",
|
|
410
|
+
db, // 0. sqlite3 * pInMemory,
|
|
411
|
+
String(filename), // 1. char *zFilename,
|
|
412
|
+
modeExport, // 2. const int isSave
|
|
413
|
+
undefined, // 3. undefined
|
|
414
|
+
dbData // 4. dbData
|
|
415
|
+
);
|
|
416
|
+
}
|
|
302
417
|
|
|
303
|
-
|
|
418
|
+
async function dbFileImportAsync({
|
|
419
|
+
db,
|
|
420
|
+
dbData,
|
|
421
|
+
filename
|
|
422
|
+
}) {
|
|
423
|
+
// This function will import <filename> to <db>
|
|
424
|
+
await dbFileExportAsync({
|
|
304
425
|
db,
|
|
305
|
-
|
|
306
|
-
}) {
|
|
307
|
-
// This function will save <db> to <filename>
|
|
308
|
-
assertOrThrow(filename, "invalid filename " + filename);
|
|
309
|
-
await dbCallAsync("__dbMemoryLoadOrSave", db, [
|
|
310
|
-
String(filename), 1
|
|
311
|
-
]);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
async function dbOpenAsync({
|
|
426
|
+
dbData,
|
|
315
427
|
filename,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
428
|
+
modeExport: 0
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async function dbNoopAsync(...argList) {
|
|
433
|
+
// this function will do nothing except return argList
|
|
434
|
+
return await cCallAsync(undefined, "_dbNoop", ...argList);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async function dbOpenAsync({
|
|
438
|
+
afterFinalization,
|
|
439
|
+
dbData,
|
|
440
|
+
filename,
|
|
441
|
+
flags,
|
|
442
|
+
rawPtr,
|
|
443
|
+
threadCount = 1
|
|
444
|
+
}) {
|
|
319
445
|
// this function will open and return sqlite-database-connection <db>
|
|
320
446
|
// int sqlite3_open_v2(
|
|
321
447
|
// const char *filename, /* Database filename (UTF-8) */
|
|
@@ -323,1538 +449,496 @@ file sqlmath.js
|
|
|
323
449
|
// int flags, /* Flags */
|
|
324
450
|
// const char *zVfs /* Name of VFS module to use */
|
|
325
451
|
// );
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
]);
|
|
344
|
-
ptr = ptr[0][0];
|
|
345
|
-
finalizer = new BigInt64Array(addon.__dbFinalizerCreate());
|
|
346
|
-
finalizer[0] = BigInt(ptr);
|
|
347
|
-
return finalizer;
|
|
348
|
-
}));
|
|
349
|
-
dbDict.set(db, {
|
|
350
|
-
busy: 0,
|
|
351
|
-
connPool,
|
|
352
|
-
ii: 0,
|
|
353
|
-
ptr: 0n
|
|
354
|
-
});
|
|
355
|
-
return db;
|
|
452
|
+
let connPool;
|
|
453
|
+
let db = {
|
|
454
|
+
filename
|
|
455
|
+
};
|
|
456
|
+
assertOrThrow(
|
|
457
|
+
typeof filename === "string",
|
|
458
|
+
`invalid filename ${filename}`
|
|
459
|
+
);
|
|
460
|
+
assertOrThrow(
|
|
461
|
+
!dbData || isExternalBuffer(dbData),
|
|
462
|
+
"dbData must be ArrayBuffer"
|
|
463
|
+
);
|
|
464
|
+
if (rawPtr) {
|
|
465
|
+
rawPtr = [
|
|
466
|
+
BigInt(rawPtr)
|
|
467
|
+
];
|
|
468
|
+
threadCount = 1;
|
|
356
469
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
assertOrThrow((
|
|
376
|
-
/^temp\."[A-Z_a-z][0-9A-Z_a-z]*?"$/
|
|
377
|
-
).test(tableName), "invalid tableName " + tableName);
|
|
378
|
-
// parse csv
|
|
379
|
-
if (!rowList && csv) {
|
|
380
|
-
rowList = jsonRowListFromCsv({
|
|
381
|
-
csv
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
rowList = jsonRowListNormalize({
|
|
385
|
-
colList,
|
|
386
|
-
colListPriority,
|
|
387
|
-
rowList
|
|
388
|
-
});
|
|
389
|
-
colList = rowList.shift();
|
|
390
|
-
sqlCreateTable = (
|
|
391
|
-
"DROP TABLE IF EXISTS " + tableName + ";"
|
|
392
|
-
+ "CREATE TEMP TABLE " + tableName + "(" + colList.join(",") + ");"
|
|
470
|
+
connPool = await Promise.all(Array.from(new Array(
|
|
471
|
+
threadCount
|
|
472
|
+
), async function () {
|
|
473
|
+
let ptr = rawPtr || await cCallAsync(
|
|
474
|
+
undefined,
|
|
475
|
+
"_dbOpen",
|
|
476
|
+
// 0. const char *filename, Database filename (UTF-8)
|
|
477
|
+
String(filename),
|
|
478
|
+
// 1. sqlite3 **ppDb, OUT: SQLite db handle
|
|
479
|
+
undefined,
|
|
480
|
+
// 2. int flags, Flags
|
|
481
|
+
flags ?? (
|
|
482
|
+
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI
|
|
483
|
+
),
|
|
484
|
+
// 3. const char *zVfs Name of VFS module to use
|
|
485
|
+
undefined,
|
|
486
|
+
// 4. wasm-only - arraybuffer of raw sqlite-database to open in wasm
|
|
487
|
+
dbData
|
|
393
488
|
);
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
489
|
+
ptr = rawPtr || [
|
|
490
|
+
ptr[0].getBigInt64(4 + 4, true)
|
|
491
|
+
];
|
|
492
|
+
dbFinalizationRegistry.register(db, {
|
|
493
|
+
afterFinalization,
|
|
494
|
+
ptr
|
|
495
|
+
});
|
|
496
|
+
return ptr;
|
|
497
|
+
}));
|
|
498
|
+
dbDict.set(db, {
|
|
499
|
+
busy: 0,
|
|
500
|
+
connPool,
|
|
501
|
+
filename,
|
|
502
|
+
ii: 0
|
|
503
|
+
});
|
|
504
|
+
return db;
|
|
505
|
+
}
|
|
409
506
|
|
|
410
|
-
|
|
411
|
-
// this function will
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
Math.min(2 ** Math.ceil(Math.log2(nn)), SQLITE_MAX_LENGTH2)
|
|
442
|
-
));
|
|
443
|
-
// copy tmp to bufResult with offset
|
|
444
|
-
bufferSetBuffer(bufResult, tmp, 0);
|
|
445
|
-
// save bufResult
|
|
446
|
-
serialize.bufResult = bufResult;
|
|
447
|
-
}
|
|
448
|
-
bufResult.setUint8(offset, datatype);
|
|
449
|
-
offset += 1;
|
|
450
|
-
}
|
|
451
|
-
function bufferSetBigint64(offset, val) {
|
|
452
|
-
// this function will set bigint <val> to buffer <bufResult> at <offset>
|
|
453
|
-
assertOrThrow(
|
|
454
|
-
BIGINT64_MIN <= val && val <= BIGINT64_MAX,
|
|
455
|
-
(
|
|
456
|
-
"The value of \"value\" is out of range."
|
|
457
|
-
+ " It must be >= -(2n ** 63n) and < 2n ** 63n."
|
|
458
|
-
)
|
|
459
|
-
);
|
|
460
|
-
bufResult.setBigInt64(offset, val, true);
|
|
461
|
-
}
|
|
462
|
-
function bufferSetBuffer(aa, bb, offset) {
|
|
463
|
-
// this function will set buffer <bb> to buffer <aa> at <offset>
|
|
464
|
-
aa = new Uint8Array(aa.buffer, aa.byteOffset, aa.byteLength);
|
|
465
|
-
bb = new Uint8Array(bb.buffer, bb.byteOffset, bb.byteLength);
|
|
466
|
-
aa.set(bb, offset);
|
|
467
|
-
return bb.byteLength;
|
|
468
|
-
}
|
|
469
|
-
function serialize(val) {
|
|
470
|
-
// this function will write to <bufResult>, <val> at given <offset>
|
|
507
|
+
function isExternalBuffer(buf) {
|
|
508
|
+
// this function will check if <buf> is ArrayBuffer or SharedArrayBuffer
|
|
509
|
+
return buf && (
|
|
510
|
+
buf.constructor === ArrayBuffer
|
|
511
|
+
|| (
|
|
512
|
+
typeof SharedArrayBuffer === "function"
|
|
513
|
+
&& buf.constructor === SharedArrayBuffer
|
|
514
|
+
)
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function jsbatonCreate() {
|
|
519
|
+
// this function will create buffer <baton>
|
|
520
|
+
let baton = new DataView(new ArrayBuffer(1024));
|
|
521
|
+
// offset nalloc, nused
|
|
522
|
+
baton.setInt32(4, SQLITE_DATATYPE_OFFSET, true);
|
|
523
|
+
return baton;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function jsbatonValuePush({
|
|
527
|
+
argi,
|
|
528
|
+
baton,
|
|
529
|
+
externalbufferList,
|
|
530
|
+
value
|
|
531
|
+
}) {
|
|
532
|
+
// this function will push <value> to buffer <baton>
|
|
533
|
+
let nn;
|
|
534
|
+
let nused;
|
|
535
|
+
let tmp;
|
|
536
|
+
let vsize;
|
|
537
|
+
let vtype;
|
|
471
538
|
/*
|
|
472
539
|
#define SQLITE_DATATYPE_BLOB 0x04
|
|
473
|
-
#define SQLITE_DATATYPE_BLOB_0 0x14
|
|
540
|
+
// #define SQLITE_DATATYPE_BLOB_0 0x14
|
|
474
541
|
#define SQLITE_DATATYPE_FLOAT 0x02
|
|
475
|
-
#define SQLITE_DATATYPE_FLOAT_0 0x12
|
|
542
|
+
// #define SQLITE_DATATYPE_FLOAT_0 0x12
|
|
476
543
|
#define SQLITE_DATATYPE_INTEGER 0x01
|
|
477
544
|
#define SQLITE_DATATYPE_INTEGER_0 0x11
|
|
478
545
|
#define SQLITE_DATATYPE_INTEGER_1 0x21
|
|
479
546
|
#define SQLITE_DATATYPE_NULL 0x05
|
|
547
|
+
#define SQLITE_DATATYPE_EXTERNALBUFFER -0x01
|
|
480
548
|
#define SQLITE_DATATYPE_TEXT 0x03
|
|
481
549
|
#define SQLITE_DATATYPE_TEXT_0 0x13
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
550
|
+
// 1. false.bigint
|
|
551
|
+
// 2. false.boolean
|
|
552
|
+
// 3. false.function
|
|
553
|
+
// 4. false.number
|
|
554
|
+
// 5. false.object
|
|
555
|
+
// 6. false.string
|
|
556
|
+
// 7. false.symbol
|
|
557
|
+
// 8. false.undefined
|
|
558
|
+
// 9. true.bigint
|
|
559
|
+
// 10. true.boolean
|
|
560
|
+
// 11. true.function
|
|
561
|
+
// 12. true.number
|
|
562
|
+
// 13. true.object
|
|
563
|
+
// 14. true.string
|
|
564
|
+
// 15. true.symbol
|
|
565
|
+
// 16. true.undefined
|
|
566
|
+
// 17. true.buffer
|
|
567
|
+
// 18. true.externalbuffer
|
|
498
568
|
*/
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
bufSharedList.length <= 0.5 * JSBATON_ARGC,
|
|
503
|
-
(
|
|
504
|
-
"too many SharedArrayBuffer's " + bufSharedList.length
|
|
505
|
-
+ " > " + (0.5 * JSBATON_ARGC)
|
|
506
|
-
)
|
|
507
|
-
);
|
|
508
|
-
bufferAppendDatatype(SQLITE_DATATYPE_SHAREDARRAYBUFFER, 0);
|
|
509
|
-
bufSharedList.push(new DataView(val));
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
// 12. true.boolean
|
|
513
|
-
if (val === 1 || val === 1n || val === true) {
|
|
514
|
-
bufferAppendDatatype(SQLITE_DATATYPE_INTEGER_1, 0);
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
switch (Boolean(val) + "." + typeof(val)) {
|
|
518
|
-
// 1. false.bigint
|
|
519
|
-
case "false.bigint":
|
|
520
|
-
// 2. false.boolean
|
|
521
|
-
case "false.boolean":
|
|
522
|
-
// 4. false.number
|
|
523
|
-
case "false.number":
|
|
524
|
-
bufferAppendDatatype(SQLITE_DATATYPE_INTEGER_0, 0);
|
|
525
|
-
return;
|
|
526
|
-
// 3. false.function
|
|
527
|
-
// case "false.function":
|
|
528
|
-
// 5. false.object
|
|
529
|
-
case "false.object":
|
|
530
|
-
// 7. false.symbol
|
|
531
|
-
// case "false.symbol":
|
|
532
|
-
// 8. false.undefined
|
|
533
|
-
case "false.undefined":
|
|
534
|
-
// 13. true.function
|
|
535
|
-
case "true.function":
|
|
536
|
-
// 17. true.symbol
|
|
537
|
-
case "true.symbol":
|
|
538
|
-
// 18. true.undefined
|
|
539
|
-
// case "true.undefined":
|
|
540
|
-
bufferAppendDatatype(SQLITE_DATATYPE_NULL, 0);
|
|
541
|
-
return;
|
|
542
|
-
// 6. false.string
|
|
543
|
-
case "false.string":
|
|
544
|
-
bufferAppendDatatype(SQLITE_DATATYPE_TEXT_0, 0);
|
|
545
|
-
return;
|
|
546
|
-
// 11. true.bigint
|
|
547
|
-
case "true.bigint":
|
|
548
|
-
bufferAppendDatatype(SQLITE_DATATYPE_INTEGER, 8);
|
|
549
|
-
bufferSetBigint64(offset, val);
|
|
550
|
-
offset += 8;
|
|
551
|
-
return;
|
|
552
|
-
// 14. true.number
|
|
553
|
-
case "true.number":
|
|
554
|
-
bufferAppendDatatype(SQLITE_DATATYPE_FLOAT, 8);
|
|
555
|
-
bufResult.setFloat64(offset, val, true);
|
|
556
|
-
offset += 8;
|
|
557
|
-
return;
|
|
558
|
-
// 16. true.string
|
|
559
|
-
case "true.string":
|
|
560
|
-
val = new TextEncoder().encode(val);
|
|
561
|
-
bufferAppendDatatype(SQLITE_DATATYPE_TEXT, 8 + val.byteLength);
|
|
562
|
-
bufferSetBigint64(offset, BigInt(val.byteLength));
|
|
563
|
-
offset += 8;
|
|
564
|
-
offset += bufferSetBuffer(bufResult, val, offset);
|
|
565
|
-
return;
|
|
566
|
-
// 15. true.object
|
|
567
|
-
default:
|
|
568
|
-
assertOrThrow(
|
|
569
|
-
val && typeof val === "object",
|
|
570
|
-
"invalid data " + (typeof val) + " " + val
|
|
571
|
-
);
|
|
572
|
-
// write buffer
|
|
573
|
-
if (ArrayBuffer.isView(val)) {
|
|
574
|
-
if (val.byteLength === 0) {
|
|
575
|
-
bufferAppendDatatype(SQLITE_DATATYPE_NULL, 0);
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
bufferAppendDatatype(
|
|
579
|
-
SQLITE_DATATYPE_BLOB,
|
|
580
|
-
8 + val.byteLength
|
|
581
|
-
);
|
|
582
|
-
bufferSetBigint64(offset, BigInt(val.byteLength));
|
|
583
|
-
offset += 8;
|
|
584
|
-
// copy val to bufResult with offset
|
|
585
|
-
bufferSetBuffer(bufResult, val, offset);
|
|
586
|
-
offset += val.byteLength;
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
// write JSON.stringify(val)
|
|
590
|
-
val = String(
|
|
591
|
-
typeof val.toJSON === "function"
|
|
592
|
-
? val.toJSON()
|
|
593
|
-
: JSON.stringify(val)
|
|
594
|
-
);
|
|
595
|
-
val = new TextEncoder().encode(val);
|
|
596
|
-
bufferAppendDatatype(SQLITE_DATATYPE_TEXT, 8 + val.byteLength);
|
|
597
|
-
bufferSetBigint64(offset, BigInt(val.byteLength));
|
|
598
|
-
offset += 8;
|
|
599
|
-
offset += bufferSetBuffer(bufResult, val, offset);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
// save bufResult
|
|
603
|
-
serialize.bufResult = bufResult;
|
|
604
|
-
// save bufSharedList
|
|
605
|
-
serialize.bufSharedList = bufSharedList;
|
|
606
|
-
return serialize;
|
|
569
|
+
// 10. true.boolean
|
|
570
|
+
if (value === 1 || value === 1n) {
|
|
571
|
+
value = true;
|
|
607
572
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
), "\n");
|
|
673
|
-
/*
|
|
674
|
-
2. The last record in the file may or may not have an ending line
|
|
675
|
-
break. For example:
|
|
676
|
-
aaa,bbb,ccc CRLF
|
|
677
|
-
zzz,yyy,xxx
|
|
678
|
-
*/
|
|
679
|
-
if (csv[csv.length - 1] !== "\n") {
|
|
680
|
-
csv += "\n";
|
|
573
|
+
switch (Boolean(value) + "." + typeof(value)) {
|
|
574
|
+
// 1. false.bigint
|
|
575
|
+
case "false.bigint":
|
|
576
|
+
// 2. false.boolean
|
|
577
|
+
case "false.boolean":
|
|
578
|
+
// 4. false.number
|
|
579
|
+
case "false.number":
|
|
580
|
+
vtype = SQLITE_DATATYPE_INTEGER_0;
|
|
581
|
+
vsize = 0;
|
|
582
|
+
break;
|
|
583
|
+
// 3. false.function
|
|
584
|
+
// case "false.function":
|
|
585
|
+
// 5. false.object
|
|
586
|
+
case "false.object":
|
|
587
|
+
// 7. false.symbol
|
|
588
|
+
case "false.symbol":
|
|
589
|
+
// 8. false.undefined
|
|
590
|
+
case "false.undefined":
|
|
591
|
+
// 11. true.function
|
|
592
|
+
case "true.function":
|
|
593
|
+
// 15. true.symbol
|
|
594
|
+
case "true.symbol":
|
|
595
|
+
// 16. true.undefined
|
|
596
|
+
// case "true.undefined":
|
|
597
|
+
vtype = SQLITE_DATATYPE_NULL;
|
|
598
|
+
vsize = 0;
|
|
599
|
+
break;
|
|
600
|
+
// 6. false.string
|
|
601
|
+
case "false.string":
|
|
602
|
+
vtype = SQLITE_DATATYPE_TEXT_0;
|
|
603
|
+
vsize = 0;
|
|
604
|
+
break;
|
|
605
|
+
// 9. true.bigint
|
|
606
|
+
case "true.bigint":
|
|
607
|
+
vtype = SQLITE_DATATYPE_INTEGER;
|
|
608
|
+
vsize = 8;
|
|
609
|
+
break;
|
|
610
|
+
// 10. true.boolean
|
|
611
|
+
case "true.boolean":
|
|
612
|
+
vtype = SQLITE_DATATYPE_INTEGER_1;
|
|
613
|
+
vsize = 0;
|
|
614
|
+
break;
|
|
615
|
+
// 12. true.number
|
|
616
|
+
case "true.number":
|
|
617
|
+
vtype = SQLITE_DATATYPE_FLOAT;
|
|
618
|
+
vsize = 8;
|
|
619
|
+
break;
|
|
620
|
+
// 13. true.object
|
|
621
|
+
// 14. true.string
|
|
622
|
+
default:
|
|
623
|
+
// 18. true.externalbuffer
|
|
624
|
+
if (isExternalBuffer(value)) {
|
|
625
|
+
assertOrThrow(
|
|
626
|
+
!IS_BROWSER,
|
|
627
|
+
"external ArrayBuffer cannot be passed directly to wasm"
|
|
628
|
+
);
|
|
629
|
+
assertOrThrow(
|
|
630
|
+
externalbufferList.length <= 8,
|
|
631
|
+
"externalbufferList.length must be less than 8"
|
|
632
|
+
);
|
|
633
|
+
externalbufferList.push(new DataView(value));
|
|
634
|
+
vtype = SQLITE_DATATYPE_EXTERNALBUFFER;
|
|
635
|
+
vsize = 4;
|
|
636
|
+
break;
|
|
681
637
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
// build val
|
|
688
|
-
val += match[1];
|
|
689
|
-
match = match[2];
|
|
690
|
-
switch (quote + "." + match) {
|
|
691
|
-
case "false.,":
|
|
692
|
-
/*
|
|
693
|
-
4. Within the header and each record, there may be one or more
|
|
694
|
-
fields, separated by commas. Each line should contain the same
|
|
695
|
-
number of fields throughout the file. Spaces are considered part
|
|
696
|
-
of a field and should not be ignored. The last field in the
|
|
697
|
-
record must not be followed by a comma. For example:
|
|
698
|
-
aaa,bbb,ccc
|
|
699
|
-
*/
|
|
700
|
-
// delimit val
|
|
701
|
-
row.push(val);
|
|
702
|
-
val = "";
|
|
638
|
+
// 17. true.buffer
|
|
639
|
+
if (ArrayBuffer.isView(value)) {
|
|
640
|
+
if (value.byteLength === 0) {
|
|
641
|
+
vtype = SQLITE_DATATYPE_NULL;
|
|
642
|
+
vsize = 0;
|
|
703
643
|
break;
|
|
704
|
-
case "false.\"":
|
|
705
|
-
case "true.\"":
|
|
706
|
-
/*
|
|
707
|
-
5. Each field may or may not be enclosed in double quotes (however
|
|
708
|
-
some programs, such as Microsoft Excel, do not use double quotes
|
|
709
|
-
at all). If fields are not enclosed with double quotes, then
|
|
710
|
-
double quotes may not appear inside the fields. For example:
|
|
711
|
-
"aaa","bbb","ccc" CRLF
|
|
712
|
-
zzz,yyy,xxx
|
|
713
|
-
*/
|
|
714
|
-
assertOrThrow(quote || val === "", (
|
|
715
|
-
"invalid csv - naked double-quote in unquoted-string "
|
|
716
|
-
+ JSON.stringify(val + "\"")
|
|
717
|
-
));
|
|
718
|
-
quote = !quote;
|
|
719
|
-
break;
|
|
720
|
-
// backtrack for naked-double-double-quote
|
|
721
|
-
case "false.\"\"":
|
|
722
|
-
quote = true;
|
|
723
|
-
rgx.lastIndex -= 1;
|
|
724
|
-
break;
|
|
725
|
-
case "false.\n":
|
|
726
|
-
case "false.\r\n":
|
|
727
|
-
/*
|
|
728
|
-
1. Each record is located on a separate line, delimited by a line
|
|
729
|
-
break (CRLF). For example:
|
|
730
|
-
aaa,bbb,ccc CRLF
|
|
731
|
-
zzz,yyy,xxx CRLF
|
|
732
|
-
*/
|
|
733
|
-
// delimit val
|
|
734
|
-
row.push(val);
|
|
735
|
-
val = "";
|
|
736
|
-
// append row
|
|
737
|
-
rowList.push(row);
|
|
738
|
-
// reset row
|
|
739
|
-
row = [];
|
|
740
|
-
break;
|
|
741
|
-
case "true.\"\"":
|
|
742
|
-
/*
|
|
743
|
-
7. If double-quotes are used to enclose fields, then a double-quote
|
|
744
|
-
appearing inside a field must be escaped by preceding it with
|
|
745
|
-
another double quote. For example:
|
|
746
|
-
"aaa","b""bb","ccc"
|
|
747
|
-
*/
|
|
748
|
-
val += "\"";
|
|
749
|
-
break;
|
|
750
|
-
default:
|
|
751
|
-
/*
|
|
752
|
-
6. Fields containing line breaks (CRLF), double quotes, and commas
|
|
753
|
-
should be enclosed in double-quotes. For example:
|
|
754
|
-
"aaa","b CRLF
|
|
755
|
-
bb","ccc" CRLF
|
|
756
|
-
zzz,yyy,xxx
|
|
757
|
-
*/
|
|
758
|
-
assertOrThrow(quote, (
|
|
759
|
-
"invalid csv - illegal character in unquoted-string "
|
|
760
|
-
+ JSON.stringify(match)
|
|
761
|
-
));
|
|
762
|
-
val += match;
|
|
763
644
|
}
|
|
645
|
+
vtype = SQLITE_DATATYPE_BLOB;
|
|
646
|
+
vsize = 4 + value.byteLength;
|
|
647
|
+
break;
|
|
764
648
|
}
|
|
649
|
+
// 13. true.object
|
|
650
|
+
value = String(
|
|
651
|
+
typeof value === "string"
|
|
652
|
+
? value
|
|
653
|
+
: typeof value.toJSON === "function"
|
|
654
|
+
? value.toJSON()
|
|
655
|
+
: JSON.stringify(value)
|
|
656
|
+
);
|
|
657
|
+
// 14. true.string
|
|
658
|
+
value = new TextEncoder().encode(value);
|
|
659
|
+
vtype = SQLITE_DATATYPE_TEXT;
|
|
660
|
+
vsize = 4 + value.byteLength;
|
|
765
661
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
//
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
if (!colList) {
|
|
799
|
-
colList = rowList[0];
|
|
800
|
-
rowList = rowList.slice(1);
|
|
801
|
-
}
|
|
802
|
-
if (!(colList?.length > 0)) {
|
|
803
|
-
throw new Error("invalid colList " + JSON.stringify(colList));
|
|
804
|
-
}
|
|
805
|
-
colList = colList.map(function (key) {
|
|
806
|
-
// sanitize column-name
|
|
807
|
-
key = String(key).replace((
|
|
808
|
-
/^[^A-Z_a-z]/
|
|
809
|
-
), "c_" + key);
|
|
810
|
-
key = key.replace((
|
|
811
|
-
/[^0-9A-Z_a-z]/g
|
|
812
|
-
), "_");
|
|
813
|
-
// for duplicate column-name, add ordinal _2, _3, _4, ...
|
|
814
|
-
colDict[key] = colDict[key] || 0;
|
|
815
|
-
colDict[key] += 1;
|
|
816
|
-
if (colDict[key] > 1) {
|
|
817
|
-
key += "_" + colDict[key];
|
|
818
|
-
}
|
|
819
|
-
return key;
|
|
820
|
-
});
|
|
821
|
-
// normalize rowList
|
|
822
|
-
rowList = rowList.map(function (row) {
|
|
823
|
-
return (
|
|
824
|
-
row.length === colList.length
|
|
825
|
-
? row
|
|
826
|
-
: colList.map(function (ignore, ii) {
|
|
827
|
-
return row[ii];
|
|
828
|
-
})
|
|
829
|
-
);
|
|
830
|
-
});
|
|
831
|
-
if (!colListPriority) {
|
|
832
|
-
rowList.unshift(colList);
|
|
833
|
-
return rowList;
|
|
662
|
+
nused = baton.getInt32(4, true);
|
|
663
|
+
nn = nused + 1 + vsize;
|
|
664
|
+
assertOrThrow(
|
|
665
|
+
nn <= 0xffff_ffff,
|
|
666
|
+
"jsbaton cannot exceed 0x7fff_ffff / 2,147,483,647 bytes"
|
|
667
|
+
);
|
|
668
|
+
// exponentially grow baton as needed
|
|
669
|
+
if (baton.byteLength < nn) {
|
|
670
|
+
tmp = baton;
|
|
671
|
+
baton = new DataView(new ArrayBuffer(
|
|
672
|
+
Math.min(2 ** Math.ceil(Math.log2(nn)), 0x7fff_ffff)
|
|
673
|
+
));
|
|
674
|
+
// update nalloc
|
|
675
|
+
baton.setInt32(0, baton.byteLength, true);
|
|
676
|
+
// copy tmp to baton
|
|
677
|
+
new Uint8Array(
|
|
678
|
+
baton.buffer,
|
|
679
|
+
baton.byteOffset,
|
|
680
|
+
nused
|
|
681
|
+
).set(new Uint8Array(tmp.buffer, tmp.byteOffset, nused), 0);
|
|
682
|
+
}
|
|
683
|
+
// push vtype
|
|
684
|
+
baton.setUint8(nused, vtype);
|
|
685
|
+
// update nused
|
|
686
|
+
baton.setInt32(4, nused + 1 + vsize, true);
|
|
687
|
+
// handle blob-value
|
|
688
|
+
switch (vtype) {
|
|
689
|
+
case SQLITE_DATATYPE_BLOB:
|
|
690
|
+
case SQLITE_DATATYPE_TEXT:
|
|
691
|
+
// set argv[ii] to blob/text location
|
|
692
|
+
if (argi !== undefined) {
|
|
693
|
+
baton.setInt32(8 + argi * 8, nused, true);
|
|
834
694
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
695
|
+
vsize -= 4;
|
|
696
|
+
// push vsize
|
|
697
|
+
assertOrThrow(
|
|
698
|
+
0 <= vsize && vsize <= 1_000_000_000,
|
|
699
|
+
(
|
|
700
|
+
"sqlite-blob byte-length must be within inclusive-range"
|
|
701
|
+
+ " 0 to 1,000,000,000"
|
|
702
|
+
)
|
|
703
|
+
);
|
|
704
|
+
baton.setInt32(nused + 1, vsize, true);
|
|
705
|
+
new Uint8Array(
|
|
706
|
+
baton.buffer,
|
|
707
|
+
nused + 1 + 4,
|
|
708
|
+
vsize
|
|
709
|
+
).set(new Uint8Array(value.buffer, value.byteOffset, vsize), 0);
|
|
710
|
+
break;
|
|
711
|
+
case SQLITE_DATATYPE_EXTERNALBUFFER:
|
|
712
|
+
vsize = value.byteLength;
|
|
713
|
+
// push vsize
|
|
714
|
+
assertOrThrow(
|
|
715
|
+
0 <= vsize && vsize <= 1_000_000_000,
|
|
716
|
+
(
|
|
717
|
+
"sqlite-blob byte-length must be within inclusive-range"
|
|
718
|
+
+ " 0 to 1,000,000,000"
|
|
719
|
+
)
|
|
720
|
+
);
|
|
721
|
+
baton.setInt32(nused + 1, vsize, true);
|
|
722
|
+
break;
|
|
723
|
+
case SQLITE_DATATYPE_FLOAT:
|
|
724
|
+
baton.setFloat64(nused + 1, value, true);
|
|
725
|
+
break;
|
|
726
|
+
case SQLITE_DATATYPE_INTEGER:
|
|
727
|
+
assertOrThrow(
|
|
728
|
+
(
|
|
729
|
+
-9_223_372_036_854_775_808n <= value
|
|
730
|
+
&& value <= 9_223_372_036_854_775_807n
|
|
731
|
+
),
|
|
732
|
+
(
|
|
733
|
+
"sqlite-integer must be within inclusive-range "
|
|
734
|
+
+ "-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807"
|
|
735
|
+
)
|
|
736
|
+
);
|
|
737
|
+
baton.setBigInt64(nused + 1, value, true);
|
|
738
|
+
break;
|
|
857
739
|
}
|
|
740
|
+
return baton;
|
|
741
|
+
}
|
|
858
742
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
743
|
+
function jsbatonValueString({
|
|
744
|
+
argi,
|
|
745
|
+
baton
|
|
746
|
+
}) {
|
|
747
|
+
// this function will return string-value from <baton> at given <offset>
|
|
748
|
+
let offset = baton.getInt32(4 + 4 + argi * 8, true);
|
|
749
|
+
return new TextDecoder().decode(new Uint8Array(
|
|
750
|
+
baton.buffer,
|
|
751
|
+
offset + 1 + 4,
|
|
752
|
+
// remove null-terminator from string
|
|
753
|
+
baton.getInt32(offset + 1, true) - 1
|
|
754
|
+
));
|
|
755
|
+
}
|
|
865
756
|
|
|
866
|
-
|
|
867
|
-
// this function will test assertXxx's handling-behavior
|
|
868
|
-
// test assertNumericalEqual's handling-behavior
|
|
869
|
-
assertNumericalEqual(1, 1);
|
|
870
|
-
assertErrorThrownAsync(function () {
|
|
871
|
-
assertNumericalEqual(0, 0);
|
|
872
|
-
}, "value cannot be 0 or falsy");
|
|
873
|
-
assertErrorThrownAsync(function () {
|
|
874
|
-
assertNumericalEqual(1, 2);
|
|
875
|
-
}, "1 != 2");
|
|
876
|
-
assertErrorThrownAsync(function () {
|
|
877
|
-
assertNumericalEqual(1, 2, "aa");
|
|
878
|
-
}, "aa");
|
|
879
|
-
}
|
|
757
|
+
function noop(val) {
|
|
880
758
|
|
|
881
|
-
|
|
882
|
-
// this function will test cCall's handling-behavior
|
|
883
|
-
[
|
|
884
|
-
[-0, "0"],
|
|
885
|
-
[-Infinity, "0"],
|
|
886
|
-
[0, "0"],
|
|
887
|
-
[1 / 0, "0"],
|
|
888
|
-
[Infinity, "0"],
|
|
889
|
-
[false, "0"],
|
|
890
|
-
[null, "0"],
|
|
891
|
-
[true, "1"],
|
|
892
|
-
[undefined, "0"],
|
|
893
|
-
[{}, "0"]
|
|
894
|
-
].forEach(async function ([
|
|
895
|
-
aa, bb
|
|
896
|
-
]) {
|
|
897
|
-
let cc;
|
|
898
|
-
cc = String(
|
|
899
|
-
await cCall("noopAsync", [
|
|
900
|
-
aa
|
|
901
|
-
])
|
|
902
|
-
)[0][0];
|
|
903
|
-
assertOrThrow(bb === cc, [aa, bb, cc]);
|
|
904
|
-
cc = String(cCall("noopSync", [
|
|
905
|
-
aa
|
|
906
|
-
]))[0][0];
|
|
907
|
-
assertOrThrow(bb === cc, [aa, bb, cc]);
|
|
908
|
-
});
|
|
909
|
-
}
|
|
759
|
+
// This function will do nothing except return <val>.
|
|
910
760
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
let db = await dbOpenAsync({
|
|
914
|
-
filename: ":memory:"
|
|
915
|
-
});
|
|
916
|
-
async function testDbGetLastBlobAsync(val) {
|
|
917
|
-
return await dbGetLastBlobAsync({
|
|
918
|
-
bindList: [
|
|
919
|
-
val
|
|
920
|
-
],
|
|
921
|
-
db,
|
|
922
|
-
sql: "SELECT 1, 2, 3; SELECT 1, 2, ?"
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
// test bigint-error handling-behavior
|
|
926
|
-
noop([
|
|
927
|
-
-(2n ** 63n),
|
|
928
|
-
2n ** 63n
|
|
929
|
-
]).forEach(function (val) {
|
|
930
|
-
assertErrorThrownAsync(testDbGetLastBlobAsync.bind(undefined, val));
|
|
931
|
-
});
|
|
932
|
-
// test datatype handling-behavior
|
|
933
|
-
[
|
|
934
|
-
// -1. SharedArrayBuffer
|
|
935
|
-
// new SharedArrayBuffer(0), null,
|
|
936
|
-
// 1. bigint
|
|
937
|
-
-0n, -0,
|
|
938
|
-
-0x7fffffffffffffffn, "-9223372036854775807",
|
|
939
|
-
-1n, -1,
|
|
940
|
-
-2n, -2,
|
|
941
|
-
0n, 0,
|
|
942
|
-
0x7fffffffffffffffn, "9223372036854775807",
|
|
943
|
-
1n, 1,
|
|
944
|
-
2n, 2,
|
|
945
|
-
// 2. boolean
|
|
946
|
-
false, 0,
|
|
947
|
-
true, 1,
|
|
948
|
-
// 3. function
|
|
949
|
-
noop, null,
|
|
950
|
-
// 4. number
|
|
951
|
-
-0, 0,
|
|
952
|
-
-1 / 0, null,
|
|
953
|
-
-1e-999, 0,
|
|
954
|
-
-1e999, null,
|
|
955
|
-
-2, -2,
|
|
956
|
-
-Infinity, null,
|
|
957
|
-
-NaN, 0,
|
|
958
|
-
0, 0,
|
|
959
|
-
1 / 0, null,
|
|
960
|
-
1e-999, 0,
|
|
961
|
-
1e999, null,
|
|
962
|
-
2, 2,
|
|
963
|
-
Infinity, null,
|
|
964
|
-
NaN, 0,
|
|
965
|
-
// 5. object
|
|
966
|
-
new Uint8Array(0), null,
|
|
967
|
-
new TextEncoder().encode(""), null,
|
|
968
|
-
new TextEncoder().encode("\u0000"), null,
|
|
969
|
-
new TextEncoder().encode("\u0000\u{1f600}\u0000"), null,
|
|
970
|
-
[], "[]",
|
|
971
|
-
new Date(0), "1970-01-01T00:00:00.000Z",
|
|
972
|
-
new RegExp(), "{}",
|
|
973
|
-
null, null,
|
|
974
|
-
{}, "{}",
|
|
975
|
-
// 6. string
|
|
976
|
-
"", "",
|
|
977
|
-
"0", "0",
|
|
978
|
-
"1", "1",
|
|
979
|
-
"2", "2",
|
|
980
|
-
"\u0000", "\u0000",
|
|
981
|
-
"\u0000\u{1f600}\u0000", "\u0000\u{1f600}\u0000",
|
|
982
|
-
"a".repeat(9999), "a".repeat(9999),
|
|
983
|
-
// 7. symbol
|
|
984
|
-
Symbol(), null,
|
|
985
|
-
// 8. undefined
|
|
986
|
-
undefined, null
|
|
987
|
-
].forEach(function (aa, ii, list) {
|
|
988
|
-
let bb = list[ii + 1];
|
|
989
|
-
if (ii % 2 === 1) {
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
ii *= 0.5;
|
|
993
|
-
// test dbGetLastBlobAsync's bind handling-behavior
|
|
994
|
-
[
|
|
995
|
-
aa
|
|
996
|
-
].forEach(async function (aa) {
|
|
997
|
-
let cc = String(bb);
|
|
998
|
-
let dd = new TextDecoder().decode(
|
|
999
|
-
await testDbGetLastBlobAsync(aa)
|
|
1000
|
-
);
|
|
1001
|
-
switch (typeof(aa)) {
|
|
1002
|
-
case "bigint":
|
|
1003
|
-
aa = Number(aa);
|
|
1004
|
-
break;
|
|
1005
|
-
case "function":
|
|
1006
|
-
case "symbol":
|
|
1007
|
-
case "undefined":
|
|
1008
|
-
cc = "";
|
|
1009
|
-
break;
|
|
1010
|
-
case "number":
|
|
1011
|
-
switch (aa) {
|
|
1012
|
-
case -2:
|
|
1013
|
-
cc = "-2.0";
|
|
1014
|
-
break;
|
|
1015
|
-
case -Infinity:
|
|
1016
|
-
cc = "-Inf";
|
|
1017
|
-
break;
|
|
1018
|
-
case 2:
|
|
1019
|
-
cc = "2.0";
|
|
1020
|
-
break;
|
|
1021
|
-
case Infinity:
|
|
1022
|
-
cc = "Inf";
|
|
1023
|
-
break;
|
|
1024
|
-
}
|
|
1025
|
-
break;
|
|
1026
|
-
case "object":
|
|
1027
|
-
if (ArrayBuffer.isView(aa)) {
|
|
1028
|
-
cc = new TextDecoder().decode(aa);
|
|
1029
|
-
break;
|
|
1030
|
-
}
|
|
1031
|
-
if (aa === null) {
|
|
1032
|
-
cc = "";
|
|
1033
|
-
}
|
|
1034
|
-
break;
|
|
1035
|
-
}
|
|
1036
|
-
// debugInline(ii, aa, bb, cc, dd);
|
|
1037
|
-
assertJsonEqual(cc, dd, {
|
|
1038
|
-
ii,
|
|
1039
|
-
aa, //jslint-quiet
|
|
1040
|
-
bb,
|
|
1041
|
-
cc,
|
|
1042
|
-
dd
|
|
1043
|
-
});
|
|
1044
|
-
});
|
|
1045
|
-
// test dbGetLastMatrixDouble's bind handling-behavior
|
|
1046
|
-
[
|
|
1047
|
-
aa
|
|
1048
|
-
].forEach(async function (aa) {
|
|
1049
|
-
let cc = Number(
|
|
1050
|
-
typeof aa === "symbol"
|
|
1051
|
-
? 0
|
|
1052
|
-
: aa
|
|
1053
|
-
) || 0;
|
|
1054
|
-
let dd = await dbGetLastMatrixDouble({
|
|
1055
|
-
bindList: [
|
|
1056
|
-
aa
|
|
1057
|
-
],
|
|
1058
|
-
db,
|
|
1059
|
-
sql: "SELECT 1, 2, 3; SELECT 1, 2, ?"
|
|
1060
|
-
});
|
|
1061
|
-
switch (typeof(aa)) {
|
|
1062
|
-
case "bigint":
|
|
1063
|
-
aa = String(aa);
|
|
1064
|
-
break;
|
|
1065
|
-
case "object":
|
|
1066
|
-
if (typeof aa?.getUTCFullYear === "function") {
|
|
1067
|
-
cc = aa.getUTCFullYear();
|
|
1068
|
-
}
|
|
1069
|
-
break;
|
|
1070
|
-
}
|
|
1071
|
-
cc = new Float64Array([
|
|
1072
|
-
1, 3, 1, 2, cc
|
|
1073
|
-
]);
|
|
1074
|
-
// debugInline(ii, aa, bb, cc, dd);
|
|
1075
|
-
cc.forEach(function (val, jj) {
|
|
1076
|
-
assertJsonEqual(
|
|
1077
|
-
val,
|
|
1078
|
-
dd[jj],
|
|
1079
|
-
{
|
|
1080
|
-
ii,
|
|
1081
|
-
aa, //jslint-quiet
|
|
1082
|
-
bb,
|
|
1083
|
-
cc,
|
|
1084
|
-
dd
|
|
1085
|
-
}
|
|
1086
|
-
);
|
|
1087
|
-
});
|
|
1088
|
-
});
|
|
1089
|
-
// test dbExecAsync's responseType handling-behavior
|
|
1090
|
-
[
|
|
1091
|
-
"arraybuffer",
|
|
1092
|
-
"list",
|
|
1093
|
-
undefined
|
|
1094
|
-
].forEach(async function (responseType) {
|
|
1095
|
-
let cc = noop(
|
|
1096
|
-
await dbExecAsync({
|
|
1097
|
-
bindList: [
|
|
1098
|
-
aa
|
|
1099
|
-
],
|
|
1100
|
-
db,
|
|
1101
|
-
responseType,
|
|
1102
|
-
sql: "SELECT ? AS val"
|
|
1103
|
-
})
|
|
1104
|
-
);
|
|
1105
|
-
// debugInline(ii, responseType, aa, bb, cc);
|
|
1106
|
-
switch (responseType) {
|
|
1107
|
-
case "arraybuffer":
|
|
1108
|
-
cc = JSON.parse(new TextDecoder().decode(cc))[0][1][0];
|
|
1109
|
-
break;
|
|
1110
|
-
case "list":
|
|
1111
|
-
cc = cc[0][1][0];
|
|
1112
|
-
break;
|
|
1113
|
-
default:
|
|
1114
|
-
cc = cc[0][0].val;
|
|
1115
|
-
}
|
|
1116
|
-
assertJsonEqual(bb, cc, {
|
|
1117
|
-
aa,
|
|
1118
|
-
bb,
|
|
1119
|
-
cc
|
|
1120
|
-
});
|
|
1121
|
-
});
|
|
1122
|
-
// test dbExecAsync's bind handling-behavior
|
|
1123
|
-
[
|
|
1124
|
-
[
|
|
1125
|
-
[
|
|
1126
|
-
bb, bb, 0
|
|
1127
|
-
],
|
|
1128
|
-
(
|
|
1129
|
-
"SELECT 0;"
|
|
1130
|
-
+ " SELECT ? AS c1, ? AS c2, ? AS c3, ? AS c4"
|
|
1131
|
-
+ " UNION ALL SELECT ?1, ?2, ?3, ?4"
|
|
1132
|
-
+ " UNION ALL SELECT ?1, ?2, ?3, ?4"
|
|
1133
|
-
)
|
|
1134
|
-
], [
|
|
1135
|
-
{
|
|
1136
|
-
k1: bb,
|
|
1137
|
-
k2: bb,
|
|
1138
|
-
k3: 0
|
|
1139
|
-
},
|
|
1140
|
-
(
|
|
1141
|
-
"SELECT 0;"
|
|
1142
|
-
+ " SELECT $k1 AS c1, $k2 AS c2, $k3 AS c3, $k4 AS c4"
|
|
1143
|
-
+ " UNION ALL SELECT :k1, :k2, :k3, :k4"
|
|
1144
|
-
+ " UNION ALL SELECT @k1, @k2, @k3, @k4"
|
|
1145
|
-
)
|
|
1146
|
-
]
|
|
1147
|
-
].forEach(async function ([
|
|
1148
|
-
bindList, sql
|
|
1149
|
-
]) {
|
|
1150
|
-
let cc = noop(
|
|
1151
|
-
await dbExecAsync({
|
|
1152
|
-
bindList,
|
|
1153
|
-
db,
|
|
1154
|
-
responseType: "list",
|
|
1155
|
-
sql
|
|
1156
|
-
})
|
|
1157
|
-
);
|
|
1158
|
-
// debugInline(ii, aa, bb, cc);
|
|
1159
|
-
assertJsonEqual(
|
|
1160
|
-
[
|
|
1161
|
-
[
|
|
1162
|
-
[
|
|
1163
|
-
"0"
|
|
1164
|
-
], [
|
|
1165
|
-
0
|
|
1166
|
-
]
|
|
1167
|
-
], [
|
|
1168
|
-
[
|
|
1169
|
-
"c1", "c2", "c3", "c4"
|
|
1170
|
-
], [
|
|
1171
|
-
bb, bb, 0, undefined
|
|
1172
|
-
], [
|
|
1173
|
-
bb, bb, 0, undefined
|
|
1174
|
-
], [
|
|
1175
|
-
bb, bb, 0, undefined
|
|
1176
|
-
]
|
|
1177
|
-
]
|
|
1178
|
-
],
|
|
1179
|
-
cc
|
|
1180
|
-
);
|
|
1181
|
-
});
|
|
1182
|
-
// test dbTableInsertAsync's bind handling-behavior
|
|
1183
|
-
[
|
|
1184
|
-
{
|
|
1185
|
-
// test list-of-list handling-behavior
|
|
1186
|
-
rowList: [
|
|
1187
|
-
[
|
|
1188
|
-
"c1", "c2", "c3"
|
|
1189
|
-
],
|
|
1190
|
-
[
|
|
1191
|
-
aa, aa
|
|
1192
|
-
]
|
|
1193
|
-
]
|
|
1194
|
-
}, {
|
|
1195
|
-
// test list-of-dict handling-behavior
|
|
1196
|
-
rowList: [
|
|
1197
|
-
{
|
|
1198
|
-
"c1": aa,
|
|
1199
|
-
"c2": aa,
|
|
1200
|
-
"c3": undefined
|
|
1201
|
-
}
|
|
1202
|
-
]
|
|
1203
|
-
}, {
|
|
1204
|
-
// test colList and list-of-list handling-behavior
|
|
1205
|
-
colList: [
|
|
1206
|
-
"c1", "c2", "c3"
|
|
1207
|
-
],
|
|
1208
|
-
rowList: [
|
|
1209
|
-
[
|
|
1210
|
-
aa, aa
|
|
1211
|
-
]
|
|
1212
|
-
]
|
|
1213
|
-
}, {
|
|
1214
|
-
// test colList and list-of-dict handling-behavior
|
|
1215
|
-
colList: [
|
|
1216
|
-
"c1", "c2", "c3"
|
|
1217
|
-
],
|
|
1218
|
-
rowList: [
|
|
1219
|
-
{
|
|
1220
|
-
"c1": aa,
|
|
1221
|
-
"c2": aa,
|
|
1222
|
-
"c3": undefined
|
|
1223
|
-
}
|
|
1224
|
-
]
|
|
1225
|
-
}, {
|
|
1226
|
-
// test colList and list-of-list handling-behavior
|
|
1227
|
-
colList: [
|
|
1228
|
-
"c1", "c3", "c2"
|
|
1229
|
-
],
|
|
1230
|
-
colListPriority: [
|
|
1231
|
-
"c1", "c2"
|
|
1232
|
-
],
|
|
1233
|
-
rowList: [
|
|
1234
|
-
[
|
|
1235
|
-
aa, undefined, aa
|
|
1236
|
-
]
|
|
1237
|
-
]
|
|
1238
|
-
}
|
|
1239
|
-
].forEach(async function ({
|
|
1240
|
-
colList,
|
|
1241
|
-
colListPriority,
|
|
1242
|
-
rowList
|
|
1243
|
-
}, jj) {
|
|
1244
|
-
let cc = noop(
|
|
1245
|
-
await dbExecAsync({
|
|
1246
|
-
db,
|
|
1247
|
-
responseType: "list",
|
|
1248
|
-
sql: `SELECT * FROM datatype_${ii}_${jj}`,
|
|
1249
|
-
tmpColList: colList,
|
|
1250
|
-
tmpColListPriority: colListPriority,
|
|
1251
|
-
tmpRowList: rowList,
|
|
1252
|
-
tmpTableName: "datatype_" + ii + "_" + jj
|
|
1253
|
-
})
|
|
1254
|
-
)[0];
|
|
1255
|
-
// debugInline(ii, jj, aa, bb, cc);
|
|
1256
|
-
assertJsonEqual([
|
|
1257
|
-
[
|
|
1258
|
-
"c1", "c2", "c3"
|
|
1259
|
-
], [
|
|
1260
|
-
bb, bb, undefined
|
|
1261
|
-
]
|
|
1262
|
-
], cc);
|
|
1263
|
-
});
|
|
1264
|
-
});
|
|
1265
|
-
}
|
|
761
|
+
return val;
|
|
762
|
+
}
|
|
1266
763
|
|
|
1267
|
-
|
|
1268
|
-
// this function will test dbCloseAsync's handling-behavior
|
|
1269
|
-
let db = await dbOpenAsync({
|
|
1270
|
-
filename: ":memory:"
|
|
1271
|
-
});
|
|
1272
|
-
// test null-case handling-behavior
|
|
1273
|
-
assertErrorThrownAsync(function () {
|
|
1274
|
-
return dbCloseAsync({});
|
|
1275
|
-
}, "invalid or closed db");
|
|
1276
|
-
// test close handling-behavior
|
|
1277
|
-
await dbCloseAsync({
|
|
1278
|
-
db
|
|
1279
|
-
});
|
|
1280
|
-
}
|
|
764
|
+
function objectDeepCopyWithKeysSorted(obj) {
|
|
1281
765
|
|
|
1282
|
-
|
|
1283
|
-
// this function will test dbExecAsync's handling-behavior
|
|
1284
|
-
let db = await dbOpenAsync({
|
|
1285
|
-
filename: ":memory:"
|
|
1286
|
-
});
|
|
1287
|
-
// test null-case handling-behavior
|
|
1288
|
-
assertErrorThrownAsync(function () {
|
|
1289
|
-
return dbExecAsync({
|
|
1290
|
-
db,
|
|
1291
|
-
sql: undefined
|
|
1292
|
-
});
|
|
1293
|
-
}, "near \"undefined\": syntax error");
|
|
1294
|
-
// test race-condition handling-behavior
|
|
1295
|
-
Array.from(new Array(4)).forEach(async function () {
|
|
1296
|
-
let result;
|
|
1297
|
-
try {
|
|
1298
|
-
result = JSON.stringify(
|
|
1299
|
-
await dbExecAsync({
|
|
1300
|
-
bindList: [
|
|
1301
|
-
new TextEncoder().encode("foob"),
|
|
1302
|
-
new TextEncoder().encode("fooba"),
|
|
1303
|
-
new TextEncoder().encode("foobar")
|
|
1304
|
-
],
|
|
1305
|
-
db,
|
|
1306
|
-
responseType: "list",
|
|
1307
|
-
sql: (`
|
|
1308
|
-
CREATE TABLE testDbExecAsync1 AS
|
|
1309
|
-
SELECT 101 AS c101, 102 AS c102
|
|
1310
|
-
--
|
|
1311
|
-
UNION ALL
|
|
1312
|
-
VALUES
|
|
1313
|
-
(201, 202),
|
|
1314
|
-
(301, NULL);
|
|
1315
|
-
CREATE TABLE testDbExecAsync2 AS
|
|
1316
|
-
SELECT 401 AS c401, 402 AS c402, 403 AS c403
|
|
1317
|
-
--
|
|
1318
|
-
UNION ALL
|
|
1319
|
-
VALUES
|
|
1320
|
-
(501, 502.0123, 5030123456789),
|
|
1321
|
-
(601, '602', '603_\"\x01\x08\x09\x0a\x0b\x0c\x0d\x0e'),
|
|
1322
|
-
(?1, ?2, ?3),
|
|
1323
|
-
(tostring(?1), tostring(?2), tostring(?3)),
|
|
1324
|
-
(tobase64(?1), tobase64(?2), tobase64(?3)),
|
|
1325
|
-
(
|
|
1326
|
-
tobase64(uncompress(compress(?1))),
|
|
1327
|
-
tobase64(uncompress(compress(?2))),
|
|
1328
|
-
tobase64(uncompress(compress(?3)))
|
|
1329
|
-
);
|
|
1330
|
-
SELECT * FROM testDbExecAsync1;
|
|
1331
|
-
SELECT * FROM testDbExecAsync2;
|
|
1332
|
-
`)
|
|
1333
|
-
})
|
|
1334
|
-
);
|
|
1335
|
-
assertJsonEqual(result, JSON.stringify([
|
|
1336
|
-
[
|
|
1337
|
-
["c101", "c102"],
|
|
1338
|
-
[101, 102],
|
|
1339
|
-
[201, 202],
|
|
1340
|
-
[301, null]
|
|
1341
|
-
],
|
|
1342
|
-
[
|
|
1343
|
-
["c401", "c402", "c403"],
|
|
1344
|
-
[401, 402, 403],
|
|
1345
|
-
[501, 502.0123, 5030123456789],
|
|
1346
|
-
[601, "602", "603_\"\u0001\b\t\n\u000b\f\r\u000e"],
|
|
1347
|
-
[
|
|
1348
|
-
null, null, null
|
|
1349
|
-
],
|
|
1350
|
-
[
|
|
1351
|
-
"foob", "fooba", "foobar"
|
|
1352
|
-
],
|
|
1353
|
-
[
|
|
1354
|
-
"Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"
|
|
1355
|
-
],
|
|
1356
|
-
[
|
|
1357
|
-
"Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"
|
|
1358
|
-
]
|
|
1359
|
-
]
|
|
1360
|
-
]));
|
|
1361
|
-
} catch (err) {
|
|
1362
|
-
assertOrThrow(
|
|
1363
|
-
err.message.indexOf(
|
|
1364
|
-
"table testDbExecAsync1 already exists"
|
|
1365
|
-
) >= 0,
|
|
1366
|
-
err
|
|
1367
|
-
);
|
|
1368
|
-
}
|
|
1369
|
-
});
|
|
1370
|
-
// test close-while-busy handling-behavior
|
|
1371
|
-
assertErrorThrownAsync(function () {
|
|
1372
|
-
return dbCloseAsync({
|
|
1373
|
-
db
|
|
1374
|
-
});
|
|
1375
|
-
}, (
|
|
1376
|
-
/db cannot close with \d+? actions pending/
|
|
1377
|
-
));
|
|
1378
|
-
// test sqlmath-defined-func handling-behavior
|
|
1379
|
-
[
|
|
1380
|
-
"COT(NULL)", null,
|
|
1381
|
-
"COT('-1')", -0.642092615934331,
|
|
1382
|
-
"COT('0')", null,
|
|
1383
|
-
"COT('1')", 0.642092615934331,
|
|
1384
|
-
"COT(-1)", -0.642092615934331,
|
|
1385
|
-
"COT(0)", null,
|
|
1386
|
-
"COT(1)", 0.642092615934331,
|
|
1387
|
-
"COTH(NULL)", null,
|
|
1388
|
-
"COTH('-1')", -1.31303528549933,
|
|
1389
|
-
"COTH('0')", null,
|
|
1390
|
-
"COTH('1')", 1.31303528549933,
|
|
1391
|
-
"COTH(-1)", -1.31303528549933,
|
|
1392
|
-
"COTH(0)", null,
|
|
1393
|
-
"COTH(1)", 1.31303528549933,
|
|
1394
|
-
"ROUNDORZERO(NULL)", 0,
|
|
1395
|
-
"ROUNDORZERO(NULL, NULL)", 0,
|
|
1396
|
-
"ROUNDORZERO(NULL, 0.5)", 0,
|
|
1397
|
-
"ROUNDORZERO(0.5, NULL)", 1,
|
|
1398
|
-
"ROUNDORZERO(0.5, 0.5)", 1,
|
|
1399
|
-
"ROUNDORZERO(0.5, 1)", 0.5,
|
|
1400
|
-
"SIGN(NULL)", null,
|
|
1401
|
-
"SIGN('-1')", -1,
|
|
1402
|
-
"SIGN('0')", 0,
|
|
1403
|
-
"SIGN('1')", 1,
|
|
1404
|
-
"SIGN(-0x7fffffffffffffff)", -1,
|
|
1405
|
-
"SIGN(-1)", -1,
|
|
1406
|
-
"SIGN(-1e999)", -1,
|
|
1407
|
-
"SIGN(0)", 0,
|
|
1408
|
-
"SIGN(0x7fffffffffffffff)", 1,
|
|
1409
|
-
"SIGN(0x8000000000000000)", -1,
|
|
1410
|
-
"SIGN(0xffffffffffffffff)", -1,
|
|
1411
|
-
"SIGN(1)", 1,
|
|
1412
|
-
"SIGN(1e999)", 1,
|
|
1413
|
-
// sentinel
|
|
1414
|
-
"NULL", null
|
|
1415
|
-
].forEach(async function (sql, ii, list) {
|
|
1416
|
-
let bb = list[ii + 1];
|
|
1417
|
-
let cc;
|
|
1418
|
-
if (ii % 2 === 1) {
|
|
1419
|
-
return;
|
|
1420
|
-
}
|
|
1421
|
-
ii *= 0.5;
|
|
1422
|
-
cc = noop(
|
|
1423
|
-
await dbExecAsync({
|
|
1424
|
-
db,
|
|
1425
|
-
responseType: "dict",
|
|
1426
|
-
sql: `SELECT ${sql} AS val`
|
|
1427
|
-
})
|
|
1428
|
-
)[0][0].val;
|
|
1429
|
-
assertJsonEqual(bb, cc, {
|
|
1430
|
-
bb,
|
|
1431
|
-
cc,
|
|
1432
|
-
ii,
|
|
1433
|
-
sql
|
|
1434
|
-
});
|
|
1435
|
-
});
|
|
1436
|
-
}
|
|
766
|
+
// This function will recursively deep-copy <obj> with keys sorted.
|
|
1437
767
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
assertErrorThrownAsync(function () {
|
|
1442
|
-
return dbExecWithRetryAsync({});
|
|
1443
|
-
}, "invalid or closed db");
|
|
768
|
+
let sorted;
|
|
769
|
+
if (typeof obj !== "object" || !obj) {
|
|
770
|
+
return obj;
|
|
1444
771
|
}
|
|
1445
772
|
|
|
1446
|
-
|
|
1447
|
-
// this function will test dbMemoryXxx's handling-behavior
|
|
1448
|
-
let data;
|
|
1449
|
-
let db = await dbOpenAsync({
|
|
1450
|
-
filename: ":memory:"
|
|
1451
|
-
});
|
|
1452
|
-
// test null-case handling-behavior
|
|
1453
|
-
assertErrorThrownAsync(function () {
|
|
1454
|
-
return dbMemoryLoadAsync({
|
|
1455
|
-
db
|
|
1456
|
-
});
|
|
1457
|
-
}, "invalid filename undefined");
|
|
1458
|
-
assertErrorThrownAsync(function () {
|
|
1459
|
-
return dbMemorySaveAsync({
|
|
1460
|
-
db
|
|
1461
|
-
});
|
|
1462
|
-
}, "invalid filename undefined");
|
|
1463
|
-
await dbExecAsync({
|
|
1464
|
-
db,
|
|
1465
|
-
sql: "CREATE TABLE t01 AS SELECT 1 AS c01"
|
|
1466
|
-
});
|
|
1467
|
-
await dbMemorySaveAsync({
|
|
1468
|
-
db,
|
|
1469
|
-
filename: ".testDbMemoryXxx.sqlite"
|
|
1470
|
-
});
|
|
1471
|
-
db = await dbOpenAsync({
|
|
1472
|
-
filename: ":memory:"
|
|
1473
|
-
});
|
|
1474
|
-
await dbMemoryLoadAsync({
|
|
1475
|
-
db,
|
|
1476
|
-
filename: ".testDbMemoryXxx.sqlite"
|
|
1477
|
-
});
|
|
1478
|
-
data = await dbExecAsync({
|
|
1479
|
-
db,
|
|
1480
|
-
sql: "SELECT * FROM t01"
|
|
1481
|
-
});
|
|
1482
|
-
assertJsonEqual(data, [
|
|
1483
|
-
[
|
|
1484
|
-
{
|
|
1485
|
-
c01: 1
|
|
1486
|
-
}
|
|
1487
|
-
]
|
|
1488
|
-
]);
|
|
1489
|
-
}
|
|
773
|
+
// Recursively deep-copy list with child-keys sorted.
|
|
1490
774
|
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
// test null-case handling-behavior
|
|
1494
|
-
assertErrorThrownAsync(function () {
|
|
1495
|
-
return dbOpenAsync({});
|
|
1496
|
-
}, "invalid filename undefined");
|
|
775
|
+
if (Array.isArray(obj)) {
|
|
776
|
+
return obj.map(objectDeepCopyWithKeysSorted);
|
|
1497
777
|
}
|
|
1498
778
|
|
|
1499
|
-
|
|
1500
|
-
// this function will test dbTableInsertAsync's handling-behavior
|
|
1501
|
-
let db = await dbOpenAsync({
|
|
1502
|
-
filename: ":memory:"
|
|
1503
|
-
});
|
|
1504
|
-
// test error handling-behavior
|
|
1505
|
-
[
|
|
1506
|
-
[
|
|
1507
|
-
undefined,
|
|
1508
|
-
(
|
|
1509
|
-
/invalid rowList undefined/
|
|
1510
|
-
)
|
|
1511
|
-
], [
|
|
1512
|
-
[
|
|
1513
|
-
[]
|
|
1514
|
-
],
|
|
1515
|
-
(
|
|
1516
|
-
/invalid colList \[\]/
|
|
1517
|
-
)
|
|
1518
|
-
], [
|
|
1519
|
-
[
|
|
1520
|
-
{}
|
|
1521
|
-
],
|
|
1522
|
-
(
|
|
1523
|
-
/invalid colList \[\]/
|
|
1524
|
-
)
|
|
1525
|
-
]
|
|
1526
|
-
].forEach(function ([
|
|
1527
|
-
rowList, rgx
|
|
1528
|
-
]) {
|
|
1529
|
-
assertErrorThrownAsync(
|
|
1530
|
-
dbTableInsertAsync.bind(
|
|
1531
|
-
undefined,
|
|
1532
|
-
{
|
|
1533
|
-
rowList
|
|
1534
|
-
}
|
|
1535
|
-
),
|
|
1536
|
-
rgx
|
|
1537
|
-
);
|
|
1538
|
-
});
|
|
1539
|
-
// test csv handling-behavior
|
|
1540
|
-
[
|
|
1541
|
-
[
|
|
1542
|
-
"0", undefined
|
|
1543
|
-
],
|
|
1544
|
-
[
|
|
1545
|
-
"0,0,0\n1,1,1",
|
|
1546
|
-
[
|
|
1547
|
-
[
|
|
1548
|
-
"c_0", "c_0_2", "c_0_3"
|
|
1549
|
-
], [
|
|
1550
|
-
"1", "1", "1"
|
|
1551
|
-
]
|
|
1552
|
-
]
|
|
1553
|
-
],
|
|
1554
|
-
[
|
|
1555
|
-
(
|
|
1556
|
-
"c1,c1,c2\n"
|
|
1557
|
-
+ "1, 2 \n"
|
|
1558
|
-
+ `"1","""2""","3\r\n"\n`
|
|
1559
|
-
+ "\n"
|
|
1560
|
-
+ "1,2,3\n"
|
|
1561
|
-
),
|
|
1562
|
-
[
|
|
1563
|
-
[
|
|
1564
|
-
"c1", "c1_2", "c2"
|
|
1565
|
-
], [
|
|
1566
|
-
"1", " 2 ", null
|
|
1567
|
-
], [
|
|
1568
|
-
"1", "\"2\"", "3\n"
|
|
1569
|
-
], [
|
|
1570
|
-
"", null, null
|
|
1571
|
-
], [
|
|
1572
|
-
"1", "2", "3"
|
|
1573
|
-
]
|
|
1574
|
-
]
|
|
1575
|
-
]
|
|
1576
|
-
].forEach(async function ([
|
|
1577
|
-
aa, bb
|
|
1578
|
-
], ii) {
|
|
1579
|
-
let cc = noop(
|
|
1580
|
-
await dbExecAsync({
|
|
1581
|
-
db,
|
|
1582
|
-
responseType: "list",
|
|
1583
|
-
sql: `SELECT * FROM temp.csv_${ii}`,
|
|
1584
|
-
tmpCsv: aa,
|
|
1585
|
-
tmpTableName: "csv_" + ii
|
|
1586
|
-
})
|
|
1587
|
-
)[0];
|
|
1588
|
-
assertOrThrow(
|
|
1589
|
-
JSON.stringify(bb) === JSON.stringify(cc),
|
|
1590
|
-
JSON.stringify([
|
|
1591
|
-
ii, aa, bb, cc
|
|
1592
|
-
], undefined, 4)
|
|
1593
|
-
);
|
|
1594
|
-
});
|
|
1595
|
-
}
|
|
779
|
+
// Recursively deep-copy obj with keys sorted.
|
|
1596
780
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
1, "SQL logic error",
|
|
1604
|
-
2, "unknown error",
|
|
1605
|
-
3, "access permission denied",
|
|
1606
|
-
4, "query aborted",
|
|
1607
|
-
5, "database is locked",
|
|
1608
|
-
6, "database table is locked",
|
|
1609
|
-
7, "out of memory",
|
|
1610
|
-
8, "attempt to write a readonly database",
|
|
1611
|
-
9, "interrupted",
|
|
1612
|
-
10, "disk I/O error",
|
|
1613
|
-
11, "database disk image is malformed",
|
|
1614
|
-
12, "unknown operation",
|
|
1615
|
-
13, "database or disk is full",
|
|
1616
|
-
14, "unable to open database file",
|
|
1617
|
-
15, "locking protocol",
|
|
1618
|
-
16, "unknown error",
|
|
1619
|
-
17, "database schema has changed",
|
|
1620
|
-
18, "string or blob too big",
|
|
1621
|
-
19, "constraint failed",
|
|
1622
|
-
20, "datatype mismatch",
|
|
1623
|
-
21, "bad parameter or other API misuse",
|
|
1624
|
-
22, "unknown error",
|
|
1625
|
-
23, "authorization denied",
|
|
1626
|
-
24, "unknown error",
|
|
1627
|
-
25, "column index out of range",
|
|
1628
|
-
26, "file is not a database",
|
|
1629
|
-
27, "notification message",
|
|
1630
|
-
28, "warning message",
|
|
1631
|
-
100, "unknown error",
|
|
1632
|
-
101, "unknown error"
|
|
1633
|
-
].forEach(function (sql, ii, list) {
|
|
1634
|
-
let bb = list[ii + 1];
|
|
1635
|
-
if (ii % 2 === 1) {
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
ii *= 0.5;
|
|
1639
|
-
sql = `SELECT throwerror(${sql})`;
|
|
1640
|
-
assertErrorThrownAsync(function () {
|
|
1641
|
-
return dbExecAsync({
|
|
1642
|
-
db,
|
|
1643
|
-
sql
|
|
1644
|
-
});
|
|
1645
|
-
}, bb);
|
|
1646
|
-
});
|
|
1647
|
-
}
|
|
781
|
+
sorted = Object.create(null);
|
|
782
|
+
Object.keys(obj).sort().forEach(function (key) {
|
|
783
|
+
sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
|
|
784
|
+
});
|
|
785
|
+
return sorted;
|
|
786
|
+
}
|
|
1648
787
|
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
788
|
+
async function sqlMessagePost(baton, cFuncName, ...argList) {
|
|
789
|
+
|
|
790
|
+
// This function will post msg to <sqlWorker> and return result
|
|
791
|
+
|
|
792
|
+
let errStack;
|
|
793
|
+
let id;
|
|
794
|
+
let result;
|
|
795
|
+
let timeElapsed = Date.now();
|
|
796
|
+
// increment sqlMessageId
|
|
797
|
+
sqlMessageId += 1;
|
|
798
|
+
id = sqlMessageId;
|
|
799
|
+
// postMessage to web-worker
|
|
800
|
+
sqlWorker.postMessage(
|
|
801
|
+
{
|
|
802
|
+
argList,
|
|
803
|
+
baton,
|
|
804
|
+
cFuncName,
|
|
805
|
+
id
|
|
806
|
+
},
|
|
807
|
+
// transfer arraybuffer without copying
|
|
1654
808
|
[
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
{
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
}
|
|
1681
|
-
]
|
|
1682
|
-
],
|
|
1683
|
-
bindList: [
|
|
1684
|
-
new Uint8Array(8)
|
|
1685
|
-
],
|
|
1686
|
-
sql: "SELECT tobase64(uncompress(compress(?))) AS c01"
|
|
1687
|
-
}
|
|
1688
|
-
].forEach(async function ({
|
|
1689
|
-
aa,
|
|
1690
|
-
bindList,
|
|
1691
|
-
sql
|
|
1692
|
-
}) {
|
|
1693
|
-
let bb = await dbExecAsync({
|
|
1694
|
-
bindList,
|
|
1695
|
-
db,
|
|
1696
|
-
sql
|
|
1697
|
-
});
|
|
1698
|
-
assertJsonEqual(aa, bb);
|
|
1699
|
-
});
|
|
809
|
+
baton.buffer,
|
|
810
|
+
...argList.filter(function (elem) {
|
|
811
|
+
return elem && elem.constructor === ArrayBuffer;
|
|
812
|
+
})
|
|
813
|
+
]
|
|
814
|
+
);
|
|
815
|
+
// preserve stack-trace
|
|
816
|
+
errStack = new Error().stack.replace((
|
|
817
|
+
/.*$/m
|
|
818
|
+
), "");
|
|
819
|
+
// await result from web-worker
|
|
820
|
+
result = await new Promise(function (resolve) {
|
|
821
|
+
sqlMessageDict[id] = resolve;
|
|
822
|
+
});
|
|
823
|
+
// cleanup sqlMessageDict
|
|
824
|
+
delete sqlMessageDict[id];
|
|
825
|
+
// debug slow postMessage
|
|
826
|
+
timeElapsed = Date.now() - timeElapsed;
|
|
827
|
+
if (timeElapsed > 500) {
|
|
828
|
+
consoleError(
|
|
829
|
+
"sqlMessagePost - " + JSON.stringify({
|
|
830
|
+
cFuncName,
|
|
831
|
+
timeElapsed
|
|
832
|
+
}) + errStack
|
|
833
|
+
);
|
|
1700
834
|
}
|
|
835
|
+
assertOrThrow(!result.errmsg, result.errmsg);
|
|
836
|
+
return [
|
|
837
|
+
result.baton, result.cFuncName, ...result.argList
|
|
838
|
+
];
|
|
839
|
+
}
|
|
1701
840
|
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
], [
|
|
1735
|
-
[
|
|
1736
|
-
0.5
|
|
1737
|
-
], 0.125, 0.5
|
|
1738
|
-
], [
|
|
1739
|
-
[
|
|
1740
|
-
1.5
|
|
1741
|
-
], 0.25, 1.5
|
|
1742
|
-
], [
|
|
1743
|
-
[
|
|
1744
|
-
2.5
|
|
1745
|
-
], 0.375, 2.5
|
|
1746
|
-
], [
|
|
1747
|
-
[
|
|
1748
|
-
3.5
|
|
1749
|
-
], 0.5, 3.5
|
|
1750
|
-
], [
|
|
1751
|
-
[
|
|
1752
|
-
4.5
|
|
1753
|
-
], 0.625, 4.5
|
|
1754
|
-
], [
|
|
1755
|
-
[
|
|
1756
|
-
5.5
|
|
1757
|
-
], 0.75, 5.5
|
|
1758
|
-
], [
|
|
1759
|
-
[
|
|
1760
|
-
6.5
|
|
1761
|
-
], 0.875, 6.5
|
|
1762
|
-
], [
|
|
1763
|
-
[
|
|
1764
|
-
7.5
|
|
1765
|
-
], 1, 8
|
|
1766
|
-
]
|
|
1767
|
-
].forEach(async function ([
|
|
1768
|
-
data, kk, expected
|
|
1769
|
-
], ii) {
|
|
1770
|
-
let actual;
|
|
1771
|
-
data = data.concat([
|
|
1772
|
-
undefined, undefined, 8, 7, 6, 5, 4, 3, 2, 1, undefined
|
|
1773
|
-
]);
|
|
1774
|
-
actual = noop(
|
|
1775
|
-
await dbExecAsync({
|
|
1776
|
-
db,
|
|
1777
|
-
sql: (`
|
|
1778
|
-
SELECT kthpercentile(val, ${kk}) AS val FROM __tmp${ii};
|
|
1779
|
-
`),
|
|
1780
|
-
tmpRowList: data.map(function (val) {
|
|
1781
|
-
return {
|
|
1782
|
-
val
|
|
1783
|
-
};
|
|
1784
|
-
}),
|
|
1785
|
-
tmpTableName: `__tmp${ii}`
|
|
1786
|
-
})
|
|
1787
|
-
)[0][0].val;
|
|
1788
|
-
assertJsonEqual(actual, expected, {
|
|
1789
|
-
data,
|
|
1790
|
-
kk
|
|
1791
|
-
});
|
|
1792
|
-
});
|
|
841
|
+
async function sqlmathInit() {
|
|
842
|
+
dbFinalizationRegistry = new FinalizationRegistry(function ({
|
|
843
|
+
afterFinalization,
|
|
844
|
+
ptr
|
|
845
|
+
}) {
|
|
846
|
+
// This function will auto-close any open sqlite3-db-pointer,
|
|
847
|
+
// after its js-wrapper has been garbage-collected
|
|
848
|
+
cCallAsync(undefined, "_dbClose", ptr[0]);
|
|
849
|
+
if (afterFinalization) {
|
|
850
|
+
afterFinalization();
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
// Feature-detect nodejs.
|
|
855
|
+
|
|
856
|
+
if (
|
|
857
|
+
typeof process === "object"
|
|
858
|
+
&& typeof process?.versions?.node === "string"
|
|
859
|
+
) {
|
|
860
|
+
cModule = await import("module");
|
|
861
|
+
cModule = cModule.createRequire(import.meta.url);
|
|
862
|
+
cModule = cModule(
|
|
863
|
+
"./_binary_sqlmath"
|
|
864
|
+
+ "_napi8"
|
|
865
|
+
+ "_" + process.platform
|
|
866
|
+
+ "_" + process.arch
|
|
867
|
+
+ ".node"
|
|
868
|
+
);
|
|
869
|
+
if (process.env.npm_config_mode_test) {
|
|
870
|
+
// mock consoleError
|
|
871
|
+
consoleError = noop;
|
|
872
|
+
}
|
|
1793
873
|
}
|
|
874
|
+
}
|
|
1794
875
|
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
testSqlError,
|
|
1813
|
-
testSqlExt,
|
|
1814
|
-
testSqlKthpercentile
|
|
1815
|
-
];
|
|
1816
|
-
Object.assign(local, {
|
|
1817
|
-
SQLITE_MAX_LENGTH2,
|
|
1818
|
-
SQLITE_OPEN_AUTOPROXY,
|
|
1819
|
-
SQLITE_OPEN_CREATE,
|
|
1820
|
-
SQLITE_OPEN_DELETEONCLOSE,
|
|
1821
|
-
SQLITE_OPEN_EXCLUSIVE,
|
|
1822
|
-
SQLITE_OPEN_FULLMUTEX,
|
|
1823
|
-
SQLITE_OPEN_MAIN_DB,
|
|
1824
|
-
SQLITE_OPEN_MAIN_JOURNAL,
|
|
1825
|
-
SQLITE_OPEN_MEMORY,
|
|
1826
|
-
SQLITE_OPEN_NOFOLLOW,
|
|
1827
|
-
SQLITE_OPEN_NOMUTEX,
|
|
1828
|
-
SQLITE_OPEN_PRIVATECACHE,
|
|
1829
|
-
SQLITE_OPEN_READONLY,
|
|
1830
|
-
SQLITE_OPEN_READWRITE,
|
|
1831
|
-
SQLITE_OPEN_SHAREDCACHE,
|
|
1832
|
-
SQLITE_OPEN_SUBJOURNAL,
|
|
1833
|
-
SQLITE_OPEN_SUPER_JOURNAL,
|
|
1834
|
-
SQLITE_OPEN_TEMP_DB,
|
|
1835
|
-
SQLITE_OPEN_TEMP_JOURNAL,
|
|
1836
|
-
SQLITE_OPEN_TRANSIENT_DB,
|
|
1837
|
-
SQLITE_OPEN_URI,
|
|
1838
|
-
SQLITE_OPEN_WAL,
|
|
1839
|
-
assertErrorThrownAsync,
|
|
1840
|
-
assertNumericalEqual,
|
|
1841
|
-
dbCloseAsync,
|
|
1842
|
-
dbExecAsync,
|
|
1843
|
-
dbExecWithRetryAsync,
|
|
1844
|
-
dbGetLastBlobAsync,
|
|
1845
|
-
dbMemoryLoadAsync,
|
|
1846
|
-
dbMemorySaveAsync,
|
|
1847
|
-
dbOpenAsync,
|
|
1848
|
-
dbTableInsertAsync,
|
|
1849
|
-
debugInline,
|
|
1850
|
-
objectDeepCopyWithKeysSorted,
|
|
1851
|
-
testAll,
|
|
1852
|
-
testList
|
|
876
|
+
function sqlmathWebworkerInit({
|
|
877
|
+
Worker
|
|
878
|
+
}) {
|
|
879
|
+
|
|
880
|
+
// Feature-detect browser.
|
|
881
|
+
|
|
882
|
+
IS_BROWSER = true;
|
|
883
|
+
Worker = Worker || globalThis.Worker;
|
|
884
|
+
sqlWorker = new Worker("sqlmath_wasm.js");
|
|
885
|
+
sqlWorker.onmessage = function ({
|
|
886
|
+
data
|
|
887
|
+
}) {
|
|
888
|
+
sqlMessageDict[data.id](data);
|
|
889
|
+
};
|
|
890
|
+
/*
|
|
891
|
+
let db = await dbOpenAsync({ //jslint-quiet
|
|
892
|
+
filename: ":memory:"
|
|
1853
893
|
});
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
}
|
|
894
|
+
debugInline(
|
|
895
|
+
await dbExecAsync({
|
|
896
|
+
db,
|
|
897
|
+
sql: "aSELECT 1234"
|
|
898
|
+
})
|
|
899
|
+
);
|
|
900
|
+
*/
|
|
901
|
+
}
|
|
1859
902
|
|
|
1860
|
-
|
|
903
|
+
await sqlmathInit({});
|
|
904
|
+
|
|
905
|
+
export {
|
|
906
|
+
SQLITE_MAX_LENGTH2,
|
|
907
|
+
SQLITE_OPEN_AUTOPROXY,
|
|
908
|
+
SQLITE_OPEN_CREATE,
|
|
909
|
+
SQLITE_OPEN_DELETEONCLOSE,
|
|
910
|
+
SQLITE_OPEN_EXCLUSIVE,
|
|
911
|
+
SQLITE_OPEN_FULLMUTEX,
|
|
912
|
+
SQLITE_OPEN_MAIN_DB,
|
|
913
|
+
SQLITE_OPEN_MAIN_JOURNAL,
|
|
914
|
+
SQLITE_OPEN_MEMORY,
|
|
915
|
+
SQLITE_OPEN_NOFOLLOW,
|
|
916
|
+
SQLITE_OPEN_NOMUTEX,
|
|
917
|
+
SQLITE_OPEN_PRIVATECACHE,
|
|
918
|
+
SQLITE_OPEN_READONLY,
|
|
919
|
+
SQLITE_OPEN_READWRITE,
|
|
920
|
+
SQLITE_OPEN_SHAREDCACHE,
|
|
921
|
+
SQLITE_OPEN_SUBJOURNAL,
|
|
922
|
+
SQLITE_OPEN_SUPER_JOURNAL,
|
|
923
|
+
SQLITE_OPEN_TEMP_DB,
|
|
924
|
+
SQLITE_OPEN_TEMP_JOURNAL,
|
|
925
|
+
SQLITE_OPEN_TRANSIENT_DB,
|
|
926
|
+
SQLITE_OPEN_URI,
|
|
927
|
+
SQLITE_OPEN_WAL,
|
|
928
|
+
assertJsonEqual,
|
|
929
|
+
assertNumericalEqual,
|
|
930
|
+
assertOrThrow,
|
|
931
|
+
dbCloseAsync,
|
|
932
|
+
dbExecAndReturnLastBlobAsync,
|
|
933
|
+
dbExecAsync,
|
|
934
|
+
dbFileExportAsync,
|
|
935
|
+
dbFileImportAsync,
|
|
936
|
+
dbNoopAsync,
|
|
937
|
+
dbOpenAsync,
|
|
938
|
+
debugInline,
|
|
939
|
+
jsbatonValueString,
|
|
940
|
+
noop,
|
|
941
|
+
objectDeepCopyWithKeysSorted,
|
|
942
|
+
sqlmathInit,
|
|
943
|
+
sqlmathWebworkerInit
|
|
944
|
+
};
|