]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Split the sqlite3BtreeMovetoUnpacked() routine into two separate routines
authordrh <>
Sat, 19 Jun 2021 18:32:20 +0000 (18:32 +0000)
committerdrh <>
Sat, 19 Jun 2021 18:32:20 +0000 (18:32 +0000)
sqlite3BtreeTableMoveto() and sqlite3BtreeIndexMoveto(), since we usually
know the type of btree in advance.  This results in less branching and
better performance.

FossilOrigin-Name: 3b0d34e5e5f9a16c3397e4551f3b534729b1b375770f05f6ed5847818b1f4c0b

manifest
manifest.uuid
src/btree.c
src/btree.h
src/vdbe.c
src/vdbeaux.c

index 2a6b8f404f26ff8c2e92d8ab2aa4844962fcc6a0..2e837545680c09447ed12c394842530dc25340f0 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Version\s3.36.0
-D 2021-06-18T18:36:39.378
+C Split\sthe\ssqlite3BtreeMovetoUnpacked()\sroutine\sinto\stwo\sseparate\sroutines\nsqlite3BtreeTableMoveto()\sand\ssqlite3BtreeIndexMoveto(),\ssince\swe\susually\nknow\sthe\stype\sof\sbtree\sin\sadvance.\s\sThis\sresults\sin\sless\sbranching\sand\nbetter\sperformance.
+D 2021-06-19T18:32:20.087
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -485,8 +485,8 @@ F src/auth.c 08954fdc4cc2da5264ba5b75cfd90b67a6fc7d1710a02ccf917c38eadec77853
 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
 F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c 399e1ebcd6c4f9ad47f5457bfe3623441db287f0923433cf6539497791557be8
-F src/btree.h 096cc53baa58be22b02c896d1cf933c38cfc6d65f9253c1367ece8cc88a24de5
+F src/btree.c 6079ee9dc399a7a6f0727f2c6ba2f43c18600c71827a76ddcdedde54a58b646e
+F src/btree.h ace9c1c243612bb95c32d848e3f9e159340c2caefcb68412b441569f56328f65
 F src/btreeInt.h 7bc15a24a02662409ebcd6aeaa1065522d14b7fda71573a2b0568b458f514ae0
 F src/build.c ea28944f65b04f771e7aa5d614d406faa1bde5fe4ce882e2ead73049f03ed568
 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
@@ -616,11 +616,11 @@ F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
 F src/util.c 41c7a72da1df47864faa378a1c720b38adb288c6838cb6be5594511b6287a048
 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286
-F src/vdbe.c 6ece0ee94fa3a95601372efdc4ec6d068cd6cc58e28af8852f3407b90be4b7f8
+F src/vdbe.c 226deb5bc5d88c4feb215cccaecdbe36924078737f27629fa06123d4da10f609
 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe
 F src/vdbeInt.h 465fcb494db4ca6630fb9c19b2f3dfed597fbe885b0d4204193a5093b0dd7dc6
 F src/vdbeapi.c aa5aaf2c37676b83af5724c6cd8207a3064ed46a217fd180957f75ac84f7a2a5
-F src/vdbeaux.c 065a10392378109f08435bd50d03dff315e384cde2831d6b8dbaec05f33b10af
+F src/vdbeaux.c 17e5f6a491d439396296dd20427829fad14c78a6be8f84415d253ff94c31ce9a
 F src/vdbeblob.c c6b8db50b227f66fb404215732068df76485b5b433e5f9d4d9ac27410b218193
 F src/vdbemem.c 53881aa0a7845922a075b3f375695588618098871a7a4120af4c297b80fa3e64
 F src/vdbesort.c cd5130f683706c1a43e165a74187745fb3351cb56052cf9dc91de820634bbde2
@@ -1918,9 +1918,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 7bd55eee1ac63cf6d5699ce85bc5a29bf51afdf7a80bce44937fa833947a40f4
-R 6b8a0a7cf847af9edb1fb9387491b821
-T +sym-release *
-T +sym-version-3.36.0 *
+P 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5
+R cc13a86c593d747f18b1766f1996fa8f
 U drh
