OLD | NEW |
1 From 31dd2fd1cdeba87223f6a46cc19bcea9eb8b2f38 Mon Sep 17 00:00:00 2001 | 1 From d176c774ba1a8b431400f38ca71459bf148f0c3a Mon Sep 17 00:00:00 2001 |
2 From: Scott Hess <shess@chromium.org> | 2 From: Scott Hess <shess@chromium.org> |
3 Date: Sat, 20 Jul 2013 11:42:21 -0700 | 3 Date: Sat, 20 Jul 2013 11:42:21 -0700 |
4 Subject: [PATCH 05/13] Virtual table supporting recovery of corrupted | 4 Subject: [PATCH 05/13] Virtual table supporting recovery of corrupted |
5 databases. | 5 databases. |
6 | 6 |
7 "recover" implements a virtual table which uses the SQLite pager layer | 7 "recover" implements a virtual table which uses the SQLite pager layer |
8 to read table pages and pull out the data which is structurally sound | 8 to read table pages and pull out the data which is structurally sound |
9 (at least at the storage layer). | 9 (at least at the storage layer). |
10 | 10 |
11 BUG=109482 | 11 BUG=109482 |
12 | 12 |
13 Since this implements a new feature for SQLite, the review URLs aren't | 13 Since this implements a new feature for SQLite, the review URLs aren't |
14 listed. This patch and the top of recover.c should be considered | 14 listed. This patch and the top of recover.c should be considered |
15 authoritative. The history is mostly under | 15 authoritative. The history is mostly under |
16 third_party/sqlite/src/src/{recover,recover-alt}.c . | 16 third_party/sqlite/src/src/{recover,recover-alt}.c . |
17 --- | 17 --- |
18 third_party/sqlite/src/Makefile.in | 1 + | 18 third_party/sqlite/src/main.mk | 6 +- |
19 third_party/sqlite/src/Makefile.linux-gcc | 4 + | 19 third_party/sqlite/src/src/main.c | 8 + |
20 third_party/sqlite/src/main.mk | 5 +- | 20 third_party/sqlite/src/src/recover.c | 2270 +++++++++++++++++++++++++++ |
21 third_party/sqlite/src/src/main.c | 8 + | 21 third_party/sqlite/src/src/recover.h | 23 + |
22 third_party/sqlite/src/src/recover.c | 2281 ++++++++++++++++++++++++++++ | 22 third_party/sqlite/src/src/recover_varint.c | 201 +++ |
23 third_party/sqlite/src/src/sqlite.h.in | 16 + | 23 third_party/sqlite/src/test/recover.test | 164 ++ |
24 third_party/sqlite/src/test/recover.test | 164 ++ | 24 third_party/sqlite/src/test/recover0.test | 532 +++++++ |
25 third_party/sqlite/src/test/recover0.test | 532 +++++++ | 25 third_party/sqlite/src/test/recover1.test | 429 +++++ |
26 third_party/sqlite/src/test/recover1.test | 429 ++++++ | 26 third_party/sqlite/src/test/recover2.test | 157 ++ |
27 third_party/sqlite/src/test/recover2.test | 157 ++ | 27 9 files changed, 3789 insertions(+), 1 deletion(-) |
28 third_party/sqlite/src/tool/mksqlite3c.tcl | 2 + | |
29 11 files changed, 3598 insertions(+), 1 deletion(-) | |
30 create mode 100644 third_party/sqlite/src/src/recover.c | 28 create mode 100644 third_party/sqlite/src/src/recover.c |
| 29 create mode 100644 third_party/sqlite/src/src/recover.h |
| 30 create mode 100644 third_party/sqlite/src/src/recover_varint.c |
31 create mode 100644 third_party/sqlite/src/test/recover.test | 31 create mode 100644 third_party/sqlite/src/test/recover.test |
32 create mode 100644 third_party/sqlite/src/test/recover0.test | 32 create mode 100644 third_party/sqlite/src/test/recover0.test |
33 create mode 100644 third_party/sqlite/src/test/recover1.test | 33 create mode 100644 third_party/sqlite/src/test/recover1.test |
34 create mode 100644 third_party/sqlite/src/test/recover2.test | 34 create mode 100644 third_party/sqlite/src/test/recover2.test |
35 | 35 |
36 diff --git a/third_party/sqlite/src/Makefile.in b/third_party/sqlite/src/Makefil
e.in | |
37 index 1fe49d6..8b965c7 100644 | |
38 --- a/third_party/sqlite/src/Makefile.in | |
39 +++ b/third_party/sqlite/src/Makefile.in | |
40 @@ -260,6 +260,7 @@ SRC = \ | |
41 $(TOP)/src/prepare.c \ | |
42 $(TOP)/src/printf.c \ | |
43 $(TOP)/src/random.c \ | |
44 + $(TOP)/src/recover.c \ | |
45 $(TOP)/src/resolve.c \ | |
46 $(TOP)/src/rowset.c \ | |
47 $(TOP)/src/select.c \ | |
48 diff --git a/third_party/sqlite/src/Makefile.linux-gcc b/third_party/sqlite/src/
Makefile.linux-gcc | |
49 index 952e8d1..f6291c0 100644 | |
50 --- a/third_party/sqlite/src/Makefile.linux-gcc | |
51 +++ b/third_party/sqlite/src/Makefile.linux-gcc | |
52 @@ -81,6 +81,10 @@ OPTS += -DSQLITE_MEMDEBUG=1 | |
53 # TODO(shess) I can't see why I need this setting. | |
54 OPTS += -DOS_UNIX=1 | |
55 | |
56 +# The recover virtual table is not generally enabled. Enable it for testing | |
57 +# purposes. | |
58 +OPTS += -DDEFAULT_ENABLE_RECOVER=1 | |
59 + | |
60 #### The suffix to add to executable files. ".exe" for windows. | |
61 # Nothing for unix. | |
62 # | |
63 diff --git a/third_party/sqlite/src/main.mk b/third_party/sqlite/src/main.mk | 36 diff --git a/third_party/sqlite/src/main.mk b/third_party/sqlite/src/main.mk |
64 index 6ff3bd4..a8629aa 100644 | 37 index 6ff3bd4..26f9f15 100644 |
65 --- a/third_party/sqlite/src/main.mk | 38 --- a/third_party/sqlite/src/main.mk |
66 +++ b/third_party/sqlite/src/main.mk | 39 +++ b/third_party/sqlite/src/main.mk |
67 @@ -67,7 +67,8 @@ LIBOBJ+= vdbe.o parse.o \ | 40 @@ -67,7 +67,8 @@ LIBOBJ+= vdbe.o parse.o \ |
68 mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \ | 41 mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \ |
69 notify.o opcodes.o os.o os_unix.o os_win.o \ | 42 notify.o opcodes.o os.o os_unix.o os_win.o \ |
70 pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \ | 43 pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \ |
71 - random.o resolve.o rowset.o rtree.o select.o sqlite3rbu.o status.o \ | 44 - random.o resolve.o rowset.o rtree.o select.o sqlite3rbu.o status.o \ |
72 + random.o recover.o resolve.o rowset.o rtree.o \ | 45 + random.o recover.o recover_varint.o resolve.o rowset.o rtree.o \ |
73 + select.o sqlite3rbu.o status.o \ | 46 + select.o sqlite3rbu.o status.o \ |
74 table.o threads.o tokenize.o treeview.o trigger.o \ | 47 table.o threads.o tokenize.o treeview.o trigger.o \ |
75 update.o userauth.o util.o vacuum.o \ | 48 update.o userauth.o util.o vacuum.o \ |
76 vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \ | 49 vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \ |
77 @@ -140,6 +141,7 @@ SRC = \ | 50 @@ -360,6 +361,8 @@ TESTSRC2 = \ |
78 $(TOP)/src/prepare.c \ | 51 $(TOP)/src/prepare.c \ |
79 $(TOP)/src/printf.c \ | 52 $(TOP)/src/printf.c \ |
80 $(TOP)/src/random.c \ | 53 $(TOP)/src/random.c \ |
81 + $(TOP)/src/recover.c \ | 54 + $(TOP)/src/recover.c \ |
82 $(TOP)/src/resolve.c \ | 55 + $(TOP)/src/recover_varint.c \ |
83 $(TOP)/src/rowset.c \ | |
84 $(TOP)/src/select.c \ | |
85 @@ -360,6 +362,7 @@ TESTSRC2 = \ | |
86 $(TOP)/src/prepare.c \ | |
87 $(TOP)/src/printf.c \ | |
88 $(TOP)/src/random.c \ | |
89 + $(TOP)/src/recover.c \ | |
90 $(TOP)/src/pcache.c \ | 56 $(TOP)/src/pcache.c \ |
91 $(TOP)/src/pcache1.c \ | 57 $(TOP)/src/pcache1.c \ |
92 $(TOP)/src/select.c \ | 58 $(TOP)/src/select.c \ |
| 59 @@ -720,6 +723,7 @@ sqlite3_analyzer$(EXE): sqlite3_analyzer.c |
| 60 # |
| 61 TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 |
| 62 TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE |
| 63 +TESTFIXTURE_FLAGS += -DDEFAULT_ENABLE_RECOVER=1 |
| 64 |
| 65 testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c |
| 66 $(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \ |
93 diff --git a/third_party/sqlite/src/src/main.c b/third_party/sqlite/src/src/main
.c | 67 diff --git a/third_party/sqlite/src/src/main.c b/third_party/sqlite/src/src/main
.c |
94 index 3be7c77..301808c 100644 | 68 index 3be7c77..301808c 100644 |
95 --- a/third_party/sqlite/src/src/main.c | 69 --- a/third_party/sqlite/src/src/main.c |
96 +++ b/third_party/sqlite/src/src/main.c | 70 +++ b/third_party/sqlite/src/src/main.c |
97 @@ -2927,6 +2927,14 @@ static int openDatabase( | 71 @@ -2927,6 +2927,14 @@ static int openDatabase( |
98 } | 72 } |
99 #endif | 73 #endif |
100 | 74 |
101 +#ifdef DEFAULT_ENABLE_RECOVER | 75 +#ifdef DEFAULT_ENABLE_RECOVER |
102 + /* Initialize recover virtual table for testing. */ | 76 + /* Initialize recover virtual table for testing. */ |
103 + extern int recoverVtableInit(sqlite3 *db); | 77 + extern int recoverVtableInit(sqlite3 *db); |
104 + if( !db->mallocFailed && rc==SQLITE_OK ){ | 78 + if( !db->mallocFailed && rc==SQLITE_OK ){ |
105 + rc = recoverVtableInit(db); | 79 + rc = recoverVtableInit(db); |
106 + } | 80 + } |
107 +#endif | 81 +#endif |
108 + | 82 + |
109 #ifdef SQLITE_ENABLE_ICU | 83 #ifdef SQLITE_ENABLE_ICU |
110 if( !db->mallocFailed && rc==SQLITE_OK ){ | 84 if( !db->mallocFailed && rc==SQLITE_OK ){ |
111 rc = sqlite3IcuInit(db); | 85 rc = sqlite3IcuInit(db); |
112 diff --git a/third_party/sqlite/src/src/recover.c b/third_party/sqlite/src/src/r
ecover.c | 86 diff --git a/third_party/sqlite/src/src/recover.c b/third_party/sqlite/src/src/r
ecover.c |
113 new file mode 100644 | 87 new file mode 100644 |
114 index 0000000..5ff6f78 | 88 index 0000000..c22fd4d |
115 --- /dev/null | 89 --- /dev/null |
116 +++ b/third_party/sqlite/src/src/recover.c | 90 +++ b/third_party/sqlite/src/src/recover.c |
117 @@ -0,0 +1,2281 @@ | 91 @@ -0,0 +1,2270 @@ |
118 +/* | 92 +/* |
119 +** 2012 Jan 11 | 93 +** 2012 Jan 11 |
120 +** | 94 +** |
121 +** The author disclaims copyright to this source code. In place of | 95 +** The author disclaims copyright to this source code. In place of |
122 +** a legal notice, here is a blessing: | 96 +** a legal notice, here is a blessing: |
123 +** | 97 +** |
124 +** May you do good and not evil. | 98 +** May you do good and not evil. |
125 +** May you find forgiveness for yourself and forgive others. | 99 +** May you find forgiveness for yourself and forgive others. |
126 +** May you share freely, never taking more than you give. | 100 +** May you share freely, never taking more than you give. |
127 +*/ | 101 +*/ |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 + */ | 294 + */ |
321 +/* TODO(shess): It might be useful to allow DEFAULT in types to | 295 +/* TODO(shess): It might be useful to allow DEFAULT in types to |
322 + * specify what to do for NULL when an ALTER TABLE case comes up. | 296 + * specify what to do for NULL when an ALTER TABLE case comes up. |
323 + * Unfortunately, simply adding it to the exposed schema and using | 297 + * Unfortunately, simply adding it to the exposed schema and using |
324 + * sqlite3_result_null() does not cause the default to be generate. | 298 + * sqlite3_result_null() does not cause the default to be generate. |
325 + * Handling it ourselves seems hard, unfortunately. | 299 + * Handling it ourselves seems hard, unfortunately. |
326 + */ | 300 + */ |
327 + | 301 + |
328 +#include <assert.h> | 302 +#include <assert.h> |
329 +#include <ctype.h> | 303 +#include <ctype.h> |
| 304 +#include <stdint.h> |
330 +#include <stdio.h> | 305 +#include <stdio.h> |
331 +#include <string.h> | 306 +#include <string.h> |
332 + | 307 + |
333 +/* Internal SQLite things that are used: | 308 +#include "sqlite3.h" |
334 + * u32, u64, i64 types. | 309 + |
335 + * Btree, Pager, and DbPage structs. | 310 +/* Some SQLite internals use, cribbed from fts5int.h. */ |
336 + * DbPage.pData, .pPager, and .pgno | 311 +#ifndef SQLITE_AMALGAMATION |
337 + * sqlite3 struct. | 312 +typedef uint8_t u8; |
338 + * sqlite3BtreePager() and sqlite3BtreeGetPageSize() | 313 +typedef uint32_t u32; |
339 + * sqlite3BtreeGetOptimalReserve() | 314 +typedef sqlite3_int64 i64; |
340 + * sqlite3PagerGet() and sqlite3PagerUnref() | 315 +typedef sqlite3_uint64 u64; |
341 + * getVarint(). | 316 + |
342 + */ | 317 +#define ArraySize(x) (sizeof(x) / sizeof(x[0])) |
343 +#include "sqliteInt.h" | 318 +#endif |
| 319 + |
| 320 +/* From recover_varint.c. */ |
| 321 +u8 recoverGetVarint(const unsigned char *p, u64 *v); |
344 + | 322 + |
345 +/* For debugging. */ | 323 +/* For debugging. */ |
346 +#if 0 | 324 +#if 0 |
347 +#define FNENTRY() fprintf(stderr, "In %s\n", __FUNCTION__) | 325 +#define FNENTRY() fprintf(stderr, "In %s\n", __FUNCTION__) |
348 +#else | 326 +#else |
349 +#define FNENTRY() | 327 +#define FNENTRY() |
350 +#endif | 328 +#endif |
351 + | 329 + |
352 +/* Generic constants and helper functions. */ | 330 +/* Generic constants and helper functions. */ |
353 + | 331 + |
354 +static const unsigned char kTableLeafPage = 0x0D; | 332 +static const unsigned char kTableLeafPage = 0x0D; |
355 +static const unsigned char kTableInteriorPage = 0x05; | 333 +static const unsigned char kTableInteriorPage = 0x05; |
356 + | 334 + |
357 +/* From section 1.2. */ | 335 +/* From section 1.2. */ |
358 +static const unsigned kiHeaderPageSizeOffset = 16; | 336 +static const unsigned kiHeaderPageSizeOffset = 16; |
359 +static const unsigned kiHeaderReservedSizeOffset = 20; | 337 +static const unsigned kiHeaderReservedSizeOffset = 20; |
360 +static const unsigned kiHeaderEncodingOffset = 56; | 338 +static const unsigned kiHeaderEncodingOffset = 56; |
361 +/* TODO(shess) |static const unsigned| fails creating the header in GetPager() | 339 +/* TODO(shess) |static const unsigned| fails creating the header in GetPager() |
362 +** because |knHeaderSize| isn't |constexpr|. But this isn't C++, either. | 340 +** because |knHeaderSize| isn't |constexpr|. But this isn't C++, either. |
363 +*/ | 341 +*/ |
364 +enum { knHeaderSize = 100}; | 342 +enum { knHeaderSize = 100}; |
365 + | 343 + |
366 +/* From section 1.5. */ | 344 +/* From section 1.5. */ |
367 +static const unsigned kiPageTypeOffset = 0; | 345 +static const unsigned kiPageTypeOffset = 0; |
368 +static const unsigned kiPageFreeBlockOffset = 1; | 346 +/* static const unsigned kiPageFreeBlockOffset = 1; */ |
369 +static const unsigned kiPageCellCountOffset = 3; | 347 +static const unsigned kiPageCellCountOffset = 3; |
370 +static const unsigned kiPageCellContentOffset = 5; | 348 +/* static const unsigned kiPageCellContentOffset = 5; */ |
371 +static const unsigned kiPageFragmentedBytesOffset = 7; | 349 +/* static const unsigned kiPageFragmentedBytesOffset = 7; */ |
372 +static const unsigned knPageLeafHeaderBytes = 8; | 350 +static const unsigned knPageLeafHeaderBytes = 8; |
373 +/* Interior pages contain an additional field. */ | 351 +/* Interior pages contain an additional field. */ |
374 +static const unsigned kiPageRightChildOffset = 8; | 352 +static const unsigned kiPageRightChildOffset = 8; |
375 +static const unsigned kiPageInteriorHeaderBytes = 12; | 353 +static const unsigned kiPageInteriorHeaderBytes = 12; |
376 + | 354 + |
377 +/* Accepted types are specified by a mask. */ | 355 +/* Accepted types are specified by a mask. */ |
378 +#define MASK_ROWID (1<<0) | 356 +#define MASK_ROWID (1<<0) |
379 +#define MASK_INTEGER (1<<1) | 357 +#define MASK_INTEGER (1<<1) |
380 +#define MASK_FLOAT (1<<2) | 358 +#define MASK_FLOAT (1<<2) |
381 +#define MASK_TEXT (1<<3) | 359 +#define MASK_TEXT (1<<3) |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 +/* TODO(shess): SQLite by default allocates page metadata in a single allocatio
n | 508 +/* TODO(shess): SQLite by default allocates page metadata in a single allocatio
n |
531 +** such that the page's data and metadata are contiguous, see pcache1AllocPage | 509 +** such that the page's data and metadata are contiguous, see pcache1AllocPage |
532 +** in pcache1.c. I believe this was intended to reduce malloc churn. It means | 510 +** in pcache1.c. I believe this was intended to reduce malloc churn. It means |
533 +** that Chromium's automated tooling would be unlikely to see page-buffer | 511 +** that Chromium's automated tooling would be unlikely to see page-buffer |
534 +** overruns. I believe that this code is safe, but for now replicate SQLite's | 512 +** overruns. I believe that this code is safe, but for now replicate SQLite's |
535 +** approach with kExcessSpace. | 513 +** approach with kExcessSpace. |
536 +*/ | 514 +*/ |
537 +const int kExcessSpace = 128; | 515 +const int kExcessSpace = 128; |
538 +typedef struct RecoverPage RecoverPage; | 516 +typedef struct RecoverPage RecoverPage; |
539 +struct RecoverPage { | 517 +struct RecoverPage { |
540 + Pgno pgno; /* Page number for this page */ | 518 + u32 pgno; /* Page number for this page */ |
541 + void *pData; /* Page data for pgno */ | 519 + void *pData; /* Page data for pgno */ |
542 + RecoverPager *pPager; /* The pager this page is part of */ | 520 + RecoverPager *pPager; /* The pager this page is part of */ |
543 +}; | 521 +}; |
544 + | 522 + |
545 +static void pageDestroy(RecoverPage *pPage){ | 523 +static void pageDestroy(RecoverPage *pPage){ |
546 + sqlite3_free(pPage->pData); | 524 + sqlite3_free(pPage->pData); |
547 + memset(pPage, 0xA5, sizeof(*pPage)); | 525 + memset(pPage, 0xA5, sizeof(*pPage)); |
548 + sqlite3_free(pPage); | 526 + sqlite3_free(pPage); |
549 +} | 527 +} |
550 + | 528 + |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
807 +} | 785 +} |
808 + | 786 + |
809 +/* Cursor for iterating interior nodes. Interior page cells contain a | 787 +/* Cursor for iterating interior nodes. Interior page cells contain a |
810 + * child page number and a rowid. The child page contains items left | 788 + * child page number and a rowid. The child page contains items left |
811 + * of the rowid (less than). The rightmost page of the subtree is | 789 + * of the rowid (less than). The rightmost page of the subtree is |
812 + * stored in the page header. | 790 + * stored in the page header. |
813 + * | 791 + * |
814 + * interiorCursorDestroy - release all resources associated with the | 792 + * interiorCursorDestroy - release all resources associated with the |
815 + * cursor and any parent cursors. | 793 + * cursor and any parent cursors. |
816 + * interiorCursorCreate - create a cursor with the given parent and page. | 794 + * interiorCursorCreate - create a cursor with the given parent and page. |
817 + * interiorCursorEOF - returns true if neither the cursor nor the | |
818 + * parent cursors can return any more data. | |
819 + * interiorCursorNextPage - fetch the next child page from the cursor. | 795 + * interiorCursorNextPage - fetch the next child page from the cursor. |
820 + * | 796 + * |
821 + * Logically, interiorCursorNextPage() returns the next child page | 797 + * Logically, interiorCursorNextPage() returns the next child page |
822 + * number from the page the cursor is currently reading, calling the | 798 + * number from the page the cursor is currently reading, calling the |
823 + * parent cursor as necessary to get new pages to read, until done. | 799 + * parent cursor as necessary to get new pages to read, until done. |
824 + * SQLITE_ROW if a page is returned, SQLITE_DONE if out of pages, | 800 + * SQLITE_ROW if a page is returned, SQLITE_DONE if out of pages, |
825 + * error otherwise. Unfortunately, if the table is corrupted | 801 + * error otherwise. Unfortunately, if the table is corrupted |
826 + * unexpected pages can be returned. If any unexpected page is found, | 802 + * unexpected pages can be returned. If any unexpected page is found, |
827 + * leaf or otherwise, it is returned to the caller for processing, | 803 + * leaf or otherwise, it is returned to the caller for processing, |
828 + * with the interior cursor left empty. The next call to | 804 + * with the interior cursor left empty. The next call to |
829 + * interiorCursorNextPage() will recurse to the parent cursor until an | 805 + * interiorCursorNextPage() will recurse to the parent cursor until an |
830 + * interior page to iterate is returned. | 806 + * interior page to iterate is returned. |
831 + * | 807 + * |
832 + * Note that while interiorCursorNextPage() will refuse to follow | 808 + * Note that while interiorCursorNextPage() will refuse to follow |
833 + * loops, it does not keep track of pages returned for purposes of | 809 + * loops, it does not keep track of pages returned for purposes of |
834 + * preventing duplication. | 810 + * preventing duplication. |
835 + * | |
836 + * Note that interiorCursorEOF() could return false (not at EOF), and | |
837 + * interiorCursorNextPage() could still return SQLITE_DONE. This | |
838 + * could happen if there are more cells to iterate in an interior | |
839 + * page, but those cells refer to invalid pages. | |
840 + */ | 811 + */ |
841 +typedef struct RecoverInteriorCursor RecoverInteriorCursor; | 812 +typedef struct RecoverInteriorCursor RecoverInteriorCursor; |
842 +struct RecoverInteriorCursor { | 813 +struct RecoverInteriorCursor { |
843 + RecoverInteriorCursor *pParent; /* Parent node to this node. */ | 814 + RecoverInteriorCursor *pParent; /* Parent node to this node. */ |
844 + RecoverPage *pPage; /* Reference to leaf page. */ | 815 + RecoverPage *pPage; /* Reference to leaf page. */ |
845 + unsigned nPageSize; /* Size of page. */ | 816 + unsigned nPageSize; /* Size of page. */ |
846 + unsigned nChildren; /* Number of children on the page. */ | 817 + unsigned nChildren; /* Number of children on the page. */ |
847 + unsigned iChild; /* Index of next child to return. */ | 818 + unsigned iChild; /* Index of next child to return. */ |
848 +}; | 819 +}; |
849 + | 820 + |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 + | 916 + |
946 + /* TODO(shess): Check for cell overlaps? Cells require 4 bytes plus | 917 + /* TODO(shess): Check for cell overlaps? Cells require 4 bytes plus |
947 + * a varint. Check could be identical to leaf check (or even a | 918 + * a varint. Check could be identical to leaf check (or even a |
948 + * shared helper testing for "Cells starting in this range"?). | 919 + * shared helper testing for "Cells starting in this range"?). |
949 + */ | 920 + */ |
950 + | 921 + |
951 + /* If the offset is broken, return an invalid page number. */ | 922 + /* If the offset is broken, return an invalid page number. */ |
952 + return 0; | 923 + return 0; |
953 +} | 924 +} |
954 + | 925 + |
955 +static int interiorCursorEOF(RecoverInteriorCursor *pCursor){ | |
956 + /* Find a parent with remaining children. EOF if none found. */ | |
957 + while( pCursor && pCursor->iChild>=pCursor->nChildren ){ | |
958 + pCursor = pCursor->pParent; | |
959 + } | |
960 + return pCursor==NULL; | |
961 +} | |
962 + | |
963 +/* Internal helper. Used to detect if iPage would cause a loop. */ | 926 +/* Internal helper. Used to detect if iPage would cause a loop. */ |
964 +static int interiorCursorPageInUse(RecoverInteriorCursor *pCursor, | 927 +static int interiorCursorPageInUse(RecoverInteriorCursor *pCursor, |
965 + unsigned iPage){ | 928 + unsigned iPage){ |
966 + /* Find any parent using the indicated page. */ | 929 + /* Find any parent using the indicated page. */ |
967 + while( pCursor && pCursor->pPage->pgno!=iPage ){ | 930 + while( pCursor && pCursor->pPage->pgno!=iPage ){ |
968 + pCursor = pCursor->pParent; | 931 + pCursor = pCursor->pParent; |
969 + } | 932 + } |
970 + return pCursor!=NULL; | 933 + return pCursor!=NULL; |
971 +} | 934 +} |
972 + | 935 + |
(...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1568 + /* B-tree leaf cells lead with varint record size, varint rowid and | 1531 + /* B-tree leaf cells lead with varint record size, varint rowid and |
1569 + * varint header size. | 1532 + * varint header size. |
1570 + */ | 1533 + */ |
1571 + /* TODO(shess): The smallest page size is 512 bytes, which has an m | 1534 + /* TODO(shess): The smallest page size is 512 bytes, which has an m |
1572 + * of 39. Three varints need at most 27 bytes to encode. I think. | 1535 + * of 39. Three varints need at most 27 bytes to encode. I think. |
1573 + */ | 1536 + */ |
1574 + if( !checkVarints(pCell, nCellMaxBytes, 3) ){ | 1537 + if( !checkVarints(pCell, nCellMaxBytes, 3) ){ |
1575 + return ValidateError(); | 1538 + return ValidateError(); |
1576 + } | 1539 + } |
1577 + | 1540 + |
1578 + nRead = getVarint(pCell, &nRecordBytes); | 1541 + nRead = recoverGetVarint(pCell, &nRecordBytes); |
1579 + assert( iCellOffset+nRead<=pCursor->nPageSize ); | 1542 + assert( iCellOffset+nRead<=pCursor->nPageSize ); |
1580 + pCursor->nRecordBytes = nRecordBytes; | 1543 + pCursor->nRecordBytes = nRecordBytes; |
1581 + | 1544 + |
1582 + nRead += getVarint(pCell + nRead, &iRowid); | 1545 + nRead += recoverGetVarint(pCell + nRead, &iRowid); |
1583 + assert( iCellOffset+nRead<=pCursor->nPageSize ); | 1546 + assert( iCellOffset+nRead<=pCursor->nPageSize ); |
1584 + pCursor->iRowid = (i64)iRowid; | 1547 + pCursor->iRowid = (i64)iRowid; |
1585 + | 1548 + |
1586 + pCursor->iRecordOffset = iCellOffset + nRead; | 1549 + pCursor->iRecordOffset = iCellOffset + nRead; |
1587 + | 1550 + |
1588 + /* Start overflow setup here because nLocalRecordBytes is needed to | 1551 + /* Start overflow setup here because nLocalRecordBytes is needed to |
1589 + * check cell overlap. | 1552 + * check cell overlap. |
1590 + */ | 1553 + */ |
1591 + rc = overflowMaybeCreate(pCursor->pPage, pCursor->nPageSize, | 1554 + rc = overflowMaybeCreate(pCursor->pPage, pCursor->nPageSize, |
1592 + pCursor->iRecordOffset, pCursor->nRecordBytes, | 1555 + pCursor->iRecordOffset, pCursor->nRecordBytes, |
1593 + &pCursor->nLocalRecordBytes, | 1556 + &pCursor->nLocalRecordBytes, |
1594 + &pCursor->pOverflow); | 1557 + &pCursor->pOverflow); |
1595 + if( rc!=SQLITE_OK ){ | 1558 + if( rc!=SQLITE_OK ){ |
1596 + return ValidateError(); | 1559 + return ValidateError(); |
1597 + } | 1560 + } |
1598 + | 1561 + |
1599 + /* Check that no other cell starts within this cell. */ | 1562 + /* Check that no other cell starts within this cell. */ |
1600 + iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes; | 1563 + iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes; |
1601 + for( i=0; i<pCursor->nCells && pCellOffsets + i*2 + 2 <= pPageEnd; ++i ){ | 1564 + for( i=0; i<pCursor->nCells && pCellOffsets + i*2 + 2 <= pPageEnd; ++i ){ |
1602 + const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2); | 1565 + const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2); |
1603 + if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){ | 1566 + if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){ |
1604 + return ValidateError(); | 1567 + return ValidateError(); |
1605 + } | 1568 + } |
1606 + } | 1569 + } |
1607 + | 1570 + |
1608 + nRecordHeaderRead = getVarint(pCell + nRead, &nRecordHeaderBytes); | 1571 + nRecordHeaderRead = recoverGetVarint(pCell + nRead, &nRecordHeaderBytes); |
1609 + assert( nRecordHeaderBytes<=nRecordBytes ); | 1572 + assert( nRecordHeaderBytes<=nRecordBytes ); |
1610 + pCursor->nRecordHeaderBytes = nRecordHeaderBytes; | 1573 + pCursor->nRecordHeaderBytes = nRecordHeaderBytes; |
1611 + | 1574 + |
1612 + /* Large headers could overflow if pages are small. */ | 1575 + /* Large headers could overflow if pages are small. */ |
1613 + rc = overflowGetSegment(pCursor->pPage, | 1576 + rc = overflowGetSegment(pCursor->pPage, |
1614 + pCursor->iRecordOffset, pCursor->nLocalRecordBytes, | 1577 + pCursor->iRecordOffset, pCursor->nLocalRecordBytes, |
1615 + pCursor->pOverflow, 0, nRecordHeaderBytes, | 1578 + pCursor->pOverflow, 0, nRecordHeaderBytes, |
1616 + &pCursor->pRecordHeader, &pCursor->bFreeRecordHeader)
; | 1579 + &pCursor->pRecordHeader, &pCursor->bFreeRecordHeader)
; |
1617 + if( rc!=SQLITE_OK ){ | 1580 + if( rc!=SQLITE_OK ){ |
1618 + return ValidateError(); | 1581 + return ValidateError(); |
1619 + } | 1582 + } |
1620 + | 1583 + |
1621 + /* Tally up the column count and size of data. */ | 1584 + /* Tally up the column count and size of data. */ |
1622 + nRecordCols = 0; | 1585 + nRecordCols = 0; |
1623 + nRecordColBytes = 0; | 1586 + nRecordColBytes = 0; |
1624 + while( nRecordHeaderRead<nRecordHeaderBytes ){ | 1587 + while( nRecordHeaderRead<nRecordHeaderBytes ){ |
1625 + u64 iSerialType; /* Type descriptor for current column. */ | 1588 + u64 iSerialType; /* Type descriptor for current column. */ |
1626 + if( !checkVarint(pCursor->pRecordHeader + nRecordHeaderRead, | 1589 + if( !checkVarint(pCursor->pRecordHeader + nRecordHeaderRead, |
1627 + nRecordHeaderBytes - nRecordHeaderRead) ){ | 1590 + nRecordHeaderBytes - nRecordHeaderRead) ){ |
1628 + return ValidateError(); | 1591 + return ValidateError(); |
1629 + } | 1592 + } |
1630 + nRecordHeaderRead += getVarint(pCursor->pRecordHeader + nRecordHeaderRead, | 1593 + nRecordHeaderRead += recoverGetVarint( |
1631 + &iSerialType); | 1594 + pCursor->pRecordHeader + nRecordHeaderRead, &iSerialType); |
1632 + if( iSerialType==10 || iSerialType==11 ){ | 1595 + if( iSerialType==10 || iSerialType==11 ){ |
1633 + return ValidateError(); | 1596 + return ValidateError(); |
1634 + } | 1597 + } |
1635 + nRecordColBytes += SerialTypeLength(iSerialType); | 1598 + nRecordColBytes += SerialTypeLength(iSerialType); |
1636 + nRecordCols++; | 1599 + nRecordCols++; |
1637 + } | 1600 + } |
1638 + pCursor->nRecordCols = nRecordCols; | 1601 + pCursor->nRecordCols = nRecordCols; |
1639 + | 1602 + |
1640 + /* Parsing the header used as many bytes as expected. */ | 1603 + /* Parsing the header used as many bytes as expected. */ |
1641 + if( nRecordHeaderRead!=nRecordHeaderBytes ){ | 1604 + if( nRecordHeaderRead!=nRecordHeaderBytes ){ |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1687 + | 1650 + |
1688 + /* Must be able to decode header size. */ | 1651 + /* Must be able to decode header size. */ |
1689 + pRecordHeader = pCursor->pRecordHeader; | 1652 + pRecordHeader = pCursor->pRecordHeader; |
1690 + if( !checkVarint(pRecordHeader, pCursor->nRecordHeaderBytes) ){ | 1653 + if( !checkVarint(pRecordHeader, pCursor->nRecordHeaderBytes) ){ |
1691 + return SQLITE_CORRUPT; | 1654 + return SQLITE_CORRUPT; |
1692 + } | 1655 + } |
1693 + | 1656 + |
1694 + /* Rather than caching the header size and how many bytes it took, | 1657 + /* Rather than caching the header size and how many bytes it took, |
1695 + * decode it every time. | 1658 + * decode it every time. |
1696 + */ | 1659 + */ |
1697 + nRead = getVarint(pRecordHeader, &nRecordHeaderBytes); | 1660 + nRead = recoverGetVarint(pRecordHeader, &nRecordHeaderBytes); |
1698 + assert( nRecordHeaderBytes==pCursor->nRecordHeaderBytes ); | 1661 + assert( nRecordHeaderBytes==pCursor->nRecordHeaderBytes ); |
1699 + | 1662 + |
1700 + /* Scan forward to the indicated column. Scans to _after_ column | 1663 + /* Scan forward to the indicated column. Scans to _after_ column |
1701 + * for later range checking. | 1664 + * for later range checking. |
1702 + */ | 1665 + */ |
1703 + /* TODO(shess): This could get expensive for very wide tables. An | 1666 + /* TODO(shess): This could get expensive for very wide tables. An |
1704 + * array of iSerialType could be built in leafCursorCellDecode(), but | 1667 + * array of iSerialType could be built in leafCursorCellDecode(), but |
1705 + * the number of columns is dynamic per row, so it would add memory | 1668 + * the number of columns is dynamic per row, so it would add memory |
1706 + * management complexity. Enough info to efficiently forward | 1669 + * management complexity. Enough info to efficiently forward |
1707 + * iterate could be kept, if all clients forward iterate | 1670 + * iterate could be kept, if all clients forward iterate |
1708 + * (recoverColumn() may not). | 1671 + * (recoverColumn() may not). |
1709 + */ | 1672 + */ |
1710 + iColEndOffset = 0; | 1673 + iColEndOffset = 0; |
1711 + nColsSkipped = 0; | 1674 + nColsSkipped = 0; |
1712 + while( nColsSkipped<=iCol && nRead<nRecordHeaderBytes ){ | 1675 + while( nColsSkipped<=iCol && nRead<nRecordHeaderBytes ){ |
1713 + if( !checkVarint(pRecordHeader + nRead, nRecordHeaderBytes - nRead) ){ | 1676 + if( !checkVarint(pRecordHeader + nRead, nRecordHeaderBytes - nRead) ){ |
1714 + return SQLITE_CORRUPT; | 1677 + return SQLITE_CORRUPT; |
1715 + } | 1678 + } |
1716 + nRead += getVarint(pRecordHeader + nRead, &iSerialType); | 1679 + nRead += recoverGetVarint(pRecordHeader + nRead, &iSerialType); |
1717 + iColEndOffset += SerialTypeLength(iSerialType); | 1680 + iColEndOffset += SerialTypeLength(iSerialType); |
1718 + nColsSkipped++; | 1681 + nColsSkipped++; |
1719 + } | 1682 + } |
1720 + | 1683 + |
1721 + /* Column's data extends past record's end. */ | 1684 + /* Column's data extends past record's end. */ |
1722 + if( nRecordHeaderBytes+iColEndOffset>pCursor->nRecordBytes ){ | 1685 + if( nRecordHeaderBytes+iColEndOffset>pCursor->nRecordBytes ){ |
1723 + return SQLITE_CORRUPT; | 1686 + return SQLITE_CORRUPT; |
1724 + } | 1687 + } |
1725 + | 1688 + |
1726 + *piColType = iSerialType; | 1689 + *piColType = iSerialType; |
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2101 + recoverRowid, /* xRowid - read data */ | 2064 + recoverRowid, /* xRowid - read data */ |
2102 + 0, /* xUpdate - write data */ | 2065 + 0, /* xUpdate - write data */ |
2103 + 0, /* xBegin - begin transaction */ | 2066 + 0, /* xBegin - begin transaction */ |
2104 + 0, /* xSync - sync transaction */ | 2067 + 0, /* xSync - sync transaction */ |
2105 + 0, /* xCommit - commit transaction */ | 2068 + 0, /* xCommit - commit transaction */ |
2106 + 0, /* xRollback - rollback transaction */ | 2069 + 0, /* xRollback - rollback transaction */ |
2107 + 0, /* xFindFunction - function overloading */ | 2070 + 0, /* xFindFunction - function overloading */ |
2108 + 0, /* xRename - rename the table */ | 2071 + 0, /* xRename - rename the table */ |
2109 +}; | 2072 +}; |
2110 + | 2073 + |
2111 +CHROMIUM_SQLITE_API | 2074 +SQLITE_API |
2112 +int recoverVtableInit(sqlite3 *db){ | 2075 +int recoverVtableInit(sqlite3 *db){ |
2113 + return sqlite3_create_module_v2(db, "recover", &recoverModule, NULL, 0); | 2076 + return sqlite3_create_module_v2(db, "recover", &recoverModule, NULL, 0); |
2114 +} | 2077 +} |
2115 + | 2078 + |
2116 +/* This section of code is for parsing the create input and | 2079 +/* This section of code is for parsing the create input and |
2117 + * initializing the module. | 2080 + * initializing the module. |
2118 + */ | 2081 + */ |
2119 + | 2082 + |
2120 +/* Find the next word in zText and place the endpoints in pzWord*. | 2083 +/* Find the next word in zText and place the endpoints in pzWord*. |
2121 + * Returns true if the word is non-empty. "Word" is defined as | 2084 + * 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... |
2339 + if( !pRecover ){ | 2302 + if( !pRecover ){ |
2340 + return SQLITE_NOMEM; | 2303 + return SQLITE_NOMEM; |
2341 + } | 2304 + } |
2342 + memset(pRecover, 0, sizeof(*pRecover)); | 2305 + memset(pRecover, 0, sizeof(*pRecover)); |
2343 + pRecover->base.pModule = &recoverModule; | 2306 + pRecover->base.pModule = &recoverModule; |
2344 + pRecover->db = db; | 2307 + pRecover->db = db; |
2345 + | 2308 + |
2346 + /* Parse out db.table, assuming main if no dot. */ | 2309 + /* Parse out db.table, assuming main if no dot. */ |
2347 + zDot = strchr(argv[3], '.'); | 2310 + zDot = strchr(argv[3], '.'); |
2348 + if( !zDot ){ | 2311 + if( !zDot ){ |
2349 + pRecover->zDb = sqlite3_strdup(db->aDb[0].zName); | 2312 + pRecover->zDb = sqlite3_strdup("main"); |
2350 + pRecover->zTable = sqlite3_strdup(argv[3]); | 2313 + pRecover->zTable = sqlite3_strdup(argv[3]); |
2351 + }else if( zDot>argv[3] && zDot[1]!='\0' ){ | 2314 + }else if( zDot>argv[3] && zDot[1]!='\0' ){ |
2352 + pRecover->zDb = sqlite3_strndup(argv[3], zDot - argv[3]); | 2315 + pRecover->zDb = sqlite3_strndup(argv[3], zDot - argv[3]); |
2353 + pRecover->zTable = sqlite3_strdup(zDot + 1); | 2316 + pRecover->zTable = sqlite3_strdup(zDot + 1); |
2354 + }else{ | 2317 + }else{ |
2355 + /* ".table" or "db." not allowed. */ | 2318 + /* ".table" or "db." not allowed. */ |
2356 + *pzErr = sqlite3_mprintf("ill-formed table specifier"); | 2319 + *pzErr = sqlite3_mprintf("ill-formed table specifier"); |
2357 + recoverRelease(pRecover); | 2320 + recoverRelease(pRecover); |
2358 + return SQLITE_ERROR; | 2321 + return SQLITE_ERROR; |
2359 + } | 2322 + } |
(...skipping 29 matching lines...) Expand all Loading... |
2389 + rc = sqlite3_declare_vtab(db, zCreateSql); | 2352 + rc = sqlite3_declare_vtab(db, zCreateSql); |
2390 + sqlite3_free(zCreateSql); | 2353 + sqlite3_free(zCreateSql); |
2391 + if( rc!=SQLITE_OK ){ | 2354 + if( rc!=SQLITE_OK ){ |
2392 + recoverRelease(pRecover); | 2355 + recoverRelease(pRecover); |
2393 + return rc; | 2356 + return rc; |
2394 + } | 2357 + } |
2395 + | 2358 + |
2396 + *ppVtab = (sqlite3_vtab *)pRecover; | 2359 + *ppVtab = (sqlite3_vtab *)pRecover; |
2397 + return SQLITE_OK; | 2360 + return SQLITE_OK; |
2398 +} | 2361 +} |
2399 diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src
/sqlite.h.in | 2362 diff --git a/third_party/sqlite/src/src/recover.h b/third_party/sqlite/src/src/r
ecover.h |
2400 index e5673fd..6829bcb 100644 | 2363 new file mode 100644 |
2401 --- a/third_party/sqlite/src/src/sqlite.h.in | 2364 index 0000000..691f2fd |
2402 +++ b/third_party/sqlite/src/src/sqlite.h.in | 2365 --- /dev/null |
2403 @@ -7411,6 +7411,22 @@ int sqlite3_strnicmp(const char *, const char *, int); | 2366 +++ b/third_party/sqlite/src/src/recover.h |
2404 */ | 2367 @@ -0,0 +1,23 @@ |
2405 int sqlite3_strglob(const char *zGlob, const char *zStr); | 2368 +/* TODO(shess): sqliteicu.h is able to make this include without |
2406 | 2369 +** trouble. It doesn't work when used with Chromium's SQLite. For |
2407 +/* Begin recover virtual table patch for Chromium */ | 2370 +** now the including code must include sqlite3.h first. |
2408 +/* Our patches don't conform to SQLite's amalgamation processing. Hack it. */ | 2371 +*/ |
2409 +#ifndef CHROMIUM_SQLITE_API | 2372 +/* #include "sqlite3.h" */ |
2410 +#define CHROMIUM_SQLITE_API SQLITE_API | 2373 + |
| 2374 +#ifdef __cplusplus |
| 2375 +extern "C" { |
2411 +#endif | 2376 +#endif |
| 2377 + |
2412 +/* | 2378 +/* |
2413 +** Call to initialize the recover virtual-table modules (see recover.c). | 2379 +** Call to initialize the recover virtual-table modules (see recover.c). |
2414 +** | 2380 +** |
2415 +** This could be loaded by default in main.c, but that would make the | 2381 +** This could be loaded by default in main.c, but that would make the |
2416 +** virtual table available to Web SQL. Breaking it out allows only | 2382 +** virtual table available to Web SQL. Breaking it out allows only |
2417 +** selected users to enable it (currently sql/recovery.cc). | 2383 +** selected users to enable it (currently sql/recovery.cc). |
2418 +*/ | 2384 +*/ |
2419 +CHROMIUM_SQLITE_API | 2385 +SQLITE_API |
2420 +int recoverVtableInit(sqlite3 *db); | 2386 +int recoverVtableInit(sqlite3 *db); |
2421 +/* End recover virtual table patch for Chromium */ | 2387 + |
2422 + | 2388 +#ifdef __cplusplus |
2423 /* Begin WebDatabase patch for Chromium */ | 2389 +} /* End of the 'extern "C"' block */ |
2424 /* Expose some SQLite internals for the WebDatabase vfs. | 2390 +#endif |
2425 ** DO NOT EXTEND THE USE OF THIS. | 2391 diff --git a/third_party/sqlite/src/src/recover_varint.c b/third_party/sqlite/sr
c/src/recover_varint.c |
| 2392 new file mode 100644 |
| 2393 index 0000000..c111e2c |
| 2394 --- /dev/null |
| 2395 +++ b/third_party/sqlite/src/src/recover_varint.c |
| 2396 @@ -0,0 +1,201 @@ |
| 2397 +/* |
| 2398 +** 2016 Feb 29 |
| 2399 +** |
| 2400 +** The author disclaims copyright to this source code. In place of |
| 2401 +** a legal notice, here is a blessing: |
| 2402 +** |
| 2403 +** May you do good and not evil. |
| 2404 +** May you find forgiveness for yourself and forgive others. |
| 2405 +** May you share freely, never taking more than you give. |
| 2406 +** |
| 2407 +****************************************************************************** |
| 2408 +** |
| 2409 +** Copy of sqlite3Fts5GetVarint() from fts3_varint.c, which in turn is copied |
| 2410 +** from SQLite core. |
| 2411 +*/ |
| 2412 + |
| 2413 +#include <assert.h> |
| 2414 +#include "sqlite3.h" |
| 2415 + |
| 2416 +/* Copied from fts3int.h. */ |
| 2417 +#ifndef SQLITE_AMALGAMATION |
| 2418 +typedef unsigned char u8; |
| 2419 +typedef unsigned int u32; |
| 2420 +typedef sqlite3_uint64 u64; |
| 2421 +#endif |
| 2422 + |
| 2423 +/* |
| 2424 +** Bitmasks used by recoverGetVarint(). These precomputed constants |
| 2425 +** are defined here rather than simply putting the constant expressions |
| 2426 +** inline in order to work around bugs in the RVT compiler. |
| 2427 +** |
| 2428 +** SLOT_2_0 A mask for (0x7f<<14) | 0x7f |
| 2429 +** |
| 2430 +** SLOT_4_2_0 A mask for (0x7f<<28) | SLOT_2_0 |
| 2431 +*/ |
| 2432 +#define SLOT_2_0 0x001fc07f |
| 2433 +#define SLOT_4_2_0 0xf01fc07f |
| 2434 + |
| 2435 +/* |
| 2436 +** Read a 64-bit variable-length integer from memory starting at p[0]. |
| 2437 +** Return the number of bytes read. The value is stored in *v. |
| 2438 +*/ |
| 2439 +u8 recoverGetVarint(const unsigned char *p, u64 *v){ |
| 2440 + u32 a,b,s; |
| 2441 + |
| 2442 + a = *p; |
| 2443 + /* a: p0 (unmasked) */ |
| 2444 + if (!(a&0x80)) |
| 2445 + { |
| 2446 + *v = a; |
| 2447 + return 1; |
| 2448 + } |
| 2449 + |
| 2450 + p++; |
| 2451 + b = *p; |
| 2452 + /* b: p1 (unmasked) */ |
| 2453 + if (!(b&0x80)) |
| 2454 + { |
| 2455 + a &= 0x7f; |
| 2456 + a = a<<7; |
| 2457 + a |= b; |
| 2458 + *v = a; |
| 2459 + return 2; |
| 2460 + } |
| 2461 + |
| 2462 + /* Verify that constants are precomputed correctly */ |
| 2463 + assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) ); |
| 2464 + assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) ); |
| 2465 + |
| 2466 + p++; |
| 2467 + a = a<<14; |
| 2468 + a |= *p; |
| 2469 + /* a: p0<<14 | p2 (unmasked) */ |
| 2470 + if (!(a&0x80)) |
| 2471 + { |
| 2472 + a &= SLOT_2_0; |
| 2473 + b &= 0x7f; |
| 2474 + b = b<<7; |
| 2475 + a |= b; |
| 2476 + *v = a; |
| 2477 + return 3; |
| 2478 + } |
| 2479 + |
| 2480 + /* CSE1 from below */ |
| 2481 + a &= SLOT_2_0; |
| 2482 + p++; |
| 2483 + b = b<<14; |
| 2484 + b |= *p; |
| 2485 + /* b: p1<<14 | p3 (unmasked) */ |
| 2486 + if (!(b&0x80)) |
| 2487 + { |
| 2488 + b &= SLOT_2_0; |
| 2489 + /* moved CSE1 up */ |
| 2490 + /* a &= (0x7f<<14)|(0x7f); */ |
| 2491 + a = a<<7; |
| 2492 + a |= b; |
| 2493 + *v = a; |
| 2494 + return 4; |
| 2495 + } |
| 2496 + |
| 2497 + /* a: p0<<14 | p2 (masked) */ |
| 2498 + /* b: p1<<14 | p3 (unmasked) */ |
| 2499 + /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
| 2500 + /* moved CSE1 up */ |
| 2501 + /* a &= (0x7f<<14)|(0x7f); */ |
| 2502 + b &= SLOT_2_0; |
| 2503 + s = a; |
| 2504 + /* s: p0<<14 | p2 (masked) */ |
| 2505 + |
| 2506 + p++; |
| 2507 + a = a<<14; |
| 2508 + a |= *p; |
| 2509 + /* a: p0<<28 | p2<<14 | p4 (unmasked) */ |
| 2510 + if (!(a&0x80)) |
| 2511 + { |
| 2512 + /* we can skip these cause they were (effectively) done above in calc'ing s
*/ |
| 2513 + /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ |
| 2514 + /* b &= (0x7f<<14)|(0x7f); */ |
| 2515 + b = b<<7; |
| 2516 + a |= b; |
| 2517 + s = s>>18; |
| 2518 + *v = ((u64)s)<<32 | a; |
| 2519 + return 5; |
| 2520 + } |
| 2521 + |
| 2522 + /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
| 2523 + s = s<<7; |
| 2524 + s |= b; |
| 2525 + /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */ |
| 2526 + |
| 2527 + p++; |
| 2528 + b = b<<14; |
| 2529 + b |= *p; |
| 2530 + /* b: p1<<28 | p3<<14 | p5 (unmasked) */ |
| 2531 + if (!(b&0x80)) |
| 2532 + { |
| 2533 + /* we can skip this cause it was (effectively) done above in calc'ing s */ |
| 2534 + /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */ |
| 2535 + a &= SLOT_2_0; |
| 2536 + a = a<<7; |
| 2537 + a |= b; |
| 2538 + s = s>>18; |
| 2539 + *v = ((u64)s)<<32 | a; |
| 2540 + return 6; |
| 2541 + } |
| 2542 + |
| 2543 + p++; |
| 2544 + a = a<<14; |
| 2545 + a |= *p; |
| 2546 + /* a: p2<<28 | p4<<14 | p6 (unmasked) */ |
| 2547 + if (!(a&0x80)) |
| 2548 + { |
| 2549 + a &= SLOT_4_2_0; |
| 2550 + b &= SLOT_2_0; |
| 2551 + b = b<<7; |
| 2552 + a |= b; |
| 2553 + s = s>>11; |
| 2554 + *v = ((u64)s)<<32 | a; |
| 2555 + return 7; |
| 2556 + } |
| 2557 + |
| 2558 + /* CSE2 from below */ |
| 2559 + a &= SLOT_2_0; |
| 2560 + p++; |
| 2561 + b = b<<14; |
| 2562 + b |= *p; |
| 2563 + /* b: p3<<28 | p5<<14 | p7 (unmasked) */ |
| 2564 + if (!(b&0x80)) |
| 2565 + { |
| 2566 + b &= SLOT_4_2_0; |
| 2567 + /* moved CSE2 up */ |
| 2568 + /* a &= (0x7f<<14)|(0x7f); */ |
| 2569 + a = a<<7; |
| 2570 + a |= b; |
| 2571 + s = s>>4; |
| 2572 + *v = ((u64)s)<<32 | a; |
| 2573 + return 8; |
| 2574 + } |
| 2575 + |
| 2576 + p++; |
| 2577 + a = a<<15; |
| 2578 + a |= *p; |
| 2579 + /* a: p4<<29 | p6<<15 | p8 (unmasked) */ |
| 2580 + |
| 2581 + /* moved CSE2 up */ |
| 2582 + /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */ |
| 2583 + b &= SLOT_2_0; |
| 2584 + b = b<<8; |
| 2585 + a |= b; |
| 2586 + |
| 2587 + s = s<<4; |
| 2588 + b = p[-4]; |
| 2589 + b &= 0x7f; |
| 2590 + b = b>>3; |
| 2591 + s |= b; |
| 2592 + |
| 2593 + *v = ((u64)s)<<32 | a; |
| 2594 + |
| 2595 + return 9; |
| 2596 +} |
| 2597 + |
2426 diff --git a/third_party/sqlite/src/test/recover.test b/third_party/sqlite/src/t
est/recover.test | 2598 diff --git a/third_party/sqlite/src/test/recover.test b/third_party/sqlite/src/t
est/recover.test |
2427 new file mode 100644 | 2599 new file mode 100644 |
2428 index 0000000..bfb7888 | 2600 index 0000000..bfb7888 |
2429 --- /dev/null | 2601 --- /dev/null |
2430 +++ b/third_party/sqlite/src/test/recover.test | 2602 +++ b/third_party/sqlite/src/test/recover.test |
2431 @@ -0,0 +1,164 @@ | 2603 @@ -0,0 +1,164 @@ |
2432 +# 2012 January 11 {} | 2604 +# 2012 January 11 {} |
2433 +# | 2605 +# |
2434 +# The author disclaims copyright to this source code. In place of | 2606 +# The author disclaims copyright to this source code. In place of |
2435 +# a legal notice, here is a blessing: | 2607 +# a legal notice, here is a blessing: |
(...skipping 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3722 + db eval {VACUUM} | 3894 + db eval {VACUUM} |
3723 + | 3895 + |
3724 + execsql { | 3896 + execsql { |
3725 + PRAGMA page_count; | 3897 + PRAGMA page_count; |
3726 + PRAGMA page_size; | 3898 + PRAGMA page_size; |
3727 + SELECT rowid, TYPEOF(value), length(value), value FROM overflow_recover; | 3899 + SELECT rowid, TYPEOF(value), length(value), value FROM overflow_recover; |
3728 + } | 3900 + } |
3729 +} [list 4 1024 1 text [string length $substr] $substr] | 3901 +} [list 4 1024 1 text [string length $substr] $substr] |
3730 + | 3902 + |
3731 +finish_test | 3903 +finish_test |
3732 diff --git a/third_party/sqlite/src/tool/mksqlite3c.tcl b/third_party/sqlite/src
/tool/mksqlite3c.tcl | |
3733 index 23241e2..1113758 100644 | |
3734 --- a/third_party/sqlite/src/tool/mksqlite3c.tcl | |
3735 +++ b/third_party/sqlite/src/tool/mksqlite3c.tcl | |
3736 @@ -361,6 +361,8 @@ foreach file { | |
3737 main.c | |
3738 notify.c | |
3739 | |
3740 + recover.c | |
3741 + | |
3742 fts3.c | |
3743 fts3_aux.c | |
3744 fts3_expr.c | |
3745 -- | 3904 -- |
3746 2.7.0 | 3905 2.5.0 |
3747 | 3906 |
OLD | NEW |