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

Pass information around between the major routines of the query planner

using a single pointer to a structure rather than a long list of parameters.

FossilOrigin-Name: 1104d42e104d561ce60d05d158acfe499ee9fd50
This commit is contained in:
drh
2012-09-25 14:29:39 +00:00
parent 4d85fa760f
commit 56f1b99d4d
3 changed files with 195 additions and 194 deletions

View File

@@ -1,5 +1,5 @@
C Remove\san\sunused\ssubfunction\sparameter\sand\san\sobsolete\scomment\sfrom\sthe\nquery\splanner\slogic\sin\swhere.c. C Pass\sinformation\saround\sbetween\sthe\smajor\sroutines\sof\sthe\squery\splanner\nusing\sa\ssingle\spointer\sto\sa\sstructure\srather\sthan\sa\slong\slist\sof\sparameters.
D 2012-09-24T19:50:00.842 D 2012-09-25T14:29:39.134
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -249,7 +249,7 @@ F src/vtab.c d8020c0a0e8ccc490ca449d7e665311b6e9f3ba9
F src/wal.c 5acb3e7bbd31f10ba39acad9ce6b399055337a9d F src/wal.c 5acb3e7bbd31f10ba39acad9ce6b399055337a9d
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 40708330a0e9bf79c0ab97109b8014fa04cce858 F src/where.c 82be1d2f8f27012de0ed9d0977753ed24312b791
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00 F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00
@@ -1016,7 +1016,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
P 22989f3588531efd555cc29d6c576e7a34b7edc4 P 349a55cd8ba9ce65ebfd987ecfebd1204f7d0a85
R af274415395e47bec73279dd70f3872e R b0986bef8aa73322a60d8a15dd219873
T *branch * qp-enhancements
T *sym-qp-enhancements *
T -sym-trunk *
U drh U drh
Z 2c59ca6ec247c019d5fe7043b4d83355 Z 6cfa0793222da70bc8fbd646a62c8a2a

View File

@@ -1 +1 @@
349a55cd8ba9ce65ebfd987ecfebd1204f7d0a85 1104d42e104d561ce60d05d158acfe499ee9fd50

View File

