Add optimizations for the IN operator in WHERE clauses. This is a partial
implementation of enhancement #63. Still need to add test cases. (CVS 610) FossilOrigin-Name: 8481e841ebdeabe07bf780246bda1aa053eb60b7
This commit is contained in:
parent
f5db2d3ea2
commit
d99f70680f
20
manifest
20
manifest
@ -1,5 +1,5 @@
|
||||
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
|
||||
@ -26,7 +26,7 @@ F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
|
||||
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
|
||||
@ -41,7 +41,7 @@ F src/select.c 1d5cb1ae0bb3376bedfde7ae22e6e927e4d0b5e2
|
||||
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
|
||||
@ -52,9 +52,9 @@ F src/tokenize.c 35c63867d03fcaf81fe520f8d8206981d0c7270e
|
||||
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
|
||||
@ -136,7 +136,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
|
||||
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
|
||||
|
@ -1 +1 @@
|
||||
d939294994e5f6c7862b66573301e111e56a2681
|
||||
8481e841ebdeabe07bf780246bda1aa053eb60b7
|
@ -12,7 +12,7 @@
|
||||
** 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_
|
||||
@ -99,6 +99,7 @@ void sqliteHashClear(Hash*);
|
||||
#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
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** 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"
|
||||
@ -411,7 +411,8 @@ struct Token {
|
||||
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
|
||||
@ -419,7 +420,8 @@ struct Expr {
|
||||
** 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>)" */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -508,6 +510,7 @@ struct WhereLevel {
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
79
src/vdbe.c
79
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.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>
|
||||
@ -198,6 +198,7 @@ struct AggElem {
|
||||
typedef struct Set Set;
|
||||
struct Set {
|
||||
Hash hash; /* A set is just a hash table */
|
||||
HashElem *prev; /* Previously accessed hash elemen */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1066,19 +1067,19 @@ static char *zOpName[] = { 0,
|
||||
"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",
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1957,7 +1958,7 @@ case OP_AddImm: {
|
||||
/* 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.
|
||||
*/
|
||||
@ -3018,7 +3019,7 @@ case OP_MoveTo: {
|
||||
** 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 *
|
||||
**
|
||||
@ -3027,7 +3028,7 @@ case OP_MoveTo: {
|
||||
** 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 *
|
||||
**
|
||||
@ -3084,7 +3085,7 @@ case OP_Found: {
|
||||
** 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;
|
||||
@ -3167,7 +3168,7 @@ case OP_IsUnique: {
|
||||
** 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;
|
||||
@ -4775,6 +4776,46 @@ case OP_SetNotFound: {
|
||||
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...
|
||||
*/
|
||||
|
100
src/vdbe.h
100
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.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_
|
||||
@ -149,62 +149,64 @@ typedef struct VdbeOp VdbeOp;
|
||||
#define OP_SetInsert 69
|
||||
#define OP_SetFound 70
|
||||
#define OP_SetNotFound 71
|
||||
#define OP_SetFirst 72
|
||||
#define OP_SetNext 73
|
||||
|
||||
#define OP_MakeRecord 72
|
||||
#define OP_MakeKey 73
|
||||
#define OP_MakeIdxKey 74
|
||||
#define OP_IncrKey 75
|
||||
#define OP_MakeRecord 74
|
||||
#define OP_MakeKey 75
|
||||
#define OP_MakeIdxKey 76
|
||||
#define OP_IncrKey 77
|
||||
|
||||
#define OP_Goto 76
|
||||
#define OP_If 77
|
||||
#define OP_IfNot 78
|
||||
#define OP_Halt 79
|
||||
#define OP_Goto 78
|
||||
#define OP_If 79
|
||||
#define OP_IfNot 80
|
||||
#define OP_Halt 81
|
||||
|
||||
#define OP_ColumnCount 80
|
||||
#define OP_ColumnName 81
|
||||
#define OP_Callback 82
|
||||
#define OP_NullCallback 83
|
||||
#define OP_ColumnCount 82
|
||||
#define OP_ColumnName 83
|
||||
#define OP_Callback 84
|
||||
#define OP_NullCallback 85
|
||||
|
||||
#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_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 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_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 118
|
||||
#define OP_Limit 120
|
||||
|
||||
|
||||
#define OP_MAX 118
|
||||
#define OP_MAX 120
|
||||
|
||||
/*
|
||||
** Prototypes for the VDBE interface. See comments on the implementation
|
||||
|
84
src/where.c
84
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.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"
|
||||
|
||||
@ -112,6 +112,7 @@ static int allowedOp(int op){
|
||||
case TK_GT:
|
||||
case TK_GE:
|
||||
case TK_EQ:
|
||||
case TK_IN:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
@ -136,7 +137,7 @@ static void exprAnalyze(int base, ExprInfo *pInfo){
|
||||
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;
|
||||
}
|
||||
@ -288,6 +289,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
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;
|
||||
@ -329,6 +331,9 @@ WhereInfo *sqliteWhereBegin(
|
||||
** 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 */
|
||||
@ -346,6 +351,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
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;
|
||||
@ -467,6 +473,7 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
|
||||
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.
|
||||
@ -475,30 +482,31 @@ WhereInfo *sqliteWhereBegin(
|
||||
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 ){
|
||||
@ -507,17 +515,37 @@ WhereInfo *sqliteWhereBegin(
|
||||
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
|
||||
@ -531,7 +559,6 @@ WhereInfo *sqliteWhereBegin(
|
||||
}
|
||||
}
|
||||
pLevel->iMem = pParse->nMem++;
|
||||
brk = pLevel->brk = sqliteVdbeMakeLabel(v);
|
||||
cont = pLevel->cont = sqliteVdbeMakeLabel(v);
|
||||
sqliteVdbeAddOp(v, OP_MakeKey, nColumn, 0);
|
||||
if( nColumn==pIdx->nColumn ){
|
||||
@ -834,6 +861,9 @@ void sqliteWhereEnd(WhereInfo *pWInfo){
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user