diff --git a/manifest b/manifest index 9590aa3ca2..8eaa4bfe54 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 82d7da5708..5b4998caed 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b1435f26b07b2208cfcca557f96342a5bd0d5328 \ No newline at end of file +2ea4a9f75f46eaa928ba17e9e91bc0432750d46d \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 83b948e8e1..204d696179 100644 --- a/src/expr.c +++ b/src/expr.c @@ -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; diff --git a/src/parse.y b/src/parse.y index aae30f5ee2..ef00925254 100644 --- a/src/parse.y +++ b/src/parse.y @@ -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); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 0974db7c91..55b7e080ae 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 */ diff --git a/test/in4.test b/test/in4.test index 5828a83cc5..0a4a75008b 100644 --- a/test/in4.test +++ b/test/in4.test @@ -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