]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
If OP_IdxDelete cannot find an index entry to delete, first search 10 entries in...
authordan <Dan Kennedy>
Mon, 16 Mar 2026 16:21:43 +0000 (16:21 +0000)
committerdan <Dan Kennedy>
Mon, 16 Mar 2026 16:21:43 +0000 (16:21 +0000)
FossilOrigin-Name: 2cb9f4e4178549144acd82e317a1646e71c9281ac9fc4aa26bf129f1068ded45

manifest
manifest.uuid
src/vdbeaux.c

index 97b09a3fa0d1cdf8733fc6efa1d2a457b2d877e5..d737e8c4bc7f963b2452a1ddef136d9d21bac901 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sproblem\swith\sthe\sfind-delete-key\smethod\son\sthis\sbranch.
-D 2026-03-16T15:49:58.396
+C If\sOP_IdxDelete\scannot\sfind\san\sindex\sentry\sto\sdelete,\sfirst\ssearch\s10\sentries\sin\seither\sdirection\sof\swhere\sthe\sentry\sshould\sbe\sin\sthe\sindex.\sIf\sthat\sfails,\ssearch\sthe\sentire\sindex\sfor\san\sentry\swith\smatching\sPK\sfields.
+D 2026-03-16T16:21:43.376
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -803,7 +803,7 @@ F src/vdbe.c 31ca4aaad332c3b973c5fb74bc76972a856fcb99c581e68efc35b6e9299a6d6c
 F src/vdbe.h 966d0677a540b7ea6549b7c4e1312fc0d830fce3a235a58c801f2cc31cf5ecf9
 F src/vdbeInt.h 68d4adddb1eb48cdbaff8cce1305ac6bc5ad9115f1a37087a13d01a045303e7a
 F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1
-F src/vdbeaux.c 6af3a26cd0ecde496eb3a0ad5ac90da098ce923a5c93f48c8d4f0bbc768863bc
+F src/vdbeaux.c df278c8a46a1e8ff9610f166167966de20b216016550d0d4fec26503c4e55006
 F src/vdbeblob.c b3f0640db9642fbdc88bd6ebcc83d6009514cafc98f062f675f2c8d505d82692
 F src/vdbemem.c 317ec5e870ddb16951b606c9fe8be22baef22ecbe46f58fdefc259662238afb7
 F src/vdbesort.c b69220f4ea9ffea5fdef34d968c60305444eea909252a81933b54c296d9cca70
@@ -2193,8 +2193,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P c4b0081f08bd0458dbcf269b43a4051941eec8067393aa8e6810d4b8422ce44a
-R a18915b4118c3d28a02387e1bb9fac1b
+P 6f49b5ecad5d924999d045a1ade93d95e731182be1781aefa5bc763b6202e9c3
+R 07aad91547589b98e374a31de7dba336
 U dan
-Z ddfe823bdcd5bb4257cbd5344ccd28d9
+Z da974e9658962ed0763a3b684d15cc9b
 # Remove this line to create a well-formed Fossil manifest.
