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