Annotation of embedaddon/sqlite3/tool/showdb.c, revision 1.1.1.1

1.1       misho       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>