-Z 05ee2bbc3eef4148ab2800c954a168c4
+Z 15ce4941abcea77bc0d9552f8406032e
index ccffbad5d95c29d60a7533df12f4c30e36042bb3..6d434249771a049491eb856913167aeb5610f690 100644 (file)
@@ -1 +1 @@
-5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5
\ No newline at end of file
+3b0d34e5e5f9a16c3397e4551f3b534729b1b375770f05f6ed5847818b1f4c0b
\ No newline at end of file
index d1e84d0a604a1e769f1044eba631f40fdc75d18a..12d07dcc01f265b868f493a3e67cbbaa3114f65c 100644 (file)
@@ -827,15 +827,13 @@ static int btreeMoveto(
     sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey);
     if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){
       rc = SQLITE_CORRUPT_BKPT;
-      goto moveto_done;
+    }else{
+      rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes);
     }
+    sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
   }else{
     pIdxKey = 0;
-  }
-  rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
-moveto_done:
-  if( pIdxKey ){
-    sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
+    rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes);
   }
   return rc;
 }
@@ -5421,12 +5419,8 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
   return rc;
 }
 
-/* Move the cursor so that it points to an entry near the key 
-** specified by pIdxKey or intKey.   Return a success code.
-**
-** For INTKEY tables, the intKey parameter is used.  pIdxKey 
-** must be NULL.  For index tables, pIdxKey is used and intKey
-** is ignored.
+/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY)
+** table near the key intKey.   Return a success code.
 **
 ** If an exact match is not found, then the cursor is always
 ** left pointing at a leaf page which would hold the entry if it
@@ -5439,39 +5433,32 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
 ** *pRes is as follows:
 **
 **     *pRes<0      The cursor is left pointing at an entry that
-**                  is smaller than intKey/pIdxKey or if the table is empty
+**                  is smaller than intKey or if the table is empty
 **                  and the cursor is therefore left point to nothing.
 **
 **     *pRes==0     The cursor is left pointing at an entry that
-**                  exactly matches intKey/pIdxKey.
+**                  exactly matches intKey.
 **
 **     *pRes>0      The cursor is left pointing at an entry that
-**                  is larger than intKey/pIdxKey.
-**
-** For index tables, the pIdxKey->eqSeen field is set to 1 if there
-** exists an entry in the table that exactly matches pIdxKey.  
+**                  is larger than intKey.
 */
