1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Btree optimization: New field BtCursor.pPage that points to the current page,

saving a single pointer dereference on each access.

FossilOrigin-Name: 373b71d19cad785922d5a80828f2fee0cbe7dff6594743e625bbdfa31b1ca131
This commit is contained in:
drh
2017-08-15 03:46:47 +00:00
parent f38dd3b68f
commit 352a35abf5
4 changed files with 103 additions and 84 deletions

View File

@@ -439,7 +439,8 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
#endif /* SQLITE_OMIT_SHARED_CACHE */
static void releasePage(MemPage *pPage); /* Forward reference */
static void releasePage(MemPage *pPage);
static void releasePageNotNull(MemPage *pPage); /* Forward reference */
/*
***** This routine is used inside of assert() only ****
@@ -598,11 +599,13 @@ static void btreeClearHasContent(BtShared *pBt){
*/
static void btreeReleaseAllCursorPages(BtCursor *pCur){
int i;
for(i=0; i<=pCur->iPage; i++){
releasePage(pCur->apPage[i]);
pCur->apPage[i] = 0;
if( pCur->iPage>=0 ){
for(i=0; i<pCur->iPage; i++){
releasePageNotNull(pCur->apPage[i]);
}
releasePageNotNull(pCur->pPage);
pCur->iPage = -1;
}
pCur->iPage = -1;
}
/*
@@ -771,7 +774,7 @@ static int btreeMoveto(
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
rc = SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
rc = SQLITE_CORRUPT;
goto moveto_done;
}
}else{
@@ -2049,7 +2052,7 @@ static int getAndInitPage(
int rc;
DbPage *pDbPage;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
assert( pCur==0 || ppPage==&pCur->pPage );
assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
assert( pCur==0 || pCur->iPage>0 );
@@ -2083,7 +2086,10 @@ static int getAndInitPage(
return SQLITE_OK;
getAndInitPage_error:
if( pCur ) pCur->iPage--;
if( pCur ){
pCur->iPage--;
pCur->pPage = pCur->apPage[pCur->iPage];
}
testcase( pgno==0 );
assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
@@ -4293,7 +4299,6 @@ void sqlite3BtreeCursorZero(BtCursor *p){
int sqlite3BtreeCloseCursor(BtCursor *pCur){
Btree *pBtree = pCur->pBtree;
if( pBtree ){
int i;
BtShared *pBt = pCur->pBt;
sqlite3BtreeEnter(pBtree);
assert( pBt->pCursor!=0 );
@@ -4309,9 +4314,7 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
pPrev = pPrev->pNext;
}while( ALWAYS(pPrev) );
}
for(i=0; i<=pCur->iPage; i++){
releasePageNotNull(pCur->apPage[i]);
}
btreeReleaseAllCursorPages(pCur);
unlockBtreeIfUnused(pBt);
sqlite3_free(pCur->aOverflow);
sqlite3_free(pCur->pKey);
@@ -4331,9 +4334,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#ifndef NDEBUG
static void assertCellInfo(BtCursor *pCur){
CellInfo info;
int iPage = pCur->iPage;
memset(&info, 0, sizeof(info));
btreeParseCell(pCur->apPage[iPage], pCur->ix, &info);
btreeParseCell(pCur->pPage, pCur->ix, &info);
assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
}
#else
@@ -4341,9 +4343,8 @@ int sqlite3BtreeCloseCursor(BtCursor *pCur){
#endif
static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
int iPage = pCur->iPage;
pCur->curFlags |= BTCF_ValidNKey;
btreeParseCell(pCur->apPage[iPage],pCur->ix,&pCur->info);
btreeParseCell(pCur->pPage,pCur->ix,&pCur->info);
}else{
assertCellInfo(pCur);
}
@@ -4541,7 +4542,7 @@ static int accessPayload(
unsigned char *aPayload;
int rc = SQLITE_OK;
int iIdx = 0;
MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
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; /* Start of original out buffer */
@@ -4737,8 +4738,8 @@ static int accessPayload(
int sqlite3BtreePayload(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->ix<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->iPage>=0 && pCur->pPage );
assert( pCur->ix<pCur->pPage->nCell );
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
@@ -4796,15 +4797,15 @@ static const void *fetchPayload(
u32 *pAmt /* Write the number of available bytes here */
){
u32 amt;
assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorOwnsBtShared(pCur) );
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->info.nSize>0 );
assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
assert( pCur->info.pPayload<pCur->apPage[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.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
amt = (int)(pCur->pPage->aDataEnd - pCur->info.pPayload);
if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
*pAmt = amt;
return (void*)pCur->info.pPayload;
@@ -4851,10 +4852,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
}
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->aiIdx[pCur->iPage++] = pCur->ix;
pCur->aiIdx[pCur->iPage] = pCur->ix;
pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
pCur, pCur->curPagerFlags);
pCur->iPage++;
return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
}
#ifdef SQLITE_DEBUG
@@ -4888,20 +4890,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
MemPage *pLeaf;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
assert( pCur->apPage[pCur->iPage] );
assert( pCur->pPage );
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 );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
pCur->ix = pCur->aiIdx[pCur->iPage-1];
releasePageNotNull(pCur->apPage[pCur->iPage--]);
pLeaf = pCur->pPage;
pCur->pPage = pCur->apPage[--pCur->iPage];
releasePageNotNull(pLeaf);
}
/*
@@ -4938,10 +4943,11 @@ static int moveToRoot(BtCursor *pCur){
if( pCur->iPage>=0 ){
if( pCur->iPage ){
do{
assert( pCur->apPage[pCur->iPage]!=0 );
releasePageNotNull(pCur->apPage[pCur->iPage--]);
}while( pCur->iPage);
releasePageNotNull(pCur->pPage);
while( --pCur->iPage ){
releasePageNotNull(pCur->apPage[pCur->iPage]);
}
pCur->pPage = pCur->apPage[0];
goto skip_init;
}
}else if( pCur->pgnoRoot==0 ){
@@ -4956,16 +4962,16 @@ static int moveToRoot(BtCursor *pCur){
}
sqlite3BtreeClearCursor(pCur);
}
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
}
pCur->iPage = 0;
pCur->curIntKey = pCur->apPage[0]->intKey;
pCur->curIntKey = pCur->pPage->intKey;
}
pRoot = pCur->apPage[0];
pRoot = pCur->pPage;
assert( pRoot->pgno==pCur->pgnoRoot );
/* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
@@ -4980,7 +4986,7 @@ static int moveToRoot(BtCursor *pCur){
** (or the freelist). */
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
return SQLITE_CORRUPT_PGNO(pCur->apPage[pCur->iPage]->pgno);
return SQLITE_CORRUPT_PGNO(pCur->pPage->pgno);
}
skip_init:
@@ -4988,7 +4994,7 @@ skip_init:
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
pRoot = pCur->apPage[0];
pRoot = pCur->pPage;
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
@@ -5018,7 +5024,7 @@ static int moveToLeftmost(BtCursor *pCur){
assert( cursorOwnsBtShared(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->ix<pPage->nCell );
pgno = get4byte(findCell(pPage, pCur->ix));
rc = moveToChild(pCur, pgno);
@@ -5043,7 +5049,7 @@ static int moveToRightmost(BtCursor *pCur){
assert( cursorOwnsBtShared(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->ix = pPage->nCell;
rc = moveToChild(pCur, pgno);
@@ -5066,11 +5072,11 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
assert( pCur->apPage[pCur->iPage]->nCell>0 );
assert( pCur->pPage->nCell>0 );
*pRes = 0;
rc = moveToLeftmost(pCur);
}else if( rc==SQLITE_EMPTY ){
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
*pRes = 1;
rc = SQLITE_OK;
}
@@ -5096,8 +5102,8 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
for(ii=0; ii<pCur->iPage; ii++){
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
}
assert( pCur->ix==pCur->apPage[pCur->iPage]->nCell-1 );
assert( pCur->apPage[pCur->iPage]->leaf );
assert( pCur->ix==pCur->pPage->nCell-1 );
assert( pCur->pPage->leaf );
#endif
return SQLITE_OK;
}
@@ -5113,7 +5119,7 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
pCur->curFlags &= ~BTCF_AtLast;
}
}else if( rc==SQLITE_EMPTY ){
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
*pRes = 1;
rc = SQLITE_OK;
}
@@ -5215,22 +5221,22 @@ int sqlite3BtreeMovetoUnpacked(
rc = moveToRoot(pCur);
if( rc ){
if( rc==SQLITE_EMPTY ){
assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
*pRes = -1;
return SQLITE_OK;
}
return rc;
}
assert( pCur->apPage[pCur->iPage] );
assert( pCur->apPage[pCur->iPage]->isInit );
assert( pCur->pPage );
assert( pCur->pPage->isInit );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->apPage[pCur->iPage]->nCell > 0 );
assert( pCur->apPage[0]->intKey==pCur->curIntKey );
assert( pCur->pPage->nCell > 0 );
assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
assert( pCur->curIntKey || 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
@@ -5369,7 +5375,7 @@ int sqlite3BtreeMovetoUnpacked(
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->ix<pCur->pPage->nCell );
pCur->ix = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
@@ -5423,9 +5429,10 @@ i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
** opcode, and it that case the cursor will always be valid and
** will always point to a leaf node. */
if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
if( NEVER(pCur->apPage[pCur->iPage]->leaf==0) ) return -1;
if( NEVER(pCur->pPage->leaf==0) ) return -1;
for(n=1, i=0; i<=pCur->iPage; i++){
n = pCur->pPage->nCell;
for(i=0; i<pCur->iPage; i++){
n *= pCur->apPage[i]->nCell;
}
return n;
@@ -5478,7 +5485,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
}
}
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
idx = ++pCur->ix;
assert( pPage->isInit );
@@ -5501,7 +5508,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
return SQLITE_DONE;
}
moveToParent(pCur);
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
}while( pCur->ix>=pPage->nCell );
if( pPage->intKey ){
return sqlite3BtreeNext(pCur, 0);
@@ -5524,7 +5531,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int flags){
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur);
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
if( (++pCur->ix)>=pPage->nCell ){
pCur->ix--;
return btreeNext(pCur);
@@ -5583,7 +5590,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
}
}
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
assert( pPage->isInit );
if( !pPage->leaf ){
int idx = pCur->ix;
@@ -5602,7 +5609,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
pCur->ix--;
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
if( pPage->intKey && !pPage->leaf ){
rc = sqlite3BtreePrevious(pCur, 0);
}else{
@@ -5620,7 +5627,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int flags){
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
|| pCur->ix==0
|| pCur->apPage[pCur->iPage]->leaf==0
|| pCur->pPage->leaf==0
){
return btreePrevious(pCur);
}
@@ -7934,7 +7941,7 @@ static int balance(BtCursor *pCur){
do {
int iPage = pCur->iPage;
MemPage *pPage = pCur->apPage[iPage];
MemPage *pPage = pCur->pPage;
if( iPage==0 ){
if( pPage->nOverflow ){
@@ -7950,7 +7957,9 @@ static int balance(BtCursor *pCur){
pCur->iPage = 1;
pCur->ix = 0;
pCur->aiIdx[0] = 0;
assert( pCur->apPage[1]->nOverflow );
pCur->apPage[0] = pPage;
pCur->pPage = pCur->apPage[1];
assert( pCur->pPage->nOverflow );
}
}else{
break;
@@ -8030,6 +8039,7 @@ static int balance(BtCursor *pCur){
releasePage(pPage);
pCur->iPage--;
assert( pCur->iPage>=0 );
pCur->pPage = pCur->apPage[pCur->iPage];
}
}while( rc==SQLITE_OK );
@@ -8161,7 +8171,7 @@ int sqlite3BtreeInsert(
}
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
@@ -8248,7 +8258,7 @@ int sqlite3BtreeInsert(
** 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;
pCur->pPage->nOverflow = 0;
pCur->eState = CURSOR_INVALID;
if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){
btreeReleaseAllCursorPages(pCur);
@@ -8265,7 +8275,7 @@ int sqlite3BtreeInsert(
pCur->nKey = pX->nKey;
}
}
assert( pCur->iPage<0 || pCur->apPage[pCur->iPage]->nOverflow==0 );
assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 );
end_insert:
return rc;
@@ -8306,13 +8316,13 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
assert( pCur->ix<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->eState==CURSOR_VALID );
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
iCellDepth = pCur->iPage;
iCellIdx = pCur->ix;
pPage = pCur->apPage[iCellDepth];
pPage = pCur->pPage;
pCell = findCell(pPage, iCellIdx);
/* If the bPreserve flag is set to true, then the cursor position must
@@ -8378,11 +8388,16 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** 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;
Pgno n;
unsigned char *pTmp;
if( iCellDepth<pCur->iPage-1 ){
n = pCur->apPage[iCellDepth+1]->pgno;
}else{
n = pCur->pPage->pgno;
}
pCell = findCell(pLeaf, pLeaf->nCell-1);
if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
nCell = pLeaf->xCellSize(pLeaf, pCell);
@@ -8414,16 +8429,19 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** well. */
rc = balance(pCur);
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
releasePageNotNull(pCur->pPage);
pCur->iPage--;
while( pCur->iPage>iCellDepth ){
releasePage(pCur->apPage[pCur->iPage--]);
}
pCur->pPage = pCur->apPage[pCur->iPage];
rc = balance(pCur);
}
if( rc==SQLITE_OK ){
if( bSkipnext ){
assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB );
assert( pPage==pCur->pPage || CORRUPT_DB );
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
pCur->eState = CURSOR_SKIPNEXT;
if( iCellIdx>=pPage->nCell ){
@@ -8920,7 +8938,7 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
** this page contains countable entries. Increment the entry counter
** accordingly.
*/
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
if( pPage->leaf || !pPage->intKey ){
nEntry += pPage->nCell;
}
@@ -8943,10 +8961,10 @@ int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
return moveToRoot(pCur);
}
moveToParent(pCur);
}while ( pCur->ix>=pCur->apPage[pCur->iPage]->nCell );
}while ( pCur->ix>=pCur->pPage->nCell );
pCur->ix++;
pPage = pCur->apPage[pCur->iPage];
pPage = pCur->pPage;
}
/* Descend to the child node of the cell that the cursor currently
@@ -9787,7 +9805,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
&& 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->intKey );
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
}