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