1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Make the result of an IN or NOT IN expression with an empty set on the

right-hand side always either false or true, respectively, even if the
left-hand side is NULL.  Ticket [80e031a00f45dc]

FossilOrigin-Name: c288ac644d0bfda2b9bc204dc86df8e74d4f6843
This commit is contained in:
drh
2010-07-14 18:24:06 +00:00
parent e84322e503
commit 094430eb71
7 changed files with 115 additions and 20 deletions

View File

@@ -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-----

View File

@@ -1 +1 @@
9f452514d96ab8d424eadc55c283c53fe831476d
c288ac644d0bfda2b9bc204dc86df8e74d4f6843

View 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

View 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

View File

@@ -959,6 +959,18 @@ 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] {
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{
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pList = Y;
@@ -967,6 +979,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
sqlite3ExprListDelete(pParse->db, Y);
}
if( N ) A.pExpr = sqlite3PExpr(pParse, TK_NOT, A.pExpr, 0, 0);
}
A.zStart = X.zStart;
A.zEnd = &E.z[E.n];
}

View 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

49
test/tkt-80e031a00f.test Normal file
View File

@@ -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