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 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 wasm = capi.wasm;
698      const arg = parseExecArgs(arguments);
699      if(!arg.sql){
700        return (''===arg.sql) ? this : toss3("exec() requires an SQL string.");
701      }
702      const opt = arg.opt;
703      const callback = opt.callback;
704      let resultRows = (Array.isArray(opt.resultRows)
705                          ? opt.resultRows : undefined);
706      let stmt;
707      let bind = opt.bind;
708      let evalFirstResult = !!(arg.cbArg || opt.columnNames) /* true to evaluate the first result-returning query */;
709      const stack = wasm.scopedAllocPush();
710      try{
711        const isTA = util.isSQLableTypedArray(arg.sql)
712        /* Optimization: if the SQL is a TypedArray we can save some string
713           conversion costs. */;
714        /* Allocate the two output pointers (ppStmt, pzTail) and heap
715           space for the SQL (pSql). When prepare_v2() returns, pzTail
716           will point to somewhere in pSql. */
717        let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql);
718        const ppStmt  = wasm.scopedAlloc(/* output (sqlite3_stmt**) arg and pzTail */
719          (2 * wasm.ptrSizeof)
720          + (sqlByteLen + 1/* SQL + NUL */));
721        const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */;
722        let pSql = pzTail + wasm.ptrSizeof;
723        const pSqlEnd = pSql + sqlByteLen;
724        if(isTA) wasm.heap8().set(arg.sql, pSql);
725        else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false);
726        wasm.setMemValue(pSql + sqlByteLen, 0/*NUL terminator*/);
727        while(pSql && wasm.getMemValue(pSql, 'i8')
728              /* Maintenance reminder:^^^ _must_ be 'i8' or else we
729                 will very likely cause an endless loop. What that's
730                 doing is checking for a terminating NUL byte. If we
731                 use i32 or similar then we read 4 bytes, read stuff
732                 around the NUL terminator, and get stuck in and
733                 endless loop at the end of the SQL, endlessly
734                 re-preparing an empty statement. */ ){
735          wasm.setPtrValue(ppStmt, 0);
736          wasm.setPtrValue(pzTail, 0);
737          DB.checkRc(this, capi.sqlite3_prepare_v3(
738            this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail
739          ));
740          const pStmt = wasm.getPtrValue(ppStmt);
741          pSql = wasm.getPtrValue(pzTail);
742          sqlByteLen = pSqlEnd - pSql;
743          if(!pStmt) continue;
744          if(Array.isArray(opt.saveSql)){
745            opt.saveSql.push(capi.sqlite3_sql(pStmt).trim());
746          }
747          stmt = new Stmt(this, pStmt, BindTypes);
748          if(bind && stmt.parameterCount){
749            stmt.bind(bind);
750            bind = null;
751          }
752          if(evalFirstResult && stmt.columnCount){
753            /* Only forward SELECT results for the FIRST query
754               in the SQL which potentially has them. */
755            evalFirstResult = false;
756            if(Array.isArray(opt.columnNames)){
757              stmt.getColumnNames(opt.columnNames);
758            }
759            while(!!arg.cbArg && stmt.step()){
760              stmt._isLocked = true;
761              const row = arg.cbArg(stmt);
762              if(resultRows) resultRows.push(row);
763              if(callback) callback.apply(opt,[row,stmt]);
764              stmt._isLocked = false;
765            }
766          }else{
767            stmt.step();
768          }
769          stmt.finalize();
770          stmt = null;
771        }
772      }/*catch(e){
773        console.warn("DB.exec() is propagating exception",opt,e);
774        throw e;
775      }*/finally{
776        if(stmt){
777          delete stmt._isLocked;
778          stmt.finalize();
779        }
780        wasm.scopedAllocPop(stack);
781      }
782      return this;
783    }/*exec()*/,
784    /**
785       Creates a new scalar UDF (User-Defined Function) which is
786       accessible via SQL code. This function may be called in any
787       of the following forms:
788
789       - (name, function)
790       - (name, function, optionsObject)
791       - (name, optionsObject)
792       - (optionsObject)
793
794       In the final two cases, the function must be defined as the
795       `callback` property of the options object (optionally called
796       `xFunc` to align with the C API documentation). In the final
797       case, the function's name must be the 'name' property.
798
799       The first two call forms can only be used for creating scalar
800       functions. Creating an aggregate or window function requires
801       the options-object form (see below for details).
802
803       UDFs cannot currently be removed from a DB handle after they're
804       added. More correctly, they can be removed as documented for
805       sqlite3_create_function_v2(), but doing so will "leak" the
806       JS-created WASM binding of those functions.
807
808       On success, returns this object. Throws on error.
809
810       When called from SQL arguments to the UDF, and its result,
811       will be converted between JS and SQL with as much fidelity as
812       is feasible, triggering an exception if a type conversion
813       cannot be determined. The docs for sqlite3_create_function_v2()
814       describe the conversions in more detail.
815
816       The values set in the options object differ for scalar and
817       aggregate functions:
818
819       - Scalar: set the `xFunc` function-type property to the UDF
820         function.
821
822       - Aggregate: set the `xStep` and `xFinal` function-type
823         properties to the "step" and "final" callbacks for the
824         aggregate. Do not set the `xFunc` property.
825
826       - Window: set the `xStep`, `xFinal`, `xValue`, and `xInverse`
827         function-type properties. Do not set the `xFunc` property.
828
829       The options object may optionally have an `xDestroy`
830       function-type property, as per sqlite3_create_function_v2().
831       Its argument will be the WASM-pointer-type value of the `pApp`
832       property, and this function will throw if `pApp` is defined but
833       is not null, undefined, or a numeric (WASM pointer)
834       value. i.e. `pApp`, if set, must be value suitable for use as a
835       WASM pointer argument, noting that `null` or `undefined` will
836       translate to 0 for that purpose.
837
838       The options object may contain flags to modify how
839       the function is defined:
840
841       - `arity`: the number of arguments which SQL calls to this
842       function expect or require. The default value is `xFunc.length`
843       or `xStep.length` (i.e. the number of declared parameters it
844       has) **MINUS 1** (see below for why). As a special case, if the
845       `length` is 0, its arity is also 0 instead of -1. A negative
846       arity value means that the function is variadic and may accept
847       any number of arguments, up to sqlite3's compile-time
848       limits. sqlite3 will enforce the argument count if is zero or
849       greater. The callback always receives a pointer to an
850       `sqlite3_context` object as its first argument. Any arguments
851       after that are from SQL code. The leading context argument does
852       _not_ count towards the function's arity. See the docs for
853       sqlite3.capi.sqlite3_create_function_v2() for why that argument
854       is needed in the interface.
855
856       The following options-object properties correspond to flags
857       documented at:
858
859       https://sqlite.org/c3ref/create_function.html
860
861       - `deterministic` = sqlite3.capi.SQLITE_DETERMINISTIC
862       - `directOnly` = sqlite3.capi.SQLITE_DIRECTONLY
863       - `innocuous` = sqlite3.capi.SQLITE_INNOCUOUS
864
865       Sidebar: the ability to add new WASM-accessible functions to
866       the runtime requires that the WASM build is compiled with the
867       equivalent functionality as that provided by Emscripten's
868       `-sALLOW_TABLE_GROWTH` flag.
869    */
870    createFunction: function f(name, xFunc, opt){
871      const isFunc = (f)=>(f instanceof Function);
872      switch(arguments.length){
873          case 1: /* (optionsObject) */
874            opt = name;
875            name = opt.name;
876            xFunc = opt.xFunc || 0;
877            break;
878          case 2: /* (name, callback|optionsObject) */
879            if(!isFunc(xFunc)){
880              opt = xFunc;
881              xFunc = opt.xFunc || 0;
882            }
883            break;
884          case 3: /* name, xFunc, opt */
885            break;
886          default: break;
887      }
888      if(!opt) opt = {};
889      if('string' !== typeof name){
890        toss3("Invalid arguments: missing function name.");
891      }
892      let xStep = opt.xStep || 0;
893      let xFinal = opt.xFinal || 0;
894      const xValue = opt.xValue || 0;
895      const xInverse = opt.xInverse || 0;
896      let isWindow = undefined;
897      if(isFunc(xFunc)){
898        isWindow = false;
899        if(isFunc(xStep) || isFunc(xFinal)){
900          toss3("Ambiguous arguments: scalar or aggregate?");
901        }
902        xStep = xFinal = null;
903      }else if(isFunc(xStep)){
904        if(!isFunc(xFinal)){
905          toss3("Missing xFinal() callback for aggregate or window UDF.");
906        }
907        xFunc = null;
908      }else if(isFunc(xFinal)){
909        toss3("Missing xStep() callback for aggregate or window UDF.");
910      }else{
911        toss3("Missing function-type properties.");
912      }
913      if(false === isWindow){
914        if(isFunc(xValue) || isFunc(xInverse)){
915          toss3("xValue and xInverse are not permitted for non-window UDFs.");
916        }
917      }else if(isFunc(xValue)){
918        if(!isFunc(xInverse)){
919          toss3("xInverse must be provided if xValue is.");
920        }
921        isWindow = true;
922      }else if(isFunc(xInverse)){
923        toss3("xValue must be provided if xInverse is.");
924      }
925      const pApp = opt.pApp;
926      if(undefined!==pApp &&
927         null!==pApp &&
928         (('number'!==typeof pApp) || !capi.util.isInt32(pApp))){
929        toss3("Invalid value for pApp property. Must be a legal WASM pointer value.");
930      }
931      const xDestroy = opt.xDestroy || 0;
932      if(xDestroy && !isFunc(xDestroy)){
933        toss3("xDestroy property must be a function.");
934      }
935      let fFlags = 0 /*flags for sqlite3_create_function_v2()*/;
936      if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC;
937      if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY;
938      if(getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS;
939      name = name.toLowerCase();
940      const xArity = xFunc || xStep;
941      const arity = getOwnOption(opt, 'arity');
942      const arityArg = ('number'===typeof arity
943                        ? arity
944                        : (xArity.length ? xArity.length-1/*for pCtx arg*/ : 0));
945      let rc;
946      if( isWindow ){
947        rc = capi.sqlite3_create_window_function(
948          this.pointer, name, arityArg,
949          capi.SQLITE_UTF8 | fFlags, pApp || 0,
950          xStep, xFinal, xValue, xInverse, xDestroy);
951      }else{
952        rc = capi.sqlite3_create_function_v2(
953          this.pointer, name, arityArg,
954          capi.SQLITE_UTF8 | fFlags, pApp || 0,
955          xFunc, xStep, xFinal, xDestroy);
956      }
957      DB.checkRc(this, rc);
958      return this;
959    }/*createFunction()*/,
960    /**
961       Prepares the given SQL, step()s it one time, and returns
962       the value of the first result column. If it has no results,
963       undefined is returned.
964
965       If passed a second argument, it is treated like an argument
966       to Stmt.bind(), so may be any type supported by that
967       function. Passing the undefined value is the same as passing
968       no value, which is useful when...
969
970       If passed a 3rd argument, it is expected to be one of the
971       SQLITE_{typename} constants. Passing the undefined value is
972       the same as not passing a value.
973
974       Throws on error (e.g. malformed SQL).
975    */
976    selectValue: function(sql,bind,asType){
977      let stmt, rc;
978      try {
979        stmt = this.prepare(sql).bind(bind);
980        if(stmt.step()) rc = stmt.get(0,asType);
981      }finally{
982        if(stmt) stmt.finalize();
983      }
984      return rc;
985    },
986
987    /**
988       Returns the number of currently-opened Stmt handles for this db
989       handle, or 0 if this DB instance is closed.
990    */
991    openStatementCount: function(){
992      return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;
993    },
994
995    /**
996       Starts a transaction, calls the given callback, and then either
997       rolls back or commits the savepoint, depending on whether the
998       callback throws. The callback is passed this db object as its
999       only argument. On success, returns the result of the
1000       callback. Throws on error.
1001
1002       Note that transactions may not be nested, so this will throw if
1003       it is called recursively. For nested transactions, use the
1004       savepoint() method or manually manage SAVEPOINTs using exec().
1005     */
1006    transaction: function(callback){
1007      affirmDbOpen(this).exec("BEGIN");
1008      try {
1009        const rc = callback(this);
1010        this.exec("COMMIT");
1011        return rc;
1012      }catch(e){
1013        this.exec("ROLLBACK");
1014        throw e;
1015      }
1016    },
1017
1018    /**
1019       This works similarly to transaction() but uses sqlite3's SAVEPOINT
1020       feature. This function starts a savepoint (with an unspecified name)
1021       and calls the given callback function, passing it this db object.
1022       If the callback returns, the savepoint is released (committed). If
1023       the callback throws, the savepoint is rolled back. If it does not
1024       throw, it returns the result of the callback.
1025    */
1026    savepoint: function(callback){
1027      affirmDbOpen(this).exec("SAVEPOINT oo1");
1028      try {
1029        const rc = callback(this);
1030        this.exec("RELEASE oo1");
1031        return rc;
1032      }catch(e){
1033        this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1");
1034        throw e;
1035      }
1036    }
1037  }/*DB.prototype*/;
1038
1039
1040  /** Throws if the given Stmt has been finalized, else stmt is
1041      returned. */
1042  const affirmStmtOpen = function(stmt){
1043    if(!stmt.pointer) toss3("Stmt has been closed.");
1044    return stmt;
1045  };
1046
1047  /** Returns an opaque truthy value from the BindTypes
1048      enum if v's type is a valid bindable type, else
1049      returns a falsy value. As a special case, a value of
1050      undefined is treated as a bind type of null. */
1051  const isSupportedBindType = function(v){
1052    let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v];
1053    switch(t){
1054        case BindTypes.boolean:
1055        case BindTypes.null:
1056        case BindTypes.number:
1057        case BindTypes.string:
1058          return t;
1059        case BindTypes.bigint:
1060          if(wasm.bigIntEnabled) return t;
1061          /* else fall through */
1062        default:
1063          //console.log("isSupportedBindType",t,v);
1064          return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
1065    }
1066  };
1067
1068  /**
1069     If isSupportedBindType(v) returns a truthy value, this
1070     function returns that value, else it throws.
1071  */
1072  const affirmSupportedBindType = function(v){
1073    //console.log('affirmSupportedBindType',v);
1074    return isSupportedBindType(v) || toss3("Unsupported bind() argument type:",typeof v);
1075  };
1076
1077  /**
1078     If key is a number and within range of stmt's bound parameter
1079     count, key is returned.
1080
1081     If key is not a number then it is checked against named
1082     parameters. If a match is found, its index is returned.
1083
1084     Else it throws.
1085  */
1086  const affirmParamIndex = function(stmt,key){
1087    const n = ('number'===typeof key)
1088          ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key);
1089    if(0===n || !util.isInt32(n)){
1090      toss3("Invalid bind() parameter name: "+key);
1091    }
1092    else if(n<1 || n>stmt.parameterCount) toss3("Bind index",key,"is out of range.");
1093    return n;
1094  };
1095
1096  /**
1097     If stmt._isLocked is truthy, this throws an exception
1098     complaining that the 2nd argument (an operation name,
1099     e.g. "bind()") is not legal while the statement is "locked".
1100     Locking happens before an exec()-like callback is passed a
1101     statement, to ensure that the callback does not mutate or
1102     finalize the statement. If it does not throw, it returns stmt.
1103  */
1104  const affirmUnlocked = function(stmt,currentOpName){
1105    if(stmt._isLocked){
1106      toss3("Operation is illegal when statement is locked:",currentOpName);
1107    }
1108    return stmt;
1109  };
1110
1111  /**
1112     Binds a single bound parameter value on the given stmt at the
1113     given index (numeric or named) using the given bindType (see
1114     the BindTypes enum) and value. Throws on error. Returns stmt on
1115     success.
1116  */
1117  const bindOne = function f(stmt,ndx,bindType,val){
1118    affirmUnlocked(stmt, 'bind()');
1119    if(!f._){
1120      f._tooBigInt = (v)=>toss3(
1121        "BigInt value is too big to store without precision loss:", v
1122      );
1123      /* Reminder: when not in BigInt mode, it's impossible for
1124         JS to represent a number out of the range we can bind,
1125         so we have no range checking. */
1126      f._ = {
1127        string: function(stmt, ndx, val, asBlob){
1128          if(1){
1129            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1130            const stack = wasm.scopedAllocPush();
1131            try{
1132              const n = wasm.jstrlen(val);
1133              const pStr = wasm.scopedAlloc(n);
1134              wasm.jstrcpy(val, wasm.heap8u(), pStr, n, false);
1135              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1136              return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
1137            }finally{
1138              wasm.scopedAllocPop(stack);
1139            }
1140          }else{
1141            const bytes = wasm.jstrToUintArray(val,false);
1142            const pStr = wasm.alloc(bytes.length || 1);
1143            wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
1144            try{
1145              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1146              return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT);
1147            }finally{
1148              wasm.dealloc(pStr);
1149            }
1150          }
1151        }
1152      };
1153    }/* static init */
1154    affirmSupportedBindType(val);
1155    ndx = affirmParamIndex(stmt,ndx);
1156    let rc = 0;
1157    switch((null===val || undefined===val) ? BindTypes.null : bindType){
1158        case BindTypes.null:
1159          rc = capi.sqlite3_bind_null(stmt.pointer, ndx);
1160          break;
1161        case BindTypes.string:
1162          rc = f._.string(stmt, ndx, val, false);
1163          break;
1164        case BindTypes.number: {
1165          let m;
1166          if(util.isInt32(val)) m = capi.sqlite3_bind_int;
1167          else if('bigint'===typeof val){
1168            if(!util.bigIntFits64(val)){
1169              f._tooBigInt(val);
1170            }else if(wasm.bigIntEnabled){
1171              m = capi.sqlite3_bind_int64;
1172            }else if(util.bigIntFitsDouble(val)){
1173              val = Number(val);
1174              m = capi.sqlite3_bind_double;
1175            }else{
1176              f._tooBigInt(val);
1177            }
1178          }else{ // !int32, !bigint
1179            val = Number(val);
1180            if(wasm.bigIntEnabled && Number.isInteger(val)){
1181              m = capi.sqlite3_bind_int64;
1182            }else{
1183              m = capi.sqlite3_bind_double;
1184            }
1185          }
1186          rc = m(stmt.pointer, ndx, val);
1187          break;
1188        }
1189        case BindTypes.boolean:
1190          rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0);
1191          break;
1192        case BindTypes.blob: {
1193          if('string'===typeof val){
1194            rc = f._.string(stmt, ndx, val, true);
1195          }else if(!util.isBindableTypedArray(val)){
1196            toss3("Binding a value as a blob requires",
1197                  "that it be a string, Uint8Array, or Int8Array.");
1198          }else if(1){
1199            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1200            const stack = wasm.scopedAllocPush();
1201            try{
1202              const pBlob = wasm.scopedAlloc(val.byteLength || 1);
1203              wasm.heap8().set(val.byteLength ? val : [0], pBlob)
1204              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1205                                         capi.SQLITE_TRANSIENT);
1206            }finally{
1207              wasm.scopedAllocPop(stack);
1208            }
1209          }else{
1210            const pBlob = wasm.allocFromTypedArray(val);
1211            try{
1212              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1213                                         capi.SQLITE_TRANSIENT);
1214            }finally{
1215              wasm.dealloc(pBlob);
1216            }
1217          }
1218          break;
1219        }
1220        default:
1221          console.warn("Unsupported bind() argument type:",val);
1222          toss3("Unsupported bind() argument type: "+(typeof val));
1223    }
1224    if(rc) DB.checkRc(stmt.db.pointer, rc);
1225    return stmt;
1226  };
1227
1228  Stmt.prototype = {
1229    /**
1230       "Finalizes" this statement. This is a no-op if the
1231       statement has already been finalizes. Returns
1232       undefined. Most methods in this class will throw if called
1233       after this is.
1234    */
1235    finalize: function(){
1236      if(this.pointer){
1237        affirmUnlocked(this,'finalize()');
1238        delete __stmtMap.get(this.db)[this.pointer];
1239        capi.sqlite3_finalize(this.pointer);
1240        __ptrMap.delete(this);
1241        delete this._mayGet;
1242        delete this.columnCount;
1243        delete this.parameterCount;
1244        delete this.db;
1245        delete this._isLocked;
1246      }
1247    },
1248    /** Clears all bound values. Returns this object.
1249        Throws if this statement has been finalized. */
1250    clearBindings: function(){
1251      affirmUnlocked(affirmStmtOpen(this), 'clearBindings()')
1252      capi.sqlite3_clear_bindings(this.pointer);
1253      this._mayGet = false;
1254      return this;
1255    },
1256    /**
1257       Resets this statement so that it may be step()ed again
1258       from the beginning. Returns this object. Throws if this
1259       statement has been finalized.
1260
1261       If passed a truthy argument then this.clearBindings() is
1262       also called, otherwise any existing bindings, along with
1263       any memory allocated for them, are retained.
1264    */
1265    reset: function(alsoClearBinds){
1266      affirmUnlocked(this,'reset()');
1267      if(alsoClearBinds) this.clearBindings();
1268      capi.sqlite3_reset(affirmStmtOpen(this).pointer);
1269      this._mayGet = false;
1270      return this;
1271    },
1272    /**
1273       Binds one or more values to its bindable parameters. It
1274       accepts 1 or 2 arguments:
1275
1276       If passed a single argument, it must be either an array, an
1277       object, or a value of a bindable type (see below).
1278
1279       If passed 2 arguments, the first one is the 1-based bind
1280       index or bindable parameter name and the second one must be
1281       a value of a bindable type.
1282
1283       Bindable value types:
1284
1285       - null is bound as NULL.
1286
1287       - undefined as a standalone value is a no-op intended to
1288         simplify certain client-side use cases: passing undefined as
1289         a value to this function will not actually bind anything and
1290         this function will skip confirmation that binding is even
1291         legal. (Those semantics simplify certain client-side uses.)
1292         Conversely, a value of undefined as an array or object
1293         property when binding an array/object (see below) is treated
1294         the same as null.
1295
1296       - Numbers are bound as either doubles or integers: doubles if
1297         they are larger than 32 bits, else double or int32, depending
1298         on whether they have a fractional part. Booleans are bound as
1299         integer 0 or 1. It is not expected the distinction of binding
1300         doubles which have no fractional parts is integers is
1301         significant for the majority of clients due to sqlite3's data
1302         typing model. If [BigInt] support is enabled then this
1303         routine will bind BigInt values as 64-bit integers if they'll
1304         fit in 64 bits. If that support disabled, it will store the
1305         BigInt as an int32 or a double if it can do so without loss
1306         of precision. If the BigInt is _too BigInt_ then it will
1307         throw.
1308
1309       - Strings are bound as strings (use bindAsBlob() to force
1310         blob binding).
1311
1312       - Uint8Array and Int8Array instances are bound as blobs.
1313         (TODO: binding the other TypedArray types.)
1314
1315       If passed an array, each element of the array is bound at
1316       the parameter index equal to the array index plus 1
1317       (because arrays are 0-based but binding is 1-based).
1318
1319       If passed an object, each object key is treated as a
1320       bindable parameter name. The object keys _must_ match any
1321       bindable parameter names, including any `$`, `@`, or `:`
1322       prefix. Because `$` is a legal identifier chararacter in
1323       JavaScript, that is the suggested prefix for bindable
1324       parameters: `stmt.bind({$a: 1, $b: 2})`.
1325
1326       It returns this object on success and throws on
1327       error. Errors include:
1328
1329       - Any bind index is out of range, a named bind parameter
1330       does not match, or this statement has no bindable
1331       parameters.
1332
1333       - Any value to bind is of an unsupported type.
1334
1335       - Passed no arguments or more than two.
1336
1337       - The statement has been finalized.
1338    */
1339    bind: function(/*[ndx,] arg*/){
1340      affirmStmtOpen(this);
1341      let ndx, arg;
1342      switch(arguments.length){
1343          case 1: ndx = 1; arg = arguments[0]; break;
1344          case 2: ndx = arguments[0]; arg = arguments[1]; break;
1345          default: toss3("Invalid bind() arguments.");
1346      }
1347      if(undefined===arg){
1348        /* It might seem intuitive to bind undefined as NULL
1349           but this approach simplifies certain client-side
1350           uses when passing on arguments between 2+ levels of
1351           functions. */
1352        return this;
1353      }else if(!this.parameterCount){
1354        toss3("This statement has no bindable parameters.");
1355      }
1356      this._mayGet = false;
1357      if(null===arg){
1358        /* bind NULL */
1359        return bindOne(this, ndx, BindTypes.null, arg);
1360      }
1361      else if(Array.isArray(arg)){
1362        /* bind each entry by index */
1363        if(1!==arguments.length){
1364          toss3("When binding an array, an index argument is not permitted.");
1365        }
1366        arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
1367        return this;
1368      }
1369      else if('object'===typeof arg/*null was checked above*/
1370              && !util.isBindableTypedArray(arg)){
1371        /* Treat each property of arg as a named bound parameter. */
1372        if(1!==arguments.length){
1373          toss3("When binding an object, an index argument is not permitted.");
1374        }
1375        Object.keys(arg)
1376          .forEach(k=>bindOne(this, k,
1377                              affirmSupportedBindType(arg[k]),
1378                              arg[k]));
1379        return this;
1380      }else{
1381        return bindOne(this, ndx, affirmSupportedBindType(arg), arg);
1382      }
1383      toss3("Should not reach this point.");
1384    },
1385    /**
1386       Special case of bind() which binds the given value using the
1387       BLOB binding mechanism instead of the default selected one for
1388       the value. The ndx may be a numbered or named bind index. The
1389       value must be of type string, null/undefined (both get treated
1390       as null), or a TypedArray of a type supported by the bind()
1391       API.
1392
1393       If passed a single argument, a bind index of 1 is assumed and
1394       the first argument is the value.
1395    */
1396    bindAsBlob: function(ndx,arg){
1397      affirmStmtOpen(this);
1398      if(1===arguments.length){
1399        arg = ndx;
1400        ndx = 1;
1401      }
1402      const t = affirmSupportedBindType(arg);
1403      if(BindTypes.string !== t && BindTypes.blob !== t
1404         && BindTypes.null !== t){
1405        toss3("Invalid value type for bindAsBlob()");
1406      }
1407      bindOne(this, ndx, BindTypes.blob, arg);
1408      this._mayGet = false;
1409      return this;
1410    },
1411    /**
1412       Steps the statement one time. If the result indicates that a
1413       row of data is available, a truthy value is returned.
1414       If no row of data is available, a falsy
1415       value is returned.  Throws on error.
1416    */
1417    step: function(){
1418      affirmUnlocked(this, 'step()');
1419      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
1420      switch(rc){
1421          case capi.SQLITE_DONE: return this._mayGet = false;
1422          case capi.SQLITE_ROW: return this._mayGet = true;
1423          default:
1424            this._mayGet = false;
1425            console.warn("sqlite3_step() rc=",rc,
1426                         capi.sqlite3_js_rc_str(rc),
1427                         "SQL =", capi.sqlite3_sql(this.pointer));
1428            DB.checkRc(this.db.pointer, rc);
1429      }
1430    },
1431    /**
1432       Functions exactly like step() except that...
1433
1434       1) On success, it calls this.reset() and returns this object.
1435       2) On error, it throws and does not call reset().
1436
1437       This is intended to simplify constructs like:
1438
1439       ```
1440       for(...) {
1441         stmt.bind(...).stepReset();
1442       }
1443       ```
1444
1445       Note that the reset() call makes it illegal to call this.get()
1446       after the step.
1447    */
1448    stepReset: function(){
1449      this.step();
1450      return this.reset();
1451    },
1452    /**
1453       Functions like step() except that it finalizes this statement
1454       immediately after stepping unless the step cannot be performed
1455       because the statement is locked. Throws on error, but any error
1456       other than the statement-is-locked case will also trigger
1457       finalization of this statement.
1458
1459       On success, it returns true if the step indicated that a row of
1460       data was available, else it returns false.
1461
1462       This is intended to simplify use cases such as:
1463
1464       ```
1465       aDb.prepare("insert into foo(a) values(?)").bind(123).stepFinalize();
1466       ```
1467    */
1468    stepFinalize: function(){
1469      const rc = this.step();
1470      this.finalize();
1471      return rc;
1472    },
1473    /**
1474       Fetches the value from the given 0-based column index of
1475       the current data row, throwing if index is out of range.
1476
1477       Requires that step() has just returned a truthy value, else
1478       an exception is thrown.
1479
1480       By default it will determine the data type of the result
1481       automatically. If passed a second arugment, it must be one
1482       of the enumeration values for sqlite3 types, which are
1483       defined as members of the sqlite3 module: SQLITE_INTEGER,
1484       SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
1485       except for undefined, will trigger an exception. Passing
1486       undefined is the same as not passing a value. It is legal
1487       to, e.g., fetch an integer value as a string, in which case
1488       sqlite3 will convert the value to a string.
1489
1490       If ndx is an array, this function behaves a differently: it
1491       assigns the indexes of the array, from 0 to the number of
1492       result columns, to the values of the corresponding column,
1493       and returns that array.
1494
1495       If ndx is a plain object, this function behaves even
1496       differentlier: it assigns the properties of the object to
1497       the values of their corresponding result columns.
1498
1499       Blobs are returned as Uint8Array instances.
1500
1501       Potential TODO: add type ID SQLITE_JSON, which fetches the
1502       result as a string and passes it (if it's not null) to
1503       JSON.parse(), returning the result of that. Until then,
1504       getJSON() can be used for that.
1505    */
1506    get: function(ndx,asType){
1507      if(!affirmStmtOpen(this)._mayGet){
1508        toss3("Stmt.step() has not (recently) returned true.");
1509      }
1510      if(Array.isArray(ndx)){
1511        let i = 0;
1512        while(i<this.columnCount){
1513          ndx[i] = this.get(i++);
1514        }
1515        return ndx;
1516      }else if(ndx && 'object'===typeof ndx){
1517        let i = 0;
1518        while(i<this.columnCount){
1519          ndx[capi.sqlite3_column_name(this.pointer,i)] = this.get(i++);
1520        }
1521        return ndx;
1522      }
1523      affirmColIndex(this, ndx);
1524      switch(undefined===asType
1525             ? capi.sqlite3_column_type(this.pointer, ndx)
1526             : asType){
1527          case capi.SQLITE_NULL: return null;
1528          case capi.SQLITE_INTEGER:{
1529            if(wasm.bigIntEnabled){
1530              const rc = capi.sqlite3_column_int64(this.pointer, ndx);
1531              if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){
1532                /* Coerce "normal" number ranges to normal number values,
1533                   and only return BigInt-type values for numbers out of this
1534                   range. */
1535                return Number(rc).valueOf();
1536              }
1537              return rc;
1538            }else{
1539              const rc = capi.sqlite3_column_double(this.pointer, ndx);
1540              if(rc>Number.MAX_SAFE_INTEGER || rc<Number.MIN_SAFE_INTEGER){
1541                /* Throwing here is arguable but, since we're explicitly
1542                   extracting an SQLITE_INTEGER-type value, it seems fair to throw
1543                   if the extracted number is out of range for that type.
1544                   This policy may be laxened to simply pass on the number and
1545                   hope for the best, as the C API would do. */
1546                toss3("Integer is out of range for JS integer range: "+rc);
1547              }
1548              //console.log("get integer rc=",rc,isInt32(rc));
1549              return util.isInt32(rc) ? (rc | 0) : rc;
1550            }
1551          }
1552          case capi.SQLITE_FLOAT:
1553            return capi.sqlite3_column_double(this.pointer, ndx);
1554          case capi.SQLITE_TEXT:
1555            return capi.sqlite3_column_text(this.pointer, ndx);
1556          case capi.SQLITE_BLOB: {
1557            const n = capi.sqlite3_column_bytes(this.pointer, ndx),
1558                  ptr = capi.sqlite3_column_blob(this.pointer, ndx),
1559                  rc = new Uint8Array(n);
1560            //heap = n ? wasm.heap8() : false;
1561            if(n) rc.set(wasm.heap8u().slice(ptr, ptr+n), 0);
1562            //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
1563            if(n && this.db._blobXfer instanceof Array){
1564              /* This is an optimization soley for the
1565                 Worker-based API. These values will be
1566                 transfered to the main thread directly
1567                 instead of being copied. */
1568              this.db._blobXfer.push(rc.buffer);
1569            }
1570            return rc;
1571          }
1572          default: toss3("Don't know how to translate",
1573                         "type of result column #"+ndx+".");
1574      }
1575      toss3("Not reached.");
1576    },
1577    /** Equivalent to get(ndx) but coerces the result to an
1578        integer. */
1579    getInt: function(ndx){return this.get(ndx,capi.SQLITE_INTEGER)},
1580    /** Equivalent to get(ndx) but coerces the result to a
1581        float. */
1582    getFloat: function(ndx){return this.get(ndx,capi.SQLITE_FLOAT)},
1583    /** Equivalent to get(ndx) but coerces the result to a
1584        string. */
1585    getString: function(ndx){return this.get(ndx,capi.SQLITE_TEXT)},
1586    /** Equivalent to get(ndx) but coerces the result to a
1587        Uint8Array. */
1588    getBlob: function(ndx){return this.get(ndx,capi.SQLITE_BLOB)},
1589    /**
1590       A convenience wrapper around get() which fetches the value
1591       as a string and then, if it is not null, passes it to
1592       JSON.parse(), returning that result. Throws if parsing
1593       fails. If the result is null, null is returned. An empty
1594       string, on the other hand, will trigger an exception.
1595    */
1596    getJSON: function(ndx){
1597      const s = this.get(ndx, capi.SQLITE_STRING);
1598      return null===s ? s : JSON.parse(s);
1599    },
1600    // Design note: the only reason most of these getters have a 'get'
1601    // prefix is for consistency with getVALUE_TYPE().  The latter
1602    // arguably really need that prefix for API readability and the
1603    // rest arguably don't, but consistency is a powerful thing.
1604    /**
1605       Returns the result column name of the given index, or
1606       throws if index is out of bounds or this statement has been
1607       finalized. This can be used without having run step()
1608       first.
1609    */
1610    getColumnName: function(ndx){
1611      return capi.sqlite3_column_name(
1612        affirmColIndex(affirmStmtOpen(this),ndx).pointer, ndx
1613      );
1614    },
1615    /**
1616       If this statement potentially has result columns, this
1617       function returns an array of all such names. If passed an
1618       array, it is used as the target and all names are appended
1619       to it. Returns the target array. Throws if this statement
1620       cannot have result columns. This object's columnCount member
1621       holds the number of columns.
1622    */
1623    getColumnNames: function(tgt=[]){
1624      affirmColIndex(affirmStmtOpen(this),0);
1625      for(let i = 0; i < this.columnCount; ++i){
1626        tgt.push(capi.sqlite3_column_name(this.pointer, i));
1627      }
1628      return tgt;
1629    },
1630    /**
1631       If this statement has named bindable parameters and the
1632       given name matches one, its 1-based bind index is
1633       returned. If no match is found, 0 is returned. If it has no
1634       bindable parameters, the undefined value is returned.
1635    */
1636    getParamIndex: function(name){
1637      return (affirmStmtOpen(this).parameterCount
1638              ? capi.sqlite3_bind_parameter_index(this.pointer, name)
1639              : undefined);
1640    }
1641  }/*Stmt.prototype*/;
1642
1643  {/* Add the `pointer` property to DB and Stmt. */
1644    const prop = {
1645      enumerable: true,
1646      get: function(){return __ptrMap.get(this)},
1647      set: ()=>toss3("The pointer property is read-only.")
1648    }
1649    Object.defineProperty(Stmt.prototype, 'pointer', prop);
1650    Object.defineProperty(DB.prototype, 'pointer', prop);
1651  }
1652
1653  /** The OO API's public namespace. */
1654  sqlite3.oo1 = {
1655    version: {
1656      lib: capi.sqlite3_libversion(),
1657      ooApi: "0.1"
1658    },
1659    DB,
1660    Stmt
1661  }/*oo1 object*/;
1662
1663  if(util.isUIThread()){
1664    /**
1665       Functionally equivalent to DB(storageName,'c','kvvfs') except
1666       that it throws if the given storage name is not one of 'local'
1667       or 'session'.
1668    */
1669    sqlite3.oo1.JsStorageDb = function(storageName='session'){
1670      if('session'!==storageName && 'local'!==storageName){
1671        toss3("JsStorageDb db name must be one of 'session' or 'local'.");
1672      }
1673      dbCtorHelper.call(this, {
1674        filename: storageName,
1675        flags: 'c',
1676        vfs: "kvvfs"
1677      });
1678    };
1679    const jdb = sqlite3.oo1.JsStorageDb;
1680    jdb.prototype = Object.create(DB.prototype);
1681    /** Equivalent to sqlite3_js_kvvfs_clear(). */
1682    jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
1683    /**
1684       Clears this database instance's storage or throws if this
1685       instance has been closed. Returns the number of
1686       database blocks which were cleaned up.
1687    */
1688    jdb.prototype.clearStorage = function(){
1689      return jdb.clearStorage(affirmDbOpen(this).filename);
1690    };
1691    /** Equivalent to sqlite3_js_kvvfs_size(). */
1692    jdb.storageSize = capi.sqlite3_js_kvvfs_size;
1693    /**
1694       Returns the _approximate_ number of bytes this database takes
1695       up in its storage or throws if this instance has been closed.
1696    */
1697    jdb.prototype.storageSize = function(){
1698      return jdb.storageSize(affirmDbOpen(this).filename);
1699    };
1700  }/*main-window-only bits*/
1701
1702});
1703
1704