V8 Coverage Report
Files covered Lines Remaining
. / sqlmath.mjs
100.00 %
2086 / 2086

0 / 2086
    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.   1437    result.sort(function (aa, bb) {
 1090.    423        return ((bb.timeElapsed - aa.timeElapsed) || (bb.count - aa.count));
 1091.   1437    });
 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