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 10 #if !defined(_MSC_VER) 11 #include <unistd.h> 12 #endif 13 14 #include <stdlib.h> 15 #include <string.h> 16 #include "sqlite3.h" 17 18 19 static int pagesize = 1024; /* Size of a database page */ 20 static int db = -1; /* File descriptor for reading the DB */ 21 static int mxPage = 0; /* Last page number */ 22 static int perLine = 16; /* HEX elements to print per line */ 23 24 typedef long long int i64; /* Datatype for 64-bit integers */ 25 26 27 /* 28 ** Convert the var-int format into i64. Return the number of bytes 29 ** in the var-int. Write the var-int value into *pVal. 30 */ 31 static int decodeVarint(const unsigned char *z, i64 *pVal){ 32 i64 v = 0; 33 int i; 34 for(i=0; i<8; i++){ 35 v = (v<<7) + (z[i]&0x7f); 36 if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; } 37 } 38 v = (v<<8) + (z[i]&0xff); 39 *pVal = v; 40 return 9; 41 } 42 43 /* 44 ** Extract a big-endian 32-bit integer 45 */ 46 static unsigned int decodeInt32(const unsigned char *z){ 47 return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3]; 48 } 49 50 /* Report an out-of-memory error and die. 51 */ 52 static void out_of_memory(void){ 53 fprintf(stderr,"Out of memory...\n"); 54 exit(1); 55 } 56 57 /* 58 ** Read content from the file. 59 ** 60 ** Space to hold the content is obtained from malloc() and needs to be 61 ** freed by the caller. 62 */ 63 static unsigned char *getContent(int ofst, int nByte){ 64 unsigned char *aData; 65 aData = malloc(nByte+32); 66 if( aData==0 ) out_of_memory(); 67 memset(aData, 0, nByte+32); 68 lseek(db, ofst, SEEK_SET); 69 read(db, aData, nByte); 70 return aData; 71 } 72 73 /* 74 ** Print a range of bytes as hex and as ascii. 75 */ 76 static unsigned char *print_byte_range( 77 int ofst, /* First byte in the range of bytes to print */ 78 int nByte, /* Number of bytes to print */ 79 int printOfst /* Add this amount to the index on the left column */ 80 ){ 81 unsigned char *aData; 82 int i, j; 83 const char *zOfstFmt; 84 85 if( ((printOfst+nByte)&~0xfff)==0 ){ 86 zOfstFmt = " %03x: "; 87 }else if( ((printOfst+nByte)&~0xffff)==0 ){ 88 zOfstFmt = " %04x: "; 89 }else if( ((printOfst+nByte)&~0xfffff)==0 ){ 90 zOfstFmt = " %05x: "; 91 }else if( ((printOfst+nByte)&~0xffffff)==0 ){ 92 zOfstFmt = " %06x: "; 93 }else{ 94 zOfstFmt = " %08x: "; 95 } 96 97 aData = getContent(ofst, nByte); 98 for(i=0; i<nByte; i += perLine){ 99 fprintf(stdout, zOfstFmt, i+printOfst); 100 for(j=0; j<perLine; j++){ 101 if( i+j>nByte ){ 102 fprintf(stdout, " "); 103 }else{ 104 fprintf(stdout,"%02x ", aData[i+j]); 105 } 106 } 107 for(j=0; j<perLine; j++){ 108 if( i+j>nByte ){ 109 fprintf(stdout, " "); 110 }else{ 111 fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.'); 112 } 113 } 114 fprintf(stdout,"\n"); 115 } 116 return aData; 117 } 118 119 /* 120 ** Print an entire page of content as hex 121 */ 122 static void print_page(int iPg){ 123 int iStart; 124 unsigned char *aData; 125 iStart = (iPg-1)*pagesize; 126 fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n", 127 iPg, iStart, iStart+pagesize-1); 128 aData = print_byte_range(iStart, pagesize, 0); 129 free(aData); 130 } 131 132 /* Print a line of decode output showing a 4-byte integer. 133 */ 134 static void print_decode_line( 135 unsigned char *aData, /* Content being decoded */ 136 int ofst, int nByte, /* Start and size of decode */ 137 const char *zMsg /* Message to append */ 138 ){ 139 int i, j; 140 int val = aData[ofst]; 141 char zBuf[100]; 142 sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]); 143 i = strlen(zBuf); 144 for(j=1; j<4; j++){ 145 if( j>=nByte ){ 146 sprintf(&zBuf[i], " "); 147 }else{ 148 sprintf(&zBuf[i], " %02x", aData[ofst+j]); 149 val = val*256 + aData[ofst+j]; 150 } 151 i += strlen(&zBuf[i]); 152 } 153 sprintf(&zBuf[i], " %9d", val); 154 printf("%s %s\n", zBuf, zMsg); 155 } 156 157 /* 158 ** Decode the database header. 159 */ 160 static void print_db_header(void){ 161 unsigned char *aData; 162 aData = print_byte_range(0, 100, 0); 163 printf("Decoded:\n"); 164 print_decode_line(aData, 16, 2, "Database page size"); 165 print_decode_line(aData, 18, 1, "File format write version"); 166 print_decode_line(aData, 19, 1, "File format read version"); 167 print_decode_line(aData, 20, 1, "Reserved space at end of page"); 168 print_decode_line(aData, 24, 4, "File change counter"); 169 print_decode_line(aData, 28, 4, "Size of database in pages"); 170 print_decode_line(aData, 32, 4, "Page number of first freelist page"); 171 print_decode_line(aData, 36, 4, "Number of freelist pages"); 172 print_decode_line(aData, 40, 4, "Schema cookie"); 173 print_decode_line(aData, 44, 4, "Schema format version"); 174 print_decode_line(aData, 48, 4, "Default page cache size"); 175 print_decode_line(aData, 52, 4, "Largest auto-vac root page"); 176 print_decode_line(aData, 56, 4, "Text encoding"); 177 print_decode_line(aData, 60, 4, "User version"); 178 print_decode_line(aData, 64, 4, "Incremental-vacuum mode"); 179 print_decode_line(aData, 68, 4, "Application ID"); 180 print_decode_line(aData, 72, 4, "meta[8]"); 181 print_decode_line(aData, 76, 4, "meta[9]"); 182 print_decode_line(aData, 80, 4, "meta[10]"); 183 print_decode_line(aData, 84, 4, "meta[11]"); 184 print_decode_line(aData, 88, 4, "meta[12]"); 185 print_decode_line(aData, 92, 4, "Change counter for version number"); 186 print_decode_line(aData, 96, 4, "SQLite version number"); 187 } 188 189 /* 190 ** Describe cell content. 191 */ 192 static int describeContent( 193 unsigned char *a, /* Cell content */ 194 int nLocal, /* Bytes in a[] */ 195 char *zDesc /* Write description here */ 196 ){ 197 int nDesc = 0; 198 int n, i, j; 199 i64 x, v; 200 const unsigned char *pData; 201 const unsigned char *pLimit; 202 char sep = ' '; 203 204 pLimit = &a[nLocal]; 205 n = decodeVarint(a, &x); 206 pData = &a[x]; 207 a += n; 208 i = x - n; 209 while( i>0 && pData<=pLimit ){ 210 n = decodeVarint(a, &x); 211 a += n; 212 i -= n; 213 nLocal -= n; 214 zDesc[0] = sep; 215 sep = ','; 216 nDesc++; 217 zDesc++; 218 if( x==0 ){ 219 sprintf(zDesc, "*"); /* NULL is a "*" */ 220 }else if( x>=1 && x<=6 ){ 221 v = (signed char)pData[0]; 222 pData++; 223 switch( x ){ 224 case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; 225 case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; 226 case 4: v = (v<<8) + pData[0]; pData++; 227 case 3: v = (v<<8) + pData[0]; pData++; 228 case 2: v = (v<<8) + pData[0]; pData++; 229 } 230 sprintf(zDesc, "%lld", v); 231 }else if( x==7 ){ 232 sprintf(zDesc, "real"); 233 pData += 8; 234 }else if( x==8 ){ 235 sprintf(zDesc, "0"); 236 }else if( x==9 ){ 237 sprintf(zDesc, "1"); 238 }else if( x>=12 ){ 239 int size = (x-12)/2; 240 if( (x&1)==0 ){ 241 sprintf(zDesc, "blob(%d)", size); 242 }else{ 243 sprintf(zDesc, "txt(%d)", size); 244 } 245 pData += size; 246 } 247 j = strlen(zDesc); 248 zDesc += j; 249 nDesc += j; 250 } 251 return nDesc; 252 } 253 254 /* 255 ** Compute the local payload size given the total payload size and 256 ** the page size. 257 */ 258 static int localPayload(i64 nPayload, char cType){ 259 int maxLocal; 260 int minLocal; 261 int surplus; 262 int nLocal; 263 if( cType==13 ){ 264 /* Table leaf */ 265 maxLocal = pagesize-35; 266 minLocal = (pagesize-12)*32/255-23; 267 }else{ 268 maxLocal = (pagesize-12)*64/255-23; 269 minLocal = (pagesize-12)*32/255-23; 270 } 271 if( nPayload>maxLocal ){ 272 surplus = minLocal + (nPayload-minLocal)%(pagesize-4); 273 if( surplus<=maxLocal ){ 274 nLocal = surplus; 275 }else{ 276 nLocal = minLocal; 277 } 278 }else{ 279 nLocal = nPayload; 280 } 281 return nLocal; 282 } 283 284 285 /* 286 ** Create a description for a single cell. 287 ** 288 ** The return value is the local cell size. 289 */ 290 static int describeCell( 291 unsigned char cType, /* Page type */ 292 unsigned char *a, /* Cell content */ 293 int showCellContent, /* Show cell content if true */ 294 char **pzDesc /* Store description here */ 295 ){ 296 int i; 297 int nDesc = 0; 298 int n = 0; 299 int leftChild; 300 i64 nPayload; 301 i64 rowid; 302 int nLocal; 303 static char zDesc[1000]; 304 i = 0; 305 if( cType<=5 ){ 306 leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3]; 307 a += 4; 308 n += 4; 309 sprintf(zDesc, "lx: %d ", leftChild); 310 nDesc = strlen(zDesc); 311 } 312 if( cType!=5 ){ 313 i = decodeVarint(a, &nPayload); 314 a += i; 315 n += i; 316 sprintf(&zDesc[nDesc], "n: %lld ", nPayload); 317 nDesc += strlen(&zDesc[nDesc]); 318 nLocal = localPayload(nPayload, cType); 319 }else{ 320 nPayload = nLocal = 0; 321 } 322 if( cType==5 || cType==13 ){ 323 i = decodeVarint(a, &rowid); 324 a += i; 325 n += i; 326 sprintf(&zDesc[nDesc], "r: %lld ", rowid); 327 nDesc += strlen(&zDesc[nDesc]); 328 } 329 if( nLocal<nPayload ){ 330 int ovfl; 331 unsigned char *b = &a[nLocal]; 332 ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3]; 333 sprintf(&zDesc[nDesc], "ov: %d ", ovfl); 334 nDesc += strlen(&zDesc[nDesc]); 335 n += 4; 336 } 337 if( showCellContent && cType!=5 ){ 338 nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]); 339 } 340 *pzDesc = zDesc; 341 return nLocal+n; 342 } 343 344 /* 345 ** Decode a btree page 346 */ 347 static void decode_btree_page( 348 unsigned char *a, /* Page content */ 349 int pgno, /* Page number */ 350 int hdrSize, /* Size of the page header. 0 or 100 */ 351 char *zArgs /* Flags to control formatting */ 352 ){ 353 const char *zType = "unknown"; 354 int nCell; 355 int i, j; 356 int iCellPtr; 357 int showCellContent = 0; 358 int showMap = 0; 359 char *zMap = 0; 360 switch( a[0] ){ 361 case 2: zType = "index interior node"; break; 362 case 5: zType = "table interior node"; break; 363 case 10: zType = "index leaf"; break; 364 case 13: zType = "table leaf"; break; 365 } 366 while( zArgs[0] ){ 367 switch( zArgs[0] ){ 368 case 'c': showCellContent = 1; break; 369 case 'm': showMap = 1; break; 370 } 371 zArgs++; 372 } 373 printf("Decode of btree page %d:\n", pgno); 374 print_decode_line(a, 0, 1, zType); 375 print_decode_line(a, 1, 2, "Offset to first freeblock"); 376 print_decode_line(a, 3, 2, "Number of cells on this page"); 377 nCell = a[3]*256 + a[4]; 378 print_decode_line(a, 5, 2, "Offset to cell content area"); 379 print_decode_line(a, 7, 1, "Fragmented byte count"); 380 if( a[0]==2 || a[0]==5 ){ 381 print_decode_line(a, 8, 4, "Right child"); 382 iCellPtr = 12; 383 }else{ 384 iCellPtr = 8; 385 } 386 if( nCell>0 ){ 387 printf(" key: lx=left-child n=payload-size r=rowid\n"); 388 } 389 if( showMap ){ 390 zMap = malloc(pagesize); 391 memset(zMap, '.', pagesize); 392 memset(zMap, '1', hdrSize); 393 memset(&zMap[hdrSize], 'H', iCellPtr); 394 memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell); 395 } 396 for(i=0; i<nCell; i++){ 397 int cofst = iCellPtr + i*2; 398 char *zDesc; 399 int n; 400 401 cofst = a[cofst]*256 + a[cofst+1]; 402 n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc); 403 if( showMap ){ 404 char zBuf[30]; 405 memset(&zMap[cofst], '*', n); 406 zMap[cofst] = '['; 407 zMap[cofst+n-1] = ']'; 408 sprintf(zBuf, "%d", i); 409 j = strlen(zBuf); 410 if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j); 411 } 412 printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); 413 } 414 if( showMap ){ 415 for(i=0; i<pagesize; i+=64){ 416 printf(" %03x: %.64s\n", i, &zMap[i]); 417 } 418 free(zMap); 419 } 420 } 421 422 /* 423 ** Decode a freelist trunk page. 424 */ 425 static void decode_trunk_page( 426 int pgno, /* The page number */ 427 int pagesize, /* Size of each page */ 428 int detail, /* Show leaf pages if true */ 429 int recursive /* Follow the trunk change if true */ 430 ){ 431 int n, i; 432 unsigned char *a; 433 while( pgno>0 ){ 434 a = getContent((pgno-1)*pagesize, pagesize); 435 printf("Decode of freelist trunk page %d:\n", pgno); 436 print_decode_line(a, 0, 4, "Next freelist trunk page"); 437 print_decode_line(a, 4, 4, "Number of entries on this page"); 438 if( detail ){ 439 n = (int)decodeInt32(&a[4]); 440 for(i=0; i<n; i++){ 441 unsigned int x = decodeInt32(&a[8+4*i]); 442 char zIdx[10]; 443 sprintf(zIdx, "[%d]", i); 444 printf(" %5s %7u", zIdx, x); 445 if( i%5==4 ) printf("\n"); 446 } 447 if( i%5!=0 ) printf("\n"); 448 } 449 if( !recursive ){ 450 pgno = 0; 451 }else{ 452 pgno = (int)decodeInt32(&a[0]); 453 } 454 free(a); 455 } 456 } 457 458 /* 459 ** A short text comment on the use of each page. 460 */ 461 static char **zPageUse; 462 463 /* 464 ** Add a comment on the use of a page. 465 */ 466 static void page_usage_msg(int pgno, const char *zFormat, ...){ 467 va_list ap; 468 char *zMsg; 469 470 va_start(ap, zFormat); 471 zMsg = sqlite3_vmprintf(zFormat, ap); 472 va_end(ap); 473 if( pgno<=0 || pgno>mxPage ){ 474 printf("ERROR: page %d out of range 1..%d: %s\n", 475 pgno, mxPage, zMsg); 476 sqlite3_free(zMsg); 477 return; 478 } 479 if( zPageUse[pgno]!=0 ){ 480 printf("ERROR: page %d used multiple times:\n", pgno); 481 printf("ERROR: previous: %s\n", zPageUse[pgno]); 482 printf("ERROR: current: %s\n", zMsg); 483 sqlite3_free(zPageUse[pgno]); 484 } 485 zPageUse[pgno] = zMsg; 486 } 487 488 /* 489 ** Find overflow pages of a cell and describe their usage. 490 */ 491 static void page_usage_cell( 492 unsigned char cType, /* Page type */ 493 unsigned char *a, /* Cell content */ 494 int pgno, /* page containing the cell */ 495 int cellno /* Index of the cell on the page */ 496 ){ 497 int i; 498 int n = 0; 499 i64 nPayload; 500 i64 rowid; 501 int nLocal; 502 i = 0; 503 if( cType<=5 ){ 504 a += 4; 505 n += 4; 506 } 507 if( cType!=5 ){ 508 i = decodeVarint(a, &nPayload); 509 a += i; 510 n += i; 511 nLocal = localPayload(nPayload, cType); 512 }else{ 513 nPayload = nLocal = 0; 514 } 515 if( cType==5 || cType==13 ){ 516 i = decodeVarint(a, &rowid); 517 a += i; 518 n += i; 519 } 520 if( nLocal<nPayload ){ 521 int ovfl = decodeInt32(a+nLocal); 522 int cnt = 0; 523 while( ovfl && (cnt++)<mxPage ){ 524 page_usage_msg(ovfl, "overflow %d from cell %d of page %d", 525 cnt, cellno, pgno); 526 a = getContent((ovfl-1)*pagesize, 4); 527 ovfl = decodeInt32(a); 528 free(a); 529 } 530 } 531 } 532 533 534 /* 535 ** Describe the usages of a b-tree page 536 */ 537 static void page_usage_btree( 538 int pgno, /* Page to describe */ 539 int parent, /* Parent of this page. 0 for root pages */ 540 int idx, /* Which child of the parent */ 541 const char *zName /* Name of the table */ 542 ){ 543 unsigned char *a; 544 const char *zType = "corrupt node"; 545 int nCell; 546 int i; 547 int hdr = pgno==1 ? 100 : 0; 548 549 if( pgno<=0 || pgno>mxPage ) return; 550 a = getContent((pgno-1)*pagesize, pagesize); 551 switch( a[hdr] ){ 552 case 2: zType = "interior node of index"; break; 553 case 5: zType = "interior node of table"; break; 554 case 10: zType = "leaf of index"; break; 555 case 13: zType = "leaf of table"; break; 556 } 557 if( parent ){ 558 page_usage_msg(pgno, "%s [%s], child %d of page %d", 559 zType, zName, idx, parent); 560 }else{ 561 page_usage_msg(pgno, "root %s [%s]", zType, zName); 562 } 563 nCell = a[hdr+3]*256 + a[hdr+4]; 564 if( a[hdr]==2 || a[hdr]==5 ){ 565 int cellstart = hdr+12; 566 unsigned int child; 567 for(i=0; i<nCell; i++){ 568 int ofst; 569 570 ofst = cellstart + i*2; 571 ofst = a[ofst]*256 + a[ofst+1]; 572 child = decodeInt32(a+ofst); 573 page_usage_btree(child, pgno, i, zName); 574 } 575 child = decodeInt32(a+cellstart-4); 576 page_usage_btree(child, pgno, i, zName); 577 } 578 if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){ 579 int cellstart = hdr + 8 + 4*(a[hdr]<=5); 580 for(i=0; i<nCell; i++){ 581 int ofst; 582 ofst = cellstart + i*2; 583 ofst = a[ofst]*256 + a[ofst+1]; 584 page_usage_cell(a[hdr], a+ofst, pgno, i); 585 } 586 } 587 free(a); 588 } 589 590 /* 591 ** Determine page usage by the freelist 592 */ 593 static void page_usage_freelist(int pgno){ 594 unsigned char *a; 595 int cnt = 0; 596 int i; 597 int n; 598 int iNext; 599 int parent = 1; 600 601 while( pgno>0 && pgno<=mxPage && (cnt++)<mxPage ){ 602 page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent); 603 a = getContent((pgno-1)*pagesize, pagesize); 604 iNext = decodeInt32(a); 605 n = decodeInt32(a+4); 606 for(i=0; i<n; i++){ 607 int child = decodeInt32(a + (i*4+8)); 608 page_usage_msg(child, "freelist leaf, child %d of trunk page %d", 609 i, pgno); 610 } 611 free(a); 612 parent = pgno; 613 pgno = iNext; 614 } 615 } 616 617 /* 618 ** Determine pages used as PTRMAP pages 619 */ 620 static void page_usage_ptrmap(unsigned char *a){ 621 if( a[55] ){ 622 int usable = pagesize - a[20]; 623 int pgno = 2; 624 int perPage = usable/5; 625 while( pgno<=mxPage ){ 626 page_usage_msg(pgno, "PTRMAP page covering %d..%d", 627 pgno+1, pgno+perPage); 628 pgno += perPage + 1; 629 } 630 } 631 } 632 633 /* 634 ** Try to figure out how every page in the database file is being used. 635 */ 636 static void page_usage_report(const char *zDbName){ 637 int i, j; 638 int rc; 639 sqlite3 *db; 640 sqlite3_stmt *pStmt; 641 unsigned char *a; 642 char zQuery[200]; 643 644 /* Avoid the pathological case */ 645 if( mxPage<1 ){ 646 printf("empty database\n"); 647 return; 648 } 649 650 /* Open the database file */ 651 rc = sqlite3_open(zDbName, &db); 652 if( rc ){ 653 printf("cannot open database: %s\n", sqlite3_errmsg(db)); 654 sqlite3_close(db); 655 return; 656 } 657 658 /* Set up global variables zPageUse[] and mxPage to record page 659 ** usages */ 660 zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) ); 661 if( zPageUse==0 ) out_of_memory(); 662 memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1)); 663 664 /* Discover the usage of each page */ 665 a = getContent(0, 100); 666 page_usage_freelist(decodeInt32(a+32)); 667 page_usage_ptrmap(a); 668 free(a); 669 page_usage_btree(1, 0, 0, "sqlite_master"); 670 sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0); 671 for(j=0; j<2; j++){ 672 sqlite3_snprintf(sizeof(zQuery), zQuery, 673 "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage" 674 " ORDER BY rowid %s", j?"DESC":""); 675 rc = sqlite3_prepare_v2(db, zQuery, -1, &pStmt, 0); 676 if( rc==SQLITE_OK ){ 677 while( sqlite3_step(pStmt)==SQLITE_ROW ){ 678 int pgno = sqlite3_column_int(pStmt, 2); 679 page_usage_btree(pgno, 0, 0, (const char*)sqlite3_column_text(pStmt,1)); 680 } 681 }else{ 682 printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db)); 683 } 684 rc = sqlite3_finalize(pStmt); 685 if( rc==SQLITE_OK ) break; 686 } 687 sqlite3_close(db); 688 689 /* Print the report and free memory used */ 690 for(i=1; i<=mxPage; i++){ 691 printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???"); 692 sqlite3_free(zPageUse[i]); 693 } 694 sqlite3_free(zPageUse); 695 zPageUse = 0; 696 } 697 698 /* 699 ** Try to figure out how every page in the database file is being used. 700 */ 701 static void ptrmap_coverage_report(const char *zDbName){ 702 unsigned int pgno; 703 unsigned char *aHdr; 704 unsigned char *a; 705 int usable; 706 int perPage; 707 unsigned int i; 708 709 /* Avoid the pathological case */ 710 if( mxPage<1 ){ 711 printf("empty database\n"); 712 return; 713 } 714 715 /* Make sure PTRMAPs are used in this database */ 716 aHdr = getContent(0, 100); 717 if( aHdr[55]==0 ){ 718 printf("database does not use PTRMAP pages\n"); 719 return; 720 } 721 usable = pagesize - aHdr[20]; 722 perPage = usable/5; 723 free(aHdr); 724 printf("%5d: root of sqlite_master\n", 1); 725 for(pgno=2; pgno<=mxPage; pgno += perPage+1){ 726 printf("%5d: PTRMAP page covering %d..%d\n", pgno, 727 pgno+1, pgno+perPage); 728 a = getContent((pgno-1)*pagesize, usable); 729 for(i=0; i+5<=usable && pgno+1+i/5<=mxPage; i+=5){ 730 const char *zType = "???"; 731 unsigned int iFrom = decodeInt32(&a[i+1]); 732 switch( a[i] ){ 733 case 1: zType = "b-tree root page"; break; 734 case 2: zType = "freelist page"; break; 735 case 3: zType = "first page of overflow"; break; 736 case 4: zType = "later page of overflow"; break; 737 case 5: zType = "b-tree non-root page"; break; 738 } 739 printf("%5d: %s, parent=%u\n", pgno+1+i/5, zType, iFrom); 740 } 741 free(a); 742 } 743 } 744 745 /* 746 ** Print a usage comment 747 */ 748 static void usage(const char *argv0){ 749 fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0); 750 fprintf(stderr, 751 "args:\n" 752 " dbheader Show database header\n" 753 " pgidx Index of how each page is used\n" 754 " ptrmap Show all PTRMAP page content\n" 755 " NNN..MMM Show hex of pages NNN through MMM\n" 756 " NNN..end Show hex of pages NNN through end of file\n" 757 " NNNb Decode btree page NNN\n" 758 " NNNbc Decode btree page NNN and show content\n" 759 " NNNbm Decode btree page NNN and show a layout map\n" 760 " NNNt Decode freelist trunk page NNN\n" 761 " NNNtd Show leaf freelist pages on the decode\n" 762 " NNNtr Recurisvely decode freelist starting at NNN\n" 763 ); 764 } 765 766 int main(int argc, char **argv){ 767 struct stat sbuf; 768 unsigned char zPgSz[2]; 769 if( argc<2 ){ 770 usage(argv[0]); 771 exit(1); 772 } 773 db = open(argv[1], O_RDONLY); 774 if( db<0 ){ 775 fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]); 776 exit(1); 777 } 778 zPgSz[0] = 0; 779 zPgSz[1] = 0; 780 lseek(db, 16, SEEK_SET); 781 read(db, zPgSz, 2); 782 pagesize = zPgSz[0]*256 + zPgSz[1]*65536; 783 if( pagesize==0 ) pagesize = 1024; 784 printf("Pagesize: %d\n", pagesize); 785 fstat(db, &sbuf); 786 mxPage = sbuf.st_size/pagesize; 787 printf("Available pages: 1..%d\n", mxPage); 788 if( argc==2 ){ 789 int i; 790 for(i=1; i<=mxPage; i++) print_page(i); 791 }else{ 792 int i; 793 for(i=2; i<argc; i++){ 794 int iStart, iEnd; 795 char *zLeft; 796 if( strcmp(argv[i], "dbheader")==0 ){ 797 print_db_header(); 798 continue; 799 } 800 if( strcmp(argv[i], "pgidx")==0 ){ 801 page_usage_report(argv[1]); 802 continue; 803 } 804 if( strcmp(argv[i], "ptrmap")==0 ){ 805 ptrmap_coverage_report(argv[1]); 806 continue; 807 } 808 if( strcmp(argv[i], "help")==0 ){ 809 usage(argv[0]); 810 continue; 811 } 812 if( !isdigit(argv[i][0]) ){ 813 fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); 814 continue; 815 } 816 iStart = strtol(argv[i], &zLeft, 0); 817 if( zLeft && strcmp(zLeft,"..end")==0 ){ 818 iEnd = mxPage; 819 }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ 820 iEnd = strtol(&zLeft[2], 0, 0); 821 }else if( zLeft && zLeft[0]=='b' ){ 822 int ofst, nByte, hdrSize; 823 unsigned char *a; 824 if( iStart==1 ){ 825 ofst = hdrSize = 100; 826 nByte = pagesize-100; 827 }else{ 828 hdrSize = 0; 829 ofst = (iStart-1)*pagesize; 830 nByte = pagesize; 831 } 832 a = getContent(ofst, nByte); 833 decode_btree_page(a, iStart, hdrSize, &zLeft[1]); 834 free(a); 835 continue; 836 }else if( zLeft && zLeft[0]=='t' ){ 837 int detail = 0; 838 int recursive = 0; 839 int i; 840 for(i=1; zLeft[i]; i++){ 841 if( zLeft[i]=='r' ) recursive = 1; 842 if( zLeft[i]=='d' ) detail = 1; 843 } 844 decode_trunk_page(iStart, pagesize, detail, recursive); 845 continue; 846 }else{ 847 iEnd = iStart; 848 } 849 if( iStart<1 || iEnd<iStart || iEnd>mxPage ){ 850 fprintf(stderr, 851 "Page argument should be LOWER?..UPPER?. Range 1 to %d\n", 852 mxPage); 853 exit(1); 854 } 855 while( iStart<=iEnd ){ 856 print_page(iStart); 857 iStart++; 858 } 859 } 860 } 861 close(db); 862 return 0; 863 } 864