Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 Add new virtual table 'recover' to src/ and the amalgamation. | 1 From 1423eb6c432e7983fd353c0f9d928e55eeb5e0ec Mon Sep 17 00:00:00 2001 |
| 2 From: Scott Hess <shess@chromium.org> | |
| 3 Date: Tue, 16 Dec 2014 13:07:57 -0800 | |
| 4 Subject: [PATCH 08/24] Virtual table supporting recovery of corrupted | |
| 5 databases. | |
| 2 | 6 |
| 3 Since recover.c is in somewhat active development, it is possible that | 7 "recover" implements a virtual table which uses the SQLite pager layer |
| 4 the patch below will not reliably re-create the file. | 8 to read table pages and pull out the data which is structurally sound |
| 9 (at least at the storage layer). | |
| 5 | 10 |
| 6 shess@chromium.org | 11 BUG=109482 |
| 12 --- | |
| 13 third_party/sqlite/src/Makefile.in | 1 + | |
| 14 third_party/sqlite/src/Makefile.linux-gcc | 4 + | |
| 15 third_party/sqlite/src/main.mk | 4 +- | |
| 16 third_party/sqlite/src/src/main.c | 8 + | |
| 17 third_party/sqlite/src/src/recover.c | 2164 ++++++++++++++++++++++++++++ | |
| 18 third_party/sqlite/src/src/sqlite.h.in | 11 + | |
| 19 third_party/sqlite/src/test/recover.test | 147 ++ | |
| 20 third_party/sqlite/src/test/recover0.test | 532 +++++++ | |
| 21 third_party/sqlite/src/test/recover1.test | 429 ++++++ | |
| 22 third_party/sqlite/src/test/recover2.test | 157 ++ | |
| 23 third_party/sqlite/src/tool/mksqlite3c.tcl | 2 + | |
| 24 11 files changed, 3458 insertions(+), 1 deletion(-) | |
| 25 create mode 100644 third_party/sqlite/src/src/recover.c | |
| 26 create mode 100644 third_party/sqlite/src/test/recover.test | |
| 27 create mode 100644 third_party/sqlite/src/test/recover0.test | |
| 28 create mode 100644 third_party/sqlite/src/test/recover1.test | |
| 29 create mode 100644 third_party/sqlite/src/test/recover2.test | |
| 7 | 30 |
| 8 Generated with: | 31 diff --git a/third_party/sqlite/src/Makefile.in b/third_party/sqlite/src/Makefil e.in |
| 9 git diff --cached --relative=third_party/sqlite/src --src-prefix='' --dst-prefix ='' > third_party/sqlite/recover.patch | |
| 10 [--cached because otherwise the diff adding recover.c wasn't generated.] | |
| 11 | |
| 12 diff --git Makefile.in Makefile.in | |
| 13 index f3239f3..216742c 100644 | 32 index f3239f3..216742c 100644 |
| 14 --- Makefile.in | 33 --- a/third_party/sqlite/src/Makefile.in |
| 15 +++ Makefile.in | 34 +++ b/third_party/sqlite/src/Makefile.in |
| 16 @@ -251,6 +251,7 @@ SRC = \ | 35 @@ -251,6 +251,7 @@ SRC = \ |
| 17 $(TOP)/src/prepare.c \ | 36 $(TOP)/src/prepare.c \ |
| 18 $(TOP)/src/printf.c \ | 37 $(TOP)/src/printf.c \ |
| 19 $(TOP)/src/random.c \ | 38 $(TOP)/src/random.c \ |
| 20 + $(TOP)/src/recover.c \ | 39 + $(TOP)/src/recover.c \ |
| 21 $(TOP)/src/resolve.c \ | 40 $(TOP)/src/resolve.c \ |
| 22 $(TOP)/src/rowset.c \ | 41 $(TOP)/src/rowset.c \ |
| 23 $(TOP)/src/select.c \ | 42 $(TOP)/src/select.c \ |
| 24 diff --git src/sqlite.h.in src/sqlite.h.in | 43 diff --git a/third_party/sqlite/src/Makefile.linux-gcc b/third_party/sqlite/src/ Makefile.linux-gcc |
| 25 index 62b9326..fb76659 100644 | 44 index 554bf56..e631816 100644 |
| 26 --- src/sqlite.h.in | 45 --- a/third_party/sqlite/src/Makefile.linux-gcc |
| 27 +++ src/sqlite.h.in | 46 +++ b/third_party/sqlite/src/Makefile.linux-gcc |
| 28 @@ -6403,6 +6403,17 @@ int sqlite3_wal_checkpoint_v2( | 47 @@ -82,6 +82,10 @@ OPTS += -DSQLITE_MEMDEBUG=1 |
| 29 #define SQLITE_CHECKPOINT_RESTART 2 | 48 # TODO(shess) I can't see why I need this setting. |
| 49 OPTS += -DOS_UNIX=1 | |
| 30 | 50 |
| 51 +# The recover virtual table is not generally enabled. Enable it for testing | |
| 52 +# purposes. | |
| 53 +OPTS += -DDEFAULT_ENABLE_RECOVER=1 | |
| 54 + | |
| 55 #### The suffix to add to executable files. ".exe" for windows. | |
| 56 # Nothing for unix. | |
| 57 # | |
| 58 diff --git a/third_party/sqlite/src/main.mk b/third_party/sqlite/src/main.mk | |
| 59 index b0aa4b2..65dd690 100644 | |
| 60 --- a/third_party/sqlite/src/main.mk | |
| 61 +++ b/third_party/sqlite/src/main.mk | |
| 62 @@ -62,7 +62,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \ | |
| 63 mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \ | |
| 64 notify.o opcodes.o os.o os_os2.o os_unix.o os_win.o \ | |
| 65 pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \ | |
| 66 - random.o resolve.o rowset.o rtree.o select.o status.o \ | |
| 67 + random.o recover.o resolve.o rowset.o rtree.o select.o status.o \ | |
| 68 table.o tokenize.o trigger.o \ | |
| 69 update.o util.o vacuum.o \ | |
| 70 vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbetrace.o \ | |
| 71 @@ -132,6 +132,7 @@ SRC = \ | |
| 72 $(TOP)/src/prepare.c \ | |
| 73 $(TOP)/src/printf.c \ | |
| 74 $(TOP)/src/random.c \ | |
| 75 + $(TOP)/src/recover.c \ | |
| 76 $(TOP)/src/resolve.c \ | |
| 77 $(TOP)/src/rowset.c \ | |
| 78 $(TOP)/src/select.c \ | |
| 79 @@ -284,6 +285,7 @@ TESTSRC2 = \ | |
| 80 $(TOP)/src/prepare.c \ | |
| 81 $(TOP)/src/printf.c \ | |
| 82 $(TOP)/src/random.c \ | |
| 83 + $(TOP)/src/recover.c \ | |
| 84 $(TOP)/src/pcache.c \ | |
| 85 $(TOP)/src/pcache1.c \ | |
| 86 $(TOP)/src/select.c \ | |
| 87 diff --git a/third_party/sqlite/src/src/main.c b/third_party/sqlite/src/src/main .c | |
| 88 index 4aaa618..696de1c 100644 | |
| 89 --- a/third_party/sqlite/src/src/main.c | |
| 90 +++ b/third_party/sqlite/src/src/main.c | |
| 91 @@ -1996,6 +1996,14 @@ static int openDatabase( | |
| 92 } | |
| 93 #endif | |
| 31 | 94 |
| 32 +/* Begin recover.patch for Chromium */ | 95 +#ifdef DEFAULT_ENABLE_RECOVER |
| 33 +/* | 96 + /* Initialize recover virtual table for testing. */ |
| 34 +** Call to initialize the recover virtual-table modules (see recover.c). | 97 + extern int recoverVtableInit(sqlite3 *db); |
| 35 +** | 98 + if( !db->mallocFailed && rc==SQLITE_OK ){ |
| 36 +** This could be loaded by default in main.c, but that would make the | 99 + rc = recoverVtableInit(db); |
| 37 +** virtual table available to Web SQL. Breaking it out allows only | 100 + } |
| 38 +** selected users to enable it (currently sql/recovery.cc). | 101 +#endif |
| 39 +*/ | |
| 40 +int recoverVtableInit(sqlite3 *db); | |
| 41 +/* End recover.patch for Chromium */ | |
| 42 + | 102 + |
| 43 /* | 103 #ifdef SQLITE_ENABLE_ICU |
| 44 ** Undo the hack that converts floating point types to integer for | 104 if( !db->mallocFailed && rc==SQLITE_OK ){ |
| 45 ** builds on processors without floating point support. | 105 rc = sqlite3IcuInit(db); |
| 46 diff --git tool/mksqlite3c.tcl tool/mksqlite3c.tcl | 106 diff --git a/third_party/sqlite/src/src/recover.c b/third_party/sqlite/src/src/r ecover.c |
| 47 index fa99f2d..df2df07 100644 | |
| 48 --- tool/mksqlite3c.tcl | |
| 49 +++ tool/mksqlite3c.tcl | |
| 50 @@ -293,6 +293,8 @@ foreach file { | |
| 51 main.c | |
| 52 notify.c | |
| 53 | |
| 54 + recover.c | |
| 55 + | |
| 56 fts3.c | |
| 57 fts3_aux.c | |
| 58 fts3_expr.c | |
| 59 diff --git src/recover.c src/recover.c | |
| 60 new file mode 100644 | 107 new file mode 100644 |
| 61 index 0000000..6430c8b | 108 index 0000000..c996d53 |
| 62 --- /dev/null | 109 --- /dev/null |
| 63 +++ src/recover.c | 110 +++ b/third_party/sqlite/src/src/recover.c |
| 64 @@ -0,0 +1,2130 @@ | 111 @@ -0,0 +1,2164 @@ |
| 65 +/* | 112 +/* |
| 66 +** 2012 Jan 11 | 113 +** 2012 Jan 11 |
| 67 +** | 114 +** |
| 68 +** The author disclaims copyright to this source code. In place of | 115 +** The author disclaims copyright to this source code. In place of |
| 69 +** a legal notice, here is a blessing: | 116 +** a legal notice, here is a blessing: |
| 70 +** | 117 +** |
| 71 +** May you do good and not evil. | 118 +** May you do good and not evil. |
| 72 +** May you find forgiveness for yourself and forgive others. | 119 +** May you find forgiveness for yourself and forgive others. |
| 73 +** May you share freely, never taking more than you give. | 120 +** May you share freely, never taking more than you give. |
| 74 +*/ | 121 +*/ |
| (...skipping 625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 + } | 747 + } |
| 701 + | 748 + |
| 702 + memset(p, 0xA5, sizeof(*p)); | 749 + memset(p, 0xA5, sizeof(*p)); |
| 703 + sqlite3_free(p); | 750 + sqlite3_free(p); |
| 704 + } | 751 + } |
| 705 +} | 752 +} |
| 706 + | 753 + |
| 707 +/* Internal helper. Reset storage in preparation for iterating pPage. */ | 754 +/* Internal helper. Reset storage in preparation for iterating pPage. */ |
| 708 +static void interiorCursorSetPage(RecoverInteriorCursor *pCursor, | 755 +static void interiorCursorSetPage(RecoverInteriorCursor *pCursor, |
| 709 + DbPage *pPage){ | 756 + DbPage *pPage){ |
| 757 + const unsigned knMinCellLength = 2 + 4 + 1; | |
| 758 + unsigned nMaxChildren; | |
|
michaeln
2015/01/29 02:40:09
whew
Scott Hess - ex-Googler
2015/01/29 22:08:33
Yeah, this set of patches had gotten outdated and
| |
| 710 + assert( PageHeader(pPage)[kiPageTypeOffset]==kTableInteriorPage ); | 759 + assert( PageHeader(pPage)[kiPageTypeOffset]==kTableInteriorPage ); |
| 711 + | 760 + |
| 712 + if( pCursor->pPage ){ | 761 + if( pCursor->pPage ){ |
| 713 + sqlite3PagerUnref(pCursor->pPage); | 762 + sqlite3PagerUnref(pCursor->pPage); |
| 714 + pCursor->pPage = NULL; | 763 + pCursor->pPage = NULL; |
| 715 + } | 764 + } |
| 716 + pCursor->pPage = pPage; | 765 + pCursor->pPage = pPage; |
| 717 + pCursor->iChild = 0; | 766 + pCursor->iChild = 0; |
| 718 + | 767 + |
| 719 + /* A child for each cell, plus one in the header. */ | 768 + /* A child for each cell, plus one in the header. */ |
| 720 + /* TODO(shess): Sanity-check the count? Page header plus per-cell | |
| 721 + * cost of 16-bit offset, 32-bit page number, and one varint | |
| 722 + * (minimum 1 byte). | |
| 723 + */ | |
| 724 + pCursor->nChildren = decodeUnsigned16(PageHeader(pPage) + | 769 + pCursor->nChildren = decodeUnsigned16(PageHeader(pPage) + |
| 725 + kiPageCellCountOffset) + 1; | 770 + kiPageCellCountOffset) + 1; |
| 771 + | |
| 772 + /* Each child requires a 16-bit offset from an array after the header, | |
| 773 + * and each child contains a 32-bit page number and at least a varint | |
| 774 + * (min size of one byte). The final child page is in the header. So | |
| 775 + * the maximum value for nChildren is: | |
| 776 + * (nPageSize - kiPageInteriorHeaderBytes) / | |
| 777 + * (sizeof(uint16) + sizeof(uint32) + 1) + 1 | |
| 778 + */ | |
| 779 + /* TODO(shess): This count is very unlikely to be corrupted in | |
| 780 + * isolation, so seeing this could signal to skip the page. OTOH, I | |
| 781 + * can't offhand think of how to get here unless this or the page-type | |
| 782 + * byte is corrupted. Could be an overflow page, but it would require | |
| 783 + * a very large database. | |
| 784 + */ | |
| 785 + nMaxChildren = | |
| 786 + (pCursor->nPageSize - kiPageInteriorHeaderBytes) / knMinCellLength + 1; | |
| 787 + if (pCursor->nChildren > nMaxChildren) { | |
| 788 + pCursor->nChildren = nMaxChildren; | |
| 789 + } | |
| 726 +} | 790 +} |
| 727 + | 791 + |
| 728 +static int interiorCursorCreate(RecoverInteriorCursor *pParent, | 792 +static int interiorCursorCreate(RecoverInteriorCursor *pParent, |
| 729 + DbPage *pPage, int nPageSize, | 793 + DbPage *pPage, int nPageSize, |
| 730 + RecoverInteriorCursor **ppCursor){ | 794 + RecoverInteriorCursor **ppCursor){ |
| 731 + RecoverInteriorCursor *pCursor = | 795 + RecoverInteriorCursor *pCursor = |
| 732 + sqlite3_malloc(sizeof(RecoverInteriorCursor)); | 796 + sqlite3_malloc(sizeof(RecoverInteriorCursor)); |
| 733 + if( !pCursor ){ | 797 + if( !pCursor ){ |
| 734 + return SQLITE_NOMEM; | 798 + return SQLITE_NOMEM; |
| 735 + } | 799 + } |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1332 +} | 1396 +} |
| 1333 + | 1397 + |
| 1334 +/* Useful for setting breakpoints. */ | 1398 +/* Useful for setting breakpoints. */ |
| 1335 +static int ValidateError(){ | 1399 +static int ValidateError(){ |
| 1336 + return SQLITE_ERROR; | 1400 + return SQLITE_ERROR; |
| 1337 +} | 1401 +} |
| 1338 + | 1402 + |
| 1339 +/* Setup the cursor for reading the information from cell iCell. */ | 1403 +/* Setup the cursor for reading the information from cell iCell. */ |
| 1340 +static int leafCursorCellDecode(RecoverLeafCursor *pCursor){ | 1404 +static int leafCursorCellDecode(RecoverLeafCursor *pCursor){ |
| 1341 + const unsigned char *pPageHeader; /* Header of current page. */ | 1405 + const unsigned char *pPageHeader; /* Header of current page. */ |
| 1406 + const unsigned char *pPageEnd; /* Byte after end of current page. */ | |
| 1342 + const unsigned char *pCellOffsets; /* Pointer to page's cell offsets. */ | 1407 + const unsigned char *pCellOffsets; /* Pointer to page's cell offsets. */ |
| 1343 + unsigned iCellOffset; /* Offset of current cell (iCell). */ | 1408 + unsigned iCellOffset; /* Offset of current cell (iCell). */ |
| 1344 + const unsigned char *pCell; /* Pointer to data at iCellOffset. */ | 1409 + const unsigned char *pCell; /* Pointer to data at iCellOffset. */ |
| 1345 + unsigned nCellMaxBytes; /* Maximum local size of iCell. */ | 1410 + unsigned nCellMaxBytes; /* Maximum local size of iCell. */ |
| 1346 + unsigned iEndOffset; /* End of iCell's in-page data. */ | 1411 + unsigned iEndOffset; /* End of iCell's in-page data. */ |
| 1347 + u64 nRecordBytes; /* Expected size of cell, w/overflow. */ | 1412 + u64 nRecordBytes; /* Expected size of cell, w/overflow. */ |
| 1348 + u64 iRowid; /* iCell's rowid (in table). */ | 1413 + u64 iRowid; /* iCell's rowid (in table). */ |
| 1349 + unsigned nRead; /* Amount of cell read. */ | 1414 + unsigned nRead; /* Amount of cell read. */ |
| 1350 + unsigned nRecordHeaderRead; /* Header data read. */ | 1415 + unsigned nRecordHeaderRead; /* Header data read. */ |
| 1351 + u64 nRecordHeaderBytes; /* Header size expected. */ | 1416 + u64 nRecordHeaderBytes; /* Header size expected. */ |
| 1352 + unsigned nRecordCols; /* Columns read from header. */ | 1417 + unsigned nRecordCols; /* Columns read from header. */ |
| 1353 + u64 nRecordColBytes; /* Bytes in payload for those columns. */ | 1418 + u64 nRecordColBytes; /* Bytes in payload for those columns. */ |
| 1354 + unsigned i; | 1419 + unsigned i; |
| 1355 + int rc; | 1420 + int rc; |
| 1356 + | 1421 + |
| 1357 + assert( pCursor->iCell<pCursor->nCells ); | 1422 + assert( pCursor->iCell<pCursor->nCells ); |
| 1358 + | 1423 + |
| 1359 + leafCursorDestroyCellData(pCursor); | 1424 + leafCursorDestroyCellData(pCursor); |
| 1360 + | 1425 + |
| 1361 + /* Find the offset to the row. */ | 1426 + /* Find the offset to the row. */ |
| 1362 + pPageHeader = PageHeader(pCursor->pPage); | 1427 + pPageHeader = PageHeader(pCursor->pPage); |
| 1363 + pCellOffsets = pPageHeader + knPageLeafHeaderBytes; | 1428 + pCellOffsets = pPageHeader + knPageLeafHeaderBytes; |
| 1429 + pPageEnd = PageData(pCursor->pPage, pCursor->nPageSize); | |
| 1430 + if( pCellOffsets + pCursor->iCell*2 + 2 > pPageEnd ){ | |
| 1431 + return ValidateError(); | |
| 1432 + } | |
| 1364 + iCellOffset = decodeUnsigned16(pCellOffsets + pCursor->iCell*2); | 1433 + iCellOffset = decodeUnsigned16(pCellOffsets + pCursor->iCell*2); |
| 1365 + if( iCellOffset>=pCursor->nPageSize ){ | 1434 + if( iCellOffset>=pCursor->nPageSize ){ |
| 1366 + return ValidateError(); | 1435 + return ValidateError(); |
| 1367 + } | 1436 + } |
| 1368 + | 1437 + |
| 1369 + pCell = PageData(pCursor->pPage, iCellOffset); | 1438 + pCell = PageData(pCursor->pPage, iCellOffset); |
| 1370 + nCellMaxBytes = pCursor->nPageSize - iCellOffset; | 1439 + nCellMaxBytes = pCursor->nPageSize - iCellOffset; |
| 1371 + | 1440 + |
| 1372 + /* B-tree leaf cells lead with varint record size, varint rowid and | 1441 + /* B-tree leaf cells lead with varint record size, varint rowid and |
| 1373 + * varint header size. | 1442 + * varint header size. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1395 + rc = overflowMaybeCreate(pCursor->pPage, pCursor->nPageSize, | 1464 + rc = overflowMaybeCreate(pCursor->pPage, pCursor->nPageSize, |
| 1396 + pCursor->iRecordOffset, pCursor->nRecordBytes, | 1465 + pCursor->iRecordOffset, pCursor->nRecordBytes, |
| 1397 + &pCursor->nLocalRecordBytes, | 1466 + &pCursor->nLocalRecordBytes, |
| 1398 + &pCursor->pOverflow); | 1467 + &pCursor->pOverflow); |
| 1399 + if( rc!=SQLITE_OK ){ | 1468 + if( rc!=SQLITE_OK ){ |
| 1400 + return ValidateError(); | 1469 + return ValidateError(); |
| 1401 + } | 1470 + } |
| 1402 + | 1471 + |
| 1403 + /* Check that no other cell starts within this cell. */ | 1472 + /* Check that no other cell starts within this cell. */ |
| 1404 + iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes; | 1473 + iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes; |
| 1405 + for( i=0; i<pCursor->nCells; ++i ){ | 1474 + for( i=0; i<pCursor->nCells && pCellOffsets + i*2 + 2 <= pPageEnd; ++i ){ |
| 1406 + const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2); | 1475 + const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2); |
| 1407 + if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){ | 1476 + if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){ |
| 1408 + return ValidateError(); | 1477 + return ValidateError(); |
| 1409 + } | 1478 + } |
| 1410 + } | 1479 + } |
| 1411 + | 1480 + |
| 1412 + nRecordHeaderRead = getVarint(pCell + nRead, &nRecordHeaderBytes); | 1481 + nRecordHeaderRead = getVarint(pCell + nRead, &nRecordHeaderBytes); |
| 1413 + assert( nRecordHeaderBytes<=nRecordBytes ); | 1482 + assert( nRecordHeaderBytes<=nRecordBytes ); |
| 1414 + pCursor->nRecordHeaderBytes = nRecordHeaderBytes; | 1483 + pCursor->nRecordHeaderBytes = nRecordHeaderBytes; |
| 1415 + | 1484 + |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1684 + pCursor = sqlite3_malloc(sizeof(RecoverCursor)); | 1753 + pCursor = sqlite3_malloc(sizeof(RecoverCursor)); |
| 1685 + if( !pCursor ){ | 1754 + if( !pCursor ){ |
| 1686 + leafCursorDestroy(pLeafCursor); | 1755 + leafCursorDestroy(pLeafCursor); |
| 1687 + return SQLITE_NOMEM; | 1756 + return SQLITE_NOMEM; |
| 1688 + } | 1757 + } |
| 1689 + memset(pCursor, 0, sizeof(*pCursor)); | 1758 + memset(pCursor, 0, sizeof(*pCursor)); |
| 1690 + pCursor->base.pVtab = pVTab; | 1759 + pCursor->base.pVtab = pVTab; |
| 1691 + pCursor->pLeafCursor = pLeafCursor; | 1760 + pCursor->pLeafCursor = pLeafCursor; |
| 1692 + pCursor->iEncoding = iEncoding; | 1761 + pCursor->iEncoding = iEncoding; |
| 1693 + | 1762 + |
| 1763 + /* If no leaf pages were found, empty result set. */ | |
| 1764 + /* TODO(shess): leafCursorNextValidCell() would return SQLITE_ROW or | |
| 1765 + * SQLITE_DONE to indicate whether there is further data to consider. | |
| 1766 + */ | |
| 1767 + pCursor->bEOF = (pLeafCursor->pPage==NULL); | |
| 1768 + | |
| 1694 + *ppCursor = (sqlite3_vtab_cursor*)pCursor; | 1769 + *ppCursor = (sqlite3_vtab_cursor*)pCursor; |
| 1695 + return SQLITE_OK; | 1770 + return SQLITE_OK; |
| 1696 +} | 1771 +} |
| 1697 + | 1772 + |
| 1698 +static int recoverClose(sqlite3_vtab_cursor *cur){ | 1773 +static int recoverClose(sqlite3_vtab_cursor *cur){ |
| 1699 + RecoverCursor *pCursor = (RecoverCursor*)cur; | 1774 + RecoverCursor *pCursor = (RecoverCursor*)cur; |
| 1700 + FNENTRY(); | 1775 + FNENTRY(); |
| 1701 + if( pCursor->pLeafCursor ){ | 1776 + if( pCursor->pLeafCursor ){ |
| 1702 + leafCursorDestroy(pCursor->pLeafCursor); | 1777 + leafCursorDestroy(pCursor->pLeafCursor); |
| 1703 + pCursor->pLeafCursor = NULL; | 1778 + pCursor->pLeafCursor = NULL; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1772 + sqlite3_vtab_cursor *pVtabCursor, | 1847 + sqlite3_vtab_cursor *pVtabCursor, |
| 1773 + int idxNum, const char *idxStr, | 1848 + int idxNum, const char *idxStr, |
| 1774 + int argc, sqlite3_value **argv | 1849 + int argc, sqlite3_value **argv |
| 1775 +){ | 1850 +){ |
| 1776 + RecoverCursor *pCursor = (RecoverCursor*)pVtabCursor; | 1851 + RecoverCursor *pCursor = (RecoverCursor*)pVtabCursor; |
| 1777 + Recover *pRecover = (Recover*)pCursor->base.pVtab; | 1852 + Recover *pRecover = (Recover*)pCursor->base.pVtab; |
| 1778 + int rc; | 1853 + int rc; |
| 1779 + | 1854 + |
| 1780 + FNENTRY(); | 1855 + FNENTRY(); |
| 1781 + | 1856 + |
| 1782 + /* Load the first cell, and iterate forward if it's not valid. */ | 1857 + /* There were no valid leaf pages in the table. */ |
| 1783 + /* TODO(shess): What happens if no cells at all are valid? */ | 1858 + if( pCursor->bEOF ){ |
| 1859 + return SQLITE_OK; | |
| 1860 + } | |
| 1861 + | |
| 1862 + /* Load the first cell, and iterate forward if it's not valid. If no cells a t | |
| 1863 + * all are valid, recoverNext() sets bEOF and returns appropriately. | |
| 1864 + */ | |
| 1784 + rc = leafCursorCellDecode(pCursor->pLeafCursor); | 1865 + rc = leafCursorCellDecode(pCursor->pLeafCursor); |
| 1785 + if( rc!=SQLITE_OK || recoverValidateLeafCell(pRecover, pCursor)!=SQLITE_OK ){ | 1866 + if( rc!=SQLITE_OK || recoverValidateLeafCell(pRecover, pCursor)!=SQLITE_OK ){ |
| 1786 + return recoverNext(pVtabCursor); | 1867 + return recoverNext(pVtabCursor); |
| 1787 + } | 1868 + } |
| 1788 + | 1869 + |
| 1789 + return SQLITE_OK; | 1870 + return SQLITE_OK; |
| 1790 +} | 1871 +} |
| 1791 + | 1872 + |
| 1792 +static int recoverEof(sqlite3_vtab_cursor *pVtabCursor){ | 1873 +static int recoverEof(sqlite3_vtab_cursor *pVtabCursor){ |
| 1793 + RecoverCursor *pCursor = (RecoverCursor*)pVtabCursor; | 1874 + RecoverCursor *pCursor = (RecoverCursor*)pVtabCursor; |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2185 + rc = sqlite3_declare_vtab(db, zCreateSql); | 2266 + rc = sqlite3_declare_vtab(db, zCreateSql); |
| 2186 + sqlite3_free(zCreateSql); | 2267 + sqlite3_free(zCreateSql); |
| 2187 + if( rc!=SQLITE_OK ){ | 2268 + if( rc!=SQLITE_OK ){ |
| 2188 + recoverRelease(pRecover); | 2269 + recoverRelease(pRecover); |
| 2189 + return rc; | 2270 + return rc; |
| 2190 + } | 2271 + } |
| 2191 + | 2272 + |
| 2192 + *ppVtab = (sqlite3_vtab *)pRecover; | 2273 + *ppVtab = (sqlite3_vtab *)pRecover; |
| 2193 + return SQLITE_OK; | 2274 + return SQLITE_OK; |
| 2194 +} | 2275 +} |
| 2276 diff --git a/third_party/sqlite/src/src/sqlite.h.in b/third_party/sqlite/src/src /sqlite.h.in | |
| 2277 index ec7e502..00c8510 100644 | |
| 2278 --- a/third_party/sqlite/src/src/sqlite.h.in | |
| 2279 +++ b/third_party/sqlite/src/src/sqlite.h.in | |
| 2280 @@ -6388,6 +6388,17 @@ int sqlite3_wal_checkpoint_v2( | |
| 2281 #define SQLITE_CHECKPOINT_RESTART 2 | |
| 2282 | |
| 2283 | |
| 2284 +/* Begin recover.patch for Chromium */ | |
| 2285 +/* | |
| 2286 +** Call to initialize the recover virtual-table modules (see recover.c). | |
| 2287 +** | |
| 2288 +** This could be loaded by default in main.c, but that would make the | |
| 2289 +** virtual table available to Web SQL. Breaking it out allows only | |
| 2290 +** selected users to enable it (currently sql/recovery.cc). | |
| 2291 +*/ | |
| 2292 +int recoverVtableInit(sqlite3 *db); | |
| 2293 +/* End recover.patch for Chromium */ | |
| 2294 + | |
| 2295 /* | |
| 2296 ** Undo the hack that converts floating point types to integer for | |
| 2297 ** builds on processors without floating point support. | |
| 2298 diff --git a/third_party/sqlite/src/test/recover.test b/third_party/sqlite/src/t est/recover.test | |
| 2299 new file mode 100644 | |
| 2300 index 0000000..b5aa182 | |
| 2301 --- /dev/null | |
| 2302 +++ b/third_party/sqlite/src/test/recover.test | |
| 2303 @@ -0,0 +1,147 @@ | |
| 2304 +# 2012 January 11 {} | |
| 2305 +# | |
| 2306 +# The author disclaims copyright to this source code. In place of | |
| 2307 +# a legal notice, here is a blessing: | |
| 2308 +# | |
| 2309 +# May you do good and not evil. | |
| 2310 +# May you find forgiveness for yourself and forgive others. | |
| 2311 +# May you share freely, never taking more than you give. | |
| 2312 +# | |
| 2313 +#*********************************************************************** | |
| 2314 +# This file implements regression tests for SQLite library. | |
| 2315 +# | |
| 2316 +# This file implements tests for the recover module, which can read | |
| 2317 +# through corrupt rows and pages. | |
| 2318 +# | |
| 2319 +# $Id$ | |
| 2320 + | |
| 2321 +# TODO(shess): These all test that the module correctly reads good | |
| 2322 +# data. It would be good to implement tests of corrupt data. | |
| 2323 + | |
| 2324 +set testdir [file dirname $argv0] | |
| 2325 +source $testdir/tester.tcl | |
| 2326 + | |
| 2327 +db eval { | |
| 2328 + DROP TABLE IF EXISTS altered; | |
| 2329 + CREATE TABLE altered ( | |
| 2330 + c TEXT | |
| 2331 + ); | |
| 2332 + INSERT INTO altered VALUES ('a'); | |
| 2333 + INSERT INTO altered VALUES ('b'); | |
| 2334 + INSERT INTO altered VALUES ('c'); | |
| 2335 + ALTER TABLE altered ADD COLUMN i INTEGER NOT NULL DEFAULT 10; | |
| 2336 + INSERT INTO altered VALUES ('d', 5); | |
| 2337 +} | |
| 2338 + | |
| 2339 +# SQLite will fill the earlier rows with the default. | |
| 2340 +do_test recover-alter-1.0 { | |
| 2341 + execsql {SELECT c, i FROM altered ORDER BY rowid} | |
| 2342 +} {a 10 b 10 c 10 d 5} | |
| 2343 + | |
| 2344 +# recover sees NULL for those rows. | |
| 2345 +do_test recover-alter-1.1 { | |
| 2346 + db eval { | |
| 2347 + DROP TABLE IF EXISTS temp.altered_recover; | |
| 2348 + CREATE VIRTUAL TABLE temp.altered_recover USING recover( | |
| 2349 + altered, | |
| 2350 + c TEXT, | |
| 2351 + i INTEGER | |
| 2352 + ); | |
| 2353 + } | |
| 2354 + execsql {SELECT c, i FROM altered_recover ORDER BY rowid} | |
| 2355 +} {a {} b {} c {} d 5} | |
| 2356 + | |
| 2357 +# Can skip those NULL columns like if they contained a real NULL. | |
| 2358 +do_test recover-alter-1.2 { | |
| 2359 + db eval { | |
| 2360 + DROP TABLE IF EXISTS temp.altered_recover; | |
| 2361 + CREATE VIRTUAL TABLE temp.altered_recover USING recover( | |
| 2362 + altered, | |
| 2363 + c TEXT, | |
| 2364 + i INTEGER NOT NULL | |
| 2365 + ); | |
| 2366 + } | |
| 2367 + execsql {SELECT c, i FROM altered_recover ORDER BY rowid} | |
| 2368 +} {d 5} | |
| 2369 + | |
| 2370 +if {0} { | |
| 2371 +# It would be neat if this could work. I tried putting "DEFAULT ..." | |
| 2372 +# in the schema exposed by the recover table, but it doesn't do the | |
| 2373 +# trick. | |
| 2374 +do_test recover-alter-1.2 { | |
| 2375 + db eval { | |
| 2376 + DROP TABLE IF EXISTS temp.altered_recover; | |
| 2377 + CREATE VIRTUAL TABLE temp.altered_recover USING recover( | |
| 2378 + altered, | |
| 2379 + c TEXT, | |
| 2380 + i INTEGER NOT NULL DEFAULT 10 | |
| 2381 + ); | |
| 2382 + } | |
| 2383 + execsql {SELECT c, i FROM altered_recover ORDER BY rowid} | |
| 2384 +} {a 10 b 10 c 10 d 5} | |
| 2385 +} | |
| 2386 + | |
| 2387 +# Helper function to generate an arbitrarily-sized table. | |
| 2388 +proc generate {table base count} { | |
| 2389 + db eval "DROP TABLE IF EXISTS $table" | |
| 2390 + db transaction immediate { | |
| 2391 + db eval "CREATE TABLE $table (t TEXT,n INT)" | |
| 2392 + for {set i 0} {$i<$count} {incr i} { | |
| 2393 + set t [concat $base $i] | |
| 2394 + db eval [concat {INSERT INTO} $table {VALUES ($t, $i)}] | |
| 2395 + } | |
| 2396 + } | |
| 2397 +} | |
| 2398 + | |
| 2399 +# Leaf-only database parses. | |
| 2400 +do_test recover-leaf-1.0 { | |
| 2401 + db close | |
| 2402 + sqlite3 db test.db | |
| 2403 + generate "leaf" "Leaf-node-generating line " 10 | |
| 2404 + | |
| 2405 + db eval { | |
| 2406 + DROP TABLE IF EXISTS temp.leaf_recover; | |
| 2407 + CREATE VIRTUAL TABLE temp.leaf_recover USING recover( | |
| 2408 + leaf, | |
| 2409 + t TEXT, | |
| 2410 + n INTEGER | |
| 2411 + ); | |
| 2412 + } | |
| 2413 + execsql {SELECT t, n FROM leaf_recover ORDER BY rowid} | |
| 2414 +} {{Leaf-node-generating line 0} 0 {Leaf-node-generating line 1} 1 {Leaf-node-g enerating line 2} 2 {Leaf-node-generating line 3} 3 {Leaf-node-generating line 4 } 4 {Leaf-node-generating line 5} 5 {Leaf-node-generating line 6} 6 {Leaf-node-g enerating line 7} 7 {Leaf-node-generating line 8} 8 {Leaf-node-generating line 9 } 9} | |
| 2415 + | |
| 2416 +# Single level of interior node. | |
| 2417 +do_test recover-interior-1.0 { | |
| 2418 + db close | |
| 2419 + sqlite3 db test.db | |
| 2420 + generate "interior" "Interior-node-generating line " 100 | |
| 2421 + | |
| 2422 + db eval { | |
| 2423 + DROP TABLE IF EXISTS temp.interior_recover; | |
| 2424 + CREATE VIRTUAL TABLE temp.interior_recover USING recover( | |
| 2425 + interior, | |
| 2426 + t TEXT, | |
| 2427 + n INTEGER | |
| 2428 + ); | |
| 2429 + } | |
| 2430 + execsql {SELECT t, n FROM interior_recover WHERE (rowid%10)=0 ORDER BY rowid} | |
| 2431 +} {{Interior-node-generating line 9} 9 {Interior-node-generating line 19} 19 {I nterior-node-generating line 29} 29 {Interior-node-generating line 39} 39 {Inter ior-node-generating line 49} 49 {Interior-node-generating line 59} 59 {Interior- node-generating line 69} 69 {Interior-node-generating line 79} 79 {Interior-node -generating line 89} 89 {Interior-node-generating line 99} 99} | |
| 2432 + | |
| 2433 +# Multiple levels of interior node. | |
| 2434 +do_test recover-interior-2.0 { | |
| 2435 + db close | |
| 2436 + sqlite3 db test.db | |
| 2437 + generate "interior2" "Interior-node-generating line " 5000 | |
| 2438 + | |
| 2439 + db eval { | |
| 2440 + DROP TABLE IF EXISTS temp.interior2_recover; | |
| 2441 + CREATE VIRTUAL TABLE temp.interior2_recover USING recover( | |
| 2442 + interior2, | |
| 2443 + t TEXT, | |
| 2444 + n INTEGER | |
| 2445 + ); | |
| 2446 + } | |
| 2447 + execsql {SELECT t, n FROM interior2_recover WHERE (rowid%500)=0 ORDER BY rowi d} | |
| 2448 +} {{Interior-node-generating line 499} 499 {Interior-node-generating line 999} 999 {Interior-node-generating line 1499} 1499 {Interior-node-generating line 199 9} 1999 {Interior-node-generating line 2499} 2499 {Interior-node-generating line 2999} 2999 {Interior-node-generating line 3499} 3499 {Interior-node-generating line 3999} 3999 {Interior-node-generating line 4499} 4499 {Interior-node-generat ing line 4999} 4999} | |
| 2449 + | |
| 2450 +finish_test | |
| 2451 diff --git a/third_party/sqlite/src/test/recover0.test b/third_party/sqlite/src/ test/recover0.test | |
| 2452 new file mode 100644 | |
| 2453 index 0000000..aac2ed9 | |
| 2454 --- /dev/null | |
| 2455 +++ b/third_party/sqlite/src/test/recover0.test | |
| 2456 @@ -0,0 +1,532 @@ | |
| 2457 +# 2012 January 4 {} | |
| 2458 +# | |
| 2459 +# The author disclaims copyright to this source code. In place of | |
| 2460 +# a legal notice, here is a blessing: | |
| 2461 +# | |
| 2462 +# May you do good and not evil. | |
| 2463 +# May you find forgiveness for yourself and forgive others. | |
| 2464 +# May you share freely, never taking more than you give. | |
| 2465 +# | |
| 2466 +#*********************************************************************** | |
| 2467 +# This file implements regression tests for SQLite library. | |
| 2468 +# | |
| 2469 +# Test recover module syntax. | |
| 2470 +# | |
| 2471 +# $Id$ | |
| 2472 + | |
| 2473 +# TODO(shess): Test with attached databases. | |
| 2474 + | |
| 2475 +# TODO(shess): Handle column mismatches? As things stand, the code | |
| 2476 +# only needs to pull the root page, so that may not be completely | |
| 2477 +# feasible. | |
| 2478 + | |
| 2479 +set testdir [file dirname $argv0] | |
| 2480 +source $testdir/tester.tcl | |
| 2481 + | |
| 2482 +db eval { | |
| 2483 + DROP TABLE IF EXISTS backing; | |
| 2484 + CREATE TABLE backing (t TEXT); | |
| 2485 + | |
| 2486 + DROP TABLE IF EXISTS backing2; | |
| 2487 + CREATE TABLE backing2 (id INTEGER PRIMARY KEY, t TEXT); | |
| 2488 +} | |
| 2489 + | |
| 2490 +# Baseline create works. | |
| 2491 +do_test recover-syntax-0.0 { | |
| 2492 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2493 + catchsql { | |
| 2494 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2495 + backing, | |
| 2496 + t TEXT | |
| 2497 + ); | |
| 2498 + } | |
| 2499 +} {0 {}} | |
| 2500 + | |
| 2501 +# Can specify database. | |
| 2502 +do_test recover-syntax-0.1 { | |
| 2503 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2504 + catchsql { | |
| 2505 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2506 + main.backing, | |
| 2507 + t TEXT | |
| 2508 + ); | |
| 2509 + } | |
| 2510 +} {0 {}} | |
| 2511 + | |
| 2512 +# Can specify sqlite_master. | |
| 2513 +do_test recover-syntax-0.2 { | |
| 2514 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2515 + catchsql { | |
| 2516 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2517 + sqlite_master, | |
| 2518 + type TEXT, | |
| 2519 + name TEXT, | |
| 2520 + tbl_name TEXT, | |
| 2521 + rootpage INTEGER, | |
| 2522 + sql TEXT | |
| 2523 + ); | |
| 2524 + } | |
| 2525 +} {0 {}} | |
| 2526 + | |
| 2527 +# Fails if virtual table is not in the temp database. | |
| 2528 +do_test recover-syntax-1.0 { | |
| 2529 + db eval {DROP TABLE IF EXISTS temp.syntax;} | |
| 2530 + catchsql { | |
| 2531 + CREATE VIRTUAL TABLE syntax USING recover( | |
| 2532 + backing, | |
| 2533 + t TEXT | |
| 2534 + ); | |
| 2535 + } | |
| 2536 +} {1 {recover table must be in temp database}} | |
| 2537 + | |
| 2538 +# Fails if mentions missing table. | |
| 2539 +do_test recover-syntax-2.0 { | |
| 2540 + db eval {DROP TABLE IF EXISTS temp.syntax;} | |
| 2541 + catchsql { | |
| 2542 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2543 + snacking, | |
| 2544 + t TEXT | |
| 2545 + ); | |
| 2546 + } | |
| 2547 +} {1 {unable to find backing table}} | |
| 2548 + | |
| 2549 +# Fails if mentions missing database. | |
| 2550 +do_test recover-syntax-2.1 { | |
| 2551 + db eval {DROP TABLE IF EXISTS temp.syntax;} | |
| 2552 + catchsql { | |
| 2553 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2554 + db.backing, | |
| 2555 + t TEXT | |
| 2556 + ); | |
| 2557 + } | |
| 2558 +} {1 {unable to find backing table}} | |
| 2559 + | |
| 2560 +# Fails if mentions garbage backing. | |
| 2561 +do_test recover-syntax-2.2 { | |
| 2562 + db eval {DROP TABLE IF EXISTS temp.syntax;} | |
| 2563 + catchsql { | |
| 2564 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2565 + main.backing excess, | |
| 2566 + t TEXT | |
| 2567 + ); | |
| 2568 + } | |
| 2569 +} {1 {unable to find backing table}} | |
| 2570 + | |
| 2571 +# Database only fails. | |
| 2572 +do_test recover-syntax-2.3 { | |
| 2573 + db eval {DROP TABLE IF EXISTS temp.syntax;} | |
| 2574 + catchsql { | |
| 2575 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2576 + main., | |
| 2577 + t TEXT | |
| 2578 + ); | |
| 2579 + } | |
| 2580 +} {1 {ill-formed table specifier}} | |
| 2581 + | |
| 2582 +# Table only fails. | |
| 2583 +do_test recover-syntax-2.4 { | |
| 2584 + db eval {DROP TABLE IF EXISTS temp.syntax;} | |
| 2585 + catchsql { | |
| 2586 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2587 + .backing, | |
| 2588 + t TEXT | |
| 2589 + ); | |
| 2590 + } | |
| 2591 +} {1 {ill-formed table specifier}} | |
| 2592 + | |
| 2593 +# Manifest typing. | |
| 2594 +do_test recover-syntax-3.0 { | |
| 2595 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2596 + execsql { | |
| 2597 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2598 + backing, | |
| 2599 + t | |
| 2600 + ); | |
| 2601 + PRAGMA table_info(syntax); | |
| 2602 + } | |
| 2603 +} {0 t {} 0 {} 0} | |
| 2604 + | |
| 2605 +# ANY as an alternative for manifest typing. | |
| 2606 +do_test recover-syntax-3.1 { | |
| 2607 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2608 + execsql { | |
| 2609 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2610 + backing, | |
| 2611 + t ANY | |
| 2612 + ); | |
| 2613 + PRAGMA table_info(syntax); | |
| 2614 + } | |
| 2615 +} {0 t {} 0 {} 0} | |
| 2616 + | |
| 2617 +# ANY NOT NULL | |
| 2618 +do_test recover-syntax-3.2 { | |
| 2619 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2620 + execsql { | |
| 2621 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2622 + backing, | |
| 2623 + t ANY NOT NULL | |
| 2624 + ); | |
| 2625 + PRAGMA table_info(syntax); | |
| 2626 + } | |
| 2627 +} {0 t {} 1 {} 0} | |
| 2628 + | |
| 2629 +# ANY STRICT is not sensible. | |
| 2630 +do_test recover-syntax-3.3 { | |
| 2631 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2632 + catchsql { | |
| 2633 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2634 + backing, | |
| 2635 + v ANY STRICT | |
| 2636 + ); | |
| 2637 + PRAGMA table_info(syntax); | |
| 2638 + } | |
| 2639 +} {1 {unable to parse column 0}} | |
| 2640 + | |
| 2641 +# TEXT column by type works. | |
| 2642 +do_test recover-syntax-4.0 { | |
| 2643 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2644 + execsql { | |
| 2645 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2646 + backing, | |
| 2647 + t TEXT | |
| 2648 + ); | |
| 2649 + PRAGMA table_info(syntax); | |
| 2650 + } | |
| 2651 +} {0 t TEXT 0 {} 0} | |
| 2652 + | |
| 2653 +# TEXT NOT NULL | |
| 2654 +do_test recover-syntax-4.1 { | |
| 2655 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2656 + execsql { | |
| 2657 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2658 + backing, | |
| 2659 + t TEXT NOT NULL | |
| 2660 + ); | |
| 2661 + PRAGMA table_info(syntax); | |
| 2662 + } | |
| 2663 +} {0 t TEXT 1 {} 0} | |
| 2664 + | |
| 2665 +# TEXT STRICT | |
| 2666 +do_test recover-syntax-4.2 { | |
| 2667 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2668 + execsql { | |
| 2669 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2670 + backing, | |
| 2671 + t TEXT STRICT | |
| 2672 + ); | |
| 2673 + PRAGMA table_info(syntax); | |
| 2674 + } | |
| 2675 +} {0 t TEXT 0 {} 0} | |
| 2676 + | |
| 2677 +# TEXT STRICT NOT NULL | |
| 2678 +do_test recover-syntax-4.3 { | |
| 2679 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2680 + execsql { | |
| 2681 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2682 + backing, | |
| 2683 + t TEXT STRICT NOT NULL | |
| 2684 + ); | |
| 2685 + PRAGMA table_info(syntax); | |
| 2686 + } | |
| 2687 +} {0 t TEXT 1 {} 0} | |
| 2688 + | |
| 2689 +# INTEGER | |
| 2690 +do_test recover-syntax-5.0 { | |
| 2691 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2692 + execsql { | |
| 2693 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2694 + backing, | |
| 2695 + i INTEGER | |
| 2696 + ); | |
| 2697 + PRAGMA table_info(syntax); | |
| 2698 + } | |
| 2699 +} {0 i INTEGER 0 {} 0} | |
| 2700 + | |
| 2701 +# INTEGER NOT NULL | |
| 2702 +do_test recover-syntax-5.1 { | |
| 2703 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2704 + execsql { | |
| 2705 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2706 + backing, | |
| 2707 + i INTEGER NOT NULL | |
| 2708 + ); | |
| 2709 + PRAGMA table_info(syntax); | |
| 2710 + } | |
| 2711 +} {0 i INTEGER 1 {} 0} | |
| 2712 + | |
| 2713 +# INTEGER STRICT | |
| 2714 +do_test recover-syntax-5.2 { | |
| 2715 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2716 + execsql { | |
| 2717 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2718 + backing, | |
| 2719 + i INTEGER STRICT | |
| 2720 + ); | |
| 2721 + PRAGMA table_info(syntax); | |
| 2722 + } | |
| 2723 +} {0 i INTEGER 0 {} 0} | |
| 2724 + | |
| 2725 +# INTEGER STRICT NOT NULL | |
| 2726 +do_test recover-syntax-5.3 { | |
| 2727 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2728 + execsql { | |
| 2729 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2730 + backing, | |
| 2731 + i INTEGER STRICT NOT NULL | |
| 2732 + ); | |
| 2733 + PRAGMA table_info(syntax); | |
| 2734 + } | |
| 2735 +} {0 i INTEGER 1 {} 0} | |
| 2736 + | |
| 2737 +# BLOB | |
| 2738 +do_test recover-syntax-6.0 { | |
| 2739 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2740 + execsql { | |
| 2741 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2742 + backing, | |
| 2743 + b BLOB | |
| 2744 + ); | |
| 2745 + PRAGMA table_info(syntax); | |
| 2746 + } | |
| 2747 +} {0 b BLOB 0 {} 0} | |
| 2748 + | |
| 2749 +# BLOB NOT NULL | |
| 2750 +do_test recover-syntax-6.1 { | |
| 2751 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2752 + execsql { | |
| 2753 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2754 + backing, | |
| 2755 + b BLOB NOT NULL | |
| 2756 + ); | |
| 2757 + PRAGMA table_info(syntax); | |
| 2758 + } | |
| 2759 +} {0 b BLOB 1 {} 0} | |
| 2760 + | |
| 2761 +# BLOB STRICT | |
| 2762 +do_test recover-syntax-6.2 { | |
| 2763 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2764 + execsql { | |
| 2765 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2766 + backing, | |
| 2767 + b BLOB STRICT | |
| 2768 + ); | |
| 2769 + PRAGMA table_info(syntax); | |
| 2770 + } | |
| 2771 +} {0 b BLOB 0 {} 0} | |
| 2772 + | |
| 2773 +# BLOB STRICT NOT NULL | |
| 2774 +do_test recover-syntax-6.3 { | |
| 2775 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2776 + execsql { | |
| 2777 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2778 + backing, | |
| 2779 + b BLOB STRICT NOT NULL | |
| 2780 + ); | |
| 2781 + PRAGMA table_info(syntax); | |
| 2782 + } | |
| 2783 +} {0 b BLOB 1 {} 0} | |
| 2784 + | |
| 2785 +# FLOAT | |
| 2786 +do_test recover-syntax-7.0 { | |
| 2787 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2788 + execsql { | |
| 2789 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2790 + backing, | |
| 2791 + f FLOAT | |
| 2792 + ); | |
| 2793 + PRAGMA table_info(syntax); | |
| 2794 + } | |
| 2795 +} {0 f FLOAT 0 {} 0} | |
| 2796 + | |
| 2797 +# FLOAT NOT NULL | |
| 2798 +do_test recover-syntax-7.1 { | |
| 2799 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2800 + execsql { | |
| 2801 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2802 + backing, | |
| 2803 + f FLOAT NOT NULL | |
| 2804 + ); | |
| 2805 + PRAGMA table_info(syntax); | |
| 2806 + } | |
| 2807 +} {0 f FLOAT 1 {} 0} | |
| 2808 + | |
| 2809 +# FLOAT STRICT | |
| 2810 +do_test recover-syntax-7.2 { | |
| 2811 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2812 + execsql { | |
| 2813 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2814 + backing, | |
| 2815 + f FLOAT STRICT | |
| 2816 + ); | |
| 2817 + PRAGMA table_info(syntax); | |
| 2818 + } | |
| 2819 +} {0 f FLOAT 0 {} 0} | |
| 2820 + | |
| 2821 +# FLOAT STRICT NOT NULL | |
| 2822 +do_test recover-syntax-7.3 { | |
| 2823 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2824 + execsql { | |
| 2825 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2826 + backing, | |
| 2827 + f FLOAT STRICT NOT NULL | |
| 2828 + ); | |
| 2829 + PRAGMA table_info(syntax); | |
| 2830 + } | |
| 2831 +} {0 f FLOAT 1 {} 0} | |
| 2832 + | |
| 2833 +# NUMERIC | |
| 2834 +do_test recover-syntax-8.0 { | |
| 2835 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2836 + execsql { | |
| 2837 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2838 + backing, | |
| 2839 + f NUMERIC | |
| 2840 + ); | |
| 2841 + PRAGMA table_info(syntax); | |
| 2842 + } | |
| 2843 +} {0 f NUMERIC 0 {} 0} | |
| 2844 + | |
| 2845 +# NUMERIC NOT NULL | |
| 2846 +do_test recover-syntax-8.1 { | |
| 2847 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2848 + execsql { | |
| 2849 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2850 + backing, | |
| 2851 + f NUMERIC NOT NULL | |
| 2852 + ); | |
| 2853 + PRAGMA table_info(syntax); | |
| 2854 + } | |
| 2855 +} {0 f NUMERIC 1 {} 0} | |
| 2856 + | |
| 2857 +# NUMERIC STRICT | |
| 2858 +do_test recover-syntax-8.2 { | |
| 2859 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2860 + execsql { | |
| 2861 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2862 + backing, | |
| 2863 + f NUMERIC STRICT | |
| 2864 + ); | |
| 2865 + PRAGMA table_info(syntax); | |
| 2866 + } | |
| 2867 +} {0 f NUMERIC 0 {} 0} | |
| 2868 + | |
| 2869 +# NUMERIC STRICT NOT NULL | |
| 2870 +do_test recover-syntax-8.3 { | |
| 2871 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2872 + execsql { | |
| 2873 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2874 + backing, | |
| 2875 + f NUMERIC STRICT NOT NULL | |
| 2876 + ); | |
| 2877 + PRAGMA table_info(syntax); | |
| 2878 + } | |
| 2879 +} {0 f NUMERIC 1 {} 0} | |
| 2880 + | |
| 2881 +# ROWID | |
| 2882 +do_test recover-syntax-9.0 { | |
| 2883 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2884 + execsql { | |
| 2885 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2886 + backing2, | |
| 2887 + id ROWID, | |
| 2888 + v | |
| 2889 + ); | |
| 2890 + PRAGMA table_info(syntax); | |
| 2891 + } | |
| 2892 +} {0 id INTEGER 1 {} 0 1 v {} 0 {} 0} | |
| 2893 + | |
| 2894 +# ROWID NOT NULL (is default) | |
| 2895 +do_test recover-syntax-9.1 { | |
| 2896 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2897 + execsql { | |
| 2898 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2899 + backing2, | |
| 2900 + id ROWID NOT NULL, | |
| 2901 + v | |
| 2902 + ); | |
| 2903 + PRAGMA table_info(syntax); | |
| 2904 + } | |
| 2905 +} {0 id INTEGER 1 {} 0 1 v {} 0 {} 0} | |
| 2906 + | |
| 2907 +# ROWID STRICT | |
| 2908 +do_test recover-syntax-9.0 { | |
| 2909 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2910 + execsql { | |
| 2911 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2912 + backing2, | |
| 2913 + id ROWID STRICT, | |
| 2914 + v | |
| 2915 + ); | |
| 2916 + PRAGMA table_info(syntax); | |
| 2917 + } | |
| 2918 +} {0 id INTEGER 1 {} 0 1 v {} 0 {} 0} | |
| 2919 + | |
| 2920 +# ROWID STRICT NOT NULL (is default) | |
| 2921 +do_test recover-syntax-9.1 { | |
| 2922 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2923 + execsql { | |
| 2924 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2925 + backing2, | |
| 2926 + id ROWID STRICT NOT NULL, | |
| 2927 + v | |
| 2928 + ); | |
| 2929 + PRAGMA table_info(syntax); | |
| 2930 + } | |
| 2931 +} {0 id INTEGER 1 {} 0 1 v {} 0 {} 0} | |
| 2932 + | |
| 2933 +# Invalid type info is not ignored. | |
| 2934 +do_test recover-syntax-10.0 { | |
| 2935 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2936 + catchsql { | |
| 2937 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2938 + backing, | |
| 2939 + v GARBAGE | |
| 2940 + ); | |
| 2941 + } | |
| 2942 +} {1 {unable to parse column 0}} | |
| 2943 + | |
| 2944 +# Extraneous type info is not ignored. | |
| 2945 +do_test recover-syntax-10.1 { | |
| 2946 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2947 + catchsql { | |
| 2948 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2949 + backing, | |
| 2950 + v INTEGER GARBAGE | |
| 2951 + ); | |
| 2952 + } | |
| 2953 +} {1 {unable to parse column 0}} | |
| 2954 + | |
| 2955 +# Extraneous type info is not ignored. | |
| 2956 +do_test recover-syntax-10.2 { | |
| 2957 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2958 + catchsql { | |
| 2959 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2960 + backing, | |
| 2961 + v INTEGER NOT NULL GARBAGE | |
| 2962 + ); | |
| 2963 + } | |
| 2964 +} {1 {unable to parse column 0}} | |
| 2965 + | |
| 2966 +# Multiple types don't work. | |
| 2967 +do_test recover-syntax-10.3 { | |
| 2968 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2969 + catchsql { | |
| 2970 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2971 + backing, | |
| 2972 + v INTEGER FLOAT BLOB | |
| 2973 + ); | |
| 2974 + } | |
| 2975 +} {1 {unable to parse column 0}} | |
| 2976 + | |
| 2977 +# Multiple types don't work. | |
| 2978 +do_test recover-syntax-10.4 { | |
| 2979 + db eval {DROP TABLE IF EXISTS temp.syntax} | |
| 2980 + catchsql { | |
| 2981 + CREATE VIRTUAL TABLE temp.syntax USING recover( | |
| 2982 + backing, | |
| 2983 + v INTEGER NOT NULL TEXT | |
| 2984 + ); | |
| 2985 + } | |
| 2986 +} {1 {unable to parse column 0}} | |
| 2987 + | |
| 2988 +finish_test | |
| 2989 diff --git a/third_party/sqlite/src/test/recover1.test b/third_party/sqlite/src/ test/recover1.test | |
| 2990 new file mode 100644 | |
| 2991 index 0000000..1d90f09 | |
| 2992 --- /dev/null | |
| 2993 +++ b/third_party/sqlite/src/test/recover1.test | |
| 2994 @@ -0,0 +1,429 @@ | |
| 2995 +# 2012 January 4 {} | |
| 2996 +# | |
| 2997 +# The author disclaims copyright to this source code. In place of | |
| 2998 +# a legal notice, here is a blessing: | |
| 2999 +# | |
| 3000 +# May you do good and not evil. | |
| 3001 +# May you find forgiveness for yourself and forgive others. | |
| 3002 +# May you share freely, never taking more than you give. | |
| 3003 +# | |
| 3004 +#*********************************************************************** | |
| 3005 +# This file implements regression tests for SQLite library. | |
| 3006 +# | |
| 3007 +# Use tables to test leaf-node reading, and also type checking. | |
| 3008 +# | |
| 3009 +# $Id$ | |
| 3010 + | |
| 3011 +set testdir [file dirname $argv0] | |
| 3012 +source $testdir/tester.tcl | |
| 3013 + | |
| 3014 +# A really basic table with manifest typing and a row of each type. | |
| 3015 +db close | |
| 3016 +sqlite3 db test.db | |
| 3017 +db eval { | |
| 3018 + DROP TABLE IF EXISTS types; | |
| 3019 + CREATE TABLE types (rowtype TEXT, value); | |
| 3020 + INSERT INTO types VALUES ("NULL", NULL); | |
| 3021 + INSERT INTO types VALUES ("INTEGER", 17); | |
| 3022 + INSERT INTO types VALUES ("FLOAT", 3.1415927); | |
| 3023 + INSERT INTO types VALUES ("TEXT", "This is text"); | |
| 3024 + INSERT INTO types VALUES ("BLOB", CAST("This is a blob" AS BLOB)); | |
| 3025 + | |
| 3026 + -- Same contents, with an alias for rowid. Testing separately | |
| 3027 + -- because it changes the structure of the data (the alias column is | |
| 3028 + -- serialized as NULL). | |
| 3029 + DROP TABLE IF EXISTS types2; | |
| 3030 + CREATE TABLE types2 (id INTEGER PRIMARY KEY, rowtype TEXT, value); | |
| 3031 + INSERT INTO types2 (id, rowtype, value) | |
| 3032 + SELECT rowid, rowtype, value FROM types; | |
| 3033 +} | |
| 3034 + | |
| 3035 +# Baseline results. | |
| 3036 +do_test recover-types-0.0 { | |
| 3037 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types} | |
| 3038 +} {1 NULL {} null 2 INTEGER 17 integer 3 FLOAT 3.1415927 real 4 TEXT {This is t ext} text 5 BLOB {This is a blob} blob} | |
| 3039 + | |
| 3040 +# With no restrictions, recover table shows identical results. | |
| 3041 +do_test recover-types-0.1 { | |
| 3042 + db eval { | |
| 3043 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3044 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3045 + types, | |
| 3046 + rowtype TEXT, | |
| 3047 + value | |
| 3048 + ); | |
| 3049 + } | |
| 3050 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3051 +} {1 NULL {} null 2 INTEGER 17 integer 3 FLOAT 3.1415927 real 4 TEXT {This is t ext} text 5 BLOB {This is a blob} blob} | |
| 3052 + | |
| 3053 +# Restrict by INTEGER | |
| 3054 +do_test recover-types-1.0 { | |
| 3055 + db eval { | |
| 3056 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3057 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3058 + types, | |
| 3059 + rowtype TEXT, | |
| 3060 + value INTEGER | |
| 3061 + ); | |
| 3062 + } | |
| 3063 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3064 +} {1 NULL {} null 2 INTEGER 17 integer} | |
| 3065 + | |
| 3066 +# Restrict by INTEGER NOT NULL | |
| 3067 +do_test recover-types-1.1 { | |
| 3068 + db eval { | |
| 3069 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3070 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3071 + types, | |
| 3072 + rowtype TEXT, | |
| 3073 + value INTEGER NOT NULL | |
| 3074 + ); | |
| 3075 + } | |
| 3076 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3077 +} {2 INTEGER 17 integer} | |
| 3078 + | |
| 3079 +# Restrict by FLOAT | |
| 3080 +do_test recover-types-2.0 { | |
| 3081 + db eval { | |
| 3082 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3083 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3084 + types, | |
| 3085 + rowtype TEXT, | |
| 3086 + value FLOAT | |
| 3087 + ); | |
| 3088 + } | |
| 3089 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3090 +} {1 NULL {} null 2 INTEGER 17.0 real 3 FLOAT 3.1415927 real} | |
| 3091 + | |
| 3092 +# Restrict by FLOAT NOT NULL | |
| 3093 +do_test recover-types-2.1 { | |
| 3094 + db eval { | |
| 3095 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3096 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3097 + types, | |
| 3098 + rowtype TEXT, | |
| 3099 + value FLOAT NOT NULL | |
| 3100 + ); | |
| 3101 + } | |
| 3102 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3103 +} {2 INTEGER 17.0 real 3 FLOAT 3.1415927 real} | |
| 3104 + | |
| 3105 +# Restrict by FLOAT STRICT | |
| 3106 +do_test recover-types-2.2 { | |
| 3107 + db eval { | |
| 3108 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3109 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3110 + types, | |
| 3111 + rowtype TEXT, | |
| 3112 + value FLOAT STRICT | |
| 3113 + ); | |
| 3114 + } | |
| 3115 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3116 +} {1 NULL {} null 3 FLOAT 3.1415927 real} | |
| 3117 + | |
| 3118 +# Restrict by FLOAT STRICT NOT NULL | |
| 3119 +do_test recover-types-2.3 { | |
| 3120 + db eval { | |
| 3121 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3122 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3123 + types, | |
| 3124 + rowtype TEXT, | |
| 3125 + value FLOAT STRICT NOT NULL | |
| 3126 + ); | |
| 3127 + } | |
| 3128 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3129 +} {3 FLOAT 3.1415927 real} | |
| 3130 + | |
| 3131 +# Restrict by TEXT | |
| 3132 +do_test recover-types-3.0 { | |
| 3133 + db eval { | |
| 3134 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3135 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3136 + types, | |
| 3137 + rowtype TEXT, | |
| 3138 + value TEXT | |
| 3139 + ); | |
| 3140 + } | |
| 3141 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3142 +} {1 NULL {} null 4 TEXT {This is text} text 5 BLOB {This is a blob} blob} | |
| 3143 + | |
| 3144 +# Restrict by TEXT NOT NULL | |
| 3145 +do_test recover-types-3.1 { | |
| 3146 + db eval { | |
| 3147 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3148 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3149 + types, | |
| 3150 + rowtype TEXT, | |
| 3151 + value TEXT NOT NULL | |
| 3152 + ); | |
| 3153 + } | |
| 3154 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3155 +} {4 TEXT {This is text} text 5 BLOB {This is a blob} blob} | |
| 3156 + | |
| 3157 +# Restrict by TEXT STRICT | |
| 3158 +do_test recover-types-3.2 { | |
| 3159 + db eval { | |
| 3160 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3161 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3162 + types, | |
| 3163 + rowtype TEXT, | |
| 3164 + value TEXT STRICT | |
| 3165 + ); | |
| 3166 + } | |
| 3167 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3168 +} {1 NULL {} null 4 TEXT {This is text} text} | |
| 3169 + | |
| 3170 +# Restrict by TEXT STRICT NOT NULL | |
| 3171 +do_test recover-types-3.3 { | |
| 3172 + db eval { | |
| 3173 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3174 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3175 + types, | |
| 3176 + rowtype TEXT, | |
| 3177 + value TEXT STRICT NOT NULL | |
| 3178 + ); | |
| 3179 + } | |
| 3180 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3181 +} {4 TEXT {This is text} text} | |
| 3182 + | |
| 3183 +# Restrict by BLOB | |
| 3184 +do_test recover-types-4.0 { | |
| 3185 + db eval { | |
| 3186 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3187 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3188 + types, | |
| 3189 + rowtype TEXT, | |
| 3190 + value BLOB | |
| 3191 + ); | |
| 3192 + } | |
| 3193 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3194 +} {1 NULL {} null 5 BLOB {This is a blob} blob} | |
| 3195 + | |
| 3196 +# Restrict by BLOB NOT NULL | |
| 3197 +do_test recover-types-4.1 { | |
| 3198 + db eval { | |
| 3199 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3200 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3201 + types, | |
| 3202 + rowtype TEXT, | |
| 3203 + value BLOB NOT NULL | |
| 3204 + ); | |
| 3205 + } | |
| 3206 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3207 +} {5 BLOB {This is a blob} blob} | |
| 3208 + | |
| 3209 +# Manifest typing. | |
| 3210 +do_test recover-types-5.0 { | |
| 3211 + db eval { | |
| 3212 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3213 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3214 + types, | |
| 3215 + rowtype TEXT, | |
| 3216 + value | |
| 3217 + ); | |
| 3218 + } | |
| 3219 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3220 +} {1 NULL {} null 2 INTEGER 17 integer 3 FLOAT 3.1415927 real 4 TEXT {This is t ext} text 5 BLOB {This is a blob} blob} | |
| 3221 + | |
| 3222 +# Should get same results specifying manifest typing explicitly. | |
| 3223 +do_test recover-types-5.1 { | |
| 3224 + db eval { | |
| 3225 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3226 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3227 + types, | |
| 3228 + rowtype TEXT, | |
| 3229 + value ANY | |
| 3230 + ); | |
| 3231 + } | |
| 3232 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3233 +} {1 NULL {} null 2 INTEGER 17 integer 3 FLOAT 3.1415927 real 4 TEXT {This is t ext} text 5 BLOB {This is a blob} blob} | |
| 3234 + | |
| 3235 +# Same results, skipping the NULL row. | |
| 3236 +do_test recover-types-5.2 { | |
| 3237 + db eval { | |
| 3238 + DROP TABLE IF EXISTS temp.types_recover; | |
| 3239 + CREATE VIRTUAL TABLE temp.types_recover USING recover( | |
| 3240 + types, | |
| 3241 + rowtype TEXT, | |
| 3242 + value ANY NOT NULL | |
| 3243 + ); | |
| 3244 + } | |
| 3245 + execsql {SELECT rowid, rowtype, value, TYPEOF(value) FROM types_recover} | |
| 3246 +} {2 INTEGER 17 integer 3 FLOAT 3.1415927 real 4 TEXT {This is text} text 5 BLO B {This is a blob} blob} | |
| 3247 + | |
| 3248 +# Test ROWID values. | |
| 3249 +do_test recover-types-6.0 { | |
| 3250 + db eval { | |
| 3251 + DROP TABLE IF EXISTS temp.types2_recover; | |
| 3252 + CREATE VIRTUAL TABLE temp.types2_recover USING recover( | |
| 3253 + types2, | |
| 3254 + id ROWID, | |
| 3255 + rowtype TEXT, | |
| 3256 + value | |
| 3257 + ); | |
| 3258 + } | |
| 3259 + execsql {SELECT rowid, id, rowtype, value, TYPEOF(value) FROM types2_recover} | |
| 3260 +} {1 1 NULL {} null 2 2 INTEGER 17 integer 3 3 FLOAT 3.1415927 real 4 4 TEXT {T his is text} text 5 5 BLOB {This is a blob} blob} | |
| 3261 + | |
| 3262 +# ROWID NOT NULL is identical. | |
| 3263 +do_test recover-types-6.1 { | |
| 3264 + db eval { | |
| 3265 + DROP TABLE IF EXISTS temp.types2_recover; | |
| 3266 + CREATE VIRTUAL TABLE temp.types2_recover USING recover( | |
| 3267 + types2, | |
| 3268 + id ROWID NOT NULL, | |
| 3269 + rowtype TEXT, | |
| 3270 + value | |
| 3271 + ); | |
| 3272 + } | |
| 3273 + execsql {SELECT rowid, id, rowtype, value, TYPEOF(value) FROM types2_recover} | |
| 3274 +} {1 1 NULL {} null 2 2 INTEGER 17 integer 3 3 FLOAT 3.1415927 real 4 4 TEXT {T his is text} text 5 5 BLOB {This is a blob} blob} | |
| 3275 + | |
| 3276 +# Check that each of the possible integer sizes is being decoded. | |
| 3277 +# TODO(shess): It would be neat to ACTUALLY test these things. As-is, | |
| 3278 +# this should exercise the code paths, but one needs logging or a | |
| 3279 +# debugger to verify that things are stored as expected. | |
| 3280 +do_test recover-types-7.0 { | |
| 3281 + db eval { | |
| 3282 + DROP TABLE IF EXISTS integers; | |
| 3283 + CREATE TABLE integers (value); | |
| 3284 + | |
| 3285 + -- encoded directly in type info. | |
| 3286 + INSERT INTO integers VALUES (0); | |
| 3287 + INSERT INTO integers VALUES (1); | |
| 3288 + | |
| 3289 + -- 8-bit signed. | |
| 3290 + INSERT INTO integers VALUES (2); | |
| 3291 + INSERT INTO integers VALUES (-2); | |
| 3292 + INSERT INTO integers VALUES (127); | |
| 3293 + INSERT INTO integers VALUES (-128); | |
| 3294 + | |
| 3295 + -- 16-bit signed. | |
| 3296 + INSERT INTO integers VALUES (12345); | |
| 3297 + INSERT INTO integers VALUES (-12345); | |
| 3298 + INSERT INTO integers VALUES (32767); | |
| 3299 + INSERT INTO integers VALUES (-32768); | |
| 3300 + | |
| 3301 + -- 24-bit signed. | |
| 3302 + INSERT INTO integers VALUES (1234567); | |
| 3303 + INSERT INTO integers VALUES (-1234567); | |
| 3304 + INSERT INTO integers VALUES (8388607); | |
| 3305 + INSERT INTO integers VALUES (-8388608); | |
| 3306 + | |
| 3307 + -- 32-bit signed. | |
| 3308 + INSERT INTO integers VALUES (1234567890); | |
| 3309 + INSERT INTO integers VALUES (-1234567890); | |
| 3310 + INSERT INTO integers VALUES (2147483647); | |
| 3311 + INSERT INTO integers VALUES (-2147483648); | |
| 3312 + | |
| 3313 + -- 48-bit signed. | |
| 3314 + INSERT INTO integers VALUES (123456789012345); | |
| 3315 + INSERT INTO integers VALUES (-123456789012345); | |
| 3316 + INSERT INTO integers VALUES (140737488355327); | |
| 3317 + INSERT INTO integers VALUES (-140737488355328); | |
| 3318 + | |
| 3319 + -- 64-bit signed. | |
| 3320 + INSERT INTO integers VALUES (9223372036854775807); | |
| 3321 + INSERT INTO integers VALUES (-9223372036854775808); | |
| 3322 + | |
| 3323 + DROP TABLE IF EXISTS integers_recover; | |
| 3324 + CREATE VIRTUAL TABLE temp.integers_recover USING recover( | |
| 3325 + integers, | |
| 3326 + value INTEGER | |
| 3327 + ); | |
| 3328 + } | |
| 3329 + execsql {SELECT rowid, value FROM integers_recover} | |
| 3330 +} {1 0 2 1 3 2 4 -2 5 127 6 -128 7 12345 8 -12345 9 32767 10 -32768 11 1234567 12 -1234567 13 8388607 14 -8388608 15 1234567890 16 -1234567890 17 2147483647 18 -2147483648 19 123456789012345 20 -123456789012345 21 140737488355327 22 -14073 7488355328 23 9223372036854775807 24 -9223372036854775808} | |
| 3331 + | |
| 3332 +# If UTF16 support is disabled, ignore the rest of the tests. | |
| 3333 +# | |
| 3334 +ifcapable {!utf16} { | |
| 3335 + finish_test | |
| 3336 + return | |
| 3337 +} | |
| 3338 + | |
| 3339 +# Baseline UTF-8. | |
| 3340 +file delete -force test.db | |
| 3341 +sqlite3 db test.db; | |
| 3342 +db eval { | |
| 3343 + PRAGMA encoding = 'UTF-8'; | |
| 3344 +} | |
| 3345 + | |
| 3346 +do_test recover-encoding-1.0 { | |
| 3347 + execsql { | |
| 3348 + DROP TABLE IF EXISTS e; | |
| 3349 + CREATE TABLE e (v TEXT); | |
| 3350 + INSERT INTO e VALUES('Mjollnir'); | |
| 3351 + INSERT INTO e VALUES('Mjölnir'); | |
| 3352 + INSERT INTO e VALUES('Mjǫlnir'); | |
| 3353 + INSERT INTO e VALUES('Mjölner'); | |
| 3354 + INSERT INTO e VALUES('Mjølner'); | |
| 3355 + INSERT INTO e VALUES('ハンマー'); | |
| 3356 + PRAGMA encoding; | |
| 3357 + | |
| 3358 + DROP TABLE IF EXISTS e_recover; | |
| 3359 + CREATE VIRTUAL TABLE temp.e_recover USING recover( | |
| 3360 + e, | |
| 3361 + v TEXT | |
| 3362 + ); | |
| 3363 + SELECT rowid, v FROM e_recover ORDER BY rowid; | |
| 3364 + } | |
| 3365 +} {UTF-8 1 Mjollnir 2 Mjölnir 3 Mjǫlnir 4 Mjölner 5 Mjølner 6 ハンマー} | |
| 3366 + | |
| 3367 +# Reset the database to UTF-16LE. | |
| 3368 +file delete -force test.db | |
| 3369 +sqlite3 db test.db; | |
| 3370 +db eval { | |
| 3371 + PRAGMA encoding = 'UTF-16LE'; | |
| 3372 +} | |
| 3373 + | |
| 3374 +do_test recover-encoding-2.0 { | |
| 3375 + execsql { | |
| 3376 + DROP TABLE IF EXISTS e; | |
| 3377 + CREATE TABLE e (v TEXT); | |
| 3378 + INSERT INTO e VALUES('Mjollnir'); | |
| 3379 + INSERT INTO e VALUES('Mjölnir'); | |
| 3380 + INSERT INTO e VALUES('Mjǫlnir'); | |
| 3381 + INSERT INTO e VALUES('Mjölner'); | |
| 3382 + INSERT INTO e VALUES('Mjølner'); | |
| 3383 + INSERT INTO e VALUES('ハンマー'); | |
| 3384 + PRAGMA encoding; | |
| 3385 + | |
| 3386 + DROP TABLE IF EXISTS e_recover; | |
| 3387 + CREATE VIRTUAL TABLE temp.e_recover USING recover( | |
| 3388 + e, | |
| 3389 + v TEXT | |
| 3390 + ); | |
| 3391 + SELECT rowid, v FROM e_recover ORDER BY rowid; | |
| 3392 + } | |
| 3393 +} {UTF-16le 1 Mjollnir 2 Mjölnir 3 Mjǫlnir 4 Mjölner 5 Mjølner 6 ハンマー} | |
| 3394 + | |
| 3395 +# Reset the database to UTF-16BE. | |
| 3396 +file delete -force test.db | |
| 3397 +sqlite3 db test.db; | |
| 3398 +db eval { | |
| 3399 + PRAGMA encoding = 'UTF-16BE'; | |
| 3400 +} | |
| 3401 + | |
| 3402 +do_test recover-encoding-3.0 { | |
| 3403 + execsql { | |
| 3404 + DROP TABLE IF EXISTS e; | |
| 3405 + CREATE TABLE e (v TEXT); | |
| 3406 + INSERT INTO e VALUES('Mjollnir'); | |
| 3407 + INSERT INTO e VALUES('Mjölnir'); | |
| 3408 + INSERT INTO e VALUES('Mjǫlnir'); | |
| 3409 + INSERT INTO e VALUES('Mjölner'); | |
| 3410 + INSERT INTO e VALUES('Mjølner'); | |
| 3411 + INSERT INTO e VALUES('ハンマー'); | |
| 3412 + PRAGMA encoding; | |
| 3413 + | |
| 3414 + DROP TABLE IF EXISTS e_recover; | |
| 3415 + CREATE VIRTUAL TABLE temp.e_recover USING recover( | |
| 3416 + e, | |
| 3417 + v TEXT | |
| 3418 + ); | |
| 3419 + SELECT rowid, v FROM e_recover ORDER BY rowid; | |
| 3420 + } | |
| 3421 +} {UTF-16be 1 Mjollnir 2 Mjölnir 3 Mjǫlnir 4 Mjölner 5 Mjølner 6 ハンマー} | |
| 3422 + | |
| 3423 +finish_test | |
| 3424 diff --git a/third_party/sqlite/src/test/recover2.test b/third_party/sqlite/src/ test/recover2.test | |
| 3425 new file mode 100644 | |
| 3426 index 0000000..8aa4e04 | |
| 3427 --- /dev/null | |
| 3428 +++ b/third_party/sqlite/src/test/recover2.test | |
| 3429 @@ -0,0 +1,157 @@ | |
| 3430 +# 2012 January 4 {} | |
| 3431 +# | |
| 3432 +# The author disclaims copyright to this source code. In place of | |
| 3433 +# a legal notice, here is a blessing: | |
| 3434 +# | |
| 3435 +# May you do good and not evil. | |
| 3436 +# May you find forgiveness for yourself and forgive others. | |
| 3437 +# May you share freely, never taking more than you give. | |
| 3438 +# | |
| 3439 +#*********************************************************************** | |
| 3440 +# This file implements regression tests for SQLite library. | |
| 3441 +# | |
| 3442 +# This file implements tests for how the recover module handles cell | |
| 3443 +# overflow. | |
| 3444 +# | |
| 3445 +# $Id$ | |
| 3446 + | |
| 3447 +set testdir [file dirname $argv0] | |
| 3448 +source $testdir/tester.tcl | |
| 3449 + | |
| 3450 +set lorem "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sagitti s gravida odio vitae ultrices. Nulla facilisi. Maecenas pulvinar, tellus ut bibe ndum semper, nibh tellus auctor nulla, in dignissim nisi ipsum id arcu. Nullam t incidunt arcu malesuada turpis faucibus in adipiscing enim mattis. Fusce augue m agna, scelerisque sollicitudin egestas in, cursus eu sapien. Pellentesque tempor risus at lectus convallis a convallis orci ornare. Integer tristique aliquam le o vel interdum. | |
| 3451 + | |
| 3452 +Phasellus quis dictum nisi. Curabitur at enim non felis pharetra imperdiet. Dui s tempus massa eu leo varius porta. Vestibulum sodales nulla at purus tincidunt ultrices. Nam euismod posuere nibh, nec sodales magna luctus ac. Ut commodo hend rerit mauris vitae gravida. In interdum justo ut sem eleifend convallis. Donec c ursus molestie elementum. Suspendisse at nisl tellus, vel consequat mauris. Null am non justo nibh. | |
| 3453 + | |
| 3454 +Maecenas varius sollicitudin libero, nec feugiat turpis facilisis eget. Quisque et sem risus. Aenean a magna quis purus hendrerit mattis eu vel lorem. Aenean f ringilla diam eget tortor lacinia sed mollis eros feugiat. Quisque ac purus sapi en. Nullam quis tellus vel magna convallis tincidunt. Donec eget ligula at liber o tincidunt congue ut ut lacus. Integer dignissim aliquet congue. Pellentesque s ed risus vitae lorem porta viverra ac eu risus. Vivamus congue suscipit odio pul vinar aliquet. Aliquam porttitor nunc non sapien auctor et vehicula augue molest ie. | |
| 3455 + | |
| 3456 +Aliquam et dui ac sem tempus dictum. Fusce arcu nulla, viverra sit amet suscipi t quis, malesuada at felis. Fusce ut diam felis. Fusce id ligula non eros fermen tum sodales in nec quam. Donec tempor bibendum arcu ac adipiscing. Praesent nisl lectus, tempor ut vehicula eget, mattis a justo. Mauris condimentum luctus eros a varius. Morbi mollis elit eget velit convallis eu sodales odio egestas. Cum s ociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus interdum, metus sit amet varius varius, lectus eros semper risus, sed s agittis ipsum libero in sapien. Nam lacinia nulla vitae magna facilisis sceleris que. Lorem ipsum dolor sit amet, consectetur adipiscing elit. | |
| 3457 + | |
| 3458 +Donec gravida dignissim eleifend. Aliquam vel tincidunt tortor. Curabitur massa ante, blandit a auctor at, ullamcorper sed nisl. Class aptent taciti sociosqu a d litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse ut fel is a eros egestas ultricies et quis mi. Vivamus ut risus massa. Donec nec ornare erat. Aliquam ornare, lorem a rhoncus aliquam, tellus diam tincidunt tellus, a mattis nunc ante ac arcu. Curabitur nec metus id risus commodo ullamcorper eu ut tortor." | |
| 3459 + | |
| 3460 +# Create a database which needs a multiple overflow pages to test the | |
| 3461 +# transition from main page to overflow, and then overflow to | |
| 3462 +# overflow. | |
| 3463 +do_test recover-overflow-1.0 { | |
| 3464 + db eval { | |
| 3465 + DROP TABLE IF EXISTS overflow; | |
| 3466 + CREATE TABLE overflow (value TEXT); | |
| 3467 + INSERT INTO overflow VALUES ($lorem); | |
| 3468 + | |
| 3469 + DROP TABLE IF EXISTS overflow_recover; | |
| 3470 + CREATE VIRTUAL TABLE temp.overflow_recover USING recover( | |
| 3471 + overflow, | |
| 3472 + value TEXT | |
| 3473 + ); | |
| 3474 + } | |
| 3475 + | |
| 3476 + # Should have root page, leaf page, and 2 overflow pages, because | |
| 3477 + # length(value) is more than 2x page_size. | |
| 3478 + execsql { | |
| 3479 + PRAGMA page_count; | |
| 3480 + PRAGMA page_size; | |
| 3481 + SELECT rowid, TYPEOF(value), length(value), value FROM overflow_recover; | |
| 3482 + } | |
| 3483 +} [list 4 1024 1 text [string length $lorem] $lorem] | |
| 3484 + | |
| 3485 +# No overflow. [1024-35 == 990, overhead of 1-byte rowid, 2-byte | |
| 3486 +# record length, 1-byte header length, 2-byte field type.] | |
| 3487 +set substr [string range $lorem 0 985] | |
| 3488 +do_test recover-overflow-1.1 { | |
| 3489 + db eval { | |
| 3490 + DROP TABLE IF EXISTS overflow; | |
| 3491 + CREATE TABLE overflow (value TEXT); | |
| 3492 + INSERT INTO overflow VALUES ($substr); | |
| 3493 + | |
| 3494 + DROP TABLE IF EXISTS overflow_recover; | |
| 3495 + CREATE VIRTUAL TABLE temp.overflow_recover USING recover( | |
| 3496 + overflow, | |
| 3497 + value TEXT | |
| 3498 + ); | |
| 3499 + } | |
| 3500 + | |
| 3501 + # Trim to remove excess pages from prior tests. | |
| 3502 + db eval {VACUUM} | |
| 3503 + | |
| 3504 + execsql { | |
| 3505 + PRAGMA page_count; | |
| 3506 + PRAGMA page_size; | |
| 3507 + SELECT rowid, TYPEOF(value), length(value), value FROM overflow_recover; | |
| 3508 + } | |
| 3509 +} [list 2 1024 1 text [string length $substr] $substr] | |
| 3510 + | |
| 3511 +# One byte of overflow. | |
| 3512 +set substr [string range $lorem 0 986] | |
| 3513 +do_test recover-overflow-1.2 { | |
| 3514 + db eval { | |
| 3515 + DROP TABLE IF EXISTS overflow; | |
| 3516 + CREATE TABLE overflow (value TEXT); | |
| 3517 + INSERT INTO overflow VALUES ($substr); | |
| 3518 + | |
| 3519 + DROP TABLE IF EXISTS overflow_recover; | |
| 3520 + CREATE VIRTUAL TABLE temp.overflow_recover USING recover( | |
| 3521 + overflow, | |
| 3522 + value TEXT | |
| 3523 + ); | |
| 3524 + } | |
| 3525 + | |
| 3526 + # Trim to remove excess pages from prior tests. | |
| 3527 + db eval {VACUUM} | |
| 3528 + | |
| 3529 + execsql { | |
| 3530 + PRAGMA page_count; | |
| 3531 + PRAGMA page_size; | |
| 3532 + SELECT rowid, TYPEOF(value), length(value), value FROM overflow_recover; | |
| 3533 + } | |
| 3534 +} [list 3 1024 1 text [string length $substr] $substr] | |
| 3535 + | |
| 3536 +# One full overflow page, plus maxLocal in-leaf. [985+1020] | |
| 3537 +set substr [string range $lorem 0 2005] | |
| 3538 +do_test recover-overflow-1.3 { | |
| 3539 + db eval { | |
| 3540 + DROP TABLE IF EXISTS overflow; | |
| 3541 + CREATE TABLE overflow (value TEXT); | |
| 3542 + INSERT INTO overflow VALUES ($substr); | |
| 3543 + | |
| 3544 + DROP TABLE IF EXISTS overflow_recover; | |
| 3545 + CREATE VIRTUAL TABLE temp.overflow_recover USING recover( | |
| 3546 + overflow, | |
| 3547 + value TEXT | |
| 3548 + ); | |
| 3549 + } | |
| 3550 + | |
| 3551 + # Trim to remove excess pages from prior tests. | |
| 3552 + db eval {VACUUM} | |
| 3553 + | |
| 3554 + execsql { | |
| 3555 + PRAGMA page_count; | |
| 3556 + PRAGMA page_size; | |
| 3557 + SELECT rowid, TYPEOF(value), length(value), value FROM overflow_recover; | |
| 3558 + } | |
| 3559 +} [list 3 1024 1 text [string length $substr] $substr] | |
| 3560 + | |
| 3561 +# Overflow to a second overflow page. | |
| 3562 +set substr [string range $lorem 0 2006] | |
| 3563 +do_test recover-overflow-1.4 { | |
| 3564 + db eval { | |
| 3565 + DROP TABLE IF EXISTS overflow; | |
| 3566 + CREATE TABLE overflow (value TEXT); | |
| 3567 + INSERT INTO overflow VALUES ($substr); | |
| 3568 + | |
| 3569 + DROP TABLE IF EXISTS overflow_recover; | |
| 3570 + CREATE VIRTUAL TABLE temp.overflow_recover USING recover( | |
| 3571 + overflow, | |
| 3572 + value TEXT | |
| 3573 + ); | |
| 3574 + } | |
| 3575 + | |
| 3576 + # Trim to remove excess pages from prior tests. | |
| 3577 + db eval {VACUUM} | |
| 3578 + | |
| 3579 + execsql { | |
| 3580 + PRAGMA page_count; | |
| 3581 + PRAGMA page_size; | |
| 3582 + SELECT rowid, TYPEOF(value), length(value), value FROM overflow_recover; | |
| 3583 + } | |
| 3584 +} [list 4 1024 1 text [string length $substr] $substr] | |
| 3585 + | |
| 3586 +finish_test | |
| 3587 diff --git a/third_party/sqlite/src/tool/mksqlite3c.tcl b/third_party/sqlite/src /tool/mksqlite3c.tcl | |
| 3588 index fa99f2d..df2df07 100644 | |
| 3589 --- a/third_party/sqlite/src/tool/mksqlite3c.tcl | |
| 3590 +++ b/third_party/sqlite/src/tool/mksqlite3c.tcl | |
| 3591 @@ -293,6 +293,8 @@ foreach file { | |
| 3592 main.c | |
| 3593 notify.c | |
| 3594 | |
| 3595 + recover.c | |
| 3596 + | |
| 3597 fts3.c | |
| 3598 fts3_aux.c | |
| 3599 fts3_expr.c | |
| 3600 -- | |
| 3601 2.2.1 | |
| 3602 | |
| OLD | NEW |