From bb4428e60589fc24fb4d41804c5a8f4479d2dd2a Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 5 Jan 2026 17:28:33 +0000 Subject: [PATCH 01/17] Add the experimental tmstmpvfs.c extension that adds a timestamp and other debugging information on each page of a database as that page is written, if the database is configured for exactly 16 bytes of reserve space. FossilOrigin-Name: 703e593dfc92676a2d44c67ca8282a78a1943b9c1e3f2447c0a9917d70a383c4 --- ext/misc/tmstmpvfs.c | 684 +++++++++++++++++++++++++++++++++++++++++++ manifest | 16 +- manifest.tags | 4 +- manifest.uuid | 2 +- 4 files changed, 697 insertions(+), 9 deletions(-) create mode 100644 ext/misc/tmstmpvfs.c diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c new file mode 100644 index 0000000000..661a2f6561 --- /dev/null +++ b/ext/misc/tmstmpvfs.c @@ -0,0 +1,684 @@ +/* +** 2026-01-05 +** +** 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 implements a VFS shim that writes a timestamp and other tracing +** information into reserved space at the end of each page of the database +** file. The additional data is written as the page is added to the WAL +** file for databases in WAL mode, or as the database file itself is modified +** in rollback modes. +** +** COMPILING +** +** To build this extension as a separately loaded shared library or +** DLL, use compiler command-lines similar to the following: +** +** (linux) gcc -fPIC -shared tmstmpvfs.c -o tmstmpvfs.so +** (mac) clang -fPIC -dynamiclib tmstmpvfs.c -o tmstmpvfs.dylib +** (windows) cl tmstmpvfs.c -link -dll -out:tmstmpvfs.dll +** +** You may want to add additional compiler options, of course, +** according to the needs of your project. +** +** LOADING +** +** To load this extension as a shared library, you first have to +** bring up a dummy SQLite database connection to use as the argument +** to the sqlite3_load_extension() API call. Then you invoke the +** sqlite3_load_extension() API and shutdown the dummy database +** connection. All subsequent database connections that are opened +** will include this extension. For example: +** +** sqlite3 *db; +** sqlite3_open(":memory:", &db); +** sqlite3_load_extension(db, "./tmstmpvfs"); +** sqlite3_close(db); +** +** Tmstmpvfs is a VFS Shim. When loaded, "tmstmpvfs" becomes the new +** default VFS and it uses the prior default VFS as the next VFS +** down in the stack. This is normally what you want. However, in +** complex situations where multiple VFS shims are being loaded, +** it might be important to ensure that tmstmpvfs is loaded in the +** correct order so that it sequences itself into the default VFS +** Shim stack in the right order. +** +** USING +** +** Open database connections using the sqlite3_open() or +** sqlite3_open_v2() interfaces, as normal. Ordinary database files +** (without a timestamp) will operate normally. +** +** Timestamping only works on databases that have a reserve-bytes +** value of exactly 16. The default value for reserve-bytes is 0. +** Hence, newly created database files will omit the timestamp by +** default. To create a database that includes a timestamp, change +** the reserve-bytes value to 16 by running: +** +** int n = 16; +** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); +** +** If you do this immediately after creating a new database file, +** before anything else has been written into the file, then that +** might be all that you need to do. Otherwise, the API call +** above should be followed by: +** +** sqlite3_exec(db, "VACUUM", 0, 0, 0); +** +** It never hurts to run the VACUUM, even if you don't need it. +** +** From the CLI, use the ".filectrl reserve_bytes 16" command, +** followed by "VACUUM;". +** +** Note that SQLite allows the number of reserve-bytes to be +** increased but not decreased. So if a database file already +** has a reserve-bytes value greater than 16, there is no way to +** activate timestamping on that database, other than to dump +** and restore the database file. Note also that other extensions +** might also make use of the reserve-bytes. Timestamping will +** be incompatible with those other extensions. +** +** IMPLEMENTATION NOTES +** +** The timestamp information is stored in the last 16 bytes of each page. +** This module only operates if the "bytes of reserved space on each page" +** value at offset 20 the SQLite database header is exactly 16. If +** the reserved-space value is not 16, this module is a no-op. +** +** The timestamp layout is as follows: +** +** bytes 0-5 Milliseconds since the Unix Epoch +** bytes 6-9 WAL frame number +** bytes 10-12 Lower 24 bits of Salt-1 +** byte 13 bit 0 (0x01) set if last frame of a transaction +** bytes 14,15 Reserved for future expansion +** +** For transactions that occur in rollback mode, bytes 6-15 are all +** zero. +*/ +#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_TMSTMPVFS_STATIC) +# define SQLITE_TMSTMPVFS_STATIC +#endif +#ifdef SQLITE_TMSTMPVFS_STATIC +# include "sqlite3.h" +#else +# include "sqlite3ext.h" + SQLITE_EXTENSION_INIT1 +#endif +#include +#include + + +/* +** Forward declaration of objects used by this utility +*/ +typedef struct sqlite3_vfs TmstmpVfs; +typedef struct TmstmpFile TmstmpFile; + +/* +** Bytes of reserved space used by this extension +*/ +#define TMSTMP_RESERVE 16 + +/* +** The magic number used to identify TmstmpFile objects +*/ +#define TMSTMP_MAGIC 0x2a87b72d + +/* +** Useful datatype abbreviations +*/ +#if !defined(SQLITE_AMALGAMATION) + typedef unsigned char u8; + typedef unsigned int u32; +#endif + +/* Access to a lower-level VFS that (might) implement dynamic loading, +** access to randomness, etc. +*/ +#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) +#define ORIGFILE(p) ((sqlite3_file*)(((TmstmpFile*)(p))+1)) + +/* An open WAL file */ +struct TmstmpFile { + sqlite3_file base; /* IO methods */ + u32 uMagic; /* Magic number for sanity checking */ + u32 salt1; /* Last WAL salt-1 value */ + u32 iFrame; /* Last WAL frame number */ + u8 isWal; /* True if this is a WAL file */ + u8 isDb; /* True if this is a DB file */ + u8 isCommit; /* Last WAL frame header was a transaction commit */ + u8 hasCorrectReserve; /* File has the correct reserve size */ + TmstmpFile *pPartner; /* DB->WAL or WAL->DB mapping */ + sqlite3_int64 iOfst; /* Offset of last WAL frame header */ + sqlite3_vfs *pSubVfs; /* Underlying VFS */ +}; + + +/* +** Methods for TmstmpFile +*/ +static int tmstmpClose(sqlite3_file*); +static int tmstmpRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); +static int tmstmpWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); +static int tmstmpTruncate(sqlite3_file*, sqlite3_int64 size); +static int tmstmpSync(sqlite3_file*, int flags); +static int tmstmpFileSize(sqlite3_file*, sqlite3_int64 *pSize); +static int tmstmpLock(sqlite3_file*, int); +static int tmstmpUnlock(sqlite3_file*, int); +static int tmstmpCheckReservedLock(sqlite3_file*, int *pResOut); +static int tmstmpFileControl(sqlite3_file*, int op, void *pArg); +static int tmstmpSectorSize(sqlite3_file*); +static int tmstmpDeviceCharacteristics(sqlite3_file*); +static int tmstmpShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); +static int tmstmpShmLock(sqlite3_file*, int offset, int n, int flags); +static void tmstmpShmBarrier(sqlite3_file*); +static int tmstmpShmUnmap(sqlite3_file*, int deleteFlag); +static int tmstmpFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); +static int tmstmpUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); + +/* +** Methods for TmstmpVfs +*/ +static int tmstmpOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); +static int tmstmpDelete(sqlite3_vfs*, const char *zName, int syncDir); +static int tmstmpAccess(sqlite3_vfs*, const char *zName, int flags, int *); +static int tmstmpFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); +static void *tmstmpDlOpen(sqlite3_vfs*, const char *zFilename); +static void tmstmpDlError(sqlite3_vfs*, int nByte, char *zErrMsg); +static void (*tmstmpDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); +static void tmstmpDlClose(sqlite3_vfs*, void*); +static int tmstmpRandomness(sqlite3_vfs*, int nByte, char *zOut); +static int tmstmpSleep(sqlite3_vfs*, int microseconds); +static int tmstmpCurrentTime(sqlite3_vfs*, double*); +static int tmstmpGetLastError(sqlite3_vfs*, int, char *); +static int tmstmpCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); +static int tmstmpSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); +static sqlite3_syscall_ptr tmstmpGetSystemCall(sqlite3_vfs*, const char *z); +static const char *tmstmpNextSystemCall(sqlite3_vfs*, const char *zName); + +static sqlite3_vfs tmstmp_vfs = { + 3, /* iVersion (set when registered) */ + 0, /* szOsFile (set when registered) */ + 1024, /* mxPathname */ + 0, /* pNext */ + "tmstmpvfs", /* zName */ + 0, /* pAppData (set when registered) */ + tmstmpOpen, /* xOpen */ + tmstmpDelete, /* xDelete */ + tmstmpAccess, /* xAccess */ + tmstmpFullPathname, /* xFullPathname */ + tmstmpDlOpen, /* xDlOpen */ + tmstmpDlError, /* xDlError */ + tmstmpDlSym, /* xDlSym */ + tmstmpDlClose, /* xDlClose */ + tmstmpRandomness, /* xRandomness */ + tmstmpSleep, /* xSleep */ + tmstmpCurrentTime, /* xCurrentTime */ + tmstmpGetLastError, /* xGetLastError */ + tmstmpCurrentTimeInt64, /* xCurrentTimeInt64 */ + tmstmpSetSystemCall, /* xSetSystemCall */ + tmstmpGetSystemCall, /* xGetSystemCall */ + tmstmpNextSystemCall /* xNextSystemCall */ +}; + +static const sqlite3_io_methods tmstmp_io_methods = { + 3, /* iVersion */ + tmstmpClose, /* xClose */ + tmstmpRead, /* xRead */ + tmstmpWrite, /* xWrite */ + tmstmpTruncate, /* xTruncate */ + tmstmpSync, /* xSync */ + tmstmpFileSize, /* xFileSize */ + tmstmpLock, /* xLock */ + tmstmpUnlock, /* xUnlock */ + tmstmpCheckReservedLock, /* xCheckReservedLock */ + tmstmpFileControl, /* xFileControl */ + tmstmpSectorSize, /* xSectorSize */ + tmstmpDeviceCharacteristics, /* xDeviceCharacteristics */ + tmstmpShmMap, /* xShmMap */ + tmstmpShmLock, /* xShmLock */ + tmstmpShmBarrier, /* xShmBarrier */ + tmstmpShmUnmap, /* xShmUnmap */ + tmstmpFetch, /* xFetch */ + tmstmpUnfetch /* xUnfetch */ +}; + +/* +** SQL function: tmstmp_init(SCHEMANAME) +** +** This SQL functions invokes: +** +** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); +** +** In order to set the reserve bytes value to 16, so that tmstmpvfs will +** operation. This interface is undocumented, apart from this comment. +** Usage example: +** +** SELECT tmstmp_init('main'); VACUUM; +*/ +static void tmstmpInitFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + int nByte = TMSTMP_RESERVE; + const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); +} + + +/* +** Close a connection +*/ +static int tmstmpClose(sqlite3_file *pFile){ + TmstmpFile *p = (TmstmpFile *)pFile; + if( p->pPartner ){ + assert( p->pPartner->pPartner==p ); + p->pPartner->pPartner = 0; + p->pPartner = 0; + } + pFile = ORIGFILE(pFile); + return pFile->pMethods->xClose(pFile); +} + +/* +** Read bytes from a file +*/ +static int tmstmpRead( + sqlite3_file *pFile, + void *zBuf, + int iAmt, + sqlite_int64 iOfst +){ + int rc; + TmstmpFile *p = (TmstmpFile*)pFile; + pFile = ORIGFILE(pFile); + rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); + if( rc==SQLITE_OK + && p->isDb + && iOfst==0 + && iAmt>=100 + ){ + p->hasCorrectReserve = (((u8*)zBuf)[20]==TMSTMP_RESERVE); + if( p->pPartner ){ + p->pPartner->hasCorrectReserve = p->hasCorrectReserve; + } + } + return rc; +} + +/* +** Write data to a tmstmp-file. +*/ +static int tmstmpWrite( + sqlite3_file *pFile, + const void *zBuf, + int iAmt, + sqlite_int64 iOfst +){ + TmstmpFile *p = (TmstmpFile*)pFile; + sqlite3_file *pSub = ORIGFILE(pFile); + if( !p->hasCorrectReserve ){ + /* The database does not have the correct reserve size. No-op */ + }else if( p->isWal ){ + /* Writing into a WAL file */ + if( iAmt==24 ){ + /* A frame header */ + u32 x; + memcpy(&p->iFrame, zBuf, 4); + memcpy(&p->salt1, zBuf+8, 4); + memcpy(&x, zBuf+4, 4); + p->isCommit = (x!=0); + p->iOfst = iOfst; + }else if( iAmt>=512 && iOfst==p->iOfst+24 ){ + sqlite3_uint64 tm = 0; + int rc; + unsigned char *s = (unsigned char*)zBuf+iAmt-TMSTMP_RESERVE; + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &tm); + memset(s, 0, TMSTMP_RESERVE); + s[0] = (tm>>40)&0xff; + s[1] = (tm>>32)&0xff; + s[2] = (tm>>24)&0xff; + s[3] = (tm>>16)&0xff; + s[4] = (tm>>8)&0xff; + s[5] = tm&0xff; + memcpy(&s[9], &p->salt1, 4); + memcpy(&s[6], &p->iFrame, 4); + s[13] = p->isCommit ? 1 : 0; + } + }else if( p->pPartner==0 ){ + /* Writing into a database in rollback mode */ + sqlite3_uint64 tm = 0; + unsigned char *s = (unsigned char*)zBuf+iAmt-TMSTMP_RESERVE; + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &tm); + memset(s, 0, TMSTMP_RESERVE); + s[0] = (tm>>40)&0xff; + s[1] = (tm>>32)&0xff; + s[2] = (tm>>24)&0xff; + s[3] = (tm>>16)&0xff; + s[4] = (tm>>8)&0xff; + s[5] = tm&0xff; + } + return pSub->pMethods->xWrite(pSub,zBuf,iAmt,iOfst); +} + +/* +** Truncate a tmstmp-file. +*/ +static int tmstmpTruncate(sqlite3_file *pFile, sqlite_int64 size){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xTruncate(pFile, size); +} + +/* +** Sync a tmstmp-file. +*/ +static int tmstmpSync(sqlite3_file *pFile, int flags){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xSync(pFile, flags); +} + +/* +** Return the current file-size of a tmstmp-file. +*/ +static int tmstmpFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ + TmstmpFile *p = (TmstmpFile *)pFile; + pFile = ORIGFILE(p); + return pFile->pMethods->xFileSize(pFile, pSize); +} + +/* +** Lock a tmstmp-file. +*/ +static int tmstmpLock(sqlite3_file *pFile, int eLock){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xLock(pFile, eLock); +} + +/* +** Unlock a tmstmp-file. +*/ +static int tmstmpUnlock(sqlite3_file *pFile, int eLock){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xUnlock(pFile, eLock); +} + +/* +** Check if another file-handle holds a RESERVED lock on a tmstmp-file. +*/ +static int tmstmpCheckReservedLock(sqlite3_file *pFile, int *pResOut){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xCheckReservedLock(pFile, pResOut); +} + +/* +** File control method. For custom operations on a tmstmp-file. +*/ +static int tmstmpFileControl(sqlite3_file *pFile, int op, void *pArg){ + int rc; + TmstmpFile *p = (TmstmpFile*)pFile; + pFile = ORIGFILE(pFile); + rc = pFile->pMethods->xFileControl(pFile, op, pArg); + if( rc==SQLITE_OK + && op==SQLITE_FCNTL_VFSNAME + && p->hasCorrectReserve + ){ + *(char**)pArg = sqlite3_mprintf("tmstmp/%z", *(char**)pArg); + } + return rc; +} + +/* +** Return the sector-size in bytes for a tmstmp-file. +*/ +static int tmstmpSectorSize(sqlite3_file *pFile){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xSectorSize(pFile); +} + +/* +** Return the device characteristic flags supported by a tmstmp-file. +*/ +static int tmstmpDeviceCharacteristics(sqlite3_file *pFile){ + int devchar = 0; + pFile = ORIGFILE(pFile); + devchar = pFile->pMethods->xDeviceCharacteristics(pFile); + return (devchar & ~SQLITE_IOCAP_SUBPAGE_READ); +} + +/* Create a shared memory file mapping */ +static int tmstmpShmMap( + sqlite3_file *pFile, + int iPg, + int pgsz, + int bExtend, + void volatile **pp +){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); +} + +/* Perform locking on a shared-memory segment */ +static int tmstmpShmLock(sqlite3_file *pFile, int offset, int n, int flags){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmLock(pFile,offset,n,flags); +} + +/* Memory barrier operation on shared memory */ +static void tmstmpShmBarrier(sqlite3_file *pFile){ + pFile = ORIGFILE(pFile); + pFile->pMethods->xShmBarrier(pFile); +} + +/* Unmap a shared memory segment */ +static int tmstmpShmUnmap(sqlite3_file *pFile, int deleteFlag){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xShmUnmap(pFile,deleteFlag); +} + +/* Fetch a page of a memory-mapped file */ +static int tmstmpFetch( + sqlite3_file *pFile, + sqlite3_int64 iOfst, + int iAmt, + void **pp +){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); +} + +/* Release a memory-mapped page */ +static int tmstmpUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ + pFile = ORIGFILE(pFile); + return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); +} + + +/* +** Open a tmstmp file handle. +*/ +static int tmstmpOpen( + sqlite3_vfs *pVfs, + const char *zName, + sqlite3_file *pFile, + int flags, + int *pOutFlags +){ + TmstmpFile *p, *pDb; + sqlite3_file *pSubFile; + sqlite3_vfs *pSubVfs; + int rc; + pSubVfs = ORIGVFS(pVfs); + if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ + /* If the file is not a persistent database or a WAL file, then + ** bypass the timestamp logic all together */ + return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); + } + if( (flags & SQLITE_OPEN_WAL)!=0 ){ + pDb = (TmstmpFile*)sqlite3_database_file_object(zName); + if( pDb==0 + || pDb->uMagic!=TMSTMP_MAGIC + || !pDb->isDb + || pDb->pPartner!=0 + ){ + return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); + } + }else{ + pDb = 0; + } + p = (TmstmpFile*)pFile; + memset(p, 0, sizeof(*p)); + pSubFile = ORIGFILE(pFile); + pFile->pMethods = &tmstmp_io_methods; + p->pSubVfs = pSubVfs; + p->uMagic = TMSTMP_MAGIC; + rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); + if( rc ) goto tmstmp_open_done; + if( pDb!=0 ){ + p->isWal = 1; + p->pPartner = pDb; + pDb->pPartner = p; + }else{ + p->isDb = 1; + } + +tmstmp_open_done: + if( rc ) pFile->pMethods = 0; + return rc; +} + +/* +** All VFS interfaces other than xOpen are passed down into the Sub-VFS. +*/ +static int tmstmpDelete(sqlite3_vfs *p, const char *zName, int syncDir){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xDelete(pSub,zName,syncDir); +} +static int tmstmpAccess(sqlite3_vfs *p, const char *zName, int flags, int *pR){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xAccess(pSub,zName,flags,pR); +} +static int tmstmpFullPathname(sqlite3_vfs*p,const char *zName,int n,char *zOut){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xFullPathname(pSub,zName,n,zOut); +} +static void *tmstmpDlOpen(sqlite3_vfs *p, const char *zFilename){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xDlOpen(pSub,zFilename); +} +static void tmstmpDlError(sqlite3_vfs *p, int nByte, char *zErrMsg){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xDlError(pSub,nByte,zErrMsg); +} +static void(*tmstmpDlSym(sqlite3_vfs *p, void *pDl, const char *zSym))(void){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xDlSym(pSub,pDl,zSym); +} +static void tmstmpDlClose(sqlite3_vfs *p, void *pDl){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xDlClose(pSub,pDl); +} +static int tmstmpRandomness(sqlite3_vfs *p, int nByte, char *zOut){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xRandomness(pSub,nByte,zOut); +} +static int tmstmpSleep(sqlite3_vfs *p, int microseconds){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xSleep(pSub,microseconds); +} +static int tmstmpCurrentTime(sqlite3_vfs *p, double *prNow){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xCurrentTime(pSub,prNow); +} +static int tmstmpGetLastError(sqlite3_vfs *p, int a, char *b){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xGetLastError(pSub,a,b); +} +static int tmstmpCurrentTimeInt64(sqlite3_vfs *p, sqlite3_int64 *piNow){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xCurrentTimeInt64(pSub,piNow); +} +static int tmstmpSetSystemCall(sqlite3_vfs *p, const char *zName, + sqlite3_syscall_ptr x){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xSetSystemCall(pSub,zName,x); +} +static sqlite3_syscall_ptr tmstmpGetSystemCall(sqlite3_vfs *p, const char *z){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xGetSystemCall(pSub,z); +} +static const char *tmstmpNextSystemCall(sqlite3_vfs *p, const char *zName){ + sqlite3_vfs *pSub = ORIGVFS(p); + return pSub->xNextSystemCall(pSub,zName); +} + +/* +** Register the tmstmp VFS as the default VFS for the system. +*/ +static int tmstmpRegisterVfs(void){ + int rc = SQLITE_OK; + sqlite3_vfs *pOrig = sqlite3_vfs_find(0); + if( pOrig==0 ) return SQLITE_ERROR; + if( pOrig==&tmstmp_vfs ) return SQLITE_OK; + tmstmp_vfs.iVersion = pOrig->iVersion; + tmstmp_vfs.pAppData = pOrig; + tmstmp_vfs.szOsFile = pOrig->szOsFile + sizeof(TmstmpFile); + rc = sqlite3_vfs_register(&tmstmp_vfs, 1); + return rc; +} + +#if defined(SQLITE_TMSTMPVFS_STATIC) +/* This variant of the initializer runs when the extension is +** statically linked. +*/ +int sqlite3_register_tmstmpvfs(const char *NotUsed){ + (void)NotUsed; + return tmstmpRegisterVfs(); +} +int sqlite3_unregister_tmstmpvfs(void){ + if( sqlite3_vfs_find("tmstmpvfs") ){ + sqlite3_vfs_unregister(&tmstmp_vfs); + sqlite3_cancel_auto_extension((void(*)(void))tmstmpRegisterFunc); + } + return SQLITE_OK; +} +#endif /* defined(SQLITE_TMSTMPVFS_STATIC */ + +#if !defined(SQLITE_TMSTMPVFS_STATIC) +/* This variant of the initializer function is used when the +** extension is shared library to be loaded at run-time. +*/ +#ifdef _WIN32 +__declspec(dllexport) +#endif +/* +** This routine is called by sqlite3_load_extension() when the +** extension is first loaded. +***/ +int sqlite3_tmstmpvfs_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc; + SQLITE_EXTENSION_INIT2(pApi); + (void)pzErrMsg; /* not used */ +#ifdef SQLITE_TMSTMPVFS_INIT_FUNCNAME + rc = sqlite3_create_function(db, SQLITE_TMSTMPVFS_INIT_FUNCTNAME, 1, + SQLITE_UTF8, 0, tmstmpInitFunc, 0, 0); + if( rc ) return rc; +#endif + rc = tmstmpRegisterVfs(); + if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; + return rc; +} +#endif /* !defined(SQLITE_TMSTMPVFS_STATIC) */ diff --git a/manifest b/manifest index bdb09cfb8f..0877dc6056 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\suninitialized\svar\suse\sreported\sin\s[forum:88561a4a1e|forum\spost\s88561a4a1e]. -D 2026-01-04T11:05:05.639 +C Add\sthe\sexperimental\stmstmpvfs.c\sextension\sthat\sadds\sa\stimestamp\sand\sother\ndebugging\sinformation\son\seach\spage\sof\sa\sdatabase\sas\sthat\spage\sis\swritten,\nif\sthe\sdatabase\sis\sconfigured\sfor\sexactly\s16\sbytes\sof\sreserve\sspace. +D 2026-01-05T17:28:33.434 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,6 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b +F ext/misc/tmstmpvfs.c 742c76f7e6705c547a66932186decf3097a5c3e36a57b84582c64c95994f54f8 F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2189,8 +2190,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f60e863e0ca2d8ab853fa5f48d3cd7b062b13167fcddffc4563bde9285b92320 -R 4acf967c5b59de5937342771fb22d43f -U stephan -Z d4f1135862bcdc1161b210d6bfccd00f +P 707c0f6442e946f23de061ee2753eb5994ab55d411c49b232799f309ba0f10cf +R eebbc04e39ff5bc6f1027ece05be9308 +T *branch * timestamp-vfs +T *sym-timestamp-vfs * +T -sym-trunk * +U drh +Z edde794cfb79a18a07337a2e938e02dc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..72032ee788 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch timestamp-vfs +tag timestamp-vfs diff --git a/manifest.uuid b/manifest.uuid index 5737a874f4..5eb1b96438 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -707c0f6442e946f23de061ee2753eb5994ab55d411c49b232799f309ba0f10cf +703e593dfc92676a2d44c67ca8282a78a1943b9c1e3f2447c0a9917d70a383c4 From d3c9cce43cdd93075e346e17f74de5412acaf490 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 6 Jan 2026 20:51:06 +0000 Subject: [PATCH 02/17] Enhance the timestamp-vfs prototype so that it also keeps an event log. FossilOrigin-Name: f087c6c0cdd542ec24b4668fff9cb434f46caf554f8856a49fd062ab3f72014e --- ext/misc/tmstmpvfs.c | 243 ++++++++++++++++++++++++++++++++----------- manifest | 15 ++- manifest.uuid | 2 +- 3 files changed, 187 insertions(+), 73 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 661a2f6561..0bfd84693a 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -94,14 +94,34 @@ ** ** The timestamp layout is as follows: ** -** bytes 0-5 Milliseconds since the Unix Epoch -** bytes 6-9 WAL frame number -** bytes 10-12 Lower 24 bits of Salt-1 -** byte 13 bit 0 (0x01) set if last frame of a transaction -** bytes 14,15 Reserved for future expansion +** bytes 0,1 Zero. Reserved for future expansion +** bytes 2-7 Milliseconds since the Unix Epoch +** bytes 8-11 WAL frame number +** bytes 12 0: WAL write 1: WAL txn 2: rollback write +** bytes 13-15 Lower 24 bits of Salt-1 ** ** For transactions that occur in rollback mode, bytes 6-15 are all ** zero. +** +** LOGGING +** +** Every open VFS creates a log file. The Database connection and the +** WAL connection are both logged to the same file. If the name of the +** database file is BASE then the logfile is named something like: +** +** BASE-tmstmp-UNIQUEID +** +** Where UNIQUEID is a character string that is unique to that particular +** connection. The log consists of 16-byte records. Each record consists +** of five unsigned integers: +** +** 1 1 6 4 4 <--- bytes +** op a1 ts a2 a3 +** +** The meanings of the a1-a3 values depend on op. ts is the timestamp +** in milliseconds since 1970-01-01. (6 bytes is sufficient for timestamps +** for almost 9000 years.) Opcodes are defined by the ELOG_* #defines +** below. */ #if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_TMSTMPVFS_STATIC) # define SQLITE_TMSTMPVFS_STATIC @@ -114,7 +134,7 @@ #endif #include #include - +#include /* ** Forward declaration of objects used by this utility @@ -140,6 +160,17 @@ typedef struct TmstmpFile TmstmpFile; typedef unsigned int u32; #endif +/* +** Current process id +*/ +#if defined(_WIN32) +# include +# define GETPID (u32)GetCurrentProcessId() +#else +# include +# define GETPID (u32)getpid() +#endif + /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ @@ -152,15 +183,32 @@ struct TmstmpFile { u32 uMagic; /* Magic number for sanity checking */ u32 salt1; /* Last WAL salt-1 value */ u32 iFrame; /* Last WAL frame number */ + u32 pgno; /* Current page number */ + u32 pgsz; /* Size of each page, in bytes */ u8 isWal; /* True if this is a WAL file */ u8 isDb; /* True if this is a DB file */ u8 isCommit; /* Last WAL frame header was a transaction commit */ u8 hasCorrectReserve; /* File has the correct reserve size */ + u8 inCkpt; /* True if in a checkpoint */ + FILE *log; /* Write logging records on this file. DB only */ TmstmpFile *pPartner; /* DB->WAL or WAL->DB mapping */ sqlite3_int64 iOfst; /* Offset of last WAL frame header */ sqlite3_vfs *pSubVfs; /* Underlying VFS */ }; +/* +** Event log opcodes +*/ +#define ELOG_OPEN_DB 0x01 +#define ELOG_OPEN_WAL 0x02 +#define ELOG_WAL_PAGE 0x03 +#define ELOG_DB_PAGE 0x04 +#define ELOG_CKPT_START 0x05 +#define ELOG_CKPT_PAGE 0x06 +#define ELOG_CKPT_DONE 0x07 +#define ELOG_WAL_RESET 0x08 +#define ELOG_CLOSE_WAL 0x0e +#define ELOG_CLOSE_DB 0x0f /* ** Methods for TmstmpFile @@ -252,35 +300,70 @@ static const sqlite3_io_methods tmstmp_io_methods = { }; /* -** SQL function: tmstmp_init(SCHEMANAME) -** -** This SQL functions invokes: -** -** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); -** -** In order to set the reserve bytes value to 16, so that tmstmpvfs will -** operation. This interface is undocumented, apart from this comment. -** Usage example: -** -** SELECT tmstmp_init('main'); VACUUM; +** Write a 6-byte millisecond timestamp into aOut[] */ -static void tmstmpInitFunc( - sqlite3_context *context, - int argc, - sqlite3_value **argv -){ - int nByte = TMSTMP_RESERVE; - const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); - sqlite3 *db = sqlite3_context_db_handle(context); - sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); +static void tmstmpPutTS(TmstmpFile *p, unsigned char *aOut){ + sqlite3_uint64 tm = 0; + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &tm); + aOut[0] = (tm>>40)&0xff; + aOut[1] = (tm>>32)&0xff; + aOut[2] = (tm>>24)&0xff; + aOut[3] = (tm>>16)&0xff; + aOut[4] = (tm>>8)&0xff; + aOut[5] = tm&0xff; } +/* +** Read a 32-bit big-endian unsigned integer and return it. +*/ +static u32 tmstmpGetU32(const unsigned char *a){ + return (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; +} + +/* Write a 32-bit integer as big-ending into a[] +*/ +static void tmstmpPutU32(u32 v, unsigned char *a){ + a[0] = (v>>24) & 0xff; + a[1] = (v>>16) & 0xff; + a[2] = (v>>8) & 0xff; + a[3] = v & 0xff; +} + + +/* +** Write a record onto the event log +*/ +static void tmstmpEvent( + TmstmpFile *p, + u8 op, + u8 a1, + u32 a2, + u32 a3 +){ + unsigned char a[16]; + if( p->isWal ){ + p = p->pPartner; + assert( p!=0 ); + assert( p->isDb ); + } + if( p->log==0 ) return; + a[0] = op; + a[1] = a1; + tmstmpPutTS(p, a+2); + tmstmpPutU32(a2, a+8); + tmstmpPutU32(a3, a+12); + (void)fwrite(a, sizeof(a), 1, p->log); +} /* ** Close a connection */ static int tmstmpClose(sqlite3_file *pFile){ TmstmpFile *p = (TmstmpFile *)pFile; + if( p->hasCorrectReserve ){ + tmstmpEvent(p, p->isDb ? ELOG_CLOSE_DB : ELOG_CLOSE_WAL, 0, 0, 0); + } + if( p->log ) fclose(p->log); if( p->pPartner ){ assert( p->pPartner->pPartner==p ); p->pPartner->pPartner = 0; @@ -303,14 +386,18 @@ static int tmstmpRead( TmstmpFile *p = (TmstmpFile*)pFile; pFile = ORIGFILE(pFile); rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); - if( rc==SQLITE_OK - && p->isDb + if( rc!=SQLITE_OK ) return rc; + if( p->isDb && iOfst==0 && iAmt>=100 ){ - p->hasCorrectReserve = (((u8*)zBuf)[20]==TMSTMP_RESERVE); + const unsigned char *a = (unsigned char*)zBuf; + p->hasCorrectReserve = (a[20]==TMSTMP_RESERVE); + p->pgsz = (a[16]<<8) + a[17]; + if( p->pgsz==1 ) p->pgsz = 65536; if( p->pPartner ){ p->pPartner->hasCorrectReserve = p->hasCorrectReserve; + p->pPartner->pgsz = p->pgsz; } } return rc; @@ -333,40 +420,36 @@ static int tmstmpWrite( /* Writing into a WAL file */ if( iAmt==24 ){ /* A frame header */ - u32 x; - memcpy(&p->iFrame, zBuf, 4); - memcpy(&p->salt1, zBuf+8, 4); - memcpy(&x, zBuf+4, 4); + u32 x = 0; + p->iFrame = (iOfst - 32)/(p->pgsz+24); + p->pgno = tmstmpGetU32((const u8*)zBuf); + p->salt1 = tmstmpGetU32(((const u8*)zBuf)+8); + memcpy(&x, ((const u8*)zBuf)+4, 4); p->isCommit = (x!=0); p->iOfst = iOfst; }else if( iAmt>=512 && iOfst==p->iOfst+24 ){ - sqlite3_uint64 tm = 0; - int rc; unsigned char *s = (unsigned char*)zBuf+iAmt-TMSTMP_RESERVE; - p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &tm); memset(s, 0, TMSTMP_RESERVE); - s[0] = (tm>>40)&0xff; - s[1] = (tm>>32)&0xff; - s[2] = (tm>>24)&0xff; - s[3] = (tm>>16)&0xff; - s[4] = (tm>>8)&0xff; - s[5] = tm&0xff; - memcpy(&s[9], &p->salt1, 4); - memcpy(&s[6], &p->iFrame, 4); - s[13] = p->isCommit ? 1 : 0; + tmstmpPutTS(p, s+2); + tmstmpPutU32(p->iFrame, s+8); + tmstmpPutU32(p->salt1, s+12); + s[12] = p->isCommit ? 1 : 0; + tmstmpEvent(p, ELOG_WAL_PAGE, s[12], p->pgno, p->iFrame); + }else if( iAmt==32 && iOfst==0 ){ + u32 salt1 = tmstmpGetU32(((const u8*)zBuf)+16); + tmstmpEvent(p, ELOG_WAL_RESET, 0, 0, salt1); } + }else if( p->inCkpt ){ + assert( p->pgsz>0 ); + tmstmpEvent(p, ELOG_CKPT_PAGE, 0, iOfst/p->pgsz, 0); }else if( p->pPartner==0 ){ /* Writing into a database in rollback mode */ - sqlite3_uint64 tm = 0; unsigned char *s = (unsigned char*)zBuf+iAmt-TMSTMP_RESERVE; - p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &tm); memset(s, 0, TMSTMP_RESERVE); - s[0] = (tm>>40)&0xff; - s[1] = (tm>>32)&0xff; - s[2] = (tm>>24)&0xff; - s[3] = (tm>>16)&0xff; - s[4] = (tm>>8)&0xff; - s[5] = tm&0xff; + tmstmpPutTS(p, s+2); + s[12] = 2; + assert( p->pgsz>0 ); + tmstmpEvent(p, ELOG_DB_PAGE, 0, (u32)(iOfst/p->pgsz), 0); } return pSub->pMethods->xWrite(pSub,zBuf,iAmt,iOfst); } @@ -428,11 +511,35 @@ static int tmstmpFileControl(sqlite3_file *pFile, int op, void *pArg){ TmstmpFile *p = (TmstmpFile*)pFile; pFile = ORIGFILE(pFile); rc = pFile->pMethods->xFileControl(pFile, op, pArg); - if( rc==SQLITE_OK - && op==SQLITE_FCNTL_VFSNAME - && p->hasCorrectReserve - ){ - *(char**)pArg = sqlite3_mprintf("tmstmp/%z", *(char**)pArg); + if( rc==SQLITE_OK ){ + switch( op ){ + case SQLITE_FCNTL_VFSNAME: { + if( p->hasCorrectReserve ){ + *(char**)pArg = sqlite3_mprintf("tmstmp/%z", *(char**)pArg); + } + break; + } + case SQLITE_FCNTL_CKPT_START: { + p->inCkpt = 1; + assert( p->isDb ); + assert( p->pPartner!=0 ); + p->pPartner->inCkpt = 1; + if( p->hasCorrectReserve ){ + tmstmpEvent(p, ELOG_CKPT_START, 0, 0, 0); + } + break; + } + case SQLITE_FCNTL_CKPT_DONE: { + p->inCkpt = 0; + assert( p->isDb ); + assert( p->pPartner!=0 ); + p->pPartner->inCkpt = 0; + if( p->hasCorrectReserve ){ + tmstmpEvent(p, ELOG_CKPT_DONE, 0, 0, 0); + } + break; + } + } } return rc; } @@ -517,6 +624,11 @@ static int tmstmpOpen( sqlite3_file *pSubFile; sqlite3_vfs *pSubVfs; int rc; + sqlite3_uint64 r1; + u32 r2; + u32 pid; + char *zLogName; + pSubVfs = ORIGVFS(pVfs); if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ /* If the file is not a persistent database or a WAL file, then @@ -549,7 +661,17 @@ static int tmstmpOpen( pDb->pPartner = p; }else{ p->isDb = 1; + r1 = 0; + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &r1); + sqlite3_randomness(sizeof(r2), &r2); + pid = GETPID; + zLogName = sqlite3_mprintf("%s-%llx%08x%08x.tmstmp", zName, r1, pid, r2); + if( zLogName ){ + p->log = fopen(zLogName, "wb"); + sqlite3_free(zLogName); + } } + tmstmpEvent(p, p->isWal ? ELOG_OPEN_WAL : ELOG_OPEN_DB, 0, GETPID, 0); tmstmp_open_done: if( rc ) pFile->pMethods = 0; @@ -672,11 +794,6 @@ int sqlite3_tmstmpvfs_init( int rc; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* not used */ -#ifdef SQLITE_TMSTMPVFS_INIT_FUNCNAME - rc = sqlite3_create_function(db, SQLITE_TMSTMPVFS_INIT_FUNCTNAME, 1, - SQLITE_UTF8, 0, tmstmpInitFunc, 0, 0); - if( rc ) return rc; -#endif rc = tmstmpRegisterVfs(); if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; diff --git a/manifest b/manifest index 0877dc6056..1c4610ae50 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sexperimental\stmstmpvfs.c\sextension\sthat\sadds\sa\stimestamp\sand\sother\ndebugging\sinformation\son\seach\spage\sof\sa\sdatabase\sas\sthat\spage\sis\swritten,\nif\sthe\sdatabase\sis\sconfigured\sfor\sexactly\s16\sbytes\sof\sreserve\sspace. -D 2026-01-05T17:28:33.434 +C Enhance\sthe\stimestamp-vfs\sprototype\sso\sthat\sit\salso\skeeps\san\sevent\slog. +D 2026-01-06T20:51:06.241 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 742c76f7e6705c547a66932186decf3097a5c3e36a57b84582c64c95994f54f8 +F ext/misc/tmstmpvfs.c 406df06b8ce336dbbe144771b944237aee7de659b8a67ac98d7cc02b3177bdfc F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2190,11 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 707c0f6442e946f23de061ee2753eb5994ab55d411c49b232799f309ba0f10cf -R eebbc04e39ff5bc6f1027ece05be9308 -T *branch * timestamp-vfs -T *sym-timestamp-vfs * -T -sym-trunk * +P 703e593dfc92676a2d44c67ca8282a78a1943b9c1e3f2447c0a9917d70a383c4 +R 5eb4c6b81b2d4f64da6be7537e974747 U drh -Z edde794cfb79a18a07337a2e938e02dc +Z a329d47bfb1365429e97ed4ed3ca25c0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5eb1b96438..61f6bb28ee 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -703e593dfc92676a2d44c67ca8282a78a1943b9c1e3f2447c0a9917d70a383c4 +f087c6c0cdd542ec24b4668fff9cb434f46caf554f8856a49fd062ab3f72014e From 8fe0385661b908bc29ced3ec4208606e3faaacd4 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 6 Jan 2026 21:18:42 +0000 Subject: [PATCH 03/17] Documentation tweaks. FossilOrigin-Name: b10b0aa7658a04b9354ca09a2dcb807eecd9421451537f3230ba5f47269ec5c1 --- ext/misc/tmstmpvfs.c | 41 ++++++++++++++++++++++++++++++----------- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 0bfd84693a..1d52c0e958 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -11,10 +11,19 @@ ****************************************************************************** ** ** This file implements a VFS shim that writes a timestamp and other tracing -** information into reserved space at the end of each page of the database -** file. The additional data is written as the page is added to the WAL -** file for databases in WAL mode, or as the database file itself is modified -** in rollback modes. +** information into 16 byts of reserved space at the end of each page of the +** database file. The additional data is written as the page is added to +** the WAL file for databases in WAL mode, or as the database file itself +** is modified in rollback modes. +** +** The VFS also generates log-files with names of the form: +** +** $(DATABASE)-$(TIME)$(PID)$(ID).tmstmp +** +** In the same directory as the database file. This log file contain one +** 16-byte record for various events, such as opening or close of the +** database or WAL file, writes to the WAL file, checkpoints, and similar. +** There is one log file for each open database connection. ** ** COMPILING ** @@ -90,7 +99,9 @@ ** The timestamp information is stored in the last 16 bytes of each page. ** This module only operates if the "bytes of reserved space on each page" ** value at offset 20 the SQLite database header is exactly 16. If -** the reserved-space value is not 16, this module is a no-op. +** the reserved-space value is not 16, no timestamp information is added +** to database pages. Some, but not all, logfile entries will be made +** still, but the size of the logs will be greatly reduced. ** ** The timestamp layout is as follows: ** @@ -100,8 +111,9 @@ ** bytes 12 0: WAL write 1: WAL txn 2: rollback write ** bytes 13-15 Lower 24 bits of Salt-1 ** -** For transactions that occur in rollback mode, bytes 6-15 are all -** zero. +** For transactions that occur in rollback mode, only the timestamp +** in bytes 2-7 and byte 12 are non-zero. Byte 12 is set to 2 for +** rollback writes. ** ** LOGGING ** @@ -109,11 +121,18 @@ ** WAL connection are both logged to the same file. If the name of the ** database file is BASE then the logfile is named something like: ** -** BASE-tmstmp-UNIQUEID +** $(DATABASE)-$(TIMESTAMP)$(PID)$(RANDOM) ** -** Where UNIQUEID is a character string that is unique to that particular -** connection. The log consists of 16-byte records. Each record consists -** of five unsigned integers: +** Where DATABASE is the database filename, TIMESTAMP is the millisecond +** resolution timestamp of when the database connection was opened, PID +** is the process ID of the process that opened the database connection, +** and RANDOM is 32-bits of randomness used to distinguish between multiple +** connections being opened on the same database from the same process. +** The last three values are all expressed in hexadecimal and are joined +** together without punctuation. +** +** The log consists of 16-byte records. Each record consists of five +** unsigned integers: ** ** 1 1 6 4 4 <--- bytes ** op a1 ts a2 a3 diff --git a/manifest b/manifest index 1c4610ae50..4fd87e8e07 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\stimestamp-vfs\sprototype\sso\sthat\sit\salso\skeeps\san\sevent\slog. -D 2026-01-06T20:51:06.241 +C Documentation\stweaks. +D 2026-01-06T21:18:42.496 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 406df06b8ce336dbbe144771b944237aee7de659b8a67ac98d7cc02b3177bdfc +F ext/misc/tmstmpvfs.c 05e80557222c648bc676e599343d8d33f9e2d4801476592271ffb580cebbab69 F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2190,8 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 703e593dfc92676a2d44c67ca8282a78a1943b9c1e3f2447c0a9917d70a383c4 -R 5eb4c6b81b2d4f64da6be7537e974747 +P f087c6c0cdd542ec24b4668fff9cb434f46caf554f8856a49fd062ab3f72014e +R 877edad71f16bed2b67db9da4be832cc U drh -Z a329d47bfb1365429e97ed4ed3ca25c0 +Z ee16842ec8595f9621e28d3f57b47daa # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 61f6bb28ee..3eb4087104 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f087c6c0cdd542ec24b4668fff9cb434f46caf554f8856a49fd062ab3f72014e +b10b0aa7658a04b9354ca09a2dcb807eecd9421451537f3230ba5f47269ec5c1 From 0b5f8766fd07794ed48677b94fc31283a729c0cf Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 7 Jan 2026 18:45:23 +0000 Subject: [PATCH 04/17] Improvements to logging. Better log-file names. Log files are in a subdirectory named after the database. Only connections that write to the database create logs. Better documentation in the header comment. FossilOrigin-Name: 5b1cf0fe73ba1a40fe4cd8f5f6e8ee5b471f96b60aff52c03c045ad6514c363a --- ext/misc/tmstmpvfs.c | 157 ++++++++++++++++++++++++++++++++++--------- manifest | 12 ++-- manifest.uuid | 2 +- 3 files changed, 131 insertions(+), 40 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 1d52c0e958..739c3e614d 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -16,14 +16,19 @@ ** the WAL file for databases in WAL mode, or as the database file itself ** is modified in rollback modes. ** -** The VFS also generates log-files with names of the form: +** The VFS also tries to generate log-files with names of the form: ** -** $(DATABASE)-$(TIME)$(PID)$(ID).tmstmp +** $(DATABASE)-tmstmp/$(TIME)-$(PID)-$(ID) ** -** In the same directory as the database file. This log file contain one -** 16-byte record for various events, such as opening or close of the -** database or WAL file, writes to the WAL file, checkpoints, and similar. -** There is one log file for each open database connection. +** Log files are only generated if directory $(DATABASE)-tmstmp exists. +** The name of each log file is the current unix-epoch time in millisecond, +** the process ID, and a random 32-bit value (to disambiguate multiple +** connections from the same process) separated by spaces. The log file +** contains one 16-byte record for various events, such as opening or close +** of the database or WAL file, writes to the WAL file, checkpoints, and +** similar. The logfile is only generated if the connection attempts to +** modify the database. There is a separate log file for each open database +** connection. ** ** COMPILING ** @@ -59,6 +64,11 @@ ** correct order so that it sequences itself into the default VFS ** Shim stack in the right order. ** +** An application can see if the tmstmpvfs is being used by examining +** the results from SQLITE_FCNTL_VFSNAME (or the .vfsname command in +** the CLI). If the answer include "tmstmp", then this VFS is being +** used. +** ** USING ** ** Open database connections using the sqlite3_open() or @@ -117,19 +127,15 @@ ** ** LOGGING ** -** Every open VFS creates a log file. The Database connection and the -** WAL connection are both logged to the same file. If the name of the -** database file is BASE then the logfile is named something like: +** An open database connection that attempts to write to the database +** will create a log file if a directory name $(DATABASE)-tmstmp exists. +** The name of the log file is: ** -** $(DATABASE)-$(TIMESTAMP)$(PID)$(RANDOM) +** $(TIME)-$(PID)-$(RANDOM) ** -** Where DATABASE is the database filename, TIMESTAMP is the millisecond -** resolution timestamp of when the database connection was opened, PID -** is the process ID of the process that opened the database connection, -** and RANDOM is 32-bits of randomness used to distinguish between multiple -** connections being opened on the same database from the same process. -** The last three values are all expressed in hexadecimal and are joined -** together without punctuation. +** Where TIME is the number of milliseconds since 1970, PID is the process +** ID, and RANDOM is a 32-bit random number. All values are expressed +** in hexadecimal. ** ** The log consists of 16-byte records. Each record consists of five ** unsigned integers: @@ -141,6 +147,44 @@ ** in milliseconds since 1970-01-01. (6 bytes is sufficient for timestamps ** for almost 9000 years.) Opcodes are defined by the ELOG_* #defines ** below. +** +** ELOG_OPEN_DB "Open a connection to the database file" +** op = 0x01 +** a2 = process-ID +** +** ELOG_OPEN_WAL "Open a connection to the -wal file" +** op = 0x02 +** a2 = process-ID +** +** ELOG_WAL_PAGE "New page added to the WAL file" +** op = 0x03 +** a1 = 1 if last page of a txn. 0 otherwise. +** a2 = page number in the DB file +** a3 = frame number in the WAL file +** +** ELOG_DB_PAGE "Database page updated using rollback mode" +** op = 0x04 +** a2 = page number in the DB file +** +** ELOG_CKPT_START "Start of a checkpoint operation" +** op = 0x05 +** +** ELOG_CKPT_PAGE "Page xfer from WAL to database" +** op = 0x06 +** a2 = database page number +** +** ELOG_CKPT_END "Start of a checkpoint operation" +** op = 0x07 +** +** ELOG_WAL_RESET "WAL file header overwritten" +** op = 0x08 +** a3 = Salt1 value +** +** ELOG_CLOSE_WAL "Close the WAL file connection" +** op = 0x0e +** +** ELOG_CLOSE_DB "Close the DB connection" +** op = 0x0f */ #if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_TMSTMPVFS_STATIC) # define SQLITE_TMSTMPVFS_STATIC @@ -160,6 +204,7 @@ */ typedef struct sqlite3_vfs TmstmpVfs; typedef struct TmstmpFile TmstmpFile; +typedef struct TmstmpLog TmstmpLog; /* ** Bytes of reserved space used by this extension @@ -196,6 +241,14 @@ typedef struct TmstmpFile TmstmpFile; #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) #define ORIGFILE(p) ((sqlite3_file*)(((TmstmpFile*)(p))+1)) +/* Information for the tmstmp log file. */ +struct TmstmpLog { + char *zLogname; /* Log filename */ + FILE *log; /* Open log file */ + int n; /* Bytes of a[] used */ + unsigned char a[16*6]; /* Buffered header for the log */ +}; + /* An open WAL file */ struct TmstmpFile { sqlite3_file base; /* IO methods */ @@ -209,7 +262,7 @@ struct TmstmpFile { u8 isCommit; /* Last WAL frame header was a transaction commit */ u8 hasCorrectReserve; /* File has the correct reserve size */ u8 inCkpt; /* True if in a checkpoint */ - FILE *log; /* Write logging records on this file. DB only */ + TmstmpLog *pLog; /* Log file */ TmstmpFile *pPartner; /* DB->WAL or WAL->DB mapping */ sqlite3_int64 iOfst; /* Offset of last WAL frame header */ sqlite3_vfs *pSubVfs; /* Underlying VFS */ @@ -323,7 +376,7 @@ static const sqlite3_io_methods tmstmp_io_methods = { */ static void tmstmpPutTS(TmstmpFile *p, unsigned char *aOut){ sqlite3_uint64 tm = 0; - p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &tm); + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, (sqlite3_int64*)&tm); aOut[0] = (tm>>40)&0xff; aOut[1] = (tm>>32)&0xff; aOut[2] = (tm>>24)&0xff; @@ -348,6 +401,30 @@ static void tmstmpPutU32(u32 v, unsigned char *a){ a[3] = v & 0xff; } +/* Free a TmstmpLog object */ +static void tmstmpLogFree(TmstmpLog *pLog){ + if( pLog==0 ) return; + sqlite3_free(pLog->zLogname); + sqlite3_free(pLog); +} + +/* Flush log content. Open the file if necessary. Return the +** number of errors. */ +static int tmstmpLogFlush(TmstmpFile *p){ + TmstmpLog *pLog = p->pLog; + assert( pLog!=0 ); + if( pLog->log==0 ){ + pLog->log = fopen(pLog->zLogname, "wb"); + if( pLog->log==0 ){ + tmstmpLogFree(pLog); + p->pLog = 0; + return 1; + } + } + (void)fwrite(pLog->a, pLog->n, 1, pLog->log); + pLog->n = 0; + return 0; +} /* ** Write a record onto the event log @@ -359,19 +436,28 @@ static void tmstmpEvent( u32 a2, u32 a3 ){ - unsigned char a[16]; + unsigned char *a; + TmstmpLog *pLog; if( p->isWal ){ p = p->pPartner; assert( p!=0 ); assert( p->isDb ); } - if( p->log==0 ) return; + pLog = p->pLog; + if( pLog==0 ) return; + if( pLog->n >= (int)sizeof(pLog->a) ){ + if( tmstmpLogFlush(p) ) return; + } + a = pLog->a + pLog->n; a[0] = op; a[1] = a1; tmstmpPutTS(p, a+2); tmstmpPutU32(a2, a+8); tmstmpPutU32(a3, a+12); - (void)fwrite(a, sizeof(a), 1, p->log); + pLog->n += 16; + if( pLog->log || (op>=ELOG_WAL_PAGE && op<=ELOG_WAL_RESET) ){ + (void)tmstmpLogFlush(p); + } } /* @@ -382,7 +468,7 @@ static int tmstmpClose(sqlite3_file *pFile){ if( p->hasCorrectReserve ){ tmstmpEvent(p, p->isDb ? ELOG_CLOSE_DB : ELOG_CLOSE_WAL, 0, 0, 0); } - if( p->log ) fclose(p->log); + tmstmpLogFree(p->pLog); if( p->pPartner ){ assert( p->pPartner->pPartner==p ); p->pPartner->pPartner = 0; @@ -643,10 +729,6 @@ static int tmstmpOpen( sqlite3_file *pSubFile; sqlite3_vfs *pSubVfs; int rc; - sqlite3_uint64 r1; - u32 r2; - u32 pid; - char *zLogName; pSubVfs = ORIGVFS(pVfs); if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ @@ -679,16 +761,24 @@ static int tmstmpOpen( p->pPartner = pDb; pDb->pPartner = p; }else{ + sqlite3_uint64 r1; + u32 r2; + u32 pid; + TmstmpLog *pLog; + p->isDb = 1; r1 = 0; - p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, &r1); + pLog = sqlite3_malloc64( sizeof(TmstmpLog) ); + if( pLog==0 ){ + return SQLITE_NOMEM; + } + memset(pLog, 0, sizeof(pLog[0])); + p->pLog = pLog; + p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, (sqlite3_int64*)&r1); sqlite3_randomness(sizeof(r2), &r2); pid = GETPID; - zLogName = sqlite3_mprintf("%s-%llx%08x%08x.tmstmp", zName, r1, pid, r2); - if( zLogName ){ - p->log = fopen(zLogName, "wb"); - sqlite3_free(zLogName); - } + pLog->zLogname = sqlite3_mprintf("%s-tmstmp/%llx-%08x-%08x", + zName, r1, pid, r2); } tmstmpEvent(p, p->isWal ? ELOG_OPEN_WAL : ELOG_OPEN_DB, 0, GETPID, 0); @@ -813,6 +903,7 @@ int sqlite3_tmstmpvfs_init( int rc; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* not used */ + (void)db; /* not used */ rc = tmstmpRegisterVfs(); if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; return rc; diff --git a/manifest b/manifest index 4fd87e8e07..3591bb9662 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Documentation\stweaks. -D 2026-01-06T21:18:42.496 +C Improvements\sto\slogging.\s\sBetter\slog-file\snames.\s\sLog\sfiles\sare\sin\sa\nsubdirectory\snamed\safter\sthe\sdatabase.\s\sOnly\sconnections\sthat\swrite\sto\nthe\sdatabase\screate\slogs.\s\sBetter\sdocumentation\sin\sthe\sheader\scomment. +D 2026-01-07T18:45:23.292 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 05e80557222c648bc676e599343d8d33f9e2d4801476592271ffb580cebbab69 +F ext/misc/tmstmpvfs.c 2d2f92a85e9a55ae3abd9d66d1638096fad30ebc0bfcf9431f3370e34b550a0b F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2190,8 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P f087c6c0cdd542ec24b4668fff9cb434f46caf554f8856a49fd062ab3f72014e -R 877edad71f16bed2b67db9da4be832cc +P b10b0aa7658a04b9354ca09a2dcb807eecd9421451537f3230ba5f47269ec5c1 +R be812e8a766a17494547e7727dd97033 U drh -Z ee16842ec8595f9621e28d3f57b47daa +Z 8f9cae05ac0b26a0b4ebaaea59bfec9f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3eb4087104..3ee21c9f49 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b10b0aa7658a04b9354ca09a2dcb807eecd9421451537f3230ba5f47269ec5c1 +5b1cf0fe73ba1a40fe4cd8f5f6e8ee5b471f96b60aff52c03c045ad6514c363a From ef5d9952ebc2a2363f7a95f1b97cf452f36d0a16 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 7 Jan 2026 19:06:11 +0000 Subject: [PATCH 05/17] Fix the static build. FossilOrigin-Name: 4e1a1b6aeffaa5b8c11e165803c6d33becabd1f646f39e4309dfba6892fd4bd6 --- ext/misc/tmstmpvfs.c | 1 - manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 739c3e614d..888b6cf5e1 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -878,7 +878,6 @@ int sqlite3_register_tmstmpvfs(const char *NotUsed){ int sqlite3_unregister_tmstmpvfs(void){ if( sqlite3_vfs_find("tmstmpvfs") ){ sqlite3_vfs_unregister(&tmstmp_vfs); - sqlite3_cancel_auto_extension((void(*)(void))tmstmpRegisterFunc); } return SQLITE_OK; } diff --git a/manifest b/manifest index 3591bb9662..af77db6249 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\slogging.\s\sBetter\slog-file\snames.\s\sLog\sfiles\sare\sin\sa\nsubdirectory\snamed\safter\sthe\sdatabase.\s\sOnly\sconnections\sthat\swrite\sto\nthe\sdatabase\screate\slogs.\s\sBetter\sdocumentation\sin\sthe\sheader\scomment. -D 2026-01-07T18:45:23.292 +C Fix\sthe\sstatic\sbuild. +D 2026-01-07T19:06:11.446 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 2d2f92a85e9a55ae3abd9d66d1638096fad30ebc0bfcf9431f3370e34b550a0b +F ext/misc/tmstmpvfs.c 4953aa97872c67d55e22351cdf3dc3d06e81ef0f28c6105f1fae2214f3250c74 F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2190,8 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b10b0aa7658a04b9354ca09a2dcb807eecd9421451537f3230ba5f47269ec5c1 -R be812e8a766a17494547e7727dd97033 +P 5b1cf0fe73ba1a40fe4cd8f5f6e8ee5b471f96b60aff52c03c045ad6514c363a +R a4b39375360ad9950610c9bec00b6e2e U drh -Z 8f9cae05ac0b26a0b4ebaaea59bfec9f +Z 5df12823a5b3f6406863ab3642f23c24 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3ee21c9f49..bd33b1421e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5b1cf0fe73ba1a40fe4cd8f5f6e8ee5b471f96b60aff52c03c045ad6514c363a +4e1a1b6aeffaa5b8c11e165803c6d33becabd1f646f39e4309dfba6892fd4bd6 From ad4b08dcaba67be53b0a3cf4cb12e8c41fd76e13 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 7 Jan 2026 23:46:44 +0000 Subject: [PATCH 06/17] Add the --csv option to the "pgidx" option to the "showdb" utility. FossilOrigin-Name: b6ad93f62eb883ee8f4c43dd90c69b31398be6b13186866a7b05d85fe588d967 --- manifest | 12 +++++----- manifest.uuid | 2 +- tool/showdb.c | 62 +++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index edd7cffb53..4b86e1f8fb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sQRF\sso\sthat\sit\sterminates\smore\squickly\sif\sit\sencounters\san\sOOM\nor\soversize\sstring\serror,\sand\sfix\sit\sso\sthat\sit\sreports\ssuch\serrors. -D 2026-01-07T16:19:18.474 +C Add\sthe\s--csv\soption\sto\sthe\s"pgidx"\soption\sto\sthe\s"showdb"\sutility. +D 2026-01-07T23:46:44.054 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -2158,7 +2158,7 @@ F tool/pagesig.c f98909b4168d9cac11a2de7f031adea0e2f3131faa7515a72807c03ec58eafe F tool/replace.tcl 511c61acfe563dfb58675efb4628bb158a13d48ff8322123ac447e9d25a82d9a F tool/restore_jrnl.tcl 1079ecba47cc82fa82115b81c1f68097ab1f956f357ee8da5fc4b2589af6bd98 F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c 3956d71e5193162609a60e8c9edfcf09274c00cfea2b1d221261427adb2b5cca +F tool/showdb.c 3071a801f2a630bf9f615f9cbc018d20c7b6dcbc01baf639274de3c693f243cc F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 @@ -2189,8 +2189,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 53f806fdab7161e439a165af47bd45332c15233b87bc35c2272621256a2dc337 -R cf85c1397cc1b2d22a690795998c55cf +P ebedeb6169cc3bc3708130d4061065af600a8851e896fc3eeaf33c8c83fe3b95 +R 4e24675c048a8ee4fad0f422ed2a04f2 U drh -Z 90a7bdaa1645e01c822a73d7422497a0 +Z 121e5d997135b09ccc3ebccbf3bcbc0b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index aff2123872..2dae99190a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ebedeb6169cc3bc3708130d4061065af600a8851e896fc3eeaf33c8c83fe3b95 +b6ad93f62eb883ee8f4c43dd90c69b31398be6b13186866a7b05d85fe588d967 diff --git a/tool/showdb.c b/tool/showdb.c index f0bd9737cf..399d785342 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -32,6 +32,7 @@ static struct GlobalData { u32 mxPage; /* Last page number */ int perLine; /* HEX elements to print per line */ int bRaw; /* True to access db file via OS APIs */ + int bCSV; /* CSV output for "pgidx" */ sqlite3_file *pFd; /* File descriptor for non-raw mode */ sqlite3 *pDb; /* Database handle that owns pFd */ } g = {1024, -1, 0, 16, 0, 0, 0}; @@ -1042,9 +1043,40 @@ static void page_usage_report(const char *zPrg, const char *zDbName){ sqlite3_close(db); /* Print the report and free memory used */ + if( g.bCSV ){ + printf("pgno,txt,parent,child,ovfl\r\n"); + } for(i=1; i<=g.mxPage; i++){ - if( zPageUse[i]==0 ) page_usage_btree(i, -1, 0, 0); - printf("%5u: %s\n", i, zPageUse[i] ? zPageUse[i] : "???"); + if( zPageUse[i]==0 ){ + zPageUse[i] = sqlite3_mprintf("???"); + if( zPageUse[i]==0 ) continue; + } + if( !g.bCSV ){ + printf("%5u: %s\n", i, zPageUse[i]); + }else{ + const char *z = zPageUse[i]; + const char *s; + printf("%u,\"%s\",", i, zPageUse[i]); + if( (s = strstr(z, " of page "))!=0 ){ + printf("%d,", atoi(s+9)); + }else if( (s = strstr(z, " of trunk page "))!=0 ){ + printf("%d,", atoi(s+15)); + }else{ + printf("0,"); + } + if( (s = strstr(z, "], child "))!=0 ){ + printf("%d,", atoi(s+9)); + }else if( (s = strstr(z, " from cell "))!=0 ){ + printf("%d,", atoi(s+12)); + }else{ + printf("-1,"); + } + if( strncmp(z,"overflow ", 9)==0 ){ + printf("%d\r\n", atoi(z+9)); + }else{ + printf("-1\r\n"); + } + } } for(i=1; i<=g.mxPage; i++){ sqlite3_free(zPageUse[i]); @@ -1115,7 +1147,7 @@ static void ptrmap_coverage_report(const char *zDbName){ ** Check the range validity for a page number. Print an error and ** exit if the page is out of range. */ -static void checkPageValidity(int iPage){ +static void checkPageValidity(unsigned int iPage){ if( iPage<1 || iPage>g.mxPage ){ fprintf(stderr, "Invalid page number %d: valid range is 1..%d\n", iPage, g.mxPage); @@ -1131,6 +1163,7 @@ static void usage(const char *argv0){ fprintf(stderr, "switches:\n" " --raw Read db file directly, bypassing SQLite VFS\n" + " --csv CSV output for \"pgidx\"\n" "args:\n" " dbheader Show database header\n" " pgidx Index of how each page is used\n" @@ -1154,14 +1187,23 @@ int main(int argc, char **argv){ char **azArg = argv; int nArg = argc; - /* Check for the "--uri" or "-uri" switch. */ - if( nArg>1 ){ - if( sqlite3_stricmp("-raw", azArg[1])==0 - || sqlite3_stricmp("--raw", azArg[1])==0 - ){ + /* Check for the switches. */ + while( nArg>1 && azArg[1][0]=='-' ){ + const char *z = azArg[1]; + if( z[1]=='-' && z[2]!=0 ) z++; + if( sqlite3_stricmp("-raw", z)==0 ){ g.bRaw = 1; azArg++; nArg--; + }else + if( strcmp("-csv", z)==0 ){ + g.bCSV = 1; + azArg++; + nArg--; + }else + { + usage(zPrg); + exit(1); } } @@ -1181,7 +1223,9 @@ int main(int argc, char **argv){ printf("Pagesize: %d\n", (int)g.pagesize); g.mxPage = (u32)((szFile+g.pagesize-1)/g.pagesize); - printf("Available pages: 1..%u\n", g.mxPage); + if( !g.bCSV ){ + printf("Available pages: 1..%u\n", g.mxPage); + } if( nArg==2 ){ u32 i; for(i=1; i<=g.mxPage; i++) print_page(i); From e46b51e23479ee43e2e3ab454787dba543c8f91e Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 8 Jan 2026 01:37:13 +0000 Subject: [PATCH 07/17] Improve showdb so that it does a better job of handling reserve-bytes. Add the --tmstmp option that causes pgidx to interpret tmstmpvfs tags if they are available. FossilOrigin-Name: d7e6e9a5781f467a5b5f02f46134099cf01607a0cf55510155533d57d4a4618a --- manifest | 13 +++-- manifest.uuid | 2 +- tool/showdb.c | 139 ++++++++++++++++++++++++++++++++++---------------- 3 files changed, 102 insertions(+), 52 deletions(-) diff --git a/manifest b/manifest index 9426f06170..543e9c293d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\stmstmpvfs.c\sextension\sto\strunk.\s\sIt\sis\snot\sa\spart\sof\sany\sdeliverable\nand\scan\seasily\sbe\sremoved\slater,\sif\sfound\sto\snot\sbe\sdesirable. -D 2026-01-08T00:41:12.638 +C Improve\sshowdb\sso\sthat\sit\sdoes\sa\sbetter\sjob\sof\shandling\sreserve-bytes.\nAdd\sthe\s--tmstmp\soption\sthat\scauses\spgidx\sto\sinterpret\stmstmpvfs\stags\nif\sthey\sare\savailable. +D 2026-01-08T01:37:13.895 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -2159,7 +2159,7 @@ F tool/pagesig.c f98909b4168d9cac11a2de7f031adea0e2f3131faa7515a72807c03ec58eafe F tool/replace.tcl 511c61acfe563dfb58675efb4628bb158a13d48ff8322123ac447e9d25a82d9a F tool/restore_jrnl.tcl 1079ecba47cc82fa82115b81c1f68097ab1f956f357ee8da5fc4b2589af6bd98 F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c 3071a801f2a630bf9f615f9cbc018d20c7b6dcbc01baf639274de3c693f243cc +F tool/showdb.c 9c2c783a64b4d3b1f5fa9fe8e64add8c620c21b1831e10a2cec51ab59768da71 F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 @@ -2190,9 +2190,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P b6ad93f62eb883ee8f4c43dd90c69b31398be6b13186866a7b05d85fe588d967 4e1a1b6aeffaa5b8c11e165803c6d33becabd1f646f39e4309dfba6892fd4bd6 -R c62a88b6743ccf33134c23eac604ca1b -T +closed 4e1a1b6aeffaa5b8c11e165803c6d33becabd1f646f39e4309dfba6892fd4bd6 +P 869f306592a86d2a78f00266c615f033cd2318a7bff0a97b3dcdd3348d99fc66 +R 84dfc7b9c377c2c122ebbcbfef876fb5 U drh -Z 16554405872f41bd820dd07a6083967e +Z da6fd7cd7ce3a4452ba602eb99ca3b3b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c1a69e9924..ae055627fe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -869f306592a86d2a78f00266c615f033cd2318a7bff0a97b3dcdd3348d99fc66 +d7e6e9a5781f467a5b5f02f46134099cf01607a0cf55510155533d57d4a4618a diff --git a/tool/showdb.c b/tool/showdb.c index 399d785342..045956e186 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -28,14 +28,21 @@ typedef sqlite3_uint64 u64; /* unsigned 64-bit */ static struct GlobalData { i64 pagesize; /* Size of a database page */ + i64 usablesize; /* pagesize-nRes */ int dbfd; /* File descriptor for reading the DB */ u32 mxPage; /* Last page number */ + u32 nRes; /* Amount of reserve space */ int perLine; /* HEX elements to print per line */ int bRaw; /* True to access db file via OS APIs */ int bCSV; /* CSV output for "pgidx" */ + int bTmstmp; /* Interpret tmstmpvfs tags on "pgidx" */ sqlite3_file *pFd; /* File descriptor for non-raw mode */ sqlite3 *pDb; /* Database handle that owns pFd */ -} g = {1024, -1, 0, 16, 0, 0, 0}; + char **zPageUse; /* Use for each page */ + struct TmstmpTag { + unsigned char a[16]; /* tmstmpvfs tag for each page */ + } *aPageTag; +} g = {4096, 4096, -1, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0}; /* ** Convert the var-int format into i64. Return the number of bytes @@ -143,11 +150,12 @@ static void fileClose(){ static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){ unsigned char *aData; int got; + int rc; aData = sqlite3_malloc64(32+(i64)nByte); if( aData==0 ) out_of_memory(); memset(aData, 0, nByte+32); if( g.bRaw==0 ){ - int rc = g.pFd->pMethods->xRead(g.pFd, (void*)aData, nByte, ofst); + rc = g.pFd->pMethods->xRead(g.pFd, (void*)aData, nByte, ofst); if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){ fprintf(stderr, "error in xRead() - %d\n", rc); exit(1); @@ -155,7 +163,21 @@ static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){ }else{ lseek(g.dbfd, (long)ofst, SEEK_SET); got = read(g.dbfd, aData, nByte); - if( got>0 && got0 && got=0 && pgno<=g.mxPage ){ + memcpy(g.aPageTag[pgno].a, &aData[nByte-16], 16); + } } return aData; } @@ -383,14 +405,14 @@ static i64 localPayload(i64 nPayload, char cType){ i64 nLocal; if( cType==13 ){ /* Table leaf */ - maxLocal = g.pagesize-35; - minLocal = (g.pagesize-12)*32/255-23; + maxLocal = g.usablesize-35; + minLocal = (g.usablesize-12)*32/255-23; }else{ - maxLocal = (g.pagesize-12)*64/255-23; - minLocal = (g.pagesize-12)*32/255-23; + maxLocal = (g.usablesize-12)*64/255-23; + minLocal = (g.usablesize-12)*32/255-23; } if( nPayload>maxLocal ){ - surplus = minLocal + (nPayload-minLocal)%(g.pagesize-4); + surplus = minLocal + (nPayload-minLocal)%(g.usablesize-4); if( surplus<=maxLocal ){ nLocal = surplus; }else{ @@ -752,7 +774,7 @@ static void decode_trunk_page( print_decode_line(a, 4, 4, "Number of entries on this page"); if( detail ){ n = decodeInt32(&a[4]); - for(i=0; i= g.pagesize ){ + if( cellidx+1 >= g.usablesize ){ printf("ERROR: page %d too many cells (%d)\n", pgno, nCell); break; } ofst = a[cellidx]*256 + a[cellidx+1]; - if( ofst=g.pagesize ){ + if( ofst=g.usablesize ){ printf("ERROR: page %d cell %d out of bounds\n", pgno, i); continue; } @@ -960,9 +977,9 @@ static void page_usage_freelist(u32 pgno){ a = fileRead((pgno-1)*g.pagesize, g.pagesize); iNext = decodeInt32(a); n = decodeInt32(a+4); - if( n>(g.pagesize - 8)/4 ){ + if( n>(g.usablesize - 8)/4 ){ printf("ERROR: page %d too many freelist entries (%d)\n", pgno, n); - n = (g.pagesize - 8)/4; + n = (g.usablesize - 8)/4; } for(i=0; i Date: Thu, 8 Jan 2026 12:22:50 +0000 Subject: [PATCH 08/17] Add the showtmlog utility for decoding the tmstmpvfs log files. Fix tmstmpvfs so that it records timestamps in milliseconds since the Unix epoch, not in JDN milliseconds. FossilOrigin-Name: 762d3cbf06218f1010425a98a71ebf7623b84b45a90e6419b7dec7f10ad0c5a5 --- Makefile.msc | 3 + ext/misc/tmstmpvfs.c | 7 ++- main.mk | 4 ++ manifest | 17 +++--- manifest.uuid | 2 +- tool/showtmlog.c | 133 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 12 deletions(-) create mode 100644 tool/showtmlog.c diff --git a/Makefile.msc b/Makefile.msc index 219f5c4f9d..561d5f58e0 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -2709,6 +2709,9 @@ showwal.exe: $(TOP)\tool\showwal.c $(SQLITE3C) $(SQLITE3H) showshm.exe: $(TOP)\tool\showshm.c $(LTLINK) $(NO_WARN) $(TOP)\tool\showshm.c /link $(LDFLAGS) $(LTLINKOPTS) +showtmlog.exe: $(TOP)\tool\showtmlog.c + $(LTLINK) $(NO_WARN) $(TOP)\tool\showtmlog.c /link $(LDFLAGS) $(LTLINKOPTS) + index_usage.exe: $(TOP)\tool\index_usage.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(TOP)\tool\index_usage.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 888b6cf5e1..94630cc4ef 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -144,9 +144,8 @@ ** op a1 ts a2 a3 ** ** The meanings of the a1-a3 values depend on op. ts is the timestamp -** in milliseconds since 1970-01-01. (6 bytes is sufficient for timestamps -** for almost 9000 years.) Opcodes are defined by the ELOG_* #defines -** below. +** in milliseconds since the unix epoch (1970-01-01 00:00:00). +** Opcodes are defined by the ELOG_* #defines below. ** ** ELOG_OPEN_DB "Open a connection to the database file" ** op = 0x01 @@ -377,6 +376,7 @@ static const sqlite3_io_methods tmstmp_io_methods = { static void tmstmpPutTS(TmstmpFile *p, unsigned char *aOut){ sqlite3_uint64 tm = 0; p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, (sqlite3_int64*)&tm); + tm -= 210866760000000LL; aOut[0] = (tm>>40)&0xff; aOut[1] = (tm>>32)&0xff; aOut[2] = (tm>>24)&0xff; @@ -775,6 +775,7 @@ static int tmstmpOpen( memset(pLog, 0, sizeof(pLog[0])); p->pLog = pLog; p->pSubVfs->xCurrentTimeInt64(p->pSubVfs, (sqlite3_int64*)&r1); + r1 -= 210866760000000LL; sqlite3_randomness(sizeof(r2), &r2); pid = GETPID; pLog->zLogname = sqlite3_mprintf("%s-tmstmp/%llx-%08x-%08x", diff --git a/main.mk b/main.mk index 91fcc1b946..8b5d2821cf 100644 --- a/main.mk +++ b/main.mk @@ -2018,6 +2018,10 @@ showshm$(T.exe): $(TOP)/tool/showshm.c $(T.link) -o $@ $(TOP)/tool/showshm.c $(LDFLAGS.configure) xbin: showshm$(T.exe) +showtmlog$(T.exe): $(TOP)/tool/showtmlog.c + $(T.link) -o $@ $(TOP)/tool/showtmlog.c $(LDFLAGS.configure) +xbin: showshm$(T.exe) + index_usage$(T.exe): $(TOP)/tool/index_usage.c sqlite3.o $(T.link) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.o \ $(LDFLAGS.libsqlite3) diff --git a/manifest b/manifest index 543e9c293d..10842b5320 100644 --- a/manifest +++ b/manifest @@ -1,12 +1,12 @@ -C Improve\sshowdb\sso\sthat\sit\sdoes\sa\sbetter\sjob\sof\shandling\sreserve-bytes.\nAdd\sthe\s--tmstmp\soption\sthat\scauses\spgidx\sto\sinterpret\stmstmpvfs\stags\nif\sthey\sare\savailable. -D 2026-01-08T01:37:13.895 +C Add\sthe\sshowtmlog\sutility\sfor\sdecoding\sthe\stmstmpvfs\slog\sfiles.\nFix\stmstmpvfs\sso\sthat\sit\srecords\stimestamps\sin\smilliseconds\ssince\sthe\nUnix\sepoch,\snot\sin\sJDN\smilliseconds. +D 2026-01-08T12:22:50.349 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md 6bc480fc673fb4acbc4094e77edb326267dd460162d7723c7f30bee2d3d9e97d F Makefile.in 3ce07126d7e87c7464301482e161fdae6a51d0a2aa06b200b8f0000ef4d6163b F Makefile.linux-generic bd3e3cacd369821a6241d4ea1967395c962dfe3057e38cb0a435cee0e8b789d0 -F Makefile.msc 48c5be34727fd835c675eb9a6ba21900d66088fcec81210cb2e134927aa0fa4f +F Makefile.msc 1fa179beafd6d438b8479146cae77fb1724dd35b330b09dbfebd8a2f0823c62a F README.md 3fa51fc7ababc32edd175ae8b2986c86d5ea120c1cb1e57c7f7849492d1405ec F VERSION 74672bfd4c7826c0fc6f84762488a707c52e7d2d94af42ccb0edcc6c74311c41 F art/icon-243x273.gif 9750b734f82fdb3dc43127753d5e6fbf3b62c9f4e136c2fbf573b2f57ea87af5 @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c 4953aa97872c67d55e22351cdf3dc3d06e81ef0f28c6105f1fae2214f3250c74 +F ext/misc/tmstmpvfs.c f7845d1641cfc26d78ae017ccabc05cb01f712db07f95ae1bad1df564d566a2a F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -659,7 +659,7 @@ F ext/wasm/tests/opfs/sahpool/index.html be736567fd92d3ecb9754c145755037cbbd2bca F ext/wasm/tests/opfs/sahpool/sahpool-pausing.js f264925cfc82155de38cecb3d204c36e0f6991460fff0cb7c15079454679a4e2 F ext/wasm/tests/opfs/sahpool/sahpool-worker.js bd25a43fc2ab2d1bafd8f2854ad3943ef673f7c3be03e95ecf1612ff6e8e2a61 F magic.txt 5ade0bc977aa135e79e3faaea894d5671b26107cc91e70783aa7dc83f22f3ba0 -F main.mk ba9ac943f81c80cd2d7b502759e60d23a988be74cc7b4b1575419932fe2afcb0 +F main.mk 9393d5982db60f26e72c5af24a8c11cf39374ff5e695fadb5a4e7376f28150c6 F make.bat a136fd0b1c93e89854a86d5f4edcf0386d211e5d5ec2434480f6eea436c7420c F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -2164,6 +2164,7 @@ F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 F tool/showstat4.c b706fcbc4cd1a6e4a73ac32549afc4b460479d650402d64b23e8d813516e8de4 +F tool/showtmlog.c 5e5d8b217ce48056583f97c7c16d68287bbaeff77ef6d4b54cbc2c7ca298a44f F tool/showwal.c 11eca547980a066b081f512636151233350ac679f29ecf4ebfce7f4530230b3d F tool/soak1.tcl a3892082ed1079671565c044e93b55c3c7f38829aedf53cc597c65d23ffdaddf F tool/spaceanal.tcl 1f83962090a6b60e1d7bf92495d643e622bef9fe82ea3f2d22350dcbce9a12d0 @@ -2190,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 869f306592a86d2a78f00266c615f033cd2318a7bff0a97b3dcdd3348d99fc66 -R 84dfc7b9c377c2c122ebbcbfef876fb5 +P d7e6e9a5781f467a5b5f02f46134099cf01607a0cf55510155533d57d4a4618a +R 480580b84284dc2078a6aa5caacd15c8 U drh -Z da6fd7cd7ce3a4452ba602eb99ca3b3b +Z 20a5cec87f22c6e120bc0b5fcbbfb23d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ae055627fe..63a01af7aa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d7e6e9a5781f467a5b5f02f46134099cf01607a0cf55510155533d57d4a4618a +762d3cbf06218f1010425a98a71ebf7623b84b45a90e6419b7dec7f10ad0c5a5 diff --git a/tool/showtmlog.c b/tool/showtmlog.c new file mode 100644 index 0000000000..d3da92f79a --- /dev/null +++ b/tool/showtmlog.c @@ -0,0 +1,133 @@ +/* +** A utility program to decode tmstmpvfs log files. +*/ +#include +#include +#include +#include + +/* +** The six bytes at a[] are a big-endian unsigned integer which is the +** number of milliseconds since 1970. Decode that value into an ISO 8601 +** date/time string stored in static space and return a pointer to that +** string. +*/ +static const char *decodeTimestamp(const unsigned char *a){ + uint64_t ms; /* Milliseconds since 1970 */ + uint64_t days; /* Days since 1970-01-01 */ + uint64_t sod; /* Start of date specified by ms */ + uint64_t z; /* Days since 0000-03-01 */ + uint64_t era; /* 400-year era */ + int i; /* Loop counter */ + int h; /* hour */ + int m; /* minute */ + int s; /* second */ + int f; /* millisecond */ + int Y; /* year */ + int M; /* month */ + int D; /* day */ + int y; /* year assuming March is first month */ + unsigned int doe; /* day of 400-year era */ + unsigned int yoe; /* year of 400-year era */ + unsigned int doy; /* day of year */ + unsigned int mp; /* month with March==0 */ + static char zOut[50]; /* Return results here */ + + for(ms=0, i=0; i<=5; i++) ms = (ms<<8) + a[i]; + if( ms>253402300800000LL ){ + /* YYYY-MM-DD HH:MM:SS.SSS */ + return "---date out of range---"; + } + days = ms/86400000; + sod = (ms%86400000)/1000; + f = (int)(ms%1000); + + h = sod/3600; + m = (sod%3600)/60; + s = sod%60; + z = days + 719468; + era = z/147097; + doe = (unsigned)(z - era*146097); + yoe = (doe - doe/1460 + doe/36524 - doe/146096)/365; + y = (int)yoe + era*400; + doy = doe - (365*yoe + yoe/4 - yoe/100); + mp = (5*doy + 2)/153; + D = doy - (153*mp + 2)/5 + 1; + M = mp + (mp<10 ? 3 : -9); + Y = y + (M <=2); + snprintf(zOut, sizeof(zOut), + "%04d-%02d-%02d %02d:%02d:%02d.%03d", + Y, M, D, h, m, s, f); + return zOut; +} + +int main(int argc, char **argv){ + int i; + FILE *in; + unsigned int a2, a3; + unsigned char a[16]; + for(i=1; i2 ){ + printf("*** %s ***\n", argv[i]); + } + while( 16==fread(a, 1, 16, in) ){ + printf("%s ", decodeTimestamp(a+2)); + for(a2=0, i=8; i<=11; i++) a2 = (a2<<8)+a[i]; + for(a3=0, i=12; i<=15; i++) a3 = (a3<<8)+a[i]; + switch( a[0] ){ + case 0x01: { + printf("open-db pid %u\n", a2); + break; + } + case 0x02: { + printf("open-wal pid %u\n", a2); + break; + } + case 0x03: { + printf("wal-page pgno %-8u frame %-8u%s\n", a2, a3, + a[1]==1 ? " txn" : ""); + break; + } + case 0x04: { + printf("db-page pgno %-8u\n", a2); + break; + } + case 0x05: { + printf("ckpt-start\n"); + break; + } + case 0x06: { + printf("ckpt-page pgno %-8u\n", a2); + break; + } + case 0x07: { + printf("ckpt-end\n"); + break; + } + case 0x08: { + printf("wal-reset salt1 0x%08x\n", a3); + break; + } + case 0x0e: { + printf("close-wal\n"); + break; + } + case 0x0f: { + printf("close-db\n"); + break; + } + default: { + printf("invalid-record\n"); + break; + } + } + } + fclose(in); + } + return 0; +} From 67429703bf205b5ba17a76b01fa170fd46f0f3c2 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 8 Jan 2026 12:39:49 +0000 Subject: [PATCH 09/17] Do not show LIKE wildcards on table names in the output of the ".schema" command in the CLI. [forum:/info/6ebb57b41691293d|Forum post 6ebb57b41691293d]. FossilOrigin-Name: 4c6f646bd2910e6dc80dfec7546a3ed7b47bb9d00402e7c3871ece2c185f4ec0 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 6 ++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 10842b5320..d4fb19e092 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sshowtmlog\sutility\sfor\sdecoding\sthe\stmstmpvfs\slog\sfiles.\nFix\stmstmpvfs\sso\sthat\sit\srecords\stimestamps\sin\smilliseconds\ssince\sthe\nUnix\sepoch,\snot\sin\sJDN\smilliseconds. -D 2026-01-08T12:22:50.349 +C Do\snot\sshow\sLIKE\swildcards\son\stable\snames\sin\sthe\soutput\sof\sthe\s".schema"\ncommand\sin\sthe\sCLI.\n[forum:/info/6ebb57b41691293d|Forum\spost\s6ebb57b41691293d]. +D 2026-01-08T12:39:49.442 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -738,7 +738,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4d45a04431db072040d6625ee21c1dc483c9b2b64a5ab419f4a4e05aabed1204 -F src/shell.c.in 587ec295ced5204e7a172cd090a470776ca58c2875ee7cc18194f18fa0d3ff2a +F src/shell.c.in 9678c58254450a00fa93931f0d9f4552478fa0ea02d52a33bbd7ed945165c86c F src/sqlite.h.in 476f3efeb5dd26ad94dcbce262ca7eb9d042d797a92d624059c67ef37d5b3ab4 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d7e6e9a5781f467a5b5f02f46134099cf01607a0cf55510155533d57d4a4618a -R 480580b84284dc2078a6aa5caacd15c8 +P 762d3cbf06218f1010425a98a71ebf7623b84b45a90e6419b7dec7f10ad0c5a5 +R bffa6e5c27e1b1d54b2f1e31deac907b U drh -Z 20a5cec87f22c6e120bc0b5fcbbfb23d +Z 97460544afe91d918809138a211e67c2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 63a01af7aa..c8768db589 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -762d3cbf06218f1010425a98a71ebf7623b84b45a90e6419b7dec7f10ad0c5a5 +4c6f646bd2910e6dc80dfec7546a3ed7b47bb9d00402e7c3871ece2c185f4ec0 diff --git a/src/shell.c.in b/src/shell.c.in index 0091c36ce6..61006033fe 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -10411,13 +10411,15 @@ static int do_meta_command(const char *zLine, ShellState *p){ || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0; if( isSchema ){ cli_printf(p->out, - "CREATE TABLE %s (\n" + "CREATE TABLE %ssqlite_schema (\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" - ");\n", zName); + ");\n", + sqlite3_strlike("sqlite_t%",zName,0)==0 ? "temp." : "" + ); } } rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); From 9f9ee82b62f2a125c0d35a31720dc1968db45455 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 8 Jan 2026 12:43:21 +0000 Subject: [PATCH 10/17] Fix ESCALE typo in shell.c, reported in [forum:b8f6a41c8b|forum post b8f6a41c8b]. FossilOrigin-Name: 6fa09449738af03d096208e26447b795f2825d6aaa397de09590cf18b065f82d --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c.in | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index d4fb19e092..92ba7418d2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sshow\sLIKE\swildcards\son\stable\snames\sin\sthe\soutput\sof\sthe\s".schema"\ncommand\sin\sthe\sCLI.\n[forum:/info/6ebb57b41691293d|Forum\spost\s6ebb57b41691293d]. -D 2026-01-08T12:39:49.442 +C Fix\sESCALE\stypo\sin\sshell.c,\sreported\sin\s[forum:b8f6a41c8b|forum\spost\sb8f6a41c8b]. +D 2026-01-08T12:43:21.947 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -738,7 +738,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4d45a04431db072040d6625ee21c1dc483c9b2b64a5ab419f4a4e05aabed1204 -F src/shell.c.in 9678c58254450a00fa93931f0d9f4552478fa0ea02d52a33bbd7ed945165c86c +F src/shell.c.in e15a10d4d11c3e34bc2059dd29e9c1f7e7eafe66c0c195310b21c4940c59511d F src/sqlite.h.in 476f3efeb5dd26ad94dcbce262ca7eb9d042d797a92d624059c67ef37d5b3ab4 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 762d3cbf06218f1010425a98a71ebf7623b84b45a90e6419b7dec7f10ad0c5a5 -R bffa6e5c27e1b1d54b2f1e31deac907b -U drh -Z 97460544afe91d918809138a211e67c2 +P 4c6f646bd2910e6dc80dfec7546a3ed7b47bb9d00402e7c3871ece2c185f4ec0 +R 94649a4f0c351b0b1058fefe4e31412a +U stephan +Z 58d0934d295cf5006c627f2984459682 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c8768db589..d35d35d420 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4c6f646bd2910e6dc80dfec7546a3ed7b47bb9d00402e7c3871ece2c185f4ec0 +6fa09449738af03d096208e26447b795f2825d6aaa397de09590cf18b065f82d diff --git a/src/shell.c.in b/src/shell.c.in index 61006033fe..3e9136f7fb 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -10479,7 +10479,7 @@ static int do_meta_command(const char *zLine, ShellState *p){ } } if( bNoSystemTabs ){ - sqlite3_str_appendf(pSql, " name NOT LIKE 'sqlite__%%' ESCALE '_' AND "); + sqlite3_str_appendf(pSql, " name NOT LIKE 'sqlite__%%' ESCAPE '_' AND "); } sqlite3_str_appendf(pSql, "sql IS NOT NULL ORDER BY snum, rowid"); if( bDebug ){ From c219d3002f9d4c77c9778b0cd96ce6d911eb96fe Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 8 Jan 2026 13:20:36 +0000 Subject: [PATCH 11/17] In the showdb utility, the -tmstmp option works without -csv for the pgidx command. FossilOrigin-Name: c0aecd2189b431d82eca1c1d6718920cf928d910d443ea506e7b3bf3c5d7e246 --- manifest | 16 ++++++------ manifest.uuid | 2 +- tool/showdb.c | 68 +++++++++++++++++++++++++++++++++++++++++++++--- tool/showtmlog.c | 6 +++-- 4 files changed, 78 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 92ba7418d2..4a963a4fd0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sESCALE\stypo\sin\sshell.c,\sreported\sin\s[forum:b8f6a41c8b|forum\spost\sb8f6a41c8b]. -D 2026-01-08T12:43:21.947 +C In\sthe\sshowdb\sutility,\sthe\s-tmstmp\soption\sworks\swithout\s-csv\sfor\sthe\spgidx\ncommand. +D 2026-01-08T13:20:36.301 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -2159,12 +2159,12 @@ F tool/pagesig.c f98909b4168d9cac11a2de7f031adea0e2f3131faa7515a72807c03ec58eafe F tool/replace.tcl 511c61acfe563dfb58675efb4628bb158a13d48ff8322123ac447e9d25a82d9a F tool/restore_jrnl.tcl 1079ecba47cc82fa82115b81c1f68097ab1f956f357ee8da5fc4b2589af6bd98 F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c 9c2c783a64b4d3b1f5fa9fe8e64add8c620c21b1831e10a2cec51ab59768da71 +F tool/showdb.c 99b1061df9077c0370042a0e414d8f17b30db01d83bbe74ab7fb8fbaf1301bfc F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 F tool/showstat4.c b706fcbc4cd1a6e4a73ac32549afc4b460479d650402d64b23e8d813516e8de4 -F tool/showtmlog.c 5e5d8b217ce48056583f97c7c16d68287bbaeff77ef6d4b54cbc2c7ca298a44f +F tool/showtmlog.c eb0e6d3f6345da795edcd8dd1f395b52985c1d3c8e861722a60e7651ded33360 F tool/showwal.c 11eca547980a066b081f512636151233350ac679f29ecf4ebfce7f4530230b3d F tool/soak1.tcl a3892082ed1079671565c044e93b55c3c7f38829aedf53cc597c65d23ffdaddf F tool/spaceanal.tcl 1f83962090a6b60e1d7bf92495d643e622bef9fe82ea3f2d22350dcbce9a12d0 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 4c6f646bd2910e6dc80dfec7546a3ed7b47bb9d00402e7c3871ece2c185f4ec0 -R 94649a4f0c351b0b1058fefe4e31412a -U stephan -Z 58d0934d295cf5006c627f2984459682 +P 6fa09449738af03d096208e26447b795f2825d6aaa397de09590cf18b065f82d +R 8fd9691005ccfe6bf27e94848c7c9911 +U drh +Z 0bc0a7bcfad2b426d91d7190bf1fff2a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d35d35d420..7e69b0f1c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6fa09449738af03d096208e26447b795f2825d6aaa397de09590cf18b065f82d +c0aecd2189b431d82eca1c1d6718920cf928d910d443ea506e7b3bf3c5d7e246 diff --git a/tool/showdb.c b/tool/showdb.c index 045956e186..78af2c49ac 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -8,6 +8,7 @@ #include #include #include +#include #if !defined(_MSC_VER) #include @@ -1008,6 +1009,63 @@ static void page_usage_ptrmap(u8 *a){ } } +/* +** The six bytes at a[] are a big-endian unsigned integer which is the +** number of milliseconds since 1970. Decode that value into an ISO 8601 +** date/time string stored in static space and return a pointer to that +** string. +*/ +static const char *decodeTimestamp(const unsigned char *a){ + uint64_t ms; /* Milliseconds since 1970 */ + uint64_t days; /* Days since 1970-01-01 */ + uint64_t sod; /* Start of date specified by ms */ + uint64_t z; /* Days since 0000-03-01 */ + uint64_t era; /* 400-year era */ + int i; /* Loop counter */ + int h; /* hour */ + int m; /* minute */ + int s; /* second */ + int f; /* millisecond */ + int Y; /* year */ + int M; /* month */ + int D; /* day */ + int y; /* year assuming March is first month */ + unsigned int doe; /* day of 400-year era */ + unsigned int yoe; /* year of 400-year era */ + unsigned int doy; /* day of year */ + unsigned int mp; /* month with March==0 */ + static char zOut[50]; /* Return results here */ + + for(ms=0, i=0; i<=5; i++) ms = (ms<<8) + a[i]; + if( ms==0 ){ + return " "; + }else if( ms>4102444800000LL ){ /* 2100-01-01 */ + /* YYYY-MM-DD HH:MM:SS.SSS */ + return " (bad date) "; + } + days = ms/86400000; + sod = (ms%86400000)/1000; + f = (int)(ms%1000); + + h = sod/3600; + m = (sod%3600)/60; + s = sod%60; + z = days + 719468; + era = z/147097; + doe = (unsigned)(z - era*146097); + yoe = (doe - doe/1460 + doe/36524 - doe/146096)/365; + y = (int)yoe + era*400; + doy = doe - (365*yoe + yoe/4 - yoe/100); + mp = (5*doy + 2)/153; + D = doy - (153*mp + 2)/5 + 1; + M = mp + (mp<10 ? 3 : -9); + Y = y + (M <=2); + snprintf(zOut, sizeof(zOut), + "%04d-%02d-%02d %02d:%02d:%02d.%03d", + Y, M, D, h, m, s, f); + return zOut; +} + /* ** Try to figure out how every page in the database file is being used. */ @@ -1080,9 +1138,7 @@ static void page_usage_report(const char *zPrg, const char *zDbName){ g.zPageUse[i] = sqlite3_mprintf("???"); if( g.zPageUse[i]==0 ) continue; } - if( !g.bCSV ){ - printf("%5u: %s\n", i, g.zPageUse[i]); - }else{ + if( g.bCSV ){ const char *z = g.zPageUse[i]; const char *s; printf("%u,", i); @@ -1119,6 +1175,12 @@ static void page_usage_report(const char *zPrg, const char *zDbName){ printf("-1,"); } printf("\"%s\"\r\n", z); + }else if( g.bTmstmp ){ + printf("%5u: %s %s\n", i, + decodeTimestamp(&g.aPageTag[i].a[2]), + g.zPageUse[i]); + }else{ + printf("%5u: %s\n", i, g.zPageUse[i]); } } for(i=1; i<=g.mxPage; i++){ diff --git a/tool/showtmlog.c b/tool/showtmlog.c index d3da92f79a..4770c6aa3b 100644 --- a/tool/showtmlog.c +++ b/tool/showtmlog.c @@ -34,9 +34,11 @@ static const char *decodeTimestamp(const unsigned char *a){ static char zOut[50]; /* Return results here */ for(ms=0, i=0; i<=5; i++) ms = (ms<<8) + a[i]; - if( ms>253402300800000LL ){ + if( ms==0 ){ + return " "; + }else if( ms>4102444800000LL ){ /* 2100-01-01 */ /* YYYY-MM-DD HH:MM:SS.SSS */ - return "---date out of range---"; + return " (bad date) "; } days = ms/86400000; sod = (ms%86400000)/1000; From 22b08034aa4b2569cf54f40add494e5451fe4b7d Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 8 Jan 2026 13:43:15 +0000 Subject: [PATCH 12/17] Enhance the --vfs command-line option to the CLI such that if the argument is not a valid VFS name, but is the name of a file, attempt to load that file as an extension, which presumably adds the desired VFS. FossilOrigin-Name: 509954b44eb305a4401ddcbcce24d8f9ed5534717290888899d716b9df40c981 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 4a963a4fd0..8250b7a1a6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sshowdb\sutility,\sthe\s-tmstmp\soption\sworks\swithout\s-csv\sfor\sthe\spgidx\ncommand. -D 2026-01-08T13:20:36.301 +C Enhance\sthe\s--vfs\scommand-line\soption\sto\sthe\sCLI\ssuch\sthat\sif\sthe\sargument\nis\snot\sa\svalid\sVFS\sname,\sbut\sis\sthe\sname\sof\sa\sfile,\sattempt\sto\sload\sthat\nfile\sas\san\sextension,\swhich\spresumably\sadds\sthe\sdesired\sVFS. +D 2026-01-08T13:43:15.539 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -738,7 +738,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4d45a04431db072040d6625ee21c1dc483c9b2b64a5ab419f4a4e05aabed1204 -F src/shell.c.in e15a10d4d11c3e34bc2059dd29e9c1f7e7eafe66c0c195310b21c4940c59511d +F src/shell.c.in 6c4f20a4787933b0a5fce307b7d9d67e00805966a52186f0c2cd04d75691c38b F src/sqlite.h.in 476f3efeb5dd26ad94dcbce262ca7eb9d042d797a92d624059c67ef37d5b3ab4 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 6fa09449738af03d096208e26447b795f2825d6aaa397de09590cf18b065f82d -R 8fd9691005ccfe6bf27e94848c7c9911 +P c0aecd2189b431d82eca1c1d6718920cf928d910d443ea506e7b3bf3c5d7e246 +R 8831b900d82357c1d3aa973bdb8ea7c9 U drh -Z 0bc0a7bcfad2b426d91d7190bf1fff2a +Z b7d5cc86868374aca5662283466f56bc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7e69b0f1c6..26f08c532c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c0aecd2189b431d82eca1c1d6718920cf928d910d443ea506e7b3bf3c5d7e246 +509954b44eb305a4401ddcbcce24d8f9ed5534717290888899d716b9df40c981 diff --git a/src/shell.c.in b/src/shell.c.in index 3e9136f7fb..d022517ec5 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -13023,6 +13023,21 @@ int SQLITE_CDECL main(int argc, char **argv){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); + }else if( access(zVfs,0)==0 ){ + /* If the VFS name is not the name of an existing VFS, but it is + ** the name of a file, then try to load that file as an extension. + ** Presumably the extension implements the desired VFS. */ + sqlite3 *db = 0; + char *zErr = 0; + sqlite3_open(":memory:", &db); + sqlite3_enable_load_extension(db, 1); + rc = sqlite3_load_extension(db, zVfs, 0, &zErr); + sqlite3_close(db); + if( (rc&0xff)!=SQLITE_OK ){ + cli_printf(stderr, "could not load extension VFS \"%s\": %s\n", + zVfs, zErr); + exit(1); + } }else{ cli_printf(stderr,"no such VFS: \"%s\"\n", zVfs); exit(1); From 92730d21ff93c2a9102aec5a232b88b1797fe472 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 8 Jan 2026 15:03:00 +0000 Subject: [PATCH 13/17] Fix the --size X flag for speedtest1.html when X=0 and force the job size to 5 for kvvfs so that it doesn't block the main thread for too awful long. FossilOrigin-Name: e2634e500cce44650ad5dd95b722b993b1f999b9f8b2396ab15154e67cb065c7 --- ext/wasm/speedtest1.html | 4 ++-- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/wasm/speedtest1.html b/ext/wasm/speedtest1.html index 22077ba4aa..d41f20a4ed 100644 --- a/ext/wasm/speedtest1.html +++ b/ext/wasm/speedtest1.html @@ -118,7 +118,7 @@ argv.push("--vfs", vfs); log2('',"Using VFS:",vfs); if('kvvfs' === vfs){ - //forceSize = 10 + forceSize = 5 /* --size > 2 is too big for local/session storage as of mid-2025, but kvvfs v2 (late 2025) lets us use transient storage. */; @@ -135,7 +135,7 @@ 'size' ].forEach(function(k){ const v = urlParams.get(k); - if(v) argv.push('--'+k, urlParams[k]); + if(v && +v) argv.push('--'+k, urlParams[k]); }); } argv.push( diff --git a/manifest b/manifest index 8250b7a1a6..fe5c58fc24 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\s--vfs\scommand-line\soption\sto\sthe\sCLI\ssuch\sthat\sif\sthe\sargument\nis\snot\sa\svalid\sVFS\sname,\sbut\sis\sthe\sname\sof\sa\sfile,\sattempt\sto\sload\sthat\nfile\sas\san\sextension,\swhich\spresumably\sadds\sthe\sdesired\sVFS. -D 2026-01-08T13:43:15.539 +C Fix\sthe\s--size\sX\sflag\sfor\sspeedtest1.html\swhen\sX=0\sand\sforce\sthe\sjob\ssize\sto\s5\sfor\skvvfs\sso\sthat\sit\sdoesn't\sblock\sthe\smain\sthread\sfor\stoo\sawful\slong. +D 2026-01-08T15:03:00.621 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -641,7 +641,7 @@ F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2 F ext/wasm/speedtest1-wasmfs.mjs 60dd5842f6d2a70a6d0bef12633a11491bde6984aff75a37c2040980d8cbf36a F ext/wasm/speedtest1-worker.html 068d4190f304fa1c34e6501a1b3a4c32fe8d8dac93c2d0f53d667a1cb386eedc F ext/wasm/speedtest1-worker.js 8acad67bfd6aeeb799bd5ae007ea32af85a082a287d8877c5a10adf4bd7efd89 -F ext/wasm/speedtest1.html 856ddb26af6f21c228614614ccff73abc1f8bd877447c1c8da15cfabba5615c2 +F ext/wasm/speedtest1.html f32c66997eb0b036c4546e6302cd0673157912661df0b290ab65816f713feac6 F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f1293583ad5af0cd3a3779e205 x F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0 F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P c0aecd2189b431d82eca1c1d6718920cf928d910d443ea506e7b3bf3c5d7e246 -R 8831b900d82357c1d3aa973bdb8ea7c9 -U drh -Z b7d5cc86868374aca5662283466f56bc +P 509954b44eb305a4401ddcbcce24d8f9ed5534717290888899d716b9df40c981 +R a11927462ed458c83a2a286cf6394157 +U stephan +Z 327465c2c2c011f71541533cf20af8e5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 26f08c532c..fa1aa09f4d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -509954b44eb305a4401ddcbcce24d8f9ed5534717290888899d716b9df40c981 +e2634e500cce44650ad5dd95b722b993b1f999b9f8b2396ab15154e67cb065c7 From 784bceae330a29f0e88d8d5d490f4474cb0cabd9 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 8 Jan 2026 15:06:28 +0000 Subject: [PATCH 14/17] Remove an obsolete '32-bit' label from tester1-worker. FossilOrigin-Name: e14d9a980351a8d5e935e6991ea02a1c40c9ea8f0ad0fadcabe07d575a9b289c --- ext/wasm/tester1-worker.c-pp.html | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/wasm/tester1-worker.c-pp.html b/ext/wasm/tester1-worker.c-pp.html index 716544ded3..71d827a35f 100644 --- a/ext/wasm/tester1-worker.c-pp.html +++ b/ext/wasm/tester1-worker.c-pp.html @@ -12,7 +12,7 @@

