/ Check-in [4b573701]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhance the "showdb" utility program with the "pgidx" option. Now requires linkage with the amalgamation.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4b5737014c6f1638de9dc162463508ea7dfe333d
User & Date: drh 2012-04-03 14:59:50
Context
2012-04-03
15:10
If the SELECT that finds all root pages in the showdb fails, then report an error. check-in: 4b161415 user: drh tags: trunk
14:59
Enhance the "showdb" utility program with the "pgidx" option. Now requires linkage with the amalgamation. check-in: 4b573701 user: drh tags: trunk
2012-04-02
21:35
The SQLITE_RTREE_INT_ONLY compile-time option causes the RTree extension to use only integer math and store only integer coordinates. check-in: 02b7640f user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to tool/showdb.c.

     5      5   #include <ctype.h>
     6      6   #include <sys/types.h>
     7      7   #include <sys/stat.h>
     8      8   #include <fcntl.h>
     9      9   #include <unistd.h>
    10     10   #include <stdlib.h>
    11     11   #include <string.h>
           12  +#include "sqlite3.h"
    12     13   
    13     14   
    14     15   static int pagesize = 1024;     /* Size of a database page */
    15     16   static int db = -1;             /* File descriptor for reading the DB */
    16     17   static int mxPage = 0;          /* Last page number */
    17     18   static int perLine = 16;        /* HEX elements to print per line */
    18     19   
