Merge trunk fixes for "x IN (?)" handling.
FossilOrigin-Name: eca35871c34374ca9189c7c9b6d490ac3c30357f
This commit is contained in:
commit
f9f1bdb0c8
24
manifest
24
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\sthe\svdbesort.c\soptimization\sfrom\strunk.
|
||||
D 2014-03-19T23:42:51.606
|
||||
C Merge\strunk\sfixes\sfor\s"x\sIN\s(?)"\shandling.
|
||||
D 2014-03-20T20:56:49.315
|
||||
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 e33fa25d2279c692ad899695cfb93db840498b65
|
||||
F src/expr.c da2b3cb41081af6b56e95e7c9e95949564ce2e21
|
||||
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 2613ca5d609c2f3d71dd297351f010bcec16e1e0
|
||||
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
@ -218,11 +218,11 @@ F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 12534449e77ff54fca5d3e9fcddc10031b13fbc1
|
||||
F src/shell.c bab4de12b441369491812ecc93212ff4deda68fa
|
||||
F src/shell.c cee9f46f2688a261601b1fd3d7f4b3cddf9b5cdf
|
||||
F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 03f7d4deeaa1a9558df62f6df7bc907bb473fcea
|
||||
F src/sqliteInt.h dc37150ad6c98e7121fa0adbe243e89a12e16525
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -285,13 +285,13 @@ F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
|
||||
F src/vdbeaux.c 5078ca7de4fd5ba4535bd17fe44d5b56c2d3294c
|
||||
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
|
||||
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
|
||||
F src/vdbesort.c 17336685efeef61170485b273cb14b3f1c68130e
|
||||
F src/vdbesort.c 4abb7c0f8f19b7d7d82f4558d5da1a30fdf9ea38
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 7c74debe2e76711082d6cb503aa89dd2afaf84cf
|
||||
F src/where.c d6d99a4d83c58dfdd66cd9d93d41a22f3488e31c
|
||||
F src/whereInt.h 2564055b440e44ebec8b47f237bbccae6719b7af
|
||||
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 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 01afbf97c0ff29667806e9a7c4d74ca717819de5 707ea170b3e26965b7e3982f7554d122d130b9a6
|
||||
R 8822581e4a84d2f390bdca26ebdb6cc0
|
||||
P e4bfffb988283c077778c60696be0d285ad66c3c d5a1530bdc7ace053d05d1a037551110021d3758
|
||||
R a45d230e7f98fec92659279ce8b3552c
|
||||
U drh
|
||||
Z db1037b5faa49e6de7af132643ccdf5b
|
||||
Z 027a45adb600d40b2564e06474072c41
|
||||
|
@ -1 +1 @@
|
||||
e4bfffb988283c077778c60696be0d285ad66c3c
|
||||
eca35871c34374ca9189c7c9b6d490ac3c30357f
|
@ -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 );
|
||||
@ -65,7 +66,11 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
** If a memory allocation error occurs, that fact is recorded in pParse->db
|
||||
** and the pExpr parameter is returned unchanged.
|
||||
*/
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
|
||||
Expr *sqlite3ExprAddCollateToken(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
|
||||
const Token *pCollName /* Name of collating sequence */
|
||||
){
|
||||
if( pCollName->n>0 ){
|
||||
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
|
||||
if( pNew ){
|
||||
@ -118,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;
|
||||
@ -1628,7 +1634,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}else{
|
||||
testcase( pParse->nQueryLoop>0 );
|
||||
pParse->nQueryLoop = 0;
|
||||
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
|
||||
eType = IN_INDEX_ROWID;
|
||||
|
27
src/parse.y
27
src/parse.y
@ -1020,6 +1020,33 @@ 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 something
|
||||
** like this:
|
||||
**
|
||||
** 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 = Y->a[0].pExpr;
|
||||
Y->a[0].pExpr = 0;
|
||||
sqlite3ExprListDelete(pParse->db, Y);
|
||||
/* pRHS cannot be NULL because a malloc error would have been detected
|
||||
** before now and control would have never reached this point */
|
||||
if( ALWAYS(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);
|
||||
if( A.pExpr ){
|
||||
|
@ -1195,7 +1195,8 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
|
||||
int iOp; /* Index of operation in p->aiIndent[] */
|
||||
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
|
||||
"NextIfOpen", "PrevIfOpen", 0 };
|
||||
const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
|
||||
const char *azGoto[] = { "Goto", 0 };
|
||||
|
||||
|
@ -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 */
|
||||
@ -3290,7 +3290,7 @@ int sqlite3ReadSchema(Parse *pParse);
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
|
||||
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
|
||||
Expr *sqlite3ExprSkipCollate(Expr*);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
|
@ -1010,12 +1010,12 @@ int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
|
||||
** a value equivalent to pIter2. So set pKey2 to NULL to prevent
|
||||
** vdbeSorterCompare() from decoding pIter2 again. */
|
||||
if( iRes<=0 ){
|
||||
pSorter->aTree[i] = (pIter1 - pSorter->aIter);
|
||||
pSorter->aTree[i] = (int)(pIter1 - pSorter->aIter);
|
||||
pIter2 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
|
||||
pKey2 = pIter2->aKey;
|
||||
}else{
|
||||
if( pIter1->pFile ) pKey2 = 0;
|
||||
pSorter->aTree[i] = (pIter2 - pSorter->aIter);
|
||||
pSorter->aTree[i] = (int)(pIter2 - pSorter->aIter);
|
||||
pIter1 = &pSorter->aIter[ pSorter->aTree[i ^ 0x0001] ];
|
||||
}
|
||||
|
||||
|
@ -3211,8 +3211,7 @@ static Bitmask codeOneLoopStart(
|
||||
pLevel->op = OP_Next;
|
||||
}
|
||||
pLevel->p1 = iIdxCur;
|
||||
assert( (WHERE_UNQ_WANTED>>16)==1 );
|
||||
pLevel->p3 = (pLoop->wsFlags>>16)&1;
|
||||
pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
|
||||
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
|
||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||
}else{
|
||||
@ -4013,6 +4012,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;
|
||||
|
177
test/in4.test
177
test/in4.test
@ -159,4 +159,181 @@ 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/}
|
||||
|
||||
# Make sure that when "x IN (?)" is converted into "x==?" that collating
|
||||
# sequence and affinity computations do not get messed up.
|
||||
#
|
||||
do_execsql_test in4-4.1 {
|
||||
CREATE TABLE t4a(a TEXT, b TEXT COLLATE nocase, c);
|
||||
INSERT INTO t4a VALUES('ABC','abc',1);
|
||||
INSERT INTO t4a VALUES('def','xyz',2);
|
||||
INSERT INTO t4a VALUES('ghi','ghi',3);
|
||||
SELECT c FROM t4a WHERE a=b ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.2 {
|
||||
SELECT c FROM t4a WHERE b=a ORDER BY c;
|
||||
} {1 3}
|
||||
do_execsql_test in4-4.3 {
|
||||
SELECT c FROM t4a WHERE (a||'')=b ORDER BY c;
|
||||
} {1 3}
|
||||
do_execsql_test in4-4.4 {
|
||||
SELECT c FROM t4a WHERE (a||'')=(b||'') ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.5 {
|
||||
SELECT c FROM t4a WHERE a IN (b) ORDER BY c;
|
||||
} {3}
|
||||
do_execsql_test in4-4.6 {
|
||||
SELECT c FROM t4a WHERE (a||'') IN (b) ORDER BY c;
|
||||
} {3}
|
||||
|
||||
|
||||
do_execsql_test in4-4.11 {
|
||||
CREATE TABLE t4b(a TEXT, b NUMERIC, c);
|
||||
INSERT INTO t4b VALUES('1.0',1,4);
|
||||
SELECT c FROM t4b WHERE a=b;
|
||||
} {4}
|
||||
do_execsql_test in4-4.12 {
|
||||
SELECT c FROM t4b WHERE b=a;
|
||||
} {4}
|
||||
do_execsql_test in4-4.13 {
|
||||
SELECT c FROM t4b WHERE +a=b;
|
||||
} {4}
|
||||
do_execsql_test in4-4.14 {
|
||||
SELECT c FROM t4b WHERE a=+b;
|
||||
} {}
|
||||
do_execsql_test in4-4.15 {
|
||||
SELECT c FROM t4b WHERE +b=a;
|
||||
} {}
|
||||
do_execsql_test in4-4.16 {
|
||||
SELECT c FROM t4b WHERE b=+a;
|
||||
} {4}
|
||||
do_execsql_test in4-4.17 {
|
||||
SELECT c FROM t4b WHERE a IN (b);
|
||||
} {}
|
||||
do_execsql_test in4-4.18 {
|
||||
SELECT c FROM t4b WHERE b IN (a);
|
||||
} {4}
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user