1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

Add oo1.DB.exec() 'returnValue' option, which specifies what exec() should return. Defaults to the db object and enables direct return of the result rows array or a list of the individual SQL statements. Other code-adjacent internal cleanups.

FossilOrigin-Name: 69d36a6aa5e2cd79d26c0fd3e0d20fe8838fd1be97db07725233bfff1dfe6643
This commit is contained in:
stephan
2022-10-31 11:09:14 +00:00
parent 549907fd67
commit 1acfe91582
5 changed files with 229 additions and 159 deletions

View File

@ -365,7 +365,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
current Stmt and returns the callback argument of the type
indicated by the input arguments.
*/
const parseExecArgs = function(args){
const parseExecArgs = function(db, args){
const out = Object.create(null);
out.opt = Object.create(null);
switch(args.length){
@ -385,20 +385,34 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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){
out.sql = util.flexibleString(out.sql);
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) {
const opt = out.opt;
switch(opt.returnValue){
case 'resultRows':
if(!opt.resultRows) opt.resultRows = [];
out.returnVal = ()=>opt.resultRows;
break;
case 'saveSql':
if(!opt.saveSql) opt.saveSql = [];
out.returnVal = ()=>opt.saveSql;
break;
case undefined:
case 'this':
break;
default:
toss3("Invalid returnValue value:",opt.returnValue);
}
if(!out.returnVal) out.returnVal = ()=>db;
if(opt.callback || opt.resultRows){
switch((undefined===opt.rowMode)
? 'array' : opt.rowMode) {
case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break;
case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
case 'stmt':
if(Array.isArray(out.opt.resultRows)){
if(Array.isArray(opt.resultRows)){
toss3("exec(): invalid rowMode for a resultRows array: must",
"be one of 'array', 'object',",
"a result column number, or column name reference.");
@ -406,32 +420,32 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
out.cbArg = (stmt)=>stmt;
break;
default:
if(util.isInt32(out.opt.rowMode)){
out.cbArg = (stmt)=>stmt.get(out.opt.rowMode);
if(util.isInt32(opt.rowMode)){
out.cbArg = (stmt)=>stmt.get(opt.rowMode);
break;
}else if('string'===typeof out.opt.rowMode && out.opt.rowMode.length>1){
}else if('string'===typeof opt.rowMode && opt.rowMode.length>1){
/* "$X", ":X", and "@X" fetch column named "X" (case-sensitive!) */
const prefix = out.opt.rowMode[0];
const prefix = opt.rowMode[0];
if(':'===prefix || '@'===prefix || '$'===prefix){
out.cbArg = function(stmt){
const rc = stmt.get(this.obj)[this.colName];
return (undefined===rc) ? toss3("exec(): unknown result column:",this.colName) : rc;
}.bind({
obj:Object.create(null),
colName: out.opt.rowMode.substr(1)
colName: opt.rowMode.substr(1)
});
break;
}
}
toss3("Invalid rowMode:",out.opt.rowMode);
toss3("Invalid rowMode:",opt.rowMode);
}
}
return out;
};
/**
Internal impl of the DB.selectRowArray() and
selectRowObject() methods.
Internal impl of the DB.selectArray() and
selectObject() methods.
*/
const __selectFirstRow = (db, sql, bind, getArg)=>{
let stmt, rc;
@ -588,9 +602,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/**
Executes one or more SQL statements in the form of a single
string. Its arguments must be either (sql,optionsObject) or
(optionsObject). In the latter case, optionsObject.sql
must contain the SQL to execute. Returns this
object. Throws on error.
(optionsObject). In the latter case, optionsObject.sql must
contain the SQL to execute. By default it returns this object
but that can be changed via the `returnValue` option as
described below. Throws on error.
If no SQL is provided, or a non-string is provided, an
exception is triggered. Empty SQL, on the other hand, is
@ -599,21 +614,25 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
The optional options object may contain any of the following
properties:
- `.sql` = the SQL to run (unless it's provided as the first
- `sql` = the SQL to run (unless it's provided as the first
argument). This must be of type string, Uint8Array, or an array
of strings. In the latter case they're concatenated together
as-is, _with no separator_ between elements, before evaluation.
The array form is often simpler for long hand-written queries.
- `.bind` = a single value valid as an argument for
- `bind` = a single value valid as an argument for
Stmt.bind(). This is _only_ applied to the _first_ non-empty
statement in the SQL which has any bindable parameters. (Empty
statements are skipped entirely.)
- `.saveSql` = an optional array. If set, the SQL of each
- `saveSql` = an optional array. If set, the SQL of each
executed statement is appended to this array before the
statement is executed (but after it is prepared - we don't have
the string until after that). Empty SQL statements are elided.
the string until after that). Empty SQL statements are elided
but can have odd effects in the output. e.g. SQL of: `"select
1; -- empty\n; select 2"` will result in an array containing
`["select 1;", "--empty \n; select 2"]`. That's simply how
sqlite3 records the SQL for the 2nd statement.
==================================================================
The following options apply _only_ to the _first_ statement
@ -621,14 +640,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
the statement actually produces any result rows.
==================================================================
- `.columnNames`: if this is an array, the column names of the
- `columnNames`: if this is an array, the column names of the
result set are stored in this array before the callback (if
any) is triggered (regardless of whether the query produces any
result rows). If no statement has result columns, this value is
unchanged. Achtung: an SQL result may have multiple columns
with identical names.
- `.callback` = a function which gets called for each row of
- `callback` = a function which gets called for each row of
the result set, but only if that statement has any result
_rows_. The callback's "this" is the options object, noting
that this function synthesizes one if the caller does not pass
@ -647,7 +666,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
The first argument passed to the callback defaults to an array of
values from the current result row but may be changed with ...
- `.rowMode` = specifies the type of he callback's first argument.
- `rowMode` = specifies the type of he callback's first argument.
It may be any of...
A) A string describing what type of argument should be passed
@ -655,7 +674,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
A.1) `'array'` (the default) causes the results of
`stmt.get([])` to be passed to the `callback` and/or appended
to `resultRows`.
to `resultRows`
A.2) `'object'` causes the results of
`stmt.get(Object.create(null))` to be passed to the
@ -687,7 +706,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
Any other `rowMode` value triggers an exception.
- `.resultRows`: if this is an array, it functions similarly to
- `resultRows`: if this is an array, it functions similarly to
the `callback` option: each row of the result set (if any),
with the exception that the `rowMode` 'stmt' is not legal. It
is legal to use both `resultRows` and `callback`, but
@ -695,28 +714,44 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
and can be used over a WebWorker-style message interface.
exec() throws if `resultRows` is set and `rowMode` is 'stmt'.
- `returnValue`: is a string specifying what this function
should return:
A) The default value is `"this"`, meaning that the
DB object itself should be returned.
B) `"resultRows"` means to return the value of the
`resultRows` option. If `resultRows` is not set, this
function behaves as if it were set to an empty array.
C) `"saveSql"` means to return the value of the
`saveSql` option. If `saveSql` is not set, this
function behaves as if it were set to an empty array.
Potential TODOs:
- `.bind`: permit an array of arrays/objects to bind. The first
- `bind`: permit an array of arrays/objects to bind. The first
sub-array would act on the first statement which has bindable
parameters (as it does now). The 2nd would act on the next such
statement, etc.
- `.callback` and `.resultRows`: permit an array entries with
semantics similar to those described for `.bind` above.
- `callback` and `resultRows`: permit an array entries with
semantics similar to those described for `bind` above.
*/
exec: function(/*(sql [,obj]) || (obj)*/){
affirmDbOpen(this);
const arg = parseExecArgs(arguments);
const arg = parseExecArgs(this, arguments);
if(!arg.sql){
return (''===arg.sql) ? this : toss3("exec() requires an SQL string.");
}
const opt = arg.opt;
const callback = opt.callback;
let resultRows = (Array.isArray(opt.resultRows)
? opt.resultRows : undefined);
const returnValue = opt.returnValue || 'this';
const resultRows = (Array.isArray(opt.resultRows)
? opt.resultRows : (
'resultRows'===returnValue ? [] : undefined
));
let stmt;
let bind = opt.bind;
let evalFirstResult = !!(arg.cbArg || opt.columnNames) /* true to evaluate the first result-returning query */;
@ -774,7 +809,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
stmt._isLocked = true;
const row = arg.cbArg(stmt);
if(resultRows) resultRows.push(row);
if(callback) callback.apply(opt,[row,stmt]);
if(callback) callback.call(opt, row, stmt);
stmt._isLocked = false;
}
}else{
@ -793,7 +828,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
wasm.scopedAllocPop(stack);
}
return this;
return arg.returnVal();
}/*exec()*/,
/**
Creates a new scalar UDF (User-Defined Function) which is

View File

@ -162,12 +162,64 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
}
});
/** Throws a new Error, the message of which is the concatenation
all args with a space between each. */
const toss = (...args)=>{throw new Error(args.join(' '))};
/**
An Error subclass specifically for reporting DB-level errors and
enabling clients to unambiguously identify such exceptions.
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 && capi.sqlite3_js_rc_str(args[0]))
|| ("Unknown result code #"+args[0]));
}else{
super(args.join(' '));
}
this.name = 'SQLite3Error';
}
};
/**
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:
https://www.sqlite.org/c3ref/intro.html
A very few exceptions require an additional level of proxy
function or may otherwise require special attention in the WASM
environment, and all such cases are document here. Those not
documented otherwise are installed as 1-to-1 proxies for their
C-side counterparts.
*/
const capi = Object.create(null);
/**
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);
};
const toss3 = SQLite3Error.toss;
if(config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)){
toss("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.");
toss3("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.");
}
/**
@ -267,7 +319,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
that v is not a supported TypedArray value. */
const affirmBindableTypedArray = (v)=>{
return isBindableTypedArray(v)
|| toss("Value is not of a supported TypedArray type.");
|| toss3("Value is not of a supported TypedArray type.");
};
const utf8Decoder = new TextDecoder('utf-8');
@ -318,21 +370,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
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:
https://www.sqlite.org/c3ref/intro.html
A very few exceptions require an additional level of proxy
function or may otherwise require special attention in the WASM
environment, and all such cases are document here. Those not
documented here are installed as 1-to-1 proxies for their C-side
counterparts.
*/
const capi = {
Object.assign(capi, {
/**
sqlite3_create_function_v2() differs from its native
counterpart only in the following ways:
@ -557,7 +595,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
values.
*/
sqlite3_randomness: (n, outPtr)=>{/*installed later*/},
}/*capi*/;
}/*capi*/);
/**
Various internal-use utilities are added here as needed. They
@ -617,7 +655,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
The symbols exported by the WASM environment.
*/
exports: config.exports
|| toss("Missing API config.exports (WASM module exports)."),
|| toss3("Missing API config.exports (WASM module exports)."),
/**
When Emscripten compiles with `-sIMPORT_MEMORY`, it
@ -626,7 +664,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
available via this.exports.memory.
*/
memory: config.memory || config.exports['memory']
|| toss("API config object requires a WebAssembly.Memory object",
|| toss3("API config object requires a WebAssembly.Memory object",
"in either config.exports.memory (exported)",
"or config.memory (imported)."),
@ -688,7 +726,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
keyDealloc = config.deallocExportName || 'free';
for(const key of [keyAlloc, keyDealloc]){
const f = wasm.exports[key];
if(!(f instanceof Function)) toss("Missing required exports[",key,"] function.");
if(!(f instanceof Function)) toss3("Missing required exports[",key,"] function.");
}
wasm.alloc = function(n){
@ -1057,43 +1095,6 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
}
})/*wasm.pstack properties*/;
/**
An Error subclass specifically for reporting DB-level errors and
enabling clients to unambiguously identify such exceptions.
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){
@ -1245,8 +1246,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
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.');
if(!pDb) toss3('Invalid sqlite3* argument.');
if(!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.');
const stack = wasm.pstack.pointer;
let pOut;
try{
@ -1263,7 +1264,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
pDb, ppOut, pSize, 0
);
if(rc){
toss("Database serialization failed with code",
toss3("Database serialization failed with code",
sqlite3.capi.sqlite3_js_rc_str(rc));
}
pOut = wasm.getPtrValue(ppOut);

View File

@ -1220,8 +1220,9 @@
.t('Table t', function(sqlite3){
const db = this.db;
let list = [];
db.exec({
let rc = db.exec({
sql:['CREATE TABLE t(a,b);',
// ^^^ using TEMP TABLE breaks the db export test
"INSERT INTO t(a,b) VALUES(1,2),(3,4),",
"(?,?),('blob',X'6869')"/*intentionally missing semicolon to test for
off-by-one bug in string-to-WASM conversion*/],
@ -1229,7 +1230,8 @@
bind: [5,6]
});
//debug("Exec'd SQL:", list);
T.assert(2 === list.length)
T.assert(rc === db)
.assert(2 === list.length)
.assert('string'===typeof list[1])
.assert(4===db.changes());
if(wasm.bigIntEnabled){
@ -1502,30 +1504,61 @@
xValue: xValueFinal
});
db.exec([
"CREATE TABLE twin(x, y); INSERT INTO twin VALUES",
"CREATE TEMP TABLE twin(x, y); INSERT INTO twin VALUES",
"('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
]);
let count = 0;
db.exec({
let rc = db.exec({
returnValue: 'resultRows',
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.");
}
}
"FROM twin ORDER BY x;"
]
});
T.assert(5 === count);
T.assert(Array.isArray(rc))
.assert(5 === rc.length);
let count = 0;
for(const row of rc){
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.");
}
}
const resultRows = [];
rc = db.exec({
resultRows,
returnValue: 'resultRows',
sql:[
"SELECT x, winsumint(y) OVER (",
"ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING",
") AS sum_y ",
"FROM twin ORDER BY x;"
]
});
T.assert(rc === resultRows)
.assert(5 === rc.length);
rc = db.exec({
returnValue: 'saveSql',
sql: "select 1; select 2; -- empty\n; select 3"
});
T.assert(Array.isArray(rc))
.assert(3===rc.length)
.assert('select 1;' === rc[0])
.assert('select 2;' === rc[1])
.assert('-- empty\n; select 3' === rc[2]
/* Strange but true. */);
T.mustThrowMatching(()=>{
db.exec({sql:'', returnValue: 'nope'});
}, /^Invalid returnValue/);
db.exec("DROP TABLE twin");
}
}/*window UDFs*/)
@ -1536,7 +1569,7 @@
db.exec({
sql:new TextEncoder('utf-8').encode([
// ^^^ testing string-vs-typedarray handling in exec()
"attach 'session' as foo;" /* name 'session' is magic for kvvfs! */,
"attach 'session' as foo;",
"create table foo.bar(a);",
"insert into foo.bar(a) values(1),(2),(3);",
"select a from foo.bar order by a;"
@ -1665,27 +1698,24 @@
;/* end of oo1 checks */
////////////////////////////////////////////////////////////////////////
T.g('kvvfs (Worker thread only)', isWorker)
.t({
name: 'kvvfs is disabled',
test: ()=>{
T.g('kvvfs')
.t('kvvfs sanity checks', function(sqlite3){
if(isWorker()){
T.assert(
!capi.sqlite3_vfs_find('kvvfs'),
"Expecting kvvfs to be unregistered."
);
log("kvvfs is (correctly) unavailable in a Worker.");
return;
}
});
T.g('kvvfs (UI thread only)', isUIThread)
.t({
name: 'kvvfs sanity checks',
test: function(sqlite3){
const filename = 'session';
const pVfs = capi.sqlite3_vfs_find('kvvfs');
T.assert(pVfs);
const JDb = sqlite3.oo1.JsStorageDb;
const unlink = ()=>JDb.clearStorage(filename);
unlink();
let db = new JDb(filename);
const filename = 'session';
const pVfs = capi.sqlite3_vfs_find('kvvfs');
T.assert(pVfs);
const JDb = sqlite3.oo1.JsStorageDb;
const unlink = ()=>JDb.clearStorage(filename);
unlink();
let db = new JDb(filename);
try {
db.exec([
'create table kvvfs(a);',
'insert into kvvfs(a) values(1),(2),(3)'
@ -1695,6 +1725,7 @@
db = new JDb(filename);
db.exec('insert into kvvfs(a) values(4),(5),(6)');
T.assert(6 === db.selectValue('select count(*) from kvvfs'));
}finally{
db.close();
unlink();
}
@ -1713,17 +1744,20 @@
const unlink = (fn=filename)=>wasm.sqlite3_wasm_vfs_unlink(pVfs,fn);
unlink();
let db = new sqlite3.opfs.OpfsDb(filename);
db.exec([
'create table p(a);',
'insert into p(a) values(1),(2),(3)'
]);
T.assert(3 === db.selectValue('select count(*) from p'));
db.close();
db = new sqlite3.opfs.OpfsDb(filename);
db.exec('insert into p(a) values(4),(5),(6)');
T.assert(6 === db.selectValue('select count(*) from p'));
db.close();
unlink();
try {
db.exec([
'create table p(a);',
'insert into p(a) values(1),(2),(3)'
]);
T.assert(3 === db.selectValue('select count(*) from p'));
db.close();
db = new sqlite3.opfs.OpfsDb(filename);
db.exec('insert into p(a) values(4),(5),(6)');
T.assert(6 === db.selectValue('select count(*) from p'));
}finally{
db.close();
unlink();
}
}
}/*OPFS sanity checks*/)
;/* end OPFS tests */

View File

@ -1,5 +1,5 @@
C Avoid\sa\ssegfault\sthat\scould\soccur\swhen\srunning\sthe\srecover\sAPI\son\sa\sdatabase\shandle\swith\smemory-mapping\senabled.
D 2022-10-31T10:53:23.735
C Add\soo1.DB.exec()\s'returnValue'\soption,\swhich\sspecifies\swhat\sexec()\sshould\sreturn.\sDefaults\sto\sthe\sdb\sobject\sand\senables\sdirect\sreturn\sof\sthe\sresult\srows\sarray\sor\sa\slist\sof\sthe\sindividual\sSQL\sstatements.\sOther\scode-adjacent\sinternal\scleanups.
D 2022-10-31T11:09:14.111
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -500,9 +500,9 @@ F ext/wasm/api/post-js-header.js d6ab3dfef4a06960d28a7eaa338d4e2a1a5981e9b387181
F ext/wasm/api/pre-js.js 287e462f969342b032c03900e668099fa1471d852df7a472de5bc349161d9c04
F ext/wasm/api/sqlite3-api-cleanup.js ecdc69dbfccfe26146f04799fcfd4a6f5790d46e7e3b9b6e9b0491f92ed8ae34
F ext/wasm/api/sqlite3-api-glue.js b87543534821ecfa56fc0d0cd153a115fa974e70d6217964baf6e93ef8d25fb1
F ext/wasm/api/sqlite3-api-oo1.js a17e2624967073f86cc50f4c1e30f8822ef631dc20dfc73b1143847b9e9723fe
F ext/wasm/api/sqlite3-api-oo1.js 4028bc2bac7e3ae2d23b7c99828155b4a06da006b51dc2a929bc0db26337370d
F ext/wasm/api/sqlite3-api-opfs.js c67cbe0b1451ec43bc6b3199e13453e1ca56d718a75c0498253b0d479c336256
F ext/wasm/api/sqlite3-api-prologue.js a218dda5e5ced8894f65760131371e4cabd31062af58803af8952cc00ea778d2
F ext/wasm/api/sqlite3-api-prologue.js 873986ca150c79510f647b910f8349bc71b14db21e444cab3b9fad9c4f39ffc7
F ext/wasm/api/sqlite3-api-worker1.js efdca1b42299d80b54f366d15a8fc5343f3b3e9e3647e5c1fd6f3ee1015e501b
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
F ext/wasm/api/sqlite3-opfs-async-proxy.js 29f6f5c314c2956e77573c6ab975c2455a0839721ed44f38004382c2a1463ab5
@ -549,7 +549,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
F ext/wasm/test-opfs-vfs.js 48fc59110e8775bb43c9be25b6d634fc07ebadab7da8fbd44889e8129c6e2548
F ext/wasm/tester1-worker.html d02b9d38876b023854cf8955e77a40912f7e516956b4dbe1ec7f215faac273ee
F ext/wasm/tester1.html c6c47e5a8071eb09cb1301104435c8e44fbb5719c92411f5b2384a461f9793c5
F ext/wasm/tester1.js 08ccc16972562ff604b7bda387b56d6eea380aaf968697fc8e2a9bb3c6ba2dda
F ext/wasm/tester1.js 2427ac48e255f658ad81163b5dc6372a8609ab6ab60e295e371d1e5fe9a495ab
F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5
F ext/wasm/wasmfs.make fb2d3c4a298b12cf1ec994ad1d0f1d027ae297449b364cde43d2eb807d68048f
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
@ -2054,8 +2054,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 cb12ac5de17e677f089d7b0b46803efbd9a9178972ffb0454a8b557b06633658
R 46019e96ebee7f43e27063daa1a45bd1
U dan
Z 31c01b86489219dc9c143f294c0c509f
P e02c697281a777c33070168af784b2d291397e488244a217620897f40aed7158
R 26339704ab975fcc1e6818338a87c2a1
U stephan
Z 2aa3561d4216c084633673f53cc5adc1
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
e02c697281a777c33070168af784b2d291397e488244a217620897f40aed7158
69d36a6aa5e2cd79d26c0fd3e0d20fe8838fd1be97db07725233bfff1dfe6643