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