diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-02-17 17:25:57 +0000 |
|---|---|---|
| committer | <> | 2015-03-17 16:26:24 +0000 |
| commit | 780b92ada9afcf1d58085a83a0b9e6bc982203d1 (patch) | |
| tree | 598f8b9fa431b228d29897e798de4ac0c1d3d970 /lang/sql/sqlite/tool/showdb.c | |
| parent | 7a2660ba9cc2dc03a69ddfcfd95369395cc87444 (diff) | |
| download | berkeleydb-master.tar.gz | |
Diffstat (limited to 'lang/sql/sqlite/tool/showdb.c')
| -rw-r--r-- | lang/sql/sqlite/tool/showdb.c | 318 |
1 files changed, 312 insertions, 6 deletions
diff --git a/lang/sql/sqlite/tool/showdb.c b/lang/sql/sqlite/tool/showdb.c index c954153c..4d274a7a 100644 --- a/lang/sql/sqlite/tool/showdb.c +++ b/lang/sql/sqlite/tool/showdb.c @@ -6,9 +6,14 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> + +#if !defined(_MSC_VER) #include <unistd.h> +#endif + #include <stdlib.h> #include <string.h> +#include "sqlite3.h" static int pagesize = 1024; /* Size of a database page */ @@ -114,7 +119,7 @@ static unsigned char *print_byte_range( /* ** Print an entire page of content as hex */ -static print_page(int iPg){ +static void print_page(int iPg){ int iStart; unsigned char *aData; iStart = (iPg-1)*pagesize; @@ -126,7 +131,7 @@ static print_page(int iPg){ /* Print a line of decode output showing a 4-byte integer. */ -static print_decode_line( +static void print_decode_line( unsigned char *aData, /* Content being decoded */ int ofst, int nByte, /* Start and size of decode */ const char *zMsg /* Message to append */ @@ -171,7 +176,7 @@ static void print_db_header(void){ print_decode_line(aData, 56, 4, "Text encoding"); print_decode_line(aData, 60, 4, "User version"); print_decode_line(aData, 64, 4, "Incremental-vacuum mode"); - print_decode_line(aData, 68, 4, "meta[7]"); + print_decode_line(aData, 68, 4, "Application ID"); print_decode_line(aData, 72, 4, "meta[8]"); print_decode_line(aData, 76, 4, "meta[9]"); print_decode_line(aData, 80, 4, "meta[10]"); @@ -423,7 +428,7 @@ static void decode_trunk_page( int detail, /* Show leaf pages if true */ int recursive /* Follow the trunk change if true */ ){ - int n, i, k; + int n, i; unsigned char *a; while( pgno>0 ){ a = getContent((pgno-1)*pagesize, pagesize); @@ -451,6 +456,293 @@ static void decode_trunk_page( } /* +** A short text comment on the use of each page. +*/ +static char **zPageUse; + +/* +** Add a comment on the use of a page. +*/ +static void page_usage_msg(int pgno, const char *zFormat, ...){ + va_list ap; + char *zMsg; + + va_start(ap, zFormat); + zMsg = sqlite3_vmprintf(zFormat, ap); + va_end(ap); + if( pgno<=0 || pgno>mxPage ){ + printf("ERROR: page %d out of range 1..%d: %s\n", + pgno, mxPage, zMsg); + sqlite3_free(zMsg); + return; + } + if( zPageUse[pgno]!=0 ){ + printf("ERROR: page %d used multiple times:\n", pgno); + printf("ERROR: previous: %s\n", zPageUse[pgno]); + printf("ERROR: current: %s\n", zMsg); + sqlite3_free(zPageUse[pgno]); + } + zPageUse[pgno] = zMsg; +} + +/* +** Find overflow pages of a cell and describe their usage. +*/ +static void page_usage_cell( + unsigned char cType, /* Page type */ + unsigned char *a, /* Cell content */ + int pgno, /* page containing the cell */ + int cellno /* Index of the cell on the page */ +){ + int i; + int n = 0; + i64 nPayload; + i64 rowid; + int nLocal; + i = 0; + if( cType<=5 ){ + a += 4; + n += 4; + } + if( cType!=5 ){ + i = decodeVarint(a, &nPayload); + a += i; + n += i; + nLocal = localPayload(nPayload, cType); + }else{ + nPayload = nLocal = 0; + } + if( cType==5 || cType==13 ){ + i = decodeVarint(a, &rowid); + a += i; + n += i; + } + if( nLocal<nPayload ){ + int ovfl = decodeInt32(a+nLocal); + int cnt = 0; + while( ovfl && (cnt++)<mxPage ){ + page_usage_msg(ovfl, "overflow %d from cell %d of page %d", + cnt, cellno, pgno); + a = getContent((ovfl-1)*pagesize, 4); + ovfl = decodeInt32(a); + free(a); + } + } +} + + +/* +** Describe the usages of a b-tree page +*/ +static void page_usage_btree( + int pgno, /* Page to describe */ + int parent, /* Parent of this page. 0 for root pages */ + int idx, /* Which child of the parent */ + const char *zName /* Name of the table */ +){ + unsigned char *a; + const char *zType = "corrupt node"; + int nCell; + int i; + int hdr = pgno==1 ? 100 : 0; + + if( pgno<=0 || pgno>mxPage ) return; + a = getContent((pgno-1)*pagesize, pagesize); + switch( a[hdr] ){ + case 2: zType = "interior node of index"; break; + case 5: zType = "interior node of table"; break; + case 10: zType = "leaf of index"; break; + case 13: zType = "leaf of table"; break; + } + if( parent ){ + page_usage_msg(pgno, "%s [%s], child %d of page %d", + zType, zName, idx, parent); + }else{ + page_usage_msg(pgno, "root %s [%s]", zType, zName); + } + nCell = a[hdr+3]*256 + a[hdr+4]; + if( a[hdr]==2 || a[hdr]==5 ){ + int cellstart = hdr+12; + unsigned int child; + for(i=0; i<nCell; i++){ + int ofst; + + ofst = cellstart + i*2; + ofst = a[ofst]*256 + a[ofst+1]; + child = decodeInt32(a+ofst); + page_usage_btree(child, pgno, i, zName); + } + child = decodeInt32(a+cellstart-4); + page_usage_btree(child, pgno, i, zName); + } + if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){ + int cellstart = hdr + 8 + 4*(a[hdr]<=5); + for(i=0; i<nCell; i++){ + int ofst; + ofst = cellstart + i*2; + ofst = a[ofst]*256 + a[ofst+1]; + page_usage_cell(a[hdr], a+ofst, pgno, i); + } + } + free(a); +} + +/* +** Determine page usage by the freelist +*/ +static void page_usage_freelist(int pgno){ + unsigned char *a; + int cnt = 0; + int i; + int n; + int iNext; + int parent = 1; + + while( pgno>0 && pgno<=mxPage && (cnt++)<mxPage ){ + page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent); + a = getContent((pgno-1)*pagesize, pagesize); + iNext = decodeInt32(a); + n = decodeInt32(a+4); + for(i=0; i<n; i++){ + int child = decodeInt32(a + (i*4+8)); + page_usage_msg(child, "freelist leaf, child %d of trunk page %d", + i, pgno); + } + free(a); + parent = pgno; + pgno = iNext; + } +} + +/* +** Determine pages used as PTRMAP pages +*/ +static void page_usage_ptrmap(unsigned char *a){ + if( a[55] ){ + int usable = pagesize - a[20]; + int pgno = 2; + int perPage = usable/5; + while( pgno<=mxPage ){ + page_usage_msg(pgno, "PTRMAP page covering %d..%d", + pgno+1, pgno+perPage); + pgno += perPage + 1; + } + } +} + +/* +** Try to figure out how every page in the database file is being used. +*/ +static void page_usage_report(const char *zDbName){ + int i, j; + int rc; + sqlite3 *db; + sqlite3_stmt *pStmt; + unsigned char *a; + char zQuery[200]; + + /* Avoid the pathological case */ + if( mxPage<1 ){ + printf("empty database\n"); + return; + } + + /* Open the database file */ + rc = sqlite3_open(zDbName, &db); + if( rc ){ + printf("cannot open database: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + return; + } + + /* Set up global variables zPageUse[] and mxPage to record page + ** usages */ + zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) ); + if( zPageUse==0 ) out_of_memory(); + memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1)); + + /* Discover the usage of each page */ + a = getContent(0, 100); + page_usage_freelist(decodeInt32(a+32)); + page_usage_ptrmap(a); + free(a); + page_usage_btree(1, 0, 0, "sqlite_master"); + sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0); + for(j=0; j<2; j++){ + sqlite3_snprintf(sizeof(zQuery), zQuery, + "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage" + " ORDER BY rowid %s", j?"DESC":""); + rc = sqlite3_prepare_v2(db, zQuery, -1, &pStmt, 0); + if( rc==SQLITE_OK ){ + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + int pgno = sqlite3_column_int(pStmt, 2); + page_usage_btree(pgno, 0, 0, (const char*)sqlite3_column_text(pStmt,1)); + } + }else{ + printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db)); + } + rc = sqlite3_finalize(pStmt); + if( rc==SQLITE_OK ) break; + } + sqlite3_close(db); + + /* Print the report and free memory used */ + for(i=1; i<=mxPage; i++){ + printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???"); + sqlite3_free(zPageUse[i]); + } + sqlite3_free(zPageUse); + zPageUse = 0; +} + +/* +** Try to figure out how every page in the database file is being used. +*/ +static void ptrmap_coverage_report(const char *zDbName){ + unsigned int pgno; + unsigned char *aHdr; + unsigned char *a; + int usable; + int perPage; + unsigned int i; + + /* Avoid the pathological case */ + if( mxPage<1 ){ + printf("empty database\n"); + return; + } + + /* Make sure PTRMAPs are used in this database */ + aHdr = getContent(0, 100); + if( aHdr[55]==0 ){ + printf("database does not use PTRMAP pages\n"); + return; + } + usable = pagesize - aHdr[20]; + perPage = usable/5; + free(aHdr); + printf("%5d: root of sqlite_master\n", 1); + for(pgno=2; pgno<=mxPage; pgno += perPage+1){ + printf("%5d: PTRMAP page covering %d..%d\n", pgno, + pgno+1, pgno+perPage); + a = getContent((pgno-1)*pagesize, usable); + for(i=0; i+5<=usable && pgno+1+i/5<=mxPage; i+=5){ + const char *zType = "???"; + unsigned int iFrom = decodeInt32(&a[i+1]); + switch( a[i] ){ + case 1: zType = "b-tree root page"; break; + case 2: zType = "freelist page"; break; + case 3: zType = "first page of overflow"; break; + case 4: zType = "later page of overflow"; break; + case 5: zType = "b-tree non-root page"; break; + } + printf("%5d: %s, parent=%u\n", pgno+1+i/5, zType, iFrom); + } + free(a); + } +} + +/* ** Print a usage comment */ static void usage(const char *argv0){ @@ -458,13 +750,15 @@ static void usage(const char *argv0){ fprintf(stderr, "args:\n" " dbheader Show database header\n" + " pgidx Index of how each page is used\n" + " ptrmap Show all PTRMAP page content\n" " NNN..MMM Show hex of pages NNN through MMM\n" " NNN..end Show hex of pages NNN through end of file\n" " NNNb Decode btree page NNN\n" " NNNbc Decode btree page NNN and show content\n" " NNNbm Decode btree page NNN and show a layout map\n" " NNNt Decode freelist trunk page NNN\n" - " NNNtd Show leave freelist pages on the decode\n" + " NNNtd Show leaf freelist pages on the decode\n" " NNNtr Recurisvely decode freelist starting at NNN\n" ); } @@ -503,6 +797,18 @@ int main(int argc, char **argv){ print_db_header(); continue; } + if( strcmp(argv[i], "pgidx")==0 ){ + page_usage_report(argv[1]); + continue; + } + if( strcmp(argv[i], "ptrmap")==0 ){ + ptrmap_coverage_report(argv[1]); + continue; + } + if( strcmp(argv[i], "help")==0 ){ + usage(argv[0]); + continue; + } if( !isdigit(argv[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); continue; @@ -528,7 +834,6 @@ int main(int argc, char **argv){ free(a); continue; }else if( zLeft && zLeft[0]=='t' ){ - unsigned char *a; int detail = 0; int recursive = 0; int i; @@ -554,4 +859,5 @@ int main(int argc, char **argv){ } } close(db); + return 0; } |
