From: drh Date: Thu, 3 May 2018 03:59:02 +0000 (+0000) Subject: The sqlite3BtreeInsert() routine tries to overwrite an existing cell with X-Git-Tag: version-3.24.0~61^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3de5d16cf7df698599136d4a6695c97dbb603c2d;p=thirdparty%2Fsqlite.git The sqlite3BtreeInsert() routine tries to overwrite an existing cell with modified content if the new content is the same size. Pages are only dirtied if they change. This prototype works some, but still has issues. FossilOrigin-Name: 489451b378819621537231c1c8a07704437e11c1f5384fd53b09f3977d2213a4 --- 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);