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