Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge in recent changes from the trunk |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | wal |
Files: | files | file ages | folders |
SHA1: |
7a0ac682c3bffcb345321fe974345633 |
User & Date: | drh 2010-04-27 01:56:22.000 |
Context
2010-04-27
| ||
05:42 | Fix a problem that occurs when one process causes the log-summary file to grow and then a second process attempts to read the database. (check-in: b51a5f8bc6 user: dan tags: wal) | |
01:56 | Merge in recent changes from the trunk (check-in: 7a0ac682c3 user: drh tags: wal) | |
2010-04-26
| ||
19:17 | Optimization: Convert an ORDER BY clause into a no-op if the query also contains a GROUP BY clause that will force the same output order. (check-in: ca9d86baf7 user: drh tags: trunk) | |
17:42 | Do not attempt to set journal_mode=wal on :memory: or temp file databases. (check-in: 30d0134454 user: dan tags: wal) | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
3436 3437 3438 3439 3440 3441 3442 | ** expressions are the same. But if you get a 0 or 1 return, then you ** can be sure the expressions are the same. In the places where ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. */ int sqlite3ExprCompare(Expr *pA, Expr *pB){ | < | < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > | 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 | ** expressions are the same. But if you get a 0 or 1 return, then you ** can be sure the expressions are the same. In the places where ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. */ int sqlite3ExprCompare(Expr *pA, Expr *pB){ if( pA==0||pB==0 ){ return pB==pA ? 0 : 2; } assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) ); assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) ); if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){ return 2; } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( pA->op!=pB->op ) return 2; if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2; if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) 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 ){ return 2; } }else if( pA->op!=TK_COLUMN && pA->u.zToken ){ if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2; if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1; if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2; 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 ** the new element. Return a negative number if malloc fails. */ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){ int i; |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 | sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1, sqlite3_free); } } } /* | | | | < | | | | < | 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 | sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1, sqlite3_free); } } } /* ** 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){ int rc = sqlite3_overload_function(db, "MATCH", 2); assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ db->mallocFailed = 1; } } /* ** Set the LIKEOPT flag on the 2-argument function with the given name. */ static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
347 348 349 350 351 352 353 | ** ** The first form reports the current persistent setting for the ** page cache size. The value returned is the maximum number of ** pages in the page cache. The second form sets both the current ** page cache size value and the persistent page cache size value ** stored in the database file. ** | | | | | | | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | ** ** The first form reports the current persistent setting for the ** page cache size. The value returned is the maximum number of ** pages in the page cache. The second form sets both the current ** page cache size value and the persistent page cache size value ** stored in the database file. ** ** 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[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ { OP_IfPos, 1, 7, 0}, { OP_Integer, 0, 2, 0}, |
︙ | ︙ | |||
380 381 382 383 384 385 386 | sqlite3VdbeChangeP1(v, addr+1, iDb); sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE); }else{ int size = atoi(zRight); if( size<0 ) size = -size; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp2(v, OP_Integer, size, 1); | < < < < | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | sqlite3VdbeChangeP1(v, addr+1, iDb); sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE); }else{ int size = atoi(zRight); if( size<0 ) size = -size; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp2(v, OP_Integer, size, 1); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } }else /* |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 | assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 ); if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){ p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy; p->selFlags &= ~SF_Distinct; isDistinct = 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 ** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. | > > > > > > > > > > > > | 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 | assert( p->pGroupBy==0 || (p->selFlags & SF_Aggregate)!=0 ); if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct ){ p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); pGroupBy = p->pGroupBy; p->selFlags &= ~SF_Distinct; 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 ** OP_OpenEphemeral instruction will be changed to an OP_Noop once ** we figure out that the sorting index is not needed. The addrSortIndex ** variable is used to facilitate that change. |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
923 924 925 926 927 928 929 | ** These must be the low-order bits of the flags field. */ #define SQLITE_QueryFlattener 0x01 /* Disable query flattening */ #define SQLITE_ColumnCache 0x02 /* Disable the column cache */ #define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */ #define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */ #define SQLITE_IndexCover 0x10 /* Disable index covering table */ | > | | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | ** These must be the low-order bits of the flags field. */ #define SQLITE_QueryFlattener 0x01 /* Disable query flattening */ #define SQLITE_ColumnCache 0x02 /* Disable the column cache */ #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_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */ #define SQLITE_OptMask 0xff /* Mask of all disablable opts */ /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. */ #define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ |
︙ | ︙ | |||
2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 | Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); Vdbe *sqlite3GetVdbe(Parse*); void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); void sqlite3PrngResetState(void); void sqlite3RollbackAll(sqlite3*); | > | 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 | Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*); 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*); void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); void sqlite3PrngResetState(void); void sqlite3RollbackAll(sqlite3*); |
︙ | ︙ |
Changes to tool/showdb.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** A utility for printing all or part of an SQLite database file. */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | /* ** A utility for printing all or part of an SQLite database file. */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <string.h> 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); } /* ** 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; 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++){ if( i+j>nByte ){ fprintf(stdout, " "); }else{ fprintf(stdout,"%02x ", aData[i+j]); } } for(j=0; j<perLine; 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); } db = open(argv[1], O_RDONLY); if( db<0 ){ 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; printf("Available pages: 1..%d\n", mxPage); if( argc==2 ){ int i; for(i=1; i<=mxPage; i++) print_page(i); }else{ int i; 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; } if( iStart<1 || iEnd<iStart || iEnd>mxPage ){ fprintf(stderr, "Page argument should be LOWER?..UPPER?. Range 1 to %d\n", mxPage); |
︙ | ︙ |