From: dan Date: Sat, 3 Aug 2024 18:45:48 +0000 (+0000) Subject: Ensure the sqlite3_index_info.colUsed mask always includes the PK fields of WITHOUT... X-Git-Tag: version-3.47.0~262^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0a83dac31c9d4c2d65d4127f9cef07405757cf4d;p=thirdparty%2Fsqlite.git Ensure the sqlite3_index_info.colUsed mask always includes the PK fields of WITHOUT ROWID vtabs in cases where they may be used. FossilOrigin-Name: c327c0c02cfefdba373cfb15933a9cdfddb578b6582f2ce7c08929203743ffe9 --- diff --git a/manifest b/manifest index cd4233fd08..c6e1fa4c8e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s--status\soption\sto\sthe\stest\sruns\susing\stestrunner.tcl.\s\sOnly\sworks\non\sUnix\splatforms.\s\sThe\s"exec"\scommand\sappears\sto\sinterfere\swith\sVT100\nescape\scodes\son\swindows. -D 2024-08-03T15:55:25.995 +C Ensure\sthe\ssqlite3_index_info.colUsed\smask\salways\sincludes\sthe\sPK\sfields\sof\sWITHOUT\sROWID\svtabs\sin\scases\swhere\sthey\smay\sbe\sused. +D 2024-08-03T18:45:48.287 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -845,7 +845,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 d87a4160e26a7a96a2f7ca283b147b1b283b54ba545c46acb14cfcc6ec37ae9e +F src/where.c 31d100c11a21e479e0dda679585f0ab2675e746a169349519a9a38d3ef10dec7 F src/whereInt.h 002adc3aa2cc10733b9b27958fdbe893987cd989fab25a9853941c1f9b9b0a65 F src/wherecode.c c9cac0b0b8e809c5e7e79d7796918907fb685ad99be2aaa9737f9787aa47349c F src/whereexpr.c 7d0d34b42b9edfd8e8ca66beb3a6ef63fe211c001af54caf2ccbcd989b783290 @@ -946,6 +946,7 @@ F test/bestindex9.test 1a4b93db117fd8abe74ae9be982f86aa72f01e60cd4ac541e6ede3967 F test/bestindexA.test e1b5def6b190797cacf008e6815ffb78fb30261999030d60a728d572eef44c7f F test/bestindexB.test 328b97b69cd1a20928d5997f9ecb04d2e00f1d18e19ab27f9e9adb44d7bc51ce F test/bestindexC.test 2df6ada16d8f00d9bb6a9664d9c323560aeed0e0ebc7a32b99d85d70037fd250 +F test/bestindexD.test 6a8f6f84990bcf17dfa59652a1f935beddb7afd96f8302830fbc86b0a13df3c3 F test/between.test b9a65fb065391980119e8a781a7409d3fcf059d89968279c750e190a9a1d5263 F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc @@ -2202,8 +2203,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1637d29d518b3b4534a1b4c0dc0eddcb770f6f71763e4177812a3e79b97d2365 -R 2baa0a7875a2461a2d1db67ee8455074 -U drh -Z cdd1e09ba643f6fa1e24fe72f8439dd6 +P 94015cda4ceb4292ceceadb951fe5d9cb3e4e20403719b7254ad094a5b749ab3 +R 0e3129b74e025069f852e333318489ef +U dan +Z 98131b222c55011293de598d5d0fb4ed # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 551ed083cd..abf3e708eb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -94015cda4ceb4292ceceadb951fe5d9cb3e4e20403719b7254ad094a5b749ab3 +c327c0c02cfefdba373cfb15933a9cdfddb578b6582f2ce7c08929203743ffe9 diff --git a/src/where.c b/src/where.c index a9a2589956..35c6f204a9 100644 --- a/src/where.c +++ b/src/where.c @@ -1501,6 +1501,16 @@ static sqlite3_index_info *allocateIndexInfo( pIdxInfo->aConstraint = pIdxCons; pIdxInfo->aOrderBy = pIdxOrderBy; pIdxInfo->aConstraintUsage = pUsage; + pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; + if( HasRowid(pTab)==0 ){ + /* Ensure that all bits associated with PK columns are set. This is to + ** ensure they are available for cases like RIGHT joins or OR loops. */ + Index *pPk = sqlite3PrimaryKeyIndex((Table*)pTab); + for(i=0; inKeyCol; i++){ + int iCol = pPk->aiColumn[i]; + pIdxInfo->colUsed |= (iCol>=BMS ? ALLBITS : MASKBIT(iCol)); + } + } pHidden->pWC = pWC; pHidden->pParse = pParse; pHidden->eDistinct = eDistinct; @@ -4216,7 +4226,6 @@ static int whereLoopAddVirtualOne( pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; - pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; pHidden->mHandleIn = 0; /* Invoke the virtual table xBestIndex() method */ diff --git a/test/bestindexD.test b/test/bestindexD.test new file mode 100644 index 0000000000..b06d6b4270 --- /dev/null +++ b/test/bestindexD.test @@ -0,0 +1,93 @@ +# 2024-08-03 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix bestindexD + +ifcapable !vtab { + finish_test + return +} + +register_tcl_module db + +proc vtab_command {method args} { + switch -- $method { + xConnect { + return "CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID" + } + + xBestIndex { + set hdl [lindex $args 0] + set ::colUsed [$hdl mask] + + set cost 1000000 + set used "" + + set cons 0 + foreach c [$hdl constraints] { + set cost [expr $cost/10] + append used " use $cons" + incr cons + } + + return "cost $cost rows $cost $used" + } + } + + return {} +} + +do_execsql_test 1.0 { + CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); + + CREATE TABLE t2(a, b); +} {} + +# This proc assumes that there is only one use of a virtual table - x1 - +# in SQL statement $sql. It tests that the colUsed value passed to the +# xBestIndex method matches the actual columns used, which is ascertained +# by searching the compiled VM code for VColumn instructions. +# +proc do_colsused_test {tn sql} { + set ::colUsed "" + execsql $sql + set got $::colUsed + + set expect 0 + db eval "EXPLAIN $sql" x { + if {$x(opcode)=="VColumn"} { + set expect [expr $expect | (1<<$x(p2))] + } + } + + uplevel [list do_test $tn.($expect/$got) [list expr ($expect & $got)] $expect] +} + +do_colsused_test 1.1 { SELECT a FROM x1 } +do_colsused_test 1.2 { SELECT a,c FROM x1 } +do_colsused_test 1.3 { SELECT b FROM x1 } +do_colsused_test 1.4 { SELECT b FROM x1 WHERE c=? } + +do_colsused_test 1.5 { + select 1 from t2 full join x1; +} + +do_colsused_test 1.6 { + select 1 from x1 WHERE (b=? AND c=?) OR (b=? AND c=?) +} + +finish_test + +