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