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