** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.691 2009/07/16 18:21:18 drh Exp $
+** $Id: btree.c,v 1.692 2009/07/20 17:11:50 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
**
** This routine updates the pointer map entry for page number 'key'
** so that it maps to type 'eType' and parent page number 'pgno'.
-** An error code is returned if something goes wrong, otherwise SQLITE_OK.
+**
+** If *pRC is initially non-zero (non-SQLITE_OK) then this routine is
+** a no-op. If an error occurs, the appropriate error code is written
+** into *pRC.
*/
-static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
+static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
DbPage *pDbPage; /* The pointer map page */
u8 *pPtrmap; /* The pointer map data */
Pgno iPtrmap; /* The pointer map page number */
int offset; /* Offset in pointer map page */
- int rc;
+ int rc; /* Return code from subfunctions */
+
+ if( *pRC ) return;
assert( sqlite3_mutex_held(pBt->mutex) );
/* The master-journal page number must never be used as a pointer map page */
assert( pBt->autoVacuum );
if( key==0 ){
- return SQLITE_CORRUPT_BKPT;
+ *pRC = SQLITE_CORRUPT_BKPT;
+ return;
}
iPtrmap = PTRMAP_PAGENO(pBt, key);
rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
if( rc!=SQLITE_OK ){
- return rc;
+ *pRC = rc;
+ return;
}
offset = PTRMAP_PTROFFSET(iPtrmap, key);
if( offset<0 ){
- rc = SQLITE_CORRUPT_BKPT;
+ *pRC = SQLITE_CORRUPT_BKPT;
goto ptrmap_exit;
}
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
- rc = sqlite3PagerWrite(pDbPage);
+ *pRC= rc = sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
put4byte(&pPtrmap[offset+1], parent);
ptrmap_exit:
sqlite3PagerUnref(pDbPage);
- return rc;
}
/*
}
#else /* if defined SQLITE_OMIT_AUTOVACUUM */
- #define ptrmapPut(w,x,y,z) SQLITE_OK
+ #define ptrmapPut(w,x,y,z,rc)
#define ptrmapGet(w,x,y,z) SQLITE_OK
- #define ptrmapPutOvflPtr(x, y) SQLITE_OK
+ #define ptrmapPutOvflPtr(x, y, rc)
#endif
/*
** to an overflow page, insert an entry into the pointer-map
** for the overflow page.
*/
-static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){
+static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
CellInfo info;
+ if( *pRC ) return;
assert( pCell!=0 );
btreeParseCellPtr(pPage, pCell, &info);
assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( info.iOverflow ){
Pgno ovfl = get4byte(&pCell[info.iOverflow]);
- return ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno);
+ ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
}
- return SQLITE_OK;
}
#endif
for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i);
- rc = ptrmapPutOvflPtr(pPage, pCell);
- if( rc!=SQLITE_OK ){
- goto set_child_ptrmaps_out;
- }
+ ptrmapPutOvflPtr(pPage, pCell, &rc);
if( !pPage->leaf ){
Pgno childPgno = get4byte(pCell);
- rc = ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno);
- if( rc!=SQLITE_OK ) goto set_child_ptrmaps_out;
+ ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc);
}
}
if( !pPage->leaf ){
Pgno childPgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- rc = ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno);
+ ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc);
}
set_child_ptrmaps_out:
}else{
Pgno nextOvfl = get4byte(pDbPage->aData);
if( nextOvfl!=0 ){
- rc = ptrmapPut(pBt, nextOvfl, PTRMAP_OVERFLOW2, iFreePage);
+ ptrmapPut(pBt, nextOvfl, PTRMAP_OVERFLOW2, iFreePage, &rc);
if( rc!=SQLITE_OK ){
return rc;
}
rc = modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType);
releasePage(pPtrPage);
if( rc==SQLITE_OK ){
- rc = ptrmapPut(pBt, iFreePage, eType, iPtrPage);
+ ptrmapPut(pBt, iFreePage, eType, iPtrPage, &rc);
}
}
return rc;
** to indicate that the page is free.
*/
if( ISAUTOVACUUM ){
- rc = ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0);
+ ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc);
if( rc ) goto freepage_out;
}
*/
if( pBt->autoVacuum && rc==SQLITE_OK ){
u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1);
- rc = ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap);
+ ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap, &rc);
if( rc ){
releasePage(pOvfl);
}
**
** "sz" must be the number of bytes in the cell.
*/
-static int dropCell(MemPage *pPage, int idx, int sz){
+static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
int i; /* Loop counter */
int pc; /* Offset to cell content of cell being deleted */
u8 *data; /* pPage->aData */
u8 *ptr; /* Used to move bytes around within data[] */
int rc; /* The return code */
+ if( *pRC ) return;
+
assert( idx>=0 && idx<pPage->nCell );
assert( sz==cellSize(pPage, idx) );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
pc = get2byte(ptr);
if( (pc<pPage->hdrOffset+6+pPage->childPtrSize)
|| (pc+sz>pPage->pBt->usableSize) ){
- return SQLITE_CORRUPT_BKPT;
+ *pRC = SQLITE_CORRUPT_BKPT;
+ return;
}
rc = freeSpace(pPage, pc, sz);
- if( rc!=SQLITE_OK ){
- return rc;
+ if( rc ){
+ *pRC = rc;
+ return;
}
for(i=idx+1; i<pPage->nCell; i++, ptr+=2){
ptr[0] = ptr[2];
pPage->nCell--;
put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
pPage->nFree += 2;
- return SQLITE_OK;
}
/*
** nSkip is non-zero, then pCell may not point to an invalid memory location
** (but pCell+nSkip is always valid).
*/
-static int insertCell(
+static void insertCell(
MemPage *pPage, /* Page into which we are copying */
int i, /* New cell becomes the i-th cell of the page */
u8 *pCell, /* Content of the new cell */
int sz, /* Bytes of content in pCell */
u8 *pTemp, /* Temp storage space for pCell, if needed */
- Pgno iChild /* If non-zero, replace first 4 bytes with this value */
+ Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
+ int *pRC /* Read and write return code from here */
){
int idx; /* Where to write new cell content in data[] */
int j; /* Loop counter */
int nSkip = (iChild ? 4 : 0);
+ if( *pRC ) return;
+
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=5460 );
assert( pPage->nOverflow<=ArraySize(pPage->aOvfl) );
}else{
int rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc!=SQLITE_OK ){
- return rc;
+ *pRC = rc;
+ return;
}
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
data = pPage->aData;
end = cellOffset + 2*pPage->nCell;
ins = cellOffset + 2*i;
rc = allocateSpace(pPage, sz, &idx);
- if( rc ) return rc;
+ if( rc ){ *pRC = rc; return; }
assert( idx>=end+2 );
if( idx+sz > pPage->pBt->usableSize ){
- return SQLITE_CORRUPT_BKPT;
+ *pRC = SQLITE_CORRUPT_BKPT;
+ return;
}
pPage->nCell++;
pPage->nFree -= (u16)(2 + sz);
/* The cell may contain a pointer to an overflow page. If so, write
** the entry for the overflow page into the pointer map.
*/
- return ptrmapPutOvflPtr(pPage, pCell);
+ ptrmapPutOvflPtr(pPage, pCell, pRC);
}
#endif
}
-
- return SQLITE_OK;
}
/*
** rollback, undoing any changes made to the parent page.
*/
if( ISAUTOVACUUM ){
- rc = ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno);
- if( szCell>pNew->minLocal && rc==SQLITE_OK ){
- rc = ptrmapPutOvflPtr(pNew, pCell);
+ ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
+ if( szCell>pNew->minLocal ){
+ ptrmapPutOvflPtr(pNew, pCell, &rc);
}
}
while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop );
/* Insert the new divider cell into pParent. */
- insertCell(pParent,pParent->nCell,pSpace,(int)(pOut-pSpace),0,pPage->pgno);
+ insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
+ 0, pPage->pgno, &rc);
/* Set the right-child pointer of pParent to point to the new page. */
put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
memcpy(&aOvflSpace[apDiv[i]-pParent->aData], apDiv[i], szNew[i]);
apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
#endif
- dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i]);
+ dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc);
}
}
/* Set the pointer-map entry for the new sibling page. */
if( ISAUTOVACUUM ){
- rc = ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno);
+ ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
}
iOvflSpace += sz;
assert( sz<=pBt->pageSize/4 );
assert( iOvflSpace<=pBt->pageSize );
- rc = insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno);
+ insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc);
if( rc!=SQLITE_OK ) goto balance_cleanup;
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
** with any child or overflow pages need to be updated. */
if( isDivider || pOld->pgno!=pNew->pgno ){
if( !leafCorrection ){
- rc = ptrmapPut(pBt, get4byte(apCell[i]), PTRMAP_BTREE, pNew->pgno);
+ ptrmapPut(pBt, get4byte(apCell[i]), PTRMAP_BTREE, pNew->pgno, &rc);
}
- if( szCell[i]>pNew->minLocal && rc==SQLITE_OK ){
- rc = ptrmapPutOvflPtr(pNew, apCell[i]);
+ if( szCell[i]>pNew->minLocal ){
+ ptrmapPutOvflPtr(pNew, apCell[i], &rc);
}
}
}
if( !leafCorrection ){
- for(i=0; rc==SQLITE_OK && i<nNew; i++){
- rc = ptrmapPut(
- pBt, get4byte(&apNew[i]->aData[8]), PTRMAP_BTREE, apNew[i]->pgno);
+ for(i=0; i<nNew; i++){
+ u32 key = get4byte(&apNew[i]->aData[8]);
+ ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc);
}
}
** page that will become the new right-child of pPage. Copy the contents
** of the node stored on pRoot into the new child page.
*/
- if( SQLITE_OK!=(rc = sqlite3PagerWrite(pRoot->pDbPage))
- || SQLITE_OK!=(rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0))
- || SQLITE_OK!=(rc = copyNodeContent(pRoot, pChild))
- || (ISAUTOVACUUM &&
- SQLITE_OK!=(rc = ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno)))
- ){
+ rc = sqlite3PagerWrite(pRoot->pDbPage);
+ if( rc==SQLITE_OK ){
+ rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
+ if( rc==SQLITE_OK ){
+ rc = copyNodeContent(pRoot, pChild);
+ if( ISAUTOVACUUM ){
+ ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
+ }
+ }
+ }
+ if( rc ){
*ppChild = 0;
releasePage(pChild);
return rc;
unsigned char *oldCell;
unsigned char *newCell = 0;
+ if( pCur->eState==CURSOR_FAULT ){
+ assert( pCur->skipNext!=SQLITE_OK );
+ return pCur->skipNext;
+ }
+
assert( cursorHoldsMutex(pCur) );
assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE && !pBt->readOnly );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
invalidateIncrblobCursors(p, pCur->pgnoRoot, nKey, 0);
}
- if( pCur->eState==CURSOR_FAULT ){
- assert( pCur->skipNext!=SQLITE_OK );
- return pCur->skipNext;
- }
-
/* Save the positions of any other cursors open on this table.
**
** In some cases, the call to btreeMoveto() below is a no-op. For
}
szOld = cellSizePtr(pPage, oldCell);
rc = clearCell(pPage, oldCell);
+ dropCell(pPage, idx, szOld, &rc);
if( rc ) goto end_insert;
- rc = dropCell(pPage, idx, szOld);
- if( rc!=SQLITE_OK ) {
- goto end_insert;
- }
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
idx = ++pCur->aiIdx[pCur->iPage];
}else{
assert( pPage->leaf );
}
- rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
+ insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
/* If no error has occured and pPage has an overflow cell, call balance()
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
rc = clearCell(pPage, pCell);
- if( rc ) return rc;
- rc = dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell));
+ dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc);
if( rc ) return rc;
/* If the cell deleted was not located on a leaf page, then the cursor
pTmp = pBt->pTmpSpace;
rc = sqlite3PagerWrite(pLeaf->pDbPage);
- if( rc ) return rc;
- rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n);
- if( rc ) return rc;
- rc = dropCell(pLeaf, pLeaf->nCell-1, nCell);
+ insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
+ dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
if( rc ) return rc;
}
}
/* Update the pointer-map and meta-data with the new root-page number. */
- rc = ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0);
+ ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc);
if( rc ){
releasePage(pRoot);
return rc;