Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -585,10 +585,11 @@ for(i=0; i<=pCur->iPage; i++){ releasePage(pCur->apPage[i]); pCur->apPage[i] = 0; } pCur->iPage = -1; + pCur->pPage = 0; } /* ** Save the current cursor position in the variables BtCursor.nKey @@ -3649,10 +3650,11 @@ } for(i=0; i<=p->iPage; i++){ releasePage(p->apPage[i]); p->apPage[i] = 0; } + p->pPage = 0; } sqlite3BtreeLeave(pBtree); } return rc; } @@ -3863,10 +3865,11 @@ /* Now that no other errors can occur, finish filling in the BtCursor ** variables and link the cursor into the BtShared list. */ pCur->pgnoRoot = (Pgno)iTable; pCur->iPage = -1; + pCur->pPage = 0; pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; assert( wrFlag==0 || wrFlag==BTCF_WriteFlag ); pCur->curFlags = wrFlag; @@ -3964,11 +3967,12 @@ #ifndef NDEBUG static void assertCellInfo(BtCursor *pCur){ CellInfo info; int iPage = pCur->iPage; memset(&info, 0, sizeof(info)); - btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info); + assert( pCur->pPage==pCur->apPage[iPage] ); + btreeParseCell(pCur->pPage, pCur->aiIdx[iPage], &info); assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 ); } #else #define assertCellInfo(x) #endif @@ -3975,11 +3979,12 @@ #ifdef _MSC_VER /* Use a real function in MSVC to work around bugs in that compiler. */ static void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ int iPage = pCur->iPage; - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); + assert( pCur->pPage==pCur->apPage[iPage] ); + btreeParseCell(pCur->pPage,pCur->aiIdx[iPage],&pCur->info); pCur->curFlags |= BTCF_ValidNKey; }else{ assertCellInfo(pCur); } } @@ -3986,11 +3991,12 @@ #else /* if not _MSC_VER */ /* Use a macro in all other compilers so that the function is inlined */ #define getCellInfo(pCur) \ if( pCur->info.nSize==0 ){ \ int iPage = pCur->iPage; \ - btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ + assert( pCur->pPage==pCur->apPage[iPage] ); \ + btreeParseCell(pCur->pPage,pCur->aiIdx[iPage],&pCur->info); \ pCur->curFlags |= BTCF_ValidNKey; \ }else{ \ assertCellInfo(pCur); \ } #endif /* _MSC_VER */ @@ -4041,11 +4047,12 @@ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 ); assert( pCur->iPageapPage[pCur->iPage]->intKeyLeaf==1 ); + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); + assert( pCur->pPage->intKeyLeaf==1 ); getCellInfo(pCur); *pSize = pCur->info.nPayload; return SQLITE_OK; } @@ -4195,18 +4202,19 @@ int eOp /* zero to read. non-zero to write. */ ){ unsigned char *aPayload; int rc = SQLITE_OK; int iIdx = 0; - MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ - BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ + MemPage *pPage = pCur->pPage; /* Btree page of current entry */ + BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ #ifdef SQLITE_DIRECT_OVERFLOW_READ unsigned char * const pBufStart = pBuf; int bEnd; /* True if reading to end of data */ #endif assert( pPage ); + assert( pPage==pCur->apPage[pCur->iPage] ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->aiIdx[pCur->iPage]nCell ); assert( cursorHoldsMutex(pCur) ); assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */ @@ -4392,12 +4400,14 @@ ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->iPage>=0 ); + assert( pCur->apPage[pCur->iPage]==pCur->pPage ); + assert( pCur->pPage!=0 ); + assert( pCur->aiIdx[pCur->iPage]pPage->nCell ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* ** Read part of the data associated with cursor pCur. Exactly @@ -4419,12 +4429,14 @@ assert( cursorHoldsMutex(pCur) ); rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); - assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->iPage>=0 ); + assert( pCur->apPage[pCur->iPage]==pCur->pPage ); + assert( pCur->pPage!=0 ); + assert( pCur->aiIdx[pCur->iPage]pPage->nCell ); rc = accessPayload(pCur, offset, amt, pBuf, 0); } return rc; } @@ -4450,19 +4462,22 @@ static const void *fetchPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 *pAmt /* Write the number of available bytes here */ ){ u32 amt; - assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); + assert( pCur!=0 ); + assert( pCur->iPage>=0 ); + assert( pCur->apPage[pCur->iPage]==pCur->pPage ); + assert( pCur->pPage!=0 ); assert( pCur->eState==CURSOR_VALID ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->aiIdx[pCur->iPage]pPage->nCell ); assert( pCur->info.nSize>0 ); - assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB ); - assert( pCur->info.pPayloadapPage[pCur->iPage]->aDataEnd ||CORRUPT_DB); - amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload); + assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB ); + assert( pCur->info.pPayloadpPage->aDataEnd || CORRUPT_DB ); + amt = (int)(pCur->pPage->aDataEnd - pCur->info.pPayload); if( pCur->info.nLocalinfo.nLocal; *pAmt = amt; return (void*)pCur->info.pPayload; } @@ -4512,11 +4527,11 @@ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->curFlags & BTCF_WriteFlag)==0 ? PAGER_GET_READONLY : 0); if( rc ) return rc; - pCur->apPage[i+1] = pNewPage; + pCur->apPage[i+1] = pCur->pPage = pNewPage; pCur->aiIdx[i+1] = 0; pCur->iPage++; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); @@ -4558,20 +4573,22 @@ */ static void moveToParent(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); - assert( pCur->apPage[pCur->iPage] ); + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); + assert( pCur->pPage!=0 ); assertParentIndex( pCur->apPage[pCur->iPage-1], pCur->aiIdx[pCur->iPage-1], - pCur->apPage[pCur->iPage]->pgno + pCur->pPage->pgno ); testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell ); - releasePage(pCur->apPage[pCur->iPage]); + releasePage(pCur->pPage); pCur->iPage--; + pCur->pPage = pCur->apPage[pCur->iPage]; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); } /* @@ -4623,11 +4640,12 @@ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; } - pRoot = pCur->apPage[0]; + assert( pCur->iPage==0 ); + pRoot = pCur->pPage = pCur->apPage[0]; assert( pRoot->pgno==pCur->pgnoRoot ); /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor ** expected to open it on an index b-tree. Otherwise, if pKeyInfo is ** NULL, the caller expects a table b-tree. If this is not the case, @@ -4673,11 +4691,11 @@ int rc = SQLITE_OK; MemPage *pPage; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){ assert( pCur->aiIdx[pCur->iPage]nCell ); pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage])); rc = moveToChild(pCur, pgno); } return rc; @@ -4698,11 +4716,11 @@ int rc = SQLITE_OK; MemPage *pPage = 0; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); - while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){ + while( !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->aiIdx[pCur->iPage] = pPage->nCell; rc = moveToChild(pCur, pgno); if( rc ) return rc; } @@ -4721,15 +4739,16 @@ assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); if( pCur->eState==CURSOR_INVALID ){ - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); *pRes = 1; }else{ - assert( pCur->apPage[pCur->iPage]->nCell>0 ); + assert( pCur->pPage->nCell>0 ); *pRes = 0; rc = moveToLeftmost(pCur); } } return rc; @@ -4752,12 +4771,13 @@ ** to the last entry in the b-tree. */ int ii; for(ii=0; iiiPage; ii++){ assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell ); } - assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 ); - assert( pCur->apPage[pCur->iPage]->leaf ); + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); + assert( pCur->aiIdx[pCur->iPage]==pCur->pPage->nCell-1 ); + assert( pCur->pPage->leaf ); #endif return SQLITE_OK; } rc = moveToRoot(pCur); @@ -4851,23 +4871,24 @@ rc = moveToRoot(pCur); if( rc ){ return rc; } - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] ); - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit ); - assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 ); + assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]==pCur->pPage ); + assert( pCur->pgnoRoot==0 || pCur->pPage!=0 ); + assert( pCur->pgnoRoot==0 || pCur->pPage->isInit ); + assert( pCur->eState==CURSOR_INVALID || pCur->pPage->nCell>0 ); if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; - assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 ); + assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 ); return SQLITE_OK; } - assert( pCur->apPage[0]->intKey || pIdxKey ); + assert( pCur->pPage->intKey || pIdxKey ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; - MemPage *pPage = pCur->apPage[pCur->iPage]; + MemPage *pPage = pCur->pPage; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page ** the cursor would have been INVALID above and this for(;;) loop ** not run. If this is not the root-page, then the moveToChild() routine @@ -4986,11 +5007,11 @@ } } assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) ); assert( pPage->isInit ); if( pPage->leaf ){ - assert( pCur->aiIdx[pCur->iPage]apPage[pCur->iPage]->nCell ); + assert( pCur->aiIdx[pCur->iPage]pPage->nCell ); pCur->aiIdx[pCur->iPage] = (u16)idx; *pRes = c; rc = SQLITE_OK; goto moveto_finish; } @@ -5074,11 +5095,11 @@ } pCur->skipNext = 0; } } - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; idx = ++pCur->aiIdx[pCur->iPage]; assert( pPage->isInit ); /* If the database file is corrupt, it is possible for the value of idx ** to be invalid here. This can only occur if a second cursor modifies @@ -5098,11 +5119,11 @@ *pRes = 1; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } moveToParent(pCur); - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); if( pPage->intKey ){ return sqlite3BtreeNext(pCur, pRes); }else{ return SQLITE_OK; @@ -5122,11 +5143,11 @@ assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID ); pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); *pRes = 0; if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes); - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){ pCur->aiIdx[pCur->iPage]--; return btreeNext(pCur, pRes); } if( pPage->leaf ){ @@ -5185,11 +5206,12 @@ } pCur->skipNext = 0; } } - pPage = pCur->apPage[pCur->iPage]; + pPage = pCur->pPage; + assert( pPage==pCur->apPage[pCur->iPage] ); assert( pPage->isInit ); if( !pPage->leaf ){ int idx = pCur->aiIdx[pCur->iPage]; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ) return rc; @@ -5205,11 +5227,12 @@ } assert( pCur->info.nSize==0 ); assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 ); pCur->aiIdx[pCur->iPage]--; - pPage = pCur->apPage[pCur->iPage]; + assert( pCur->apPage[pCur->iPage]==pCur->pPage ); + pPage = pCur->pPage; if( pPage->intKey && !pPage->leaf ){ rc = sqlite3BtreePrevious(pCur, pRes); }else{ rc = SQLITE_OK; } @@ -5224,11 +5247,11 @@ *pRes = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey); pCur->info.nSize = 0; if( pCur->eState!=CURSOR_VALID || pCur->aiIdx[pCur->iPage]==0 - || pCur->apPage[pCur->iPage]->leaf==0 + || pCur->pPage->leaf==0 ){ return btreePrevious(pCur, pRes); } pCur->aiIdx[pCur->iPage]--; return SQLITE_OK; @@ -7417,11 +7440,12 @@ TESTONLY( int balance_quick_called = 0 ); TESTONLY( int balance_deeper_called = 0 ); do { int iPage = pCur->iPage; - MemPage *pPage = pCur->apPage[iPage]; + MemPage *pPage = pCur->pPage; + assert( pPage==pCur->apPage[iPage] ); if( iPage==0 ){ if( pPage->nOverflow ){ /* The root page of the b-tree is overfull. In this case call the ** balance_deeper() function to create a new child for the root-page @@ -7432,11 +7456,12 @@ rc = balance_deeper(pPage, &pCur->apPage[1]); if( rc==SQLITE_OK ){ pCur->iPage = 1; pCur->aiIdx[0] = 0; pCur->aiIdx[1] = 0; - assert( pCur->apPage[1]->nOverflow ); + pCur->pPage = pCur->apPage[1]; + assert( pCur->pPage->nOverflow ); } }else{ break; } }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ @@ -7511,10 +7536,11 @@ /* The next iteration of the do-loop balances the parent page. */ releasePage(pPage); pCur->iPage--; assert( pCur->iPage>=0 ); + pCur->pPage = pCur->apPage[pCur->iPage]; } }while( rc==SQLITE_OK ); if( pFree ){ sqlite3PageFree(pFree); @@ -7613,11 +7639,12 @@ rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc); if( rc ) return rc; } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); - pPage = pCur->apPage[pCur->iPage]; + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); + pPage = pCur->pPage; assert( pPage->intKey || nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, nKey, nData, pPage->pgno, @@ -7680,14 +7707,15 @@ /* Must make sure nOverflow is reset to zero even if the balance() ** fails. Internal data structure corruption will result otherwise. ** Also, set the cursor state to invalid. This stops saveCursorPosition() ** from trying to save the current position of the cursor. */ - pCur->apPage[pCur->iPage]->nOverflow = 0; + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); + pCur->pPage->nOverflow = 0; pCur->eState = CURSOR_INVALID; } - assert( pCur->apPage[pCur->iPage]->nOverflow==0 ); + assert( pCur->pPage->nOverflow==0 ); end_insert: return rc; } @@ -7709,12 +7737,13 @@ assert( pBt->inTransaction==TRANS_WRITE ); assert( (pBt->btsFlags & BTS_READ_ONLY)==0 ); assert( pCur->curFlags & BTCF_WriteFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); - if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell) + if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->pPage->nCell) || NEVER(pCur->eState!=CURSOR_VALID) ){ return SQLITE_ERROR; /* Something has gone awry. */ } @@ -7760,11 +7789,11 @@ ** is currently pointing to the largest entry in the sub-tree headed ** by the child-page of the cell that was just deleted from an internal ** node. The cell from the leaf node needs to be moved to the internal ** node to replace the deleted cell. */ if( !pPage->leaf ){ - MemPage *pLeaf = pCur->apPage[pCur->iPage]; + MemPage *pLeaf = pCur->pPage; int nCell; Pgno n = pCur->apPage[iCellDepth+1]->pgno; unsigned char *pTmp; pCell = findCell(pLeaf, pLeaf->nCell-1); @@ -7796,10 +7825,11 @@ rc = balance(pCur); if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ while( pCur->iPage>iCellDepth ){ releasePage(pCur->apPage[pCur->iPage--]); } + pCur->pPage = pCur->apPage[pCur->iPage]; rc = balance(pCur); } if( rc==SQLITE_OK ){ moveToRoot(pCur); @@ -8300,11 +8330,12 @@ /* If this is a leaf page or the tree is not an int-key tree, then ** this page contains countable entries. Increment the entry counter ** accordingly. */ - pPage = pCur->apPage[pCur->iPage]; + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); + pPage = pCur->pPage; if( pPage->leaf || !pPage->intKey ){ nEntry += pPage->nCell; } /* pPage is a leaf node. This loop navigates the cursor so that it @@ -8323,14 +8354,15 @@ /* All pages of the b-tree have been visited. Return successfully. */ *pnEntry = nEntry; return moveToRoot(pCur); } moveToParent(pCur); - }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell ); + }while ( pCur->aiIdx[pCur->iPage]>=pCur->pPage->nCell ); pCur->aiIdx[pCur->iPage]++; - pPage = pCur->apPage[pCur->iPage]; + assert( pCur->pPage==pCur->apPage[pCur->iPage] ); + pPage = pCur->pPage; } /* Descend to the child node of the cell that the cursor currently ** points at. This is the right-child if (iIdx==pPage->nCell). */ @@ -9109,10 +9141,11 @@ assert( (pCsr->pBt->btsFlags & BTS_READ_ONLY)==0 && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); assert( pCsr->apPage[pCsr->iPage]->intKey ); + assert( pCsr->pPage==pCsr->apPage[pCsr->iPage] ); return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); } /* Index: src/btreeInt.h ================================================================== --- src/btreeInt.h +++ src/btreeInt.h @@ -516,10 +516,11 @@ u8 curFlags; /* zero or more BTCF_* flags defined below */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ u8 hints; /* As configured by CursorSetHints() */ i16 iPage; /* Index of current page in apPage */ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ + MemPage *pPage; /* Current page */ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ }; /* ** Legal values for BtCursor.curFlags