]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
The "x IN (?)" optimization in check-ins [2ff3b25f40] and [e68b427afb] is
authordrh <drh@noemail.net>
Thu, 20 Mar 2014 17:03:30 +0000 (17:03 +0000)
committerdrh <drh@noemail.net>
Thu, 20 Mar 2014 17:03:30 +0000 (17:03 +0000)
incorrect, as demonstrated by the in4-5.1 test case in this check-in.
The "COLLATE binary" that was being added to the RHS of IN was overriding
the implicit collating sequence of the LHS.  This change defines the EP_Generic
expression node property that blocks all affinity or collating sequence
information in the expression subtree and adds that property to the expression
taken from RHS of the IN operator.

FossilOrigin-Name: 2ea4a9f75f46eaa928ba17e9e91bc0432750d46d

manifest
manifest.uuid
src/expr.c
src/parse.y
src/sqliteInt.h
test/in4.test

index 9590aa3ca2f3c07386c2440ddd7ea6e4ce6c5e2c..8eaa4bfe54f12112b1f7e1ac6932531f50bf3df3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sharmless\scompiler\swarnings.
-D 2014-03-20T15:14:08.664
+C The\s"x\sIN\s(?)"\soptimization\sin\scheck-ins\s[2ff3b25f40]\sand\s[e68b427afb]\sis\nincorrect,\sas\sdemonstrated\sby\sthe\sin4-5.1\stest\scase\sin\sthis\scheck-in.\nThe\s"COLLATE\sbinary"\sthat\swas\sbeing\sadded\sto\sthe\sRHS\sof\sIN\swas\soverriding\nthe\simplicit\scollating\ssequence\sof\sthe\sLHS.\s\sThis\schange\sdefines\sthe\sEP_Generic\nexpression\snode\sproperty\sthat\sblocks\sall\saffinity\sor\scollating\ssequence\ninformation\sin\sthe\sexpression\ssubtree\sand\sadds\sthat\sproperty\sto\sthe\sexpression\ntaken\sfrom\sRHS\sof\sthe\sIN\soperator.
+D 2014-03-20T17:03:30.667
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -173,7 +173,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
 F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
 F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280
-F src/expr.c b74939e7935c4ad9e7f87b31ce05713fd5dafc3a
+F src/expr.c 16ea9cefe7c8f998816b4eb8b8e7a88f0d2d3797
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
 F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
@@ -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 d21075457487f84a72f848c2545e3319d6452e6f
+F src/parse.y fb3280d85a103f623e5cf551b5b96b9df33151ac
 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
 F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
@@ -222,7 +222,7 @@ F src/shell.c bab4de12b441369491812ecc93212ff4deda68fa
 F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h db6d7cf6e44d1c862f4f5290716098a0b90f1310
+F src/sqliteInt.h 42acfa3d3b793822915ceb7e83c0cbc774d37d66
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -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 18202389003284e8e019750c04e4bc6333df9c99
+F test/in4.test 41c1c031aa46b1eb4411df2687ed2ed498da23b5
 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 2ff3b25f40fd117c8a2da1d1a3625f6b167b7b16
-R b4897cbb8b99db805aa2642c2b5c6a8f
+P b1435f26b07b2208cfcca557f96342a5bd0d5328
+R a33b75c3e29794aff199068a6fe53400
 U drh
