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