- 'session'
- 'local'
- - An empty string means both of 'local' and 'session' storage.
+ - '' - see below.
- A transient kvvfs storage object name.
In the first two cases, only sessionStorage resp. localStorage is
cleared. If passed an an empty string (the default) then its
- behavior depends on:
+ behavior depends on the second argument:
- - If called in the main thread an empty stream means to act on
- both localStorage and sessionStorage. Only storage keys which
- match the pattern used by kvvfs are cleared: any other
- client-side data are retained. Version 1 of this API always
- behaves this way. (This is backwards-compatibility behavior to
- account for an admitted misuse of "".)
-
- - If called from a thread where globalThis.Storage is not available
- then an empty string is considered to be a legal storage unit name.
+ If emptyIsAName is false (the default) then an empty string means
+ both of 'local' and 'session' storage. (For backwards
+ compatibility.) if emptyIsAName is true then the empty string is
+ treated as a storage name instead.
Returns the number of entries cleared.
- It accepts an arbitrary storage name. In v1 this was a silent
no-op for any names other than ('local','session','').
- - In threads where local/sessionStorage are not available, an
- empty string argument is treated as a storage unit name.
+ - The second argument was added.
- It throws if a db currently has the storage opened. That
version 1 did not throw for this case was due to an architectural
limitation which has since been overcome.
*/
- capi.sqlite3_js_kvvfs_clear = function callee(which=""){
- if( !which && cache.storagePool.local ){
+ capi.sqlite3_js_kvvfs_clear = function callee(which="", emptyIsAName=false){
+ if( !which && !emptyIsAName && cache.storagePool.local ){
return callee('local') + callee('session');
}
const store = storageForZClass(which);
if( !store ) return 0;
const keyPrefix = store.prefix;
- /*undecided:
if( store.files.length ){
toss3(capi.SQLITE_ACCESS,
"Cannot clear in-use database storage.");
- }*/
+ }
const s = store.storage;
const toRm = [] /* keys to remove */;
let i, n = s.length;
This routine guesses the approximate amount of
storage used by the given kvvfs back-end.
- The 'which' argument is as documented for
- sqlite3_js_kvvfs_clear(), only the operation this performs is
- different:
+ Its arguments are as documented for sqlite3_js_kvvfs_clear(),
+ only the operation this performs is different.
The returned value is twice the "length" value of every matching
key and value, noting that JavaScript stores each character in 2
unspecified and may include per-entry overhead invisible to
clients.
*/
- capi.sqlite3_js_kvvfs_size = function callee(which=""){
- if( !which && cache.storagePool.local ){
+ capi.sqlite3_js_kvvfs_size = function callee(which="", emptyIsAName=false){
+ if( !which && !emptyIsAName ){
return callee('local') + callee('session');
}
const store = storageForZClass(which);
Added in version 3.?? (tenatively 3.52).
*/
- capi.sqlite3_js_kvvfs_export = function(storageName,includeJournal=true){
+ const sqlite3_js_kvvfs_export = function(storageName,includeJournal=true){
const store = storageForZClass(storageName);
if( !store ){
toss3(capi.SQLITE_NOTFOUND,
(v)=>rc.pages.push(pages[v])
);
return rc;
- }/* capi.sqlite3_js_kvvfs_export */;
+ }/* sqlite3_js_kvvfs_export */;
/**
INCOMPLETE. This interface is subject to change.
exp.name refers to a new storage name then if it throws, the name
does not get installed.
*/
- capi.sqlite3_js_kvvfs_import = function(exp, overwrite=false){
+ const sqlite3_js_kvvfs_import = function(exp, overwrite=false){
if( !exp?.timestamp
|| !exp.name
|| undefined===exp.size
toss3(capi.SQLITE_IOERR_ACCESS,
"Cannot import db storage while it is in use.");
}
- capi.sqlite3_js_kvvfs_clear(exp.name);
+ capi.sqlite3_js_kvvfs_clear(exp.name, true);
}else{
store = newStorageObj(exp.name);
//warn("Installing new storage:",store);
if( isNew ) installStorageAndJournal(store);
}catch(e){
if( !isNew ){
- try{capi.sqlite3_js_kvvfs_clear(exp.name);}
+ try{capi.sqlite3_js_kvvfs_clear(exp.name, true);}
catch(ee){/*ignored*/}
}
throw e;
return this;
};
+ /**
+ If no kvvfs storage exists with the given name, one is
+ installed. If one exists, its reference count is increased so
+ that it won't be freed by the closing of a database or journal
+ file.
+
+ Throws if the name is not valid for a new storage object.
+ */
+ const sqlite3_js_kvvfs_reserve = function(name){
+ let store = storageForZClass(name);
+ if( store ){
+ ++store.refc;
+ return;
+ }
+ validateStorageName(name);
+ installStorageAndJournal(newStorageObj(name));
+ };
+
/**
Adds an event listener to a kvvfs storage object. The idea is
that this can be used to asynchronously back up one kvvfs storage
- 'delete' gets the string-type key of the deleted record.
*/
- capi.sqlite3_js_kvvfs_listen = function(opt){
+ const sqlite3_js_kvvfs_listen = function(opt){
if( !opt || 'object'!==typeof opt ){
toss3(capi.SQLITE_MISUSE, "Expecting a listener object.");
}
let store = storageForZClass(opt.storage);
if( !store ){
if( opt.storage && opt.reserve ){
- capi.sqlite3_js_kvvfs_reserve(opt.storage);
+ sqlite3_js_kvvfs_reserve(opt.storage);
store = storageForZClass(opt.storage);
util.assert(store,
"Unexpectedly cannot fetch reserved storage "
This has no side effects if opt is invalid or is not a match for
any listeners.
*/
- capi.sqlite3_js_kvvfs_unlisten = function(opt){
+ const sqlite3_js_kvvfs_unlisten = function(opt){
const store = storageForZClass(opt?.storage);
if( store && opt.events ){
store.listeners = store.listeners.filter((v)=>v!==opt.events);
}
};
- /**
- If no kvvfs storage exists with the given name, one is
- installed. If one exists, its reference count is increased so
- that it won't be freed by the closing of a database or journal
- file.
-
- Throws if the name is not valid for a new storage object.
- */
- capi.sqlite3_js_kvvfs_reserve = function(name){
- let store = storageForZClass(name);
- if( store ){
- ++store.refc;
- return;
- }
- validateStorageName(name);
- installStorageAndJournal(newStorageObj(name));
- };
-
if(sqlite3?.oo1?.DB){
/**
Functionally equivalent to DB(storageName,'c','kvvfs') except
database blocks which were cleaned up.
*/
jdb.prototype.clearStorage = function(){
- return jdb.clearStorage(this.affirmOpen().filename);
+ return jdb.clearStorage(this.affirmOpen().filename, true);
};
/** Equivalent to sqlite3_js_kvvfs_size(). */
jdb.storageSize = capi.sqlite3_js_kvvfs_size;
up in its storage or throws if this instance has been closed.
*/
jdb.prototype.storageSize = function(){
- return jdb.storageSize(this.affirmOpen().filename);
+ return jdb.storageSize(this.affirmOpen().filename, true);
};
if( sqlite3.__isUnderTest ){
}/* __isUnderTest */
}/*sqlite3.oo1.JsStorageDb*/
+ /**
+ Public interface for kvvfs v2. The capi.sqlite3_js_kvvfs_...()
+ routines remain in place for v1. Some members of this class proxy
+ to those functions but use different default argument values in
+ some cases.
+ */
+ sqlite3.kvvfs = Object.assign(Object.create(null),{
+ reserve: sqlite3_js_kvvfs_reserve,
+ import: sqlite3_js_kvvfs_import,
+ export: sqlite3_js_kvvfs_export,
+ listen: sqlite3_js_kvvfs_listen,
+ unlisten: sqlite3_js_kvvfs_unlisten,
+ // DIFFERENT DEFAULTS for the second arguments:
+ size: (which,emptyIsAName=true)=>capi.sqlite3_js_kvvfs_size(which,emptyIsAName),
+ clear: (which,emptyIsAName=true)=>capi.sqlite3_js_kvvfs_clear(which,emptyIsAName),
+ });
+
})/*globalThis.sqlite3ApiBootstrap.initializers*/;
//#endif not omit-kvvfs
.assert( globalThis.sessionStorage===x.storage )
.assert( 'kvvfs-session-' === x.keyPrefix );
const filename = this.kvvfsDbFile = 'session';
- const unlink = this.kvvfsUnlink = ()=>JDb.clearStorage(filename);
+ const unlink = this.kvvfsUnlink = ()=>sqlite3.kvvfs.clear(filename);
unlink();
let db = new JDb(filename);
try {
const filename = 'localThread' /* preinstalled instance */;
const JDb = sqlite3.oo1.JsStorageDb;
const DB = sqlite3.oo1.DB;
- JDb.clearStorage(filename);
+ sqlite3.kvvfs.clear(filename);
let db = new JDb(filename);
const sqlSetup = [
'create table kvvfs(a);',
];
try {
T.assert( 0===db.storageSize(), "expecting 0 storage size" );
- //T.mustThrowMatching(()=>db.clearStorage(), /in-use/);
- db.clearStorage();
+ T.mustThrowMatching(()=>db.clearStorage(), /in-use/);
+ //db.clearStorage();
T.assert( 0===db.storageSize(), "expecting 0 storage size" );
db.exec(sqlSetup);
T.assert( 0<db.storageSize(), "expecting non-0 db size" );
- //T.mustThrowMatching(()=>db.clearStorage(), /in-use/);
- db.clearStorage(/*wiping everything out from under it*/);
- T.assert( 0===db.storageSize(), "expecting 0 storage size" );
- db.exec(sqlSetup/*that actually worked*/);
+ T.mustThrowMatching(()=>db.clearStorage(), /in-use/);
+ //db.clearStorage(/*wiping everything out from under it*/);
+ T.assert( 0<db.storageSize(), "expecting non-0 storage size" );
+ //db.exec(sqlSetup/*that actually worked*/);
+ /* Clearing the storage out from under the db does actually
+ work so long as we re-initialize it before reading.
+ It is tentatively disallowed for sanity's sake rather
+ than it not working.
+ */
T.assert( 0<db.storageSize(), "expecting non-0 db size" );
const close = ()=>{
db.close();
T.assert(3 === db.selectValue('select count(*) from kvvfs'));
close();
- const exportDb = capi.sqlite3_js_kvvfs_export;
+ const exportDb = sqlite3.kvvfs.export;
db = new JDb(filename);
db.exec('insert into kvvfs(a) values(4),(5),(6)');
T.assert(6 === db.selectValue('select count(*) from kvvfs'));
//console.warn("db.dbFilename() =",dbFilename);
T.assert(3 === db.selectValue('select count(*) from kvvfs'));
console.debug("kvvfs to Object:",exportDb(dbFilename));
- const n = capi.sqlite3_js_kvvfs_size( dbFilename );
+ const n = sqlite3.kvvfs.size( dbFilename );
T.assert( n>0, "Db size count failed" );
if( 1 ){
}, capi.SQLITE_RANGE);
try {
- const exportDb = capi.sqlite3_js_kvvfs_export;
+ const exportDb = sqlite3.kvvfs.export;
const dbFileRaw = 'file:'+filename+'?vfs=kvvfs&delete-on-close=1';
+ sqlite3.kvvfs.clear(filename);
db = new DB(dbFileRaw);
- capi.sqlite3_js_kvvfs_clear(filename);
db.exec(sqlSetup);
T.assert(3 === db.selectValue(sqlCount));
finally{ddb.close()}
}, /.*no such table: kvvfs.*/);
- const importDb = capi.sqlite3_js_kvvfs_import;
+ const importDb = sqlite3.kvvfs.import;
duo = new JDb(filename);
T.mustThrowMatching(()=>importDb(exp,true), /.*in use.*/);
duo.close();
}
}
};
- capi.sqlite3_js_kvvfs_listen(listener);
+ sqlite3.kvvfs.listen(listener);
const dbFileRaw = 'file:'+filename+'?vfs=kvvfs&delete-on-close=1';
db = new DB(dbFileRaw);
db.exec(sqlSetup);
.assert( counts.write )
.assert( counts.open===counts.close );
const before = JSON.stringify(counts);
- capi.sqlite3_js_kvvfs_unlisten(listener);
+ sqlite3.kvvfs.unlisten(listener);
db = new DB(dbFileRaw);
db.exec("delete from kvvfs");
db.close();
-C Add\san\sexplicit\srollback\stest\sfor\skvvfs.
-D 2025-11-25T16:07:05.776
+C Add\sthe\ssqlite3.kvvfs\snamespace\sfor\sthe\snew\skvvfs\sAPIs\sinstead\sof\sadding\smore\ssqlite3_js_kvvfs_...()\smethods.\sReinstate\sthat\sclearing\skvvfs\sstorage\sis\sillegal\swhen\sdb\shandles\sare\sopened,\ssolely\sfor\ssanity's\ssake\s(they\scan\sactually\srecover\sfrom\sthat\sbut\ssupporting\ssuch\suse\sfeels\sill-advised).
+D 2025-11-25T16:41:56.975
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
-F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 5eb75df70a029f042437a161994fa3bc15e38ad5ab1b2f3d56a48907a5563b8d
+F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js c9dcbfb0aca85c11491427c9980174294022a0982f6aaf8c6a8374fa5ca76c83
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js a2eea6442556867b589e04107796c6e1d04a472219529eeb45b7cd221d7d048b
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72a76124213cbc9469d757676da86
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a
F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
-F ext/wasm/tester1.c-pp.js 4f60d6b8543132556fb14195bd1cd890c0e2076981b686448bde05509a1f45df
+F ext/wasm/tester1.c-pp.js 5030080f96b0f85ce78e3937fffd51e2a54b32d1fd7e6d3bce6c6bf7dcc5646a
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P d391f1ce691fca4504c21a7e3e05a029f247da23d432ee34b0dae14be51d909c
-R c1d4fff97440a131249bd90e6bd13e0a
+P 2bf31ef8027a3e15887d4dcd26fe09463b5f8852c5ce443f7d07c23d29c37311
+R 30d74c08232d6eedb21ecc8d5c58c72f
U stephan
-Z f68b904bbc8cb67b750643f6622fc5c8
+Z 2911ac5a013b42fb37b269f1bdfc6178
# Remove this line to create a well-formed Fossil manifest.