| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2012 Jan 11 | 2 ** 2012 Jan 11 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 */ | 10 */ |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 */ | 203 */ |
| 204 /* TODO(shess): It might be useful to allow DEFAULT in types to | 204 /* TODO(shess): It might be useful to allow DEFAULT in types to |
| 205 * specify what to do for NULL when an ALTER TABLE case comes up. | 205 * specify what to do for NULL when an ALTER TABLE case comes up. |
| 206 * Unfortunately, simply adding it to the exposed schema and using | 206 * Unfortunately, simply adding it to the exposed schema and using |
| 207 * sqlite3_result_null() does not cause the default to be generate. | 207 * sqlite3_result_null() does not cause the default to be generate. |
| 208 * Handling it ourselves seems hard, unfortunately. | 208 * Handling it ourselves seems hard, unfortunately. |
| 209 */ | 209 */ |
| 210 | 210 |
| 211 #include <assert.h> | 211 #include <assert.h> |
| 212 #include <ctype.h> | 212 #include <ctype.h> |
| 213 #include <stdint.h> |
| 213 #include <stdio.h> | 214 #include <stdio.h> |
| 215 #include <stdlib.h> |
| 214 #include <string.h> | 216 #include <string.h> |
| 215 | 217 |
| 216 /* Internal SQLite things that are used: | 218 #if defined(SQLITE_CORE) && !defined(SQLITE_CORE_NOT_REALLY) |
| 217 * u32, u64, i64 types. | 219 |
| 218 * Btree, Pager, and DbPage structs. | 220 /* Compiling as part of SQLite core, pull in internal APIs. */ |
| 219 * DbPage.pData, .pPager, and .pgno | |
| 220 * sqlite3 struct. | |
| 221 * sqlite3BtreePager() and sqlite3BtreeGetPageSize() | |
| 222 * sqlite3BtreeGetOptimalReserve() | |
| 223 * sqlite3PagerGet() and sqlite3PagerUnref() | |
| 224 * getVarint(). | |
| 225 */ | |
| 226 #include "sqliteInt.h" | 221 #include "sqliteInt.h" |
| 222 #define recoverGetVarint(p, v) sqlite3GetVarint(p, v) |
| 223 |
| 224 #else |
| 225 |
| 226 /* Compiling as a module outside of SQLite. Define local versions of some types |
| 227 ** and functions. These are copied and modestly adapted from SQLite source |
| 228 ** code. |
| 229 */ |
| 230 #include "sqlite3.h" |
| 231 |
| 232 /* Copied from SQLite internals. */ |
| 233 typedef uint8_t u8; |
| 234 typedef uint32_t u32; |
| 235 typedef uint64_t u64; |
| 236 typedef int64_t i64; |
| 237 |
| 238 /* |
| 239 ** A convenience macro that returns the number of elements in |
| 240 ** an array. |
| 241 */ |
| 242 #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) |
| 243 |
| 244 /* |
| 245 ** Bitmasks used by sqlite3GetVarint(). These precomputed constants |
| 246 ** are defined here rather than simply putting the constant expressions |
| 247 ** inline in order to work around bugs in the RVT compiler. |
| 248 ** |
| 249 ** SLOT_2_0 A mask for (0x7f<<14) | 0x7f |
| 250 ** |
| 251 ** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 |
| 252 */ |
| 253 #define SLOT_2_0 0x001fc07f |
| 254 #define SLOT_4_2_0 0xf01fc07f |
| 255 |
| 256 /* |
| 257 ** Read a 64-bit variable-length integer from memory starting at p[0]. |
| 258 ** Return the number of bytes read. The value is stored in *v. |
| 259 */ |
| 260 static unsigned char recoverGetVarint(const unsigned char *p, u64 *v){ |
| 261 u32 a,b,s; |
| 262 |
| 263 a = *p; |
| 264 /* a: p0 (unmasked) */ |
| 265 if (!(a&0x80)) |
| 266 { |
| 267 *v = a; |
| 268 return 1; |
| 269 } |
| 270 |
| 271 p++; |
| 272 b = *p; |
| 273 /* b: p1 (unmasked) */ |
| 274 if (!(b&0x80)) |
| 275 { |
| 276 a &= 0x7f; |
| 277 a = a<<7; |
| 278 a |= b; |
| 279 *v = a; |
| 280 return 2; |
| 281 } |
| 282 |
| 283 /* Verify that constants are precomputed correctly */ |
| 284 assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); |
| 285 assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); |
| 286 |
| 287 p++; |
| 288 a = a<<14; |
| 289 a |= *p; |
| 290 /* a: p0<<14 | p2 (unmasked) */ |
| 291 if (!(a&0x80)) |
| 292 { |
| 293 a &= SLOT_2_0; |
| 294 b &= 0x7f; |
| 295 b = b<<7; |
| 296 a |= b; |
| 297 *v = a; |
| 298 return 3; |
| 299 } |
| 300 |
| 301 /* CSE1 from below */ |
| 302 a &= SLOT_2_0; |
| 303 p++; |
| 304 b = b<<14; |
| 305 b |= *p; |
| 306 /* b: p1<<14 | p3 (unmasked) */ |
| 307 if (!(b&0x80)) |
| 308 { |
| 309 b &= SLOT_2_0; |
| 310 /* moved CSE1 up */ |
| 311 /* a &= (0x7f<<14)|(0x7f); */ |
| 312 a = a<<7; |
| 313 a |= b; |
| 314 *v = a; |
| 315 return 4; |
| 316 } |
| 317 |
| 318 /* a: p0<<14 | p2 (masked) */ |
| 319 /* b: p1<<14 | p3 (unmasked) */ |
| 320 /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
| 321 /* moved CSE1 up */ |
| 322 /* a &= (0x7f<<14)|(0x7f); */ |
| 323 b &= SLOT_2_0; |
| 324 s = a; |
| 325 /* s: p0<<14 | p2 (masked) */ |
| 326 |
| 327 p++; |
| 328 a = a<<14; |
| 329 a |= *p; |
| 330 /* a: p0<<28 | p2<<14 | p4 (unmasked) */ |
| 331 if (!(a&0x80)) |
| 332 { |
| 333 /* we can skip these cause they were (effectively) done above |
| 334 ** while calculating s */ |
| 335 /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ |
| 336 /* b &= (0x7f<<14)|(0x7f); */ |
| 337 b = b<<7; |
| 338 a |= b; |
| 339 s = s>>18; |
| 340 *v = ((u64)s)<<32 | a; |
| 341 return 5; |
| 342 } |
| 343 |
| 344 /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
| 345 s = s<<7; |
| 346 s |= b; |
| 347 /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
| 348 |
| 349 p++; |
| 350 b = b<<14; |
| 351 b |= *p; |
| 352 /* b: p1<<28 | p3<<14 | p5 (unmasked) */ |
| 353 if (!(b&0x80)) |
| 354 { |
| 355 /* we can skip this cause it was (effectively) done above in calc'ing s */ |
| 356 /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ |
| 357 a &= SLOT_2_0; |
| 358 a = a<<7; |
| 359 a |= b; |
| 360 s = s>>18; |
| 361 *v = ((u64)s)<<32 | a; |
| 362 return 6; |
| 363 } |
| 364 |
| 365 p++; |
| 366 a = a<<14; |
| 367 a |= *p; |
| 368 /* a: p2<<28 | p4<<14 | p6 (unmasked) */ |
| 369 if (!(a&0x80)) |
| 370 { |
| 371 a &= SLOT_4_2_0; |
| 372 b &= SLOT_2_0; |
| 373 b = b<<7; |
| 374 a |= b; |
| 375 s = s>>11; |
| 376 *v = ((u64)s)<<32 | a; |
| 377 return 7; |
| 378 } |
| 379 |
| 380 /* CSE2 from below */ |
| 381 a &= SLOT_2_0; |
| 382 p++; |
| 383 b = b<<14; |
| 384 b |= *p; |
| 385 /* b: p3<<28 | p5<<14 | p7 (unmasked) */ |
| 386 if (!(b&0x80)) |
| 387 { |
| 388 b &= SLOT_4_2_0; |
| 389 /* moved CSE2 up */ |
| 390 /* a &= (0x7f<<14)|(0x7f); */ |
| 391 a = a<<7; |
| 392 a |= b; |
| 393 s = s>>4; |
| 394 *v = ((u64)s)<<32 | a; |
| 395 return 8; |
| 396 } |
| 397 |
| 398 p++; |
| 399 a = a<<15; |
| 400 a |= *p; |
| 401 /* a: p4<<29 | p6<<15 | p8 (unmasked) */ |
| 402 |
| 403 /* moved CSE2 up */ |
| 404 /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ |
| 405 b &= SLOT_2_0; |
| 406 b = b<<8; |
| 407 a |= b; |
| 408 |
| 409 s = s<<4; |
| 410 b = p[-4]; |
| 411 b &= 0x7f; |
| 412 b = b>>3; |
| 413 s |= b; |
| 414 |
| 415 *v = ((u64)s)<<32 | a; |
| 416 |
| 417 return 9; |
| 418 } |
| 419 #endif |
| 227 | 420 |
| 228 /* For debugging. */ | 421 /* For debugging. */ |
| 229 #if 0 | 422 #if 0 |
| 230 #define FNENTRY() fprintf(stderr, "In %s\n", __FUNCTION__) | 423 #define FNENTRY() fprintf(stderr, "In %s\n", __FUNCTION__) |
| 231 #else | 424 #else |
| 232 #define FNENTRY() | 425 #define FNENTRY() |
| 233 #endif | 426 #endif |
| 234 | 427 |
| 235 /* Generic constants and helper functions. */ | 428 /* Generic constants and helper functions. */ |
| 236 | 429 |
| 237 static const unsigned char kTableLeafPage = 0x0D; | 430 static const unsigned char kTableLeafPage = 0x0D; |
| 238 static const unsigned char kTableInteriorPage = 0x05; | 431 static const unsigned char kTableInteriorPage = 0x05; |
| 239 | 432 |
| 240 /* From section 1.2. */ | 433 /* From section 1.2. */ |
| 241 static const unsigned kiHeaderPageSizeOffset = 16; | 434 static const unsigned kiHeaderPageSizeOffset = 16; |
| 242 static const unsigned kiHeaderReservedSizeOffset = 20; | 435 static const unsigned kiHeaderReservedSizeOffset = 20; |
| 243 static const unsigned kiHeaderEncodingOffset = 56; | 436 static const unsigned kiHeaderEncodingOffset = 56; |
| 244 /* TODO(shess) |static const unsigned| fails creating the header in GetPager() | 437 static const unsigned knHeaderSize = 100; |
| 245 ** because |knHeaderSize| isn't |constexpr|. But this isn't C++, either. | |
| 246 */ | |
| 247 enum { knHeaderSize = 100}; | |
| 248 | 438 |
| 249 /* From section 1.5. */ | 439 /* From section 1.5. */ |
| 250 static const unsigned kiPageTypeOffset = 0; | 440 static const unsigned kiPageTypeOffset = 0; |
| 251 static const unsigned kiPageFreeBlockOffset = 1; | 441 /*static const unsigned kiPageFreeBlockOffset = 1;*/ |
| 252 static const unsigned kiPageCellCountOffset = 3; | 442 static const unsigned kiPageCellCountOffset = 3; |
| 253 static const unsigned kiPageCellContentOffset = 5; | 443 /*static const unsigned kiPageCellContentOffset = 5;*/ |
| 254 static const unsigned kiPageFragmentedBytesOffset = 7; | 444 /*static const unsigned kiPageFragmentedBytesOffset = 7;*/ |
| 255 static const unsigned knPageLeafHeaderBytes = 8; | 445 static const unsigned knPageLeafHeaderBytes = 8; |
| 256 /* Interior pages contain an additional field. */ | 446 /* Interior pages contain an additional field. */ |
| 257 static const unsigned kiPageRightChildOffset = 8; | 447 static const unsigned kiPageRightChildOffset = 8; |
| 258 static const unsigned kiPageInteriorHeaderBytes = 12; | 448 static const unsigned kiPageInteriorHeaderBytes = 12; |
| 259 | 449 |
| 260 /* Accepted types are specified by a mask. */ | 450 /* Accepted types are specified by a mask. */ |
| 261 #define MASK_ROWID (1<<0) | 451 #define MASK_ROWID (1<<0) |
| 262 #define MASK_INTEGER (1<<1) | 452 #define MASK_INTEGER (1<<1) |
| 263 #define MASK_FLOAT (1<<2) | 453 #define MASK_FLOAT (1<<2) |
| 264 #define MASK_TEXT (1<<3) | 454 #define MASK_TEXT (1<<3) |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 /* TODO(shess): SQLite by default allocates page metadata in a single allocation | 603 /* TODO(shess): SQLite by default allocates page metadata in a single allocation |
| 414 ** such that the page's data and metadata are contiguous, see pcache1AllocPage | 604 ** such that the page's data and metadata are contiguous, see pcache1AllocPage |
| 415 ** in pcache1.c. I believe this was intended to reduce malloc churn. It means | 605 ** in pcache1.c. I believe this was intended to reduce malloc churn. It means |
| 416 ** that Chromium's automated tooling would be unlikely to see page-buffer | 606 ** that Chromium's automated tooling would be unlikely to see page-buffer |
| 417 ** overruns. I believe that this code is safe, but for now replicate SQLite's | 607 ** overruns. I believe that this code is safe, but for now replicate SQLite's |
| 418 ** approach with kExcessSpace. | 608 ** approach with kExcessSpace. |
| 419 */ | 609 */ |
| 420 const int kExcessSpace = 128; | 610 const int kExcessSpace = 128; |
| 421 typedef struct RecoverPage RecoverPage; | 611 typedef struct RecoverPage RecoverPage; |
| 422 struct RecoverPage { | 612 struct RecoverPage { |
| 423 Pgno pgno; /* Page number for this page */ | 613 u32 pgno; /* Page number for this page */ |
| 424 void *pData; /* Page data for pgno */ | 614 void *pData; /* Page data for pgno */ |
| 425 RecoverPager *pPager; /* The pager this page is part of */ | 615 RecoverPager *pPager; /* The pager this page is part of */ |
| 426 }; | 616 }; |
| 427 | 617 |
| 428 static void pageDestroy(RecoverPage *pPage){ | 618 static void pageDestroy(RecoverPage *pPage){ |
| 429 sqlite3_free(pPage->pData); | 619 sqlite3_free(pPage->pData); |
| 430 memset(pPage, 0xA5, sizeof(*pPage)); | 620 memset(pPage, 0xA5, sizeof(*pPage)); |
| 431 sqlite3_free(pPage); | 621 sqlite3_free(pPage); |
| 432 } | 622 } |
| 433 | 623 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 return PageData(pPage, knHeaderSize); | 680 return PageData(pPage, knHeaderSize); |
| 491 }else{ | 681 }else{ |
| 492 return PageData(pPage, 0); | 682 return PageData(pPage, 0); |
| 493 } | 683 } |
| 494 } | 684 } |
| 495 | 685 |
| 496 /* Helper to fetch the pager and page size for the named database. */ | 686 /* Helper to fetch the pager and page size for the named database. */ |
| 497 static int GetPager(sqlite3 *db, const char *zName, | 687 static int GetPager(sqlite3 *db, const char *zName, |
| 498 RecoverPager **ppPager, unsigned *pnPageSize, | 688 RecoverPager **ppPager, unsigned *pnPageSize, |
| 499 int *piEncoding){ | 689 int *piEncoding){ |
| 500 int rc, iEncoding; | 690 int i, rc, iEncoding; |
| 501 unsigned nPageSize, nReservedSize; | 691 unsigned nPageSize, nReservedSize; |
| 502 unsigned char header[knHeaderSize]; | 692 unsigned char header[knHeaderSize]; |
| 503 sqlite3_file *pFile = NULL; | 693 sqlite3_file *pFile = NULL; |
| 504 RecoverPager *pPager; | 694 RecoverPager *pPager; |
| 505 | 695 |
| 506 rc = sqlite3_file_control(db, zName, SQLITE_FCNTL_FILE_POINTER, &pFile); | 696 rc = sqlite3_file_control(db, zName, SQLITE_FCNTL_FILE_POINTER, &pFile); |
| 507 if( rc!=SQLITE_OK ) { | 697 if( rc!=SQLITE_OK ) { |
| 508 return rc; | 698 return rc; |
| 509 } else if( pFile==NULL ){ | 699 } else if( pFile==NULL ){ |
| 510 /* The documentation for sqlite3PagerFile() indicates it can return NULL if | 700 /* The documentation for sqlite3PagerFile() indicates it can return NULL if |
| (...skipping 17 matching lines...) Expand all Loading... |
| 528 if( rc==SQLITE_IOERR_SHORT_READ ){ | 718 if( rc==SQLITE_IOERR_SHORT_READ ){ |
| 529 return SQLITE_CORRUPT; | 719 return SQLITE_CORRUPT; |
| 530 } | 720 } |
| 531 return rc; | 721 return rc; |
| 532 } | 722 } |
| 533 | 723 |
| 534 /* Page size must be a power of two between 512 and 32768 inclusive. */ | 724 /* Page size must be a power of two between 512 and 32768 inclusive. */ |
| 535 nPageSize = decodeUnsigned16(header + kiHeaderPageSizeOffset); | 725 nPageSize = decodeUnsigned16(header + kiHeaderPageSizeOffset); |
| 536 if( (nPageSize&(nPageSize-1)) || nPageSize>32768 || nPageSize<512 ){ | 726 if( (nPageSize&(nPageSize-1)) || nPageSize>32768 || nPageSize<512 ){ |
| 537 pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE); | 727 pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE); |
| 538 return rc; | 728 return SQLITE_CORRUPT; |
| 539 } | 729 } |
| 540 | 730 |
| 541 /* Space reserved a the end of the page for extensions. Usually 0. */ | 731 /* Space reserved a the end of the page for extensions. Usually 0. */ |
| 542 nReservedSize = header[kiHeaderReservedSizeOffset]; | 732 nReservedSize = header[kiHeaderReservedSizeOffset]; |
| 543 | 733 |
| 544 /* 1 for UTF-8, 2 for UTF-16le, 3 for UTF-16be. */ | 734 /* 1 for UTF-8, 2 for UTF-16le, 3 for UTF-16be. */ |
| 545 iEncoding = decodeUnsigned32(header + kiHeaderEncodingOffset); | 735 iEncoding = decodeUnsigned32(header + kiHeaderEncodingOffset); |
| 546 if( iEncoding==3 ){ | 736 if( iEncoding==3 ){ |
| 547 *piEncoding = SQLITE_UTF16BE; | 737 *piEncoding = SQLITE_UTF16BE; |
| 548 } else if( iEncoding==2 ){ | 738 } else if( iEncoding==2 ){ |
| 549 *piEncoding = SQLITE_UTF16LE; | 739 *piEncoding = SQLITE_UTF16LE; |
| 550 } else if( iEncoding==1 ){ | 740 } else if( iEncoding==1 ){ |
| 551 *piEncoding = SQLITE_UTF8; | 741 *piEncoding = SQLITE_UTF8; |
| 552 } else { | 742 } else { |
| 553 /* This case should not be possible. */ | 743 /* This case should not be possible. */ |
| 554 *piEncoding = SQLITE_UTF8; | 744 *piEncoding = SQLITE_UTF8; |
| 555 } | 745 } |
| 746 /*assert( iEncoding==1 || iEncoding==2 || iEncoding==3 );*/ |
| 556 | 747 |
| 557 rc = pagerCreate(pFile, nPageSize, &pPager); | 748 rc = pagerCreate(pFile, nPageSize, &pPager); |
| 558 if( rc!=SQLITE_OK ){ | 749 if( rc!=SQLITE_OK ){ |
| 559 pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE); | 750 pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE); |
| 560 return rc; | 751 return rc; |
| 561 } | 752 } |
| 562 | 753 |
| 563 *ppPager = pPager; | 754 *ppPager = pPager; |
| 564 *pnPageSize = nPageSize - nReservedSize; | 755 *pnPageSize = nPageSize - nReservedSize; |
| 565 *piEncoding = iEncoding; | 756 *piEncoding = iEncoding; |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 828 | 1019 |
| 829 /* TODO(shess): Check for cell overlaps? Cells require 4 bytes plus | 1020 /* TODO(shess): Check for cell overlaps? Cells require 4 bytes plus |
| 830 * a varint. Check could be identical to leaf check (or even a | 1021 * a varint. Check could be identical to leaf check (or even a |
| 831 * shared helper testing for "Cells starting in this range"?). | 1022 * shared helper testing for "Cells starting in this range"?). |
| 832 */ | 1023 */ |
| 833 | 1024 |
| 834 /* If the offset is broken, return an invalid page number. */ | 1025 /* If the offset is broken, return an invalid page number. */ |
| 835 return 0; | 1026 return 0; |
| 836 } | 1027 } |
| 837 | 1028 |
| 1029 #if 0 |
| 838 static int interiorCursorEOF(RecoverInteriorCursor *pCursor){ | 1030 static int interiorCursorEOF(RecoverInteriorCursor *pCursor){ |
| 839 /* Find a parent with remaining children. EOF if none found. */ | 1031 /* Find a parent with remaining children. EOF if none found. */ |
| 840 while( pCursor && pCursor->iChild>=pCursor->nChildren ){ | 1032 while( pCursor && pCursor->iChild>=pCursor->nChildren ){ |
| 841 pCursor = pCursor->pParent; | 1033 pCursor = pCursor->pParent; |
| 842 } | 1034 } |
| 843 return pCursor==NULL; | 1035 return pCursor==NULL; |
| 844 } | 1036 } |
| 1037 #endif |
| 845 | 1038 |
| 846 /* Internal helper. Used to detect if iPage would cause a loop. */ | 1039 /* Internal helper. Used to detect if iPage would cause a loop. */ |
| 847 static int interiorCursorPageInUse(RecoverInteriorCursor *pCursor, | 1040 static int interiorCursorPageInUse(RecoverInteriorCursor *pCursor, |
| 848 unsigned iPage){ | 1041 unsigned iPage){ |
| 849 /* Find any parent using the indicated page. */ | 1042 /* Find any parent using the indicated page. */ |
| 850 while( pCursor && pCursor->pPage->pgno!=iPage ){ | 1043 while( pCursor && pCursor->pPage->pgno!=iPage ){ |
| 851 pCursor = pCursor->pParent; | 1044 pCursor = pCursor->pParent; |
| 852 } | 1045 } |
| 853 return pCursor!=NULL; | 1046 return pCursor!=NULL; |
| 854 } | 1047 } |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1451 /* B-tree leaf cells lead with varint record size, varint rowid and | 1644 /* B-tree leaf cells lead with varint record size, varint rowid and |
| 1452 * varint header size. | 1645 * varint header size. |
| 1453 */ | 1646 */ |
| 1454 /* TODO(shess): The smallest page size is 512 bytes, which has an m | 1647 /* TODO(shess): The smallest page size is 512 bytes, which has an m |
| 1455 * of 39. Three varints need at most 27 bytes to encode. I think. | 1648 * of 39. Three varints need at most 27 bytes to encode. I think. |
| 1456 */ | 1649 */ |
| 1457 if( !checkVarints(pCell, nCellMaxBytes, 3) ){ | 1650 if( !checkVarints(pCell, nCellMaxBytes, 3) ){ |
| 1458 return ValidateError(); | 1651 return ValidateError(); |
| 1459 } | 1652 } |
| 1460 | 1653 |
| 1461 nRead = getVarint(pCell, &nRecordBytes); | 1654 nRead = recoverGetVarint(pCell, &nRecordBytes); |
| 1462 assert( iCellOffset+nRead<=pCursor->nPageSize ); | 1655 assert( iCellOffset+nRead<=pCursor->nPageSize ); |
| 1463 pCursor->nRecordBytes = nRecordBytes; | 1656 pCursor->nRecordBytes = nRecordBytes; |
| 1464 | 1657 |
| 1465 nRead += getVarint(pCell + nRead, &iRowid); | 1658 nRead += recoverGetVarint(pCell + nRead, &iRowid); |
| 1466 assert( iCellOffset+nRead<=pCursor->nPageSize ); | 1659 assert( iCellOffset+nRead<=pCursor->nPageSize ); |
| 1467 pCursor->iRowid = (i64)iRowid; | 1660 pCursor->iRowid = (i64)iRowid; |
| 1468 | 1661 |
| 1469 pCursor->iRecordOffset = iCellOffset + nRead; | 1662 pCursor->iRecordOffset = iCellOffset + nRead; |
| 1470 | 1663 |
| 1471 /* Start overflow setup here because nLocalRecordBytes is needed to | 1664 /* Start overflow setup here because nLocalRecordBytes is needed to |
| 1472 * check cell overlap. | 1665 * check cell overlap. |
| 1473 */ | 1666 */ |
| 1474 rc = overflowMaybeCreate(pCursor->pPage, pCursor->nPageSize, | 1667 rc = overflowMaybeCreate(pCursor->pPage, pCursor->nPageSize, |
| 1475 pCursor->iRecordOffset, pCursor->nRecordBytes, | 1668 pCursor->iRecordOffset, pCursor->nRecordBytes, |
| 1476 &pCursor->nLocalRecordBytes, | 1669 &pCursor->nLocalRecordBytes, |
| 1477 &pCursor->pOverflow); | 1670 &pCursor->pOverflow); |
| 1478 if( rc!=SQLITE_OK ){ | 1671 if( rc!=SQLITE_OK ){ |
| 1479 return ValidateError(); | 1672 return ValidateError(); |
| 1480 } | 1673 } |
| 1481 | 1674 |
| 1482 /* Check that no other cell starts within this cell. */ | 1675 /* Check that no other cell starts within this cell. */ |
| 1483 iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes; | 1676 iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes; |
| 1484 for( i=0; i<pCursor->nCells && pCellOffsets + i*2 + 2 <= pPageEnd; ++i ){ | 1677 for( i=0; i<pCursor->nCells && pCellOffsets + i*2 + 2 <= pPageEnd; ++i ){ |
| 1485 const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2); | 1678 const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2); |
| 1486 if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){ | 1679 if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){ |
| 1487 return ValidateError(); | 1680 return ValidateError(); |
| 1488 } | 1681 } |
| 1489 } | 1682 } |
| 1490 | 1683 |
| 1491 nRecordHeaderRead = getVarint(pCell + nRead, &nRecordHeaderBytes); | 1684 nRecordHeaderRead = recoverGetVarint(pCell + nRead, &nRecordHeaderBytes); |
| 1492 assert( nRecordHeaderBytes<=nRecordBytes ); | 1685 assert( nRecordHeaderBytes<=nRecordBytes ); |
| 1493 pCursor->nRecordHeaderBytes = nRecordHeaderBytes; | 1686 pCursor->nRecordHeaderBytes = nRecordHeaderBytes; |
| 1494 | 1687 |
| 1495 /* Large headers could overflow if pages are small. */ | 1688 /* Large headers could overflow if pages are small. */ |
| 1496 rc = overflowGetSegment(pCursor->pPage, | 1689 rc = overflowGetSegment(pCursor->pPage, |
| 1497 pCursor->iRecordOffset, pCursor->nLocalRecordBytes, | 1690 pCursor->iRecordOffset, pCursor->nLocalRecordBytes, |
| 1498 pCursor->pOverflow, 0, nRecordHeaderBytes, | 1691 pCursor->pOverflow, 0, nRecordHeaderBytes, |
| 1499 &pCursor->pRecordHeader, &pCursor->bFreeRecordHeader); | 1692 &pCursor->pRecordHeader, &pCursor->bFreeRecordHeader); |
| 1500 if( rc!=SQLITE_OK ){ | 1693 if( rc!=SQLITE_OK ){ |
| 1501 return ValidateError(); | 1694 return ValidateError(); |
| 1502 } | 1695 } |
| 1503 | 1696 |
| 1504 /* Tally up the column count and size of data. */ | 1697 /* Tally up the column count and size of data. */ |
| 1505 nRecordCols = 0; | 1698 nRecordCols = 0; |
| 1506 nRecordColBytes = 0; | 1699 nRecordColBytes = 0; |
| 1507 while( nRecordHeaderRead<nRecordHeaderBytes ){ | 1700 while( nRecordHeaderRead<nRecordHeaderBytes ){ |
| 1508 u64 iSerialType; /* Type descriptor for current column. */ | 1701 u64 iSerialType; /* Type descriptor for current column. */ |
| 1509 if( !checkVarint(pCursor->pRecordHeader + nRecordHeaderRead, | 1702 if( !checkVarint(pCursor->pRecordHeader + nRecordHeaderRead, |
| 1510 nRecordHeaderBytes - nRecordHeaderRead) ){ | 1703 nRecordHeaderBytes - nRecordHeaderRead) ){ |
| 1511 return ValidateError(); | 1704 return ValidateError(); |
| 1512 } | 1705 } |
| 1513 nRecordHeaderRead += getVarint(pCursor->pRecordHeader + nRecordHeaderRead, | 1706 nRecordHeaderRead += |
| 1514 &iSerialType); | 1707 recoverGetVarint(pCursor->pRecordHeader + nRecordHeaderRead, |
| 1708 &iSerialType); |
| 1515 if( iSerialType==10 || iSerialType==11 ){ | 1709 if( iSerialType==10 || iSerialType==11 ){ |
| 1516 return ValidateError(); | 1710 return ValidateError(); |
| 1517 } | 1711 } |
| 1518 nRecordColBytes += SerialTypeLength(iSerialType); | 1712 nRecordColBytes += SerialTypeLength(iSerialType); |
| 1519 nRecordCols++; | 1713 nRecordCols++; |
| 1520 } | 1714 } |
| 1521 pCursor->nRecordCols = nRecordCols; | 1715 pCursor->nRecordCols = nRecordCols; |
| 1522 | 1716 |
| 1523 /* Parsing the header used as many bytes as expected. */ | 1717 /* Parsing the header used as many bytes as expected. */ |
| 1524 if( nRecordHeaderRead!=nRecordHeaderBytes ){ | 1718 if( nRecordHeaderRead!=nRecordHeaderBytes ){ |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1570 | 1764 |
| 1571 /* Must be able to decode header size. */ | 1765 /* Must be able to decode header size. */ |
| 1572 pRecordHeader = pCursor->pRecordHeader; | 1766 pRecordHeader = pCursor->pRecordHeader; |
| 1573 if( !checkVarint(pRecordHeader, pCursor->nRecordHeaderBytes) ){ | 1767 if( !checkVarint(pRecordHeader, pCursor->nRecordHeaderBytes) ){ |
| 1574 return SQLITE_CORRUPT; | 1768 return SQLITE_CORRUPT; |
| 1575 } | 1769 } |
| 1576 | 1770 |
| 1577 /* Rather than caching the header size and how many bytes it took, | 1771 /* Rather than caching the header size and how many bytes it took, |
| 1578 * decode it every time. | 1772 * decode it every time. |
| 1579 */ | 1773 */ |
| 1580 nRead = getVarint(pRecordHeader, &nRecordHeaderBytes); | 1774 nRead = recoverGetVarint(pRecordHeader, &nRecordHeaderBytes); |
| 1581 assert( nRecordHeaderBytes==pCursor->nRecordHeaderBytes ); | 1775 assert( nRecordHeaderBytes==pCursor->nRecordHeaderBytes ); |
| 1582 | 1776 |
| 1583 /* Scan forward to the indicated column. Scans to _after_ column | 1777 /* Scan forward to the indicated column. Scans to _after_ column |
| 1584 * for later range checking. | 1778 * for later range checking. |
| 1585 */ | 1779 */ |
| 1586 /* TODO(shess): This could get expensive for very wide tables. An | 1780 /* TODO(shess): This could get expensive for very wide tables. An |
| 1587 * array of iSerialType could be built in leafCursorCellDecode(), but | 1781 * array of iSerialType could be built in leafCursorCellDecode(), but |
| 1588 * the number of columns is dynamic per row, so it would add memory | 1782 * the number of columns is dynamic per row, so it would add memory |
| 1589 * management complexity. Enough info to efficiently forward | 1783 * management complexity. Enough info to efficiently forward |
| 1590 * iterate could be kept, if all clients forward iterate | 1784 * iterate could be kept, if all clients forward iterate |
| 1591 * (recoverColumn() may not). | 1785 * (recoverColumn() may not). |
| 1592 */ | 1786 */ |
| 1593 iColEndOffset = 0; | 1787 iColEndOffset = 0; |
| 1594 nColsSkipped = 0; | 1788 nColsSkipped = 0; |
| 1595 while( nColsSkipped<=iCol && nRead<nRecordHeaderBytes ){ | 1789 while( nColsSkipped<=iCol && nRead<nRecordHeaderBytes ){ |
| 1596 if( !checkVarint(pRecordHeader + nRead, nRecordHeaderBytes - nRead) ){ | 1790 if( !checkVarint(pRecordHeader + nRead, nRecordHeaderBytes - nRead) ){ |
| 1597 return SQLITE_CORRUPT; | 1791 return SQLITE_CORRUPT; |
| 1598 } | 1792 } |
| 1599 nRead += getVarint(pRecordHeader + nRead, &iSerialType); | 1793 nRead += recoverGetVarint(pRecordHeader + nRead, &iSerialType); |
| 1600 iColEndOffset += SerialTypeLength(iSerialType); | 1794 iColEndOffset += SerialTypeLength(iSerialType); |
| 1601 nColsSkipped++; | 1795 nColsSkipped++; |
| 1602 } | 1796 } |
| 1603 | 1797 |
| 1604 /* Column's data extends past record's end. */ | 1798 /* Column's data extends past record's end. */ |
| 1605 if( nRecordHeaderBytes+iColEndOffset>pCursor->nRecordBytes ){ | 1799 if( nRecordHeaderBytes+iColEndOffset>pCursor->nRecordBytes ){ |
| 1606 return SQLITE_CORRUPT; | 1800 return SQLITE_CORRUPT; |
| 1607 } | 1801 } |
| 1608 | 1802 |
| 1609 *piColType = iSerialType; | 1803 *piColType = iSerialType; |
| (...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1984 recoverRowid, /* xRowid - read data */ | 2178 recoverRowid, /* xRowid - read data */ |
| 1985 0, /* xUpdate - write data */ | 2179 0, /* xUpdate - write data */ |
| 1986 0, /* xBegin - begin transaction */ | 2180 0, /* xBegin - begin transaction */ |
| 1987 0, /* xSync - sync transaction */ | 2181 0, /* xSync - sync transaction */ |
| 1988 0, /* xCommit - commit transaction */ | 2182 0, /* xCommit - commit transaction */ |
| 1989 0, /* xRollback - rollback transaction */ | 2183 0, /* xRollback - rollback transaction */ |
| 1990 0, /* xFindFunction - function overloading */ | 2184 0, /* xFindFunction - function overloading */ |
| 1991 0, /* xRename - rename the table */ | 2185 0, /* xRename - rename the table */ |
| 1992 }; | 2186 }; |
| 1993 | 2187 |
| 1994 CHROMIUM_SQLITE_API | 2188 SQLITE_API |
| 1995 int recoverVtableInit(sqlite3 *db){ | 2189 int recoverVtableInit(sqlite3 *db){ |
| 1996 return sqlite3_create_module_v2(db, "recover", &recoverModule, NULL, 0); | 2190 return sqlite3_create_module_v2(db, "recover", &recoverModule, NULL, 0); |
| 1997 } | 2191 } |
| 1998 | 2192 |
| 1999 /* This section of code is for parsing the create input and | 2193 /* This section of code is for parsing the create input and |
| 2000 * initializing the module. | 2194 * initializing the module. |
| 2001 */ | 2195 */ |
| 2002 | 2196 |
| 2003 /* Find the next word in zText and place the endpoints in pzWord*. | 2197 /* Find the next word in zText and place the endpoints in pzWord*. |
| 2004 * Returns true if the word is non-empty. "Word" is defined as | 2198 * Returns true if the word is non-empty. "Word" is defined as |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2222 if( !pRecover ){ | 2416 if( !pRecover ){ |
| 2223 return SQLITE_NOMEM; | 2417 return SQLITE_NOMEM; |
| 2224 } | 2418 } |
| 2225 memset(pRecover, 0, sizeof(*pRecover)); | 2419 memset(pRecover, 0, sizeof(*pRecover)); |
| 2226 pRecover->base.pModule = &recoverModule; | 2420 pRecover->base.pModule = &recoverModule; |
| 2227 pRecover->db = db; | 2421 pRecover->db = db; |
| 2228 | 2422 |
| 2229 /* Parse out db.table, assuming main if no dot. */ | 2423 /* Parse out db.table, assuming main if no dot. */ |
| 2230 zDot = strchr(argv[3], '.'); | 2424 zDot = strchr(argv[3], '.'); |
| 2231 if( !zDot ){ | 2425 if( !zDot ){ |
| 2232 pRecover->zDb = sqlite3_strdup(db->aDb[0].zName); | 2426 pRecover->zDb = sqlite3_strdup("main"); |
| 2233 pRecover->zTable = sqlite3_strdup(argv[3]); | 2427 pRecover->zTable = sqlite3_strdup(argv[3]); |
| 2234 }else if( zDot>argv[3] && zDot[1]!='\0' ){ | 2428 }else if( zDot>argv[3] && zDot[1]!='\0' ){ |
| 2235 pRecover->zDb = sqlite3_strndup(argv[3], zDot - argv[3]); | 2429 pRecover->zDb = sqlite3_strndup(argv[3], zDot - argv[3]); |
| 2236 pRecover->zTable = sqlite3_strdup(zDot + 1); | 2430 pRecover->zTable = sqlite3_strdup(zDot + 1); |
| 2237 }else{ | 2431 }else{ |
| 2238 /* ".table" or "db." not allowed. */ | 2432 /* ".table" or "db." not allowed. */ |
| 2239 *pzErr = sqlite3_mprintf("ill-formed table specifier"); | 2433 *pzErr = sqlite3_mprintf("ill-formed table specifier"); |
| 2240 recoverRelease(pRecover); | 2434 recoverRelease(pRecover); |
| 2241 return SQLITE_ERROR; | 2435 return SQLITE_ERROR; |
| 2242 } | 2436 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2272 rc = sqlite3_declare_vtab(db, zCreateSql); | 2466 rc = sqlite3_declare_vtab(db, zCreateSql); |
| 2273 sqlite3_free(zCreateSql); | 2467 sqlite3_free(zCreateSql); |
| 2274 if( rc!=SQLITE_OK ){ | 2468 if( rc!=SQLITE_OK ){ |
| 2275 recoverRelease(pRecover); | 2469 recoverRelease(pRecover); |
| 2276 return rc; | 2470 return rc; |
| 2277 } | 2471 } |
| 2278 | 2472 |
| 2279 *ppVtab = (sqlite3_vtab *)pRecover; | 2473 *ppVtab = (sqlite3_vtab *)pRecover; |
| 2280 return SQLITE_OK; | 2474 return SQLITE_OK; |
| 2281 } | 2475 } |
| OLD | NEW |