Merge in recent changes from the trunk
FossilOrigin-Name: 7a0ac682c3bffcb345321fe97434563350ac90f9
This commit is contained in:
commit
29d4beccc0
34
manifest
34
manifest
@ -1,5 +1,8 @@
|
||||
C Do\snot\sattempt\sto\sset\sjournal_mode=wal\son\s:memory:\sor\stemp\sfile\sdatabases.
|
||||
D 2010-04-26T17:42:56
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Merge\sin\srecent\schanges\sfrom\sthe\strunk
|
||||
D 2010-04-27T01:56:22
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in d83a0ffef3dcbfb08b410a6c6dd6c009ec9167fb
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@ -118,10 +121,10 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 51553a859994d01d8bf3500747f66a890c459774
|
||||
F src/date.c 485a4409a384310e6d93fd1104a9d0a8658becd9
|
||||
F src/delete.c 610dc008e88a9599f905f5cbe9577ac9c36e0581
|
||||
F src/expr.c 6baed2a0448d494233d9c0a610eea018ab386a32
|
||||
F src/expr.c 286f62b24217ade1c14ba56de413ffdd607b6a41
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
|
||||
F src/func.c b4af81088b1ad2ceea42d70a7aa048a48d18733f
|
||||
F src/func.c 0c28599430856631216b6c0131c51c89bf516026
|
||||
F src/global.c 5a9c1e3c93213ca574786ac1caa976ce8f709105
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
@ -158,17 +161,17 @@ F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 6dc1871ce8ead9187161c370a58cd06c84221f76
|
||||
F src/pragma.c bae3ce82ca6d0ac5d3ca3e46b286856d1f0ddd70
|
||||
F src/pragma.c 5ba364af022d9dbdfb39daf4fd26cbf26571fc0e
|
||||
F src/prepare.c fd1398cb1da54385ba5bd68d93928f10d10a1d9c
|
||||
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c b7c9a40bc1567bceff52ad4b73108734ee4bf268
|
||||
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
|
||||
F src/shell.c c40427c7245535a04a9cb4a417b6cc05c022e6a4
|
||||
F src/sqlite.h.in 96b0bed7825da354119a9742a83033087c537133
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h de668d16e73ef456b940ab3f60b2ac8842957853
|
||||
F src/sqliteInt.h 700a2df7b8dfe57c3b8d83c52ff40928e026220c
|
||||
F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
|
||||
F src/status.c 4df6fe7dce2d256130b905847c6c60055882bdbe
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -797,7 +800,7 @@ F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/shell1.test ef08a3e738b9fee4fc228920956950bc35db0575
|
||||
F tool/shell2.test 8f51f61c13b88618e71c17439fe0847c2421c5d1
|
||||
F tool/shell3.test ff663e83100670a295d473515c12beb8103a78b6
|
||||
F tool/showdb.c 8ab8b3b53884312aafb7ef60982e255a6c31d238
|
||||
F tool/showdb.c 12fbece85695e3a61bdb4f7607b61f264120c4b6
|
||||
F tool/showjournal.c ec3b171be148656827c4949fbfb8ab4370822f87
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
|
||||
@ -808,7 +811,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 6a944f028d4a070bef29e1fbc6fbef481ebcd34c
|
||||
R 74f903b2272910b858a0c5c9e03f5db8
|
||||
U dan
|
||||
Z 9dd751e835cbcac366a5e64c32910528
|
||||
P 30d0134454734fd9335896372c30a903e9adcc64 ca9d86baf70f210d331ce93102177c8005c494cb
|
||||
R b0a15978d17250dbff5ca26f38578573
|
||||
U drh
|
||||
Z 50883e064ff8d31e35ff6084caafc75f
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFL1kRKoxKgR168RlERAhGtAJ0ZNNVfZUQ2rD2DR5znbRsfpO0FrQCeMGjZ
|
||||
bgsVZnQebWJklqCayCQA1Cc=
|
||||
=MFJQ
|
||||
-----END PGP SIGNATURE-----
|
||||
|
@ -1 +1 @@
|
||||
30d0134454734fd9335896372c30a903e9adcc64
|
||||
7a0ac682c3bffcb345321fe97434563350ac90f9
|
39
src/expr.c
39
src/expr.c
@ -3440,7 +3440,6 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
** an incorrect 0 or 1 could lead to a malfunction.
|
||||
*/
|
||||
int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
int i;
|
||||
if( pA==0||pB==0 ){
|
||||
return pB==pA ? 0 : 2;
|
||||
}
|
||||
@ -3453,18 +3452,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
if( pA->op!=pB->op ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
|
||||
|
||||
if( pA->x.pList && pB->x.pList ){
|
||||
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 2;
|
||||
for(i=0; i<pA->x.pList->nExpr; i++){
|
||||
Expr *pExprA = pA->x.pList->a[i].pExpr;
|
||||
Expr *pExprB = pB->x.pList->a[i].pExpr;
|
||||
if( sqlite3ExprCompare(pExprA, pExprB) ) return 2;
|
||||
}
|
||||
}else if( pA->x.pList || pB->x.pList ){
|
||||
return 2;
|
||||
}
|
||||
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
|
||||
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( ExprHasProperty(pA, EP_IntValue) ){
|
||||
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
|
||||
@ -3481,6 +3469,31 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare two ExprList objects. Return 0 if they are identical and
|
||||
** non-zero if they differ in any way.
|
||||
**
|
||||
** This routine might return non-zero for equivalent ExprLists. The
|
||||
** only consequence will be disabled optimizations. But this routine
|
||||
** must never return 0 if the two ExprList objects are different, or
|
||||
** a malfunction will result.
|
||||
**
|
||||
** Two NULL pointers are considered to be the same. But a NULL pointer
|
||||
** always differs from a non-NULL pointer.
|
||||
*/
|
||||
int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
|
||||
int i;
|
||||
if( pA==0 && pB==0 ) return 0;
|
||||
if( pA==0 || pB==0 ) return 1;
|
||||
if( pA->nExpr!=pB->nExpr ) return 1;
|
||||
for(i=0; i<pA->nExpr; i++){
|
||||
Expr *pExprA = pA->a[i].pExpr;
|
||||
Expr *pExprB = pB->a[i].pExpr;
|
||||
if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
|
||||
if( sqlite3ExprCompare(pExprA, pExprB) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a new element to the pAggInfo->aCol[] array. Return the index of
|
||||
|
16
src/func.c
16
src/func.c
@ -1411,17 +1411,15 @@ static void groupConcatFinalize(sqlite3_context *context){
|
||||
}
|
||||
|
||||
/*
|
||||
** This function registered all of the above C functions as SQL
|
||||
** functions. This should be the only routine in this file with
|
||||
** external linkage.
|
||||
** This routine does per-connection function registration. Most
|
||||
** of the built-in functions above are part of the global function set.
|
||||
** This routine only deals with those that are not global.
|
||||
*/
|
||||
void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
if( !db->mallocFailed ){
|
||||
int rc = sqlite3_overload_function(db, "MATCH", 2);
|
||||
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
int rc = sqlite3_overload_function(db, "MATCH", 2);
|
||||
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
14
src/pragma.c
14
src/pragma.c
@ -351,11 +351,11 @@ void sqlite3Pragma(
|
||||
** page cache size value and the persistent page cache size value
|
||||
** stored in the database file.
|
||||
**
|
||||
** The default cache size is stored in meta-value 2 of page 1 of the
|
||||
** database file. The cache size is actually the absolute value of
|
||||
** this memory location. The sign of meta-value 2 determines the
|
||||
** synchronous setting. A negative value means synchronous is off
|
||||
** and a positive value means synchronous is on.
|
||||
** Older versions of SQLite would set the default cache size to a
|
||||
** negative number to indicate synchronous=OFF. These days, synchronous
|
||||
** is always on by default regardless of the sign of the default cache
|
||||
** size. But continue to take the absolute value of the default cache
|
||||
** size of historical compatibility.
|
||||
*/
|
||||
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
|
||||
static const VdbeOpList getCacheSize[] = {
|
||||
@ -384,10 +384,6 @@ void sqlite3Pragma(
|
||||
if( size<0 ) size = -size;
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, BTREE_DEFAULT_CACHE_SIZE);
|
||||
addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
|
12
src/select.c
12
src/select.c
@ -3718,6 +3718,18 @@ int sqlite3Select(
|
||||
isDistinct = 0;
|
||||
}
|
||||
|
||||
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
||||
** identical, then disable the ORDER BY clause since the GROUP BY
|
||||
** will cause elements to come out in the correct order. This is
|
||||
** an optimization - the correct answer should result regardless.
|
||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
|
||||
** to disable this optimization for testing purposes.
|
||||
*/
|
||||
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
|
||||
&& (db->flags & SQLITE_GroupByOrder)==0 ){
|
||||
pOrderBy = 0;
|
||||
}
|
||||
|
||||
/* If there is an ORDER BY clause, then this sorting
|
||||
** index might end up being unused if the data can be
|
||||
** extracted in pre-sorted order. If that is the case, then the
|
||||
|
@ -927,7 +927,8 @@ struct sqlite3 {
|
||||
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
|
||||
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
|
||||
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
|
||||
#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
|
||||
#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
|
||||
#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
@ -2691,6 +2692,7 @@ void sqlite3Vacuum(Parse*);
|
||||
int sqlite3RunVacuum(char**, sqlite3*);
|
||||
char *sqlite3NameFromToken(sqlite3*, Token*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*);
|
||||
int sqlite3ExprListCompare(ExprList*, ExprList*);
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||
Vdbe *sqlite3GetVdbe(Parse*);
|
||||
|
267
tool/showdb.c
267
tool/showdb.c
@ -8,41 +8,247 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static int pagesize = 1024;
|
||||
static int db = -1;
|
||||
static int mxPage = 0;
|
||||
static int perLine = 32;
|
||||
static int pagesize = 1024; /* Size of a database page */
|
||||
static int db = -1; /* File descriptor for reading the DB */
|
||||
static int mxPage = 0; /* Last page number */
|
||||
static int perLine = 16; /* HEX elements to print per line */
|
||||
|
||||
typedef long long int i64; /* Datatype for 64-bit integers */
|
||||
|
||||
|
||||
/*
|
||||
** Convert the var-int format into i64. Return the number of bytes
|
||||
** in the var-int. Write the var-int value into *pVal.
|
||||
*/
|
||||
static int decodeVarint(const unsigned char *z, i64 *pVal){
|
||||
i64 v = 0;
|
||||
int i;
|
||||
for(i=0; i<8; i++){
|
||||
v = (v<<7) + (z[i]&0x7f);
|
||||
if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
|
||||
}
|
||||
v = (v<<8) + (z[i]&0xff);
|
||||
*pVal = v;
|
||||
return 9;
|
||||
}
|
||||
|
||||
/* Report an out-of-memory error and die.
|
||||
*/
|
||||
static void out_of_memory(void){
|
||||
fprintf(stderr,"Out of memory...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static print_page(int iPg){
|
||||
/*
|
||||
** Read content from the file.
|
||||
**
|
||||
** Space to hold the content is obtained from malloc() and needs to be
|
||||
** freed by the caller.
|
||||
*/
|
||||
static unsigned char *getContent(int ofst, int nByte){
|
||||
unsigned char *aData;
|
||||
aData = malloc(nByte);
|
||||
if( aData==0 ) out_of_memory();
|
||||
lseek(db, ofst, SEEK_SET);
|
||||
read(db, aData, nByte);
|
||||
return aData;
|
||||
}
|
||||
|
||||
/*
|
||||
** Print a range of bytes as hex and as ascii.
|
||||
*/
|
||||
static unsigned char *print_byte_range(
|
||||
int ofst, /* First byte in the range of bytes to print */
|
||||
int nByte, /* Number of bytes to print */
|
||||
int printOfst /* Add this amount to the index on the left column */
|
||||
){
|
||||
unsigned char *aData;
|
||||
int i, j;
|
||||
aData = malloc(pagesize);
|
||||
if( aData==0 ) out_of_memory();
|
||||
lseek(db, (iPg-1)*(long long int)pagesize, SEEK_SET);
|
||||
read(db, aData, pagesize);
|
||||
fprintf(stdout, "Page %d:\n", iPg);
|
||||
for(i=0; i<pagesize; i += perLine){
|
||||
fprintf(stdout, " %03x: ",i);
|
||||
const char *zOfstFmt;
|
||||
|
||||
if( ((printOfst+nByte)&~0xfff)==0 ){
|
||||
zOfstFmt = " %03x: ";
|
||||
}else if( ((printOfst+nByte)&~0xffff)==0 ){
|
||||
zOfstFmt = " %04x: ";
|
||||
}else if( ((printOfst+nByte)&~0xfffff)==0 ){
|
||||
zOfstFmt = " %05x: ";
|
||||
}else if( ((printOfst+nByte)&~0xffffff)==0 ){
|
||||
zOfstFmt = " %06x: ";
|
||||
}else{
|
||||
zOfstFmt = " %08x: ";
|
||||
}
|
||||
|
||||
aData = getContent(ofst, nByte);
|
||||
for(i=0; i<nByte; i += perLine){
|
||||
fprintf(stdout, zOfstFmt, i+printOfst);
|
||||
for(j=0; j<perLine; j++){
|
||||
fprintf(stdout,"%02x ", aData[i+j]);
|
||||
if( i+j>nByte ){
|
||||
fprintf(stdout, " ");
|
||||
}else{
|
||||
fprintf(stdout,"%02x ", aData[i+j]);
|
||||
}
|
||||
}
|
||||
for(j=0; j<perLine; j++){
|
||||
fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
|
||||
if( i+j>nByte ){
|
||||
fprintf(stdout, " ");
|
||||
}else{
|
||||
fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
|
||||
}
|
||||
}
|
||||
fprintf(stdout,"\n");
|
||||
}
|
||||
return aData;
|
||||
}
|
||||
|
||||
/*
|
||||
** Print an entire page of content as hex
|
||||
*/
|
||||
static print_page(int iPg){
|
||||
int iStart;
|
||||
unsigned char *aData;
|
||||
iStart = (iPg-1)*pagesize;
|
||||
fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n",
|
||||
iPg, iStart, iStart+pagesize-1);
|
||||
aData = print_byte_range(iStart, pagesize, 0);
|
||||
free(aData);
|
||||
}
|
||||
|
||||
/* Print a line of decode output showing a 4-byte integer.
|
||||
*/
|
||||
static print_decode_line(
|
||||
unsigned char *aData, /* Content being decoded */
|
||||
int ofst, int nByte, /* Start and size of decode */
|
||||
const char *zMsg /* Message to append */
|
||||
){
|
||||
int i, j;
|
||||
int val = aData[ofst];
|
||||
char zBuf[100];
|
||||
sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
|
||||
i = strlen(zBuf);
|
||||
for(j=1; j<4; j++){
|
||||
if( j>=nByte ){
|
||||
sprintf(&zBuf[i], " ");
|
||||
}else{
|
||||
sprintf(&zBuf[i], " %02x", aData[ofst+j]);
|
||||
val = val*256 + aData[ofst+j];
|
||||
}
|
||||
i += strlen(&zBuf[i]);
|
||||
}
|
||||
sprintf(&zBuf[i], " %9d", val);
|
||||
printf("%s %s\n", zBuf, zMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode the database header.
|
||||
*/
|
||||
static void print_db_header(void){
|
||||
unsigned char *aData;
|
||||
aData = print_byte_range(0, 100, 0);
|
||||
printf("Decoded:\n");
|
||||
print_decode_line(aData, 16, 2, "Database page size");
|
||||
print_decode_line(aData, 18, 1, "File format write version");
|
||||
print_decode_line(aData, 19, 1, "File format read version");
|
||||
print_decode_line(aData, 20, 1, "Reserved space at end of page");
|
||||
print_decode_line(aData, 24, 4, "File change counter");
|
||||
print_decode_line(aData, 28, 4, "Size of database in pages");
|
||||
print_decode_line(aData, 32, 4, "Page number of first freelist page");
|
||||
print_decode_line(aData, 36, 4, "Number of freelist pages");
|
||||
print_decode_line(aData, 40, 4, "Schema cookie");
|
||||
print_decode_line(aData, 44, 4, "Schema format version");
|
||||
print_decode_line(aData, 48, 4, "Default page cache size");
|
||||
print_decode_line(aData, 52, 4, "Largest auto-vac root page");
|
||||
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, 72, 4, "meta[8]");
|
||||
print_decode_line(aData, 76, 4, "meta[9]");
|
||||
print_decode_line(aData, 80, 4, "meta[10]");
|
||||
print_decode_line(aData, 84, 4, "meta[11]");
|
||||
print_decode_line(aData, 88, 4, "meta[12]");
|
||||
print_decode_line(aData, 92, 4, "meta[13]");
|
||||
print_decode_line(aData, 96, 4, "SQLite version number");
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a description for a single cell.
|
||||
*/
|
||||
static int describeCell(unsigned char cType, unsigned char *a, char **pzDesc){
|
||||
int i;
|
||||
int nDesc = 0;
|
||||
int n = 0;
|
||||
int leftChild;
|
||||
i64 nPayload;
|
||||
i64 rowid;
|
||||
static char zDesc[100];
|
||||
i = 0;
|
||||
if( cType<=5 ){
|
||||
leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
|
||||
a += 4;
|
||||
n += 4;
|
||||
sprintf(zDesc, "left-child: %d ", leftChild);
|
||||
nDesc = strlen(zDesc);
|
||||
}
|
||||
if( cType!=5 ){
|
||||
i = decodeVarint(a, &nPayload);
|
||||
a += i;
|
||||
n += i;
|
||||
sprintf(&zDesc[nDesc], "sz: %lld ", nPayload);
|
||||
nDesc += strlen(&zDesc[nDesc]);
|
||||
}
|
||||
if( cType==5 || cType==13 ){
|
||||
i = decodeVarint(a, &rowid);
|
||||
a += i;
|
||||
n += i;
|
||||
sprintf(&zDesc[nDesc], "rowid: %lld ", rowid);
|
||||
nDesc += strlen(&zDesc[nDesc]);
|
||||
}
|
||||
*pzDesc = zDesc;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode a btree page
|
||||
*/
|
||||
static void decode_btree_page(unsigned char *a, int pgno, int hdrSize){
|
||||
const char *zType = "unknown";
|
||||
int nCell;
|
||||
int i;
|
||||
int iCellPtr;
|
||||
switch( a[0] ){
|
||||
case 2: zType = "index interior node"; break;
|
||||
case 5: zType = "table interior node"; break;
|
||||
case 10: zType = "index leaf"; break;
|
||||
case 13: zType = "table leaf"; break;
|
||||
}
|
||||
printf("Decode of 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;
|
||||
}
|
||||
for(i=0; i<nCell; i++){
|
||||
int cofst = iCellPtr + i*2;
|
||||
char *zDesc;
|
||||
cofst = a[cofst]*256 + a[cofst+1];
|
||||
describeCell(a[0], &a[cofst-hdrSize], &zDesc);
|
||||
printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct stat sbuf;
|
||||
unsigned char zPgSz[2];
|
||||
if( argc<2 ){
|
||||
fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]);
|
||||
exit(1);
|
||||
@ -52,8 +258,16 @@ int main(int argc, char **argv){
|
||||
fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
zPgSz[0] = 0;
|
||||
zPgSz[1] = 0;
|
||||
lseek(db, 16, SEEK_SET);
|
||||
read(db, zPgSz, 2);
|
||||
pagesize = zPgSz[0]*256 + zPgSz[1];
|
||||
if( pagesize==0 ) pagesize = 1024;
|
||||
printf("Pagesize: %d\n", pagesize);
|
||||
fstat(db, &sbuf);
|
||||
mxPage = sbuf.st_size/pagesize + 1;
|
||||
mxPage = sbuf.st_size/pagesize;
|
||||
printf("Available pages: 1..%d\n", mxPage);
|
||||
if( argc==2 ){
|
||||
int i;
|
||||
for(i=1; i<=mxPage; i++) print_page(i);
|
||||
@ -62,11 +276,34 @@ int main(int argc, char **argv){
|
||||
for(i=2; i<argc; i++){
|
||||
int iStart, iEnd;
|
||||
char *zLeft;
|
||||
if( strcmp(argv[i], "dbheader")==0 ){
|
||||
print_db_header();
|
||||
continue;
|
||||
}
|
||||
if( !isdigit(argv[i][0]) ){
|
||||
fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
|
||||
continue;
|
||||
}
|
||||
iStart = strtol(argv[i], &zLeft, 0);
|
||||
if( zLeft && strcmp(zLeft,"..end")==0 ){
|
||||
iEnd = mxPage;
|
||||
}else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
|
||||
iEnd = strtol(&zLeft[2], 0, 0);
|
||||
}else if( zLeft && zLeft[0]=='b' ){
|
||||
int ofst, nByte, hdrSize;
|
||||
unsigned char *a;
|
||||
if( iStart==1 ){
|
||||
ofst = hdrSize = 100;
|
||||
nByte = pagesize-100;
|
||||
}else{
|
||||
hdrSize = 0;
|
||||
ofst = (iStart-1)*pagesize;
|
||||
nByte = pagesize;
|
||||
}
|
||||
a = getContent(ofst, nByte);
|
||||
decode_btree_page(a, iStart, hdrSize);
|
||||
free(a);
|
||||
continue;
|
||||
}else{
|
||||
iEnd = iStart;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user