-Z 8f62a0caca3ff37dd6879b77616b6faf
+Z 9b4a07b9ddb6d1760a1f90c03adda56a
index 82d7da57088500ab93c8212e439f3ee4d7defe17..5b4998caed9befb4858863aa72f783bd9b58f458 100644 (file)
@@ -1 +1 @@
-b1435f26b07b2208cfcca557f96342a5bd0d5328
\ No newline at end of file
+2ea4a9f75f46eaa928ba17e9e91bc0432750d46d
\ No newline at end of file
index 83b948e8e1167c9f85e18d5717d6643251cbb800..204d69617936df092fe8594d6e414a56a02b91df 100644 (file)
@@ -33,6 +33,7 @@
 char sqlite3ExprAffinity(Expr *pExpr){
   int op;
   pExpr = sqlite3ExprSkipCollate(pExpr);
+  if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
   op = pExpr->op;
   if( op==TK_SELECT ){
     assert( pExpr->flags&EP_xIsSelect );
@@ -122,6 +123,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
   Expr *p = pExpr;
   while( p ){
     int op = p->op;
+    if( p->flags & EP_Generic ) break;
     if( op==TK_CAST || op==TK_UPLUS ){
       p = p->pLeft;
       continue;
index aae30f5ee2f87aa2ea37c9f9d695c857592e2d4a..ef00925254c0627784196d8208080b018421b31b 100644 (file)
@@ -1026,15 +1026,24 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
       **      expr1 IN (?1)
       **      expr1 NOT IN (?2)
       **
-      ** with exactly one value on the RHS can be simplified to:
+      ** with exactly one value on the RHS can be simplified to something
+      ** like this:
       **
-      **      expr1 == (+?1 COLLATE binary)
-      **      expr1 <> (+?2 COLLATE binary)
+      **      expr1 == ?1
+      **      expr1 <> ?2
+      **
+      ** But, the RHS of the == or <> is marked with the EP_Generic flag
+      ** so that it may not contribute to the computation of comparison
+      ** affinity or the collating sequence to use for comparison.  Otherwise,
+      ** the semantics would be subtly different from IN or NOT IN.
       */
-      Expr *pRHS = sqlite3ExprAddCollateString(pParse, Y->a[0].pExpr, "binary");
+      Expr *pRHS = Y->a[0].pExpr;
       Y->a[0].pExpr = 0;
       sqlite3ExprListDelete(pParse->db, Y);
-      pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0, 0);
+      if( pRHS ){
+        pRHS->flags &= ~EP_Collate;
+        pRHS->flags |= EP_Generic;
+      }
       A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0);
     }else{
       A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
index 0974db7c919379ff6461745c98027f4306012339..55b7e080ae4fb46198e217d9645f34085d8308d0 100644 (file)
@@ -1893,8 +1893,8 @@ struct Expr {
 #define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
 #define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
 #define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
-#define EP_Collate   0x000100 /* Tree contains a TK_COLLATE opeartor */
-      /* unused      0x000200 */
+#define EP_Collate   0x000100 /* Tree contains a TK_COLLATE operator */
+#define EP_Generic   0x000200 /* Ignore COLLATE or affinity on this tree */
 #define EP_IntValue  0x000400 /* Integer value contained in u.iValue */
 #define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
 #define EP_Skip      0x001000 /* COLLATE, AS, or UNLIKELY */
index 5828a83cc54f68677bdff14f7c096e58266ee56e..0a4a75008bd3a1a1617c45914ef1af83854ad68f 100644 (file)
@@ -302,8 +302,38 @@ do_execsql_test in4-4.19 {
   SELECT c FROM t4b WHERE +b IN (a);
 } {}
 
+do_execsql_test in4-5.1 {
+  CREATE TABLE t5(c INTEGER PRIMARY KEY, d TEXT COLLATE nocase);
+  INSERT INTO t5 VALUES(17, 'fuzz');
+  SELECT 1 FROM t5 WHERE 'fuzz' IN (d);  -- match
+  SELECT 2 FROM t5 WHERE 'FUZZ' IN (d);  -- no match
+  SELECT 3 FROM t5 WHERE d IN ('fuzz');  -- match
+  SELECT 4 FROM t5 WHERE d IN ('FUZZ');  -- match
+} {1 3 4}
 
+# An expression of the form "x IN (y)" can be used as "x=y" by the
+# query planner when computing transitive constraints or to run the
+# query using an index on y.
+#
+do_execsql_test in4-6.1 {
+  CREATE TABLE t6a(a INTEGER PRIMARY KEY, b);
+  INSERT INTO t6a VALUES(1,2),(3,4),(5,6);
+  CREATE TABLE t6b(c INTEGER PRIMARY KEY, d);
+  INSERT INTO t6b VALUES(4,44),(5,55),(6,66);
 
+  SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
+} {3 4 4 44}
+do_execsql_test in4-6.1-eqp {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
+} {~/SCAN/}
+do_execsql_test in4-6.2 {
+  SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
+} {3 4 4 44}
+do_execsql_test in4-6.2-eqp {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
+} {~/SCAN/}
 
 
 finish_test