From: dan Date: Mon, 10 Sep 2018 12:17:16 +0000 (+0000) Subject: Fix a problem with processing a "vtab.col IS NULL" expression within X-Git-Tag: version-3.25.0~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eb3fe0b9d45a70753b6e764f1d67a7eae9d89bdd;p=thirdparty%2Fsqlite.git Fix a problem with processing a "vtab.col IS NULL" expression within the WHERE clause of a query when "vtab" is a virtual table on the rhs of a LEFT JOIN. FossilOrigin-Name: 83da4d4104ee1870a2a95bb5fa15ee6584c655d8b314b6b8ab97592dad4ee811 --- diff --git a/manifest b/manifest index 3bd96cd52d..fd0a13639c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sunreachable\sbranch\sin\sthe\snew\ssqlite3WhereOrderByLimitOptLabel()\nfunction\sof\sthe\squery\splanner. -D 2018-09-08T20:29:04.477 +C Fix\sa\sproblem\swith\sprocessing\sa\s"vtab.col\sIS\sNULL"\sexpression\swithin\nthe\sWHERE\sclause\sof\sa\squery\swhen\s"vtab"\sis\sa\svirtual\stable\son\sthe\srhs\sof\sa\nLEFT\sJOIN. +D 2018-09-10T12:17:16.759 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 6b650013511fd9d8b094203ac268af9220d292cc7d4e1bc9fbca15aacd8c7995 @@ -586,7 +586,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c df50883d93689d009be5ad9bdc4e53a4ee45fcc291087ec9272569d00b360791 F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4 -F src/where.c ff7f4024cba3d7619dd92239d006364d8c836037afb5c4f8ebf861c9a360b8f3 +F src/where.c 071572677469d54899ef0d9fc3ad380a849b860375df5af5ebdc4f49f1dc20cc F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 F src/wherecode.c 2b6cd1b27736cc803060289e04ecf9849976106f4077aa67d1a2c0e3ec420159 F src/whereexpr.c d87df2c00ecc0c2ef4409562608d19cec259a6a03ca72b86fc999db9c07ce119 @@ -665,6 +665,7 @@ F test/bestindex2.test 9a0ccd320b6525eec3a706aae6cdab7e1b7b5abca75027e39f39f755e F test/bestindex3.test 001788a114ad96d81d5154fe77c7f1e26e84b3a2b5635ca29e4f96f6decc534e F test/bestindex4.test 4cb5ff7dbaebadb87d366f51969271778423b455 F test/bestindex5.test 412b42f8036b28d8b2f3534d89389ad946a4b1a65a12263f51936f7424296f1b +F test/bestindex6.test d856a9bb63d927493575823eed44053bc36251e241aa364e54d0f2a2d302e1d4 F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc @@ -1764,7 +1765,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 206720129ed2fa8875a286266d05b99fb2caf8671e4b74b26a6286a2073fcd8b -R c6d02a1d720ce0f314484950383248d6 -U drh -Z 283f6327b802e617589c73f6c602d59b +P 5a954533edbde58aa7158572ece7ceeb1c6e610b71f3ae45d0b8371d74f9fea5 +R 756e7ce3d56663b883e7e3032dfd4880 +U dan +Z f6d9c644621f4f427fb7da91247b3ddb diff --git a/manifest.uuid b/manifest.uuid index 103a7d6784..7770ef4c64 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5a954533edbde58aa7158572ece7ceeb1c6e610b71f3ae45d0b8371d74f9fea5 \ No newline at end of file +83da4d4104ee1870a2a95bb5fa15ee6584c655d8b314b6b8ab97592dad4ee811 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 1146323d9d..61c671ac21 100644 --- a/src/where.c +++ b/src/where.c @@ -966,6 +966,18 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; + if( (pSrc->fg.jointype & JT_LEFT)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && (pTerm->eOperator & (WO_IS|WO_ISNULL)) + ){ + /* An "IS" term in the WHERE clause where the virtual table is the rhs + ** of a LEFT JOIN. Do not pass this term to the virtual table + ** implementation, as this can lead to incorrect results from SQL such + ** as: + ** + ** "LEFT JOIN vtab WHERE vtab.col IS NULL" */ + continue; + } assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; diff --git a/test/bestindex6.test b/test/bestindex6.test new file mode 100644 index 0000000000..8396d07ce0 --- /dev/null +++ b/test/bestindex6.test @@ -0,0 +1,109 @@ +# 2018-09-09 +# +# 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 bestindex6 + +ifcapable !vtab { + finish_test + return +} + +register_tcl_module db + +proc vtab_command {src method args} { + switch -- $method { + xConnect { + return [db one {SELECT sql FROM sqlite_master where name = $src}] + } + + xBestIndex { + set clist [lindex $args 0] + set wlist 1 + + set iCons 0 + set ret [list] + foreach cons $clist { + catch { array unset C } + array set C $cons + + if {$C(usable)} { + set col [db one { + SELECT name FROM pragma_table_info($src) WHERE cid=$C(column) + }] + switch $C(op) { + isnull { + lappend wlist "$col IS NULL" + lappend ret omit $iCons + } + eq { + lappend wlist "$col = %$iCons%" + lappend ret omit $iCons + } + } + } + incr iCons + } + #puts "xBestIndex: $ret" + lappend ret idxStr [join $wlist " AND "] + return $ret + } + + xFilter { + foreach {idxnum idxstr aa} $args {} + set map [list] + for {set iCons 0} {$iCons < [llength $aa]} {incr iCons} { + lappend map %$iCons% [lindex $aa $iCons] + } + set ret [list sql \ + "SELECT rowid, * FROM $src WHERE [string map $map $idxstr]" + ] + # puts "xFilter: $ret" + return $ret + } + + } + + return {} +} + +do_execsql_test 1.0 { + CREATE TABLE t1(id int, value text); + CREATE TABLE t2(ctx int, id int, value text); + + INSERT INTO t1 VALUES(1,'try'); + INSERT INTO t2 VALUES(1,1,'good'); + INSERT INTO t2 VALUES(2,2,'evil'); + + CREATE VIRTUAL TABLE vt1 USING tcl(vtab_command t1); + CREATE VIRTUAL TABLE vt2 USING tcl(vtab_command t2); +} + +do_execsql_test 1.1 { + select * from t2 left join t1 on t1.id=t2.ctx where t1.value is null; +} {2 2 evil {} {}} + +do_execsql_test 1.2 { + select * from vt2 left join vt1 on vt1.id=vt2.ctx where vt1.value is null; +} {2 2 evil {} {}} + +unset -nocomplain xxx +do_execsql_test 1.3 { + select * from vt2 left join vt1 on vt1.id=vt2.ctx where vt1.value is $xxx; +} {2 2 evil {} {}} + +do_execsql_test 1.4 { + select * from t2 left join vt1 on vt1.id=t2.ctx where vt1.value = 3 +} {} + +finish_test