From: drh Date: Mon, 18 Apr 2016 16:12:04 +0000 (+0000) Subject: Fix a problem in the code generator for joins on virtual tables where the X-Git-Tag: version-3.12.2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=38e98808780f5110ca46e450cae66d7034601f6c;p=thirdparty%2Fsqlite.git Fix a problem in the code generator for joins on virtual tables where the outer loop of the join uses the IN operator. FossilOrigin-Name: a2cf49689642c2157288829e96c21c0de83e3a1b --- diff --git a/manifest b/manifest index 348b5c25e3..211533b3a7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\ssqlite3BtreeDelete()\sroutine\sso\sthat\sit\spreserves\sthe\scorrect\nkey\seven\swhen\sthe\srow\sbeing\sdeleted\sis\snot\son\sa\sleaf\spage.\nFix\sfor\sticket\s[a306e56ff68b8fa56] -D 2016-04-18T16:06:03.711 +C Fix\sa\sproblem\sin\sthe\scode\sgenerator\sfor\sjoins\son\svirtual\stables\swhere\sthe\nouter\sloop\sof\sthe\sjoin\suses\sthe\sIN\soperator. +D 2016-04-18T16:12:04.978 F Makefile.in f53429fb2f313c099283659d0df6f20f932c861f F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc b00bcf0ec7001857aea81ee39fae45d20f5f4e59 @@ -435,7 +435,7 @@ F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354 F src/where.c 99cc6270fc3915201e2a90bbac3768f007a89c44 F src/whereInt.h 93297d56edd137b7ea004490690fb6e2ce028a34 -F src/wherecode.c 863aedf086131743763c1960637fde904eadc442 +F src/wherecode.c 8fdad9fbba723df1c1e8d07e7ea8507572040340 F src/whereexpr.c fb87944b1254234e5bba671aaf6dee476241506a F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -497,7 +497,7 @@ F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c -F test/bestindex1.test d5ba89a7941a941476d8d69be39b146aaed3614c +F test/bestindex1.test 0cf1bd2d7b97d3a3a8c10736125274f64765c4ee F test/bestindex2.test 4a06b8922ab2fd09434870da8d1cdf525aaf7060 F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59 @@ -1459,8 +1459,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9c37e9ce07b42bdbaa0cecfdd2bc8181b1eded47 -Q +ca2ef8a86cf806cbbcc64db03251b1df5b2c5501 -R 4710e941720805c2cc7e949e21895ad6 +P 368e86c760477f2e646f71f6135b69d40eeb82e7 +Q +6c56b3a04778bc62ca50307ad838dd301cd91ac2 +R acf6a347f3f839bd74b9fc7a6f34fbf3 U drh -Z e361cdd0aa73a2909e88537a2c8c4051 +Z 542d8ddb7626d61cadebfc7721d64c25 diff --git a/manifest.uuid b/manifest.uuid index e879e4e2f6..baefd8fce3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -368e86c760477f2e646f71f6135b69d40eeb82e7 \ No newline at end of file +a2cf49689642c2157288829e96c21c0de83e3a1b \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index 3705aab51d..8105e99dde 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -941,7 +941,13 @@ Bitmask sqlite3WhereCodeOneLoopStart( } } } - sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + /* These registers need to be preserved in case there is an IN operator + ** loop. So we could deallocate the registers here (and potentially + ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems + ** simpler and safer to simply not reuse the registers. + ** + ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + */ sqlite3ExprCachePop(pParse); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ diff --git a/test/bestindex1.test b/test/bestindex1.test index 97ae4b0f81..f90f96bf44 100644 --- a/test/bestindex1.test +++ b/test/bestindex1.test @@ -165,4 +165,111 @@ foreach {tn mode} { } $plan($mode) } +# 2016-04-09. +# Demonstrate a register overwrite problem when using two virtual +# tables where the outer loop uses the IN operator. +# +set G(collist) [list PrimaryKey flagA columnA] +set G(cols) [join $G(collist) ,] +set G(nulls) "NULL" + +proc vtab_command {method args} { + global G + + switch -- $method { + xConnect { + return "CREATE TABLE t1($G(cols))" + } + + xBestIndex { + set clist [lindex $args 0] + #puts $clist + set W [list] + set U [list] + + set i 0 + for {set idx 0} {$idx < [llength $clist]} {incr idx} { + array set c [lindex $clist $idx] + if {$c(op)=="eq" && $c(usable)} { + lappend W "[lindex $G(collist) $c(column)] = %$i%" + lappend U use $idx + incr i + } + } + + if {$W==""} { + set sql "SELECT rowid, * FROM t1" + } else { + set sql "SELECT rowid, * FROM t1 WHERE [join $W { AND }]" + } + + return [concat [list idxstr $sql] $U] + } + + xFilter { + foreach {idxnum idxstr vals} $args {} + + set map [list] + for {set i 0} {$i < [llength $vals]} {incr i} { + lappend map "%$i%" + set v [lindex $vals $i] + if {[string is integer $v]} { + lappend map $v + } else { + lappend map "'$v'" + } + } + set sql [string map $map $idxstr] + + #puts "SQL: $sql" + return [list sql $sql] + } + } + + return {} +} + +db close +forcedelete test.db +sqlite3 db test.db +register_tcl_module db + +do_execsql_test 3.1 " + CREATE TABLE t1($G(cols)); + INSERT INTO t1 VALUES(1, 0, 'ValueA'); + INSERT INTO t1 VALUES(2, 0, 'ValueA'); + INSERT INTO t1 VALUES(3, 0, 'ValueB'); + INSERT INTO t1 VALUES(4, 0, 'ValueB'); +" + +do_execsql_test 3.2 { + CREATE VIRTUAL TABLE VirtualTableA USING tcl(vtab_command); + CREATE VIRTUAL TABLE VirtualTableB USING tcl(vtab_command); +} + +do_execsql_test 3.3 { SELECT primarykey FROM VirtualTableA } {1 2 3 4} + +do_execsql_test 3.4 { + SELECT * FROM + VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey + WHERE a.ColumnA IN ('ValueA', 'ValueB') AND a.FlagA=0 +} { + 1 0 ValueA 1 0 ValueA + 2 0 ValueA 2 0 ValueA + 3 0 ValueB 3 0 ValueB + 4 0 ValueB 4 0 ValueB +} + +do_execsql_test 3.5 { + SELECT * FROM + VirtualTableA a CROSS JOIN VirtualTableB b ON b.PrimaryKey=a.PrimaryKey + WHERE a.FlagA=0 AND a.ColumnA IN ('ValueA', 'ValueB') +} { + 1 0 ValueA 1 0 ValueA + 2 0 ValueA 2 0 ValueA + 3 0 ValueB 3 0 ValueB + 4 0 ValueB 4 0 ValueB +} + + finish_test