1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Expose sqlite3_vfs_unregister() to WASM and unregister kvvfs in Worker threads to avoid its unintended use there (in contexts other than local/sessionStorage). Correct registration of window functions, extend oo1.DB.createFunction() to support window functions, and add window function tests to tester1.js. Correct an incorrect 1-arg handling case for DB.exec(). Add per-test assertion counts to tester1.js.

FossilOrigin-Name: f07ce15479b7224b0d1ba9f147a433136e70c1461aa667d2737d4a918f778f55
This commit is contained in:
stephan
2022-10-21 05:27:40 +00:00
parent 6f3286cafd
commit a6ca996e4a
7 changed files with 257 additions and 158 deletions

View File

@ -89,5 +89,6 @@ _sqlite3_value_text
_sqlite3_value_type
_sqlite3_vfs_find
_sqlite3_vfs_register
_sqlite3_vfs_unregister
_malloc
_free

View File

@ -443,10 +443,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
try{
const funcArgs = __xWrapFuncs({xStep, xFinal, xValue, xInverse, xDestroy},
uninstall);
rc = sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
pApp, ...funcArgs);
rc = sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
pApp, ...funcArgs);
}catch(e){
console.error("sqlite3_create_function_v2() setup threw:",e);
console.error("sqlite3_create_window_function() setup threw:",e);
for(let v of uninstall){
wasm.uninstallFunction(v);
}
@ -607,6 +607,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
// 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);
@ -614,89 +618,96 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
}/*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 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 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 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 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);
}
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]
);
}
}/*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);
}
}/*kvvfs*/
}/*pKvvfs*/
});

View File

