Index: third_party/sqlite/src/src/recover.c |
diff --git a/third_party/sqlite/src/src/recover.c b/third_party/sqlite/src/src/recover.c |
index 58dd89e1f2f6f9011b028137acccd5a27e7525b8..f7e108fc6496d59ea34b5596d60e374ff927091f 100644 |
--- a/third_party/sqlite/src/src/recover.c |
+++ b/third_party/sqlite/src/src/recover.c |
@@ -370,8 +370,82 @@ static int ascii_strcasecmp(const char *s1, const char *s2){ |
return ascii_strncasecmp(s1, s2, strlen(s1)+1); |
} |
+/* Provide access to the pages of a SQLite database in a way similar to SQLite's |
+** Pager. Will be re-implemented in terms of sqlite3_file. |
+*/ |
+typedef struct RecoverPager RecoverPager; |
+struct RecoverPager { |
+ Pager *pSqlitePager; /* SQLite's pager. */ |
+}; |
+ |
+static void pagerDestroy(RecoverPager *pPager){ |
+ memset(pPager, 0xA5, sizeof(*pPager)); |
+ sqlite3_free(pPager); |
+} |
+ |
+static int pagerCreate(Pager *pSqlitePager, u32 nPageSize, |
+ RecoverPager **ppPager){ |
+ RecoverPager *pPager = sqlite3_malloc(sizeof(RecoverPager)); |
+ if( !pPager ){ |
+ return SQLITE_NOMEM; |
+ } |
+ |
+ memset(pPager, 0, sizeof(*pPager)); |
+ pPager->pSqlitePager = pSqlitePager; |
+ *ppPager = pPager; |
+ return SQLITE_OK; |
+} |
+ |
+/* Matches DbPage (aka PgHdr) from SQLite internals. */ |
+typedef struct RecoverPage RecoverPage; |
+struct RecoverPage { |
+ DbPage *pSqlitePage; /* SQLite's page. */ |
+ Pgno pgno; /* Page number for this page */ |
+ void *pData; /* Page data */ |
+ RecoverPager *pPager; /* The pager this page is part of */ |
+}; |
+ |
+static void pageDestroy(RecoverPage *pPage){ |
+ sqlite3PagerUnref(pPage->pSqlitePage); |
+ memset(pPage, 0xA5, sizeof(*pPage)); |
+ sqlite3_free(pPage); |
+} |
+ |
+static int pageCreate(RecoverPager *pPager, DbPage *pSqlitePage, |
+ RecoverPage **ppPage){ |
+ RecoverPage *pPage = sqlite3_malloc(sizeof(RecoverPage)); |
+ if( !pPage ){ |
+ return SQLITE_NOMEM; |
+ } |
+ |
+ memset(pPage, 0, sizeof(*pPage)); |
+ pPage->pPager = pPager; |
+ pPage->pSqlitePage = pSqlitePage; |
+ pPage->pgno = pSqlitePage->pgno; |
+ pPage->pData = pSqlitePage->pData; |
+ |
+ *ppPage = pPage; |
+ return SQLITE_OK; |
+} |
+ |
+static int pagerGetPage(RecoverPager *pPager, u32 iPage, RecoverPage **ppPage) { |
+ DbPage *pSqlitePage; |
+ int rc = sqlite3PagerGet(pPager->pSqlitePager, iPage, &pSqlitePage, 0); |
+ if( rc!=SQLITE_OK ){ |
+ return rc; |
+ } |
+ |
+ rc = pageCreate(pPager, pSqlitePage, ppPage); |
+ if( rc!=SQLITE_OK ){ |
+ sqlite3PagerUnref(pSqlitePage); |
+ return rc; |
+ } |
+ |
+ return SQLITE_OK; |
+} |
+ |
/* For some reason I kept making mistakes with offset calculations. */ |
-static const unsigned char *PageData(DbPage *pPage, unsigned iOffset){ |
+static const unsigned char *PageData(RecoverPage *pPage, unsigned iOffset){ |
assert( iOffset<=pPage->nPageSize ); |
return (unsigned char *)pPage->pData + iOffset; |
} |
@@ -381,7 +455,7 @@ static const unsigned char *PageData(DbPage *pPage, unsigned iOffset){ |
* the offsets in the page's header information are relative to the |
* beginning of the page, NOT the end of the page header. |
*/ |
-static const unsigned char *PageHeader(DbPage *pPage){ |
+static const unsigned char *PageHeader(RecoverPage *pPage){ |
if( pPage->pgno==1 ){ |
const unsigned nDatabaseHeader = 100; |
return PageData(pPage, nDatabaseHeader); |
@@ -392,9 +466,10 @@ static const unsigned char *PageHeader(DbPage *pPage){ |
/* Helper to fetch the pager and page size for the named database. */ |
static int GetPager(sqlite3 *db, const char *zName, |
- Pager **pPager, unsigned *pnPageSize){ |
+ RecoverPager **ppPager, unsigned *pnPageSize){ |
Btree *pBt = NULL; |
- int i; |
+ int i, rc; |
+ RecoverPager *pPager; |
for( i=0; i<db->nDb; ++i ){ |
if( ascii_strcasecmp(db->aDb[i].zName, zName)==0 ){ |
pBt = db->aDb[i].pBt; |
@@ -405,7 +480,12 @@ static int GetPager(sqlite3 *db, const char *zName, |
return SQLITE_ERROR; |
} |
- *pPager = sqlite3BtreePager(pBt); |
+ rc = pagerCreate(sqlite3BtreePager(pBt), 0, &pPager); |
+ if( rc!=SQLITE_OK ){ |
+ return rc; |
+ } |
+ |
+ *ppPager = pPager; |
*pnPageSize = |
sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetOptimalReserve(pBt); |
return SQLITE_OK; |
@@ -431,7 +511,7 @@ static u32 SerialTypeLength(u64 iSerialType){ |
case 7 : return 8; /* 64-bit float. */ |
case 8 : return 0; /* Constant 0. */ |
case 9 : return 0; /* Constant 1. */ |
- case 10 : case 11 : assert( !"RESERVED TYPE"); return 0; |
+ case 10 : case 11 : assert( "RESERVED TYPE"==NULL ); return 0; |
} |
return (u32)((iSerialType>>1) - 6); |
} |
@@ -457,8 +537,8 @@ static int SerialTypeIsCompatible(u64 iSerialType, unsigned char mask){ |
case 7 : return (mask&MASK_FLOAT)!=0; |
case 8 : return (mask&MASK_INTEGER)!=0; |
case 9 : return (mask&MASK_INTEGER)!=0; |
- case 10 : assert( !"RESERVED TYPE"); return 0; |
- case 11 : assert( !"RESERVED TYPE"); return 0; |
+ case 10 : assert( "RESERVED TYPE"==NULL ); return 0; |
+ case 11 : assert( "RESERVED TYPE"==NULL ); return 0; |
} |
return (mask&(SerialTypeIsBlob(iSerialType) ? MASK_BLOB : MASK_TEXT)); |
} |
@@ -620,7 +700,7 @@ static int getEncoding(sqlite3 *db, const char *zDb, int* piEncoding){ |
typedef struct RecoverInteriorCursor RecoverInteriorCursor; |
struct RecoverInteriorCursor { |
RecoverInteriorCursor *pParent; /* Parent node to this node. */ |
- DbPage *pPage; /* Reference to leaf page. */ |
+ RecoverPage *pPage; /* Reference to leaf page. */ |
unsigned nPageSize; /* Size of page. */ |
unsigned nChildren; /* Number of children on the page. */ |
unsigned iChild; /* Index of next child to return. */ |
@@ -633,7 +713,7 @@ static void interiorCursorDestroy(RecoverInteriorCursor *pCursor){ |
pCursor = pCursor->pParent; |
if( p->pPage ){ |
- sqlite3PagerUnref(p->pPage); |
+ pageDestroy(p->pPage); |
p->pPage = NULL; |
} |
@@ -644,13 +724,13 @@ static void interiorCursorDestroy(RecoverInteriorCursor *pCursor){ |
/* Internal helper. Reset storage in preparation for iterating pPage. */ |
static void interiorCursorSetPage(RecoverInteriorCursor *pCursor, |
- DbPage *pPage){ |
+ RecoverPage *pPage){ |
const unsigned knMinCellLength = 2 + 4 + 1; |
unsigned nMaxChildren; |
assert( PageHeader(pPage)[kiPageTypeOffset]==kTableInteriorPage ); |
if( pCursor->pPage ){ |
- sqlite3PagerUnref(pCursor->pPage); |
+ pageDestroy(pCursor->pPage); |
pCursor->pPage = NULL; |
} |
pCursor->pPage = pPage; |
@@ -681,7 +761,7 @@ static void interiorCursorSetPage(RecoverInteriorCursor *pCursor, |
} |
static int interiorCursorCreate(RecoverInteriorCursor *pParent, |
- DbPage *pPage, int nPageSize, |
+ RecoverPage *pPage, int nPageSize, |
RecoverInteriorCursor **ppCursor){ |
RecoverInteriorCursor *pCursor = |
sqlite3_malloc(sizeof(RecoverInteriorCursor)); |
@@ -766,7 +846,7 @@ static int interiorCursorPageInUse(RecoverInteriorCursor *pCursor, |
* reverse the list during traversal. |
*/ |
static int interiorCursorNextPage(RecoverInteriorCursor **ppCursor, |
- DbPage **ppPage){ |
+ RecoverPage **ppPage){ |
RecoverInteriorCursor *pCursor = *ppCursor; |
while( 1 ){ |
int rc; |
@@ -779,7 +859,7 @@ static int interiorCursorNextPage(RecoverInteriorCursor **ppCursor, |
if( interiorCursorPageInUse(pCursor, iPage) ){ |
fprintf(stderr, "Loop detected at %d\n", iPage); |
}else{ |
- int rc = sqlite3PagerGet(pCursor->pPage->pPager, iPage, ppPage, 0); |
+ int rc = pagerGetPage(pCursor->pPage->pPager, iPage, ppPage); |
if( rc==SQLITE_OK ){ |
return SQLITE_ROW; |
} |
@@ -833,7 +913,7 @@ static int interiorCursorNextPage(RecoverInteriorCursor **ppCursor, |
typedef struct RecoverOverflow RecoverOverflow; |
struct RecoverOverflow { |
RecoverOverflow *pNextOverflow; |
- DbPage *pPage; |
+ RecoverPage *pPage; |
unsigned nPageSize; |
}; |
@@ -843,7 +923,7 @@ static void overflowDestroy(RecoverOverflow *pOverflow){ |
pOverflow = p->pNextOverflow; |
if( p->pPage ){ |
- sqlite3PagerUnref(p->pPage); |
+ pageDestroy(p->pPage); |
p->pPage = NULL; |
} |
@@ -870,7 +950,7 @@ static int overflowPageInUse(RecoverOverflow *pOverflow, unsigned iPage){ |
* overflowGetSegment() will do the right thing regardless of whether |
* those values are set to be in-page or not. |
*/ |
-static int overflowMaybeCreate(DbPage *pPage, unsigned nPageSize, |
+static int overflowMaybeCreate(RecoverPage *pPage, unsigned nPageSize, |
unsigned iRecordOffset, unsigned nRecordBytes, |
unsigned *pnLocalRecordBytes, |
RecoverOverflow **ppOverflow){ |
@@ -923,14 +1003,14 @@ static int overflowMaybeCreate(DbPage *pPage, unsigned nPageSize, |
while( iNextPage && nBytes<nRecordBytes ){ |
RecoverOverflow *pOverflow; /* New overflow page for the list. */ |
- rc = sqlite3PagerGet(pPage->pPager, iNextPage, &pPage, 0); |
+ rc = pagerGetPage(pPage->pPager, iNextPage, &pPage); |
if( rc!=SQLITE_OK ){ |
break; |
} |
pOverflow = sqlite3_malloc(sizeof(RecoverOverflow)); |
if( !pOverflow ){ |
- sqlite3PagerUnref(pPage); |
+ pageDestroy(pPage); |
rc = SQLITE_NOMEM; |
break; |
} |
@@ -994,7 +1074,7 @@ static int overflowMaybeCreate(DbPage *pPage, unsigned nPageSize, |
* and overflow pages consistently by adjusting the values |
* appropriately. |
*/ |
-static int overflowGetSegment(DbPage *pPage, unsigned iRecordOffset, |
+static int overflowGetSegment(RecoverPage *pPage, unsigned iRecordOffset, |
unsigned nLocalRecordBytes, |
RecoverOverflow *pOverflow, |
unsigned iRequestOffset, unsigned nRequestBytes, |
@@ -1101,7 +1181,8 @@ static int overflowGetSegment(DbPage *pPage, unsigned iRecordOffset, |
typedef struct RecoverLeafCursor RecoverLeafCursor; |
struct RecoverLeafCursor { |
RecoverInteriorCursor *pParent; /* Parent node to this node. */ |
- DbPage *pPage; /* Reference to leaf page. */ |
+ RecoverPager *pPager; /* Page provider. */ |
+ RecoverPage *pPage; /* Current leaf page. */ |
unsigned nPageSize; /* Size of pPage. */ |
unsigned nCells; /* Number of cells in pPage. */ |
unsigned iCell; /* Current cell. */ |
@@ -1136,13 +1217,13 @@ struct RecoverLeafCursor { |
* If SQLITE_OK is returned, the caller no longer owns pPage, |
* otherwise the caller is responsible for discarding it. |
*/ |
-static int leafCursorLoadPage(RecoverLeafCursor *pCursor, DbPage *pPage){ |
+static int leafCursorLoadPage(RecoverLeafCursor *pCursor, RecoverPage *pPage){ |
const unsigned char *pPageHeader; /* Header of *pPage */ |
unsigned nCells; /* Number of cells in the page */ |
/* Release the current page. */ |
if( pCursor->pPage ){ |
- sqlite3PagerUnref(pCursor->pPage); |
+ pageDestroy(pCursor->pPage); |
pCursor->pPage = NULL; |
pCursor->iCell = pCursor->nCells = 0; |
} |
@@ -1164,14 +1245,14 @@ static int leafCursorLoadPage(RecoverLeafCursor *pCursor, DbPage *pPage){ |
/* Not a leaf page, skip it. */ |
if( pPageHeader[kiPageTypeOffset]!=kTableLeafPage ){ |
- sqlite3PagerUnref(pPage); |
+ pageDestroy(pPage); |
return SQLITE_OK; |
} |
/* Leaf contains no data, skip it. Empty tables, for instance. */ |
nCells = decodeUnsigned16(pPageHeader + kiPageCellCountOffset);; |
if( nCells<1 ){ |
- sqlite3PagerUnref(pPage); |
+ pageDestroy(pPage); |
return SQLITE_OK; |
} |
@@ -1193,7 +1274,7 @@ static int leafCursorNextPage(RecoverLeafCursor *pCursor){ |
/* Repeatedly load the parent's next child page until a leaf is found. */ |
do { |
- DbPage *pNextPage; |
+ RecoverPage *pNextPage; |
int rc = interiorCursorNextPage(&pCursor->pParent, &pNextPage); |
if( rc!=SQLITE_ROW ){ |
assert( rc==SQLITE_DONE ); |
@@ -1202,7 +1283,7 @@ static int leafCursorNextPage(RecoverLeafCursor *pCursor){ |
rc = leafCursorLoadPage(pCursor, pNextPage); |
if( rc!=SQLITE_OK ){ |
- sqlite3PagerUnref(pNextPage); |
+ pageDestroy(pNextPage); |
return rc; |
} |
} while( !pCursor->pPage ); |
@@ -1232,10 +1313,15 @@ static void leafCursorDestroy(RecoverLeafCursor *pCursor){ |
} |
if( pCursor->pPage ){ |
- sqlite3PagerUnref(pCursor->pPage); |
+ pageDestroy(pCursor->pPage); |
pCursor->pPage = NULL; |
} |
+ if( pCursor->pPager ){ |
+ pagerDestroy(pCursor->pPager); |
+ pCursor->pPager = NULL; |
+ } |
+ |
memset(pCursor, 0xA5, sizeof(*pCursor)); |
sqlite3_free(pCursor); |
} |
@@ -1253,30 +1339,31 @@ static void leafCursorDestroy(RecoverLeafCursor *pCursor){ |
* - pPage is a valid interior page who's leaves contain no valid cells. |
* - pPage is not a valid leaf or interior page. |
*/ |
-static int leafCursorCreate(Pager *pPager, unsigned nPageSize, |
+static int leafCursorCreate(RecoverPager *pPager, unsigned nPageSize, |
u32 iRootPage, RecoverLeafCursor **ppCursor){ |
- DbPage *pPage; /* Reference to page at iRootPage. */ |
+ RecoverPage *pPage; /* Reference to page at iRootPage. */ |
RecoverLeafCursor *pCursor; /* Leaf cursor being constructed. */ |
int rc; |
/* Start out with the root page. */ |
- rc = sqlite3PagerGet(pPager, iRootPage, &pPage, 0); |
+ rc = pagerGetPage(pPager, iRootPage, &pPage); |
if( rc!=SQLITE_OK ){ |
return rc; |
} |
pCursor = sqlite3_malloc(sizeof(RecoverLeafCursor)); |
if( !pCursor ){ |
- sqlite3PagerUnref(pPage); |
+ pageDestroy(pPage); |
return SQLITE_NOMEM; |
} |
memset(pCursor, 0, sizeof(*pCursor)); |
pCursor->nPageSize = nPageSize; |
+ pCursor->pPager = pPager; |
rc = leafCursorLoadPage(pCursor, pPage); |
if( rc!=SQLITE_OK ){ |
- sqlite3PagerUnref(pPage); |
+ pageDestroy(pPage); |
leafCursorDestroy(pCursor); |
return rc; |
} |
@@ -1619,7 +1706,7 @@ static int recoverOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ |
u32 iRootPage; /* Root page of the backing table. */ |
int iEncoding; /* UTF encoding for backing database. */ |
unsigned nPageSize; /* Size of pages in backing database. */ |
- Pager *pPager; /* Backing database pager. */ |
+ RecoverPager *pPager; /* Backing database pager. */ |
RecoverLeafCursor *pLeafCursor; /* Cursor to read table's leaf pages. */ |
RecoverCursor *pCursor; /* Cursor to read rows from leaves. */ |
int rc; |
@@ -1646,6 +1733,7 @@ static int recoverOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ |
rc = leafCursorCreate(pPager, nPageSize, iRootPage, &pLeafCursor); |
if( rc!=SQLITE_OK ){ |
+ pagerDestroy(pPager); |
return rc; |
} |