]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Make the result of an IN or NOT IN expression with an empty set on the
authordrh <drh@noemail.net>
Wed, 14 Jul 2010 18:24:06 +0000 (18:24 +0000)
committerdrh <drh@noemail.net>
Wed, 14 Jul 2010 18:24:06 +0000 (18:24 +0000)
right-hand side always either false or true, respectively, even if the
left-hand side is NULL.  Ticket [80e031a00f45dc]

FossilOrigin-Name: c288ac644d0bfda2b9bc204dc86df8e74d4f6843

manifest
manifest.uuid
src/expr.c
src/global.c
src/parse.y
src/sqliteInt.h
test/tkt-80e031a00f.test [new file with mode: 0644]

index 208e02b1a640f20d8cfcf7d6f3f7aea1371c5abb..ec05b283d69eba76f14a2c78e0cd3152a370e9b1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,8 @@
-C Fix\san\sassert()\sfailure\sin\swal2.test\scaused\sby\smessing\swith\sthe\scontents\sof\sshared\smemory.
-D 2010-07-14T18:10:03
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C Make\sthe\sresult\sof\san\sIN\sor\sNOT\sIN\sexpression\swith\san\sempty\sset\son\sthe\s\nright-hand\sside\salways\seither\sfalse\sor\strue,\srespectively,\seven\sif\sthe\nleft-hand\sside\sis\sNULL.\s\sTicket\s[80e031a00f45dc]
+D 2010-07-14T18:24:06
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -122,11 +125,11 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
 F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
 F src/delete.c 41cb4f78557810eecc167b7e2317de7e12d20929
-F src/expr.c 7b1df28226b8a2bb2b9d7c794a42818a81f5edd8
+F src/expr.c 92ff9389ab774922e988c1488087f84a9f2dc09d
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
 F src/func.c 0c28599430856631216b6c0131c51c89bf516026
-F src/global.c 3fedfe02f1b2b1f6118455c881d132b804a1f0a7
+F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
@@ -158,7 +161,7 @@ F src/os_unix.c 417a378a1941b9203d2613c082133fee85199f74
 F src/os_win.c 61734aad7f50b28f3c76eb4b19b63472f6d825d9
 F src/pager.c 78ca1e1f3315c8227431c403c04d791dccf242fb
 F src/pager.h 879fdde5a102d2f21a3135d6f647530b21c2796c
-F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
+F src/parse.y 3d7f529e00d621953af155d2bc64511710619745
 F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
 F src/pcache1.c 3a7c28f46a61b43ff0b5c087a7983c154f4b264c
@@ -172,7 +175,7 @@ F src/select.c 4903ff1bbd08b55cbce00ea43c645530de41b362
 F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
 F src/sqlite.h.in c394e27c259dff2de8b5939ecddd30262eb901ad
 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
-F src/sqliteInt.h 8e3bc49a0e9217ff489a6b8f70cfcba0f5ad7437
+F src/sqliteInt.h d9e42f2029d4c526f9ba960bda1980ef17429c30
 F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
 F src/status.c 4df6fe7dce2d256130b905847c6c60055882bdbe
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -636,6 +639,7 @@ F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
 F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
 F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
 F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527
+F test/tkt-80e031a00f.test ee36b2d166c413392d90b97a978754f762e3cc37
 F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f
 F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
 F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589
@@ -834,7 +838,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 45bb84c6283d803fc29077fdc2d06fa50ec06a59
-R 6afba8a53d6303169f23fc8d1371e421
-U dan
-Z 85a69e887995213762e743af65322fda
+P 9f452514d96ab8d424eadc55c283c53fe831476d
+R 0696a4857e0fc2e6e3cb38528ebe2bf1
+U drh
+Z eaca9dffd50a6ab2db3b5e0788a52b1d
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQFMPgDNoxKgR168RlERAodgAJ4kq+hDLacVgaUBEnEKpkM8L28pOgCfXevs
+u11vnZz3vLbMyWPx174qXyI=
+=mydy
+-----END PGP SIGNATURE-----
index 5c59a8c2564c0c4f921426b3e0c1f9b1bdf67f0f..afccf60106c3ea7a7de6afbd0d1ea295ad056874 100644 (file)
@@ -1 +1 @@
-9f452514d96ab8d424eadc55c283c53fe831476d
\ No newline at end of file
+c288ac644d0bfda2b9bc204dc86df8e74d4f6843
\ No newline at end of file
index b776979619ebc26aba8f77d11884653406e96038..8ddf473b2346bebea1dc5b8d1b04605d8f2cd7e0 100644 (file)
@@ -1705,7 +1705,6 @@ int sqlite3CodeSubselect(
       ** an integer 0 (not exists) or 1 (exists) into a memory cell
       ** and record that memory cell in iColumn.
       */
-      static const Token one = { "1", 1 };  /* Token for literal value 1 */
       Select *pSel;                         /* SELECT statement to encode */
       SelectDest dest;                      /* How to deal with SELECt result */
 
@@ -1726,7 +1725,8 @@ int sqlite3CodeSubselect(
         VdbeComment((v, "Init EXISTS result"));
       }
       sqlite3ExprDelete(pParse->db, pSel->pLimit);
-      pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one);
+      pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
+                                  &sqlite3IntTokens[1]);
       if( sqlite3Select(pParse, pSel, &dest) ){
         return 0;
       }
