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