-C Add\scomments\sto\stest\scases.\s\sImprovements\sto\sthe\squery\splan\stest\svariable.\s(CVS\s2555)
-D 2005-07-21T03:48:20
+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)
+D 2005-07-21T18:23:20
F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f
F src/btree.c ec55bd70052cdd0958f3a0e79ad58d93561acb20
F src/btree.h 41a71ce027db9ddee72cb43df2316bbe3a1d92af
-F src/build.c a908365b4f900096f406f9028181550f818f59fd
+F src/build.c c2b9379e3b51775de01137a68d3a67359e29d3aa
F src/callback.c 0910b611e0c158f107ee3ff86f8a371654971e2b
F src/date.c 7444b0900a28da77e57e3337a636873cff0ae940
-F src/delete.c 250d436a68fe371b4ab403d1c0f6fdc9a6860c39
+F src/delete.c be1fc25c9e109cd8cbab42a43ee696263da7c04b
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
-F src/expr.c cf5146e8a0a1ce7261ac2f9ecb15e99eb98de7ac
+F src/expr.c 0e158f7cc8df562320faa9f2de48cfd856458a52
F src/func.c 2be0799df0c05066a29e589485ebee0b3f756a15
F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
-F src/insert.c c4533240451b73ead88098b5d819cb70fa0880bd
+F src/insert.c 484c73bc1309f283a31baa0e114f3ee980536397
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
F src/main.c 568005dc335c17bf1f7ce346652c1c505f412fd7
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
F src/select.c c611471052773b94af771693686bd5bcdbbb0dba
F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
F src/sqlite.h.in 838382ed6b48d392366a55e07f49d9d71263e1fe
-F src/sqliteInt.h a3252616131187e227268fc405c8c536b3be9fac
+F src/sqliteInt.h 89ace2d46348c2924368ff97d41adec5cacacfdc
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c cccaf6b78c290d824cf8ea089b8b27377e545830
F src/test1.c 722c1444b5774705eb6eb11163343fc94ffe17f7
F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5
F src/tokenize.c 57ec9926612fb9e325b57a141303573bc20c79bf
F src/trigger.c f51dec15921629591cb98bf2e350018e268b109a
-F src/update.c 49a9c618c3ba1ca57038d9ce41f14e958442fe58
+F src/update.c a9d2c5f504212d62da1b094476f1389c0e02f83f
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
F src/util.c 668d31be592753e5b8ea00e69ea8d3eedb29fa22
F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c
-F src/vdbe.c 7b41a1979d3421dbbe34a3a48970b4e75fb1d634
+F src/vdbe.c aa8b8d30aa5b1b046a6a5acf502370a064581e09
F src/vdbe.h 75e466d84d362b0c4498978a9d6b1e6bd32ecf3b
F src/vdbeInt.h 9be9a6c43d38124bd03cc5cf05715605b1789fd9
F src/vdbeapi.c 7f392f0792d1258c958083d7de9eae7c3530c9a6
F src/vdbeaux.c 3732a86566a6be4da4c606e9334baf3fd98667af
F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e
F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03
-F src/where.c 9e5bd5f1ab83a2d55c9e84a7e6613602b477e328
+F src/where.c 65d9b27edaf29edaba95442f65a3cfc36ae6dbdb
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
-P c30cbba9ead1b4d07f225b1e8a65d5d5230ea45d
-R ce3457bbcec9a76540a332d37f4098ee
+P ef3a157f469d72cbd2f713f997598ddf47f340d2
+R 36cfab460ee644fb8d42d82df874b83c
U drh
-Z a55f9e28ea4b33602aa900e8cfaf2b57
+Z b75bf1e0203a3ee4b4ae420ba35e8ecb
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
-** $Id: where.c,v 1.149 2005/07/21 03:48:20 drh Exp $
+** $Id: where.c,v 1.150 2005/07/21 18:23:20 drh Exp $
*/
#include "sqliteInt.h"
/*
** The number of bits in a Bitmask. "BMS" means "BitMask Size".
*/
-#define BMS (sizeof(Bitmask)*8-1)
+#define BMS (sizeof(Bitmask)*8)
/*
** Determine the number of elements in an array.
*/
typedef struct WhereClause WhereClause;
-/*
-** An instance of the following structure holds information about how well
-** a particular index helps in a search. A list of such structures is
-** attached to each SrcList_item of a SrcList.
-*/
-struct WhereIdx {
- Index *pIdx; /* The index under consideration */
- Bitmask prereq; /* Prerequesite FROM clause elements for using this index */
- int nEqTerm; /* Number of Idx column constrainted by == or IN */
- int nTerm; /* Total number of Index Columns used */
- int flags; /* Flags. See below */
- double rRowEst; /* Estimated number of rows selected */
- double rScore; /* Score of this index */
- WhereIdx *pNext; /* Next WhereIdx on the same FROM clause element */
-};
-
/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause. Each WHERE
** end |-- by sqlite3WhereEnd()
** end /
**
+** Note that the loops might not be nested in the order in which they
+** appear in the FROM clause if a different order is better able to make
+** use of indices.
+**
** There are Btree cursors associated with each table. t1 uses cursor
** number pTabList->a[0].iCursor. t2 uses the cursor pTabList->a[1].iCursor.
** And so forth. This routine generates code to open those VDBE cursors
WhereClause wc; /* The WHERE clause is divided into these terms */
struct SrcList_item *pTabItem; /* A single entry from pTabList */
WhereLevel *pLevel; /* A single level in the pWInfo list */
+ int iFrom; /* First unused FROM clause element */
- /* The number of terms 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
*/
- if( pTabList->nSrc>sizeof(Bitmask)*8 ){
- sqlite3ErrorMsg(pParse, "at most %d tables in a join",
- sizeof(Bitmask)*8);
+ if( pTabList->nSrc>BMS ){
+ sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
return 0;
}
/* Split the WHERE clause into separate subexpressions where each
- ** subexpression is separated by an AND operator. If the wc.a[]
- ** array fills up, the last entry might point to an expression which
- ** contains additional unfactored AND operators.
+ ** subexpression is separated by an AND operator.
*/
initMaskSet(&maskSet);
whereClauseInit(&wc, pParse);
pWhere = 0;
}
- /* Analyze all of the subexpressions.
+ /* Analyze all of the subexpressions. Note that exprAnalyze() might
+ ** add new virtual terms onto the end of the WHERE clause. We do not
+ ** want to analyze these virtual terms, so start analyzing at the end
+ ** and work forward so that they added virtual terms are never processed.
*/
for(i=0; i<pTabList->nSrc; i++){
createMask(&maskSet, pTabList->a[i].iCursor);
exprAnalyze(pTabList, &maskSet, &wc.a[i]);
}
- /* 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.
+ **
+ ** This loop fills in the pWInfo->a[].pIdx and pWInfo->a[].flags fields
+ ** with information
+ ** Reorder tables if necessary in order to choose a good ordering.
+ ** However, LEFT JOIN tables cannot be reordered.
*/
notReady = ~(Bitmask)0;
pTabItem = pTabList->a;
pLevel = pWInfo->a;
- for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){
- Index *pBest;
- int flags;
- bestIndex(pParse, &wc, pTabItem, notReady,
- (i==0 && ppOrderBy) ? *ppOrderBy : 0,
- &pBest, &flags);
- if( flags & WHERE_ORDERBY ){
+ for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
+ Index *pIdx; /* Index for FROM table at pTabItem */
+ int flags; /* Flags asssociated with pIdx */
+ double score; /* The score for pIdx */
+ int j; /* For looping over FROM tables */
+ Index *pBest = 0; /* The best index seen so far */
+ int bestFlags = 0; /* Flags associated with pBest */
+ double bestScore = -1.0; /* The score of pBest */
+ int bestJ; /* The value of j */
+ Bitmask m; /* Bitmask value for j or bestJ */
+
+ for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
+ m = getMask(&maskSet, pTabItem->iCursor);
+ if( (m & notReady)==0 ){
+ if( j==iFrom ) iFrom++;
+ continue;
+ }
+ score = bestIndex(pParse, &wc, pTabItem, notReady,
+ (j==0 && ppOrderBy) ? *ppOrderBy : 0,
+ &pIdx, &flags);
+ if( score>bestScore ){
+ bestScore = score;
+ pBest = pIdx;
+ bestFlags = flags;
+ bestJ = j;
+ }
+ if( (pTabItem->jointype & JT_LEFT)!=0
+ || (j>0 && (pTabItem[-1].jointype & JT_LEFT)!=0)
+ ){
+ break;
+ }
+ }
+ if( bestFlags & WHERE_ORDERBY ){
*ppOrderBy = 0;
}
- pLevel->flags = flags;
+ pLevel->flags = bestFlags;
pLevel->pIdx = pBest;
if( pBest ){
pLevel->iIdxCur = pParse->nTab++;
}else{
pLevel->iIdxCur = -1;
}
- notReady &= ~getMask(&maskSet, pTabItem->iCursor);
+ notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
+ pLevel->iFrom = bestJ;
}
/* Open all tables in the pTabList and any indices selected for
*/
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
pLevel = pWInfo->a;
- for(i=0, pTabItem=pTabList->a; i<pTabList->nSrc; i++, pTabItem++, pLevel++){
+ for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
Table *pTab;
Index *pIx;
int iIdxCur = pLevel->iIdxCur;
+ pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
if( pTab->isTransient || pTab->pSelect ) continue;
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
pLevel->iTabCur = pTabItem->iCursor;
if( (pIx = pLevel->pIdx)!=0 ){
sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
+ VdbeComment((v, "# %s", pIx->zName));
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
(char*)&pIx->keyInfo, P3_KEYINFO);
}
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
}
sqlite3CodeVerifySchema(pParse, pTab->iDb);
-
-#ifdef SQLITE_TEST
- /* Record in the query plan information about the current table
- ** and the index used to access it (if any). If the table itself
- ** is not used, its name is just '{}'. If no index is used
- ** the index is listed as "{}"
- */
- {
- char *z = pTabItem->zAlias;
- int n;
- if( z==0 ) z = pTab->zName;
- n = strlen(z);
- if( n+nQPlan < sizeof(sqlite3_query_plan)-10 ){
- if( pLevel->flags & WHERE_IDX_ONLY ){
- strcpy(&sqlite3_query_plan[nQPlan], "{}");
- nQPlan += 2;
- }else{
- strcpy(&sqlite3_query_plan[nQPlan], z);
- nQPlan += n;
- }
- sqlite3_query_plan[nQPlan++] = ' ';
- }
- if( pIx==0 ){
- strcpy(&sqlite3_query_plan[nQPlan], " {}");
- nQPlan += 3;
- }else{
- n = strlen(pIx->zName);
- if( n+nQPlan < sizeof(sqlite3_query_plan)-2 ){
- strcpy(&sqlite3_query_plan[nQPlan], pIx->zName);
- nQPlan += n;
- sqlite3_query_plan[nQPlan++] = ' ';
- }
- }
- }
-#endif
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
-#ifdef SQLITE_TEST
- /* Terminate the query plan description
- */
- while( nQPlan>0 && sqlite3_query_plan[nQPlan-1]==' ' ){
- sqlite3_query_plan[--nQPlan] = 0;
- }
- sqlite3_query_plan[nQPlan] = 0;
- nQPlan = 0;
-#endif
-
- /* Generate the code to do the search
+ /* Generate the code to do the search. Each iteration of the for
+ ** loop below generates code for a single nested loop of the VM
+ ** program.
*/
notReady = ~(Bitmask)0;
- pLevel = pWInfo->a;
- pTabItem = pTabList->a;
- for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){
+ for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
int j;
int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */
Index *pIdx; /* The index we will be using */
int iIdxCur; /* The VDBE cursor for the index */
int omitTable; /* True if we use the index only */
+ int bRev; /* True if we need to scan in reverse order */
+ pTabItem = &pTabList->a[pLevel->iFrom];
+ iCur = pTabItem->iCursor;
pIdx = pLevel->pIdx;
iIdxCur = pLevel->iIdxCur;
pLevel->inOp = OP_Noop;
+ bRev = (pLevel->flags & WHERE_REVERSE)!=0;
+ omitTable = (pLevel->flags & WHERE_IDX_ONLY)!=0;
- /* Check to see if it is appropriate to omit the use of the table
- ** here and use its index instead.
+ /* Create labels for the "break" and "continue" instructions
+ ** for the current loop. Jump to brk to break out of a loop.
+ ** Jump to cont to go immediately to the next iteration of the
+ ** loop.
*/
- omitTable = (pLevel->flags & WHERE_IDX_ONLY)!=0;
+ brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
+ cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
/* If this is the right table of a LEFT OUTER JOIN, allocate and
** initialize a memory cell that records if this table matches any
** row of the left table of the join.
*/
- if( i>0 && (pTabList->a[i-1].jointype & JT_LEFT)!=0 ){
+ if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
if( !pParse->nMem ) pParse->nMem++;
pLevel->iLeftJoin = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
assert( pTerm->pExpr!=0 );
assert( pTerm->leftCursor==iCur );
assert( omitTable==0 );
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
codeEqualityTerm(pParse, pTerm, brk, pLevel);
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk);
sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk);
VdbeComment((v, "pk"));
*/
int start;
int nColumn;
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
/* For each column of the index, find the term of the WHERE clause that
** constraints that column. If the WHERE clause term is X=expr, then
}
nColumn = j;
pLevel->iMem = pParse->nMem++;
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
buildIndexProbe(v, nColumn, brk, pIdx);
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
** the last matching element of the table. The code (1) is executed
** once to initialize the search, the code (2) is executed before each
** iteration of the scan to see if the scan has finished. */
- if( pLevel->flags & WHERE_REVERSE ){
+ if( bRev ){
/* Scan in reverse order */
sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk);
start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
int testOp = OP_Noop;
int start;
WhereTerm *pStart, *pEnd;
- int bRev = (pLevel->flags & WHERE_REVERSE)!=0;
assert( omitTable==0 );
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
if( pLevel->flags & WHERE_BTM_LIMIT ){
pStart = findTerm(&wc, iCur, -1, notReady, WO_GT|WO_GE, 0);
assert( pStart!=0 );
int testOp;
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
- int bRev = (pLevel->flags & WHERE_REVERSE)!=0;
/* Evaluate the equality constraints
*/
sqlite3VdbeAddOp(v, OP_Dup, nEqColumn-1, 0);
}
- /* Labels for the beginning and end of the loop
- */
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
-
/* Generate the termination key. This is the key value that
** will end the search. There is no termination key if there
** are no equality terms and no "X<..." term.
/* Case 5: There is no usable index. We must do a complete
** scan of the entire table.
*/
- int start;
int opRewind;
assert( omitTable==0 );
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
- cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
- if( pLevel->flags & WHERE_REVERSE ){
+ if( bRev ){
opRewind = OP_Last;
pLevel->op = OP_Prev;
}else{
opRewind = OP_Rewind;
pLevel->op = OP_Next;
}
- sqlite3VdbeAddOp(v, opRewind, iCur, brk);
- start = sqlite3VdbeCurrentAddr(v);
pLevel->p1 = iCur;
- pLevel->p2 = start;
+ pLevel->p2 = 1 + sqlite3VdbeAddOp(v, opRewind, iCur, brk);
}
notReady &= ~getMask(&maskSet, iCur);
sqlite3ExprIfFalse(pParse, pE, cont, 1);
pTerm->flags |= TERM_CODED;
}
- brk = cont;
/* For a LEFT OUTER JOIN, generate code that will record the fact that
** at least one row of the right table has matched the left table.
for(i=0; i<pTabList->nSrc; i++){
char *z;
int n;
- pTabItem = &pTabList->a[i];
pLevel = &pWInfo->a[i];
+ pTabItem = &pTabList->a[pLevel->iFrom];
z = pTabItem->zAlias;
if( z==0 ) z = pTabItem->pTab->zName;
n = strlen(z);
nQPlan = 0;
#endif /* SQLITE_TEST // Testing and debugging use only */
-
+ /* Record the continuation address in the WhereInfo structure. Then
+ ** clean up and return.
+ */
pWInfo->iContinue = cont;
freeMaskSet(&maskSet);
whereClauseClear(&wc);
int i;
WhereLevel *pLevel;
SrcList *pTabList = pWInfo->pTabList;
- struct SrcList_item *pTabItem;
/* Generate loop termination code.
*/
*/
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
- /* Close all of the cursors that were opend by sqlite3WhereBegin.
+ /* Close all of the cursors that were opened by sqlite3WhereBegin.
*/
- pLevel = pWInfo->a;
- pTabItem = pTabList->a;
- for(i=0; i<pTabList->nSrc; i++, pTabItem++, pLevel++){
+ for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
+ struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
if( pTab->isTransient || pTab->pSelect ) continue;
sqliteFree(pWInfo);
return;
}
-
-
-/*
-** Delete a list of WhereIdx structures.
-*/
-void sqlite3WhereIdxListDelete(WhereIdx *p){
- WhereIdx *pNext;
- while( p ){
- pNext = p->pNext;
- sqliteFree(p);
- p = pNext;
- }
-}