From: dan Date: Wed, 22 Apr 2026 16:58:36 +0000 (+0000) Subject: Detect and omit cases where an index key is being replaced with an identical key. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8606a52934961c73831b306788a0b1020f54cd90;p=thirdparty%2Fsqlite.git Detect and omit cases where an index key is being replaced with an identical key. FossilOrigin-Name: 7a01caf0d0864a462eb81b7643dcf89048f4ae56a29d762f0cfc38066218504f --- diff --git a/manifest b/manifest index 8fa43adb30..df6ce7afdc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sinteger\stype\sbug\sin\sthe\sprevious\scheck-in. -D 2026-04-22T13:41:20.203 +C Detect\sand\somit\scases\swhere\san\sindex\skey\sis\sbeing\sreplaced\swith\san\sidentical\skey. +D 2026-04-22T16:58:36.117 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -685,7 +685,7 @@ F src/complete.c f216b970ce99c5a657556cf1f17e7ddd494515d3beb63df426bf59ff43bd3d9 F src/date.c 61e92f1f7e2e88e1cd91e91dc69eb2b2854e7877254470f9fabd776bfac922b8 F src/dbpage.c c9ea81c11727f27e02874611e92773e68e2a90a875ef2404b084564c235fd91f F src/dbstat.c 73362c0df0f40ad5523a6f5501224959d0976757b511299bf892313e79d14f5c -F src/delete.c 1f2268d6fe3c78fc1bf794ba65d7026498b78e2342ffaf85825dedae546e6fde +F src/delete.c dbde329841d214a85b1fa9f4c7ce9f53e4fc3066d2f5d491b3364cd43ec3bc14 F src/expr.c 68400681c5f6e41231d2c85abf6bb432aeeb2e36c4abdf90eb7b78551a5ce0f3 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 931f74cec1dc8038a0217ef340c91ce147dd1bbed08dc40c47ee0ec6edfffb08 @@ -802,7 +802,7 @@ F src/upsert.c 215328c3f91623c520ec8672c44323553f12caeb4f01b1090ebdca99fdf7b4f1 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 F src/util.c 377af5da226519a0f374dc3c6d408c9d303a92943e3ae5986432c7d52e6679a2 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 -F src/vdbe.c 6c57525d7db0232d52687d30da1093db0c152f14206c2ef1adf0c19a09d863e3 +F src/vdbe.c aeb80f9f9e3b7750b14dcaa439bbf026a4c71cd1881da86d04dfa1348ca8a474 F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71 F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1 F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 @@ -2202,8 +2202,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P dbc1d6f0a3452607e4e92155df0fdb1c5ea4ea5ad1654664f86383faf6c105ef -R feff29d9635a2e79cc3708641148218b -U drh -Z 064078e48b7f7788e91c44276a045e81 +P 5e1b5ff1c170e94956bf77bd38afcad6369cb9f9333864711212af045281ad0e +R 6a9d04ec755fb9001a47ce242326fc64 +T *branch * index-detect-noop +T *sym-index-detect-noop * +T -sym-trunk * +U dan +Z bd48131fa723540fccfa324eb37cb0d1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..0a396c097d 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch index-detect-noop +tag index-detect-noop diff --git a/manifest.uuid b/manifest.uuid index 493050eeb1..d88f411344 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5e1b5ff1c170e94956bf77bd38afcad6369cb9f9333864711212af045281ad0e +7a01caf0d0864a462eb81b7643dcf89048f4ae56a29d762f0cfc38066218504f diff --git a/src/delete.c b/src/delete.c index 95020c4df9..e450c2ad64 100644 --- a/src/delete.c +++ b/src/delete.c @@ -922,10 +922,9 @@ void sqlite3GenerateRowIndexDelete( VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); - sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, - pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn - ); + sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, aRegIdx ? aRegIdx[i] : 0); sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX); + sqlite3VdbeChangeP5(v, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } diff --git a/src/vdbe.c b/src/vdbe.c index 20b96d4721..e28b61d01e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -708,7 +708,6 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){ return h; } - /* ** For OP_Column, factor out the case where content is loaded from ** overflow pages, so that the code to implement this case is separate @@ -794,6 +793,40 @@ static SQLITE_NOINLINE int vdbeColumnFromOverflow( return rc; } +/* +** Memory cell pMem may contain a blob or a NULL value. Cursor pCsr is +** open on an index. If the current index entry matches the blob value in +** pMem byte-for-byte, set pMem to NULL and return 1. Otherwise, return 0. +** +** If an error occurs, set (*pRc) to an SQLite error code. Return 1 in this +** case as well. +*/ +static SQLITE_NOINLINE int vdbeIndexKeyCompare( + BtCursor *pCsr, /* Cursor to compare key to */ + Mem *pMem, + int *pRc +){ + int ret = 0; + u32 nKey = 0; + + assert( pMem->flags & (MEM_Blob|MEM_Null) ); + nKey = sqlite3BtreePayloadSize(pCsr); + if( nKey==pMem->n && (pMem->flags & MEM_Blob) ){ + /* This code could just use sqlite3BtreePayloadFetch(). But calling that + ** function here apparently prevents compilers from inlining it in other, + ** more performance critical, places. So this code uses + ** MemFromBtreeZeroOffset(), which is just as fast in most cases, but also + ** handles the case where the index record uses overflow pages. */ + Mem m; + memset(&m, 0, sizeof(m)); + *pRc = sqlite3VdbeMemFromBtreeZeroOffset(pCsr, nKey, &m); + ret = (*pRc!=SQLITE_OK || 0==memcmp(pMem->z, m.z, nKey)); + sqlite3VdbeMemReleaseMalloc(&m); + } + + return ret; +} + /* ** Send a "statement aborts" message to the error log. */ @@ -6577,6 +6610,7 @@ case OP_IdxInsert: { /* in2 */ assert( pC!=0 ); assert( !isSorter(pC) ); pIn2 = &aMem[pOp->p2]; + if( (pIn2->flags & MEM_Null) && (pOp->p5 & OPFLAG_PREFORMAT)==0 ) break; assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) ); if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; assert( pC->eCurType==CURTYPE_BTREE ); @@ -6622,8 +6656,8 @@ case OP_SorterInsert: { /* in2 */ break; } -/* Opcode: IdxDelete P1 P2 P3 P4 * -** Synopsis: key=r[P2@P3] +/* Opcode: IdxDelete P1 P2 P3 P4 P5 +** Synopsis: key=r[P2@P5] ** ** The content of P3 registers starting at register P2 form ** an unpacked index key. This opcode removes that entry from the @@ -6631,6 +6665,11 @@ case OP_SorterInsert: { /* in2 */ ** ** P4 is a pointer to an Index structure. ** +** If P3 is non-zero, it is the register number of a register holding +** a record that will be inserted into this index. If that record is +** identical to the one that would be deleted by this instruction, +** skip the delete and set register P3 to NULL. +** ** Raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found ** and not in writable_schema mode. */ @@ -6640,8 +6679,8 @@ case OP_IdxDelete: { int res; UnpackedRecord r; - assert( pOp->p3>0 ); - assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 ); + assert( pOp->p5>0 ); + assert( pOp->p2>0 && pOp->p2+pOp->p5<=(p->nMem+1 - p->nCursor)+1 ); assert( pOp->p1>=0 && pOp->p1nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); @@ -6650,7 +6689,7 @@ case OP_IdxDelete: { pCrsr = pC->uc.pCursor; assert( pCrsr!=0 ); r.pKeyInfo = pC->pKeyInfo; - r.nField = (u16)pOp->p3; + r.nField = pOp->p5; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); @@ -6669,6 +6708,13 @@ case OP_IdxDelete: { break; } } + + if( pOp->p3 && vdbeIndexKeyCompare(pCrsr, &aMem[pOp->p3], &rc) ){ + if( rc ) goto abort_due_to_error; + sqlite3VdbeMemSetNull(&aMem[pOp->p3]); + break; + } + rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); if( rc ) goto abort_due_to_error; assert( pC->deferredMoveto==0 );