index 5140ff4fc4b13cc0dc1856a3a0416cb1fbfcd00c..d600a01baae1578ec1e765d364b23ff9f64cf760 100644 (file)
@@ -1 +1 @@
-6f49b5ecad5d924999d045a1ade93d95e731182be1781aefa5bc763b6202e9c3
+2cb9f4e4178549144acd82e317a1646e71c9281ac9fc4aa26bf129f1068ded45
index c024cce9f7eda0c2f78b82c80bd2fa81e2b7eb98..2a6833e7650992f3285a13c2da9f153f2c03af1f 100644 (file)
@@ -5395,24 +5395,10 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
 
 /*
 ** This function compares the unpacked record with the current key that
-** cursor pCur points to. It returns the usual less than zero, zero, or
-** greater than zero if the cursor key is less than, equal to or greater
-** than p. i.e.
-**
-**          (pCur->pKey) - (p)
-**
-** Except that:
-**
-**   * if the PK fields of the keys match, zero is always returned, even
-**     if the preceding fields do not match.
-**
-**   * otherwise, if the preceding fields are not identical, the result
-**     of comparing them is returned.
-**
-**   * finally, if the preceding fields all match but the PK fields do 
-**     not, the result of comparing the PK fields is returned.
-**
-** This function is not optimized. It is not expected to be called often.
+** cursor pCur points to, ignoring the first nKeyCol fields. It returns 
+** the usual less than zero, zero, or greater than zero if the remaining
+** fields of the cursor cursor key are less than, equal to or greater 
+** than those in (*p).
 */
 static int vdbeIsDeleteKey(
   BtCursor *pCur,                 /* Cursor open on index */
@@ -5439,20 +5425,16 @@ static int vdbeIsDeleteKey(
   if( rc==SQLITE_OK ){
     int szHdr = 0;                /* Size of record header in bytes */
     int idxHdr = 0;               /* Current index in header */
-    int idxRec = 0;               /* Current index in record */
-    int ii = 0;
-    int nCol = 0;
-    int res = 0;
 
     idxHdr = getVarint32(aRec, szHdr);
     if( szHdr>98307 ){
       rc = SQLITE_CORRUPT;
     }else{
-      int recres = 0;             /* Result of comparing record fields */
       int res = 0;                /* Result of this function call */
+      int idxRec = szHdr;         /* Index of next field in record body */
+      int ii = 0;                 /* Iterator variable */
 
-      idxRec = szHdr; 
-      nCol = p->pKeyInfo->nAllField;
+      int nCol = p->pKeyInfo->nAllField;
       for(ii=0; ii<nCol && rc==SQLITE_OK; ii++){
         u32 iSerial = 0;
         int nSerial = 0;
@@ -5462,20 +5444,12 @@ static int vdbeIsDeleteKey(
         nSerial = sqlite3VdbeSerialTypeLen(iSerial);
         if( (idxRec+nSerial)>nRec ){
           rc = SQLITE_CORRUPT_BKPT;
-        }else{
+        }else if( ii>=nKeyCol ){
           sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem);
-          idxRec += sqlite3VdbeSerialTypeLen(iSerial);
-          r2 = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
-          if( r2!=0 ){
-            if( ii<nKeyCol ){
-              if( recres==0 ) recres = r2;
-            }else{
-              res = recres;
-              if( res==0 ) res = r2;
-              break;
-            }
-          }
+          res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]);
+          if( res!=0 ) break;
         }
+        idxRec += sqlite3VdbeSerialTypeLen(iSerial);
       }
 
       *piRes = res;
@@ -5503,16 +5477,9 @@ static int vdbeIsDeleteKey(
 **
 ** The algorithm used to find the correct record is:
 **
-**   * Test the PK columns of the current record to see if they match (*p).
-**     If so, delete the current record.
+**   * Scan up to BTREE_FDK_RANGE entries either side of the current entry.
 **
-**   * If the caller's (*pRes) value was -ve, advance the cursor forward one
-**     entry. Then test the PK fields again. Repeat until the cursor points
-**     to an entry larger than (*p).
-**
-**   * Or, if the caller's (*pRes) value was +ve, move the cursor backwards 
-**     one entry. Then test the PK fields again. Repeat until the cursor 
-**     points to an entry larger than (*p).
+**   * If the above fails to find an entry to delete, search the entire index.
 */
 int sqlite3VdbeFindDeleteKey(
   BtCursor *pCur, 
@@ -5520,26 +5487,50 @@ int sqlite3VdbeFindDeleteKey(
   UnpackedRecord *p, 
   int *pRes
 ){
-  int resCaller = *pRes;
-  int res = resCaller;
+#define BTREE_FDK_RANGE 10
+  int nStep = 0;
+  int res = 1;
   int rc = SQLITE_OK;
+  int ii = 0;
+
+  /* Move the cursor back BTREE_FDK_RANGE entries. If this hits an EOF, 
+  ** position the cursor at the first entry in the index and set nStep
+  ** to -1 so that the first loop below scans the entire index. Otherwise,
+  ** set nStep to BTREE_FDK_RANGE*2 so that the first loop below scans
+  ** just that many entries.  */
+  for(ii=0; sqlite3BtreeEof(pCur)==0 && ii<BTREE_FDK_RANGE; ii++){
+    rc = sqlite3BtreePrevious(pCur, 0);
+  }
+  if( rc==SQLITE_DONE ){
+    rc = sqlite3BtreeFirst(pCur, &res);
+    nStep = -1;
+  }else{
+    nStep = BTREE_FDK_RANGE*2;
+  }
 
-  assert( resCaller==-1 || resCaller==0 || resCaller==+1 );
-  while( sqlite3BtreeEof(pCur)==0 && rc==SQLITE_OK ){
-    rc = vdbeIsDeleteKey(pCur, nKeyCol, p, &res);
-    assert( res==-1 || res==0 || res==+1 );
-    if( res!=resCaller ) break;
-
-    if( rc==SQLITE_OK ){
-      if( resCaller<0 ){
-        rc = sqlite3BtreeNext(pCur, 0);
-      }else{
-        rc = sqlite3BtreePrevious(pCur, 0);
-      }
+  /* This loop runs at most twice to search for a key with matching PK 
+  ** fields in the index. The second iteration always searches the entire 
+  ** index. The first iteration searches nStep entries starting with the
+  ** current cursor entry if (nStep>=0), or the entire index if (nStep<0).  */
+  while( 1 ){
+    for(ii=0; rc==SQLITE_OK && (ii<nStep || nStep<0); ii++){
+      rc = vdbeIsDeleteKey(pCur, nKeyCol, p, &res);
+      if( res==0 || rc!=SQLITE_OK ) break;
+      rc = sqlite3BtreeNext(pCur, 0);
     }
+    if( rc==SQLITE_DONE ){
+      rc = SQLITE_OK;
+      assert( res!=0 );
+    }
+    if( nStep<0 || rc!=SQLITE_OK || res==0 ) break;
+
+    /* The first, non-exhaustive, search failed to find an entry with 
+    ** matching PK fields. So restart for an exhaustive search of the 
+    ** entire index.  */
+    nStep = -1;
+    rc = sqlite3BtreeFirst(pCur, &res);
   }
 
-  if( rc==SQLITE_DONE ) rc = SQLITE_OK;
   *pRes = res;
   return rc;
 }