File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / tool / showdb.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 4 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    1: /*
    2: ** A utility for printing all or part of an SQLite database file.
    3: */
    4: #include <stdio.h>
    5: #include <ctype.h>
    6: #include <sys/types.h>
    7: #include <sys/stat.h>
    8: #include <fcntl.h>
    9: #include <unistd.h>
   10: #include <stdlib.h>
   11: #include <string.h>
   12: 
   13: 
   14: static int pagesize = 1024;     /* Size of a database page */
   15: static int db = -1;             /* File descriptor for reading the DB */
   16: static int mxPage = 0;          /* Last page number */
   17: static int perLine = 16;        /* HEX elements to print per line */
   18: 
   19: typedef long long int i64;      /* Datatype for 64-bit integers */
   20: 
   21: 
   22: /*
   23: ** Convert the var-int format into i64.  Return the number of bytes
   24: ** in the var-int.  Write the var-int value into *pVal.
   25: */
   26: static int decodeVarint(const unsigned char *z, i64 *pVal){
   27:   i64 v = 0;
   28:   int i;
   29:   for(i=0; i<8; i++){
   30:     v = (v<<7) + (z[i]&0x7f);
   31:     if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
   32:   }
   33:   v = (v<<8) + (z[i]&0xff);
   34:   *pVal = v;
   35:   return 9;
   36: }
   37: 
   38: /*
   39: ** Extract a big-endian 32-bit integer
   40: */
   41: static unsigned int decodeInt32(const unsigned char *z){
   42:   return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
   43: }
   44: 
   45: /* Report an out-of-memory error and die.
   46: */
   47: static void out_of_memory(void){
   48:   fprintf(stderr,"Out of memory...\n");
   49:   exit(1);
   50: }
   51: 
   52: /*
   53: ** Read content from the file.
   54: **
   55: ** Space to hold the content is obtained from malloc() and needs to be
   56: ** freed by the caller.
   57: */
   58: static unsigned char *getContent(int ofst, int nByte){
   59:   unsigned char *aData;
   60:   aData = malloc(nByte+32);
   61:   if( aData==0 ) out_of_memory();
   62:   memset(aData, 0, nByte+32);
   63:   lseek(db, ofst, SEEK_SET);
   64:   read(db, aData, nByte);
   65:   return aData;
   66: }
   67: 
   68: /*
   69: ** Print a range of bytes as hex and as ascii.
   70: */
   71: static unsigned char *print_byte_range(
   72:   int ofst,          /* First byte in the range of bytes to print */
   73:   int nByte,         /* Number of bytes to print */
   74:   int printOfst      /* Add this amount to the index on the left column */
   75: ){
   76:   unsigned char *aData;
   77:   int i, j;
   78:   const char *zOfstFmt;
   79: 
   80:   if( ((printOfst+nByte)&~0xfff)==0 ){
   81:     zOfstFmt = " %03x: ";
   82:   }else if( ((printOfst+nByte)&~0xffff)==0 ){
   83:     zOfstFmt = " %04x: ";
   84:   }else if( ((printOfst+nByte)&~0xfffff)==0 ){
   85:     zOfstFmt = " %05x: ";
   86:   }else if( ((printOfst+nByte)&~0xffffff)==0 ){
   87:     zOfstFmt = " %06x: ";
   88:   }else{
   89:     zOfstFmt = " %08x: ";
   90:   }
   91: 
   92:   aData = getContent(ofst, nByte);
   93:   for(i=0; i<nByte; i += perLine){
   94:     fprintf(stdout, zOfstFmt, i+printOfst);
   95:     for(j=0; j<perLine; j++){
   96:       if( i+j>nByte ){
   97:         fprintf(stdout, "   ");
   98:       }else{
   99:         fprintf(stdout,"%02x ", aData[i+j]);
  100:       }
  101:     }
  102:     for(j=0; j<perLine; j++){
  103:       if( i+j>nByte ){
  104:         fprintf(stdout, " ");
  105:       }else{
  106:         fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
  107:       }
  108:     }
  109:     fprintf(stdout,"\n");
  110:   }
  111:   return aData;
  112: }
  113: 
  114: /*
  115: ** Print an entire page of content as hex
  116: */
  117: static print_page(int iPg){
  118:   int iStart;
  119:   unsigned char *aData;
  120:   iStart = (iPg-1)*pagesize;
  121:   fprintf(stdout, "Page %d:   (offsets 0x%x..0x%x)\n",
  122:           iPg, iStart, iStart+pagesize-1);
  123:   aData = print_byte_range(iStart, pagesize, 0);
  124:   free(aData);
  125: }
  126: 
  127: /* Print a line of decode output showing a 4-byte integer.
  128: */
  129: static print_decode_line(
  130:   unsigned char *aData,      /* Content being decoded */
  131:   int ofst, int nByte,       /* Start and size of decode */
  132:   const char *zMsg           /* Message to append */
  133: ){
  134:   int i, j;
  135:   int val = aData[ofst];
  136:   char zBuf[100];
  137:   sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
  138:   i = strlen(zBuf);
  139:   for(j=1; j<4; j++){
  140:     if( j>=nByte ){
  141:       sprintf(&zBuf[i], "   ");
  142:     }else{
  143:       sprintf(&zBuf[i], " %02x", aData[ofst+j]);
  144:       val = val*256 + aData[ofst+j];
  145:     }
  146:     i += strlen(&zBuf[i]);
  147:   }
  148:   sprintf(&zBuf[i], "   %9d", val);
  149:   printf("%s  %s\n", zBuf, zMsg);
  150: }
  151: 
  152: /*
  153: ** Decode the database header.
  154: */
  155: static void print_db_header(void){
  156:   unsigned char *aData;
  157:   aData = print_byte_range(0, 100, 0);
  158:   printf("Decoded:\n");
  159:   print_decode_line(aData, 16, 2, "Database page size");
  160:   print_decode_line(aData, 18, 1, "File format write version");
  161:   print_decode_line(aData, 19, 1, "File format read version");
  162:   print_decode_line(aData, 20, 1, "Reserved space at end of page");
  163:   print_decode_line(aData, 24, 4, "File change counter");
  164:   print_decode_line(aData, 28, 4, "Size of database in pages");
  165:   print_decode_line(aData, 32, 4, "Page number of first freelist page");
  166:   print_decode_line(aData, 36, 4, "Number of freelist pages");
  167:   print_decode_line(aData, 40, 4, "Schema cookie");
  168:   print_decode_line(aData, 44, 4, "Schema format version");
  169:   print_decode_line(aData, 48, 4, "Default page cache size");
  170:   print_decode_line(aData, 52, 4, "Largest auto-vac root page");
  171:   print_decode_line(aData, 56, 4, "Text encoding");
  172:   print_decode_line(aData, 60, 4, "User version");
  173:   print_decode_line(aData, 64, 4, "Incremental-vacuum mode");
  174:   print_decode_line(aData, 68, 4, "meta[7]");
  175:   print_decode_line(aData, 72, 4, "meta[8]");
  176:   print_decode_line(aData, 76, 4, "meta[9]");
  177:   print_decode_line(aData, 80, 4, "meta[10]");
  178:   print_decode_line(aData, 84, 4, "meta[11]");
  179:   print_decode_line(aData, 88, 4, "meta[12]");
  180:   print_decode_line(aData, 92, 4, "Change counter for version number");
  181:   print_decode_line(aData, 96, 4, "SQLite version number");
  182: }
  183: 
  184: /*
  185: ** Describe cell content.
  186: */
  187: static int describeContent(
  188:   unsigned char *a,       /* Cell content */
  189:   int nLocal,             /* Bytes in a[] */
  190:   char *zDesc             /* Write description here */
  191: ){
  192:   int nDesc = 0;
  193:   int n, i, j;
  194:   i64 x, v;
  195:   const unsigned char *pData;
  196:   const unsigned char *pLimit;
  197:   char sep = ' ';
  198: 
  199:   pLimit = &a[nLocal];
  200:   n = decodeVarint(a, &x);
  201:   pData = &a[x];
  202:   a += n;
  203:   i = x - n;
  204:   while( i>0 && pData<=pLimit ){
  205:     n = decodeVarint(a, &x);
  206:     a += n;
  207:     i -= n;
  208:     nLocal -= n;
  209:     zDesc[0] = sep;
  210:     sep = ',';
  211:     nDesc++;
  212:     zDesc++;
  213:     if( x==0 ){
  214:       sprintf(zDesc, "*");     /* NULL is a "*" */
  215:     }else if( x>=1 && x<=6 ){
  216:       v = (signed char)pData[0];
  217:       pData++;
  218:       switch( x ){
  219:         case 6:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2;
  220:         case 5:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2;
  221:         case 4:  v = (v<<8) + pData[0];  pData++;
  222:         case 3:  v = (v<<8) + pData[0];  pData++;
  223:         case 2:  v = (v<<8) + pData[0];  pData++;
  224:       }
  225:       sprintf(zDesc, "%lld", v);
  226:     }else if( x==7 ){
  227:       sprintf(zDesc, "real");
  228:       pData += 8;
  229:     }else if( x==8 ){
  230:       sprintf(zDesc, "0");
  231:     }else if( x==9 ){
  232:       sprintf(zDesc, "1");
  233:     }else if( x>=12 ){
  234:       int size = (x-12)/2;
  235:       if( (x&1)==0 ){
  236:         sprintf(zDesc, "blob(%d)", size);
  237:       }else{
  238:         sprintf(zDesc, "txt(%d)", size);
  239:       }
  240:       pData += size;
  241:     }
  242:     j = strlen(zDesc);
  243:     zDesc += j;
  244:     nDesc += j;
  245:   }
  246:   return nDesc;
  247: }
  248: 
  249: /*
  250: ** Compute the local payload size given the total payload size and
  251: ** the page size.
  252: */
  253: static int localPayload(i64 nPayload, char cType){
  254:   int maxLocal;
  255:   int minLocal;
  256:   int surplus;
  257:   int nLocal;
  258:   if( cType==13 ){
  259:     /* Table leaf */
  260:     maxLocal = pagesize-35;
  261:     minLocal = (pagesize-12)*32/255-23;
  262:   }else{
  263:     maxLocal = (pagesize-12)*64/255-23;
  264:     minLocal = (pagesize-12)*32/255-23;
  265:   }
  266:   if( nPayload>maxLocal ){
  267:     surplus = minLocal + (nPayload-minLocal)%(pagesize-4);
  268:     if( surplus<=maxLocal ){
  269:       nLocal = surplus;
  270:     }else{
  271:       nLocal = minLocal;
  272:     }
  273:   }else{
  274:     nLocal = nPayload;
  275:   }
  276:   return nLocal;
  277: }
  278:   
  279: 
  280: /*
  281: ** Create a description for a single cell.
  282: **
  283: ** The return value is the local cell size.
  284: */
  285: static int describeCell(
  286:   unsigned char cType,    /* Page type */
  287:   unsigned char *a,       /* Cell content */
  288:   int showCellContent,    /* Show cell content if true */
  289:   char **pzDesc           /* Store description here */
  290: ){
  291:   int i;
  292:   int nDesc = 0;
  293:   int n = 0;
  294:   int leftChild;
  295:   i64 nPayload;
  296:   i64 rowid;
  297:   int nLocal;
  298:   static char zDesc[1000];
  299:   i = 0;
  300:   if( cType<=5 ){
  301:     leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
  302:     a += 4;
  303:     n += 4;
  304:     sprintf(zDesc, "lx: %d ", leftChild);
  305:     nDesc = strlen(zDesc);
  306:   }
  307:   if( cType!=5 ){
  308:     i = decodeVarint(a, &nPayload);
  309:     a += i;
  310:     n += i;
  311:     sprintf(&zDesc[nDesc], "n: %lld ", nPayload);
  312:     nDesc += strlen(&zDesc[nDesc]);
  313:     nLocal = localPayload(nPayload, cType);
  314:   }else{
  315:     nPayload = nLocal = 0;
  316:   }
  317:   if( cType==5 || cType==13 ){
  318:     i = decodeVarint(a, &rowid);
  319:     a += i;
  320:     n += i;
  321:     sprintf(&zDesc[nDesc], "r: %lld ", rowid);
  322:     nDesc += strlen(&zDesc[nDesc]);
  323:   }
  324:   if( nLocal<nPayload ){
  325:     int ovfl;
  326:     unsigned char *b = &a[nLocal];
  327:     ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3];
  328:     sprintf(&zDesc[nDesc], "ov: %d ", ovfl);
  329:     nDesc += strlen(&zDesc[nDesc]);
  330:     n += 4;
  331:   }
  332:   if( showCellContent && cType!=5 ){
  333:     nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]);
  334:   }
  335:   *pzDesc = zDesc;
  336:   return nLocal+n;
  337: }
  338: 
  339: /*
  340: ** Decode a btree page
  341: */
  342: static void decode_btree_page(
  343:   unsigned char *a,   /* Page content */
  344:   int pgno,           /* Page number */
  345:   int hdrSize,        /* Size of the page header.  0 or 100 */
  346:   char *zArgs         /* Flags to control formatting */
  347: ){
  348:   const char *zType = "unknown";
  349:   int nCell;
  350:   int i, j;
  351:   int iCellPtr;
  352:   int showCellContent = 0;
  353:   int showMap = 0;
  354:   char *zMap = 0;
  355:   switch( a[0] ){
  356:     case 2:  zType = "index interior node";  break;
  357:     case 5:  zType = "table interior node";  break;
  358:     case 10: zType = "index leaf";           break;
  359:     case 13: zType = "table leaf";           break;
  360:   }
  361:   while( zArgs[0] ){
  362:     switch( zArgs[0] ){
  363:       case 'c': showCellContent = 1;  break;
  364:       case 'm': showMap = 1;          break;
  365:     }
  366:     zArgs++;
  367:   }
  368:   printf("Decode of btree page %d:\n", pgno);
  369:   print_decode_line(a, 0, 1, zType);
  370:   print_decode_line(a, 1, 2, "Offset to first freeblock");
  371:   print_decode_line(a, 3, 2, "Number of cells on this page");
  372:   nCell = a[3]*256 + a[4];
  373:   print_decode_line(a, 5, 2, "Offset to cell content area");
  374:   print_decode_line(a, 7, 1, "Fragmented byte count");
  375:   if( a[0]==2 || a[0]==5 ){
  376:     print_decode_line(a, 8, 4, "Right child");
  377:     iCellPtr = 12;
  378:   }else{
  379:     iCellPtr = 8;
  380:   }
  381:   if( nCell>0 ){
  382:     printf(" key: lx=left-child n=payload-size r=rowid\n");
  383:   }
  384:   if( showMap ){
  385:     zMap = malloc(pagesize);
  386:     memset(zMap, '.', pagesize);
  387:     memset(zMap, '1', hdrSize);
  388:     memset(&zMap[hdrSize], 'H', iCellPtr);
  389:     memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell);
  390:   }
  391:   for(i=0; i<nCell; i++){
  392:     int cofst = iCellPtr + i*2;
  393:     char *zDesc;
  394:     int n;
  395: 
  396:     cofst = a[cofst]*256 + a[cofst+1];
  397:     n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc);
  398:     if( showMap ){
  399:       char zBuf[30];
  400:       memset(&zMap[cofst], '*', n);
  401:       zMap[cofst] = '[';
  402:       zMap[cofst+n-1] = ']';
  403:       sprintf(zBuf, "%d", i);
  404:       j = strlen(zBuf);
  405:       if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j);
  406:     }
  407:     printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
  408:   }
  409:   if( showMap ){
  410:     for(i=0; i<pagesize; i+=64){
  411:       printf(" %03x: %.64s\n", i, &zMap[i]);
  412:     }
  413:     free(zMap);
  414:   }  
  415: }
  416: 
  417: /*
  418: ** Decode a freelist trunk page.
  419: */
  420: static void decode_trunk_page(
  421:   int pgno,             /* The page number */
  422:   int pagesize,         /* Size of each page */
  423:   int detail,           /* Show leaf pages if true */
  424:   int recursive         /* Follow the trunk change if true */
  425: ){
  426:   int n, i, k;
  427:   unsigned char *a;
  428:   while( pgno>0 ){
  429:     a = getContent((pgno-1)*pagesize, pagesize);
  430:     printf("Decode of freelist trunk page %d:\n", pgno);
  431:     print_decode_line(a, 0, 4, "Next freelist trunk page");
  432:     print_decode_line(a, 4, 4, "Number of entries on this page");
  433:     if( detail ){
  434:       n = (int)decodeInt32(&a[4]);
  435:       for(i=0; i<n; i++){
  436:         unsigned int x = decodeInt32(&a[8+4*i]);
  437:         char zIdx[10];
  438:         sprintf(zIdx, "[%d]", i);
  439:         printf("  %5s %7u", zIdx, x);
  440:         if( i%5==4 ) printf("\n");
  441:       }
  442:       if( i%5!=0 ) printf("\n");
  443:     }
  444:     if( !recursive ){
  445:       pgno = 0;
  446:     }else{
  447:       pgno = (int)decodeInt32(&a[0]);
  448:     }
  449:     free(a);
  450:   }
  451: }
  452: 
  453: /*
  454: ** Print a usage comment
  455: */
  456: static void usage(const char *argv0){
  457:   fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0);
  458:   fprintf(stderr,
  459:     "args:\n"
  460:     "    dbheader        Show database header\n"
  461:     "    NNN..MMM        Show hex of pages NNN through MMM\n"
  462:     "    NNN..end        Show hex of pages NNN through end of file\n"
  463:     "    NNNb            Decode btree page NNN\n"
  464:     "    NNNbc           Decode btree page NNN and show content\n"
  465:     "    NNNbm           Decode btree page NNN and show a layout map\n"
  466:     "    NNNt            Decode freelist trunk page NNN\n"
  467:     "    NNNtd           Show leaf freelist pages on the decode\n"
  468:     "    NNNtr           Recurisvely decode freelist starting at NNN\n"
  469:   );
  470: }
  471: 
  472: int main(int argc, char **argv){
  473:   struct stat sbuf;
  474:   unsigned char zPgSz[2];
  475:   if( argc<2 ){
  476:     usage(argv[0]);
  477:     exit(1);
  478:   }
  479:   db = open(argv[1], O_RDONLY);
  480:   if( db<0 ){
  481:     fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
  482:     exit(1);
  483:   }
  484:   zPgSz[0] = 0;
  485:   zPgSz[1] = 0;
  486:   lseek(db, 16, SEEK_SET);
  487:   read(db, zPgSz, 2);
  488:   pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
  489:   if( pagesize==0 ) pagesize = 1024;
  490:   printf("Pagesize: %d\n", pagesize);
  491:   fstat(db, &sbuf);
  492:   mxPage = sbuf.st_size/pagesize;
  493:   printf("Available pages: 1..%d\n", mxPage);
  494:   if( argc==2 ){
  495:     int i;
  496:     for(i=1; i<=mxPage; i++) print_page(i);
  497:   }else{
  498:     int i;
  499:     for(i=2; i<argc; i++){
  500:       int iStart, iEnd;
  501:       char *zLeft;
  502:       if( strcmp(argv[i], "dbheader")==0 ){
  503:         print_db_header();
  504:         continue;
  505:       }
  506:       if( !isdigit(argv[i][0]) ){
  507:         fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
  508:         continue;
  509:       }
  510:       iStart = strtol(argv[i], &zLeft, 0);
  511:       if( zLeft && strcmp(zLeft,"..end")==0 ){
  512:         iEnd = mxPage;
  513:       }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
  514:         iEnd = strtol(&zLeft[2], 0, 0);
  515:       }else if( zLeft && zLeft[0]=='b' ){
  516:         int ofst, nByte, hdrSize;
  517:         unsigned char *a;
  518:         if( iStart==1 ){
  519:           ofst = hdrSize = 100;
  520:           nByte = pagesize-100;
  521:         }else{
  522:           hdrSize = 0;
  523:           ofst = (iStart-1)*pagesize;
  524:           nByte = pagesize;
  525:         }
  526:         a = getContent(ofst, nByte);
  527:         decode_btree_page(a, iStart, hdrSize, &zLeft[1]);
  528:         free(a);
  529:         continue;
  530:       }else if( zLeft && zLeft[0]=='t' ){
  531:         unsigned char *a;
  532:         int detail = 0;
  533:         int recursive = 0;
  534:         int i;
  535:         for(i=1; zLeft[i]; i++){
  536:           if( zLeft[i]=='r' ) recursive = 1;
  537:           if( zLeft[i]=='d' ) detail = 1;
  538:         }
  539:         decode_trunk_page(iStart, pagesize, detail, recursive);
  540:         continue;
  541:       }else{
  542:         iEnd = iStart;
  543:       }
  544:       if( iStart<1 || iEnd<iStart || iEnd>mxPage ){
  545:         fprintf(stderr,
  546:           "Page argument should be LOWER?..UPPER?.  Range 1 to %d\n",
  547:           mxPage);
  548:         exit(1);
  549:       }
  550:       while( iStart<=iEnd ){
  551:         print_page(iStart);
  552:         iStart++;
  553:       }
  554:     }
  555:   }
  556:   close(db);
  557: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>