]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Improve showdb so that it does a better job of handling reserve-bytes.
authordrh <>
Thu, 8 Jan 2026 01:37:13 +0000 (01:37 +0000)
committerdrh <>
Thu, 8 Jan 2026 01:37:13 +0000 (01:37 +0000)
Add the --tmstmp option that causes pgidx to interpret tmstmpvfs tags
if they are available.

FossilOrigin-Name: d7e6e9a5781f467a5b5f02f46134099cf01607a0cf55510155533d57d4a4618a

manifest
manifest.uuid
tool/showdb.c

index 9426f06170371a88e79bfa13c708748f7e264116..543e9c293d49d2029178a7f2d4435346021b96d7 100644 (file)
--- 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.
index c1a69e9924c72f74944c04cd3a11ee25d086c66c..ae055627fe85ed2440da678f96a81fa05dfa4427 100644 (file)
@@ -1 +1 @@
-869f306592a86d2a78f00266c615f033cd2318a7bff0a97b3dcdd3348d99fc66
+d7e6e9a5781f467a5b5f02f46134099cf01607a0cf55510155533d57d4a4618a
index 399d78534210edcde76581d6ed6978829effa8be..045956e186c594a30ce5732e644bda43c3afef1f 100644 (file)
@@ -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 && got<nByte ) memset(aData+got, 0, nByte-got);
+    if( got==nByte ){
+      rc = SQLITE_OK;
+    }else if( got>0 && got<nByte ){
+      memset(aData+got, 0, nByte-got);
+      rc = SQLITE_IOERR_SHORT_READ;
+    }else{
+      memset(aData,0,nByte);
+      rc = SQLITE_IOERR;
+    }
+  }
+  if( g.aPageTag && nByte==(int)g.pagesize ){
+    unsigned int pgno = (unsigned int)(ofst/g.pagesize);
+    if( pgno>=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<n && i<g.pagesize/4; i++){
+      for(i=0; i<n && i<g.usablesize/4; i++){
         u32 x = decodeInt32(&a[8+4*i]);
         char zIdx[13];
         sprintf(zIdx, "[%d]", i);
@@ -770,11 +792,6 @@ static void decode_trunk_page(
   }
 }
 
-/*
-** A short text comment on the use of each page.
-*/
-static char **zPageUse;
-
 /*
 ** Add a comment on the use of a page.
 */
@@ -791,13 +808,13 @@ static void page_usage_msg(u32 pgno, const char *zFormat, ...){
     sqlite3_free(zMsg);
     return;
   }
-  if( zPageUse[pgno]!=0 ){
+  if( g.zPageUse[pgno]!=0 ){
     printf("ERROR: page %d used multiple times:\n", pgno);
-    printf("ERROR:    previous: %s\n", zPageUse[pgno]);
+    printf("ERROR:    previous: %s\n", g.zPageUse[pgno]);
     printf("ERROR:    current:  %s\n", zMsg);
-    sqlite3_free(zPageUse[pgno]);
+    sqlite3_free(g.zPageUse[pgno]);
   }
-  zPageUse[pgno] = zMsg;
+  g.zPageUse[pgno] = zMsg;
 }
 
 /*
@@ -917,12 +934,12 @@ static void page_usage_btree(
       u32 ofst;
 
       cellidx = cellstart + i*2;
-      if( cellidx+1 >= 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<cellidx+2 || ofst+4>=g.pagesize ){
+      if( ofst<cellidx+2 || ofst+4>=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<n; i++){
       int child = decodeInt32(a + (i*4+8));
@@ -1011,14 +1028,22 @@ static void page_usage_report(const char *zPrg, const char *zDbName){
   /* Open the database file */
   db = openDatabase(zPrg, zDbName);
 
-  /* Set up global variables zPageUse[] and g.mxPage to record page
+  /* Set up global variables g.zPageUse[] and g.mxPage to record page
   ** usages */
-  zPageUse = sqlite3_malloc64( sizeof(zPageUse[0])*(g.mxPage+1) );
-  if( zPageUse==0 ) out_of_memory();
-  memset(zPageUse, 0, sizeof(zPageUse[0])*(g.mxPage+1));
+  g.zPageUse = sqlite3_malloc64( sizeof(g.zPageUse[0])*(g.mxPage+1) );
+  if( g.zPageUse==0 ) out_of_memory();
+  memset(g.zPageUse, 0, sizeof(g.zPageUse[0])*(g.mxPage+1));
 
   /* Discover the usage of each page */
   a = fileRead(0, 100);
+  if( g.bTmstmp && a[20]==16 ){
+    g.aPageTag = sqlite3_malloc64( sizeof(struct TmstmpTag)*(g.mxPage+1) );
+    if( g.aPageTag==0 ) out_of_memory();
+    memset(g.aPageTag, 0, sizeof(struct TmstmpTag)*(g.mxPage+1) );
+  }else{
+    g.bTmstmp = 0;
+    g.aPageTag = 0;
+  }
   page_usage_freelist(decodeInt32(a+32));
   page_usage_ptrmap(a);
   sqlite3_free(a);
@@ -1044,19 +1069,36 @@ static void page_usage_report(const char *zPrg, const char *zDbName){
 
   /* Print the report and free memory used */
   if( g.bCSV ){
-    printf("pgno,txt,parent,child,ovfl\r\n");
+    if( g.bTmstmp ){
+      printf("pgno,tm,frame,flg,salt,parent,child,ovfl,txt\r\n");
+    }else{
+      printf("pgno,parent,child,ovfl,txt\r\n");
+    }
   }
   for(i=1; i<=g.mxPage; i++){
-    if( zPageUse[i]==0 ){
-      zPageUse[i] = sqlite3_mprintf("???");
-      if( zPageUse[i]==0 ) continue;
+    if( g.zPageUse[i]==0 ){
+      g.zPageUse[i] = sqlite3_mprintf("???");
+      if( g.zPageUse[i]==0 ) continue;
     }
     if( !g.bCSV ){
-      printf("%5u: %s\n", i, zPageUse[i]);
+      printf("%5u: %s\n", i, g.zPageUse[i]);
     }else{
-      const char *z = zPageUse[i];
+      const char *z = g.zPageUse[i];
       const char *s;
-      printf("%u,\"%s\",", i, zPageUse[i]);
+      printf("%u,", i);
+      if( g.bTmstmp ){
+        const unsigned char *a = g.aPageTag[i].a;
+        sqlite3_uint64 tm = 0;
+        unsigned int x;
+        int k;
+        for(k=2; k<=7; k++) tm = (tm<<8)+a[k];
+        printf("%llu.%03u,", tm/1000, (unsigned int)(tm%1000));
+        for(x=0, k=8; k<=11; k++) x = (x<<8)+a[k];
+        printf("%u,", x);
+        printf("%u,", a[12]);
+        for(x=0, k=13; k<=15; k++) x = (x<<8)+a[k];
+        printf("%u,", x);
+      }
       if( (s = strstr(z, " of page "))!=0 ){
         printf("%d,", atoi(s+9));
       }else if( (s = strstr(z, " of trunk page "))!=0 ){
@@ -1072,17 +1114,18 @@ static void page_usage_report(const char *zPrg, const char *zDbName){
         printf("-1,");
       }
       if( strncmp(z,"overflow ", 9)==0 ){
-        printf("%d\r\n", atoi(z+9));
+        printf("%d,", atoi(z+9));
       }else{
-        printf("-1\r\n");
+        printf("-1,");
       }
+      printf("\"%s\"\r\n", z);
     }
   }
   for(i=1; i<=g.mxPage; i++){
-    sqlite3_free(zPageUse[i]);
+    sqlite3_free(g.zPageUse[i]);
   }
-  sqlite3_free(zPageUse);
-  zPageUse = 0;
+  sqlite3_free(g.zPageUse);
+  g.zPageUse = 0;
 }
 
 /*
@@ -1162,8 +1205,9 @@ static void usage(const char *argv0){
   fprintf(stderr, "Usage %s ?--uri? FILENAME ?args...?\n\n", argv0);
   fprintf(stderr,
     "switches:\n"
-    "    --raw           Read db file directly, bypassing SQLite VFS\n"
     "    --csv           CSV output for \"pgidx\"\n"
+    "    --raw           Read db file directly, bypassing SQLite VFS\n"
+    "    --tmstmp        Interpret tmstmpvfs tags\n"
     "args:\n"
     "    dbheader        Show database header\n"
     "    pgidx           Index of how each page is used\n"
@@ -1201,6 +1245,11 @@ int main(int argc, char **argv){
       azArg++;
       nArg--;
     }else
+    if( strcmp("-tmstmp", z)==0 ){
+      g.bTmstmp = 1;
+      azArg++;
+      nArg--;
+    }else
     {
       usage(zPrg);
       exit(1);
@@ -1215,15 +1264,17 @@ int main(int argc, char **argv){
   fileOpen(zPrg, azArg[1]);
   szFile = fileGetsize();
 
-  zPgSz = fileRead(16, 2);
-  g.pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
-  if( g.pagesize==0 ) g.pagesize = 1024;
+  zPgSz = fileRead(0, 24);
+  g.pagesize = zPgSz[16]*256 + zPgSz[17]*65536;
+  if( g.pagesize==0 ) g.pagesize = 4096;
+  g.nRes = zPgSz[20];
+  g.usablesize = g.pagesize - g.nRes;
   sqlite3_free(zPgSz);
-
-  printf("Pagesize: %d\n", (int)g.pagesize);
   g.mxPage = (u32)((szFile+g.pagesize-1)/g.pagesize);
 
   if( !g.bCSV ){
+    printf("Pagesize: %d\n", (int)g.pagesize);
+    if( g.nRes ) printf("Useable-size: %d\n", (int)g.usablesize);
     printf("Available pages: 1..%u\n", g.mxPage);
   }
   if( nArg==2 ){