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