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