1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-08 03:22:21 +03:00

Begin adding code to support multiple IN constraints on the same index. (CVS 2557)

FossilOrigin-Name: 103f8ccb9013689a480766ebffbf570d4aa8bac5
This commit is contained in:
drh
2005-07-22 00:31:39 +00:00
parent 29dda4ae65
commit e23399fc9c
4 changed files with 98 additions and 39 deletions

View File

@@ -1,5 +1,5 @@
C Split\sthe\sOP_Integer\sopcode\sinto\sOP_Integer\sand\sOP_Int64.\s\sThis\sallows\ncomments\sto\sbe\sadded\sto\sOP_Integer.\s\sCleanup\sin\sthe\soptimizer.\s\sAllow\nterms\sof\sthe\sFROM\sclause\sto\sbe\sreordered\sautomatically.\s(CVS\s2556) C Begin\sadding\scode\sto\ssupport\smultiple\sIN\sconstraints\son\sthe\ssame\sindex.\s(CVS\s2557)
D 2005-07-21T18:23:20 D 2005-07-22T00:31:40
F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165 F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -64,7 +64,7 @@ F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
F src/select.c c611471052773b94af771693686bd5bcdbbb0dba F src/select.c c611471052773b94af771693686bd5bcdbbb0dba
F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26 F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe
F src/sqliteInt.h 89ace2d46348c2924368ff97d41adec5cacacfdc F src/sqliteInt.h 810f2ccd49338944ec53c95182e5a8b56da42fa0
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830 F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830
F src/test1.c 722c1444b5774705eb6eb11163343fc94ffe17f7 F src/test1.c 722c1444b5774705eb6eb11163343fc94ffe17f7
@@ -85,7 +85,7 @@ F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6
F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03 F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
F src/where.c 65d9b27edaf29edaba95442f65a3cfc36ae6dbdb F src/where.c 70b2195b4732ce785be32140f982b2ed471d205d
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6 F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
@@ -286,7 +286,7 @@ F www/tclsqlite.tcl 425be741b8ae664f55cb1ef2371aab0a75109cf9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
P ef3a157f469d72cbd2f713f997598ddf47f340d2 P e2f822ac82d0a5a59de0b63cce65d4fd6c178ff1
R 36cfab460ee644fb8d42d82df874b83c R 156ee4225ef63d3a2b0a126183a1b6ad
U drh U drh
Z b75bf1e0203a3ee4b4ae420ba35e8ecb Z b87a4baf4ad23e926496089f67763fa0

View File