@ -374,11 +374,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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;
}else if(Array.isArray(args[0])){
out.sql = args[0];
}
break;
case 2:
@ -392,7 +392,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}else if(Array.isArray(out.sql)){
out.sql = out.sql.join('');
}else if('string'!==typeof out.sql){
toss3("Missing SQL argument.");
toss3("Missing SQL argument or unsupported SQL value type.");
}
if(out.opt.callback || out.opt.resultRows){
switch((undefined===out.opt.rowMode)
@ -811,8 +811,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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).
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
@ -837,14 +837,19 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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.
- Window: set the `xStep`, `xFinal`, `xValue`, and `xInverse`
function-type properties. Do not set the `xFunc` property.
The optional options object may contain flags to modify how
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
@ -855,36 +860,39 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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
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:
The following options-object properties correspond to flags
documented at:
https://sqlite.org/c3ref/create_function.html
- .deterministic = SQLITE_DETERMINISTIC
- .directOnly = SQLITE_DIRECTONLY
- .innocuous = SQLITE_INNOCUOUS
- `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){
let xStep, xFinal;
const isFunc = (f)=>(f instanceof Function);
switch(arguments.length){
case 1: /* (optionsObject) */
opt = name;
name = opt.name;
xFunc = opt.xFunc;
xFunc = opt.xFunc || 0;
break;
case 2: /* (name, callback|optionsObject) */
if(!isFunc(xFunc)){
opt = xFunc;
xFunc = opt.xFunc;
xFunc = opt.xFunc || 0;
}
break;
case 3: /* name, xFunc, opt */
@ -895,30 +903,46 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
if('string' !== typeof name){
toss3("Invalid arguments: missing function name.");
}
xStep = opt.xStep;
xFinal = opt.xFinal;
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 UDF.");
toss3("Missing xFinal() callback for aggregate or window UDF.");
}
xFunc = null;
}else if(isFunc(xFinal)){
toss3("Missing xStep() callback for aggregate UDF.");
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;
const xDestroy = opt.xDestroy || 0;
if(xDestroy && !isFunc(xDestroy)){
toss3("xDestroy property must be a function.");
}
@ -929,13 +953,22 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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));
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()*/,
/**
@ -1642,7 +1675,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
dbCtorHelper
}/*oo1 object*/;
if(util.isMainWindow()){
if(util.isUIThread()){
/**
Functionally equivalent to DB(storageName,'c','kvvfs') except
that it throws if the given storage name is not one of 'local'

View File

@ -289,7 +289,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
```
*/
WasmAllocError.toss = (...args)=>{
throw new WasmAllocError(args.join(' '));
throw new WasmAllocError(...args);
};
/**
@ -530,9 +530,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
isBindableTypedArray,
isInt32, isSQLableTypedArray, isTypedArray,
typedArrayToString,
isMainWindow: ()=>{
return 'undefined' === typeof WorkerGlobalScope
}
isUIThread: ()=>'undefined'===typeof WorkerGlobalScope
},
/**
@ -839,7 +837,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
["sqlite3_value_text", "string", "sqlite3_value*"],
["sqlite3_value_type", "int", "sqlite3_value*"],
["sqlite3_vfs_find", "*", "string"],
["sqlite3_vfs_register", "int", "*", "int"]
["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
]/*wasm.bindingSignatures*/;
if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
@ -1026,10 +1025,18 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
class SQLite3Error extends Error {
/**
Constructs this object with a message equal to all arguments
concatenated with a space between each one.
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){
super(args.join(' '));
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';
}
};
@ -1042,7 +1049,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
```
*/
SQLite3Error.toss = (...args)=>{
throw new SQLite3Error(args.join(' '));
throw new SQLite3Error(...args);
};
/** State for sqlite3_wasmfs_opfs_dir(). */
@ -1219,7 +1226,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
: 0);
};
if( capi.util.isMainWindow() ){
if( capi.util.isUIThread() ){
/* Features specific to the main window thread... */
/**

View File

@ -50,7 +50,7 @@
const mapToString = (v)=>{
switch(typeof v){
case 'number': case 'string': case 'boolean':
case 'undefined':
case 'undefined': case 'bigint':
return ''+v;
default: break;
}
@ -216,7 +216,7 @@
}
log(TestUtil.separator);
logClass('group-start',"Group #"+this.number+':',this.name);
const indent = '....';
const indent = ' ';
const assertCount = TestUtil.counter;
const groupState = Object.create(null);
const skipped = [];
@ -230,7 +230,7 @@
const tc = TestUtil.counter
log(indent, n+":", t.name);
await t.test.call(groupState, sqlite3);
//log(indent, indent, 'assertion count:',TestUtil.counter - tc);
log(indent, indent, TestUtil.counter - tc, 'assertion(s)');
}
}
logClass('green',
@ -312,6 +312,8 @@
T.assert(e instanceof Error)
.assert(e instanceof sqlite3.WasmAllocError);
}
try{ throw new sqlite3.SQLite3Error(capi.SQLITE_SCHEMA) }
catch(e){ T.assert('SQLITE_SCHEMA' === e.message) }
})
////////////////////////////////////////////////////////////////////
.t('strglob/strlike', function(sqlite3){
@ -1092,7 +1094,7 @@
const vfsList = capi.sqlite3_js_vfs_list();
T.assert(vfsList.length>1);
T.assert('string'===typeof vfsList[0]);
//log("vfsList =",vfsList);
for(const v of vfsList){
T.assert('string' === typeof v)
.assert(capi.sqlite3_vfs_find(v) > 0);
@ -1282,7 +1284,7 @@
const sjac = capi.sqlite3_js_aggregate_context;
db.createFunction({
name: 'summer',
xStep: function(pCtx, n){
xStep: (pCtx, n)=>{
const ac = sjac(pCtx, 4);
wasm.setMemValue(ac, wasm.getMemValue(ac,'i32') + Number(n), 'i32');
},
@ -1305,11 +1307,11 @@
db.createFunction({
name: 'summerN',
arity: -1,
xStep: function(pCtx, ...args){
const pAgg = sjac(pCtx, 4);
let sum = wasm.getMemValue(pAgg, 'i32');
xStep: (pCtx, ...args)=>{
const ac = sjac(pCtx, 4);
let sum = wasm.getMemValue(ac, 'i32');
for(const v of args) sum += Number(v);
wasm.setMemValue(pAgg, sum, 'i32');
wasm.setMemValue(ac, sum, 'i32');
},
xFinal: (pCtx)=>{
const ac = sjac(pCtx, 0);
@ -1352,9 +1354,9 @@
const sjac = capi.sqlite3_js_aggregate_context;
db.createFunction({
name: 'summer64',
xStep: function(pCtx, n){
const pAgg = sjac(pCtx, 8);
wasm.setMemValue(pAgg, wasm.getMemValue(pAgg,'i64') + BigInt(n), 'i64');
xStep: (pCtx, n)=>{
const ac = sjac(pCtx, 8);
wasm.setMemValue(ac, wasm.getMemValue(ac,'i64') + BigInt(n), 'i64');
},
xFinal: (pCtx)=>{
const ac = sjac(pCtx, 0);
@ -1362,19 +1364,64 @@
}
});
let v = db.selectValue([
"with cte(v) as (",
"select 3 union all select 5 union all select 7",
") select summer64(v*10), summer64(v+1) from cte"
"with cte(v) as (",
"select 9007199254740991 union all select 1 union all select 2",
") select summer64(v), summer64(v+1) from cte"
]);
T.assert(150n===BigInt(v));
T.assert(9007199254740994n===v);
}
}/*aggregate UDFs*/)
////////////////////////////////////////////////////////////////////
.t({
name: 'Window UDFs (tests are TODO)',
predicate: testIsTodo
})
name: 'Window UDFs',
test: function(){
/* Example window function, table, and results taken from:
https://sqlite.org/windowfunctions.html#udfwinfunc */
const db = this.db;
const sjac = (cx,n=4)=>capi.sqlite3_js_aggregate_context(cx,n);
const xValueFinal = (pCtx)=>{
const ac = sjac(pCtx, 0);
return ac ? wasm.getMemValue(ac,'i32') : 0;
};
const xStepInverse = (pCtx, n)=>{
const ac = sjac(pCtx);
wasm.setMemValue(ac, wasm.getMemValue(ac,'i32') + Number(n), 'i32');
};
db.createFunction({
name: 'winsumint',
xStep: (pCtx, n)=>xStepInverse(pCtx, n),
xInverse: (pCtx, n)=>xStepInverse(pCtx, -n),
xFinal: xValueFinal,
xValue: xValueFinal
});
db.exec([
"CREATE TABLE twin(x, y); INSERT INTO twin VALUES",
"('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
]);
let count = 0;
db.exec({
sql:[
"SELECT x, winsumint(y) OVER (",
"ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING",
") AS sum_y ",
"FROM twin ORDER BY x;",
"DROP TABLE twin;"
],
callback: function(row){
switch(++count){
case 1: T.assert('a'===row[0] && 9===row[1]); break;
case 2: T.assert('b'===row[0] && 12===row[1]); break;
case 3: T.assert('c'===row[0] && 16===row[1]); break;
case 4: T.assert('d'===row[0] && 12===row[1]); break;
case 5: T.assert('e'===row[0] && 9===row[1]); break;
default: toss("Too many rows to window function.");
}
}
});
T.assert(5 === count);
}
}/*window UDFs*/)
////////////////////////////////////////////////////////////////////
.t("ATTACH", function(){

View File

@ -1,5 +1,5 @@
C Make\ssemantics\sfor\sUDF\sxFinal()\sresult\shandling\sand\serror\sreporting\shandling\smore\sflexible.
D 2022-10-20T23:48:38.866
C Expose\ssqlite3_vfs_unregister()\sto\sWASM\sand\sunregister\skvvfs\sin\sWorker\sthreads\sto\savoid\sits\sunintended\suse\sthere\s(in\scontexts\sother\sthan\slocal/sessionStorage).\sCorrect\sregistration\sof\swindow\sfunctions,\sextend\soo1.DB.createFunction()\sto\ssupport\swindow\sfunctions,\sand\sadd\swindow\sfunction\stests\sto\stester1.js.\sCorrect\san\sincorrect\s1-arg\shandling\scase\sfor\sDB.exec().\sAdd\sper-test\sassertion\scounts\sto\stester1.js.
D 2022-10-21T05:27:40.995
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -475,7 +475,7 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce
F ext/wasm/GNUmakefile 645bd5670a56acf2c8f1e969c427555e3e8e74dfd6eac8c948858f530617c7d5
F ext/wasm/README-dist.txt e78e44a58772d5b5d7a5a179b5bf639cd67b62249aac66138e2c319bd02dd243
F ext/wasm/README.md 1e5b28158b74ab3ffc9d54fcbc020f0bbeb82c2ff8bbd904214c86c70e8a3066
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 89983a8d122c35a90c65ec667844b95a78bcd04f3198a99c1e0c8368c1a0b03a
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api 36f413ab4dbb057d2dec938fb366ac0a4c5e85ba14660a8d672f0277602c0fc5
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md 1350088aee90e959ad9a94fab1bb6bcb5e99d4d27f976db389050f54f2640c78
F ext/wasm/api/extern-post-js.js efbed835f290b3741259acc5faf68714a60d38e6834e6cfe172d5354c87566d2
@ -484,10 +484,10 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08
F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1ecc5ba9e64ef90a8b
F ext/wasm/api/pre-js.js 151e0616614a49f3db19ed544fa13b38c87c108959fbcd4029ea8399a562d94f
F ext/wasm/api/sqlite3-api-cleanup.js 4d07a7524dc9b7b050acfde57163e839243ad2383bd7ee0de0178b1b3e988588
F ext/wasm/api/sqlite3-api-glue.js ea760df5991cee48e29aa6ced503027760462d5696d50521f7273a91e0e1430c
F ext/wasm/api/sqlite3-api-oo1.js 0e278d131dad72e9eb348a3dda6a4ff734a9e08925b4ed7e6e5a688d2edaf525
F ext/wasm/api/sqlite3-api-glue.js 6e4e472eb5afc732a695cd7c5ded6dee6ef8b480e61aa0d648a3fc9033c84745
F ext/wasm/api/sqlite3-api-oo1.js 5016f6dd4b6b461bb6047fe6a2d3d7cbe85aa6b110c263ebf0347672a0cd897e
F ext/wasm/api/sqlite3-api-opfs.js 22d60ba956e873b65e2e0591e239178082bd53a6d563c3c58db7dc03e562e8f7
F ext/wasm/api/sqlite3-api-prologue.js e4fbfa66eb6c5c544c52dea6cb48051eddcdc21c276c39a80801f5e76e6c5b56
F ext/wasm/api/sqlite3-api-prologue.js fa00d55f927e5a4ec51cf2c80f6f0eaed2f4f5774341ecf3d63a0ea4c738f8f5
F ext/wasm/api/sqlite3-api-worker1.js a7f38f03275d6c27ab2aef3e83215d3c97ce09c43e6904df47c3764d9d4572b4
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
F ext/wasm/api/sqlite3-opfs-async-proxy.js 206ce6bbc3c30ad51a37d9c25e3a2712e70b586e0f9a2cf8cb0b9619017c2671
@ -533,7 +533,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
F ext/wasm/test-opfs-vfs.js 48fc59110e8775bb43c9be25b6d634fc07ebadab7da8fbd44889e8129c6e2548
F ext/wasm/tester1-worker.html 048c341f124fdb61ca14dfd1bd1f78742490f208aa3bb1e84399f83f1e7e6a74
F ext/wasm/tester1.html 37ccc958fa0d95074af2d72b7241c8e2d982bbec6dda4dc790241af3d933c3b6
F ext/wasm/tester1.js 5533cd100dc663dbe548fb04aefc490aa4b3d2e0ec2212f79881bb4893266e39
F ext/wasm/tester1.js 3fc539001b861d6360ea8c4825351157251204781b7a45389527574ad338c7e1
F ext/wasm/version-info.c 5fa356d38859d71a0369b5c37e1935def7413fcc8a4e349a39d9052c1d0479f4
F ext/wasm/wasmfs.make ee0004813e16c283ff633e08b482008d56adf9b7d42f6c5612f7ab002b924f69
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
@ -2036,8 +2036,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 9d034ef5e1bab7c9651c2450dc85765fa6365d3f1414c711550de858ff8b3ece
R dfb3978c0632c8b69ab9fb0976c9a2ee
P 89f3e1982ec32c010af67d15ef780847df20de568669e5c9d02f3cf084f51330
R 8a68d8975e926edd4ad048c9589fdc73
U stephan
Z c86f3e45c75ca0a38f433f4183ca8f53
Z 78e197950cf91aa30272843b46106df8
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
89f3e1982ec32c010af67d15ef780847df20de568669e5c9d02f3cf084f51330
f07ce15479b7224b0d1ba9f147a433136e70c1461aa667d2737d4a918f778f55