Updated SQLite to 3.3.13 - why? I have no idea

This commit is contained in:
Scott Ehlert
2007-03-21 20:19:37 +00:00
parent eaa4122c5a
commit a004e906dd
55 changed files with 9336 additions and 3963 deletions

View File

@ -387,17 +387,13 @@ struct BtCursor {
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_SHARED_CACHE
void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#endif
};
/*
** Potential values for BtCursor.eState. The first two values (VALID and
** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur
** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined.
** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called.
@ -425,16 +421,17 @@ struct BtCursor {
*/
#if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace )\
{ sqlite3DebugPrintf X; fflush(stdout); }
/* { sqlite3DebugPrintf X; fflush(stdout); } */ \
{ printf X; fflush(stdout); }
int sqlite3_btree_trace=0; /* True to enable tracing */
#else
# define TRACE(X)
#endif
int sqlite3_btree_trace=0; /* True to enable tracing */
/*
** Forward declaration
*/
static int checkReadLocks(BtShared*,Pgno,BtCursor*);
static int checkReadLocks(Btree*,Pgno,BtCursor*);
/*
** Read or write a two- and four-byte big-endian integer values.
@ -509,105 +506,8 @@ struct BtLock {
#define queryTableLock(a,b,c) SQLITE_OK
#define lockTable(a,b,c) SQLITE_OK
#define unlockAllTables(a)
#define restoreOrClearCursorPosition(a,b) SQLITE_OK
#define saveAllCursors(a,b,c) SQLITE_OK
#else
static void releasePage(MemPage *pPage);
/*
** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
*/
static int saveCursorPosition(BtCursor *pCur){
int rc;
assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey );
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
/* If this is an intKey table, then the above call to BtreeKeySize()
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
** table, then malloc space for and store the pCur->nKey bytes of key
** data.
*/
if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
void *pKey = sqliteMalloc((int)pCur->nKey);
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, (u32)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
pCur->pKey = pKey;
}else{
sqliteFree(pKey);
}
}else{
rc = SQLITE_NOMEM;
}
}
assert( !pCur->pPage->intKey || !pCur->pKey );
if( rc==SQLITE_OK ){
releasePage(pCur->pPage);
pCur->pPage = 0;
pCur->eState = CURSOR_REQUIRESEEK;
}
return rc;
}
/*
** Save the positions of all cursors except pExcept open on the table
** with root-page iRoot. Usually, this is called just before cursor
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p;
if( sqlite3ThreadDataReadOnly()->useSharedData ){
for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
p->eState==CURSOR_VALID ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
}
}
}
}
return SQLITE_OK;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
** when saveCursorPosition() was called. Note that this call deletes the
** saved position info stored by saveCursorPosition(), so there can be
** at most one effective restoreOrClearCursorPosition() call after each
** saveCursorPosition().
**
** If the second argument argument - doSeek - is false, then instead of
** returning the cursor to it's saved position, any saved position is deleted
** and the cursor state set to CURSOR_INVALID.
*/
static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
int rc = SQLITE_OK;
assert( sqlite3ThreadDataReadOnly()->useSharedData );
assert( pCur->eState==CURSOR_REQUIRESEEK );
pCur->eState = CURSOR_INVALID;
if( doSeek ){
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
}
if( rc==SQLITE_OK ){
sqliteFree(pCur->pKey);
pCur->pKey = 0;
assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
}
return rc;
}
#define restoreOrClearCursorPosition(p,x) \
(p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
/*
** Query to see if btree handle p may obtain a lock of type eLock
@ -747,6 +647,98 @@ static void unlockAllTables(Btree *p){
}
#endif /* SQLITE_OMIT_SHARED_CACHE */
static void releasePage(MemPage *pPage); /* Forward reference */
/*
** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
*/
static int saveCursorPosition(BtCursor *pCur){
int rc;
assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey );
rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
/* If this is an intKey table, then the above call to BtreeKeySize()
** stores the integer key in pCur->nKey. In this case this value is
** all that is required. Otherwise, if pCur is not open on an intKey
** table, then malloc space for and store the pCur->nKey bytes of key
** data.
*/
if( rc==SQLITE_OK && 0==pCur->pPage->intKey){
void *pKey = sqliteMalloc((int)pCur->nKey);
if( pKey ){
rc = sqlite3BtreeKey(pCur, 0, (u32)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
pCur->pKey = pKey;
}else{
sqliteFree(pKey);
}
}else{
rc = SQLITE_NOMEM;
}
}
assert( !pCur->pPage->intKey || !pCur->pKey );
if( rc==SQLITE_OK ){
releasePage(pCur->pPage);
pCur->pPage = 0;
pCur->eState = CURSOR_REQUIRESEEK;
}
return rc;
}
/*
** Save the positions of all cursors except pExcept open on the table
** with root-page iRoot. Usually, this is called just before cursor
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
BtCursor *p;
for(p=pBt->pCursor; p; p=p->pNext){
if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
p->eState==CURSOR_VALID ){
int rc = saveCursorPosition(p);
if( SQLITE_OK!=rc ){
return rc;
}
}
}
return SQLITE_OK;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
** when saveCursorPosition() was called. Note that this call deletes the
** saved position info stored by saveCursorPosition(), so there can be
** at most one effective restoreOrClearCursorPosition() call after each
** saveCursorPosition().
**
** If the second argument argument - doSeek - is false, then instead of
** returning the cursor to it's saved position, any saved position is deleted
** and the cursor state set to CURSOR_INVALID.
*/
static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
int rc = SQLITE_OK;
assert( pCur->eState==CURSOR_REQUIRESEEK );
pCur->eState = CURSOR_INVALID;
if( doSeek ){
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
}
if( rc==SQLITE_OK ){
sqliteFree(pCur->pKey);
pCur->pKey = 0;
assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
}
return rc;
}
#define restoreOrClearCursorPosition(p,x) \
(p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** These macros define the location of the pointer-map entry for a
@ -1048,91 +1040,6 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){
#endif
/*
** Do sanity checking on a page. Throw an exception if anything is
** not right.
**
** This routine is used for internal error checking only. It is omitted
** from most builds.
*/
#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
static void _pageIntegrity(MemPage *pPage){
int usableSize;
u8 *data;
int i, j, idx, c, pc, hdr, nFree;
int cellOffset;
int nCell, cellLimit;
u8 *used;
used = sqliteMallocRaw( pPage->pBt->pageSize );
if( used==0 ) return;
usableSize = pPage->pBt->usableSize;
assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
hdr = pPage->hdrOffset;
assert( hdr==(pPage->pgno==1 ? 100 : 0) );
assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
c = pPage->aData[hdr];
if( pPage->isInit ){
assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
assert( pPage->leafData == ((c & PTF_LEAFDATA)!=0) );
assert( pPage->intKey == ((c & (PTF_INTKEY|PTF_LEAFDATA))!=0) );
assert( pPage->hasData ==
!(pPage->zeroData || (!pPage->leaf && pPage->leafData)) );
assert( pPage->cellOffset==pPage->hdrOffset+12-4*pPage->leaf );
assert( pPage->nCell = get2byte(&pPage->aData[hdr+3]) );
}
data = pPage->aData;
memset(used, 0, usableSize);
for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
nFree = 0;
pc = get2byte(&data[hdr+1]);
while( pc ){
int size;
assert( pc>0 && pc<usableSize-4 );
size = get2byte(&data[pc+2]);
assert( pc+size<=usableSize );
nFree += size;
for(i=pc; i<pc+size; i++){
assert( used[i]==0 );
used[i] = 1;
}
pc = get2byte(&data[pc]);
}
idx = 0;
nCell = get2byte(&data[hdr+3]);
cellLimit = get2byte(&data[hdr+5]);
assert( pPage->isInit==0
|| pPage->nFree==nFree+data[hdr+7]+cellLimit-(cellOffset+2*nCell) );
cellOffset = pPage->cellOffset;
for(i=0; i<nCell; i++){
int size;
pc = get2byte(&data[cellOffset+2*i]);
assert( pc>0 && pc<usableSize-4 );
size = cellSize(pPage, &data[pc]);
assert( pc+size<=usableSize );
for(j=pc; j<pc+size; j++){
assert( used[j]==0 );
used[j] = 1;
}
}
for(i=cellOffset+2*nCell; i<cellimit; i++){
assert( used[i]==0 );
used[i] = 1;
}
nFree = 0;
for(i=0; i<usableSize; i++){
assert( used[i]<=1 );
if( used[i]==0 ) nFree++;
}
assert( nFree==data[hdr+7] );
sqliteFree(used);
}
#define pageIntegrity(X) _pageIntegrity(X)
#else
# define pageIntegrity(X)
#endif
/* A bunch of assert() statements to check the transaction state variables
** of handle p (type Btree*) are internally consistent.
*/
@ -1439,7 +1346,6 @@ static int initPage(
}
pPage->isInit = 1;
pageIntegrity(pPage);
return SQLITE_OK;
}
@ -1470,7 +1376,6 @@ static void zeroPage(MemPage *pPage, int flags){
pPage->idxShift = 0;
pPage->nCell = 0;
pPage->isInit = 1;
pageIntegrity(pPage);
}
/*
@ -1591,9 +1496,9 @@ int sqlite3BtreeOpen(
*/
#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
#ifdef SQLITE_OMIT_MEMORYDB
const int isMemdb = !zFilename;
const int isMemdb = 0;
#else
const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1);
const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
#endif
#endif
@ -1645,8 +1550,13 @@ int sqlite3BtreeOpen(
return SQLITE_NOMEM;
}
rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
if( rc==SQLITE_OK ){
rc = sqlite3pager_read_fileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
}
if( rc!=SQLITE_OK ){
if( pBt->pPager ) sqlite3pager_close(pBt->pPager);
if( pBt->pPager ){
sqlite3pager_close(pBt->pPager);
}
sqliteFree(pBt);
sqliteFree(p);
*ppBtree = 0;
@ -1659,7 +1569,6 @@ int sqlite3BtreeOpen(
pBt->pCursor = 0;
pBt->pPage1 = 0;
pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader);
pBt->pageSize = get2byte(&zDbHeader[16]);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
@ -2022,13 +1931,15 @@ static int lockBtreeWithRetry(Btree *pRef){
*/
static void unlockBtreeIfUnused(BtShared *pBt){
if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){
if( pBt->pPage1->aData==0 ){
MemPage *pPage = pBt->pPage1;
pPage->aData = &((u8*)pPage)[-pBt->pageSize];
pPage->pBt = pBt;
pPage->pgno = 1;
if( sqlite3pager_refcount(pBt->pPager)>=1 ){
if( pBt->pPage1->aData==0 ){
MemPage *pPage = pBt->pPage1;
pPage->aData = &((u8*)pPage)[-pBt->pageSize];
pPage->pBt = pBt;
pPage->pgno = 1;
}
releasePage(pBt->pPage1);
}
releasePage(pBt->pPage1);
pBt->pPage1 = 0;
pBt->inStmt = 0;
}
@ -2367,7 +2278,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
MemPage *pFreeMemPage = 0; /* "" */
#ifndef NDEBUG
int nRef = *sqlite3pager_stats(pPager);
int nRef = sqlite3pager_refcount(pPager);
#endif
assert( pBt->autoVacuum );
@ -2475,7 +2386,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
assert( finSize!=PENDING_BYTE_PAGE(pBt) );
autovacuum_out:
assert( nRef==*sqlite3pager_stats(pPager) );
assert( nRef==sqlite3pager_refcount(pPager) );
if( rc!=SQLITE_OK ){
sqlite3pager_rollback(pPager);
}
@ -2548,7 +2459,7 @@ static int countWriteCursors(BtShared *pBt){
}
#endif
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** Print debugging information about all cursors to standard output.
*/
@ -2778,7 +2689,7 @@ int sqlite3BtreeCursor(
if( pBt->readOnly ){
return SQLITE_READONLY;
}
if( checkReadLocks(pBt, iTable, 0) ){
if( checkReadLocks(p, iTable, 0) ){
return SQLITE_LOCKED;
}
}
@ -2980,7 +2891,6 @@ static int getPayload(
assert( pCur->eState==CURSOR_VALID );
pBt = pCur->pBtree->pBt;
pPage = pCur->pPage;
pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader;
@ -3118,7 +3028,6 @@ static const unsigned char *fetchPayload(
assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage;
pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur);
aPayload = pCur->info.pCell;
@ -3180,7 +3089,6 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
assert( pCur->eState==CURSOR_VALID );
rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage);
if( rc ) return rc;
pageIntegrity(pNewPage);
pNewPage->idxParent = pCur->idx;
pOldPage = pCur->pPage;
pOldPage->idxShift = 0;
@ -3228,10 +3136,8 @@ static void moveToParent(BtCursor *pCur){
pPage = pCur->pPage;
assert( pPage!=0 );
assert( !isRootPage(pPage) );
pageIntegrity(pPage);
pParent = pPage->pParent;
assert( pParent!=0 );
pageIntegrity(pParent);
idxParent = pPage->idxParent;
sqlite3pager_ref(pParent->aData);
releasePage(pPage);
@ -3261,7 +3167,6 @@ static int moveToRoot(BtCursor *pCur){
return rc;
}
releasePage(pCur->pPage);
pageIntegrity(pRoot);
pCur->pPage = pRoot;
}
pCur->idx = 0;
@ -3405,7 +3310,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
assert( pCur->pPage->nCell==0 );
return SQLITE_OK;
}
for(;;){
for(;;){
int lwr, upr;
Pgno chldPg;
MemPage *pPage = pCur->pPage;
@ -3415,7 +3320,6 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
if( !pPage->intKey && pKey==0 ){
return SQLITE_CORRUPT_BKPT;
}
pageIntegrity(pPage);
while( lwr<=upr ){
void *pCellKey;
i64 nCellKey;
@ -3668,14 +3572,14 @@ static int allocatePage(
int rc;
int n; /* Number of pages on the freelist */
int k; /* Number of leaves on the trunk of the freelist */
MemPage *pTrunk = 0;
MemPage *pPrevTrunk = 0;
pPage1 = pBt->pPage1;
n = get4byte(&pPage1->aData[36]);
if( n>0 ){
/* There are pages on the freelist. Reuse one of those pages. */
MemPage *pTrunk = 0;
Pgno iTrunk;
MemPage *pPrevTrunk = 0;
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
/* If the 'exact' parameter was true and a query of the pointer-map
@ -3716,16 +3620,8 @@ static int allocatePage(
}
rc = getPage(pBt, iTrunk, &pTrunk);
if( rc ){
releasePage(pPrevTrunk);
return rc;
}
/* TODO: This should move to after the loop? */
rc = sqlite3pager_write(pTrunk->aData);
if( rc ){
releasePage(pTrunk);
releasePage(pPrevTrunk);
return rc;
pTrunk = 0;
goto end_allocate_page;
}
k = get4byte(&pTrunk->aData[4]);
@ -3734,6 +3630,10 @@ static int allocatePage(
** So extract the trunk page itself and use it as the newly
** allocated page */
assert( pPrevTrunk==0 );
rc = sqlite3pager_write(pTrunk->aData);
if( rc ){
goto end_allocate_page;
}
*pPgno = iTrunk;
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
@ -3741,7 +3641,8 @@ static int allocatePage(
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>pBt->usableSize/4 - 8 ){
/* Value of k is out of range. Database corruption */
return SQLITE_CORRUPT_BKPT;
rc = SQLITE_CORRUPT_BKPT;
goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList && nearby==iTrunk ){
/* The list is being searched and this trunk page is the page
@ -3750,6 +3651,10 @@ static int allocatePage(
assert( *pPgno==iTrunk );
*ppPage = pTrunk;
searchList = 0;
rc = sqlite3pager_write(pTrunk->aData);
if( rc ){
goto end_allocate_page;
}
if( k==0 ){
if( !pPrevTrunk ){
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
@ -3765,26 +3670,26 @@ static int allocatePage(
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
rc = getPage(pBt, iNewTrunk, &pNewTrunk);
if( rc!=SQLITE_OK ){
releasePage(pTrunk);
releasePage(pPrevTrunk);
return rc;
goto end_allocate_page;
}
rc = sqlite3pager_write(pNewTrunk->aData);
if( rc!=SQLITE_OK ){
releasePage(pNewTrunk);
releasePage(pTrunk);
releasePage(pPrevTrunk);
return rc;
goto end_allocate_page;
}
memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4);
put4byte(&pNewTrunk->aData[4], k-1);
memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4);
releasePage(pNewTrunk);
if( !pPrevTrunk ){
put4byte(&pPage1->aData[32], iNewTrunk);
}else{
rc = sqlite3pager_write(pPrevTrunk->aData);
if( rc ){
goto end_allocate_page;
}
put4byte(&pPrevTrunk->aData[0], iNewTrunk);
}
releasePage(pNewTrunk);
}
pTrunk = 0;
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
@ -3794,6 +3699,10 @@ static int allocatePage(
int closest;
Pgno iPage;
unsigned char *aData = pTrunk->aData;
rc = sqlite3pager_write(aData);
if( rc ){
goto end_allocate_page;
}
if( nearby>0 ){
int i, dist;
closest = 0;
@ -3837,8 +3746,8 @@ static int allocatePage(
}
}
releasePage(pPrevTrunk);
pPrevTrunk = 0;
}while( searchList );
releasePage(pTrunk);
}else{
/* There are no pages on the freelist, so create a new page at the
** end of the file */
@ -3867,6 +3776,10 @@ static int allocatePage(
}
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
end_allocate_page:
releasePage(pTrunk);
releasePage(pPrevTrunk);
return rc;
}
@ -4267,7 +4180,6 @@ static int insertCell(
put2byte(&data[ins], idx);
put2byte(&data[hdr+3], pPage->nCell);
pPage->idxShift = 1;
pageIntegrity(pPage);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
/* The cell may contain a pointer to an overflow page. If so, write
@ -5007,8 +4919,6 @@ static int balance_nonroot(MemPage *pPage){
** But the parent page will always be initialized.
*/
assert( pParent->isInit );
/* assert( pPage->isInit ); // No! pPage might have been added to freelist */
/* pageIntegrity(pPage); // No! pPage might have been added to freelist */
rc = balance(pParent, 0);
/*
@ -5215,27 +5125,35 @@ static int balance(MemPage *pPage, int insert){
/*
** This routine checks all cursors that point to table pgnoRoot.
** If any of those cursors other than pExclude were opened with
** wrFlag==0 then this routine returns SQLITE_LOCKED. If all
** cursors that point to pgnoRoot were opened with wrFlag==1
** then this routine returns SQLITE_OK.
** If any of those cursors were opened with wrFlag==0 in a different
** database connection (a database connection that shares the pager
** cache with the current connection) and that other connection
** is not in the ReadUncommmitted state, then this routine returns
** SQLITE_LOCKED.
**
** In addition to checking for read-locks (where a read-lock
** means a cursor opened with wrFlag==0) this routine also moves
** all cursors other than pExclude so that they are pointing to the
** first Cell on root page. This is necessary because an insert
** all cursors write cursors so that they are pointing to the
** first Cell on the root page. This is necessary because an insert
** or delete might change the number of cells on a page or delete
** a page entirely and we do not want to leave any cursors
** pointing to non-existant pages or cells.
*/
static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){
static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){
BtCursor *p;
BtShared *pBt = pBtree->pBt;
sqlite3 *db = pBtree->pSqlite;
for(p=pBt->pCursor; p; p=p->pNext){
u32 flags = (p->pBtree->pSqlite ? p->pBtree->pSqlite->flags : 0);
if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue;
if( p->wrFlag==0 && flags&SQLITE_ReadUncommitted ) continue;
if( p->wrFlag==0 ) return SQLITE_LOCKED;
if( p->pPage->pgno!=p->pgnoRoot ){
if( p==pExclude ) continue;
if( p->eState!=CURSOR_VALID ) continue;
if( p->pgnoRoot!=pgnoRoot ) continue;
if( p->wrFlag==0 ){
sqlite3 *dbOther = p->pBtree->pSqlite;
if( dbOther==0 ||
(dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){
return SQLITE_LOCKED;
}
}else if( p->pPage->pgno!=p->pgnoRoot ){
moveToRoot(p);
}
}
@ -5272,7 +5190,7 @@ int sqlite3BtreeInsert(
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Cursor not open for writing */
}
if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
@ -5354,7 +5272,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Did not open this cursor for writing */
}
if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
@ -5393,8 +5311,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){
BtCursor leafCur;
unsigned char *pNext;
int szNext = 0; /* The compiler warning is wrong: szNext is always
** initialized before use. Adding an extra initialization
** to silence the compiler slows down the code. */
** initialized before use. Adding an extra initialization
** to silence the compiler slows down the code. */
int notUsed;
unsigned char *tempCell = 0;
assert( !pPage->leafData );
@ -5631,25 +5549,13 @@ cleardatabasepage_out:
*/
int sqlite3BtreeClearTable(Btree *p, int iTable){
int rc;
BtCursor *pCur;
BtShared *pBt = p->pBt;
sqlite3 *db = p->pSqlite;
if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
/* If this connection is not in read-uncommitted mode and currently has
** a read-cursor open on the table being cleared, return SQLITE_LOCKED.
*/
if( 0==db || 0==(db->flags&SQLITE_ReadUncommitted) ){
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( pCur->pBtree==p && pCur->pgnoRoot==(Pgno)iTable ){
if( 0==pCur->wrFlag ){
return SQLITE_LOCKED;
}
moveToRoot(pCur);
}
}
rc = checkReadLocks(p, iTable, 0);
if( rc ){
return rc;
}
/* Save the position of all cursors open on this table */
@ -5969,7 +5875,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
}
#endif
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
@ -5984,6 +5890,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
** aResult[7] = Header size in bytes
** aResult[8] = Local payload size
** aResult[9] = Parent page number
** aResult[10]= Page number of the first overflow page
**
** This routine is used for testing and debugging only.
*/
@ -5997,14 +5904,12 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
return rc;
}
pageIntegrity(pPage);
assert( pPage->isInit );
getTempCursor(pCur, &tmpCur);
while( upCnt-- ){
moveToParent(&tmpCur);
}
pPage = tmpCur.pPage;
pageIntegrity(pPage);
aResult[0] = sqlite3pager_pagenumber(pPage->aData);
assert( aResult[0]==pPage->pgno );
aResult[1] = tmpCur.idx;
@ -6034,6 +5939,11 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
}else{
aResult[9] = pPage->pParent->pgno;
}
if( tmpCur.info.iOverflow ){
aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]);
}else{
aResult[10] = 0;
}
releaseTempCursor(&tmpCur);
return SQLITE_OK;
}
@ -6054,10 +5964,12 @@ Pager *sqlite3BtreePager(Btree *p){
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */
char *zErrMsg; /* An error message. NULL of no errors seen. */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */
int mxErr; /* Stop accumulating errors when this reaches zero */
char *zErrMsg; /* An error message. NULL if no errors seen. */
int nErr; /* Number of messages written to zErrMsg so far */
};
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
@ -6072,6 +5984,9 @@ static void checkAppendMsg(
){
va_list ap;
char *zMsg2;
if( !pCheck->mxErr ) return;
pCheck->mxErr--;
pCheck->nErr++;
va_start(ap, zFormat);
zMsg2 = sqlite3VMPrintf(zFormat, ap);
va_end(ap);
@ -6155,7 +6070,7 @@ static void checkList(
int i;
int expected = N;
int iFirst = iPage;
while( N-- > 0 ){
while( N-- > 0 && pCheck->mxErr ){
unsigned char *pOvfl;
if( iPage<1 ){
checkAppendMsg(pCheck, zContext,
@ -6267,7 +6182,7 @@ static int checkTreePage(
/* Check out all the cells.
*/
depth = 0;
for(i=0; i<pPage->nCell; i++){
for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
u8 *pCell;
int sz;
CellInfo info;
@ -6382,19 +6297,28 @@ static int checkTreePage(
** and a pointer to that error message is returned. The calling function
** is responsible for freeing the error message when it is done.
*/
char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
char *sqlite3BtreeIntegrityCheck(
Btree *p, /* The btree to be checked */
int *aRoot, /* An array of root pages numbers for individual trees */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr /* Write number of errors seen to this variable */
){
int i;
int nRef;
IntegrityCk sCheck;
BtShared *pBt = p->pBt;
nRef = *sqlite3pager_stats(pBt->pPager);
nRef = sqlite3pager_refcount(pBt->pPager);
if( lockBtreeWithRetry(p)!=SQLITE_OK ){
return sqliteStrDup("Unable to acquire a read lock on the database");
}
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
*pnErr = 0;
if( sCheck.nPage==0 ){
unlockBtreeIfUnused(pBt);
return 0;
@ -6402,6 +6326,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
if( !sCheck.anRef ){
unlockBtreeIfUnused(pBt);
*pnErr = 1;
return sqlite3MPrintf("Unable to malloc %d bytes",
(sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
}
@ -6419,7 +6344,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Check all the tables.
*/
for(i=0; i<nRoot; i++){
for(i=0; i<nRoot && sCheck.mxErr; i++){
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){
@ -6431,7 +6356,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure every page in the file is referenced
*/
for(i=1; i<=sCheck.nPage; i++){
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( sCheck.anRef[i]==0 ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
@ -6454,16 +6379,17 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure this analysis did not leave any unref() pages
*/
unlockBtreeIfUnused(pBt);
if( nRef != *sqlite3pager_stats(pBt->pPager) ){
if( nRef != sqlite3pager_refcount(pBt->pPager) ){
checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis",
nRef, *sqlite3pager_stats(pBt->pPager)
nRef, sqlite3pager_refcount(pBt->pPager)
);
}
/* Clean up and report errors.
*/
sqliteFree(sCheck.anRef);
*pnErr = sCheck.nErr;
return sCheck.zErrMsg;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@ -6522,7 +6448,6 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
if( rc ) break;
rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
if( rc ) break;
sqlite3pager_unref(pPage);
}
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
@ -6558,6 +6483,13 @@ int sqlite3BtreeIsInStmt(Btree *p){
return (p->pBt && p->pBt->inStmt);
}
/*
** Return non-zero if a read (or write) transaction is active.
*/
int sqlite3BtreeIsInReadTrans(Btree *p){
return (p && (p->inTrans!=TRANS_NONE));
}
/*
** This call is a no-op if no write-transaction is currently active on pBt.
**