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