diff options
Diffstat (limited to 'tool/showdb.c')
-rw-r--r-- | tool/showdb.c | 279 |
1 files changed, 238 insertions, 41 deletions
diff --git a/tool/showdb.c b/tool/showdb.c index 27424e0..1a51e9d 100644 --- a/tool/showdb.c +++ b/tool/showdb.c @@ -9,6 +9,8 @@ #if !defined(_MSC_VER) #include <unistd.h> +#else +#include <io.h> #endif #include <stdlib.h> @@ -66,7 +68,7 @@ static unsigned char *getContent(int ofst, int nByte){ if( aData==0 ) out_of_memory(); memset(aData, 0, nByte+32); lseek(db, ofst, SEEK_SET); - read(db, aData, nByte); + if( read(db, aData, nByte)<nByte ) memset(aData, 0, nByte); return aData; } @@ -119,7 +121,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; @@ -129,9 +131,10 @@ static print_page(int iPg){ free(aData); } + /* 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 */ @@ -140,7 +143,7 @@ static print_decode_line( int val = aData[ofst]; char zBuf[100]; sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]); - i = strlen(zBuf); + i = (int)strlen(zBuf); for(j=1; j<4; j++){ if( j>=nByte ){ sprintf(&zBuf[i], " "); @@ -148,7 +151,7 @@ static print_decode_line( sprintf(&zBuf[i], " %02x", aData[ofst+j]); val = val*256 + aData[ofst+j]; } - i += strlen(&zBuf[i]); + i += (int)strlen(&zBuf[i]); } sprintf(&zBuf[i], " %9d", val); printf("%s %s\n", zBuf, zMsg); @@ -189,14 +192,14 @@ static void print_db_header(void){ /* ** Describe cell content. */ -static int describeContent( +static i64 describeContent( unsigned char *a, /* Cell content */ - int nLocal, /* Bytes in a[] */ + i64 nLocal, /* Bytes in a[] */ char *zDesc /* Write description here */ ){ - int nDesc = 0; - int n, i, j; - i64 x, v; + i64 nDesc = 0; + int n, j; + i64 i, x, v; const unsigned char *pData; const unsigned char *pLimit; char sep = ' '; @@ -236,15 +239,15 @@ static int describeContent( }else if( x==9 ){ sprintf(zDesc, "1"); }else if( x>=12 ){ - int size = (x-12)/2; + i64 size = (x-12)/2; if( (x&1)==0 ){ - sprintf(zDesc, "blob(%d)", size); + sprintf(zDesc, "blob(%lld)", size); }else{ - sprintf(zDesc, "txt(%d)", size); + sprintf(zDesc, "txt(%lld)", size); } pData += size; } - j = strlen(zDesc); + j = (int)strlen(zDesc); zDesc += j; nDesc += j; } @@ -255,11 +258,11 @@ static int describeContent( ** Compute the local payload size given the total payload size and ** the page size. */ -static int localPayload(i64 nPayload, char cType){ - int maxLocal; - int minLocal; - int surplus; - int nLocal; +static i64 localPayload(i64 nPayload, char cType){ + i64 maxLocal; + i64 minLocal; + i64 surplus; + i64 nLocal; if( cType==13 ){ /* Table leaf */ maxLocal = pagesize-35; @@ -287,19 +290,19 @@ static int localPayload(i64 nPayload, char cType){ ** ** The return value is the local cell size. */ -static int describeCell( +static i64 describeCell( unsigned char cType, /* Page type */ unsigned char *a, /* Cell content */ int showCellContent, /* Show cell content if true */ char **pzDesc /* Store description here */ ){ int i; - int nDesc = 0; + i64 nDesc = 0; int n = 0; int leftChild; i64 nPayload; i64 rowid; - int nLocal; + i64 nLocal; static char zDesc[1000]; i = 0; if( cType<=5 ){ @@ -341,6 +344,180 @@ static int describeCell( return nLocal+n; } +/* Print an offset followed by nByte bytes. Add extra white-space +** at the end so that subsequent text is aligned. +*/ +static void printBytes( + unsigned char *aData, /* Content being decoded */ + unsigned char *aStart, /* Start of content to be printed */ + int nByte /* Number of bytes to print */ +){ + int j; + printf(" %03x: ", (int)(aStart-aData)); + for(j=0; j<9; j++){ + if( j>=nByte ){ + printf(" "); + }else{ + printf("%02x ", aStart[j]); + } + } +} + + +/* +** Write a full decode on stdout for the cell at a[ofst]. +** Assume the page contains a header of size szPgHdr bytes. +*/ +static void decodeCell( + unsigned char *a, /* Page content (without the page-1 header) */ + unsigned pgno, /* Page number */ + int iCell, /* Cell index */ + int szPgHdr, /* Size of the page header. 0 or 100 */ + int ofst /* Cell begins at a[ofst] */ +){ + int i, j; + int leftChild; + i64 k; + i64 nPayload; + i64 rowid; + i64 nHdr; + i64 iType; + i64 nLocal; + unsigned char *x = a + ofst; + unsigned char *end; + unsigned char cType = a[0]; + int nCol = 0; + int szCol[2000]; + int ofstCol[2000]; + int typeCol[2000]; + + printf("Cell[%d]:\n", iCell); + if( cType<=5 ){ + leftChild = ((x[0]*256 + x[1])*256 + x[2])*256 + x[3]; + printBytes(a, x, 4); + printf("left child page:: %d\n", leftChild); + x += 4; + } + if( cType!=5 ){ + i = decodeVarint(x, &nPayload); + printBytes(a, x, i); + nLocal = localPayload(nPayload, cType); + if( nLocal==nPayload ){ + printf("payload-size: %lld\n", nPayload); + }else{ + printf("payload-size: %lld (%lld local, %lld overflow)\n", + nPayload, nLocal, nPayload-nLocal); + } + x += i; + }else{ + nPayload = nLocal = 0; + } + end = x + nLocal; + if( cType==5 || cType==13 ){ + i = decodeVarint(x, &rowid); + printBytes(a, x, i); + printf("rowid: %lld\n", rowid); + x += i; + } + if( nLocal>0 ){ + i = decodeVarint(x, &nHdr); + printBytes(a, x, i); + printf("record-header-size: %d\n", (int)nHdr); + j = i; + nCol = 0; + k = nHdr; + while( x+j<end && j<nHdr ){ + const char *zTypeName; + int sz = 0; + char zNm[30]; + i = decodeVarint(x+j, &iType); + printBytes(a, x+j, i); + printf("typecode[%d]: %d - ", nCol, (int)iType); + switch( iType ){ + case 0: zTypeName = "NULL"; sz = 0; break; + case 1: zTypeName = "int8"; sz = 1; break; + case 2: zTypeName = "int16"; sz = 2; break; + case 3: zTypeName = "int24"; sz = 3; break; + case 4: zTypeName = "int32"; sz = 4; break; + case 5: zTypeName = "int48"; sz = 6; break; + case 6: zTypeName = "int64"; sz = 8; break; + case 7: zTypeName = "double"; sz = 8; break; + case 8: zTypeName = "zero"; sz = 0; break; + case 9: zTypeName = "one"; sz = 0; break; + case 10: + case 11: zTypeName = "error"; sz = 0; break; + default: { + sz = (int)(iType-12)/2; + sprintf(zNm, (iType&1)==0 ? "blob(%d)" : "text(%d)", sz); + zTypeName = zNm; + break; + } + } + printf("%s\n", zTypeName); + szCol[nCol] = sz; + ofstCol[nCol] = (int)k; + typeCol[nCol] = (int)iType; + k += sz; + nCol++; + j += i; + } + for(i=0; i<nCol && ofstCol[i]+szCol[i]<=nLocal; i++){ + int s = ofstCol[i]; + i64 v; + const unsigned char *pData; + if( szCol[i]==0 ) continue; + printBytes(a, x+s, szCol[i]); + printf("data[%d]: ", i); + pData = x+s; + if( typeCol[i]<=7 ){ + v = (signed char)pData[0]; + for(k=1; k<szCol[i]; k++){ + v = (v<<8) + pData[k]; + } + if( typeCol[i]==7 ){ + double r; + memcpy(&r, &v, sizeof(r)); + printf("%#g\n", r); + }else{ + printf("%lld\n", v); + } + }else{ + int ii, jj; + char zConst[32]; + if( (typeCol[i]&1)==0 ){ + zConst[0] = 'x'; + zConst[1] = '\''; + for(ii=2, jj=0; jj<szCol[i] && ii<24; jj++, ii+=2){ + sprintf(zConst+ii, "%02x", pData[jj]); + } + }else{ + zConst[0] = '\''; + for(ii=1, jj=0; jj<szCol[i] && ii<24; jj++, ii++){ + zConst[ii] = isprint(pData[jj]) ? pData[jj] : '.'; + } + zConst[ii] = 0; + } + if( jj<szCol[i] ){ + memcpy(zConst+ii, "...'", 5); + }else{ + memcpy(zConst+ii, "'", 2); + } + printf("%s\n", zConst); + } + j = ofstCol[i] + szCol[i]; + } + } + if( j<nLocal ){ + printBytes(a, x+j, 0); + printf("... %lld bytes of content ...\n", nLocal-j); + } + if( nLocal<nPayload ){ + printBytes(a, x+nLocal, 4); + printf("overflow-page: %d\n", decodeInt32(x+nLocal)); + } +} + + /* ** Decode a btree page */ @@ -356,6 +533,7 @@ static void decode_btree_page( int iCellPtr; int showCellContent = 0; int showMap = 0; + int cellToDecode = -2; char *zMap = 0; switch( a[0] ){ case 2: zType = "index interior node"; break; @@ -367,23 +545,37 @@ static void decode_btree_page( switch( zArgs[0] ){ case 'c': showCellContent = 1; break; case 'm': showMap = 1; break; + case 'd': { + if( !isdigit(zArgs[1]) ){ + cellToDecode = -1; + }else{ + cellToDecode = 0; + while( isdigit(zArgs[1]) ){ + zArgs++; + cellToDecode = cellToDecode*10 + zArgs[0] - '0'; + } + } + break; + } } zArgs++; } - printf("Decode of btree page %d:\n", pgno); + nCell = a[3]*256 + a[4]; + iCellPtr = (a[0]==2 || a[0]==5) ? 12 : 8; + if( cellToDecode>=nCell ){ + printf("Page %d has only %d cells\n", pgno, nCell); + return; + } + printf("Header on btree page %d:\n", pgno); print_decode_line(a, 0, 1, zType); print_decode_line(a, 1, 2, "Offset to first freeblock"); print_decode_line(a, 3, 2, "Number of cells on this page"); - nCell = a[3]*256 + a[4]; print_decode_line(a, 5, 2, "Offset to cell content area"); print_decode_line(a, 7, 1, "Fragmented byte count"); if( a[0]==2 || a[0]==5 ){ print_decode_line(a, 8, 4, "Right child"); - iCellPtr = 12; - }else{ - iCellPtr = 8; } - if( nCell>0 ){ + if( cellToDecode==(-2) && nCell>0 ){ printf(" key: lx=left-child n=payload-size r=rowid\n"); } if( showMap ){ @@ -396,27 +588,32 @@ static void decode_btree_page( for(i=0; i<nCell; i++){ int cofst = iCellPtr + i*2; char *zDesc; - int n; + i64 n; cofst = a[cofst]*256 + a[cofst+1]; n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc); if( showMap ){ char zBuf[30]; - memset(&zMap[cofst], '*', n); + memset(&zMap[cofst], '*', (size_t)n); zMap[cofst] = '['; zMap[cofst+n-1] = ']'; sprintf(zBuf, "%d", i); - j = strlen(zBuf); + j = (int)strlen(zBuf); if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j); } - printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); + if( cellToDecode==(-2) ){ + printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); + }else if( cellToDecode==(-1) || cellToDecode==i ){ + decodeCell(a, pgno, i, hdrSize, cofst-hdrSize); + } } if( showMap ){ + printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n"); for(i=0; i<pagesize; i+=64){ printf(" %03x: %.64s\n", i, &zMap[i]); } free(zMap); - } + } } /* @@ -428,7 +625,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); @@ -495,11 +692,10 @@ static void page_usage_cell( int cellno /* Index of the cell on the page */ ){ int i; - int nDesc = 0; int n = 0; i64 nPayload; i64 rowid; - int nLocal; + i64 nLocal; i = 0; if( cType<=5 ){ a += 4; @@ -677,7 +873,7 @@ static void page_usage_report(const char *zDbName){ if( rc==SQLITE_OK ){ while( sqlite3_step(pStmt)==SQLITE_ROW ){ int pgno = sqlite3_column_int(pStmt, 2); - page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1)); + page_usage_btree(pgno, 0, 0, (const char*)sqlite3_column_text(pStmt,1)); } }else{ printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db)); @@ -700,12 +896,12 @@ static void page_usage_report(const char *zDbName){ ** 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; + int pgno; unsigned char *aHdr; unsigned char *a; int usable; int perPage; - unsigned int i; + int i; /* Avoid the pathological case */ if( mxPage<1 ){ @@ -758,6 +954,7 @@ static void usage(const char *argv0){ " 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" + " NNNbdCCC Decode cell CCC on btree page NNN\n" " NNNt Decode freelist trunk page NNN\n" " NNNtd Show leaf freelist pages on the decode\n" " NNNtr Recurisvely decode freelist starting at NNN\n" @@ -779,7 +976,7 @@ int main(int argc, char **argv){ zPgSz[0] = 0; zPgSz[1] = 0; lseek(db, 16, SEEK_SET); - read(db, zPgSz, 2); + if( read(db, zPgSz, 2)<2 ) memset(zPgSz, 0, 2); pagesize = zPgSz[0]*256 + zPgSz[1]*65536; if( pagesize==0 ) pagesize = 1024; printf("Pagesize: %d\n", pagesize); @@ -835,7 +1032,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; @@ -861,4 +1057,5 @@ int main(int argc, char **argv){ } } close(db); + return 0; } |