1/*
2  2022-07-22
3
4  The author disclaims copyright to this source code.  In place of a
5  legal notice, here is a blessing:
6
7  *   May you do good and not evil.
8  *   May you find forgiveness for yourself and forgive others.
9  *   May you share freely, never taking more than you give.
10
11  ***********************************************************************
12
13  This file contains the so-called OO #1 API wrapper for the sqlite3
14  WASM build. It requires that sqlite3-api-glue.js has already run
15  and it installs its deliverable as self.sqlite3.oo1.
16*/
17self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
18  const toss = (...args)=>{throw new Error(args.join(' '))};
19  const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
20
21  const capi = sqlite3.capi, wasm = capi.wasm, util = capi.util;
22  /* What follows is colloquially known as "OO API #1". It is a
23     binding of the sqlite3 API which is designed to be run within
24     the same thread (main or worker) as the one in which the
25     sqlite3 WASM binding was initialized. This wrapper cannot use
26     the sqlite3 binding if, e.g., the wrapper is in the main thread
27     and the sqlite3 API is in a worker. */
28
29  /**
30     In order to keep clients from manipulating, perhaps
31     inadvertently, the underlying pointer values of DB and Stmt
32     instances, we'll gate access to them via the `pointer` property
33     accessor and store their real values in this map. Keys = DB/Stmt
34     objects, values = pointer values. This also unifies how those are
35     accessed, for potential use downstream via custom
36     wasm.xWrap() function signatures which know how to extract
37     it.
38  */
39  const __ptrMap = new WeakMap();
40  /**
41     Map of DB instances to objects, each object being a map of Stmt
42     wasm pointers to Stmt objects.
43  */
44  const __stmtMap = new WeakMap();
45
46  /** If object opts has _its own_ property named p then that
47      property's value is returned, else dflt is returned. */
48  const getOwnOption = (opts, p, dflt)=>{
49    const d = Object.getOwnPropertyDescriptor(opts,p);
50    return d ? d.value : dflt;
51  };
52
53  // Documented in DB.checkRc()
54  const checkSqlite3Rc = function(dbPtr, sqliteResultCode){
55    if(sqliteResultCode){
56      if(dbPtr instanceof DB) dbPtr = dbPtr.pointer;
57      toss3(
58        "sqlite result code",sqliteResultCode+":",
59        (dbPtr
60         ? capi.sqlite3_errmsg(dbPtr)
61         : capi.sqlite3_errstr(sqliteResultCode))
62      );
63    }
64  };
65
66  /**
67     sqlite3_trace_v2() callback which gets installed by the DB ctor
68     if its open-flags contain "t".
69  */
70  const __dbTraceToConsole =
71        wasm.installFunction('i(ippp)', function(t,c,p,x){
72          if(capi.SQLITE_TRACE_STMT===t){
73            // x == SQL, p == sqlite3_stmt*
74            console.log("SQL TRACE #"+(++this.counter),
75                        wasm.cstringToJs(x));
76          }
77        }.bind({counter: 0}));
78
79  /**
80     A map of sqlite3_vfs pointers to SQL code to run when the DB
81     constructor opens a database with the given VFS.
82  */
83  const __vfsPostOpenSql = Object.create(null);
84
85  /**
86     A proxy for DB class constructors. It must be called with the
87     being-construct DB object as its "this". See the DB constructor
88     for the argument docs. This is split into a separate function
89     in order to enable simple creation of special-case DB constructors,
90     e.g. JsStorageDb and OpfsDb.
91
92     Expects to be passed a configuration object with the following
93     properties:
94
95     - `.filename`: the db filename. It may be a special name like ":memory:"
96       or "".
97
98     - `.flags`: as documented in the DB constructor.
99
100     - `.vfs`: as documented in the DB constructor.
101
102     It also accepts those as the first 3 arguments.
103  */
104  const dbCtorHelper = function ctor(...args){
105    if(!ctor._name2vfs){
106      /**
107         Map special filenames which we handle here (instead of in C)
108         to some helpful metadata...
109
110         As of 2022-09-20, the C API supports the names :localStorage:
111         and :sessionStorage: for kvvfs. However, C code cannot
112         determine (without embedded JS code, e.g. via Emscripten's
113         EM_JS()) whether the kvvfs is legal in the current browser
114         context (namely the main UI thread). In order to help client
115         code fail early on, instead of it being delayed until they
116         try to read or write a kvvfs-backed db, we'll check for those
117         names here and throw if they're not legal in the current
118         context.
119      */
120      ctor._name2vfs = Object.create(null);
121      const isWorkerThread = ('function'===typeof importScripts/*===running in worker thread*/)
122            ? (n)=>toss3("The VFS for",n,"is only available in the main window thread.")
123            : false;
124      ctor._name2vfs[':localStorage:'] = {
125        vfs: 'kvvfs', filename: isWorkerThread || (()=>'local')
126      };
127      ctor._name2vfs[':sessionStorage:'] = {
128        vfs: 'kvvfs', filename: isWorkerThread || (()=>'session')
129      };
130    }
131    const opt = ctor.normalizeArgs(...args);
132    let fn = opt.filename, vfsName = opt.vfs, flagsStr = opt.flags;
133    if(('string'!==typeof fn && 'number'!==typeof fn)
134       || 'string'!==typeof flagsStr
135       || (vfsName && ('string'!==typeof vfsName && 'number'!==typeof vfsName))){
136      console.error("Invalid DB ctor args",opt,arguments);
137      toss3("Invalid arguments for DB constructor.");
138    }
139    let fnJs = ('number'===typeof fn) ? wasm.cstringToJs(fn) : fn;
140    const vfsCheck = ctor._name2vfs[fnJs];
141    if(vfsCheck){
142      vfsName = vfsCheck.vfs;
143      fn = fnJs = vfsCheck.filename(fnJs);
144    }
145    let pDb, oflags = 0;
146    if( flagsStr.indexOf('c')>=0 ){
147      oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
148    }
149    if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
150    if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
151    oflags |= capi.SQLITE_OPEN_EXRESCODE;
152    const stack = wasm.pstack.pointer;
153    try {
154      const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;
155      let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
156      pDb = wasm.getPtrValue(pPtr);
157      checkSqlite3Rc(pDb, rc);
158      if(flagsStr.indexOf('t')>=0){
159        capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
160                              __dbTraceToConsole, 0);
161      }
162      // Check for per-VFS post-open SQL...
163      const pVfs = capi.sqlite3_js_db_vfs(pDb);
164      //console.warn("Opened db",fn,"with vfs",vfsName,pVfs);
165      if(!pVfs) toss3("Internal error: cannot get VFS for new db handle.");
166      const postInitSql = __vfsPostOpenSql[pVfs];
167      if(postInitSql){
168        rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0);
169        checkSqlite3Rc(pDb, rc);
170      }
171    }catch( e ){
172      if( pDb ) capi.sqlite3_close_v2(pDb);
173      throw e;
174    }finally{
175      wasm.pstack.restore(stack);
176    }
177    this.filename = fnJs;
178    __ptrMap.set(this, pDb);
179    __stmtMap.set(this, Object.create(null));
180  };
181
182  /**
183     Sets SQL which should be exec()'d on a DB instance after it is
184     opened with the given VFS pointer. This is intended only for use
185     by DB subclasses or sqlite3_vfs implementations.
186  */
187  dbCtorHelper.setVfsPostOpenSql = function(pVfs, sql){
188    __vfsPostOpenSql[pVfs] = sql;
189  };
190
191  /**
192     A helper for DB constructors. It accepts either a single
193     config-style object or up to 3 arguments (filename, dbOpenFlags,
194     dbVfsName). It returns a new object containing:
195
196     { filename: ..., flags: ..., vfs: ... }
197
198     If passed an object, any additional properties it has are copied
199     as-is into the new object.
200  */
201  dbCtorHelper.normalizeArgs = function(filename=':memory:',flags = 'c',vfs = null){
202    const arg = {};
203    if(1===arguments.length && 'object'===typeof arguments[0]){
204      const x = arguments[0];
205      Object.keys(x).forEach((k)=>arg[k] = x[k]);
206      if(undefined===arg.flags) arg.flags = 'c';
207      if(undefined===arg.vfs) arg.vfs = null;
208      if(undefined===arg.filename) arg.filename = ':memory:';
209    }else{
210      arg.filename = filename;
211      arg.flags = flags;
212      arg.vfs = vfs;
213    }
214    return arg;
215  };
216  /**
217     The DB class provides a high-level OO wrapper around an sqlite3
218     db handle.
219
220     The given db filename must be resolvable using whatever
221     filesystem layer (virtual or otherwise) is set up for the default
222     sqlite3 VFS.
223
224     Note that the special sqlite3 db names ":memory:" and ""
225     (temporary db) have their normal special meanings here and need
226     not resolve to real filenames, but "" uses an on-storage
227     temporary database and requires that the VFS support that.
228
229     The second argument specifies the open/create mode for the
230     database. It must be string containing a sequence of letters (in
231     any order, but case sensitive) specifying the mode:
232
233     - "c": create if it does not exist, else fail if it does not
234       exist. Implies the "w" flag.
235
236     - "w": write. Implies "r": a db cannot be write-only.
237
238     - "r": read-only if neither "w" nor "c" are provided, else it
239       is ignored.
240
241     - "t": enable tracing of SQL executed on this database handle,
242       sending it to `console.log()`. To disable it later, call
243       `sqlite3.capi.sqlite3_trace_v2(thisDb.pointer, 0, 0, 0)`.
244
245     If "w" is not provided, the db is implicitly read-only, noting
246     that "rc" is meaningless
247
248     Any other letters are currently ignored. The default is
249     "c". These modes are ignored for the special ":memory:" and ""
250     names and _may_ be ignored altogether for certain VFSes.
251
252     The final argument is analogous to the final argument of
253     sqlite3_open_v2(): the name of an sqlite3 VFS. Pass a falsy value,
254     or none at all, to use the default. If passed a value, it must
255     be the string name of a VFS.
256
257     The constructor optionally (and preferably) takes its arguments
258     in the form of a single configuration object with the following
259     properties:
260
261     - `.filename`: database file name
262     - `.flags`: open-mode flags
263     - `.vfs`: the VFS fname
264
265     The `filename` and `vfs` arguments may be either JS strings or
266     C-strings allocated via WASM. `flags` is required to be a JS
267     string (because it's specific to this API, which is specific
268     to JS).
269
270     For purposes of passing a DB instance to C-style sqlite3
271     functions, the DB object's read-only `pointer` property holds its
272     `sqlite3*` pointer value. That property can also be used to check
273     whether this DB instance is still open.
274
275     In the main window thread, the filenames `":localStorage:"` and
276     `":sessionStorage:"` are special: they cause the db to use either
277     localStorage or sessionStorage for storing the database using
278     the kvvfs. If one of these names are used, they trump
279     any vfs name set in the arguments.
280  */
281  const DB = function(...args){
282    dbCtorHelper.apply(this, args);
283  };
284
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(Array.isArray(args[0])){
375            out.sql = args[0];
376          }else if(args[0] && 'object'===typeof args[0]){
377            out.opt = args[0];
378            out.sql = out.opt.sql;
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 or unsupported SQL value type.");
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 (optionally called
807       `xFunc` to align with the C API documentation). In the final
808       case, the function's name must be the 'name' property.
809
810       The first two call forms can only be used for creating scalar
811       functions. Creating an aggregate or window function requires
812       the options-object form (see below for details).
813
814       UDFs cannot currently be removed from a DB handle after they're
815       added. More correctly, they can be removed as documented for
816       sqlite3_create_function_v2(), but doing so will "leak" the
817       JS-created WASM binding of those functions.
818
819       On success, returns this object. Throws on error.
820
821       When called from SQL arguments to the UDF, and its result,
822       will be converted between JS and SQL with as much fidelity as
823       is feasible, triggering an exception if a type conversion
824       cannot be determined. The docs for sqlite3_create_function_v2()
825       describe the conversions in more detail.
826
827       The values set in the options object differ for scalar and
828       aggregate functions:
829
830       - Scalar: set the `xFunc` function-type property to the UDF
831         function.
832
833       - Aggregate: set the `xStep` and `xFinal` function-type
834         properties to the "step" and "final" callbacks for the
835         aggregate. Do not set the `xFunc` property.
836
837       - Window: set the `xStep`, `xFinal`, `xValue`, and `xInverse`
838         function-type properties. Do not set the `xFunc` property.
839
840       The options object may optionally have an `xDestroy`
841       function-type property, as per sqlite3_create_function_v2().
842       Its argument will be the WASM-pointer-type value of the `pApp`
843       property, and this function will throw if `pApp` is defined but
844       is not null, undefined, or a numeric (WASM pointer)
845       value. i.e. `pApp`, if set, must be value suitable for use as a
846       WASM pointer argument, noting that `null` or `undefined` will
847       translate to 0 for that purpose.
848
849       The options object may contain flags to modify how
850       the function is defined:
851
852       - `arity`: the number of arguments which SQL calls to this
853       function expect or require. The default value is `xFunc.length`
854       or `xStep.length` (i.e. the number of declared parameters it
855       has) **MINUS 1** (see below for why). As a special case, if the
856       `length` is 0, its arity is also 0 instead of -1. A negative
857       arity value means that the function is variadic and may accept
858       any number of arguments, up to sqlite3's compile-time
859       limits. sqlite3 will enforce the argument count if is zero or
860       greater. The callback always receives a pointer to an
861       `sqlite3_context` object as its first argument. Any arguments
862       after that are from SQL code. The leading context argument does
863       _not_ count towards the function's arity. See the docs for
864       sqlite3.capi.sqlite3_create_function_v2() for why that argument
865       is needed in the interface.
866
867       The following options-object properties correspond to flags
868       documented at:
869
870       https://sqlite.org/c3ref/create_function.html
871
872       - `deterministic` = sqlite3.capi.SQLITE_DETERMINISTIC
873       - `directOnly` = sqlite3.capi.SQLITE_DIRECTONLY
874       - `innocuous` = sqlite3.capi.SQLITE_INNOCUOUS
875
876       Sidebar: the ability to add new WASM-accessible functions to
877       the runtime requires that the WASM build is compiled with the
878       equivalent functionality as that provided by Emscripten's
879       `-sALLOW_TABLE_GROWTH` flag.
880    */
881    createFunction: function f(name, xFunc, opt){
882      const isFunc = (f)=>(f instanceof Function);
883      switch(arguments.length){
884          case 1: /* (optionsObject) */
885            opt = name;
886            name = opt.name;
887            xFunc = opt.xFunc || 0;
888            break;
889          case 2: /* (name, callback|optionsObject) */
890            if(!isFunc(xFunc)){
891              opt = xFunc;
892              xFunc = opt.xFunc || 0;
893            }
894            break;
895          case 3: /* name, xFunc, opt */
896            break;
897          default: break;
898      }
899      if(!opt) opt = {};
900      if('string' !== typeof name){
901        toss3("Invalid arguments: missing function name.");
902      }
903      let xStep = opt.xStep || 0;
904      let xFinal = opt.xFinal || 0;
905      const xValue = opt.xValue || 0;
906      const xInverse = opt.xInverse || 0;
907      let isWindow = undefined;
908      if(isFunc(xFunc)){
909        isWindow = false;
910        if(isFunc(xStep) || isFunc(xFinal)){
911          toss3("Ambiguous arguments: scalar or aggregate?");
912        }
913        xStep = xFinal = null;
914      }else if(isFunc(xStep)){
915        if(!isFunc(xFinal)){
916          toss3("Missing xFinal() callback for aggregate or window UDF.");
917        }
918        xFunc = null;
919      }else if(isFunc(xFinal)){
920        toss3("Missing xStep() callback for aggregate or window UDF.");
921      }else{
922        toss3("Missing function-type properties.");
923      }
924      if(false === isWindow){
925        if(isFunc(xValue) || isFunc(xInverse)){
926          toss3("xValue and xInverse are not permitted for non-window UDFs.");
927        }
928      }else if(isFunc(xValue)){
929        if(!isFunc(xInverse)){
930          toss3("xInverse must be provided if xValue is.");
931        }
932        isWindow = true;
933      }else if(isFunc(xInverse)){
934        toss3("xValue must be provided if xInverse is.");
935      }
936      const pApp = opt.pApp;
937      if(undefined!==pApp &&
938         null!==pApp &&
939         (('number'!==typeof pApp) || !capi.util.isInt32(pApp))){
940        toss3("Invalid value for pApp property. Must be a legal WASM pointer value.");
941      }
942      const xDestroy = opt.xDestroy || 0;
943      if(xDestroy && !isFunc(xDestroy)){
944        toss3("xDestroy property must be a function.");
945      }
946      let fFlags = 0 /*flags for sqlite3_create_function_v2()*/;
947      if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC;
948      if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY;
949      if(getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS;
950      name = name.toLowerCase();
951      const xArity = xFunc || xStep;
952      const arity = getOwnOption(opt, 'arity');
953      const arityArg = ('number'===typeof arity
954                        ? arity
955                        : (xArity.length ? xArity.length-1/*for pCtx arg*/ : 0));
956      let rc;
957      if( isWindow ){
958        rc = capi.sqlite3_create_window_function(
959          this.pointer, name, arityArg,
960          capi.SQLITE_UTF8 | fFlags, pApp || 0,
961          xStep, xFinal, xValue, xInverse, xDestroy);
962      }else{
963        rc = capi.sqlite3_create_function_v2(
964          this.pointer, name, arityArg,
965          capi.SQLITE_UTF8 | fFlags, pApp || 0,
966          xFunc, xStep, xFinal, xDestroy);
967      }
968      DB.checkRc(this, rc);
969      return this;
970    }/*createFunction()*/,
971    /**
972       Prepares the given SQL, step()s it one time, and returns
973       the value of the first result column. If it has no results,
974       undefined is returned.
975
976       If passed a second argument, it is treated like an argument
977       to Stmt.bind(), so may be any type supported by that
978       function. Passing the undefined value is the same as passing
979       no value, which is useful when...
980
981       If passed a 3rd argument, it is expected to be one of the
982       SQLITE_{typename} constants. Passing the undefined value is
983       the same as not passing a value.
984
985       Throws on error (e.g. malformed SQL).
986    */
987    selectValue: function(sql,bind,asType){
988      let stmt, rc;
989      try {
990        stmt = this.prepare(sql).bind(bind);
991        if(stmt.step()) rc = stmt.get(0,asType);
992      }finally{
993        if(stmt) stmt.finalize();
994      }
995      return rc;
996    },
997
998    /**
999       Returns the number of currently-opened Stmt handles for this db
1000       handle, or 0 if this DB instance is closed.
1001    */
1002    openStatementCount: function(){
1003      return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;
1004    },
1005
1006    /**
1007       Starts a transaction, calls the given callback, and then either
1008       rolls back or commits the savepoint, depending on whether the
1009       callback throws. The callback is passed this db object as its
1010       only argument. On success, returns the result of the
1011       callback. Throws on error.
1012
1013       Note that transactions may not be nested, so this will throw if
1014       it is called recursively. For nested transactions, use the
1015       savepoint() method or manually manage SAVEPOINTs using exec().
1016     */
1017    transaction: function(callback){
1018      affirmDbOpen(this).exec("BEGIN");
1019      try {
1020        const rc = callback(this);
1021        this.exec("COMMIT");
1022        return rc;
1023      }catch(e){
1024        this.exec("ROLLBACK");
1025        throw e;
1026      }
1027    },
1028
1029    /**
1030       This works similarly to transaction() but uses sqlite3's SAVEPOINT
1031       feature. This function starts a savepoint (with an unspecified name)
1032       and calls the given callback function, passing it this db object.
1033       If the callback returns, the savepoint is released (committed). If
1034       the callback throws, the savepoint is rolled back. If it does not
1035       throw, it returns the result of the callback.
1036    */
1037    savepoint: function(callback){
1038      affirmDbOpen(this).exec("SAVEPOINT oo1");
1039      try {
1040        const rc = callback(this);
1041        this.exec("RELEASE oo1");
1042        return rc;
1043      }catch(e){
1044        this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1");
1045        throw e;
1046      }
1047    }
1048  }/*DB.prototype*/;
1049
1050
1051  /** Throws if the given Stmt has been finalized, else stmt is
1052      returned. */
1053  const affirmStmtOpen = function(stmt){
1054    if(!stmt.pointer) toss3("Stmt has been closed.");
1055    return stmt;
1056  };
1057
1058  /** Returns an opaque truthy value from the BindTypes
1059      enum if v's type is a valid bindable type, else
1060      returns a falsy value. As a special case, a value of
1061      undefined is treated as a bind type of null. */
1062  const isSupportedBindType = function(v){
1063    let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v];
1064    switch(t){
1065        case BindTypes.boolean:
1066        case BindTypes.null:
1067        case BindTypes.number:
1068        case BindTypes.string:
1069          return t;
1070        case BindTypes.bigint:
1071          if(wasm.bigIntEnabled) return t;
1072          /* else fall through */
1073        default:
1074          //console.log("isSupportedBindType",t,v);
1075          return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
1076    }
1077  };
1078
1079  /**
1080     If isSupportedBindType(v) returns a truthy value, this
1081     function returns that value, else it throws.
1082  */
1083  const affirmSupportedBindType = function(v){
1084    //console.log('affirmSupportedBindType',v);
1085    return isSupportedBindType(v) || toss3("Unsupported bind() argument type:",typeof v);
1086  };
1087
1088  /**
1089     If key is a number and within range of stmt's bound parameter
1090     count, key is returned.
1091
1092     If key is not a number then it is checked against named
1093     parameters. If a match is found, its index is returned.
1094
1095     Else it throws.
1096  */
1097  const affirmParamIndex = function(stmt,key){
1098    const n = ('number'===typeof key)
1099          ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key);
1100    if(0===n || !util.isInt32(n)){
1101      toss3("Invalid bind() parameter name: "+key);
1102    }
1103    else if(n<1 || n>stmt.parameterCount) toss3("Bind index",key,"is out of range.");
1104    return n;
1105  };
1106
1107  /**
1108     If stmt._isLocked is truthy, this throws an exception
1109     complaining that the 2nd argument (an operation name,
1110     e.g. "bind()") is not legal while the statement is "locked".
1111     Locking happens before an exec()-like callback is passed a
1112     statement, to ensure that the callback does not mutate or
1113     finalize the statement. If it does not throw, it returns stmt.
1114  */
1115  const affirmUnlocked = function(stmt,currentOpName){
1116    if(stmt._isLocked){
1117      toss3("Operation is illegal when statement is locked:",currentOpName);
1118    }
1119    return stmt;
1120  };
1121
1122  /**
1123     Binds a single bound parameter value on the given stmt at the
1124     given index (numeric or named) using the given bindType (see
1125     the BindTypes enum) and value. Throws on error. Returns stmt on
1126     success.
1127  */
1128  const bindOne = function f(stmt,ndx,bindType,val){
1129    affirmUnlocked(stmt, 'bind()');
1130    if(!f._){
1131      f._tooBigInt = (v)=>toss3(
1132        "BigInt value is too big to store without precision loss:", v
1133      );
1134      /* Reminder: when not in BigInt mode, it's impossible for
1135         JS to represent a number out of the range we can bind,
1136         so we have no range checking. */
1137      f._ = {
1138        string: function(stmt, ndx, val, asBlob){
1139          if(1){
1140            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1141            const stack = wasm.scopedAllocPush();
1142            try{
1143              const n = wasm.jstrlen(val);
1144              const pStr = wasm.scopedAlloc(n);
1145              wasm.jstrcpy(val, wasm.heap8u(), pStr, n, false);
1146              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1147              return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
1148            }finally{
1149              wasm.scopedAllocPop(stack);
1150            }
1151          }else{
1152            const bytes = wasm.jstrToUintArray(val,false);
1153            const pStr = wasm.alloc(bytes.length || 1);
1154            wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
1155            try{
1156              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1157              return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT);
1158            }finally{
1159              wasm.dealloc(pStr);
1160            }
1161          }
1162        }
1163      };
1164    }/* static init */
1165    affirmSupportedBindType(val);
1166    ndx = affirmParamIndex(stmt,ndx);
1167    let rc = 0;
1168    switch((null===val || undefined===val) ? BindTypes.null : bindType){
1169        case BindTypes.null:
1170          rc = capi.sqlite3_bind_null(stmt.pointer, ndx);
1171          break;
1172        case BindTypes.string:
1173          rc = f._.string(stmt, ndx, val, false);
1174          break;
1175        case BindTypes.number: {
1176          let m;
1177          if(util.isInt32(val)) m = capi.sqlite3_bind_int;
1178          else if('bigint'===typeof val){
1179            if(!util.bigIntFits64(val)){
1180              f._tooBigInt(val);
1181            }else if(wasm.bigIntEnabled){
1182              m = capi.sqlite3_bind_int64;
1183            }else if(util.bigIntFitsDouble(val)){
1184              val = Number(val);
1185              m = capi.sqlite3_bind_double;
1186            }else{
1187              f._tooBigInt(val);
1188            }
1189          }else{ // !int32, !bigint
1190            val = Number(val);
1191            if(wasm.bigIntEnabled && Number.isInteger(val)){
1192              m = capi.sqlite3_bind_int64;
1193            }else{
1194              m = capi.sqlite3_bind_double;
1195            }
1196          }
1197          rc = m(stmt.pointer, ndx, val);
1198          break;
1199        }
1200        case BindTypes.boolean:
1201          rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0);
1202          break;
1203        case BindTypes.blob: {
1204          if('string'===typeof val){
1205            rc = f._.string(stmt, ndx, val, true);
1206          }else if(!util.isBindableTypedArray(val)){
1207            toss3("Binding a value as a blob requires",
1208                  "that it be a string, Uint8Array, or Int8Array.");
1209          }else if(1){
1210            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1211            const stack = wasm.scopedAllocPush();
1212            try{
1213              const pBlob = wasm.scopedAlloc(val.byteLength || 1);
1214              wasm.heap8().set(val.byteLength ? val : [0], pBlob)
1215              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1216                                         capi.SQLITE_TRANSIENT);
1217            }finally{
1218              wasm.scopedAllocPop(stack);
1219            }
1220          }else{
1221            const pBlob = wasm.allocFromTypedArray(val);
1222            try{
1223              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1224                                         capi.SQLITE_TRANSIENT);
1225            }finally{
1226              wasm.dealloc(pBlob);
1227            }
1228          }
1229          break;
1230        }
1231        default:
1232          console.warn("Unsupported bind() argument type:",val);
1233          toss3("Unsupported bind() argument type: "+(typeof val));
1234    }
1235    if(rc) DB.checkRc(stmt.db.pointer, rc);
1236    return stmt;
1237  };
1238
1239  Stmt.prototype = {
1240    /**
1241       "Finalizes" this statement. This is a no-op if the
1242       statement has already been finalizes. Returns
1243       undefined. Most methods in this class will throw if called
1244       after this is.
1245    */
1246    finalize: function(){
1247      if(this.pointer){
1248        affirmUnlocked(this,'finalize()');
1249        delete __stmtMap.get(this.db)[this.pointer];
1250        capi.sqlite3_finalize(this.pointer);
1251        __ptrMap.delete(this);
1252        delete this._mayGet;
1253        delete this.columnCount;
1254        delete this.parameterCount;
1255        delete this.db;
1256        delete this._isLocked;
1257      }
1258    },
1259    /** Clears all bound values. Returns this object.
1260        Throws if this statement has been finalized. */
1261    clearBindings: function(){
1262      affirmUnlocked(affirmStmtOpen(this), 'clearBindings()')
1263      capi.sqlite3_clear_bindings(this.pointer);
1264      this._mayGet = false;
1265      return this;
1266    },
1267    /**
1268       Resets this statement so that it may be step()ed again
1269       from the beginning. Returns this object. Throws if this
1270       statement has been finalized.
1271
1272       If passed a truthy argument then this.clearBindings() is
1273       also called, otherwise any existing bindings, along with
1274       any memory allocated for them, are retained.
1275    */
1276    reset: function(alsoClearBinds){
1277      affirmUnlocked(this,'reset()');
1278      if(alsoClearBinds) this.clearBindings();
1279      capi.sqlite3_reset(affirmStmtOpen(this).pointer);
1280      this._mayGet = false;
1281      return this;
1282    },
1283    /**
1284       Binds one or more values to its bindable parameters. It
1285       accepts 1 or 2 arguments:
1286
1287       If passed a single argument, it must be either an array, an
1288       object, or a value of a bindable type (see below).
1289
1290       If passed 2 arguments, the first one is the 1-based bind
1291       index or bindable parameter name and the second one must be
1292       a value of a bindable type.
1293
1294       Bindable value types:
1295
1296       - null is bound as NULL.
1297
1298       - undefined as a standalone value is a no-op intended to
1299         simplify certain client-side use cases: passing undefined as
1300         a value to this function will not actually bind anything and
1301         this function will skip confirmation that binding is even
1302         legal. (Those semantics simplify certain client-side uses.)
1303         Conversely, a value of undefined as an array or object
1304         property when binding an array/object (see below) is treated
1305         the same as null.
1306
1307       - Numbers are bound as either doubles or integers: doubles if
1308         they are larger than 32 bits, else double or int32, depending
1309         on whether they have a fractional part. Booleans are bound as
1310         integer 0 or 1. It is not expected the distinction of binding
1311         doubles which have no fractional parts is integers is
1312         significant for the majority of clients due to sqlite3's data
1313         typing model. If [BigInt] support is enabled then this
1314         routine will bind BigInt values as 64-bit integers if they'll
1315         fit in 64 bits. If that support disabled, it will store the
1316         BigInt as an int32 or a double if it can do so without loss
1317         of precision. If the BigInt is _too BigInt_ then it will
1318         throw.
1319
1320       - Strings are bound as strings (use bindAsBlob() to force
1321         blob binding).
1322
1323       - Uint8Array and Int8Array instances are bound as blobs.
1324         (TODO: binding the other TypedArray types.)
1325
1326       If passed an array, each element of the array is bound at
1327       the parameter index equal to the array index plus 1
1328       (because arrays are 0-based but binding is 1-based).
1329
1330       If passed an object, each object key is treated as a
1331       bindable parameter name. The object keys _must_ match any
1332       bindable parameter names, including any `$`, `@`, or `:`
1333       prefix. Because `$` is a legal identifier chararacter in
1334       JavaScript, that is the suggested prefix for bindable
1335       parameters: `stmt.bind({$a: 1, $b: 2})`.
1336
1337       It returns this object on success and throws on
1338       error. Errors include:
1339
1340       - Any bind index is out of range, a named bind parameter
1341       does not match, or this statement has no bindable
1342       parameters.
1343
1344       - Any value to bind is of an unsupported type.
1345
1346       - Passed no arguments or more than two.
1347
1348       - The statement has been finalized.
1349    */
1350    bind: function(/*[ndx,] arg*/){
1351      affirmStmtOpen(this);
1352      let ndx, arg;
1353      switch(arguments.length){
1354          case 1: ndx = 1; arg = arguments[0]; break;
1355          case 2: ndx = arguments[0]; arg = arguments[1]; break;
1356          default: toss3("Invalid bind() arguments.");
1357      }
1358      if(undefined===arg){
1359        /* It might seem intuitive to bind undefined as NULL
1360           but this approach simplifies certain client-side
1361           uses when passing on arguments between 2+ levels of
1362           functions. */
1363        return this;
1364      }else if(!this.parameterCount){
1365        toss3("This statement has no bindable parameters.");
1366      }
1367      this._mayGet = false;
1368      if(null===arg){
1369        /* bind NULL */
1370        return bindOne(this, ndx, BindTypes.null, arg);
1371      }
1372      else if(Array.isArray(arg)){
1373        /* bind each entry by index */
1374        if(1!==arguments.length){
1375          toss3("When binding an array, an index argument is not permitted.");
1376        }
1377        arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
1378        return this;
1379      }
1380      else if('object'===typeof arg/*null was checked above*/
1381              && !util.isBindableTypedArray(arg)){
1382        /* Treat each property of arg as a named bound parameter. */
1383        if(1!==arguments.length){
1384          toss3("When binding an object, an index argument is not permitted.");
1385        }
1386        Object.keys(arg)
1387          .forEach(k=>bindOne(this, k,
1388                              affirmSupportedBindType(arg[k]),
1389                              arg[k]));
1390        return this;
1391      }else{
1392        return bindOne(this, ndx, affirmSupportedBindType(arg), arg);
1393      }
1394      toss3("Should not reach this point.");
1395    },
1396    /**
1397       Special case of bind() which binds the given value using the
1398       BLOB binding mechanism instead of the default selected one for
1399       the value. The ndx may be a numbered or named bind index. The
1400       value must be of type string, null/undefined (both get treated
1401       as null), or a TypedArray of a type supported by the bind()
1402       API.
1403
1404       If passed a single argument, a bind index of 1 is assumed and
1405       the first argument is the value.
1406    */
1407    bindAsBlob: function(ndx,arg){
1408      affirmStmtOpen(this);
1409      if(1===arguments.length){
1410        arg = ndx;
1411        ndx = 1;
1412      }
1413      const t = affirmSupportedBindType(arg);
1414      if(BindTypes.string !== t && BindTypes.blob !== t
1415         && BindTypes.null !== t){
1416        toss3("Invalid value type for bindAsBlob()");
1417      }
1418      bindOne(this, ndx, BindTypes.blob, arg);
1419      this._mayGet = false;
1420      return this;
1421    },
1422    /**
1423       Steps the statement one time. If the result indicates that a
1424       row of data is available, a truthy value is returned.
1425       If no row of data is available, a falsy
1426       value is returned.  Throws on error.
1427    */
1428    step: function(){
1429      affirmUnlocked(this, 'step()');
1430      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
1431      switch(rc){
1432          case capi.SQLITE_DONE: return this._mayGet = false;
1433          case capi.SQLITE_ROW: return this._mayGet = true;
1434          default:
1435            this._mayGet = false;
1436            console.warn("sqlite3_step() rc=",rc,
1437                         capi.sqlite3_js_rc_str(rc),
1438                         "SQL =", capi.sqlite3_sql(this.pointer));
1439            DB.checkRc(this.db.pointer, rc);
1440      }
1441    },
1442    /**
1443       Functions exactly like step() except that...
1444
1445       1) On success, it calls this.reset() and returns this object.
1446       2) On error, it throws and does not call reset().
1447
1448       This is intended to simplify constructs like:
1449
1450       ```
1451       for(...) {
1452         stmt.bind(...).stepReset();
1453       }
1454       ```
1455
1456       Note that the reset() call makes it illegal to call this.get()
1457       after the step.
1458    */
1459    stepReset: function(){
1460      this.step();
1461      return this.reset();
1462    },
1463    /**
1464       Functions like step() except that it finalizes this statement
1465       immediately after stepping unless the step cannot be performed
1466       because the statement is locked. Throws on error, but any error
1467       other than the statement-is-locked case will also trigger
1468       finalization of this statement.
1469
1470       On success, it returns true if the step indicated that a row of
1471       data was available, else it returns false.
1472
1473       This is intended to simplify use cases such as:
1474
1475       ```
1476       aDb.prepare("insert into foo(a) values(?)").bind(123).stepFinalize();
1477       ```
1478    */
1479    stepFinalize: function(){
1480      const rc = this.step();
1481      this.finalize();
1482      return rc;
1483    },
1484    /**
1485       Fetches the value from the given 0-based column index of
1486       the current data row, throwing if index is out of range.
1487
1488       Requires that step() has just returned a truthy value, else
1489       an exception is thrown.
1490
1491       By default it will determine the data type of the result
1492       automatically. If passed a second arugment, it must be one
1493       of the enumeration values for sqlite3 types, which are
1494       defined as members of the sqlite3 module: SQLITE_INTEGER,
1495       SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
1496       except for undefined, will trigger an exception. Passing
1497       undefined is the same as not passing a value. It is legal
1498       to, e.g., fetch an integer value as a string, in which case
1499       sqlite3 will convert the value to a string.
1500
1501       If ndx is an array, this function behaves a differently: it
1502       assigns the indexes of the array, from 0 to the number of
1503       result columns, to the values of the corresponding column,
1504       and returns that array.
1505
1506       If ndx is a plain object, this function behaves even
1507       differentlier: it assigns the properties of the object to
1508       the values of their corresponding result columns.
1509
1510       Blobs are returned as Uint8Array instances.
1511
1512       Potential TODO: add type ID SQLITE_JSON, which fetches the
1513       result as a string and passes it (if it's not null) to
1514       JSON.parse(), returning the result of that. Until then,
1515       getJSON() can be used for that.
1516    */
1517    get: function(ndx,asType){
1518      if(!affirmStmtOpen(this)._mayGet){
1519        toss3("Stmt.step() has not (recently) returned true.");
1520      }
1521      if(Array.isArray(ndx)){
1522        let i = 0;
1523        while(i<this.columnCount){
1524          ndx[i] = this.get(i++);
1525        }
1526        return ndx;
1527      }else if(ndx && 'object'===typeof ndx){
1528        let i = 0;
1529        while(i<this.columnCount){
1530          ndx[capi.sqlite3_column_name(this.pointer,i)] = this.get(i++);
1531        }
1532        return ndx;
1533      }
1534      affirmColIndex(this, ndx);
1535      switch(undefined===asType
1536             ? capi.sqlite3_column_type(this.pointer, ndx)
1537             : asType){
1538          case capi.SQLITE_NULL: return null;
1539          case capi.SQLITE_INTEGER:{
1540            if(wasm.bigIntEnabled){
1541              const rc = capi.sqlite3_column_int64(this.pointer, ndx);
1542              if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){
1543                /* Coerce "normal" number ranges to normal number values,
1544                   and only return BigInt-type values for numbers out of this
1545                   range. */
1546                return Number(rc).valueOf();
1547              }
1548              return rc;
1549            }else{
1550              const rc = capi.sqlite3_column_double(this.pointer, ndx);
1551              if(rc>Number.MAX_SAFE_INTEGER || rc<Number.MIN_SAFE_INTEGER){
1552                /* Throwing here is arguable but, since we're explicitly
1553                   extracting an SQLITE_INTEGER-type value, it seems fair to throw
1554                   if the extracted number is out of range for that type.
1555                   This policy may be laxened to simply pass on the number and
1556                   hope for the best, as the C API would do. */
1557                toss3("Integer is out of range for JS integer range: "+rc);
1558              }
1559              //console.log("get integer rc=",rc,isInt32(rc));
1560              return util.isInt32(rc) ? (rc | 0) : rc;
1561            }
1562          }
1563          case capi.SQLITE_FLOAT:
1564            return capi.sqlite3_column_double(this.pointer, ndx);
1565          case capi.SQLITE_TEXT:
1566            return capi.sqlite3_column_text(this.pointer, ndx);
1567          case capi.SQLITE_BLOB: {
1568            const n = capi.sqlite3_column_bytes(this.pointer, ndx),
1569                  ptr = capi.sqlite3_column_blob(this.pointer, ndx),
1570                  rc = new Uint8Array(n);
1571            //heap = n ? wasm.heap8() : false;
1572            if(n) rc.set(wasm.heap8u().slice(ptr, ptr+n), 0);
1573            //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
1574            if(n && this.db._blobXfer instanceof Array){
1575              /* This is an optimization soley for the
1576                 Worker-based API. These values will be
1577                 transfered to the main thread directly
1578                 instead of being copied. */
1579              this.db._blobXfer.push(rc.buffer);
1580            }
1581            return rc;
1582          }
1583          default: toss3("Don't know how to translate",
1584                         "type of result column #"+ndx+".");
1585      }
1586      toss3("Not reached.");
1587    },
1588    /** Equivalent to get(ndx) but coerces the result to an
1589        integer. */
1590    getInt: function(ndx){return this.get(ndx,capi.SQLITE_INTEGER)},
1591    /** Equivalent to get(ndx) but coerces the result to a
1592        float. */
1593    getFloat: function(ndx){return this.get(ndx,capi.SQLITE_FLOAT)},
1594    /** Equivalent to get(ndx) but coerces the result to a
1595        string. */
1596    getString: function(ndx){return this.get(ndx,capi.SQLITE_TEXT)},
1597    /** Equivalent to get(ndx) but coerces the result to a
1598        Uint8Array. */
1599    getBlob: function(ndx){return this.get(ndx,capi.SQLITE_BLOB)},
1600    /**
1601       A convenience wrapper around get() which fetches the value
1602       as a string and then, if it is not null, passes it to
1603       JSON.parse(), returning that result. Throws if parsing
1604       fails. If the result is null, null is returned. An empty
1605       string, on the other hand, will trigger an exception.
1606    */
1607    getJSON: function(ndx){
1608      const s = this.get(ndx, capi.SQLITE_STRING);
1609      return null===s ? s : JSON.parse(s);
1610    },
1611    // Design note: the only reason most of these getters have a 'get'
1612    // prefix is for consistency with getVALUE_TYPE().  The latter
1613    // arguably really need that prefix for API readability and the
1614    // rest arguably don't, but consistency is a powerful thing.
1615    /**
1616       Returns the result column name of the given index, or
1617       throws if index is out of bounds or this statement has been
1618       finalized. This can be used without having run step()
1619       first.
1620    */
1621    getColumnName: function(ndx){
1622      return capi.sqlite3_column_name(
1623        affirmColIndex(affirmStmtOpen(this),ndx).pointer, ndx
1624      );
1625    },
1626    /**
1627       If this statement potentially has result columns, this
1628       function returns an array of all such names. If passed an
1629       array, it is used as the target and all names are appended
1630       to it. Returns the target array. Throws if this statement
1631       cannot have result columns. This object's columnCount member
1632       holds the number of columns.
1633    */
1634    getColumnNames: function(tgt=[]){
1635      affirmColIndex(affirmStmtOpen(this),0);
1636      for(let i = 0; i < this.columnCount; ++i){
1637        tgt.push(capi.sqlite3_column_name(this.pointer, i));
1638      }
1639      return tgt;
1640    },
1641    /**
1642       If this statement has named bindable parameters and the
1643       given name matches one, its 1-based bind index is
1644       returned. If no match is found, 0 is returned. If it has no
1645       bindable parameters, the undefined value is returned.
1646    */
1647    getParamIndex: function(name){
1648      return (affirmStmtOpen(this).parameterCount
1649              ? capi.sqlite3_bind_parameter_index(this.pointer, name)
1650              : undefined);
1651    }
1652  }/*Stmt.prototype*/;
1653
1654  {/* Add the `pointer` property to DB and Stmt. */
1655    const prop = {
1656      enumerable: true,
1657      get: function(){return __ptrMap.get(this)},
1658      set: ()=>toss3("The pointer property is read-only.")
1659    }
1660    Object.defineProperty(Stmt.prototype, 'pointer', prop);
1661    Object.defineProperty(DB.prototype, 'pointer', prop);
1662  }
1663
1664  /** The OO API's public namespace. */
1665  sqlite3.oo1 = {
1666    version: {
1667      lib: capi.sqlite3_libversion(),
1668      ooApi: "0.1"
1669    },
1670    DB,
1671    Stmt,
1672    dbCtorHelper
1673  }/*oo1 object*/;
1674
1675  if(util.isUIThread()){
1676    /**
1677       Functionally equivalent to DB(storageName,'c','kvvfs') except
1678       that it throws if the given storage name is not one of 'local'
1679       or 'session'.
1680    */
1681    sqlite3.oo1.JsStorageDb = function(storageName='session'){
1682      if('session'!==storageName && 'local'!==storageName){
1683        toss3("JsStorageDb db name must be one of 'session' or 'local'.");
1684      }
1685      dbCtorHelper.call(this, {
1686        filename: storageName,
1687        flags: 'c',
1688        vfs: "kvvfs"
1689      });
1690    };
1691    const jdb = sqlite3.oo1.JsStorageDb;
1692    jdb.prototype = Object.create(DB.prototype);
1693    /** Equivalent to sqlite3_js_kvvfs_clear(). */
1694    jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
1695    /**
1696       Clears this database instance's storage or throws if this
1697       instance has been closed. Returns the number of
1698       database blocks which were cleaned up.
1699    */
1700    jdb.prototype.clearStorage = function(){
1701      return jdb.clearStorage(affirmDbOpen(this).filename);
1702    };
1703    /** Equivalent to sqlite3_js_kvvfs_size(). */
1704    jdb.storageSize = capi.sqlite3_js_kvvfs_size;
1705    /**
1706       Returns the _approximate_ number of bytes this database takes
1707       up in its storage or throws if this instance has been closed.
1708    */
1709    jdb.prototype.storageSize = function(){
1710      return jdb.storageSize(affirmDbOpen(this).filename);
1711    };
1712  }/*main-window-only bits*/
1713
1714});
1715
1716