Check-in [bd2d5a287f]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Latest upstream sqlite3.js/wasm.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: bd2d5a287f9eb118b52334cd44b7ce10fea67ef9836bf81e19534a66b01571ce
User & Date: stephan 2022-10-27 06:30:51
Context
2022-10-28
06:26
Add 'Related Works' section. check-in: 54a018b9f6 user: stephan tags: trunk
2022-10-27
06:30
Latest upstream sqlite3.js/wasm. check-in: bd2d5a287f user: stephan tags: trunk
04:57
Style tweaks for consistency with the main sqlite.org site. check-in: 1a1933855a user: stephan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to jswasm/sqlite3.js.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** *   May you share freely, never taking more than you give.
*/
/*
** This code was built from sqlite3 version...
** 
** SQLITE_VERSION "3.40.0"
** SQLITE_VERSION_NUMBER 3040000
** SQLITE_SOURCE_ID "2022-10-14 15:52:29 a4423ca234453c14eb40db7fe5943f63b30fd9dc2207388e8a2966733a004e9d"
*/

var sqlite3InitModule = (() => {
  var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
  
  return (
function(sqlite3InitModule) {







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** *   May you share freely, never taking more than you give.
*/
/*
** This code was built from sqlite3 version...
** 
** SQLITE_VERSION "3.40.0"
** SQLITE_VERSION_NUMBER 3040000
** SQLITE_SOURCE_ID "2022-10-27 03:57:48 ed8d3f25a4d6ac04d9f7918c791d8d2c6f23ce846278ca63f8fbadb7ea27alt1"
*/

var sqlite3InitModule = (() => {
  var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
  
  return (
function(sqlite3InitModule) {
4005
4006
4007
4008
4009
4010
4011





4012
4013
4014
4015
4016
4017
4018
  return (_sqlite3_initialize = Module["_sqlite3_initialize"] = Module["asm"]["sqlite3_initialize"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_vfs_register = Module["_sqlite3_vfs_register"] = function() {
  return (_sqlite3_vfs_register = Module["_sqlite3_vfs_register"] = Module["asm"]["sqlite3_vfs_register"]).apply(null, arguments);
};






/** @type {function(...*):?} */
var _sqlite3_malloc = Module["_sqlite3_malloc"] = function() {
  return (_sqlite3_malloc = Module["_sqlite3_malloc"] = Module["asm"]["sqlite3_malloc"]).apply(null, arguments);
};

/** @type {function(...*):?} */







>
>
>
>
>







4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
  return (_sqlite3_initialize = Module["_sqlite3_initialize"] = Module["asm"]["sqlite3_initialize"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_vfs_register = Module["_sqlite3_vfs_register"] = function() {
  return (_sqlite3_vfs_register = Module["_sqlite3_vfs_register"] = Module["asm"]["sqlite3_vfs_register"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_vfs_unregister = Module["_sqlite3_vfs_unregister"] = function() {
  return (_sqlite3_vfs_unregister = Module["_sqlite3_vfs_unregister"] = Module["asm"]["sqlite3_vfs_unregister"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_malloc = Module["_sqlite3_malloc"] = function() {
  return (_sqlite3_malloc = Module["_sqlite3_malloc"] = Module["asm"]["sqlite3_malloc"]).apply(null, arguments);
};

/** @type {function(...*):?} */
4030
4031
4032
4033
4034
4035
4036





4037
4038
4039
4040
4041
4042
4043
  return (_sqlite3_realloc = Module["_sqlite3_realloc"] = Module["asm"]["sqlite3_realloc"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_realloc64 = Module["_sqlite3_realloc64"] = function() {
  return (_sqlite3_realloc64 = Module["_sqlite3_realloc64"] = Module["asm"]["sqlite3_realloc64"]).apply(null, arguments);
};






/** @type {function(...*):?} */
var _sqlite3_serialize = Module["_sqlite3_serialize"] = function() {
  return (_sqlite3_serialize = Module["_sqlite3_serialize"] = Module["asm"]["sqlite3_serialize"]).apply(null, arguments);
};

/** @type {function(...*):?} */







>
>
>
>
>







4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
  return (_sqlite3_realloc = Module["_sqlite3_realloc"] = Module["asm"]["sqlite3_realloc"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_realloc64 = Module["_sqlite3_realloc64"] = function() {
  return (_sqlite3_realloc64 = Module["_sqlite3_realloc64"] = Module["asm"]["sqlite3_realloc64"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_randomness = Module["_sqlite3_randomness"] = function() {
  return (_sqlite3_randomness = Module["_sqlite3_randomness"] = Module["asm"]["sqlite3_randomness"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_serialize = Module["_sqlite3_serialize"] = function() {
  return (_sqlite3_serialize = Module["_sqlite3_serialize"] = Module["asm"]["sqlite3_serialize"]).apply(null, arguments);
};

/** @type {function(...*):?} */
4480
4481
4482
4483
4484
4485
4486





4487
4488
4489
4490
4491
4492
4493
  return (_sqlite3_wasm_enum_json = Module["_sqlite3_wasm_enum_json"] = Module["asm"]["sqlite3_wasm_enum_json"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_wasm_vfs_unlink = Module["_sqlite3_wasm_vfs_unlink"] = function() {
  return (_sqlite3_wasm_vfs_unlink = Module["_sqlite3_wasm_vfs_unlink"] = Module["asm"]["sqlite3_wasm_vfs_unlink"]).apply(null, arguments);
};






/** @type {function(...*):?} */
var _sqlite3_wasm_db_reset = Module["_sqlite3_wasm_db_reset"] = function() {
  return (_sqlite3_wasm_db_reset = Module["_sqlite3_wasm_db_reset"] = Module["asm"]["sqlite3_wasm_db_reset"]).apply(null, arguments);
};

/** @type {function(...*):?} */







>
>
>
>
>







4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
  return (_sqlite3_wasm_enum_json = Module["_sqlite3_wasm_enum_json"] = Module["asm"]["sqlite3_wasm_enum_json"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_wasm_vfs_unlink = Module["_sqlite3_wasm_vfs_unlink"] = function() {
  return (_sqlite3_wasm_vfs_unlink = Module["_sqlite3_wasm_vfs_unlink"] = Module["asm"]["sqlite3_wasm_vfs_unlink"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_wasm_db_vfs = Module["_sqlite3_wasm_db_vfs"] = function() {
  return (_sqlite3_wasm_db_vfs = Module["_sqlite3_wasm_db_vfs"] = Module["asm"]["sqlite3_wasm_db_vfs"]).apply(null, arguments);
};

/** @type {function(...*):?} */
var _sqlite3_wasm_db_reset = Module["_sqlite3_wasm_db_reset"] = function() {
  return (_sqlite3_wasm_db_reset = Module["_sqlite3_wasm_db_reset"] = Module["asm"]["sqlite3_wasm_db_reset"]).apply(null, arguments);
};

/** @type {function(...*):?} */
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
** *   May you share freely, never taking more than you give.
*/
/*
** This code was built from sqlite3 version...
** 
** SQLITE_VERSION "3.40.0"
** SQLITE_VERSION_NUMBER 3040000
** SQLITE_SOURCE_ID "2022-10-14 15:52:29 a4423ca234453c14eb40db7fe5943f63b30fd9dc2207388e8a2966733a004e9d"
*/
/* END FILE: ./bld/sqlite3-license-version.js */
/* BEGIN FILE: api/sqlite3-api-prologue.js */
/*
  2022-05-22

  The author disclaims copyright to this source code.  In place of a







|







4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
** *   May you share freely, never taking more than you give.
*/
/*
** This code was built from sqlite3 version...
** 
** SQLITE_VERSION "3.40.0"
** SQLITE_VERSION_NUMBER 3040000
** SQLITE_SOURCE_ID "2022-10-27 03:57:48 ed8d3f25a4d6ac04d9f7918c791d8d2c6f23ce846278ca63f8fbadb7ea27alt1"
*/
/* END FILE: ./bld/sqlite3-license-version.js */
/* BEGIN FILE: api/sqlite3-api-prologue.js */
/*
  2022-05-22

  The author disclaims copyright to this source code.  In place of a
4938
4939
4940
4941
4942
4943
4944


























4945
4946
4947
4948
4949
4950
4951
  };

  /** Returns v if v appears to be a TypedArray, else false. */
  const isTypedArray = (v)=>{
    return (v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT)) ? v : false;
  };



























  /**
     Returns true if v appears to be one of our bind()-able
     TypedArray types: Uint8Array or Int8Array. Support for
     TypedArrays with element sizes >1 is TODO.
  */
  const isBindableTypedArray = (v)=>{
    return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
  };

  /** Returns v if v appears to be a TypedArray, else false. */
  const isTypedArray = (v)=>{
    return (v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT)) ? v : false;
  };


  /** Internal helper to use in operations which need to distinguish
      between TypedArrays which are backed by a SharedArrayBuffer
      from those which are not. */
  const __SAB = ('undefined'===typeof SharedArrayBuffer)
        ? function(){} : SharedArrayBuffer;
  /** Returns true if the given TypedArray object is backed by a
      SharedArrayBuffer, else false. */
  const isSharedTypedArray = (aTypedArray)=>(aTypedArray.buffer instanceof __SAB);

  /**
     Returns either aTypedArray.slice(begin,end) (if
     aTypedArray.buffer is a SharedArrayBuffer) or
     aTypedArray.subarray(begin,end) (if it's not).

     This distinction is important for APIs which don't like to
     work on SABs, e.g. TextDecoder, and possibly for our
     own APIs which work on memory ranges which "might" be
     modified by other threads while they're working.
  */
  const typedArrayPart = (aTypedArray, begin, end)=>{
    return isSharedTypedArray(aTypedArray)
      ? aTypedArray.slice(begin, end)
      : aTypedArray.subarray(begin, end);
  };

  /**
     Returns true if v appears to be one of our bind()-able
     TypedArray types: Uint8Array or Int8Array. Support for
     TypedArrays with element sizes >1 is TODO.
  */
  const isBindableTypedArray = (v)=>{
    return v && v.constructor && (1===v.constructor.BYTES_PER_ELEMENT);
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978

4979



4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
  const affirmBindableTypedArray = (v)=>{
    return isBindableTypedArray(v)
      || toss("Value is not of a supported TypedArray type.");
  };

  const utf8Decoder = new TextDecoder('utf-8');

  /** Internal helper to use in operations which need to distinguish
      between SharedArrayBuffer heap memory and non-shared heap. */
  const __SAB = ('undefined'===typeof SharedArrayBuffer)

        ? function(){} : SharedArrayBuffer;



  const typedArrayToString = function(arrayBuffer, begin, end){
    return utf8Decoder.decode(
      (arrayBuffer.buffer instanceof __SAB)
        ? arrayBuffer.slice(begin, end)
        : arrayBuffer.subarray(begin, end)
    );
  };

  /**
     If v is-a Array, its join('') result is returned.  If
     isSQLableTypedArray(v) is true then typedArrayToString(v) is
     returned. Else v is returned as-is.
  */







|
|
|
>
|
>
>
>
|
|
<
<
<
<







5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026




5027
5028
5029
5030
5031
5032
5033
  const affirmBindableTypedArray = (v)=>{
    return isBindableTypedArray(v)
      || toss("Value is not of a supported TypedArray type.");
  };

  const utf8Decoder = new TextDecoder('utf-8');

  /**
     Uses TextDecoder to decode the given half-open range of the
     given TypedArray to a string. This differs from a simple
     call to TextDecoder in that it accounts for whether the
     first argument is backed by a SharedArrayBuffer or not,
     and can work more efficiently if it's not (TextDecoder
     refuses to act upon an SAB).
  */
  const typedArrayToString = function(typedArray, begin, end){
    return utf8Decoder.decode(typedArrayPart(typedArray, begin,end));




  };

  /**
     If v is-a Array, its join('') result is returned.  If
     isSQLableTypedArray(v) is true then typedArrayToString(v) is
     returned. Else v is returned as-is.
  */
5003
5004
5005
5006
5007
5008
5009








5010
5011
5012
5013
5014
5015
5016
5017
5018
  */
  class WasmAllocError extends Error {
    constructor(...args){
      super(...args);
      this.name = 'WasmAllocError';
    }
  };








  WasmAllocError.toss = (...args)=>{
    throw new WasmAllocError(args.join(' '));
  };

  /** 
      The main sqlite3 binding API gets installed into this object,
      mimicking the C API as closely as we can. The numerous members
      names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
      possible, identically to the C-native counterparts, as documented at:







>
>
>
>
>
>
>
>

|







5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
  */
  class WasmAllocError extends Error {
    constructor(...args){
      super(...args);
      this.name = 'WasmAllocError';
    }
  };
  /**
     Functionally equivalent to the WasmAllocError constructor but may
     be used as part of an expression, e.g.:

     ```
     return someAllocatingFunction(x) || WasmAllocError.toss(...);
     ```
  */
  WasmAllocError.toss = (...args)=>{
    throw new WasmAllocError(...args);
  };

  /** 
      The main sqlite3 binding API gets installed into this object,
      mimicking the C API as closely as we can. The numerous members
      names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
      possible, identically to the C-native counterparts, as documented at:
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
















5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253

5254
5255
5256
5257
5258
5259
5260
                         stmtPtrPtr,strPtrPtr)=>{}/*installed later*/,

    /**
       This binding enables the callback argument to be a JavaScript.

       If the callback is a function, then for the duration of the
       sqlite3_exec() call, it installs a WASM-bound function which
       acts as a proxy for the given callback. That proxy will
       also perform a conversion of the callback's arguments from
       `(char**)` to JS arrays of strings. However, for API
       consistency's sake it will still honor the C-level
       callback parameter order and will call it like:

       `callback(pVoid, colCount, listOfValues, listOfColNames)`

       If the callback is not a JS function then this binding performs
       no translation of the callback, but the sql argument is still
       converted to a WASM string for the call using the
       "flexible-string" argument converter.
    */
    sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/,
















    /**
       Various internal-use utilities are added here as needed. They
       are bound to an object only so that we have access to them in
       the differently-scoped steps of the API bootstrapping
       process. At the end of the API setup process, this object gets
       removed.
    */
    util:{
      affirmBindableTypedArray, flexibleString,
      bigIntFits32, bigIntFits64, bigIntFitsDouble,
      isBindableTypedArray,
      isInt32, isSQLableTypedArray, isTypedArray, 
      typedArrayToString,
      isMainWindow: ()=>{
        return self.window===self && self.document;
      }

    },
    
    /**
       Holds state which are specific to the WASM-related
       infrastructure and glue code. It is not expected that client
       code will normally need these, but they're exposed here in case
       it does. These APIs are _not_ to be considered an







|
|

|
|









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|







|
|
<
>







5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317

5318
5319
5320
5321
5322
5323
5324
5325
                         stmtPtrPtr,strPtrPtr)=>{}/*installed later*/,

    /**
       This binding enables the callback argument to be a JavaScript.

       If the callback is a function, then for the duration of the
       sqlite3_exec() call, it installs a WASM-bound function which
       acts as a proxy for the given callback. That proxy will also
       perform a conversion of the callback's arguments from
       `(char**)` to JS arrays of strings. However, for API
       consistency's sake it will still honor the C-level callback
       parameter order and will call it like:

       `callback(pVoid, colCount, listOfValues, listOfColNames)`

       If the callback is not a JS function then this binding performs
       no translation of the callback, but the sql argument is still
       converted to a WASM string for the call using the
       "flexible-string" argument converter.
    */
    sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg)=>{}/*installed later*/,

    /**
       If passed a single argument which appears to be a byte-oriented
       TypedArray (Int8Array or Uint8Array), this function treats that
       TypedArray as an output target, fetches `theArray.byteLength`
       bytes of randomness, and populates the whole array with it. As
       a special case, if the array's length is 0, this function
       behaves as if it were passed (0,0). When called this way, it
       returns its argument, else it returns the `undefined` value.

       If called with any other arguments, they are passed on as-is
       to the C API. Results are undefined if passed any incompatible
       values.
     */
    sqlite3_randomness: (n, outPtr)=>{/*installed later*/},

    /**
       Various internal-use utilities are added here as needed. They
       are bound to an object only so that we have access to them in
       the differently-scoped steps of the API bootstrapping
       process. At the end of the API setup process, this object gets
       removed. These are NOT part of the public API.
    */
    util:{
      affirmBindableTypedArray, flexibleString,
      bigIntFits32, bigIntFits64, bigIntFitsDouble,
      isBindableTypedArray,
      isInt32, isSQLableTypedArray, isTypedArray, 
      typedArrayToString,
      isUIThread: ()=>'undefined'===typeof WorkerGlobalScope,
      isSharedTypedArray,

      typedArrayPart
    },
    
    /**
       Holds state which are specific to the WASM-related
       infrastructure and glue code. It is not expected that client
       code will normally need these, but they're exposed here in case
       it does. These APIs are _not_ to be considered an
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
      */
      dealloc: undefined/*installed later*/

      /* Many more wasm-related APIs get installed later on. */
    }/*wasm*/
  }/*capi*/;

  const wasm = capi.wasm;

  /**
     wasm.alloc()'s srcTypedArray.byteLength bytes,
     populates them with the values from the source
     TypedArray, and returns the pointer to that memory. The
     returned pointer must eventually be passed to
     wasm.dealloc() to clean it up.







|







5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
      */
      dealloc: undefined/*installed later*/

      /* Many more wasm-related APIs get installed later on. */
    }/*wasm*/
  }/*capi*/;

  const wasm = capi.wasm, util = capi.util;

  /**
     wasm.alloc()'s srcTypedArray.byteLength bytes,
     populates them with the values from the source
     TypedArray, and returns the pointer to that memory. The
     returned pointer must eventually be passed to
     wasm.dealloc() to clean it up.
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494

5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
     result/argument type strings gets plugged in at a later phase in
     the API initialization process.
  */
  wasm.bindingSignatures = [
    // Please keep these sorted by function name!
    ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
    ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"
     /* We should arguably write a custom wrapper which knows how
        to handle Blob, TypedArrays, and JS strings. */
    ],
    ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
    ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
    ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
    ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
    ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
    ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int"
     /* We should arguably create a hand-written binding
        which does more flexible text conversion, along the lines of
        sqlite3_prepare_v3(). The slightly problematic part is the
        final argument (text destructor). */
    ],
    ["sqlite3_close_v2", "int", "sqlite3*"],
    ["sqlite3_changes", "int", "sqlite3*"],
    ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
    ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
    ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
    ["sqlite3_column_count", "int", "sqlite3_stmt*"],
    ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
    ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
    ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
    ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
    ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
    ["sqlite3_compileoption_get", "string", "int"],
    ["sqlite3_compileoption_used", "int", "string"],
    /* sqlite3_create_function_v2() is handled separate to simplify conversion
       of its callback argument */

    ["sqlite3_data_count", "int", "sqlite3_stmt*"],
    ["sqlite3_db_filename", "string", "sqlite3*", "string"],
    ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
    ["sqlite3_db_name", "string", "sqlite3*", "int"],
    ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
    /* Careful! Short version: de/serialize() are problematic because they
       might use a different allocator that the user for managing the
       deserialized block. de/serialize() are ONLY safe to use with
       sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
    ["sqlite3_errmsg", "string", "sqlite3*"],
    ["sqlite3_error_offset", "int", "sqlite3*"],
    ["sqlite3_errstr", "string", "int"],
    /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**"
      Handled seperately to perform translation of the callback







|
|







|
|
|
|














|
|
>






|







5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
     result/argument type strings gets plugged in at a later phase in
     the API initialization process.
  */
  wasm.bindingSignatures = [
    // Please keep these sorted by function name!
    ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
    ["sqlite3_bind_blob","int", "sqlite3_stmt*", "int", "*", "int", "*"
     /* TODO: we should arguably write a custom wrapper which knows
        how to handle Blob, TypedArrays, and JS strings. */
    ],
    ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
    ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
    ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
    ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
    ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
    ["sqlite3_bind_text","int", "sqlite3_stmt*", "int", "string", "int", "int"
     /* We should arguably create a hand-written binding of
        bind_text() which does more flexible text conversion, along
        the lines of sqlite3_prepare_v3(). The slightly problematic
        part is the final argument (text destructor). */
    ],
    ["sqlite3_close_v2", "int", "sqlite3*"],
    ["sqlite3_changes", "int", "sqlite3*"],
    ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
    ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
    ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
    ["sqlite3_column_count", "int", "sqlite3_stmt*"],
    ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
    ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
    ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
    ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
    ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
    ["sqlite3_compileoption_get", "string", "int"],
    ["sqlite3_compileoption_used", "int", "string"],
    /* sqlite3_create_function(), sqlite3_create_function_v2(), and
       sqlite3_create_window_function() use hand-written bindings to
       simplify handling of their function-type arguments. */
    ["sqlite3_data_count", "int", "sqlite3_stmt*"],
    ["sqlite3_db_filename", "string", "sqlite3*", "string"],
    ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
    ["sqlite3_db_name", "string", "sqlite3*", "int"],
    ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
    /* Careful! Short version: de/serialize() are problematic because they
       might use a different allocator than the user for managing the
       deserialized block. de/serialize() are ONLY safe to use with
       sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
    ["sqlite3_errmsg", "string", "sqlite3*"],
    ["sqlite3_error_offset", "int", "sqlite3*"],
    ["sqlite3_errstr", "string", "int"],
    /*["sqlite3_exec", "int", "sqlite3*", "string", "*", "*", "**"
      Handled seperately to perform translation of the callback
5522
5523
5524
5525
5526
5527
5528


5529
5530
5531
5532
5533
5534
5535
    ["sqlite3_libversion_number", "int"],
    ["sqlite3_malloc", "*","int"],
    ["sqlite3_open", "int", "string", "*"],
    ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
    /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
       separately due to us requiring two different sets of semantics
       for those, depending on how their SQL argument is provided. */


    ["sqlite3_realloc", "*","*","int"],
    ["sqlite3_reset", "int", "sqlite3_stmt*"],
    ["sqlite3_result_blob",undefined, "*", "*", "int", "*"],
    ["sqlite3_result_double",undefined, "*", "f64"],
    ["sqlite3_result_error",undefined, "*", "string", "int"],
    ["sqlite3_result_error_code", undefined, "*", "int"],
    ["sqlite3_result_error_nomem", undefined, "*"],







>
>







5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
    ["sqlite3_libversion_number", "int"],
    ["sqlite3_malloc", "*","int"],
    ["sqlite3_open", "int", "string", "*"],
    ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
    /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
       separately due to us requiring two different sets of semantics
       for those, depending on how their SQL argument is provided. */
    /* sqlite3_randomness() uses a hand-written wrapper to extend
       the range of supported argument types. */
    ["sqlite3_realloc", "*","*","int"],
    ["sqlite3_reset", "int", "sqlite3_stmt*"],
    ["sqlite3_result_blob",undefined, "*", "*", "int", "*"],
    ["sqlite3_result_double",undefined, "*", "f64"],
    ["sqlite3_result_error",undefined, "*", "string", "int"],
    ["sqlite3_result_error_code", undefined, "*", "int"],
    ["sqlite3_result_error_nomem", undefined, "*"],
5553
5554
5555
5556
5557
5558
5559
5560

5561
5562
5563
5564
5565
5566
5567
    ["sqlite3_value_blob", "*", "sqlite3_value*"],
    ["sqlite3_value_bytes","int", "sqlite3_value*"],
    ["sqlite3_value_double","f64", "sqlite3_value*"],
    ["sqlite3_value_int","int", "sqlite3_value*"],
    ["sqlite3_value_text", "string", "sqlite3_value*"],
    ["sqlite3_value_type", "int", "sqlite3_value*"],
    ["sqlite3_vfs_find", "*", "string"],
    ["sqlite3_vfs_register", "int", "*", "int"]

  ]/*wasm.bindingSignatures*/;

  if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
    /* ^^^ "the problem" is that this is an option feature and the
       build-time function-export list does not currently take
       optional features into account. */
    wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);







|
>







5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
    ["sqlite3_value_blob", "*", "sqlite3_value*"],
    ["sqlite3_value_bytes","int", "sqlite3_value*"],
    ["sqlite3_value_double","f64", "sqlite3_value*"],
    ["sqlite3_value_int","int", "sqlite3_value*"],
    ["sqlite3_value_text", "string", "sqlite3_value*"],
    ["sqlite3_value_type", "int", "sqlite3_value*"],
    ["sqlite3_vfs_find", "*", "string"],
    ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
    ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
  ]/*wasm.bindingSignatures*/;

  if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
    /* ^^^ "the problem" is that this is an option feature and the
       build-time function-export list does not currently take
       optional features into account. */
    wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596


5597
5598
5599
5600
5601
5602
5603
5604
    ["sqlite3_uri_int64", "i64", ["string", "string", "i64"]],
    ["sqlite3_value_int64","i64", "sqlite3_value*"],
  ];

  /**
     Functions which are intended solely for API-internal use by the
     WASM components, not client code. These get installed into
     wasm.

     TODO: get rid of sqlite3_wasm_vfs_unlink(). It is ill-conceived
     and only rarely actually useful.
  */
  wasm.bindingSignatures.wasm = [


    ["sqlite3_wasm_vfs_unlink", "int", "string"]
  ];


  /**
     sqlite3.wasm.pstack (pseudo-stack) holds a special-case
     stack-style allocator intended only for use with _small_ data of
     not more than (in total) a few kb in size, managed as if it were







|
<
<
<


>
>
|







5653
5654
5655
5656
5657
5658
5659
5660



5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
    ["sqlite3_uri_int64", "i64", ["string", "string", "i64"]],
    ["sqlite3_value_int64","i64", "sqlite3_value*"],
  ];

  /**
     Functions which are intended solely for API-internal use by the
     WASM components, not client code. These get installed into
     capi.wasm.



  */
  wasm.bindingSignatures.wasm = [
    ["sqlite3_wasm_db_reset", "int", "sqlite3*"],
    ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
    ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
  ];


  /**
     sqlite3.wasm.pstack (pseudo-stack) holds a special-case
     stack-style allocator intended only for use with _small_ data of
     not more than (in total) a few kb in size, managed as if it were
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
     space managed by Emscripten's stack-management, so does not
     collide with Emscripten-provided stack allocation APIs. The
     memory lives in the WASM heap and can be used with routines such
     as wasm.setMemValue() and any wasm.heap8u().slice().
  */
  wasm.pstack = Object.assign(Object.create(null),{
    /**
       Sets the current ppstack position to the given pointer.
       Results are undefined if the passed-in value did not come from
       this.pointer.
    */
    restore: wasm.exports.sqlite3_wasm_pstack_restore,
    /**
       Attempts to allocate the given number of bytes from the
       pstack. On success, it zeroes out a block of memory of the
       given size, adjusts the pstack pointer, and returns a pointer
       to the memory. On error, returns throws a WasmAllocError. The
       memory must eventually be released using restore().

       This method always adjusts the given value to be a multiple
       of 8 bytes because failing to do so can lead to incorrect
       results when reading and writing 64-bit values from/to the WASM
       heap.
    */
    alloc: (n)=>{
      return wasm.exports.sqlite3_wasm_pstack_alloc(n)
        || WasmAllocError.toss("Could not allocate",n,
                               "bytes from the pstack.");
    },
    /**
       Allocates n chunks, each sz bytes, as a single memory block and
       returns the addresses as an array of n element, each holding
       the address of one chunk.

       Throws a WasmAllocError if allocation fails.

       Example:








|
|













|







|







5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
     space managed by Emscripten's stack-management, so does not
     collide with Emscripten-provided stack allocation APIs. The
     memory lives in the WASM heap and can be used with routines such
     as wasm.setMemValue() and any wasm.heap8u().slice().
  */
  wasm.pstack = Object.assign(Object.create(null),{
    /**
       Sets the current pstack position to the given pointer. Results
       are undefined if the passed-in value did not come from
       this.pointer.
    */
    restore: wasm.exports.sqlite3_wasm_pstack_restore,
    /**
       Attempts to allocate the given number of bytes from the
       pstack. On success, it zeroes out a block of memory of the
       given size, adjusts the pstack pointer, and returns a pointer
       to the memory. On error, returns throws a WasmAllocError. The
       memory must eventually be released using restore().

       This method always adjusts the given value to be a multiple
       of 8 bytes because failing to do so can lead to incorrect
       results when reading and writing 64-bit values from/to the WASM
       heap. Similarly, the returned address is always 8-byte aligned.
    */
    alloc: (n)=>{
      return wasm.exports.sqlite3_wasm_pstack_alloc(n)
        || WasmAllocError.toss("Could not allocate",n,
                               "bytes from the pstack.");
    },
    /**
       alloc()'s n chunks, each sz bytes, as a single memory block and
       returns the addresses as an array of n element, each holding
       the address of one chunk.

       Throws a WasmAllocError if allocation fails.

       Example:

5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
       double or int64, and that value must be written or fetched,
       e.g. using wasm.setMemValue() or wasm.getMemValue(), it is
       important that the pointer in question be aligned to an 8-byte
       boundary or else it will not be fetched or written properly and
       will corrupt or read neighboring memory.

       However, when all pointers involved point to "small" data, it
       is safe to pass a falsy value to save to memory.
    */
    allocPtr: (n=1,safePtrSize=true)=>{
      return 1===n
        ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof)
        : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof);
    }
  })/*wasm.pstack*/;







|







5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
       double or int64, and that value must be written or fetched,
       e.g. using wasm.setMemValue() or wasm.getMemValue(), it is
       important that the pointer in question be aligned to an 8-byte
       boundary or else it will not be fetched or written properly and
       will corrupt or read neighboring memory.

       However, when all pointers involved point to "small" data, it
       is safe to pass a falsy value to save a tiny bit of memory.
    */
    allocPtr: (n=1,safePtrSize=true)=>{
      return 1===n
        ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptrSizeof)
        : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptrSizeof);
    }
  })/*wasm.pstack*/;
5741
5742
5743
5744
5745
5746
5747
5748




5749
5750



5751

5752
5753
5754








5755
5756
5757
5758

































5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
     The C-level APIs never throw, but some of the higher-level
     C-style APIs do and the object-oriented APIs use exceptions
     exclusively to report errors.
  */
  class SQLite3Error extends Error {
    /**
       Constructs this object with a message equal to all arguments
       concatenated with a space between each one.




    */
    constructor(...args){



      super(args.join(' '));

      this.name = 'SQLite3Error';
    }
  };








  SQLite3Error.toss = (...args)=>{
    throw new SQLite3Error(args.join(' '));
  };


































  /** State for sqlite3_wasmfs_opfs_dir(). */
  let __persistentDir = undefined;
  /**
     If the wasm environment has a WASMFS/OPFS-backed persistent
     storage directory, its path is returned by this function. If it
     does not then it returns "" (noting that "" is a falsy value).

     The first time this is called, this function inspects the current
     environment to determine whether persistence support is available
     and, if it is, enables it (if needed).

     This function currently only recognizes the WASMFS/OPFS storage
     combination and its path refers to storage rooted in the
     Emscripten-managed virtual filesystem.
  */
  capi.sqlite3_wasmfs_opfs_dir = function(){
    if(undefined !== __persistentDir) return __persistentDir;
    // If we have no OPFS, there is no persistent dir
    const pdir = config.wasmfsOpfsDir;
    if(!pdir
       || !self.FileSystemHandle
       || !self.FileSystemDirectoryHandle
       || !self.FileSystemFileHandle){
      return __persistentDir = "";
    }
    try{
      if(pdir && 0===wasm.xCallWrapped(
        'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
      )){
        return __persistentDir = pdir;
      }else{
        return __persistentDir = "";
      }
    }catch(e){
      // sqlite3_wasm_init_wasmfs() is not available
      return __persistentDir = "";
    }
  };

  /**
     Experimental and subject to change or removal.

     Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
     non-empty string and the given name starts with (that string +
     '/'), else returns false.

     Potential (but arguable) TODO: return true if the name is one of
     (":localStorage:", "local", ":sessionStorage:", "session") and
     kvvfs is available.
  */
  capi.sqlite3_web_filename_is_persistent = function(name){
    const p = capi.sqlite3_wasmfs_opfs_dir();
    return (p && name) ? name.startsWith(p+'/') : false;
  };

  // This bit is highly arguable and is incompatible with the fiddle shell.
  if(false && 0===wasm.exports.sqlite3_vfs_find(0)){
    /* Assume that sqlite3_initialize() has not yet been called.







|
>
>
>
>


>
>
>
|
>



>
>
>
>
>
>
>
>

|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|














|






|





|

|



|









<
<
<
<

|







5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920




5921
5922
5923
5924
5925
5926
5927
5928
5929
     The C-level APIs never throw, but some of the higher-level
     C-style APIs do and the object-oriented APIs use exceptions
     exclusively to report errors.
  */
  class SQLite3Error extends Error {
    /**
       Constructs this object with a message equal to all arguments
       concatenated with a space between each one. As a special case,
       if it's passed only a single integer argument, the string form
       of that argument is the result of
       sqlite3.capi.sqlite3_js_rc_str() or (if that returns falsy), a
       synthesized string which contains that integer.
    */
    constructor(...args){
      if(1===args.length && 'number'===typeof args[0] && args[0]===(args[0] | 0)){
        super(capi.sqlite3_js_rc_str(args[0]) || ("Unknown result code #"+args[0]));
      }else{
        super(args.join(' '));
      }
      this.name = 'SQLite3Error';
    }
  };
  /**
     Functionally equivalent to the SQLite3Error constructor but may
     be used as part of an expression, e.g.:

     ```
     return someFunction(x) || SQLite3Error.toss(...);
     ```
  */
  SQLite3Error.toss = (...args)=>{
    throw new SQLite3Error(...args);
  };

  capi.sqlite3_randomness = (...args)=>{
    if(1===args.length && util.isTypedArray(args[0])
      && 1===args[0].BYTES_PER_ELEMENT){
      const ta = args[0];
      if(0===ta.byteLength){
        wasm.exports.sqlite3_randomness(0,0);
        return ta;
      }
      const stack = wasm.pstack.pointer;
      try {
        let n = ta.byteLength, offset = 0;
        const r = wasm.exports.sqlite3_randomness;
        const heap = wasm.heap8u();
        const nAlloc = n < 512 ? n : 512;
        const ptr = wasm.pstack.alloc(nAlloc);
        do{
          const j = (n>nAlloc ? nAlloc : n);
          r(j, ptr);
          ta.set(typedArrayPart(heap, ptr, ptr+j), offset);
          n -= j;
          offset += j;
        } while(n > 0);
      }catch(e){
        console.error("Highly unexpected (and ignored!) "+
                      "exception in sqlite3_randomness():",e);
      }finally{
        wasm.pstack.restore(stack);
      }
      return ta;
    }
    capi.wasm.exports.sqlite3_randomness(...args);
  };

  /** State for sqlite3_wasmfs_opfs_dir(). */
  let __wasmfsOpfsDir = undefined;
  /**
     If the wasm environment has a WASMFS/OPFS-backed persistent
     storage directory, its path is returned by this function. If it
     does not then it returns "" (noting that "" is a falsy value).

     The first time this is called, this function inspects the current
     environment to determine whether persistence support is available
     and, if it is, enables it (if needed).

     This function currently only recognizes the WASMFS/OPFS storage
     combination and its path refers to storage rooted in the
     Emscripten-managed virtual filesystem.
  */
  capi.sqlite3_wasmfs_opfs_dir = function(){
    if(undefined !== __wasmfsOpfsDir) return __wasmfsOpfsDir;
    // If we have no OPFS, there is no persistent dir
    const pdir = config.wasmfsOpfsDir;
    if(!pdir
       || !self.FileSystemHandle
       || !self.FileSystemDirectoryHandle
       || !self.FileSystemFileHandle){
      return __wasmfsOpfsDir = "";
    }
    try{
      if(pdir && 0===wasm.xCallWrapped(
        'sqlite3_wasm_init_wasmfs', 'i32', ['string'], pdir
      )){
        return __wasmfsOpfsDir = pdir;
      }else{
        return __wasmfsOpfsDir = "";
      }
    }catch(e){
      // sqlite3_wasm_init_wasmfs() is not available
      return __wasmfsOpfsDir = "";
    }
  };

  /**
     Experimental and subject to change or removal.

     Returns true if sqlite3.capi.sqlite3_wasmfs_opfs_dir() is a
     non-empty string and the given name starts with (that string +
     '/'), else returns false.




  */
  capi.sqlite3_wasmfs_filename_is_persistent = function(name){
    const p = capi.sqlite3_wasmfs_opfs_dir();
    return (p && name) ? name.startsWith(p+'/') : false;
  };

  // This bit is highly arguable and is incompatible with the fiddle shell.
  if(false && 0===wasm.exports.sqlite3_vfs_find(0)){
    /* Assume that sqlite3_initialize() has not yet been called.
5824
5825
5826
5827
5828
5829
5830
5831
5832


5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922























5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
     that VFS, else returns false. If pDb is falsy then the 3rd
     argument is ignored and this function returns a truthy value if
     the default VFS name matches that of the 2nd argument. Results
     are undefined if pDb is truthy but refers to an invalid
     pointer. The 3rd argument specifies the database name of the
     given database connection to check, defaulting to the main db.

     The 2nd and 3rd arguments may either be a JS string or a C-string
     allocated from the wasm environment.



     The truthy value it returns is a pointer to the `sqlite3_vfs`
     object.

     To permit safe use of this function from APIs which may be called
     via the C stack (like SQL UDFs), this function does not throw: if
     bad arguments cause a conversion error when passing into
     wasm-space, false is returned.
  */
  capi.sqlite3_web_db_uses_vfs = function(pDb,vfsName,dbName="main"){
    try{
      const pK = capi.sqlite3_vfs_find(vfsName);
      if(!pK) return false;
      else if(!pDb){
        return capi.sqlite3_vfs_find(0)===pK ? pK : false;
      }
      const ppVfs = wasm.allocPtr();
      try{
        return (
          (0===capi.sqlite3_file_control(
            pDb, dbName, capi.SQLITE_FCNTL_VFS_POINTER, ppVfs
          )) && (wasm.getPtrValue(ppVfs) === pK)
        ) ? pK : false;
      }finally{
        wasm.dealloc(ppVfs);
      }
    }catch(e){
      /* Ignore - probably bad args to a wasm-bound function. */
      return false;
    }
  };

  /**
     Returns an array of the names of all currently-registered sqlite3
     VFSes.
  */
  capi.sqlite3_web_vfs_list = function(){
    const rc = [];
    let pVfs = capi.sqlite3_vfs_find(0);
    while(pVfs){
      const oVfs = new capi.sqlite3_vfs(pVfs);
      rc.push(wasm.cstringToJs(oVfs.$zName));
      pVfs = oVfs.$pNext;
      oVfs.dispose();
    }
    return rc;
  };

  /**
     Serializes the given `sqlite3*` pointer to a Uint8Array, as per
     sqlite3_serialize(). On success it returns a Uint8Array. On
     error it throws with a description of the problem.
  */
  capi.sqlite3_web_db_export = function(pDb){
    if(!pDb) toss('Invalid sqlite3* argument.');
    if(!wasm.bigIntEnabled) toss('BigInt64 support is not enabled.');
    const stack = wasm.pstack.pointer;
    let pOut;
    try{
      const pSize = wasm.pstack.alloc(8/*i64*/ + wasm.ptrSizeof);
      const ppOut = pSize + 8;
      /**
         Maintenance reminder, since this cost a full hour of grief
         and confusion: if the order of pSize/ppOut are reversed in
         that memory block, fetching the value of pSize after the
         export reads a garbage size because it's not on an 8-byte
         memory boundary!
      */
      let rc = wasm.exports.sqlite3_wasm_db_serialize(
        pDb, ppOut, pSize, 0
      );
      if(rc){
        toss("Database serialization failed with code",
             sqlite3.capi.sqlite3_web_rc_str(rc));
      }
      pOut = wasm.getPtrValue(ppOut);
      const nOut = wasm.getMemValue(pSize, 'i64');
      rc = nOut
        ? wasm.heap8u().slice(pOut, pOut + Number(nOut))
        : new Uint8Array();
      return rc;
    }catch(e){
      console.error('internal error?',e);
      throw w;
    }finally{
      if(pOut) wasm.exports.sqlite3_free(pOut);
      wasm.pstack.restore(stack);
    }
  };
  























  if( capi.util.isMainWindow() ){
    /* Features specific to the main window thread... */

    /**
       Internal helper for sqlite3_web_kvvfs_clear() and friends.
       Its argument should be one of ('local','session','').
    */
    const __kvvfsInfo = function(which){
      const rc = Object.create(null);
      rc.prefix = 'kvvfs-'+which;
      rc.stores = [];
      if('session'===which || ''===which) rc.stores.push(self.sessionStorage);







|
|
>
>









|




|
|
<
<
<
<
<
<
|
<
<











|
















|



















|







<
<
<





|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|



|







5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963






5964


5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020



6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
     that VFS, else returns false. If pDb is falsy then the 3rd
     argument is ignored and this function returns a truthy value if
     the default VFS name matches that of the 2nd argument. Results
     are undefined if pDb is truthy but refers to an invalid
     pointer. The 3rd argument specifies the database name of the
     given database connection to check, defaulting to the main db.

     The 2nd and 3rd arguments may either be a JS string or a WASM
     C-string. If the 2nd argument is a NULL WASM pointer, the default
     VFS is assumed. If the 3rd is a NULL WASM pointer, "main" is
     assumed.

     The truthy value it returns is a pointer to the `sqlite3_vfs`
     object.

     To permit safe use of this function from APIs which may be called
     via the C stack (like SQL UDFs), this function does not throw: if
     bad arguments cause a conversion error when passing into
     wasm-space, false is returned.
  */
  capi.sqlite3_js_db_uses_vfs = function(pDb,vfsName,dbName="main"){
    try{
      const pK = capi.sqlite3_vfs_find(vfsName);
      if(!pK) return false;
      else if(!pDb){
        return pK===capi.sqlite3_vfs_find(0) ? pK : false;
      }else{






        return pK===capi.sqlite3_js_db_vfs(pDb) ? pK : false;


      }
    }catch(e){
      /* Ignore - probably bad args to a wasm-bound function. */
      return false;
    }
  };

  /**
     Returns an array of the names of all currently-registered sqlite3
     VFSes.
  */
  capi.sqlite3_js_vfs_list = function(){
    const rc = [];
    let pVfs = capi.sqlite3_vfs_find(0);
    while(pVfs){
      const oVfs = new capi.sqlite3_vfs(pVfs);
      rc.push(wasm.cstringToJs(oVfs.$zName));
      pVfs = oVfs.$pNext;
      oVfs.dispose();
    }
    return rc;
  };

  /**
     Serializes the given `sqlite3*` pointer to a Uint8Array, as per
     sqlite3_serialize(). On success it returns a Uint8Array. On
     error it throws with a description of the problem.
  */
  capi.sqlite3_js_db_export = function(pDb){
    if(!pDb) toss('Invalid sqlite3* argument.');
    if(!wasm.bigIntEnabled) toss('BigInt64 support is not enabled.');
    const stack = wasm.pstack.pointer;
    let pOut;
    try{
      const pSize = wasm.pstack.alloc(8/*i64*/ + wasm.ptrSizeof);
      const ppOut = pSize + 8;
      /**
         Maintenance reminder, since this cost a full hour of grief
         and confusion: if the order of pSize/ppOut are reversed in
         that memory block, fetching the value of pSize after the
         export reads a garbage size because it's not on an 8-byte
         memory boundary!
      */
      let rc = wasm.exports.sqlite3_wasm_db_serialize(
        pDb, ppOut, pSize, 0
      );
      if(rc){
        toss("Database serialization failed with code",
             sqlite3.capi.sqlite3_js_rc_str(rc));
      }
      pOut = wasm.getPtrValue(ppOut);
      const nOut = wasm.getMemValue(pSize, 'i64');
      rc = nOut
        ? wasm.heap8u().slice(pOut, pOut + Number(nOut))
        : new Uint8Array();
      return rc;



    }finally{
      if(pOut) wasm.exports.sqlite3_free(pOut);
      wasm.pstack.restore(stack);
    }
  };

  /**
     Given a `sqlite3*` and a database name (JS string or WASM
     C-string pointer, which may be 0), returns a pointer to the
     sqlite3_vfs responsible for it. If the given db name is null/0,
     or not provided, then "main" is assumed.
  */
  capi.sqlite3_js_db_vfs =
    (dbPointer, dbName=0)=>wasm.sqlite3_wasm_db_vfs(dbPointer, dbName);

  /**
     A thin wrapper around capi.sqlite3_aggregate_context() which
     behaves the same except that it throws a WasmAllocError if that
     function returns 0. As a special case, if n is falsy it does
     _not_ throw if that function returns 0. That special case is
     intended for use with xFinal() implementations.
  */
  capi.sqlite3_js_aggregate_context = (pCtx, n)=>{
    return capi.sqlite3_aggregate_context(pCtx, n)
      || (n ? WasmAllocError.toss("Cannot allocate",n,
                                  "bytes for sqlite3_aggregate_context()")
          : 0);
  };
  
  if( capi.util.isUIThread() ){
    /* Features specific to the main window thread... */

    /**
       Internal helper for sqlite3_js_kvvfs_clear() and friends.
       Its argument should be one of ('local','session','').
    */
    const __kvvfsInfo = function(which){
      const rc = Object.create(null);
      rc.prefix = 'kvvfs-'+which;
      rc.stores = [];
      if('session'===which || ''===which) rc.stores.push(self.sessionStorage);
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
       the pattern used by kvvfs are cleared: any other client-side
       data are retained.

       This function is only available in the main window thread.

       Returns the number of entries cleared.
    */
    capi.sqlite3_web_kvvfs_clear = function(which=''){
      let rc = 0;
      const kvinfo = __kvvfsInfo(which);
      kvinfo.stores.forEach((s)=>{
        const toRm = [] /* keys to remove */;
        let i;
        for( i = 0; i < s.length; ++i ){
          const k = s.key(i);







|







6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
       the pattern used by kvvfs are cleared: any other client-side
       data are retained.

       This function is only available in the main window thread.

       Returns the number of entries cleared.
    */
    capi.sqlite3_js_kvvfs_clear = function(which=''){
      let rc = 0;
      const kvinfo = __kvvfsInfo(which);
      kvinfo.stores.forEach((s)=>{
        const toRm = [] /* keys to remove */;
        let i;
        for( i = 0; i < s.length; ++i ){
          const k = s.key(i);
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992

       Note that the returned size is not authoritative from the
       perspective of how much data can fit into localStorage and
       sessionStorage, as the precise algorithms for determining
       those limits are unspecified and may include per-entry
       overhead invisible to clients.
    */
    capi.sqlite3_web_kvvfs_size = function(which=''){
      let sz = 0;
      const kvinfo = __kvvfsInfo(which);
      kvinfo.stores.forEach((s)=>{
        let i;
        for(i = 0; i < s.length; ++i){
          const k = s.key(i);
          if(k.startsWith(kvinfo.prefix)){







|







6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119

       Note that the returned size is not authoritative from the
       perspective of how much data can fit into localStorage and
       sessionStorage, as the precise algorithms for determining
       those limits are unspecified and may include per-entry
       overhead invisible to clients.
    */
    capi.sqlite3_js_kvvfs_size = function(which=''){
      let sz = 0;
      const kvinfo = __kvvfsInfo(which);
      kvinfo.stores.forEach((s)=>{
        let i;
        for(i = 0; i < s.length; ++i){
          const k = s.key(i);
          if(k.startsWith(kvinfo.prefix)){
6855
6856
6857
6858
6859
6860
6861

















6862
6863
6864
6865
6866
6867
6868
      pointer-to-pointer values. */
  target.getPtrValue = (ptr)=>target.getMemValue(ptr, ptrIR);

  /** Convenience form of setMemValue() intended for setting
      pointer-to-pointer values. */
  target.setPtrValue = (ptr, value)=>target.setMemValue(ptr, value, ptrIR);


















  /**
     Expects ptr to be a pointer into the WASM heap memory which
     refers to a NUL-terminated C-style string encoded as UTF-8.
     Returns the length, in bytes, of the string, as for `strlen(3)`.
     As a special case, if !ptr then it it returns `null`. Throws if
     ptr is out of range for target.heap8u().
  */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
      pointer-to-pointer values. */
  target.getPtrValue = (ptr)=>target.getMemValue(ptr, ptrIR);

  /** Convenience form of setMemValue() intended for setting
      pointer-to-pointer values. */
  target.setPtrValue = (ptr, value)=>target.setMemValue(ptr, value, ptrIR);

  /**
     Returns true if the given value appears to be legal for use as
     a WASM pointer value. Its _range_ of values is not (cannot be)
     validated except to ensure that it is a 32-bit integer with a
     value of 0 or greater. Likewise, it cannot verify whether the
     value actually refers to allocated memory in the WASM heap.
  */
  target.isPtr32 = (ptr)=>('number'===typeof ptr && (ptr===(ptr|0)) && ptr>=0);

  /**
     isPtr() is an alias for isPtr32(). If/when 64-bit WASM pointer
     support becomes widespread, it will become an alias for either
     isPtr32() or the as-yet-hypothetical isPtr64(), depending on a
     configuration option.
  */
  target.isPtr = target.isPtr32;

  /**
     Expects ptr to be a pointer into the WASM heap memory which
     refers to a NUL-terminated C-style string encoded as UTF-8.
     Returns the length, in bytes, of the string, as for `strlen(3)`.
     As a special case, if !ptr then it it returns `null`. Throws if
     ptr is out of range for target.heap8u().
  */
7380
7381
7382
7383
7384
7385
7386
7387

7388
7389
7390
7391
7392
7393
7394
  xcv.arg.i8  = (i)=>((i | 0) & 0xFF);
  xcv.arg.f32 = xcv.arg.float = (i)=>Number(i).valueOf();
  xcv.arg.f64 = xcv.arg.double = xcv.arg.f32;
  xcv.arg.int = xcv.arg.i32;
  xcv.result['*'] = xcv.result['pointer'] = xcv.arg['**'] = xcv.arg[ptrIR];
  xcv.result['number'] = (v)=>Number(v);

  {

    const copyToResult = ['i8', 'i16', 'i32', 'int',
                          'f32', 'float', 'f64', 'double'];
    if(target.bigIntEnabled) copyToResult.push('i64');
    for(const t of copyToResult){
      xcv.arg[t+'*'] = xcv.result[t+'*'] = xcv.arg[ptrIR];
      xcv.result[t] = xcv.arg[t] || toss("Missing arg converter:",t);
    }







|
>







7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
  xcv.arg.i8  = (i)=>((i | 0) & 0xFF);
  xcv.arg.f32 = xcv.arg.float = (i)=>Number(i).valueOf();
  xcv.arg.f64 = xcv.arg.double = xcv.arg.f32;
  xcv.arg.int = xcv.arg.i32;
  xcv.result['*'] = xcv.result['pointer'] = xcv.arg['**'] = xcv.arg[ptrIR];
  xcv.result['number'] = (v)=>Number(v);

  { /* Copy certain xcv.arg[...] handlers to xcv.result[...] and
       add pointer-style variants of them. */
    const copyToResult = ['i8', 'i16', 'i32', 'int',
                          'f32', 'float', 'f64', 'double'];
    if(target.bigIntEnabled) copyToResult.push('i64');
    for(const t of copyToResult){
      xcv.arg[t+'*'] = xcv.result[t+'*'] = xcv.arg[ptrIR];
      xcv.result[t] = xcv.arg[t] || toss("Missing arg converter:",t);
    }
8634
8635
8636
8637
8638
8639
8640
8641
8642
8643
8644
8645
8646
8647
8648
    /*  "The problem" is that the following isn't even remotely
        type-safe. OTOH, nothing about WASM pointers is. */
    const argPointer = wasm.xWrap.argAdapter('*');
    wasm.xWrap.argAdapter('StructType', (v)=>{
      if(v && v.constructor && v instanceof StructBinder.StructType){
        v = v.pointer;
      }
      return (v === (v | 0) /* v is a 32-bit integer */)
        ? argPointer(v)
        : toss("Invalid (object) type for StructType-type argument.");
    });
  }

  if(1){/* Convert Arrays and certain TypedArrays to strings for
           'flexible-string'-type arguments */







|







8779
8780
8781
8782
8783
8784
8785
8786
8787
8788
8789
8790
8791
8792
8793
    /*  "The problem" is that the following isn't even remotely
        type-safe. OTOH, nothing about WASM pointers is. */
    const argPointer = wasm.xWrap.argAdapter('*');
    wasm.xWrap.argAdapter('StructType', (v)=>{
      if(v && v.constructor && v instanceof StructBinder.StructType){
        v = v.pointer;
      }
      return wasm.isPtr(v)
        ? argPointer(v)
        : toss("Invalid (object) type for StructType-type argument.");
    });
  }

  if(1){/* Convert Arrays and certain TypedArrays to strings for
           'flexible-string'-type arguments */
8661
8662
8663
8664
8665
8666
8667

8668
8669

8670
8671
8672
8673
8674
8675
8676
8677
8678
       `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
    */
    const aPtr = wasm.xWrap.argAdapter('*');
    wasm.xWrap.argAdapter('sqlite3*', aPtr)
    ('sqlite3_stmt*', aPtr)
    ('sqlite3_context*', aPtr)
    ('sqlite3_value*', aPtr)

    ('void*', aPtr);
    wasm.xWrap.resultAdapter('sqlite3*', aPtr)

    ('sqlite3_stmt*', aPtr)
    ('sqlite3_context*', aPtr)
    ('void*', aPtr);

    /**
       Populate api object with sqlite3_...() by binding the "raw" wasm
       exports into type-converting proxies using wasm.xWrap().
    */
    for(const e of wasm.bindingSignatures){







>


>

|







8806
8807
8808
8809
8810
8811
8812
8813
8814
8815
8816
8817
8818
8819
8820
8821
8822
8823
8824
8825
       `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
    */
    const aPtr = wasm.xWrap.argAdapter('*');
    wasm.xWrap.argAdapter('sqlite3*', aPtr)
    ('sqlite3_stmt*', aPtr)
    ('sqlite3_context*', aPtr)
    ('sqlite3_value*', aPtr)
    ('sqlite3_vfs*', aPtr)
    ('void*', aPtr);
    wasm.xWrap.resultAdapter('sqlite3*', aPtr)
    ('sqlite3_context*', aPtr)
    ('sqlite3_stmt*', aPtr)
    ('sqlite3_vfs*', aPtr)
    ('void*', aPtr);

    /**
       Populate api object with sqlite3_...() by binding the "raw" wasm
       exports into type-converting proxies using wasm.xWrap().
    */
    for(const e of wasm.bindingSignatures){
8813
8814
8815
8816
8817
8818
8819



8820
8821
8822
8823
8824
8825
8826
       "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/,
       "*"/*xInverse*/, "*"/*xDestroy*/]
    );

    const __udfSetResult = function(pCtx, val){
      //console.warn("udfSetResult",typeof val, val);
      switch(typeof val) {



          case 'boolean':
            capi.sqlite3_result_int(pCtx, val ? 1 : 0);
            break;
          case 'bigint':
            if(wasm.bigIntEnabled){
              if(util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val);
              else toss3("BigInt value",val.toString(),"is too BigInt for int64.");







>
>
>







8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974
8975
8976
       "*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/,
       "*"/*xInverse*/, "*"/*xDestroy*/]
    );

    const __udfSetResult = function(pCtx, val){
      //console.warn("udfSetResult",typeof val, val);
      switch(typeof val) {
          case 'undefined':
            /* Assume that the client already called sqlite3_result_xxx(). */
            break;
          case 'boolean':
            capi.sqlite3_result_int(pCtx, val ? 1 : 0);
            break;
          case 'bigint':
            if(wasm.bigIntEnabled){
              if(util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val);
              else toss3("BigInt value",val.toString(),"is too BigInt for int64.");
8907
8908
8909
8910
8911
8912
8913

8914
8915
8916
8917
8918
8919
8920
8921
      return tgt;
    }/*__udfConvertArgs()*/;

    const __udfSetError = (pCtx, e)=>{
      if(e instanceof sqlite3.WasmAllocError){
        capi.sqlite3_result_error_nomem(pCtx);
      }else{

        capi.sqlite3_result_error(pCtx, e.message, -1);
      }
    };

    const __xFunc = function(callback){
      return function(pCtx, argc, pArgv){
        try{ __udfSetResult(pCtx, callback(pCtx, ...__udfConvertArgs(argc, pArgv))) }
        catch(e){







>
|







9057
9058
9059
9060
9061
9062
9063
9064
9065
9066
9067
9068
9069
9070
9071
9072
      return tgt;
    }/*__udfConvertArgs()*/;

    const __udfSetError = (pCtx, e)=>{
      if(e instanceof sqlite3.WasmAllocError){
        capi.sqlite3_result_error_nomem(pCtx);
      }else{
        const msg = ('string'===typeof e) ? e : e.message;
        capi.sqlite3_result_error(pCtx, msg, -1);
      }
    };

    const __xFunc = function(callback){
      return function(pCtx, argc, pArgv){
        try{ __udfSetResult(pCtx, callback(pCtx, ...__udfConvertArgs(argc, pArgv))) }
        catch(e){
9026
9027
9028
9029
9030
9031
9032
9033
9034
9035
9036
9037
9038
9039
9040
9041
9042
9043
9044
9045
9046
9047
9048
9049
9050
9051
9052
9053
9054
9055





9056
9057
9058
9059
9060
9061
9062
      /* Wrap the callbacks in a WASM-bound functions... */
      const wasm = capi.wasm;
      const uninstall = [/*funcs to uninstall on error*/];
      let rc;
      try{
        const funcArgs = __xWrapFuncs({xStep, xFinal, xValue, xInverse, xDestroy},
                                      uninstall);
        rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
                                   pApp, ...funcArgs);
      }catch(e){
        console.error("sqlite3_create_function_v2() setup threw:",e);
        for(let v of uninstall){
          wasm.uninstallFunction(v);
        }
        rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
                                        "Creation of UDF threw: "+e.message);
      }
      return rc;
    };
    /**
       A helper for UDFs implemented in JS and bound to WASM by the
       client. Given a JS value, udfSetResult(pCtx,X) calls one of the
       sqlite3_result_xyz(pCtx,...)  routines, depending on X's data
       type:

       - `null`: sqlite3_result_null()
       - `boolean`: sqlite3_result_int()
       - `number`: sqlite3_result_int() or sqlite3_result_double()
       - `string`: sqlite3_result_text()
       - Uint8Array or Int8Array: sqlite3_result_blob()






       Anything else triggers sqlite3_result_error().
    */
    capi.sqlite3_create_function_v2.udfSetResult =
      capi.sqlite3_create_function.udfSetResult =
      capi.sqlite3_create_window_function.udfSetResult = __udfSetResult;








|
|

|



















>
>
>
>
>







9177
9178
9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
9190
9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
9204
9205
9206
9207
9208
9209
9210
9211
9212
9213
9214
9215
9216
9217
9218
      /* Wrap the callbacks in a WASM-bound functions... */
      const wasm = capi.wasm;
      const uninstall = [/*funcs to uninstall on error*/];
      let rc;
      try{
        const funcArgs = __xWrapFuncs({xStep, xFinal, xValue, xInverse, xDestroy},
                                      uninstall);
        rc = sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
                                         pApp, ...funcArgs);
      }catch(e){
        console.error("sqlite3_create_window_function() setup threw:",e);
        for(let v of uninstall){
          wasm.uninstallFunction(v);
        }
        rc = util.sqlite3_wasm_db_error(pDb, capi.SQLITE_ERROR,
                                        "Creation of UDF threw: "+e.message);
      }
      return rc;
    };
    /**
       A helper for UDFs implemented in JS and bound to WASM by the
       client. Given a JS value, udfSetResult(pCtx,X) calls one of the
       sqlite3_result_xyz(pCtx,...)  routines, depending on X's data
       type:

       - `null`: sqlite3_result_null()
       - `boolean`: sqlite3_result_int()
       - `number`: sqlite3_result_int() or sqlite3_result_double()
       - `string`: sqlite3_result_text()
       - Uint8Array or Int8Array: sqlite3_result_blob()
       - `undefined`: indicates that the UDF called one of the
         `sqlite3_result_xyz()` routines on its own, making this
         function a no-op. Results are _undefined_ if this function is
         passed the `undefined` value but did _not_ call one of the
         `sqlite3_result_xyz()` routines.

       Anything else triggers sqlite3_result_error().
    */
    capi.sqlite3_create_function_v2.udfSetResult =
      capi.sqlite3_create_function.udfSetResult =
      capi.sqlite3_create_window_function.udfSetResult = __udfSetResult;

9081
9082
9083
9084
9085
9086
9087
9088
9089
9090
9091
9092
9093
9094
9095
9096
9097
9098
    capi.sqlite3_create_function_v2.udfConvertArgs =
      capi.sqlite3_create_function.udfConvertArgs =
      capi.sqlite3_create_window_function.udfConvertArgs = __udfConvertArgs;

    /**
       A helper for UDFs implemented in JS and bound to WASM by the
       client. It expects to be a passed `(sqlite3_context*, Error)`
       (i.e. an exception object). And it sets the current UDF's
       result to sqlite3_result_error_nomem() or sqlite3_result_error(),
       depending on whether the 2nd argument is a
       sqlite3.WasmAllocError object or not.
    */
    capi.sqlite3_create_function_v2.udfSetError =
      capi.sqlite3_create_function.udfSetError =
      capi.sqlite3_create_window_function.udfSetError = __udfSetError;

  }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;








|
|
|
|







9237
9238
9239
9240
9241
9242
9243
9244
9245
9246
9247
9248
9249
9250
9251
9252
9253
9254
    capi.sqlite3_create_function_v2.udfConvertArgs =
      capi.sqlite3_create_function.udfConvertArgs =
      capi.sqlite3_create_window_function.udfConvertArgs = __udfConvertArgs;

    /**
       A helper for UDFs implemented in JS and bound to WASM by the
       client. It expects to be a passed `(sqlite3_context*, Error)`
       (an exception object or message string). And it sets the
       current UDF's result to sqlite3_result_error_nomem() or
       sqlite3_result_error(), depending on whether the 2nd argument
       is a sqlite3.WasmAllocError object or not.
    */
    capi.sqlite3_create_function_v2.udfSetError =
      capi.sqlite3_create_function.udfSetError =
      capi.sqlite3_create_window_function.udfSetError = __udfSetError;

  }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;

9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
9190
9191




9192
9193
9194
9195
9196
9197
9198
9199
9200

9201
9202
9203
9204
9205
9206
9207
9208
9209
9210
9211
9212
9213
9214
9215
9216
9217
9218
9219
9220
9221
9222
9223
9224
9225
9226
9227
9228
9229
9230
9231
9232
9233
9234
9235
9236
9237
9238
9239
9240
9241
9242
9243
9244
9245
9246
9247
9248
9249
9250
9251
9252
9253
9254
9255
9256
9257
9258
9259
9260
9261
9262
9263
9264
9265
9266
9267
9268
9269
9270
9271
9272
9273
9274
9275
9276
9277
9278
9279
9280
9281






9282
9283
9284
9285
9286
9287
9288
9289
9290
9291
9292
9293
9294
9295
        __rcMap[e[1]] = e[0];
      }
    }
    /**
       For the given integer, returns the SQLITE_xxx result code as a
       string, or undefined if no such mapping is found.
    */
    capi.sqlite3_web_rc_str = (rc)=>__rcMap[rc];
    /* Bind all registered C-side structs... */
    const notThese = Object.assign(Object.create(null),{
      // Structs NOT to register
      WasmTestStruct: true
    });




    for(const s of wasm.ctype.structs){
      if(!notThese[s.name]){
        capi[s.name] = sqlite3.StructBinder(s);
      }
    }
  }/*end C constant imports*/

  if( util.isMainWindow()
      && 0!==capi.sqlite3_vfs_find("kvvfs") ){/* kvvfs-specific glue */

    const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
      wasm.exports.sqlite3_wasm_kvvfs_methods()
    );
    delete capi.sqlite3_kvvfs_methods;

    const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
          pstack = wasm.pstack,
          pAllocRaw = wasm.exports.sqlite3_wasm_pstack_alloc;

    const kvvfsStorage = (zClass)=>
          ((115/*=='s'*/===wasm.getMemValue(zClass))
           ? sessionStorage : localStorage);
    
    const kvvfsImpls = {
      xRead: (zClass, zKey, zBuf, nBuf)=>{
        const stack = pstack.pointer,
              astack = wasm.scopedAllocPush();
        try {
          const zXKey = kvvfsMakeKey(zClass,zKey);
          if(!zXKey) return -3/*OOM*/;
          const jKey = wasm.cstringToJs(zXKey);
          const jV = kvvfsStorage(zClass).getItem(jKey);
          if(!jV) return -1;
          const nV = jV.length /* Note that we are relying 100% on v being
                                  ASCII so that jV.length is equal to the
                                  C-string's byte length. */;
          if(nBuf<=0) return nV;
          else if(1===nBuf){
            wasm.setMemValue(zBuf, 0);
            return nV;
          }
          const zV = wasm.scopedAllocCString(jV);
          if(nBuf > nV + 1) nBuf = nV + 1;
          wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1);
          wasm.setMemValue(zBuf + nBuf - 1, 0);
          return nBuf - 1;
        }catch(e){
          console.error("kvstorageRead()",e);
          return -2;
        }finally{
          pstack.restore(stack);
          wasm.scopedAllocPop(astack);
        }
      },
      xWrite: (zClass, zKey, zData)=>{
        const stack = pstack.pointer;
        try {
          const zXKey = kvvfsMakeKey(zClass,zKey);
          if(!zXKey) return 1/*OOM*/;
          const jKey = wasm.cstringToJs(zXKey);
          kvvfsStorage(zClass).setItem(jKey, wasm.cstringToJs(zData));
          return 0;
        }catch(e){
          console.error("kvstorageWrite()",e);
          return capi.SQLITE_IOERR;
        }finally{
          pstack.restore(stack);
        }
      },
      xDelete: (zClass, zKey)=>{
        const stack = pstack.pointer;
        try {
          const zXKey = kvvfsMakeKey(zClass,zKey);
          if(!zXKey) return 1/*OOM*/;
          kvvfsStorage(zClass).removeItem(wasm.cstringToJs(zXKey));
          return 0;
        }catch(e){
          console.error("kvstorageDelete()",e);
          return capi.SQLITE_IOERR;
        }finally{
          pstack.restore(stack);
        }
      }
    }/*kvvfsImpls*/;
    for(let k of Object.keys(kvvfsImpls)){
      kvvfsMethods[kvvfsMethods.memberKey(k)] =
        wasm.installFunction(
          kvvfsMethods.memberSignature(k),
          kvvfsImpls[k]
        );
    }






  }/*kvvfs*/

});
/* END FILE: api/sqlite3-api-glue.js */
/* BEGIN FILE: ./bld/sqlite3-api-build-version.js */
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
  sqlite3.version = {"libVersion": "3.40.0", "libVersionNumber": 3040000, "sourceId": "2022-10-14 15:52:29 a4423ca234453c14eb40db7fe5943f63b30fd9dc2207388e8a2966733a004e9d"};
});
/* END FILE: ./bld/sqlite3-api-build-version.js */
/* BEGIN FILE: api/sqlite3-api-oo1.js */
/*
  2022-07-22

  The author disclaims copyright to this source code.  In place of a







|





>
>
>
>







|
|
>
|
|
|
|

|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
|





|







9335
9336
9337
9338
9339
9340
9341
9342
9343
9344
9345
9346
9347
9348
9349
9350
9351
9352
9353
9354
9355
9356
9357
9358
9359
9360
9361
9362
9363
9364
9365
9366
9367
9368
9369
9370
9371
9372
9373
9374
9375
9376
9377
9378
9379
9380
9381
9382
9383
9384
9385
9386
9387
9388
9389
9390
9391
9392
9393
9394
9395
9396
9397
9398
9399
9400
9401
9402
9403
9404
9405
9406
9407
9408
9409
9410
9411
9412
9413
9414
9415
9416
9417
9418
9419
9420
9421
9422
9423
9424
9425
9426
9427
9428
9429
9430
9431
9432
9433
9434
9435
9436
9437
9438
9439
9440
9441
9442
9443
9444
9445
9446
9447
9448
9449
9450
9451
9452
9453
9454
9455
9456
9457
9458
9459
9460
9461
9462
        __rcMap[e[1]] = e[0];
      }
    }
    /**
       For the given integer, returns the SQLITE_xxx result code as a
       string, or undefined if no such mapping is found.
    */
    capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
    /* Bind all registered C-side structs... */
    const notThese = Object.assign(Object.create(null),{
      // Structs NOT to register
      WasmTestStruct: true
    });
    if(!util.isUIThread()){
      /* We remove the kvvfs VFS from Worker threads below. */
      notThese.sqlite3_kvvfs_methods = true;
    }
    for(const s of wasm.ctype.structs){
      if(!notThese[s.name]){
        capi[s.name] = sqlite3.StructBinder(s);
      }
    }
  }/*end C constant imports*/

  const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
  if( pKvvfs ){/* kvvfs-specific glue */
    if(util.isUIThread()){
      const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
        wasm.exports.sqlite3_wasm_kvvfs_methods()
      );
      delete capi.sqlite3_kvvfs_methods;

      const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
            pstack = wasm.pstack,
            pAllocRaw = wasm.exports.sqlite3_wasm_pstack_alloc;

      const kvvfsStorage = (zClass)=>
            ((115/*=='s'*/===wasm.getMemValue(zClass))
             ? sessionStorage : localStorage);
      
      const kvvfsImpls = {
        xRead: (zClass, zKey, zBuf, nBuf)=>{
          const stack = pstack.pointer,
                astack = wasm.scopedAllocPush();
          try {
            const zXKey = kvvfsMakeKey(zClass,zKey);
            if(!zXKey) return -3/*OOM*/;
            const jKey = wasm.cstringToJs(zXKey);
            const jV = kvvfsStorage(zClass).getItem(jKey);
            if(!jV) return -1;
            const nV = jV.length /* Note that we are relying 100% on v being
                                    ASCII so that jV.length is equal to the
                                    C-string's byte length. */;
            if(nBuf<=0) return nV;
            else if(1===nBuf){
              wasm.setMemValue(zBuf, 0);
              return nV;
            }
            const zV = wasm.scopedAllocCString(jV);
            if(nBuf > nV + 1) nBuf = nV + 1;
            wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1);
            wasm.setMemValue(zBuf + nBuf - 1, 0);
            return nBuf - 1;
          }catch(e){
            console.error("kvstorageRead()",e);
            return -2;
          }finally{
            pstack.restore(stack);
            wasm.scopedAllocPop(astack);
          }
        },
        xWrite: (zClass, zKey, zData)=>{
          const stack = pstack.pointer;
          try {
            const zXKey = kvvfsMakeKey(zClass,zKey);
            if(!zXKey) return 1/*OOM*/;
            const jKey = wasm.cstringToJs(zXKey);
            kvvfsStorage(zClass).setItem(jKey, wasm.cstringToJs(zData));
            return 0;
          }catch(e){
            console.error("kvstorageWrite()",e);
            return capi.SQLITE_IOERR;
          }finally{
            pstack.restore(stack);
          }
        },
        xDelete: (zClass, zKey)=>{
          const stack = pstack.pointer;
          try {
            const zXKey = kvvfsMakeKey(zClass,zKey);
            if(!zXKey) return 1/*OOM*/;
            kvvfsStorage(zClass).removeItem(wasm.cstringToJs(zXKey));
            return 0;
          }catch(e){
            console.error("kvstorageDelete()",e);
            return capi.SQLITE_IOERR;
          }finally{
            pstack.restore(stack);
          }
        }
      }/*kvvfsImpls*/;
      for(let k of Object.keys(kvvfsImpls)){
        kvvfsMethods[kvvfsMethods.memberKey(k)] =
          wasm.installFunction(
            kvvfsMethods.memberSignature(k),
            kvvfsImpls[k]
          );
      }
    }else{
      /* Worker thread: unregister kvvfs to avoid it being used
         for anything other than local/sessionStorage. It "can"
         be used that way but it's not really intended to be. */
      capi.sqlite3_vfs_unregister(pKvvfs);
    }
  }/*pKvvfs*/

});
/* END FILE: api/sqlite3-api-glue.js */
/* BEGIN FILE: ./bld/sqlite3-api-build-version.js */
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
  sqlite3.version = {"libVersion": "3.40.0", "libVersionNumber": 3040000, "sourceId": "2022-10-27 03:57:48 ed8d3f25a4d6ac04d9f7918c791d8d2c6f23ce846278ca63f8fbadb7ea27alt1","downloadVersion": 3400000};
});
/* END FILE: ./bld/sqlite3-api-build-version.js */
/* BEGIN FILE: api/sqlite3-api-oo1.js */
/*
  2022-07-22

  The author disclaims copyright to this source code.  In place of a
9374
9375
9376
9377
9378
9379
9380
9381
9382
9383
9384
9385
9386
9387
9388
  const __vfsPostOpenSql = Object.create(null);

  /**
     A proxy for DB class constructors. It must be called with the
     being-construct DB object as its "this". See the DB constructor
     for the argument docs. This is split into a separate function
     in order to enable simple creation of special-case DB constructors,
     e.g. JsStorageDB and OpfsDB.

     Expects to be passed a configuration object with the following
     properties:

     - `.filename`: the db filename. It may be a special name like ":memory:"
       or "".








|







9541
9542
9543
9544
9545
9546
9547
9548
9549
9550
9551
9552
9553
9554
9555
  const __vfsPostOpenSql = Object.create(null);

  /**
     A proxy for DB class constructors. It must be called with the
     being-construct DB object as its "this". See the DB constructor
     for the argument docs. This is split into a separate function
     in order to enable simple creation of special-case DB constructors,
     e.g. JsStorageDb and OpfsDb.

     Expects to be passed a configuration object with the following
     properties:

     - `.filename`: the db filename. It may be a special name like ":memory:"
       or "".

9436
9437
9438
9439
9440
9441
9442
9443
9444
9445
9446
9447
9448
9449
9450
9451
9452
9453
9454
9455
9456
9457
9458

9459
9460
9461
9462
9463
9464
9465
9466
9467
9468
9469
9470
9471
9472
9473
9474
9475
9476
9477
9478
    let pDb, oflags = 0;
    if( flagsStr.indexOf('c')>=0 ){
      oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
    }
    if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
    if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
    oflags |= capi.SQLITE_OPEN_EXRESCODE;
    const scope = wasm.scopedAllocPush();
    try {
      const pPtr = wasm.allocPtr() /* output (sqlite3**) arg */;
      const pVfsName = vfsName ? (
        ('number'===typeof vfsName ? vfsName : wasm.scopedAllocCString(vfsName))
      ): 0;
      let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, pVfsName);
      pDb = wasm.getPtrValue(pPtr);
      checkSqlite3Rc(pDb, rc);
      if(flagsStr.indexOf('t')>=0){
        capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
                              __dbTraceToConsole, 0);
      }
      // Check for per-VFS post-open SQL...
      wasm.setPtrValue(pPtr, 0);
      if(0===capi.sqlite3_file_control(

        pDb, "main", capi.SQLITE_FCNTL_VFS_POINTER, pPtr
      )){
        const postInitSql = __vfsPostOpenSql[wasm.getPtrValue(pPtr)];
        if(postInitSql){
          rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0);
          checkSqlite3Rc(pDb, rc);
        }
      }      
    }catch( e ){
      if( pDb ) capi.sqlite3_close_v2(pDb);
      throw e;
    }finally{
      wasm.scopedAllocPop(scope);
    }
    this.filename = fnJs;
    __ptrMap.set(this, pDb);
    __stmtMap.set(this, Object.create(null));
  };

  /**







|

|
<
<
<
|







<
|
>
|
<
|
|
|
|
<





|







9603
9604
9605
9606
9607
9608
9609
9610
9611
9612



9613
9614
9615
9616
9617
9618
9619
9620

9621
9622
9623

9624
9625
9626
9627

9628
9629
9630
9631
9632
9633
9634
9635
9636
9637
9638
9639
9640
    let pDb, oflags = 0;
    if( flagsStr.indexOf('c')>=0 ){
      oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
    }
    if( flagsStr.indexOf('w')>=0 ) oflags |= capi.SQLITE_OPEN_READWRITE;
    if( 0===oflags ) oflags |= capi.SQLITE_OPEN_READONLY;
    oflags |= capi.SQLITE_OPEN_EXRESCODE;
    const stack = wasm.pstack.pointer;
    try {
      const pPtr = wasm.pstack.allocPtr() /* output (sqlite3**) arg */;



      let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || 0);
      pDb = wasm.getPtrValue(pPtr);
      checkSqlite3Rc(pDb, rc);
      if(flagsStr.indexOf('t')>=0){
        capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT,
                              __dbTraceToConsole, 0);
      }
      // Check for per-VFS post-open SQL...

      const pVfs = capi.sqlite3_js_db_vfs(pDb);
      //console.warn("Opened db",fn,"with vfs",vfsName,pVfs);
      if(!pVfs) toss3("Internal error: cannot get VFS for new db handle.");

      const postInitSql = __vfsPostOpenSql[pVfs];
      if(postInitSql){
        rc = capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0);
        checkSqlite3Rc(pDb, rc);

      }      
    }catch( e ){
      if( pDb ) capi.sqlite3_close_v2(pDb);
      throw e;
    }finally{
      wasm.pstack.restore(stack);
    }
    this.filename = fnJs;
    __ptrMap.set(this, pDb);
    __stmtMap.set(this, Object.create(null));
  };

  /**
9662
9663
9664
9665
9666
9667
9668


9669
9670
9671
9672
9673
9674
9675
9676
9677
9678
9679
9680
9681
9682
9683
9684
9685
9686
9687
9688
9689
9690
9691
9692
9693
9694
9695
  */
  const parseExecArgs = function(args){
    const out = Object.create(null);
    out.opt = Object.create(null);
    switch(args.length){
        case 1:
          if('string'===typeof args[0] || util.isSQLableTypedArray(args[0])){


            out.sql = args[0];
          }else if(args[0] && 'object'===typeof args[0]){
            out.opt = args[0];
            out.sql = out.opt.sql;
          }else if(Array.isArray(args[0])){
            out.sql = args[0];
          }
          break;
        case 2:
          out.sql = args[0];
          out.opt = args[1];
          break;
        default: toss3("Invalid argument count for exec().");
    };
    if(util.isSQLableTypedArray(out.sql)){
      out.sql = util.typedArrayToString(out.sql);
    }else if(Array.isArray(out.sql)){
      out.sql = out.sql.join('');
    }else if('string'!==typeof out.sql){
      toss3("Missing SQL argument.");
    }
    if(out.opt.callback || out.opt.resultRows){
      switch((undefined===out.opt.rowMode)
             ? 'array' : out.opt.rowMode) {
          case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break;
          case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
          case 'stmt':







>
>




<
<













|







9824
9825
9826
9827
9828
9829
9830
9831
9832
9833
9834
9835
9836


9837
9838
9839
9840
9841
9842
9843
9844
9845
9846
9847
9848
9849
9850
9851
9852
9853
9854
9855
9856
9857
  */
  const parseExecArgs = function(args){
    const out = Object.create(null);
    out.opt = Object.create(null);
    switch(args.length){
        case 1:
          if('string'===typeof args[0] || util.isSQLableTypedArray(args[0])){
            out.sql = args[0];
          }else if(Array.isArray(args[0])){
            out.sql = args[0];
          }else if(args[0] && 'object'===typeof args[0]){
            out.opt = args[0];
            out.sql = out.opt.sql;


          }
          break;
        case 2:
          out.sql = args[0];
          out.opt = args[1];
          break;
        default: toss3("Invalid argument count for exec().");
    };
    if(util.isSQLableTypedArray(out.sql)){
      out.sql = util.typedArrayToString(out.sql);
    }else if(Array.isArray(out.sql)){
      out.sql = out.sql.join('');
    }else if('string'!==typeof out.sql){
      toss3("Missing SQL argument or unsupported SQL value type.");
    }
    if(out.opt.callback || out.opt.resultRows){
      switch((undefined===out.opt.rowMode)
             ? 'array' : out.opt.rowMode) {
          case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break;
          case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
          case 'stmt':
9807
9808
9809
9810
9811
9812
9813
9814
9815
9816
9817
9818
9819
9820
9821
9822
9823
9824
9825
9826
9827
9828
9829
9830
9831
9832
9833
9834
9835
9836
9837
9838
9839
      }else{
        return sixtyFour
          ? capi.sqlite3_changes64(p)
          : capi.sqlite3_changes(p);
      }
    },
    /**
       Similar to the this.filename property but will return a falsy
       value for special names like ":memory:". Throws if the DB has
       been closed. If passed an argument it then it will return the
       filename of the ATTACHEd db with that name, else it assumes a
       name of `main`. The argument may be either a JS string or
       a pointer to a WASM-allocated C-string.
    */
    getFilename: function(dbName='main'){
      return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);
    },
    /**
       Returns true if this db instance has a name which resolves to a
       file. If the name is "" or starts with ":", it resolves to false.
       Note that it is not aware of the peculiarities of URI-style
       names and a URI-style name for a ":memory:" db will fool it.
       Returns false if this db is closed.
    */
    hasFilename: function(){
      return this.filename && ':'!==this.filename[0];
    },
    /**
       Returns the name of the given 0-based db number, as documented
       for sqlite3_db_name().
    */
    dbName: function(dbNumber=0){
      return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber);







|
|
<
<
|
|

|

<
<
<
<
<
<
<
<
<
<







9969
9970
9971
9972
9973
9974
9975
9976
9977


9978
9979
9980
9981
9982










9983
9984
9985
9986
9987
9988
9989
      }else{
        return sixtyFour
          ? capi.sqlite3_changes64(p)
          : capi.sqlite3_changes(p);
      }
    },
    /**
       Similar to the this.filename but returns the
       sqlite3_db_filename() value for the given database name,


       defaulting to "main".  The argument may be either a JS string
       or a pointer to a WASM-allocated C-string.
    */
    dbFilename: function(dbName='main'){
      return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);










    },
    /**
       Returns the name of the given 0-based db number, as documented
       for sqlite3_db_name().
    */
    dbName: function(dbNumber=0){
      return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber);
10100
10101
10102
10103
10104
10105
10106
10107
10108
10109
10110
10111
10112
10113
10114
10115

       In the final two cases, the function must be defined as the
       `callback` property of the options object (optionally called
       `xFunc` to align with the C API documentation). In the final
       case, the function's name must be the 'name' property.

       The first two call forms can only be used for creating scalar
       functions. Creating an aggregate function requires the
       options-object form (see below for details).

       UDFs cannot currently be removed from a DB handle after they're
       added. More correctly, they can be removed as documented for
       sqlite3_create_function_v2(), but doing so will "leak" the
       JS-created WASM binding of those functions.

       On success, returns this object. Throws on error.







|
|







10250
10251
10252
10253
10254
10255
10256
10257
10258
10259
10260
10261
10262
10263
10264
10265

       In the final two cases, the function must be defined as the
       `callback` property of the options object (optionally called
       `xFunc` to align with the C API documentation). In the final
       case, the function's name must be the 'name' property.

       The first two call forms can only be used for creating scalar
       functions. Creating an aggregate or window function requires
       the options-object form (see below for details).

       UDFs cannot currently be removed from a DB handle after they're
       added. More correctly, they can be removed as documented for
       sqlite3_create_function_v2(), but doing so will "leak" the
       JS-created WASM binding of those functions.

       On success, returns this object. Throws on error.
10126
10127
10128
10129
10130
10131
10132



10133
10134
10135
10136
10137
10138



10139
10140
10141
10142
10143
10144
10145
10146
10147
10148
10149
10150
10151
10152
10153
10154
10155
10156
10157
10158
10159
10160

10161
10162
10163
10164
10165
10166





10167
10168
10169
10170
10171
10172
10173
10174
10175
10176
10177
10178
10179
10180
10181
10182
10183
10184
10185
10186
10187
10188
10189
10190
10191
10192



10193

10194
10195
10196
10197
10198
10199
10200
10201
10202
10203
10204
10205
10206
10207












10208
10209
10210
10211
10212
10213
10214
10215
10216
10217
10218
10219
10220
10221
10222
10223
10224
10225
10226
10227
10228
10229




10230





10231


10232
10233
10234
10235
10236
10237
10238
       - Scalar: set the `xFunc` function-type property to the UDF
         function.

       - Aggregate: set the `xStep` and `xFinal` function-type
         properties to the "step" and "final" callbacks for the
         aggregate. Do not set the `xFunc` property.




       The options object may optionally have an `xDestroy`
       function-type property, as per
       sqlite3_create_function_v2(). Its argument will be the
       WASM-pointer-type value of the `pApp` property, and this
       function will throw if `pApp` is defined but is not null,
       undefined, or a numeric (WASM pointer) value.




       The optional options object may contain flags to modify how
       the function is defined:

       - `arity`: the number of arguments which SQL calls to this
       function expect or require. The default value is `xFunc.length`
       or `xStep.length` (i.e. the number of declared parameters it
       has) **MINUS 1** (see below for why). As a special case, if the
       `length` is 0, its arity is also 0 instead of -1. A negative
       arity value means that the function is variadic and may accept
       any number of arguments, up to sqlite3's compile-time
       limits. sqlite3 will enforce the argument count if is zero or
       greater.

       The callback always receives a pointer to an `sqlite3_context`
       object as its first argument. Any arguments after that are from
       SQL code. The leading context argument does _not_ count towards
       the function's arity. See the docs for
       sqlite3.capi.sqlite3_create_function_v2() for why that argument
       is needed in the interface.

       The following properties correspond to flags documented at:


       https://sqlite.org/c3ref/create_function.html

       - .deterministic = SQLITE_DETERMINISTIC
       - .directOnly = SQLITE_DIRECTONLY
       - .innocuous = SQLITE_INNOCUOUS





    */
    createFunction: function f(name, xFunc, opt){
      let xStep, xFinal;
      const isFunc = (f)=>(f instanceof Function);
      switch(arguments.length){
          case 1: /* (optionsObject) */
            opt = name;
            name = opt.name;
            xFunc = opt.xFunc;
            break;
          case 2: /* (name, callback|optionsObject) */
            if(!isFunc(xFunc)){
              opt = xFunc;
              xFunc = opt.xFunc;
            }
            break;
          case 3: /* name, xFunc, opt */
            break;
          default: break;
      }
      if(!opt) opt = {};
      if('string' !== typeof name){
        toss3("Invalid arguments: missing function name.");
      }
      xStep = opt.xStep;
      xFinal = opt.xFinal;



      if(isFunc(xFunc)){

        if(isFunc(xStep) || isFunc(xFinal)){
          toss3("Ambiguous arguments: scalar or aggregate?");
        }
        xStep = xFinal = null;
      }else if(isFunc(xStep)){
        if(!isFunc(xFinal)){
          toss3("Missing xFinal() callback for aggregate UDF.");
        }
        xFunc = null;
      }else if(isFunc(xFinal)){
        toss3("Missing xStep() callback for aggregate UDF.");
      }else{
        toss3("Missing function-type properties.");
      }












      const pApp = opt.pApp;
      if(undefined!==pApp &&
         null!==pApp &&
         (('number'!==typeof pApp) || !capi.util.isInt32(pApp))){
        toss3("Invalid value for pApp property. Must be a legal WASM pointer value.");
      }
      const xDestroy = opt.xDestroy;
      if(xDestroy && !isFunc(xDestroy)){
        toss3("xDestroy property must be a function.");
      }
      let fFlags = 0 /*flags for sqlite3_create_function_v2()*/;
      if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC;
      if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY;
      if(getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS;
      name = name.toLowerCase();
      const xArity = xFunc || xStep;
      const arity = getOwnOption(opt, 'arity');
      DB.checkRc(this, capi.sqlite3_create_function_v2(
        this.pointer, name,
        ('number'===typeof arity
         ? arity
         : (xArity.length ? xArity.length-1/*for pCtx arg*/ : 0)),




        capi.SQLITE_UTF8 | fFlags, pApp,





        xFunc, xStep, xFinal, xDestroy));


      return this;
    }/*createFunction()*/,
    /**
       Prepares the given SQL, step()s it one time, and returns
       the value of the first result column. If it has no results,
       undefined is returned.








>
>
>

|
<
|
|
|
>
>
>

|










<
<
|
|
|
|



|
>



|
|
|
>
>
>
>
>


<





|




|










|
|
>
>
>

>






|



|



>
>
>
>
>
>
>
>
>
>
>
>






|










<
<
|
|
|
>
>
>
>
|
>
>
>
>
>
|
>
>







10276
10277
10278
10279
10280
10281
10282
10283
10284
10285
10286
10287

10288
10289
10290
10291
10292
10293
10294
10295
10296
10297
10298
10299
10300
10301
10302
10303
10304
10305


10306
10307
10308
10309
10310
10311
10312
10313
10314
10315
10316
10317
10318
10319
10320
10321
10322
10323
10324
10325
10326
10327

10328
10329
10330
10331
10332
10333
10334
10335
10336
10337
10338
10339
10340
10341
10342
10343
10344
10345
10346
10347
10348
10349
10350
10351
10352
10353
10354
10355
10356
10357
10358
10359
10360
10361
10362
10363
10364
10365
10366
10367
10368
10369
10370
10371
10372
10373
10374
10375
10376
10377
10378
10379
10380
10381
10382
10383
10384
10385
10386
10387
10388
10389
10390
10391
10392
10393
10394
10395
10396
10397
10398


10399
10400
10401
10402
10403
10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415
10416
10417
10418
10419
10420
10421
       - Scalar: set the `xFunc` function-type property to the UDF
         function.

       - Aggregate: set the `xStep` and `xFinal` function-type
         properties to the "step" and "final" callbacks for the
         aggregate. Do not set the `xFunc` property.

       - Window: set the `xStep`, `xFinal`, `xValue`, and `xInverse`
         function-type properties. Do not set the `xFunc` property.

       The options object may optionally have an `xDestroy`
       function-type property, as per sqlite3_create_function_v2().

       Its argument will be the WASM-pointer-type value of the `pApp`
       property, and this function will throw if `pApp` is defined but
       is not null, undefined, or a numeric (WASM pointer)
       value. i.e. `pApp`, if set, must be value suitable for use as a
       WASM pointer argument, noting that `null` or `undefined` will
       translate to 0 for that purpose.

       The options object may contain flags to modify how
       the function is defined:

       - `arity`: the number of arguments which SQL calls to this
       function expect or require. The default value is `xFunc.length`
       or `xStep.length` (i.e. the number of declared parameters it
       has) **MINUS 1** (see below for why). As a special case, if the
       `length` is 0, its arity is also 0 instead of -1. A negative
       arity value means that the function is variadic and may accept
       any number of arguments, up to sqlite3's compile-time
       limits. sqlite3 will enforce the argument count if is zero or


       greater. The callback always receives a pointer to an
       `sqlite3_context` object as its first argument. Any arguments
       after that are from SQL code. The leading context argument does
       _not_ count towards the function's arity. See the docs for
       sqlite3.capi.sqlite3_create_function_v2() for why that argument
       is needed in the interface.

       The following options-object properties correspond to flags
       documented at:

       https://sqlite.org/c3ref/create_function.html

       - `deterministic` = sqlite3.capi.SQLITE_DETERMINISTIC
       - `directOnly` = sqlite3.capi.SQLITE_DIRECTONLY
       - `innocuous` = sqlite3.capi.SQLITE_INNOCUOUS

       Sidebar: the ability to add new WASM-accessible functions to
       the runtime requires that the WASM build is compiled with the
       equivalent functionality as that provided by Emscripten's
       `-sALLOW_TABLE_GROWTH` flag.
    */
    createFunction: function f(name, xFunc, opt){

      const isFunc = (f)=>(f instanceof Function);
      switch(arguments.length){
          case 1: /* (optionsObject) */
            opt = name;
            name = opt.name;
            xFunc = opt.xFunc || 0;
            break;
          case 2: /* (name, callback|optionsObject) */
            if(!isFunc(xFunc)){
              opt = xFunc;
              xFunc = opt.xFunc || 0;
            }
            break;
          case 3: /* name, xFunc, opt */
            break;
          default: break;
      }
      if(!opt) opt = {};
      if('string' !== typeof name){
        toss3("Invalid arguments: missing function name.");
      }
      let xStep = opt.xStep || 0;
      let xFinal = opt.xFinal || 0;
      const xValue = opt.xValue || 0;
      const xInverse = opt.xInverse || 0;
      let isWindow = undefined;
      if(isFunc(xFunc)){
        isWindow = false;
        if(isFunc(xStep) || isFunc(xFinal)){
          toss3("Ambiguous arguments: scalar or aggregate?");
        }
        xStep = xFinal = null;
      }else if(isFunc(xStep)){
        if(!isFunc(xFinal)){
          toss3("Missing xFinal() callback for aggregate or window UDF.");
        }
        xFunc = null;
      }else if(isFunc(xFinal)){
        toss3("Missing xStep() callback for aggregate or window UDF.");
      }else{
        toss3("Missing function-type properties.");
      }
      if(false === isWindow){
        if(isFunc(xValue) || isFunc(xInverse)){
          toss3("xValue and xInverse are not permitted for non-window UDFs.");
        }
      }else if(isFunc(xValue)){
        if(!isFunc(xInverse)){
          toss3("xInverse must be provided if xValue is.");
        }
        isWindow = true;
      }else if(isFunc(xInverse)){
        toss3("xValue must be provided if xInverse is.");
      }
      const pApp = opt.pApp;
      if(undefined!==pApp &&
         null!==pApp &&
         (('number'!==typeof pApp) || !capi.util.isInt32(pApp))){
        toss3("Invalid value for pApp property. Must be a legal WASM pointer value.");
      }
      const xDestroy = opt.xDestroy || 0;
      if(xDestroy && !isFunc(xDestroy)){
        toss3("xDestroy property must be a function.");
      }
      let fFlags = 0 /*flags for sqlite3_create_function_v2()*/;
      if(getOwnOption(opt, 'deterministic')) fFlags |= capi.SQLITE_DETERMINISTIC;
      if(getOwnOption(opt, 'directOnly')) fFlags |= capi.SQLITE_DIRECTONLY;
      if(getOwnOption(opt, 'innocuous')) fFlags |= capi.SQLITE_INNOCUOUS;
      name = name.toLowerCase();
      const xArity = xFunc || xStep;
      const arity = getOwnOption(opt, 'arity');


      const arityArg = ('number'===typeof arity
                        ? arity
                        : (xArity.length ? xArity.length-1/*for pCtx arg*/ : 0));
      let rc;
      if( isWindow ){
        rc = capi.sqlite3_create_window_function(
          this.pointer, name, arityArg,
          capi.SQLITE_UTF8 | fFlags, pApp || 0,
          xStep, xFinal, xValue, xInverse, xDestroy);
      }else{
        rc = capi.sqlite3_create_function_v2(
          this.pointer, name, arityArg,
          capi.SQLITE_UTF8 | fFlags, pApp || 0,
          xFunc, xStep, xFinal, xDestroy);
      }
      DB.checkRc(this, rc);
      return this;
    }/*createFunction()*/,
    /**
       Prepares the given SQL, step()s it one time, and returns
       the value of the first result column. If it has no results,
       undefined is returned.

10693
10694
10695
10696
10697
10698
10699
10700
10701
10702
10703
10704
10705
10706
10707
      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
      switch(rc){
          case capi.SQLITE_DONE: return this._mayGet = false;
          case capi.SQLITE_ROW: return this._mayGet = true;
          default:
            this._mayGet = false;
            console.warn("sqlite3_step() rc=",rc,
                         capi.sqlite3_web_rc_str(rc),
                         "SQL =", capi.sqlite3_sql(this.pointer));
            DB.checkRc(this.db.pointer, rc);
      }
    },
    /**
       Functions exactly like step() except that...








|







10876
10877
10878
10879
10880
10881
10882
10883
10884
10885
10886
10887
10888
10889
10890
      const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
      switch(rc){
          case capi.SQLITE_DONE: return this._mayGet = false;
          case capi.SQLITE_ROW: return this._mayGet = true;
          default:
            this._mayGet = false;
            console.warn("sqlite3_step() rc=",rc,
                         capi.sqlite3_js_rc_str(rc),
                         "SQL =", capi.sqlite3_sql(this.pointer));
            DB.checkRc(this.db.pointer, rc);
      }
    },
    /**
       Functions exactly like step() except that...

10931
10932
10933
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946
10947
10948
10949
10950
10951
10952
10953
10954
10955
10956
10957
10958
10959
10960
10961
10962
10963
10964
10965
10966
10967
10968
10969
10970
10971
10972
10973
10974
      ooApi: "0.1"
    },
    DB,
    Stmt,
    dbCtorHelper
  }/*oo1 object*/;

  if(util.isMainWindow()){
    /**
       Functionally equivalent to DB(storageName,'c','kvvfs') except
       that it throws if the given storage name is not one of 'local'
       or 'session'.
    */
    sqlite3.oo1.JsStorageDb = function(storageName='session'){
      if('session'!==storageName && 'local'!==storageName){
        toss3("JsStorageDb db name must be one of 'session' or 'local'.");
      }
      dbCtorHelper.call(this, {
        filename: storageName,
        flags: 'c',
        vfs: "kvvfs"
      });
    };
    const jdb = sqlite3.oo1.JsStorageDb;
    jdb.prototype = Object.create(DB.prototype);
    /** Equivalent to sqlite3_web_kvvfs_clear(). */
    jdb.clearStorage = capi.sqlite3_web_kvvfs_clear;
    /**
       Clears this database instance's storage or throws if this
       instance has been closed. Returns the number of
       database blocks which were cleaned up.
    */
    jdb.prototype.clearStorage = function(){
      return jdb.clearStorage(affirmDbOpen(this).filename);
    };
    /** Equivalent to sqlite3_web_kvvfs_size(). */
    jdb.storageSize = capi.sqlite3_web_kvvfs_size;
    /**
       Returns the _approximate_ number of bytes this database takes
       up in its storage or throws if this instance has been closed.
    */
    jdb.prototype.storageSize = function(){
      return jdb.storageSize(affirmDbOpen(this).filename);
    };







|

















|
|








|
|







11114
11115
11116
11117
11118
11119
11120
11121
11122
11123
11124
11125
11126
11127
11128
11129
11130
11131
11132
11133
11134
11135
11136
11137
11138
11139
11140
11141
11142
11143
11144
11145
11146
11147
11148
11149
11150
11151
11152
11153
11154
11155
11156
11157
      ooApi: "0.1"
    },
    DB,
    Stmt,
    dbCtorHelper
  }/*oo1 object*/;

  if(util.isUIThread()){
    /**
       Functionally equivalent to DB(storageName,'c','kvvfs') except
       that it throws if the given storage name is not one of 'local'
       or 'session'.
    */
    sqlite3.oo1.JsStorageDb = function(storageName='session'){
      if('session'!==storageName && 'local'!==storageName){
        toss3("JsStorageDb db name must be one of 'session' or 'local'.");
      }
      dbCtorHelper.call(this, {
        filename: storageName,
        flags: 'c',
        vfs: "kvvfs"
      });
    };
    const jdb = sqlite3.oo1.JsStorageDb;
    jdb.prototype = Object.create(DB.prototype);
    /** Equivalent to sqlite3_js_kvvfs_clear(). */
    jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
    /**
       Clears this database instance's storage or throws if this
       instance has been closed. Returns the number of
       database blocks which were cleaned up.
    */
    jdb.prototype.clearStorage = function(){
      return jdb.clearStorage(affirmDbOpen(this).filename);
    };
    /** Equivalent to sqlite3_js_kvvfs_size(). */
    jdb.storageSize = capi.sqlite3_js_kvvfs_size;
    /**
       Returns the _approximate_ number of bytes this database takes
       up in its storage or throws if this instance has been closed.
    */
    jdb.prototype.storageSize = function(){
      return jdb.storageSize(affirmDbOpen(this).filename);
    };
11143
11144
11145
11146
11147
11148
11149
11150
11151
11152
11153
11154
11155
11156
11157

      wasmfsOpfsEnabled: true if persistent storage is enabled in the
      current environment. Only files stored under wasmfsOpfsDir
      will persist using that mechanism, however. It is legal to use
      the non-WASMFS OPFS VFS to open a database via a URI-style
      db filename.

      vfsList: result of sqlite3.capi.sqlite3_web_vfs_list()
   }
  }
  ```


  ====================================================================
  "open" a database







|







11326
11327
11328
11329
11330
11331
11332
11333
11334
11335
11336
11337
11338
11339
11340

      wasmfsOpfsEnabled: true if persistent storage is enabled in the
      current environment. Only files stored under wasmfsOpfsDir
      will persist using that mechanism, however. It is legal to use
      the non-WASMFS OPFS VFS to open a database via a URI-style
      db filename.

      vfsList: result of sqlite3.capi.sqlite3_js_vfs_list()
   }
  }
  ```


  ====================================================================
  "open" a database
11201
11202
11203
11204
11205
11206
11207
11208
11209
11210
11211
11212


11213
11214
11215
11216
11217
11218
11219
11220
11221
  Message format:

  ```
  {
    type: "close",
    messageId: ...as above...
    dbId: ...as above...
    args: none
  }
  ```

  If the dbId does not refer to an opened ID, this is a no-op. The


  inability to close a db (because it's not opened) or delete its
  file does not trigger an error.

  Response:

  ```
  {
    type: "close",
    messageId: ...as above...,







|



|
>
>
|
|







11384
11385
11386
11387
11388
11389
11390
11391
11392
11393
11394
11395
11396
11397
11398
11399
11400
11401
11402
11403
11404
11405
11406
  Message format:

  ```
  {
    type: "close",
    messageId: ...as above...
    dbId: ...as above...
    args: OPTIONAL {unlink: boolean}
  }
  ```

  If the `dbId` does not refer to an opened ID, this is a no-op. If
  the `args` object contains a truthy `unlink` value then the database
  will be unlinked (deleted) after closing it. The inability to close a
  db (because it's not opened) or delete its file does not trigger an
  error.

  Response:

  ```
  {
    type: "close",
    messageId: ...as above...,
11340
11341
11342
11343
11344
11345
11346
11347

11348
11349
11350
11351
11352
11353
11354
11355
11356
11357
11358
11359
11360
11361
      this.dbs[getDbId(db)] = db;
      if(!this.defaultDb) this.defaultDb = db;
      return db;
    },
    close: function(db,alsoUnlink){
      if(db){
        delete this.dbs[getDbId(db)];
        const filename = db.getFilename();

        db.close();
        if(db===this.defaultDb) this.defaultDb = undefined;
        if(alsoUnlink && filename){
          /* This isn't necessarily correct: the db might be using a
             VFS other than the default. How do we best resolve this
             without having to special-case the opfs VFSes? */
          sqlite3.capi.wasm.sqlite3_wasm_vfs_unlink(filename);
        }
      }
    },
    /**
       Posts the given worker message value. If xferList is provided,
       it must be an array, in which case a copy of it passed as
       postMessage()'s second argument and xferList.length is set to







|
>


|
<
<
<
|







11525
11526
11527
11528
11529
11530
11531
11532
11533
11534
11535
11536



11537
11538
11539
11540
11541
11542
11543
11544
      this.dbs[getDbId(db)] = db;
      if(!this.defaultDb) this.defaultDb = db;
      return db;
    },
    close: function(db,alsoUnlink){
      if(db){
        delete this.dbs[getDbId(db)];
        const filename = db.filename;
        const pVfs = sqlite3.capi.wasm.sqlite3_wasm_db_vfs(db.pointer, 0);
        db.close();
        if(db===this.defaultDb) this.defaultDb = undefined;
        if(alsoUnlink && filename && pVfs){



          sqlite3.capi.wasm.sqlite3_wasm_vfs_unlink(pVfs, filename);
        }
      }
    },
    /**
       Posts the given worker message value. If xferList is provided,
       it must be an array, in which case a copy of it passed as
       postMessage()'s second argument and xferList.length is set to
11410
11411
11412
11413
11414
11415
11416
11417
11418
11419
11420
11421
11422
11423
11424
11425
11426
11427
11428
11429
11430
11431
11432
      if(args.simulateError){ // undocumented internal testing option
        toss("Throwing because of simulateError flag.");
      }
      const rc = Object.create(null);
      const pDir = sqlite3.capi.sqlite3_wasmfs_opfs_dir();
      if(!args.filename || ':memory:'===args.filename){
        oargs.filename = args.filename || '';
      }else if(pDir){
        oargs.filename = pDir + ('/'===args.filename[0] ? args.filename : ('/'+args.filename));
      }else{
        oargs.filename = args.filename;
      }
      const db = wState.open(oargs);
      rc.filename = db.filename;
      rc.persistent = (!!pDir && db.filename.startsWith(pDir))
        || sqlite3.capi.sqlite3_web_db_uses_vfs(db.pointer, "opfs");
      rc.dbId = getDbId(db);
      return rc;
    },

    close: function(ev){
      const db = getMsgDb(ev,false);
      const response = {







<
<





|
|







11593
11594
11595
11596
11597
11598
11599


11600
11601
11602
11603
11604
11605
11606
11607
11608
11609
11610
11611
11612
11613
      if(args.simulateError){ // undocumented internal testing option
        toss("Throwing because of simulateError flag.");
      }
      const rc = Object.create(null);
      const pDir = sqlite3.capi.sqlite3_wasmfs_opfs_dir();
      if(!args.filename || ':memory:'===args.filename){
        oargs.filename = args.filename || '';


      }else{
        oargs.filename = args.filename;
      }
      const db = wState.open(oargs);
      rc.filename = db.filename;
      rc.persistent = (!!pDir && db.filename.startsWith(pDir+'/'))
        || sqlite3.capi.sqlite3_js_db_uses_vfs(db.pointer, "opfs");
      rc.dbId = getDbId(db);
      return rc;
    },

    close: function(ev){
      const db = getMsgDb(ev,false);
      const response = {
11499
11500
11501
11502
11503
11504
11505
11506
11507
11508
11509
11510
11511
11512
11513
      [
        'wasmfsOpfsDir', 'bigIntEnabled'
      ].forEach(function(k){
        if(Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k];
      });
      rc.wasmfsOpfsEnabled = !!sqlite3.capi.sqlite3_wasmfs_opfs_dir();
      rc.version = sqlite3.version;
      rc.vfsList = sqlite3.capi.sqlite3_web_vfs_list();
      return rc;
    },

    /**
       TO(RE)DO, once we can abstract away access to the
       JS environment's virtual filesystem. Currently this
       always throws.







|







11680
11681
11682
11683
11684
11685
11686
11687
11688
11689
11690
11691
11692
11693
11694
      [
        'wasmfsOpfsDir', 'bigIntEnabled'
      ].forEach(function(k){
        if(Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k];
      });
      rc.wasmfsOpfsEnabled = !!sqlite3.capi.sqlite3_wasmfs_opfs_dir();
      rc.version = sqlite3.version;
      rc.vfsList = sqlite3.capi.sqlite3_js_vfs_list();
      return rc;
    },

    /**
       TO(RE)DO, once we can abstract away access to the
       JS environment's virtual filesystem. Currently this
       always throws.
11613
11614
11615
11616
11617
11618
11619
11620
11621
11622
11623
11624
11625
11626



11627
11628
11629
11630
11631
11632
11633
11634
  ***********************************************************************

  This file holds the synchronous half of an sqlite3_vfs
  implementation which proxies, in a synchronous fashion, the
  asynchronous Origin-Private FileSystem (OPFS) APIs using a second
  Worker, implemented in sqlite3-opfs-async-proxy.js.  This file is
  intended to be appended to the main sqlite3 JS deliverable somewhere
  after sqlite3-api-glue.js and before sqlite3-api-cleanup.js.
*/
'use strict';
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
   installOpfsVfs() returns a Promise which, on success, installs
   an sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs



   which accept a VFS. It uses the Origin-Private FileSystem API for
   all file storage. On error it is rejected with an exception
   explaining the problem. Reasons for rejection include, but are
   not limited to:

   - The counterpart Worker (see below) could not be loaded.

   - The environment does not support OPFS. That includes when







|




|
|
>
>
>
|







11794
11795
11796
11797
11798
11799
11800
11801
11802
11803
11804
11805
11806
11807
11808
11809
11810
11811
11812
11813
11814
11815
11816
11817
11818
  ***********************************************************************

  This file holds the synchronous half of an sqlite3_vfs
  implementation which proxies, in a synchronous fashion, the
  asynchronous Origin-Private FileSystem (OPFS) APIs using a second
  Worker, implemented in sqlite3-opfs-async-proxy.js.  This file is
  intended to be appended to the main sqlite3 JS deliverable somewhere
  after sqlite3-api-oo1.js and before sqlite3-api-cleanup.js.
*/
'use strict';
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
   installOpfsVfs() returns a Promise which, on success, installs an
   sqlite3_vfs named "opfs", suitable for use with all sqlite3 APIs
   which accept a VFS. It is intended to be called via
   sqlite3ApiBootstrap.initializersAsync or an equivalent mechanism.

   The installed VFS uses the Origin-Private FileSystem API for
   all file storage. On error it is rejected with an exception
   explaining the problem. Reasons for rejection include, but are
   not limited to:

   - The counterpart Worker (see below) could not be loaded.

   - The environment does not support OPFS. That includes when
11646
11647
11648
11649
11650
11651
11652
11653
11654
11655
11656
11657
11658
11659




11660
11661
11662
11663
11664
11665
11666
11667
11668
11669
11670
11671
11672
11673
11674
11675
11676
11677
11678
11679
11680
11681
11682
11683
11684
11685
11686
11687
11688

11689
11690
11691

11692
11693
11694
11695
11696
11697
11698

  - It requires the SharedArrayBuffer and Atomics classes, and the
    former is only available if the HTTP server emits the so-called
    COOP and COEP response headers. These features are required for
    proxying OPFS's synchronous API via the synchronous interface
    required by the sqlite3_vfs API.

  - This function may only be called a single time and it must be
    called from the client, as opposed to the library initialization,
    in case the client requires a custom path for this API's
    "counterpart": this function's argument is the relative URI to
    this module's "asynchronous half". When called, this function removes
    itself from the sqlite3 object.





   The argument may optionally be a plain object with the following
   configuration options:

   - proxyUri: as described above

   - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables
     logging of errors. 2 enables logging of warnings and errors. 3
     additionally enables debugging info.

   - sanityChecks (=false): if true, some basic sanity tests are
     run on the OPFS VFS API after it's initialized, before the
     returned Promise resolves.

   On success, the Promise resolves to the top-most sqlite3 namespace
   object and that object gets a new object installed in its
   `opfs` property, containing several OPFS-specific utilities.
*/
const installOpfsVfs = function callee(asyncProxyUri = callee.defaultProxyUri){
  if(!self.SharedArrayBuffer ||
     !self.Atomics ||
     !self.FileSystemHandle ||
     !self.FileSystemDirectoryHandle ||
     !self.FileSystemFileHandle ||
     !self.FileSystemFileHandle.prototype.createSyncAccessHandle ||
     !navigator.storage.getDirectory){
    return Promise.reject(
      new Error("This environment does not have OPFS support.")
    );
  }

  const options = (asyncProxyUri && 'object'===asyncProxyUri) ? asyncProxyUri : {
    proxyUri: asyncProxyUri
  };

  const urlParams = new URL(self.location.href).searchParams;
  if(undefined===options.verbose){
    options.verbose = urlParams.has('opfs-verbose') ? 3 : 2;
  }
  if(undefined===options.sanityChecks){
    options.sanityChecks = urlParams.has('opfs-sanity-check');
  }







|
<
<
<
<
|

>
>
>
>
|
|

|

|
|
|

|
|
|

|
|
|

|











>
|
<
<
>







11830
11831
11832
11833
11834
11835
11836
11837




11838
11839
11840
11841
11842
11843
11844
11845
11846
11847
11848
11849
11850
11851
11852
11853
11854
11855
11856
11857
11858
11859
11860
11861
11862
11863
11864
11865
11866
11867
11868
11869
11870
11871
11872
11873
11874


11875
11876
11877
11878
11879
11880
11881
11882

  - It requires the SharedArrayBuffer and Atomics classes, and the
    former is only available if the HTTP server emits the so-called
    COOP and COEP response headers. These features are required for
    proxying OPFS's synchronous API via the synchronous interface
    required by the sqlite3_vfs API.

  - This function may only be called a single time. When called, this




    function removes itself from the sqlite3 object.

  All arguments to this function are for internal/development purposes
  only. They do not constitute a public API and may change at any
  time.

  The argument may optionally be a plain object with the following
  configuration options:

  - proxyUri: as described above

  - verbose (=2): an integer 0-3. 0 disables all logging, 1 enables
    logging of errors. 2 enables logging of warnings and errors. 3
    additionally enables debugging info.

  - sanityChecks (=false): if true, some basic sanity tests are
    run on the OPFS VFS API after it's initialized, before the
    returned Promise resolves.

  On success, the Promise resolves to the top-most sqlite3 namespace
  object and that object gets a new object installed in its
  `opfs` property, containing several OPFS-specific utilities.
*/
const installOpfsVfs = function callee(options){
  if(!self.SharedArrayBuffer ||
     !self.Atomics ||
     !self.FileSystemHandle ||
     !self.FileSystemDirectoryHandle ||
     !self.FileSystemFileHandle ||
     !self.FileSystemFileHandle.prototype.createSyncAccessHandle ||
     !navigator.storage.getDirectory){
    return Promise.reject(
      new Error("This environment does not have OPFS support.")
    );
  }
  if(!options || 'object'!==typeof options){
    options = Object.create(null);


  }
  const urlParams = new URL(self.location.href).searchParams;
  if(undefined===options.verbose){
    options.verbose = urlParams.has('opfs-verbose') ? 3 : 2;
  }
  if(undefined===options.sanityChecks){
    options.sanityChecks = urlParams.has('opfs-sanity-check');
  }
11711
11712
11713
11714
11715
11716
11717
11718
11719
11720
11721
11722
11723
11724
11725
    };
    const logImpl = (level,...args)=>{
      if(options.verbose>level) loggers[level]("OPFS syncer:",...args);
    };
    const log =    (...args)=>logImpl(2, ...args);
    const warn =   (...args)=>logImpl(1, ...args);
    const error =  (...args)=>logImpl(0, ...args);
    //warn("The OPFS VFS feature is very much experimental and under construction.");
    const toss = function(...args){throw new Error(args.join(' '))};
    const capi = sqlite3.capi;
    const wasm = capi.wasm;
    const sqlite3_vfs = capi.sqlite3_vfs;
    const sqlite3_file = capi.sqlite3_file;
    const sqlite3_io_methods = capi.sqlite3_io_methods;
    /**







<







11895
11896
11897
11898
11899
11900
11901

11902
11903
11904
11905
11906
11907
11908
    };
    const logImpl = (level,...args)=>{
      if(options.verbose>level) loggers[level]("OPFS syncer:",...args);
    };
    const log =    (...args)=>logImpl(2, ...args);
    const warn =   (...args)=>logImpl(1, ...args);
    const error =  (...args)=>logImpl(0, ...args);

    const toss = function(...args){throw new Error(args.join(' '))};
    const capi = sqlite3.capi;
    const wasm = capi.wasm;
    const sqlite3_vfs = capi.sqlite3_vfs;
    const sqlite3_file = capi.sqlite3_file;
    const sqlite3_io_methods = capi.sqlite3_io_methods;
    /**
11756
11757
11758
11759
11760
11761
11762
11763
11764
11765
11766
11767
11768
11769
11770
11771
11772
          r(metrics[k] = Object.create(null));
        }
        let s = metrics.s11n = Object.create(null);
        s = s.serialize = Object.create(null);
        s.count = s.time = 0;
        s = metrics.s11n.deserialize = Object.create(null);
        s.count = s.time = 0;
        //[ // timed routines which are not in state.opIds
        //  'xFileControl'
        //].forEach((k)=>r(metrics[k] = Object.create(null)));
      }
    }/*metrics*/;      
    const promiseReject = function(err){
      opfsVfs.dispose();
      return promiseReject_(err);
    };
    const W = new Worker(options.proxyUri);







<
<
<







11939
11940
11941
11942
11943
11944
11945



11946
11947
11948
11949
11950
11951
11952
          r(metrics[k] = Object.create(null));
        }
        let s = metrics.s11n = Object.create(null);
        s = s.serialize = Object.create(null);
        s.count = s.time = 0;
        s = metrics.s11n.deserialize = Object.create(null);
        s.count = s.time = 0;



      }
    }/*metrics*/;      
    const promiseReject = function(err){
      opfsVfs.dispose();
      return promiseReject_(err);
    };
    const W = new Worker(options.proxyUri);
11821
11822
11823
11824
11825
11826
11827
11828



11829
11830
11831
11832
11833
11834
11835
11836
11837

11838
11839
11840
11841
11842
11843
11844
11845
11846
11847
11848
11849
11850
11851

11852
11853
11854
11855
11856
11857
11858
11859
11860
11861
11862
11863

11864
11865
11866
11867
11868
11869
11870
       Atomics.notify() on that slot.

       The approach of using a single SAB to serialize comms for all
       instances might(?) lead to deadlock situations in multi-db
       cases. We should probably have one SAB here with a single slot
       for locking a per-file initialization step and then allocate a
       separate SAB like the above one for each file. That will
       require a bit of acrobatics but should be feasible.



    */
    const state = Object.create(null);
    state.verbose = options.verbose;
    state.littleEndian = (()=>{
      const buffer = new ArrayBuffer(2);
      new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
      // Int16Array uses the platform's endianness.
      return new Int16Array(buffer)[0] === 256;
    })();

    /** Whether the async counterpart should log exceptions to
        the serialization channel. That produces a great deal of
        noise for seemingly innocuous things like xAccess() checks
        for missing files, so this option may have one of 3 values:

        0 = no exception logging

        1 = only log exceptions for "significant" ops like xOpen(),
        xRead(), and xWrite().

        2 = log all exceptions.
    */
    state.asyncS11nExceptions = 1;
    /* Size of file I/O buffer block. 64k = max sqlite3 page size. */

    state.fileBufferSize =
      1024 * 64;
    state.sabS11nOffset = state.fileBufferSize;
    /**
       The size of the block in our SAB for serializing arguments and
       result values. Needs to be large enough to hold serialized
       values of any of the proxied APIs. Filenames are the largest
       part but are limited to opfsVfs.$mxPathname bytes.
    */
    state.sabS11nSize = opfsVfs.$mxPathname * 2;
    /**
       The SAB used for all data I/O (files and arg/result s11n).

    */
    state.sabIO = new SharedArrayBuffer(
      state.fileBufferSize/* file i/o block */
      + state.sabS11nSize/* argument/result serialization block */
    );
    state.opIds = Object.create(null);
    const metrics = Object.create(null);







|
>
>
>





|



>
|
|
|
|

|

|
|

|


|
>
|
<









|
>







12001
12002
12003
12004
12005
12006
12007
12008
12009
12010
12011
12012
12013
12014
12015
12016
12017
12018
12019
12020
12021
12022
12023
12024
12025
12026
12027
12028
12029
12030
12031
12032
12033
12034
12035
12036
12037

12038
12039
12040
12041
12042
12043
12044
12045
12046
12047
12048
12049
12050
12051
12052
12053
12054
12055
       Atomics.notify() on that slot.

       The approach of using a single SAB to serialize comms for all
       instances might(?) lead to deadlock situations in multi-db
       cases. We should probably have one SAB here with a single slot
       for locking a per-file initialization step and then allocate a
       separate SAB like the above one for each file. That will
       require a bit of acrobatics but should be feasible. The most
       problematic part is that xOpen() would have to use
       postMessage() to communicate its SharedArrayBuffer, and mixing
       that approach with Atomics.wait/notify() gets a bit messy.
    */
    const state = Object.create(null);
    state.verbose = options.verbose;
    state.littleEndian = (()=>{
      const buffer = new ArrayBuffer(2);
      new DataView(buffer).setInt16(0, 256, true /* ==>littleEndian */);
      // Int16Array uses the platform's endianness.
      return new Int16Array(buffer)[0] === 256;
    })();
    /**
       Whether the async counterpart should log exceptions to
       the serialization channel. That produces a great deal of
       noise for seemingly innocuous things like xAccess() checks
       for missing files, so this option may have one of 3 values:

       0 = no exception logging

       1 = only log exceptions for "significant" ops like xOpen(),
       xRead(), and xWrite().

       2 = log all exceptions.
    */
    state.asyncS11nExceptions = 1;
    /* Size of file I/O buffer block. 64k = max sqlite3 page size, and
       xRead/xWrite() will never deal in blocks larger than that. */
    state.fileBufferSize = 1024 * 64;

    state.sabS11nOffset = state.fileBufferSize;
    /**
       The size of the block in our SAB for serializing arguments and
       result values. Needs to be large enough to hold serialized
       values of any of the proxied APIs. Filenames are the largest
       part but are limited to opfsVfs.$mxPathname bytes.
    */
    state.sabS11nSize = opfsVfs.$mxPathname * 2;
    /**
       The SAB used for all data I/O between the synchronous and
       async halves (file i/o and arg/result s11n).
    */
    state.sabIO = new SharedArrayBuffer(
      state.fileBufferSize/* file i/o block */
      + state.sabS11nSize/* argument/result serialization block */
    );
    state.opIds = Object.create(null);
    const metrics = Object.create(null);
11895
11896
11897
11898
11899
11900
11901




11902


11903
11904
11905
11906
11907
11908
11909
      state.opIds.xSync = i++;
      state.opIds.xTruncate = i++;
      state.opIds.xUnlock = i++;
      state.opIds.xWrite = i++;
      state.opIds.mkdir = i++;
      state.opIds['opfs-async-metrics'] = i++;
      state.opIds['opfs-async-shutdown'] = i++;




      state.sabOP = new SharedArrayBuffer(i * 4/*sizeof int32*/);


      opfsUtil.metrics.reset();
    }
    /**
       SQLITE_xxx constants to export to the async worker
       counterpart...
    */
    state.sq3Codes = Object.create(null);







>
>
>
>
|
>
>







12080
12081
12082
12083
12084
12085
12086
12087
12088
12089
12090
12091
12092
12093
12094
12095
12096
12097
12098
12099
12100
      state.opIds.xSync = i++;
      state.opIds.xTruncate = i++;
      state.opIds.xUnlock = i++;
      state.opIds.xWrite = i++;
      state.opIds.mkdir = i++;
      state.opIds['opfs-async-metrics'] = i++;
      state.opIds['opfs-async-shutdown'] = i++;
      /* The retry slot is used by the async part for wait-and-retry
         semantics. Though we could hypothetically use the xSleep slot
         for that, doing so might lead to undesired side effects. */
      state.opIds.retry = i++;
      state.sabOP = new SharedArrayBuffer(
        i * 4/* ==sizeof int32, noting that Atomics.wait() and friends
                can only function on Int32Array views of an SAB. */);
      opfsUtil.metrics.reset();
    }
    /**
       SQLITE_xxx constants to export to the async worker
       counterpart...
    */
    state.sq3Codes = Object.create(null);
11936
11937
11938
11939
11940
11941
11942
11943

11944
11945


11946
11947
11948
11949
11950
11951
11952
11953
11954
11955
11956

11957
11958


11959
11960
11961
11962
11963
11964
11965
11966
11967


11968
11969
11970
11971
11972
11973
11974
       async op.
    */
    const opRun = (op,...args)=>{
      const opNdx = state.opIds[op] || toss("Invalid op ID:",op);
      state.s11n.serialize(...args);
      Atomics.store(state.sabOPView, state.opIds.rc, -1);
      Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx);
      Atomics.notify(state.sabOPView, state.opIds.whichOp) /* async thread will take over here */;

      const t = performance.now();
      Atomics.wait(state.sabOPView, state.opIds.rc, -1);


      const rc = Atomics.load(state.sabOPView, state.opIds.rc);
      metrics[op].wait += performance.now() - t;
      if(rc && state.asyncS11nExceptions){
        const err = state.s11n.deserialize();
        if(err) error(op+"() async error:",...err);
      }
      return rc;
    };

    const initS11n = ()=>{
      /**

         ACHTUNG: this code is 100% duplicated in the other half of this
         proxy! The documentation is maintained in the "synchronous half".



         This proxy de/serializes cross-thread function arguments and
         output-pointer values via the state.sabIO SharedArrayBuffer,
         using the region defined by (state.sabS11nOffset,
         state.sabS11nOffset]. Only one dataset is recorded at a time.

         This is not a general-purpose format. It only supports the range
         of operations, and data sizes, needed by the sqlite3_vfs and
         sqlite3_io_methods operations.



         The data format can be succinctly summarized as:

         Nt...Td...D

         Where:








|
>

|
>
>











>
|
|
>
>






|
|
|
>
>







12127
12128
12129
12130
12131
12132
12133
12134
12135
12136
12137
12138
12139
12140
12141
12142
12143
12144
12145
12146
12147
12148
12149
12150
12151
12152
12153
12154
12155
12156
12157
12158
12159
12160
12161
12162
12163
12164
12165
12166
12167
12168
12169
12170
12171
12172
12173
       async op.
    */
    const opRun = (op,...args)=>{
      const opNdx = state.opIds[op] || toss("Invalid op ID:",op);
      state.s11n.serialize(...args);
      Atomics.store(state.sabOPView, state.opIds.rc, -1);
      Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx);
      Atomics.notify(state.sabOPView, state.opIds.whichOp)
      /* async thread will take over here */;
      const t = performance.now();
      Atomics.wait(state.sabOPView, state.opIds.rc, -1)
      /* When this wait() call returns, the async half will have
         completed the operation and reported its results. */;
      const rc = Atomics.load(state.sabOPView, state.opIds.rc);
      metrics[op].wait += performance.now() - t;
      if(rc && state.asyncS11nExceptions){
        const err = state.s11n.deserialize();
        if(err) error(op+"() async error:",...err);
      }
      return rc;
    };

    const initS11n = ()=>{
      /**
         !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
         ACHTUNG: this code is 100% duplicated in the other half of
         this proxy! The documentation is maintained in the
         "synchronous half".
         !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

         This proxy de/serializes cross-thread function arguments and
         output-pointer values via the state.sabIO SharedArrayBuffer,
         using the region defined by (state.sabS11nOffset,
         state.sabS11nOffset]. Only one dataset is recorded at a time.

         This is not a general-purpose format. It only supports the
         range of operations, and data sizes, needed by the
         sqlite3_vfs and sqlite3_io_methods operations. Serialized
         data are transient and this serialization algorithm may
         change at any time.

         The data format can be succinctly summarized as:

         Nt...Td...D

         Where:

11984
11985
11986
11987
11988
11989
11990
11991

11992
11993
11994
11995
11996
11997
11998
         - ...D = raw bytes of the 2nd and subsequent arguments (per-type
         size).

         All types except strings have fixed sizes. Strings are stored
         using their TextEncoder/TextDecoder representations. It would
         arguably make more sense to store them as Int16Arrays of
         their JS character values, but how best/fastest to get that
         in and out of string form us an open point.


         Historical note: this impl was initially about 1% this size by
         using using JSON.stringify/parse(), but using fit-to-purpose
         serialization saves considerable runtime.
      */
      if(state.s11n) return state.s11n;
      const textDecoder = new TextDecoder(),







|
>







12183
12184
12185
12186
12187
12188
12189
12190
12191
12192
12193
12194
12195
12196
12197
12198
         - ...D = raw bytes of the 2nd and subsequent arguments (per-type
         size).

         All types except strings have fixed sizes. Strings are stored
         using their TextEncoder/TextDecoder representations. It would
         arguably make more sense to store them as Int16Arrays of
         their JS character values, but how best/fastest to get that
         in and out of string form is an open point. Initial
         experimentation with that approach did not gain us any speed.

         Historical note: this impl was initially about 1% this size by
         using using JSON.stringify/parse(), but using fit-to-purpose
         serialization saves considerable runtime.
      */
      if(state.s11n) return state.s11n;
      const textDecoder = new TextDecoder(),
12181
12182
12183
12184
12185
12186
12187
12188
12189
12190



12191
12192
12193
12194
12195
12196
12197
12198
12199
12200
12201
12202
12203
12204
12205
12206
12207
12208
12209
12210
12211
12212
12213
12214
12215
12216
12217
12218
12219
12220
12221
12222
12223

12224
12225







12226
12227
12228
12229
12230
12231
12232
        };
      }/*static init*/
      const sigN = tgt.memberSignature(name);
      if(sigN.length<2){
        toss("Member",name," is not a function pointer. Signature =",sigN);
      }
      const memKey = tgt.memberKey(name);
      //log("installMethod",tgt, name, sigN);
      const fProxy = 0
      // We can remove this proxy middle-man once the VFS is working



            ? callee.argcProxy(func, sigN)
            : func;
      const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
      tgt[memKey] = pFunc;
      if(!tgt.ondispose) tgt.ondispose = [];
      if(!tgt.ondispose.__removeFuncList){
        tgt.ondispose.push('ondispose.__removeFuncList handler',
                           callee.removeFuncList);
        tgt.ondispose.__removeFuncList = [];
      }
      tgt.ondispose.__removeFuncList.push(memKey, pFunc);
      return (n,f)=>callee(tgt, n, f);
    }/*installMethod*/;

    const opTimer = Object.create(null);
    opTimer.op = undefined;
    opTimer.start = undefined;
    const mTimeStart = (op)=>{
      opTimer.start = performance.now();
      opTimer.op = op;
      //metrics[op] || toss("Maintenance required: missing metrics for",op);
      ++metrics[op].count;
    };
    const mTimeEnd = ()=>(
      metrics[opTimer.op].time += performance.now() - opTimer.start
    );

    /**
       Impls for the sqlite3_io_methods methods. Maintenance reminder:
       members are in alphabetical order to simplify finding them.
    */
    const ioSyncWrappers = {
      xCheckReservedLock: function(pFile,pOut){

        // Exclusive lock is automatically acquired when opened
        //warn("xCheckReservedLock(",arguments,") is a no-op");







        const f = __openFiles[pFile];
        wasm.setMemValue(pOut, f.lockMode ? 1 : 0, 'i32');
        return 0;
      },
      xClose: function(pFile){
        mTimeStart('xClose');
        let rc = 0;







<

|
>
>
>




















<












>
|
<
>
>
>
>
>
>
>







12381
12382
12383
12384
12385
12386
12387

12388
12389
12390
12391
12392
12393
12394
12395
12396
12397
12398
12399
12400
12401
12402
12403
12404
12405
12406
12407
12408
12409
12410
12411
12412

12413
12414
12415
12416
12417
12418
12419
12420
12421
12422
12423
12424
12425
12426

12427
12428
12429
12430
12431
12432
12433
12434
12435
12436
12437
12438
12439
12440
        };
      }/*static init*/
      const sigN = tgt.memberSignature(name);
      if(sigN.length<2){
        toss("Member",name," is not a function pointer. Signature =",sigN);
      }
      const memKey = tgt.memberKey(name);

      const fProxy = 0
      /** This middle-man proxy is only for use during development, to
          confirm that we always pass the proper number of
          arguments. We know that the C-level code will always use the
          correct argument count. */
            ? callee.argcProxy(func, sigN)
            : func;
      const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
      tgt[memKey] = pFunc;
      if(!tgt.ondispose) tgt.ondispose = [];
      if(!tgt.ondispose.__removeFuncList){
        tgt.ondispose.push('ondispose.__removeFuncList handler',
                           callee.removeFuncList);
        tgt.ondispose.__removeFuncList = [];
      }
      tgt.ondispose.__removeFuncList.push(memKey, pFunc);
      return (n,f)=>callee(tgt, n, f);
    }/*installMethod*/;

    const opTimer = Object.create(null);
    opTimer.op = undefined;
    opTimer.start = undefined;
    const mTimeStart = (op)=>{
      opTimer.start = performance.now();
      opTimer.op = op;

      ++metrics[op].count;
    };
    const mTimeEnd = ()=>(
      metrics[opTimer.op].time += performance.now() - opTimer.start
    );

    /**
       Impls for the sqlite3_io_methods methods. Maintenance reminder:
       members are in alphabetical order to simplify finding them.
    */
    const ioSyncWrappers = {
      xCheckReservedLock: function(pFile,pOut){
        /**
           As of late 2022, only a single lock can be held on an OPFS

           file. We have no way of checking whether any _other_ db
           connection has a lock except by trying to obtain and (on
           success) release a sync-handle for it, but doing so would
           involve an inherent race condition. For the time being,
           pending a better solution, we simply report whether the
           given pFile instance has a lock.
        */
        const f = __openFiles[pFile];
        wasm.setMemValue(pOut, f.lockMode ? 1 : 0, 'i32');
        return 0;
      },
      xClose: function(pFile){
        mTimeStart('xClose');
        let rc = 0;
12271
12272
12273
12274
12275
12276
12277
12278
12279
12280
12281
12282
12283
12284




12285
12286
12287
12288
12289
12290
12291
12292
        }else{
          f.lockType = lockType;
        }
        mTimeEnd();
        return rc;
      },
      xRead: function(pFile,pDest,n,offset64){
        /* int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst) */
        mTimeStart('xRead');
        const f = __openFiles[pFile];
        let rc;
        try {
          rc = opRun('xRead',pFile, n, Number(offset64));
          if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){




            // set() seems to be the fastest way to copy this...
            wasm.heap8u().set(f.sabView.subarray(0, n), pDest);
          }
        }catch(e){
          error("xRead(",arguments,") failed:",e,f);
          rc = capi.SQLITE_IOERR_READ;
        }
        mTimeEnd();







<





|
>
>
>
>
|







12479
12480
12481
12482
12483
12484
12485

12486
12487
12488
12489
12490
12491
12492
12493
12494
12495
12496
12497
12498
12499
12500
12501
12502
12503
        }else{
          f.lockType = lockType;
        }
        mTimeEnd();
        return rc;
      },
      xRead: function(pFile,pDest,n,offset64){

        mTimeStart('xRead');
        const f = __openFiles[pFile];
        let rc;
        try {
          rc = opRun('xRead',pFile, n, Number(offset64));
          if(0===rc || capi.SQLITE_IOERR_SHORT_READ===rc){ 
            /**
               Results get written to the SharedArrayBuffer f.sabView.
               Because the heap is _not_ a SharedArrayBuffer, we have
               to copy the results. TypedArray.set() seems to be the
               fastest way to copy this. */
            wasm.heap8u().set(f.sabView.subarray(0, n), pDest);
          }
        }catch(e){
          error("xRead(",arguments,") failed:",e,f);
          rc = capi.SQLITE_IOERR_READ;
        }
        mTimeEnd();
12311
12312
12313
12314
12315
12316
12317
12318
12319
12320
12321
12322
12323
12324
12325
          rc = opRun('xUnlock', pFile, lockType);
        }
        if( 0===rc ) f.lockType = lockType;
        mTimeEnd();
        return rc;
      },
      xWrite: function(pFile,pSrc,n,offset64){
        /* int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst) */
        mTimeStart('xWrite');
        const f = __openFiles[pFile];
        let rc;
        try {
          f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc+n));
          rc = opRun('xWrite', pFile, n, Number(offset64));
        }catch(e){







<







12522
12523
12524
12525
12526
12527
12528

12529
12530
12531
12532
12533
12534
12535
          rc = opRun('xUnlock', pFile, lockType);
        }
        if( 0===rc ) f.lockType = lockType;
        mTimeEnd();
        return rc;
      },
      xWrite: function(pFile,pSrc,n,offset64){

        mTimeStart('xWrite');
        const f = __openFiles[pFile];
        let rc;
        try {
          f.sabView.set(wasm.heap8u().subarray(pSrc, pSrc+n));
          rc = opRun('xWrite', pFile, n, Number(offset64));
        }catch(e){
12377
12378
12379
12380
12381
12382
12383
12384
12385
12386
12387
12388
12389
12390
12391
12392
12393
12394
12395
12396
12397
12398
12399
12400
12401
12402
12403
12404
12405
12406
12407
12408
12409
12410
12411
12412
           to encode them... TextEncoder can do that for us. */
        warn("OPFS xGetLastError() has nothing sensible to return.");
        return 0;
      },
      //xSleep is optionally defined below
      xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
        mTimeStart('xOpen');
        if(!f._){
          f._ = {
            fileTypes: {
              SQLITE_OPEN_MAIN_DB: 'mainDb',
              SQLITE_OPEN_MAIN_JOURNAL: 'mainJournal',
              SQLITE_OPEN_TEMP_DB: 'tempDb',
              SQLITE_OPEN_TEMP_JOURNAL: 'tempJournal',
              SQLITE_OPEN_TRANSIENT_DB: 'transientDb',
              SQLITE_OPEN_SUBJOURNAL: 'subjournal',
              SQLITE_OPEN_SUPER_JOURNAL: 'superJournal',
              SQLITE_OPEN_WAL: 'wal'
            },
            getFileType: function(filename,oflags){
              const ft = f._.fileTypes;
              for(let k of Object.keys(ft)){
                if(oflags & capi[k]) return ft[k];
              }
              warn("Cannot determine fileType based on xOpen() flags for file",filename);
              return '???';
            }
          };
        }
        if(0===zName){
          zName = randomFilename();
        }else if('number'===typeof zName){
          zName = wasm.cstringToJs(zName);
        }
        const fh = Object.create(null);
        fh.fid = pFile;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







12587
12588
12589
12590
12591
12592
12593






















12594
12595
12596
12597
12598
12599
12600
           to encode them... TextEncoder can do that for us. */
        warn("OPFS xGetLastError() has nothing sensible to return.");
        return 0;
      },
      //xSleep is optionally defined below
      xOpen: function f(pVfs, zName, pFile, flags, pOutFlags){
        mTimeStart('xOpen');






















        if(0===zName){
          zName = randomFilename();
        }else if('number'===typeof zName){
          zName = wasm.cstringToJs(zName);
        }
        const fh = Object.create(null);
        fh.fid = pFile;
12682
12683
12684
12685
12686
12687
12688
12689
12690
12691
12692
12693
12694
12695
12696
12697
12698
12699
12700
12701
12702
12703
12704
12705
            }
            break;
          }
          default:
            promiseReject(e);
            error("Unexpected message from the async worker:",data);
            break;
      }
    };

  })/*thePromise*/;
  return thePromise;
}/*installOpfsVfs()*/;
installOpfsVfs.defaultProxyUri =
    //self.location.pathname.replace(/[^/]*$/, "sqlite3-opfs-async-proxy.js");
  "sqlite3-opfs-async-proxy.js";
//console.warn("sqlite3.installOpfsVfs.defaultProxyUri =",sqlite3.installOpfsVfs.defaultProxyUri);
self.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
  if(sqlite3.scriptInfo && !sqlite3.scriptInfo.isWorker){
    return;
  }
  try{
    let proxyJs = installOpfsVfs.defaultProxyUri;
    if(sqlite3.scriptInfo.sqlite3Dir){







|
<
|




<

<







12870
12871
12872
12873
12874
12875
12876
12877

12878
12879
12880
12881
12882

12883

12884
12885
12886
12887
12888
12889
12890
            }
            break;
          }
          default:
            promiseReject(e);
            error("Unexpected message from the async worker:",data);
            break;
      }/*switch(data.type)*/

    }/*W.onmessage()*/;
  })/*thePromise*/;
  return thePromise;
}/*installOpfsVfs()*/;
installOpfsVfs.defaultProxyUri =

  "sqlite3-opfs-async-proxy.js";

