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