2 ** A utility for printing all or part of an SQLite database file.
10 #if !defined(_MSC_VER)
21 static int pagesize
= 1024; /* Size of a database page */
22 static int db
= -1; /* File descriptor for reading the DB */
23 static int mxPage
= 0; /* Last page number */
24 static int perLine
= 16; /* HEX elements to print per line */
26 typedef long long int i64
; /* Datatype for 64-bit integers */
30 ** Convert the var-int format into i64. Return the number of bytes
31 ** in the var-int. Write the var-int value into *pVal.
33 static int decodeVarint(const unsigned char *z
, i64
*pVal
){
37 v
= (v
<<7) + (z
[i
]&0x7f);
38 if( (z
[i
]&0x80)==0 ){ *pVal
= v
; return i
+1; }
40 v
= (v
<<8) + (z
[i
]&0xff);
46 ** Extract a big-endian 32-bit integer
48 static unsigned int decodeInt32(const unsigned char *z
){
49 return (z
[0]<<24) + (z
[1]<<16) + (z
[2]<<8) + z
[3];
52 /* Report an out-of-memory error and die.
54 static void out_of_memory(void){
55 fprintf(stderr
,"Out of memory...\n");
60 ** Read content from the file.
62 ** Space to hold the content is obtained from malloc() and needs to be
63 ** freed by the caller.
65 static unsigned char *getContent(int ofst
, int nByte
){
67 aData
= malloc(nByte
+32);
68 if( aData
==0 ) out_of_memory();
69 memset(aData
, 0, nByte
+32);
70 lseek(db
, ofst
, SEEK_SET
);
71 if( read(db
, aData
, nByte
)<nByte
) memset(aData
, 0, nByte
);
76 ** Print a range of bytes as hex and as ascii.
78 static unsigned char *print_byte_range(
79 int ofst
, /* First byte in the range of bytes to print */
80 int nByte
, /* Number of bytes to print */
81 int printOfst
/* Add this amount to the index on the left column */
87 if( ((printOfst
+nByte
)&~0xfff)==0 ){
89 }else if( ((printOfst
+nByte
)&~0xffff)==0 ){
91 }else if( ((printOfst
+nByte
)&~0xfffff)==0 ){
93 }else if( ((printOfst
+nByte
)&~0xffffff)==0 ){
99 aData
= getContent(ofst
, nByte
);
100 for(i
=0; i
<nByte
; i
+= perLine
){
101 fprintf(stdout
, zOfstFmt
, i
+printOfst
);
102 for(j
=0; j
<perLine
; j
++){
104 fprintf(stdout
, " ");
106 fprintf(stdout
,"%02x ", aData
[i
+j
]);
109 for(j
=0; j
<perLine
; j
++){
111 fprintf(stdout
, " ");
113 fprintf(stdout
,"%c", isprint(aData
[i
+j
]) ? aData
[i
+j
] : '.');
116 fprintf(stdout
,"\n");
122 ** Print an entire page of content as hex
124 static void print_page(int iPg
){
126 unsigned char *aData
;
127 iStart
= (iPg
-1)*pagesize
;
128 fprintf(stdout
, "Page %d: (offsets 0x%x..0x%x)\n",
129 iPg
, iStart
, iStart
+pagesize
-1);
130 aData
= print_byte_range(iStart
, pagesize
, 0);
135 /* Print a line of decode output showing a 4-byte integer.
137 static void print_decode_line(
138 unsigned char *aData
, /* Content being decoded */
139 int ofst
, int nByte
, /* Start and size of decode */
140 const char *zMsg
/* Message to append */
143 int val
= aData
[ofst
];
145 sprintf(zBuf
, " %03x: %02x", ofst
, aData
[ofst
]);
146 i
= (int)strlen(zBuf
);
149 sprintf(&zBuf
[i
], " ");
151 sprintf(&zBuf
[i
], " %02x", aData
[ofst
+j
]);
152 val
= val
*256 + aData
[ofst
+j
];
154 i
+= (int)strlen(&zBuf
[i
]);
156 sprintf(&zBuf
[i
], " %9d", val
);
157 printf("%s %s\n", zBuf
, zMsg
);
161 ** Decode the database header.
163 static void print_db_header(void){
164 unsigned char *aData
;
165 aData
= print_byte_range(0, 100, 0);
166 printf("Decoded:\n");
167 print_decode_line(aData
, 16, 2, "Database page size");
168 print_decode_line(aData
, 18, 1, "File format write version");
169 print_decode_line(aData
, 19, 1, "File format read version");
170 print_decode_line(aData
, 20, 1, "Reserved space at end of page");
171 print_decode_line(aData
, 24, 4, "File change counter");
172 print_decode_line(aData
, 28, 4, "Size of database in pages");
173 print_decode_line(aData
, 32, 4, "Page number of first freelist page");
174 print_decode_line(aData
, 36, 4, "Number of freelist pages");
175 print_decode_line(aData
, 40, 4, "Schema cookie");
176 print_decode_line(aData
, 44, 4, "Schema format version");
177 print_decode_line(aData
, 48, 4, "Default page cache size");
178 print_decode_line(aData
, 52, 4, "Largest auto-vac root page");
179 print_decode_line(aData
, 56, 4, "Text encoding");
180 print_decode_line(aData
, 60, 4, "User version");
181 print_decode_line(aData
, 64, 4, "Incremental-vacuum mode");
182 print_decode_line(aData
, 68, 4, "Application ID");
183 print_decode_line(aData
, 72, 4, "meta[8]");
184 print_decode_line(aData
, 76, 4, "meta[9]");
185 print_decode_line(aData
, 80, 4, "meta[10]");
186 print_decode_line(aData
, 84, 4, "meta[11]");
187 print_decode_line(aData
, 88, 4, "meta[12]");
188 print_decode_line(aData
, 92, 4, "Change counter for version number");
189 print_decode_line(aData
, 96, 4, "SQLite version number");
193 ** Describe cell content.
195 static i64
describeContent(
196 unsigned char *a
, /* Cell content */
197 i64 nLocal
, /* Bytes in a[] */
198 char *zDesc
/* Write description here */
203 const unsigned char *pData
;
204 const unsigned char *pLimit
;
208 n
= decodeVarint(a
, &x
);
212 while( i
>0 && pData
<=pLimit
){
213 n
= decodeVarint(a
, &x
);
222 sprintf(zDesc
, "*"); /* NULL is a "*" */
223 }else if( x
>=1 && x
<=6 ){
224 v
= (signed char)pData
[0];
227 case 6: v
= (v
<<16) + (pData
[0]<<8) + pData
[1]; pData
+= 2;
228 case 5: v
= (v
<<16) + (pData
[0]<<8) + pData
[1]; pData
+= 2;
229 case 4: v
= (v
<<8) + pData
[0]; pData
++;
230 case 3: v
= (v
<<8) + pData
[0]; pData
++;
231 case 2: v
= (v
<<8) + pData
[0]; pData
++;
233 sprintf(zDesc
, "%lld", v
);
235 sprintf(zDesc
, "real");
244 sprintf(zDesc
, "blob(%lld)", size
);
246 sprintf(zDesc
, "txt(%lld)", size
);
250 j
= (int)strlen(zDesc
);
258 ** Compute the local payload size given the total payload size and
261 static i64
localPayload(i64 nPayload
, char cType
){
268 maxLocal
= pagesize
-35;
269 minLocal
= (pagesize
-12)*32/255-23;
271 maxLocal
= (pagesize
-12)*64/255-23;
272 minLocal
= (pagesize
-12)*32/255-23;
274 if( nPayload
>maxLocal
){
275 surplus
= minLocal
+ (nPayload
-minLocal
)%(pagesize
-4);
276 if( surplus
<=maxLocal
){
289 ** Create a description for a single cell.
291 ** The return value is the local cell size.
293 static i64
describeCell(
294 unsigned char cType
, /* Page type */
295 unsigned char *a
, /* Cell content */
296 int showCellContent
, /* Show cell content if true */
297 char **pzDesc
/* Store description here */
306 static char zDesc
[1000];
309 leftChild
= ((a
[0]*256 + a
[1])*256 + a
[2])*256 + a
[3];
312 sprintf(zDesc
, "lx: %d ", leftChild
);
313 nDesc
= strlen(zDesc
);
316 i
= decodeVarint(a
, &nPayload
);
319 sprintf(&zDesc
[nDesc
], "n: %lld ", nPayload
);
320 nDesc
+= strlen(&zDesc
[nDesc
]);
321 nLocal
= localPayload(nPayload
, cType
);
323 nPayload
= nLocal
= 0;
325 if( cType
==5 || cType
==13 ){
326 i
= decodeVarint(a
, &rowid
);
329 sprintf(&zDesc
[nDesc
], "r: %lld ", rowid
);
330 nDesc
+= strlen(&zDesc
[nDesc
]);
332 if( nLocal
<nPayload
){
334 unsigned char *b
= &a
[nLocal
];
335 ovfl
= ((b
[0]*256 + b
[1])*256 + b
[2])*256 + b
[3];
336 sprintf(&zDesc
[nDesc
], "ov: %d ", ovfl
);
337 nDesc
+= strlen(&zDesc
[nDesc
]);
340 if( showCellContent
&& cType
!=5 ){
341 nDesc
+= describeContent(a
, nLocal
, &zDesc
[nDesc
-1]);
347 /* Print an offset followed by nByte bytes. Add extra white-space
348 ** at the end so that subsequent text is aligned.
350 static void printBytes(
351 unsigned char *aData
, /* Content being decoded */
352 unsigned char *aStart
, /* Start of content to be printed */
353 int nByte
/* Number of bytes to print */
356 printf(" %03x: ", (int)(aStart
-aData
));
361 printf("%02x ", aStart
[j
]);
368 ** Write a full decode on stdout for the cell at a[ofst].
369 ** Assume the page contains a header of size szPgHdr bytes.
371 static void decodeCell(
372 unsigned char *a
, /* Page content (without the page-1 header) */
373 unsigned pgno
, /* Page number */
374 int iCell
, /* Cell index */
375 int szPgHdr
, /* Size of the page header. 0 or 100 */
376 int ofst
/* Cell begins at a[ofst] */
386 unsigned char *x
= a
+ ofst
;
388 unsigned char cType
= a
[0];
394 printf("Cell[%d]:\n", iCell
);
396 leftChild
= ((x
[0]*256 + x
[1])*256 + x
[2])*256 + x
[3];
398 printf("left child page:: %d\n", leftChild
);
402 i
= decodeVarint(x
, &nPayload
);
404 nLocal
= localPayload(nPayload
, cType
);
405 if( nLocal
==nPayload
){
406 printf("payload-size: %lld\n", nPayload
);
408 printf("payload-size: %lld (%lld local, %lld overflow)\n",
409 nPayload
, nLocal
, nPayload
-nLocal
);
413 nPayload
= nLocal
= 0;
416 if( cType
==5 || cType
==13 ){
417 i
= decodeVarint(x
, &rowid
);
419 printf("rowid: %lld\n", rowid
);
423 i
= decodeVarint(x
, &nHdr
);
425 printf("record-header-size: %d\n", (int)nHdr
);
429 while( x
+j
<end
&& j
<nHdr
){
430 const char *zTypeName
;
433 i
= decodeVarint(x
+j
, &iType
);
434 printBytes(a
, x
+j
, i
);
435 printf("typecode[%d]: %d - ", nCol
, (int)iType
);
437 case 0: zTypeName
= "NULL"; sz
= 0; break;
438 case 1: zTypeName
= "int8"; sz
= 1; break;
439 case 2: zTypeName
= "int16"; sz
= 2; break;
440 case 3: zTypeName
= "int24"; sz
= 3; break;
441 case 4: zTypeName
= "int32"; sz
= 4; break;
442 case 5: zTypeName
= "int48"; sz
= 6; break;
443 case 6: zTypeName
= "int64"; sz
= 8; break;
444 case 7: zTypeName
= "double"; sz
= 8; break;
445 case 8: zTypeName
= "zero"; sz
= 0; break;
446 case 9: zTypeName
= "one"; sz
= 0; break;
448 case 11: zTypeName
= "error"; sz
= 0; break;
450 sz
= (int)(iType
-12)/2;
451 sprintf(zNm
, (iType
&1)==0 ? "blob(%d)" : "text(%d)", sz
);
456 printf("%s\n", zTypeName
);
458 ofstCol
[nCol
] = (int)k
;
459 typeCol
[nCol
] = (int)iType
;
464 for(i
=0; i
<nCol
&& ofstCol
[i
]+szCol
[i
]<=nLocal
; i
++){
467 const unsigned char *pData
;
468 if( szCol
[i
]==0 ) continue;
469 printBytes(a
, x
+s
, szCol
[i
]);
470 printf("data[%d]: ", i
);
473 v
= (signed char)pData
[0];
474 for(k
=1; k
<szCol
[i
]; k
++){
475 v
= (v
<<8) + pData
[k
];
479 memcpy(&r
, &v
, sizeof(r
));
487 if( (typeCol
[i
]&1)==0 ){
490 for(ii
=2, jj
=0; jj
<szCol
[i
] && ii
<24; jj
++, ii
+=2){
491 sprintf(zConst
+ii
, "%02x", pData
[jj
]);
495 for(ii
=1, jj
=0; jj
<szCol
[i
] && ii
<24; jj
++, ii
++){
496 zConst
[ii
] = isprint(pData
[jj
]) ? pData
[jj
] : '.';
501 memcpy(zConst
+ii
, "...'", 5);
503 memcpy(zConst
+ii
, "'", 2);
505 printf("%s\n", zConst
);
507 j
= ofstCol
[i
] + szCol
[i
];
511 printBytes(a
, x
+j
, 0);
512 printf("... %lld bytes of content ...\n", nLocal
-j
);
514 if( nLocal
<nPayload
){
515 printBytes(a
, x
+nLocal
, 4);
516 printf("overflow-page: %d\n", decodeInt32(x
+nLocal
));
522 ** Decode a btree page
524 static void decode_btree_page(
525 unsigned char *a
, /* Page content */
526 int pgno
, /* Page number */
527 int hdrSize
, /* Size of the page header. 0 or 100 */
528 char *zArgs
/* Flags to control formatting */
530 const char *zType
= "unknown";
534 int showCellContent
= 0;
536 int cellToDecode
= -2;
539 case 2: zType
= "index interior node"; break;
540 case 5: zType
= "table interior node"; break;
541 case 10: zType
= "index leaf"; break;
542 case 13: zType
= "table leaf"; break;
546 case 'c': showCellContent
= 1; break;
547 case 'm': showMap
= 1; break;
549 if( !isdigit(zArgs
[1]) ){
553 while( isdigit(zArgs
[1]) ){
555 cellToDecode
= cellToDecode
*10 + zArgs
[0] - '0';
563 nCell
= a
[3]*256 + a
[4];
564 iCellPtr
= (a
[0]==2 || a
[0]==5) ? 12 : 8;
565 if( cellToDecode
>=nCell
){
566 printf("Page %d has only %d cells\n", pgno
, nCell
);
569 printf("Header on btree page %d:\n", pgno
);
570 print_decode_line(a
, 0, 1, zType
);
571 print_decode_line(a
, 1, 2, "Offset to first freeblock");
572 print_decode_line(a
, 3, 2, "Number of cells on this page");
573 print_decode_line(a
, 5, 2, "Offset to cell content area");
574 print_decode_line(a
, 7, 1, "Fragmented byte count");
575 if( a
[0]==2 || a
[0]==5 ){
576 print_decode_line(a
, 8, 4, "Right child");
578 if( cellToDecode
==(-2) && nCell
>0 ){
579 printf(" key: lx=left-child n=payload-size r=rowid\n");
582 zMap
= malloc(pagesize
);
583 memset(zMap
, '.', pagesize
);
584 memset(zMap
, '1', hdrSize
);
585 memset(&zMap
[hdrSize
], 'H', iCellPtr
);
586 memset(&zMap
[hdrSize
+iCellPtr
], 'P', 2*nCell
);
588 for(i
=0; i
<nCell
; i
++){
589 int cofst
= iCellPtr
+ i
*2;
593 cofst
= a
[cofst
]*256 + a
[cofst
+1];
594 n
= describeCell(a
[0], &a
[cofst
-hdrSize
], showCellContent
, &zDesc
);
597 memset(&zMap
[cofst
], '*', (size_t)n
);
599 zMap
[cofst
+n
-1] = ']';
600 sprintf(zBuf
, "%d", i
);
601 j
= (int)strlen(zBuf
);
602 if( j
<=n
-2 ) memcpy(&zMap
[cofst
+1], zBuf
, j
);
604 if( cellToDecode
==(-2) ){
605 printf(" %03x: cell[%d] %s\n", cofst
, i
, zDesc
);
606 }else if( cellToDecode
==(-1) || cellToDecode
==i
){
607 decodeCell(a
, pgno
, i
, hdrSize
, cofst
-hdrSize
);
611 printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n");
612 for(i
=0; i
<pagesize
; i
+=64){
613 printf(" %03x: %.64s\n", i
, &zMap
[i
]);
620 ** Decode a freelist trunk page.
622 static void decode_trunk_page(
623 int pgno
, /* The page number */
624 int pagesize
, /* Size of each page */
625 int detail
, /* Show leaf pages if true */
626 int recursive
/* Follow the trunk change if true */
631 a
= getContent((pgno
-1)*pagesize
, pagesize
);
632 printf("Decode of freelist trunk page %d:\n", pgno
);
633 print_decode_line(a
, 0, 4, "Next freelist trunk page");
634 print_decode_line(a
, 4, 4, "Number of entries on this page");
636 n
= (int)decodeInt32(&a
[4]);
638 unsigned int x
= decodeInt32(&a
[8+4*i
]);
640 sprintf(zIdx
, "[%d]", i
);
641 printf(" %5s %7u", zIdx
, x
);
642 if( i
%5==4 ) printf("\n");
644 if( i
%5!=0 ) printf("\n");
649 pgno
= (int)decodeInt32(&a
[0]);
656 ** A short text comment on the use of each page.
658 static char **zPageUse
;
661 ** Add a comment on the use of a page.
663 static void page_usage_msg(int pgno
, const char *zFormat
, ...){
667 va_start(ap
, zFormat
);
668 zMsg
= sqlite3_vmprintf(zFormat
, ap
);
670 if( pgno
<=0 || pgno
>mxPage
){
671 printf("ERROR: page %d out of range 1..%d: %s\n",
676 if( zPageUse
[pgno
]!=0 ){
677 printf("ERROR: page %d used multiple times:\n", pgno
);
678 printf("ERROR: previous: %s\n", zPageUse
[pgno
]);
679 printf("ERROR: current: %s\n", zMsg
);
680 sqlite3_free(zPageUse
[pgno
]);
682 zPageUse
[pgno
] = zMsg
;
686 ** Find overflow pages of a cell and describe their usage.
688 static void page_usage_cell(
689 unsigned char cType
, /* Page type */
690 unsigned char *a
, /* Cell content */
691 int pgno
, /* page containing the cell */
692 int cellno
/* Index of the cell on the page */
705 i
= decodeVarint(a
, &nPayload
);
708 nLocal
= localPayload(nPayload
, cType
);
710 nPayload
= nLocal
= 0;
712 if( cType
==5 || cType
==13 ){
713 i
= decodeVarint(a
, &rowid
);
717 if( nLocal
<nPayload
){
718 int ovfl
= decodeInt32(a
+nLocal
);
720 while( ovfl
&& (cnt
++)<mxPage
){
721 page_usage_msg(ovfl
, "overflow %d from cell %d of page %d",
723 a
= getContent((ovfl
-1)*pagesize
, 4);
724 ovfl
= decodeInt32(a
);
732 ** Describe the usages of a b-tree page
734 static void page_usage_btree(
735 int pgno
, /* Page to describe */
736 int parent
, /* Parent of this page. 0 for root pages */
737 int idx
, /* Which child of the parent */
738 const char *zName
/* Name of the table */
741 const char *zType
= "corrupt node";
744 int hdr
= pgno
==1 ? 100 : 0;
746 if( pgno
<=0 || pgno
>mxPage
) return;
747 a
= getContent((pgno
-1)*pagesize
, pagesize
);
749 case 2: zType
= "interior node of index"; break;
750 case 5: zType
= "interior node of table"; break;
751 case 10: zType
= "leaf of index"; break;
752 case 13: zType
= "leaf of table"; break;
755 page_usage_msg(pgno
, "%s [%s], child %d of page %d",
756 zType
, zName
, idx
, parent
);
758 page_usage_msg(pgno
, "root %s [%s]", zType
, zName
);
760 nCell
= a
[hdr
+3]*256 + a
[hdr
+4];
761 if( a
[hdr
]==2 || a
[hdr
]==5 ){
762 int cellstart
= hdr
+12;
764 for(i
=0; i
<nCell
; i
++){
767 ofst
= cellstart
+ i
*2;
768 ofst
= a
[ofst
]*256 + a
[ofst
+1];
769 child
= decodeInt32(a
+ofst
);
770 page_usage_btree(child
, pgno
, i
, zName
);
772 child
= decodeInt32(a
+cellstart
-4);
773 page_usage_btree(child
, pgno
, i
, zName
);
775 if( a
[hdr
]==2 || a
[hdr
]==10 || a
[hdr
]==13 ){
776 int cellstart
= hdr
+ 8 + 4*(a
[hdr
]<=5);
777 for(i
=0; i
<nCell
; i
++){
779 ofst
= cellstart
+ i
*2;
780 ofst
= a
[ofst
]*256 + a
[ofst
+1];
781 page_usage_cell(a
[hdr
], a
+ofst
, pgno
, i
);
788 ** Determine page usage by the freelist
790 static void page_usage_freelist(int pgno
){
798 while( pgno
>0 && pgno
<=mxPage
&& (cnt
++)<mxPage
){
799 page_usage_msg(pgno
, "freelist trunk #%d child of %d", cnt
, parent
);
800 a
= getContent((pgno
-1)*pagesize
, pagesize
);
801 iNext
= decodeInt32(a
);
802 n
= decodeInt32(a
+4);
804 int child
= decodeInt32(a
+ (i
*4+8));
805 page_usage_msg(child
, "freelist leaf, child %d of trunk page %d",
815 ** Determine pages used as PTRMAP pages
817 static void page_usage_ptrmap(unsigned char *a
){
819 int usable
= pagesize
- a
[20];
821 int perPage
= usable
/5;
822 while( pgno
<=mxPage
){
823 page_usage_msg(pgno
, "PTRMAP page covering %d..%d",
824 pgno
+1, pgno
+perPage
);
831 ** Try to figure out how every page in the database file is being used.
833 static void page_usage_report(const char *zDbName
){
841 /* Avoid the pathological case */
843 printf("empty database\n");
847 /* Open the database file */
848 rc
= sqlite3_open(zDbName
, &db
);
850 printf("cannot open database: %s\n", sqlite3_errmsg(db
));
855 /* Set up global variables zPageUse[] and mxPage to record page
857 zPageUse
= sqlite3_malloc( sizeof(zPageUse
[0])*(mxPage
+1) );
858 if( zPageUse
==0 ) out_of_memory();
859 memset(zPageUse
, 0, sizeof(zPageUse
[0])*(mxPage
+1));
861 /* Discover the usage of each page */
862 a
= getContent(0, 100);
863 page_usage_freelist(decodeInt32(a
+32));
864 page_usage_ptrmap(a
);
866 page_usage_btree(1, 0, 0, "sqlite_master");
867 sqlite3_exec(db
, "PRAGMA writable_schema=ON", 0, 0, 0);
869 sqlite3_snprintf(sizeof(zQuery
), zQuery
,
870 "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage"
871 " ORDER BY rowid %s", j
?"DESC":"");
872 rc
= sqlite3_prepare_v2(db
, zQuery
, -1, &pStmt
, 0);
874 while( sqlite3_step(pStmt
)==SQLITE_ROW
){
875 int pgno
= sqlite3_column_int(pStmt
, 2);
876 page_usage_btree(pgno
, 0, 0, (const char*)sqlite3_column_text(pStmt
,1));
879 printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db
));
881 rc
= sqlite3_finalize(pStmt
);
882 if( rc
==SQLITE_OK
) break;
886 /* Print the report and free memory used */
887 for(i
=1; i
<=mxPage
; i
++){
888 printf("%5d: %s\n", i
, zPageUse
[i
] ? zPageUse
[i
] : "???");
889 sqlite3_free(zPageUse
[i
]);
891 sqlite3_free(zPageUse
);
896 ** Try to figure out how every page in the database file is being used.
898 static void ptrmap_coverage_report(const char *zDbName
){
906 /* Avoid the pathological case */
908 printf("empty database\n");
912 /* Make sure PTRMAPs are used in this database */
913 aHdr
= getContent(0, 100);
915 printf("database does not use PTRMAP pages\n");
918 usable
= pagesize
- aHdr
[20];
921 printf("%5d: root of sqlite_master\n", 1);
922 for(pgno
=2; pgno
<=mxPage
; pgno
+= perPage
+1){
923 printf("%5d: PTRMAP page covering %d..%d\n", pgno
,
924 pgno
+1, pgno
+perPage
);
925 a
= getContent((pgno
-1)*pagesize
, usable
);
926 for(i
=0; i
+5<=usable
&& pgno
+1+i
/5<=mxPage
; i
+=5){
927 const char *zType
= "???";
928 unsigned int iFrom
= decodeInt32(&a
[i
+1]);
930 case 1: zType
= "b-tree root page"; break;
931 case 2: zType
= "freelist page"; break;
932 case 3: zType
= "first page of overflow"; break;
933 case 4: zType
= "later page of overflow"; break;
934 case 5: zType
= "b-tree non-root page"; break;
936 printf("%5d: %s, parent=%u\n", pgno
+1+i
/5, zType
, iFrom
);
943 ** Print a usage comment
945 static void usage(const char *argv0
){
946 fprintf(stderr
, "Usage %s FILENAME ?args...?\n\n", argv0
);
949 " dbheader Show database header\n"
950 " pgidx Index of how each page is used\n"
951 " ptrmap Show all PTRMAP page content\n"
952 " NNN..MMM Show hex of pages NNN through MMM\n"
953 " NNN..end Show hex of pages NNN through end of file\n"
954 " NNNb Decode btree page NNN\n"
955 " NNNbc Decode btree page NNN and show content\n"
956 " NNNbm Decode btree page NNN and show a layout map\n"
957 " NNNbdCCC Decode cell CCC on btree page NNN\n"
958 " NNNt Decode freelist trunk page NNN\n"
959 " NNNtd Show leaf freelist pages on the decode\n"
960 " NNNtr Recursively decode freelist starting at NNN\n"
964 int main(int argc
, char **argv
){
966 unsigned char zPgSz
[2];
971 db
= open(argv
[1], O_RDONLY
);
973 fprintf(stderr
,"%s: can't open %s\n", argv
[0], argv
[1]);
978 lseek(db
, 16, SEEK_SET
);
979 if( read(db
, zPgSz
, 2)<2 ) memset(zPgSz
, 0, 2);
980 pagesize
= zPgSz
[0]*256 + zPgSz
[1]*65536;
981 if( pagesize
==0 ) pagesize
= 1024;
982 printf("Pagesize: %d\n", pagesize
);
984 mxPage
= sbuf
.st_size
/pagesize
;
985 printf("Available pages: 1..%d\n", mxPage
);
988 for(i
=1; i
<=mxPage
; i
++) print_page(i
);
991 for(i
=2; i
<argc
; i
++){
994 if( strcmp(argv
[i
], "dbheader")==0 ){
998 if( strcmp(argv
[i
], "pgidx")==0 ){
999 page_usage_report(argv
[1]);
1002 if( strcmp(argv
[i
], "ptrmap")==0 ){
1003 ptrmap_coverage_report(argv
[1]);
1006 if( strcmp(argv
[i
], "help")==0 ){
1010 if( !isdigit(argv
[i
][0]) ){
1011 fprintf(stderr
, "%s: unknown option: [%s]\n", argv
[0], argv
[i
]);
1014 iStart
= strtol(argv
[i
], &zLeft
, 0);
1015 if( zLeft
&& strcmp(zLeft
,"..end")==0 ){
1017 }else if( zLeft
&& zLeft
[0]=='.' && zLeft
[1]=='.' ){
1018 iEnd
= strtol(&zLeft
[2], 0, 0);
1019 }else if( zLeft
&& zLeft
[0]=='b' ){
1020 int ofst
, nByte
, hdrSize
;
1023 ofst
= hdrSize
= 100;
1024 nByte
= pagesize
-100;
1027 ofst
= (iStart
-1)*pagesize
;
1030 a
= getContent(ofst
, nByte
);
1031 decode_btree_page(a
, iStart
, hdrSize
, &zLeft
[1]);
1034 }else if( zLeft
&& zLeft
[0]=='t' ){
1038 for(i
=1; zLeft
[i
]; i
++){
1039 if( zLeft
[i
]=='r' ) recursive
= 1;
1040 if( zLeft
[i
]=='d' ) detail
= 1;
1042 decode_trunk_page(iStart
, pagesize
, detail
, recursive
);
1047 if( iStart
<1 || iEnd
<iStart
|| iEnd
>mxPage
){
1049 "Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
1053 while( iStart
<=iEnd
){