+_sqlite3_aggregate_context
_sqlite3_bind_blob
_sqlite3_bind_double
_sqlite3_bind_int
_sqlite3_result_error_nomem
_sqlite3_result_error_toobig
_sqlite3_result_int
+_sqlite3_result_int64
_sqlite3_result_null
_sqlite3_result_text
_sqlite3_serialize
_sqlite3_uri_int64
_sqlite3_uri_key
_sqlite3_uri_parameter
+_sqlite3_user_data
_sqlite3_value_blob
_sqlite3_value_bytes
_sqlite3_value_double
+_sqlite3_value_int
+_sqlite3_value_int64
_sqlite3_value_text
_sqlite3_value_type
_sqlite3_vfs_find
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
'use strict';
const toss = (...args)=>{throw new Error(args.join(' '))};
+ const toss3 = sqlite3.SQLite3Error.toss;
const capi = sqlite3.capi, wasm = capi.wasm, util = capi.util;
self.WhWasmUtilInstaller(capi.wasm);
delete self.WhWasmUtilInstaller;
`sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
*/
const aPtr = wasm.xWrap.argAdapter('*');
- wasm.xWrap.argAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr);
- wasm.xWrap.resultAdapter('sqlite3*', aPtr)('sqlite3_stmt*', aPtr);
+ 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
"*"/*xStep*/,"*"/*xFinal*/, "*"/*xValue*/,
"*"/*xInverse*/, "*"/*xDestroy*/]
);
- const __setResult = function(pCx, val){
+
+ const __setUdfResult = function(pCtx, val){
+ //console.warn("setUdfResult",typeof val, val);
switch(typeof val) {
case 'boolean':
- capi.sqlite3_result_int(pCx, val ? 1 : 0);
+ 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.");
+ }else if(util.bigIntFits32(val)){
+ capi.sqlite3_result_int(pCtx, Number(val));
+ }else if(util.bigIntFitsDouble(val)){
+ capi.sqlite3_result_double(pCtx, Number(val));
+ }else{
+ toss3("BigInt value",val.toString(),"is too BigInt.");
+ }
break;
case 'number': {
(util.isInt32(val)
? capi.sqlite3_result_int
- : capi.sqlite3_result_double)(pCx, val);
+ : capi.sqlite3_result_double)(pCtx, val);
break;
}
case 'string':
- capi.sqlite3_result_text(pCx, val, -1, capi.SQLITE_TRANSIENT);
+ capi.sqlite3_result_text(pCtx, val, -1, capi.SQLITE_TRANSIENT);
break;
case 'object':
if(null===val/*yes, typeof null === 'object'*/) {
- capi.sqlite3_result_null(pCx);
+ capi.sqlite3_result_null(pCtx);
break;
}else if(util.isBindableTypedArray(val)){
const pBlob = wasm.allocFromTypedArray(val);
capi.sqlite3_result_blob(
- pCx, pBlob, val.byteLength,
+ pCtx, pBlob, val.byteLength,
wasm.exports[sqlite3.config.deallocExportName]
);
break;
}
// else fall through
default:
- toss3("Don't not how to handle this UDF result value:",val);
+ toss3("Don't not how to handle this UDF result value:",(typeof val), val);
};
- }/*__setResult()*/;
- const __extractArgs = function(argc, pArgv){
+ }/*__setUdfResult()*/;
+
+ const __convertUdfArgs = function(argc, pArgv){
let i, pVal, valType, arg;
const tgt = [];
for(i = 0; i < argc; ++i){
valType = capi.sqlite3_value_type(pVal);
switch(valType){
case capi.SQLITE_INTEGER:
+ if(wasm.bigIntEnabled){
+ arg = capi.sqlite3_value_int64(pVal);
+ if(util.bigIntFitsDouble(arg)) arg = Number(arg);
+ }
+ else arg = capi.sqlite3_value_double(pVal)/*yes, double, for larger integers*/;
+ break;
case capi.SQLITE_FLOAT:
arg = capi.sqlite3_value_double(pVal);
break;
case capi.SQLITE_BLOB:{
const n = capi.sqlite3_value_bytes(pVal);
const pBlob = capi.sqlite3_value_blob(pVal);
- arg = new Uint8Array(n);
- let i;
- const heap = n ? wasm.heap8() : false;
- for(i = 0; i < n; ++i) arg[i] = heap[pBlob+i];
+ if(n && !pBlob) sqlite3.WasmAllocError.toss(
+ "Cannot allocate memory for blob argument of",n,"byte(s)"
+ );
+ arg = n ? wasm.heap8u().slice(pBlob, pBlob + Number(n)) : null;
break;
}
case capi.SQLITE_NULL:
tgt.push(arg);
}
return tgt;
- }/*__extractArgs()*/;
+ }/*__convertUdfArgs()*/;
- const __setCxErr = (pCx, e)=>{
- if(e instanceof capi.WasmAllocError){
- capi.sqlite3_result_error_nomem(pCx);
+ const __setUdfError = (pCtx, e)=>{
+ if(e instanceof sqlite3.WasmAllocError){
+ capi.sqlite3_result_error_nomem(pCtx);
}else{
- capi.sqlite3_result_error(pCx, e.message, -1);
+ capi.sqlite3_result_error(pCtx, e.message, -1);
}
};
- /* TODO: pass on the pCx pointer to all callbacks. This requires
- fixing test code and updating oodles of docs. Once that is in place,
- export sqlite3_aggregate_context().
- */
-
const __xFunc = function(callback){
- return function(pCx, argc, pArgv){
- try{ __setResult(pCx, callback(...__extractArgs(argc, pArgv))) }
- catch(e){ __setCxErr(pCx, e) }
+ return function(pCtx, argc, pArgv){
+ try{ __setUdfResult(pCtx, callback(pCtx, ...__convertUdfArgs(argc, pArgv))) }
+ catch(e){
+ //console.error('xFunc() caught:',e);
+ __setUdfError(pCtx, e);
+ }
};
};
const __xInverseAndStep = function(callback){
- return function(pCx, argc, pArgv){
- try{ callback(...__extractArgs(argc, pArgv)) }
- catch(e){ __setCxErr(pCx, e) }
+ return function(pCtx, argc, pArgv){
+ try{ callback(pCtx, ...__convertUdfArgs(argc, pArgv)) }
+ catch(e){ __setUdfError(pCtx, e) }
};
};
const __xFinalAndValue = function(callback){
- return function(pCx){
- try{ __setResult(pCx, callback()) }
- catch(e){ __setCxErr(pCx, e) }
+ return function(pCtx){
+ try{ __setUdfResult(pCtx, callback(pCtx)) }
+ catch(e){ __setUdfError(pCtx, e) }
};
};
}
return rc;
};
+ /**
+ A helper for UDFs implemented in JS and bound to WASM by the
+ client. Given a JS value, setUdfResult(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.setUdfResult =
+ capi.sqlite3_create_function.setUdfResult =
+ capi.sqlite3_create_window_function.setUdfResult = __setUdfResult;
+
+ /**
+ A helper for UDFs implemented in JS and bound to WASM by the
+ client. When passed the
+ (argc,argv) values from the UDF-related functions which receive
+ them (xFunc, xStep, xInverse), it creates a JS array
+ representing those arguments, converting each to JS in a manner
+ appropriate to its data type: numeric, text, blob
+ (Uint8Array()), or null.
+
+ Results are undefined if it's passed anything other than those
+ two arguments from those specific contexts.
+
+ Thus an argc of 4 will result in a length-4 array containing
+ the converted values from the corresponding argv.
+
+ The conversion will throw only on allocation error or an internal
+ error.
+ */
+ capi.sqlite3_create_function_v2.convertUdfArgs =
+ capi.sqlite3_create_function.convertUdfArgs =
+ capi.sqlite3_create_window_function.convertUdfArgs = __convertUdfArgs;
+
+ /**
+ 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.setUdfError =
+ capi.sqlite3_create_function.setUdfError =
+ capi.sqlite3_create_window_function.setUdfError = __setUdfError;
}/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;
the function is defined:
- .arity: the number of arguments which SQL calls to this
- function expect or require. The default value is the
- callback's length property (i.e. the number of declared
- parameters it has). A value of -1 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.
+ function expect or require. The default value is
+ `callback.length` (i.e. the number of declared parameters it
+ has) **MINUS 1** (see below for why). As a special case, if
+ callback.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:
name = name.toLowerCase();
DB.checkRc(this, capi.sqlite3_create_function_v2(
this.pointer, name,
- (opt.hasOwnProperty('arity') ? +opt.arity : callback.length),
+ (opt.hasOwnProperty('arity')
+ ? +opt.arity
+ : (callback.length ? callback.length-1/*for pCtx arg*/ : 0)),
capi.SQLITE_UTF8 | fFlags, null/*pApp*/, callback,
null/*xStep*/, null/*xFinal*/, null/*xDestroy*/));
return this;
const bindOne = function f(stmt,ndx,bindType,val){
affirmUnlocked(stmt, 'bind()');
if(!f._){
- if(wasm.bigIntEnabled){
- f._maxInt = BigInt("0x7fffffffffffffff");
- f._minInt = ~f._maxInt;
- }
+ f._tooBigInt = (v)=>toss3(
+ "BigInt value is too big to store without precision loss:", v
+ );
/* Reminder: when not in BigInt mode, it's impossible for
JS to represent a number out of the range we can bind,
so we have no range checking. */
let m;
if(util.isInt32(val)) m = capi.sqlite3_bind_int;
else if('bigint'===typeof val){
- if(val<f._minInt || val>f._maxInt){
- toss3("BigInt value is out of range for storing as int64: "+val);
+ if(!util.bigIntFits64(val)){
+ f._tooBigInt(val);
}else if(wasm.bigIntEnabled){
m = capi.sqlite3_bind_int64;
- }else if(val >= Number.MIN_SAFE_INTEGER && val <= Number.MAX_SAFE_INTEGER){
+ }else if(util.bigIntFitsDouble(val)){
val = Number(val);
m = capi.sqlite3_bind_double;
}else{
- toss3("BigInt value is out of range for storing as double: "+val);
+ f._tooBigInt(val);
}
}else{ // !int32, !bigint
val = Number(val);
case capi.SQLITE_ROW: return this._mayGet = true;
default:
this._mayGet = false;
- console.warn("sqlite3_step() rc=",rc,"SQL =",
- capi.sqlite3_sql(this.pointer));
+ console.warn("sqlite3_step() rc=",rc,
+ capi.sqlite3_web_rc_str(rc),
+ "SQL =", capi.sqlite3_sql(this.pointer));
DB.checkRc(this.db.pointer, rc);
}
},
double-type DB operations for integer values in order to keep
more precision.
*/
- const isInt32 = function(n){
+ const isInt32 = (n)=>{
return ('bigint'!==typeof n /*TypeError: can't convert BigInt to number*/)
&& !!(n===(n|0) && n<=2147483647 && n>=-2147483648);
};
+ /**
+ Returns true if the given BigInt value is small enough to fit
+ into an int64 value, else false.
+ */
+ const bigIntFits64 = function f(b){
+ if(!f._max){
+ f._max = BigInt("0x7fffffffffffffff");
+ f._min = ~f._max;
+ }
+ return b >= f._min && b <= f._max;
+ };
+
+ /**
+ Returns true if the given BigInt value is small enough to fit
+ into an int32, else false.
+ */
+ const bigIntFits32 = (b)=>(b >= (-0x7fffffffn - 1n) && b <= 0x7fffffffn);
+
+ /**
+ Returns true if the given BigInt value is small enough to fit
+ into a double value without loss of precision, else false.
+ */
+ const bigIntFitsDouble = function f(b){
+ if(!f._min){
+ f._min = Number.MIN_SAFE_INTEGER;
+ f._max = Number.MAX_SAFE_INTEGER;
+ }
+ return b >= f._min && b <= f._max;
+ };
/** Returns v if v appears to be a TypedArray, else false. */
const isTypedArray = (v)=>{
The semantics of JS functions are:
- xFunc: is passed `(arrayOfValues)`. Its return value becomes
+ xFunc: is passed `(pCtx, ...values)`. Its return value becomes
the new SQL function's result.
- xStep: is passed `(arrayOfValues)`. Its return value is
+ xStep: is passed `(pCtx, ...values)`. Its return value is
ignored.
- xFinal: is passed no arguments. Its return value becomes the
- new aggragate SQL function's result.
+ xFinal: is passed `(pCtx)`. Its return value becomes the new
+ aggregate SQL function's result.
xDestroy: is passed `(void*)`. Its return value is ignored. The
pointer passed to it is the one from the 5th argument to
sqlite3_create_function_v2().
- Note that JS callback implementations have different call
- signatures than their native counterparts (namely, they do not
- get passed an `sqlite3_context*` argument) because practice has
- shown that this is almost always more convenient and desirable
- in JS code. Clients which need access to the full range of
- native arguments will have to create a WASM-bound function
- themselves (using wasm.installFunction() or equivalent) and
- pass that function's WASM pointer to this function, rather than
- passing a JS function. Be warned, however, that working with
- UDFs at that level from JS is quite tedious.
+ Note that:
+
+ - `pCtx` in the above descriptions is a `sqlite3_context*`. 99
+ times out of a hundred, or maybe more, that initial argument
+ will be irrelevant for JS UDF bindings, but it needs to be
+ there so that the cases where it _is_ relevant, in particular
+ with window and aggregate functions, have full access to the
+ underlying sqlite3 APIs.
+
+ - When wrapping JS functions, the remaining arguments arrive as
+ positional arguments, not as an array of arguments, because
+ that allows callback definitions to be more JS-idiomatic than
+ C-like, for example `(pCtx,a,b)=>a+b` is more intuitive and
+ legible than `(pCtx,args)=>args[0]+args[1]`. For cases where
+ an array of arguments would be more convenient, the callbacks
+ simply need to be declared like `(pCtx,...args)=>{...}`, in
+ which case `args` will be an array.
+
+ - If a JS wrapper throws, it gets translated to
+ sqlite3_result_error() or sqlite3_result_error_nomem(),
+ depending on whether the exception is an
+ sqlite3.WasmAllocError object or not.
+
+ - When passing on WASM function pointers, arguments are _not_
+ converted or reformulated. They are passed on as-is in raw
+ pointer form using their native C signatures. Only JS
+ functions passed in to this routine, and thus wrapped by this
+ routine, get automatic conversions of arguments and result
+ values. The routines which perform those conversions are
+ exposed for client-side use as
+ sqlite3_create_function_v2.convertUdfArgs() and
+ sqlite3_create_function_v2.setUdfResult(). sqlite3_create_function()
+ and sqlite3_create_window_function() have those same methods.
For xFunc(), xStep(), and xFinal():
doubles. TODO: use BigInt support if enabled. That feature
was added after this functionality was implemented.
- If any JS-side functions throw, those exceptions are
- intercepted and converted to database-side errors with
- the exception of xFinal(): any exception from it is
- ignored, possibly generating a console.error() message.
- Destructors must not throw.
+ If any JS-side bound functions throw, those exceptions are
+ intercepted and converted to database-side errors with the
+ exception of xDestroy(): any exception from it is ignored,
+ possibly generating a console.error() message. Destructors
+ must not throw.
Once installed, there is currently no way to uninstall the
- bound methods from WASM. They can be uninstalled from the
- database as documented in the C API, but this wrapper currently
- has no infrastructure in place to also free the WASM-bound JS
- wrappers, effectively resulting in a memory leak if the client
- uninstalls the UDF. Improving that is a potential TODO, but
- removing client-installed UDFs is rare in practice.
+ automatically-converted WASM-bound JS functions from WASM. They
+ can be uninstalled from the database as documented in the C
+ API, but this wrapper currently has no infrastructure in place
+ to also free the WASM-bound JS wrappers, effectively resulting
+ in a memory leak if the client uninstalls the UDF. Improving that
+ is a potential TODO, but removing client-installed UDFs is rare
+ in practice. If this factor is relevant for a given client,
+ they can create WASM-bound JS functions themselves, hold on to their
+ pointers, and pass the pointers in to here. Later on, they can
+ free those pointers (using `wasm.uninstallFunction()` or
+ equivalent).
+
+ C reference: https://www.sqlite.org/c3ref/create_function.html
Maintenance reminder: the ability to add new
WASM-accessible functions to the runtime requires that the
*/
sqlite3_create_function_v2: function(
pDb, funcName, nArg, eTextRep, pApp,
- xFunc, //function(arrayOfValues)
- xStep, //function(arrayOfValues)
- xFinal, //function()
- xDestroy //function(void*)
+ xFunc, xStep, xFinal, xDestroy
){/*installed later*/},
/**
Equivalent to passing the same arguments to
*/
sqlite3_create_function:function(
pDb, funcName, nArg, eTextRep, pApp,
- xFunc, //function(arrayOfValues)
- xStep, //function(arrayOfValues)
- xFinal //function()
+ xFunc, xStep, xFinal
){/*installed later*/},
/**
The sqlite3_create_window_function() JS wrapper differs from
*/
sqlite3_create_window_function: function(
pDb, funcName, nArg, eTextRep, pApp,
- xStep, //function(arrayOfValues)
- xFinal, //function()
- xValue, //function()
- xInverse,//function(arrayOfValues)
- xDestroy //function(void*)
+ xStep, xFinal, xValue, xInverse, xDestroy
){/*installed later*/},
/**
The sqlite3_prepare_v3() binding handles two different uses
removed.
*/
util:{
- affirmBindableTypedArray, arrayToString, isBindableTypedArray,
+ affirmBindableTypedArray, arrayToString,
+ bigIntFits32, bigIntFits64, bigIntFitsDouble,
+ isBindableTypedArray,
isInt32, isSQLableTypedArray, isTypedArray,
typedArrayToString,
isMainWindow: ()=>{
*/
capi.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_uri_boolean", "int", "string", "string", "int"],
["sqlite3_uri_key", "string", "string", "int"],
["sqlite3_uri_parameter", "string", "string", "string"],
- ["sqlite3_value_blob", "*", "*"],
- ["sqlite3_value_bytes","int", "*"],
- ["sqlite3_value_double","f64", "*"],
- ["sqlite3_value_text", "string", "*"],
- ["sqlite3_value_type", "int", "*"],
+ ["sqlite3_user_data","void*", "sqlite3_context*"],
+ ["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"]
]/*capi.wasm.bindingSignatures*/;
["sqlite3_malloc64", "*","i64"],
["sqlite3_msize", "i64", "*"],
["sqlite3_realloc64", "*","*", "i64"],
+ ["sqlite3_result_int64",undefined, "*", "i64"],
["sqlite3_total_changes64", "i64", ["sqlite3*"]],
- ["sqlite3_uri_int64", "i64", ["string", "string", "i64"]]
+ ["sqlite3_uri_int64", "i64", ["string", "string", "i64"]],
+ ["sqlite3_value_int64","i64", "sqlite3_value*"],
];
/**
log("Create a scalar UDF...");
db.createFunction({
name: 'twice',
- callback: function(arg){ // note the call arg count
+ callback: function(pCx, arg){ // note the call arg count
return arg + arg;
}
});
}/*testBasicSanity()*/;
const testUDF = function(db){
- db.createFunction("foo",function(a,b){return a+b});
+ db.createFunction("foo",(pCx,a,b)=>a+b);
T.assert(7===db.selectValue("select foo(3,4)")).
assert(5===db.selectValue("select foo(3,?)",2)).
assert(5===db.selectValue("select foo(?,?2)",[1,4])).
assert(5===db.selectValue("select foo($a,$b)",{$a:0,$b:5}));
db.createFunction("bar", {
arity: -1,
- callback: function(){
+ callback: function(pCx){
var rc = 0;
- for(let i = 0; i < arguments.length; ++i) rc += arguments[i];
+ for(let i = 1; i < arguments.length; ++i) rc += arguments[i];
return rc;
}
}).createFunction({
name: "asis",
- callback: (arg)=>arg
+ callback: (pCx,arg)=>arg
});
-
+
//log("Testing DB::selectValue() w/ UDF...");
T.assert(0===db.selectValue("select bar()")).
assert(1===db.selectValue("select bar(1)")).
assert(3===db.selectValue("select bar(1,2)")).
assert(-1===db.selectValue("select bar(1,2,-4)")).
- assert('hi'===db.selectValue("select asis('hi')"));
-
- T.assert('hi' === db.selectValue("select ?",'hi')).
- assert(null===db.selectValue("select null")).
- assert(null === db.selectValue("select ?",null)).
- assert(null === db.selectValue("select ?",[null])).
- assert(null === db.selectValue("select $a",{$a:null})).
+ assert('hi' === db.selectValue("select asis('hi')")).
+ assert('hi' === db.selectValue("select ?",'hi')).
+ assert(null === db.selectValue("select null")).
+ assert(null === db.selectValue("select asis(null)")).
+ assert(1 === db.selectValue("select ?",1)).
+ assert(2 === db.selectValue("select ?",[2])).
+ assert(3 === db.selectValue("select $a",{$a:3})).
assert(eqApprox(3.1,db.selectValue("select 3.0 + 0.1"))).
- assert(eqApprox(1.3,db.selectValue("select asis(1 + 0.3)")))
- ;
+ assert(eqApprox(1.3,db.selectValue("select asis(1 + 0.3)")));
//log("Testing binding and UDF propagation of blobs...");
let blobArg = new Uint8Array(2);
T.assert(g64(pMin) === minMaxI64[0]).
assert(minMaxI64[0] === db.selectValue("select ?",g64(pMin))).
assert(minMaxI64[1] === db.selectValue("select ?",g64(pMax)));
- const rxRange = /out of range for storing as int64/;
+ const rxRange = /too big/;
T.mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[0] - BigInt(1))},
rxRange).
mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[1] + BigInt(1))},
-C JS:\sclean\sup\screate_function()\swrapper\sand\sadd\ssupport\sfor\screate_window_function().\sEliminate\san\sextraneous\sblob\scopy\swhen\sa\sUDF\sreturns\sa\sblob.\sMake\suse\sof\snewfound\sJS-fu\sto\sclean\sup\show\ssqlite3ApiBootstrap()\sconfig\sis\sinitialized.
-D 2022-10-02T20:08:53.027
+C More\scleanups\sin\sthe\sUDF\sargument\sand\sresult\shandling,\sin\sparticular\sint64.\sConsolidate\ssome\sduplicate\sint64/bigint\srange\schecking\scode.\sExpose\sthe\sUDF\slow-level\sutilities\s(arg/result\sconversion)\sto\sclient\scode.\sAdd\sthe\ssqlite3_context\spointer\sto\sthe\sJS-side\sUDF\swrappers\sfor\sAPI\sconsistency.
+D 2022-10-02T22:50:04.828
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/wasm/EXPORTED_RUNTIME_METHODS.fiddle 0e88c8cfc3719e4b7e74980d9da664c709e68acf863e48386cda376edfd3bfb0
F ext/wasm/GNUmakefile b313a82060c733c990b91afa981e10f5e21a0b33a483f33b739ce932ed6bc725
F ext/wasm/README.md 1e5b28158b74ab3ffc9d54fcbc020f0bbeb82c2ff8bbd904214c86c70e8a3066
-F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api e35ddfbfcde83571a1169a910dbcb59bf598a3a8f5283b42d88555b9ccaa6042
+F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 9b16040f37805ee7c30f922a970a57d3f2a822d0675a8f5d70f15061e300c4ce
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md 1e350b611465566cfa2e5eccf7c9b29a34f48ee38bbf6d5fb086dd06ce32b3ff
F ext/wasm/api/extern-post-js.js dc68cbf552d8ea085181400a6963907c32e0b088b03ffd8969b1869fea246629
F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1ecc5ba9e64ef90a8b
F ext/wasm/api/pre-js.js 2db711eb637991b383fc6b5c0f3df65ec48a7201e5730e304beba8de2d3f9b0b
F ext/wasm/api/sqlite3-api-cleanup.js 5d22d1d3818ecacb23bfa223d5970cd0617d8cdbb48c8bc4bbd463f05b021a99
-F ext/wasm/api/sqlite3-api-glue.js d1587736ed73fcb44e32f1ff1933e4c91a2d3b3c39acef0d13c0b3fd6859a7b1
-F ext/wasm/api/sqlite3-api-oo1.js 48d2269544301cd97726ef2d9a82e4384350d12dcf832fa417f211811ae5272d
+F ext/wasm/api/sqlite3-api-glue.js b962bad752b62366651dae26c0b969d297f81e17879685025fb12130786509cb
+F ext/wasm/api/sqlite3-api-oo1.js 484f9ea5c7140d07745f4b534a1f6dd67120c65ef34abcf7cdb3a388d73f5ef4
F ext/wasm/api/sqlite3-api-opfs.js 1b097808b7b081b0f0700cf97d49ef19760e401706168edff9cd45cf9169f541
-F ext/wasm/api/sqlite3-api-prologue.js d71ad817cdef8a9b3b64a394b781a8f64872d4983eac583167e29f9f96ef8e4e
+F ext/wasm/api/sqlite3-api-prologue.js bf270c17e759814decf57f6dd29fee9b5e44dd89a798a1ba9ba1e34d6f76ceaf
F ext/wasm/api/sqlite3-api-worker1.js 7f4f46cb6b512a48572d7567233896e6a9c46570c44bdc3d13419730c7c221c8
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c 2a0f9e4bf1b141a787918951360601128d6a0a190a31a8e5cfe237c99fa640c6
F ext/wasm/common/whwasmutil.js 427eb8b695bd5f38497601a6bda933e83d1a5900b75f5f1af8dbb381898d2ee4
F ext/wasm/demo-123-worker.html e419b66495d209b5211ec64903b4cfb3ca7df20d652b41fcd28bf018a773234f
F ext/wasm/demo-123.html aa281d33b7eefa755f3122b7b5a18f39a42dc5fb69c8879171bf14b4c37c4ec4
-F ext/wasm/demo-123.js 536579fd587974c2511c5bf82034b253d4fdeceabb726927ad7599ef6b7578e8
+F ext/wasm/demo-123.js 9fbc5cd3af842d361e9f8353ae4af9f471c2b2517e55446474406620485b9ee6
F ext/wasm/demo-kvvfs1.html 7d4f28873de67f51ac18c584b7d920825139866a96049a49c424d6f5a0ea5e7f
F ext/wasm/demo-kvvfs1.js 105596bd2ccd0b1deb5fde8e99b536e8242d4bb5932fac0c8403ff3a6bc547e8
F ext/wasm/fiddle.make 3f4efd62bc2a9c883bfcea52ae2755114a62d444d6d042df287f4aef301d6c6c
F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
F ext/wasm/testing-worker1-promiser.js bd788e33c1807e0a6dda9c9a9d784bd3350ca49c9dd8ae2cc8719b506b6e013e
F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae
-F ext/wasm/testing1.js bdea170b16189028c1f63023c620df52ddf31ed416bad56d729c60031b1e27ae
+F ext/wasm/testing1.js 0f87073086eff3a152f013874f1c9a710e63d2e069f90dfeb8333ffe82476d04
F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
F ext/wasm/testing2.js 88f40ef3cd8201bdadd120a711c36bbf0ce56cc0eab1d5e7debb71fed7822494
F ext/wasm/wasmfs.make 3cce1820006196de140f90f2da4b4ea657083fb5bfee7d125be43f7a85748c8f
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 435ab33384017967e46f52b70bee851a85a28808990a0e58dd5288f606b89c9c
-R 8d670d2cae99839795cb81bda9741460
+P d3bad9347c5423fa7f19ae729461636f1043c99a1f01f168efa10bebefb1cdd1
+R 46b070d886b6400d4ed82000c86b9d6e
U stephan
-Z 74556b5dc28de703cf507dc7ef6550bd
+Z fc77e81a038294d78aff4ec7221b0be3
# Remove this line to create a well-formed Fossil manifest.
-d3bad9347c5423fa7f19ae729461636f1043c99a1f01f168efa10bebefb1cdd1
\ No newline at end of file
+10ab77af952abf09f93f342a9d07a3b133f2c4c0a3588df3390cd3a923cafae4
\ No newline at end of file