From: drh <> Date: Fri, 9 Aug 2024 17:09:18 +0000 (+0000) Subject: Do not attempt to use a covering index based purely on columns-used X-Git-Tag: version-3.47.0~239^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8bc2647e0c66be6ef91071a3663bd1b7fa5d0943;p=thirdparty%2Fsqlite.git Do not attempt to use a covering index based purely on columns-used when doing an UPDATE or DELETE of a WITHOUT ROWID table. Raise an SQLITE_INTERNAL error if there is ever a situation where a table reference cannot be converted into an index reference when the query planner thinks that a covering index is appropriate. FossilOrigin-Name: fae39ae9320c0f4fcc2e3b3baf0a4170ba2b9a04634a0a1fa41dd4918a74b106 --- diff --git a/manifest b/manifest index 10fc3d74d8..3b74d15e9f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bind\sthe\snew\sdebug\sparameters\sin\sfuzzinvariants.c. -D 2024-08-09T12:35:27.067 +C Do\snot\sattempt\sto\suse\sa\scovering\sindex\sbased\spurely\son\scolumns-used\nwhen\sdoing\san\sUPDATE\sor\sDELETE\sof\sa\sWITHOUT\sROWID\stable.\s\sRaise\san\nSQLITE_INTERNAL\serror\sif\sthere\sis\sever\sa\ssituation\swhere\sa\stable\sreference\ncannot\sbe\sconverted\sinto\san\sindex\sreference\swhen\sthe\squery\splanner\sthinks\nthat\sa\scovering\sindex\sis\sappropriate. +D 2024-08-09T17:09:18.697 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -846,7 +846,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 887fc4ca3f020ebb2e376f222069570834ac63bf50111ef0cbf3ae417048ed89 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452 F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2 -F src/where.c 5bbe53db73ae6c8ee34a5eab693a5586ad8ff4f094ff0e524df965b683bec884 +F src/where.c 5fa17ec4e344e57cf43dd7b2977c95a518bfc2d43edb42df0cd1d5c2b42cee04 F src/whereInt.h 002adc3aa2cc10733b9b27958fdbe893987cd989fab25a9853941c1f9b9b0a65 F src/wherecode.c c9cac0b0b8e809c5e7e79d7796918907fb685ad99be2aaa9737f9787aa47349c F src/whereexpr.c 7d0d34b42b9edfd8e8ca66beb3a6ef63fe211c001af54caf2ccbcd989b783290 @@ -2204,8 +2204,11 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P fa047c3ea7a03d76afd6a11f58ef7b84c653f583ed795e0de5be2a6b986e558e -R 4385e87b815ad1924711e2dcdab3d5bb +P 7e1dc263051cf50db04643d1a2aa9f91559b2b121859b750ce4446012d5f3c3e +R a22c0892de474f9ba14db4c65993edff +T *branch * covering-index-patch +T *sym-covering-index-patch * +T -sym-trunk * U drh -Z 5861d6c430a2b6c91eb7ed0d9c3ba80b +Z b1c9594c16be220e78f6cfe69b132d52 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c2f77959c0..30b7a517ca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7e1dc263051cf50db04643d1a2aa9f91559b2b121859b750ce4446012d5f3c3e +fae39ae9320c0f4fcc2e3b3baf0a4170ba2b9a04634a0a1fa41dd4918a74b106 diff --git a/src/where.c b/src/where.c index c850121c34..15f5fe7d96 100644 --- a/src/where.c +++ b/src/where.c @@ -4047,7 +4047,9 @@ static int whereLoopAddBtree( " according to whereIsCoveringIndex()\n", pProbe->zName)); } } - }else if( m==0 ){ + }else if( m==0 + && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) + ){ WHERETRACE(0x200, ("-> %s a covering index according to bitmasks\n", pProbe->zName, m==0 ? "is" : "is not")); @@ -7078,26 +7080,6 @@ whereBeginError: } #endif -#ifdef SQLITE_DEBUG -/* -** Return true if cursor iCur is opened by instruction k of the -** bytecode. Used inside of assert() only. -*/ -static int cursorIsOpen(Vdbe *v, int iCur, int k){ - while( k>=0 ){ - VdbeOp *pOp = sqlite3VdbeGetOp(v,k--); - if( pOp->p1!=iCur ) continue; - if( pOp->opcode==OP_Close ) return 0; - if( pOp->opcode==OP_OpenRead ) return 1; - if( pOp->opcode==OP_OpenWrite ) return 1; - if( pOp->opcode==OP_OpenDup ) return 1; - if( pOp->opcode==OP_OpenAutoindex ) return 1; - if( pOp->opcode==OP_OpenEphemeral ) return 1; - } - return 0; -} -#endif /* SQLITE_DEBUG */ - /* ** Generate the end of the WHERE loop. See comments on ** sqlite3WhereBegin() for additional information. @@ -7376,18 +7358,20 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ assert( pIdx->pTable==pTab ); #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC if( pOp->opcode==OP_Offset ){ - /* Do not need to translate the column number */ + x = 0; }else #endif - if( !HasRowid(pTab) ){ - Index *pPk = sqlite3PrimaryKeyIndex(pTab); - x = pPk->aiColumn[x]; - assert( x>=0 ); - }else{ - testcase( x!=sqlite3StorageColumnToTable(pTab,x) ); - x = sqlite3StorageColumnToTable(pTab,x); + { + if( !HasRowid(pTab) ){ + Index *pPk = sqlite3PrimaryKeyIndex(pTab); + x = pPk->aiColumn[x]; + assert( x>=0 ); + }else{ + testcase( x!=sqlite3StorageColumnToTable(pTab,x) ); + x = sqlite3StorageColumnToTable(pTab,x); + } + x = sqlite3TableColumnToIndex(pIdx, x); } - x = sqlite3TableColumnToIndex(pIdx, x); if( x>=0 ){ pOp->p2 = x; pOp->p1 = pLevel->iIdxCur; @@ -7397,16 +7381,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** reference. Verify that this is harmless - that the ** table being referenced really is open. */ -#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - || cursorIsOpen(v,pOp->p1,k) - || pOp->opcode==OP_Offset - ); -#else - assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 - || cursorIsOpen(v,pOp->p1,k) - ); -#endif + if( pLoop->wsFlags & WHERE_IDX_ONLY ){ + sqlite3ErrorMsg(pParse, "internal query planner error"); + pParse->rc = SQLITE_INTERNAL; + } } }else if( pOp->opcode==OP_Rowid ){ pOp->p1 = pLevel->iIdxCur;