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