]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Convert expressions of the form "X IN (?)" with exactly one value on the
authordrh <drh@noemail.net>
Thu, 20 Mar 2014 13:26:47 +0000 (13:26 +0000)
committerdrh <drh@noemail.net>
Thu, 20 Mar 2014 13:26:47 +0000 (13:26 +0000)
RHS of the IN into equality tests:  "X=?".  Add test cases to verify that
statements work correctly on this corner case.
Fix for ticket [e39d032577df6942].

FossilOrigin-Name: e68b427afbc82e201c64474117851aa4c9eb0c92

manifest
manifest.uuid
src/parse.y
src/where.c
test/in4.test

index 41cb481776a8676c30fe19b055266d80e564f0f3..16ca144d3ea49822e32ff01348ddc34123f9a6a2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\san\sunnecessarily\sobtuse\suse\sof\sa\sbitmask\sflag.
-D 2014-03-20T12:17:35.051
+C Convert\sexpressions\sof\sthe\sform\s"X\sIN\s(?)"\swith\sexactly\sone\svalue\son\sthe\nRHS\sof\sthe\sIN\sinto\sequality\stests:\s\s"X=?".\s\sAdd\stest\scases\sto\sverify\sthat\nstatements\swork\scorrectly\son\sthis\scorner\scase.\nFix\sfor\sticket\s[e39d032577df6942].
+D 2014-03-20T13:26:47.152
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -207,7 +207,7 @@ F src/os_unix.c 18f7f95dc6bcb9cf4d4a238d8e2de96611bc2ae5
 F src/os_win.c e71678ac927d0a0fb11d993db20a9748eabf808e
 F src/pager.c 97a8908bf4e6e7c3adea09d3597cfa48ae33ab4e
 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
-F src/parse.y 2613ca5d609c2f3d71dd297351f010bcec16e1e0
+F src/parse.y 52d749e7fd1289d9a576fe88782d9637a2f7bb6d
 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
 F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
@@ -291,7 +291,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
 F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
-F src/where.c e433accd201ca482c761e679f4a2ce2f6a7348e6
+F src/where.c a2f20bdc6565a3add38ac5e4d9e71523ed5b2f2b
 F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -593,7 +593,7 @@ F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
 F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
-F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
+F test/in4.test ed42587bed8c8e2219a09a6a6e3675edffc011da
 F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
 F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
@@ -1156,7 +1156,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 707ea170b3e26965b7e3982f7554d122d130b9a6
-R 829b1d227d22721b3fefbad8e2ead1b7
+P ca3140813198ab7ce470cf86334e55207f3461f9
+R abb091fc1f04a82c7540caf08b56e8dd
 U drh
-Z fcfbdaafabd38e7e728b08b0509fc847
+Z 8ed34cb3369a2d9b188815f2f4b333aa
index 444963914a24a7d883d97262dd51148053343878..6fc3864b4fb5e49897fd9775529ca3c39da7f8de 100644 (file)
@@ -1 +1 @@
-ca3140813198ab7ce470cf86334e55207f3461f9
\ No newline at end of file
+e68b427afbc82e201c64474117851aa4c9eb0c92
\ No newline at end of file
index ad9bedf0b477b66e8bad5456f6bd0fff6b82b1e1..1e6d859881feb6e3e10e1a27642343460eeddd34 100644 (file)
@@ -1020,6 +1020,21 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
       */
       A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
       sqlite3ExprDelete(pParse->db, X.pExpr);
