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