]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add new file missing from [3c4061428544].
authorstephan <stephan@noemail.net>
Fri, 21 Nov 2025 15:03:38 +0000 (15:03 +0000)
committerstephan <stephan@noemail.net>
Fri, 21 Nov 2025 15:03:38 +0000 (15:03 +0000)
FossilOrigin-Name: 41f94eca01d8317364aa60ddd8e5fe3cd21a215040ef271a157d450a914139d0

ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js [new file with mode: 0644]
manifest
manifest.uuid

diff --git a/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js b/ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js
new file mode 100644 (file)
index 0000000..c4f9109
--- /dev/null
@@ -0,0 +1,333 @@
+//#if not omit-kvvfs
+/*
+  2025-11-21
+
+  The author disclaims copyright to this source code.  In place of a
+  legal notice, here is a blessing:
+
+  *   May you do good and not evil.
+  *   May you find forgiveness for yourself and forgive others.
+  *   May you share freely, never taking more than you give.
+
+  ***********************************************************************
+
+  This file houses the "kvvfs" pieces of the JS API.
+
+  Main project home page: https://sqlite.org
+
+  Documentation home page: https://sqlite.org/wasm
+*/
+globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
+  'use strict';
+  /* We unregister the kvvfs VFS from Worker threads later on. */
+  const util = sqlite3.util,
+        capi = sqlite3.capi,
+        wasm = sqlite3.wasm,
+        sqlite3_kvvfs_methods = capi.sqlite3_kvvfs_methods,
+        pKvvfs = sqlite3.capi.sqlite3_vfs_find("kvvfs");
+  delete capi.sqlite3_kvvfs_methods /* this is JS plumbing, not part
+                                       of the public API */;
+  if( !pKvvfs ) return /* built without kvvfs */;
+
+  if( !util.isUIThread() ){
+    /* One test currently relies on this VFS not being visible
+       in Workers. If we add generic object storage, we can
+       retain this VFS in Workers. */
+    capi.sqlite3_vfs_unregister(pKvvfs);
+    return;
+  }
+
+    /**
+       Internal helper for sqlite3_js_kvvfs_clear() and friends.
+       Its argument should be one of ('local','session',"").
+    */
+  const __kvfsWhich = function(which){
+    const rc = Object.create(null);
+    rc.prefix = 'kvvfs-'+which;
+    rc.stores = [];
+    if('session'===which || ""===which) rc.stores.push(globalThis.sessionStorage);
+    if('local'===which || ""===which) rc.stores.push(globalThis.localStorage);
+    return rc;
+  };
+
+  /**
+     Clears all storage used by the kvvfs DB backend, deleting any
+     DB(s) stored there. Its argument must be either 'session',
+     'local', or "". In the first two cases, only sessionStorage
+     resp. localStorage is cleared. If it's an empty string (the
+     default) then both are cleared. Only storage keys which match
+     the pattern used by kvvfs are cleared: any other client-side
+     data are retained.
+
+     This function is only available in the main window thread.
+
+     Returns the number of entries cleared.
+  */
+  capi.sqlite3_js_kvvfs_clear = function(which=""){
+    let rc = 0;
+    const kvWhich = __kvfsWhich(which);
+    kvWhich.stores.forEach((s)=>{
+      const toRm = [] /* keys to remove */;
+      let i;
+      for( i = 0; i < s.length; ++i ){
+        const k = s.key(i);
+        if(k.startsWith(kvWhich.prefix)) toRm.push(k);
+      }
+      toRm.forEach((kk)=>s.removeItem(kk));
+      rc += toRm.length;
+    });
+    return rc;
+  };
+
+  /**
+     This routine guesses the approximate amount of
+     window.localStorage and/or window.sessionStorage in use by the
+     kvvfs database backend. Its argument must be one of ('session',
+     'local', ""). In the first two cases, only sessionStorage
+     resp. localStorage is counted. If it's an empty string (the
+     default) then both are counted. Only storage keys which match
+     the pattern used by kvvfs are counted. The returned value is
+     twice the "length" value of every matching key and value,
+     noting that JavaScript stores each character in 2 bytes.
+
+     The returned size is not authoritative from the perspective of
+     how much data can fit into localStorage and sessionStorage, as
+     the precise algorithms for determining those limits are
+     unspecified and may include per-entry overhead invisible to
+     clients.
+  */
+  capi.sqlite3_js_kvvfs_size = function(which=""){
+    let sz = 0;
+    const kvWhich = __kvfsWhich(which);
+    kvWhich.stores.forEach((s)=>{
+      let i;
+      for(i = 0; i < s.length; ++i){
+        const k = s.key(i);
+        if(k.startsWith(kvWhich.prefix)){
+          sz += k.length;
+          sz += s.getItem(k).length;
+        }
+      }
+    });
+    return sz * 2 /* because JS uses 2-byte char encoding */;
+  };
+
+  const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack;
+  const pstack = wasm.pstack;
+  const kvvfsStorage = (zClass)=>((115/*=='s'*/===wasm.peek(zClass))
+                                  ? sessionStorage : localStorage);
+
+  { /* Override native sqlite3_kvvfs_methods */
+    const kvvfsMethods = new sqlite3_kvvfs_methods(
+      /* Wraps the static sqlite3_api_methods singleton */
+      wasm.exports.sqlite3__wasm_kvvfs_methods()
+    );
+    try{
+      /**
+         Implementations for members of the object referred to by
+         sqlite3__wasm_kvvfs_methods(). We swap out the native
+         implementations with these, which use JS Storage for their
+         backing store.
+
+         The interface docs for these methods are in
+         src/os_kv.c:kvstorageRead(), kvstorageWrite(), and
+         kvstorageDelete().
+      */
+      for(const e of Object.entries({
+        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.cstrToJs(zXKey);
+            const jV = kvvfsStorage(zClass).getItem(jKey);
+            if(!jV) return -1;
+            const nV = jV.length /* 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.poke(zBuf, 0);
+              return nV;
+            }
+            const zV = wasm.scopedAllocCString(jV);
+            if(nBuf > nV + 1) nBuf = nV + 1;
+            wasm.heap8u().copyWithin(
+              Number(zBuf), Number(zV), wasm.ptr.addn(zV, nBuf,- 1)
+            );
+            wasm.poke(wasm.ptr.add(zBuf, nBuf, -1), 0);
+            return nBuf - 1;
+          }catch(e){
+            sqlite3.config.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.cstrToJs(zXKey);
+            kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData));
+            return 0;
+          }catch(e){
+            sqlite3.config.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.cstrToJs(zXKey));
+            return 0;
+          }catch(e){
+            sqlite3.config.error("kvstorageDelete()",e);
+            return capi.SQLITE_IOERR;
+          }finally{
+            pstack.restore(stack);
+          }
+        }
+      })){
+        kvvfsMethods[kvvfsMethods.memberKey(e[0])] =
+          wasm.installFunction(kvvfsMethods.memberSignature(e[0]), e[1]);
+      }
+    }finally{
+      kvvfsMethods.dispose();
+    }
+  }/* Override native sqlite3_api_methods */
+
+  /**
+     After initial refactoring to support the use of arbitrary Storage
+     objects (the interface from which localStorage and sessionStorage
+     dervie), we will apparently need to override some of the
+     associated sqlite3_vfs and sqlite3_io_methods members.
+
+     We can call back into the native impls when needed, but we need
+     to override certain operations here to bypass its strict
+     db-naming rules (which, funnily enough, are in place because
+     they're relevant (only) for this browser-side
+     implementation). Apropos: the port to generic objects would also
+     make non-persistent kvvfs available in Worker threads and
+     non-browser builds.
+  */
+  const eventualTodo = 1 || {
+    vfsMethods:{
+      /**
+      */
+      xOpen: function(pProtoVfs,zName,pProtoFile,flags,pOutFlags){},
+      xDelete: function(pVfs, zName, iSyncFlag){},
+      xAccess:function(pProtoVfs, zPath, flags, pResOut){},
+      xFullPathname: function(pVfs, zPath, nOut, zOut){},
+      xDlOpen: function(pVfs, zFilename){},
+      xSleep: function(pVfs,usec){},
+      xCurrentTime: function(pVfs,pOutDbl){},
+      xCurrentTimeInt64: function(pVfs,pOutI64){},
+      xRandomness: function(pVfs, nOut, pOut){
+        const heap = wasm.heap8u();
+        let i = 0;
+        const npOut = Number(pOut);
+        for(; i < nOut; ++i) heap[npOut + i] = (Math.random()*255000) & 0xFF;
+        return i;
+      }
+    },
+
+    /**
+       kvvfs has separate impls for some of the I/O methods,
+       depending on whether it's a db or journal file.
+    */
+    ioMethods:{
+      db:{
+        xClose: function(pFile){},
+        xRead: function(pFile,pTgt,n,iOff64){},
+        xWrite: function(pFile,pSrc,n,iOff64){},
+        xTruncate: function(pFile,i64){},
+        xSync: function(pFile,flags){},
+        xFileControl: function(pFile, opId, pArg){},
+        xFileSize: function(pFile,pi64Out){},
+        xLock: function(pFile,iLock){},
+        xUnlock: function(pFile,iLock){},
+        xCheckReservedLock: function(pFile,piOut){},
+        xFileControl: function(pFile,iOp,pArg){},
+        xSectorSize: function(pFile){},
+        xDeviceCharacteristics: function(pFile){}
+      },
+      jrnl:{
+        xClose: todoIOMethodsDb.xClose,
+        xRead: function(pFile,pTgt,n,iOff64){},
+        xWrite: function(pFile,pSrc,n,iOff64){},
+        xTruncate: function(pFile,i64){},
+        xSync: function(pFile,flags){},
+        xFileControl: function(pFile, opId, pArg){},
+        xFileSize: function(pFile,pi64Out){},
+        xLock: todoIOMethodsDb.xLock,
+        xUnlock: todoIOMethodsDb.xUnlock,
+        xCheckReservedLock: todoIOMethodsDb.xCheckReservedLock,
+        xFileControl: function(pFile,iOp,pArg){},
+        xSectorSize: todoIOMethodsDb.xSectorSize,
+        xDeviceCharacteristics: todoIOMethodsDb.xDeviceCharacteristics
+      }
+    }
+  }/*eventualTodo*/;
+
+  if(sqlite3?.oo1?.DB){
+    /**
+       Functionally equivalent to DB(storageName,'c','kvvfs') except
+       that it throws if the given storage name is not one of 'local'
+       or 'session'.
+
+       As of version 3.46, the argument may optionally be an options
+       object in the form:
+
+       {
+         filename: 'session'|'local',
+         ... etc. (all options supported by the DB ctor)
+       }
+
+       noting that the 'vfs' option supported by main DB
+       constructor is ignored here: the vfs is always 'kvvfs'.
+    */
+    sqlite3.oo1.JsStorageDb = function(
+      storageName = sqlite3.oo1.JsStorageDb.defaultStorageName
+    ){
+      const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...arguments);
+      storageName = opt.filename;
+      if('session'!==storageName && 'local'!==storageName){
+        toss3("JsStorageDb db name must be one of 'session' or 'local'.");
+      }
+      opt.vfs = 'kvvfs';
+      sqlite3.oo1.DB.dbCtorHelper.call(this, opt);
+    };
+    sqlite3.oo1.JsStorageDb.defaultStorageName = 'session';
+    const jdb = sqlite3.oo1.JsStorageDb;
+    jdb.prototype = Object.create(sqlite3.oo1.DB.prototype);
+    /** Equivalent to sqlite3_js_kvvfs_clear(). */
+    jdb.clearStorage = capi.sqlite3_js_kvvfs_clear;
+    /**
+       Clears this database instance's storage or throws if this
+       instance has been closed. Returns the number of
+       database blocks which were cleaned up.
+    */
+    jdb.prototype.clearStorage = function(){
+      return jdb.clearStorage(this.affirmDbOpen().filename);
+    };
+    /** Equivalent to sqlite3_js_kvvfs_size(). */
+    jdb.storageSize = capi.sqlite3_js_kvvfs_size;
+    /**
+       Returns the _approximate_ number of bytes this database takes
+       up in its storage or throws if this instance has been closed.
+    */
+    jdb.prototype.storageSize = function(){
+      return jdb.storageSize(this.affirmDbOpen().filename);
+    };
+  }/*sqlite3.oo1.JsStorageDb*/
+
+})/*globalThis.sqlite3ApiBootstrap.initializers*/;
+//#endif not omit-kvvfs
index b2773d549f156ec951ea0a25c1566b71cb5ad8b1..eaff89674fb38ee3438540492b4a38a336f4f329 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Enhance\sALTER\sTABLE\sto\ssupport\sadding\sand\sremoving\sNOT\sNULL\sand\sCHECK\nconstraints.
-D 2025-11-21T14:15:56.853
+C Add\snew\sfile\smissing\sfrom\s[3c4061428544].
+D 2025-11-21T15:03:38.538
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -600,6 +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 f44a4396b2305b27dc81c00a1629fe4f615520f7fb11ed4e606255e365956ba2
 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 26cb41d5a62f46a106b6371eb00fef02de3cdbfaa51338ba087a45f53028e0d0
 F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js aa330fa0e8ef35cbd92eb0d52e05fbaa07e61540c5cb164e693c82428ce1d763
 F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 9097074724172e31e56ce20ccd7482259cf72a76124213cbc9469d757676da86
@@ -2177,9 +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 e1ba175124be83da4db6d5d4e583b9b3b7dcb82e983c6f185d590469dcdc3139 57555d75daa2ee8345f8329749841a322b3e57679e5c4899ef749c8bc814812d
-R a08830703de06847124f417f6313a8fd
-T +closed 57555d75daa2ee8345f8329749841a322b3e57679e5c4899ef749c8bc814812d
-U drh
-Z c52ca5465c06951a7373da17d60cecb6
+P 895498e4431e02cff65a5d96db22f0b0cb9c96aedf1e3cdcdeb3c34c6fec432b
+R ce0350baf4d1de88228e71ca89be9093
+U stephan
+Z 923ff40315e60b496c7ed96ee0be8e80
 # Remove this line to create a well-formed Fossil manifest.
index 47c7899bd5d2113a0429e73ce47318d2ea9d1867..675d8849ad4b499e08f77bdffbd49a77ebda571c 100644 (file)
@@ -1 +1 @@
-895498e4431e02cff65a5d96db22f0b0cb9c96aedf1e3cdcdeb3c34c6fec432b
+41f94eca01d8317364aa60ddd8e5fe3cd21a215040ef271a157d450a914139d0