]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problem with processing a "vtab.col IS NULL" expression within
authordan <dan@noemail.net>
Mon, 10 Sep 2018 12:17:16 +0000 (12:17 +0000)
committerdan <dan@noemail.net>
Mon, 10 Sep 2018 12:17:16 +0000 (12:17 +0000)
the WHERE clause of a query when "vtab" is a virtual table on the rhs of a
LEFT JOIN.

FossilOrigin-Name: 83da4d4104ee1870a2a95bb5fa15ee6584c655d8b314b6b8ab97592dad4ee811

manifest
manifest.uuid
src/where.c
test/bestindex6.test [new file with mode: 0644]

index 3bd96cd52df3790aeed8c0d2033c51e9e233d4e8..fd0a13639cd513b52f289f3272e50674a0a59163 100644 (file)
--- 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
index 103a7d678456da43fd2ba513b2fae220197d4764..7770ef4c64bc4ae346d5e7fbd719016f04655232 100644 (file)
@@ -1 +1 @@
-5a954533edbde58aa7158572ece7ceeb1c6e610b71f3ae45d0b8371d74f9fea5
\ No newline at end of file
+83da4d4104ee1870a2a95bb5fa15ee6584c655d8b314b6b8ab97592dad4ee811
\ No newline at end of file
index 1146323d9dd4e16084c9de6df2980918d7ff2e4a..61c671ac211e92b88ffd2f62742c1d6ada72322e 100644 (file)
@@ -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 (file)
index 0000000..8396d07
--- /dev/null
@@ -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