1/*
2  2022-05-22
3
4  The author disclaims copyright to this source code.  In place of a
5  legal notice, here is a blessing:
6
7  *   May you do good and not evil.
8  *   May you find forgiveness for yourself and forgive others.
9  *   May you share freely, never taking more than you give.
10
11  ***********************************************************************
12
13  This file is intended to be combined at build-time with other
14  related code, most notably a header and footer which wraps this whole
15  file into an Emscripten Module.postRun() handler which has a parameter
16  named "Module" (the Emscripten Module object). The exact requirements,
17  conventions, and build process are very much under construction and
18  will be (re)documented once they've stopped fluctuating so much.
19
20  Specific goals of this project:
21
22  - Except where noted in the non-goals, provide a more-or-less
23    feature-complete wrapper to the sqlite3 C API, insofar as WASM
24    feature parity with C allows for. In fact, provide at least 3
25    APIs...
26
27    1) Bind a low-level sqlite3 API which is as close to the native
28       one as feasible in terms of usage.
29
30    2) A higher-level API, more akin to sql.js and node.js-style
31       implementations. This one speaks directly to the low-level
32       API. This API must be used from the same thread as the
33       low-level API.
34
35    3) A second higher-level API which speaks to the previous APIs via
36       worker messages. This one is intended for use in the main
37       thread, with the lower-level APIs installed in a Worker thread,
38       and talking to them via Worker messages. Because Workers are
39       asynchronouns and have only a single message channel, some
40       acrobatics are needed here to feed async work results back to
41       the client (as we cannot simply pass around callbacks between
42       the main and Worker threads).
43
44  - Insofar as possible, support client-side storage using JS
45    filesystem APIs. As of this writing, such things are still very
46    much TODO. Initial testing with using IndexedDB as backing storage
47    showed it to work reasonably well, but it's also too easy to
48    corrupt by using a web page in two browser tabs because IndexedDB
49    lacks the locking features needed to support that.
50
51  Specific non-goals of this project:
52
53  - As WASM is a web-centric technology and UTF-8 is the King of
54    Encodings in that realm, there are no currently plans to support
55    the UTF16-related sqlite3 APIs. They would add a complication to
56    the bindings for no appreciable benefit. Though web-related
57    implementation details take priority, the lower-level WASM module
58    "should" work in non-web WASM environments.
59
60  - Supporting old or niche-market platforms. WASM is built for a
61    modern web and requires modern platforms.
62
63  - Though scalar User-Defined Functions (UDFs) may be created in
64    JavaScript, there are currently no plans to add support for
65    aggregate and window functions.
66
67  Attribution:
68
69  This project is endebted to the work of sql.js:
70
71  https://github.com/sql-js/sql.js
72
73  sql.js was an essential stepping stone in this code's development as
74  it demonstrated how to handle some of the WASM-related voodoo (like
75  handling pointers-to-pointers and adding JS implementations of
76  C-bound callback functions). These APIs have a considerably
77  different shape than sql.js's, however.
78*/
79
80/**
81   sqlite3ApiBootstrap() is the only global symbol exposed by this
82   API. It is intended to be called one time at the end of the API
83   amalgamation process, passed configuration details for the current
84   environment, and then optionally be removed from the global object
85   using `delete self.sqlite3ApiBootstrap`.
86
87   This function expects a configuration object, intended to abstract
88   away details specific to any given WASM environment, primarily so
89   that it can be used without any _direct_ dependency on
90   Emscripten. The config object is only honored the first time this
91   is called. Subsequent calls ignore the argument and return the same
92   (configured) object which gets initialized by the first call.
93
94   The config object properties include:
95
96   - `Module`[^1]: Emscripten-style module object. Currently only required
97     by certain test code and is _not_ part of the public interface.
98     (TODO: rename this to EmscriptenModule to be more explicit.)
99
100   - `exports`[^1]: the "exports" object for the current WASM
101     environment. In an Emscripten build, this should be set to
102     `Module['asm']`.
103
104   - `memory`[^1]: optional WebAssembly.Memory object, defaulting to
105     `exports.memory`. In Emscripten environments this should be set
106     to `Module.wasmMemory` if the build uses `-sIMPORT_MEMORY`, or be
107     left undefined/falsy to default to `exports.memory` when using
108     WASM-exported memory.
109
110   - `bigIntEnabled`: true if BigInt support is enabled. Defaults to
111     true if self.BigInt64Array is available, else false. Some APIs
112     will throw exceptions if called without BigInt support, as BigInt
113     is required for marshalling C-side int64 into and out of JS.
114
115   - `allocExportName`: the name of the function, in `exports`, of the
116     `malloc(3)`-compatible routine for the WASM environment. Defaults
117     to `"malloc"`.
118
119   - `deallocExportName`: the name of the function, in `exports`, of
120     the `free(3)`-compatible routine for the WASM
121     environment. Defaults to `"free"`.
122
123   - `persistentDirName`[^1]: if the environment supports persistent storage, this
124     directory names the "mount point" for that directory. It must be prefixed
125     by `/` and may currently contain only a single directory-name part. Using
126     the root directory name is not supported by any current persistent backend.
127
128
129   [^1] = This property may optionally be a function, in which case this
130          function re-assigns it to the value returned from that function,
131          enabling delayed evaluation.
132
133*/
134'use strict';
135self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
136  apiConfig = (sqlite3ApiBootstrap.defaultConfig || self.sqlite3ApiConfig)
137){
138  if(sqlite3ApiBootstrap.sqlite3){ /* already initalized */
139    console.warn("sqlite3ApiBootstrap() called multiple times.",
140                 "Config and external initializers are ignored on calls after the first.");
141    return sqlite3ApiBootstrap.sqlite3;
142  }
143  apiConfig = apiConfig || {};
144  const config = Object.create(null);
145  {
146    const configDefaults = {
147      Module: undefined/*needed for some test code, not part of the public API*/,
148      exports: undefined,
149      memory: undefined,
150      bigIntEnabled: !!self.BigInt64Array,
151      allocExportName: 'malloc',
152      deallocExportName: 'free',
153      persistentDirName: '/persistent'
154    };
155    Object.keys(configDefaults).forEach(function(k){
156      config[k] = Object.getOwnPropertyDescriptor(apiConfig, k)
157        ? apiConfig[k] : configDefaults[k];
158    });
159    // Copy over any properties apiConfig defines but configDefaults does not...
160    Object.keys(apiConfig).forEach(function(k){
161      if(!Object.getOwnPropertyDescriptor(config, k)){
162        config[k] = apiConfig[k];
163      }
164    });
165  }
166
167  [
168    // If any of these config options are functions, replace them with
169    // the result of calling that function...
170    'Module', 'exports', 'memory', 'persistentDirName'
171  ].forEach((k)=>{
172    if('function' === typeof config[k]){
173      config[k] = config[k]();
174    }
175  });
176
177  /** Throws a new Error, the message of which is the concatenation
178      all args with a space between each. */
179  const toss = (...args)=>{throw new Error(args.join(' '))};
180
181  if(config.persistentDirName && !/^\/[^/]+$/.test(config.persistentDirName)){
182    toss("config.persistentDirName must be falsy or in the form '/dir-name'.");
183  }
184
185  /**
186     Returns true if n is a 32-bit (signed) integer, else
187     false. This is used for determining when we need to switch to
188     double-type DB operations for integer values in order to keep
189     more precision.
190  */
191  const isInt32 = function(n){
192    return ('bigint'!==typeof n /*TypeError: can't convert BigInt to number*/)
193      && !!(n===(n|0) && n<=2147483647 && n>=-2147483648);
194  };
195
196  /** Returns v if v appears to be a TypedArray, else false. */
197  const isTypedArray = (v)=>{
198    return (v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT)) ? v : false;
199  };
200
201  /**
202     Returns true if v appears to be one of our bind()-able
203     TypedArray types: Uint8Array or Int8Array. Support for
204     TypedArrays with element sizes >1 is TODO.
205  */
206  const isBindableTypedArray = (v)=>{
207    return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);
208  };
209
210  /**
211     Returns true if v appears to be one of the TypedArray types
212     which is legal for holding SQL code (as opposed to binary blobs).
213
214     Currently this is the same as isBindableTypedArray() but it
215     seems likely that we'll eventually want to add Uint32Array
216     and friends to the isBindableTypedArray() list but not to the
217     isSQLableTypedArray() list.
218  */
219  const isSQLableTypedArray = (v)=>{
220    return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);
221  };
222
223  /** Returns true if isBindableTypedArray(v) does, else throws with a message
224      that v is not a supported TypedArray value. */
225  const affirmBindableTypedArray = (v)=>{
226    return isBindableTypedArray(v)
227      || toss("Value is not of a supported TypedArray type.");
228  };
229
230  const utf8Decoder = new TextDecoder('utf-8');
231
232  /** Internal helper to use in operations which need to distinguish
233      between SharedArrayBuffer heap memory and non-shared heap. */
234  const __SAB = ('undefined'===typeof SharedArrayBuffer)
235        ? function(){} : SharedArrayBuffer;
236  const typedArrayToString = function(arrayBuffer, begin, end){
237    return utf8Decoder.decode(
238      (arrayBuffer.buffer instanceof __SAB)
239        ? arrayBuffer.slice(begin, end)
240        : arrayBuffer.subarray(begin, end)
241    );
242  };
243
244  /**
245     An Error subclass specifically for reporting Wasm-level malloc()
246     failure and enabling clients to unambiguously identify such
247     exceptions.
248  */
249  class WasmAllocError extends Error {
250    constructor(...args){
251      super(...args);
252      this.name = 'WasmAllocError';
253    }
254  };
255
256  /**
257      The main sqlite3 binding API gets installed into this object,
258      mimicking the C API as closely as we can. The numerous members
259      names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
260      possible, identically to the C-native counterparts, as documented at:
261
262      https://www.sqlite.org/c3ref/intro.html
263
264      A very few exceptions require an additional level of proxy
265      function or may otherwise require special attention in the WASM
266      environment, and all such cases are document here. Those not
267      documented here are installed as 1-to-1 proxies for their C-side
268      counterparts.
269  */
270  const capi = {
271    /**
272       When using sqlite3_open_v2() it is important to keep the following
273       in mind:
274
275       https://www.sqlite.org/c3ref/open.html
276
277       - The flags for use with its 3rd argument are installed in this
278       object using the C-cide names, e.g. SQLITE_OPEN_CREATE.
279
280       - If the combination of flags passed to it are invalid,
281       behavior is undefined. Thus is is never okay to call this
282       with fewer than 3 arguments, as JS will default the
283       missing arguments to `undefined`, which will result in a
284       flag value of 0. Most of the available SQLITE_OPEN_xxx
285       flags are meaningless in the WASM build, e.g. the mutext-
286       and cache-related flags, but they are retained in this
287       API for consistency's sake.
288
289       - The final argument to this function specifies the VFS to
290       use, which is largely (but not entirely!) meaningless in
291       the WASM environment. It should always be null or
292       undefined, and it is safe to elide that argument when
293       calling this function.
294    */
295    sqlite3_open_v2: function(filename,dbPtrPtr,flags,vfsStr){}/*installed later*/,
296    /**
297       The sqlite3_prepare_v3() binding handles two different uses
298       with differing JS/WASM semantics:
299
300       1) sqlite3_prepare_v3(pDb, sqlString, -1, prepFlags, ppStmt [, null])
301
302       2) sqlite3_prepare_v3(pDb, sqlPointer, sqlByteLen, prepFlags, ppStmt, sqlPointerToPointer)
303
304       Note that the SQL length argument (the 3rd argument) must, for
305       usage (1), always be negative because it must be a byte length
306       and that value is expensive to calculate from JS (where only
307       the character length of strings is readily available). It is
308       retained in this API's interface for code/documentation
309       compatibility reasons but is currently _always_ ignored. With
310       usage (2), the 3rd argument is used as-is but is is still
311       critical that the C-style input string (2nd argument) be
312       terminated with a 0 byte.
313
314       In usage (1), the 2nd argument must be of type string,
315       Uint8Array, or Int8Array (either of which is assumed to
316       hold SQL). If it is, this function assumes case (1) and
317       calls the underyling C function with the equivalent of:
318
319       (pDb, sqlAsString, -1, prepFlags, ppStmt, null)
320
321       The pzTail argument is ignored in this case because its result
322       is meaningless when a string-type value is passed through
323       (because the string goes through another level of internal
324       conversion for WASM's sake and the result pointer would refer
325       to that transient conversion's memory, not the passed-in
326       string).
327
328       If the sql argument is not a string, it must be a _pointer_ to
329       a NUL-terminated string which was allocated in the WASM memory
330       (e.g. using cwapi.wasm.alloc() or equivalent). In that case,
331       the final argument may be 0/null/undefined or must be a pointer
332       to which the "tail" of the compiled SQL is written, as
333       documented for the C-side sqlite3_prepare_v3(). In case (2),
334       the underlying C function is called with the equivalent of:
335
336       (pDb, sqlAsPointer, (sqlByteLen||-1), prepFlags, ppStmt, pzTail)
337
338       It returns its result and compiled statement as documented in
339       the C API. Fetching the output pointers (5th and 6th
340       parameters) requires using capi.wasm.getMemValue() (or
341       equivalent) and the pzTail will point to an address relative to
342       the sqlAsPointer value.
343
344       If passed an invalid 2nd argument type, this function will
345       return SQLITE_MISUSE but will unfortunately be able to return
346       any additional error information because we have no way to set
347       the db's error state such that this function could return a
348       non-0 integer and the client could call sqlite3_errcode() or
349       sqlite3_errmsg() to fetch it. See the RFE at:
350
351       https://sqlite.org/forum/forumpost/f9eb79b11aefd4fc81d
352
353       The alternative would be to throw an exception for that case,
354       but that would be in strong constrast to the rest of the
355       C-level API and seems likely to cause more confusion.
356
357       Side-note: in the C API the function does not fail if provided
358       an empty string but its result output pointer will be NULL.
359    */
360    sqlite3_prepare_v3: function(dbPtr, sql, sqlByteLen, prepFlags,
361                                 stmtPtrPtr, strPtrPtr){}/*installed later*/,
362
363    /**
364       Equivalent to calling sqlite3_prapare_v3() with 0 as its 4th argument.
365    */
366    sqlite3_prepare_v2: function(dbPtr, sql, sqlByteLen, stmtPtrPtr,
367                                 strPtrPtr){}/*installed later*/,
368
369    /**
370       Various internal-use utilities are added here as needed. They
371       are bound to an object only so that we have access to them in
372       the differently-scoped steps of the API bootstrapping
373       process. At the end of the API setup process, this object gets
374       removed.
375    */
376    util:{
377      isInt32, isTypedArray, isBindableTypedArray, isSQLableTypedArray,
378      affirmBindableTypedArray, typedArrayToString
379    },
380
381    /**
382       Holds state which are specific to the WASM-related
383       infrastructure and glue code. It is not expected that client
384       code will normally need these, but they're exposed here in case
385       it does. These APIs are _not_ to be considered an
386       official/stable part of the sqlite3 WASM API. They may change
387       as the developers' experience suggests appropriate changes.
388
389       Note that a number of members of this object are injected
390       dynamically after the api object is fully constructed, so
391       not all are documented inline here.
392    */
393    wasm: {
394    //^^^ TODO?: move wasm from sqlite3.capi.wasm to sqlite3.wasm
395      /**
396         Emscripten APIs have a deep-seated assumption that all pointers
397         are 32 bits. We'll remain optimistic that that won't always be
398         the case and will use this constant in places where we might
399         otherwise use a hard-coded 4.
400      */
401      ptrSizeof: config.wasmPtrSizeof || 4,
402      /**
403         The WASM IR (Intermediate Representation) value for
404         pointer-type values. It MUST refer to a value type of the
405         size described by this.ptrSizeof _or_ it may be any value
406         which ends in '*', which Emscripten's glue code internally
407         translates to i32.
408      */
409      ptrIR: config.wasmPtrIR || "i32",
410      /**
411         True if BigInt support was enabled via (e.g.) the
412         Emscripten -sWASM_BIGINT flag, else false. When
413         enabled, certain 64-bit sqlite3 APIs are enabled which
414         are not otherwise enabled due to JS/WASM int64
415         impedence mismatches.
416      */
417      bigIntEnabled: !!config.bigIntEnabled,
418      /**
419         The symbols exported by the WASM environment.
420      */
421      exports: config.exports
422        || toss("Missing API config.exports (WASM module exports)."),
423
424      /**
425         When Emscripten compiles with `-sIMPORT_MEMORY`, it
426         initalizes the heap and imports it into wasm, as opposed to
427         the other way around. In this case, the memory is not
428         available via this.exports.memory.
429      */
430      memory: config.memory || config.exports['memory']
431        || toss("API config object requires a WebAssembly.Memory object",
432                "in either config.exports.memory (exported)",
433                "or config.memory (imported)."),
434
435      /**
436         The API's one single point of access to the WASM-side memory
437         allocator. Works like malloc(3) (and is likely bound to
438         malloc()) but throws an WasmAllocError if allocation fails. It is
439         important that any code which might pass through the sqlite3 C
440         API NOT throw and must instead return SQLITE_NOMEM (or
441         equivalent, depending on the context).
442
443         That said, very few cases in the API can result in
444         client-defined functions propagating exceptions via the C-style
445         API. Most notably, this applies ot User-defined SQL Functions
446         (UDFs) registered via sqlite3_create_function_v2(). For that
447         specific case it is recommended that all UDF creation be
448         funneled through a utility function and that a wrapper function
449         be added around the UDF which catches any exception and sets
450         the error state to OOM. (The overall complexity of registering
451         UDFs essentially requires a helper for doing so!)
452      */
453      alloc: undefined/*installed later*/,
454      /**
455         The API's one single point of access to the WASM-side memory
456         deallocator. Works like free(3) (and is likely bound to
457         free()).
458      */
459      dealloc: undefined/*installed later*/
460
461      /* Many more wasm-related APIs get installed later on. */
462    }/*wasm*/
463  }/*capi*/;
464
465  /**
466     capi.wasm.alloc()'s srcTypedArray.byteLength bytes,
467     populates them with the values from the source
468     TypedArray, and returns the pointer to that memory. The
469     returned pointer must eventually be passed to
470     capi.wasm.dealloc() to clean it up.
471
472     As a special case, to avoid further special cases where
473     this is used, if srcTypedArray.byteLength is 0, it
474     allocates a single byte and sets it to the value
475     0. Even in such cases, calls must behave as if the
476     allocated memory has exactly srcTypedArray.byteLength
477     bytes.
478
479     ACHTUNG: this currently only works for Uint8Array and
480     Int8Array types and will throw if srcTypedArray is of
481     any other type.
482  */
483  capi.wasm.allocFromTypedArray = function(srcTypedArray){
484    affirmBindableTypedArray(srcTypedArray);
485    const pRet = this.alloc(srcTypedArray.byteLength || 1);
486    this.heapForSize(srcTypedArray.constructor).set(srcTypedArray.byteLength ? srcTypedArray : [0], pRet);
487    return pRet;
488  }.bind(capi.wasm);
489
490  const keyAlloc = config.allocExportName || 'malloc',
491        keyDealloc =  config.deallocExportName || 'free';
492  for(const key of [keyAlloc, keyDealloc]){
493    const f = capi.wasm.exports[key];
494    if(!(f instanceof Function)) toss("Missing required exports[",key,"] function.");
495  }
496
497  capi.wasm.alloc = function(n){
498    const m = this.exports[keyAlloc](n);
499    if(!m) throw new WasmAllocError("Failed to allocate "+n+" bytes.");
500    return m;
501  }.bind(capi.wasm)
502
503  capi.wasm.dealloc = (m)=>capi.wasm.exports[keyDealloc](m);
504
505  /**
506     Reports info about compile-time options using
507     sqlite_compileoption_get() and sqlite3_compileoption_used(). It
508     has several distinct uses:
509
510     If optName is an array then it is expected to be a list of
511     compilation options and this function returns an object
512     which maps each such option to true or false, indicating
513     whether or not the given option was included in this
514     build. That object is returned.
515
516     If optName is an object, its keys are expected to be compilation
517     options and this function sets each entry to true or false,
518     indicating whether the compilation option was used or not. That
519     object is returned.
520
521     If passed no arguments then it returns an object mapping
522     all known compilation options to their compile-time values,
523     or boolean true if they are defined with no value. This
524     result, which is relatively expensive to compute, is cached
525     and returned for future no-argument calls.
526
527     In all other cases it returns true if the given option was
528     active when when compiling the sqlite3 module, else false.
529
530     Compile-time option names may optionally include their
531     "SQLITE_" prefix. When it returns an object of all options,
532     the prefix is elided.
533  */
534  capi.wasm.compileOptionUsed = function f(optName){
535    if(!arguments.length){
536      if(f._result) return f._result;
537      else if(!f._opt){
538        f._rx = /^([^=]+)=(.+)/;
539        f._rxInt = /^-?\d+$/;
540        f._opt = function(opt, rv){
541          const m = f._rx.exec(opt);
542          rv[0] = (m ? m[1] : opt);
543          rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true;
544        };
545      }
546      const rc = {}, ov = [0,0];
547      let i = 0, k;
548      while((k = capi.sqlite3_compileoption_get(i++))){
549        f._opt(k,ov);
550        rc[ov[0]] = ov[1];
551      }
552      return f._result = rc;
553    }else if(Array.isArray(optName)){
554      const rc = {};
555      optName.forEach((v)=>{
556        rc[v] = capi.sqlite3_compileoption_used(v);
557      });
558      return rc;
559    }else if('object' === typeof optName){
560      Object.keys(optName).forEach((k)=> {
561        optName[k] = capi.sqlite3_compileoption_used(k);
562      });
563      return optName;
564    }
565    return (
566      'string'===typeof optName
567    ) ? !!capi.sqlite3_compileoption_used(optName) : false;
568  }/*compileOptionUsed()*/;
569
570  capi.wasm.bindingSignatures = [
571    /**
572       Signatures for the WASM-exported C-side functions. Each entry
573       is an array with 2+ elements:
574
575       ["c-side name",
576        "result type" (capi.wasm.xWrap() syntax),
577         [arg types in xWrap() syntax]
578         // ^^^ this needn't strictly be an array: it can be subsequent
579         // elements instead: [x,y,z] is equivalent to x,y,z
580       ]
581    */
582    // Please keep these sorted by function name!
583    ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"],
584    ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
585    ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
586    ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
587    ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
588    ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
589    ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int"],
590    ["sqlite3_close_v2", "int", "sqlite3*"],
591    ["sqlite3_changes", "int", "sqlite3*"],
592    ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
593    ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
594    ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
595    ["sqlite3_column_count", "int", "sqlite3_stmt*"],
596    ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
597    ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
598    ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
599    ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
600    ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
601    ["sqlite3_compileoption_get", "string", "int"],
602    ["sqlite3_compileoption_used", "int", "string"],
603    ["sqlite3_create_function_v2", "int",
604     "sqlite3*", "string", "int", "int", "*", "*", "*", "*", "*"],
605    ["sqlite3_data_count", "int", "sqlite3_stmt*"],
606    ["sqlite3_db_filename", "string", "sqlite3*", "string"],
607    ["sqlite3_db_name", "string", "sqlite3*", "int"],
608    ["sqlite3_errmsg", "string", "sqlite3*"],
609    ["sqlite3_error_offset", "int", "sqlite3*"],
610    ["sqlite3_errstr", "string", "int"],
611    //["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**"],
612    // ^^^ TODO: we need a wrapper to support passing a function pointer or a function
613    // for the callback.
614    ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
615    ["sqlite3_extended_errcode", "int", "sqlite3*"],
616    ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
617    ["sqlite3_finalize", "int", "sqlite3_stmt*"],
618    ["sqlite3_initialize", undefined],
619    ["sqlite3_interrupt", undefined, "sqlite3*"
620     /* ^^^ we cannot actually currently support this because JS is
621        single-threaded and we don't have a portable way to access a DB
622        from 2 SharedWorkers concurrently. */],
623    ["sqlite3_libversion", "string"],
624    ["sqlite3_libversion_number", "int"],
625    ["sqlite3_open", "int", "string", "*"],
626    ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
627    /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
628       separately due to us requiring two different sets of semantics
629       for those, depending on how their SQL argument is provided. */
630    ["sqlite3_reset", "int", "sqlite3_stmt*"],
631    ["sqlite3_result_blob",undefined, "*", "*", "int", "*"],
632    ["sqlite3_result_double",undefined, "*", "f64"],
633    ["sqlite3_result_error",undefined, "*", "string", "int"],
634    ["sqlite3_result_error_code", undefined, "*", "int"],
635    ["sqlite3_result_error_nomem", undefined, "*"],
636    ["sqlite3_result_error_toobig", undefined, "*"],
637    ["sqlite3_result_int",undefined, "*", "int"],
638    ["sqlite3_result_null",undefined, "*"],
639    ["sqlite3_result_text",undefined, "*", "string", "int", "*"],
640    ["sqlite3_sourceid", "string"],
641    ["sqlite3_sql", "string", "sqlite3_stmt*"],
642    ["sqlite3_step", "int", "sqlite3_stmt*"],
643    ["sqlite3_strglob", "int", "string","string"],
644    ["sqlite3_strlike", "int", "string","string","int"],
645    ["sqlite3_total_changes", "int", "sqlite3*"],
646    ["sqlite3_value_blob", "*", "*"],
647    ["sqlite3_value_bytes","int", "*"],
648    ["sqlite3_value_double","f64", "*"],
649    ["sqlite3_value_text", "string", "*"],
650    ["sqlite3_value_type", "int", "*"],
651    ["sqlite3_vfs_find", "*", "string"],
652    ["sqlite3_vfs_register", "int", "*", "int"],
653    ["sqlite3_wasm_vfs_unlink", "int", "string"]
654  ]/*capi.wasm.bindingSignatures*/;
655
656  if(false && capi.wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
657    /* ^^^ "the problem" is that this is an option feature and the
658       build-time function-export list does not currently take
659       optional features into account. */
660    capi.wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
661  }
662
663  /**
664     Functions which require BigInt (int64) support are separated from
665     the others because we need to conditionally bind them or apply
666     dummy impls, depending on the capabilities of the environment.
667  */
668  capi.wasm.bindingSignatures.int64 = [
669      ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
670      ["sqlite3_changes64","i64", ["sqlite3*"]],
671      ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
672      ["sqlite3_total_changes64", "i64", ["sqlite3*"]]
673  ];
674
675  /** State for sqlite3_web_persistent_dir(). */
676  let __persistentDir;
677  /**
678     An experiment. Do not use.
679
680     If the wasm environment has a persistent storage directory,
681     its path is returned by this function. If it does not then
682     it returns "" (noting that "" is a falsy value).
683
684     The first time this is called, this function inspects the current
685     environment to determine whether persistence filesystem support
686     is available and, if it is, enables it (if needed).
687
688     TODOs and caveats:
689
690     - If persistent storage is available at the root of the virtual
691       filesystem, this interface cannot currently distinguish that
692       from the lack of persistence. That case cannot currently (with
693       WASMFS/OPFS) happen, but it is conceivably possible in future
694       environments or non-browser runtimes (none of which are yet
695       supported targets).
696  */
697  capi.sqlite3_web_persistent_dir = function(){
698    if(undefined !== __persistentDir) return __persistentDir;
699    // If we have no OPFS, there is no persistent dir
700    const pdir = config.persistentDirName;
701    if(!pdir
702       || !self.FileSystemHandle
703       || !self.FileSystemDirectoryHandle
704       || !self.FileSystemFileHandle){
705      return __persistentDir = "";
706    }
707    try{
708      if(pdir && 0===this.wasm.xCallWrapped(
709        'sqlite3_wasm_init_opfs', 'i32', ['string'], pdir
710      )){
711        /** OPFS does not support locking and will trigger errors if
712            we try to lock. We don't _really_ want to
713            _unconditionally_ install a non-locking sqlite3 VFS as the
714            default, but we do so here for simplicy's sake for the
715            time being. That said: locking is a no-op on all of the
716            current WASM storage, so this isn't (currently) as bad as
717            it may initially seem. */
718        const pVfs = sqlite3.capi.sqlite3_vfs_find("unix-none");
719        if(pVfs){
720          capi.sqlite3_vfs_register(pVfs,1);
721          console.warn("Installed 'unix-none' as the default sqlite3 VFS.");
722        }
723        return __persistentDir = pdir;
724      }else{
725        return __persistentDir = "";
726      }
727    }catch(e){
728      // sqlite3_wasm_init_opfs() is not available
729      return __persistentDir = "";
730    }
731  }.bind(capi);
732
733  /**
734     Returns true if sqlite3.capi.sqlite3_web_persistent_dir() is a
735     non-empty string and the given name has that string as its
736     prefix, else returns false.
737  */
738  capi.sqlite3_web_filename_is_persistent = function(name){
739    const p = this.sqlite3_web_persistent_dir();
740    return (p && name) ? name.startsWith(p) : false;
741  }.bind(capi);
742
743  /* The remainder of the API will be set up in later steps. */
744  const sqlite3 = {
745    WasmAllocError: WasmAllocError,
746    capi,
747    config
748  };
749  sqlite3ApiBootstrap.initializers.forEach((f)=>f(sqlite3));
750  delete sqlite3ApiBootstrap.initializers;
751  sqlite3ApiBootstrap.sqlite3 = sqlite3;
752  return sqlite3;
753}/*sqlite3ApiBootstrap()*/;
754/**
755  self.sqlite3ApiBootstrap.initializers is an internal detail used by
756  the various pieces of the sqlite3 API's amalgamation process. It
757  must not be modified by client code except when plugging such code
758  into the amalgamation process.
759
760  Each component of the amalgamation is expected to append a function
761  to this array. When sqlite3ApiBootstrap() is called for the first
762  time, each such function will be called (in their appended order)
763  and passed the sqlite3 namespace object, into which they can install
764  their features (noting that most will also require that certain
765  features alread have been installed).  At the end of that process,
766  this array is deleted.
767*/
768self.sqlite3ApiBootstrap.initializers = [];
769/**
770   Client code may assign sqlite3ApiBootstrap.defaultConfig an
771   object-type value before calling sqlite3ApiBootstrap() (without
772   arguments) in order to tell that call to use this object as its
773   default config value. The intention of this is to provide
774   downstream clients with a reasonably flexible approach for plugging in
775   an environment-suitable configuration without having to define a new
776   global-scope symbol.
777*/
778self.sqlite3ApiBootstrap.defaultConfig = Object.create(null);
779/** Placeholder: gets installed by the first call to
780    self.sqlite3ApiBootstrap(). */
781self.sqlite3ApiBootstrap.sqlite3 = undefined;
782