@@ -267,6 +267,26 @@ struct WhereCost {
#define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */ #define WHERE_DISTINCT 0x40000000 /* Correct order for DISTINCT */
#define WHERE_COVER_SCAN 0x80000000 /* Full scan of a covering index */ #define WHERE_COVER_SCAN 0x80000000 /* Full scan of a covering index */
/*
** This module contains many separate subroutines that work together to
** find the best indices to use for accessing a particular table in a query.
** An instance of the following structure holds context information about the
** index search so that it can be more easily passed between the various
** routines.
*/
typedef struct WhereBestIdx WhereBestIdx;
struct WhereBestIdx {
Parse *pParse; /* Parser context */
WhereClause *pWC; /* The WHERE clause */
struct SrcList_item *pSrc; /* The FROM clause term to search */
Bitmask notReady; /* Mask of cursors not available */
Bitmask notValid; /* Cursors not available for any purpose */
ExprList *pOrderBy; /* The ORDER BY clause */
ExprList *pDistinct; /* The select-list if query is DISTINCT */
sqlite3_index_info **ppIdxInfo; /* Index information passed to xBestIndex */
WhereCost cost; /* Lowest cost query plan */
};
/* /*
** Initialize a preallocated WhereClause structure. ** Initialize a preallocated WhereClause structure.
*/ */
@@ -1811,9 +1831,7 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
/* /*
** Required because bestIndex() is called by bestOrClauseIndex() ** Required because bestIndex() is called by bestOrClauseIndex()
*/ */
static void bestIndex( static void bestIndex(WhereBestIdx*);
Parse*, WhereClause*, struct SrcList_item*,
Bitmask, Bitmask, WhereCost*);
/* /*
** This routine attempts to find an scanning strategy that can be used ** This routine attempts to find an scanning strategy that can be used
@@ -1822,17 +1840,11 @@ static void bestIndex(
** The table associated with FROM clause term pSrc may be either a ** The table associated with FROM clause term pSrc may be either a
** regular B-Tree table or a virtual table. ** regular B-Tree table or a virtual table.
*/ */
static void bestOrClauseIndex( static void bestOrClauseIndex(WhereBestIdx *p){
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors not available for indexing */
Bitmask notValid, /* Cursors not available for any purpose */
ExprList *pOrderBy, /* The ORDER BY clause */
WhereCost *pCost /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_OR_OPTIMIZATION #ifndef SQLITE_OMIT_OR_OPTIMIZATION
const int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ WhereClause *pWC = p->pWC; /* The WHERE clause */
struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
const int iCur = pSrc->iCursor; /* The cursor of the table */
const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur); /* Bitmask for pSrc */ const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur); /* Bitmask for pSrc */
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */ WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
WhereTerm *pTerm; /* A single term of the WHERE clause */ WhereTerm *pTerm; /* A single term of the WHERE clause */
@@ -1849,7 +1861,7 @@ static void bestOrClauseIndex(
/* Search the WHERE clause terms for a usable WO_OR term. */ /* Search the WHERE clause terms for a usable WO_OR term. */
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( pTerm->eOperator==WO_OR if( pTerm->eOperator==WO_OR
&& ((pTerm->prereqAll & ~maskSrc) & notReady)==0 && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
&& (pTerm->u.pOrInfo->indexable & maskSrc)!=0 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0
){ ){
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
@@ -1859,15 +1871,19 @@ static void bestOrClauseIndex(
double rTotal = 0; double rTotal = 0;
double nRow = 0; double nRow = 0;
Bitmask used = 0; Bitmask used = 0;
WhereBestIdx sBOI;
sBOI = *p;
sBOI.pOrderBy = 0;
sBOI.pDistinct = 0;
sBOI.ppIdxInfo = 0;
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){ for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
WhereCost sTermCost;
WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
(pOrTerm - pOrWC->a), (pTerm - pWC->a) (pOrTerm - pOrWC->a), (pTerm - pWC->a)
)); ));
if( pOrTerm->eOperator==WO_AND ){ if( pOrTerm->eOperator==WO_AND ){
WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc; sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
bestIndex(pParse, pAndWC, pSrc, notReady, notValid, &sTermCost); bestIndex(&sBOI);
}else if( pOrTerm->leftCursor==iCur ){ }else if( pOrTerm->leftCursor==iCur ){
WhereClause tempWC; WhereClause tempWC;
tempWC.pParse = pWC->pParse; tempWC.pParse = pWC->pParse;
@@ -1877,19 +1893,20 @@ static void bestOrClauseIndex(
tempWC.a = pOrTerm; tempWC.a = pOrTerm;
tempWC.wctrlFlags = 0; tempWC.wctrlFlags = 0;
tempWC.nTerm = 1; tempWC.nTerm = 1;
bestIndex(pParse, &tempWC, pSrc, notReady, notValid, &sTermCost); sBOI.pWC = &tempWC;
bestIndex(&sBOI);
}else{ }else{
continue; continue;
} }
rTotal += sTermCost.rCost; rTotal += sBOI.cost.rCost;
nRow += sTermCost.plan.nRow; nRow += sBOI.cost.plan.nRow;
used |= sTermCost.used; used |= sBOI.cost.used;
if( rTotal>=pCost->rCost ) break; if( rTotal>=p->cost.rCost ) break;
} }
/* If there is an ORDER BY clause, increase the scan cost to account /* If there is an ORDER BY clause, increase the scan cost to account
** for the cost of the sort. */ ** for the cost of the sort. */
if( pOrderBy!=0 ){ if( p->pOrderBy!=0 ){
WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n", WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
rTotal, rTotal+nRow*estLog(nRow))); rTotal, rTotal+nRow*estLog(nRow)));
rTotal += nRow*estLog(nRow); rTotal += nRow*estLog(nRow);
@@ -1899,12 +1916,12 @@ static void bestOrClauseIndex(
** less than the current cost stored in pCost, replace the contents ** less than the current cost stored in pCost, replace the contents
** of pCost. */ ** of pCost. */
WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow)); WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
if( rTotal<pCost->rCost ){ if( rTotal<p->cost.rCost ){
pCost->rCost = rTotal; p->cost.rCost = rTotal;
pCost->used = used; p->cost.used = used;
pCost->plan.nRow = nRow; p->cost.plan.nRow = nRow;
pCost->plan.wsFlags = flags; p->cost.plan.wsFlags = flags;
pCost->plan.u.pTerm = pTerm; p->cost.plan.u.pTerm = pTerm;
} }
} }
} }
@@ -1941,13 +1958,10 @@ static int termCanDriveIndex(
** is taken into account, then alter the query plan to use the ** is taken into account, then alter the query plan to use the
** transient index. ** transient index.
*/ */
static void bestAutomaticIndex( static void bestAutomaticIndex(WhereBestIdx *p){
Parse *pParse, /* The parsing context */ Parse *pParse = p->pParse; /* The parsing context */
WhereClause *pWC, /* The WHERE clause */ WhereClause *pWC = p->pWC; /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors that are not available */
WhereCost *pCost /* Lowest cost query plan */
){
double nTableRow; /* Rows in the input table */ double nTableRow; /* Rows in the input table */
double logN; /* log(nTableRow) */ double logN; /* log(nTableRow) */
double costTempIdx; /* per-query cost of the transient index */ double costTempIdx; /* per-query cost of the transient index */
@@ -1963,7 +1977,7 @@ static void bestAutomaticIndex(
/* Automatic indices are disabled at run-time */ /* Automatic indices are disabled at run-time */
return; return;
} }
if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){ if( (p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
/* We already have some kind of index in use for this query. */ /* We already have some kind of index in use for this query. */
return; return;
} }
@@ -1981,7 +1995,7 @@ static void bestAutomaticIndex(
nTableRow = pTable->nRowEst; nTableRow = pTable->nRowEst;
logN = estLog(nTableRow); logN = estLog(nTableRow);
costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1); costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
if( costTempIdx>=pCost->rCost ){ if( costTempIdx>=p->cost.rCost ){
/* The cost of creating the transient table would be greater than /* The cost of creating the transient table would be greater than
** doing the full table scan */ ** doing the full table scan */
return; return;
@@ -1990,19 +2004,19 @@ static void bestAutomaticIndex(
/* Search for any equality comparison term */ /* Search for any equality comparison term */
pWCEnd = &pWC->a[pWC->nTerm]; pWCEnd = &pWC->a[pWC->nTerm];
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( termCanDriveIndex(pTerm, pSrc, notReady) ){ if( termCanDriveIndex(pTerm, pSrc, p->notReady) ){
WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n", WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n",
pCost->rCost, costTempIdx)); p->cost.rCost, costTempIdx));
pCost->rCost = costTempIdx; p->cost.rCost = costTempIdx;
pCost->plan.nRow = logN + 1; p->cost.plan.nRow = logN + 1;
pCost->plan.wsFlags = WHERE_TEMP_INDEX; p->cost.plan.wsFlags = WHERE_TEMP_INDEX;
pCost->used = pTerm->prereqRight; p->cost.used = pTerm->prereqRight;
break; break;
} }
} }
} }
#else #else
# define bestAutomaticIndex(A,B,C,D,E) /* no-op */ # define bestAutomaticIndex(A) /* no-op */
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
@@ -2163,12 +2177,11 @@ static void constructAutomaticIndex(
** responsibility of the caller to eventually release the structure ** responsibility of the caller to eventually release the structure
** by passing the pointer returned by this function to sqlite3_free(). ** by passing the pointer returned by this function to sqlite3_free().
*/ */
static sqlite3_index_info *allocateIndexInfo( static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
Parse *pParse, Parse *pParse = p->pParse;
WhereClause *pWC, WhereClause *pWC = p->pWC;
struct SrcList_item *pSrc, struct SrcList_item *pSrc = p->pSrc;
ExprList *pOrderBy ExprList *pOrderBy = p->pOrderBy;
){
int i, j; int i, j;
int nTerm; int nTerm;
struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint *pIdxCons;
@@ -2198,12 +2211,13 @@ static sqlite3_index_info *allocateIndexInfo(
*/ */
nOrderBy = 0; nOrderBy = 0;
if( pOrderBy ){ if( pOrderBy ){
for(i=0; i<pOrderBy->nExpr; i++){ int n = pOrderBy->nExpr;
for(i=0; i<n; i++){
Expr *pExpr = pOrderBy->a[i].pExpr; Expr *pExpr = pOrderBy->a[i].pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break; if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
} }
if( i==pOrderBy->nExpr ){ if( i==n){
nOrderBy = pOrderBy->nExpr; nOrderBy = n;
} }
} }
@@ -2327,16 +2341,10 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
** routine takes care of freeing the sqlite3_index_info structure after ** routine takes care of freeing the sqlite3_index_info structure after
** everybody has finished with it. ** everybody has finished with it.
*/ */
static void bestVirtualIndex( static void bestVirtualIndex(WhereBestIdx *p){
Parse *pParse, /* The parsing context */ Parse *pParse = p->pParse; /* The parsing context */
WhereClause *pWC, /* The WHERE clause */ WhereClause *pWC = p->pWC; /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors not available for index */
Bitmask notValid, /* Cursors not valid for any purpose */
ExprList *pOrderBy, /* The order by clause */
WhereCost *pCost, /* Lowest cost query plan */
sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
){
Table *pTab = pSrc->pTab; Table *pTab = pSrc->pTab;
sqlite3_index_info *pIdxInfo; sqlite3_index_info *pIdxInfo;
struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint *pIdxCons;
@@ -2350,15 +2358,15 @@ static void bestVirtualIndex(
** malloc in allocateIndexInfo() fails and this function returns leaving ** malloc in allocateIndexInfo() fails and this function returns leaving
** wsFlags in an uninitialized state, the caller may behave unpredictably. ** wsFlags in an uninitialized state, the caller may behave unpredictably.
*/ */
memset(pCost, 0, sizeof(*pCost)); memset(&p->cost, 0, sizeof(p->cost));
pCost->plan.wsFlags = WHERE_VIRTUALTABLE; p->cost.plan.wsFlags = WHERE_VIRTUALTABLE;
/* If the sqlite3_index_info structure has not been previously /* If the sqlite3_index_info structure has not been previously
** allocated and initialized, then allocate and initialize it now. ** allocated and initialized, then allocate and initialize it now.
*/ */
pIdxInfo = *ppIdxInfo; pIdxInfo = *p->ppIdxInfo;
if( pIdxInfo==0 ){ if( pIdxInfo==0 ){
*ppIdxInfo = pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pOrderBy); *p->ppIdxInfo = pIdxInfo = allocateIndexInfo(p);
} }
if( pIdxInfo==0 ){ if( pIdxInfo==0 ){
return; return;
@@ -2403,7 +2411,7 @@ static void bestVirtualIndex(
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
j = pIdxCons->iTermOffset; j = pIdxCons->iTermOffset;
pTerm = &pWC->a[j]; pTerm = &pWC->a[j];
pIdxCons->usable = (pTerm->prereqRight&notReady) ? 0 : 1; pIdxCons->usable = (pTerm->prereqRight&p->notReady) ? 0 : 1;
} }
memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
if( pIdxInfo->needToFreeIdxStr ){ if( pIdxInfo->needToFreeIdxStr ){
@@ -2416,7 +2424,7 @@ static void bestVirtualIndex(
/* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
nOrderBy = pIdxInfo->nOrderBy; nOrderBy = pIdxInfo->nOrderBy;
if( !pOrderBy ){ if( !p->pOrderBy ){
pIdxInfo->nOrderBy = 0; pIdxInfo->nOrderBy = 0;
} }
@@ -2427,7 +2435,7 @@ static void bestVirtualIndex(
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++){ for(i=0; i<pIdxInfo->nConstraint; i++){
if( pUsage[i].argvIndex>0 ){ if( pUsage[i].argvIndex>0 ){
pCost->used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight; p->cost.used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight;
} }
} }
@@ -2436,7 +2444,7 @@ static void bestVirtualIndex(
** matches the processing for non-virtual tables in bestBtreeIndex(). ** matches the processing for non-virtual tables in bestBtreeIndex().
*/ */
rCost = pIdxInfo->estimatedCost; rCost = pIdxInfo->estimatedCost;
if( pOrderBy && pIdxInfo->orderByConsumed==0 ){ if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){
rCost += estLog(rCost)*rCost; rCost += estLog(rCost)*rCost;
} }
@@ -2448,21 +2456,21 @@ static void bestVirtualIndex(
** is defined. ** is defined.
*/ */
if( (SQLITE_BIG_DBL/((double)2))<rCost ){ if( (SQLITE_BIG_DBL/((double)2))<rCost ){
pCost->rCost = (SQLITE_BIG_DBL/((double)2)); p->cost.rCost = (SQLITE_BIG_DBL/((double)2));
}else{ }else{
pCost->rCost = rCost; p->cost.rCost = rCost;
} }
pCost->plan.u.pVtabIdx = pIdxInfo; p->cost.plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo->orderByConsumed ){ if( pIdxInfo->orderByConsumed ){
pCost->plan.wsFlags |= WHERE_ORDERBY; p->cost.plan.wsFlags |= WHERE_ORDERBY;
} }
pCost->plan.nEq = 0; p->cost.plan.nEq = 0;
pIdxInfo->nOrderBy = nOrderBy; pIdxInfo->nOrderBy = nOrderBy;
/* Try to find a more efficient access pattern by using multiple indexes /* Try to find a more efficient access pattern by using multiple indexes
** to optimize an OR expression within the WHERE clause. ** to optimize an OR expression within the WHERE clause.
*/ */
bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); bestOrClauseIndex(p);
} }
#endif /* SQLITE_OMIT_VIRTUALTABLE */ #endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -2864,8 +2872,7 @@ static int whereInScanEst(
/* /*
** Find the best query plan for accessing a particular table. Write the ** Find the best query plan for accessing a particular table. Write the
** best query plan and its cost into the WhereCost object supplied as the ** best query plan and its cost into the p->cost.
** last parameter.
** **
** The lowest cost plan wins. The cost is an estimate of the amount of ** The lowest cost plan wins. The cost is an estimate of the amount of
** CPU and disk I/O needed to process the requested result. ** CPU and disk I/O needed to process the requested result.
@@ -2890,16 +2897,10 @@ static int whereInScanEst(
** selected plan may still take advantage of the built-in rowid primary key ** selected plan may still take advantage of the built-in rowid primary key
** index. ** index.
*/ */
static void bestBtreeIndex( static void bestBtreeIndex(WhereBestIdx *p){
Parse *pParse, /* The parsing context */ Parse *pParse = p->pParse; /* The parsing context */
WhereClause *pWC, /* The WHERE clause */ WhereClause *pWC = p->pWC; /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors not available for indexing */
Bitmask notValid, /* Cursors not available for any purpose */
ExprList *pOrderBy, /* The ORDER BY clause */
ExprList *pDistinct, /* The select-list if query is DISTINCT */
WhereCost *pCost /* Lowest cost query plan */
){
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
Index *pProbe; /* An index we are evaluating */ Index *pProbe; /* An index we are evaluating */
Index *pIdx; /* Copy of pProbe, or zero for IPK index */ Index *pIdx; /* Copy of pProbe, or zero for IPK index */
@@ -2908,11 +2909,11 @@ static void bestBtreeIndex(
Index sPk; /* A fake index object for the primary key */ Index sPk; /* A fake index object for the primary key */
tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */
int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */
int wsFlagMask; /* Allowed flags in pCost->plan.wsFlag */ int wsFlagMask; /* Allowed flags in p->cost.plan.wsFlag */
/* Initialize the cost to a worst-case value */ /* Initialize the cost to a worst-case value */
memset(pCost, 0, sizeof(*pCost)); memset(&p->cost, 0, sizeof(p->cost));
pCost->rCost = SQLITE_BIG_DBL; p->cost.rCost = SQLITE_BIG_DBL;
/* If the pSrc table is the right table of a LEFT JOIN then we may not /* If the pSrc table is the right table of a LEFT JOIN then we may not
** use an index to satisfy IS NULL constraints on that table. This is ** use an index to satisfy IS NULL constraints on that table. This is
@@ -3036,8 +3037,8 @@ static void bestBtreeIndex(
int nInMul = 1; /* Number of distinct equalities to lookup */ int nInMul = 1; /* Number of distinct equalities to lookup */
double rangeDiv = (double)1; /* Estimated reduction in search space */ double rangeDiv = (double)1; /* Estimated reduction in search space */
int nBound = 0; /* Number of range constraints seen */ int nBound = 0; /* Number of range constraints seen */
int bSort = !!pOrderBy; /* True if external sort required */ int bSort = !!p->pOrderBy; /* True if external sort required */
int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */ int bDist = !!p->pDistinct; /* True if index cannot help with DISTINCT */
int bLookup = 0; /* True if not a covering index */ int bLookup = 0; /* True if not a covering index */
WhereTerm *pTerm; /* A single term of the WHERE clause */ WhereTerm *pTerm; /* A single term of the WHERE clause */
#ifdef SQLITE_ENABLE_STAT3 #ifdef SQLITE_ENABLE_STAT3
@@ -3047,7 +3048,7 @@ static void bestBtreeIndex(
/* Determine the values of nEq and nInMul */ /* Determine the values of nEq and nInMul */
for(nEq=0; nEq<pProbe->nColumn; nEq++){ for(nEq=0; nEq<pProbe->nColumn; nEq++){
int j = pProbe->aiColumn[nEq]; int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx); pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
if( pTerm==0 ) break; if( pTerm==0 ) break;
wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ); wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
testcase( pTerm->pWC!=pWC ); testcase( pTerm->pWC!=pWC );
@@ -3088,9 +3089,10 @@ static void bestBtreeIndex(
} }
}else if( pProbe->bUnordered==0 ){ }else if( pProbe->bUnordered==0 ){
int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]); int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]);
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ if( findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); WhereTerm *pTop, *pBtm;
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx); pTop = findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE, pIdx);
pBtm = findTerm(pWC, iCur, j, p->notReady, WO_GT|WO_GE, pIdx);
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &rangeDiv); whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &rangeDiv);
if( pTop ){ if( pTop ){
nBound = 1; nBound = 1;
@@ -3113,7 +3115,7 @@ static void bestBtreeIndex(
** in wsFlags. Otherwise, if there is an ORDER BY clause but the index ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index
** will scan rows in a different order, set the bSort variable. */ ** will scan rows in a different order, set the bSort variable. */
if( isSortingIndex( if( isSortingIndex(
pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev) pParse, pWC->pMaskSet, pProbe, iCur, p->pOrderBy, nEq, wsFlags, &rev)
){ ){
bSort = 0; bSort = 0;
wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
@@ -3123,7 +3125,7 @@ static void bestBtreeIndex(
/* If there is a DISTINCT qualifier and this index will scan rows in /* If there is a DISTINCT qualifier and this index will scan rows in
** order of the DISTINCT expressions, clear bDist and set the appropriate ** order of the DISTINCT expressions, clear bDist and set the appropriate
** flags in wsFlags. */ ** flags in wsFlags. */
if( isDistinctIndex(pParse, pWC, pProbe, iCur, pDistinct, nEq) if( isDistinctIndex(pParse, pWC, pProbe, iCur, p->pDistinct, nEq)
&& (wsFlags & WHERE_COLUMN_IN)==0 && (wsFlags & WHERE_COLUMN_IN)==0
){ ){
bDist = 0; bDist = 0;
@@ -3283,7 +3285,7 @@ static void bestBtreeIndex(
** might be selected even when there exists an optimal index that has ** might be selected even when there exists an optimal index that has
** no such dependency. ** no such dependency.
*/ */
if( nRow>2 && cost<=pCost->rCost ){ if( nRow>2 && cost<=p->cost.rCost ){
int k; /* Loop counter */ int k; /* Loop counter */
int nSkipEq = nEq; /* Number of == constraints to skip */ int nSkipEq = nEq; /* Number of == constraints to skip */
int nSkipRange = nBound; /* Number of < constraints to skip */ int nSkipRange = nBound; /* Number of < constraints to skip */
@@ -3292,7 +3294,7 @@ static void bestBtreeIndex(
thisTab = getMask(pWC->pMaskSet, iCur); thisTab = getMask(pWC->pMaskSet, iCur);
for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){ for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
if( pTerm->wtFlags & TERM_VIRTUAL ) continue; if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
if( (pTerm->prereqAll & notValid)!=thisTab ) continue; if( (pTerm->prereqAll & p->notValid)!=thisTab ) continue;
if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){ if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
if( nSkipEq ){ if( nSkipEq ){
/* Ignore the first nEq equality matches since the index /* Ignore the first nEq equality matches since the index
@@ -3331,21 +3333,21 @@ static void bestBtreeIndex(
" notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n", " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n",
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"), pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
nEq, nInMul, (int)rangeDiv, bSort, bLookup, wsFlags, nEq, nInMul, (int)rangeDiv, bSort, bLookup, wsFlags,
notReady, log10N, nRow, cost, used p->notReady, log10N, nRow, cost, used
)); ));
/* If this index is the best we have seen so far, then record this /* If this index is the best we have seen so far, then record this
** index and its cost in the pCost structure. ** index and its cost in the pCost structure.
*/ */
if( (!pIdx || wsFlags) if( (!pIdx || wsFlags)
&& (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->plan.nRow)) && (cost<p->cost.rCost || (cost<=p->cost.rCost && nRow<p->cost.plan.nRow))
){ ){
pCost->rCost = cost; p->cost.rCost = cost;
pCost->used = used; p->cost.used = used;
pCost->plan.nRow = nRow; p->cost.plan.nRow = nRow;
pCost->plan.wsFlags = (wsFlags&wsFlagMask); p->cost.plan.wsFlags = (wsFlags&wsFlagMask);
pCost->plan.nEq = nEq; p->cost.plan.nEq = nEq;
pCost->plan.u.pIdx = pIdx; p->cost.plan.u.pIdx = pIdx;
} }
/* If there was an INDEXED BY clause, then only that one index is /* If there was an INDEXED BY clause, then only that one index is
@@ -3362,25 +3364,25 @@ static void bestBtreeIndex(
** in. This is used for application testing, to help find cases ** in. This is used for application testing, to help find cases
** where application behaviour depends on the (undefined) order that ** where application behaviour depends on the (undefined) order that
** SQLite outputs rows in in the absence of an ORDER BY clause. */ ** SQLite outputs rows in in the absence of an ORDER BY clause. */
if( !pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){ if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
pCost->plan.wsFlags |= WHERE_REVERSE; p->cost.plan.wsFlags |= WHERE_REVERSE;
} }
assert( pOrderBy || (pCost->plan.wsFlags&WHERE_ORDERBY)==0 ); assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERBY)==0 );
assert( pCost->plan.u.pIdx==0 || (pCost->plan.wsFlags&WHERE_ROWID_EQ)==0 ); assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 );
assert( pSrc->pIndex==0 assert( pSrc->pIndex==0
|| pCost->plan.u.pIdx==0 || p->cost.plan.u.pIdx==0
|| pCost->plan.u.pIdx==pSrc->pIndex || p->cost.plan.u.pIdx==pSrc->pIndex
); );
WHERETRACE(("best index is: %s\n", WHERETRACE(("best index is: %s\n",
((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : ((p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk") p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk")
)); ));
bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); bestOrClauseIndex(p);
bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost); bestAutomaticIndex(p);
pCost->plan.wsFlags |= eqTermMask; p->cost.plan.wsFlags |= eqTermMask;
} }
/* /*
@@ -3395,26 +3397,20 @@ static void bestBtreeIndex(
** details will be reconsidered later if the optimization is found to be ** details will be reconsidered later if the optimization is found to be
** applicable. ** applicable.
*/ */
static void bestIndex( static void bestIndex(WhereBestIdx *p){
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors not available for indexing */
Bitmask notValid, /* Cursors not available for any purpose */
WhereCost *pCost /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pSrc->pTab) ){ if( IsVirtual(p->pSrc->pTab) ){
sqlite3_index_info *p = 0; sqlite3_index_info *pIdxInfo = 0;
bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, 0, pCost, &p); p->ppIdxInfo = &pIdxInfo;
if( p->needToFreeIdxStr ){ bestVirtualIndex(p);
sqlite3_free(p->idxStr); if( pIdxInfo->needToFreeIdxStr ){
sqlite3_free(pIdxInfo->idxStr);
} }
sqlite3DbFree(pParse->db, p); sqlite3DbFree(p->pParse->db, pIdxInfo);
}else }else
#endif #endif
{ {
bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, 0, 0, pCost); bestBtreeIndex(p);
} }
} }
@@ -4700,14 +4696,18 @@ WhereInfo *sqlite3WhereBegin(
WhereInfo *pWInfo; /* Will become the return value of this function */ WhereInfo *pWInfo; /* Will become the return value of this function */
Vdbe *v = pParse->pVdbe; /* The virtual database engine */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */
Bitmask notReady; /* Cursors that are not yet positioned */ Bitmask notReady; /* Cursors that are not yet positioned */
WhereBestIdx sWBI; /* Best index search context */
WhereMaskSet *pMaskSet; /* The expression mask set */ WhereMaskSet *pMaskSet; /* The expression mask set */
WhereClause *pWC; /* Decomposition of the WHERE clause */
struct SrcList_item *pTabItem; /* A single entry from pTabList */
WhereLevel *pLevel; /* A single level in pWInfo->a[] */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */
int iFrom; /* First unused FROM clause element */ int iFrom; /* First unused FROM clause element */
int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */ int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */
sqlite3 *db; /* Database connection */ sqlite3 *db; /* Database connection */
/* Variable initialization */
memset(&sWBI, 0, sizeof(sWBI));
sWBI.pParse = pParse;
/* 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
*/ */
@@ -4747,10 +4747,10 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse; pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList; pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v); pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo]; pWInfo->pWC = sWBI.pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags; pWInfo->wctrlFlags = wctrlFlags;
pWInfo->savedNQueryLoop = pParse->nQueryLoop; pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pMaskSet = (WhereMaskSet*)&pWC[1]; pMaskSet = (WhereMaskSet*)&sWBI.pWC[1];
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
@@ -4760,9 +4760,9 @@ WhereInfo *sqlite3WhereBegin(
** subexpression is separated by an AND operator. ** subexpression is separated by an AND operator.
*/ */
initMaskSet(pMaskSet); initMaskSet(pMaskSet);
whereClauseInit(pWC, pParse, pMaskSet, wctrlFlags); whereClauseInit(sWBI.pWC, pParse, pMaskSet, wctrlFlags);
sqlite3ExprCodeConstants(pParse, pWhere); sqlite3ExprCodeConstants(pParse, pWhere);
whereSplit(pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ whereSplit(sWBI.pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */
/* Special case: a WHERE clause that is constant. Evaluate the /* Special case: a WHERE clause that is constant. Evaluate the
** expression and either jump over all of the code or fall thru. ** expression and either jump over all of the code or fall thru.
@@ -4793,12 +4793,12 @@ WhereInfo *sqlite3WhereBegin(
** equal to pTabList->nSrc but might be shortened to 1 if the ** equal to pTabList->nSrc but might be shortened to 1 if the
** WHERE_ONETABLE_ONLY flag is set. ** WHERE_ONETABLE_ONLY flag is set.
*/ */
assert( pWC->vmask==0 && pMaskSet->n==0 ); assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 );
for(i=0; i<pTabList->nSrc; i++){ for(i=0; i<pTabList->nSrc; i++){
createMask(pMaskSet, pTabList->a[i].iCursor); createMask(pMaskSet, pTabList->a[i].iCursor);
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){ if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){
pWC->vmask |= ((Bitmask)1 << i); sWBI.pWC->vmask |= ((Bitmask)1 << i);
} }
#endif #endif
} }
@@ -4818,7 +4818,7 @@ WhereInfo *sqlite3WhereBegin(
** want to analyze these virtual terms, so start analyzing at the end ** want to analyze these virtual terms, so start analyzing at the end
** and work forward so that the added virtual terms are never processed. ** and work forward so that the added virtual terms are never processed.
*/ */
exprAnalyzeAll(pTabList, pWC); exprAnalyzeAll(pTabList, sWBI.pWC);
if( db->mallocFailed ){ if( db->mallocFailed ){
goto whereBeginError; goto whereBeginError;
} }
@@ -4827,7 +4827,7 @@ WhereInfo *sqlite3WhereBegin(
** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to ** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to
** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT. ** WHERE_DISTINCT_UNIQUE to tell the caller to ignore the DISTINCT.
*/ */
if( pDistinct && isDistinctRedundant(pParse, pTabList, pWC, pDistinct) ){ if( pDistinct && isDistinctRedundant(pParse, pTabList, sWBI.pWC, pDistinct) ){
pDistinct = 0; pDistinct = 0;
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
} }
@@ -4910,48 +4910,43 @@ WhereInfo *sqlite3WhereBegin(
nUnconstrained = 0; nUnconstrained = 0;
notIndexed = 0; notIndexed = 0;
for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){ for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
Bitmask mask; /* Mask of tables not yet ready */ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */ int doNotReorder; /* True if this table should not be reordered */
WhereCost sCost; /* Cost information from best[Virtual]Index() */
ExprList *pOB; /* ORDER BY clause for index to optimize */
ExprList *pDist; /* DISTINCT clause for index to optimize */
doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0; doNotReorder = (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0;
if( j!=iFrom && doNotReorder ) break; if( j!=iFrom && doNotReorder ) break;
m = getMask(pMaskSet, pTabItem->iCursor); m = getMask(pMaskSet, sWBI.pSrc->iCursor);
if( (m & notReady)==0 ){ if( (m & notReady)==0 ){
if( j==iFrom ) iFrom++; if( j==iFrom ) iFrom++;
continue; continue;
} }
mask = (isOptimal ? m : notReady); sWBI.notValid = notReady;
pOB = (i==0) ? pOrderBy : 0; sWBI.notReady = (isOptimal ? m : notReady);
pDist = (i==0 ? pDistinct : 0); sWBI.pOrderBy = (i==0) ? pOrderBy : 0;
if( pTabItem->pIndex==0 ) nUnconstrained++; sWBI.pDistinct = (i==0 ? pDistinct : 0);
if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
WHERETRACE(("=== trying table %d with isOptimal=%d ===\n", WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
j, isOptimal)); j, isOptimal));
assert( pTabItem->pTab ); assert( sWBI.pSrc->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTabItem->pTab) ){ if( IsVirtual(sWBI.pSrc->pTab) ){
sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo; sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOB, bestVirtualIndex(&sWBI);
&sCost, pp);
}else }else
#endif #endif
{ {
bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOB, bestBtreeIndex(&sWBI);
pDist, &sCost);
} }
assert( isOptimal || (sCost.used&notReady)==0 ); assert( isOptimal || (sWBI.cost.used&notReady)==0 );
/* If an INDEXED BY clause is present, then the plan must use that /* If an INDEXED BY clause is present, then the plan must use that
** index if it uses any index at all */ ** index if it uses any index at all */
assert( pTabItem->pIndex==0 assert( sWBI.pSrc->pIndex==0
|| (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|| sCost.plan.u.pIdx==pTabItem->pIndex ); || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex );
if( isOptimal && (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
notIndexed |= m; notIndexed |= m;
} }
@@ -4975,20 +4970,20 @@ WhereInfo *sqlite3WhereBegin(
** (4) The plan cost must be lower than prior plans or else the ** (4) The plan cost must be lower than prior plans or else the
** cost must be the same and the number of rows must be lower. ** cost must be the same and the number of rows must be lower.
*/ */
if( (sCost.used&notReady)==0 /* (1) */ if( (sWBI.cost.used&notReady)==0 /* (1) */
&& (bestJ<0 || (notIndexed&m)!=0 /* (2) */ && (bestJ<0 || (notIndexed&m)!=0 /* (2) */
|| (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|| (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0) || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
&& (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */ && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
|| NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
&& (bestJ<0 || sCost.rCost<bestPlan.rCost /* (4) */ && (bestJ<0 || sWBI.cost.rCost<bestPlan.rCost /* (4) */
|| (sCost.rCost<=bestPlan.rCost || (sWBI.cost.rCost<=bestPlan.rCost
&& sCost.plan.nRow<bestPlan.plan.nRow)) && sWBI.cost.plan.nRow<bestPlan.plan.nRow))
){ ){
WHERETRACE(("=== table %d is best so far" WHERETRACE(("=== table %d is best so far"
" with cost=%g and nRow=%g\n", " with cost=%g and nRow=%g\n",
j, sCost.rCost, sCost.plan.nRow)); j, sWBI.cost.rCost, sWBI.cost.plan.nRow));
bestPlan = sCost; bestPlan = sWBI.cost;
bestJ = j; bestJ = j;
} }
if( doNotReorder ) break; if( doNotReorder ) break;
@@ -5077,6 +5072,7 @@ WhereInfo *sqlite3WhereBegin(
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){ for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
Table *pTab; /* Table to open */ Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */ int iDb; /* Index of database containing table/index */
struct SrcList_item *pTabItem;
pTabItem = &pTabList->a[pLevel->iFrom]; pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab; pTab = pTabItem->pTab;
@@ -5112,7 +5108,7 @@ WhereInfo *sqlite3WhereBegin(
} }
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){ if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel); constructAutomaticIndex(pParse, sWBI.pWC, pTabItem, notReady, pLevel);
}else }else
#endif #endif
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){ if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
@@ -5126,7 +5122,7 @@ WhereInfo *sqlite3WhereBegin(
VdbeComment((v, "%s", pIx->zName)); VdbeComment((v, "%s", pIx->zName));
} }
sqlite3CodeVerifySchema(pParse, iDb); sqlite3CodeVerifySchema(pParse, iDb);
notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor); notReady &= ~getMask(sWBI.pWC->pMaskSet, pTabItem->iCursor);
} }
pWInfo->iTop = sqlite3VdbeCurrentAddr(v); pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
if( db->mallocFailed ) goto whereBeginError; if( db->mallocFailed ) goto whereBeginError;
@@ -5154,6 +5150,8 @@ WhereInfo *sqlite3WhereBegin(
char *z; char *z;
int n; int n;
int w; int w;
struct SrcList_item *pTabItem;
pLevel = &pWInfo->a[i]; pLevel = &pWInfo->a[i];
w = pLevel->plan.wsFlags; w = pLevel->plan.wsFlags;
pTabItem = &pTabList->a[pLevel->iFrom]; pTabItem = &pTabList->a[pLevel->iFrom];