From: dan Date: Tue, 16 Jun 2026 18:06:46 +0000 (+0000) Subject: After opening a non-covering index cursor, pass the corresponding table cursor to... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=544b208113d7b94ef19a9ba288c55ca23a4399bd;p=thirdparty%2Fsqlite.git After opening a non-covering index cursor, pass the corresponding table cursor to the implementation via sqlite3BtreeCursorHint(). FossilOrigin-Name: d48c6d2dcd50128f35bba8931371e708d24b63f2ea7a5988af8864d18ef5d14e --- diff --git a/manifest b/manifest index 099218cd84..8d04d6dbc6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Limit\sVIEW\srecursion\sdepth\sto\sSQLITE_LIMIT_EXPR_DEPTH\sto\sprevent\s\nstatic\soverflow\sin\smalicious\sschemas\swith\stens\sof\sthousands\sof\nlevels\sof\srecursive\sviews.\n[bugs:/info/2026-06-16T04:21:51Z|Bug\s2026-06-16T04:21:51Z] -D 2026-06-16T13:43:08.110 +C After\sopening\sa\snon-covering\sindex\scursor,\spass\sthe\scorresponding\stable\scursor\sto\sthe\simplementation\svia\ssqlite3BtreeCursorHint(). +D 2026-06-16T18:06:46.153 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -677,9 +677,9 @@ F src/auth.c b5ece4e1edccad082c0332fa0087df225473bae0feea9269f824312201377185 F src/backup.c 6ebe22ccbedfcb92423833992130e8d65824be4e6599c3a03f540ab38fc7d13c F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399 F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea -F src/btree.c c9b13797b0b68e0c057ec796976b1ab1e8b4e766d1a7c7f919b2d8a1d2193a80 -F src/btree.h e823c46d87f63d904d735a24b76146d19f51f04445ea561f71cc3382fd1307f0 -F src/btreeInt.h 9c0f9ea5c9b5f4dcaea18111d43efe95f2ac276cd86d770dce10fd99ccc93886 +F src/btree.c 515cf62220ceb483ba9a31ebb3d7565ea9d63ffc3d61bb974b2815fef393df0e +F src/btree.h 2886ff5e136ed6472edc77515896892e3f9105436f191d95320a15d967ac4889 +F src/btreeInt.h 4f512ad31083216b6789762d4c345b73367985d3b39421c9ba7c0902d09fb38b F src/build.c 866e584cdf40fbc83f530af9fd4d0991582a6fdbd8a9911b7cdbbea5f26a4a9e F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179 @@ -804,7 +804,7 @@ F src/upsert.c dd9f0fcccbfb4f20e1026a21a7254ba3f2c08e9cfa92affaff5b5ec3b00ea549 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165 F src/util.c 98cf12c8ba65623a76c1eb6e6afa98ff40107c9919bf79af42f4bfc70e654232 F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82 -F src/vdbe.c 39658ee12b9d6bf5fc546e1ede20b307d86d9e988ae709c9b461249a8312513d +F src/vdbe.c 6397694fa506aa1841dc8bb6a17c514aa602a4ad2515024fcd5880558c1ef57f F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71 F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1 F src/vdbeapi.c 6cdcbe5c7afa754c998e73d2d5d2805556268362914b952811bdfb9c78a37cf1 @@ -819,7 +819,7 @@ F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c abfd99239725a258af4f733681b24dd7a9ee298babe389a36d29c197e2443ebf F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014 -F src/where.c 33e4a6558ee69f33d6a4e7069e3a40a55959d14e5653a9a83926e70305d471f3 +F src/where.c e76636ee3a58a3fc84e6a0362c69dd61234c24a77cfc9219b8db8cc2278ae5b7 F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da F src/wherecode.c bc39ccbe3648f01157038b16cc55bdbff128590972b7185521b5526dc2815765 F src/whereexpr.c a1e22cf9f6cb59770d9652c757dcf1924078ad2d48a9da89e254be9327677465 @@ -1031,8 +1031,8 @@ F test/createtab.test 85cdfdae5c3de331cd888d6c66e1aba575b47c2e3c3cc4a1d6f5414069 F test/cse.test 00b3aea44b16828833c94fbe92475fd6977583fcb064ae0bc590986812b38d0c F test/csv01.test 96bc1634961682363a7b4ad5c0e38450e6e9743b38ac626422e1b56cbdc06cd8 F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c4773 -F test/cursorhint.test 05cf0febe5c5f8a31f199401fd1c9322249e753950d55f26f9d5aca61408a270 -F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f +F test/cursorhint.test d8b93ac48dfdb2cf4284142710d63e860b6497afff2e9c525daf752a229e5b97 +F test/cursorhint2.test a10f29c0c52d4d73c19cf639f3c33cccbf5024bcf950fa48f2a8cdc14628b985 F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8 F test/date.test 328ed63091d34c8a6e8dcec4f999a031ce310f24395b8f0f67f07eaf36cbfd1f F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1 @@ -2208,8 +2208,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 0b72246732fecd7909add28f2d95f1727e1c4dc6c8f3b8e6e3482f6d17c92d34 -R 0aa2d61f35a87c7a58d6909964314503 -U drh -Z 423360f46549491b114d6ada047fd081 +P 3f3fb9b638f59ad982beafb7c117f24ddd3da612e62c862510805fa672ffae06 +R 237ea409b5f47403026e3eec6a17c3ca +T *branch * cursor-hint-tblcsr +T *sym-cursor-hint-tblcsr * +T -sym-trunk * +U dan +Z 8b75c7202ab01c7d8eacb5d6b04a0202 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..0cbf1751fe 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch cursor-hint-tblcsr +tag cursor-hint-tblcsr diff --git a/manifest.uuid b/manifest.uuid index d8df050953..e5e445823a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3f3fb9b638f59ad982beafb7c117f24ddd3da612e62c862510805fa672ffae06 +d48c6d2dcd50128f35bba8931371e708d24b63f2ea7a5988af8864d18ef5d14e diff --git a/src/btree.c b/src/btree.c index 9bafc37874..09125a02b2 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1005,24 +1005,41 @@ int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow){ void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){ /* Used only by system that substitute their own storage engine */ #ifdef SQLITE_DEBUG - if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){ - va_list ap; + va_list ap; + va_start(ap, eHintType); + if( eHintType==BTREE_HINT_RANGE ){ Expr *pExpr; Walker w; memset(&w, 0, sizeof(w)); w.xExprCallback = sqlite3CursorRangeHintExprCheck; - va_start(ap, eHintType); pExpr = va_arg(ap, Expr*); w.u.aMem = va_arg(ap, Mem*); - va_end(ap); assert( pExpr!=0 ); assert( w.u.aMem!=0 ); sqlite3WalkExpr(&w, pExpr); + }else if( ALWAYS(eHintType==BTREE_HINT_TABLECURSOR) ){ + BtCursor *pCsr = va_arg(ap, BtCursor*); + assert( pCur->pCursorHintTableCursor==0 + || pCur->pCursorHintTableCursor==pCsr + ); + assert( pCsr->pKeyInfo==0 || CORRUPT_DB ); + pCur->pCursorHintTableCursor = pCsr; } + va_end(ap); #endif /* SQLITE_DEBUG */ } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ +#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) +/* +** Return the pointer configured via the BTREE_HINT_TABLECURSOR hint on +** cursor pCsr. This is used from OP_DeferredSeek to assert() that the +** index cursor has been correctly configured with the table cursor. +*/ +BtCursor *sqlite3BtreeCursorHintTblCsr(BtCursor *pCsr){ + return pCsr->pCursorHintTableCursor; +} +#endif /* ** Provide flag hints to the cursor. diff --git a/src/btree.h b/src/btree.h index 96f4c4c607..5139dfad5d 100644 --- a/src/btree.h +++ b/src/btree.h @@ -188,6 +188,7 @@ int sqlite3BtreeNewDb(Btree *p); ** engine. */ #define BTREE_HINT_RANGE 0 /* Range constraints on queries */ +#define BTREE_HINT_TABLECURSOR 1 /* Table csr associated with this index csr */ /* ** Values that may be OR'd together to form the argument to the @@ -247,6 +248,9 @@ void sqlite3BtreeCursorZero(BtCursor*); void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned); #ifdef SQLITE_ENABLE_CURSOR_HINTS void sqlite3BtreeCursorHint(BtCursor*, int, ...); + #ifdef SQLITE_DEBUG + BtCursor *sqlite3BtreeCursorHintTblCsr(BtCursor*); + #endif #endif int sqlite3BtreeCloseCursor(BtCursor*); diff --git a/src/btreeInt.h b/src/btreeInt.h index 17e3a1add5..52c5b22653 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -538,6 +538,9 @@ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ Pgno *aOverflow; /* Cache of overflow page locations */ void *pKey; /* Saved key that was cursor last known position */ +#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) + BtCursor *pCursorHintTableCursor; +#endif /* All fields above are zeroed when the cursor is allocated. See ** sqlite3BtreeCursorZero(). Fields that follow must be manually ** initialized. */ diff --git a/src/vdbe.c b/src/vdbe.c index a1592c18ef..b2fabcd758 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -6789,6 +6789,11 @@ case OP_IdxRowid: { /* out2, ncycle */ assert( pTabCur->eCurType==CURTYPE_BTREE ); assert( pTabCur->uc.pCursor!=0 ); assert( pTabCur->isTable ); +#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG) + assert( + sqlite3BtreeCursorHintTblCsr(pC->uc.pCursor)==pTabCur->uc.pCursor + ); +#endif pTabCur->nullRow = 0; pTabCur->movetoTarget = rowid; pTabCur->deferredMoveto = 1; @@ -9171,23 +9176,37 @@ case OP_Init: { /* jump0 */ } #ifdef SQLITE_ENABLE_CURSOR_HINTS -/* Opcode: CursorHint P1 * * P4 * +/* Opcode: CursorHint P1 * P3 P4 * +** +** Provide a hint to cursor P1. ** -** Provide a hint to cursor P1 that it only needs to return rows that -** satisfy the Expr in P4. TK_REGISTER terms in the P4 expression refer -** to values currently held in registers. TK_COLUMN terms in the P4 +** If P4 is of type P4_EXPR, then the hint is that the cursor need only return +** rows that satisfy the Expr in P4. TK_REGISTER terms in the P4 expression +** refer to values currently held in registers. TK_COLUMN terms in the P4 ** expression refer to columns in the b-tree to which cursor P1 is pointing. +** P3 is ignore in this case. +** +** Or, if P4 is P4_NOTUSED, then the hint is that cursor P1 is an index cursor +** used to drive table cursor P3. In other words, that this VM may execute +** OP_DeferredSeek instructions to lazily position P3 based on current +** position of P1. */ case OP_CursorHint: { VdbeCursor *pC; + pC = p->apCsr[pOp->p1]; assert( pOp->p1>=0 && pOp->p1nCursor ); - assert( pOp->p4type==P4_EXPR ); - pC = p->apCsr[pOp->p1]; + if( pC ){ assert( pC->eCurType==CURTYPE_BTREE ); - sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE, - pOp->p4.pExpr, aMem); + if( pOp->p4type==P4_EXPR ){ + sqlite3BtreeCursorHint(pC->uc.pCursor, BTREE_HINT_RANGE, + pOp->p4.pExpr, aMem); + }else if( p->apCsr[pOp->p3] ){ + sqlite3BtreeCursorHint( + pC->uc.pCursor, BTREE_HINT_TABLECURSOR, p->apCsr[pOp->p3]->uc.pCursor + ); + } } break; } diff --git a/src/where.c b/src/where.c index 3d4f28cc8a..9083d04f9b 100644 --- a/src/where.c +++ b/src/where.c @@ -7388,6 +7388,11 @@ WhereInfo *sqlite3WhereBegin( (u8*)&colUsed, P4_INT64); } #endif /* SQLITE_ENABLE_COLUMN_USED_MASK */ +#ifdef SQLITE_ENABLE_CURSOR_HINTS + if( HasRowid(pTab) ){ + sqlite3VdbeAddOp3(v, OP_CursorHint, iIndexCur, 0, pTabItem->iCursor); + } +#endif } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); diff --git a/test/cursorhint.test b/test/cursorhint.test index d1bd4e8e78..b363237d59 100644 --- a/test/cursorhint.test +++ b/test/cursorhint.test @@ -38,7 +38,7 @@ do_execsql_test 1.0 { proc p4_of_opcode {db opcode sql} { set res {} $db eval "EXPLAIN $sql" x { - if {$x(opcode)==$opcode} {lappend res $x(p4)} + if {$x(opcode)==$opcode && $x(p4)!=""} {lappend res $x(p4)} } return $res } diff --git a/test/cursorhint2.test b/test/cursorhint2.test index a78d151b98..974e6c674e 100644 --- a/test/cursorhint2.test +++ b/test/cursorhint2.test @@ -36,7 +36,9 @@ proc extract_hints {sql} { set csr($a(p1)) $lookup($a(p2)) } CursorHint { - lappend ret $csr($a(p1)) $a(p4) + if {$a(p4)!=""} { + lappend ret $csr($a(p1)) $a(p4) + } } } }