]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite3.kvvfs namespace for the new kvvfs APIs instead of adding more sqlite3...
authorstephan <stephan@noemail.net>
Tue, 25 Nov 2025 16:41:56 +0000 (16:41 +0000)
committerstephan <stephan@noemail.net>
Tue, 25 Nov 2025 16:41:56 +0000 (16:41 +0000)
FossilOrigin-Name: 02793c5905e6b99379cd5ad6bfe1eb6cccf839da081fc174dce7b06245e212fb

ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js
ext/wasm/tester1.c-pp.js
manifest
manifest.uuid

index c161a3a4ba17d07d43fa6ff9756408597aa5894b..6bf7371cb12977b4c83be3964b10edaa5214ddc9 100644 (file)
@@ -876,22 +876,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
      - '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.
 
@@ -906,25 +901,23 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      - 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;
@@ -943,9 +936,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      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
@@ -957,8 +949,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      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);
@@ -1024,7 +1016,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
      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,
@@ -1071,7 +1063,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       (v)=>rc.pages.push(pages[v])
     );
     return rc;
-  }/* capi.sqlite3_js_kvvfs_export */;
+  }/* sqlite3_js_kvvfs_export */;
 
   /**
      INCOMPLETE. This interface is subject to change.
@@ -1099,7 +1091,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      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
@@ -1124,7 +1116,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
         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);
@@ -1142,7 +1134,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
       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;
@@ -1150,6 +1142,24 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     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
@@ -1189,14 +1199,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 
      - '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 "
@@ -1218,31 +1228,13 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
      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
@@ -1285,7 +1277,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
        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;
@@ -1294,7 +1286,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
        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 ){
@@ -1305,5 +1297,22 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
     }/* __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
index 637475590369c2d3365e37668b2e9ba7a8b3d1b0..9f9ed7e2e3a7548dce6b260f47b68f256953505f 100644 (file)
@@ -2893,7 +2893,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
           .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 {
@@ -2921,7 +2921,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
         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);',
@@ -2929,15 +2929,20 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
         ];
         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();
@@ -2946,7 +2951,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
           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'));
@@ -2967,7 +2972,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
           //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 ){
@@ -3015,10 +3020,10 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
         }, 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));
 
@@ -3036,7 +3041,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
             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();
@@ -3113,7 +3118,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
               }
             }
           };
-          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);
@@ -3125,7 +3130,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
             .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();
index 064faf88ac917eae46e153ce38ae559a0093965a..7103ec9a3e83b3d9cad7a7111861f472c59f9fe0 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -600,7 +600,7 @@ F ext/wasm/api/sqlite3-api-worker1.c-pp.js 1041dd645e8e821c082b628cd8d9acf70c667
 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
@@ -647,7 +647,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
 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
@@ -2178,8 +2178,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
 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.
index b7215ce6da192240bbf7820e785b7a828418bcbd..c62c523ce79825f312bac83d8488e0e52b912d57 100644 (file)
@@ -1 +1 @@
-2bf31ef8027a3e15887d4dcd26fe09463b5f8852c5ce443f7d07c23d29c37311
+02793c5905e6b99379cd5ad6bfe1eb6cccf839da081fc174dce7b06245e212fb