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