From: drh Date: Mon, 28 Jan 2002 15:53:03 +0000 (+0000) Subject: Bug fix: The IN operator was not working if either side derived from X-Git-Tag: version-3.6.10~5668 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6b12545f4f6b87a60078582bdd98877077ad8241;p=thirdparty%2Fsqlite.git Bug fix: The IN operator was not working if either side derived from an INTEGER PRIMARY KEY. (CVS 354) FossilOrigin-Name: dbcfe198fbaa155874ef82a96b6a4b993ccf3931 --- diff --git a/VERSION b/VERSION index 530cdd91a2..21bb5e156f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.4 +2.2.5 diff --git a/manifest b/manifest index 1e78302997..beebc46355 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Do\snot\sescape\sthe\sbackslash\scharacter\sin\sshell\soutput.\s(CVS\s353) -D 2002-01-24T00:00:21 +C Bug\sfix:\sThe\sIN\soperator\swas\snot\sworking\sif\seither\sside\sderived\sfrom\nan\sINTEGER\sPRIMARY\sKEY.\s(CVS\s354) +D 2002-01-28T15:53:04 F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af F Makefile.template 3e26a3b9e7aee1b811deaf673e8d8973bdb3f22d F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 -F VERSION 2af606990ed9af7308a6e04cd7c9efd550f4e7be +F VERSION 79f8cff9811acbf454323afd9f2fa6cd2a8b7674 F aclocal.m4 11faa843caa38fd451bc6aeb43e248d1723a269d F config.guess f38b1e93d1e0fa6f5a6913e9e7b12774b9232588 F config.log 6a73d03433669b10a3f0c221198c3f26b9413914 @@ -21,12 +21,12 @@ F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6 F src/btree.c c796e387da340cb628dc1e41f684fc20253f561e F src/btree.h 9ead7f54c270d8a554e59352ca7318fdaf411390 -F src/build.c bf8456b56011bb3761f11ff4a14121cfbbbd78da +F src/build.c 3f40a6e6cea4180fb742a3d0ce71f06df8121cab F src/delete.c cc200609f927ee8fefdda5d11d3f3b2288493c0f F src/expr.c 4cae8bf44d5732182e5e8c25b4552c05ea55593e F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46 F src/hash.h a5f5b3ce2d086a172c5879b0b06a27a82eac9fac -F src/insert.c 813c37719866c583e6ca7660f94f10230f4e385d +F src/insert.c e3a3b5a1d46a02778feb3e2ccd9a6989201c03b5 F src/main.c 0205771a6c31a9858ff131fc1e797b589afb76bf F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c F src/os.c c615faa4d23e742e0650e0751a6ad2a18438ad53 @@ -36,7 +36,7 @@ F src/pager.h f78d064c780855ff70beacbeba0e2324471b26fe F src/parse.y f3fc4fb5766393003577bd175eb611495f6efd9f F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d F src/random.c f6b36bec5ebd3edb3440224bf5bf811fe4ac9a1b -F src/select.c de0d1d12e258d339a7936556512680366177f277 +F src/select.c fc11d5a8c2bae1b62d8028ffb111c773ad6bf161 F src/shell.c c102dfe388c7618a668c944ff157c49cb48f28e3 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c @@ -47,11 +47,11 @@ F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f F src/test2.c e9f99aa5ee73872819259d6612c11e55e1644321 F src/test3.c d6775f95fd91f5b3cf0e2382a28e5aaeb68f745b F src/tokenize.c 830e9ef684334070a26583d94770bb869e2727bf -F src/update.c f30a47928fb7e894221eab2a81c8fa2653f96fb0 +F src/update.c 6f87a9aa0b3ec0dfec0b0758104461445e701fdb F src/util.c 8f8973dd55a6ec63be9632fc5de86965c99d6327 -F src/vdbe.c 158bab65e4eafceb75a83f616caafa2c58f00242 -F src/vdbe.h e5cc6fb13d1905a4339db4d6dba4ab393c0765fa -F src/where.c a9b286ac7323e7ebed5d3d217b3963acf1e6a355 +F src/vdbe.c 71c0b7d368dd4c58867d7e577df0ee5404e25722 +F src/vdbe.h 22d4df31cc16ca50b66b8125caec3495e5b407b2 +F src/where.c 2dda39367f193194e4c7d2e0dcab31527d9d8aba F test/all.test 2a51e5395ac7c2c539689b123b9782a05e3837fe F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/btree.test 6ab4dc5f595905a276ef588fad3c9236dc07a47b @@ -61,7 +61,7 @@ F test/copy.test 768e6f1701a07d08090e1ca7f7dcce0a7a72b43e F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8 F test/expr.test c8a495050dcec3f9e68538c3ef466726933302c1 F test/func.test 51dbe3f8a4c28972751697423e6acc5d6b551df1 -F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e +F test/in.test c09312672e3f0709fa02c8e2e9cd8fb4bd6269aa F test/index.test c8a471243bbf878974b99baf5badd59407237cf3 F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11 F test/insert2.test d6901ca931e308fea7fca8c95ebe7dc957cc9fc2 @@ -105,7 +105,7 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4 F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b F www/c_interface.tcl 82a026b1681757f13b3f62e035f3a31407c1d353 -F www/changes.tcl f3f730787338087282e50bd27d152ed68686df15 +F www/changes.tcl 6b802e152436c7596308b6a4901e91415be0d9d4 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060 F www/download.tcl 1ea61f9d89a2a5a9b2cee36b0d5cf97321bdefe0 F www/dynload.tcl 02eb8273aa78cfa9070dd4501dca937fb22b466c @@ -119,7 +119,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 16712dae4feedd001d8153141a55e298b3a80a94 -R 0530842c82f7bef6b5f9c0ae1cc69c65 +P 5f8c097ebef28315ac2335a768d101e995ccbba2 +R 8bfbd1ab9c2165331e9740c7a67704b7 U drh -Z 61c11f99131a5810bde1ae96d98c46d4 +Z 7c022c8c65d60ef92494dfd3fd54cead diff --git a/manifest.uuid b/manifest.uuid index 6eeda72068..fc78220e96 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5f8c097ebef28315ac2335a768d101e995ccbba2 \ No newline at end of file +dbcfe198fbaa155874ef82a96b6a4b993ccf3931 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 1fbf6351d1..22e68df83c 100644 --- a/src/build.c +++ b/src/build.c @@ -25,7 +25,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.65 2002/01/22 03:13:42 drh Exp $ +** $Id: build.c,v 1.66 2002/01/28 15:53:05 drh Exp $ */ #include "sqliteInt.h" #include @@ -730,7 +730,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){ addr = sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n); sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); - sqliteVdbeAddOp(v, OP_Put, 0, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); changeCookie(db); sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0); sqliteVdbeAddOp(v, OP_Close, 0, 0); @@ -1074,7 +1074,7 @@ void sqliteCreateIndex( sqliteVdbeChangeP3(v, addr, pStart->z, n); } sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0); - sqliteVdbeAddOp(v, OP_Put, 0, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); } if( pTable ){ sqliteVdbeAddOp(v, isTemp ? OP_OpenAux : OP_Open, 2, pTab->tnum); @@ -1383,7 +1383,7 @@ void sqliteCopy( } } sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); - sqliteVdbeAddOp(v, OP_Put, 0, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( pIdx->pNext ){ sqliteVdbeAddOp(v, OP_Dup, 0, 0); diff --git a/src/insert.c b/src/insert.c index d6d7638778..c24d019e53 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.32 2002/01/06 17:07:40 drh Exp $ +** $Id: insert.c,v 1.33 2002/01/28 15:53:05 drh Exp $ */ #include "sqliteInt.h" @@ -252,7 +252,7 @@ void sqliteInsert( /* Create the new record and put it into the database. */ sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); - sqliteVdbeAddOp(v, OP_Put, base, keyColumn>=0); + sqliteVdbeAddOp(v, OP_PutIntKey, base, keyColumn>=0); /* Create appropriate entries for the new data row in all indices ** of the table. diff --git a/src/select.c b/src/select.c index 9395d6f76a..b0ef7081fe 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.55 2002/01/22 14:11:29 drh Exp $ +** $Id: select.c,v 1.56 2002/01/28 15:53:05 drh Exp $ */ #include "sqliteInt.h" @@ -130,7 +130,7 @@ static int selectInnerLoop( sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); sqliteVdbeResolveLabel(v, lbl); sqliteVdbeAddOp(v, OP_String, 0, 0); - sqliteVdbeAddOp(v, OP_Put, distinct, 0); + sqliteVdbeAddOp(v, OP_PutStrKey, distinct, 0); } /* If there is an ORDER BY clause, then store the results @@ -158,7 +158,7 @@ static int selectInnerLoop( if( eDest==SRT_Union ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); sqliteVdbeAddOp(v, OP_String, iParm, 0); - sqliteVdbeAddOp(v, OP_Put, iParm, 0); + sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); }else /* Store the result as data using a unique key. @@ -167,7 +167,7 @@ static int selectInnerLoop( sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0); - sqliteVdbeAddOp(v, OP_Put, iParm, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, iParm, 0); }else /* Construct a record from the query result, but instead of @@ -187,7 +187,7 @@ static int selectInnerLoop( if( eDest==SRT_Set ){ assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_String, 0, 0); - sqliteVdbeAddOp(v, OP_Put, iParm, 0); + sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); }else diff --git a/src/update.c b/src/update.c index 016545aa9e..88df296423 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.27 2002/01/22 03:13:42 drh Exp $ +** $Id: update.c,v 1.28 2002/01/28 15:53:05 drh Exp $ */ #include "sqliteInt.h" @@ -265,7 +265,7 @@ void sqliteUpdate( /* Write the new data back into the database. */ sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); - sqliteVdbeAddOp(v, OP_Put, base, 0); + sqliteVdbeAddOp(v, OP_PutIntKey, base, 0); /* Increment the count of rows affected by the update */ diff --git a/src/vdbe.c b/src/vdbe.c index 602f9503bf..ce025f4624 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.107 2002/01/16 21:00:27 drh Exp $ +** $Id: vdbe.c,v 1.108 2002/01/28 15:53:05 drh Exp $ */ #include "sqliteInt.h" #include @@ -852,31 +852,32 @@ static char *zOpName[] = { 0, "Transaction", "Commit", "Rollback", "ReadCookie", "SetCookie", "VerifyCookie", "Open", "OpenTemp", "OpenWrite", "OpenAux", "OpenWrAux", "Close", - "MoveTo", "NewRecno", "Put", "Distinct", - "Found", "NotFound", "Delete", "Column", - "KeyAsData", "Recno", "FullKey", "Rewind", - "Next", "Destroy", "Clear", "CreateIndex", - "CreateTable", "Reorganize", "IdxPut", "IdxDelete", - "IdxRecno", "IdxGT", "IdxGE", "MemLoad", - "MemStore", "ListWrite", "ListRewind", "ListRead", - "ListReset", "SortPut", "SortMakeRec", "SortMakeKey", - "Sort", "SortNext", "SortCallback", "SortReset", - "FileOpen", "FileRead", "FileColumn", "AggReset", - "AggFocus", "AggIncr", "AggNext", "AggSet", - "AggGet", "SetInsert", "SetFound", "SetNotFound", - "MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey", - "Goto", "If", "Halt", "ColumnCount", - "ColumnName", "Callback", "NullCallback", "Integer", - "String", "Pop", "Dup", "Pull", - "MustBeInt", "Add", "AddImm", "Subtract", - "Multiply", "Divide", "Remainder", "BitAnd", - "BitOr", "BitNot", "ShiftLeft", "ShiftRight", - "AbsValue", "Precision", "Min", "Max", - "Like", "Glob", "Eq", "Ne", - "Lt", "Le", "Gt", "Ge", - "IsNull", "NotNull", "Negative", "And", - "Or", "Not", "Concat", "Noop", - "Strlen", "Substr", "Limit", + "MoveTo", "NewRecno", "PutIntKey", "PutStrKey", + "Distinct", "Found", "NotFound", "NotExists", + "Delete", "Column", "KeyAsData", "Recno", + "FullKey", "Rewind", "Next", "Destroy", + "Clear", "CreateIndex", "CreateTable", "Reorganize", + "IdxPut", "IdxDelete", "IdxRecno", "IdxGT", + "IdxGE", "MemLoad", "MemStore", "ListWrite", + "ListRewind", "ListRead", "ListReset", "SortPut", + "SortMakeRec", "SortMakeKey", "Sort", "SortNext", + "SortCallback", "SortReset", "FileOpen", "FileRead", + "FileColumn", "AggReset", "AggFocus", "AggIncr", + "AggNext", "AggSet", "AggGet", "SetInsert", + "SetFound", "SetNotFound", "MakeRecord", "MakeKey", + "MakeIdxKey", "IncrKey", "Goto", "If", + "Halt", "ColumnCount", "ColumnName", "Callback", + "NullCallback", "Integer", "String", "Pop", + "Dup", "Pull", "MustBeInt", "Add", + "AddImm", "Subtract", "Multiply", "Divide", + "Remainder", "BitAnd", "BitOr", "BitNot", + "ShiftLeft", "ShiftRight", "AbsValue", "Precision", + "Min", "Max", "Like", "Glob", + "Eq", "Ne", "Lt", "Le", + "Gt", "Ge", "IsNull", "NotNull", + "Negative", "And", "Or", "Not", + "Concat", "Noop", "Strlen", "Substr", + "Limit", }; /* @@ -2645,7 +2646,7 @@ case OP_MoveTo: { /* Opcode: Distinct P1 P2 * ** -** Use the top of the stack as a key. If a record with that key does +** Use the top of the stack as a string key. If a record with that key does ** not exist in the table of cursor P1, then jump to P2. If the record ** does already exist, then fall thru. The cursor is left pointing ** at the record if it exists. The key is not popped from the stack. @@ -2657,7 +2658,7 @@ case OP_MoveTo: { */ /* Opcode: Found P1 P2 * ** -** Use the top of the stack as a key. If a record with that key +** Use the top of the stack as a string key. If a record with that key ** does exist in table of P1, then jump to P2. If the record ** does not exist, then fall thru. The cursor is left pointing ** to the record if it exists. The key is popped from the stack. @@ -2666,7 +2667,7 @@ case OP_MoveTo: { */ /* Opcode: NotFound P1 P2 * ** -** Use the top of the stack as a key. If a record with that key +** Use the top of the stack as a string key. If a record with that key ** does not exist in table of P1, then jump to P2. If the record ** does exist, then fall thru. The cursor is left pointing to the ** record if it exists. The key is popped from the stack. @@ -2674,7 +2675,7 @@ case OP_MoveTo: { ** The difference between this operation and Distinct is that ** Distinct does not pop the key from the stack. ** -** See also: Distinct, Found, MoveTo +** See also: Distinct, Found, MoveTo, NotExists */ case OP_Distinct: case OP_NotFound: @@ -2686,13 +2687,8 @@ case OP_Found: { VERIFY( if( tos<0 ) goto not_enough_stack; ) if( VERIFY( i>=0 && inCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){ int res, rx; - if( aStack[tos].flags & STK_Int ){ - int iKey = intToKey(aStack[tos].i); - rx = sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res); - }else{ - if( Stringify(p, tos) ) goto no_mem; - rx = sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); - } + if( Stringify(p, tos) ) goto no_mem; + rx = sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); alreadyExists = rx==SQLITE_OK && res==0; } if( pOp->opcode==OP_Found ){ @@ -2706,6 +2702,38 @@ case OP_Found: { break; } +/* Opcode: NotExists P1 P2 * +** +** Use the top of the stack as a integer key. If a record with that key +** does not exist in table of P1, then jump to P2. If the record +** does exist, then fall thru. The cursor is left pointing to the +** record if it exists. The integer key is popped from the stack. +** +** The difference between this operation and NotFound is that this +** operation assumes the key is an integer and NotFound assumes it +** is a string. +** +** See also: Distinct, Found, MoveTo, NotExists +*/ +case OP_NotExists: { + int i = pOp->p1; + int tos = p->tos; + int alreadyExists = 0; + Cursor *pC; + VERIFY( if( tos<0 ) goto not_enough_stack; ) + if( VERIFY( i>=0 && inCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){ + int res, rx, iKey; + assert( aStack[tos].flags & STK_Int ); + iKey = intToKey(aStack[tos].i); + rx = sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res); + if( rx!=SQLITE_OK || res!=0 ){ + pc = pOp->p2 - 1; + } + } + POPSTACK; + break; +} + /* Opcode: NewRecno P1 * * ** ** Get a new integer record number used as the key to a table. @@ -2770,18 +2798,30 @@ case OP_NewRecno: { break; } -/* Opcode: Put P1 P2 * +/* Opcode: PutIK P1 P2 * +** +** Write an entry into the database file P1. A new entry is +** created if it doesn't already exist or the data for an existing +** entry is overwritten. The data is the value on the top of the +** stack. The key is the next value down on the stack. The key must +** be an integer. The stack is popped twice by this instruction. +** +** If P2==1 then overwriting is prohibited. If a prior entry with +** the same key exists, an SQLITE_CONSTRAINT exception is raised. +*/ +/* Opcode: PutSK P1 P2 * ** ** Write an entry into the database file P1. A new entry is ** created if it doesn't already exist or the data for an existing ** entry is overwritten. The data is the value on the top of the -** stack. The key is the next value down on the stack. The stack -** is popped twice by this instruction. +** stack. The key is the next value down on the stack. The key must +** be a string. The stack is popped twice by this instruction. ** ** If P2==1 then overwriting is prohibited. If a prior entry with ** the same key exists, an SQLITE_CONSTRAINT exception is raised. */ -case OP_Put: { +case OP_PutIntKey: +case OP_PutStrKey: { int tos = p->tos; int nos = p->tos-1; int i = pOp->p1; @@ -2789,11 +2829,12 @@ case OP_Put: { if( VERIFY( i>=0 && inCursor && ) p->aCsr[i].pCursor!=0 ){ char *zKey; int nKey, iKey; - if( (aStack[nos].flags & STK_Int)==0 ){ + if( pOp->opcode==OP_PutStrKey ){ if( Stringify(p, nos) ) goto no_mem; nKey = aStack[nos].n; zKey = zStack[nos]; }else{ + assert( aStack[nos].flags & STK_Int ); nKey = sizeof(int); iKey = intToKey(aStack[nos].i); zKey = (char*)&iKey; diff --git a/src/vdbe.h b/src/vdbe.h index 4f48f23a07..0f270b92fd 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.37 2001/12/22 14:49:26 drh Exp $ +** $Id: vdbe.h,v 1.38 2002/01/28 15:53:05 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -84,120 +84,122 @@ typedef struct VdbeOp VdbeOp; #define OP_Close 12 #define OP_MoveTo 13 #define OP_NewRecno 14 -#define OP_Put 15 -#define OP_Distinct 16 -#define OP_Found 17 -#define OP_NotFound 18 -#define OP_Delete 19 -#define OP_Column 20 -#define OP_KeyAsData 21 -#define OP_Recno 22 -#define OP_FullKey 23 -#define OP_Rewind 24 -#define OP_Next 25 - -#define OP_Destroy 26 -#define OP_Clear 27 -#define OP_CreateIndex 28 -#define OP_CreateTable 29 -#define OP_Reorganize 30 - -#define OP_IdxPut 31 -#define OP_IdxDelete 32 -#define OP_IdxRecno 33 -#define OP_IdxGT 34 -#define OP_IdxGE 35 - -#define OP_MemLoad 36 -#define OP_MemStore 37 - -#define OP_ListWrite 38 -#define OP_ListRewind 39 -#define OP_ListRead 40 -#define OP_ListReset 41 - -#define OP_SortPut 42 -#define OP_SortMakeRec 43 -#define OP_SortMakeKey 44 -#define OP_Sort 45 -#define OP_SortNext 46 -#define OP_SortCallback 47 -#define OP_SortReset 48 - -#define OP_FileOpen 49 -#define OP_FileRead 50 -#define OP_FileColumn 51 - -#define OP_AggReset 52 -#define OP_AggFocus 53 -#define OP_AggIncr 54 -#define OP_AggNext 55 -#define OP_AggSet 56 -#define OP_AggGet 57 - -#define OP_SetInsert 58 -#define OP_SetFound 59 -#define OP_SetNotFound 60 - -#define OP_MakeRecord 61 -#define OP_MakeKey 62 -#define OP_MakeIdxKey 63 -#define OP_IncrKey 64 - -#define OP_Goto 65 -#define OP_If 66 -#define OP_Halt 67 - -#define OP_ColumnCount 68 -#define OP_ColumnName 69 -#define OP_Callback 70 -#define OP_NullCallback 71 - -#define OP_Integer 72 -#define OP_String 73 -#define OP_Pop 74 -#define OP_Dup 75 -#define OP_Pull 76 -#define OP_MustBeInt 77 - -#define OP_Add 78 -#define OP_AddImm 79 -#define OP_Subtract 80 -#define OP_Multiply 81 -#define OP_Divide 82 -#define OP_Remainder 83 -#define OP_BitAnd 84 -#define OP_BitOr 85 -#define OP_BitNot 86 -#define OP_ShiftLeft 87 -#define OP_ShiftRight 88 -#define OP_AbsValue 89 -#define OP_Precision 90 -#define OP_Min 91 -#define OP_Max 92 -#define OP_Like 93 -#define OP_Glob 94 -#define OP_Eq 95 -#define OP_Ne 96 -#define OP_Lt 97 -#define OP_Le 98 -#define OP_Gt 99 -#define OP_Ge 100 -#define OP_IsNull 101 -#define OP_NotNull 102 -#define OP_Negative 103 -#define OP_And 104 -#define OP_Or 105 -#define OP_Not 106 -#define OP_Concat 107 -#define OP_Noop 108 - -#define OP_Strlen 109 -#define OP_Substr 110 - -#define OP_Limit 111 - -#define OP_MAX 111 +#define OP_PutIntKey 15 +#define OP_PutStrKey 16 +#define OP_Distinct 17 +#define OP_Found 18 +#define OP_NotFound 19 +#define OP_NotExists 20 +#define OP_Delete 21 +#define OP_Column 22 +#define OP_KeyAsData 23 +#define OP_Recno 24 +#define OP_FullKey 25 +#define OP_Rewind 26 +#define OP_Next 27 + +#define OP_Destroy 28 +#define OP_Clear 29 +#define OP_CreateIndex 30 +#define OP_CreateTable 31 +#define OP_Reorganize 32 + +#define OP_IdxPut 33 +#define OP_IdxDelete 34 +#define OP_IdxRecno 35 +#define OP_IdxGT 36 +#define OP_IdxGE 37 + +#define OP_MemLoad 38 +#define OP_MemStore 39 + +#define OP_ListWrite 40 +#define OP_ListRewind 41 +#define OP_ListRead 42 +#define OP_ListReset 43 + +#define OP_SortPut 44 +#define OP_SortMakeRec 45 +#define OP_SortMakeKey 46 +#define OP_Sort 47 +#define OP_SortNext 48 +#define OP_SortCallback 49 +#define OP_SortReset 50 + +#define OP_FileOpen 51 +#define OP_FileRead 52 +#define OP_FileColumn 53 + +#define OP_AggReset 54 +#define OP_AggFocus 55 +#define OP_AggIncr 56 +#define OP_AggNext 57 +#define OP_AggSet 58 +#define OP_AggGet 59 + +#define OP_SetInsert 60 +#define OP_SetFound 61 +#define OP_SetNotFound 62 + +#define OP_MakeRecord 63 +#define OP_MakeKey 64 +#define OP_MakeIdxKey 65 +#define OP_IncrKey 66 + +#define OP_Goto 67 +#define OP_If 68 +#define OP_Halt 69 + +#define OP_ColumnCount 70 +#define OP_ColumnName 71 +#define OP_Callback 72 +#define OP_NullCallback 73 + +#define OP_Integer 74 +#define OP_String 75 +#define OP_Pop 76 +#define OP_Dup 77 +#define OP_Pull 78 +#define OP_MustBeInt 79 + +#define OP_Add 80 +#define OP_AddImm 81 +#define OP_Subtract 82 +#define OP_Multiply 83 +#define OP_Divide 84 +#define OP_Remainder 85 +#define OP_BitAnd 86 +#define OP_BitOr 87 +#define OP_BitNot 88 +#define OP_ShiftLeft 89 +#define OP_ShiftRight 90 +#define OP_AbsValue 91 +#define OP_Precision 92 +#define OP_Min 93 +#define OP_Max 94 +#define OP_Like 95 +#define OP_Glob 96 +#define OP_Eq 97 +#define OP_Ne 98 +#define OP_Lt 99 +#define OP_Le 100 +#define OP_Gt 101 +#define OP_Ge 102 +#define OP_IsNull 103 +#define OP_NotNull 104 +#define OP_Negative 105 +#define OP_And 106 +#define OP_Or 107 +#define OP_Not 108 +#define OP_Concat 109 +#define OP_Noop 110 + +#define OP_Strlen 111 +#define OP_Substr 112 + +#define OP_Limit 113 + +#define OP_MAX 113 /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/src/where.c b/src/where.c index 526f2aeed2..022cfbb7b5 100644 --- a/src/where.c +++ b/src/where.c @@ -13,7 +13,7 @@ ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** -** $Id: where.c,v 1.32 2002/01/09 03:20:00 drh Exp $ +** $Id: where.c,v 1.33 2002/01/28 15:53:05 drh Exp $ */ #include "sqliteInt.h" @@ -439,12 +439,19 @@ WhereInfo *sqliteWhereBegin( cont = pLevel->cont = brk; sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk); if( i==pTabList->nId-1 && pushKey ){ + /* Note: The OP_Dup below will cause the key to be left on the + ** stack if the key does not exists and the OP_NotExists jump is + ** taken. This violates a general rule of the VDBE that you should + ** never leave values on the stack in order to avoid a stack overflow. + ** But in this case, the OP_Dup will never happen inside of a loop, + ** so it is safe to leave it on the stack. + */ haveKey = 1; - sqliteVdbeAddOp(v, OP_Distinct, base+idx, brk); + sqliteVdbeAddOp(v, OP_Dup, 0, 0); }else{ - sqliteVdbeAddOp(v, OP_NotFound, base+idx, brk); haveKey = 0; } + sqliteVdbeAddOp(v, OP_NotExists, base+idx, brk); pLevel->op = OP_Noop; }else if( pIdx!=0 && pLevel->score%4==0 ){ /* Case 2: All index constraints are equality operators. diff --git a/test/in.test b/test/in.test index e8c9417f65..92bc422507 100644 --- a/test/in.test +++ b/test/in.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the IN and BETWEEN operator. # -# $Id: in.test,v 1.5 2001/09/16 00:13:28 drh Exp $ +# $Id: in.test,v 1.6 2002/01/28 15:53:05 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -156,4 +156,72 @@ do_test in-5.1 { } } {hello world} +# Make sure the IN operator works with INTEGER PRIMARY KEY fields. +# +do_test in-6.1 { + execsql { + CREATE TABLE ta(a INTEGER PRIMARY KEY, b); + INSERT INTO ta VALUES(1,1); + INSERT INTO ta VALUES(2,2); + INSERT INTO ta VALUES(3,3); + INSERT INTO ta VALUES(4,4); + INSERT INTO ta VALUES(6,6); + INSERT INTO ta VALUES(8,8); + SELECT * FROM ta; + } +} {1 1 2 2 3 3 4 4 6 6 8 8} +do_test in-6.2 { + execsql { + CREATE TABLE tb(a INTEGER PRIMARY KEY, b); + INSERT INTO tb VALUES(1,1); + INSERT INTO tb VALUES(2,2); + INSERT INTO tb VALUES(3,3); + INSERT INTO tb VALUES(5,5); + INSERT INTO tb VALUES(7,7); + INSERT INTO tb VALUES(9,9); + SELECT * FROM tb; + } +} {1 1 2 2 3 3 5 5 7 7 9 9} +do_test in-6.3 { + execsql { + SELECT a FROM ta WHERE b IN (SELECT a FROM tb); + } +} {1 2 3} +do_test in-6.4 { + execsql { + SELECT a FROM ta WHERE b NOT IN (SELECT a FROM tb); + } +} {4 6 8} +do_test in-6.5 { + execsql { + SELECT a FROM ta WHERE b IN (SELECT b FROM tb); + } +} {1 2 3} +do_test in-6.6 { + execsql { + SELECT a FROM ta WHERE b NOT IN (SELECT b FROM tb); + } +} {4 6 8} +do_test in-6.7 { + execsql { + SELECT a FROM ta WHERE a IN (SELECT a FROM tb); + } +} {1 2 3} +do_test in-6.8 { + execsql { + SELECT a FROM ta WHERE a NOT IN (SELECT a FROM tb); + } +} {4 6 8} +do_test in-6.9 { + execsql { + SELECT a FROM ta WHERE a IN (SELECT b FROM tb); + } +} {1 2 3} +do_test in-6.10 { + execsql { + SELECT a FROM ta WHERE a NOT IN (SELECT b FROM tb); + } +} {4 6 8} + + finish_test diff --git a/www/changes.tcl b/www/changes.tcl index 02e9d74a41..2a6ba3c237 100644 --- a/www/changes.tcl +++ b/www/changes.tcl @@ -17,6 +17,13 @@ proc chng {date desc} { puts "

    $desc

" } +chng {2002 Jan 28 (2.2.5)} { +
  • Important bug fix: the IN operator was not working if either the + left-hand or right-hand side was derived from an INTEGER PRIMARY KEY.
  • +
  • Do not escape the backslash '\' character in the output of the + sqlite command-line access program.
  • +} + chng {2002 Jan 22 (2.2.4)} {
  • The label to the right of an AS in the column list of a SELECT can now be used as part of an expression in the WHERE, ORDER BY, GROUP BY, and/or