+    }else if( Y->nExpr==1 ){
+      /* Expressions of the form:
+      **
+      **      expr1 IN (?1)
+      **      expr1 NOT IN (?2)
+      **
+      ** with exactly one value on the RHS can be simplified to:
+      **
+      **      expr1 == ?1
+      **      expr1 <> ?2
+      */
+      Expr *pRHS = Y->a[0].pExpr;
+      Y->a[0].pExpr = 0;
+      sqlite3ExprListDelete(pParse->db, Y);
+      A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0);
     }else{
       A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
       if( A.pExpr ){
index d13258ad66594ef32ffa060bff7b23a36565549c..e3ce8b8697d99bdf825d679caab8220c0317ef53 100644 (file)
@@ -4009,6 +4009,8 @@ static int whereLoopAddBtreeIndex(
         /* "x IN (value, value, ...)" */
         nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
       }
+      assert( nIn>0 );  /* RHS always has 2 or more terms...  The parser
+                        ** changes "x IN (?)" into "x=?". */
       pNew->rRun += nIn;
       pNew->u.btree.nEq++;
       pNew->nOut = nRowEst + nInMul + nIn;
index 470f4f0e346fed68ba79e4ebd5d2645a655834c1..b8ae4d9825a37ec5a82220e2de58f074a59f0d46 100644 (file)
@@ -159,4 +159,92 @@ do_test in4-3.12 {
   execsql { SELECT * FROM t3 WHERE x IN (1, 2) AND y IN ()}
 } {}
 
+# Tests for "... IN (?)" and "... NOT IN (?)".  In other words, tests
+# for when the RHS of IN is a single expression.  This should work the
+# same as the == and <> operators.
+#
+do_execsql_test in4-3.21 {
+  SELECT * FROM t3 WHERE x=10 AND y IN (10);
+} {10 10 10}
+do_execsql_test in4-3.22 {
+  SELECT * FROM t3 WHERE x IN (10) AND y=10;
+} {10 10 10}
+do_execsql_test in4-3.23 {
+  SELECT * FROM t3 WHERE x IN (10) AND y IN (10);
+} {10 10 10}
+do_execsql_test in4-3.24 {
+  SELECT * FROM t3 WHERE x=1 AND y NOT IN (10);
+} {1 1 1}
+do_execsql_test in4-3.25 {
+  SELECT * FROM t3 WHERE x  NOT IN (10) AND y=1;
+} {1 1 1}
+do_execsql_test in4-3.26 {
+  SELECT * FROM t3 WHERE x NOT IN (10) AND y NOT IN (10);
+} {1 1 1}
+
+# The query planner recognizes that "x IN (?)" only generates a
+# single match and can use this information to optimize-out ORDER BY
+# clauses.
+#
+do_execsql_test in4-3.31 {
+  DROP INDEX t3i1;
+  CREATE UNIQUE INDEX t3xy ON t3(x,y);
+
+  SELECT *, '|' FROM t3 A, t3 B
+   WHERE A.x=10 AND A.y IN (10)
+     AND B.x=1 AND B.y IN (1);
+} {10 10 10 1 1 1 |}
+do_execsql_test in4-3.32 {
+  EXPLAIN QUERY PLAN
+  SELECT *, '|' FROM t3 A, t3 B
+   WHERE A.x=10 AND A.y IN (10)
+     AND B.x=1 AND B.y IN (1);
+} {~/B-TREE/}  ;# No separate sorting pass
+do_execsql_test in4-3.33 {
+  SELECT *, '|' FROM t3 A, t3 B
+   WHERE A.x IN (10) AND A.y=10
+     AND B.x IN (1) AND B.y=1;
+} {10 10 10 1 1 1 |}
+do_execsql_test in4-3.34 {
+  EXPLAIN QUERY PLAN
+  SELECT *, '|' FROM t3 A, t3 B
+   WHERE A.x IN (10) AND A.y=10
+     AND B.x IN (1) AND B.y=1;
+} {~/B-TREE/}  ;# No separate sorting pass
+
+# An expression of the form "x IN (?,?)" creates an ephemeral table to
+# hold the list of values on the RHS.  But "x IN (?)" does not create
+# an ephemeral table.
+#
+do_execsql_test in4-3.41 {
+  SELECT * FROM t3 WHERE x IN (10,11);
+} {10 10 10}
+do_execsql_test in4-3.42 {
+  EXPLAIN
+  SELECT * FROM t3 WHERE x IN (10,11);
+} {/OpenEphemeral/}
+do_execsql_test in4-3.43 {
+  SELECT * FROM t3 WHERE x IN (10);
+} {10 10 10}
+do_execsql_test in4-3.44 {
+  EXPLAIN
+  SELECT * FROM t3 WHERE x IN (10);
+} {~/OpenEphemeral/}
+do_execsql_test in4-3.45 {
+  SELECT * FROM t3 WHERE x NOT IN (10,11);
+} {1 1 1}
+do_execsql_test in4-3.46 {
+  EXPLAIN
+  SELECT * FROM t3 WHERE x NOT IN (10,11);
+} {/OpenEphemeral/}
+do_execsql_test in4-3.47 {
+  SELECT * FROM t3 WHERE x NOT IN (10);
+} {1 1 1}
+do_execsql_test in4-3.48 {
+  EXPLAIN
+  SELECT * FROM t3 WHERE x NOT IN (10);
+} {~/OpenEphemeral/}
+
+
+
 finish_test