@@ -1794,8 +1794,20 @@ static void sqlite3ExprCodeIN(
   sqlite3ExprCachePush(pParse);
   r1 = sqlite3GetTempReg(pParse);
   sqlite3ExprCode(pParse, pExpr->pLeft, r1);
-  sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull);
 
+  /* If the LHS is NULL, then the result is either false or NULL depending
+  ** on whether the RHS is empty or not, respectively.
+  */
+  if( destIfNull==destIfFalse ){
+    /* Shortcut for the common case where the false and NULL outcomes are
+    ** the same. */
+    sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull);
+  }else{
+    int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1);
+    sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
+    sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
+    sqlite3VdbeJumpHere(v, addr1);
+  }
 
   if( eType==IN_INDEX_ROWID ){
     /* In this case, the RHS is the ROWID of table b-tree
index d2dbe4aebe9a7dc8957edb4a059672cf97bd6056..0c890684d97b623de7a5a38fa56d7b0268fb2d32 100644 (file)
@@ -176,6 +176,15 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
 */
 SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
 
+/*
+** Constant tokens for values 0 and 1.
+*/
+const Token sqlite3IntTokens[] = {
+   { "0", 1 },
+   { "1", 1 }
+};
+
+
 /*
 ** The value of the "pending" byte must be 0x40000000 (1 byte past the
 ** 1-gibabyte boundary) in a compatible database.  SQLite never uses
index 98714ee343ab7092f4a43c67d86d3a321928777f..1f54a6ff3912535f26fc6c32d666ca91afa0ffb8 100644 (file)
@@ -959,14 +959,27 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
   in_op(A) ::= IN.      {A = 0;}
   in_op(A) ::= NOT IN.  {A = 1;}
   expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] {
-    A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
-    if( A.pExpr ){
-      A.pExpr->x.pList = Y;
-      sqlite3ExprSetHeight(pParse, A.pExpr);
+    if( Y==0 ){
+      // Expressions of the form
+      //
+      //      expr1 IN ()
+      //      expr1 NOT IN ()
+      //
+      // simplify to constants 0 (false) and 1 (true), respectively,
+      // regardless of the value of expr1.
+      //
+      A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
+      sqlite3ExprDelete(pParse->db, X.pExpr);
     }else{
-      sqlite3ExprListDelete(pParse->db, Y);
+      A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
+      if( A.pExpr ){
+        A.pExpr->x.pList = Y;
+        sqlite3ExprSetHeight(pParse, A.pExpr);
+      }else{
+        sqlite3ExprListDelete(pParse->db, Y);
+      }
+      if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
     }
-    if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
     A.zStart = X.zStart;
     A.zEnd = &E.z[E.n];
   }
index 154116e90b084e651bbd5fa0452f872dcb7f3bd1..15fedf52d452c321954c4faa25c4b91db25a6f2c 100644 (file)
@@ -2890,6 +2890,7 @@ void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
 extern const unsigned char sqlite3OpcodeProperty[];
 extern const unsigned char sqlite3UpperToLower[];
 extern const unsigned char sqlite3CtypeMap[];
+extern const Token sqlite3IntTokens[];
 extern SQLITE_WSD struct Sqlite3Config sqlite3Config;
 extern SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
 #ifndef SQLITE_OMIT_WSD
diff --git a/test/tkt-80e031a00f.test b/test/tkt-80e031a00f.test
new file mode 100644 (file)
index 0000000..52a6cef
--- /dev/null
@@ -0,0 +1,49 @@
+# 2010 July 14
+#
+# 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.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. Specifically,
+# it tests that ticket [80e031a00f45dca877ed92b225209cfa09280f4f] has been
+# resolved.  That ticket is about IN and NOT IN operators with empty-set
+# right-hand sides.  Such expressions should always return TRUE or FALSE
+# even if the left-hand side is NULL.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+source $testdir/malloc_common.tcl
+
+do_execsql_test tkt-80e031a00f.1 {SELECT 1 IN ()} 0
+do_execsql_test tkt-80e031a00f.2 {SELECT 1 NOT IN ()} 1
+do_execsql_test tkt-80e031a00f.3 {SELECT null IN ()} 0
+do_execsql_test tkt-80e031a00f.4 {SELECT null NOT IN ()} 1
+do_execsql_test tkt-80e031a00f.5 {
+  CREATE TABLE t1(x);
+  SELECT 1 IN t1;
+} 0
+do_execsql_test tkt-80e031a00f.6 {SELECT 1 NOT IN t1} 1
+do_execsql_test tkt-80e031a00f.7 {SELECT null IN t1} 0
+do_execsql_test tkt-80e031a00f.8 {SELECT null NOT IN t1} 1
+do_execsql_test tkt-80e031a00f.9 {
+  CREATE TABLE t2(y INTEGER PRIMARY KEY);
+  SELECT 1 IN t2;
+} 0
+do_execsql_test tkt-80e031a00f.10 {SELECT 1 NOT IN t2} 1
+do_execsql_test tkt-80e031a00f.11 {SELECT null IN t2} 0
+do_execsql_test tkt-80e031a00f.12 {SELECT null NOT IN t2} 1
+do_execsql_test tkt-80e031a00f.9 {
+  CREATE TABLE t3(z INT UNIQUE);
+  SELECT 1 IN t3;
+} 0
+do_execsql_test tkt-80e031a00f.13 {SELECT 1 NOT IN t3} 1
+do_execsql_test tkt-80e031a00f.14 {SELECT null IN t3} 0
+do_execsql_test tkt-80e031a00f.15 {SELECT null NOT IN t3} 1
+
+finish_test