Annotation of embedaddon/sqlite3/tool/showdb.c, revision 1.1.1.1
1.1 misho 1: /*
2: ** A utility for printing all or part of an SQLite database file.
3: */
4: #include <stdio.h>
5: #include <ctype.h>
6: #include <sys/types.h>
7: #include <sys/stat.h>
8: #include <fcntl.h>
9: #include <unistd.h>
10: #include <stdlib.h>
11: #include <string.h>
12:
13:
14: static int pagesize = 1024; /* Size of a database page */
15: static int db = -1; /* File descriptor for reading the DB */
16: static int mxPage = 0; /* Last page number */
17: static int perLine = 16; /* HEX elements to print per line */
18:
19: typedef long long int i64; /* Datatype for 64-bit integers */
20:
21:
22: /*
23: ** Convert the var-int format into i64. Return the number of bytes
24: ** in the var-int. Write the var-int value into *pVal.
25: */
26: static int decodeVarint(const unsigned char *z, i64 *pVal){
27: i64 v = 0;
28: int i;
29: for(i=0; i<8; i++){
30: v = (v<<7) + (z[i]&0x7f);
31: if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
32: }
33: v = (v<<8) + (z[i]&0xff);
34: *pVal = v;
35: return 9;
36: }
37:
38: /*
39: ** Extract a big-endian 32-bit integer
40: */
41: static unsigned int decodeInt32(const unsigned char *z){
42: return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
43: }
44:
45: /* Report an out-of-memory error and die.
46: */
47: static void out_of_memory(void){
48: fprintf(stderr,"Out of memory...\n");
49: exit(1);
50: }
51:
52: /*
53: ** Read content from the file.
54: **
55: ** Space to hold the content is obtained from malloc() and needs to be
56: ** freed by the caller.
57: */
58: static unsigned char *getContent(int ofst, int nByte){
59: unsigned char *aData;
60: aData = malloc(nByte+32);
61: if( aData==0 ) out_of_memory();
62: memset(aData, 0, nByte+32);
63: lseek(db, ofst, SEEK_SET);
64: read(db, aData, nByte);
65: return aData;
66: }
67:
68: /*
69: ** Print a range of bytes as hex and as ascii.
70: */
71: static unsigned char *print_byte_range(
72: int ofst, /* First byte in the range of bytes to print */
73: int nByte, /* Number of bytes to print */
74: int printOfst /* Add this amount to the index on the left column */
75: ){
76: unsigned char *aData;
77: int i, j;
78: const char *zOfstFmt;
79:
80: if( ((printOfst+nByte)&~0xfff)==0 ){
81: zOfstFmt = " %03x: ";
82: }else if( ((printOfst+nByte)&~0xffff)==0 ){
83: zOfstFmt = " %04x: ";
84: }else if( ((printOfst+nByte)&~0xfffff)==0 ){
85: zOfstFmt = " %05x: ";
86: }else if( ((printOfst+nByte)&~0xffffff)==0 ){
87: zOfstFmt = " %06x: ";
88: }else{
89: zOfstFmt = " %08x: ";
90: }
91:
92: aData = getContent(ofst, nByte);
93: for(i=0; i<nByte; i += perLine){
94: fprintf(stdout, zOfstFmt, i+printOfst);
95: for(j=0; j<perLine; j++){
96: if( i+j>nByte ){
97: fprintf(stdout, " ");
98: }else{
99: fprintf(stdout,"%02x ", aData[i+j]);
100: }
101: }
102: for(j=0; j<perLine; j++){
103: if( i+j>nByte ){
104: fprintf(stdout, " ");
105: }else{
106: fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
107: }
108: }
109: fprintf(stdout,"\n");
110: }
111: return aData;
112: }
113:
114: /*
115: ** Print an entire page of content as hex
116: */
117: static print_page(int iPg){
118: int iStart;
119: unsigned char *aData;
120: iStart = (iPg-1)*pagesize;
121: fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n",
122: iPg, iStart, iStart+pagesize-1);
123: aData = print_byte_range(iStart, pagesize, 0);
124: free(aData);
125: }
126:
127: /* Print a line of decode output showing a 4-byte integer.
128: */
129: static print_decode_line(
130: unsigned char *aData, /* Content being decoded */
131: int ofst, int nByte, /* Start and size of decode */
132: const char *zMsg /* Message to append */
133: ){
134: int i, j;
135: int val = aData[ofst];
136: char zBuf[100];
137: sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
138: i = strlen(zBuf);
139: for(j=1; j<4; j++){
140: if( j>=nByte ){
141: sprintf(&zBuf[i], " ");
142: }else{
143: sprintf(&zBuf[i], " %02x", aData[ofst+j]);
144: val = val*256 + aData[ofst+j];
145: }
146: i += strlen(&zBuf[i]);
147: }
148: sprintf(&zBuf[i], " %9d", val);
149: printf("%s %s\n", zBuf, zMsg);
150: }
151:
152: /*
153: ** Decode the database header.
154: */
155: static void print_db_header(void){
156: unsigned char *aData;
157: aData = print_byte_range(0, 100, 0);
158: printf("Decoded:\n");
159: print_decode_line(aData, 16, 2, "Database page size");
160: print_decode_line(aData, 18, 1, "File format write version");
161: print_decode_line(aData, 19, 1, "File format read version");
162: print_decode_line(aData, 20, 1, "Reserved space at end of page");
163: print_decode_line(aData, 24, 4, "File change counter");
164: print_decode_line(aData, 28, 4, "Size of database in pages");
165: print_decode_line(aData, 32, 4, "Page number of first freelist page");
166: print_decode_line(aData, 36, 4, "Number of freelist pages");
167: print_decode_line(aData, 40, 4, "Schema cookie");
168: print_decode_line(aData, 44, 4, "Schema format version");
169: print_decode_line(aData, 48, 4, "Default page cache size");
170: print_decode_line(aData, 52, 4, "Largest auto-vac root page");
171: print_decode_line(aData, 56, 4, "Text encoding");
172: print_decode_line(aData, 60, 4, "User version");
173: print_decode_line(aData, 64, 4, "Incremental-vacuum mode");
174: print_decode_line(aData, 68, 4, "meta[7]");
175: print_decode_line(aData, 72, 4, "meta[8]");
176: print_decode_line(aData, 76, 4, "meta[9]");
177: print_decode_line(aData, 80, 4, "meta[10]");
178: print_decode_line(aData, 84, 4, "meta[11]");
179: print_decode_line(aData, 88, 4, "meta[12]");
180: print_decode_line(aData, 92, 4, "Change counter for version number");
181: print_decode_line(aData, 96, 4, "SQLite version number");
182: }
183:
184: /*
185: ** Describe cell content.
186: */
187: static int describeContent(
188: unsigned char *a, /* Cell content */
189: int nLocal, /* Bytes in a[] */
190: char *zDesc /* Write description here */
191: ){
192: int nDesc = 0;
193: int n, i, j;
194: i64 x, v;
195: const unsigned char *pData;
196: const unsigned char *pLimit;
197: char sep = ' ';
198:
199: pLimit = &a[nLocal];
200: n = decodeVarint(a, &x);
201: pData = &a[x];
202: a += n;
203: i = x - n;
204: while( i>0 && pData<=pLimit ){
205: n = decodeVarint(a, &x);
206: a += n;
207: i -= n;
208: nLocal -= n;
209: zDesc[0] = sep;
210: sep = ',';
211: nDesc++;
212: zDesc++;
213: if( x==0 ){
214: sprintf(zDesc, "*"); /* NULL is a "*" */
215: }else if( x>=1 && x<=6 ){
216: v = (signed char)pData[0];
217: pData++;
218: switch( x ){
219: case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
220: case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
221: case 4: v = (v<<8) + pData[0]; pData++;
222: case 3: v = (v<<8) + pData[0]; pData++;
223: case 2: v = (v<<8) + pData[0]; pData++;
224: }
225: sprintf(zDesc, "%lld", v);
226: }else if( x==7 ){
227: sprintf(zDesc, "real");
228: pData += 8;
229: }else if( x==8 ){
230: sprintf(zDesc, "0");
231: }else if( x==9 ){
232: sprintf(zDesc, "1");
233: }else if( x>=12 ){
234: int size = (x-12)/2;
235: if( (x&1)==0 ){
236: sprintf(zDesc, "blob(%d)", size);
237: }else{
238: sprintf(zDesc, "txt(%d)", size);
239: }
240: pData += size;
241: }
242: j = strlen(zDesc);
243: zDesc += j;
244: nDesc += j;
245: }
246: return nDesc;
247: }
248:
249: /*
250: ** Compute the local payload size given the total payload size and
251: ** the page size.
252: */
253: static int localPayload(i64 nPayload, char cType){
254: int maxLocal;
255: int minLocal;
256: int surplus;
257: int nLocal;
258: if( cType==13 ){
259: /* Table leaf */
260: maxLocal = pagesize-35;
261: minLocal = (pagesize-12)*32/255-23;
262: }else{
263: maxLocal = (pagesize-12)*64/255-23;
264: minLocal = (pagesize-12)*32/255-23;
265: }
266: if( nPayload>maxLocal ){
267: surplus = minLocal + (nPayload-minLocal)%(pagesize-4);
268: if( surplus<=maxLocal ){
269: nLocal = surplus;
270: }else{
271: nLocal = minLocal;
272: }
273: }else{
274: nLocal = nPayload;
275: }
276: return nLocal;
277: }
278:
279:
280: /*
281: ** Create a description for a single cell.
282: **
283: ** The return value is the local cell size.
284: */
285: static int describeCell(
286: unsigned char cType, /* Page type */
287: unsigned char *a, /* Cell content */
288: int showCellContent, /* Show cell content if true */
289: char **pzDesc /* Store description here */
290: ){
291: int i;
292: int nDesc = 0;
293: int n = 0;
294: int leftChild;
295: i64 nPayload;
296: i64 rowid;
297: int nLocal;
298: static char zDesc[1000];
299: i = 0;
300: if( cType<=5 ){
301: leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
302: a += 4;
303: n += 4;
304: sprintf(zDesc, "lx: %d ", leftChild);
305: nDesc = strlen(zDesc);
306: }
307: if( cType!=5 ){
308: i = decodeVarint(a, &nPayload);
309: a += i;
310: n += i;
311: sprintf(&zDesc[nDesc], "n: %lld ", nPayload);
312: nDesc += strlen(&zDesc[nDesc]);
313: nLocal = localPayload(nPayload, cType);
314: }else{
315: nPayload = nLocal = 0;
316: }
317: if( cType==5 || cType==13 ){
318: i = decodeVarint(a, &rowid);
319: a += i;
320: n += i;
321: sprintf(&zDesc[nDesc], "r: %lld ", rowid);
322: nDesc += strlen(&zDesc[nDesc]);
323: }
324: if( nLocal<nPayload ){
325: int ovfl;
326: unsigned char *b = &a[nLocal];
327: ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3];
328: sprintf(&zDesc[nDesc], "ov: %d ", ovfl);
329: nDesc += strlen(&zDesc[nDesc]);
330: n += 4;
331: }
332: if( showCellContent && cType!=5 ){
333: nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]);
334: }
335: *pzDesc = zDesc;
336: return nLocal+n;
337: }
338:
339: /*
340: ** Decode a btree page
341: */
342: static void decode_btree_page(
343: unsigned char *a, /* Page content */
344: int pgno, /* Page number */
345: int hdrSize, /* Size of the page header. 0 or 100 */
346: char *zArgs /* Flags to control formatting */
347: ){
348: const char *zType = "unknown";
349: int nCell;
350: int i, j;
351: int iCellPtr;
352: int showCellContent = 0;
353: int showMap = 0;
354: char *zMap = 0;
355: switch( a[0] ){
356: case 2: zType = "index interior node"; break;
357: case 5: zType = "table interior node"; break;
358: case 10: zType = "index leaf"; break;
359: case 13: zType = "table leaf"; break;
360: }
361: while( zArgs[0] ){
362: switch( zArgs[0] ){
363: case 'c': showCellContent = 1; break;
364: case 'm': showMap = 1; break;
365: }
366: zArgs++;
367: }
368: printf("Decode of btree page %d:\n", pgno);
369: print_decode_line(a, 0, 1, zType);
370: print_decode_line(a, 1, 2, "Offset to first freeblock");
371: print_decode_line(a, 3, 2, "Number of cells on this page");
372: nCell = a[3]*256 + a[4];
373: print_decode_line(a, 5, 2, "Offset to cell content area");
374: print_decode_line(a, 7, 1, "Fragmented byte count");
375: if( a[0]==2 || a[0]==5 ){
376: print_decode_line(a, 8, 4, "Right child");
377: iCellPtr = 12;
378: }else{
379: iCellPtr = 8;
380: }
381: if( nCell>0 ){
382: printf(" key: lx=left-child n=payload-size r=rowid\n");
383: }
384: if( showMap ){
385: zMap = malloc(pagesize);
386: memset(zMap, '.', pagesize);
387: memset(zMap, '1', hdrSize);
388: memset(&zMap[hdrSize], 'H', iCellPtr);
389: memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell);
390: }
391: for(i=0; i<nCell; i++){
392: int cofst = iCellPtr + i*2;
393: char *zDesc;
394: int n;
395:
396: cofst = a[cofst]*256 + a[cofst+1];
397: n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc);
398: if( showMap ){
399: char zBuf[30];
400: memset(&zMap[cofst], '*', n);
401: zMap[cofst] = '[';
402: zMap[cofst+n-1] = ']';
403: sprintf(zBuf, "%d", i);
404: j = strlen(zBuf);
405: if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j);
406: }
407: printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
408: }
409: if( showMap ){
410: for(i=0; i<pagesize; i+=64){
411: printf(" %03x: %.64s\n", i, &zMap[i]);
412: }
413: free(zMap);
414: }
415: }
416:
417: /*
418: ** Decode a freelist trunk page.
419: */
420: static void decode_trunk_page(
421: int pgno, /* The page number */
422: int pagesize, /* Size of each page */
423: int detail, /* Show leaf pages if true */
424: int recursive /* Follow the trunk change if true */
425: ){
426: int n, i, k;
427: unsigned char *a;
428: while( pgno>0 ){
429: a = getContent((pgno-1)*pagesize, pagesize);
430: printf("Decode of freelist trunk page %d:\n", pgno);
431: print_decode_line(a, 0, 4, "Next freelist trunk page");
432: print_decode_line(a, 4, 4, "Number of entries on this page");
433: if( detail ){
434: n = (int)decodeInt32(&a[4]);
435: for(i=0; i<n; i++){
436: unsigned int x = decodeInt32(&a[8+4*i]);
437: char zIdx[10];
438: sprintf(zIdx, "[%d]", i);
439: printf(" %5s %7u", zIdx, x);
440: if( i%5==4 ) printf("\n");
441: }
442: if( i%5!=0 ) printf("\n");
443: }
444: if( !recursive ){
445: pgno = 0;
446: }else{
447: pgno = (int)decodeInt32(&a[0]);
448: }
449: free(a);
450: }
451: }
452:
453: /*
454: ** Print a usage comment
455: */
456: static void usage(const char *argv0){
457: fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0);
458: fprintf(stderr,
459: "args:\n"
460: " dbheader Show database header\n"
461: " NNN..MMM Show hex of pages NNN through MMM\n"
462: " NNN..end Show hex of pages NNN through end of file\n"
463: " NNNb Decode btree page NNN\n"
464: " NNNbc Decode btree page NNN and show content\n"
465: " NNNbm Decode btree page NNN and show a layout map\n"
466: " NNNt Decode freelist trunk page NNN\n"
467: " NNNtd Show leaf freelist pages on the decode\n"
468: " NNNtr Recurisvely decode freelist starting at NNN\n"
469: );
470: }
471:
472: int main(int argc, char **argv){
473: struct stat sbuf;
474: unsigned char zPgSz[2];
475: if( argc<2 ){
476: usage(argv[0]);
477: exit(1);
478: }
479: db = open(argv[1], O_RDONLY);
480: if( db<0 ){
481: fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
482: exit(1);
483: }
484: zPgSz[0] = 0;
485: zPgSz[1] = 0;
486: lseek(db, 16, SEEK_SET);
487: read(db, zPgSz, 2);
488: pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
489: if( pagesize==0 ) pagesize = 1024;
490: printf("Pagesize: %d\n", pagesize);
491: fstat(db, &sbuf);
492: mxPage = sbuf.st_size/pagesize;
493: printf("Available pages: 1..%d\n", mxPage);
494: if( argc==2 ){
495: int i;
496: for(i=1; i<=mxPage; i++) print_page(i);
497: }else{
498: int i;
499: for(i=2; i<argc; i++){
500: int iStart, iEnd;
501: char *zLeft;
502: if( strcmp(argv[i], "dbheader")==0 ){
503: print_db_header();
504: continue;
505: }
506: if( !isdigit(argv[i][0]) ){
507: fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
508: continue;
509: }
510: iStart = strtol(argv[i], &zLeft, 0);
511: if( zLeft && strcmp(zLeft,"..end")==0 ){
512: iEnd = mxPage;
513: }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
514: iEnd = strtol(&zLeft[2], 0, 0);
515: }else if( zLeft && zLeft[0]=='b' ){
516: int ofst, nByte, hdrSize;
517: unsigned char *a;
518: if( iStart==1 ){
519: ofst = hdrSize = 100;
520: nByte = pagesize-100;
521: }else{
522: hdrSize = 0;
523: ofst = (iStart-1)*pagesize;
524: nByte = pagesize;
525: }
526: a = getContent(ofst, nByte);
527: decode_btree_page(a, iStart, hdrSize, &zLeft[1]);
528: free(a);
529: continue;
530: }else if( zLeft && zLeft[0]=='t' ){
531: unsigned char *a;
532: int detail = 0;
533: int recursive = 0;
534: int i;
535: for(i=1; zLeft[i]; i++){
536: if( zLeft[i]=='r' ) recursive = 1;
537: if( zLeft[i]=='d' ) detail = 1;
538: }
539: decode_trunk_page(iStart, pagesize, detail, recursive);
540: continue;
541: }else{
542: iEnd = iStart;
543: }
544: if( iStart<1 || iEnd<iStart || iEnd>mxPage ){
545: fprintf(stderr,
546: "Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
547: mxPage);
548: exit(1);
549: }
550: while( iStart<=iEnd ){
551: print_page(iStart);
552: iStart++;
553: }
554: }
555: }
556: close(db);
557: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>