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