@@ -1 +1 @@
e2f822ac82d0a5a59de0b63cce65d4fd6c178ff1 103f8ccb9013689a480766ebffbf570d4aa8bac5

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.396 2005/07/21 18:23:20 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.397 2005/07/22 00:31:40 drh Exp $
*/ */
#ifndef _SQLITEINT_H_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@@ -960,7 +960,8 @@ struct WhereLevel {
int cont; /* Jump here to continue with the next loop cycle */ int cont; /* Jump here to continue with the next loop cycle */
int top; /* First instruction of interior of the loop */ int top; /* First instruction of interior of the loop */
int op, p1, p2; /* Opcode used to terminate the loop */ int op, p1, p2; /* Opcode used to terminate the loop */
int inOp, inP1, inP2; /* Opcode used to implement an IN operator */ int nIn; /* Number of IN operators constraining this loop */
int *aInLoop; /* Loop terminators for IN operators */
}; };
/* /*

View File

@@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting ** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer". ** indices, you might also think of this module as the "query optimizer".
** **
** $Id: where.c,v 1.150 2005/07/21 18:23:20 drh Exp $ ** $Id: where.c,v 1.151 2005/07/22 00:31:40 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -97,6 +97,35 @@ struct WhereClause {
WhereTerm aStatic[10]; /* Initial static space for the terms */ WhereTerm aStatic[10]; /* Initial static space for the terms */
}; };
/*
** When WhereTerms are used to select elements from an index, we
** call those terms "constraints". For example, consider the following
** SQL:
**
** CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
** CREATE INDEX t1i1 ON t1(b,c);
**
** SELECT * FROM t1 WHERE d=5 AND b=7 AND c>11;
**
** In the SELECT statement, the "b=7" and "c>11" terms are constraints
** because they can be used to choose rows out of the t1i1 index. But
** the "d=5" term is not a constraint because it is not indexed.
**
** When generating code to access an index, we have to keep track of
** all of the constraints associated with that index. This is done
** using an array of instanaces of the following structure. There is
** one instance of this structure for each constraint on the index.
**
** Actually, we allocate the array of this structure based on the total
** number of terms in the entire WHERE clause (because the number of
** constraints can never be more than that) and reuse it when coding
** each index.
*/
typedef struct WhereConstraint WhereConstraint;
struct WhereConstraint {
int iMem; /* Mem cell used to hold <expr> part of constraint */
};
/* /*
** An instance of the following structure keeps track of a mapping ** An instance of the following structure keeps track of a mapping
** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
@@ -242,11 +271,6 @@ static void createMask(ExprMaskSet *pMaskSet, int iCursor){
pMaskSet->ix[pMaskSet->n++] = iCursor; pMaskSet->ix[pMaskSet->n++] = iCursor;
} }
/*
** Destroy an expression mask set
*/
#define freeMaskSet(P) /* NO-OP */
/* /*
** This routine walks (recursively) an expression tree and generates ** This routine walks (recursively) an expression tree and generates
** a bitmask indicating which tables are used in that expression ** a bitmask indicating which tables are used in that expression
@@ -576,16 +600,18 @@ static int sortableByRowid(
/* /*
** Value for flags returned by bestIndex() ** Value for flags returned by bestIndex()
*/ */
#define WHERE_ROWID_EQ 0x001 /* rowid=EXPR or rowid IN (...) */ #define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */
#define WHERE_ROWID_RANGE 0x002 /* rowid<EXPR and/or rowid>EXPR */ #define WHERE_ROWID_RANGE 0x0002 /* rowid<EXPR and/or rowid>EXPR */
#define WHERE_COLUMN_EQ 0x004 /* x=EXPR or x IN (...) */ #define WHERE_COLUMN_EQ 0x0004 /* x=EXPR or x IN (...) */
#define WHERE_COLUMN_RANGE 0x008 /* x<EXPR and/or x>EXPR */ #define WHERE_COLUMN_RANGE 0x0008 /* x<EXPR and/or x>EXPR */
#define WHERE_SCAN 0x010 /* Do a full table scan */ #define WHERE_SCAN 0x0010 /* Do a full table scan */
#define WHERE_REVERSE 0x020 /* Scan in reverse order */ #define WHERE_REVERSE 0x0020 /* Scan in reverse order */
#define WHERE_ORDERBY 0x040 /* Output will appear in correct order */ #define WHERE_ORDERBY 0x0040 /* Output will appear in correct order */
#define WHERE_IDX_ONLY 0x080 /* Use index only - omit table */ #define WHERE_IDX_ONLY 0x0080 /* Use index only - omit table */
#define WHERE_TOP_LIMIT 0x100 /* x<EXPR or x<=EXPR constraint */ #define WHERE_TOP_LIMIT 0x0100 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x200 /* x>EXPR or x>=EXPR constraint */ #define WHERE_BTM_LIMIT 0x0200 /* x>EXPR or x>=EXPR constraint */
#define WHERE_USES_IN 0x0400 /* True if the IN operator is used */
#define WHERE_UNIQUE 0x0800 /* True if fully specifies a unique idx */
/* /*
** Find the best index for accessing a particular table. Return the index, ** Find the best index for accessing a particular table. Return the index,
@@ -619,7 +645,7 @@ static double bestIndex(
if( pOrderBy ) *pFlags |= WHERE_ORDERBY; if( pOrderBy ) *pFlags |= WHERE_ORDERBY;
return 1.0e10; return 1.0e10;
}else{ }else{
*pFlags = WHERE_ROWID_EQ; *pFlags = WHERE_ROWID_EQ | WHERE_USES_IN;
return 1.0e9; return 1.0e9;
} }
} }
@@ -675,12 +701,22 @@ static double bestIndex(
/* The optimization type is RANGE if there are no == or IN constraints /* The optimization type is RANGE if there are no == or IN constraints
*/ */
if( usesIN || nEq ){ if( usesIN ){
flags = WHERE_COLUMN_EQ | WHERE_USES_IN;
}else if( nEq ){
flags = WHERE_COLUMN_EQ; flags = WHERE_COLUMN_EQ;
}else{ }else{
flags = WHERE_COLUMN_RANGE; flags = WHERE_COLUMN_RANGE;
} }
/* Check for a uniquely specified row
*/
#if 0
if( nEq==pProbe->nColumn && pProbe->isUnique ){
flags |= WHERE_UNIQUE;
}
#endif
/* Look for range constraints /* Look for range constraints
*/ */
if( !usesIN && nEq<pProbe->nColumn ){ if( !usesIN && nEq<pProbe->nColumn ){
@@ -819,7 +855,7 @@ static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){
*/ */
static void codeEqualityTerm( static void codeEqualityTerm(
Parse *pParse, /* The parsing context */ Parse *pParse, /* The parsing context */
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
int brk, /* Jump here to abandon the loop */ int brk, /* Jump here to abandon the loop */
WhereLevel *pLevel /* When level of the FROM clause we are working on */ WhereLevel *pLevel /* When level of the FROM clause we are working on */
){ ){
@@ -830,15 +866,22 @@ static void codeEqualityTerm(
#ifndef SQLITE_OMIT_SUBQUERY #ifndef SQLITE_OMIT_SUBQUERY
}else{ }else{
int iTab; int iTab;
int *aIn;
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
sqlite3CodeSubselect(pParse, pX); sqlite3CodeSubselect(pParse, pX);
iTab = pX->iTable; iTab = pX->iTable;
sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk); sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z)); VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
pLevel->inP2 = sqlite3VdbeAddOp(v, OP_Column, iTab, 0); pLevel->nIn++;
pLevel->inOp = OP_Next; pLevel->aInLoop = aIn = sqliteRealloc(pLevel->aInLoop,
pLevel->inP1 = iTab; sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
if( aIn ){
aIn += pLevel->nIn*3 - 3;
aIn[0] = OP_Next;
aIn[1] = iTab;
aIn[2] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
}
#endif #endif
} }
disableTerm(pLevel, pTerm); disableTerm(pLevel, pTerm);
@@ -961,6 +1004,7 @@ WhereInfo *sqlite3WhereBegin(
struct SrcList_item *pTabItem; /* A single entry from pTabList */ struct SrcList_item *pTabItem; /* A single entry from pTabList */
WhereLevel *pLevel; /* A single level in the pWInfo list */ WhereLevel *pLevel; /* A single level in the pWInfo list */
int iFrom; /* First unused FROM clause element */ int iFrom; /* First unused FROM clause element */
WhereConstraint *aConstraint; /* Information on constraints */
/* The number of tables in the FROM clause is limited by the number of /* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask ** bits in a Bitmask
@@ -982,9 +1026,7 @@ WhereInfo *sqlite3WhereBegin(
*/ */
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel)); pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
if( sqlite3_malloc_failed ){ if( sqlite3_malloc_failed ){
sqliteFree(pWInfo); /* Avoid leaking memory when malloc fails */ goto whereBeginNoMem;
whereClauseClear(&wc);
return 0;
} }
pWInfo->pParse = pParse; pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList; pWInfo->pTabList = pTabList;
@@ -1009,6 +1051,10 @@ WhereInfo *sqlite3WhereBegin(
for(i=wc.nTerm-1; i>=0; i--){ for(i=wc.nTerm-1; i>=0; i--){
exprAnalyze(pTabList, &maskSet, &wc.a[i]); exprAnalyze(pTabList, &maskSet, &wc.a[i]);
} }
aConstraint = sqliteMalloc( wc.nTerm*sizeof(aConstraint[0]) );
if( aConstraint==0 && wc.nTerm>0 ){
goto whereBeginNoMem;
}
/* Chose the best index to use for each table in the FROM clause. /* Chose the best index to use for each table in the FROM clause.
** **
@@ -1057,6 +1103,8 @@ WhereInfo *sqlite3WhereBegin(
} }
pLevel->flags = bestFlags; pLevel->flags = bestFlags;
pLevel->pIdx = pBest; pLevel->pIdx = pBest;
pLevel->aInLoop = 0;
pLevel->nIn = 0;
if( pBest ){ if( pBest ){
pLevel->iIdxCur = pParse->nTab++; pLevel->iIdxCur = pParse->nTab++;
}else{ }else{
@@ -1113,7 +1161,6 @@ WhereInfo *sqlite3WhereBegin(
iCur = pTabItem->iCursor; iCur = pTabItem->iCursor;
pIdx = pLevel->pIdx; pIdx = pLevel->pIdx;
iIdxCur = pLevel->iIdxCur; iIdxCur = pLevel->iIdxCur;
pLevel->inOp = OP_Noop;
bRev = (pLevel->flags & WHERE_REVERSE)!=0; bRev = (pLevel->flags & WHERE_REVERSE)!=0;
omitTable = (pLevel->flags & WHERE_IDX_ONLY)!=0; omitTable = (pLevel->flags & WHERE_IDX_ONLY)!=0;
@@ -1511,9 +1558,15 @@ WhereInfo *sqlite3WhereBegin(
** clean up and return. ** clean up and return.
*/ */
pWInfo->iContinue = cont; pWInfo->iContinue = cont;
freeMaskSet(&maskSet);
whereClauseClear(&wc); whereClauseClear(&wc);
sqliteFree(aConstraint);
return pWInfo; return pWInfo;
/* Jump here if malloc fails */
whereBeginNoMem:
whereClauseClear(&wc);
sqliteFree(pWInfo);
return 0;
} }
/* /*
@@ -1535,8 +1588,13 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2); sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
} }
sqlite3VdbeResolveLabel(v, pLevel->brk); sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->inOp!=OP_Noop ){ if( pLevel->nIn ){
sqlite3VdbeAddOp(v, pLevel->inOp, pLevel->inP1, pLevel->inP2); int *a;
int j;
for(j=pLevel->nIn, a=&pLevel->aInLoop[j*3-3]; j>0; j--, a-=3){
sqlite3VdbeAddOp(v, a[0], a[1], a[2]);
}
sqliteFree(pLevel->aInLoop);
} }
if( pLevel->iLeftJoin ){ if( pLevel->iLeftJoin ){
int addr; int addr;