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  }/*DB.prototype*/;
1030
1031
1032  /** Throws if the given Stmt has been finalized, else stmt is
1033      returned. */
1034  const affirmStmtOpen = function(stmt){
1035    if(!stmt.pointer) toss3("Stmt has been closed.");
1036    return stmt;
1037  };
1038
1039  /** Returns an opaque truthy value from the BindTypes
1040      enum if v's type is a valid bindable type, else
1041      returns a falsy value. As a special case, a value of
1042      undefined is treated as a bind type of null. */
1043  const isSupportedBindType = function(v){
1044    let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v];
1045    switch(t){
1046        case BindTypes.boolean:
1047        case BindTypes.null:
1048        case BindTypes.number:
1049        case BindTypes.string:
1050          return t;
1051        case BindTypes.bigint:
1052          if(capi.wasm.bigIntEnabled) return t;
1053          /* else fall through */
1054        default:
1055          //console.log("isSupportedBindType",t,v);
1056          return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
1057    }
1058  };
1059
1060  /**
1061     If isSupportedBindType(v) returns a truthy value, this
1062     function returns that value, else it throws.
1063  */
1064  const affirmSupportedBindType = function(v){
1065    //console.log('affirmSupportedBindType',v);
1066    return isSupportedBindType(v) || toss3("Unsupported bind() argument type:",typeof v);
1067  };
1068
1069  /**
1070     If key is a number and within range of stmt's bound parameter
1071     count, key is returned.
1072
1073     If key is not a number then it is checked against named
1074     parameters. If a match is found, its index is returned.
1075
1076     Else it throws.
1077  */
1078  const affirmParamIndex = function(stmt,key){
1079    const n = ('number'===typeof key)
1080          ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key);
1081    if(0===n || !util.isInt32(n)){
1082      toss3("Invalid bind() parameter name: "+key);
1083    }
1084    else if(n<1 || n>stmt.parameterCount) toss3("Bind index",key,"is out of range.");
1085    return n;
1086  };
1087
1088  /**
1089     If stmt._isLocked is truthy, this throws an exception
1090     complaining that the 2nd argument (an operation name,
1091     e.g. "bind()") is not legal while the statement is "locked".
1092     Locking happens before an exec()-like callback is passed a
1093     statement, to ensure that the callback does not mutate or
1094     finalize the statement. If it does not throw, it returns stmt.
1095  */
1096  const affirmUnlocked = function(stmt,currentOpName){
1097    if(stmt._isLocked){
1098      toss3("Operation is illegal when statement is locked:",currentOpName);
1099    }
1100    return stmt;
1101  };
1102
1103  /**
1104     Binds a single bound parameter value on the given stmt at the
1105     given index (numeric or named) using the given bindType (see
1106     the BindTypes enum) and value. Throws on error. Returns stmt on
1107     success.
1108  */
1109  const bindOne = function f(stmt,ndx,bindType,val){
1110    affirmUnlocked(stmt, 'bind()');
1111    if(!f._){
1112      if(capi.wasm.bigIntEnabled){
1113        f._maxInt = BigInt("0x7fffffffffffffff");
1114        f._minInt = ~f._maxInt;
1115      }
1116      /* Reminder: when not in BigInt mode, it's impossible for
1117         JS to represent a number out of the range we can bind,
1118         so we have no range checking. */
1119      f._ = {
1120        string: function(stmt, ndx, val, asBlob){
1121          if(1){
1122            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1123            const stack = capi.wasm.scopedAllocPush();
1124            try{
1125              const n = capi.wasm.jstrlen(val);
1126              const pStr = capi.wasm.scopedAlloc(n);
1127              capi.wasm.jstrcpy(val, capi.wasm.heap8u(), pStr, n, false);
1128              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1129              return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
1130            }finally{
1131              capi.wasm.scopedAllocPop(stack);
1132            }
1133          }else{
1134            const bytes = capi.wasm.jstrToUintArray(val,false);
1135            const pStr = capi.wasm.alloc(bytes.length || 1);
1136            capi.wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
1137            try{
1138              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
1139              return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT);
1140            }finally{
1141              capi.wasm.dealloc(pStr);
1142            }
1143          }
1144        }
1145      };
1146    }
1147    affirmSupportedBindType(val);
1148    ndx = affirmParamIndex(stmt,ndx);
1149    let rc = 0;
1150    switch((null===val || undefined===val) ? BindTypes.null : bindType){
1151        case BindTypes.null:
1152          rc = capi.sqlite3_bind_null(stmt.pointer, ndx);
1153          break;
1154        case BindTypes.string:
1155          rc = f._.string(stmt, ndx, val, false);
1156          break;
1157        case BindTypes.number: {
1158          let m;
1159          if(util.isInt32(val)) m = capi.sqlite3_bind_int;
1160          else if(capi.wasm.bigIntEnabled && ('bigint'===typeof val)){
1161            if(val<f._minInt || val>f._maxInt){
1162              toss3("BigInt value is out of range for int64: "+val);
1163            }
1164            m = capi.sqlite3_bind_int64;
1165          }else if(Number.isInteger(val)){
1166            m = capi.sqlite3_bind_int64;
1167          }else{
1168            m = capi.sqlite3_bind_double;
1169          }
1170          rc = m(stmt.pointer, ndx, val);
1171          break;
1172        }
1173        case BindTypes.boolean:
1174          rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0);
1175          break;
1176        case BindTypes.blob: {
1177          if('string'===typeof val){
1178            rc = f._.string(stmt, ndx, val, true);
1179          }else if(!util.isBindableTypedArray(val)){
1180            toss3("Binding a value as a blob requires",
1181                  "that it be a string, Uint8Array, or Int8Array.");
1182          }else if(1){
1183            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1184            const stack = capi.wasm.scopedAllocPush();
1185            try{
1186              const pBlob = capi.wasm.scopedAlloc(val.byteLength || 1);
1187              capi.wasm.heap8().set(val.byteLength ? val : [0], pBlob)
1188              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1189                                         capi.SQLITE_TRANSIENT);
1190            }finally{
1191              capi.wasm.scopedAllocPop(stack);
1192            }
1193          }else{
1194            const pBlob = capi.wasm.allocFromTypedArray(val);
1195            try{
1196              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1197                                         capi.SQLITE_TRANSIENT);
1198            }finally{
1199              capi.wasm.dealloc(pBlob);
1200            }
1201          }
1202          break;
1203        }
1204        default:
1205          console.warn("Unsupported bind() argument type:",val);
1206          toss3("Unsupported bind() argument type: "+(typeof val));
1207    }
1208    if(rc) DB.checkRc(stmt.db.pointer, rc);
1209    return stmt;
1210  };
1211
1212  Stmt.prototype = {
1213    /**
1214       "Finalizes" this statement. This is a no-op if the
1215       statement has already been finalizes. Returns
1216       undefined. Most methods in this class will throw if called
1217       after this is.
1218    */
1219    finalize: function(){
1220      if(this.pointer){
1221        affirmUnlocked(this,'finalize()');
1222        delete __stmtMap.get(this.db)[this.pointer];
1223        capi.sqlite3_finalize(this.pointer);
1224        __ptrMap.delete(this);
1225        delete this._mayGet;
1226        delete this.columnCount;
1227        delete this.parameterCount;
1228        delete this.db;
1229        delete this._isLocked;
1230      }
1231    },
1232    /** Clears all bound values. Returns this object.
1233        Throws if this statement has been finalized. */
1234    clearBindings: function(){
1235      affirmUnlocked(affirmStmtOpen(this), 'clearBindings()')
1236      capi.sqlite3_clear_bindings(this.pointer);
1237      this._mayGet = false;
1238      return this;
1239    },
1240    /**
1241       Resets this statement so that it may be step()ed again
1242       from the beginning. Returns this object. Throws if this
1243       statement has been finalized.
1244
1245       If passed a truthy argument then this.clearBindings() is
1246       also called, otherwise any existing bindings, along with
1247       any memory allocated for them, are retained.
1248    */
1249    reset: function(alsoClearBinds){
1250      affirmUnlocked(this,'reset()');
1251      if(alsoClearBinds) this.clearBindings();
1252      capi.sqlite3_reset(affirmStmtOpen(this).pointer);
1253      this._mayGet = false;
1254      return this;
1255    },
1256    /**
1257       Binds one or more values to its bindable parameters. It
1258       accepts 1 or 2 arguments:
1259
1260       If passed a single argument, it must be either an array, an
1261       object, or a value of a bindable type (see below).
1262
1263       If passed 2 arguments, the first one is the 1-based bind
1264       index or bindable parameter name and the second one must be
1265       a value of a bindable type.
1266
1267       Bindable value types:
1268
1269       - null is bound as NULL.
1270
1271       - undefined as a standalone value is a no-op intended to
1272       simplify certain client-side use cases: passing undefined
1273       as a value to this function will not actually bind
1274       anything and this function will skip confirmation that
1275       binding is even legal. (Those semantics simplify certain
1276       client-side uses.) Conversely, a value of undefined as an
1277       array or object property when binding an array/object
1278       (see below) is treated the same as null.
1279
1280       - Numbers are bound as either doubles or integers: doubles
1281       if they are larger than 32 bits, else double or int32,
1282       depending on whether they have a fractional part. (It is,
1283       as of this writing, illegal to call (from JS) a WASM
1284       function which either takes or returns an int64.)
1285       Booleans are bound as integer 0 or 1. It is not expected
1286       the distinction of binding doubles which have no
1287       fractional parts is integers is significant for the
1288       majority of clients due to sqlite3's data typing
1289       model. If capi.wasm.bigIntEnabled is true then this
1290       routine will bind BigInt values as 64-bit integers.
1291
1292       - Strings are bound as strings (use bindAsBlob() to force
1293       blob binding).
1294
1295       - Uint8Array and Int8Array instances are bound as blobs.
1296       (TODO: binding the other TypedArray types.)
1297
1298       If passed an array, each element of the array is bound at
1299       the parameter index equal to the array index plus 1
1300       (because arrays are 0-based but binding is 1-based).
1301
1302       If passed an object, each object key is treated as a
1303       bindable parameter name. The object keys _must_ match any
1304       bindable parameter names, including any `$`, `@`, or `:`
1305       prefix. Because `$` is a legal identifier chararacter in
1306       JavaScript, that is the suggested prefix for bindable
1307       parameters: `stmt.bind({$a: 1, $b: 2})`.
1308
1309       It returns this object on success and throws on
1310       error. Errors include:
1311
1312       - Any bind index is out of range, a named bind parameter
1313       does not match, or this statement has no bindable
1314       parameters.
1315
1316       - Any value to bind is of an unsupported type.
1317
1318       - Passed no arguments or more than two.
1319
1320       - The statement has been finalized.
1321    */
1322    bind: function(/*[ndx,] arg*/){
1323      affirmStmtOpen(this);
1324      let ndx, arg;
1325      switch(arguments.length){
1326          case 1: ndx = 1; arg = arguments[0]; break;
1327          case 2: ndx = arguments[0]; arg = arguments[1]; break;
1328          default: toss3("Invalid bind() arguments.");
1329      }
1330      if(undefined===arg){
1331        /* It might seem intuitive to bind undefined as NULL
1332           but this approach simplifies certain client-side
1333           uses when passing on arguments between 2+ levels of
1334           functions. */
1335        return this;
1336      }else if(!this.parameterCount){
1337        toss3("This statement has no bindable parameters.");
1338      }
1339      this._mayGet = false;
1340      if(null===arg){
1341        /* bind NULL */
1342        return bindOne(this, ndx, BindTypes.null, arg);
1343      }
1344      else if(Array.isArray(arg)){
1345        /* bind each entry by index */
1346        if(1!==arguments.length){
1347          toss3("When binding an array, an index argument is not permitted.");
1348        }
1349        arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
1350        return this;
1351      }
1352      else if('object'===typeof arg/*null was checked above*/
1353              && !util.isBindableTypedArray(arg)){
1354        /* Treat each property of arg as a named bound parameter. */
1355        if(1!==arguments.length){
1356          toss3("When binding an object, an index argument is not permitted.");
1357        }
1358        Object.keys(arg)
1359          .forEach(k=>bindOne(this, k,
1360                              affirmSupportedBindType(arg[k]),
1361                              arg[k]));
1362        return this;
1363      }else{
1364        return bindOne(this, ndx, affirmSupportedBindType(arg), arg);
1365      }
1366      toss3("Should not reach this point.");
1367    },
1368    /**
1369       Special case of bind() which binds the given value using the
1370       BLOB binding mechanism instead of the default selected one for
1371       the value. The ndx may be a numbered or named bind index. The
1372       value must be of type string, null/undefined (both get treated
1373       as null), or a TypedArray of a type supported by the bind()
1374       API.
1375
1376       If passed a single argument, a bind index of 1 is assumed and
1377       the first argument is the value.
1378    */
1379    bindAsBlob: function(ndx,arg){
1380      affirmStmtOpen(this);
1381      if(1===arguments.length){
1382        arg = ndx;
1383        ndx = 1;
1384      }
1385      const t = affirmSupportedBindType(arg);
1386      if(BindTypes.string !== t && BindTypes.blob !== t
1387         && BindTypes.null !== t){
1388        toss3("Invalid value type for bindAsBlob()");
1389      }
1390      bindOne(this, ndx, BindTypes.blob, arg);
1391      this._mayGet = false;
1392      return this;
1393    },
1394    /**
1395       Steps the statement one time. If the result indicates that a
1396       row of data is available, a truthy value is returned.
1397       If no row of data is available, a falsy
1398       value is returned.  Throws on error.
1399    */
1400    step: function(){
1401      affirmUnlocked(this, 'step()');
1402      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
1403      switch(rc){
1404          case capi.SQLITE_DONE: return this._mayGet = false;
1405          case capi.SQLITE_ROW: return this._mayGet = true;
1406          default:
1407            this._mayGet = false;
1408            console.warn("sqlite3_step() rc=",rc,"SQL =",
1409                         capi.sqlite3_sql(this.pointer));
1410            DB.checkRc(this.db.pointer, rc);
1411      }
1412    },
1413    /**
1414       Functions exactly like step() except that...
1415
1416       1) On success, it calls this.reset() and returns this object.
1417       2) On error, it throws and does not call reset().
1418
1419       This is intended to simplify constructs like:
1420
1421       ```
1422       for(...) {
1423         stmt.bind(...).stepReset();
1424       }
1425       ```
1426
1427       Note that the reset() call makes it illegal to call this.get()
1428       after the step.
1429    */
1430    stepReset: function(){
1431      this.step();
1432      return this.reset();
1433    },
1434    /**
1435       Functions like step() except that it finalizes this statement
1436       immediately after stepping unless the step cannot be performed
1437       because the statement is locked. Throws on error, but any error
1438       other than the statement-is-locked case will also trigger
1439       finalization of this statement.
1440
1441       On success, it returns true if the step indicated that a row of
1442       data was available, else it returns false.
1443
1444       This is intended to simplify use cases such as:
1445
1446       ```
1447       aDb.prepare("insert in foo(a) values(?)").bind(123).stepFinalize();
1448       ```
1449    */
1450    stepFinalize: function(){
1451      const rc = this.step();
1452      this.finalize();
1453      return rc;
1454    },
1455    /**
1456       Fetches the value from the given 0-based column index of
1457       the current data row, throwing if index is out of range.
1458
1459       Requires that step() has just returned a truthy value, else
1460       an exception is thrown.
1461
1462       By default it will determine the data type of the result
1463       automatically. If passed a second arugment, it must be one
1464       of the enumeration values for sqlite3 types, which are
1465       defined as members of the sqlite3 module: SQLITE_INTEGER,
1466       SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
1467       except for undefined, will trigger an exception. Passing
1468       undefined is the same as not passing a value. It is legal
1469       to, e.g., fetch an integer value as a string, in which case
1470       sqlite3 will convert the value to a string.
1471
1472       If ndx is an array, this function behaves a differently: it
1473       assigns the indexes of the array, from 0 to the number of
1474       result columns, to the values of the corresponding column,
1475       and returns that array.
1476
1477       If ndx is a plain object, this function behaves even
1478       differentlier: it assigns the properties of the object to
1479       the values of their corresponding result columns.
1480
1481       Blobs are returned as Uint8Array instances.
1482
1483       Potential TODO: add type ID SQLITE_JSON, which fetches the
1484       result as a string and passes it (if it's not null) to
1485       JSON.parse(), returning the result of that. Until then,
1486       getJSON() can be used for that.
1487    */
1488    get: function(ndx,asType){
1489      if(!affirmStmtOpen(this)._mayGet){
1490        toss3("Stmt.step() has not (recently) returned true.");
1491      }
1492      if(Array.isArray(ndx)){
1493        let i = 0;
1494        while(i<this.columnCount){
1495          ndx[i] = this.get(i++);
1496        }
1497        return ndx;
1498      }else if(ndx && 'object'===typeof ndx){
1499        let i = 0;
1500        while(i<this.columnCount){
1501          ndx[capi.sqlite3_column_name(this.pointer,i)] = this.get(i++);
1502        }
1503        return ndx;
1504      }
1505      affirmColIndex(this, ndx);
1506      switch(undefined===asType
1507             ? capi.sqlite3_column_type(this.pointer, ndx)
1508             : asType){
1509          case capi.SQLITE_NULL: return null;
1510          case capi.SQLITE_INTEGER:{
1511            if(capi.wasm.bigIntEnabled){
1512              const rc = capi.sqlite3_column_int64(this.pointer, ndx);
1513              if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){
1514                /* Coerce "normal" number ranges to normal number values,
1515                   and only return BigInt-type values for numbers out of this
1516                   range. */
1517                return Number(rc).valueOf();
1518              }
1519              return rc;
1520            }else{
1521              const rc = capi.sqlite3_column_double(this.pointer, ndx);
1522              if(rc>Number.MAX_SAFE_INTEGER || rc<Number.MIN_SAFE_INTEGER){
1523                /* Throwing here is arguable but, since we're explicitly
1524                   extracting an SQLITE_INTEGER-type value, it seems fair to throw
1525                   if the extracted number is out of range for that type.
1526                   This policy may be laxened to simply pass on the number and
1527                   hope for the best, as the C API would do. */
1528                toss3("Integer is out of range for JS integer range: "+rc);
1529              }
1530              //console.log("get integer rc=",rc,isInt32(rc));
1531              return util.isInt32(rc) ? (rc | 0) : rc;
1532            }
1533          }
1534          case capi.SQLITE_FLOAT:
1535            return capi.sqlite3_column_double(this.pointer, ndx);
1536          case capi.SQLITE_TEXT:
1537            return capi.sqlite3_column_text(this.pointer, ndx);
1538          case capi.SQLITE_BLOB: {
1539            const n = capi.sqlite3_column_bytes(this.pointer, ndx),
1540                  ptr = capi.sqlite3_column_blob(this.pointer, ndx),
1541                  rc = new Uint8Array(n);
1542            //heap = n ? capi.wasm.heap8() : false;
1543            if(n) rc.set(capi.wasm.heap8u().slice(ptr, ptr+n), 0);
1544            //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
1545            if(n && this.db._blobXfer instanceof Array){
1546              /* This is an optimization soley for the
1547                 Worker-based API. These values will be
1548                 transfered to the main thread directly
1549                 instead of being copied. */
1550              this.db._blobXfer.push(rc.buffer);
1551            }
1552            return rc;
1553          }
1554          default: toss3("Don't know how to translate",
1555                         "type of result column #"+ndx+".");
1556      }
1557      toss3("Not reached.");
1558    },
1559    /** Equivalent to get(ndx) but coerces the result to an
1560        integer. */
1561    getInt: function(ndx){return this.get(ndx,capi.SQLITE_INTEGER)},
1562    /** Equivalent to get(ndx) but coerces the result to a
1563        float. */
1564    getFloat: function(ndx){return this.get(ndx,capi.SQLITE_FLOAT)},
1565    /** Equivalent to get(ndx) but coerces the result to a
1566        string. */
1567    getString: function(ndx){return this.get(ndx,capi.SQLITE_TEXT)},
1568    /** Equivalent to get(ndx) but coerces the result to a
1569        Uint8Array. */
1570    getBlob: function(ndx){return this.get(ndx,capi.SQLITE_BLOB)},
1571    /**
1572       A convenience wrapper around get() which fetches the value
1573       as a string and then, if it is not null, passes it to
1574       JSON.parse(), returning that result. Throws if parsing
1575       fails. If the result is null, null is returned. An empty
1576       string, on the other hand, will trigger an exception.
1577    */
1578    getJSON: function(ndx){
1579      const s = this.get(ndx, capi.SQLITE_STRING);
1580      return null===s ? s : JSON.parse(s);
1581    },
1582    // Design note: the only reason most of these getters have a 'get'
1583    // prefix is for consistency with getVALUE_TYPE().  The latter
1584    // arguablly really need that prefix for API readability and the
1585    // rest arguably don't, but consistency is a powerful thing.
1586    /**
1587       Returns the result column name of the given index, or
1588       throws if index is out of bounds or this statement has been
1589       finalized. This can be used without having run step()
1590       first.
1591    */
1592    getColumnName: function(ndx){
1593      return capi.sqlite3_column_name(
1594        affirmColIndex(affirmStmtOpen(this),ndx).pointer, ndx
1595      );
1596    },
1597    /**
1598       If this statement potentially has result columns, this
1599       function returns an array of all such names. If passed an
1600       array, it is used as the target and all names are appended
1601       to it. Returns the target array. Throws if this statement
1602       cannot have result columns. This object's columnCount member
1603       holds the number of columns.
1604    */
1605    getColumnNames: function(tgt){
1606      affirmColIndex(affirmStmtOpen(this),0);
1607      if(!tgt) tgt = [];
1608      for(let i = 0; i < this.columnCount; ++i){
1609        tgt.push(capi.sqlite3_column_name(this.pointer, i));
1610      }
1611      return tgt;
1612    },
1613    /**
1614       If this statement has named bindable parameters and the
1615       given name matches one, its 1-based bind index is
1616       returned. If no match is found, 0 is returned. If it has no
1617       bindable parameters, the undefined value is returned.
1618    */
1619    getParamIndex: function(name){
1620      return (affirmStmtOpen(this).parameterCount
1621              ? capi.sqlite3_bind_parameter_index(this.pointer, name)
1622              : undefined);
1623    }
1624  }/*Stmt.prototype*/;
1625
1626  {/* Add the `pointer` property to DB and Stmt. */
1627    const prop = {
1628      enumerable: true,
1629      get: function(){return __ptrMap.get(this)},
1630      set: ()=>toss3("The pointer property is read-only.")
1631    }
1632    Object.defineProperty(Stmt.prototype, 'pointer', prop);
1633    Object.defineProperty(DB.prototype, 'pointer', prop);
1634  }
1635
1636  /** The OO API's public namespace. */
1637  sqlite3.oo1 = {
1638    version: {
1639      lib: capi.sqlite3_libversion(),
1640      ooApi: "0.1"
1641    },
1642    DB,
1643    Stmt,
1644    dbCtorHelper
1645  }/*oo1 object*/;
1646
1647});
1648
1649