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