Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: third_party/sqlite/ext/recover.c

Issue 1700483002: [sqlite] iOS running recover virtual table. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@zzsql_recover_handle_review2
Patch Set: Manually find sql/test/data for now. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/sqlite/ext/recover.h ('k') | third_party/sqlite/sqlite.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « third_party/sqlite/ext/recover.h ('k') | third_party/sqlite/sqlite.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698