diff --git a/manifest b/manifest index 866465edaf..734d14e6c0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Prevent\sVACUUM\sfrom\srunning\sany\scommands\sin\ssqlite_master.sql\sother\sthan\nCREATE\sstatements.\s\sThat\sis\sall\sthat\sshould\sbe\sthere\sanyhow.\s\sThis\sfixes\na\sproblem\sdiscovered\sby\sOSSFuzz.\s\sTest\scases\sin\sTH3. -D 2018-05-02T15:00:26.033 +C The\ssqlite3BtreeInsert()\sroutine\stries\sto\soverwrite\san\sexisting\scell\swith\nmodified\scontent\sif\sthe\snew\scontent\sis\sthe\ssame\ssize.\s\sPages\sare\sonly\sdirtied\nif\sthey\schange.\s\sThis\sprototype\sworks\ssome,\sbut\sstill\shas\sissues. +D 2018-05-03T03:59:02.523 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 5ce9343cba9c189046f1afe6d2bcc1f68079439febc05267b98aec6ecc752439 @@ -434,7 +434,7 @@ F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73 F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c fa7da0a5584e5182b92536bc4b7622a154a468997a075d5901345efb79a05ffe +F src/btree.c d1b1bd0602381cd668fefdc21bb376083d34a202c7f978ddd6cdfe8b576880fa F src/btree.h 0866c0a08255142ea0e754aabd211c843cab32045c978a592a43152405ed0c84 F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96 F src/build.c 0c2be5839f22aa2938f217c6c6c2120d9fc96872a546a37541a8271541cb355e @@ -1727,7 +1727,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0c67150749cb3d067e14b2dcac9c3489e0f14bd18c0387f1d9bc93d21fc96fe5 -R 05ae73916277803fcebbb023b759986c +P ab0d99d0b5edece4c639baa47ce1ca2c02774cb2515e5b7f36d9bd312ccd3310 +R d19653c30e874527a8180a99ea6a4aad +T *branch * cell-overwrite-prototype +T *sym-cell-overwrite-prototype * +T -sym-trunk * U drh -Z 0a57dfa0969cac36c6f9349555316be2 +Z 4db008fe8cce4e65f98c2fd1a101b30c diff --git a/manifest.uuid b/manifest.uuid index 1f86bdd5bb..44cef5c9c1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ab0d99d0b5edece4c639baa47ce1ca2c02774cb2515e5b7f36d9bd312ccd3310 \ No newline at end of file +489451b378819621537231c1c8a07704437e11c1f5384fd53b09f3977d2213a4 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 700138efca..0a8c172212 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; ipDbPage); + if( rc ) return rc; + memset(pDest + i, 0, iAmt - i); + } + }else{ + if( nDatapData) + 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( iOffsetcurFlags&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);