self.sqlite3ApiBootstrap.initializersAsync.push(async (sqlite3)=>{
  if(sqlite3.scriptInfo && !sqlite3.scriptInfo.isWorker){
    return;
  }
  try{
    let proxyJs = installOpfsVfs.defaultProxyUri;
    if(sqlite3.scriptInfo.sqlite3Dir){
12805
12806
12807
12808
12809
12810
12811
12812
12813



12814
12815
12816
12817
12818
12819
12820
if (typeof exports === 'object' && typeof module === 'object')
  module.exports = sqlite3InitModule;
else if (typeof define === 'function' && define['amd'])
  define([], function() { return sqlite3InitModule; });
else if (typeof exports === 'object')
  exports["sqlite3InitModule"] = sqlite3InitModule;
/* extern-post-js.js must be appended to the resulting sqlite3.js
   file. It gets its name from being used as the value for
   the --extern-post-js=... Emscripten flag. */



(function(){
  /**
     In order to hide the sqlite3InitModule()'s resulting Emscripten
     module from downstream clients (and simplify our documentation by
     being able to elide those details), we rewrite
     sqlite3InitModule() to return the sqlite3 object.








|
|
>
>
>







12990
12991
12992
12993
12994
12995
12996
12997
12998
12999
13000
13001
13002
13003
13004
13005
13006
13007
13008
if (typeof exports === 'object' && typeof module === 'object')
  module.exports = sqlite3InitModule;
else if (typeof define === 'function' && define['amd'])
  define([], function() { return sqlite3InitModule; });
else if (typeof exports === 'object')
  exports["sqlite3InitModule"] = sqlite3InitModule;
/* extern-post-js.js must be appended to the resulting sqlite3.js
   file. It gets its name from being used as the value for the
   --extern-post-js=... Emscripten flag. Note that this code, unlike
   most of the associated JS code, runs outside of the
   Emscripten-generated module init scope, in the current
   global scope. */
(function(){
  /**
     In order to hide the sqlite3InitModule()'s resulting Emscripten
     module from downstream clients (and simplify our documentation by
     being able to elide those details), we rewrite
     sqlite3InitModule() to return the sqlite3 object.

12829
12830
12831
12832
12833
12834
12835
12836
12837
12838
12839
12840
12841
12842
12843
12844
12845
12846
12847
12848





12849
12850
12851
12852
12853
12854
12855
  /**
     We need to add some state which our custom Module.locateFile()
     can see, but an Emscripten limitation currently prevents us from
     attaching it to the sqlite3InitModule function object:

     https://github.com/emscripten-core/emscripten/issues/18071

     The only current workaround is to temporarily stash this state
     into the global scope and delete it when sqlite3InitModule()
     is called.
  */
  const initModuleState = self.sqlite3InitModuleState = Object.assign(Object.create(null),{
    moduleScript: self?.document?.currentScript,
    isWorker: (!self.document && self.window !== self),
    location: self.location,
    urlParams: new URL(self.location.href).searchParams
  });
  if(initModuleState.urlParams.has('sqlite3.dir')){
    initModuleState.sqlite3Dir = initModuleState.urlParams.get('sqlite3.dir') +'/';
  };






  self.sqlite3InitModule = (...args)=>{
    //console.warn("Using replaced sqlite3InitModule()",self.location);
    return originalInit(...args).then((EmscriptenModule)=>{
      if(self.window!==self &&
         (EmscriptenModule['ENVIRONMENT_IS_PTHREAD']
          || EmscriptenModule['_pthread_self']







|





|





|
>
>
>
>
>







13017
13018
13019
13020
13021
13022
13023
13024
13025
13026
13027
13028
13029
13030
13031
13032
13033
13034
13035
13036
13037
13038
13039
13040
13041
13042
13043
13044
13045
13046
13047
13048
  /**
     We need to add some state which our custom Module.locateFile()
     can see, but an Emscripten limitation currently prevents us from
     attaching it to the sqlite3InitModule function object:

     https://github.com/emscripten-core/emscripten/issues/18071

     The only(?) current workaround is to temporarily stash this state
     into the global scope and delete it when sqlite3InitModule()
     is called.
  */
  const initModuleState = self.sqlite3InitModuleState = Object.assign(Object.create(null),{
    moduleScript: self?.document?.currentScript,
    isWorker: ('undefined' !== typeof WorkerGlobalScope),
    location: self.location,
    urlParams: new URL(self.location.href).searchParams
  });
  if(initModuleState.urlParams.has('sqlite3.dir')){
    initModuleState.sqlite3Dir = initModuleState.urlParams.get('sqlite3.dir') +'/';
  }else if(initModuleState.moduleScript){
    const li = initModuleState.moduleScript.src.split('/');
    li.pop();
    initModuleState.sqlite3Dir = li.join('/') + '/';
  }
  //console.warn("initModuleState =",initModuleState);

  self.sqlite3InitModule = (...args)=>{
    //console.warn("Using replaced sqlite3InitModule()",self.location);
    return originalInit(...args).then((EmscriptenModule)=>{
      if(self.window!==self &&
         (EmscriptenModule['ENVIRONMENT_IS_PTHREAD']
          || EmscriptenModule['_pthread_self']
12885
12886
12887
12888
12889
12890
12891








12892
    console.warn("Replaced sqlite3InitModule()");
    console.warn("self.location.href =",self.location.href);
    if('undefined' !== typeof document){
      console.warn("document.currentScript.src =",
                   document?.currentScript?.src);
    }
  }








})();







>
>
>
>
>
>
>
>

13078
13079
13080
13081
13082
13083
13084
13085
13086
13087
13088
13089
13090
13091
13092
13093
    console.warn("Replaced sqlite3InitModule()");
    console.warn("self.location.href =",self.location.href);
    if('undefined' !== typeof document){
      console.warn("document.currentScript.src =",
                   document?.currentScript?.src);
    }
  }
  /* Replace the various module exports performed by the Emscripten
     glue... */
  if (typeof exports === 'object' && typeof module === 'object')
    module.exports = sqlite3InitModule;
  else if (typeof exports === 'object')
    exports["sqlite3InitModule"] = sqlite3InitModule;
  /* AMD modules get injected in a way we cannot override,
     so we can't handle those here. */
})();

Changes to jswasm/sqlite3.wasm.

cannot compute difference between binary files