2 ** A utility for printing all or part of an SQLite database file.
6 #define ISDIGIT(X) isdigit((unsigned char)(X))
7 #define ISPRINT(X) isprint((unsigned char)(X))
12 #if !defined(_MSC_VER)
23 typedef unsigned char u8
; /* unsigned 8-bit */
24 typedef unsigned int u32
; /* unsigned 32-bit */
25 typedef sqlite3_int64 i64
; /* signed 64-bit */
26 typedef sqlite3_uint64 u64
; /* unsigned 64-bit */
29 static struct GlobalData
{
30 u32 pagesize
; /* Size of a database page */
31 int dbfd
; /* File descriptor for reading the DB */
32 u32 mxPage
; /* Last page number */
33 int perLine
; /* HEX elements to print per line */
34 int bRaw
; /* True to access db file via OS APIs */
35 sqlite3_file
*pFd
; /* File descriptor for non-raw mode */
36 sqlite3
*pDb
; /* Database handle that owns pFd */
37 } g
= {1024, -1, 0, 16, 0, 0, 0};
40 ** Convert the var-int format into i64. Return the number of bytes
41 ** in the var-int. Write the var-int value into *pVal.
43 static int decodeVarint(const unsigned char *z
, i64
*pVal
){
47 v
= (v
<<7) + (z
[i
]&0x7f);
48 if( (z
[i
]&0x80)==0 ){ *pVal
= v
; return i
+1; }
50 v
= (v
<<8) + (z
[i
]&0xff);
56 ** Extract a big-endian 32-bit integer
58 static u32
decodeInt32(const u8
*z
){
59 return (z
[0]<<24) + (z
[1]<<16) + (z
[2]<<8) + z
[3];
62 /* Report an out-of-memory error and die.
64 static void out_of_memory(void){
65 fprintf(stderr
,"Out of memory...\n");
70 ** Open a database connection.
72 static sqlite3
*openDatabase(const char *zPrg
, const char *zName
){
74 int flags
= SQLITE_OPEN_READWRITE
| SQLITE_OPEN_URI
;
75 int rc
= sqlite3_open_v2(zName
, &db
, flags
, 0);
77 const char *zErr
= sqlite3_errmsg(db
);
78 fprintf(stderr
, "%s: can't open %s (%s)\n", zPrg
, zName
, zErr
);
85 /**************************************************************************
86 ** Beginning of low-level file access functions.
88 ** All low-level access to the database file read by this program is
89 ** performed using the following four functions:
91 ** fileOpen() - open the db file
92 ** fileClose() - close the db file
93 ** fileRead() - read raw data from the db file
94 ** fileGetsize() - return the size of the db file in bytes
98 ** Open the database file.
100 static void fileOpen(const char *zPrg
, const char *zName
){
104 void *pArg
= (void *)(&g
.pFd
);
105 g
.pDb
= openDatabase(zPrg
, zName
);
106 rc
= sqlite3_file_control(g
.pDb
, "main", SQLITE_FCNTL_FILE_POINTER
, pArg
);
109 "%s: failed to obtain fd for %s (SQLite too old?)\n", zPrg
, zName
114 g
.dbfd
= open(zName
, O_RDONLY
);
116 fprintf(stderr
,"%s: can't open %s\n", zPrg
, zName
);
123 ** Close the database file opened by fileOpen()
125 static void fileClose(){
127 sqlite3_close(g
.pDb
);
137 ** Read content from the file.
139 ** Space to hold the content is obtained from sqlite3_malloc() and needs
140 ** to be freed by the caller.
142 static unsigned char *fileRead(sqlite3_int64 ofst
, int nByte
){
143 unsigned char *aData
;
145 aData
= sqlite3_malloc64(32+(i64
)nByte
);
146 if( aData
==0 ) out_of_memory();
147 memset(aData
, 0, nByte
+32);
149 int rc
= g
.pFd
->pMethods
->xRead(g
.pFd
, (void*)aData
, nByte
, ofst
);
150 if( rc
!=SQLITE_OK
&& rc
!=SQLITE_IOERR_SHORT_READ
){
151 fprintf(stderr
, "error in xRead() - %d\n", rc
);
155 lseek(g
.dbfd
, (long)ofst
, SEEK_SET
);
156 got
= read(g
.dbfd
, aData
, nByte
);
157 if( got
>0 && got
<nByte
) memset(aData
+got
, 0, nByte
-got
);
163 ** Return the size of the file in byte.
165 static i64
fileGetsize(void){
168 int rc
= g
.pFd
->pMethods
->xFileSize(g
.pFd
, &res
);
170 fprintf(stderr
, "error in xFileSize() - %d\n", rc
);
175 fstat(g
.dbfd
, &sbuf
);
176 res
= (sqlite3_int64
)(sbuf
.st_size
);
182 ** End of low-level file access functions.
183 **************************************************************************/
186 ** Print a range of bytes as hex and as ascii.
188 static unsigned char *print_byte_range(
189 sqlite3_int64 ofst
, /* First byte in the range of bytes to print */
190 int nByte
, /* Number of bytes to print */
191 int printOfst
/* Add this amount to the index on the left column */
193 unsigned char *aData
;
195 const char *zOfstFmt
;
197 if( ((printOfst
+nByte
)&~0xfff)==0 ){
198 zOfstFmt
= " %03x: ";
199 }else if( ((printOfst
+nByte
)&~0xffff)==0 ){
200 zOfstFmt
= " %04x: ";
201 }else if( ((printOfst
+nByte
)&~0xfffff)==0 ){
202 zOfstFmt
= " %05x: ";
203 }else if( ((printOfst
+nByte
)&~0xffffff)==0 ){
204 zOfstFmt
= " %06x: ";
206 zOfstFmt
= " %08x: ";
209 aData
= fileRead(ofst
, nByte
);
210 for(i
=0; i
<nByte
; i
+= g
.perLine
){
212 for(j
=0; j
<g
.perLine
; j
++){
213 if( i
+j
>nByte
){ break; }
214 if( aData
[i
+j
] ){ go
= 1; break; }
216 if( !go
&& i
>0 && i
+g
.perLine
<nByte
) continue;
217 fprintf(stdout
, zOfstFmt
, i
+printOfst
);
218 for(j
=0; j
<g
.perLine
; j
++){
220 fprintf(stdout
, " ");
222 fprintf(stdout
,"%02x ", aData
[i
+j
]);
225 for(j
=0; j
<g
.perLine
; j
++){
227 fprintf(stdout
, " ");
229 fprintf(stdout
,"%c", ISPRINT(aData
[i
+j
]) ? aData
[i
+j
] : '.');
232 fprintf(stdout
,"\n");
238 ** Print an entire page of content as hex
240 static void print_page(u32 iPg
){
242 unsigned char *aData
;
243 iStart
= ((i64
)(iPg
-1))*g
.pagesize
;
244 fprintf(stdout
, "Page %u: (offsets 0x%llx..0x%llx)\n",
245 iPg
, iStart
, iStart
+g
.pagesize
-1);
246 aData
= print_byte_range(iStart
, g
.pagesize
, 0);
251 /* Print a line of decoded output showing a 4-byte unsigned integer.
253 static void print_decode_line(
254 unsigned char *aData
, /* Content being decoded */
255 int ofst
, int nByte
, /* Start and size of decode */
256 const char *zMsg
/* Message to append */
259 u32 val
= aData
[ofst
];
261 sprintf(zBuf
, " %03x: %02x", ofst
, aData
[ofst
]);
262 i
= (int)strlen(zBuf
);
265 sprintf(&zBuf
[i
], " ");
267 sprintf(&zBuf
[i
], " %02x", aData
[ofst
+j
]);
268 val
= val
*256 + aData
[ofst
+j
];
270 i
+= (int)strlen(&zBuf
[i
]);
272 sprintf(&zBuf
[i
], " %10u", val
);
273 printf("%s %s\n", zBuf
, zMsg
);
277 ** Decode the database header.
279 static void print_db_header(void){
280 unsigned char *aData
;
281 aData
= print_byte_range(0, 100, 0);
282 printf("Decoded:\n");
283 print_decode_line(aData
, 16, 2, "Database page size");
284 print_decode_line(aData
, 18, 1, "File format write version");
285 print_decode_line(aData
, 19, 1, "File format read version");
286 print_decode_line(aData
, 20, 1, "Reserved space at end of page");
287 print_decode_line(aData
, 24, 4, "File change counter");
288 print_decode_line(aData
, 28, 4, "Size of database in pages");
289 print_decode_line(aData
, 32, 4, "Page number of first freelist page");
290 print_decode_line(aData
, 36, 4, "Number of freelist pages");
291 print_decode_line(aData
, 40, 4, "Schema cookie");
292 print_decode_line(aData
, 44, 4, "Schema format version");
293 print_decode_line(aData
, 48, 4, "Default page cache size");
294 print_decode_line(aData
, 52, 4, "Largest auto-vac root page");
295 print_decode_line(aData
, 56, 4, "Text encoding");
296 print_decode_line(aData
, 60, 4, "User version");
297 print_decode_line(aData
, 64, 4, "Incremental-vacuum mode");
298 print_decode_line(aData
, 68, 4, "Application ID");
299 print_decode_line(aData
, 72, 4, "meta[8]");
300 print_decode_line(aData
, 76, 4, "meta[9]");
301 print_decode_line(aData
, 80, 4, "meta[10]");
302 print_decode_line(aData
, 84, 4, "meta[11]");
303 print_decode_line(aData
, 88, 4, "meta[12]");
304 print_decode_line(aData
, 92, 4, "Change counter for version number");
305 print_decode_line(aData
, 96, 4, "SQLite version number");
310 ** Describe cell content.
312 static i64
describeContent(
313 unsigned char *a
, /* Cell content */
314 i64 nLocal
, /* Bytes in a[] */
315 char *zDesc
/* Write description here */
320 const unsigned char *pData
;
321 const unsigned char *pLimit
;
325 n
= decodeVarint(a
, &x
);
329 while( i
>0 && pData
<=pLimit
){
330 n
= decodeVarint(a
, &x
);
339 sprintf(zDesc
, "*"); /* NULL is a "*" */
340 }else if( x
>=1 && x
<=6 ){
341 v
= (signed char)pData
[0];
344 case 6: v
= (v
<<16) + (pData
[0]<<8) + pData
[1]; pData
+= 2;
345 case 5: v
= (v
<<16) + (pData
[0]<<8) + pData
[1]; pData
+= 2;
346 case 4: v
= (v
<<8) + pData
[0]; pData
++;
347 case 3: v
= (v
<<8) + pData
[0]; pData
++;
348 case 2: v
= (v
<<8) + pData
[0]; pData
++;
350 sprintf(zDesc
, "%lld", v
);
352 sprintf(zDesc
, "real");
361 sprintf(zDesc
, "blob(%lld)", size
);
363 sprintf(zDesc
, "txt(%lld)", size
);
367 j
= (int)strlen(zDesc
);
375 ** Compute the local payload size given the total payload size and
378 static i64
localPayload(i64 nPayload
, char cType
){
385 maxLocal
= g
.pagesize
-35;
386 minLocal
= (g
.pagesize
-12)*32/255-23;
388 maxLocal
= (g
.pagesize
-12)*64/255-23;
389 minLocal
= (g
.pagesize
-12)*32/255-23;
391 if( nPayload
>maxLocal
){
392 surplus
= minLocal
+ (nPayload
-minLocal
)%(g
.pagesize
-4);
393 if( surplus
<=maxLocal
){
406 ** Create a description for a single cell.
408 ** The return value is the local cell size.
410 static i64
describeCell(
411 unsigned char cType
, /* Page type */
412 unsigned char *a
, /* Cell content */
413 int showCellContent
, /* Show cell content if true */
414 char **pzDesc
/* Store description here */
423 static char zDesc
[1000];
426 leftChild
= ((a
[0]*256 + a
[1])*256 + a
[2])*256 + a
[3];
429 sprintf(zDesc
, "lx: %u ", leftChild
);
430 nDesc
= strlen(zDesc
);
433 i
= decodeVarint(a
, &nPayload
);
436 sprintf(&zDesc
[nDesc
], "n: %lld ", nPayload
);
437 nDesc
+= strlen(&zDesc
[nDesc
]);
438 nLocal
= localPayload(nPayload
, cType
);
440 nPayload
= nLocal
= 0;
442 if( cType
==5 || cType
==13 ){
443 i
= decodeVarint(a
, &rowid
);
446 sprintf(&zDesc
[nDesc
], "r: %lld ", rowid
);
447 nDesc
+= strlen(&zDesc
[nDesc
]);
449 if( nLocal
<nPayload
){
451 unsigned char *b
= &a
[nLocal
];
452 ovfl
= ((b
[0]*256 + b
[1])*256 + b
[2])*256 + b
[3];
453 sprintf(&zDesc
[nDesc
], "ov: %u ", ovfl
);
454 nDesc
+= strlen(&zDesc
[nDesc
]);
457 if( showCellContent
&& cType
!=5 ){
458 nDesc
+= describeContent(a
, nLocal
, &zDesc
[nDesc
-1]);
464 /* Print an offset followed by nByte bytes. Add extra white-space
465 ** at the end so that subsequent text is aligned.
467 static void printBytes(
468 unsigned char *aData
, /* Content being decoded */
469 unsigned char *aStart
, /* Start of content to be printed */
470 int nByte
/* Number of bytes to print */
473 printf(" %03x: ", (int)(aStart
-aData
));
478 printf("%02x ", aStart
[j
]);
485 ** Write a full decode on stdout for the cell at a[ofst].
486 ** Assume the page contains a header of size szPgHdr bytes.
488 static void decodeCell(
489 unsigned char *a
, /* Page content (without the page-1 header) */
490 unsigned pgno
, /* Page number */
491 int iCell
, /* Cell index */
492 int szPgHdr
, /* Size of the page header. 0 or 100 */
493 int ofst
/* Cell begins at a[ofst] */
503 unsigned char *x
= a
+ ofst
;
505 unsigned char cType
= a
[0];
511 printf("Cell[%d]:\n", iCell
);
513 leftChild
= ((x
[0]*256 + x
[1])*256 + x
[2])*256 + x
[3];
515 printf("left child page:: %u\n", leftChild
);
519 i
= decodeVarint(x
, &nPayload
);
521 nLocal
= localPayload(nPayload
, cType
);
522 if( nLocal
==nPayload
){
523 printf("payload-size: %lld\n", nPayload
);
525 printf("payload-size: %lld (%lld local, %lld overflow)\n",
526 nPayload
, nLocal
, nPayload
-nLocal
);
530 nPayload
= nLocal
= 0;
533 if( cType
==5 || cType
==13 ){
534 i
= decodeVarint(x
, &rowid
);
536 printf("rowid: %lld\n", rowid
);
540 i
= decodeVarint(x
, &nHdr
);
542 printf("record-header-size: %d\n", (int)nHdr
);
546 while( x
+j
<=end
&& j
<nHdr
){
547 const char *zTypeName
;
550 i
= decodeVarint(x
+j
, &iType
);
551 printBytes(a
, x
+j
, i
);
552 printf("typecode[%d]: %d - ", nCol
, (int)iType
);
554 case 0: zTypeName
= "NULL"; sz
= 0; break;
555 case 1: zTypeName
= "int8"; sz
= 1; break;
556 case 2: zTypeName
= "int16"; sz
= 2; break;
557 case 3: zTypeName
= "int24"; sz
= 3; break;
558 case 4: zTypeName
= "int32"; sz
= 4; break;
559 case 5: zTypeName
= "int48"; sz
= 6; break;
560 case 6: zTypeName
= "int64"; sz
= 8; break;
561 case 7: zTypeName
= "double"; sz
= 8; break;
562 case 8: zTypeName
= "zero"; sz
= 0; break;
563 case 9: zTypeName
= "one"; sz
= 0; break;
565 case 11: zTypeName
= "error"; sz
= 0; break;
567 sz
= (int)(iType
-12)/2;
568 sprintf(zNm
, (iType
&1)==0 ? "blob(%d)" : "text(%d)", sz
);
573 printf("%s\n", zTypeName
);
575 ofstCol
[nCol
] = (int)k
;
576 typeCol
[nCol
] = (int)iType
;
581 for(i
=0; i
<nCol
&& ofstCol
[i
]+szCol
[i
]<=nLocal
; i
++){
584 const unsigned char *pData
;
585 if( szCol
[i
]==0 ) continue;
586 printBytes(a
, x
+s
, szCol
[i
]);
587 printf("data[%d]: ", i
);
590 v
= (signed char)pData
[0];
591 for(k
=1; k
<szCol
[i
]; k
++){
592 v
= (v
<<8) + pData
[k
];
596 memcpy(&r
, &v
, sizeof(r
));
604 if( (typeCol
[i
]&1)==0 ){
607 for(ii
=2, jj
=0; jj
<szCol
[i
] && ii
<24; jj
++, ii
+=2){
608 sprintf(zConst
+ii
, "%02x", pData
[jj
]);
612 for(ii
=1, jj
=0; jj
<szCol
[i
] && ii
<24; jj
++, ii
++){
613 zConst
[ii
] = ISPRINT(pData
[jj
]) ? pData
[jj
] : '.';
618 memcpy(zConst
+ii
, "...'", 5);
620 memcpy(zConst
+ii
, "'", 2);
622 printf("%s\n", zConst
);
624 j
= ofstCol
[i
] + szCol
[i
];
628 printBytes(a
, x
+j
, 0);
629 printf("... %lld bytes of content ...\n", nLocal
-j
);
631 if( nLocal
<nPayload
){
632 printBytes(a
, x
+nLocal
, 4);
633 printf("overflow-page: %u\n", decodeInt32(x
+nLocal
));
639 ** Decode a btree page
641 static void decode_btree_page(
642 unsigned char *a
, /* Page content */
643 int pgno
, /* Page number */
644 int hdrSize
, /* Size of the page header. 0 or 100 */
645 char *zArgs
/* Flags to control formatting */
647 const char *zType
= "unknown";
651 int showCellContent
= 0;
653 int cellToDecode
= -2;
656 case 2: zType
= "index interior node"; break;
657 case 5: zType
= "table interior node"; break;
658 case 10: zType
= "index leaf"; break;
659 case 13: zType
= "table leaf"; break;
663 case 'c': showCellContent
= 1; break;
664 case 'm': showMap
= 1; break;
666 if( !ISDIGIT(zArgs
[1]) ){
670 while( ISDIGIT(zArgs
[1]) ){
672 cellToDecode
= cellToDecode
*10 + zArgs
[0] - '0';
680 nCell
= a
[3]*256 + a
[4];
681 iCellPtr
= (a
[0]==2 || a
[0]==5) ? 12 : 8;
682 if( cellToDecode
>=nCell
){
683 printf("Page %d has only %d cells\n", pgno
, nCell
);
686 printf("Header on btree page %d:\n", pgno
);
687 print_decode_line(a
, 0, 1, zType
);
688 print_decode_line(a
, 1, 2, "Offset to first freeblock");
689 print_decode_line(a
, 3, 2, "Number of cells on this page");
690 print_decode_line(a
, 5, 2, "Offset to cell content area");
691 print_decode_line(a
, 7, 1, "Fragmented byte count");
692 if( a
[0]==2 || a
[0]==5 ){
693 print_decode_line(a
, 8, 4, "Right child");
695 if( cellToDecode
==(-2) && nCell
>0 ){
696 printf(" key: lx=left-child n=payload-size r=rowid\n");
699 zMap
= sqlite3_malloc(g
.pagesize
);
700 memset(zMap
, '.', g
.pagesize
);
701 memset(zMap
, '1', hdrSize
);
702 memset(&zMap
[hdrSize
], 'H', iCellPtr
);
703 memset(&zMap
[hdrSize
+iCellPtr
], 'P', 2*nCell
);
705 for(i
=0; i
<nCell
; i
++){
706 int cofst
= iCellPtr
+ i
*2;
710 cofst
= a
[cofst
]*256 + a
[cofst
+1];
711 n
= describeCell(a
[0], &a
[cofst
-hdrSize
], showCellContent
, &zDesc
);
714 memset(&zMap
[cofst
], '*', (size_t)n
);
716 zMap
[cofst
+n
-1] = ']';
717 sprintf(zBuf
, "%d", i
);
718 j
= (int)strlen(zBuf
);
719 if( j
<=n
-2 ) memcpy(&zMap
[cofst
+1], zBuf
, j
);
721 if( cellToDecode
==(-2) ){
722 printf(" %03x: cell[%d] %s\n", cofst
, i
, zDesc
);
723 }else if( cellToDecode
==(-1) || cellToDecode
==i
){
724 decodeCell(a
, pgno
, i
, hdrSize
, cofst
-hdrSize
);
728 printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n");
729 for(i
=0; (u32
)i
<g
.pagesize
; i
+=64){
730 printf(" %03x: %.64s\n", i
, &zMap
[i
]);
737 ** Decode a freelist trunk page.
739 static void decode_trunk_page(
740 u32 pgno
, /* The page number */
741 int detail
, /* Show leaf pages if true */
742 int recursive
/* Follow the trunk change if true */
748 a
= fileRead((pgno
-1)*g
.pagesize
, g
.pagesize
);
749 printf("Decode of freelist trunk page %d:\n", pgno
);
750 print_decode_line(a
, 0, 4, "Next freelist trunk page");
751 print_decode_line(a
, 4, 4, "Number of entries on this page");
753 n
= decodeInt32(&a
[4]);
754 for(i
=0; i
<n
&& i
<g
.pagesize
/4; i
++){
755 u32 x
= decodeInt32(&a
[8+4*i
]);
757 sprintf(zIdx
, "[%d]", i
);
758 printf(" %5s %7u", zIdx
, x
);
759 if( i
%5==4 ) printf("\n");
761 if( i
%5!=0 ) printf("\n");
766 pgno
= decodeInt32(&a
[0]);
773 ** A short text comment on the use of each page.
775 static char **zPageUse
;
778 ** Add a comment on the use of a page.
780 static void page_usage_msg(u32 pgno
, const char *zFormat
, ...){
784 va_start(ap
, zFormat
);
785 zMsg
= sqlite3_vmprintf(zFormat
, ap
);
787 if( pgno
<=0 || pgno
>g
.mxPage
){
788 printf("ERROR: page %d out of range 1..%u: %s\n",
789 pgno
, g
.mxPage
, zMsg
);
793 if( zPageUse
[pgno
]!=0 ){
794 printf("ERROR: page %d used multiple times:\n", pgno
);
795 printf("ERROR: previous: %s\n", zPageUse
[pgno
]);
796 printf("ERROR: current: %s\n", zMsg
);
797 sqlite3_free(zPageUse
[pgno
]);
799 zPageUse
[pgno
] = zMsg
;
803 ** Find overflow pages of a cell and describe their usage.
805 static void page_usage_cell(
806 unsigned char cType
, /* Page type */
807 unsigned char *a
, /* Cell content */
808 u32 pgno
, /* page containing the cell */
809 int cellno
/* Index of the cell on the page */
822 i
= decodeVarint(a
, &nPayload
);
825 nLocal
= localPayload(nPayload
, cType
);
827 nPayload
= nLocal
= 0;
829 if( cType
==5 || cType
==13 ){
830 i
= decodeVarint(a
, &rowid
);
834 if( nLocal
<nPayload
){
835 u32 ovfl
= decodeInt32(a
+nLocal
);
837 while( ovfl
&& (cnt
++)<g
.mxPage
){
838 page_usage_msg(ovfl
, "overflow %d from cell %d of page %u",
840 a
= fileRead((ovfl
-1)*(sqlite3_int64
)g
.pagesize
, 4);
841 ovfl
= decodeInt32(a
);
848 ** True if the memory is all zeros
850 static int allZero(unsigned char *a
, int n
){
851 while( n
&& (a
++)[0]==0 ){ n
--; }
857 ** Describe the usages of a b-tree page.
859 ** If parent==0, then this is the root of a btree. If parent<0 then
860 ** this is an orphan page.
862 static void page_usage_btree(
863 u32 pgno
, /* Page to describe */
864 int parent
, /* Parent of this page. 0 for root pages */
865 int idx
, /* Which child of the parent */
866 const char *zName
/* Name of the table */
869 const char *zType
= "corrupt node";
872 int hdr
= pgno
==1 ? 100 : 0;
875 if( pgno
<=0 || pgno
>g
.mxPage
) return;
876 a
= fileRead((pgno
-1)*g
.pagesize
, g
.pagesize
);
879 if( allZero(a
, g
.pagesize
) ){
880 zType
= "zeroed page";
881 }else if( parent
<0 ){
884 zType
= "corrupt node";
888 case 2: zType
= "interior node of index"; break;
889 case 5: zType
= "interior node of table"; break;
890 case 10: zType
= "leaf of index"; break;
891 case 13: zType
= "leaf of table"; break;
893 if( parent
<0 ) return;
894 zType
= "corrupt node";
897 nCell
= a
[hdr
+3]*256 + a
[hdr
+4];
899 sqlite3_snprintf(sizeof(zEntry
),zEntry
,"1 row");
901 sqlite3_snprintf(sizeof(zEntry
),zEntry
,"%d rows", nCell
);
904 page_usage_msg(pgno
, "%s [%s], child %d of page %d, %s",
905 zType
, zName
, idx
, parent
, zEntry
);
906 }else if( parent
==0 ){
907 page_usage_msg(pgno
, "root %s [%s], %s", zType
, zName
, zEntry
);
909 page_usage_msg(pgno
, "orphaned %s, %s", zType
, zEntry
);
911 if( a
[hdr
]==2 || a
[hdr
]==5 ){
912 int cellstart
= hdr
+12;
914 for(i
=0; i
<nCell
; i
++){
918 cellidx
= cellstart
+ i
*2;
919 if( cellidx
+1 >= g
.pagesize
){
920 printf("ERROR: page %d too many cells (%d)\n", pgno
, nCell
);
923 ofst
= a
[cellidx
]*256 + a
[cellidx
+1];
924 if( ofst
<cellidx
+2 || ofst
+4>=g
.pagesize
){
925 printf("ERROR: page %d cell %d out of bounds\n", pgno
, i
);
928 child
= decodeInt32(a
+ofst
);
929 page_usage_btree(child
, pgno
, i
, zName
);
931 child
= decodeInt32(a
+cellstart
-4);
932 page_usage_btree(child
, pgno
, i
, zName
);
934 if( a
[hdr
]==2 || a
[hdr
]==10 || a
[hdr
]==13 ){
935 int cellstart
= hdr
+ 8 + 4*(a
[hdr
]<=5);
936 for(i
=0; i
<nCell
; i
++){
938 ofst
= cellstart
+ i
*2;
939 ofst
= a
[ofst
]*256 + a
[ofst
+1];
940 page_usage_cell(a
[hdr
], a
+ofst
, pgno
, i
);
947 ** Determine page usage by the freelist
949 static void page_usage_freelist(u32 pgno
){
957 while( pgno
>0 && pgno
<=g
.mxPage
&& (u32
)(cnt
++)<g
.mxPage
){
958 page_usage_msg(pgno
, "freelist trunk #%d child of %d", cnt
, parent
);
959 a
= fileRead((pgno
-1)*g
.pagesize
, g
.pagesize
);
960 iNext
= decodeInt32(a
);
961 n
= decodeInt32(a
+4);
962 if( n
>(g
.pagesize
- 8)/4 ){
963 printf("ERROR: page %d too many freelist entries (%d)\n", pgno
, n
);
964 n
= (g
.pagesize
- 8)/4;
967 int child
= decodeInt32(a
+ (i
*4+8));
968 page_usage_msg(child
, "freelist leaf, child %d of trunk page %d",
978 ** Determine pages used as PTRMAP pages
980 static void page_usage_ptrmap(u8
*a
){
981 if( decodeInt32(a
+52) ){
982 int usable
= g
.pagesize
- a
[20];
984 int perPage
= usable
/5;
985 while( pgno
<=g
.mxPage
){
986 page_usage_msg((u32
)pgno
, "PTRMAP page covering %llu..%llu",
987 pgno
+1, pgno
+perPage
);
994 ** Try to figure out how every page in the database file is being used.
996 static void page_usage_report(const char *zPrg
, const char *zDbName
){
1000 sqlite3_stmt
*pStmt
;
1004 /* Avoid the pathological case */
1006 printf("empty database\n");
1010 /* Open the database file */
1011 db
= openDatabase(zPrg
, zDbName
);
1013 /* Set up global variables zPageUse[] and g.mxPage to record page
1015 zPageUse
= sqlite3_malloc64( sizeof(zPageUse
[0])*(g
.mxPage
+1) );
1016 if( zPageUse
==0 ) out_of_memory();
1017 memset(zPageUse
, 0, sizeof(zPageUse
[0])*(g
.mxPage
+1));
1019 /* Discover the usage of each page */
1020 a
= fileRead(0, 100);
1021 page_usage_freelist(decodeInt32(a
+32));
1022 page_usage_ptrmap(a
);
1024 page_usage_btree(1, 0, 0, "sqlite_schema");
1025 sqlite3_exec(db
, "PRAGMA writable_schema=ON", 0, 0, 0);
1027 sqlite3_snprintf(sizeof(zQuery
), zQuery
,
1028 "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage"
1029 " ORDER BY rowid %s", j
?"DESC":"");
1030 rc
= sqlite3_prepare_v2(db
, zQuery
, -1, &pStmt
, 0);
1031 if( rc
==SQLITE_OK
){
1032 while( sqlite3_step(pStmt
)==SQLITE_ROW
){
1033 u32 pgno
= (u32
)sqlite3_column_int64(pStmt
, 2);
1034 page_usage_btree(pgno
, 0, 0, (const char*)sqlite3_column_text(pStmt
,1));
1037 printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db
));
1039 rc
= sqlite3_finalize(pStmt
);
1040 if( rc
==SQLITE_OK
) break;
1044 /* Print the report and free memory used */
1045 for(i
=1; i
<=g
.mxPage
; i
++){
1046 if( zPageUse
[i
]==0 ) page_usage_btree(i
, -1, 0, 0);
1047 printf("%5u: %s\n", i
, zPageUse
[i
] ? zPageUse
[i
] : "???");
1049 for(i
=1; i
<=g
.mxPage
; i
++){
1050 sqlite3_free(zPageUse
[i
]);
1052 sqlite3_free(zPageUse
);
1057 ** Try to figure out how every page in the database file is being used.
1059 static void ptrmap_coverage_report(const char *zDbName
){
1061 unsigned char *aHdr
;
1067 /* Avoid the pathological case */
1069 printf("empty database\n");
1073 /* Make sure PTRMAPs are used in this database */
1074 aHdr
= fileRead(0, 100);
1076 printf("database does not use PTRMAP pages\n");
1079 usable
= g
.pagesize
- aHdr
[20];
1082 printf("%5d: root of sqlite_schema\n", 1);
1083 for(pgno
=2; pgno
<=g
.mxPage
; pgno
+= perPage
+1){
1084 printf("%5llu: PTRMAP page covering %llu..%llu\n", pgno
,
1085 pgno
+1, pgno
+perPage
);
1086 a
= fileRead((pgno
-1)*g
.pagesize
, usable
);
1087 for(i
=0; i
+5<=usable
&& pgno
+1+i
/5<=g
.mxPage
; i
+=5){
1088 const char *zType
= "???";
1089 u32 iFrom
= decodeInt32(&a
[i
+1]);
1091 case 1: zType
= "b-tree root page"; break;
1092 case 2: zType
= "freelist page"; break;
1093 case 3: zType
= "first page of overflow"; break;
1094 case 4: zType
= "later page of overflow"; break;
1095 case 5: zType
= "b-tree non-root page"; break;
1097 printf("%5llu: %s, parent=%u\n", pgno
+1+i
/5, zType
, iFrom
);
1104 ** Check the range validity for a page number. Print an error and
1105 ** exit if the page is out of range.
1107 static void checkPageValidity(int iPage
){
1108 if( iPage
<1 || iPage
>g
.mxPage
){
1109 fprintf(stderr
, "Invalid page number %d: valid range is 1..%d\n",
1116 ** Print a usage comment
1118 static void usage(const char *argv0
){
1119 fprintf(stderr
, "Usage %s ?--uri? FILENAME ?args...?\n\n", argv0
);
1122 " --raw Read db file directly, bypassing SQLite VFS\n"
1124 " dbheader Show database header\n"
1125 " pgidx Index of how each page is used\n"
1126 " ptrmap Show all PTRMAP page content\n"
1127 " NNN..MMM Show hex of pages NNN through MMM\n"
1128 " NNN..end Show hex of pages NNN through end of file\n"
1129 " NNNb Decode btree page NNN\n"
1130 " NNNbc Decode btree page NNN and show content\n"
1131 " NNNbm Decode btree page NNN and show a layout map\n"
1132 " NNNbdCCC Decode cell CCC on btree page NNN\n"
1133 " NNNt Decode freelist trunk page NNN\n"
1134 " NNNtd Show leaf freelist pages on the decode\n"
1135 " NNNtr Recursively decode freelist starting at NNN\n"
1139 int main(int argc
, char **argv
){
1140 sqlite3_int64 szFile
;
1141 unsigned char *zPgSz
;
1142 const char *zPrg
= argv
[0]; /* Name of this executable */
1143 char **azArg
= argv
;
1146 /* Check for the "--uri" or "-uri" switch. */
1148 if( sqlite3_stricmp("-raw", azArg
[1])==0
1149 || sqlite3_stricmp("--raw", azArg
[1])==0
1162 fileOpen(zPrg
, azArg
[1]);
1163 szFile
= fileGetsize();
1165 zPgSz
= fileRead(16, 2);
1166 g
.pagesize
= zPgSz
[0]*256 + zPgSz
[1]*65536;
1167 if( g
.pagesize
==0 ) g
.pagesize
= 1024;
1168 sqlite3_free(zPgSz
);
1170 printf("Pagesize: %d\n", g
.pagesize
);
1171 g
.mxPage
= (u32
)((szFile
+g
.pagesize
-1)/g
.pagesize
);
1173 printf("Available pages: 1..%u\n", g
.mxPage
);
1176 for(i
=1; i
<=g
.mxPage
; i
++) print_page(i
);
1179 for(i
=2; i
<nArg
; i
++){
1182 if( strcmp(azArg
[i
], "dbheader")==0 ){
1186 if( strcmp(azArg
[i
], "pgidx")==0 ){
1187 page_usage_report(zPrg
, azArg
[1]);
1190 if( strcmp(azArg
[i
], "ptrmap")==0 ){
1191 ptrmap_coverage_report(azArg
[1]);
1194 if( strcmp(azArg
[i
], "help")==0 ){
1198 if( !ISDIGIT(azArg
[i
][0]) ){
1199 fprintf(stderr
, "%s: unknown option: [%s]\n", zPrg
, azArg
[i
]);
1202 iStart
= strtoul(azArg
[i
], &zLeft
, 0);
1203 checkPageValidity(iStart
);
1204 if( zLeft
&& strcmp(zLeft
,"..end")==0 ){
1206 }else if( zLeft
&& zLeft
[0]=='.' && zLeft
[1]=='.' ){
1207 iEnd
= strtol(&zLeft
[2], 0, 0);
1208 checkPageValidity(iEnd
);
1209 }else if( zLeft
&& zLeft
[0]=='b' ){
1210 int ofst
, nByte
, hdrSize
;
1213 ofst
= hdrSize
= 100;
1214 nByte
= g
.pagesize
-100;
1217 ofst
= (iStart
-1)*g
.pagesize
;
1220 a
= fileRead(ofst
, nByte
);
1221 decode_btree_page(a
, iStart
, hdrSize
, &zLeft
[1]);
1224 }else if( zLeft
&& zLeft
[0]=='t' ){
1228 for(j
=1; zLeft
[j
]; j
++){
1229 if( zLeft
[j
]=='r' ) recursive
= 1;
1230 if( zLeft
[j
]=='d' ) detail
= 1;
1232 decode_trunk_page(iStart
, detail
, recursive
);
1237 if( iStart
<1 || iEnd
<iStart
|| iEnd
>g
.mxPage
){
1239 "Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
1243 while( iStart
<=iEnd
){