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