blob: d378d05d367026db5cb8921324db643f46197f0d [file] [log] [blame]
drh0de8c112002-07-06 16:32:14 +00001/*
2** A utility for printing all or part of an SQLite database file.
3*/
4#include <stdio.h>
5#include <ctype.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <unistd.h>
10#include <stdlib.h>
drh562cedb2010-04-26 15:44:07 +000011#include <string.h>
drh3aeea462012-04-03 14:59:50 +000012#include "sqlite3.h"
drh0de8c112002-07-06 16:32:14 +000013
14
drh562cedb2010-04-26 15:44:07 +000015static int pagesize = 1024; /* Size of a database page */
16static int db = -1; /* File descriptor for reading the DB */
17static int mxPage = 0; /* Last page number */
18static int perLine = 16; /* HEX elements to print per line */
drh0de8c112002-07-06 16:32:14 +000019
drh562cedb2010-04-26 15:44:07 +000020typedef long long int i64; /* Datatype for 64-bit integers */
21
22
23/*
24** Convert the var-int format into i64. Return the number of bytes
25** in the var-int. Write the var-int value into *pVal.
26*/
drh7ecc1472010-04-26 16:47:12 +000027static int decodeVarint(const unsigned char *z, i64 *pVal){
drh562cedb2010-04-26 15:44:07 +000028 i64 v = 0;
drh7ecc1472010-04-26 16:47:12 +000029 int i;
30 for(i=0; i<8; i++){
drh562cedb2010-04-26 15:44:07 +000031 v = (v<<7) + (z[i]&0x7f);
32 if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
33 }
34 v = (v<<8) + (z[i]&0xff);
35 *pVal = v;
36 return 9;
37}
38
drh7d105f82010-08-23 15:26:49 +000039/*
40** Extract a big-endian 32-bit integer
41*/
42static unsigned int decodeInt32(const unsigned char *z){
43 return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
44}
45
drh562cedb2010-04-26 15:44:07 +000046/* Report an out-of-memory error and die.
47*/
drh0de8c112002-07-06 16:32:14 +000048static void out_of_memory(void){
49 fprintf(stderr,"Out of memory...\n");
50 exit(1);
51}
52
drh562cedb2010-04-26 15:44:07 +000053/*
54** Read content from the file.
55**
56** Space to hold the content is obtained from malloc() and needs to be
57** freed by the caller.
58*/
59static unsigned char *getContent(int ofst, int nByte){
60 unsigned char *aData;
drh5240aeb2011-01-06 01:26:38 +000061 aData = malloc(nByte+32);
drh562cedb2010-04-26 15:44:07 +000062 if( aData==0 ) out_of_memory();
drhb7787ee2011-01-06 15:51:18 +000063 memset(aData, 0, nByte+32);
drh562cedb2010-04-26 15:44:07 +000064 lseek(db, ofst, SEEK_SET);
65 read(db, aData, nByte);
66 return aData;
67}
68
69/*
70** Print a range of bytes as hex and as ascii.
71*/
72static unsigned char *print_byte_range(
73 int ofst, /* First byte in the range of bytes to print */
74 int nByte, /* Number of bytes to print */
75 int printOfst /* Add this amount to the index on the left column */
76){
drh0de8c112002-07-06 16:32:14 +000077 unsigned char *aData;
78 int i, j;
drh562cedb2010-04-26 15:44:07 +000079 const char *zOfstFmt;
80
81 if( ((printOfst+nByte)&~0xfff)==0 ){
82 zOfstFmt = " %03x: ";
83 }else if( ((printOfst+nByte)&~0xffff)==0 ){
84 zOfstFmt = " %04x: ";
85 }else if( ((printOfst+nByte)&~0xfffff)==0 ){
86 zOfstFmt = " %05x: ";
87 }else if( ((printOfst+nByte)&~0xffffff)==0 ){
88 zOfstFmt = " %06x: ";
89 }else{
90 zOfstFmt = " %08x: ";
91 }
92
93 aData = getContent(ofst, nByte);
94 for(i=0; i<nByte; i += perLine){
95 fprintf(stdout, zOfstFmt, i+printOfst);
drhc9ac5ca2005-11-04 22:03:30 +000096 for(j=0; j<perLine; j++){
drh562cedb2010-04-26 15:44:07 +000097 if( i+j>nByte ){
98 fprintf(stdout, " ");
99 }else{
100 fprintf(stdout,"%02x ", aData[i+j]);
101 }
drh0de8c112002-07-06 16:32:14 +0000102 }
drhc9ac5ca2005-11-04 22:03:30 +0000103 for(j=0; j<perLine; j++){
drh562cedb2010-04-26 15:44:07 +0000104 if( i+j>nByte ){
105 fprintf(stdout, " ");
106 }else{
107 fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
108 }
drh0de8c112002-07-06 16:32:14 +0000109 }
110 fprintf(stdout,"\n");
111 }
drh562cedb2010-04-26 15:44:07 +0000112 return aData;
113}
114
115/*
116** Print an entire page of content as hex
117*/
118static print_page(int iPg){
119 int iStart;
120 unsigned char *aData;
121 iStart = (iPg-1)*pagesize;
122 fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n",
123 iPg, iStart, iStart+pagesize-1);
124 aData = print_byte_range(iStart, pagesize, 0);
drh0de8c112002-07-06 16:32:14 +0000125 free(aData);
126}
127
drh562cedb2010-04-26 15:44:07 +0000128/* Print a line of decode output showing a 4-byte integer.
129*/
130static print_decode_line(
131 unsigned char *aData, /* Content being decoded */
132 int ofst, int nByte, /* Start and size of decode */
133 const char *zMsg /* Message to append */
134){
135 int i, j;
136 int val = aData[ofst];
137 char zBuf[100];
138 sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
139 i = strlen(zBuf);
140 for(j=1; j<4; j++){
141 if( j>=nByte ){
142 sprintf(&zBuf[i], " ");
143 }else{
144 sprintf(&zBuf[i], " %02x", aData[ofst+j]);
145 val = val*256 + aData[ofst+j];
146 }
147 i += strlen(&zBuf[i]);
148 }
149 sprintf(&zBuf[i], " %9d", val);
drh7ecc1472010-04-26 16:47:12 +0000150 printf("%s %s\n", zBuf, zMsg);
drh562cedb2010-04-26 15:44:07 +0000151}
152
153/*
154** Decode the database header.
155*/
drh7ecc1472010-04-26 16:47:12 +0000156static void print_db_header(void){
drh562cedb2010-04-26 15:44:07 +0000157 unsigned char *aData;
158 aData = print_byte_range(0, 100, 0);
159 printf("Decoded:\n");
160 print_decode_line(aData, 16, 2, "Database page size");
161 print_decode_line(aData, 18, 1, "File format write version");
162 print_decode_line(aData, 19, 1, "File format read version");
163 print_decode_line(aData, 20, 1, "Reserved space at end of page");
164 print_decode_line(aData, 24, 4, "File change counter");
165 print_decode_line(aData, 28, 4, "Size of database in pages");
166 print_decode_line(aData, 32, 4, "Page number of first freelist page");
167 print_decode_line(aData, 36, 4, "Number of freelist pages");
168 print_decode_line(aData, 40, 4, "Schema cookie");
169 print_decode_line(aData, 44, 4, "Schema format version");
170 print_decode_line(aData, 48, 4, "Default page cache size");
171 print_decode_line(aData, 52, 4, "Largest auto-vac root page");
172 print_decode_line(aData, 56, 4, "Text encoding");
173 print_decode_line(aData, 60, 4, "User version");
174 print_decode_line(aData, 64, 4, "Incremental-vacuum mode");
175 print_decode_line(aData, 68, 4, "meta[7]");
176 print_decode_line(aData, 72, 4, "meta[8]");
177 print_decode_line(aData, 76, 4, "meta[9]");
178 print_decode_line(aData, 80, 4, "meta[10]");
179 print_decode_line(aData, 84, 4, "meta[11]");
180 print_decode_line(aData, 88, 4, "meta[12]");
drhb28e59b2010-06-17 02:13:39 +0000181 print_decode_line(aData, 92, 4, "Change counter for version number");
drhc6d2b4a2010-04-26 17:30:52 +0000182 print_decode_line(aData, 96, 4, "SQLite version number");
drh562cedb2010-04-26 15:44:07 +0000183}
184
drh7ecc1472010-04-26 16:47:12 +0000185/*
drh100335b2011-01-05 21:20:52 +0000186** Describe cell content.
187*/
188static int describeContent(
drh5240aeb2011-01-06 01:26:38 +0000189 unsigned char *a, /* Cell content */
190 int nLocal, /* Bytes in a[] */
191 char *zDesc /* Write description here */
drh100335b2011-01-05 21:20:52 +0000192){
193 int nDesc = 0;
194 int n, i, j;
195 i64 x, v;
196 const unsigned char *pData;
drh5240aeb2011-01-06 01:26:38 +0000197 const unsigned char *pLimit;
drh100335b2011-01-05 21:20:52 +0000198 char sep = ' ';
199
drh5240aeb2011-01-06 01:26:38 +0000200 pLimit = &a[nLocal];
drh100335b2011-01-05 21:20:52 +0000201 n = decodeVarint(a, &x);
202 pData = &a[x];
203 a += n;
204 i = x - n;
drh5240aeb2011-01-06 01:26:38 +0000205 while( i>0 && pData<=pLimit ){
drh100335b2011-01-05 21:20:52 +0000206 n = decodeVarint(a, &x);
207 a += n;
208 i -= n;
drh5240aeb2011-01-06 01:26:38 +0000209 nLocal -= n;
drh100335b2011-01-05 21:20:52 +0000210 zDesc[0] = sep;
211 sep = ',';
212 nDesc++;
213 zDesc++;
214 if( x==0 ){
drh5240aeb2011-01-06 01:26:38 +0000215 sprintf(zDesc, "*"); /* NULL is a "*" */
drh100335b2011-01-05 21:20:52 +0000216 }else if( x>=1 && x<=6 ){
217 v = (signed char)pData[0];
218 pData++;
219 switch( x ){
220 case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
221 case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
222 case 4: v = (v<<8) + pData[0]; pData++;
223 case 3: v = (v<<8) + pData[0]; pData++;
224 case 2: v = (v<<8) + pData[0]; pData++;
225 }
226 sprintf(zDesc, "%lld", v);
227 }else if( x==7 ){
228 sprintf(zDesc, "real");
229 pData += 8;
230 }else if( x==8 ){
231 sprintf(zDesc, "0");
232 }else if( x==9 ){
233 sprintf(zDesc, "1");
234 }else if( x>=12 ){
235 int size = (x-12)/2;
drhb2c062d2011-01-05 21:46:52 +0000236 if( (x&1)==0 ){
drh100335b2011-01-05 21:20:52 +0000237 sprintf(zDesc, "blob(%d)", size);
238 }else{
drh5240aeb2011-01-06 01:26:38 +0000239 sprintf(zDesc, "txt(%d)", size);
drh100335b2011-01-05 21:20:52 +0000240 }
241 pData += size;
242 }
243 j = strlen(zDesc);
244 zDesc += j;
245 nDesc += j;
246 }
247 return nDesc;
248}
drh5240aeb2011-01-06 01:26:38 +0000249
250/*
251** Compute the local payload size given the total payload size and
252** the page size.
253*/
254static int localPayload(i64 nPayload, char cType){
255 int maxLocal;
256 int minLocal;
257 int surplus;
258 int nLocal;
259 if( cType==13 ){
260 /* Table leaf */
261 maxLocal = pagesize-35;
262 minLocal = (pagesize-12)*32/255-23;
263 }else{
264 maxLocal = (pagesize-12)*64/255-23;
265 minLocal = (pagesize-12)*32/255-23;
266 }
267 if( nPayload>maxLocal ){
268 surplus = minLocal + (nPayload-minLocal)%(pagesize-4);
269 if( surplus<=maxLocal ){
270 nLocal = surplus;
271 }else{
272 nLocal = minLocal;
273 }
274 }else{
275 nLocal = nPayload;
276 }
277 return nLocal;
278}
drh100335b2011-01-05 21:20:52 +0000279
280
281/*
drh7ecc1472010-04-26 16:47:12 +0000282** Create a description for a single cell.
drh5240aeb2011-01-06 01:26:38 +0000283**
284** The return value is the local cell size.
drh7ecc1472010-04-26 16:47:12 +0000285*/
drh100335b2011-01-05 21:20:52 +0000286static int describeCell(
287 unsigned char cType, /* Page type */
288 unsigned char *a, /* Cell content */
289 int showCellContent, /* Show cell content if true */
290 char **pzDesc /* Store description here */
291){
drh7ecc1472010-04-26 16:47:12 +0000292 int i;
293 int nDesc = 0;
294 int n = 0;
295 int leftChild;
296 i64 nPayload;
297 i64 rowid;
drh100335b2011-01-05 21:20:52 +0000298 int nLocal;
299 static char zDesc[1000];
drh7ecc1472010-04-26 16:47:12 +0000300 i = 0;
301 if( cType<=5 ){
302 leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
303 a += 4;
304 n += 4;
drh100335b2011-01-05 21:20:52 +0000305 sprintf(zDesc, "lx: %d ", leftChild);
drh7ecc1472010-04-26 16:47:12 +0000306 nDesc = strlen(zDesc);
307 }
308 if( cType!=5 ){
309 i = decodeVarint(a, &nPayload);
310 a += i;
311 n += i;
drh100335b2011-01-05 21:20:52 +0000312 sprintf(&zDesc[nDesc], "n: %lld ", nPayload);
drh7ecc1472010-04-26 16:47:12 +0000313 nDesc += strlen(&zDesc[nDesc]);
drh5240aeb2011-01-06 01:26:38 +0000314 nLocal = localPayload(nPayload, cType);
315 }else{
316 nPayload = nLocal = 0;
drh7ecc1472010-04-26 16:47:12 +0000317 }
318 if( cType==5 || cType==13 ){
319 i = decodeVarint(a, &rowid);
320 a += i;
321 n += i;
drh100335b2011-01-05 21:20:52 +0000322 sprintf(&zDesc[nDesc], "r: %lld ", rowid);
drh7ecc1472010-04-26 16:47:12 +0000323 nDesc += strlen(&zDesc[nDesc]);
324 }
drhb7787ee2011-01-06 15:51:18 +0000325 if( nLocal<nPayload ){
326 int ovfl;
327 unsigned char *b = &a[nLocal];
328 ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3];
329 sprintf(&zDesc[nDesc], "ov: %d ", ovfl);
330 nDesc += strlen(&zDesc[nDesc]);
331 n += 4;
332 }
drh100335b2011-01-05 21:20:52 +0000333 if( showCellContent && cType!=5 ){
drh5240aeb2011-01-06 01:26:38 +0000334 nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]);
drh100335b2011-01-05 21:20:52 +0000335 }
drh7ecc1472010-04-26 16:47:12 +0000336 *pzDesc = zDesc;
drh5240aeb2011-01-06 01:26:38 +0000337 return nLocal+n;
drh7ecc1472010-04-26 16:47:12 +0000338}
339
340/*
341** Decode a btree page
342*/
drh100335b2011-01-05 21:20:52 +0000343static void decode_btree_page(
344 unsigned char *a, /* Page content */
345 int pgno, /* Page number */
346 int hdrSize, /* Size of the page header. 0 or 100 */
347 char *zArgs /* Flags to control formatting */
348){
drh7ecc1472010-04-26 16:47:12 +0000349 const char *zType = "unknown";
350 int nCell;
drh5240aeb2011-01-06 01:26:38 +0000351 int i, j;
drh7ecc1472010-04-26 16:47:12 +0000352 int iCellPtr;
drh100335b2011-01-05 21:20:52 +0000353 int showCellContent = 0;
drh5240aeb2011-01-06 01:26:38 +0000354 int showMap = 0;
355 char *zMap = 0;
drh7ecc1472010-04-26 16:47:12 +0000356 switch( a[0] ){
357 case 2: zType = "index interior node"; break;
358 case 5: zType = "table interior node"; break;
359 case 10: zType = "index leaf"; break;
360 case 13: zType = "table leaf"; break;
361 }
drh100335b2011-01-05 21:20:52 +0000362 while( zArgs[0] ){
363 switch( zArgs[0] ){
364 case 'c': showCellContent = 1; break;
drh5240aeb2011-01-06 01:26:38 +0000365 case 'm': showMap = 1; break;
drh100335b2011-01-05 21:20:52 +0000366 }
367 zArgs++;
368 }
drh7ecc1472010-04-26 16:47:12 +0000369 printf("Decode of btree page %d:\n", pgno);
370 print_decode_line(a, 0, 1, zType);
371 print_decode_line(a, 1, 2, "Offset to first freeblock");
372 print_decode_line(a, 3, 2, "Number of cells on this page");
373 nCell = a[3]*256 + a[4];
374 print_decode_line(a, 5, 2, "Offset to cell content area");
375 print_decode_line(a, 7, 1, "Fragmented byte count");
376 if( a[0]==2 || a[0]==5 ){
377 print_decode_line(a, 8, 4, "Right child");
378 iCellPtr = 12;
379 }else{
380 iCellPtr = 8;
381 }
drh5240aeb2011-01-06 01:26:38 +0000382 if( nCell>0 ){
383 printf(" key: lx=left-child n=payload-size r=rowid\n");
384 }
385 if( showMap ){
386 zMap = malloc(pagesize);
387 memset(zMap, '.', pagesize);
388 memset(zMap, '1', hdrSize);
389 memset(&zMap[hdrSize], 'H', iCellPtr);
390 memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell);
391 }
drh7ecc1472010-04-26 16:47:12 +0000392 for(i=0; i<nCell; i++){
393 int cofst = iCellPtr + i*2;
394 char *zDesc;
drh5240aeb2011-01-06 01:26:38 +0000395 int n;
396
drh7ecc1472010-04-26 16:47:12 +0000397 cofst = a[cofst]*256 + a[cofst+1];
drh5240aeb2011-01-06 01:26:38 +0000398 n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc);
399 if( showMap ){
400 char zBuf[30];
401 memset(&zMap[cofst], '*', n);
402 zMap[cofst] = '[';
403 zMap[cofst+n-1] = ']';
404 sprintf(zBuf, "%d", i);
405 j = strlen(zBuf);
406 if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j);
407 }
drh7ecc1472010-04-26 16:47:12 +0000408 printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
409 }
drh5240aeb2011-01-06 01:26:38 +0000410 if( showMap ){
411 for(i=0; i<pagesize; i+=64){
412 printf(" %03x: %.64s\n", i, &zMap[i]);
413 }
414 free(zMap);
415 }
drh7ecc1472010-04-26 16:47:12 +0000416}
417
drh7d105f82010-08-23 15:26:49 +0000418/*
419** Decode a freelist trunk page.
420*/
421static void decode_trunk_page(
422 int pgno, /* The page number */
423 int pagesize, /* Size of each page */
424 int detail, /* Show leaf pages if true */
425 int recursive /* Follow the trunk change if true */
426){
427 int n, i, k;
428 unsigned char *a;
429 while( pgno>0 ){
430 a = getContent((pgno-1)*pagesize, pagesize);
431 printf("Decode of freelist trunk page %d:\n", pgno);
432 print_decode_line(a, 0, 4, "Next freelist trunk page");
433 print_decode_line(a, 4, 4, "Number of entries on this page");
434 if( detail ){
435 n = (int)decodeInt32(&a[4]);
436 for(i=0; i<n; i++){
437 unsigned int x = decodeInt32(&a[8+4*i]);
438 char zIdx[10];
439 sprintf(zIdx, "[%d]", i);
440 printf(" %5s %7u", zIdx, x);
441 if( i%5==4 ) printf("\n");
442 }
443 if( i%5!=0 ) printf("\n");
444 }
445 if( !recursive ){
446 pgno = 0;
447 }else{
448 pgno = (int)decodeInt32(&a[0]);
449 }
450 free(a);
451 }
452}
453
454/*
drh3aeea462012-04-03 14:59:50 +0000455** A short text comment on the use of each page.
456*/
457static char **zPageUse;
458
459/*
460** Add a comment on the use of a page.
461*/
462static void page_usage_msg(int pgno, const char *zFormat, ...){
463 va_list ap;
464 char *zMsg;
465
466 va_start(ap, zFormat);
467 zMsg = sqlite3_vmprintf(zFormat, ap);
468 va_end(ap);
469 if( pgno<=0 || pgno>mxPage ){
470 printf("ERROR: page %d out of bounds. Range=1..%d. Msg: %s\n",
471 pgno, mxPage, zMsg);
472 sqlite3_free(zMsg);
473 return;
474 }
475 if( zPageUse[pgno]!=0 ){
476 printf("ERROR: page %d used multiple times:\n", pgno);
477 printf("ERROR: previous: %s\n", zPageUse[pgno]);
478 printf("ERROR: current: %s\n", zPageUse[pgno]);
479 sqlite3_free(zPageUse[pgno]);
480 }
481 zPageUse[pgno] = zMsg;
482}
483
484/*
485** Find overflow pages of a cell and describe their usage.
486*/
487static void page_usage_cell(
488 unsigned char cType, /* Page type */
489 unsigned char *a, /* Cell content */
490 int pgno, /* page containing the cell */
491 int cellno /* Index of the cell on the page */
492){
493 int i;
494 int nDesc = 0;
495 int n = 0;
496 i64 nPayload;
497 i64 rowid;
498 int nLocal;
499 i = 0;
500 if( cType<=5 ){
501 a += 4;
502 n += 4;
503 }
504 if( cType!=5 ){
505 i = decodeVarint(a, &nPayload);
506 a += i;
507 n += i;
508 nLocal = localPayload(nPayload, cType);
509 }else{
510 nPayload = nLocal = 0;
511 }
512 if( cType==5 || cType==13 ){
513 i = decodeVarint(a, &rowid);
514 a += i;
515 n += i;
516 }
517 if( nLocal<nPayload ){
518 int ovfl = decodeInt32(a+nLocal);
519 int cnt = 0;
520 while( ovfl && (cnt++)<mxPage ){
521 page_usage_msg(ovfl, "overflow %d from cell %d of page %d",
522 cnt, cellno, pgno);
523 a = getContent((ovfl-1)*pagesize, 4);
524 ovfl = decodeInt32(a);
525 free(a);
526 }
527 }
528}
529
530
531/*
532** Describe the usages of a b-tree page
533*/
534static void page_usage_btree(
535 int pgno, /* Page to describe */
536 int parent, /* Parent of this page. 0 for root pages */
537 int idx, /* Which child of the parent */
538 const char *zName /* Name of the table */
539){
540 unsigned char *a;
541 const char *zType = "corrupt node";
542 int nCell;
543 int i;
544 int hdr = pgno==1 ? 100 : 0;
545
546 if( pgno<=0 || pgno>mxPage ) return;
547 a = getContent((pgno-1)*pagesize, pagesize);
548 switch( a[hdr] ){
549 case 2: zType = "interior node of index"; break;
550 case 5: zType = "interior node of table"; break;
551 case 10: zType = "leaf of index"; break;
552 case 13: zType = "leaf of table"; break;
553 }
554 if( parent ){
555 page_usage_msg(pgno, "%s [%s], child %d of page %d",
556 zType, zName, idx, parent);
557 }else{
558 page_usage_msg(pgno, "root %s [%s]", zType, zName);
559 }
560 nCell = a[hdr+3]*256 + a[hdr+4];
561 if( a[hdr]==2 || a[hdr]==5 ){
562 int cellstart = hdr+12;
563 unsigned int child;
564 for(i=0; i<nCell; i++){
565 int ofst;
566
567 ofst = cellstart + i*2;
568 ofst = a[ofst]*256 + a[ofst+1];
569 child = decodeInt32(a+ofst);
570 page_usage_btree(child, pgno, i, zName);
571 }
572 child = decodeInt32(a+cellstart-4);
573 page_usage_btree(child, pgno, i, zName);
574 }
575 if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){
576 int cellstart = hdr + 8 + 4*(a[hdr]<=5);
577 for(i=0; i<nCell; i++){
578 int ofst;
579 ofst = cellstart + i*2;
580 ofst = a[ofst]*256 + a[ofst+1];
581 page_usage_cell(a[hdr], a+ofst, pgno, i);
582 }
583 }
584 free(a);
585}
586
587/*
588** Determine page usage by the freelist
589*/
590static void page_usage_freelist(int pgno){
591 unsigned char *a;
592 int cnt = 0;
593 int i;
594 int n;
595 int iNext;
596 int parent = 1;
597
598 while( pgno>0 && pgno<=mxPage && (cnt++)<mxPage ){
599 page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent);
600 a = getContent((pgno-1)*pagesize, pagesize);
601 iNext = decodeInt32(a);
602 n = decodeInt32(a+4);
603 for(i=0; i<n; i++){
604 int child = decodeInt32(a + (i*4+8));
605 page_usage_msg(child, "freelist leaf, child %d of trunk page %d",
606 i, pgno);
607 }
608 free(a);
609 parent = pgno;
610 pgno = iNext;
611 }
612}
613
614/*
615** Try to figure out how every page in the database file is being used.
616*/
617static void page_usage_report(const char *zDbName){
618 int i;
619 int rc;
620 sqlite3 *db;
621 sqlite3_stmt *pStmt;
622 unsigned char *a;
623
624 /* Avoid the pathological case */
625 if( mxPage<1 ){
626 printf("empty database\n");
627 return;
628 }
629
630 /* Open the database file */
631 rc = sqlite3_open(zDbName, &db);
632 if( rc ){
633 printf("cannot open database: %s\n", sqlite3_errmsg(db));
634 sqlite3_close(db);
635 return;
636 }
637
638 /* Set up global variables zPageUse[] and mxPage to record page
639 ** usages */
640 zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) );
641 if( zPageUse==0 ) out_of_memory();
642 memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1));
643
644 /* Discover the usage of each page */
645 a = getContent(0, 100);
646 page_usage_freelist(decodeInt32(a+32));
647 free(a);
648 page_usage_btree(1, 0, 0, "sqlite_master");
649 rc = sqlite3_prepare_v2(db,
650 "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage",
651 -1, &pStmt, 0);
652 if( rc==SQLITE_OK ){
653 while( sqlite3_step(pStmt)==SQLITE_ROW ){
654 int pgno = sqlite3_column_int(pStmt, 2);
655 page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1));
656 }
drh5d4e1e12012-04-03 15:10:34 +0000657 }else{
658 printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db));
drh3aeea462012-04-03 14:59:50 +0000659 }
660 sqlite3_finalize(pStmt);
661 sqlite3_close(db);
662
663 /* Print the report and free memory used */
664 for(i=1; i<=mxPage; i++){
665 printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???");
666 sqlite3_free(zPageUse[i]);
667 }
668 sqlite3_free(zPageUse);
669 zPageUse = 0;
670}
671
672/*
drh7d105f82010-08-23 15:26:49 +0000673** Print a usage comment
674*/
675static void usage(const char *argv0){
676 fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0);
677 fprintf(stderr,
678 "args:\n"
679 " dbheader Show database header\n"
drh3aeea462012-04-03 14:59:50 +0000680 " pgidx Index of how each page is used\n"
drh7d105f82010-08-23 15:26:49 +0000681 " NNN..MMM Show hex of pages NNN through MMM\n"
682 " NNN..end Show hex of pages NNN through end of file\n"
683 " NNNb Decode btree page NNN\n"
drh5240aeb2011-01-06 01:26:38 +0000684 " NNNbc Decode btree page NNN and show content\n"
685 " NNNbm Decode btree page NNN and show a layout map\n"
drh7d105f82010-08-23 15:26:49 +0000686 " NNNt Decode freelist trunk page NNN\n"
drh47fb0002011-04-13 16:52:41 +0000687 " NNNtd Show leaf freelist pages on the decode\n"
drh7d105f82010-08-23 15:26:49 +0000688 " NNNtr Recurisvely decode freelist starting at NNN\n"
689 );
690}
691
drh0de8c112002-07-06 16:32:14 +0000692int main(int argc, char **argv){
693 struct stat sbuf;
drh562cedb2010-04-26 15:44:07 +0000694 unsigned char zPgSz[2];
drh0de8c112002-07-06 16:32:14 +0000695 if( argc<2 ){
drh7d105f82010-08-23 15:26:49 +0000696 usage(argv[0]);
drh0de8c112002-07-06 16:32:14 +0000697 exit(1);
698 }
699 db = open(argv[1], O_RDONLY);
700 if( db<0 ){
701 fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
702 exit(1);
703 }
drh562cedb2010-04-26 15:44:07 +0000704 zPgSz[0] = 0;
705 zPgSz[1] = 0;
706 lseek(db, 16, SEEK_SET);
707 read(db, zPgSz, 2);
drh7d105f82010-08-23 15:26:49 +0000708 pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
drh562cedb2010-04-26 15:44:07 +0000709 if( pagesize==0 ) pagesize = 1024;
710 printf("Pagesize: %d\n", pagesize);
drh0de8c112002-07-06 16:32:14 +0000711 fstat(db, &sbuf);
drh562cedb2010-04-26 15:44:07 +0000712 mxPage = sbuf.st_size/pagesize;
713 printf("Available pages: 1..%d\n", mxPage);
drh0de8c112002-07-06 16:32:14 +0000714 if( argc==2 ){
715 int i;
716 for(i=1; i<=mxPage; i++) print_page(i);
717 }else{
718 int i;
719 for(i=2; i<argc; i++){
720 int iStart, iEnd;
721 char *zLeft;
drh562cedb2010-04-26 15:44:07 +0000722 if( strcmp(argv[i], "dbheader")==0 ){
723 print_db_header();
724 continue;
725 }
drh3aeea462012-04-03 14:59:50 +0000726 if( strcmp(argv[i], "pgidx")==0 ){
727 page_usage_report(argv[1]);
728 continue;
729 }
drh562cedb2010-04-26 15:44:07 +0000730 if( !isdigit(argv[i][0]) ){
731 fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
732 continue;
733 }
drh0de8c112002-07-06 16:32:14 +0000734 iStart = strtol(argv[i], &zLeft, 0);
735 if( zLeft && strcmp(zLeft,"..end")==0 ){
736 iEnd = mxPage;
737 }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
738 iEnd = strtol(&zLeft[2], 0, 0);
drh7ecc1472010-04-26 16:47:12 +0000739 }else if( zLeft && zLeft[0]=='b' ){
740 int ofst, nByte, hdrSize;
741 unsigned char *a;
742 if( iStart==1 ){
743 ofst = hdrSize = 100;
744 nByte = pagesize-100;
745 }else{
746 hdrSize = 0;
747 ofst = (iStart-1)*pagesize;
748 nByte = pagesize;
749 }
750 a = getContent(ofst, nByte);
drh100335b2011-01-05 21:20:52 +0000751 decode_btree_page(a, iStart, hdrSize, &zLeft[1]);
drh7ecc1472010-04-26 16:47:12 +0000752 free(a);
753 continue;
drh7d105f82010-08-23 15:26:49 +0000754 }else if( zLeft && zLeft[0]=='t' ){
755 unsigned char *a;
756 int detail = 0;
757 int recursive = 0;
758 int i;
759 for(i=1; zLeft[i]; i++){
760 if( zLeft[i]=='r' ) recursive = 1;
761 if( zLeft[i]=='d' ) detail = 1;
762 }
763 decode_trunk_page(iStart, pagesize, detail, recursive);
764 continue;
drh0de8c112002-07-06 16:32:14 +0000765 }else{
766 iEnd = iStart;
767 }
768 if( iStart<1 || iEnd<iStart || iEnd>mxPage ){
769 fprintf(stderr,
770 "Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
771 mxPage);
772 exit(1);
773 }
774 while( iStart<=iEnd ){
775 print_page(iStart);
776 iStart++;
777 }
778 }
779 }
780 close(db);
781}