................................................................................
   445    446         pgno = 0;
   446    447       }else{
   447    448         pgno = (int)decodeInt32(&a[0]);
   448    449       }
   449    450       free(a);
   450    451     }
   451    452   }
          453  +
          454  +/*
          455  +** A short text comment on the use of each page.
          456  +*/
          457  +static char **zPageUse;
          458  +
          459  +/*
          460  +** Add a comment on the use of a page.
          461  +*/
          462  +static void page_usage_msg(int pgno, const char *zFormat, ...){
          463  +  va_list ap;
          464  +  char *zMsg;
          465  +
          466  +  va_start(ap, zFormat);
          467  +  zMsg = sqlite3_vmprintf(zFormat, ap);
          468  +  va_end(ap);
          469  +  if( pgno<=0 || pgno>mxPage ){
          470  +    printf("ERROR: page %d out of bounds.  Range=1..%d.  Msg: %s\n",
          471  +            pgno, mxPage, zMsg);
          472  +    sqlite3_free(zMsg);
          473  +    return;
          474  +  }
          475  +  if( zPageUse[pgno]!=0 ){
          476  +    printf("ERROR: page %d used multiple times:\n", pgno);
          477  +    printf("ERROR:    previous: %s\n", zPageUse[pgno]);
          478  +    printf("ERROR:    current:  %s\n", zPageUse[pgno]);
          479  +    sqlite3_free(zPageUse[pgno]);
          480  +  }
          481  +  zPageUse[pgno] = zMsg;
          482  +}
          483  +
          484  +/*
          485  +** Find overflow pages of a cell and describe their usage.
          486  +*/
          487  +static void page_usage_cell(
          488  +  unsigned char cType,    /* Page type */
          489  +  unsigned char *a,       /* Cell content */
          490  +  int pgno,               /* page containing the cell */
          491  +  int cellno              /* Index of the cell on the page */
          492  +){
          493  +  int i;
          494  +  int nDesc = 0;
          495  +  int n = 0;
          496  +  i64 nPayload;
          497  +  i64 rowid;
          498  +  int nLocal;
          499  +  i = 0;
          500  +  if( cType<=5 ){
          501  +    a += 4;
          502  +    n += 4;
          503  +  }
          504  +  if( cType!=5 ){
          505  +    i = decodeVarint(a, &nPayload);
          506  +    a += i;
          507  +    n += i;
          508  +    nLocal = localPayload(nPayload, cType);
          509  +  }else{
          510  +    nPayload = nLocal = 0;
          511  +  }
          512  +  if( cType==5 || cType==13 ){
          513  +    i = decodeVarint(a, &rowid);
          514  +    a += i;
          515  +    n += i;
          516  +  }
          517  +  if( nLocal<nPayload ){
          518  +    int ovfl = decodeInt32(a+nLocal);
          519  +    int cnt = 0;
          520  +    while( ovfl && (cnt++)<mxPage ){
          521  +      page_usage_msg(ovfl, "overflow %d from cell %d of page %d",
          522  +                     cnt, cellno, pgno);
          523  +      a = getContent((ovfl-1)*pagesize, 4);
          524  +      ovfl = decodeInt32(a);
          525  +      free(a);
          526  +    }
          527  +  }
          528  +}
          529  +
          530  +
          531  +/*
          532  +** Describe the usages of a b-tree page
          533  +*/
          534  +static void page_usage_btree(
          535  +  int pgno,             /* Page to describe */
          536  +  int parent,           /* Parent of this page.  0 for root pages */
          537  +  int idx,              /* Which child of the parent */
          538  +  const char *zName     /* Name of the table */
          539  +){
          540  +  unsigned char *a;
          541  +  const char *zType = "corrupt node";
          542  +  int nCell;
          543  +  int i;
          544  +  int hdr = pgno==1 ? 100 : 0;
          545  +
          546  +  if( pgno<=0 || pgno>mxPage ) return;
          547  +  a = getContent((pgno-1)*pagesize, pagesize);
          548  +  switch( a[hdr] ){
          549  +    case 2:  zType = "interior node of index";  break;
          550  +    case 5:  zType = "interior node of table";  break;
          551  +    case 10: zType = "leaf of index";           break;
          552  +    case 13: zType = "leaf of table";           break;
          553  +  }
          554  +  if( parent ){
          555  +    page_usage_msg(pgno, "%s [%s], child %d of page %d",
          556  +                   zType, zName, idx, parent);
          557  +  }else{
          558  +    page_usage_msg(pgno, "root %s [%s]", zType, zName);
          559  +  }
          560  +  nCell = a[hdr+3]*256 + a[hdr+4];
          561  +  if( a[hdr]==2 || a[hdr]==5 ){
          562  +    int cellstart = hdr+12;
          563  +    unsigned int child;
          564  +    for(i=0; i<nCell; i++){
          565  +      int ofst;
          566  +
          567  +      ofst = cellstart + i*2;
          568  +      ofst = a[ofst]*256 + a[ofst+1];
          569  +      child = decodeInt32(a+ofst);
          570  +      page_usage_btree(child, pgno, i, zName);
          571  +    }
          572  +    child = decodeInt32(a+cellstart-4);
          573  +    page_usage_btree(child, pgno, i, zName);
          574  +  }
          575  +  if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){
          576  +    int cellstart = hdr + 8 + 4*(a[hdr]<=5);
          577  +    for(i=0; i<nCell; i++){
          578  +      int ofst;
          579  +      ofst = cellstart + i*2;
          580  +      ofst = a[ofst]*256 + a[ofst+1];
          581  +      page_usage_cell(a[hdr], a+ofst, pgno, i);
          582  +    }
          583  +  }
          584  +  free(a);
          585  +}
          586  +
          587  +/*
          588  +** Determine page usage by the freelist
          589  +*/
          590  +static void page_usage_freelist(int pgno){
          591  +  unsigned char *a;
          592  +  int cnt = 0;
          593  +  int i;
          594  +  int n;
          595  +  int iNext;
          596  +  int parent = 1;
          597  +
          598  +  while( pgno>0 && pgno<=mxPage && (cnt++)<mxPage ){
          599  +    page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent);
          600  +    a = getContent((pgno-1)*pagesize, pagesize);
          601  +    iNext = decodeInt32(a);
          602  +    n = decodeInt32(a+4);
          603  +    for(i=0; i<n; i++){
          604  +      int child = decodeInt32(a + (i*4+8));
          605  +      page_usage_msg(child, "freelist leaf, child %d of trunk page %d",
          606  +                     i, pgno);
          607  +    }
          608  +    free(a);
          609  +    parent = pgno;
          610  +    pgno = iNext;
          611  +  }
          612  +}
          613  +
          614  +/*
          615  +** Try to figure out how every page in the database file is being used.
          616  +*/
          617  +static void page_usage_report(const char *zDbName){
          618  +  int i;
          619  +  int rc;
          620  +  sqlite3 *db;
          621  +  sqlite3_stmt *pStmt;
          622  +  unsigned char *a;
          623  +
          624  +  /* Avoid the pathological case */
          625  +  if( mxPage<1 ){
          626  +    printf("empty database\n");
          627  +    return;
          628  +  }
          629  +
          630  +  /* Open the database file */
          631  +  rc = sqlite3_open(zDbName, &db);
          632  +  if( rc ){
          633  +    printf("cannot open database: %s\n", sqlite3_errmsg(db));
          634  +    sqlite3_close(db);
          635  +    return;
          636  +  }
          637  +
          638  +  /* Set up global variables zPageUse[] and mxPage to record page
          639  +  ** usages */
          640  +  zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) );
          641  +  if( zPageUse==0 ) out_of_memory();
          642  +  memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1));
          643  +
          644  +  /* Discover the usage of each page */
          645  +  a = getContent(0, 100);
          646  +  page_usage_freelist(decodeInt32(a+32));
          647  +  free(a);
          648  +  page_usage_btree(1, 0, 0, "sqlite_master");
          649  +  rc = sqlite3_prepare_v2(db,
          650  +           "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage",
          651  +           -1, &pStmt, 0);
          652  +  if( rc==SQLITE_OK ){
          653  +    while( sqlite3_step(pStmt)==SQLITE_ROW ){
          654  +      int pgno = sqlite3_column_int(pStmt, 2);
          655  +      page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1));
          656  +    }
          657  +  }
          658  +  sqlite3_finalize(pStmt);
          659  +  sqlite3_close(db);
          660  +
          661  +  /* Print the report and free memory used */
          662  +  for(i=1; i<=mxPage; i++){
          663  +    printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???");
          664  +    sqlite3_free(zPageUse[i]);
          665  +  }
          666  +  sqlite3_free(zPageUse);
          667  +  zPageUse = 0;
          668  +}
   452    669   
   453    670   /*
   454    671   ** Print a usage comment
   455    672   */
   456    673   static void usage(const char *argv0){
   457    674     fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0);
   458    675     fprintf(stderr,
   459    676       "args:\n"
   460    677       "    dbheader        Show database header\n"
          678  +    "    pgidx           Index of how each page is used\n"
   461    679       "    NNN..MMM        Show hex of pages NNN through MMM\n"
   462    680       "    NNN..end        Show hex of pages NNN through end of file\n"
   463    681       "    NNNb            Decode btree page NNN\n"
   464    682       "    NNNbc           Decode btree page NNN and show content\n"
   465    683       "    NNNbm           Decode btree page NNN and show a layout map\n"
   466    684       "    NNNt            Decode freelist trunk page NNN\n"
   467    685       "    NNNtd           Show leaf freelist pages on the decode\n"
................................................................................
   498    716       int i;
   499    717       for(i=2; i<argc; i++){
   500    718         int iStart, iEnd;
   501    719         char *zLeft;
   502    720         if( strcmp(argv[i], "dbheader")==0 ){
   503    721           print_db_header();
   504    722           continue;
          723  +      }
          724  +      if( strcmp(argv[i], "pgidx")==0 ){
          725  +        page_usage_report(argv[1]);
          726  +        continue;
   505    727         }
   506    728         if( !isdigit(argv[i][0]) ){
   507    729           fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
   508    730           continue;
   509    731         }
   510    732         iStart = strtol(argv[i], &zLeft, 0);
   511    733         if( zLeft && strcmp(zLeft,"..end")==0 ){