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(resultRows) resultRows.push(row);
579              if(callback) callback(row, stmt);
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       Starts a transaction, calls the given callback, and then either
824       rolls back or commits the transaction, depending on whether the
825       callback throw. The callback is pass this db object as its only
826       argument.  On success, returns the result of the callback.
827       Throws on error.
828     */
829    callInTransaction: function(callback){
830      affirmDbOpen(this);
831      let err, rc;
832      this.exec("BEGIN");
833      try { rc = callback(this); }
834      catch(e){
835        err = e;
836        throw e;
837      }finally{
838        if(err) this.exec("ROLLBACK");
839        else this.exec("COMMIT");
840      }
841      return rc;
842    },
843
844    /**
845       This function currently does nothing and always throws.  It
846       WILL BE REMOVED pending other refactoring, to eliminate a hard
847       dependency on Emscripten. This feature will be moved into a
848       higher-level API or a runtime-configurable feature.
849
850       That said, what its replacement should eventually do is...
851
852       Exports a copy of this db's file as a Uint8Array and
853       returns it. It is technically not legal to call this while
854       any prepared statement are currently active because,
855       depending on the platform, it might not be legal to read
856       the db while a statement is locking it. Throws if this db
857       is not open or has any opened statements.
858
859       The resulting buffer can be passed to this class's
860       constructor to restore the DB.
861
862       Maintenance reminder: the corresponding sql.js impl of this
863       feature closes the current db, finalizing any active
864       statements and (seemingly unnecessarily) destroys any UDFs,
865       copies the file, and then re-opens it (without restoring
866       the UDFs). Those gymnastics are not necessary on the tested
867       platform but might be necessary on others. Because of that
868       eventuality, this interface currently enforces that no
869       statements are active when this is run. It will throw if
870       any are.
871    */
872    exportBinaryImage: function(){
873      toss3("exportBinaryImage() is slated for removal for portability reasons.");
874      /***********************
875         The following is currently kept only for reference when
876         porting to some other layer, noting that we may well not be
877         able to implement this, at this level, when using the OPFS
878         VFS because of its exclusive locking policy.
879
880         affirmDbOpen(this);
881         if(this.openStatementCount()>0){
882           toss3("Cannot export with prepared statements active!",
883                 "finalize() all statements and try again.");
884         }
885         return MODCFG.FS.readFile(this.filename, {encoding:"binary"});
886      ***********************/
887    }
888  }/*DB.prototype*/;
889
890
891  /** Throws if the given Stmt has been finalized, else stmt is
892      returned. */
893  const affirmStmtOpen = function(stmt){
894    if(!stmt.pointer) toss3("Stmt has been closed.");
895    return stmt;
896  };
897
898  /** Returns an opaque truthy value from the BindTypes
899      enum if v's type is a valid bindable type, else
900      returns a falsy value. As a special case, a value of
901      undefined is treated as a bind type of null. */
902  const isSupportedBindType = function(v){
903    let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v];
904    switch(t){
905        case BindTypes.boolean:
906        case BindTypes.null:
907        case BindTypes.number:
908        case BindTypes.string:
909          return t;
910        case BindTypes.bigint:
911          if(capi.wasm.bigIntEnabled) return t;
912          /* else fall through */
913        default:
914          //console.log("isSupportedBindType",t,v);
915          return util.isBindableTypedArray(v) ? BindTypes.blob : undefined;
916    }
917  };
918
919  /**
920     If isSupportedBindType(v) returns a truthy value, this
921     function returns that value, else it throws.
922  */
923  const affirmSupportedBindType = function(v){
924    //console.log('affirmSupportedBindType',v);
925    return isSupportedBindType(v) || toss3("Unsupported bind() argument type:",typeof v);
926  };
927
928  /**
929     If key is a number and within range of stmt's bound parameter
930     count, key is returned.
931
932     If key is not a number then it is checked against named
933     parameters. If a match is found, its index is returned.
934
935     Else it throws.
936  */
937  const affirmParamIndex = function(stmt,key){
938    const n = ('number'===typeof key)
939          ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key);
940    if(0===n || !util.isInt32(n)){
941      toss3("Invalid bind() parameter name: "+key);
942    }
943    else if(n<1 || n>stmt.parameterCount) toss3("Bind index",key,"is out of range.");
944    return n;
945  };
946
947  /**
948     If stmt._isLocked is truthy, this throws an exception
949     complaining that the 2nd argument (an operation name,
950     e.g. "bind()") is not legal while the statement is "locked".
951     Locking happens before an exec()-like callback is passed a
952     statement, to ensure that the callback does not mutate or
953     finalize the statement. If it does not throw, it returns stmt.
954  */
955  const affirmUnlocked = function(stmt,currentOpName){
956    if(stmt._isLocked){
957      toss3("Operation is illegal when statement is locked:",currentOpName);
958    }
959    return stmt;
960  };
961
962  /**
963     Binds a single bound parameter value on the given stmt at the
964     given index (numeric or named) using the given bindType (see
965     the BindTypes enum) and value. Throws on error. Returns stmt on
966     success.
967  */
968  const bindOne = function f(stmt,ndx,bindType,val){
969    affirmUnlocked(stmt, 'bind()');
970    if(!f._){
971      if(capi.wasm.bigIntEnabled){
972        f._maxInt = BigInt("0x7fffffffffffffff");
973        f._minInt = ~f._maxInt;
974      }
975      /* Reminder: when not in BigInt mode, it's impossible for
976         JS to represent a number out of the range we can bind,
977         so we have no range checking. */
978      f._ = {
979        string: function(stmt, ndx, val, asBlob){
980          if(1){
981            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
982            const stack = capi.wasm.scopedAllocPush();
983            try{
984              const n = capi.wasm.jstrlen(val);
985              const pStr = capi.wasm.scopedAlloc(n);
986              capi.wasm.jstrcpy(val, capi.wasm.heap8u(), pStr, n, false);
987              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
988              return f(stmt.pointer, ndx, pStr, n, capi.SQLITE_TRANSIENT);
989            }finally{
990              capi.wasm.scopedAllocPop(stack);
991            }
992          }else{
993            const bytes = capi.wasm.jstrToUintArray(val,false);
994            const pStr = capi.wasm.alloc(bytes.length || 1);
995            capi.wasm.heap8u().set(bytes.length ? bytes : [0], pStr);
996            try{
997              const f = asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text;
998              return f(stmt.pointer, ndx, pStr, bytes.length, capi.SQLITE_TRANSIENT);
999            }finally{
1000              capi.wasm.dealloc(pStr);
1001            }
1002          }
1003        }
1004      };
1005    }
1006    affirmSupportedBindType(val);
1007    ndx = affirmParamIndex(stmt,ndx);
1008    let rc = 0;
1009    switch((null===val || undefined===val) ? BindTypes.null : bindType){
1010        case BindTypes.null:
1011          rc = capi.sqlite3_bind_null(stmt.pointer, ndx);
1012          break;
1013        case BindTypes.string:
1014          rc = f._.string(stmt, ndx, val, false);
1015          break;
1016        case BindTypes.number: {
1017          let m;
1018          if(util.isInt32(val)) m = capi.sqlite3_bind_int;
1019          else if(capi.wasm.bigIntEnabled && ('bigint'===typeof val)){
1020            if(val<f._minInt || val>f._maxInt){
1021              toss3("BigInt value is out of range for int64: "+val);
1022            }
1023            m = capi.sqlite3_bind_int64;
1024          }else if(Number.isInteger(val)){
1025            m = capi.sqlite3_bind_int64;
1026          }else{
1027            m = capi.sqlite3_bind_double;
1028          }
1029          rc = m(stmt.pointer, ndx, val);
1030          break;
1031        }
1032        case BindTypes.boolean:
1033          rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0);
1034          break;
1035        case BindTypes.blob: {
1036          if('string'===typeof val){
1037            rc = f._.string(stmt, ndx, val, true);
1038          }else if(!util.isBindableTypedArray(val)){
1039            toss3("Binding a value as a blob requires",
1040                  "that it be a string, Uint8Array, or Int8Array.");
1041          }else if(1){
1042            /* _Hypothetically_ more efficient than the impl in the 'else' block. */
1043            const stack = capi.wasm.scopedAllocPush();
1044            try{
1045              const pBlob = capi.wasm.scopedAlloc(val.byteLength || 1);
1046              capi.wasm.heap8().set(val.byteLength ? val : [0], pBlob)
1047              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1048                                         capi.SQLITE_TRANSIENT);
1049            }finally{
1050              capi.wasm.scopedAllocPop(stack);
1051            }
1052          }else{
1053            const pBlob = capi.wasm.mallocFromTypedArray(val);
1054            try{
1055              rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength,
1056                                         capi.SQLITE_TRANSIENT);
1057            }finally{
1058              capi.wasm.dealloc(pBlob);
1059            }
1060          }
1061          break;
1062        }
1063        default:
1064          console.warn("Unsupported bind() argument type:",val);
1065          toss3("Unsupported bind() argument type: "+(typeof val));
1066    }
1067    if(rc) DB.checkRc(stmt.db.pointer, rc);
1068    return stmt;
1069  };
1070
1071  Stmt.prototype = {
1072    /**
1073       "Finalizes" this statement. This is a no-op if the
1074       statement has already been finalizes. Returns
1075       undefined. Most methods in this class will throw if called
1076       after this is.
1077    */
1078    finalize: function(){
1079      if(this.pointer){
1080        affirmUnlocked(this,'finalize()');
1081        delete __stmtMap.get(this.db)[this.pointer];
1082        capi.sqlite3_finalize(this.pointer);
1083        __ptrMap.delete(this);
1084        delete this.columnCount;
1085        delete this.parameterCount;
1086        delete this.db;
1087        delete this._isLocked;
1088      }
1089    },
1090    /** Clears all bound values. Returns this object.
1091        Throws if this statement has been finalized. */
1092    clearBindings: function(){
1093      affirmUnlocked(affirmStmtOpen(this), 'clearBindings()')
1094      capi.sqlite3_clear_bindings(this.pointer);
1095      this._mayGet = false;
1096      return this;
1097    },
1098    /**
1099       Resets this statement so that it may be step()ed again
1100       from the beginning. Returns this object. Throws if this
1101       statement has been finalized.
1102
1103       If passed a truthy argument then this.clearBindings() is
1104       also called, otherwise any existing bindings, along with
1105       any memory allocated for them, are retained.
1106    */
1107    reset: function(alsoClearBinds){
1108      affirmUnlocked(this,'reset()');
1109      if(alsoClearBinds) this.clearBindings();
1110      capi.sqlite3_reset(affirmStmtOpen(this).pointer);
1111      this._mayGet = false;
1112      return this;
1113    },
1114    /**
1115       Binds one or more values to its bindable parameters. It
1116       accepts 1 or 2 arguments:
1117
1118       If passed a single argument, it must be either an array, an
1119       object, or a value of a bindable type (see below).
1120
1121       If passed 2 arguments, the first one is the 1-based bind
1122       index or bindable parameter name and the second one must be
1123       a value of a bindable type.
1124
1125       Bindable value types:
1126
1127       - null is bound as NULL.
1128
1129       - undefined as a standalone value is a no-op intended to
1130       simplify certain client-side use cases: passing undefined
1131       as a value to this function will not actually bind
1132       anything and this function will skip confirmation that
1133       binding is even legal. (Those semantics simplify certain
1134       client-side uses.) Conversely, a value of undefined as an
1135       array or object property when binding an array/object
1136       (see below) is treated the same as null.
1137
1138       - Numbers are bound as either doubles or integers: doubles
1139       if they are larger than 32 bits, else double or int32,
1140       depending on whether they have a fractional part. (It is,
1141       as of this writing, illegal to call (from JS) a WASM
1142       function which either takes or returns an int64.)
1143       Booleans are bound as integer 0 or 1. It is not expected
1144       the distinction of binding doubles which have no
1145       fractional parts is integers is significant for the
1146       majority of clients due to sqlite3's data typing
1147       model. If capi.wasm.bigIntEnabled is true then this
1148       routine will bind BigInt values as 64-bit integers.
1149
1150       - Strings are bound as strings (use bindAsBlob() to force
1151       blob binding).
1152
1153       - Uint8Array and Int8Array instances are bound as blobs.
1154       (TODO: binding the other TypedArray types.)
1155
1156       If passed an array, each element of the array is bound at
1157       the parameter index equal to the array index plus 1
1158       (because arrays are 0-based but binding is 1-based).
1159
1160       If passed an object, each object key is treated as a
1161       bindable parameter name. The object keys _must_ match any
1162       bindable parameter names, including any `$`, `@`, or `:`
1163       prefix. Because `$` is a legal identifier chararacter in
1164       JavaScript, that is the suggested prefix for bindable
1165       parameters: `stmt.bind({$a: 1, $b: 2})`.
1166
1167       It returns this object on success and throws on
1168       error. Errors include:
1169
1170       - Any bind index is out of range, a named bind parameter
1171       does not match, or this statement has no bindable
1172       parameters.
1173
1174       - Any value to bind is of an unsupported type.
1175
1176       - Passed no arguments or more than two.
1177
1178       - The statement has been finalized.
1179    */
1180    bind: function(/*[ndx,] arg*/){
1181      affirmStmtOpen(this);
1182      let ndx, arg;
1183      switch(arguments.length){
1184          case 1: ndx = 1; arg = arguments[0]; break;
1185          case 2: ndx = arguments[0]; arg = arguments[1]; break;
1186          default: toss3("Invalid bind() arguments.");
1187      }
1188      if(undefined===arg){
1189        /* It might seem intuitive to bind undefined as NULL
1190           but this approach simplifies certain client-side
1191           uses when passing on arguments between 2+ levels of
1192           functions. */
1193        return this;
1194      }else if(!this.parameterCount){
1195        toss3("This statement has no bindable parameters.");
1196      }
1197      this._mayGet = false;
1198      if(null===arg){
1199        /* bind NULL */
1200        return bindOne(this, ndx, BindTypes.null, arg);
1201      }
1202      else if(Array.isArray(arg)){
1203        /* bind each entry by index */
1204        if(1!==arguments.length){
1205          toss3("When binding an array, an index argument is not permitted.");
1206        }
1207        arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v));
1208        return this;
1209      }
1210      else if('object'===typeof arg/*null was checked above*/
1211              && !util.isBindableTypedArray(arg)){
1212        /* Treat each property of arg as a named bound parameter. */
1213        if(1!==arguments.length){
1214          toss3("When binding an object, an index argument is not permitted.");
1215        }
1216        Object.keys(arg)
1217          .forEach(k=>bindOne(this, k,
1218                              affirmSupportedBindType(arg[k]),
1219                              arg[k]));
1220        return this;
1221      }else{
1222        return bindOne(this, ndx, affirmSupportedBindType(arg), arg);
1223      }
1224      toss3("Should not reach this point.");
1225    },
1226    /**
1227       Special case of bind() which binds the given value using the
1228       BLOB binding mechanism instead of the default selected one for
1229       the value. The ndx may be a numbered or named bind index. The
1230       value must be of type string, null/undefined (both get treated
1231       as null), or a TypedArray of a type supported by the bind()
1232       API.
1233
1234       If passed a single argument, a bind index of 1 is assumed and
1235       the first argument is the value.
1236    */
1237    bindAsBlob: function(ndx,arg){
1238      affirmStmtOpen(this);
1239      if(1===arguments.length){
1240        arg = ndx;
1241        ndx = 1;
1242      }
1243      const t = affirmSupportedBindType(arg);
1244      if(BindTypes.string !== t && BindTypes.blob !== t
1245         && BindTypes.null !== t){
1246        toss3("Invalid value type for bindAsBlob()");
1247      }
1248      bindOne(this, ndx, BindTypes.blob, arg);
1249      this._mayGet = false;
1250      return this;
1251    },
1252    /**
1253       Steps the statement one time. If the result indicates that a
1254       row of data is available, a truthy value is returned.
1255       If no row of data is available, a falsy
1256       value is returned.  Throws on error.
1257    */
1258    step: function(){
1259      affirmUnlocked(this, 'step()');
1260      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
1261      switch(rc){
1262          case capi.SQLITE_DONE: return this._mayGet = false;
1263          case capi.SQLITE_ROW: return this._mayGet = true;
1264          default:
1265            this._mayGet = false;
1266            console.warn("sqlite3_step() rc=",rc,"SQL =",
1267                         capi.sqlite3_sql(this.pointer));
1268            DB.checkRc(this.db.pointer, rc);
1269      }
1270    },
1271    /**
1272       Functions like step() except that
1273       it finalizes this statement immediately after stepping unless
1274       the step cannot be performed because the statement is
1275       locked. Throws on error, but any error other than the
1276       statement-is-locked case will also trigger finalization of this
1277       statement.
1278
1279       On success, it returns true if the step indicated that a row of
1280       data was available, else it returns false.
1281
1282       This is intended to simplify use cases such as:
1283
1284       ```
1285       aDb.prepare("insert in foo(a) values(?)").bind(123).stepFinalize();
1286       ```
1287    */
1288    stepFinalize: function(){
1289      affirmUnlocked(this, 'step()');
1290      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
1291      switch(rc){
1292          case capi.SQLITE_DONE: this.finalize(); return false;
1293          case capi.SQLITE_ROW: this.finalize(); return true;
1294          default:
1295            this.finalize();
1296            console.warn("sqlite3_step() rc=",rc,"SQL =",
1297                         capi.sqlite3_sql(this.pointer));
1298            DB.checkRc(this.db.pointer, rc);
1299      }
1300    },
1301    /**
1302       Fetches the value from the given 0-based column index of
1303       the current data row, throwing if index is out of range.
1304
1305       Requires that step() has just returned a truthy value, else
1306       an exception is thrown.
1307
1308       By default it will determine the data type of the result
1309       automatically. If passed a second arugment, it must be one
1310       of the enumeration values for sqlite3 types, which are
1311       defined as members of the sqlite3 module: SQLITE_INTEGER,
1312       SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value,
1313       except for undefined, will trigger an exception. Passing
1314       undefined is the same as not passing a value. It is legal
1315       to, e.g., fetch an integer value as a string, in which case
1316       sqlite3 will convert the value to a string.
1317
1318       If ndx is an array, this function behaves a differently: it
1319       assigns the indexes of the array, from 0 to the number of
1320       result columns, to the values of the corresponding column,
1321       and returns that array.
1322
1323       If ndx is a plain object, this function behaves even
1324       differentlier: it assigns the properties of the object to
1325       the values of their corresponding result columns.
1326
1327       Blobs are returned as Uint8Array instances.
1328
1329       Potential TODO: add type ID SQLITE_JSON, which fetches the
1330       result as a string and passes it (if it's not null) to
1331       JSON.parse(), returning the result of that. Until then,
1332       getJSON() can be used for that.
1333    */
1334    get: function(ndx,asType){
1335      if(!affirmStmtOpen(this)._mayGet){
1336        toss3("Stmt.step() has not (recently) returned true.");
1337      }
1338      if(Array.isArray(ndx)){
1339        let i = 0;
1340        while(i<this.columnCount){
1341          ndx[i] = this.get(i++);
1342        }
1343        return ndx;
1344      }else if(ndx && 'object'===typeof ndx){
1345        let i = 0;
1346        while(i<this.columnCount){
1347          ndx[capi.sqlite3_column_name(this.pointer,i)] = this.get(i++);
1348        }
1349        return ndx;
1350      }
1351      affirmColIndex(this, ndx);
1352      switch(undefined===asType
1353             ? capi.sqlite3_column_type(this.pointer, ndx)
1354             : asType){
1355          case capi.SQLITE_NULL: return null;
1356          case capi.SQLITE_INTEGER:{
1357            if(capi.wasm.bigIntEnabled){
1358              const rc = capi.sqlite3_column_int64(this.pointer, ndx);
1359              if(rc>=Number.MIN_SAFE_INTEGER && rc<=Number.MAX_SAFE_INTEGER){
1360                /* Coerce "normal" number ranges to normal number values,
1361                   and only return BigInt-type values for numbers out of this
1362                   range. */
1363                return Number(rc).valueOf();
1364              }
1365              return rc;
1366            }else{
1367              const rc = capi.sqlite3_column_double(this.pointer, ndx);
1368              if(rc>Number.MAX_SAFE_INTEGER || rc<Number.MIN_SAFE_INTEGER){
1369                /* Throwing here is arguable but, since we're explicitly
1370                   extracting an SQLITE_INTEGER-type value, it seems fair to throw
1371                   if the extracted number is out of range for that type.
1372                   This policy may be laxened to simply pass on the number and
1373                   hope for the best, as the C API would do. */
1374                toss3("Integer is out of range for JS integer range: "+rc);
1375              }
1376              //console.log("get integer rc=",rc,isInt32(rc));
1377              return util.isInt32(rc) ? (rc | 0) : rc;
1378            }
1379          }
1380          case capi.SQLITE_FLOAT:
1381            return capi.sqlite3_column_double(this.pointer, ndx);
1382          case capi.SQLITE_TEXT:
1383            return capi.sqlite3_column_text(this.pointer, ndx);
1384          case capi.SQLITE_BLOB: {
1385            const n = capi.sqlite3_column_bytes(this.pointer, ndx),
1386                  ptr = capi.sqlite3_column_blob(this.pointer, ndx),
1387                  rc = new Uint8Array(n);
1388            //heap = n ? capi.wasm.heap8() : false;
1389            if(n) rc.set(capi.wasm.heap8u().slice(ptr, ptr+n), 0);
1390            //for(let i = 0; i < n; ++i) rc[i] = heap[ptr + i];
1391            if(n && this.db._blobXfer instanceof Array){
1392              /* This is an optimization soley for the
1393                 Worker-based API. These values will be
1394                 transfered to the main thread directly
1395                 instead of being copied. */
1396              this.db._blobXfer.push(rc.buffer);
1397            }
1398            return rc;
1399          }
1400          default: toss3("Don't know how to translate",
1401                         "type of result column #"+ndx+".");
1402      }
1403      abort("Not reached.");
1404    },
1405    /** Equivalent to get(ndx) but coerces the result to an
1406        integer. */
1407    getInt: function(ndx){return this.get(ndx,capi.SQLITE_INTEGER)},
1408    /** Equivalent to get(ndx) but coerces the result to a
1409        float. */
1410    getFloat: function(ndx){return this.get(ndx,capi.SQLITE_FLOAT)},
1411    /** Equivalent to get(ndx) but coerces the result to a
1412        string. */
1413    getString: function(ndx){return this.get(ndx,capi.SQLITE_TEXT)},
1414    /** Equivalent to get(ndx) but coerces the result to a
1415        Uint8Array. */
1416    getBlob: function(ndx){return this.get(ndx,capi.SQLITE_BLOB)},
1417    /**
1418       A convenience wrapper around get() which fetches the value
1419       as a string and then, if it is not null, passes it to
1420       JSON.parse(), returning that result. Throws if parsing
1421       fails. If the result is null, null is returned. An empty
1422       string, on the other hand, will trigger an exception.
1423    */
1424    getJSON: function(ndx){
1425      const s = this.get(ndx, capi.SQLITE_STRING);
1426      return null===s ? s : JSON.parse(s);
1427    },
1428    // Design note: the only reason most of these getters have a 'get'
1429    // prefix is for consistency with getVALUE_TYPE().  The latter
1430    // arguablly really need that prefix for API readability and the
1431    // rest arguably don't, but consistency is a powerful thing.
1432    /**
1433       Returns the result column name of the given index, or
1434       throws if index is out of bounds or this statement has been
1435       finalized. This can be used without having run step()
1436       first.
1437    */
1438    getColumnName: function(ndx){
1439      return capi.sqlite3_column_name(
1440        affirmColIndex(affirmStmtOpen(this),ndx).pointer, ndx
1441      );
1442    },
1443    /**
1444       If this statement potentially has result columns, this
1445       function returns an array of all such names. If passed an
1446       array, it is used as the target and all names are appended
1447       to it. Returns the target array. Throws if this statement
1448       cannot have result columns. This object's columnCount member
1449       holds the number of columns.
1450    */
1451    getColumnNames: function(tgt){
1452      affirmColIndex(affirmStmtOpen(this),0);
1453      if(!tgt) tgt = [];
1454      for(let i = 0; i < this.columnCount; ++i){
1455        tgt.push(capi.sqlite3_column_name(this.pointer, i));
1456      }
1457      return tgt;
1458    },
1459    /**
1460       If this statement has named bindable parameters and the
1461       given name matches one, its 1-based bind index is
1462       returned. If no match is found, 0 is returned. If it has no
1463       bindable parameters, the undefined value is returned.
1464    */
1465    getParamIndex: function(name){
1466      return (affirmStmtOpen(this).parameterCount
1467              ? capi.sqlite3_bind_parameter_index(this.pointer, name)
1468              : undefined);
1469    }
1470  }/*Stmt.prototype*/;
1471
1472  {/* Add the `pointer` property to DB and Stmt. */
1473    const prop = {
1474      enumerable: true,
1475      get: function(){return __ptrMap.get(this)},
1476      set: ()=>toss3("The pointer property is read-only.")
1477    }
1478    Object.defineProperty(Stmt.prototype, 'pointer', prop);
1479    Object.defineProperty(DB.prototype, 'pointer', prop);
1480  }
1481
1482  /** The OO API's public namespace. */
1483  sqlite3.oo1 = {
1484    version: {
1485      lib: capi.sqlite3_libversion(),
1486      ooApi: "0.1"
1487    },
1488    DB,
1489    Stmt
1490  }/*SQLite3 object*/;
1491})(self);
1492