1. 1// MIT License
2. 1//
3. 1// Copyright (c) 2021 Kai Zhu
4. 1//
5. 1// Permission is hereby granted, free of charge, to any person obtaining a copy
6. 1// of this software and associated documentation files (the "Software"), to deal
7. 1// in the Software without restriction, including without limitation the rights
8. 1// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9. 1// copies of the Software, and to permit persons to whom the Software is
10. 1// furnished to do so, subject to the following conditions:
11. 1//
12. 1// The above copyright notice and this permission notice shall be included in
13. 1// all copies or substantial portions of the Software.
14. 1//
15. 1// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16. 1// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17. 1// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18. 1// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19. 1// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20. 1// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21. 1// SOFTWARE.
22. 1
23. 1
24. 1/*jslint beta, bitwise, name, node*/
25. 1/*global FinalizationRegistry*/
26. 1"use strict";
27. 1
28. 1const JSBATON_ARGC = 8;
29. 1const JSBATON_OFFSET_ALL = 256;
30. 1const JSBATON_OFFSET_ARGV = 128;
31. 1const JSBATON_OFFSET_BUFV = 192;
32. 1// const JSBATON_OFFSET_ERRMSG = 48;
33. 1const JSBATON_OFFSET_FUNCNAME = 8;
34. 1const JS_MAX_SAFE_INTEGER = 0x1f_ffff_ffff_ffff;
35. 1const JS_MIN_SAFE_INTEGER = -0x1f_ffff_ffff_ffff;
36. 1const SIZEOF_BLOB_MAX = 1_000_000_000;
37. 1// const SIZEOF_ERRMSG = 80;
38. 1const SIZEOF_FUNCNAME = 16;
39. 1const SQLITE_DATATYPE_BLOB = 0x04;
40. 1const SQLITE_DATATYPE_EXTERNALBUFFER = 0x71;
41. 1const SQLITE_DATATYPE_FLOAT = 0x02;
42. 1const SQLITE_DATATYPE_INTEGER = 0x01;
43. 1const SQLITE_DATATYPE_INTEGER_0 = 0x00;
44. 1const SQLITE_DATATYPE_INTEGER_1 = 0x21;
45. 1const SQLITE_DATATYPE_NULL = 0x05;
46. 1const SQLITE_DATATYPE_TEXT = 0x03;
47. 1const SQLITE_DATATYPE_TEXT_0 = 0x13;
48. 1const SQLITE_RESPONSETYPE_LASTBLOB = 1;
49. 1const SQLITE_RESPONSETYPE_LASTVALUE = 2;
50. 1
51. 1const FILENAME_DBTMP = "/tmp/__dbtmp1"; //jslint-ignore-line
52. 1
53. 1const LGBM_DTYPE_FLOAT32 = 0; /* float32 (single precision float)*/
54. 1const LGBM_DTYPE_FLOAT64 = 1; /* float64 (double precision float)*/
55. 1const LGBM_DTYPE_INT32 = 2; /* int32*/
56. 1const LGBM_DTYPE_INT64 = 3; /* int64*/
57. 1const LGBM_FEATURE_IMPORTANCE_GAIN = 1; /* Gain type of feature importance*/
58. 1const LGBM_FEATURE_IMPORTANCE_SPLIT = 0;/* Split type of feature importance*/
59. 1const LGBM_MATRIX_TYPE_CSC = 1; /* CSC sparse matrix type*/
60. 1const LGBM_MATRIX_TYPE_CSR = 0; /* CSR sparse matrix type*/
61. 1const LGBM_PREDICT_CONTRIB = 3; /* Predict feature contributions (SHAP values)*/
62. 1const LGBM_PREDICT_LEAF_INDEX = 2; /* Predict leaf index*/
63. 1const LGBM_PREDICT_NORMAL = 0; /* Normal prediction w/ transform (if needed)*/
64. 1const LGBM_PREDICT_RAW_SCORE = 1; /* Predict raw score*/
65. 1const SQLITE_OPEN_AUTOPROXY = 0x00000020; /* VFS only */
66. 1const SQLITE_OPEN_CREATE = 0x00000004; /* Ok for sqlite3_open_v2() */
67. 1const SQLITE_OPEN_DELETEONCLOSE = 0x00000008; /* VFS only */
68. 1const SQLITE_OPEN_EXCLUSIVE = 0x00000010; /* VFS only */
69. 1const SQLITE_OPEN_FULLMUTEX = 0x00010000; /* Ok for sqlite3_open_v2() */
70. 1const SQLITE_OPEN_MAIN_DB = 0x00000100; /* VFS only */
71. 1const SQLITE_OPEN_MAIN_JOURNAL = 0x00000800; /* VFS only */
72. 1const SQLITE_OPEN_MEMORY = 0x00000080; /* Ok for sqlite3_open_v2() */
73. 1const SQLITE_OPEN_NOFOLLOW = 0x01000000; /* Ok for sqlite3_open_v2() */
74. 1const SQLITE_OPEN_NOMUTEX = 0x00008000; /* Ok for sqlite3_open_v2() */
75. 1const SQLITE_OPEN_PRIVATECACHE = 0x00040000; /* Ok for sqlite3_open_v2() */
76. 1const SQLITE_OPEN_READONLY = 0x00000001; /* Ok for sqlite3_open_v2() */
77. 1const SQLITE_OPEN_READWRITE = 0x00000002; /* Ok for sqlite3_open_v2() */
78. 1const SQLITE_OPEN_SHAREDCACHE = 0x00020000; /* Ok for sqlite3_open_v2() */
79. 1const SQLITE_OPEN_SUBJOURNAL = 0x00002000; /* VFS only */
80. 1const SQLITE_OPEN_SUPER_JOURNAL = 0x00004000; /* VFS only */
81. 1const SQLITE_OPEN_TEMP_DB = 0x00000200; /* VFS only */
82. 1const SQLITE_OPEN_TEMP_JOURNAL = 0x00001000; /* VFS only */
83. 1const SQLITE_OPEN_TRANSIENT_DB = 0x00000400; /* VFS only */
84. 1const SQLITE_OPEN_URI = 0x00000040; /* Ok for sqlite3_open_v2() */
85. 1const SQLITE_OPEN_WAL = 0x00080000; /* VFS only */
86. 1
87. 1let IS_BROWSER;
88. 1let SQLMATH_EXE;
89. 1let SQLMATH_NODE;
90. 1let cModule;
91. 1let cModulePath;
92. 1let consoleError = console.error;
93. 1let dbFinalizationRegistry;
94. 1// init debugInline
95. 1let debugInline = (function () {
96. 3 let __consoleError = function () {
97. 3 return;
98. 3 };
99. 1 function debug(...argv) {
100. 1
101. 1// This function will print <argv> to stderr and then return <argv>[0].
102. 1
103. 1 __consoleError("\n\ndebugInline");
104. 1 __consoleError(...argv);
105. 1 __consoleError("\n");
106. 1 return argv[0];
107. 1 }
108. 1 debug(); // Coverage-hack.
109. 1 __consoleError = console.error; //jslint-ignore-line
110. 1 return debug;
111. 1}());
112. 1let moduleChildProcess;
113. 1let moduleChildProcessSpawn;
114. 1let moduleCrypto;
115. 1let moduleFs;
116. 1let moduleFsInitResolveList;
117. 1let modulePath;
118. 1let moduleUrl;
119. 1let {
120. 1 npm_config_mode_debug,
121. 1 npm_config_mode_setup,
122. 1 npm_config_mode_test
123. 1} = typeof process === "object" && process?.env;
124. 1let sqlMessageDict = {}; // dict of web-worker-callbacks
125. 1let sqlMessageId = 0;
126. 1let sqlWorker;
127. 1let version = "v2025.9.1-beta";
128. 1
129. 88async function assertErrorThrownAsync(asyncFunc, regexp) {
130. 88
131. 88// This function will assert calling <asyncFunc> throws an error.
132. 88
133. 88 let err;
134. 88 try {
135. 1 await asyncFunc();
136. 87 } catch (errCaught) {
137. 87 err = errCaught;
138. 87 }
139. 88 assertOrThrow(err, "No error thrown.");
140. 88 assertOrThrow(
141. 85 !regexp || new RegExp(regexp).test(err.message),
142. 88 err
143. 88 );
144. 88}
145. 1
146. 14292function assertInt64(val) {
147. 14292 // This function will assert <val> is within range of c99-signed-long-long.
148. 14292 val = BigInt(val);
149. 14292 if (!(
150. 14285 -9_223_372_036_854_775_808n <= val && val <= 9_223_372_036_854_775_807n
151. 14 )) {
152. 14 throw new Error(
153. 14 `integer ${val} outside signed-64-bit inclusive-range`
154. 14 + " -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807"
155. 14 );
156. 14 }
157. 14292}
158. 1
159. 4930function assertJsonEqual(aa, bb, message) {
160. 4930
161. 4930// This function will assert JSON.stringify(<aa>) === JSON.stringify(<bb>).
162. 4930
163. 4930 aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa), undefined, 1);
164. 4930 bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb), undefined, 1);
165. 3 if (aa !== bb) {
166. 3 throw new Error(
167. 3 "\n" + aa + "\n!==\n" + bb
168. 3 + (
169. 3 typeof message === "string"
170. 3 ? " - " + message
171. 3 : message
172. 3 ? " - " + JSON.stringify(message)
173. 3 : ""
174. 3 )
175. 3 );
176. 3 }
177. 4930}
178. 1
179. 4function assertNumericalEqual(aa, bb, message) {
180. 4
181. 4// This function will assert aa - bb <= Number.EPSILON.
182. 4
183. 4 assertOrThrow(aa, "value cannot be 0 or falsy");
184. 2 if (!(Math.abs((aa - bb) / Math.max(aa, bb)) <= 256 * Number.EPSILON)) {
185. 2 throw new Error(
186. 2 JSON.stringify(aa) + " != " + JSON.stringify(bb) + (
187. 2 message
188. 2 ? " - " + message
189. 2 : ""
190. 2 )
191. 2 );
192. 2 }
193. 4}
194. 1
195. 48090function assertOrThrow(condition, message) {
196. 48090
197. 48090// This function will throw <message> if <condition> is falsy.
198. 48090
199. 72 if (!condition) {
200. 72 throw (
201. 72 (!message || typeof message === "string")
202. 72 ? new Error(String(message).slice(0, 2048))
203. 72 : message
204. 72 );
205. 72 }
206. 48090}
207. 1
208. 15async function childProcessSpawn2(command, args, option) {
209. 15
210. 15// This function will run child_process.spawn as a promise.
211. 15
212. 15 return await new Promise(function (resolve, reject) {
213. 15 let bufList = [[], [], []];
214. 15 let child;
215. 15 let {
216. 15 modeCapture,
217. 15 modeDebug,
218. 15 stdio = []
219. 15 } = option;
220. 1 if (modeDebug) {
221. 1 consoleError(
222. 1 `childProcessSpawn2 - ${command} ${JSON.stringify(args)}`
223. 1 );
224. 1 }
225. 15 child = moduleChildProcessSpawn(
226. 15 command,
227. 15 args,
228. 15 Object.assign({}, option, {
229. 15 stdio: [
230. 15 "ignore",
231. 15 (
232. 15 modeCapture
233. 1 ? "pipe"
234. 14 : stdio[1]
235. 15 ),
236. 15 (
237. 15 modeCapture
238. 1 ? "pipe"
239. 14 : stdio[2]
240. 15 )
241. 15 ]
242. 15 })
243. 15 );
244. 1 if (modeCapture) {
245. 1 [
246. 1 child.stdin, child.stdout, child.stderr
247. 3 ].forEach(function (pipe, ii) {
248. 1 if (ii === 0) {
249. 1 return;
250. 2 }
251. 2 pipe.on("data", function (chunk) {
252. 2 bufList[ii].push(chunk);
253. 2 if (stdio[ii] !== "ignore") {
254. 2 switch (ii) {
255. 2 case 1:
256. 2 process.stdout.write(chunk);
257. 2 break;
258. 2 case 2:
259. 2 process.stderr.write(chunk);
260. 2 break;
261. 2 }
262. 2 }
263. 2 });
264. 2 });
265. 1 }
266. 15 child.on("exit", function (exitCode) {
267. 15 let resolve0 = resolve;
268. 15 let stderr;
269. 15 let stdout;
270. 15 // coverage-hack
271. 15 if (exitCode || npm_config_mode_test) {
272. 15 resolve = reject;
273. 15 }
274. 15 // coverage-hack
275. 15 if (npm_config_mode_test) {
276. 15 resolve = resolve0;
277. 15 }
278. 15 [
279. 15 stdout, stderr
280. 30 ] = bufList.slice(1).map(function (buf) {
281. 30 return (
282. 30 typeof modeCapture === "string"
283. 2 ? Buffer.concat(buf).toString(modeCapture)
284. 28 : Buffer.concat(buf)
285. 30 );
286. 30 });
287. 15 resolve([
288. 15 exitCode, stdout, stderr
289. 15 ]);
290. 15 });
291. 15 });
292. 15}
293. 1
294. 7async function ciBuildExt({
295. 7 process
296. 7}) {
297. 7
298. 7// This function will build sqlmath from c.
299. 7
300. 7 let binNodegyp;
301. 7 let exitCode;
302. 7 binNodegyp = modulePath.resolve(
303. 7 modulePath.dirname(process.execPath || ""),
304. 7 "node_modules/npm/node_modules/node-gyp/bin/node-gyp.js"
305. 7 ).replace("/bin/node_modules/", "/lib/node_modules/");
306. 7 if (!noop(
307. 7 await fsExistsUnlessTest(cModulePath)
308. 7 )) {
309. 7 await ciBuildExt1NodejsConfigure({
310. 7 binNodegyp,
311. 7 process
312. 7 });
313. 7 }
314. 7 consoleError(
315. 7 `ciBuildExt2Nodejs - linking lib ${modulePath.resolve(cModulePath)}`
316. 7 );
317. 7 [
318. 7 exitCode
319. 7 ] = await childProcessSpawn2(
320. 7 "sh",
321. 7 [
322. 7 "-c",
323. 7 (`
324. 7(set -e
325. 7 # rebuild binding
326. 7 rm -rf build/Release/obj/SRC_SQLMATH_CUSTOM/
327. 7 node "${binNodegyp}" build --release
328. 7 # node "${binNodegyp}" build --release --loglevel=verbose
329. 7 mv build/Release/binding.node "${cModulePath}"
330. 7 mv build/Release/shell "${SQLMATH_EXE}"
331. 7 # ugly-hack - win32-sqlite-shell doesn't like nodejs-builtin-zlib,
332. 7 # so link with external-zlib.
333. 7 if (uname | grep -q "MING\\|MSYS")
334. 7 then
335. 7 rm -f ${SQLMATH_EXE}
336. 7 python setup.py exe_link \
337. 7 ./build/Release/SRC_SQLITE_BASE.lib \
338. 7 ./build/Release/SRC_SQLMATH_CUSTOM.lib \
339. 7 ./build/Release/obj/shell/sqlmath_external_sqlite.obj \
340. 7 ./zlib.lib \
341. 7 \
342. 7 -ltcg \
343. 7 -nologo \
344. 7 -out:${SQLMATH_EXE} \
345. 7 -subsystem:console
346. 7 fi
347. 7)
348. 7 `)
349. 7 ],
350. 7 {modeDebug: npm_config_mode_debug, stdio: ["ignore", 1, 2]}
351. 7 );
352. 7 assertOrThrow(!exitCode, `ciBuildExt - exitCode=${exitCode}`);
353. 7}
354. 1
355. 7async function ciBuildExt1NodejsConfigure({
356. 7 binNodegyp
357. 7 // process
358. 7}) {
359. 7
360. 7// This function will setup posix/win32 env for building c-extension.
361. 7
362. 7 let cflagWallList = [];
363. 7 let cflagWnoList = [];
364. 7 String(
365. 7 await fsReadFileUnlessTest(".ci.sh", "utf8", (`
366. 7SQLMATH_CFLAG_WALL_LIST=" \\
367. 7"
368. 7SQLMATH_CFLAG_WNO_LIST=" \\
369. 7"
370. 7 `))
371. 7 ).replace((
372. 7 /(SQLMATH_CFLAG_WALL_LIST|SQLMATH_CFLAG_WNO_LIST)=" \\([\S\s]*?)"/g
373. 14 ), function (ignore, cflagType, cflagList) {
374. 14 cflagList = cflagList.split(/[\s\\]/).filter(noop);
375. 14 switch (cflagType) {
376. 7 case "SQLMATH_CFLAG_WALL_LIST":
377. 7 cflagWallList = cflagList;
378. 7 break;
379. 7 case "SQLMATH_CFLAG_WNO_LIST":
380. 7 cflagWnoList = cflagList;
381. 7 break;
382. 14 }
383. 14 return "";
384. 14 });
385. 7 consoleError(`ciBuildExt1Nodejs - configure binding.gyp`);
386. 7 await fsWriteFileUnlessTest("binding.gyp", JSON.stringify({
387. 7 "target_defaults": {
388. 7 "cflags": cflagWallList,
389. 7// https://github.com/nodejs/node-gyp/blob/v10.3.1/gyp/pylib/gyp/MSVSSettings.py
390. 7 "msvs_settings": {
391. 7 "VCCLCompilerTool": {
392. 7 "WarnAsError": 1,
393. 7 "WarningLevel": 4
394. 7 }
395. 7 },
396. 7 "xcode_settings": {
397. 7 "OTHER_CFLAGS": cflagWallList
398. 7 }
399. 7 },
400. 7 "targets": [
401. 7 {
402. 7 "cflags": cflagWnoList,
403. 7 "defines": [
404. 7 "SRC_SQLITE_BASE_C2"
405. 7 ],
406. 7 "msvs_settings": {
407. 7 "VCCLCompilerTool": {
408. 7 "WarnAsError": 1,
409. 7 "WarningLevel": 2
410. 7 }
411. 7 },
412. 7 "sources": [
413. 7 "sqlmath_external_sqlite.c"
414. 7 ],
415. 7 "target_name": "SRC_SQLITE_BASE",
416. 7 "type": "static_library",
417. 7 "xcode_settings": {
418. 7 "OTHER_CFLAGS": cflagWnoList
419. 7 }
420. 7 },
421. 7 {
422. 7 "defines": [
423. 7 "SRC_SQLMATH_BASE_C2",
424. 7 "SRC_SQLMATH_CUSTOM_C2"
425. 7 ],
426. 7 "dependencies": [
427. 7 "SRC_SQLITE_BASE"
428. 7 ],
429. 7 "sources": [
430. 7 "sqlmath_base.c",
431. 7 "sqlmath_custom.c"
432. 7 ],
433. 7 "target_name": "SRC_SQLMATH_CUSTOM",
434. 7 "type": "static_library"
435. 7 },
436. 7 {
437. 7 "defines": [
438. 7 "SRC_SQLMATH_NODEJS_C2"
439. 7 ],
440. 7 "dependencies": [
441. 7 "SRC_SQLMATH_CUSTOM"
442. 7 ],
443. 7 "sources": [
444. 7 "sqlmath_base.c"
445. 7 ],
446. 7 "target_name": "binding"
447. 7 },
448. 7 {
449. 7 "conditions": [
450. 7 [
451. 7 "OS==\"win\"",
452. 7 {},
453. 7 {
454. 7 "libraries": [
455. 7 "-lz"
456. 7 ]
457. 7 }
458. 7 ]
459. 7 ],
460. 7 "defines": [
461. 7 "SRC_SQLITE_SHELL_C2"
462. 7 ],
463. 7 "dependencies": [
464. 7 "SRC_SQLMATH_CUSTOM"
465. 7 ],
466. 7 "sources": [
467. 7 "sqlmath_external_sqlite.c"
468. 7 ],
469. 7 "target_name": "shell",
470. 7 "type": "executable"
471. 7 }
472. 7 ]
473. 7 }, undefined, 4) + "\n");
474. 7 await childProcessSpawn2(
475. 7 "sh",
476. 7 [
477. 7 "-c",
478. 7 (`
479. 7(set -e
480. 7 # node "${binNodegyp}" clean
481. 7 node "${binNodegyp}" configure
482. 7)
483. 7 `)
484. 7 ],
485. 7 {modeDebug: npm_config_mode_debug, stdio: ["ignore", 1, 2]}
486. 7 );
487. 7}
488. 1
489. 3979async function dbCallAsync(baton, argList, mode) {
490. 3979
491. 3979// This function will call c-function dbXxx() with given <funcname>
492. 3979// and return [<baton>, ...argList].
493. 3979
494. 3979 let db;
495. 3979 let errStack;
496. 3979 let funcname;
497. 3979 let id;
498. 3979 let result;
499. 3979 let timeElapsed;
500. 3979 // If argList contains <db>, then mark it as busy.
501. 1931 if (mode === "modeDb") {
502. 1931 // init db
503. 1931 db = argList[0];
504. 1931 assertOrThrow(
505. 1931 db.busy >= 0,
506. 1931 `dbCallAsync - invalid db.busy = ${db.busy}`
507. 1931 );
508. 1931 db.ii = (db.ii + 1) % db.connPool.length;
509. 1931 db.ptr = db.connPool[db.ii][0];
510. 1931 // increment db.busy
511. 1931 db.busy += 1;
512. 1931 try {
513. 1931 return await dbCallAsync(baton, [db.ptr, ...argList.slice(1)]);
514. 1931 } finally {
515. 1931 // decrement db.busy
516. 1931 db.busy -= 1;
517. 1931 assertOrThrow(
518. 1931 db.busy >= 0,
519. 1931 `dbCallAsync - invalid db.busy = ${db.busy}`
520. 1931 );
521. 1931 }
522. 2048 }
523. 2048 // copy argList to avoid side-effect
524. 2048 argList = [...argList];
525. 2048 assertOrThrow(
526. 2048 argList.length <= JSBATON_ARGC,
527. 2048 `dbCallAsync - argList.length must be less than than ${JSBATON_ARGC}`
528. 2048 );
529. 2048 // pad argList to length JSBATON_ARGC
530. 6375 while (argList.length < JSBATON_ARGC) {
531. 6375 argList.push(0n);
532. 6375 }
533. 2048 // serialize js-value to c-value
534. 16246 argList = argList.map(function (val, argi) {
535. 16245 if (val === null || val === undefined) {
536. 2048 val = 0;
537. 2048 }
538. 16246 switch (typeof val) {
539. 8232 case "bigint":
540. 10151 case "boolean":
541. 14260 case "number":
542. 14260 // check for min/max safe-integer
543. 14260 assertOrThrow(
544. 14260 (
545. 14260 (JS_MIN_SAFE_INTEGER <= val && val <= JS_MAX_SAFE_INTEGER)
546. 14260 || typeof val === "bigint"
547. 14260 ),
548. 14260 (
549. 14260 "dbCallAsync - "
550. 14260 + "non-bigint-integer must be within inclusive-range"
551. 14260 + ` ${JS_MIN_SAFE_INTEGER} to ${JS_MAX_SAFE_INTEGER}`
552. 14260 )
553. 14260 );
554. 14260 val = BigInt(val);
555. 14260 assertInt64(val);
556. 14260 baton.setBigInt64(JSBATON_OFFSET_ARGV + argi * 8, val, true);
557. 14260 return val;
558. 16246 // case "object":
559. 16246 // break;
560. 2048 case "string":
561. 2048 baton = jsbatonSetValue(baton, argi, (
562. 2048 val.endsWith("\u0000")
563. 2048 ? val
564. 2048 // append null-terminator to string
565. 2048 : val + "\u0000"
566. 2048 ));
567. 2048 return;
568. 2048 }
569. 2048 assertOrThrow(
570. 2048 !ArrayBuffer.isView(val) || val.byteOffset === 0,
571. 16246 (
572. 16246 "dbCallAsync - argList cannot contain arraybuffer-views"
573. 16246 + " with non-zero byteOffset"
574. 16246 )
575. 16246 );
576. 2048 if (isExternalBuffer(val)) {
577. 2048 return val;
578. 2048 }
579. 2048 throw new Error(`dbCallAsync - invalid arg-type "${typeof val}"`);
580. 2048 });
581. 2048 // assert byteOffset === 0
582. 18225 [baton, ...argList].forEach(function (arg) {
583. 2048 assertOrThrow(!ArrayBuffer.isView(arg) || arg.byteOffset === 0, arg);
584. 18225 });
585. 2048 // extract funcname
586. 2048 funcname = new TextDecoder().decode(
587. 2048 new DataView(baton.buffer, JSBATON_OFFSET_FUNCNAME, SIZEOF_FUNCNAME)
588. 2048 ).replace((/\u0000/g), "");
589. 2048 // preserve stack-trace
590. 2048 errStack = new Error().stack.replace((/.*$/m), "");
591. 2048 try {
592. 2048
593. 2048// Dispatch to nodejs-napi.
594. 2048
595. 2048 if (!IS_BROWSER) {
596. 2023 await cModule._jspromiseCreate(baton.buffer, argList, funcname);
597. 2023 // prepend baton to argList
598. 2023 return [baton, ...argList];
599. 2023 }
600. 2
601. 2// Dispatch to web-worker.
602. 2
603. 2 // increment sqlMessageId
604. 2 sqlMessageId += 1;
605. 2 id = sqlMessageId;
606. 2 // postMessage to web-worker
607. 2 sqlWorker.postMessage(
608. 2 {
609. 2 FILENAME_DBTMP,
610. 2 JSBATON_OFFSET_ALL,
611. 2 JSBATON_OFFSET_BUFV,
612. 2 argList,
613. 2 baton,
614. 2 funcname,
615. 2 id
616. 2 },
617. 2 // transfer arraybuffer without copying
618. 2 [baton.buffer, ...argList.filter(isExternalBuffer)]
619. 2 );
620. 2 // init timeElapsed
621. 2 timeElapsed = Date.now();
622. 2 // await result from web-worker
623. 2 result = await new Promise(function (resolve) {
624. 2 sqlMessageDict[id] = resolve;
625. 2 });
626. 2 // cleanup sqlMessageDict
627. 2 delete sqlMessageDict[id];
628. 2 // debug slow postMessage
629. 2 timeElapsed = Date.now() - timeElapsed;
630. 2 if (timeElapsed > 500 || funcname === "testTimeElapsed") {
631. 1 consoleError(
632. 1 "sqlMessagePost - "
633. 1 + JSON.stringify({funcname, timeElapsed})
634. 1 + errStack
635. 1 );
636. 2 }
637. 2 assertOrThrow(!result.errmsg, result.errmsg);
638. 2 // prepend baton to argList
639. 2 return [result.baton, ...result.argList];
640. 55 } catch (err) {
641. 55 err.stack += errStack;
642. 55 assertOrThrow(undefined, err);
643. 55 }
644. 3979}
645. 1
646. 3async function dbCloseAsync(db) {
647. 3
648. 3// This function will close sqlite-database-connection <db>.
649. 3
650. 3 // prevent segfault - do not close db if actions are pending
651. 3 assertOrThrow(
652. 3 db.busy === 0,
653. 3 `dbCloseAsync - cannot close db with ${db.busy} actions pending`
654. 3 );
655. 3 // cleanup connPool
656. 1 await Promise.all(db.connPool.map(async function (ptr) {
657. 1 let val = ptr[0];
658. 1 ptr[0] = 0n;
659. 1 await dbCallAsync(jsbatonCreate("_dbClose"), [val, db.filename]);
660. 1 }));
661. 1}
662. 1
663. 58function dbExecAndReturnLastBlob({
664. 58 bindList = [],
665. 58 db,
666. 58 sql
667. 58}) {
668. 58
669. 58// This function will exec <sql> in <db>,
670. 58// and return last-value retrieved from execution as raw blob/buffer.
671. 58
672. 58 return dbExecAsync({
673. 58 bindList,
674. 58 db,
675. 58 responseType: "lastblob",
676. 58 sql
677. 58 });
678. 58}
679. 1
680. 115async function dbExecAndReturnLastRow({
681. 115 bindList = [],
682. 115 db,
683. 115 sql
684. 115}) {
685. 115
686. 115// This function will exec <sql> in <db>,
687. 115// and return last-row or empty-object.
688. 115
689. 101 let result = await dbExecAsync({bindList, db, sql});
690. 101 result = result[result.length - 1] || [];
691. 1 result = result[result.length - 1] || {};
692. 115 return result;
693. 115}
694. 1
695. 65async function dbExecAndReturnLastTable({
696. 65 bindList = [],
697. 65 db,
698. 65 sql
699. 65}) {
700. 65
701. 65// This function will exec <sql> in <db>,
702. 65// and return last-table or empty-list.
703. 65
704. 65 let result = await dbExecAsync({bindList, db, sql});
705. 1 result = result[result.length - 1] || [];
706. 65 return result;
707. 65}
708. 1
709. 1184function dbExecAndReturnLastValue({
710. 1184 bindList = [],
711. 1184 db,
712. 1184 sql
713. 1184}) {
714. 1184
715. 1184// This function will exec <sql> in <db>,
716. 1184// and return last-json-value.
717. 1184
718. 1184 return dbExecAsync({
719. 1184 bindList,
720. 1184 db,
721. 1184 responseType: "lastvalue",
722. 1184 sql
723. 1184 });
724. 1184}
725. 1
726. 1929async function dbExecAsync({
727. 1929 bindList = [],
728. 1929 db,
729. 1929 modeNoop,
730. 1929 responseType,
731. 1929 sql
732. 1929}) {
733. 1929
734. 1929// This function will exec <sql> in <db> and return <result>.
735. 1929
736. 1929 let baton = jsbatonCreate("_dbExec");
737. 1929 let bindByKey = !Array.isArray(bindList);
738. 1929 let bufi = [0];
739. 1929 let referenceList = [];
740. 1929 let result;
741. 1 if (modeNoop) {
742. 1 return;
743. 1928 }
744. 1928 if (bindByKey) {
745. 1347 Object.entries(bindList).forEach(function ([key, val]) {
746. 1347 baton = jsbatonSetValue(baton, undefined, `:${key}\u0000`);
747. 1347 baton = jsbatonSetValue(
748. 1347 baton,
749. 1347 undefined,
750. 1347 val,
751. 1347 bufi,
752. 1347 referenceList
753. 1347 );
754. 1347 });
755. 1235 } else {
756. 693 bindList.forEach(function (val) {
757. 693 baton = jsbatonSetValue(
758. 693 baton,
759. 693 undefined,
760. 693 val,
761. 693 bufi,
762. 693 referenceList
763. 693 );
764. 693 });
765. 1916 }
766. 1916 [baton, ...result] = await dbCallAsync(
767. 1916 baton,
768. 1916 [
769. 1916 // 0. db
770. 1916 db,
771. 1916 // 1. sql
772. 1916 String(sql) + "\n;\nPRAGMA noop",
773. 1916 // 2. bindList.length
774. 1916 (
775. 1916 bindByKey
776. 1916 ? Object.keys(bindList).length
777. 681 : bindList.length
778. 1929 ),
779. 1929 // 3. bindByKey
780. 1929 bindByKey,
781. 1929 // 4. responseType
782. 1929 (
783. 1929 responseType === "lastblob"
784. 56 ? SQLITE_RESPONSETYPE_LASTBLOB
785. 1860 : responseType === "lastvalue"
786. 1860 ? SQLITE_RESPONSETYPE_LASTVALUE
787. 1860 : 0
788. 1929 )
789. 1929 ],
790. 1929 "modeDb"
791. 1861 );
792. 1861 result = result[0];
793. 1861 if (!IS_BROWSER) {
794. 1861 result = cModule._jsbatonStealCbuffer(
795. 1861 baton.buffer,
796. 1861 0,
797. 1861 Number(
798. 1861 responseType !== "arraybuffer" && responseType !== "lastblob"
799. 1861 )
800. 1861 );
801. 1861 }
802. 1861 switch (responseType) {
803. 1861 case "arraybuffer":
804. 110 case "lastblob":
805. 110 return result;
806. 1236 case "lastvalue":
807. 1403 case "list":
808. 1403 return jsonParseArraybuffer(result);
809. 348 default:
810. 374 return jsonParseArraybuffer(result).map(function (table) {
811. 374 let colList = table.shift();
812. 13942 return table.map(function (row) {
813. 13942 let dict = {};
814. 43367 colList.forEach(function (key, ii) {
815. 43367 dict[key] = row[ii];
816. 43367 });
817. 13942 return dict;
818. 13942 });
819. 374 });
820. 1929 }
821. 1929}
822. 1
823. 18async function dbFileLoadAsync({
824. 18 db,
825. 18 dbData,
826. 18 filename,
827. 18 modeNoop,
828. 18 modeSave = 0
829. 18}) {
830. 18
831. 18// This function will load <filename> to <db>.
832. 18
833. 18 let filename2;
834. 15 async function _dbFileLoad() {
835. 15 dbData = await dbCallAsync(
836. 15 jsbatonCreate("_dbFileLoad"),
837. 15 [
838. 15 // 0. sqlite3 * pInMemory
839. 15 db,
840. 15 // 1. char *zFilename
841. 15 filename,
842. 15 // 2. const int isSave
843. 15 modeSave,
844. 15 // 3. undefined
845. 15 undefined,
846. 15 // 4. dbData - same position as dbOpenAsync
847. 15 dbData
848. 15 ],
849. 15 "modeDb"
850. 15 );
851. 15 }
852. 1 if (modeNoop) {
853. 1 return;
854. 17 }
855. 17 if (IS_BROWSER) {
856. 1 filename = FILENAME_DBTMP;
857. 17 }
858. 17 assertOrThrow(
859. 17 typeof filename === "string" && filename,
860. 18 `invalid filename ${filename}`
861. 18 );
862. 18 // Save to tmpfile and then atomically-rename to actual-filename.
863. 15 if (moduleFs && modeSave) {
864. 13 filename2 = filename;
865. 13 filename = modulePath.join(
866. 13 modulePath.dirname(filename),
867. 13 `.dbFileSaveAsync.${moduleCrypto.randomUUID()}`
868. 13 );
869. 13 try {
870. 13 await _dbFileLoad();
871. 13 await moduleFs.promises.rename(filename, filename2);
872. 13 } finally {
873. 13 await moduleFs.promises.unlink(filename).catch(noop);
874. 13 }
875. 13 } else {
876. 2 await _dbFileLoad();
877. 15 }
878. 15 return dbData[1 + 0];
879. 15}
880. 1
881. 14async function dbFileSaveAsync({
882. 14 db,
883. 14 dbData,
884. 14 filename,
885. 14 modeNoop
886. 14}) {
887. 14
888. 14// This function will save <db> to <filename>.
889. 14
890. 14 return await dbFileLoadAsync({
891. 14 db,
892. 14 dbData,
893. 14 filename,
894. 14 modeNoop,
895. 14 modeSave: 1
896. 14 });
897. 14}
898. 1
899. 56async function dbNoopAsync(...argList) {
900. 56
901. 56// This function will do nothing except return <argList>.
902. 56
903. 56 return await dbCallAsync(jsbatonCreate("_dbNoop"), argList);
904. 56}
905. 1
906. 32async function dbOpenAsync({
907. 32 afterFinalization,
908. 32 dbData,
909. 32 filename,
910. 32 flags,
911. 32 threadCount = 1
912. 32}) {
913. 32
914. 32// This function will open and return sqlite-database-connection <db>.
915. 32
916. 32// int sqlite3_open_v2(
917. 32// const char *filename, /* Database filename (UTF-8) */
918. 32// sqlite3 **ppDb, /* OUT: SQLite db handle */
919. 32// int flags, /* Flags */
920. 32// const char *zVfs /* Name of VFS module to use */
921. 32// );
922. 32 let connPool;
923. 32 let db = {busy: 0, filename, ii: 0};
924. 32 let fileLgbm;
925. 32 assertOrThrow(typeof filename === "string", `invalid filename ${filename}`);
926. 32 assertOrThrow(
927. 1 !dbData || isExternalBuffer(dbData),
928. 32 "dbData must be ArrayBuffer"
929. 32 );
930. 32 connPool = await Promise.all(Array.from(new Array(
931. 32 threadCount
932. 31 ), async function () {
933. 31 let [ptr] = await dbCallAsync(
934. 31 jsbatonCreate("_dbOpen"),
935. 31 [
936. 31 // 0. const char *filename, Database filename (UTF-8)
937. 31 filename,
938. 31 // 1. sqlite3 **ppDb, OUT: SQLite db handle
939. 31 undefined,
940. 31 // 2. int flags, Flags
941. 31 flags ?? (
942. 31 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI
943. 31 ),
944. 31 // 3. const char *zVfs Name of VFS module to use
945. 31 undefined,
946. 31 // 4. wasm-only - arraybuffer of raw sqlite-database
947. 31 dbData
948. 31 ]
949. 31 );
950. 31 ptr = [ptr.getBigInt64(JSBATON_OFFSET_ARGV + 0, true)];
951. 31 dbFinalizationRegistry.register(db, {afterFinalization, ptr});
952. 31 return ptr;
953. 31 }));
954. 31 db.connPool = connPool;
955. 31 // init lightgbm
956. 31 if (!IS_BROWSER) {
957. 31 fileLgbm = process.platform;
958. 31 fileLgbm = fileLgbm.replace("darwin", "lib_lightgbm.dylib");
959. 31 fileLgbm = fileLgbm.replace("win32", "lib_lightgbm.dll");
960. 31 fileLgbm = fileLgbm.replace(process.platform, "lib_lightgbm.so");
961. 31 fileLgbm = `${import.meta.dirname}/sqlmath/${fileLgbm}`;
962. 31 await moduleFs.promises.access(fileLgbm).then(async function () {
963. 31 await dbExecAsync({
964. 31 db,
965. 31 sql: `SELECT lgbm_dlopen('${fileLgbm}');`
966. 31 });
967. 31 }).catch(noop);
968. 31 }
969. 31 return db;
970. 31}
971. 1
972. 47async function dbTableImportAsync({
973. 47 db,
974. 47 filename,
975. 47 headerMissing,
976. 47 mode,
977. 47 tableName,
978. 47 textData
979. 47}) {
980. 47// this function will create table from imported csv/json <textData>
981. 47 let colList;
982. 47 let rowList;
983. 47 let rowidList;
984. 47 let tmp;
985. 42 if (filename) {
986. 42 textData = await moduleFs.promises.readFile(filename, "utf8");
987. 42 }
988. 47 switch (mode) {
989. 2 case "csv":
990. 2 rowList = jsonRowListFromCsv({
991. 2 csv: textData
992. 2 });
993. 2 break;
994. 43 case "tsv":
995. 43 rowList = [];
996. 99001 textData.trimEnd().replace((/.+/g), function (line) {
997. 99001 rowList.push(line.split("\t"));
998. 99001 });
999. 43 break;
1000. 47 // case "json":
1001. 2 default:
1002. 2 rowList = JSON.parse(textData);
1003. 47 }
1004. 1 if (!(typeof rowList === "object" && rowList)) {
1005. 1 rowList = [];
1006. 1 }
1007. 47 // normalize rowList to list
1008. 1 if (!Array.isArray(rowList)) {
1009. 1 rowidList = [];
1010. 2 rowList = Object.entries(rowList).map(function ([
1011. 2 key, val
1012. 2 ]) {
1013. 2 rowidList.push(key);
1014. 2 return val;
1015. 2 });
1016. 1 }
1017. 47 // headerMissing
1018. 42 if (headerMissing && (rowList.length > 0 && Array.isArray(rowList[0]))) {
1019. 714 rowList.unshift(Array.from(rowList[0]).map(function (ignore, ii) {
1020. 714 return String(ii + 1);
1021. 714 }));
1022. 42 }
1023. 47 // normalize rowList[ii] to list
1024. 1 if (rowList.length === 0) {
1025. 1 rowList.push([
1026. 1 "undefined"
1027. 1 ]);
1028. 1 }
1029. 1 if (!Array.isArray(rowList[0])) {
1030. 1 colList = Array.from(
1031. 1 new Set(
1032. 2 rowList.map(function (obj) {
1033. 2 return Object.keys(obj);
1034. 2 }).flat()
1035. 1 )
1036. 1 );
1037. 2 rowList = rowList.map(function (obj) {
1038. 4 return colList.map(function (key) {
1039. 4 return obj[key];
1040. 4 });
1041. 2 });
1042. 1 rowList.unshift(colList);
1043. 1 }
1044. 47 // init colList
1045. 47 colList = rowList.shift();
1046. 47 // preserve rowid
1047. 1 if (rowidList) {
1048. 1 colList.unshift("rowid");
1049. 2 rowList.forEach(function (row, ii) {
1050. 2 row.unshift(rowidList[ii]);
1051. 2 });
1052. 1 }
1053. 47 // normalize colList
1054. 47 tmp = new Set();
1055. 723 colList = colList.map(function (colName) {
1056. 723 let colName2;
1057. 723 let duplicate = 0;
1058. 723 colName = colName.trim();
1059. 723 colName = colName.replace((/\W/g), "_");
1060. 723 colName = colName.replace((/^[^A-Z_a-z]|^$/gm), "_$&");
1061. 724 while (true) {
1062. 724 duplicate += 1;
1063. 724 colName2 = (
1064. 724 duplicate === 1
1065. 724 ? colName
1066. 724 : colName + "_" + duplicate
1067. 724 );
1068. 724 if (!tmp.has(colName2)) {
1069. 724 tmp.add(colName2);
1070. 724 return colName2;
1071. 724 }
1072. 724 }
1073. 723 });
1074. 47 // create dbtable from rowList
1075. 47 await dbExecAsync({
1076. 47 bindList: {
1077. 47 rowList: JSON.stringify(rowList)
1078. 47 },
1079. 47 db,
1080. 47 sql: (
1081. 47 rowList.length === 0
1082. 3 ? `CREATE TABLE ${tableName} (${colList.join(",")});`
1083. 44 : (
1084. 44 `CREATE TABLE ${tableName} AS SELECT `
1085. 719 + colList.map(function (colName, ii) {
1086. 719 return "value->>" + ii + " AS " + colName;
1087. 719 }).join(",")
1088. 44 + " FROM JSON_EACH($rowList);"
1089. 44 )
1090. 47 )
1091. 47 });
1092. 47}
1093. 1
1094. 2async function fsCopyFileUnlessTest(file1, file2, mode) {
1095. 2
1096. 2// This function will copy <file1> to <file2> unless <npm_config_mode_test> = 1.
1097. 2
1098. 1 if (npm_config_mode_test && mode !== "force") {
1099. 1 return;
1100. 1 }
1101. 1 await moduleFs.promises.copyFile(file1, file2, mode | 0);
1102. 1}
1103. 1
1104. 10async function fsExistsUnlessTest(file, mode) {
1105. 10
1106. 10// This function will test if <file> exists unless <npm_config_mode_test> = 1.
1107. 10
1108. 8 if (npm_config_mode_test && mode !== "force") {
1109. 8 return false;
1110. 8 }
1111. 2 try {
1112. 2 await moduleFs.promises.access(file);
1113. 1 return true;
1114. 1 } catch (ignore) {
1115. 1 return false;
1116. 1 }
1117. 10}
1118. 1
1119. 22async function fsReadFileUnlessTest(file, mode, defaultData) {
1120. 22
1121. 22// This function will read <data> from <file> unless <npm_config_mode_test> = 1.
1122. 22
1123. 8 if (npm_config_mode_test && mode !== "force") {
1124. 8 return defaultData;
1125. 14 }
1126. 14 return await moduleFs.promises.readFile(
1127. 14 file,
1128. 14 mode && mode.replace("force", "utf8")
1129. 22 );
1130. 22}
1131. 1
1132. 10async function fsWriteFileUnlessTest(file, data, mode) {
1133. 10
1134. 10// This function will write <data> to <file> unless <npm_config_mode_test> = 1.
1135. 10
1136. 9 if (npm_config_mode_test && mode !== "force") {
1137. 9 return;
1138. 9 }
1139. 1 await moduleFs.promises.writeFile(file, data);
1140. 1}
1141. 1
1142. 31function isExternalBuffer(buf) {
1143. 31
1144. 31// This function will check if <buf> is ArrayBuffer.
1145. 31
1146. 17 return buf && buf.constructor === ArrayBuffer;
1147. 31}
1148. 1
1149. 2061function jsbatonCreate(funcname) {
1150. 2061
1151. 2061// This function will create buffer <baton>.
1152. 2061
1153. 2061 let baton = new DataView(new ArrayBuffer(JSBATON_OFFSET_ALL));
1154. 2061 // init nallc, nused
1155. 2061 baton.setInt32(4, JSBATON_OFFSET_ALL, true);
1156. 2061 // copy funcname into baton
1157. 2061 new Uint8Array(
1158. 2061 baton.buffer,
1159. 2061 baton.byteOffset + JSBATON_OFFSET_FUNCNAME,
1160. 2061 SIZEOF_FUNCNAME - 1
1161. 2061 ).set(new TextEncoder().encode(funcname));
1162. 2061 return baton;
1163. 2061}
1164. 1
1165. 24function jsbatonGetInt64(baton, argi) {
1166. 24
1167. 24// This function will return int64-value from <baton> at <argi>.
1168. 24
1169. 24 return baton.getBigInt64(JSBATON_OFFSET_ARGV + argi * 8, true);
1170. 24}
1171. 1
1172. 9function jsbatonGetString(baton, argi) {
1173. 9
1174. 9// This function will return string-value from <baton> at <argi>.
1175. 9
1176. 9 let offset = baton.getInt32(JSBATON_OFFSET_ARGV + argi * 8, true);
1177. 9 return new TextDecoder().decode(new Uint8Array(
1178. 9 baton.buffer,
1179. 9 baton.byteOffset + offset + 1 + 4,
1180. 9 // remove null-terminator from string
1181. 9 baton.getInt32(offset + 1, true) - 1
1182. 9 ));
1183. 9}
1184. 1
1185. 5182function jsbatonSetValue(baton, argi, val, bufi, referenceList) {
1186. 5182
1187. 5182// This function will set <val> to buffer <baton>.
1188. 5182
1189. 5182 let nn;
1190. 5182 let nused;
1191. 5182 let tmp;
1192. 5182 let vsize;
1193. 5182 let vtype;
1194. 5182/*
1195. 5182#define SQLITE_DATATYPE_BLOB 0x04
1196. 5182#define SQLITE_DATATYPE_EXTERNALBUFFER 0x71
1197. 5182#define SQLITE_DATATYPE_FLOAT 0x02
1198. 5182#define SQLITE_DATATYPE_INTEGER 0x01
1199. 5182#define SQLITE_DATATYPE_INTEGER_0 0x00
1200. 5182#define SQLITE_DATATYPE_INTEGER_1 0x21
1201. 5182#define SQLITE_DATATYPE_NULL 0x05
1202. 5182#define SQLITE_DATATYPE_TEXT 0x03
1203. 5182#define SQLITE_DATATYPE_TEXT_0 0x13
1204. 5182 // 1. 0.bigint
1205. 5182 // 2. 0.boolean
1206. 5182 // 3. 0.function
1207. 5182 // 4. 0.number
1208. 5182 // 5. 0.object
1209. 5182 // 6. 0.string
1210. 5182 // 7. 0.symbol
1211. 5182 // 8. 0.undefined
1212. 5182 // 9. 1.bigint
1213. 5182 // 10. 1.boolean
1214. 5182 // 11. 1.function
1215. 5182 // 12. 1.number
1216. 5182 // 13. 1.object
1217. 5182 // 14. 1.string
1218. 5182 // 15. 1.symbol
1219. 5182 // 16. 1.undefined
1220. 5182 // 17. 1.buffer
1221. 5182 // 18. 1.externalbuffer
1222. 5182*/
1223. 5182 // 10. 1.boolean
1224. 5158 if (val === 1 || val === 1n) {
1225. 30 val = true;
1226. 30 }
1227. 5182 switch (
1228. 5182 val
1229. 4801 ? "1." + typeof(val)
1230. 381 : "0." + typeof(val)
1231. 5182 ) {
1232. 5182 // 1. 0.bigint
1233. 24 case "0.bigint":
1234. 5182 // 2. 0.boolean
1235. 30 case "0.boolean":
1236. 5182 // 4. 0.number
1237. 250 case "0.number":
1238. 250 if (Number.isNaN(val)) {
1239. 250 vtype = SQLITE_DATATYPE_NULL;
1240. 250 vsize = 0;
1241. 250 break;
1242. 250 }
1243. 250 vtype = SQLITE_DATATYPE_INTEGER_0;
1244. 250 vsize = 0;
1245. 250 break;
1246. 5182 // 3. 0.function
1247. 5182 // case "0.function":
1248. 5182 // 5. 0.object
1249. 98 case "0.object":
1250. 5182 // 7. 0.symbol
1251. 98 case "0.symbol":
1252. 5182 // 8. 0.undefined
1253. 105 case "0.undefined":
1254. 5182 // 11. 1.function
1255. 119 case "1.function":
1256. 5182 // 15. 1.symbol
1257. 125 case "1.symbol":
1258. 125 // 16. 1.undefined
1259. 125 // case "1.undefined":
1260. 125 vtype = SQLITE_DATATYPE_NULL;
1261. 125 vsize = 0;
1262. 125 break;
1263. 5182 // 6. 0.string
1264. 26 case "0.string":
1265. 26 vtype = SQLITE_DATATYPE_TEXT_0;
1266. 26 vsize = 0;
1267. 26 break;
1268. 5182 // 9. 1.bigint
1269. 42 case "1.bigint":
1270. 42 vtype = SQLITE_DATATYPE_INTEGER;
1271. 42 vsize = 8;
1272. 42 break;
1273. 5182 // 10. 1.boolean
1274. 36 case "1.boolean":
1275. 36 vtype = SQLITE_DATATYPE_INTEGER_1;
1276. 36 vsize = 0;
1277. 36 break;
1278. 5182 // 12. 1.number
1279. 561 case "1.number":
1280. 561 vtype = SQLITE_DATATYPE_FLOAT;
1281. 561 vsize = 8;
1282. 561 break;
1283. 5182 // 14. 1.string
1284. 4060 case "1.string":
1285. 4060 val = new TextEncoder().encode(val);
1286. 4060 vtype = SQLITE_DATATYPE_TEXT;
1287. 4060 vsize = 4 + val.byteLength;
1288. 4060 break;
1289. 5182 // 13. 1.object
1290. 82 default:
1291. 82 // 18. 1.externalbuffer
1292. 82 if (val.constructor === ArrayBuffer) {
1293. 82 assertOrThrow(
1294. 82 !IS_BROWSER,
1295. 82 "external ArrayBuffer cannot be passed directly to wasm"
1296. 82 );
1297. 82 vtype = SQLITE_DATATYPE_EXTERNALBUFFER;
1298. 82 vsize = 4;
1299. 82 break;
1300. 82 }
1301. 82 // 17. 1.buffer
1302. 82 if (ArrayBuffer.isView(val)) {
1303. 82 if (val.byteLength === 0) {
1304. 82 vtype = SQLITE_DATATYPE_NULL;
1305. 82 vsize = 0;
1306. 82 break;
1307. 82 }
1308. 82 vtype = SQLITE_DATATYPE_BLOB;
1309. 82 vsize = 4 + val.byteLength;
1310. 82 break;
1311. 82 }
1312. 82 // 13. 1.object
1313. 82 val = new TextEncoder().encode(
1314. 82 typeof val.toJSON === "function"
1315. 82 ? val.toJSON()
1316. 82 : JSON.stringify(val)
1317. 82 );
1318. 82 vtype = SQLITE_DATATYPE_TEXT;
1319. 82 vsize = 4 + val.byteLength;
1320. 5182 }
1321. 5182 nused = baton.getInt32(4, true);
1322. 5182 nn = nused + 1 + vsize;
1323. 5182 assertOrThrow(
1324. 5182 nn <= 0xffff_ffff,
1325. 5182 "jsbaton cannot exceed 0x7fff_ffff / 2,147,483,647 bytes"
1326. 5182 );
1327. 5182 // exponentially grow baton as needed
1328. 2164 if (baton.byteLength < nn) {
1329. 2164 tmp = baton;
1330. 2164 baton = new DataView(new ArrayBuffer(
1331. 2164 Math.min(2 ** Math.ceil(Math.log2(nn)), 0x7fff_ffff)
1332. 2164 ));
1333. 2164 // update nallc
1334. 2164 baton.setInt32(0, baton.byteLength, true);
1335. 2164 // copy old-baton into new-baton
1336. 2164 new Uint8Array(baton.buffer, baton.byteOffset, nused).set(
1337. 2164 new Uint8Array(tmp.buffer, tmp.byteOffset, nused)
1338. 2164 );
1339. 2164 }
1340. 5182 // push vtype - 1-byte
1341. 5182 baton.setUint8(nused, vtype);
1342. 5182 // update nused
1343. 5182 baton.setInt32(4, nused + 1 + vsize, true);
1344. 5182 // handle blob-value
1345. 5182 switch (vtype) {
1346. 30 case SQLITE_DATATYPE_BLOB:
1347. 4118 case SQLITE_DATATYPE_TEXT:
1348. 4118 // set argv[ii] to blob/text location
1349. 4118 if (argi !== undefined) {
1350. 4118 baton.setInt32(JSBATON_OFFSET_ARGV + argi * 8, nused, true);
1351. 4118 }
1352. 4118 vsize -= 4;
1353. 4118 assertOrThrow(
1354. 4118 0 <= vsize && vsize <= SIZEOF_BLOB_MAX,
1355. 4118 (
1356. 4118 "sqlite-blob byte-length must be within inclusive-range"
1357. 4118 + ` 0 to ${SIZEOF_BLOB_MAX}`
1358. 4118 )
1359. 4118 );
1360. 4118 // push vsize - 4-byte
1361. 4118 baton.setInt32(nused + 1, vsize, true);
1362. 4118 // push SQLITE-BLOB/TEXT - vsize-byte
1363. 4118 new Uint8Array(
1364. 4118 baton.buffer,
1365. 4118 baton.byteOffset + nused + 1 + 4,
1366. 4118 vsize
1367. 4118 ).set(new Uint8Array(val.buffer, val.byteOffset, vsize));
1368. 4118 break;
1369. 12 case SQLITE_DATATYPE_EXTERNALBUFFER:
1370. 12 vsize = val.byteLength;
1371. 12 assertOrThrow(
1372. 12 0 <= vsize && vsize <= SIZEOF_BLOB_MAX,
1373. 12 (
1374. 12 "sqlite-blob byte-length must be within inclusive-range"
1375. 12 + ` 0 to ${SIZEOF_BLOB_MAX}`
1376. 12 )
1377. 12 );
1378. 12 assertOrThrow(
1379. 12 bufi[0] < JSBATON_ARGC,
1380. 12 `cannot pass more than ${JSBATON_ARGC} arraybuffers`
1381. 12 );
1382. 12 // push externalbuffer - 4-byte
1383. 12 baton.setInt32(nused + 1, bufi[0], true);
1384. 12 // set buffer
1385. 12 cModule._jsbatonSetArraybuffer(baton.buffer, bufi[0], val);
1386. 12 // increment bufi
1387. 12 bufi[0] += 1;
1388. 12 // add buffer to reference_list to prevent gc during db_call.
1389. 12 referenceList.push(val);
1390. 12 break;
1391. 561 case SQLITE_DATATYPE_FLOAT:
1392. 561 // push SQLITE-REAL - 8-byte
1393. 561 baton.setFloat64(nused + 1, val, true);
1394. 561 break;
1395. 42 case SQLITE_DATATYPE_INTEGER:
1396. 42 assertInt64(val);
1397. 42 // push SQLITE-INTEGER - 8-byte
1398. 42 baton.setBigInt64(nused + 1, val, true);
1399. 42 break;
1400. 5170 }
1401. 5170 return baton;
1402. 5170}
1403. 1
1404. 1752function jsonParseArraybuffer(buf) {
1405. 1752
1406. 1752// This function will JSON.parse arraybuffer <buf>.
1407. 1752
1408. 1752 return JSON.parse(
1409. 1752 (
1410. 1752 IS_BROWSER
1411. 1 ? new TextDecoder().decode(buf)
1412. 1751 : buf
1413. 1752 )
1414. 1 || "null"
1415. 1752 );
1416. 1752}
1417. 1
1418. 2function jsonRowListFromCsv({
1419. 2 csv
1420. 2}) {
1421. 2// this function will convert <csv>-text to json list-of-list
1422. 2//
1423. 2// https://tools.ietf.org/html/rfc4180#section-2
1424. 2// Definition of the CSV Format
1425. 2// While there are various specifications and implementations for the
1426. 2// CSV format (for ex. [4], [5], [6] and [7]), there is no formal
1427. 2// specification in existence, which allows for a wide variety of
1428. 2// interpretations of CSV files. This section documents the format that
1429. 2// seems to be followed by most implementations:
1430. 2//
1431. 2// 1. Each record is located on a separate line, delimited by a line
1432. 2// break (CRLF). For example:
1433. 2// aaa,bbb,ccc CRLF
1434. 2// zzz,yyy,xxx CRLF
1435. 2//
1436. 2// 2. The last record in the file may or may not have an ending line
1437. 2// break. For example:
1438. 2// aaa,bbb,ccc CRLF
1439. 2// zzz,yyy,xxx
1440. 2//
1441. 2// 3. There maybe an optional header line appearing as the first line
1442. 2// of the file with the same format as normal record lines. This
1443. 2// header will contain names corresponding to the fields in the file
1444. 2// and should contain the same number of fields as the records in
1445. 2// the rest of the file (the presence or absence of the header line
1446. 2// should be indicated via the optional "header" parameter of this
1447. 2// MIME type). For example:
1448. 2// field_name,field_name,field_name CRLF
1449. 2// aaa,bbb,ccc CRLF
1450. 2// zzz,yyy,xxx CRLF
1451. 2//
1452. 2// 4. Within the header and each record, there may be one or more
1453. 2// fields, separated by commas. Each line should contain the same
1454. 2// number of fields throughout the file. Spaces are considered part
1455. 2// of a field and should not be ignored. The last field in the
1456. 2// record must not be followed by a comma. For example:
1457. 2// aaa,bbb,ccc
1458. 2//
1459. 2// 5. Each field may or may not be enclosed in double quotes (however
1460. 2// some programs, such as Microsoft Excel, do not use double quotes
1461. 2// at all). If fields are not enclosed with double quotes, then
1462. 2// double quotes may not appear inside the fields. For example:
1463. 2// "aaa","bbb","ccc" CRLF
1464. 2// zzz,yyy,xxx
1465. 2//
1466. 2// 6. Fields containing line breaks (CRLF), double quotes, and commas
1467. 2// should be enclosed in double-quotes. For example:
1468. 2// "aaa","b CRLF
1469. 2// bb","ccc" CRLF
1470. 2// zzz,yyy,xxx
1471. 2//
1472. 2// 7. If double-quotes are used to enclose fields, then a double-quote
1473. 2// appearing inside a field must be escaped by preceding it with
1474. 2// another double quote. For example:
1475. 2// "aaa","b""bb","ccc"
1476. 2 let match;
1477. 2 let quote;
1478. 2 let rgx;
1479. 2 let row;
1480. 2 let rowList;
1481. 2 let val;
1482. 2 // normalize "\r\n" to "\n"
1483. 2 csv = csv.trimEnd().replace((
1484. 2 /\r\n?/gu
1485. 2 ), "\n") + "\n";
1486. 2 rgx = (
1487. 2 /(.*?)(""|"|,|\n)/gu
1488. 2 );
1489. 2 rowList = [];
1490. 2 // reset row
1491. 2 row = [];
1492. 2 val = "";
1493. 28 while (true) {
1494. 28 match = rgx.exec(csv);
1495. 28 if (!match) {
1496. 28// 2. The last record in the file may or may not have an ending line
1497. 28// break. For example:
1498. 28// aaa,bbb,ccc CRLF
1499. 28// zzz,yyy,xxx
1500. 28 if (!row.length) {
1501. 28 break;
1502. 28 }
1503. 28 // // if eof missing crlf, then mock it
1504. 28 // rgx.lastIndex = csv.length;
1505. 28 // match = [
1506. 28 // "\n", "", "\n"
1507. 28 // ];
1508. 28 }
1509. 28 // build val
1510. 28 val += match[1];
1511. 28 if (match[2] === "\"") {
1512. 28// 5. Each field may or may not be enclosed in double quotes (however
1513. 28// some programs, such as Microsoft Excel, do not use double quotes
1514. 28// at all). If fields are not enclosed with double quotes, then
1515. 28// double quotes may not appear inside the fields. For example:
1516. 28// "aaa","bbb","ccc" CRLF
1517. 28// zzz,yyy,xxx
1518. 28 quote = !quote;
1519. 28 } else if (quote) {
1520. 28// 7. If double-quotes are used to enclose fields, then a double-quote
1521. 28// appearing inside a field must be escaped by preceding it with
1522. 28// another double quote. For example:
1523. 28// "aaa","b""bb","ccc"
1524. 28 if (match[2] === "\"\"") {
1525. 28 val += "\"";
1526. 28// 6. Fields containing line breaks (CRLF), double quotes, and commas
1527. 28// should be enclosed in double-quotes. For example:
1528. 28// "aaa","b CRLF
1529. 28// bb","ccc" CRLF
1530. 28// zzz,yyy,xxx
1531. 28 } else {
1532. 28 val += match[2];
1533. 28 }
1534. 28 } else if (match[2] === ",") {
1535. 28// 4. Within the header and each record, there may be one or more
1536. 28// fields, separated by commas. Each line should contain the same
1537. 28// number of fields throughout the file. Spaces are considered part
1538. 28// of a field and should not be ignored. The last field in the
1539. 28// record must not be followed by a comma. For example:
1540. 28// aaa,bbb,ccc
1541. 28 // delimit val
1542. 28 row.push(val);
1543. 28 val = "";
1544. 28 } else if (match[2] === "\n") {
1545. 28// 1. Each record is located on a separate line, delimited by a line
1546. 28// break (CRLF). For example:
1547. 28// aaa,bbb,ccc CRLF
1548. 28// zzz,yyy,xxx CRLF
1549. 28 // delimit val
1550. 28 row.push(val);
1551. 28 val = "";
1552. 28 // append row
1553. 28 rowList.push(row);
1554. 28 // reset row
1555. 28 row = [];
1556. 28 }
1557. 28 }
1558. 2 // // append val
1559. 2 // if (val) {
1560. 2 // row.push(val);
1561. 2 // }
1562. 2 // // append row
1563. 2 // if (row.length) {
1564. 2 // rowList.push(row);
1565. 2 // }
1566. 2 return rowList;
1567. 2}
1568. 1
1569. 1function listOrEmptyList(list) {
1570. 1
1571. 1// This function will return <list> or empty-list if falsy.
1572. 1
1573. 1 return list || [];
1574. 1}
1575. 1
1576. 8async function moduleFsInit() {
1577. 8
1578. 8// This function will import nodejs builtin-modules if they have not yet been
1579. 8// imported.
1580. 8
1581. 8// State 3 - Modules already imported.
1582. 8
1583. 6 if (moduleFs !== undefined) {
1584. 6 return;
1585. 6 }
1586. 2
1587. 2// State 2 - Wait while modules are importing.
1588. 2
1589. 2 if (moduleFsInitResolveList !== undefined) {
1590. 1 return new Promise(function (resolve) {
1591. 1 moduleFsInitResolveList.push(resolve);
1592. 1 });
1593. 1 }
1594. 1
1595. 1// State 1 - Start importing modules.
1596. 1
1597. 1 moduleFsInitResolveList = [];
1598. 1 [
1599. 1 moduleChildProcess,
1600. 1 moduleCrypto,
1601. 1 moduleFs,
1602. 1 modulePath,
1603. 1 moduleUrl
1604. 1 ] = await Promise.all([
1605. 1 import("child_process"),
1606. 1 import("crypto"),
1607. 1 import("fs"),
1608. 1 import("path"),
1609. 1 import("url")
1610. 1 ]);
1611. 1 while (moduleFsInitResolveList.length > 0) {
1612. 1 moduleFsInitResolveList.shift()();
1613. 1 }
1614. 1 SQLMATH_NODE = `_sqlmath.napi6_${process.platform}_${process.arch}.node`;
1615. 1 SQLMATH_EXE = (
1616. 1 SQLMATH_NODE.replace((/\.node$/), "")
1617. 1 + process.platform.replace(
1618. 1 "win32",
1619. 1 ".exe"
1620. 1 ).replace(
1621. 1 process.platform,
1622. 1 ""
1623. 1 )
1624. 1 );
1625. 1}
1626. 1
1627. 264function noop(val) {
1628. 264
1629. 264// This function will do nothing except return <val>.
1630. 264
1631. 264 return val;
1632. 264}
1633. 1
1634. 42774function objectDeepCopyWithKeysSorted(obj) {
1635. 42774
1636. 42774// This function will recursively deep-copy <obj> with keys sorted.
1637. 42774
1638. 42774 let sorted;
1639. 28326 if (typeof obj !== "object" || !obj) {
1640. 28326 return obj;
1641. 28326 }
1642. 14448
1643. 14448// Recursively deep-copy list with child-keys sorted.
1644. 14448
1645. 14448 if (Array.isArray(obj)) {
1646. 2202 return obj.map(objectDeepCopyWithKeysSorted);
1647. 12246 }
1648. 12246
1649. 12246// Recursively deep-copy obj with keys sorted.
1650. 12246
1651. 12246 sorted = Object.create(null);
1652. 13714 Object.keys(obj).sort().forEach(function (key) {
1653. 13714 sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
1654. 13714 });
1655. 12246 return sorted;
1656. 12246}
1657. 1
1658. 3async function sqlmathInit() {
1659. 3
1660. 3// This function will init sqlmath.
1661. 3
1662. 3 let moduleModule;
1663. 3 dbFinalizationRegistry = (
1664. 3 dbFinalizationRegistry
1665. 28 ) || new FinalizationRegistry(function ({afterFinalization, ptr}) {
1666. 28
1667. 28// This function will auto-close any open sqlite3-db-pointer,
1668. 28// after its js-wrapper has been garbage-collected.
1669. 28
1670. 28 dbCallAsync(jsbatonCreate("_dbClose"), [ptr[0]]);
1671. 1 if (afterFinalization) {
1672. 1 afterFinalization();
1673. 1 }
1674. 28 });
1675. 3
1676. 3// Feature-detect nodejs.
1677. 3
1678. 3 if (
1679. 3 typeof process !== "object"
1680. 3 || typeof process?.versions?.node !== "string"
1681. 3 || cModule
1682. 1 ) {
1683. 1 return;
1684. 2 }
1685. 2
1686. 2// Init moduleFs.
1687. 2
1688. 2 await moduleFsInit();
1689. 2 moduleFsInit(); // coverage-hack
1690. 2 moduleChildProcessSpawn = moduleChildProcess.spawn;
1691. 2
1692. 2// Init moduleFs.
1693. 2
1694. 2 await moduleFsInit();
1695. 2 moduleFsInit(); // coverage-hack
1696. 2 moduleChildProcessSpawn = moduleChildProcess.spawn;
1697. 2 cModulePath = moduleUrl.fileURLToPath(import.meta.url).replace(
1698. 2 (/\bsqlmath\.mjs$/),
1699. 2 SQLMATH_NODE
1700. 2 );
1701. 2
1702. 2// Import napi c-addon.
1703. 2
1704. 2 if (!npm_config_mode_setup) {
1705. 2 moduleModule = await import("module");
1706. 2 if (!cModule) {
1707. 2 cModule = moduleModule.createRequire(cModulePath);
1708. 2 cModule = cModule(cModulePath);
1709. 2 }
1710. 2 }
1711. 2 if (npm_config_mode_test) {
1712. 2
1713. 2// Mock consoleError.
1714. 2
1715. 2 consoleError = noop;
1716. 2
1717. 2// Mock moduleChildProcessSpawn.
1718. 2
1719. 15 moduleChildProcessSpawn = function () {
1720. 15 let child = {
1721. 15 end: noop,
1722. 17 on: function (onType, resolve) {
1723. 17 switch (onType) {
1724. 2 case "data":
1725. 2 resolve(Buffer.alloc(0));
1726. 2 return;
1727. 15 default:
1728. 15 resolve(0);
1729. 17 }
1730. 17 },
1731. 15 setEncoding: noop,
1732. 15 write: noop
1733. 15 };
1734. 15 child.stderr = child;
1735. 15 child.stdin = child;
1736. 15 child.stdout = child;
1737. 15 return child;
1738. 15 };
1739. 2 }
1740. 3}
1741. 1
1742. 1function sqlmathWebworkerInit({
1743. 1 db,
1744. 1 modeTest
1745. 1}) {
1746. 1
1747. 1// This function will init sqlmath web-worker.
1748. 1
1749. 1// Feature-detect browser.
1750. 1
1751. 1 let Worker = globalThis.Worker;
1752. 1 IS_BROWSER = true;
1753. 1 if (modeTest) {
1754. 1 Worker = function () {
1755. 1 return;
1756. 1 };
1757. 1 }
1758. 1 sqlWorker = new Worker("sqlmath_wasm.js");
1759. 2 sqlWorker.onmessage = function ({
1760. 2 data
1761. 2 }) {
1762. 2 sqlMessageDict[data.id](data);
1763. 2 };
1764. 1 if (modeTest) {
1765. 2 sqlWorker.postMessage = function (data) {
1766. 2 setTimeout(function () {
1767. 2 sqlWorker.onmessage({data});
1768. 2 });
1769. 2 };
1770. 1 // test dbCallAsync handling-behavior
1771. 1 dbCallAsync(jsbatonCreate("testTimeElapsed"), [true]);
1772. 1 // test dbFileLoadAsync handling-behavior
1773. 1 dbFileLoadAsync({db, filename: "aa", modeTest});
1774. 1 // test jsonParseArraybuffer handling-behavior
1775. 1 jsonParseArraybuffer(new TextEncoder().encode("0"));
1776. 1 // revert IS_BROWSER
1777. 1 IS_BROWSER = undefined;
1778. 1 }
1779. 1}
1780. 1
1781. 1function waitAsync(timeout) {
1782. 1
1783. 1// This function will wait <timeout> ms.
1784. 1
1785. 1 return new Promise(function (resolve) {
1786. 1 setTimeout(resolve, timeout * !npm_config_mode_test);
1787. 1 });
1788. 1}
1789. 1
1790. 1sqlmathInit(); // coverage-hack
1791. 1await sqlmathInit();
1792. 1sqlmathInit(); // coverage-hack
1793. 1
1794. 1export {
1795. 1 LGBM_DTYPE_FLOAT32,
1796. 1 LGBM_DTYPE_FLOAT64,
1797. 1 LGBM_DTYPE_INT32,
1798. 1 LGBM_DTYPE_INT64,
1799. 1 LGBM_FEATURE_IMPORTANCE_GAIN,
1800. 1 LGBM_FEATURE_IMPORTANCE_SPLIT,
1801. 1 LGBM_MATRIX_TYPE_CSC,
1802. 1 LGBM_MATRIX_TYPE_CSR,
1803. 1 LGBM_PREDICT_CONTRIB,
1804. 1 LGBM_PREDICT_LEAF_INDEX,
1805. 1 LGBM_PREDICT_NORMAL,
1806. 1 LGBM_PREDICT_RAW_SCORE,
1807. 1 SQLITE_OPEN_AUTOPROXY,
1808. 1 SQLITE_OPEN_CREATE,
1809. 1 SQLITE_OPEN_DELETEONCLOSE,
1810. 1 SQLITE_OPEN_EXCLUSIVE,
1811. 1 SQLITE_OPEN_FULLMUTEX,
1812. 1 SQLITE_OPEN_MAIN_DB,
1813. 1 SQLITE_OPEN_MAIN_JOURNAL,
1814. 1 SQLITE_OPEN_MEMORY,
1815. 1 SQLITE_OPEN_NOFOLLOW,
1816. 1 SQLITE_OPEN_NOMUTEX,
1817. 1 SQLITE_OPEN_PRIVATECACHE,
1818. 1 SQLITE_OPEN_READONLY,
1819. 1 SQLITE_OPEN_READWRITE,
1820. 1 SQLITE_OPEN_SHAREDCACHE,
1821. 1 SQLITE_OPEN_SUBJOURNAL,
1822. 1 SQLITE_OPEN_SUPER_JOURNAL,
1823. 1 SQLITE_OPEN_TEMP_DB,
1824. 1 SQLITE_OPEN_TEMP_JOURNAL,
1825. 1 SQLITE_OPEN_TRANSIENT_DB,
1826. 1 SQLITE_OPEN_URI,
1827. 1 SQLITE_OPEN_WAL,
1828. 1 SQLMATH_EXE,
1829. 1 SQLMATH_NODE,
1830. 1 assertErrorThrownAsync,
1831. 1 assertInt64,
1832. 1 assertJsonEqual,
1833. 1 assertNumericalEqual,
1834. 1 assertOrThrow,
1835. 1 childProcessSpawn2,
1836. 1 ciBuildExt,
1837. 1 dbCloseAsync,
1838. 1 dbExecAndReturnLastBlob,
1839. 1 dbExecAndReturnLastRow,
1840. 1 dbExecAndReturnLastTable,
1841. 1 dbExecAndReturnLastValue,
1842. 1 dbExecAsync,
1843. 1 dbFileLoadAsync,
1844. 1 dbFileSaveAsync,
1845. 1 dbNoopAsync,
1846. 1 dbOpenAsync,
1847. 1 dbTableImportAsync,
1848. 1 debugInline,
1849. 1 fsCopyFileUnlessTest,
1850. 1 fsExistsUnlessTest,
1851. 1 fsReadFileUnlessTest,
1852. 1 fsWriteFileUnlessTest,
1853. 1 jsbatonGetInt64,
1854. 1 jsbatonGetString,
1855. 1 listOrEmptyList,
1856. 1 noop,
1857. 1 objectDeepCopyWithKeysSorted,
1858. 1 sqlmathWebworkerInit,
1859. 1 version,
1860. 1 waitAsync
1861. 1};
1862. 1