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