-C Bug\sfix:\sdo\snot\ssegfault\sif\sa\sSELECT\swithout\sa\sFROM\sclause\sincludes\nthe\s*\swildcard\sin\sthe\sresult\scolumn\slist.\s(CVS\s609)
-D 2002-06-06T23:42:28
+C Add\soptimizations\sfor\sthe\sIN\soperator\sin\sWHERE\sclauses.\s\sThis\sis\sa\spartial\nimplementation\sof\senhancement\s#63.\s\sStill\sneed\sto\sadd\stest\scases.\s(CVS\s610)
+D 2002-06-08T23:25:09
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
F src/expr.c 8ce9c22655735ff62b1e33ab11ad9d44c4ab99c6
F src/func.c 061a520a122da7e4f9dcac15697bb996aac7d5df
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
-F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
+F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
F src/insert.c 4b0bd94296fea46ef1b2ed8bfd05e12a38ce2c90
F src/main.c 6e53c49a390fabd5fecce9e3b128c61c85208000
F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b
F src/shell.c 1d22fe870ee852cfb975fd000dbe3973713d0a15
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in 0038faa6d642de06b91143ee65a131bd831d020b
-F src/sqliteInt.h 3fd61a32c101b10aea610de8e7d931744657712f
+F src/sqliteInt.h 09f3e26d0368284965efef7d1a9999b0eba801d3
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
F src/tclsqlite.c 9300c9606a38bc0c75d6c0bc8a6197ab979353d1
F src/test1.c 09d95048b66ce6dcd2bae90f443589043d7d631e
F src/trigger.c d02f8e3510c7c2ad948a0e8c3bb0cca8adaf80c5
F src/update.c f68375173bf5338cae3e97012708e10f206aedd9
F src/util.c 7cf46b5612f5d12601c697374b9c6b38b2332ce8
-F src/vdbe.c 27b71e3c6cc77c071421b24462872f32047e2c20
-F src/vdbe.h b8706429131c14b307a07aab7e47f95a9da53610
-F src/where.c b054f2f23127bd57eb5f973bcd38764b875d73fe
+F src/vdbe.c b315d7ad5086164bb8d8aee8bc9edeafcb68b8ea
+F src/vdbe.h 1742d6f8b40f40879475b4c41cf4f9980ceb0e21
+F src/where.c d5308069f8794ec7e9f5084ffd611fe0922ae9f0
F test/all.test e4d3821eeba751829b419cd47814bd20af4286d1
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
F test/btree.test bf326f546a666617367a7033fa2c07451bd4f8e1
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P a0abef62bfe1b0f8c6249ba520dd2735190783a5
-R 5d70f1605b7b9ff2e858e45ab5b5947d
+P d939294994e5f6c7862b66573301e111e56a2681
+R 3ccd9ba147258740a1a4d6ac8604b91f
U drh
-Z 6eb753fe6a2122abae187660dd07b07e
+Z 0bb147d1fd50388db4609fcd1f1c4973
-d939294994e5f6c7862b66573301e111e56a2681
\ No newline at end of file
+8481e841ebdeabe07bf780246bda1aa053eb60b7
\ No newline at end of file
** This is the header file for the generic hash-table implemenation
** used in SQLite.
**
-** $Id: hash.h,v 1.4 2002/02/23 23:45:45 drh Exp $
+** $Id: hash.h,v 1.5 2002/06/08 23:25:09 drh Exp $
*/
#ifndef _SQLITE_HASH_H_
#define _SQLITE_HASH_H_
#define sqliteHashNext(E) ((E)->next)
#define sqliteHashData(E) ((E)->data)
#define sqliteHashKey(E) ((E)->pKey)
+#define sqliteHashKeysize(E) ((E)->nKey)
/*
** Number of entries in a hash table
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.120 2002/06/06 18:54:41 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.121 2002/06/08 23:25:09 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
struct Expr {
int op; /* Operation performed by this node */
Expr *pLeft, *pRight; /* Left and right subnodes */
- ExprList *pList; /* A list of expressions used as a function argument */
+ ExprList *pList; /* A list of expressions used as function arguments
+ ** or in "<expr> IN (<expr-list)" */
Token token; /* An operand token */
Token span; /* Complete text of the expression */
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
** op==TK_FUNCTION, iColumn holds the function id */
int iAgg; /* When op==TK_COLUMN and pParse->useAgg==TRUE, pull
** result from the iAgg-th element of the aggregator */
- Select *pSelect; /* When the expression is a sub-select */
+ Select *pSelect; /* When the expression is a sub-select. Also the
+ ** right side of "<expr> IN (<select>)" */
};
/*
int op, p1, p2; /* Opcode used to terminate the loop */
int iLeftJoin; /* Memory cell used to implement LEFT OUTER JOIN */
int top; /* First instruction of interior of the loop */
+ int inOp, inP1, inP2;/* Opcode used to implement an IN operator */
};
/*
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.153 2002/06/06 23:16:06 drh Exp $
+** $Id: vdbe.c,v 1.154 2002/06/08 23:25:09 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
typedef struct Set Set;
struct Set {
Hash hash; /* A set is just a hash table */
+ HashElem *prev; /* Previously accessed hash elemen */
};
/*
"FileOpen", "FileRead", "FileColumn", "AggReset",
"AggFocus", "AggNext", "AggSet", "AggGet",
"AggFunc", "AggInit", "AggPush", "AggPop",
- "SetInsert", "SetFound", "SetNotFound", "MakeRecord",
- "MakeKey", "MakeIdxKey", "IncrKey", "Goto",
- "If", "IfNot", "Halt", "ColumnCount",
- "ColumnName", "Callback", "NullCallback", "Integer",
- "String", "Pop", "Dup", "Pull",
- "Push", "MustBeInt", "Add", "AddImm",
- "Subtract", "Multiply", "Divide", "Remainder",
- "BitAnd", "BitOr", "BitNot", "ShiftLeft",
- "ShiftRight", "AbsValue", "Eq", "Ne",
- "Lt", "Le", "Gt", "Ge",
- "IsNull", "NotNull", "Negative", "And",
- "Or", "Not", "Concat", "Noop",
- "Function", "Limit",
+ "SetInsert", "SetFound", "SetNotFound", "SetFirst",
+ "SetNext", "MakeRecord", "MakeKey", "MakeIdxKey",
+ "IncrKey", "Goto", "If", "IfNot",
+ "Halt", "ColumnCount", "ColumnName", "Callback",
+ "NullCallback", "Integer", "String", "Pop",
+ "Dup", "Pull", "Push", "MustBeInt",
+ "Add", "AddImm", "Subtract", "Multiply",
+ "Divide", "Remainder", "BitAnd", "BitOr",
+ "BitNot", "ShiftLeft", "ShiftRight", "AbsValue",
+ "Eq", "Ne", "Lt", "Le",
+ "Gt", "Ge", "IsNull", "NotNull",
+ "Negative", "And", "Or", "Not",
+ "Concat", "Noop", "Function", "Limit",
};
/*
/* Opcode: MustBeInt * P2 *
**
** Force the top of the stack to be an integer. If the top of the
-** stack is not an integer and cannot be comverted into an integer
+** stack is not an integer and cannot be converted into an integer
** with out data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
*/
** This operation is similar to NotFound except that this operation
** does not pop the key from the stack.
**
-** See also: Found, NotFound, MoveTo
+** See also: Found, NotFound, MoveTo, IsUnique, NotExists
*/
/* Opcode: Found P1 P2 *
**
** does not exist, then fall thru. The cursor is left pointing
** to the record if it exists. The key is popped from the stack.
**
-** See also: Distinct, NotFound, MoveTo
+** See also: Distinct, NotFound, MoveTo, IsUnique, NotExists
*/
/* Opcode: NotFound P1 P2 *
**
** number for that entry is pushed onto the stack and control
** falls through to the next instruction.
**
-** See also: Distinct, NotFound, NotExists
+** See also: Distinct, NotFound, NotExists, Found
*/
case OP_IsUnique: {
int i = pOp->p1;
** operation assumes the key is an integer and NotFound assumes it
** is a string.
**
-** See also: Distinct, Found, MoveTo, NotExists
+** See also: Distinct, Found, MoveTo, NotFound, IsUnique
*/
case OP_NotExists: {
int i = pOp->p1;
break;
}
+/* Opcode: SetFirst P1 P2 *
+**
+** Read the first element from set P1 and push it onto the stack. If the
+** set is empty, push nothing and jump immediately to P2. This opcode is
+** used in combination with OP_SetNext to loop over all elements of a set.
+*/
+/* Opcode: SetNext P1 P2 *
+**
+** Read the next element from set P1 and push it onto the stack. If there
+** are no more elements in the set, do not do the push and fall through.
+** Otherwise, jump to P2 after pushing the next set element.
+*/
+case OP_SetFirst:
+case OP_SetNext: {
+ Set *pSet;
+ int tos;
+ VERIFY( if( pOp->p1<0 || pOp->p1>=p->nSet ) goto bad_instruction; )
+ pSet = &p->aSet[pOp->p1];
+ if( pOp->opcode==OP_SetFirst ){
+ pSet->prev = sqliteHashFirst(&pSet->hash);
+ if( pSet->prev==0 ){
+ pc = pOp->p2 - 1;
+ break;
+ }
+ }else{
+ VERIFY( if( pSet->prev==0 ) goto bad_instruction; )
+ pSet->prev = sqliteHashNext(pSet->prev);
+ if( pSet->prev==0 ){
+ break;
+ }else{
+ pc = pOp->p2 - 1;
+ }
+ }
+ tos = ++p->tos;
+ VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
+ zStack[tos] = sqliteHashKey(pSet->prev);
+ aStack[tos].n = sqliteHashKeysize(pSet->prev);
+ aStack[tos].flags = STK_Str | STK_Static;
+ break;
+}
/* An other opcode is illegal...
*/
** 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.53 2002/05/26 20:54:34 drh Exp $
+** $Id: vdbe.h,v 1.54 2002/06/08 23:25:09 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#define OP_SetInsert 69
#define OP_SetFound 70
#define OP_SetNotFound 71
-
-#define OP_MakeRecord 72
-#define OP_MakeKey 73
-#define OP_MakeIdxKey 74
-#define OP_IncrKey 75
-
-#define OP_Goto 76
-#define OP_If 77
-#define OP_IfNot 78
-#define OP_Halt 79
-
-#define OP_ColumnCount 80
-#define OP_ColumnName 81
-#define OP_Callback 82
-#define OP_NullCallback 83
-
-#define OP_Integer 84
-#define OP_String 85
-#define OP_Pop 86
-#define OP_Dup 87
-#define OP_Pull 88
-#define OP_Push 89
-#define OP_MustBeInt 90
-
-#define OP_Add 91
-#define OP_AddImm 92
-#define OP_Subtract 93
-#define OP_Multiply 94
-#define OP_Divide 95
-#define OP_Remainder 96
-#define OP_BitAnd 97
-#define OP_BitOr 98
-#define OP_BitNot 99
-#define OP_ShiftLeft 100
-#define OP_ShiftRight 101
-#define OP_AbsValue 102
-#define OP_Eq 103
-#define OP_Ne 104
-#define OP_Lt 105
-#define OP_Le 106
-#define OP_Gt 107
-#define OP_Ge 108
-#define OP_IsNull 109
-#define OP_NotNull 110
-#define OP_Negative 111
-#define OP_And 112
-#define OP_Or 113
-#define OP_Not 114
-#define OP_Concat 115
-#define OP_Noop 116
-#define OP_Function 117
-
-#define OP_Limit 118
-
-
-#define OP_MAX 118
+#define OP_SetFirst 72
+#define OP_SetNext 73
+
+#define OP_MakeRecord 74
+#define OP_MakeKey 75
+#define OP_MakeIdxKey 76
+#define OP_IncrKey 77
+
+#define OP_Goto 78
+#define OP_If 79
+#define OP_IfNot 80
+#define OP_Halt 81
+
+#define OP_ColumnCount 82
+#define OP_ColumnName 83
+#define OP_Callback 84
+#define OP_NullCallback 85
+
+#define OP_Integer 86
+#define OP_String 87
+#define OP_Pop 88
+#define OP_Dup 89
+#define OP_Pull 90
+#define OP_Push 91
+#define OP_MustBeInt 92
+
+#define OP_Add 93
+#define OP_AddImm 94
+#define OP_Subtract 95
+#define OP_Multiply 96
+#define OP_Divide 97
+#define OP_Remainder 98
+#define OP_BitAnd 99
+#define OP_BitOr 100
+#define OP_BitNot 101
+#define OP_ShiftLeft 102
+#define OP_ShiftRight 103
+#define OP_AbsValue 104
+#define OP_Eq 105
+#define OP_Ne 106
+#define OP_Lt 107
+#define OP_Le 108
+#define OP_Gt 109
+#define OP_Ge 110
+#define OP_IsNull 111
+#define OP_NotNull 112
+#define OP_Negative 113
+#define OP_And 114
+#define OP_Or 115
+#define OP_Not 116
+#define OP_Concat 117
+#define OP_Noop 118
+#define OP_Function 119
+
+#define OP_Limit 120
+
+
+#define OP_MAX 120
/*
** Prototypes for the VDBE interface. See comments on the implementation
** the WHERE clause of SQL statements. Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
-** $Id: where.c,v 1.48 2002/05/26 20:54:34 drh Exp $
+** $Id: where.c,v 1.49 2002/06/08 23:25:10 drh Exp $
*/
#include "sqliteInt.h"
case TK_GT:
case TK_GE:
case TK_EQ:
+ case TK_IN:
return 1;
default:
return 0;
pInfo->idxLeft = -1;
pInfo->idxRight = -1;
if( allowedOp(pExpr->op) && (pInfo->prereqRight & pInfo->prereqLeft)==0 ){
- if( pExpr->pRight->op==TK_COLUMN ){
+ if( pExpr->pRight && pExpr->pRight->op==TK_COLUMN ){
pInfo->idxRight = pExpr->pRight->iTable - base;
pInfo->indexable = 1;
}
if( aExpr[j].idxLeft==idx && aExpr[j].p->pLeft->iColumn<0
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
switch( aExpr[j].p->op ){
+ case TK_IN:
case TK_EQ: iDirectEq[i] = j; break;
case TK_LE:
case TK_LT: iDirectLt[i] = j; break;
** there is an inequality used as a termination key. (ex: "x<...")
** If score&2 is not 0 then there is an inequality used as the
** start key. (ex: "x>...");
+ **
+ ** The IN operator as in "<expr> IN (...)" is treated the same as
+ ** an equality comparison.
*/
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int eqMask = 0; /* Index columns covered by an x=... constraint */
for(k=0; k<pIdx->nColumn; k++){
if( pIdx->aiColumn[k]==iColumn ){
switch( aExpr[j].p->op ){
+ case TK_IN:
case TK_EQ: {
eqMask |= 1<<k;
break;
}
pIdx = pLevel->pIdx;
+ pLevel->inOp = OP_Noop;
if( i<ARRAYSIZE(iDirectEq) && iDirectEq[i]>=0 ){
/* Case 1: We can directly reference a single row using an
** equality comparison against the ROWID field.
assert( k<nExpr );
assert( aExpr[k].p!=0 );
assert( aExpr[k].idxLeft==idx || aExpr[k].idxRight==idx );
+ brk = pLevel->brk = sqliteVdbeMakeLabel(v);
if( aExpr[k].idxLeft==idx ){
- sqliteExprCode(pParse, aExpr[k].p->pRight);
+ Expr *pX = aExpr[k].p;
+ if( pX->op!=TK_IN ){
+ sqliteExprCode(pParse, aExpr[k].p->pRight);
+ }else if( pX->pList ){
+ sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
+ pLevel->inOp = OP_SetNext;
+ pLevel->inP1 = pX->iTable;
+ pLevel->inP2 = sqliteVdbeCurrentAddr(v);
+ }else{
+ assert( pX->pSelect );
+ sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);
+ sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
+ pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);
+ pLevel->inOp = OP_Next;
+ pLevel->inP1 = pX->iTable;
+ }
}else{
sqliteExprCode(pParse, aExpr[k].p->pLeft);
}
aExpr[k].p = 0;
- brk = pLevel->brk = sqliteVdbeMakeLabel(v);
- cont = pLevel->cont = brk;
+ cont = pLevel->cont = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk);
- if( i==pTabList->nSrc-1 && pushKey ){
- /* Note: The OP_Dup below will cause the recno to be left on the
- ** stack if the record 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,
- ** because the pushKey flag is only true for UPDATE and DELETE, not
- ** for SELECT, and nested loops only occur on a SELECT.
- ** So it is safe to leave the recno on the stack.
- */
- haveKey = 1;
- sqliteVdbeAddOp(v, OP_Dup, 0, 0);
- }else{
- haveKey = 0;
- }
+ haveKey = 0;
sqliteVdbeAddOp(v, OP_NotExists, base+idx, brk);
pLevel->op = OP_Noop;
}else if( pIdx!=0 && pLevel->score%4==0 ){
int start;
int testOp;
int nColumn = pLevel->score/4;
+ brk = pLevel->brk = sqliteVdbeMakeLabel(v);
for(j=0; j<nColumn; j++){
for(k=0; k<nExpr; k++){
- if( aExpr[k].p==0 ) continue;
+ Expr *pX = aExpr[k].p;
+ if( pX==0 ) continue;
if( aExpr[k].idxLeft==idx
- && aExpr[k].p->op==TK_EQ
&& (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
- && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
+ && pX->pLeft->iColumn==pIdx->aiColumn[j]
){
- sqliteExprCode(pParse, aExpr[k].p->pRight);
- aExpr[k].p = 0;
- break;
+ if( pX->op==TK_EQ ){
+ sqliteExprCode(pParse, pX->pRight);
+ aExpr[k].p = 0;
+ break;
+ }
+ if( pX->op==TK_IN && nColumn==1 ){
+ if( pX->pList ){
+ sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
+ pLevel->inOp = OP_SetNext;
+ pLevel->inP1 = pX->iTable;
+ pLevel->inP2 = sqliteVdbeCurrentAddr(v);
+ }else{
+ assert( pX->pSelect );
+ sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);
+ sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
+ pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);
+ pLevel->inOp = OP_Next;
+ pLevel->inP1 = pX->iTable;
+ }
+ aExpr[k].p = 0;
+ break;
+ }
}
if( aExpr[k].idxRight==idx
&& aExpr[k].p->op==TK_EQ
}
}
pLevel->iMem = pParse->nMem++;
- brk = pLevel->brk = sqliteVdbeMakeLabel(v);
cont = pLevel->cont = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_MakeKey, nColumn, 0);
if( nColumn==pIdx->nColumn ){
sqliteVdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
}
sqliteVdbeResolveLabel(v, pLevel->brk);
+ if( pLevel->inOp!=OP_Noop ){
+ sqliteVdbeAddOp(v, pLevel->inOp, pLevel->inP1, pLevel->inP2);
+ }
if( pLevel->iLeftJoin ){
int addr;
addr = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0);