-int sqlite3BtreeMovetoUnpacked(
+int sqlite3BtreeTableMoveto(
   BtCursor *pCur,          /* The cursor to be moved */
-  UnpackedRecord *pIdxKey, /* Unpacked index key */
   i64 intKey,              /* The table key */
   int biasRight,           /* If true, bias the search to the high end */
   int *pRes                /* Write search results here */
 ){
   int rc;
-  RecordCompare xRecordCompare;
 
   assert( cursorOwnsBtShared(pCur) );
   assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
   assert( pRes );
-  assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
-  assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
+  assert( pCur->pKeyInfo==0 );
+  assert( pCur->eState!=CURSOR_VALID || pCur->curIntKey!=0 );
 
   /* If the cursor is already positioned at the point we are trying
   ** to move to, then just return without doing any work */
-  if( pIdxKey==0
-   && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
-  ){
+  if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){
     if( pCur->info.nKey==intKey ){
       *pRes = 0;
       return SQLITE_OK;
@@ -5506,17 +5493,6 @@ int sqlite3BtreeMovetoUnpacked(
   pCur->pBtree->nSeek++;   /* Performance measurement during testing */
 #endif
 
-  if( pIdxKey ){
-    xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
-    pIdxKey->errCode = 0;
-    assert( pIdxKey->default_rc==1 
-         || pIdxKey->default_rc==0 
-         || pIdxKey->default_rc==-1
-    );
-  }else{
-    xRecordCompare = 0; /* All keys are integers */
-  }
-
   rc = moveToRoot(pCur);
   if( rc ){
     if( rc==SQLITE_EMPTY ){
@@ -5531,7 +5507,8 @@ int sqlite3BtreeMovetoUnpacked(
   assert( pCur->eState==CURSOR_VALID );
   assert( pCur->pPage->nCell > 0 );
   assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
-  assert( pCur->curIntKey || pIdxKey );
+  assert( pCur->curIntKey );
+
   for(;;){
     int lwr, upr, idx, c;
     Pgno chldPg;
@@ -5545,133 +5522,238 @@ int sqlite3BtreeMovetoUnpacked(
     ** be the right kind (index or table) of b-tree page. Otherwise
     ** a moveToChild() or moveToRoot() call would have detected corruption.  */
     assert( pPage->nCell>0 );
-    assert( pPage->intKey==(pIdxKey==0) );
+    assert( pPage->intKey );
     lwr = 0;
     upr = pPage->nCell-1;
     assert( biasRight==0 || biasRight==1 );
     idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
     pCur->ix = (u16)idx;
-    if( xRecordCompare==0 ){
-      for(;;){
-        i64 nCellKey;
-        pCell = findCellPastPtr(pPage, idx);
-        if( pPage->intKeyLeaf ){
-          while( 0x80 <= *(pCell++) ){
-            if( pCell>=pPage->aDataEnd ){
-              return SQLITE_CORRUPT_PAGE(pPage);
-            }
+    for(;;){
+      i64 nCellKey;
+      pCell = findCellPastPtr(pPage, idx);
+      if( pPage->intKeyLeaf ){
+        while( 0x80 <= *(pCell++) ){
+          if( pCell>=pPage->aDataEnd ){
+            return SQLITE_CORRUPT_PAGE(pPage);
           }
         }
-        getVarint(pCell, (u64*)&nCellKey);
-        if( nCellKey<intKey ){
-          lwr = idx+1;
-          if( lwr>upr ){ c = -1; break; }
-        }else if( nCellKey>intKey ){
-          upr = idx-1;
-          if( lwr>upr ){ c = +1; break; }
+      }
+      getVarint(pCell, (u64*)&nCellKey);
+      if( nCellKey<intKey ){
+        lwr = idx+1;
+        if( lwr>upr ){ c = -1; break; }
+      }else if( nCellKey>intKey ){
+        upr = idx-1;
+        if( lwr>upr ){ c = +1; break; }
+      }else{
+        assert( nCellKey==intKey );
+        pCur->ix = (u16)idx;
+        if( !pPage->leaf ){
+          lwr = idx;
+          goto moveto_table_next_layer;
         }else{
-          assert( nCellKey==intKey );
-          pCur->ix = (u16)idx;
-          if( !pPage->leaf ){
-            lwr = idx;
-            goto moveto_next_layer;
-          }else{
-            pCur->curFlags |= BTCF_ValidNKey;
-            pCur->info.nKey = nCellKey;
-            pCur->info.nSize = 0;
-            *pRes = 0;
-            return SQLITE_OK;
-          }
+          pCur->curFlags |= BTCF_ValidNKey;
+          pCur->info.nKey = nCellKey;
+          pCur->info.nSize = 0;
+          *pRes = 0;
+          return SQLITE_OK;
         }
-        assert( lwr+upr>=0 );
-        idx = (lwr+upr)>>1;  /* idx = (lwr+upr)/2; */
       }
+      assert( lwr+upr>=0 );
+      idx = (lwr+upr)>>1;  /* idx = (lwr+upr)/2; */
+    }
+    assert( lwr==upr+1 || !pPage->leaf );
+    assert( pPage->isInit );
+    if( pPage->leaf ){
+      assert( pCur->ix<pCur->pPage->nCell );
+      pCur->ix = (u16)idx;
+      *pRes = c;
+      rc = SQLITE_OK;
+      goto moveto_table_finish;
+    }
+moveto_table_next_layer:
+    if( lwr>=pPage->nCell ){
+      chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
     }else{
-      for(;;){
-        int nCell;  /* Size of the pCell cell in bytes */
-        pCell = findCellPastPtr(pPage, idx);
-
-        /* The maximum supported page-size is 65536 bytes. This means that
-        ** the maximum number of record bytes stored on an index B-Tree
-        ** page is less than 16384 bytes and may be stored as a 2-byte
-        ** varint. This information is used to attempt to avoid parsing 
-        ** the entire cell by checking for the cases where the record is 
-        ** stored entirely within the b-tree page by inspecting the first 
-        ** 2 bytes of the cell.
-        */
-        nCell = pCell[0];
-        if( nCell<=pPage->max1bytePayload ){
-          /* This branch runs if the record-size field of the cell is a
-          ** single byte varint and the record fits entirely on the main
-          ** b-tree page.  */
-          testcase( pCell+nCell+1==pPage->aDataEnd );
-          c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
-        }else if( !(pCell[1] & 0x80) 
-          && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
-        ){
-          /* The record-size field is a 2 byte varint and the record 
-          ** fits entirely on the main b-tree page.  */
-          testcase( pCell+nCell+2==pPage->aDataEnd );
-          c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
-        }else{
-          /* The record flows over onto one or more overflow pages. In
-          ** this case the whole cell needs to be parsed, a buffer allocated
-          ** and accessPayload() used to retrieve the record into the
-          ** buffer before VdbeRecordCompare() can be called. 
-          **
-          ** If the record is corrupt, the xRecordCompare routine may read
-          ** up to two varints past the end of the buffer. An extra 18 
-          ** bytes of padding is allocated at the end of the buffer in
-          ** case this happens.  */
-          void *pCellKey;
-          u8 * const pCellBody = pCell - pPage->childPtrSize;
-          const int nOverrun = 18;  /* Size of the overrun padding */
-          pPage->xParseCell(pPage, pCellBody, &pCur->info);
-          nCell = (int)pCur->info.nKey;
-          testcase( nCell<0 );   /* True if key size is 2^32 or more */
-          testcase( nCell==0 );  /* Invalid key size:  0x80 0x80 0x00 */
-          testcase( nCell==1 );  /* Invalid key size:  0x80 0x80 0x01 */
-          testcase( nCell==2 );  /* Minimum legal index key size */
-          if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
-            rc = SQLITE_CORRUPT_PAGE(pPage);
-            goto moveto_finish;
-          }
-          pCellKey = sqlite3Malloc( nCell+nOverrun );
-          if( pCellKey==0 ){
-            rc = SQLITE_NOMEM_BKPT;
-            goto moveto_finish;
-          }
-          pCur->ix = (u16)idx;
-          rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
-          memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */
-          pCur->curFlags &= ~BTCF_ValidOvfl;
-          if( rc ){
-            sqlite3_free(pCellKey);
-            goto moveto_finish;
-          }
-          c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
-          sqlite3_free(pCellKey);
+      chldPg = get4byte(findCell(pPage, lwr));
+    }
+    pCur->ix = (u16)lwr;
+    rc = moveToChild(pCur, chldPg);
+    if( rc ) break;
+  }
+moveto_table_finish:
+  pCur->info.nSize = 0;
+  assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
+  return rc;
+}
+
+/* Move the cursor so that it points to an entry in an index table
+** near the key pIdxKey.   Return a success code.
+**
+** If an exact match is not found, then the cursor is always
+** left pointing at a leaf page which would hold the entry if it
+** were present.  The cursor might point to an entry that comes
+** before or after the key.
+**
+** An integer is written into *pRes which is the result of
+** comparing the key with the entry to which the cursor is 
+** pointing.  The meaning of the integer written into
+** *pRes is as follows:
+**
+**     *pRes<0      The cursor is left pointing at an entry that
+**                  is smaller than pIdxKey or if the table is empty
+**                  and the cursor is therefore left point to nothing.
+**
+**     *pRes==0     The cursor is left pointing at an entry that
+**                  exactly matches pIdxKey.
+**
+**     *pRes>0      The cursor is left pointing at an entry that
+**                  is larger than pIdxKey.
+**
+** The pIdxKey->eqSeen field is set to 1 if there
+** exists an entry in the table that exactly matches pIdxKey.  
+*/
+int sqlite3BtreeIndexMoveto(
+  BtCursor *pCur,          /* The cursor to be moved */
+  UnpackedRecord *pIdxKey, /* Unpacked index key */
+  int *pRes                /* Write search results here */
+){
+  int rc;
+  RecordCompare xRecordCompare;
+
+  assert( cursorOwnsBtShared(pCur) );
+  assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
+  assert( pRes );
+  assert( pCur->pKeyInfo!=0 );
+
+#ifdef SQLITE_DEBUG
+  pCur->pBtree->nSeek++;   /* Performance measurement during testing */
+#endif
+
+  xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
+  pIdxKey->errCode = 0;
+  assert( pIdxKey->default_rc==1 
+       || pIdxKey->default_rc==0 
+       || pIdxKey->default_rc==-1
+  );
+
+  rc = moveToRoot(pCur);
+  if( rc ){
+    if( rc==SQLITE_EMPTY ){
+      assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+      *pRes = -1;
+      return SQLITE_OK;
+    }
+    return rc;
+  }
+  assert( pCur->pPage );
+  assert( pCur->pPage->isInit );
+  assert( pCur->eState==CURSOR_VALID );
+  assert( pCur->pPage->nCell > 0 );
+  assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
+  assert( pCur->curIntKey || pIdxKey );
+  for(;;){
+    int lwr, upr, idx, c;
+    Pgno chldPg;
+    MemPage *pPage = pCur->pPage;
+    u8 *pCell;                          /* Pointer to current cell in pPage */
+
+    /* pPage->nCell must be greater than zero. If this is the root-page
+    ** the cursor would have been INVALID above and this for(;;) loop
+    ** not run. If this is not the root-page, then the moveToChild() routine
+    ** would have already detected db corruption. Similarly, pPage must
+    ** be the right kind (index or table) of b-tree page. Otherwise
+    ** a moveToChild() or moveToRoot() call would have detected corruption.  */
+    assert( pPage->nCell>0 );
+    assert( pPage->intKey==(pIdxKey==0) );
+    lwr = 0;
+    upr = pPage->nCell-1;
+    idx = upr>>1; /* idx = (lwr+upr)/2; */
+    pCur->ix = (u16)idx;
+    for(;;){
+      int nCell;  /* Size of the pCell cell in bytes */
+      pCell = findCellPastPtr(pPage, idx);
+
+      /* The maximum supported page-size is 65536 bytes. This means that
+      ** the maximum number of record bytes stored on an index B-Tree
+      ** page is less than 16384 bytes and may be stored as a 2-byte
+      ** varint. This information is used to attempt to avoid parsing 
+      ** the entire cell by checking for the cases where the record is 
+      ** stored entirely within the b-tree page by inspecting the first 
+      ** 2 bytes of the cell.
+      */
+      nCell = pCell[0];
+      if( nCell<=pPage->max1bytePayload ){
+        /* This branch runs if the record-size field of the cell is a
+        ** single byte varint and the record fits entirely on the main
+        ** b-tree page.  */
+        testcase( pCell+nCell+1==pPage->aDataEnd );
+        c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
+      }else if( !(pCell[1] & 0x80) 
+        && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
+      ){
+        /* The record-size field is a 2 byte varint and the record 
+        ** fits entirely on the main b-tree page.  */
+        testcase( pCell+nCell+2==pPage->aDataEnd );
+        c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
+      }else{
+        /* The record flows over onto one or more overflow pages. In
+        ** this case the whole cell needs to be parsed, a buffer allocated
+        ** and accessPayload() used to retrieve the record into the
+        ** buffer before VdbeRecordCompare() can be called. 
+        **
+        ** If the record is corrupt, the xRecordCompare routine may read
+        ** up to two varints past the end of the buffer. An extra 18 
+        ** bytes of padding is allocated at the end of the buffer in
+        ** case this happens.  */
+        void *pCellKey;
+        u8 * const pCellBody = pCell - pPage->childPtrSize;
+        const int nOverrun = 18;  /* Size of the overrun padding */
+        pPage->xParseCell(pPage, pCellBody, &pCur->info);
+        nCell = (int)pCur->info.nKey;
+        testcase( nCell<0 );   /* True if key size is 2^32 or more */
+        testcase( nCell==0 );  /* Invalid key size:  0x80 0x80 0x00 */
+        testcase( nCell==1 );  /* Invalid key size:  0x80 0x80 0x01 */
+        testcase( nCell==2 );  /* Minimum legal index key size */
+        if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
+          rc = SQLITE_CORRUPT_PAGE(pPage);
+          goto moveto_index_finish;
         }
-        assert( 
-            (pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
-         && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
-        );
-        if( c<0 ){
-          lwr = idx+1;
-        }else if( c>0 ){
-          upr = idx-1;
-        }else{
-          assert( c==0 );
-          *pRes = 0;
-          rc = SQLITE_OK;
-          pCur->ix = (u16)idx;
-          if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
-          goto moveto_finish;
+        pCellKey = sqlite3Malloc( nCell+nOverrun );
+        if( pCellKey==0 ){
+          rc = SQLITE_NOMEM_BKPT;
+          goto moveto_index_finish;
+        }
+        pCur->ix = (u16)idx;
+        rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
+        memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */
+        pCur->curFlags &= ~BTCF_ValidOvfl;
+        if( rc ){
+          sqlite3_free(pCellKey);
+          goto moveto_index_finish;
         }
-        if( lwr>upr ) break;
-        assert( lwr+upr>=0 );
-        idx = (lwr+upr)>>1;  /* idx = (lwr+upr)/2 */
+        c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
+        sqlite3_free(pCellKey);
+      }
+      assert( 
+          (pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
+       && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
+      );
+      if( c<0 ){
+        lwr = idx+1;
+      }else if( c>0 ){
+        upr = idx-1;
+      }else{
+        assert( c==0 );
+        *pRes = 0;
+        rc = SQLITE_OK;
+        pCur->ix = (u16)idx;
+        if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
+        goto moveto_index_finish;
       }
+      if( lwr>upr ) break;
+      assert( lwr+upr>=0 );
+      idx = (lwr+upr)>>1;  /* idx = (lwr+upr)/2 */
     }
     assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
     assert( pPage->isInit );
@@ -5680,9 +5762,8 @@ int sqlite3BtreeMovetoUnpacked(
       pCur->ix = (u16)idx;
       *pRes = c;
       rc = SQLITE_OK;
-      goto moveto_finish;
+      goto moveto_index_finish;
     }
-moveto_next_layer:
     if( lwr>=pPage->nCell ){
       chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
     }else{
@@ -5692,7 +5773,7 @@ moveto_next_layer:
     rc = moveToChild(pCur, chldPg);
     if( rc ) break;
   }
-moveto_finish:
+moveto_index_finish:
   pCur->info.nSize = 0;
   assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
   return rc;
@@ -8798,7 +8879,8 @@ int sqlite3BtreeInsert(
       ** to an adjacent cell.  Move the cursor so that it is pointing either
       ** to the cell to be overwritten or an adjacent cell.
       */
-      rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
+      rc = sqlite3BtreeTableMoveto(pCur, pX->nKey, 
+               (flags & BTREE_APPEND)!=0, &loc);
       if( rc ) return rc;
     }
   }else{
@@ -8825,9 +8907,10 @@ int sqlite3BtreeInsert(
         r.r1 = 0;
         r.r2 = 0;
         r.eqSeen = 0;
-        rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc);
+        rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc);
       }else{
-        rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc);
+        rc = btreeMoveto(pCur, pX->pKey, pX->nKey, 
+                    (flags & BTREE_APPEND)!=0, &loc);
       }
       if( rc ) return rc;
     }
index b7afecc426eb7a713815a564554e63683371802c..fe724d6bb51af61a2a212177dd88b33606d84bee 100644 (file)
@@ -247,13 +247,17 @@ void sqlite3BtreeCursorHint(BtCursor*, int, ...);
 #endif
 
 int sqlite3BtreeCloseCursor(BtCursor*);
-int sqlite3BtreeMovetoUnpacked(
+int sqlite3BtreeTableMoveto(
   BtCursor*,
-  UnpackedRecord *pUnKey,
   i64 intKey,
   int bias,
   int *pRes
 );
+int sqlite3BtreeIndexMoveto(
+  BtCursor*,
+  UnpackedRecord *pUnKey,
+  int *pRes
+);
 int sqlite3BtreeCursorHasMoved(BtCursor*);
 int sqlite3BtreeCursorRestore(BtCursor*, int*);
 int sqlite3BtreeDelete(BtCursor*, u8 flags);
index 4442f7d9f7d448480fda8570eed21d0556c5eea8..6623009aac6366eda98f0ba8e90e263d780a360d 100644 (file)
@@ -4307,7 +4307,7 @@ case OP_SeekGT: {       /* jump, in3, group */
         if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
       }
     }
-    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
+    rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res);
     pC->movetoTarget = iKey;  /* Used by OP_Delete */
     if( rc!=SQLITE_OK ){
       goto abort_due_to_error;
@@ -4354,7 +4354,7 @@ case OP_SeekGT: {       /* jump, in3, group */
     { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
 #endif
     r.eqSeen = 0;
-    rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
+    rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res);
     if( rc!=SQLITE_OK ){
       goto abort_due_to_error;
     }
@@ -4773,7 +4773,7 @@ case OP_Found: {        /* jump, in3 */
       }
     }
   }
-  rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
+  rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &res);
   if( pFree ) sqlite3DbFreeNN(db, pFree);
   if( rc!=SQLITE_OK ){
     goto abort_due_to_error;
@@ -4882,7 +4882,7 @@ notExistsWithKey:
   pCrsr = pC->uc.pCursor;
   assert( pCrsr!=0 );
   res = 0;
-  rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
+  rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res);
   assert( rc==SQLITE_OK || res==0 );
   pC->movetoTarget = iKey;  /* Used by OP_Delete */
   pC->nullRow = 0;
@@ -5039,7 +5039,7 @@ case OP_NewRowid: {           /* out2 */
       do{
         sqlite3_randomness(sizeof(v), &v);
         v &= (MAX_ROWID>>1); v++;  /* Ensure that v is greater than zero */
-      }while(  ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v,
+      }while(  ((rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)v,
                                                  0, &res))==SQLITE_OK)
             && (res==0)
             && (++cnt<100));
@@ -5937,7 +5937,7 @@ case OP_IdxDelete: {
   r.nField = (u16)pOp->p3;
   r.default_rc = 0;
   r.aMem = &aMem[pOp->p2];
-  rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
+  rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
   if( rc ) goto abort_due_to_error;
   if( res==0 ){
     rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
index d22a6a55923b9d2c0eb12a51eeb1543202fa2096..edbf062749b100a5292cc1d8d7a72e7cceeaeed0 100644 (file)
@@ -3501,7 +3501,7 @@ int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
   assert( p->deferredMoveto );
   assert( p->isTable );
   assert( p->eCurType==CURTYPE_BTREE );
-  rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
+  rc = sqlite3BtreeTableMoveto(p->uc.pCursor, p->movetoTarget, 0, &res);
   if( rc ) return rc;
   if( res!=0 ) return SQLITE_CORRUPT_BKPT;
 #ifdef SQLITE_TEST