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