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