1/*
2  2022-07-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 contains the so-called OO #1 API wrapper for the sqlite3
14  WASM build. It requires that sqlite3-api-glue.js has already run
15  and it installs its deliverable as self.sqlite3.oo1.
16*/
17self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
18  const toss = (...args)=>{throw new Error(args.join(' '))};
19  const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
20
21  const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
22  /* What follows is colloquially known as "OO API #1". It is a
23     binding of the sqlite3 API which is designed to be run within
24     the same thread (main or worker) as the one in which the
25     sqlite3 WASM binding was initialized. This wrapper cannot use
26     the sqlite3 binding if, e.g., the wrapper is in the main thread
27     and the sqlite3 API is in a worker. */
28
29  /**
30     In order to keep clients from manipulating, perhaps
31     inadvertently, the underlying pointer values of DB and Stmt
32     instances, we'll gate access to them via the `pointer` property
33     accessor and store their real values in this map. Keys = DB/Stmt
34     objects, values = pointer values. This also unifies how those are
35     accessed, for potential use downstream via custom
36     wasm.xWrap() function signatures which know how to extract
37     it.
38  */
39  const __ptrMap = new WeakMap();
40  /**
41     Map of DB instances to objects, each object being a map of Stmt
42     wasm pointers to Stmt objects.
43  */
44  const __stmtMap = new WeakMap();
45
46  /** If object opts has _its own_ property named p then that
47      property's value is returned, else dflt is returned. */
48  const getOwnOption = (opts, p, dflt)=>{
49    const d = Object.getOwnPropertyDescriptor(opts,p);
50    return d ? d.value : dflt;
51  };
52
53  // Documented in DB.checkRc()
54  const checkSqlite3Rc = function(dbPtr, sqliteResultCode){
55    if(sqliteResultCode){
56      if(dbPtr instanceof DB) dbPtr = dbPtr.pointer;
57      toss3(
58        "sqlite result code",sqliteResultCode+":",
59        (dbPtr
60         ? capi.sqlite3_errmsg(dbPtr)
61         : capi.sqlite3_errstr(sqliteResultCode))
62      );
63    }
64  };
65
66  /**
67     sqlite3_trace_v2() callback which gets installed by the DB ctor
68     if its open-flags contain "t".
69  */
70  const __dbTraceToConsole =
71        wasm.installFunction('i(ippp)', function(t,c,p,x){
72          if(capi.SQLITE_TRACE_STMT===t){
73            // x == SQL, p == sqlite3_stmt*
74            console.log("SQL TRACE #"+(++this.counter),
75                        wasm.cstringToJs(x));
76          }
77        }.bind({counter: 0}));
78
79  /**
80     A map of sqlite3_vfs pointers to SQL code to run when the DB
81     constructor opens a database with the given VFS.
82  */
83  const __vfsPostOpenSql = Object.create(null);
84
85  /**
86     A proxy for DB class constructors. It must be called with the
87     being-construct DB object as its "this". See the DB constructor
88     for the argument docs. This is split into a separate function
89     in order to enable simple creation of special-case DB constructors,
90     e.g. JsStorageDb and OpfsDb.
91
92     Expects to be passed a configuration object with the following
93     properties:
94
95     - `.filename`: the db filename. It may be a special name like ":memory:"
96       or "".
97
98     - `.flags`: as documented in the DB constructor.
99
100     - `.vfs`: as documented in the DB constructor.
101
102     It also accepts those as the first 3 arguments.
103  */
104  const dbCtorHelper = function ctor(...args){
105    if(!ctor._name2vfs){
106      /**
107         Map special filenames which we handle here (instead of in C)
108         to some helpful metadata...
109
110         As of 2022-09-20, the C API supports the names :localStorage:
111         and :sessionStorage: for kvvfs. However, C code cannot
112         determine (without embedded JS code, e.g. via Emscripten's
113         EM_JS()) whether the kvvfs is legal in the current browser
114         context (namely the main UI thread). In order to help client
115         code fail early on, instead of it being delayed until they
116         try to read or write a kvvfs-backed db, we'll check for those
117         names here and throw if they're not legal in the current
118         context.
119      */
120      ctor._name2vfs = Object.create(null);
121      const isWorkerThread = ('function'===typeof importScripts/*===running in worker thread*/)
122            ? (n)=>toss3("The VFS for",n,"is only available in the main window thread.")
123            : false;
124      ctor._name2vfs[':localStorage:'] = {
125        vfs: 'kvvfs', filename: isWorkerThread || (()=>'local')
126      };
127      ctor._name2vfs[':sessionStorage:'] = {
128        vfs: 'kvvfs', filename: isWorkerThread || (()=>'session')
129      };
130    }
131    const opt = ctor.normalizeArgs(...args);
132    let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
133    if(('string'!==typeof fn && 'number'!==typeof fn)
134       || 'string'!==typeof flagsStr
135       || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
136      console.error("Invalid DB ctor args",opt,arguments);
137      toss3("Invalid arguments for DB constructor.");
138    }
139    let fnJs = ('number'===typeof fn) ? wasm.cstringToJs(fn) : fn;
140    const vfsCheck = ctor._name2vfs[fnJs];
141    if(vfsCheck){
142      vfsName = vfsCheck.vfs;
143      fn = fnJs = vfsCheck.filename(fnJs);
144    }
145    let pDb, oflags = 0;
146    if( flagsStr.indexOf('c')>=0 ){
147      oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
148    }
149    if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
150    if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
151    oflags |= capi.SQLITE_OPEN_EXRESCODE;
152    const stack = wasm.pstack.pointer;
153    try {
154      const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
155      let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
156      pDb = wasm.getPtrValue(pPtr);
157      checkSqlite3Rc(pDb, rc);
158      if(flagsStr.indexOf('t')>=0){
159        capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
160                              __dbTraceToConsole, 0);
161      }
162      // Check for per-VFS post-open SQL...
163      const pVfs = capi.sqlite3_js_db_vfs(pDb);
164      //console.warn("Opened db",fn,"with vfs",vfsName,pVfs);
165      if(!pVfs) toss3("Internal error: cannot get VFS for new db handle.");
166      const postInitSql = __vfsPostOpenSql[pVfs];
167      if(postInitSql){
168        rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0);
169        checkSqlite3Rc(pDb, rc);
170      }
171    }catch( e ){
172      if( pDb ) capi.sqlite3_close_v2(pDb);
173      throw e;
174    }finally{
175      wasm.pstack.restore(stack);
176    }
177    this.filename = fnJs;
178    __ptrMap.set(this, pDb);
179    __stmtMap.set(this, Object.create(null));
180  };
181
182  /**
183     Sets SQL which should be exec()'d on a DB instance after it is
184     opened with the given VFS pointer. This is intended only for use
185     by DB subclasses or sqlite3_vfs implementations.
186  */
187  dbCtorHelper.setVfsPostOpenSql = function(pVfs, sql){
188    __vfsPostOpenSql[pVfs] = sql;
189  };
190
191  /**
192     A helper for DB constructors. It accepts either a single
193     config-style object or up to 3 arguments (filename, dbOpenFlags,
194     dbVfsName). It returns a new object containing:
195
196     { filename: ..., flags: ..., vfs: ... }
197
198     If passed an object, any additional properties it has are copied
199     as-is into the new object.
200  */
201  dbCtorHelper.normalizeArgs = function(filename=':memory:',flags = 'c',vfs = null){
202    const arg = {};
203    if(1===arguments.length && 'object'===typeof arguments[0]){
204      const x = arguments[0];
205      Object.keys(x).forEach((k)=>arg[k] = x[k]);
206      if(undefined===arg.flags) arg.flags = 'c';
207      if(undefined===arg.vfs) arg.vfs = null;
208      if(undefined===arg.filename) arg.filename = ':memory:';
209    }else{
210      arg.filename = filename;
211      arg.flags = flags;
212      arg.vfs = vfs;
213    }
214    return arg;
215  };
216  /**
217     The DB class provides a high-level OO wrapper around an sqlite3
218     db handle.
219
220     The given db filename must be resolvable using whatever
221     filesystem layer (virtual or otherwise) is set up for the default
222     sqlite3 VFS.
223
224     Note that the special sqlite3 db names ":memory:" and ""
225     (temporary db) have their normal special meanings here and need
226     not resolve to real filenames, but "" uses an on-storage
227     temporary database and requires that the VFS support that.
228
229     The second argument specifies the open/create mode for the
230     database. It must be string containing a sequence of letters (in
231     any order, but case sensitive) specifying the mode:
232
233     - "c": create if it does not exist, else fail if it does not
234       exist. Implies the "w" flag.
235
236     - "w": write. Implies "r": a db cannot be write-only.
237
238     - "r": read-only if neither "w" nor "c" are provided, else it
239       is ignored.
240
241     - "t": enable tracing of SQL executed on this database handle,
242       sending it to `console.log()`. To disable it later, call
243       `sqlite3.capi.sqlite3_trace_v2(thisDb.pointer, 0, 0, 0)`.
244
245     If "w" is not provided, the db is implicitly read-only, noting
246     that "rc" is meaningless
247
248     Any other letters are currently ignored. The default is
249     "c". These modes are ignored for the special ":memory:" and ""
250     names and _may_ be ignored altogether for certain VFSes.
251
252     The final argument is analogous to the final argument of
253     sqlite3_open_v2(): the name of an sqlite3 VFS. Pass a falsy value,
254     or none at all, to use the default. If passed a value, it must
255     be the string name of a VFS.
256
257     The constructor optionally (and preferably) takes its arguments
258     in the form of a single configuration object with the following
259     properties:
260
261     - `.filename`: database file name
262     - `.flags`: open-mode flags
263     - `.vfs`: the VFS fname
264
265     The `filename` and `vfs` arguments may be either JS strings or
266     C-strings allocated via WASM. `flags` is required to be a JS
267     string (because it's specific to this API, which is specific
268     to JS).
269
270     For purposes of passing a DB instance to C-style sqlite3
271     functions, the DB object's read-only `pointer` property holds its
272     `sqlite3*` pointer value. That property can also be used to check
273     whether this DB instance is still open.
274
275     In the main window thread, the filenames `":localStorage:"` and
276     `":sessionStorage:"` are special: they cause the db to use either
277     localStorage or sessionStorage for storing the database using
278     the kvvfs. If one of these names are used, they trump
279     any vfs name set in the arguments.
280  */
281  const DB = function(...args){
282    dbCtorHelper.apply(this, args);
283  };
284  DB.dbCtorHelper = dbCtorHelper;
285
286  /**
287     Internal-use enum for mapping JS types to DB-bindable types.
288     These do not (and need not) line up with the SQLITE_type
289     values. All values in this enum must be truthy and distinct
290     but they need not be numbers.
291  */
292  const BindTypes = {
293    null: 1,
294    number: 2,
295    string: 3,
296    boolean: 4,
297    blob: 5
298  };
299  BindTypes['undefined'] == BindTypes.null;
300  if(wasm.bigIntEnabled){
301    BindTypes.bigint = BindTypes.number;
302  }
303
304  /**
305     This class wraps sqlite3_stmt. Calling this constructor
306     directly will trigger an exception. Use DB.prepare() to create
307     new instances.
308
309     For purposes of passing a Stmt instance to C-style sqlite3
310     functions, its read-only `pointer` property holds its `sqlite3_stmt*`
311     pointer value.
312
313     Other non-function properties include:
314
315     - `db`: the DB object which created the statement.
316
317     - `columnCount`: the number of result columns in the query, or 0 for
318     queries which cannot return results.
319
320     - `parameterCount`: the number of bindable paramters in the query.
321  */
322  const Stmt = function(){
323    if(BindTypes!==arguments[2]){
324      toss3("Do not call the Stmt constructor directly. Use DB.prepare().");
325    }
326    this.db = arguments[0];
327    __ptrMap.set(this, arguments[1]);
328    this.columnCount = capi.sqlite3_column_count(this.pointer);
329    this.parameterCount = capi.sqlite3_bind_parameter_count(this.pointer);
330  };
331
332  /** Throws if the given DB has been closed, else it is returned. */
333  const affirmDbOpen = function(db){
334    if(!db.pointer) toss3("DB has been closed.");
335    return db;
336  };
337
338  /** Throws if ndx is not an integer or if it is out of range
339      for stmt.columnCount, else returns stmt.
340
341      Reminder: this will also fail after the statement is finalized
342      but the resulting error will be about an out-of-bounds column
343      index rather than a statement-is-finalized error.
344  */
345  const affirmColIndex = function(stmt,ndx){
346    if((ndx !== (ndx|0)) || ndx<0 || ndx>=stmt.columnCount){
347      toss3("Column index",ndx,"is out of range.");
348    }
349    return stmt;
350  };
351
352  /**
353     Expects to be passed the `arguments` object from DB.exec(). Does
354     the argument processing/validation, throws on error, and returns
355     a new object on success:
356
357     { sql: the SQL, opt: optionsObj, cbArg: function}
358
359     The opt object is a normalized copy of any passed to this
360     function. The sql will be converted to a string if it is provided
361     in one of the supported non-string formats.
362
363     cbArg is only set if the opt.callback or opt.resultRows are set,
364     in which case it's a function which expects to be passed the
365     current Stmt and returns the callback argument of the type
366     indicated by the input arguments.
367  */
368  const parseExecArgs = function(args){
369    const out = Object.create(null);
370    out.opt = Object.create(null);
371    switch(args.length){
372        case 1:
373          if('string'===typeof args[0] || util.isSQLableTypedArray(args[0])){
374            out.sql = args[0];
375          }else if(Array.isArray(args[0])){
376            out.sql = args[0];
377          }else if(args[0] && 'object'===typeof args[0]){
378            out.opt = args[0];
379            out.sql = out.opt.sql;
380          }
381          break;
382        case 2:
383          out.sql = args[0];
384          out.opt = args[1];
385          break;
386        default: toss3("Invalid argument count for exec().");
387    };
388    if(util.isSQLableTypedArray(out.sql)){
389      out.sql = util.typedArrayToString(out.sql);
390    }else if(Array.isArray(out.sql)){
391      out.sql = out.sql.join('');
392    }else if('string'!==typeof out.sql){
393      toss3("Missing SQL argument or unsupported SQL value type.");
394    }
395    if(out.opt.callback || out.opt.resultRows){
396      switch((undefined===out.opt.rowMode)
397             ? 'array' : out.opt.rowMode) {
398          case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break;
399          case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
400          case 'stmt':
401            if(Array.isArray(out.opt.resultRows)){
402              toss3("exec(): invalid rowMode for a resultRows array: must",
403                    "be one of 'array', 'object',",
404                    "a result column number, or column name reference.");
405            }
406            out.cbArg = (stmt)=>stmt;
407            break;
408          default:
409            if(util.isInt32(out.opt.rowMode)){
410              out.cbArg = (stmt)=>stmt.get(out.opt.rowMode);
411              break;
412            }else if('string'===typeof out.opt.rowMode && out.opt.rowMode.length>1){
413              /* "$X", ":X", and "@X" fetch column named "X" (case-sensitive!) */
414              const prefix = out.opt.rowMode[0];
415              if(':'===prefix || '@'===prefix || '$'===prefix){
416                out.cbArg = function(stmt){
417                  const rc = stmt.get(this.obj)[this.colName];
418                  return (undefined===rc) ? toss3("exec(): unknown result column:",this.colName) : rc;
419                }.bind({
420                  obj:Object.create(null),
421                  colName: out.opt.rowMode.substr(1)
422                });
423                break;
424              }
425            }
426            toss3("Invalid rowMode:",out.opt.rowMode);
427      }
428    }
429    return out;
430  };
431
432  /**
433     Expects to be given a DB instance or an `sqlite3*` pointer (may
434     be null) and an sqlite3 API result code. If the result code is
435     not falsy, this function throws an SQLite3Error with an error
436     message from sqlite3_errmsg(), using dbPtr as the db handle, or
437     sqlite3_errstr() if dbPtr is falsy. Note that if it's passed a
438     non-error code like SQLITE_ROW or SQLITE_DONE, it will still
439     throw but the error string might be "Not an error."  The various
440     non-0 non-error codes need to be checked for in
441     client code where they are expected.
442  */
443  DB.checkRc = checkSqlite3Rc;
444
445  DB.prototype = {
446    /** Returns true if this db handle is open, else false. */
447    isOpen: function(){
448      return !!this.pointer;
449    },
450    /** Throws if this given DB has been closed, else returns `this`. */
451    affirmOpen: function(){
452      return affirmDbOpen(this);
453    },
454    /**
455       Finalizes all open statements and closes this database
456       connection. This is a no-op if the db has already been
457       closed. After calling close(), `this.pointer` will resolve to
458       `undefined`, so that can be used to check whether the db
459       instance is still opened.
460
461       If this.onclose.before is a function then it is called before
462       any close-related cleanup.
463
464       If this.onclose.after is a function then it is called after the
465       db is closed but before auxiliary state like this.filename is
466       cleared.
467
468       Both onclose handlers are passed this object. If this db is not
469       opened, neither of the handlers are called. Any exceptions the
470       handlers throw are ignored because "destructors must not
471       throw."
472
473       Note that garbage collection of a db handle, if it happens at
474       all, will never trigger close(), so onclose handlers are not a
475       reliable way to implement close-time cleanup or maintenance of
476       a db.
477    */
478    close: function(){
479      if(this.pointer){
480        if(this.onclose && (this.onclose.before instanceof Function)){
481          try{this.onclose.before(this)}
482          catch(e){/*ignore*/}
483        }
484        const pDb = this.pointer;
485        Object.keys(__stmtMap.get(this)).forEach((k,s)=>{
486          if(s && s.pointer) s.finalize();
487        });
488        __ptrMap.delete(this);
489        __stmtMap.delete(this);
490        capi.sqlite3_close_v2(pDb);
491        if(this.onclose && (this.onclose.after instanceof Function)){
492          try{this.onclose.after(this)}
493          catch(e){/*ignore*/}
494        }
495        delete this.filename;
496      }
497    },
498    /**
499       Returns the number of changes, as per sqlite3_changes()
500       (if the first argument is false) or sqlite3_total_changes()
501       (if it's true). If the 2nd argument is true, it uses
502       sqlite3_changes64() or sqlite3_total_changes64(), which
503       will trigger an exception if this build does not have
504       BigInt support enabled.
505    */
506    changes: function(total=false,sixtyFour=false){
507      const p = affirmDbOpen(this).pointer;
508      if(total){
509        return sixtyFour
510          ? capi.sqlite3_total_changes64(p)
511          : capi.sqlite3_total_changes(p);
512      }else{
513        return sixtyFour
514          ? capi.sqlite3_changes64(p)
515          : capi.sqlite3_changes(p);
516      }
517    },
518    /**
519       Similar to the this.filename but returns the
520       sqlite3_db_filename() value for the given database name,
521       defaulting to "main".  The argument may be either a JS string
522       or a pointer to a WASM-allocated C-string.
523    */
524    dbFilename: function(dbName='main'){
525      return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);
526    },
527    /**
528       Returns the name of the given 0-based db number, as documented
529       for sqlite3_db_name().
530    */
531    dbName: function(dbNumber=0){
532      return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber);
533    },
534    /**
535       Compiles the given SQL and returns a prepared Stmt. This is
536       the only way to create new Stmt objects. Throws on error.
537
538       The given SQL must be a string, a Uint8Array holding SQL, a
539       WASM pointer to memory holding the NUL-terminated SQL string,
540       or an array of strings. In the latter case, the array is
541       concatenated together, with no separators, to form the SQL
542       string (arrays are often a convenient way to formulate long
543       statements).  If the SQL contains no statements, an
544       SQLite3Error is thrown.
545
546       Design note: the C API permits empty SQL, reporting it as a 0
547       result code and a NULL stmt pointer. Supporting that case here
548       would cause extra work for all clients: any use of the Stmt API
549       on such a statement will necessarily throw, so clients would be
550       required to check `stmt.pointer` after calling `prepare()` in
551       order to determine whether the Stmt instance is empty or not.
552       Long-time practice (with other sqlite3 script bindings)
553       suggests that the empty-prepare case is sufficiently rare that
554       supporting it here would simply hurt overall usability.
555    */
556    prepare: function(sql){
557      affirmDbOpen(this);
558      const stack = wasm.pstack.pointer;
559      let ppStmt, pStmt;
560      try{
561        ppStmt = wasm.pstack.alloc(8)/* output (sqlite3_stmt**) arg */;
562        DB.checkRc(this, capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null));
563        pStmt = wasm.getPtrValue(ppStmt);
564      }
565      finally {
566        wasm.pstack.restore(stack);
567      }
568      if(!pStmt) toss3("Cannot prepare empty SQL.");
569      const stmt = new Stmt(this, pStmt, BindTypes);
570      __stmtMap.get(this)[pStmt] = stmt;
571      return stmt;
572    },
573    /**
574       Executes one or more SQL statements in the form of a single
575       string. Its arguments must be either (sql,optionsObject) or
576       (optionsObject). In the latter case, optionsObject.sql
577       must contain the SQL to execute. Returns this
578       object. Throws on error.
579
580       If no SQL is provided, or a non-string is provided, an
581       exception is triggered. Empty SQL, on the other hand, is
582       simply a no-op.
583
584       The optional options object may contain any of the following
585       properties:
586
587       - `.sql` = the SQL to run (unless it's provided as the first
588       argument). This must be of type string, Uint8Array, or an array
589       of strings. In the latter case they're concatenated together
590       as-is, _with no separator_ between elements, before evaluation.
591       The array form is often simpler for long hand-written queries.
592
593       - `.bind` = a single value valid as an argument for
594       Stmt.bind(). This is _only_ applied to the _first_ non-empty
595       statement in the SQL which has any bindable parameters. (Empty
596       statements are skipped entirely.)
597
598       - `.saveSql` = an optional array. If set, the SQL of each
599       executed statement is appended to this array before the
600       statement is executed (but after it is prepared - we don't have
601       the string until after that). Empty SQL statements are elided.
602
603       ==================================================================
604       The following options apply _only_ to the _first_ statement
605       which has a non-zero result column count, regardless of whether
606       the statement actually produces any result rows.
607       ==================================================================
608
609       - `.columnNames`: if this is an array, the column names of the
610       result set are stored in this array before the callback (if
611       any) is triggered (regardless of whether the query produces any
612       result rows). If no statement has result columns, this value is
613       unchanged. Achtung: an SQL result may have multiple columns
614       with identical names.
615
616       - `.callback` = a function which gets called for each row of
617       the result set, but only if that statement has any result
618       _rows_. The callback's "this" is the options object, noting
619       that this function synthesizes one if the caller does not pass
620       one to exec(). The second argument passed to the callback is
621       always the current Stmt object, as it's needed if the caller
622       wants to fetch the column names or some such (noting that they
623       could also be fetched via `this.columnNames`, if the client
624       provides the `columnNames` option).
625
626       ACHTUNG: The callback MUST NOT modify the Stmt object. Calling
627       any of the Stmt.get() variants, Stmt.getColumnName(), or
628       similar, is legal, but calling step() or finalize() is
629       not. Member methods which are illegal in this context will
630       trigger an exception.
631
632       The first argument passed to the callback defaults to an array of
633       values from the current result row but may be changed with ...
634
635       - `.rowMode` = specifies the type of he callback's first argument.
636       It may be any of...
637
638       A) A string describing what type of argument should be passed
639       as the first argument to the callback:
640
641         A.1) `'array'` (the default) causes the results of
642         `stmt.get([])` to be passed to the `callback` and/or appended
643         to `resultRows`.
644
645         A.2) `'object'` causes the results of
646         `stmt.get(Object.create(null))` to be passed to the
647         `callback` and/or appended to `resultRows`.  Achtung: an SQL
648         result may have multiple columns with identical names. In
649         that case, the right-most column will be the one set in this
650         object!
651
652         A.3) `'stmt'` causes the current Stmt to be passed to the
653         callback, but this mode will trigger an exception if
654         `resultRows` is an array because appending the statement to
655         the array would be downright unhelpful.
656
657       B) An integer, indicating a zero-based column in the result
658       row. Only that one single value will be passed on.
659
660       C) A string with a minimum length of 2 and leading character of
661       ':', '$', or '@' will fetch the row as an object, extract that
662       one field, and pass that field's value to the callback. Note
663       that these keys are case-sensitive so must match the case used
664       in the SQL. e.g. `"select a A from t"` with a `rowMode` of
665       `'$A'` would work but `'$a'` would not. A reference to a column
666       not in the result set will trigger an exception on the first
667       row (as the check is not performed until rows are fetched).
668       Note also that `$` is a legal identifier character in JS so
669       need not be quoted. (Design note: those 3 characters were
670       chosen because they are the characters support for naming bound
671       parameters.)
672
673       Any other `rowMode` value triggers an exception.
674
675       - `.resultRows`: if this is an array, it functions similarly to
676       the `callback` option: each row of the result set (if any),
677       with the exception that the `rowMode` 'stmt' is not legal. It
678       is legal to use both `resultRows` and `callback`, but
679       `resultRows` is likely much simpler to use for small data sets
680       and can be used over a WebWorker-style message interface.
681       exec() throws if `resultRows` is set and `rowMode` is 'stmt'.
682
683
684       Potential TODOs:
685
686       - `.bind`: permit an array of arrays/objects to bind. The first
687       sub-array would act on the first statement which has bindable
688       parameters (as it does now). The 2nd would act on the next such
689       statement, etc.
690
691       - `.callback` and `.resultRows`: permit an array entries with
692       semantics similar to those described for `.bind` above.
693
694    */
695    exec: function(/*(sql [,obj]) || (obj)*/){
696      affirmDbOpen(this);
697      const arg = parseExecArgs(arguments);
698      if(!arg.sql){
699        return (''===arg.sql) ? this : toss3("exec() requires an SQL string.");
700      }
701      const opt = arg.opt;
702      const callback = opt.callback;
703      let resultRows = (Array.isArray(opt.resultRows)
704                          ? opt.resultRows : undefined);
705      let stmt;
706      let bind = opt.bind;
707      let evalFirstResult = !!(arg.cbArg || opt.columnNames) /* true to evaluate the first result-returning query */;
708      const stack = wasm.scopedAllocPush();
709      try{
710        const isTA = util.isSQLableTypedArray(arg.sql)
711        /* Optimization: if the SQL is a TypedArray we can save some string
712           conversion costs. */;
713        /* Allocate the two output pointers (ppStmt, pzTail) and heap
714           space for the SQL (pSql). When prepare_v2() returns, pzTail
715           will point to somewhere in pSql. */
716        let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql);
717        const ppStmt  = wasm.scopedAlloc(/* output (sqlite3_stmt**) arg and pzTail */
718          (2 * wasm.ptrSizeof)
719          + (sqlByteLen + 1/* SQL + NUL */));
720        const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */;
721        let pSql = pzTail + wasm.ptrSizeof;
722        const pSqlEnd = pSql + sqlByteLen;
723        if(isTA) wasm.heap8().set(arg.sql, pSql);
724        else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false);
725        wasm.setMemValue(pSql + sqlByteLen, 0/*NUL terminator*/);
726        while(pSql && wasm.getMemValue(pSql, 'i8')
727              /* Maintenance reminder:^^^ _must_ be 'i8' or else we
728                 will very likely cause an endless loop. What that's
729                 doing is checking for a terminating NUL byte. If we
730                 use i32 or similar then we read 4 bytes, read stuff
731                 around the NUL terminator, and get stuck in and
732                 endless loop at the end of the SQL, endlessly
733                 re-preparing an empty statement. */ ){
734          wasm.setPtrValue(ppStmt, 0);
735          wasm.setPtrValue(pzTail, 0);
736          DB.checkRc(this, capi.sqlite3_prepare_v3(
737            this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail
738          ));
739          const pStmt = wasm.getPtrValue(ppStmt);
740          pSql = wasm.getPtrValue(pzTail);
741          sqlByteLen = pSqlEnd - pSql;
742          if(!pStmt) continue;
743          if(Array.isArray(opt.saveSql)){
744            opt.saveSql.push(capi.sqlite3_sql(pStmt).trim());
745          }
746          stmt = new Stmt(this, pStmt, BindTypes);
747          if(bind && stmt.parameterCount){
748            stmt.bind(bind);
749            bind = null;
750          }
751          if(evalFirstResult && stmt.columnCount){
752            /* Only forward SELECT results for the FIRST query
753               in the SQL which potentially has them. */
754            evalFirstResult = false;
755            if(Array.isArray(opt.columnNames)){
756              stmt.getColumnNames(opt.columnNames);
757            }
758            while(!!arg.cbArg && stmt.step()){
759              stmt._isLocked = true;
760              const row = arg.cbArg(stmt);
761              if(resultRows) resultRows.push(row);
762              if(callback) callback.apply(opt,[row,stmt]);
763              stmt._isLocked = false;
764            }
765          }else{
766            stmt.step();
767          }
768          stmt.finalize();
769          stmt = null;
770        }
771      }/*catch(e){
772        console.warn("DB.exec() is propagating exception",opt,e);
773        throw e;
774      }*/finally{
775        if(stmt){
776          delete stmt._isLocked;
777          stmt.finalize();
778        }
779        wasm.scopedAllocPop(stack);
780      }
781      return this;
782    }/*exec()*/,
783    /**
784       Creates a new scalar UDF (User-Defined Function) which is
785       accessible via SQL code. This function may be called in any
786       of the following forms:
787
788       - (name, function)
789       - (name, function, optionsObject)
790       - (name, optionsObject)
791       - (optionsObject)
792
793       In the final two cases, the function must be defined as the
794       `callback` property of the options object (optionally called
795       `xFunc` to align with the C API documentation). In the final
796       case, the function's name must be the 'name' property.
797
798       The first two call forms can only be used for creating scalar
799       functions. Creating an aggregate or window function requires
800       the options-object form (see below for details).
801
802       UDFs cannot currently be removed from a DB handle after they're
803       added. More correctly, they can be removed as documented for
804       sqlite3_create_function_v2(), but doing so will "leak" the
805       JS-created WASM binding of those functions.
806
807       On success, returns this object. Throws on error.
808
809       When called from SQL arguments to the UDF, and its result,
810       will be converted between JS and SQL with as much fidelity as
811       is feasible, triggering an exception if a type conversion
812       cannot be determined. The docs for sqlite3_create_function_v2()
813       describe the conversions in more detail.
814
815       The values set in the options object differ for scalar and
816       aggregate functions:
817
818       - Scalar: set the `xFunc` function-type property to the UDF
819         function.
820
821       - Aggregate: set the `xStep` and `xFinal` function-type
822         properties to the "step" and "final" callbacks for the
823         aggregate. Do not set the `xFunc` property.
824
825       - Window: set the `xStep`, `xFinal`, `xValue`, and `xInverse`
826         function-type properties. Do not set the `xFunc` property.
827
828       The options object may optionally have an `xDestroy`
829       function-type property, as per sqlite3_create_function_v2().
830       Its argument will be the WASM-pointer-type value of the `pApp`
831       property, and this function will throw if `pApp` is defined but
832       is not null, undefined, or a numeric (WASM pointer)
833       value. i.e. `pApp`, if set, must be value suitable for use as a
834       WASM pointer argument, noting that `null` or `undefined` will
835       translate to 0 for that purpose.
836
837       The options object may contain flags to modify how
838       the function is defined:
839
840       - `arity`: the number of arguments which SQL calls to this
841       function expect or require. The default value is `xFunc.length`
842       or `xStep.length` (i.e. the number of declared parameters it
843       has) **MINUS 1** (see below for why). As a special case, if the
844       `length` is 0, its arity is also 0 instead of -1. A negative
845       arity value means that the function is variadic and may accept
846       any number of arguments, up to sqlite3's compile-time
847       limits. sqlite3 will enforce the argument count if is zero or
848       greater. The callback always receives a pointer to an
849       `sqlite3_context` object as its first argument. Any arguments
850       after that are from SQL code. The leading context argument does
851       _not_ count towards the function's arity. See the docs for
852       sqlite3.capi.sqlite3_create_function_v2() for why that argument
853       is needed in the interface.
854
855       The following options-object properties correspond to flags
856       documented at:
857
858       https://sqlite.org/c3ref/create_function.html
859
860       - `deterministic` = sqlite3.capi.SQLITE_DETERMINISTIC
861       - `directOnly` = sqlite3.capi.SQLITE_DIRECTONLY
862       - `innocuous` = sqlite3.capi.SQLITE_INNOCUOUS
863
864       Sidebar: the ability to add new WASM-accessible functions to
865       the runtime requires that the WASM build is compiled with the
866       equivalent functionality as that provided by Emscripten's
867       `-sALLOW_TABLE_GROWTH` flag.
868    */
869    createFunction: function f(name, xFunc, opt){
870      const isFunc = (f)=>(f instanceof Function);
871      switch(arguments.length){
872          case 1: /* (optionsObject) */
873            opt = name;
874            name = opt.name;
875            xFunc = opt.xFunc || 0;
876            break;
877          case 2: /* (name, callback|optionsObject) */
878            if(!isFunc(xFunc)){
879              opt = xFunc;
880              xFunc = opt.xFunc || 0;
881            }
882            break;
883          case 3: /* name, xFunc, opt */
884            break;
885          default: break;
886      }
887      if(!opt) opt = {};
888      if('string' !== typeof name){
889        toss3("Invalid arguments: missing function name.");
890      }
891      let xStep = opt.xStep || 0;
892      let xFinal = opt.xFinal || 0;
893      const xValue = opt.xValue || 0;
894      const xInverse = opt.xInverse || 0;
895      let isWindow = undefined;
896      if(isFunc(xFunc)){
897        isWindow = false;
898        if(isFunc(xStep) || isFunc(xFinal)){
899          toss3("Ambiguous arguments: scalar or aggregate?");
900        }
901        xStep = xFinal = null;
902      }else if(isFunc(xStep)){
903        if(!isFunc(xFinal)){
904          toss3("Missing xFinal() callback for aggregate or window UDF.");
905        }
906        xFunc = null;
907      }else if(isFunc(xFinal)){
908        toss3("Missing xStep() callback for aggregate or window UDF.");
909      }else{
910        toss3("Missing function-type properties.");
911      }
912      if(false === isWindow){
913        if(isFunc(xValue) || isFunc(xInverse)){
914          toss3("xValue and xInverse are not permitted for non-window UDFs.");
915        }
916      }else if(isFunc(xValue)){
917        if(!isFunc(xInverse)){
918          toss3("xInverse must be provided if xValue is.");
919        }
920        isWindow = true;
921      }else if(isFunc(xInverse)){
922        toss3("xValue must be provided if xInverse is.");
923      }
924      const pApp = opt.pApp;
925      if(undefined!==pApp &&
926         null!==pApp &&
927         (('number'!==typeof pApp) || !util.isInt32(pApp))){
928        toss3("Invalid value for pApp property. Must be a legal WASM pointer value.");
929      }
930      const xDestroy = opt.xDestroy || 0;
931      if(xDestroy && !isFunc(xDestroy)){
932        toss3("xDestroy property must be a function.");
933      }
934      let fFlags = 0 /*flags for sqlite3_create_function_v2()*/;
935      if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC;
936      if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY;
937      if(getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS;
938      name = name.toLowerCase();
939      const xArity = xFunc || xStep;
940      const arity = getOwnOption(opt, 'arity');
941      const arityArg = ('number'===typeof arity
942                        ? arity
943                        : (xArity.length ? xArity.length-1/*for pCtx arg*/ : 0));
944      let rc;
945      if( isWindow ){
946        rc = capi.sqlite3_create_window_function(
947          this.pointer, name, arityArg,
948          capi.SQLITE_UTF8 | fFlags, pApp || 0,
949          xStep, xFinal, xValue, xInverse, xDestroy);
950      }else{
951        rc = capi.sqlite3_create_function_v2(
952          this.pointer, name, arityArg,
953          capi.SQLITE_UTF8 | fFlags, pApp || 0,
954          xFunc, xStep, xFinal, xDestroy);
955      }
956      DB.checkRc(this, rc);
957      return this;
958    }/*createFunction()*/,
959    /**
960       Prepares the given SQL, step()s it one time, and returns
961       the value of the first result column. If it has no results,
962       undefined is returned.
963
964       If passed a second argument, it is treated like an argument
965       to Stmt.bind(), so may be any type supported by that
966       function. Passing the undefined value is the same as passing
967       no value, which is useful when...
968
969       If passed a 3rd argument, it is expected to be one of the
970       SQLITE_{typename} constants. Passing the undefined value is
971       the same as not passing a value.
972
973       Throws on error (e.g. malformed SQL).
974    */
975    selectValue: function(sql,bind,asType){
976      let stmt, rc;
977      try {
978        stmt = this.prepare(sql).bind(bind);
979        if(stmt.step()) rc = stmt.get(0,asType);
980      }finally{
981        if(stmt) stmt.finalize();
982      }
983      return rc;
984    },
985
986    /**
987       Returns the number of currently-opened Stmt handles for this db
988       handle, or 0 if this DB instance is closed.
989    */
990    openStatementCount: function(){
991      return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;
992    },
993
994    /**
995       Starts a transaction, calls the given callback, and then either
996       rolls back or commits the savepoint, depending on whether the
997       callback throws. The callback is passed this db object as its
998       only argument. On success, returns the result of the
999       callback. Throws on error.
1000
1001       Note that transactions may not be nested, so this will throw if
1002       it is called recursively. For nested transactions, use the
1003       savepoint() method or manually manage SAVEPOINTs using exec().
1004     */
1005    transaction: function(callback){
1006      affirmDbOpen(this).exec("BEGIN");
1007      try {
1008        const rc = callback(this);
1009        this.exec("COMMIT");
1010        return rc;
1011      }catch(e){
1012        this.exec("ROLLBACK");
1013        throw e;
1014      }
1015    },
1016
1017    /**
1018       This works similarly to transaction() but uses sqlite3's SAVEPOINT
1019       feature. This function starts a savepoint (with an unspecified name)
1020       and calls the given callback function, passing it this db object.
1021       If the callback returns, the savepoint is released (committed). If
1022       the callback throws, the savepoint is rolled back. If it does not
1023       throw, it returns the result of the callback.
1024    */
1025    savepoint: function(callback){
1026      affirmDbOpen(this).exec("SAVEPOINT oo1");
1027      try {
1028        const rc = callback(this);
1029        this.exec("RELEASE oo1");
1030        return rc;
1031      }catch(e){
1032        this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1");
1033        throw e;
1034      }
1035    }
1036  }/*DB.prototype*/;
1037
1038
1039  /** Throws if the given Stmt has been finalized, else stmt is
1040      returned. */
1041  const affirmStmtOpen = function(stmt){
1042    if(!stmt.pointer) toss3("Stmt has been closed.");
1043    return stmt;
1044  };
1045
1046  /** Returns an opaque truthy value from the BindTypes
1047      enum if v's type is a valid bindable type, else
1048      returns a falsy value. As a special case, a value of
1049      undefined is treated as a bind type of null. */
1050  const isSupportedBindType = function(v){
1051    let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v];
1052    switch(t){
1053        case BindTypes.boolean:
1054        case BindTypes.null:
1055        case BindTypes.number:
1056        case BindTypes.string:
1057          return t;
1058        case BindTypes.bigint:
1059          if(wasm.bigIntEnabled) return t;
1060          /* else fall through */
1061        default:
1062          //console.log("isSupportedBindType",t,v);
1063          return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
1064    }
1065  };
1066
1067  /**
1068     If isSupportedBindType(v) returns a truthy value, this
1069     function returns that value, else it throws.
1070  */
1071  const affirmSupportedBindType = function(v){
1072    //console.log('affirmSupportedBindType',v);
1073    return isSupportedBindType(v) || toss3("Unsupported bind() argument type:",typeof v);
1074  };
1075
1076  /**
1077     If key is a number and within range of stmt's bound parameter
1078     count, key is returned.
1079
1080     If key is not a number then it is checked against named
1081     parameters. If a match is found, its index is returned.
1082
1083     Else it throws.
1084  */
1085  const affirmParamIndex = function(stmt,key){
1086    const n = ('number'===typeof key)
1087          ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key);
1088    if(0===n || !util.isInt32(n)){
1089      toss3("Invalid bind() parameter name: "+key);
1090    }
1091    else if(n<1 || n>stmt.parameterCount) toss3("Bind index",key,"is out of range.");
1092    return n;
1093  };
1094
1095  /**
1096     If stmt._isLocked is truthy, this throws an exception
1097     complaining that the 2nd argument (an operation name,
1098     e.g. "bind()") is not legal while the statement is "locked".
1099     Locking happens before an exec()-like callback is passed a
1100     statement, to ensure that the callback does not mutate or
1101     finalize the statement. If it does not throw, it returns stmt.
1102  */
1103  const affirmUnlocked = function(stmt,currentOpName){
1104    if(stmt._isLocked){
1105      toss3("Operation is illegal when statement is locked:",currentOpName);
1106    }
1107    return stmt;
1108  };
1109
1110  /**
1111     Binds a single bound parameter value on the given stmt at the
1112     given index (numeric or named) using the given bindType (see
1113     the BindTypes enum) and value. Throws on error. Returns stmt on
1114     success.
1115  */
1116  const bindOne = function f(stmt,ndx,bindType,val){
1117    affirmUnlocked(stmt, 'bind()');
1118    if(!f._){
1119      f._tooBigInt = (v)=>toss3(
1120        "BigInt value is too big to store without precision loss:", v
1121      );
1122      /* Reminder: when not in BigInt mode, it's impossible for
1123         JS to represent a number out of the range we can bind,
1124         so we have no range checking. */
1125      f._ = {
1126        string: function(stmt, ndx, val, asBlob){
1127          if(1){
1128            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1129            const stack = wasm.scopedAllocPush();
1130            try{
1131              const n = wasm.jstrlen(val);
1132              const pStr = wasm.scopedAlloc(n);
1133              wasm.jstrcpy(val, wasm.heap8u(), pStr, n, false);
1134              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1135              return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
1136            }finally{
1137              wasm.scopedAllocPop(stack);
1138            }
1139          }else{
1140            const bytes = wasm.jstrToUintArray(val,false);
1141            const pStr = wasm.alloc(bytes.length || 1);
1142            wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
1143            try{
1144              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1145              return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT);
1146            }finally{
1147              wasm.dealloc(pStr);
1148            }
1149          }
1150        }
1151      };
1152    }/* static init */
1153    affirmSupportedBindType(val);
1154    ndx = affirmParamIndex(stmt,ndx);
1155    let rc = 0;
1156    switch((null===val || undefined===val) ? BindTypes.null : bindType){
1157        case BindTypes.null:
1158          rc = capi.sqlite3_bind_null(stmt.pointer, ndx);
1159          break;
1160        case BindTypes.string:
1161          rc = f._.string(stmt, ndx, val, false);
1162          break;
1163        case BindTypes.number: {
1164          let m;
1165          if(util.isInt32(val)) m = capi.sqlite3_bind_int;
1166          else if('bigint'===typeof val){
1167            if(!util.bigIntFits64(val)){
1168              f._tooBigInt(val);
1169            }else if(wasm.bigIntEnabled){
1170              m = capi.sqlite3_bind_int64;
1171            }else if(util.bigIntFitsDouble(val)){
1172              val = Number(val);
1173              m = capi.sqlite3_bind_double;
1174            }else{
1175              f._tooBigInt(val);
1176            }
1177          }else{ // !int32, !bigint
1178            val = Number(val);
1179            if(wasm.bigIntEnabled && Number.isInteger(val)){
1180              m = capi.sqlite3_bind_int64;
1181            }else{
1182              m = capi.sqlite3_bind_double;
1183            }
1184          }
1185          rc = m(stmt.pointer, ndx, val);
1186          break;
1187        }
1188        case BindTypes.boolean:
1189          rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0);
1190          break;
1191        case BindTypes.blob: {
1192          if('string'===typeof val){
1193            rc = f._.string(stmt, ndx, val, true);
1194          }else if(!util.isBindableTypedArray(val)){
1195            toss3("Binding a value as a blob requires",
1196                  "that it be a string, Uint8Array, or Int8Array.");
1197          }else if(1){
1198            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1199            const stack = wasm.scopedAllocPush();
1200            try{
1201              const pBlob = wasm.scopedAlloc(val.byteLength || 1);
1202              wasm.heap8().set(val.byteLength ? val : [0], pBlob)
1203              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1204                                         capi.SQLITE_TRANSIENT);
1205            }finally{
1206              wasm.scopedAllocPop(stack);
1207            }
1208          }else{
1209            const pBlob = wasm.allocFromTypedArray(val);
1210            try{
1211              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1212                                         capi.SQLITE_TRANSIENT);
1213            }finally{
1214              wasm.dealloc(pBlob);
1215            }
1216          }
1217          break;
1218        }
1219        default:
1220          console.warn("Unsupported bind() argument type:",val);
1221          toss3("Unsupported bind() argument type: "+(typeof val));
1222    }
1223    if(rc) DB.checkRc(stmt.db.pointer, rc);
1224    return stmt;
1225  };
1226
1227  Stmt.prototype = {
1228    /**
1229       "Finalizes" this statement. This is a no-op if the
1230       statement has already been finalizes. Returns
1231       undefined. Most methods in this class will throw if called
1232       after this is.
1233    */
1234    finalize: function(){
1235      if(this.pointer){
1236        affirmUnlocked(this,'finalize()');
1237        delete __stmtMap.get(this.db)[this.pointer];
1238        capi.sqlite3_finalize(this.pointer);
1239        __ptrMap.delete(this);
1240        delete this._mayGet;
1241        delete this.columnCount;
1242        delete this.parameterCount;
1243        delete this.db;
1244        delete this._isLocked;
1245      }
1246    },
1247    /** Clears all bound values. Returns this object.
1248        Throws if this statement has been finalized. */
1249    clearBindings: function(){
1250      affirmUnlocked(affirmStmtOpen(this), 'clearBindings()')
1251      capi.sqlite3_clear_bindings(this.pointer);
1252      this._mayGet = false;
1253      return this;
1254    },
1255    /**
1256       Resets this statement so that it may be step()ed again
1257       from the beginning. Returns this object. Throws if this
1258       statement has been finalized.
1259
1260       If passed a truthy argument then this.clearBindings() is
1261       also called, otherwise any existing bindings, along with
1262       any memory allocated for them, are retained.
1263    */
1264    reset: function(alsoClearBinds){
1265      affirmUnlocked(this,'reset()');
1266      if(alsoClearBinds) this.clearBindings();
1267      capi.sqlite3_reset(affirmStmtOpen(this).pointer);
1268      this._mayGet = false;
1269      return this;
1270    },
1271    /**
1272       Binds one or more values to its bindable parameters. It
1273       accepts 1 or 2 arguments:
1274
1275       If passed a single argument, it must be either an array, an
1276       object, or a value of a bindable type (see below).
1277
1278       If passed 2 arguments, the first one is the 1-based bind
1279       index or bindable parameter name and the second one must be
1280       a value of a bindable type.
1281
1282       Bindable value types:
1283
1284       - null is bound as NULL.
1285
1286       - undefined as a standalone value is a no-op intended to
1287         simplify certain client-side use cases: passing undefined as
1288         a value to this function will not actually bind anything and
1289         this function will skip confirmation that binding is even
1290         legal. (Those semantics simplify certain client-side uses.)
1291         Conversely, a value of undefined as an array or object
1292         property when binding an array/object (see below) is treated
1293         the same as null.
1294
1295       - Numbers are bound as either doubles or integers: doubles if
1296         they are larger than 32 bits, else double or int32, depending
1297         on whether they have a fractional part. Booleans are bound as
1298         integer 0 or 1. It is not expected the distinction of binding
1299         doubles which have no fractional parts is integers is
1300         significant for the majority of clients due to sqlite3's data
1301         typing model. If [BigInt] support is enabled then this
1302         routine will bind BigInt values as 64-bit integers if they'll
1303         fit in 64 bits. If that support disabled, it will store the
1304         BigInt as an int32 or a double if it can do so without loss
1305         of precision. If the BigInt is _too BigInt_ then it will
1306         throw.
1307
1308       - Strings are bound as strings (use bindAsBlob() to force
1309         blob binding).
1310
1311       - Uint8Array and Int8Array instances are bound as blobs.
1312         (TODO: binding the other TypedArray types.)
1313
1314       If passed an array, each element of the array is bound at
1315       the parameter index equal to the array index plus 1
1316       (because arrays are 0-based but binding is 1-based).
1317
1318       If passed an object, each object key is treated as a
1319       bindable parameter name. The object keys _must_ match any
1320       bindable parameter names, including any `$`, `@`, or `:`
1321       prefix. Because `$` is a legal identifier chararacter in
1322       JavaScript, that is the suggested prefix for bindable
1323       parameters: `stmt.bind({$a: 1, $b: 2})`.
1324
1325       It returns this object on success and throws on
1326       error. Errors include:
1327
1328       - Any bind index is out of range, a named bind parameter
1329       does not match, or this statement has no bindable
1330       parameters.
1331
1332       - Any value to bind is of an unsupported type.
1333
1334       - Passed no arguments or more than two.
1335
1336       - The statement has been finalized.
1337    */
1338    bind: function(/*[ndx,] arg*/){
1339      affirmStmtOpen(this);
1340      let ndx, arg;
1341      switch(arguments.length){
1342          case 1: ndx = 1; arg = arguments[0]; break;
1343          case 2: ndx = arguments[0]; arg = arguments[1]; break;
1344          default: toss3("Invalid bind() arguments.");
1345      }
1346      if(undefined===arg){
1347        /* It might seem intuitive to bind undefined as NULL
1348           but this approach simplifies certain client-side
1349           uses when passing on arguments between 2+ levels of
1350           functions. */
1351        return this;
1352      }else if(!this.parameterCount){
1353        toss3("This statement has no bindable parameters.");
1354      }
1355      this._mayGet = false;
1356      if(null===arg){
1357        /* bind NULL */
1358        return bindOne(this, ndx, BindTypes.null, arg);
1359      }
1360      else if(Array.isArray(arg)){
1361        /* bind each entry by index */
1362        if(1!==arguments.length){
1363          toss3("When binding an array, an index argument is not permitted.");
1364        }
1365        arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
1366        return this;
1367      }
1368      else if('object'===typeof arg/*null was checked above*/
1369              && !util.isBindableTypedArray(arg)){
1370        /* Treat each property of arg as a named bound parameter. */
1371        if(1!==arguments.length){
1372          toss3("When binding an object, an index argument is not permitted.");
1373        }
1374        Object.keys(arg)
1375          .forEach(k=>bindOne(this, k,
1376                              affirmSupportedBindType(arg[k]),
1377                              arg[k]));
1378        return this;
1379      }else{
1380        return bindOne(this, ndx, affirmSupportedBindType(arg), arg);
1381      }
1382      toss3("Should not reach this point.");
1383    },
1384    /**
1385       Special case of bind() which binds the given value using the
1386       BLOB binding mechanism instead of the default selected one for
1387       the value. The ndx may be a numbered or named bind index. The
1388       value must be of type string, null/undefined (both get treated
1389       as null), or a TypedArray of a type supported by the bind()
1390       API.
1391
1392       If passed a single argument, a bind index of 1 is assumed and
1393       the first argument is the value.
1394    */
1395    bindAsBlob: function(ndx,arg){
1396      affirmStmtOpen(this);
1397      if(1===arguments.length){
1398        arg = ndx;
1399        ndx = 1;
1400      }
1401      const t = affirmSupportedBindType(arg);
1402      if(BindTypes.string !== t && BindTypes.blob !== t
1403         && BindTypes.null !== t){
1404        toss3("Invalid value type for bindAsBlob()");
1405      }
1406      bindOne(this, ndx, BindTypes.blob, arg);
1407      this._mayGet = false;
1408      return this;
1409    },
1410    /**
1411       Steps the statement one time. If the result indicates that a
1412       row of data is available, a truthy value is returned.
1413       If no row of data is available, a falsy
1414       value is returned.  Throws on error.
1415    */
1416    step: function(){
1417      affirmUnlocked(this, 'step()');
1418      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
1419      switch(rc){
1420          case capi.SQLITE_DONE: return this._mayGet = false;
1421          case capi.SQLITE_ROW: return this._mayGet = true;
1422          default:
1423            this._mayGet = false;
1424            console.warn("sqlite3_step() rc=",rc,
1425                         capi.sqlite3_js_rc_str(rc),
1426                         "SQL =", capi.sqlite3_sql(this.pointer));
1427            DB.checkRc(this.db.pointer, rc);
1428      }
1429    },
1430    /**
1431       Functions exactly like step() except that...
1432
1433       1) On success, it calls this.reset() and returns this object.
1434       2) On error, it throws and does not call reset().
1435
1436       This is intended to simplify constructs like:
1437
1438       ```
1439       for(...) {
1440         stmt.bind(...).stepReset();
1441       }
1442       ```
1443
1444       Note that the reset() call makes it illegal to call this.get()
1445       after the step.
1446    */
1447    stepReset: function(){
1448      this.step();
1449      return this.reset();
1450    },
1451    /**
1452       Functions like step() except that it finalizes this statement
1453       immediately after stepping unless the step cannot be performed
1454       because the statement is locked. Throws on error, but any error
1455       other than the statement-is-locked case will also trigger
1456       finalization of this statement.
1457
1458       On success, it returns true if the step indicated that a row of
1459       data was available, else it returns false.
1460
1461       This is intended to simplify use cases such as:
1462
1463       ```
1464       aDb.prepare("insert into foo(a) values(?)").bind(123).stepFinalize();
1465       ```
1466    */
1467    stepFinalize: function(){
1468      const rc = this.step();
1469      this.finalize();
1470      return rc;
1471    },
1472    /**
1473       Fetches the value from the given 0-based column index of
1474       the current data row, throwing if index is out of range.
1475
1476       Requires that step() has just returned a truthy value, else
1477       an exception is thrown.
1478
1479       By default it will determine the data type of the result
1480       automatically. If passed a second arugment, it must be one
1481       of the enumeration values for sqlite3 types, which are
1482       defined as members of the sqlite3 module: SQLITE_INTEGER,
1483       SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
1484       except for undefined, will trigger an exception. Passing
1485       undefined is the same as not passing a value. It is legal
1486       to, e.g., fetch an integer value as a string, in which case
1487       sqlite3 will convert the value to a string.
1488
1489       If ndx is an array, this function behaves a differently: it
1490       assigns the indexes of the array, from 0 to the number of
1491       result columns, to the values of the corresponding column,
1492       and returns that array.
1493
1494       If ndx is a plain object, this function behaves even
1495       differentlier: it assigns the properties of the object to
1496       the values of their corresponding result columns.
1497
1498       Blobs are returned as Uint8Array instances.
1499
1500       Potential TODO: add type ID SQLITE_JSON, which fetches the
1501       result as a string and passes it (if it's not null) to
1502       JSON.parse(), returning the result of that. Until then,
1503       getJSON() can be used for that.
1504    */
1505    get: function(ndx,asType){
1506      if(!affirmStmtOpen(this)._mayGet){
1507        toss3("Stmt.step() has not (recently) returned true.");
1508      }
1509      if(Array.isArray(ndx)){
1510        let i = 0;
1511        while(i<this.columnCount){
1512          ndx[i] = this.get(i++);
1513        }
1514        return ndx;
1515      }else if(ndx && 'object'===typeof ndx){
1516        let i = 0;
1517        while(i<this.columnCount){
1518          ndx[capi.sqlite3_column_name(this.pointer,i)] = this.get(i++);
1519        }
1520        return ndx;
1521      }
1522      affirmColIndex(this, ndx);
1523      switch(undefined===asType
1524             ? capi.sqlite3_column_type(this.pointer, ndx)
1525             : asType){
1526          case capi.SQLITE_NULL: return null;
1527          case capi.SQLITE_INTEGER:{
1528            if(wasm.bigIntEnabled){
1529              const rc = capi.sqlite3_column_int64(this.pointer, ndx);
1530              if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){
1531                /* Coerce "normal" number ranges to normal number values,
1532                   and only return BigInt-type values for numbers out of this
1533                   range. */
1534                return Number(rc).valueOf();
1535              }
1536              return rc;
1537            }else{
1538              const rc = capi.sqlite3_column_double(this.pointer, ndx);
1539              if(rc>Number.MAX_SAFE_INTEGER || rc<Number.MIN_SAFE_INTEGER){
1540                /* Throwing here is arguable but, since we're explicitly
1541                   extracting an SQLITE_INTEGER-type value, it seems fair to throw
1542                   if the extracted number is out of range for that type.
1543                   This policy may be laxened to simply pass on the number and
1544                   hope for the best, as the C API would do. */
1545                toss3("Integer is out of range for JS integer range: "+rc);
1546              }
1547              //console.log("get integer rc=",rc,isInt32(rc));
1548              return util.isInt32(rc) ? (rc | 0) : rc;
1549            }
1550          }
1551          case capi.SQLITE_FLOAT:
1552            return capi.sqlite3_column_double(this.pointer, ndx);
1553          case capi.SQLITE_TEXT:
1554            return capi.sqlite3_column_text(this.pointer, ndx);
1555          case capi.SQLITE_BLOB: {
1556            const n = capi.sqlite3_column_bytes(this.pointer, ndx),
1557                  ptr = capi.sqlite3_column_blob(this.pointer, ndx),
1558                  rc = new Uint8Array(n);
1559            //heap = n ? wasm.heap8() : false;
1560            if(n) rc.set(wasm.heap8u().slice(ptr, ptr+n), 0);
1561            //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
1562            if(n && this.db._blobXfer instanceof Array){
1563              /* This is an optimization soley for the
1564                 Worker-based API. These values will be
1565                 transfered to the main thread directly
1566                 instead of being copied. */
1567              this.db._blobXfer.push(rc.buffer);
1568            }
1569            return rc;
1570          }
1571          default: toss3("Don't know how to translate",
1572                         "type of result column #"+ndx+".");
1573      }
1574      toss3("Not reached.");
1575    },
1576    /** Equivalent to get(ndx) but coerces the result to an
1577        integer. */
1578    getInt: function(ndx){return this.get(ndx,capi.SQLITE_INTEGER)},
1579    /** Equivalent to get(ndx) but coerces the result to a
1580        float. */
1581    getFloat: function(ndx){return this.get(ndx,capi.SQLITE_FLOAT)},
1582    /** Equivalent to get(ndx) but coerces the result to a
1583        string. */
1584    getString: function(ndx){return this.get(ndx,capi.SQLITE_TEXT)},
1585    /** Equivalent to get(ndx) but coerces the result to a
1586        Uint8Array. */
1587    getBlob: function(ndx){return this.get(ndx,capi.SQLITE_BLOB)},
1588    /**
1589       A convenience wrapper around get() which fetches the value
1590       as a string and then, if it is not null, passes it to
1591       JSON.parse(), returning that result. Throws if parsing
1592       fails. If the result is null, null is returned. An empty
1593       string, on the other hand, will trigger an exception.
1594    */
1595    getJSON: function(ndx){
1596      const s = this.get(ndx, capi.SQLITE_STRING);
1597      return null===s ? s : JSON.parse(s);
1598    },
1599    // Design note: the only reason most of these getters have a 'get'
1600    // prefix is for consistency with getVALUE_TYPE().  The latter
1601    // arguably really need that prefix for API readability and the
1602    // rest arguably don't, but consistency is a powerful thing.
1603    /**
1604       Returns the result column name of the given index, or
1605       throws if index is out of bounds or this statement has been
1606       finalized. This can be used without having run step()
1607       first.
1608    */
1609    getColumnName: function(ndx){
1610      return capi.sqlite3_column_name(
1611        affirmColIndex(affirmStmtOpen(this),ndx).pointer, ndx
1612      );
1613    },
1614    /**
1615       If this statement potentially has result columns, this
1616       function returns an array of all such names. If passed an
1617       array, it is used as the target and all names are appended
1618       to it. Returns the target array. Throws if this statement
1619       cannot have result columns. This object's columnCount member
1620       holds the number of columns.
1621    */
1622    getColumnNames: function(tgt=[]){
1623      affirmColIndex(affirmStmtOpen(this),0);
1624      for(let i = 0; i < this.columnCount; ++i){
1625        tgt.push(capi.sqlite3_column_name(this.pointer, i));
1626      }
1627      return tgt;
1628    },
1629    /**
1630       If this statement has named bindable parameters and the
1631       given name matches one, its 1-based bind index is
1632       returned. If no match is found, 0 is returned. If it has no
1633       bindable parameters, the undefined value is returned.
1634    */
1635    getParamIndex: function(name){
1636      return (affirmStmtOpen(this).parameterCount
1637              ? capi.sqlite3_bind_parameter_index(this.pointer, name)
1638              : undefined);
1639    }
1640  }/*Stmt.prototype*/;
1641
1642  {/* Add the `pointer` property to DB and Stmt. */
1643    const prop = {
1644      enumerable: true,
1645      get: function(){return __ptrMap.get(this)},
1646      set: ()=>toss3("The pointer property is read-only.")
1647    }
1648    Object.defineProperty(Stmt.prototype, 'pointer', prop);
1649    Object.defineProperty(DB.prototype, 'pointer', prop);
1650  }
1651
1652  /** The OO API's public namespace. */
1653  sqlite3.oo1 = {
1654    version: {
1655      lib: capi.sqlite3_libversion(),
1656      ooApi: "0.1"
1657    },
1658    DB,
1659    Stmt
1660  }/*oo1 object*/;
1661
1662  if(util.isUIThread()){
1663    /**
1664       Functionally equivalent to DB(storageName,'c','kvvfs') except
1665       that it throws if the given storage name is not one of 'local'
1666       or 'session'.
1667    */
1668    sqlite3.oo1.JsStorageDb = function(storageName='session'){
1669      if('session'!==storageName && 'local'!==storageName){
1670        toss3("JsStorageDb db name must be one of 'session' or 'local'.");
1671      }
1672      dbCtorHelper.call(this, {
1673        filename: storageName,
1674        flags: 'c',
1675        vfs: "kvvfs"
1676      });
1677    };
1678    const jdb = sqlite3.oo1.JsStorageDb;
1679    jdb.prototype = Object.create(DB.prototype);
1680    /** Equivalent to sqlite3_js_kvvfs_clear(). */
1681    jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
1682    /**
1683       Clears this database instance's storage or throws if this
1684       instance has been closed. Returns the number of
1685       database blocks which were cleaned up.
1686    */
1687    jdb.prototype.clearStorage = function(){
1688      return jdb.clearStorage(affirmDbOpen(this).filename);
1689    };
1690    /** Equivalent to sqlite3_js_kvvfs_size(). */
1691    jdb.storageSize = capi.sqlite3_js_kvvfs_size;
1692    /**
1693       Returns the _approximate_ number of bytes this database takes
1694       up in its storage or throws if this instance has been closed.
1695    */
1696    jdb.prototype.storageSize = function(){
1697      return jdb.storageSize(affirmDbOpen(this).filename);
1698    };
1699  }/*main-window-only bits*/
1700
1701});
1702
1703