]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The sqlite3BtreeInsert() routine tries to overwrite an existing cell with
authordrh <drh@noemail.net>
Thu, 3 May 2018 03:59:02 +0000 (03:59 +0000)
committerdrh <drh@noemail.net>
Thu, 3 May 2018 03:59:02 +0000 (03:59 +0000)
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

manifest
manifest.uuid
src/btree.c

index 866465edaf32e98fe925a38c9e91384d6b0c9c19..734d14e6c0771e7e70a96e0119e855e658cb4573 100644 (file)
--- 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
index 1f86bdd5bb3f91f5f0233678c6752fe7a6e22af1..44cef5c9c189cfe3ff7f3f2b74c44cd051a9db69 100644 (file)
@@ -1 +1 @@
-ab0d99d0b5edece4c639baa47ce1ca2c02774cb2515e5b7f36d9bd312ccd3310
\ No newline at end of file
+489451b378819621537231c1c8a07704437e11c1f5384fd53b09f3977d2213a4
\ No newline at end of file
index 700138efca82329cbde5158755e3859e70fdd298..0a8c172212ba4e061146fca183116b696eac8f72 100644 (file)
@@ -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);