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)
24 static struct GlobalData
{
25 int pagesize
; /* Size of a database page */
26 int dbfd
; /* File descriptor for reading the DB */
27 int mxPage
; /* Last page number */
28 int perLine
; /* HEX elements to print per line */
29 int bRaw
; /* True to access db file via OS APIs */
30 sqlite3_file
*pFd
; /* File descriptor for non-raw mode */
31 sqlite3
*pDb
; /* Database handle that owns pFd */
32 } g
= {1024, -1, 0, 16, 0, 0, 0};
35 typedef long long int i64
; /* Datatype for 64-bit integers */
39 ** Convert the var-int format into i64. Return the number of bytes
40 ** in the var-int. Write the var-int value into *pVal.
42 static int decodeVarint(const unsigned char *z
, i64
*pVal
){
46 v
= (v
<<7) + (z
[i
]&0x7f);
47 if( (z
[i
]&0x80)==0 ){ *pVal
= v
; return i
+1; }
49 v
= (v
<<8) + (z
[i
]&0xff);
55 ** Extract a big-endian 32-bit integer
57 static unsigned int decodeInt32(const unsigned char *z
){
58 return (z
[0]<<24) + (z
[1]<<16) + (z
[2]<<8) + z
[3];
61 /* Report an out-of-memory error and die.
63 static void out_of_memory(void){
64 fprintf(stderr
,"Out of memory...\n");
69 ** Open a database connection.
71 static sqlite3
*openDatabase(const char *zPrg
, const char *zName
){
73 int flags
= SQLITE_OPEN_READWRITE
| SQLITE_OPEN_URI
;
74 int rc
= sqlite3_open_v2(zName
, &db
, flags
, 0);
76 const char *zErr
= sqlite3_errmsg(db
);
77 fprintf(stderr
, "%s: can't open %s (%s)\n", zPrg
, zName
, zErr
);
84 /**************************************************************************
85 ** Beginning of low-level file access functions.
87 ** All low-level access to the database file read by this program is
88 ** performed using the following four functions:
90 ** fileOpen() - open the db file
91 ** fileClose() - close the db file
92 ** fileRead() - read raw data from the db file
93 ** fileGetsize() - return the size of the db file in bytes
97 ** Open the database file.
99 static void fileOpen(const char *zPrg
, const char *zName
){
103 void *pArg
= (void *)(&g
.pFd
);
104 g
.pDb
= openDatabase(zPrg
, zName
);
105 rc
= sqlite3_file_control(g
.pDb
, "main", SQLITE_FCNTL_FILE_POINTER
, pArg
);
108 "%s: failed to obtain fd for %s (SQLite too old?)\n", zPrg
, zName
113 g
.dbfd
= open(zName
, O_RDONLY
);
115 fprintf(stderr
,"%s: can't open %s\n", zPrg
, zName
);
122 ** Close the database file opened by fileOpen()
124 static void fileClose(){
126 sqlite3_close(g
.pDb
);
136 ** Read content from the file.
138 ** Space to hold the content is obtained from sqlite3_malloc() and needs
139 ** to be freed by the caller.
141 static unsigned char *fileRead(sqlite3_int64 ofst
, int nByte
){
142 unsigned char *aData
;
144 aData
= sqlite3_malloc(nByte
+32);
145 if( aData
==0 ) out_of_memory();
146 memset(aData
, 0, nByte
+32);
148 int rc
= g
.pFd
->pMethods
->xRead(g
.pFd
, (void*)aData
, nByte
, ofst
);
149 if( rc
!=SQLITE_OK
&& rc
!=SQLITE_IOERR_SHORT_READ
){
150 fprintf(stderr
, "error in xRead() - %d\n", rc
);
154 lseek(g
.dbfd
, (long)ofst
, SEEK_SET
);
155 got
= read(g
.dbfd
, aData
, nByte
);
156 if( got
>0 && got
<nByte
) memset(aData
+got
, 0, nByte
-got
);
162 ** Return the size of the file in byte.
164 static sqlite3_int64
fileGetsize(void){
165 sqlite3_int64 res
= 0;
167 int rc
= g
.pFd
->pMethods
->xFileSize(g
.pFd
, &res
);
169 fprintf(stderr
, "error in xFileSize() - %d\n", rc
);
174 fstat(g
.dbfd
, &sbuf
);
175 res
= (sqlite3_int64
)(sbuf
.st_size
);
181 ** End of low-level file access functions.
182 **************************************************************************/
185 ** Print a range of bytes as hex and as ascii.
187 static unsigned char *print_byte_range(
188 int ofst
, /* First byte in the range of bytes to print */
189 int nByte
, /* Number of bytes to print */
190 int printOfst
/* Add this amount to the index on the left column */
192 unsigned char *aData
;
194 const char *zOfstFmt
;
196 if( ((printOfst
+nByte
)&~0xfff)==0 ){
197 zOfstFmt
= " %03x: ";
198 }else if( ((printOfst
+nByte
)&~0xffff)==0 ){
199 zOfstFmt
= " %04x: ";
200 }else if( ((printOfst
+nByte
)&~0xfffff)==0 ){
201 zOfstFmt
= " %05x: ";
202 }else if( ((printOfst
+nByte
)&~0xffffff)==0 ){
203 zOfstFmt
= " %06x: ";
205 zOfstFmt
= " %08x: ";
208 aData
= fileRead(ofst
, nByte
);
209 for(i
=0; i
<nByte
; i
+= g
.perLine
){
210 fprintf(stdout
, zOfstFmt
, i
+printOfst
);
211 for(j
=0; j
<g
.perLine
; j
++){
213 fprintf(stdout
, " ");
215 fprintf(stdout
,"%02x ", aData
[i
+j
]);
218 for(j
=0; j
<g
.perLine
; j
++){
220 fprintf(stdout
, " ");
222 fprintf(stdout
,"%c", ISPRINT(aData
[i
+j
]) ? aData
[i
+j
] : '.');
225 fprintf(stdout
,"\n");
231 ** Print an entire page of content as hex
233 static void print_page(int iPg
){
235 unsigned char *aData
;
236 iStart
= (iPg
-1)*g
.pagesize
;
237 fprintf(stdout
, "Page %d: (offsets 0x%x..0x%x)\n",
238 iPg
, iStart
, iStart
+g
.pagesize
-1);
239 aData
= print_byte_range(iStart
, g
.pagesize
, 0);
244 /* Print a line of decode output showing a 4-byte integer.
246 static void print_decode_line(
247 unsigned char *aData
, /* Content being decoded */
248 int ofst
, int nByte
, /* Start and size of decode */
249 const char *zMsg
/* Message to append */
252 int val
= aData
[ofst
];
254 sprintf(zBuf
, " %03x: %02x", ofst
, aData
[ofst
]);
255 i
= (int)strlen(zBuf
);
258 sprintf(&zBuf
[i
], " ");
260 sprintf(&zBuf
[i
], " %02x", aData
[ofst
+j
]);
261 val
= val
*256 + aData
[ofst
+j
];
263 i
+= (int)strlen(&zBuf
[i
]);
265 sprintf(&zBuf
[i
], " %9d", val
);
266 printf("%s %s\n", zBuf
, zMsg
);
270 ** Decode the database header.
272 static void print_db_header(void){
273 unsigned char *aData
;
274 aData
= print_byte_range(0, 100, 0);
275 printf("Decoded:\n");
276 print_decode_line(aData
, 16, 2, "Database page size");
277 print_decode_line(aData
, 18, 1, "File format write version");
278 print_decode_line(aData
, 19, 1, "File format read version");
279 print_decode_line(aData
, 20, 1, "Reserved space at end of page");
280 print_decode_line(aData
, 24, 4, "File change counter");
281 print_decode_line(aData
, 28, 4, "Size of database in pages");
282 print_decode_line(aData
, 32, 4, "Page number of first freelist page");
283 print_decode_line(aData
, 36, 4, "Number of freelist pages");
284 print_decode_line(aData
, 40, 4, "Schema cookie");
285 print_decode_line(aData
, 44, 4, "Schema format version");
286 print_decode_line(aData
, 48, 4, "Default page cache size");
287 print_decode_line(aData
, 52, 4, "Largest auto-vac root page");
288 print_decode_line(aData
, 56, 4, "Text encoding");
289 print_decode_line(aData
, 60, 4, "User version");
290 print_decode_line(aData
, 64, 4, "Incremental-vacuum mode");
291 print_decode_line(aData
, 68, 4, "Application ID");
292 print_decode_line(aData
, 72, 4, "meta[8]");
293 print_decode_line(aData
, 76, 4, "meta[9]");
294 print_decode_line(aData
, 80, 4, "meta[10]");
295 print_decode_line(aData
, 84, 4, "meta[11]");
296 print_decode_line(aData
, 88, 4, "meta[12]");
297 print_decode_line(aData
, 92, 4, "Change counter for version number");
298 print_decode_line(aData
, 96, 4, "SQLite version number");
302 ** Describe cell content.
304 static i64
describeContent(
305 unsigned char *a
, /* Cell content */
306 i64 nLocal
, /* Bytes in a[] */
307 char *zDesc
/* Write description here */
312 const unsigned char *pData
;
313 const unsigned char *pLimit
;
317 n
= decodeVarint(a
, &x
);
321 while( i
>0 && pData
<=pLimit
){
322 n
= decodeVarint(a
, &x
);
331 sprintf(zDesc
, "*"); /* NULL is a "*" */
332 }else if( x
>=1 && x
<=6 ){
333 v
= (signed char)pData
[0];
336 case 6: v
= (v
<<16) + (pData
[0]<<8) + pData
[1]; pData
+= 2;
337 case 5: v
= (v
<<16) + (pData
[0]<<8) + pData
[1]; pData
+= 2;
338 case 4: v
= (v
<<8) + pData
[0]; pData
++;
339 case 3: v
= (v
<<8) + pData
[0]; pData
++;
340 case 2: v
= (v
<<8) + pData
[0]; pData
++;
342 sprintf(zDesc
, "%lld", v
);
344 sprintf(zDesc
, "real");
353 sprintf(zDesc
, "blob(%lld)", size
);
355 sprintf(zDesc
, "txt(%lld)", size
);
359 j
= (int)strlen(zDesc
);
367 ** Compute the local payload size given the total payload size and
370 static i64
localPayload(i64 nPayload
, char cType
){
377 maxLocal
= g
.pagesize
-35;
378 minLocal
= (g
.pagesize
-12)*32/255-23;
380 maxLocal
= (g
.pagesize
-12)*64/255-23;
381 minLocal
= (g
.pagesize
-12)*32/255-23;
383 if( nPayload
>maxLocal
){
384 surplus
= minLocal
+ (nPayload
-minLocal
)%(g
.pagesize
-4);
385 if( surplus
<=maxLocal
){
398 ** Create a description for a single cell.
400 ** The return value is the local cell size.
402 static i64
describeCell(
403 unsigned char cType
, /* Page type */
404 unsigned char *a
, /* Cell content */
405 int showCellContent
, /* Show cell content if true */
406 char **pzDesc
/* Store description here */
415 static char zDesc
[1000];
418 leftChild
= ((a
[0]*256 + a
[1])*256 + a
[2])*256 + a
[3];
421 sprintf(zDesc
, "lx: %d ", leftChild
);
422 nDesc
= strlen(zDesc
);
425 i
= decodeVarint(a
, &nPayload
);
428 sprintf(&zDesc
[nDesc
], "n: %lld ", nPayload
);
429 nDesc
+= strlen(&zDesc
[nDesc
]);
430 nLocal
= localPayload(nPayload
, cType
);
432 nPayload
= nLocal
= 0;
434 if( cType
==5 || cType
==13 ){
435 i
= decodeVarint(a
, &rowid
);
438 sprintf(&zDesc
[nDesc
], "r: %lld ", rowid
);
439 nDesc
+= strlen(&zDesc
[nDesc
]);
441 if( nLocal
<nPayload
){
443 unsigned char *b
= &a
[nLocal
];
444 ovfl
= ((b
[0]*256 + b
[1])*256 + b
[2])*256 + b
[3];
445 sprintf(&zDesc
[nDesc
], "ov: %d ", ovfl
);
446 nDesc
+= strlen(&zDesc
[nDesc
]);
449 if( showCellContent
&& cType
!=5 ){
450 nDesc
+= describeContent(a
, nLocal
, &zDesc
[nDesc
-1]);
456 /* Print an offset followed by nByte bytes. Add extra white-space
457 ** at the end so that subsequent text is aligned.
459 static void printBytes(
460 unsigned char *aData
, /* Content being decoded */
461 unsigned char *aStart
, /* Start of content to be printed */
462 int nByte
/* Number of bytes to print */
465 printf(" %03x: ", (int)(aStart
-aData
));
470 printf("%02x ", aStart
[j
]);
477 ** Write a full decode on stdout for the cell at a[ofst].
478 ** Assume the page contains a header of size szPgHdr bytes.
480 static void decodeCell(
481 unsigned char *a
, /* Page content (without the page-1 header) */
482 unsigned pgno
, /* Page number */
483 int iCell
, /* Cell index */
484 int szPgHdr
, /* Size of the page header. 0 or 100 */
485 int ofst
/* Cell begins at a[ofst] */
495 unsigned char *x
= a
+ ofst
;
497 unsigned char cType
= a
[0];
503 printf("Cell[%d]:\n", iCell
);
505 leftChild
= ((x
[0]*256 + x
[1])*256 + x
[2])*256 + x
[3];
507 printf("left child page:: %d\n", leftChild
);
511 i
= decodeVarint(x
, &nPayload
);
513 nLocal
= localPayload(nPayload
, cType
);
514 if( nLocal
==nPayload
){
515 printf("payload-size: %lld\n", nPayload
);
517 printf("payload-size: %lld (%lld local, %lld overflow)\n",
518 nPayload
, nLocal
, nPayload
-nLocal
);
522 nPayload
= nLocal
= 0;
525 if( cType
==5 || cType
==13 ){
526 i
= decodeVarint(x
, &rowid
);
528 printf("rowid: %lld\n", rowid
);
532 i
= decodeVarint(x
, &nHdr
);
534 printf("record-header-size: %d\n", (int)nHdr
);
538 while( x
+j
<=end
&& j
<nHdr
){
539 const char *zTypeName
;
542 i
= decodeVarint(x
+j
, &iType
);
543 printBytes(a
, x
+j
, i
);
544 printf("typecode[%d]: %d - ", nCol
, (int)iType
);
546 case 0: zTypeName
= "NULL"; sz
= 0; break;
547 case 1: zTypeName
= "int8"; sz
= 1; break;
548 case 2: zTypeName
= "int16"; sz
= 2; break;
549 case 3: zTypeName
= "int24"; sz
= 3; break;
550 case 4: zTypeName
= "int32"; sz
= 4; break;
551 case 5: zTypeName
= "int48"; sz
= 6; break;
552 case 6: zTypeName
= "int64"; sz
= 8; break;
553 case 7: zTypeName
= "double"; sz
= 8; break;
554 case 8: zTypeName
= "zero"; sz
= 0; break;
555 case 9: zTypeName
= "one"; sz
= 0; break;
557 case 11: zTypeName
= "error"; sz
= 0; break;
559 sz
= (int)(iType
-12)/2;
560 sprintf(zNm
, (iType
&1)==0 ? "blob(%d)" : "text(%d)", sz
);
565 printf("%s\n", zTypeName
);
567 ofstCol
[nCol
] = (int)k
;
568 typeCol
[nCol
] = (int)iType
;
573 for(i
=0; i
<nCol
&& ofstCol
[i
]+szCol
[i
]<=nLocal
; i
++){
576 const unsigned char *pData
;
577 if( szCol
[i
]==0 ) continue;
578 printBytes(a
, x
+s
, szCol
[i
]);
579 printf("data[%d]: ", i
);
582 v
= (signed char)pData
[0];
583 for(k
=1; k
<szCol
[i
]; k
++){
584 v
= (v
<<8) + pData
[k
];
588 memcpy(&r
, &v
, sizeof(r
));
596 if( (typeCol
[i
]&1)==0 ){
599 for(ii
=2, jj
=0; jj
<szCol
[i
] && ii
<24; jj
++, ii
+=2){
600 sprintf(zConst
+ii
, "%02x", pData
[jj
]);
604 for(ii
=1, jj
=0; jj
<szCol
[i
] && ii
<24; jj
++, ii
++){
605 zConst
[ii
] = ISPRINT(pData
[jj
]) ? pData
[jj
] : '.';
610 memcpy(zConst
+ii
, "...'", 5);
612 memcpy(zConst
+ii
, "'", 2);
614 printf("%s\n", zConst
);
616 j
= ofstCol
[i
] + szCol
[i
];
620 printBytes(a
, x
+j
, 0);
621 printf("... %lld bytes of content ...\n", nLocal
-j
);
623 if( nLocal
<nPayload
){
624 printBytes(a
, x
+nLocal
, 4);
625 printf("overflow-page: %d\n", decodeInt32(x
+nLocal
));
631 ** Decode a btree page
633 static void decode_btree_page(
634 unsigned char *a
, /* Page content */
635 int pgno
, /* Page number */
636 int hdrSize
, /* Size of the page header. 0 or 100 */
637 char *zArgs
/* Flags to control formatting */
639 const char *zType
= "unknown";
643 int showCellContent
= 0;
645 int cellToDecode
= -2;
648 case 2: zType
= "index interior node"; break;
649 case 5: zType
= "table interior node"; break;
650 case 10: zType
= "index leaf"; break;
651 case 13: zType
= "table leaf"; break;
655 case 'c': showCellContent
= 1; break;
656 case 'm': showMap
= 1; break;
658 if( !ISDIGIT(zArgs
[1]) ){
662 while( ISDIGIT(zArgs
[1]) ){
664 cellToDecode
= cellToDecode
*10 + zArgs
[0] - '0';
672 nCell
= a
[3]*256 + a
[4];
673 iCellPtr
= (a
[0]==2 || a
[0]==5) ? 12 : 8;
674 if( cellToDecode
>=nCell
){
675 printf("Page %d has only %d cells\n", pgno
, nCell
);
678 printf("Header on btree page %d:\n", pgno
);
679 print_decode_line(a
, 0, 1, zType
);
680 print_decode_line(a
, 1, 2, "Offset to first freeblock");
681 print_decode_line(a
, 3, 2, "Number of cells on this page");
682 print_decode_line(a
, 5, 2, "Offset to cell content area");
683 print_decode_line(a
, 7, 1, "Fragmented byte count");
684 if( a
[0]==2 || a
[0]==5 ){
685 print_decode_line(a
, 8, 4, "Right child");
687 if( cellToDecode
==(-2) && nCell
>0 ){
688 printf(" key: lx=left-child n=payload-size r=rowid\n");
691 zMap
= sqlite3_malloc(g
.pagesize
);
692 memset(zMap
, '.', g
.pagesize
);
693 memset(zMap
, '1', hdrSize
);
694 memset(&zMap
[hdrSize
], 'H', iCellPtr
);
695 memset(&zMap
[hdrSize
+iCellPtr
], 'P', 2*nCell
);
697 for(i
=0; i
<nCell
; i
++){
698 int cofst
= iCellPtr
+ i
*2;
702 cofst
= a
[cofst
]*256 + a
[cofst
+1];
703 n
= describeCell(a
[0], &a
[cofst
-hdrSize
], showCellContent
, &zDesc
);
706 memset(&zMap
[cofst
], '*', (size_t)n
);
708 zMap
[cofst
+n
-1] = ']';
709 sprintf(zBuf
, "%d", i
);
710 j
= (int)strlen(zBuf
);
711 if( j
<=n
-2 ) memcpy(&zMap
[cofst
+1], zBuf
, j
);
713 if( cellToDecode
==(-2) ){
714 printf(" %03x: cell[%d] %s\n", cofst
, i
, zDesc
);
715 }else if( cellToDecode
==(-1) || cellToDecode
==i
){
716 decodeCell(a
, pgno
, i
, hdrSize
, cofst
-hdrSize
);
720 printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n");
721 for(i
=0; i
<g
.pagesize
; i
+=64){
722 printf(" %03x: %.64s\n", i
, &zMap
[i
]);
729 ** Decode a freelist trunk page.
731 static void decode_trunk_page(
732 int pgno
, /* The page number */
733 int detail
, /* Show leaf pages if true */
734 int recursive
/* Follow the trunk change if true */
739 a
= fileRead((pgno
-1)*g
.pagesize
, g
.pagesize
);
740 printf("Decode of freelist trunk page %d:\n", pgno
);
741 print_decode_line(a
, 0, 4, "Next freelist trunk page");
742 print_decode_line(a
, 4, 4, "Number of entries on this page");
744 n
= (int)decodeInt32(&a
[4]);
746 unsigned int x
= decodeInt32(&a
[8+4*i
]);
748 sprintf(zIdx
, "[%d]", i
);
749 printf(" %5s %7u", zIdx
, x
);
750 if( i
%5==4 ) printf("\n");
752 if( i
%5!=0 ) printf("\n");
757 pgno
= (int)decodeInt32(&a
[0]);
764 ** A short text comment on the use of each page.
766 static char **zPageUse
;
769 ** Add a comment on the use of a page.
771 static void page_usage_msg(int pgno
, const char *zFormat
, ...){
775 va_start(ap
, zFormat
);
776 zMsg
= sqlite3_vmprintf(zFormat
, ap
);
778 if( pgno
<=0 || pgno
>g
.mxPage
){
779 printf("ERROR: page %d out of range 1..%d: %s\n",
780 pgno
, g
.mxPage
, zMsg
);
784 if( zPageUse
[pgno
]!=0 ){
785 printf("ERROR: page %d used multiple times:\n", pgno
);
786 printf("ERROR: previous: %s\n", zPageUse
[pgno
]);
787 printf("ERROR: current: %s\n", zMsg
);
788 sqlite3_free(zPageUse
[pgno
]);
790 zPageUse
[pgno
] = zMsg
;
794 ** Find overflow pages of a cell and describe their usage.
796 static void page_usage_cell(
797 unsigned char cType
, /* Page type */
798 unsigned char *a
, /* Cell content */
799 int pgno
, /* page containing the cell */
800 int cellno
/* Index of the cell on the page */
813 i
= decodeVarint(a
, &nPayload
);
816 nLocal
= localPayload(nPayload
, cType
);
818 nPayload
= nLocal
= 0;
820 if( cType
==5 || cType
==13 ){
821 i
= decodeVarint(a
, &rowid
);
825 if( nLocal
<nPayload
){
826 int ovfl
= decodeInt32(a
+nLocal
);
828 while( ovfl
&& (cnt
++)<g
.mxPage
){
829 page_usage_msg(ovfl
, "overflow %d from cell %d of page %d",
831 a
= fileRead((ovfl
-1)*g
.pagesize
, 4);
832 ovfl
= decodeInt32(a
);
840 ** Describe the usages of a b-tree page
842 static void page_usage_btree(
843 int pgno
, /* Page to describe */
844 int parent
, /* Parent of this page. 0 for root pages */
845 int idx
, /* Which child of the parent */
846 const char *zName
/* Name of the table */
849 const char *zType
= "corrupt node";
852 int hdr
= pgno
==1 ? 100 : 0;
854 if( pgno
<=0 || pgno
>g
.mxPage
) return;
855 a
= fileRead((pgno
-1)*g
.pagesize
, g
.pagesize
);
857 case 2: zType
= "interior node of index"; break;
858 case 5: zType
= "interior node of table"; break;
859 case 10: zType
= "leaf of index"; break;
860 case 13: zType
= "leaf of table"; break;
863 page_usage_msg(pgno
, "%s [%s], child %d of page %d",
864 zType
, zName
, idx
, parent
);
866 page_usage_msg(pgno
, "root %s [%s]", zType
, zName
);
868 nCell
= a
[hdr
+3]*256 + a
[hdr
+4];
869 if( a
[hdr
]==2 || a
[hdr
]==5 ){
870 int cellstart
= hdr
+12;
872 for(i
=0; i
<nCell
; i
++){
875 ofst
= cellstart
+ i
*2;
876 ofst
= a
[ofst
]*256 + a
[ofst
+1];
877 child
= decodeInt32(a
+ofst
);
878 page_usage_btree(child
, pgno
, i
, zName
);
880 child
= decodeInt32(a
+cellstart
-4);
881 page_usage_btree(child
, pgno
, i
, zName
);
883 if( a
[hdr
]==2 || a
[hdr
]==10 || a
[hdr
]==13 ){
884 int cellstart
= hdr
+ 8 + 4*(a
[hdr
]<=5);
885 for(i
=0; i
<nCell
; i
++){
887 ofst
= cellstart
+ i
*2;
888 ofst
= a
[ofst
]*256 + a
[ofst
+1];
889 page_usage_cell(a
[hdr
], a
+ofst
, pgno
, i
);
896 ** Determine page usage by the freelist
898 static void page_usage_freelist(int pgno
){
906 while( pgno
>0 && pgno
<=g
.mxPage
&& (cnt
++)<g
.mxPage
){
907 page_usage_msg(pgno
, "freelist trunk #%d child of %d", cnt
, parent
);
908 a
= fileRead((pgno
-1)*g
.pagesize
, g
.pagesize
);
909 iNext
= decodeInt32(a
);
910 n
= decodeInt32(a
+4);
912 int child
= decodeInt32(a
+ (i
*4+8));
913 page_usage_msg(child
, "freelist leaf, child %d of trunk page %d",
923 ** Determine pages used as PTRMAP pages
925 static void page_usage_ptrmap(unsigned char *a
){
927 int usable
= g
.pagesize
- a
[20];
929 int perPage
= usable
/5;
930 while( pgno
<=g
.mxPage
){
931 page_usage_msg(pgno
, "PTRMAP page covering %d..%d",
932 pgno
+1, pgno
+perPage
);
939 ** Try to figure out how every page in the database file is being used.
941 static void page_usage_report(const char *zPrg
, const char *zDbName
){
949 /* Avoid the pathological case */
951 printf("empty database\n");
955 /* Open the database file */
956 db
= openDatabase(zPrg
, zDbName
);
958 /* Set up global variables zPageUse[] and g.mxPage to record page
960 zPageUse
= sqlite3_malloc( sizeof(zPageUse
[0])*(g
.mxPage
+1) );
961 if( zPageUse
==0 ) out_of_memory();
962 memset(zPageUse
, 0, sizeof(zPageUse
[0])*(g
.mxPage
+1));
964 /* Discover the usage of each page */
965 a
= fileRead(0, 100);
966 page_usage_freelist(decodeInt32(a
+32));
967 page_usage_ptrmap(a
);
969 page_usage_btree(1, 0, 0, "sqlite_master");
970 sqlite3_exec(db
, "PRAGMA writable_schema=ON", 0, 0, 0);
972 sqlite3_snprintf(sizeof(zQuery
), zQuery
,
973 "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage"
974 " ORDER BY rowid %s", j
?"DESC":"");
975 rc
= sqlite3_prepare_v2(db
, zQuery
, -1, &pStmt
, 0);
977 while( sqlite3_step(pStmt
)==SQLITE_ROW
){
978 int pgno
= sqlite3_column_int(pStmt
, 2);
979 page_usage_btree(pgno
, 0, 0, (const char*)sqlite3_column_text(pStmt
,1));
982 printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db
));
984 rc
= sqlite3_finalize(pStmt
);
985 if( rc
==SQLITE_OK
) break;
989 /* Print the report and free memory used */
990 for(i
=1; i
<=g
.mxPage
; i
++){
991 printf("%5d: %s\n", i
, zPageUse
[i
] ? zPageUse
[i
] : "???");
992 sqlite3_free(zPageUse
[i
]);
994 sqlite3_free(zPageUse
);
999 ** Try to figure out how every page in the database file is being used.
1001 static void ptrmap_coverage_report(const char *zDbName
){
1003 unsigned char *aHdr
;
1009 /* Avoid the pathological case */
1011 printf("empty database\n");
1015 /* Make sure PTRMAPs are used in this database */
1016 aHdr
= fileRead(0, 100);
1018 printf("database does not use PTRMAP pages\n");
1021 usable
= g
.pagesize
- aHdr
[20];
1024 printf("%5d: root of sqlite_master\n", 1);
1025 for(pgno
=2; pgno
<=g
.mxPage
; pgno
+= perPage
+1){
1026 printf("%5d: PTRMAP page covering %d..%d\n", pgno
,
1027 pgno
+1, pgno
+perPage
);
1028 a
= fileRead((pgno
-1)*g
.pagesize
, usable
);
1029 for(i
=0; i
+5<=usable
&& pgno
+1+i
/5<=g
.mxPage
; i
+=5){
1030 const char *zType
= "???";
1031 unsigned int iFrom
= decodeInt32(&a
[i
+1]);
1033 case 1: zType
= "b-tree root page"; break;
1034 case 2: zType
= "freelist page"; break;
1035 case 3: zType
= "first page of overflow"; break;
1036 case 4: zType
= "later page of overflow"; break;
1037 case 5: zType
= "b-tree non-root page"; break;
1039 printf("%5d: %s, parent=%u\n", pgno
+1+i
/5, zType
, iFrom
);
1046 ** Print a usage comment
1048 static void usage(const char *argv0
){
1049 fprintf(stderr
, "Usage %s ?--uri? FILENAME ?args...?\n\n", argv0
);
1052 " --raw Read db file directly, bypassing SQLite VFS\n"
1054 " dbheader Show database header\n"
1055 " pgidx Index of how each page is used\n"
1056 " ptrmap Show all PTRMAP page content\n"
1057 " NNN..MMM Show hex of pages NNN through MMM\n"
1058 " NNN..end Show hex of pages NNN through end of file\n"
1059 " NNNb Decode btree page NNN\n"
1060 " NNNbc Decode btree page NNN and show content\n"
1061 " NNNbm Decode btree page NNN and show a layout map\n"
1062 " NNNbdCCC Decode cell CCC on btree page NNN\n"
1063 " NNNt Decode freelist trunk page NNN\n"
1064 " NNNtd Show leaf freelist pages on the decode\n"
1065 " NNNtr Recursively decode freelist starting at NNN\n"
1069 int main(int argc
, char **argv
){
1070 sqlite3_int64 szFile
;
1071 unsigned char *zPgSz
;
1072 const char *zPrg
= argv
[0]; /* Name of this executable */
1073 char **azArg
= argv
;
1076 /* Check for the "--uri" or "-uri" switch. */
1078 if( sqlite3_stricmp("-raw", azArg
[1])==0
1079 || sqlite3_stricmp("--raw", azArg
[1])==0
1092 fileOpen(zPrg
, azArg
[1]);
1093 szFile
= fileGetsize();
1095 zPgSz
= fileRead(16, 2);
1096 g
.pagesize
= zPgSz
[0]*256 + zPgSz
[1]*65536;
1097 if( g
.pagesize
==0 ) g
.pagesize
= 1024;
1098 sqlite3_free(zPgSz
);
1100 printf("Pagesize: %d\n", g
.pagesize
);
1101 g
.mxPage
= (int)((szFile
+g
.pagesize
-1)/g
.pagesize
);
1103 printf("Available pages: 1..%d\n", g
.mxPage
);
1106 for(i
=1; i
<=g
.mxPage
; i
++) print_page(i
);
1109 for(i
=2; i
<nArg
; i
++){
1112 if( strcmp(azArg
[i
], "dbheader")==0 ){
1116 if( strcmp(azArg
[i
], "pgidx")==0 ){
1117 page_usage_report(zPrg
, azArg
[1]);
1120 if( strcmp(azArg
[i
], "ptrmap")==0 ){
1121 ptrmap_coverage_report(azArg
[1]);
1124 if( strcmp(azArg
[i
], "help")==0 ){
1128 if( !ISDIGIT(azArg
[i
][0]) ){
1129 fprintf(stderr
, "%s: unknown option: [%s]\n", zPrg
, azArg
[i
]);
1132 iStart
= strtol(azArg
[i
], &zLeft
, 0);
1133 if( zLeft
&& strcmp(zLeft
,"..end")==0 ){
1135 }else if( zLeft
&& zLeft
[0]=='.' && zLeft
[1]=='.' ){
1136 iEnd
= strtol(&zLeft
[2], 0, 0);
1137 }else if( zLeft
&& zLeft
[0]=='b' ){
1138 int ofst
, nByte
, hdrSize
;
1141 ofst
= hdrSize
= 100;
1142 nByte
= g
.pagesize
-100;
1145 ofst
= (iStart
-1)*g
.pagesize
;
1148 a
= fileRead(ofst
, nByte
);
1149 decode_btree_page(a
, iStart
, hdrSize
, &zLeft
[1]);
1152 }else if( zLeft
&& zLeft
[0]=='t' ){
1156 for(j
=1; zLeft
[j
]; j
++){
1157 if( zLeft
[j
]=='r' ) recursive
= 1;
1158 if( zLeft
[j
]=='d' ) detail
= 1;
1160 decode_trunk_page(iStart
, detail
, recursive
);
1165 if( iStart
<1 || iEnd
<iStart
|| iEnd
>g
.mxPage
){
1167 "Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
1171 while( iStart
<=iEnd
){