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