sqlite3 tester #1: Worker thread (@bitness@-bit WASM)

-
Variants (32-bit): +
Variants: conventional UI thread: (32-bit, 64-bit), diff --git a/manifest b/manifest index fe5c58fc24..c3bb94ffa0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\s--size\sX\sflag\sfor\sspeedtest1.html\swhen\sX=0\sand\sforce\sthe\sjob\ssize\sto\s5\sfor\skvvfs\sso\sthat\sit\sdoesn't\sblock\sthe\smain\sthread\sfor\stoo\sawful\slong. -D 2026-01-08T15:03:00.621 +C Remove\san\sobsolete\s'32-bit'\slabel\sfrom\stester1-worker. +D 2026-01-08T15:06:28.736 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -647,7 +647,7 @@ F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d826 F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5 F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c -F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a +F ext/wasm/tester1-worker.c-pp.html d0032241d0b24d996cf1c4dd0dde364189693af9b5c986e48af7d3d720fcd244 F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb F ext/wasm/tester1.c-pp.js 7bc90f6e3d133c735fad05d5409915bd1389f4b5d6ce7c5daca33856669e706b F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 509954b44eb305a4401ddcbcce24d8f9ed5534717290888899d716b9df40c981 -R a11927462ed458c83a2a286cf6394157 +P e2634e500cce44650ad5dd95b722b993b1f999b9f8b2396ab15154e67cb065c7 +R 09c7e4f9e51b68995275f1b08c5fc647 U stephan -Z 327465c2c2c011f71541533cf20af8e5 +Z 3ce2c4087e51df424d65b55ac9e30b7a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fa1aa09f4d..032962a0f9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e2634e500cce44650ad5dd95b722b993b1f999b9f8b2396ab15154e67cb065c7 +e14d9a980351a8d5e935e6991ea02a1c40c9ea8f0ad0fadcabe07d575a9b289c From 403c153dfadd67576959ad7abd2c519803d74b1b Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 8 Jan 2026 15:25:04 +0000 Subject: [PATCH 15/17] Minor bug fixes in tmstmpvfs.c, showdb.c, and showtmlog.c. FossilOrigin-Name: 1fee8265f7eab649ee8b28456c37d95198f5cde54e905154e3eccc0b328ece9a --- ext/misc/tmstmpvfs.c | 50 ++++++++++++++++++++++---------------------- manifest | 18 ++++++++-------- manifest.uuid | 2 +- tool/showdb.c | 8 +++---- tool/showtmlog.c | 6 +++--- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index 94630cc4ef..c2836bd86c 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -616,34 +616,34 @@ static int tmstmpFileControl(sqlite3_file *pFile, int op, void *pArg){ TmstmpFile *p = (TmstmpFile*)pFile; pFile = ORIGFILE(pFile); rc = pFile->pMethods->xFileControl(pFile, op, pArg); - if( rc==SQLITE_OK ){ - switch( op ){ - case SQLITE_FCNTL_VFSNAME: { - if( p->hasCorrectReserve ){ - *(char**)pArg = sqlite3_mprintf("tmstmp/%z", *(char**)pArg); - } - break; + switch( op ){ + case SQLITE_FCNTL_VFSNAME: { + if( p->hasCorrectReserve && rc==SQLITE_OK ){ + *(char**)pArg = sqlite3_mprintf("tmstmp/%z", *(char**)pArg); } - case SQLITE_FCNTL_CKPT_START: { - p->inCkpt = 1; - assert( p->isDb ); - assert( p->pPartner!=0 ); - p->pPartner->inCkpt = 1; - if( p->hasCorrectReserve ){ - tmstmpEvent(p, ELOG_CKPT_START, 0, 0, 0); - } - break; + break; + } + case SQLITE_FCNTL_CKPT_START: { + p->inCkpt = 1; + assert( p->isDb ); + assert( p->pPartner!=0 ); + p->pPartner->inCkpt = 1; + if( p->hasCorrectReserve ){ + tmstmpEvent(p, ELOG_CKPT_START, 0, 0, 0); } - case SQLITE_FCNTL_CKPT_DONE: { - p->inCkpt = 0; - assert( p->isDb ); - assert( p->pPartner!=0 ); - p->pPartner->inCkpt = 0; - if( p->hasCorrectReserve ){ - tmstmpEvent(p, ELOG_CKPT_DONE, 0, 0, 0); - } - break; + rc = SQLITE_OK; + break; + } + case SQLITE_FCNTL_CKPT_DONE: { + p->inCkpt = 0; + assert( p->isDb ); + assert( p->pPartner!=0 ); + p->pPartner->inCkpt = 0; + if( p->hasCorrectReserve ){ + tmstmpEvent(p, ELOG_CKPT_DONE, 0, 0, 0); } + rc = SQLITE_OK; + break; } } return rc; diff --git a/manifest b/manifest index c3bb94ffa0..b825a3333b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sobsolete\s'32-bit'\slabel\sfrom\stester1-worker. -D 2026-01-08T15:06:28.736 +C Minor\sbug\sfixes\sin\stmstmpvfs.c,\sshowdb.c,\sand\sshowtmlog.c. +D 2026-01-08T15:25:04.189 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c f7845d1641cfc26d78ae017ccabc05cb01f712db07f95ae1bad1df564d566a2a +F ext/misc/tmstmpvfs.c ff66db6b88bc5bd011d5a92e8f5e35af93499d4d615330ab14a61a23ce5c7856 F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2159,12 +2159,12 @@ F tool/pagesig.c f98909b4168d9cac11a2de7f031adea0e2f3131faa7515a72807c03ec58eafe F tool/replace.tcl 511c61acfe563dfb58675efb4628bb158a13d48ff8322123ac447e9d25a82d9a F tool/restore_jrnl.tcl 1079ecba47cc82fa82115b81c1f68097ab1f956f357ee8da5fc4b2589af6bd98 F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 -F tool/showdb.c 99b1061df9077c0370042a0e414d8f17b30db01d83bbe74ab7fb8fbaf1301bfc +F tool/showdb.c db1fba9149d29bc4d9fe2826b881d66da980a5f01e0c0858244e93f18d388321 F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564 F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a809 F tool/showstat4.c b706fcbc4cd1a6e4a73ac32549afc4b460479d650402d64b23e8d813516e8de4 -F tool/showtmlog.c eb0e6d3f6345da795edcd8dd1f395b52985c1d3c8e861722a60e7651ded33360 +F tool/showtmlog.c 2ee3cfe698f64256419b2c2beacd504f24b020d6e2a91115f872a28ede188aa1 F tool/showwal.c 11eca547980a066b081f512636151233350ac679f29ecf4ebfce7f4530230b3d F tool/soak1.tcl a3892082ed1079671565c044e93b55c3c7f38829aedf53cc597c65d23ffdaddf F tool/spaceanal.tcl 1f83962090a6b60e1d7bf92495d643e622bef9fe82ea3f2d22350dcbce9a12d0 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e2634e500cce44650ad5dd95b722b993b1f999b9f8b2396ab15154e67cb065c7 -R 09c7e4f9e51b68995275f1b08c5fc647 -U stephan -Z 3ce2c4087e51df424d65b55ac9e30b7a +P e14d9a980351a8d5e935e6991ea02a1c40c9ea8f0ad0fadcabe07d575a9b289c +R 5732f9b90659e548d32a735de971cff5 +U drh +Z af5bc160622d940e12d2af419055b1c0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 032962a0f9..79dd7159a3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e14d9a980351a8d5e935e6991ea02a1c40c9ea8f0ad0fadcabe07d575a9b289c +1fee8265f7eab649ee8b28456c37d95198f5cde54e905154e3eccc0b328ece9a diff --git a/tool/showdb.c b/tool/showdb.c index 78af2c49ac..6ee39707c7 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -175,8 +175,8 @@ static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){ } } if( g.aPageTag && nByte==(int)g.pagesize ){ - unsigned int pgno = (unsigned int)(ofst/g.pagesize); - if( pgno>=0 && pgno<=g.mxPage ){ + unsigned int pgno = (unsigned int)(ofst/g.pagesize) + 1; + if( pgno>0 && pgno<=g.mxPage ){ memcpy(g.aPageTag[pgno].a, &aData[nByte-16], 16); } } @@ -856,7 +856,7 @@ static void page_usage_cell( while( ovfl && (cnt++) Date: Thu, 8 Jan 2026 15:26:19 +0000 Subject: [PATCH 16/17] Add a missing #if check for SQLITE_OMIT_LOAD_EXTENSION to shell.c.in, trigged by the fiddle build. FossilOrigin-Name: 1091f3371f4af75344c2e6da26656c259fa96c8a8da9acde3db79df8aa95fd0a --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c.in | 12 ++++++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index b825a3333b..ba34527608 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sbug\sfixes\sin\stmstmpvfs.c,\sshowdb.c,\sand\sshowtmlog.c. -D 2026-01-08T15:25:04.189 +C Add\sa\smissing\s#if\scheck\sfor\sSQLITE_OMIT_LOAD_EXTENSION\sto\sshell.c.in,\strigged\sby\sthe\sfiddle\sbuild. +D 2026-01-08T15:26:19.338 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -738,7 +738,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 47aa7fdc9ec4c19b103ac5e79d7887d30119b5675309facf5eed1118391c868b F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4d45a04431db072040d6625ee21c1dc483c9b2b64a5ab419f4a4e05aabed1204 -F src/shell.c.in 6c4f20a4787933b0a5fce307b7d9d67e00805966a52186f0c2cd04d75691c38b +F src/shell.c.in 3bc4c6aa962bdf950dc144c2138eb4bc734bf7e305f2ac42dbda5a83c4a4c660 F src/sqlite.h.in 476f3efeb5dd26ad94dcbce262ca7eb9d042d797a92d624059c67ef37d5b3ab4 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P e14d9a980351a8d5e935e6991ea02a1c40c9ea8f0ad0fadcabe07d575a9b289c -R 5732f9b90659e548d32a735de971cff5 -U drh -Z af5bc160622d940e12d2af419055b1c0 +P 1fee8265f7eab649ee8b28456c37d95198f5cde54e905154e3eccc0b328ece9a +R fe4ee4892cd00e82736e5e46be687a34 +U stephan +Z 9dd4f85e828d41aa6fa3065c0d3c9df1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 79dd7159a3..1a9fbe8739 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1fee8265f7eab649ee8b28456c37d95198f5cde54e905154e3eccc0b328ece9a +1091f3371f4af75344c2e6da26656c259fa96c8a8da9acde3db79df8aa95fd0a diff --git a/src/shell.c.in b/src/shell.c.in index d022517ec5..4ef9f28ee6 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -39,6 +39,10 @@ typedef unsigned short int u16; ** and this build mode rewires the user input subsystem to account for ** that. */ +#if defined(SQLITE_SHELL_FIDDLE) +# undef SQLITE_OMIT_LOAD_EXTENSION +# define SQLITE_OMIT_LOAD_EXTENSION 1 +#endif /* ** Warning pragmas copied from msvc.h in the core. @@ -13023,7 +13027,9 @@ int SQLITE_CDECL main(int argc, char **argv){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); - }else if( access(zVfs,0)==0 ){ + } +#if !defined(SQLITE_OMIT_LOAD_EXTENSION) + else if( access(zVfs,0)==0 ){ /* If the VFS name is not the name of an existing VFS, but it is ** the name of a file, then try to load that file as an extension. ** Presumably the extension implements the desired VFS. */ @@ -13038,7 +13044,9 @@ int SQLITE_CDECL main(int argc, char **argv){ zVfs, zErr); exit(1); } - }else{ + } +#endif + else{ cli_printf(stderr,"no such VFS: \"%s\"\n", zVfs); exit(1); } From 5df3efe6f4a6d83eb5b27f4916f10616560eb12f Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 8 Jan 2026 17:52:42 +0000 Subject: [PATCH 17/17] Fix an off-by-one error in the page number of ELOG_CKPT_PAGE log messages in tmstmpvfs.c FossilOrigin-Name: 6fafd010de2d9820f77ee6d2a5f0a7ab1260872d09e95b6932c959ef017aaa77 --- ext/misc/tmstmpvfs.c | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/misc/tmstmpvfs.c b/ext/misc/tmstmpvfs.c index c2836bd86c..37e76f60cb 100644 --- a/ext/misc/tmstmpvfs.c +++ b/ext/misc/tmstmpvfs.c @@ -546,7 +546,7 @@ static int tmstmpWrite( } }else if( p->inCkpt ){ assert( p->pgsz>0 ); - tmstmpEvent(p, ELOG_CKPT_PAGE, 0, iOfst/p->pgsz, 0); + tmstmpEvent(p, ELOG_CKPT_PAGE, 0, (iOfst/p->pgsz)+1, 0); }else if( p->pPartner==0 ){ /* Writing into a database in rollback mode */ unsigned char *s = (unsigned char*)zBuf+iAmt-TMSTMP_RESERVE; diff --git a/manifest b/manifest index ba34527608..57040dae8b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\smissing\s#if\scheck\sfor\sSQLITE_OMIT_LOAD_EXTENSION\sto\sshell.c.in,\strigged\sby\sthe\sfiddle\sbuild. -D 2026-01-08T15:26:19.338 +C Fix\san\soff-by-one\serror\sin\sthe\spage\snumber\sof\sELOG_CKPT_PAGE\slog\nmessages\sin\stmstmpvfs.c +D 2026-01-08T17:52:42.103 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -402,7 +402,7 @@ F ext/misc/sqlite3_stdio.h 27a4ecea47e61bc9574ccdf2806f468afe23af2f95028c9b689bf F ext/misc/stmt.c b090086cd6bd6281c21271d38d576eeffe662f0e6b67536352ce32bbaa438321 F ext/misc/stmtrand.c 59cffa5d8e158943ff1ce078956d8e208e8c04e67307e8f249dece2436dcb7fc F ext/misc/templatevtab.c 10f15b165b95423ddef593bc5dcb915ec4eb5e0f1066d585e5435a368b8bc22b -F ext/misc/tmstmpvfs.c ff66db6b88bc5bd011d5a92e8f5e35af93499d4d615330ab14a61a23ce5c7856 +F ext/misc/tmstmpvfs.c 95994e33526581b75bebb320628d220d86c0734807d9780b4f1804e6c7248df2 F ext/misc/totype.c ba11aac3c0b52c685bd25aa4e0f80c41c624fb1cc5ab763250e09ddc762bc3a8 F ext/misc/uint.c 327afc166058acf566f33a15bf47c869d2d3564612644d9ff81a23efc8b36039 F ext/misc/unionvtab.c 716d385256d5fb4beea31b0efede640807e423e85c9784d21d22f0cce010a785 @@ -2191,8 +2191,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 1fee8265f7eab649ee8b28456c37d95198f5cde54e905154e3eccc0b328ece9a -R fe4ee4892cd00e82736e5e46be687a34 -U stephan -Z 9dd4f85e828d41aa6fa3065c0d3c9df1 +P 1091f3371f4af75344c2e6da26656c259fa96c8a8da9acde3db79df8aa95fd0a +R 35b1dce7128d82186c4ed7ed350ed492 +U drh +Z 095da220d3fdcc217b40575d36e33cc3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1a9fbe8739..53aa2038fb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1091f3371f4af75344c2e6da26656c259fa96c8a8da9acde3db79df8aa95fd0a +6fafd010de2d9820f77ee6d2a5f0a7ab1260872d09e95b6932c959ef017aaa77