13961b263Sstephan/*
23961b263Sstephan  2022-05-22
33961b263Sstephan
43961b263Sstephan  The author disclaims copyright to this source code.  In place of a
53961b263Sstephan  legal notice, here is a blessing:
63961b263Sstephan
73961b263Sstephan  *   May you do good and not evil.
83961b263Sstephan  *   May you find forgiveness for yourself and forgive others.
93961b263Sstephan  *   May you share freely, never taking more than you give.
103961b263Sstephan
113961b263Sstephan  ***********************************************************************
123961b263Sstephan
133961b263Sstephan  This file is intended to be combined at build-time with other
143961b263Sstephan  related code, most notably a header and footer which wraps this whole
153961b263Sstephan  file into an Emscripten Module.postRun() handler which has a parameter
163961b263Sstephan  named "Module" (the Emscripten Module object). The exact requirements,
173961b263Sstephan  conventions, and build process are very much under construction and
183961b263Sstephan  will be (re)documented once they've stopped fluctuating so much.
193961b263Sstephan
20c0a18d6aSstephan  Project home page: https://sqlite.org
21c0a18d6aSstephan
22c0a18d6aSstephan  Documentation home page: https://sqlite.org/wasm
23c0a18d6aSstephan
24c0a18d6aSstephan  Specific goals of this subproject:
253961b263Sstephan
263961b263Sstephan  - Except where noted in the non-goals, provide a more-or-less
273961b263Sstephan    feature-complete wrapper to the sqlite3 C API, insofar as WASM
28c0a18d6aSstephan    feature parity with C allows for. In fact, provide at least 4
293961b263Sstephan    APIs...
303961b263Sstephan
31c0a18d6aSstephan    1) 1-to-1 bindings as exported from WASM, with no automatic
32c0a18d6aSstephan       type conversions between JS and C.
333961b263Sstephan
34c0a18d6aSstephan    2) A binding of (1) which provides certain JS/C type conversions
35c0a18d6aSstephan       to greatly simplify its use.
36c0a18d6aSstephan
37c0a18d6aSstephan    3) A higher-level API, more akin to sql.js and node.js-style
383961b263Sstephan       implementations. This one speaks directly to the low-level
393961b263Sstephan       API. This API must be used from the same thread as the
403961b263Sstephan       low-level API.
413961b263Sstephan
42c0a18d6aSstephan    4) A second higher-level API which speaks to the previous APIs via
433961b263Sstephan       worker messages. This one is intended for use in the main
443961b263Sstephan       thread, with the lower-level APIs installed in a Worker thread,
453961b263Sstephan       and talking to them via Worker messages. Because Workers are
463961b263Sstephan       asynchronouns and have only a single message channel, some
473961b263Sstephan       acrobatics are needed here to feed async work results back to
483961b263Sstephan       the client (as we cannot simply pass around callbacks between
493961b263Sstephan       the main and Worker threads).
503961b263Sstephan
513961b263Sstephan  - Insofar as possible, support client-side storage using JS
523961b263Sstephan    filesystem APIs. As of this writing, such things are still very
535b915007Sstephan    much under development.
543961b263Sstephan
553961b263Sstephan  Specific non-goals of this project:
563961b263Sstephan
573961b263Sstephan  - As WASM is a web-centric technology and UTF-8 is the King of
583961b263Sstephan    Encodings in that realm, there are no currently plans to support
593961b263Sstephan    the UTF16-related sqlite3 APIs. They would add a complication to
603961b263Sstephan    the bindings for no appreciable benefit. Though web-related
615b915007Sstephan    implementation details take priority, and the JavaScript
625b915007Sstephan    components of the API specifically focus on browser clients, the
635b915007Sstephan    lower-level WASM module "should" work in non-web WASM
645b915007Sstephan    environments.
653961b263Sstephan
663961b263Sstephan  - Supporting old or niche-market platforms. WASM is built for a
673961b263Sstephan    modern web and requires modern platforms.
683961b263Sstephan
693961b263Sstephan  - Though scalar User-Defined Functions (UDFs) may be created in
703961b263Sstephan    JavaScript, there are currently no plans to add support for
713961b263Sstephan    aggregate and window functions.
723961b263Sstephan
733961b263Sstephan  Attribution:
743961b263Sstephan
753961b263Sstephan  This project is endebted to the work of sql.js:
763961b263Sstephan
773961b263Sstephan  https://github.com/sql-js/sql.js
783961b263Sstephan
793961b263Sstephan  sql.js was an essential stepping stone in this code's development as
803961b263Sstephan  it demonstrated how to handle some of the WASM-related voodoo (like
813961b263Sstephan  handling pointers-to-pointers and adding JS implementations of
823961b263Sstephan  C-bound callback functions). These APIs have a considerably
833961b263Sstephan  different shape than sql.js's, however.
843961b263Sstephan*/
853961b263Sstephan
863961b263Sstephan/**
875b915007Sstephan   sqlite3ApiBootstrap() is the only global symbol persistently
885b915007Sstephan   exposed by this API. It is intended to be called one time at the
895b915007Sstephan   end of the API amalgamation process, passed configuration details
905b915007Sstephan   for the current environment, and then optionally be removed from
915b915007Sstephan   the global object using `delete self.sqlite3ApiBootstrap`.
923961b263Sstephan
93e3cd6760Sstephan   This function expects a configuration object, intended to abstract
943961b263Sstephan   away details specific to any given WASM environment, primarily so
95e3cd6760Sstephan   that it can be used without any _direct_ dependency on
965b915007Sstephan   Emscripten. (Note the default values for the config object!) The
975b915007Sstephan   config object is only honored the first time this is
985b915007Sstephan   called. Subsequent calls ignore the argument and return the same
99e3cd6760Sstephan   (configured) object which gets initialized by the first call.
100c0a18d6aSstephan   This function will throw if any of the required config options are
101c0a18d6aSstephan   missing.
102e3cd6760Sstephan
103e3cd6760Sstephan   The config object properties include:
104e3cd6760Sstephan
1059a34509aSstephan   - `exports`[^1]: the "exports" object for the current WASM
106c0a18d6aSstephan     environment. In an Emscripten-based build, this should be set to
107e3cd6760Sstephan     `Module['asm']`.
108e3cd6760Sstephan
1099a34509aSstephan   - `memory`[^1]: optional WebAssembly.Memory object, defaulting to
110e3cd6760Sstephan     `exports.memory`. In Emscripten environments this should be set
111e3cd6760Sstephan     to `Module.wasmMemory` if the build uses `-sIMPORT_MEMORY`, or be
112e3cd6760Sstephan     left undefined/falsy to default to `exports.memory` when using
113e3cd6760Sstephan     WASM-exported memory.
114e3cd6760Sstephan
115e3cd6760Sstephan   - `bigIntEnabled`: true if BigInt support is enabled. Defaults to
116c0a18d6aSstephan     true if `self.BigInt64Array` is available, else false. Some APIs
117e3cd6760Sstephan     will throw exceptions if called without BigInt support, as BigInt
118e3cd6760Sstephan     is required for marshalling C-side int64 into and out of JS.
119e3cd6760Sstephan
120e3cd6760Sstephan   - `allocExportName`: the name of the function, in `exports`, of the
121e3cd6760Sstephan     `malloc(3)`-compatible routine for the WASM environment. Defaults
122e3cd6760Sstephan     to `"malloc"`.
123e3cd6760Sstephan
124e3cd6760Sstephan   - `deallocExportName`: the name of the function, in `exports`, of
125e3cd6760Sstephan     the `free(3)`-compatible routine for the WASM
126e3cd6760Sstephan     environment. Defaults to `"free"`.
127e3cd6760Sstephan
128c0a18d6aSstephan   - `wasmfsOpfsDir`[^1]: if the environment supports persistent
129c0a18d6aSstephan     storage, this directory names the "mount point" for that
130c0a18d6aSstephan     directory. It must be prefixed by `/` and may contain only a
131c0a18d6aSstephan     single directory-name part. Using the root directory name is not
132c0a18d6aSstephan     supported by any current persistent backend.  This setting is
133c0a18d6aSstephan     only used in WASMFS-enabled builds.
1343961b263Sstephan
1359a34509aSstephan
1369a34509aSstephan   [^1] = This property may optionally be a function, in which case this
1379a34509aSstephan          function re-assigns it to the value returned from that function,
1389a34509aSstephan          enabling delayed evaluation.
1399a34509aSstephan
1409a34509aSstephan*/
1419a34509aSstephan'use strict';
1429a34509aSstephanself.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
1435b915007Sstephan  apiConfig = (self.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig)
1449a34509aSstephan){
145e3cd6760Sstephan  if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */
146e3cd6760Sstephan    console.warn("sqlite3ApiBootstrap() called multiple times.",
147e3cd6760Sstephan                 "Config and external initializers are ignored on calls after the first.");
148e3cd6760Sstephan    return sqlite3ApiBootstrap.sqlite3;
149e3cd6760Sstephan  }
15092ede964Sstephan  const config = Object.assign(Object.create(null),{
151e3cd6760Sstephan    exports: undefined,
152e3cd6760Sstephan    memory: undefined,
1536110a5d0Sstephan    bigIntEnabled: (()=>{
15460d9aa7cSstephan      if('undefined'!==typeof Module){
155eb97743cSstephan        /* Emscripten module will contain HEAPU64 when built with
15660d9aa7cSstephan           -sWASM_BIGINT=1, else it will not. */
15760d9aa7cSstephan        return !!Module.HEAPU64;
15860d9aa7cSstephan      }
1596110a5d0Sstephan      return !!self.BigInt64Array;
1606110a5d0Sstephan    })(),
161e3cd6760Sstephan    allocExportName: 'malloc',
162e3cd6760Sstephan    deallocExportName: 'free',
1633d645484Sstephan    wasmfsOpfsDir: '/opfs'
16492ede964Sstephan  }, apiConfig || {});
165e3cd6760Sstephan
1669a34509aSstephan  [
1679a34509aSstephan    // If any of these config options are functions, replace them with
1689a34509aSstephan    // the result of calling that function...
169eb97743cSstephan    'exports', 'memory', 'wasmfsOpfsDir'
1709a34509aSstephan  ].forEach((k)=>{
1719a34509aSstephan    if('function' === typeof config[k]){
1729a34509aSstephan      config[k] = config[k]();
1739a34509aSstephan    }
1749a34509aSstephan  });
1759a34509aSstephan
1761acfe915Sstephan  /**
1771acfe915Sstephan      The main sqlite3 binding API gets installed into this object,
1781acfe915Sstephan      mimicking the C API as closely as we can. The numerous members
1791acfe915Sstephan      names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
1801acfe915Sstephan      possible, identically to the C-native counterparts, as documented at:
1811acfe915Sstephan
1821acfe915Sstephan      https://www.sqlite.org/c3ref/intro.html
1831acfe915Sstephan
1841acfe915Sstephan      A very few exceptions require an additional level of proxy
1851acfe915Sstephan      function or may otherwise require special attention in the WASM
1860f32760eSstephan      environment, and all such cases are documented somewhere below
1870f32760eSstephan      in this file or in sqlite3-api-glue.js. capi members which are
1880f32760eSstephan      not documented are installed as 1-to-1 proxies for their
1891acfe915Sstephan      C-side counterparts.
1901acfe915Sstephan  */
1911acfe915Sstephan  const capi = Object.create(null);
1920f32760eSstephan  /**
1930f32760eSstephan     Holds state which are specific to the WASM-related
1940f32760eSstephan     infrastructure and glue code. It is not expected that client
1950f32760eSstephan     code will normally need these, but they're exposed here in case
1960f32760eSstephan     it does. These APIs are _not_ to be considered an
1970f32760eSstephan     official/stable part of the sqlite3 WASM API. They may change
1980f32760eSstephan     as the developers' experience suggests appropriate changes.
1990f32760eSstephan
2000f32760eSstephan     Note that a number of members of this object are injected
2010f32760eSstephan     dynamically after the api object is fully constructed, so
2020f32760eSstephan     not all are documented in this file.
2030f32760eSstephan  */
2040f32760eSstephan  const wasm = Object.create(null);
2051acfe915Sstephan
206f45c3370Sstephan  /** Internal helper for SQLite3Error ctor. */
207f45c3370Sstephan  const __rcStr = (rc)=>{
208f45c3370Sstephan    return (capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(rc))
209f45c3370Sstephan           || ("Unknown result code #"+rc);
210f45c3370Sstephan  };
211f45c3370Sstephan
212f45c3370Sstephan  /** Internal helper for SQLite3Error ctor. */
213f45c3370Sstephan  const __isInt = (n)=>'number'===typeof n && n===(n | 0);
214f45c3370Sstephan
215f45c3370Sstephan  /**
216f45c3370Sstephan     An Error subclass specifically for reporting DB-level errors and
217f45c3370Sstephan     enabling clients to unambiguously identify such exceptions.
218f45c3370Sstephan     The C-level APIs never throw, but some of the higher-level
219f45c3370Sstephan     C-style APIs do and the object-oriented APIs use exceptions
220f45c3370Sstephan     exclusively to report errors.
221f45c3370Sstephan  */
222f45c3370Sstephan  class SQLite3Error extends Error {
223f45c3370Sstephan    /**
224f45c3370Sstephan       Constructs this object with a message depending on its arguments:
225f45c3370Sstephan
226f45c3370Sstephan       - If it's passed only a single integer argument, it is assumed
227f45c3370Sstephan       to be an sqlite3 C API result code. The message becomes the
228f45c3370Sstephan       result of sqlite3.capi.sqlite3_js_rc_str() or (if that returns
229f45c3370Sstephan       falsy) a synthesized string which contains that integer.
230f45c3370Sstephan
231f45c3370Sstephan       - If passed 2 arguments and the 2nd is a object, it bevaves
232f45c3370Sstephan       like the Error(string,object) constructor except that the first
233f45c3370Sstephan       argument is subject to the is-integer semantics from the
234f45c3370Sstephan       previous point.
235f45c3370Sstephan
236f45c3370Sstephan       - Else all arguments are concatenated with a space between each
237f45c3370Sstephan       one, using args.join(' '), to create the error message.
238f45c3370Sstephan    */
239f45c3370Sstephan    constructor(...args){
240f45c3370Sstephan      if(1===args.length && __isInt(args[0])){
241f45c3370Sstephan        super(__rcStr(args[0]));
242f45c3370Sstephan      }else if(2===args.length && 'object'===typeof args){
243f45c3370Sstephan        if(__isInt(args[0])) super(__rcStr(args[0]), args[1]);
244f45c3370Sstephan        else super(...args);
245f45c3370Sstephan      }else{
246f45c3370Sstephan        super(args.join(' '));
247f45c3370Sstephan      }
248f45c3370Sstephan      this.name = 'SQLite3Error';
249f45c3370Sstephan    }
250f45c3370Sstephan  };
251f45c3370Sstephan
2521acfe915Sstephan  /**
2531acfe915Sstephan     Functionally equivalent to the SQLite3Error constructor but may
2541acfe915Sstephan     be used as part of an expression, e.g.:
2551acfe915Sstephan
2561acfe915Sstephan     ```
2571acfe915Sstephan     return someFunction(x) || SQLite3Error.toss(...);
2581acfe915Sstephan     ```
2591acfe915Sstephan  */
2601acfe915Sstephan  SQLite3Error.toss = (...args)=>{
2611acfe915Sstephan    throw new SQLite3Error(...args);
2621acfe915Sstephan  };
2631acfe915Sstephan  const toss3 = SQLite3Error.toss;
2643961b263Sstephan
2653d645484Sstephan  if(config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)){
2661acfe915Sstephan    toss3("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.");
267e3cd6760Sstephan  }
268e3cd6760Sstephan
2693961b263Sstephan  /**
2703961b263Sstephan     Returns true if n is a 32-bit (signed) integer, else
2713961b263Sstephan     false. This is used for determining when we need to switch to
2723961b263Sstephan     double-type DB operations for integer values in order to keep
2733961b263Sstephan     more precision.
2743961b263Sstephan  */
275510a9d1cSstephan  const isInt32 = (n)=>{
2763961b263Sstephan    return ('bigint'!==typeof n /*TypeError: can't convert BigInt to number*/)
2773961b263Sstephan      && !!(n===(n|0) && n<=2147483647 && n>=-2147483648);
2783961b263Sstephan  };
279510a9d1cSstephan  /**
280510a9d1cSstephan     Returns true if the given BigInt value is small enough to fit
281510a9d1cSstephan     into an int64 value, else false.
282510a9d1cSstephan  */
283510a9d1cSstephan  const bigIntFits64 = function f(b){
284510a9d1cSstephan    if(!f._max){
285510a9d1cSstephan      f._max = BigInt("0x7fffffffffffffff");
286510a9d1cSstephan      f._min = ~f._max;
287510a9d1cSstephan    }
288510a9d1cSstephan    return b >= f._min && b <= f._max;
289510a9d1cSstephan  };
290510a9d1cSstephan
291510a9d1cSstephan  /**
292510a9d1cSstephan     Returns true if the given BigInt value is small enough to fit
293510a9d1cSstephan     into an int32, else false.
294510a9d1cSstephan  */
295510a9d1cSstephan  const bigIntFits32 = (b)=>(b >= (-0x7fffffffn - 1n) && b <= 0x7fffffffn);
296510a9d1cSstephan
297510a9d1cSstephan  /**
298510a9d1cSstephan     Returns true if the given BigInt value is small enough to fit
299510a9d1cSstephan     into a double value without loss of precision, else false.
300510a9d1cSstephan  */
301510a9d1cSstephan  const bigIntFitsDouble = function f(b){
302510a9d1cSstephan    if(!f._min){
303510a9d1cSstephan      f._min = Number.MIN_SAFE_INTEGER;
304510a9d1cSstephan      f._max = Number.MAX_SAFE_INTEGER;
305510a9d1cSstephan    }
306510a9d1cSstephan    return b >= f._min && b <= f._max;
307510a9d1cSstephan  };
3083961b263Sstephan
3093961b263Sstephan  /** Returns v if v appears to be a TypedArray, else false. */
3103961b263Sstephan  const isTypedArray = (v)=>{
3113961b263Sstephan    return (v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT)) ? v : false;
3123961b263Sstephan  };
3133961b263Sstephan
314de868175Sstephan
315de868175Sstephan  /** Internal helper to use in operations which need to distinguish
316de868175Sstephan      between TypedArrays which are backed by a SharedArrayBuffer
317de868175Sstephan      from those which are not. */
318de868175Sstephan  const __SAB = ('undefined'===typeof SharedArrayBuffer)
319de868175Sstephan        ? function(){} : SharedArrayBuffer;
320de868175Sstephan  /** Returns true if the given TypedArray object is backed by a
321de868175Sstephan      SharedArrayBuffer, else false. */
322de868175Sstephan  const isSharedTypedArray = (aTypedArray)=>(aTypedArray.buffer instanceof __SAB);
323de868175Sstephan
324de868175Sstephan  /**
325de868175Sstephan     Returns either aTypedArray.slice(begin,end) (if
326de868175Sstephan     aTypedArray.buffer is a SharedArrayBuffer) or
327de868175Sstephan     aTypedArray.subarray(begin,end) (if it's not).
328de868175Sstephan
329de868175Sstephan     This distinction is important for APIs which don't like to
330de868175Sstephan     work on SABs, e.g. TextDecoder, and possibly for our
331de868175Sstephan     own APIs which work on memory ranges which "might" be
3324f975c33Sstephan     modified by other threads while they're working.
333de868175Sstephan  */
334de868175Sstephan  const typedArrayPart = (aTypedArray, begin, end)=>{
335de868175Sstephan    return isSharedTypedArray(aTypedArray)
336de868175Sstephan      ? aTypedArray.slice(begin, end)
337de868175Sstephan      : aTypedArray.subarray(begin, end);
338de868175Sstephan  };
339de868175Sstephan
3403961b263Sstephan  /**
3413961b263Sstephan     Returns true if v appears to be one of our bind()-able
3423961b263Sstephan     TypedArray types: Uint8Array or Int8Array. Support for
3433961b263Sstephan     TypedArrays with element sizes >1 is TODO.
3443961b263Sstephan  */
3453961b263Sstephan  const isBindableTypedArray = (v)=>{
3463961b263Sstephan    return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);
3473961b263Sstephan  };
3483961b263Sstephan
3493961b263Sstephan  /**
3503961b263Sstephan     Returns true if v appears to be one of the TypedArray types
3513961b263Sstephan     which is legal for holding SQL code (as opposed to binary blobs).
3523961b263Sstephan
3533961b263Sstephan     Currently this is the same as isBindableTypedArray() but it
3543961b263Sstephan     seems likely that we'll eventually want to add Uint32Array
3553961b263Sstephan     and friends to the isBindableTypedArray() list but not to the
3563961b263Sstephan     isSQLableTypedArray() list.
3573961b263Sstephan  */
3583961b263Sstephan  const isSQLableTypedArray = (v)=>{
3593961b263Sstephan    return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);
3603961b263Sstephan  };
3613961b263Sstephan
3623961b263Sstephan  /** Returns true if isBindableTypedArray(v) does, else throws with a message
3633961b263Sstephan      that v is not a supported TypedArray value. */
3643961b263Sstephan  const affirmBindableTypedArray = (v)=>{
3653961b263Sstephan    return isBindableTypedArray(v)
3661acfe915Sstephan      || toss3("Value is not of a supported TypedArray type.");
3673961b263Sstephan  };
3683961b263Sstephan
3693961b263Sstephan  const utf8Decoder = new TextDecoder('utf-8');
370e3cd6760Sstephan
371de868175Sstephan  /**
372de868175Sstephan     Uses TextDecoder to decode the given half-open range of the
373de868175Sstephan     given TypedArray to a string. This differs from a simple
374de868175Sstephan     call to TextDecoder in that it accounts for whether the
3754f975c33Sstephan     first argument is backed by a SharedArrayBuffer or not,
376de868175Sstephan     and can work more efficiently if it's not (TextDecoder
377de868175Sstephan     refuses to act upon an SAB).
378de868175Sstephan  */
379de868175Sstephan  const typedArrayToString = function(typedArray, begin, end){
380de868175Sstephan    return utf8Decoder.decode(typedArrayPart(typedArray, begin,end));
381e3cd6760Sstephan  };
3823961b263Sstephan
3833961b263Sstephan  /**
3844df2ab57Sstephan     If v is-a Array, its join("") result is returned.  If
385ef9cd12eSstephan     isSQLableTypedArray(v) is true then typedArrayToString(v) is
3860f32760eSstephan     returned. If it looks like a WASM pointer, wasm.cstringToJs(v) is
387e67a0f40Sstephan     returned. Else v is returned as-is.
388e67a0f40Sstephan  */
389ef9cd12eSstephan  const flexibleString = function(v){
390e67a0f40Sstephan    if(isSQLableTypedArray(v)) return typedArrayToString(v);
3914df2ab57Sstephan    else if(Array.isArray(v)) return v.join("");
3920f32760eSstephan    else if(wasm.isPtr(v)) v = wasm.cstringToJs(v);
393e67a0f40Sstephan    return v;
394e67a0f40Sstephan  };
395e67a0f40Sstephan
396e67a0f40Sstephan  /**
3973961b263Sstephan     An Error subclass specifically for reporting Wasm-level malloc()
3983961b263Sstephan     failure and enabling clients to unambiguously identify such
3993961b263Sstephan     exceptions.
4003961b263Sstephan  */
4013961b263Sstephan  class WasmAllocError extends Error {
402*690d4c54Sstephan    /**
403*690d4c54Sstephan       If called with 2 arguments and the 2nd one is an object, it
404*690d4c54Sstephan       behaves like the Error constructor, else it concatenates all
405*690d4c54Sstephan       arguments together with a single space between each to
406*690d4c54Sstephan       construct an error message string. As a special case, if
407*690d4c54Sstephan       called with no arguments then it uses a default error
408*690d4c54Sstephan       message.
409*690d4c54Sstephan    */
4103961b263Sstephan    constructor(...args){
411*690d4c54Sstephan      if(2===args.length && 'object'===typeof args){
4123961b263Sstephan        super(...args);
413*690d4c54Sstephan      }else if(args.length){
414*690d4c54Sstephan        super(args.join(' '));
415*690d4c54Sstephan      }else{
416*690d4c54Sstephan        super("Allocation failed.");
417*690d4c54Sstephan      }
4183961b263Sstephan      this.name = 'WasmAllocError';
4193961b263Sstephan    }
4203961b263Sstephan  };
42196b6371dSstephan  /**
42296b6371dSstephan     Functionally equivalent to the WasmAllocError constructor but may
42396b6371dSstephan     be used as part of an expression, e.g.:
42496b6371dSstephan
42596b6371dSstephan     ```
42696b6371dSstephan     return someAllocatingFunction(x) || WasmAllocError.toss(...);
42796b6371dSstephan     ```
42896b6371dSstephan  */
42963e9ec2fSstephan  WasmAllocError.toss = (...args)=>{
430a6ca996eSstephan    throw new WasmAllocError(...args);
43163e9ec2fSstephan  };
4323961b263Sstephan
4331acfe915Sstephan  Object.assign(capi, {
4343961b263Sstephan    /**
4359892883eSstephan       sqlite3_create_function_v2() differs from its native
4369892883eSstephan       counterpart only in the following ways:
4373961b263Sstephan
4389892883eSstephan       1) The fourth argument (`eTextRep`) argument must not specify
4398d9e5955Sstephan       any encoding other than sqlite3.SQLITE_UTF8. The JS API does not
4409892883eSstephan       currently support any other encoding and likely never
4419892883eSstephan       will. This function does not replace that argument on its own
4429892883eSstephan       because it may contain other flags.
4433961b263Sstephan
4449892883eSstephan       2) Any of the four final arguments may be either WASM pointers
4459892883eSstephan       (assumed to be function pointers) or JS Functions. In the
4469892883eSstephan       latter case, each gets bound to WASM using
4479892883eSstephan       sqlite3.capi.wasm.installFunction() and that wrapper is passed
4489892883eSstephan       on to the native implementation.
4493961b263Sstephan
4509892883eSstephan       The semantics of JS functions are:
4513961b263Sstephan
452510a9d1cSstephan       xFunc: is passed `(pCtx, ...values)`. Its return value becomes
4539892883eSstephan       the new SQL function's result.
4549892883eSstephan
455510a9d1cSstephan       xStep: is passed `(pCtx, ...values)`. Its return value is
4569892883eSstephan       ignored.
4579892883eSstephan
458510a9d1cSstephan       xFinal: is passed `(pCtx)`. Its return value becomes the new
459510a9d1cSstephan       aggregate SQL function's result.
4609892883eSstephan
4619892883eSstephan       xDestroy: is passed `(void*)`. Its return value is ignored. The
4629892883eSstephan       pointer passed to it is the one from the 5th argument to
4639892883eSstephan       sqlite3_create_function_v2().
4649892883eSstephan
465510a9d1cSstephan       Note that:
466510a9d1cSstephan
4678d9e5955Sstephan       - `pCtx` in the above descriptions is a `sqlite3_context*`. At
4688d9e5955Sstephan         least 99 times out of a hundred, that initial argument will
4698d9e5955Sstephan         be irrelevant for JS UDF bindings, but it needs to be there
4708d9e5955Sstephan         so that the cases where it _is_ relevant, in particular with
4718d9e5955Sstephan         window and aggregate functions, have full access to the
4728d9e5955Sstephan         lower-level sqlite3 APIs.
473510a9d1cSstephan
4748d9e5955Sstephan       - When wrapping JS functions, the remaining arguments are passd
4758d9e5955Sstephan         to them as positional arguments, not as an array of
4768d9e5955Sstephan         arguments, because that allows callback definitions to be
4778d9e5955Sstephan         more JS-idiomatic than C-like. For example `(pCtx,a,b)=>a+b`
4788d9e5955Sstephan         is more intuitive and legible than
4798d9e5955Sstephan         `(pCtx,args)=>args[0]+args[1]`. For cases where an array of
4808d9e5955Sstephan         arguments would be more convenient, the callbacks simply need
4818d9e5955Sstephan         to be declared like `(pCtx,...args)=>{...}`, in which case
4828d9e5955Sstephan         `args` will be an array.
483510a9d1cSstephan
484510a9d1cSstephan       - If a JS wrapper throws, it gets translated to
485510a9d1cSstephan         sqlite3_result_error() or sqlite3_result_error_nomem(),
486510a9d1cSstephan         depending on whether the exception is an
487510a9d1cSstephan         sqlite3.WasmAllocError object or not.
488510a9d1cSstephan
489510a9d1cSstephan       - When passing on WASM function pointers, arguments are _not_
490510a9d1cSstephan         converted or reformulated. They are passed on as-is in raw
491510a9d1cSstephan         pointer form using their native C signatures. Only JS
492510a9d1cSstephan         functions passed in to this routine, and thus wrapped by this
493510a9d1cSstephan         routine, get automatic conversions of arguments and result
494510a9d1cSstephan         values. The routines which perform those conversions are
495510a9d1cSstephan         exposed for client-side use as
496510a9d1cSstephan         sqlite3_create_function_v2.convertUdfArgs() and
497510a9d1cSstephan         sqlite3_create_function_v2.setUdfResult(). sqlite3_create_function()
498510a9d1cSstephan         and sqlite3_create_window_function() have those same methods.
4999892883eSstephan
5009892883eSstephan       For xFunc(), xStep(), and xFinal():
5019892883eSstephan
5029892883eSstephan       - When called from SQL, arguments to the UDF, and its result,
5039892883eSstephan         will be converted between JS and SQL with as much fidelity as
5049892883eSstephan         is feasible, triggering an exception if a type conversion
5059892883eSstephan         cannot be determined. Some freedom is afforded to numeric
5069892883eSstephan         conversions due to friction between the JS and C worlds:
5078d9e5955Sstephan         integers which are larger than 32 bits may be treated as
5088d9e5955Sstephan         doubles or BigInts.
5099892883eSstephan
510510a9d1cSstephan       If any JS-side bound functions throw, those exceptions are
511510a9d1cSstephan       intercepted and converted to database-side errors with the
512510a9d1cSstephan       exception of xDestroy(): any exception from it is ignored,
513510a9d1cSstephan       possibly generating a console.error() message.  Destructors
514510a9d1cSstephan       must not throw.
5159892883eSstephan
5169892883eSstephan       Once installed, there is currently no way to uninstall the
517510a9d1cSstephan       automatically-converted WASM-bound JS functions from WASM. They
518510a9d1cSstephan       can be uninstalled from the database as documented in the C
519510a9d1cSstephan       API, but this wrapper currently has no infrastructure in place
520510a9d1cSstephan       to also free the WASM-bound JS wrappers, effectively resulting
521510a9d1cSstephan       in a memory leak if the client uninstalls the UDF. Improving that
522510a9d1cSstephan       is a potential TODO, but removing client-installed UDFs is rare
523510a9d1cSstephan       in practice. If this factor is relevant for a given client,
524510a9d1cSstephan       they can create WASM-bound JS functions themselves, hold on to their
525510a9d1cSstephan       pointers, and pass the pointers in to here. Later on, they can
526510a9d1cSstephan       free those pointers (using `wasm.uninstallFunction()` or
527510a9d1cSstephan       equivalent).
528510a9d1cSstephan
529510a9d1cSstephan       C reference: https://www.sqlite.org/c3ref/create_function.html
5309892883eSstephan
5319892883eSstephan       Maintenance reminder: the ability to add new
5329892883eSstephan       WASM-accessible functions to the runtime requires that the
5339892883eSstephan       WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH`
5349892883eSstephan       flag.
5353961b263Sstephan    */
5369892883eSstephan    sqlite3_create_function_v2: function(
5379892883eSstephan      pDb, funcName, nArg, eTextRep, pApp,
538510a9d1cSstephan      xFunc, xStep, xFinal, xDestroy
5399892883eSstephan    ){/*installed later*/},
5409892883eSstephan    /**
5419892883eSstephan       Equivalent to passing the same arguments to
5429892883eSstephan       sqlite3_create_function_v2(), with 0 as the final argument.
5439892883eSstephan    */
5449892883eSstephan    sqlite3_create_function:function(
5459892883eSstephan      pDb, funcName, nArg, eTextRep, pApp,
546510a9d1cSstephan      xFunc, xStep, xFinal
5479892883eSstephan    ){/*installed later*/},
5483961b263Sstephan    /**
54992ede964Sstephan       The sqlite3_create_window_function() JS wrapper differs from
55092ede964Sstephan       its native implementation in the exact same way that
55192ede964Sstephan       sqlite3_create_function_v2() does. The additional function,
55292ede964Sstephan       xInverse(), is treated identically to xStep() by the wrapping
55392ede964Sstephan       layer.
55492ede964Sstephan    */
55592ede964Sstephan    sqlite3_create_window_function: function(
55692ede964Sstephan      pDb, funcName, nArg, eTextRep, pApp,
557510a9d1cSstephan      xStep, xFinal, xValue, xInverse, xDestroy
55892ede964Sstephan    ){/*installed later*/},
55992ede964Sstephan    /**
5603961b263Sstephan       The sqlite3_prepare_v3() binding handles two different uses
5613961b263Sstephan       with differing JS/WASM semantics:
5623961b263Sstephan
563d9801185Sstephan       1) sqlite3_prepare_v3(pDb, sqlString, -1, prepFlags, ppStmt , null)
5643961b263Sstephan
5653961b263Sstephan       2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer)
5663961b263Sstephan
5673961b263Sstephan       Note that the SQL length argument (the 3rd argument) must, for
5683961b263Sstephan       usage (1), always be negative because it must be a byte length
5693961b263Sstephan       and that value is expensive to calculate from JS (where only
5703961b263Sstephan       the character length of strings is readily available). It is
5713961b263Sstephan       retained in this API's interface for code/documentation
5723961b263Sstephan       compatibility reasons but is currently _always_ ignored. With
5733961b263Sstephan       usage (2), the 3rd argument is used as-is but is is still
5743961b263Sstephan       critical that the C-style input string (2nd argument) be
5753961b263Sstephan       terminated with a 0 byte.
5763961b263Sstephan
5773961b263Sstephan       In usage (1), the 2nd argument must be of type string,
5783961b263Sstephan       Uint8Array, or Int8Array (either of which is assumed to
5793961b263Sstephan       hold SQL). If it is, this function assumes case (1) and
5803961b263Sstephan       calls the underyling C function with the equivalent of:
5813961b263Sstephan
5823961b263Sstephan       (pDb, sqlAsString, -1, prepFlags, ppStmt, null)
5833961b263Sstephan
584d9801185Sstephan       The `pzTail` argument is ignored in this case because its
585d9801185Sstephan       result is meaningless when a string-type value is passed
586d9801185Sstephan       through: the string goes through another level of internal
5873961b263Sstephan       conversion for WASM's sake and the result pointer would refer
5883961b263Sstephan       to that transient conversion's memory, not the passed-in
589d9801185Sstephan       string.
5903961b263Sstephan
5913961b263Sstephan       If the sql argument is not a string, it must be a _pointer_ to
5923961b263Sstephan       a NUL-terminated string which was allocated in the WASM memory
593d9801185Sstephan       (e.g. using capi.wasm.alloc() or equivalent). In that case,
5943961b263Sstephan       the final argument may be 0/null/undefined or must be a pointer
5953961b263Sstephan       to which the "tail" of the compiled SQL is written, as
5963961b263Sstephan       documented for the C-side sqlite3_prepare_v3(). In case (2),
5973961b263Sstephan       the underlying C function is called with the equivalent of:
5983961b263Sstephan
599d9801185Sstephan       (pDb, sqlAsPointer, sqlByteLen, prepFlags, ppStmt, pzTail)
6003961b263Sstephan
6013961b263Sstephan       It returns its result and compiled statement as documented in
6023961b263Sstephan       the C API. Fetching the output pointers (5th and 6th
603d9801185Sstephan       parameters) requires using `capi.wasm.getMemValue()` (or
604d9801185Sstephan       equivalent) and the `pzTail` will point to an address relative to
605d9801185Sstephan       the `sqlAsPointer` value.
6063961b263Sstephan
6073961b263Sstephan       If passed an invalid 2nd argument type, this function will
608d9801185Sstephan       return SQLITE_MISUSE and sqlite3_errmsg() will contain a string
609d9801185Sstephan       describing the problem.
6103961b263Sstephan
611d9801185Sstephan       Side-note: if given an empty string, or one which contains only
612d9801185Sstephan       comments or an empty SQL expression, 0 is returned but the result
613d9801185Sstephan       output pointer will be NULL.
6143961b263Sstephan    */
615e67a0f40Sstephan    sqlite3_prepare_v3: (dbPtr, sql, sqlByteLen, prepFlags,
616e67a0f40Sstephan                         stmtPtrPtr, strPtrPtr)=>{}/*installed later*/,
6173961b263Sstephan
6183961b263Sstephan    /**
6193961b263Sstephan       Equivalent to calling sqlite3_prapare_v3() with 0 as its 4th argument.
6203961b263Sstephan    */
621e67a0f40Sstephan    sqlite3_prepare_v2: (dbPtr, sql, sqlByteLen,
622e67a0f40Sstephan                         stmtPtrPtr,strPtrPtr)=>{}/*installed later*/,
6233961b263Sstephan
6243961b263Sstephan    /**
625e67a0f40Sstephan       This binding enables the callback argument to be a JavaScript.
626e67a0f40Sstephan
627e67a0f40Sstephan       If the callback is a function, then for the duration of the
628e67a0f40Sstephan       sqlite3_exec() call, it installs a WASM-bound function which
629de868175Sstephan       acts as a proxy for the given callback. That proxy will also
630de868175Sstephan       perform a conversion of the callback's arguments from
631e67a0f40Sstephan       `(char**)` to JS arrays of strings. However, for API
632de868175Sstephan       consistency's sake it will still honor the C-level callback
633de868175Sstephan       parameter order and will call it like:
634e67a0f40Sstephan
635e67a0f40Sstephan       `callback(pVoid, colCount, listOfValues, listOfColNames)`
636e67a0f40Sstephan
637e67a0f40Sstephan       If the callback is not a JS function then this binding performs
638e67a0f40Sstephan       no translation of the callback, but the sql argument is still
639e67a0f40Sstephan       converted to a WASM string for the call using the
640e67a0f40Sstephan       "flexible-string" argument converter.
641e67a0f40Sstephan    */
642e67a0f40Sstephan    sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/,
64396b6371dSstephan
644e67a0f40Sstephan    /**
645de868175Sstephan       If passed a single argument which appears to be a byte-oriented
646de868175Sstephan       TypedArray (Int8Array or Uint8Array), this function treats that
647de868175Sstephan       TypedArray as an output target, fetches `theArray.byteLength`
648de868175Sstephan       bytes of randomness, and populates the whole array with it. As
649de868175Sstephan       a special case, if the array's length is 0, this function
650de868175Sstephan       behaves as if it were passed (0,0). When called this way, it
651de868175Sstephan       returns its argument, else it returns the `undefined` value.
652de868175Sstephan
653de868175Sstephan       If called with any other arguments, they are passed on as-is
654de868175Sstephan       to the C API. Results are undefined if passed any incompatible
655de868175Sstephan       values.
656de868175Sstephan     */
657de868175Sstephan    sqlite3_randomness: (n, outPtr)=>{/*installed later*/},
6581acfe915Sstephan  }/*capi*/);
659de868175Sstephan
660de868175Sstephan  /**
6613961b263Sstephan     Various internal-use utilities are added here as needed. They
6623961b263Sstephan     are bound to an object only so that we have access to them in
6633961b263Sstephan     the differently-scoped steps of the API bootstrapping
6643961b263Sstephan     process. At the end of the API setup process, this object gets
665de868175Sstephan     removed. These are NOT part of the public API.
6663961b263Sstephan  */
6678948fbeeSstephan  const util = {
668ef9cd12eSstephan    affirmBindableTypedArray, flexibleString,
669510a9d1cSstephan    bigIntFits32, bigIntFits64, bigIntFitsDouble,
670510a9d1cSstephan    isBindableTypedArray,
671e67a0f40Sstephan    isInt32, isSQLableTypedArray, isTypedArray,
672e67a0f40Sstephan    typedArrayToString,
673de868175Sstephan    isUIThread: ()=>'undefined'===typeof WorkerGlobalScope,
674de868175Sstephan    isSharedTypedArray,
675de868175Sstephan    typedArrayPart
6768948fbeeSstephan  };
6773961b263Sstephan
6780f32760eSstephan  Object.assign(wasm, {
6793961b263Sstephan    /**
6803961b263Sstephan       Emscripten APIs have a deep-seated assumption that all pointers
6813961b263Sstephan       are 32 bits. We'll remain optimistic that that won't always be
6823961b263Sstephan       the case and will use this constant in places where we might
6833961b263Sstephan       otherwise use a hard-coded 4.
6843961b263Sstephan    */
6853961b263Sstephan    ptrSizeof: config.wasmPtrSizeof || 4,
6863961b263Sstephan    /**
6873961b263Sstephan       The WASM IR (Intermediate Representation) value for
6883961b263Sstephan       pointer-type values. It MUST refer to a value type of the
6893961b263Sstephan       size described by this.ptrSizeof _or_ it may be any value
6903961b263Sstephan       which ends in '*', which Emscripten's glue code internally
6913961b263Sstephan       translates to i32.
6923961b263Sstephan    */
6933961b263Sstephan    ptrIR: config.wasmPtrIR || "i32",
6943961b263Sstephan    /**
6953961b263Sstephan       True if BigInt support was enabled via (e.g.) the
6963961b263Sstephan       Emscripten -sWASM_BIGINT flag, else false. When
6973961b263Sstephan       enabled, certain 64-bit sqlite3 APIs are enabled which
6983961b263Sstephan       are not otherwise enabled due to JS/WASM int64
6993961b263Sstephan       impedence mismatches.
7003961b263Sstephan    */
7013961b263Sstephan    bigIntEnabled: !!config.bigIntEnabled,
7023961b263Sstephan    /**
7033961b263Sstephan       The symbols exported by the WASM environment.
7043961b263Sstephan    */
7053961b263Sstephan    exports: config.exports
7061acfe915Sstephan      || toss3("Missing API config.exports (WASM module exports)."),
7073961b263Sstephan
7083961b263Sstephan    /**
7093961b263Sstephan       When Emscripten compiles with `-sIMPORT_MEMORY`, it
7103961b263Sstephan       initalizes the heap and imports it into wasm, as opposed to
7113961b263Sstephan       the other way around. In this case, the memory is not
7123961b263Sstephan       available via this.exports.memory.
7133961b263Sstephan    */
7143961b263Sstephan    memory: config.memory || config.exports['memory']
7151acfe915Sstephan      || toss3("API config object requires a WebAssembly.Memory object",
7163961b263Sstephan              "in either config.exports.memory (exported)",
7173961b263Sstephan              "or config.memory (imported)."),
718453af2f6Sstephan
719453af2f6Sstephan    /**
720453af2f6Sstephan       The API's one single point of access to the WASM-side memory
721453af2f6Sstephan       allocator. Works like malloc(3) (and is likely bound to
722453af2f6Sstephan       malloc()) but throws an WasmAllocError if allocation fails. It is
723453af2f6Sstephan       important that any code which might pass through the sqlite3 C
724453af2f6Sstephan       API NOT throw and must instead return SQLITE_NOMEM (or
725453af2f6Sstephan       equivalent, depending on the context).
726453af2f6Sstephan
727*690d4c54Sstephan       Very few cases in the sqlite3 JS APIs can result in
728453af2f6Sstephan       client-defined functions propagating exceptions via the C-style
729*690d4c54Sstephan       API. Most notably, this applies to WASM-bound JS functions
730*690d4c54Sstephan       which are created directly by clients and passed on _as WASM
731*690d4c54Sstephan       function pointers_ to functions such as
732*690d4c54Sstephan       sqlite3_create_function_v2(). Such bindings created
733*690d4c54Sstephan       transparently by this API will automatically use wrappers which
734*690d4c54Sstephan       catch exceptions and convert them to appropriate error codes.
735*690d4c54Sstephan
736*690d4c54Sstephan       For cases where non-throwing allocation is required, use
737*690d4c54Sstephan       sqlite3.wasm.alloc.impl(), which is direct binding of the
738*690d4c54Sstephan       underlying C-level allocator.
739*690d4c54Sstephan
740*690d4c54Sstephan       Design note: this function is not named "malloc" primarily
741*690d4c54Sstephan       because Emscripten uses that name and we wanted to avoid any
742*690d4c54Sstephan       confusion early on in this code's development, when it still
743*690d4c54Sstephan       had close ties to Emscripten's glue code.
744453af2f6Sstephan    */
745453af2f6Sstephan    alloc: undefined/*installed later*/,
746*690d4c54Sstephan
747453af2f6Sstephan    /**
748453af2f6Sstephan       The API's one single point of access to the WASM-side memory
749453af2f6Sstephan       deallocator. Works like free(3) (and is likely bound to
750453af2f6Sstephan       free()).
751*690d4c54Sstephan
752*690d4c54Sstephan       Design note: this function is not named "free" for the same
753*690d4c54Sstephan       reason that this.alloc() is not called this.malloc().
754453af2f6Sstephan    */
755453af2f6Sstephan    dealloc: undefined/*installed later*/
756453af2f6Sstephan
7573961b263Sstephan    /* Many more wasm-related APIs get installed later on. */
7580f32760eSstephan  }/*wasm*/);
7592b776ee2Sstephan
7603961b263Sstephan  /**
7612b776ee2Sstephan     wasm.alloc()'s srcTypedArray.byteLength bytes,
7623961b263Sstephan     populates them with the values from the source
7633961b263Sstephan     TypedArray, and returns the pointer to that memory. The
7643961b263Sstephan     returned pointer must eventually be passed to
7652b776ee2Sstephan     wasm.dealloc() to clean it up.
7663961b263Sstephan
7673961b263Sstephan     As a special case, to avoid further special cases where
7683961b263Sstephan     this is used, if srcTypedArray.byteLength is 0, it
7693961b263Sstephan     allocates a single byte and sets it to the value
7703961b263Sstephan     0. Even in such cases, calls must behave as if the
7713961b263Sstephan     allocated memory has exactly srcTypedArray.byteLength
7723961b263Sstephan     bytes.
7733961b263Sstephan
7743961b263Sstephan     ACHTUNG: this currently only works for Uint8Array and
7753961b263Sstephan     Int8Array types and will throw if srcTypedArray is of
7763961b263Sstephan     any other type.
7773961b263Sstephan  */
7782b776ee2Sstephan  wasm.allocFromTypedArray = function(srcTypedArray){
7793961b263Sstephan    affirmBindableTypedArray(srcTypedArray);
7802b776ee2Sstephan    const pRet = wasm.alloc(srcTypedArray.byteLength || 1);
781*690d4c54Sstephan    wasm.heapForSize(srcTypedArray.constructor).set(
782*690d4c54Sstephan      srcTypedArray.byteLength ? srcTypedArray : [0], pRet
783*690d4c54Sstephan    );
7843961b263Sstephan    return pRet;
78592ede964Sstephan  };
7863961b263Sstephan
7873961b263Sstephan  const keyAlloc = config.allocExportName || 'malloc',
7883961b263Sstephan        keyDealloc =  config.deallocExportName || 'free';
7893961b263Sstephan  for(const key of [keyAlloc, keyDealloc]){
7902b776ee2Sstephan    const f = wasm.exports[key];
7911acfe915Sstephan    if(!(f instanceof Function)) toss3("Missing required exports[",key,"] function.");
7923961b263Sstephan  }
793453af2f6Sstephan
794*690d4c54Sstephan  wasm.alloc = function f(n){
795*690d4c54Sstephan    const m = f.impl(n);
796*690d4c54Sstephan    if(!m) throw new WasmAllocError("Failed to allocate",n," bytes.");
7973961b263Sstephan    return m;
79892ede964Sstephan  };
799*690d4c54Sstephan  wasm.alloc.impl = wasm.exports[keyAlloc];
800*690d4c54Sstephan  wasm.dealloc = wasm.exports[keyDealloc];
8013961b263Sstephan
8023961b263Sstephan  /**
8033961b263Sstephan     Reports info about compile-time options using
8043961b263Sstephan     sqlite_compileoption_get() and sqlite3_compileoption_used(). It
8053961b263Sstephan     has several distinct uses:
8063961b263Sstephan
8073961b263Sstephan     If optName is an array then it is expected to be a list of
8083961b263Sstephan     compilation options and this function returns an object
8093961b263Sstephan     which maps each such option to true or false, indicating
8103961b263Sstephan     whether or not the given option was included in this
8113961b263Sstephan     build. That object is returned.
8123961b263Sstephan
8133961b263Sstephan     If optName is an object, its keys are expected to be compilation
8143961b263Sstephan     options and this function sets each entry to true or false,
8153961b263Sstephan     indicating whether the compilation option was used or not. That
8163961b263Sstephan     object is returned.
8173961b263Sstephan
8183961b263Sstephan     If passed no arguments then it returns an object mapping
8193961b263Sstephan     all known compilation options to their compile-time values,
8203961b263Sstephan     or boolean true if they are defined with no value. This
8213961b263Sstephan     result, which is relatively expensive to compute, is cached
8223961b263Sstephan     and returned for future no-argument calls.
8233961b263Sstephan
8243961b263Sstephan     In all other cases it returns true if the given option was
8253961b263Sstephan     active when when compiling the sqlite3 module, else false.
8263961b263Sstephan
8273961b263Sstephan     Compile-time option names may optionally include their
8283961b263Sstephan     "SQLITE_" prefix. When it returns an object of all options,
8293961b263Sstephan     the prefix is elided.
8303961b263Sstephan  */
8312b776ee2Sstephan  wasm.compileOptionUsed = function f(optName){
8323961b263Sstephan    if(!arguments.length){
8333961b263Sstephan      if(f._result) return f._result;
8343961b263Sstephan      else if(!f._opt){
8353961b263Sstephan        f._rx = /^([^=]+)=(.+)/;
8363961b263Sstephan        f._rxInt = /^-?\d+$/;
8373961b263Sstephan        f._opt = function(opt, rv){
8383961b263Sstephan          const m = f._rx.exec(opt);
8393961b263Sstephan          rv[0] = (m ? m[1] : opt);
8403961b263Sstephan          rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true;
8413961b263Sstephan        };
8423961b263Sstephan      }
8433961b263Sstephan      const rc = {}, ov = [0,0];
8443961b263Sstephan      let i = 0, k;
8453961b263Sstephan      while((k = capi.sqlite3_compileoption_get(i++))){
8463961b263Sstephan        f._opt(k,ov);
8473961b263Sstephan        rc[ov[0]] = ov[1];
8483961b263Sstephan      }
8493961b263Sstephan      return f._result = rc;
8503961b263Sstephan    }else if(Array.isArray(optName)){
8513961b263Sstephan      const rc = {};
8523961b263Sstephan      optName.forEach((v)=>{
8533961b263Sstephan        rc[v] = capi.sqlite3_compileoption_used(v);
8543961b263Sstephan      });
8553961b263Sstephan      return rc;
8563961b263Sstephan    }else if('object' === typeof optName){
8573961b263Sstephan      Object.keys(optName).forEach((k)=> {
8583961b263Sstephan        optName[k] = capi.sqlite3_compileoption_used(k);
8593961b263Sstephan      });
8603961b263Sstephan      return optName;
8613961b263Sstephan    }
8623961b263Sstephan    return (
8633961b263Sstephan      'string'===typeof optName
8643961b263Sstephan    ) ? !!capi.sqlite3_compileoption_used(optName) : false;
8653961b263Sstephan  }/*compileOptionUsed()*/;
8663961b263Sstephan
8673961b263Sstephan  /**
8683961b263Sstephan     Signatures for the WASM-exported C-side functions. Each entry
8693961b263Sstephan     is an array with 2+ elements:
8703961b263Sstephan
8713961b263Sstephan     [ "c-side name",
8722b776ee2Sstephan       "result type" (wasm.xWrap() syntax),
8733961b263Sstephan       [arg types in xWrap() syntax]
8743961b263Sstephan       // ^^^ this needn't strictly be an array: it can be subsequent
8753961b263Sstephan       // elements instead: [x,y,z] is equivalent to x,y,z
8763961b263Sstephan     ]
8775b915007Sstephan
8785b915007Sstephan     Note that support for the API-specific data types in the
8795b915007Sstephan     result/argument type strings gets plugged in at a later phase in
8805b915007Sstephan     the API initialization process.
8813961b263Sstephan  */
8822b776ee2Sstephan  wasm.bindingSignatures = [
8833961b263Sstephan    // Please keep these sorted by function name!
884510a9d1cSstephan    ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
8856167d5cfSstephan    ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"
886de868175Sstephan     /* TODO: we should arguably write a custom wrapper which knows
887de868175Sstephan        how to handle Blob, TypedArrays, and JS strings. */
8886167d5cfSstephan    ],
8893961b263Sstephan    ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
8903961b263Sstephan    ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
8913961b263Sstephan    ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
8923961b263Sstephan    ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
8933961b263Sstephan    ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
8946167d5cfSstephan    ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int"
895de868175Sstephan     /* We should arguably create a hand-written binding of
896de868175Sstephan        bind_text() which does more flexible text conversion, along
897de868175Sstephan        the lines of sqlite3_prepare_v3(). The slightly problematic
898de868175Sstephan        part is the final argument (text destructor). */
8996167d5cfSstephan    ],
9003961b263Sstephan    ["sqlite3_close_v2", "int", "sqlite3*"],
9013961b263Sstephan    ["sqlite3_changes", "int", "sqlite3*"],
9023961b263Sstephan    ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
9033961b263Sstephan    ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
9043961b263Sstephan    ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
9053961b263Sstephan    ["sqlite3_column_count", "int", "sqlite3_stmt*"],
9063961b263Sstephan    ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
9073961b263Sstephan    ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
9083961b263Sstephan    ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
9093961b263Sstephan    ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
9103961b263Sstephan    ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
9113961b263Sstephan    ["sqlite3_compileoption_get", "string", "int"],
9123961b263Sstephan    ["sqlite3_compileoption_used", "int", "string"],
913de868175Sstephan    /* sqlite3_create_function(), sqlite3_create_function_v2(), and
914de868175Sstephan       sqlite3_create_window_function() use hand-written bindings to
915de868175Sstephan       simplify handling of their function-type arguments. */
9163961b263Sstephan    ["sqlite3_data_count", "int", "sqlite3_stmt*"],
9173961b263Sstephan    ["sqlite3_db_filename", "string", "sqlite3*", "string"],
9185b915007Sstephan    ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
9193961b263Sstephan    ["sqlite3_db_name", "string", "sqlite3*", "int"],
92053d4e01dSstephan    ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
92153d4e01dSstephan    /* Careful! Short version: de/serialize() are problematic because they
922de868175Sstephan       might use a different allocator than the user for managing the
92353d4e01dSstephan       deserialized block. de/serialize() are ONLY safe to use with
92453d4e01dSstephan       sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
9253961b263Sstephan    ["sqlite3_errmsg", "string", "sqlite3*"],
9263961b263Sstephan    ["sqlite3_error_offset", "int", "sqlite3*"],
9273961b263Sstephan    ["sqlite3_errstr", "string", "int"],
928e67a0f40Sstephan    /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**"
929e67a0f40Sstephan      Handled seperately to perform translation of the callback
930e67a0f40Sstephan      into a WASM-usable one. ],*/
9313961b263Sstephan    ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
9323961b263Sstephan    ["sqlite3_extended_errcode", "int", "sqlite3*"],
9333961b263Sstephan    ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
9345b915007Sstephan    ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
9353961b263Sstephan    ["sqlite3_finalize", "int", "sqlite3_stmt*"],
93653d4e01dSstephan    ["sqlite3_free", undefined,"*"],
9373961b263Sstephan    ["sqlite3_initialize", undefined],
938ffbc653dSstephan    /*["sqlite3_interrupt", undefined, "sqlite3*"
939ffbc653dSstephan       ^^^ we cannot actually currently support this because JS is
9403961b263Sstephan        single-threaded and we don't have a portable way to access a DB
941ffbc653dSstephan        from 2 SharedWorkers concurrently. ],*/
9423961b263Sstephan    ["sqlite3_libversion", "string"],
9433961b263Sstephan    ["sqlite3_libversion_number", "int"],
94453d4e01dSstephan    ["sqlite3_malloc", "*","int"],
9453961b263Sstephan    ["sqlite3_open", "int", "string", "*"],
9463961b263Sstephan    ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
9473961b263Sstephan    /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
9483961b263Sstephan       separately due to us requiring two different sets of semantics
9493961b263Sstephan       for those, depending on how their SQL argument is provided. */
950de868175Sstephan    /* sqlite3_randomness() uses a hand-written wrapper to extend
951de868175Sstephan       the range of supported argument types. */
95253d4e01dSstephan    ["sqlite3_realloc", "*","*","int"],
9533961b263Sstephan    ["sqlite3_reset", "int", "sqlite3_stmt*"],
9543961b263Sstephan    ["sqlite3_result_blob",undefined, "*", "*", "int", "*"],
9553961b263Sstephan    ["sqlite3_result_double",undefined, "*", "f64"],
9563961b263Sstephan    ["sqlite3_result_error",undefined, "*", "string", "int"],
9573961b263Sstephan    ["sqlite3_result_error_code", undefined, "*", "int"],
9583961b263Sstephan    ["sqlite3_result_error_nomem", undefined, "*"],
9593961b263Sstephan    ["sqlite3_result_error_toobig", undefined, "*"],
9603961b263Sstephan    ["sqlite3_result_int",undefined, "*", "int"],
9613961b263Sstephan    ["sqlite3_result_null",undefined, "*"],
9623961b263Sstephan    ["sqlite3_result_text",undefined, "*", "string", "int", "*"],
96353d4e01dSstephan    ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
964ef11fb91Sstephan    ["sqlite3_shutdown", undefined],
9653961b263Sstephan    ["sqlite3_sourceid", "string"],
9663961b263Sstephan    ["sqlite3_sql", "string", "sqlite3_stmt*"],
9673961b263Sstephan    ["sqlite3_step", "int", "sqlite3_stmt*"],
9683961b263Sstephan    ["sqlite3_strglob", "int", "string","string"],
9693961b263Sstephan    ["sqlite3_strlike", "int", "string","string","int"],
9704f5bbedbSstephan    ["sqlite3_trace_v2", "int", "sqlite3*", "int", "*", "*"],
9713961b263Sstephan    ["sqlite3_total_changes", "int", "sqlite3*"],
97289071030Sstephan    ["sqlite3_uri_boolean", "int", "string", "string", "int"],
97389071030Sstephan    ["sqlite3_uri_key", "string", "string", "int"],
97489071030Sstephan    ["sqlite3_uri_parameter", "string", "string", "string"],
975510a9d1cSstephan    ["sqlite3_user_data","void*", "sqlite3_context*"],
976510a9d1cSstephan    ["sqlite3_value_blob", "*", "sqlite3_value*"],
977510a9d1cSstephan    ["sqlite3_value_bytes","int", "sqlite3_value*"],
978510a9d1cSstephan    ["sqlite3_value_double","f64", "sqlite3_value*"],
979510a9d1cSstephan    ["sqlite3_value_int","int", "sqlite3_value*"],
980510a9d1cSstephan    ["sqlite3_value_text", "string", "sqlite3_value*"],
981510a9d1cSstephan    ["sqlite3_value_type", "int", "sqlite3_value*"],
9823961b263Sstephan    ["sqlite3_vfs_find", "*", "string"],
983a6ca996eSstephan    ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
984a6ca996eSstephan    ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
9852b776ee2Sstephan  ]/*wasm.bindingSignatures*/;
9863961b263Sstephan
9872b776ee2Sstephan  if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
9883961b263Sstephan    /* ^^^ "the problem" is that this is an option feature and the
9893961b263Sstephan       build-time function-export list does not currently take
9903961b263Sstephan       optional features into account. */
9912b776ee2Sstephan    wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
9923961b263Sstephan  }
9933961b263Sstephan
9943961b263Sstephan  /**
9953961b263Sstephan     Functions which require BigInt (int64) support are separated from
9963961b263Sstephan     the others because we need to conditionally bind them or apply
9973961b263Sstephan     dummy impls, depending on the capabilities of the environment.
9983961b263Sstephan  */
9992b776ee2Sstephan  wasm.bindingSignatures.int64 = [
10003961b263Sstephan    ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
10013961b263Sstephan    ["sqlite3_changes64","i64", ["sqlite3*"]],
10023961b263Sstephan    ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
100353d4e01dSstephan    ["sqlite3_malloc64", "*","i64"],
1004dc6ae602Sstephan    ["sqlite3_msize", "i64", "*"],
100553d4e01dSstephan    ["sqlite3_realloc64", "*","*", "i64"],
1006510a9d1cSstephan    ["sqlite3_result_int64",undefined, "*", "i64"],
100789071030Sstephan    ["sqlite3_total_changes64", "i64", ["sqlite3*"]],
1008510a9d1cSstephan    ["sqlite3_uri_int64", "i64", ["string", "string", "i64"]],
1009510a9d1cSstephan    ["sqlite3_value_int64","i64", "sqlite3_value*"],
10103961b263Sstephan  ];
10113961b263Sstephan
101273079dbaSstephan  /**
101373079dbaSstephan     Functions which are intended solely for API-internal use by the
101473079dbaSstephan     WASM components, not client code. These get installed into
10158948fbeeSstephan     sqlite3.wasm.
101673079dbaSstephan  */
10172b776ee2Sstephan  wasm.bindingSignatures.wasm = [
1018842c5ee8Sstephan    ["sqlite3_wasm_db_reset", "int", "sqlite3*"],
1019842c5ee8Sstephan    ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
1020f45c3370Sstephan    ["sqlite3_wasm_vfs_create_file", "int",
1021f45c3370Sstephan     "sqlite3_vfs*","string","*", "int"],
1022842c5ee8Sstephan    ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
102373079dbaSstephan  ];
102473079dbaSstephan
10253afad4d4Sstephan
10263afad4d4Sstephan  /**
10272b776ee2Sstephan     sqlite3.wasm.pstack (pseudo-stack) holds a special-case
10283afad4d4Sstephan     stack-style allocator intended only for use with _small_ data of
10293afad4d4Sstephan     not more than (in total) a few kb in size, managed as if it were
10303afad4d4Sstephan     stack-based.
10313afad4d4Sstephan
10323afad4d4Sstephan     It has only a single intended usage:
10333afad4d4Sstephan
10343afad4d4Sstephan     ```
10353afad4d4Sstephan     const stackPos = pstack.pointer;
10363afad4d4Sstephan     try{
10373afad4d4Sstephan       const ptr = pstack.alloc(8);
10383afad4d4Sstephan       // ==> pstack.pointer === ptr
10393afad4d4Sstephan       const otherPtr = pstack.alloc(8);
10403afad4d4Sstephan       // ==> pstack.pointer === otherPtr
10413afad4d4Sstephan       ...
10423afad4d4Sstephan     }finally{
10433afad4d4Sstephan       pstack.restore(stackPos);
10443afad4d4Sstephan       // ==> pstack.pointer === stackPos
10453afad4d4Sstephan     }
10463afad4d4Sstephan     ```
10473afad4d4Sstephan
10483afad4d4Sstephan     This allocator is much faster than a general-purpose one but is
10493afad4d4Sstephan     limited to usage patterns like the one shown above.
10503afad4d4Sstephan
10513afad4d4Sstephan     It operates from a static range of memory which lives outside of
10523afad4d4Sstephan     space managed by Emscripten's stack-management, so does not
10533afad4d4Sstephan     collide with Emscripten-provided stack allocation APIs. The
10543afad4d4Sstephan     memory lives in the WASM heap and can be used with routines such
10553afad4d4Sstephan     as wasm.setMemValue() and any wasm.heap8u().slice().
10563afad4d4Sstephan  */
10572b776ee2Sstephan  wasm.pstack = Object.assign(Object.create(null),{
10583afad4d4Sstephan    /**
1059d89a66ecSstephan       Sets the current pstack position to the given pointer. Results
1060d89a66ecSstephan       are undefined if the passed-in value did not come from
10613afad4d4Sstephan       this.pointer.
10623afad4d4Sstephan    */
10632b776ee2Sstephan    restore: wasm.exports.sqlite3_wasm_pstack_restore,
10643afad4d4Sstephan    /**
10653afad4d4Sstephan       Attempts to allocate the given number of bytes from the
10663afad4d4Sstephan       pstack. On success, it zeroes out a block of memory of the
10673afad4d4Sstephan       given size, adjusts the pstack pointer, and returns a pointer
106863e9ec2fSstephan       to the memory. On error, returns throws a WasmAllocError. The
106963e9ec2fSstephan       memory must eventually be released using restore().
10703afad4d4Sstephan
10713afad4d4Sstephan       This method always adjusts the given value to be a multiple
1072193ee11fSstephan       of 8 bytes because failing to do so can lead to incorrect
1073193ee11fSstephan       results when reading and writing 64-bit values from/to the WASM
1074842c5ee8Sstephan       heap. Similarly, the returned address is always 8-byte aligned.
10753afad4d4Sstephan    */
107663e9ec2fSstephan    alloc: (n)=>{
10772b776ee2Sstephan      return wasm.exports.sqlite3_wasm_pstack_alloc(n)
107863e9ec2fSstephan        || WasmAllocError.toss("Could not allocate",n,
107963e9ec2fSstephan                               "bytes from the pstack.");
10802b776ee2Sstephan    },
10813afad4d4Sstephan    /**
1082d89a66ecSstephan       alloc()'s n chunks, each sz bytes, as a single memory block and
10832b776ee2Sstephan       returns the addresses as an array of n element, each holding
10842b776ee2Sstephan       the address of one chunk.
10852b776ee2Sstephan
10862b776ee2Sstephan       Throws a WasmAllocError if allocation fails.
10872b776ee2Sstephan
10882b776ee2Sstephan       Example:
10892b776ee2Sstephan
10902b776ee2Sstephan       ```
10912b776ee2Sstephan       const [p1, p2, p3] = wasm.pstack.allocChunks(3,4);
10922b776ee2Sstephan       ```
10933afad4d4Sstephan    */
10942b776ee2Sstephan    allocChunks: (n,sz)=>{
10952b776ee2Sstephan      const mem = wasm.pstack.alloc(n * sz);
1096d85d0839Sstephan      const rc = [];
10972b776ee2Sstephan      let i = 0, offset = 0;
10982b776ee2Sstephan      for(; i < n; offset = (sz * ++i)){
10992b776ee2Sstephan        rc.push(mem + offset);
11002b776ee2Sstephan      }
11012b776ee2Sstephan      return rc;
11022b776ee2Sstephan    },
11032b776ee2Sstephan    /**
1104d92c652aSstephan       A convenience wrapper for allocChunks() which sizes each chunk
11052b776ee2Sstephan       as either 8 bytes (safePtrSize is truthy) or wasm.ptrSizeof (if
11062b776ee2Sstephan       safePtrSize is falsy).
11072b776ee2Sstephan
11082b776ee2Sstephan       How it returns its result differs depending on its first
11092b776ee2Sstephan       argument: if it's 1, it returns a single pointer value. If it's
11102b776ee2Sstephan       more than 1, it returns the same as allocChunks().
11112b776ee2Sstephan
11122b776ee2Sstephan       When a returned pointers will refer to a 64-bit value, e.g. a
11132b776ee2Sstephan       double or int64, and that value must be written or fetched,
11142b776ee2Sstephan       e.g. using wasm.setMemValue() or wasm.getMemValue(), it is
11152b776ee2Sstephan       important that the pointer in question be aligned to an 8-byte
11162b776ee2Sstephan       boundary or else it will not be fetched or written properly and
11172b776ee2Sstephan       will corrupt or read neighboring memory.
11182b776ee2Sstephan
11192b776ee2Sstephan       However, when all pointers involved point to "small" data, it
1120d89a66ecSstephan       is safe to pass a falsy value to save a tiny bit of memory.
11212b776ee2Sstephan    */
11222b776ee2Sstephan    allocPtr: (n=1,safePtrSize=true)=>{
11232b776ee2Sstephan      return 1===n
11242b776ee2Sstephan        ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof)
11252b776ee2Sstephan        : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof);
11262b776ee2Sstephan    }
11272b776ee2Sstephan  })/*wasm.pstack*/;
11282b776ee2Sstephan  Object.defineProperties(wasm.pstack, {
11292b776ee2Sstephan    /**
11302b776ee2Sstephan       sqlite3.wasm.pstack.pointer resolves to the current pstack
11312716cd25Sstephan       position pointer. This value is intended _only_ to be saved
11322716cd25Sstephan       for passing to restore(). Writing to this memory, without
11332716cd25Sstephan       first reserving it via wasm.pstack.alloc() and friends, leads
11342716cd25Sstephan       to undefined results.
11352b776ee2Sstephan    */
11362b776ee2Sstephan    pointer: {
11373afad4d4Sstephan      configurable: false, iterable: true, writeable: false,
11382b776ee2Sstephan      get: wasm.exports.sqlite3_wasm_pstack_ptr
11393afad4d4Sstephan      //Whether or not a setter as an alternative to restore() is
11403afad4d4Sstephan      //clearer or would just lead to confusion is unclear.
11412b776ee2Sstephan      //set: wasm.exports.sqlite3_wasm_pstack_restore
11422b776ee2Sstephan    },
11433afad4d4Sstephan    /**
1144f03ddccaSstephan       sqlite3.wasm.pstack.quota to the total number of bytes
1145f03ddccaSstephan       available in the pstack, including any space which is currently
1146f03ddccaSstephan       allocated. This value is a compile-time constant.
11472b776ee2Sstephan    */
11482b776ee2Sstephan    quota: {
11492b776ee2Sstephan      configurable: false, iterable: true, writeable: false,
11502b776ee2Sstephan      get: wasm.exports.sqlite3_wasm_pstack_quota
1151f03ddccaSstephan    },
11522b776ee2Sstephan    /**
1153f03ddccaSstephan       sqlite3.wasm.pstack.remaining resolves to the amount of space
1154f03ddccaSstephan       remaining in the pstack.
11553afad4d4Sstephan    */
1156f03ddccaSstephan    remaining: {
11573afad4d4Sstephan      configurable: false, iterable: true, writeable: false,
11582b776ee2Sstephan      get: wasm.exports.sqlite3_wasm_pstack_remaining
1159f03ddccaSstephan    }
1160f03ddccaSstephan  })/*wasm.pstack properties*/;
11613afad4d4Sstephan
1162de868175Sstephan  capi.sqlite3_randomness = (...args)=>{
1163de868175Sstephan    if(1===args.length && util.isTypedArray(args[0])
1164de868175Sstephan      && 1===args[0].BYTES_PER_ELEMENT){
1165de868175Sstephan      const ta = args[0];
1166de868175Sstephan      if(0===ta.byteLength){
1167de868175Sstephan        wasm.exports.sqlite3_randomness(0,0);
1168de868175Sstephan        return ta;
1169de868175Sstephan      }
1170de868175Sstephan      const stack = wasm.pstack.pointer;
1171de868175Sstephan      try {
1172de868175Sstephan        let n = ta.byteLength, offset = 0;
1173de868175Sstephan        const r = wasm.exports.sqlite3_randomness;
1174de868175Sstephan        const heap = wasm.heap8u();
1175de868175Sstephan        const nAlloc = n < 512 ? n : 512;
1176de868175Sstephan        const ptr = wasm.pstack.alloc(nAlloc);
1177de868175Sstephan        do{
1178de868175Sstephan          const j = (n>nAlloc ? nAlloc : n);
1179de868175Sstephan          r(j, ptr);
1180de868175Sstephan          ta.set(typedArrayPart(heap, ptr, ptr+j), offset);
1181de868175Sstephan          n -= j;
1182de868175Sstephan          offset += j;
1183de868175Sstephan        } while(n > 0);
1184de868175Sstephan      }catch(e){
1185de868175Sstephan        console.error("Highly unexpected (and ignored!) "+
1186de868175Sstephan                      "exception in sqlite3_randomness():",e);
1187de868175Sstephan      }finally{
1188de868175Sstephan        wasm.pstack.restore(stack);
1189de868175Sstephan      }
1190de868175Sstephan      return ta;
1191de868175Sstephan    }
11928948fbeeSstephan    wasm.exports.sqlite3_randomness(...args);
1193de868175Sstephan  };
1194de868175Sstephan
11955b9973d8Sstephan  /** State for sqlite3_wasmfs_opfs_dir(). */
1196de868175Sstephan  let __wasmfsOpfsDir = undefined;
11979a4c63b0Sstephan  /**
11983afad4d4Sstephan     If the wasm environment has a WASMFS/OPFS-backed persistent
11993afad4d4Sstephan     storage directory, its path is returned by this function. If it
12003afad4d4Sstephan     does not then it returns "" (noting that "" is a falsy value).
12019a4c63b0Sstephan
1202453af2f6Sstephan     The first time this is called, this function inspects the current
12033afad4d4Sstephan     environment to determine whether persistence support is available
12043afad4d4Sstephan     and, if it is, enables it (if needed).
12059a4c63b0Sstephan
1206f3860120Sstephan     This function currently only recognizes the WASMFS/OPFS storage
12073afad4d4Sstephan     combination and its path refers to storage rooted in the
12083afad4d4Sstephan     Emscripten-managed virtual filesystem.
12099a4c63b0Sstephan  */
12105b9973d8Sstephan  capi.sqlite3_wasmfs_opfs_dir = function(){
1211de868175Sstephan    if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir;
12129a4c63b0Sstephan    // If we have no OPFS, there is no persistent dir
12133d645484Sstephan    const pdir = config.wasmfsOpfsDir;
1214e3cd6760Sstephan    if(!pdir
1215e3cd6760Sstephan       || !self.FileSystemHandle
1216e3cd6760Sstephan       || !self.FileSystemDirectoryHandle
12179a4c63b0Sstephan       || !self.FileSystemFileHandle){
1218de868175Sstephan      return __wasmfsOpfsDir = "";
12199a4c63b0Sstephan    }
12209a4c63b0Sstephan    try{
12212b776ee2Sstephan      if(pdir && 0===wasm.xCallWrapped(
122228ef9bddSstephan        'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
1223e3cd6760Sstephan      )){
1224de868175Sstephan        return __wasmfsOpfsDir = pdir;
12259a4c63b0Sstephan      }else{
1226de868175Sstephan        return __wasmfsOpfsDir = "";
12279a4c63b0Sstephan      }
12289a4c63b0Sstephan    }catch(e){
122928ef9bddSstephan      // sqlite3_wasm_init_wasmfs() is not available
1230de868175Sstephan      return __wasmfsOpfsDir = "";
12319a4c63b0Sstephan    }
12325360f5fcSstephan  };
12339a4c63b0Sstephan
1234453af2f6Sstephan  /**
1235b5ae85ecSstephan     Experimental and subject to change or removal.
1236b5ae85ecSstephan
12375b9973d8Sstephan     Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
12385b915007Sstephan     non-empty string and the given name starts with (that string +
12395b915007Sstephan     '/'), else returns false.
1240453af2f6Sstephan  */
1241842c5ee8Sstephan  capi.sqlite3_wasmfs_filename_is_persistent = function(name){
12425b9973d8Sstephan    const p = capi.sqlite3_wasmfs_opfs_dir();
12435b915007Sstephan    return (p && name) ? name.startsWith(p+'/') : false;
12445360f5fcSstephan  };
12455360f5fcSstephan
124660d9aa7cSstephan  // This bit is highly arguable and is incompatible with the fiddle shell.
12472b776ee2Sstephan  if(false && 0===wasm.exports.sqlite3_vfs_find(0)){
12485360f5fcSstephan    /* Assume that sqlite3_initialize() has not yet been called.
12495360f5fcSstephan       This will be the case in an SQLITE_OS_KV build. */
12502b776ee2Sstephan    wasm.exports.sqlite3_initialize();
12515360f5fcSstephan  }
1252453af2f6Sstephan
1253f3860120Sstephan  /**
125449048b14Sstephan     Given an `sqlite3*`, an sqlite3_vfs name, and an optional db name
125549048b14Sstephan     (defaulting to "main"), returns a truthy value (see below) if
125649048b14Sstephan     that db uses that VFS, else returns false. If pDb is falsy then
125749048b14Sstephan     the 3rd argument is ignored and this function returns a truthy
125849048b14Sstephan     value if the default VFS name matches that of the 2nd
125949048b14Sstephan     argument. Results are undefined if pDb is truthy but refers to an
126049048b14Sstephan     invalid pointer. The 3rd argument specifies the database name of
126149048b14Sstephan     the given database connection to check, defaulting to the main
126249048b14Sstephan     db.
1263f3860120Sstephan
126496b6371dSstephan     The 2nd and 3rd arguments may either be a JS string or a WASM
126596b6371dSstephan     C-string. If the 2nd argument is a NULL WASM pointer, the default
126696b6371dSstephan     VFS is assumed. If the 3rd is a NULL WASM pointer, "main" is
126796b6371dSstephan     assumed.
1268f3860120Sstephan
1269f3860120Sstephan     The truthy value it returns is a pointer to the `sqlite3_vfs`
1270f3860120Sstephan     object.
1271f3860120Sstephan
1272f3860120Sstephan     To permit safe use of this function from APIs which may be called
1273f3860120Sstephan     via the C stack (like SQL UDFs), this function does not throw: if
1274f3860120Sstephan     bad arguments cause a conversion error when passing into
1275f3860120Sstephan     wasm-space, false is returned.
1276f3860120Sstephan  */
127749048b14Sstephan  capi.sqlite3_js_db_uses_vfs = function(pDb,vfsName,dbName=0){
1278f3860120Sstephan    try{
1279278d3fafSstephan      const pK = capi.sqlite3_vfs_find(vfsName);
1280f3860120Sstephan      if(!pK) return false;
1281f3860120Sstephan      else if(!pDb){
128296b6371dSstephan        return pK===capi.sqlite3_vfs_find(0) ? pK : false;
128396b6371dSstephan      }else{
128449048b14Sstephan        return pK===capi.sqlite3_js_db_vfs(pDb,dbName) ? pK : false;
1285f3860120Sstephan      }
1286f3860120Sstephan    }catch(e){
1287f3860120Sstephan      /* Ignore - probably bad args to a wasm-bound function. */
1288f3860120Sstephan      return false;
1289f3860120Sstephan    }
1290f3860120Sstephan  };
1291f3860120Sstephan
12920e0687ccSstephan  /**
12930e0687ccSstephan     Returns an array of the names of all currently-registered sqlite3
12940e0687ccSstephan     VFSes.
12950e0687ccSstephan  */
12968a8244b5Sstephan  capi.sqlite3_js_vfs_list = function(){
12970e0687ccSstephan    const rc = [];
12980e0687ccSstephan    let pVfs = capi.sqlite3_vfs_find(0);
12990e0687ccSstephan    while(pVfs){
13000e0687ccSstephan      const oVfs = new capi.sqlite3_vfs(pVfs);
13012b776ee2Sstephan      rc.push(wasm.cstringToJs(oVfs.$zName));
13020e0687ccSstephan      pVfs = oVfs.$pNext;
13030e0687ccSstephan      oVfs.dispose();
13040e0687ccSstephan    }
13050e0687ccSstephan    return rc;
13060e0687ccSstephan  };
13070e0687ccSstephan
130832781427Sstephan  /**
130932781427Sstephan     Serializes the given `sqlite3*` pointer to a Uint8Array, as per
131032781427Sstephan     sqlite3_serialize(). On success it returns a Uint8Array. On
131132781427Sstephan     error it throws with a description of the problem.
131232781427Sstephan  */
13138a8244b5Sstephan  capi.sqlite3_js_db_export = function(pDb){
13141acfe915Sstephan    if(!pDb) toss3('Invalid sqlite3* argument.');
13151acfe915Sstephan    if(!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.');
1316f064a3bbSstephan    const stack = wasm.pstack.pointer;
131732781427Sstephan    let pOut;
131832781427Sstephan    try{
13193afad4d4Sstephan      const pSize = wasm.pstack.alloc(8/*i64*/ + wasm.ptrSizeof);
132032781427Sstephan      const ppOut = pSize + 8;
132132781427Sstephan      /**
132232781427Sstephan         Maintenance reminder, since this cost a full hour of grief
132332781427Sstephan         and confusion: if the order of pSize/ppOut are reversed in
132432781427Sstephan         that memory block, fetching the value of pSize after the
132532781427Sstephan         export reads a garbage size because it's not on an 8-byte
132632781427Sstephan         memory boundary!
132732781427Sstephan      */
132832781427Sstephan      let rc = wasm.exports.sqlite3_wasm_db_serialize(
132932781427Sstephan        pDb, ppOut, pSize, 0
133032781427Sstephan      );
133132781427Sstephan      if(rc){
13321acfe915Sstephan        toss3("Database serialization failed with code",
13338a8244b5Sstephan             sqlite3.capi.sqlite3_js_rc_str(rc));
133432781427Sstephan      }
13353afad4d4Sstephan      pOut = wasm.getPtrValue(ppOut);
133632781427Sstephan      const nOut = wasm.getMemValue(pSize, 'i64');
133732781427Sstephan      rc = nOut
133832781427Sstephan        ? wasm.heap8u().slice(pOut, pOut + Number(nOut))
133932781427Sstephan        : new Uint8Array();
134032781427Sstephan      return rc;
134132781427Sstephan    }finally{
134232781427Sstephan      if(pOut) wasm.exports.sqlite3_free(pOut);
13433afad4d4Sstephan      wasm.pstack.restore(stack);
134432781427Sstephan    }
134532781427Sstephan  };
134632781427Sstephan
134796b6371dSstephan  /**
134896b6371dSstephan     Given a `sqlite3*` and a database name (JS string or WASM
134996b6371dSstephan     C-string pointer, which may be 0), returns a pointer to the
135096b6371dSstephan     sqlite3_vfs responsible for it. If the given db name is null/0,
135196b6371dSstephan     or not provided, then "main" is assumed.
135296b6371dSstephan  */
135396b6371dSstephan  capi.sqlite3_js_db_vfs =
135496b6371dSstephan    (dbPointer, dbName=0)=>wasm.sqlite3_wasm_db_vfs(dbPointer, dbName);
135596b6371dSstephan
135696b6371dSstephan  /**
135796b6371dSstephan     A thin wrapper around capi.sqlite3_aggregate_context() which
135896b6371dSstephan     behaves the same except that it throws a WasmAllocError if that
13596f3286caSstephan     function returns 0. As a special case, if n is falsy it does
13606f3286caSstephan     _not_ throw if that function returns 0. That special case is
13616f3286caSstephan     intended for use with xFinal() implementations.
136296b6371dSstephan  */
136396b6371dSstephan  capi.sqlite3_js_aggregate_context = (pCtx, n)=>{
136496b6371dSstephan    return capi.sqlite3_aggregate_context(pCtx, n)
13656f3286caSstephan      || (n ? WasmAllocError.toss("Cannot allocate",n,
13666f3286caSstephan                                  "bytes for sqlite3_aggregate_context()")
13676f3286caSstephan          : 0);
136896b6371dSstephan  };
136996b6371dSstephan
13708948fbeeSstephan  if( util.isUIThread() ){
13715b915007Sstephan    /* Features specific to the main window thread... */
13725b915007Sstephan
13735b915007Sstephan    /**
13748a8244b5Sstephan       Internal helper for sqlite3_js_kvvfs_clear() and friends.
13754df2ab57Sstephan       Its argument should be one of ('local','session',"").
13765b915007Sstephan    */
13775b915007Sstephan    const __kvvfsInfo = function(which){
13785b915007Sstephan      const rc = Object.create(null);
13795b915007Sstephan      rc.prefix = 'kvvfs-'+which;
13805b915007Sstephan      rc.stores = [];
13814df2ab57Sstephan      if('session'===which || ""===which) rc.stores.push(self.sessionStorage);
13824df2ab57Sstephan      if('local'===which || ""===which) rc.stores.push(self.localStorage);
13835b915007Sstephan      return rc;
13845b915007Sstephan    };
13855b915007Sstephan
13865b915007Sstephan    /**
13875b915007Sstephan       Clears all storage used by the kvvfs DB backend, deleting any
13885b915007Sstephan       DB(s) stored there. Its argument must be either 'session',
13894df2ab57Sstephan       'local', or "". In the first two cases, only sessionStorage
13905b915007Sstephan       resp. localStorage is cleared. If it's an empty string (the
13915b915007Sstephan       default) then both are cleared. Only storage keys which match
13925b915007Sstephan       the pattern used by kvvfs are cleared: any other client-side
13935b915007Sstephan       data are retained.
13945b915007Sstephan
13955b915007Sstephan       This function is only available in the main window thread.
13965b915007Sstephan
13975b915007Sstephan       Returns the number of entries cleared.
13985b915007Sstephan    */
13994df2ab57Sstephan    capi.sqlite3_js_kvvfs_clear = function(which=""){
14005b915007Sstephan      let rc = 0;
14015b915007Sstephan      const kvinfo = __kvvfsInfo(which);
14025b915007Sstephan      kvinfo.stores.forEach((s)=>{
14035b915007Sstephan        const toRm = [] /* keys to remove */;
14045b915007Sstephan        let i;
14055b915007Sstephan        for( i = 0; i < s.length; ++i ){
14065b915007Sstephan          const k = s.key(i);
14075b915007Sstephan          if(k.startsWith(kvinfo.prefix)) toRm.push(k);
14085b915007Sstephan        }
14095b915007Sstephan        toRm.forEach((kk)=>s.removeItem(kk));
14105b915007Sstephan        rc += toRm.length;
14115b915007Sstephan      });
14125b915007Sstephan      return rc;
14135b915007Sstephan    };
14145b915007Sstephan
14155b915007Sstephan    /**
14165b915007Sstephan       This routine guesses the approximate amount of
14175b915007Sstephan       window.localStorage and/or window.sessionStorage in use by the
14185b915007Sstephan       kvvfs database backend. Its argument must be one of
14194df2ab57Sstephan       ('session', 'local', ""). In the first two cases, only
14205b915007Sstephan       sessionStorage resp. localStorage is counted. If it's an empty
14215b915007Sstephan       string (the default) then both are counted. Only storage keys
14225b915007Sstephan       which match the pattern used by kvvfs are counted. The returned
14235b915007Sstephan       value is the "length" value of every matching key and value,
142481439a07Sstephan       noting that JavaScript stores each character in 2 bytes.
14255b915007Sstephan
14265b915007Sstephan       Note that the returned size is not authoritative from the
14275b915007Sstephan       perspective of how much data can fit into localStorage and
14285b915007Sstephan       sessionStorage, as the precise algorithms for determining
14295b915007Sstephan       those limits are unspecified and may include per-entry
14305b915007Sstephan       overhead invisible to clients.
14315b915007Sstephan    */
14324df2ab57Sstephan    capi.sqlite3_js_kvvfs_size = function(which=""){
14335b915007Sstephan      let sz = 0;
14345b915007Sstephan      const kvinfo = __kvvfsInfo(which);
14355b915007Sstephan      kvinfo.stores.forEach((s)=>{
14365b915007Sstephan        let i;
14375b915007Sstephan        for(i = 0; i < s.length; ++i){
14385b915007Sstephan          const k = s.key(i);
14395b915007Sstephan          if(k.startsWith(kvinfo.prefix)){
14405b915007Sstephan            sz += k.length;
14415b915007Sstephan            sz += s.getItem(k).length;
14425b915007Sstephan          }
14435b915007Sstephan        }
14445b915007Sstephan      });
144532781427Sstephan      return sz * 2 /* because JS uses 2-byte char encoding */;
14465b915007Sstephan    };
14475b915007Sstephan
14485b915007Sstephan  }/* main-window-only bits */
14495b915007Sstephan
14505b9973d8Sstephan
14513961b263Sstephan  /* The remainder of the API will be set up in later steps. */
1452e3cd6760Sstephan  const sqlite3 = {
1453453af2f6Sstephan    WasmAllocError: WasmAllocError,
1454193ee11fSstephan    SQLite3Error: SQLite3Error,
14553961b263Sstephan    capi,
14568948fbeeSstephan    util,
14578948fbeeSstephan    wasm,
14585b9973d8Sstephan    config,
14595b9973d8Sstephan    /**
14608ffc9899Sstephan       Holds the version info of the sqlite3 source tree from which
14618ffc9899Sstephan       the generated sqlite3-api.js gets built. Note that its version
14628ffc9899Sstephan       may well differ from that reported by sqlite3_libversion(), but
14638ffc9899Sstephan       that should be considered a source file mismatch, as the JS and
14648ffc9899Sstephan       WASM files are intended to be built and distributed together.
14658ffc9899Sstephan
14668ffc9899Sstephan       This object is initially a placeholder which gets replaced by a
14678ffc9899Sstephan       build-generated object.
14688ffc9899Sstephan    */
14698ffc9899Sstephan    version: Object.create(null),
14708ffc9899Sstephan    /**
14715b9973d8Sstephan       Performs any optional asynchronous library-level initialization
14725b9973d8Sstephan       which might be required. This function returns a Promise which
1473ff891b4eSstephan       resolves to the sqlite3 namespace object. Any error in the
1474ff891b4eSstephan       async init will be fatal to the init as a whole, but init
1475ff891b4eSstephan       routines are themselves welcome to install dummy catch()
1476ff891b4eSstephan       handlers which are not fatal if their failure should be
1477ff891b4eSstephan       considered non-fatal. If called more than once, the second and
14785b9973d8Sstephan       subsequent calls are no-ops which return a pre-resolved
14795b9973d8Sstephan       Promise.
14805b9973d8Sstephan
1481d18f1bbfSstephan       Ideally this function is called as part of the Promise chain
1482d18f1bbfSstephan       which handles the loading and bootstrapping of the API.  If not
1483d18f1bbfSstephan       then it must be called by client-level code, which must not use
1484d18f1bbfSstephan       the library until the returned promise resolves.
14855b9973d8Sstephan
14865b9973d8Sstephan       Bug: if called while a prior call is still resolving, the 2nd
14875b9973d8Sstephan       call will resolve prematurely, before the 1st call has finished
1488d18f1bbfSstephan       resolving. The current build setup precludes that possibility,
1489d18f1bbfSstephan       so it's only a hypothetical problem if/when this function
1490d18f1bbfSstephan       ever needs to be invoked by clients.
1491b94a9860Sstephan
1492b94a9860Sstephan       In Emscripten-based builds, this function is called
1493b94a9860Sstephan       automatically and deleted from this object.
14945b9973d8Sstephan    */
14955b9973d8Sstephan    asyncPostInit: async function(){
14965b9973d8Sstephan      let lip = sqlite3ApiBootstrap.initializersAsync;
14975b9973d8Sstephan      delete sqlite3ApiBootstrap.initializersAsync;
14985b9973d8Sstephan      if(!lip || !lip.length) return Promise.resolve(sqlite3);
14995b9973d8Sstephan      // Is it okay to resolve these in parallel or do we need them
15005b9973d8Sstephan      // to resolve in order? We currently only have 1, so it
15015b9973d8Sstephan      // makes no difference.
1502ff891b4eSstephan      lip = lip.map((f)=>{
1503ff891b4eSstephan        const p = (f instanceof Promise) ? f : f(sqlite3);
1504ff891b4eSstephan        return p.catch((e)=>{
1505ff891b4eSstephan          console.error("an async sqlite3 initializer failed:",e);
1506ff891b4eSstephan          throw e;
1507ff891b4eSstephan        });
1508ff891b4eSstephan      });
15095b9973d8Sstephan      //let p = lip.shift();
15105b9973d8Sstephan      //while(lip.length) p = p.then(lip.shift());
15115b9973d8Sstephan      //return p.then(()=>sqlite3);
15125b9973d8Sstephan      return Promise.all(lip).then(()=>sqlite3);
1513cd0df83cSstephan    },
1514cd0df83cSstephan    /**
1515cd0df83cSstephan       scriptInfo ideally gets injected into this object by the
1516cd0df83cSstephan       infrastructure which assembles the JS/WASM module. It contains
1517cd0df83cSstephan       state which must be collected before sqlite3ApiBootstrap() can
1518cd0df83cSstephan       be declared. It is not necessarily available to any
1519cd0df83cSstephan       sqlite3ApiBootstrap.initializers but "should" be in place (if
1520cd0df83cSstephan       it's added at all) by the time that
1521cd0df83cSstephan       sqlite3ApiBootstrap.initializersAsync is processed.
1522cd0df83cSstephan
1523cd0df83cSstephan       This state is not part of the public API, only intended for use
1524cd0df83cSstephan       with the sqlite3 API bootstrapping and wasm-loading process.
1525cd0df83cSstephan    */
1526cd0df83cSstephan    scriptInfo: undefined
15273961b263Sstephan  };
15289a55773bSstephan  try{
15299a55773bSstephan    sqlite3ApiBootstrap.initializers.forEach((f)=>{
15309a55773bSstephan      f(sqlite3);
15319a55773bSstephan    });
15329a55773bSstephan  }catch(e){
15339a55773bSstephan    /* If we don't report this here, it can get completely swallowed
15349a55773bSstephan       up and disappear into the abyss of Promises and Workers. */
15359a55773bSstephan    console.error("sqlite3 bootstrap initializer threw:",e);
15369a55773bSstephan    throw e;
15379a55773bSstephan  }
1538e3cd6760Sstephan  delete sqlite3ApiBootstrap.initializers;
1539e3cd6760Sstephan  sqlite3ApiBootstrap.sqlite3 = sqlite3;
1540e3cd6760Sstephan  return sqlite3;
15413961b263Sstephan}/*sqlite3ApiBootstrap()*/;
1542e3cd6760Sstephan/**
1543e3cd6760Sstephan  self.sqlite3ApiBootstrap.initializers is an internal detail used by
1544e3cd6760Sstephan  the various pieces of the sqlite3 API's amalgamation process. It
1545e3cd6760Sstephan  must not be modified by client code except when plugging such code
1546e3cd6760Sstephan  into the amalgamation process.
1547e3cd6760Sstephan
1548e3cd6760Sstephan  Each component of the amalgamation is expected to append a function
1549e3cd6760Sstephan  to this array. When sqlite3ApiBootstrap() is called for the first
1550e3cd6760Sstephan  time, each such function will be called (in their appended order)
1551e3cd6760Sstephan  and passed the sqlite3 namespace object, into which they can install
1552e3cd6760Sstephan  their features (noting that most will also require that certain
1553e3cd6760Sstephan  features alread have been installed).  At the end of that process,
1554e3cd6760Sstephan  this array is deleted.
15555b9973d8Sstephan
15565b9973d8Sstephan  Note that the order of insertion into this array is significant for
15578948fbeeSstephan  some pieces. e.g. sqlite3.capi and sqlite3.wasm cannot be fully
1558ff891b4eSstephan  utilized until the whwasmutil.js part is plugged in via
1559ff891b4eSstephan  sqlite3-api-glue.js.
1560e3cd6760Sstephan*/
1561e3cd6760Sstephanself.sqlite3ApiBootstrap.initializers = [];
15629a34509aSstephan/**
15635b9973d8Sstephan  self.sqlite3ApiBootstrap.initializersAsync is an internal detail
15645b9973d8Sstephan  used by the sqlite3 API's amalgamation process. It must not be
15655b9973d8Sstephan  modified by client code except when plugging such code into the
15665b9973d8Sstephan  amalgamation process.
15675b9973d8Sstephan
1568ff891b4eSstephan  The counterpart of self.sqlite3ApiBootstrap.initializers,
1569ff891b4eSstephan  specifically for initializers which are asynchronous. All entries in
1570ff891b4eSstephan  this list must be either async functions, non-async functions which
1571ff891b4eSstephan  return a Promise, or a Promise. Each function in the list is called
1572ff891b4eSstephan  with the sqlite3 ojbect as its only argument.
1573ff891b4eSstephan
1574ff891b4eSstephan  The resolved value of any Promise is ignored and rejection will kill
1575ff891b4eSstephan  the asyncPostInit() process (at an indeterminate point because all
1576ff891b4eSstephan  of them are run asynchronously in parallel).
15775b9973d8Sstephan
15785b9973d8Sstephan  This list is not processed until the client calls
15795b9973d8Sstephan  sqlite3.asyncPostInit(). This means, for example, that intializers
15805b9973d8Sstephan  added to self.sqlite3ApiBootstrap.initializers may push entries to
15815b9973d8Sstephan  this list.
15825b9973d8Sstephan*/
15835b9973d8Sstephanself.sqlite3ApiBootstrap.initializersAsync = [];
15845b9973d8Sstephan/**
15859a34509aSstephan   Client code may assign sqlite3ApiBootstrap.defaultConfig an
15869a34509aSstephan   object-type value before calling sqlite3ApiBootstrap() (without
15879a34509aSstephan   arguments) in order to tell that call to use this object as its
15889a34509aSstephan   default config value. The intention of this is to provide
15899a34509aSstephan   downstream clients with a reasonably flexible approach for plugging in
15909a34509aSstephan   an environment-suitable configuration without having to define a new
15919a34509aSstephan   global-scope symbol.
15929a34509aSstephan*/
15939a34509aSstephanself.sqlite3ApiBootstrap.defaultConfig = Object.create(null);
15945b915007Sstephan/**
15955b915007Sstephan   Placeholder: gets installed by the first call to
15965b915007Sstephan   self.sqlite3ApiBootstrap(). However, it is recommended that the
15975b915007Sstephan   caller of sqlite3ApiBootstrap() capture its return value and delete
15985b915007Sstephan   self.sqlite3ApiBootstrap after calling it. It returns the same
15995b915007Sstephan   value which will be stored here.
16005b915007Sstephan*/
16019a34509aSstephanself.sqlite3ApiBootstrap.sqlite3 = undefined;
1602cd0df83cSstephan
1603