diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/btree.c b/src/btree.c index 700138efc..0a8c17221 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8152,6 +8152,83 @@ static int balance(BtCursor *pCur){ return rc; } +/* Overwrite content from pX into pDest. Only do the write if the +** content is different from what is already there. +*/ +static int btreeOverwriteContent( + MemPage *pPage, /* MemPage on which writing will occur */ + u8 *pDest, /* Pointer to the place to start writing */ + const BtreePayload *pX, /* Source of data to write */ + int iOffset, /* Offset of first byte to write */ + int iAmt /* Number of bytes to be written */ +){ + int nData = pX->nData - iOffset; + if( nData<=0 ){ + /* Overwritting with zeros */ + int i; + for(i=0; i<iAmt && pDest[i]==0; i++){} + if( i<iAmt ){ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + memset(pDest + i, 0, iAmt - i); + } + }else{ + if( nData<iAmt ){ + /* Mixed read data and zeros at the end. Make a recursive call + ** to write the zeros then fall through to write the real data */ + btreeOverwriteContent(pPage, pDest+nData, pX, iOffset+nData, iAmt-nData); + iAmt = nData; + } + if( memcmp(pDest, ((u8*)pX->pData) + iOffset, iAmt)!=0 ){ + int rc = sqlite3PagerWrite(pPage->pDbPage); + if( rc ) return rc; + memcpy(pDest, ((u8*)pX->pData) + iOffset, iAmt); + } + } + return SQLITE_OK; +} + +/* +** Overwrite the cell that cursor pCur is pointing to with fresh content +** contained in pX. +*/ +static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){ + int iOffset; /* Next byte of pX->pData to write */ + int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */ + int rc; /* Return code */ + MemPage *pPage = pCur->pPage; /* Page being written */ + BtShared *pBt; /* Btree */ + Pgno ovflPgno; /* Next overflow page to write */ + u32 ovflPageSize; /* Size to write on overflow page */ + + /* Overwrite the local portion first */ + rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX, + 0, pCur->info.nLocal); + if( rc ) return rc; + if( pCur->info.nLocal==nTotal ) return SQLITE_OK; + + /* Now overwrite the overflow pages */ + iOffset = pCur->info.nLocal; + ovflPgno = get4byte(pCur->info.pPayload + iOffset); + pBt = pPage->pBt; + ovflPageSize = pBt->usableSize - 4; + do{ + rc = btreeGetPage(pBt, ovflPgno, &pPage, 0); + if( rc ) return rc; + if( iOffset+ovflPageSize>nTotal ){ + ovflPgno = get4byte(pPage->aData + ovflPageSize); + }else{ + ovflPageSize = nTotal - iOffset; + } + rc = btreeOverwriteContent(pPage, pPage->aData, pX, + iOffset, ovflPageSize); + if( rc ) return rc; + iOffset += ovflPageSize; + sqlite3PagerUnref(pPage->pDbPage); + }while( iOffset<nTotal ); + return SQLITE_OK; +} + /* ** Insert a new record into the BTree. The content of the new record @@ -8250,6 +8327,11 @@ int sqlite3BtreeInsert( ** new row onto the end, set the "loc" to avoid an unnecessary ** btreeMoveto() call */ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){ + /* The current is currently pointing to the entry that is to be + ** overwritten */ + if( pCur->info.nPayload==pX->nData+pX->nZero ){ + return btreeOverwriteCell(pCur, pX); + } loc = 0; }else if( loc==0 ){ rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc); |