1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-22 20:22:44 +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.
D 2012-09-24T19:50:00.842
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-25T14:29:39.134
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -249,7 +249,7 @@ F src/vtab.c d8020c0a0e8ccc490ca449d7e665311b6e9f3ba9
F src/wal.c 5acb3e7bbd31f10ba39acad9ce6b399055337a9d
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 40708330a0e9bf79c0ab97109b8014fa04cce858
F src/where.c 82be1d2f8f27012de0ed9d0977753ed24312b791
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00
@@ -1016,7 +1016,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9
P 22989f3588531efd555cc29d6c576e7a34b7edc4
R af274415395e47bec73279dd70f3872e
P 349a55cd8ba9ce65ebfd987ecfebd1204f7d0a85
R b0986bef8aa73322a60d8a15dd219873
T *branch * qp-enhancements
T *sym-qp-enhancements *
T -sym-trunk *
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_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.
*/
@@ -1811,9 +1831,7 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
/*
** Required because bestIndex() is called by bestOrClauseIndex()
*/
static void bestIndex(
Parse*, WhereClause*, struct SrcList_item*,
Bitmask, Bitmask, WhereCost*);
static void bestIndex(WhereBestIdx*);
/*
** This routine attempts to find an scanning strategy that can be used
@@ -1822,20 +1840,14 @@ static void bestIndex(
** The table associated with FROM clause term pSrc may be either a
** regular B-Tree table or a virtual table.
*/
static void bestOrClauseIndex(
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 */
){
static void bestOrClauseIndex(WhereBestIdx *p){
#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 */
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 */
/* The OR-clause optimization is disallowed if the INDEXED BY or
** NOT INDEXED clauses are used or if the WHERE_AND_ONLY bit is set. */
@@ -1849,7 +1861,7 @@ static void bestOrClauseIndex(
/* Search the WHERE clause terms for a usable WO_OR term. */
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( pTerm->eOperator==WO_OR
&& ((pTerm->prereqAll & ~maskSrc) & notReady)==0
&& ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0
&& (pTerm->u.pOrInfo->indexable & maskSrc)!=0
){
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
@@ -1859,15 +1871,19 @@ static void bestOrClauseIndex(
double rTotal = 0;
double nRow = 0;
Bitmask used = 0;
WhereBestIdx sBOI;
sBOI = *p;
sBOI.pOrderBy = 0;
sBOI.pDistinct = 0;
sBOI.ppIdxInfo = 0;
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
WhereCost sTermCost;
WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
(pOrTerm - pOrWC->a), (pTerm - pWC->a)
));
if( pOrTerm->eOperator==WO_AND ){
WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
bestIndex(pParse, pAndWC, pSrc, notReady, notValid, &sTermCost);
sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
bestIndex(&sBOI);
}else if( pOrTerm->leftCursor==iCur ){
WhereClause tempWC;
tempWC.pParse = pWC->pParse;
@@ -1877,19 +1893,20 @@ static void bestOrClauseIndex(
tempWC.a = pOrTerm;
tempWC.wctrlFlags = 0;
tempWC.nTerm = 1;
bestIndex(pParse, &tempWC, pSrc, notReady, notValid, &sTermCost);
sBOI.pWC = &tempWC;
bestIndex(&sBOI);
}else{
continue;
}
rTotal += sTermCost.rCost;
nRow += sTermCost.plan.nRow;
used |= sTermCost.used;
if( rTotal>=pCost->rCost ) break;
rTotal += sBOI.cost.rCost;
nRow += sBOI.cost.plan.nRow;
used |= sBOI.cost.used;
if( rTotal>=p->cost.rCost ) break;
}
/* If there is an ORDER BY clause, increase the scan cost to account
** for the cost of the sort. */
if( pOrderBy!=0 ){
if( p->pOrderBy!=0 ){
WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
rTotal, 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
** of pCost. */
WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
if( rTotal<pCost->rCost ){
pCost->rCost = rTotal;
pCost->used = used;
pCost->plan.nRow = nRow;
pCost->plan.wsFlags = flags;
pCost->plan.u.pTerm = pTerm;
if( rTotal<p->cost.rCost ){
p->cost.rCost = rTotal;
p->cost.used = used;
p->cost.plan.nRow = nRow;
p->cost.plan.wsFlags = flags;
p->cost.plan.u.pTerm = pTerm;
}
}
}
@@ -1941,15 +1958,12 @@ static int termCanDriveIndex(
** is taken into account, then alter the query plan to use the
** transient index.
*/
static void bestAutomaticIndex(
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 that are not available */
WhereCost *pCost /* Lowest cost query plan */
){
double nTableRow; /* Rows in the input table */
double logN; /* log(nTableRow) */
static void bestAutomaticIndex(WhereBestIdx *p){
Parse *pParse = p->pParse; /* The parsing context */
WhereClause *pWC = p->pWC; /* The WHERE clause */
struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
double nTableRow; /* Rows in the input table */
double logN; /* log(nTableRow) */
double costTempIdx; /* per-query cost of the transient index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
WhereTerm *pWCEnd; /* End of pWC->a[] */
@@ -1963,7 +1977,7 @@ static void bestAutomaticIndex(
/* Automatic indices are disabled at run-time */
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. */
return;
}
@@ -1981,7 +1995,7 @@ static void bestAutomaticIndex(
nTableRow = pTable->nRowEst;
logN = estLog(nTableRow);
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
** doing the full table scan */
return;
@@ -1990,19 +2004,19 @@ static void bestAutomaticIndex(
/* Search for any equality comparison term */
pWCEnd = &pWC->a[pWC->nTerm];
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",
pCost->rCost, costTempIdx));
pCost->rCost = costTempIdx;
pCost->plan.nRow = logN + 1;
pCost->plan.wsFlags = WHERE_TEMP_INDEX;
pCost->used = pTerm->prereqRight;
p->cost.rCost, costTempIdx));
p->cost.rCost = costTempIdx;
p->cost.plan.nRow = logN + 1;
p->cost.plan.wsFlags = WHERE_TEMP_INDEX;
p->cost.used = pTerm->prereqRight;
break;
}
}
}
#else
# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
# define bestAutomaticIndex(A) /* no-op */
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
@@ -2163,12 +2177,11 @@ static void constructAutomaticIndex(
** responsibility of the caller to eventually release the structure
** by passing the pointer returned by this function to sqlite3_free().
*/
static sqlite3_index_info *allocateIndexInfo(
Parse *pParse,
WhereClause *pWC,
struct SrcList_item *pSrc,
ExprList *pOrderBy
){
static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
Parse *pParse = p->pParse;
WhereClause *pWC = p->pWC;
struct SrcList_item *pSrc = p->pSrc;
ExprList *pOrderBy = p->pOrderBy;
int i, j;
int nTerm;
struct sqlite3_index_constraint *pIdxCons;
@@ -2198,12 +2211,13 @@ static sqlite3_index_info *allocateIndexInfo(
*/
nOrderBy = 0;
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;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
}
if( i==pOrderBy->nExpr ){
nOrderBy = pOrderBy->nExpr;
if( i==n){
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
** everybody has finished with it.
*/
static void bestVirtualIndex(
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 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 */
){
static void bestVirtualIndex(WhereBestIdx *p){
Parse *pParse = p->pParse; /* The parsing context */
WhereClause *pWC = p->pWC; /* The WHERE clause */
struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
Table *pTab = pSrc->pTab;
sqlite3_index_info *pIdxInfo;
struct sqlite3_index_constraint *pIdxCons;
@@ -2350,15 +2358,15 @@ static void bestVirtualIndex(
** malloc in allocateIndexInfo() fails and this function returns leaving
** wsFlags in an uninitialized state, the caller may behave unpredictably.
*/
memset(pCost, 0, sizeof(*pCost));
pCost->plan.wsFlags = WHERE_VIRTUALTABLE;
memset(&p->cost, 0, sizeof(p->cost));
p->cost.plan.wsFlags = WHERE_VIRTUALTABLE;
/* If the sqlite3_index_info structure has not been previously
** allocated and initialized, then allocate and initialize it now.
*/
pIdxInfo = *ppIdxInfo;
pIdxInfo = *p->ppIdxInfo;
if( pIdxInfo==0 ){
*ppIdxInfo = pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pOrderBy);
*p->ppIdxInfo = pIdxInfo = allocateIndexInfo(p);
}
if( pIdxInfo==0 ){
return;
@@ -2403,7 +2411,7 @@ static void bestVirtualIndex(
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
j = pIdxCons->iTermOffset;
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);
if( pIdxInfo->needToFreeIdxStr ){
@@ -2416,7 +2424,7 @@ static void bestVirtualIndex(
/* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */
pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2);
nOrderBy = pIdxInfo->nOrderBy;
if( !pOrderBy ){
if( !p->pOrderBy ){
pIdxInfo->nOrderBy = 0;
}
@@ -2427,7 +2435,7 @@ static void bestVirtualIndex(
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++){
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().
*/
rCost = pIdxInfo->estimatedCost;
if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){
rCost += estLog(rCost)*rCost;
}
@@ -2448,21 +2456,21 @@ static void bestVirtualIndex(
** is defined.
*/
if( (SQLITE_BIG_DBL/((double)2))<rCost ){
pCost->rCost = (SQLITE_BIG_DBL/((double)2));
p->cost.rCost = (SQLITE_BIG_DBL/((double)2));
}else{
pCost->rCost = rCost;
p->cost.rCost = rCost;
}
pCost->plan.u.pVtabIdx = pIdxInfo;
p->cost.plan.u.pVtabIdx = pIdxInfo;
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;
/* Try to find a more efficient access pattern by using multiple indexes
** to optimize an OR expression within the WHERE clause.
*/
bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
bestOrClauseIndex(p);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -2864,8 +2872,7 @@ static int whereInScanEst(
/*
** 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
** last parameter.
** best query plan and its cost into the p->cost.
**
** 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.
@@ -2890,16 +2897,10 @@ static int whereInScanEst(
** selected plan may still take advantage of the built-in rowid primary key
** index.
*/
static void bestBtreeIndex(
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 */
ExprList *pDistinct, /* The select-list if query is DISTINCT */
WhereCost *pCost /* Lowest cost query plan */
){
static void bestBtreeIndex(WhereBestIdx *p){
Parse *pParse = p->pParse; /* The parsing context */
WhereClause *pWC = p->pWC; /* The WHERE clause */
struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
Index *pProbe; /* An index we are evaluating */
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 */
tRowcnt aiRowEstPk[2]; /* The aiRowEst[] 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 */
memset(pCost, 0, sizeof(*pCost));
pCost->rCost = SQLITE_BIG_DBL;
memset(&p->cost, 0, sizeof(p->cost));
p->cost.rCost = SQLITE_BIG_DBL;
/* 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
@@ -3036,8 +3037,8 @@ static void bestBtreeIndex(
int nInMul = 1; /* Number of distinct equalities to lookup */
double rangeDiv = (double)1; /* Estimated reduction in search space */
int nBound = 0; /* Number of range constraints seen */
int bSort = !!pOrderBy; /* True if external sort required */
int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */
int bSort = !!p->pOrderBy; /* True if external sort required */
int bDist = !!p->pDistinct; /* True if index cannot help with DISTINCT */
int bLookup = 0; /* True if not a covering index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
#ifdef SQLITE_ENABLE_STAT3
@@ -3047,7 +3048,7 @@ static void bestBtreeIndex(
/* Determine the values of nEq and nInMul */
for(nEq=0; nEq<pProbe->nColumn; 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;
wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
testcase( pTerm->pWC!=pWC );
@@ -3088,9 +3089,10 @@ static void bestBtreeIndex(
}
}else if( pProbe->bUnordered==0 ){
int j = (nEq==pProbe->nColumn ? -1 : pProbe->aiColumn[nEq]);
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
if( findTerm(pWC, iCur, j, p->notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop, *pBtm;
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);
if( pTop ){
nBound = 1;
@@ -3113,7 +3115,7 @@ static void bestBtreeIndex(
** in wsFlags. Otherwise, if there is an ORDER BY clause but the index
** will scan rows in a different order, set the bSort variable. */
if( isSortingIndex(
pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, nEq, wsFlags, &rev)
pParse, pWC->pMaskSet, pProbe, iCur, p->pOrderBy, nEq, wsFlags, &rev)
){
bSort = 0;
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
** order of the DISTINCT expressions, clear bDist and set the appropriate
** 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
){
bDist = 0;
@@ -3283,7 +3285,7 @@ static void bestBtreeIndex(
** might be selected even when there exists an optimal index that has
** no such dependency.
*/
if( nRow>2 && cost<=pCost->rCost ){
if( nRow>2 && cost<=p->cost.rCost ){
int k; /* Loop counter */
int nSkipEq = nEq; /* 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);
for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
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( nSkipEq ){
/* 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",
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
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
** index and its cost in the pCost structure.
*/
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;
pCost->used = used;
pCost->plan.nRow = nRow;
pCost->plan.wsFlags = (wsFlags&wsFlagMask);
pCost->plan.nEq = nEq;
pCost->plan.u.pIdx = pIdx;
p->cost.rCost = cost;
p->cost.used = used;
p->cost.plan.nRow = nRow;
p->cost.plan.wsFlags = (wsFlags&wsFlagMask);
p->cost.plan.nEq = nEq;
p->cost.plan.u.pIdx = pIdx;
}
/* 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
** where application behaviour depends on the (undefined) order that
** SQLite outputs rows in in the absence of an ORDER BY clause. */
if( !pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
pCost->plan.wsFlags |= WHERE_REVERSE;
if( !p->pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){
p->cost.plan.wsFlags |= WHERE_REVERSE;
}
assert( pOrderBy || (pCost->plan.wsFlags&WHERE_ORDERBY)==0 );
assert( pCost->plan.u.pIdx==0 || (pCost->plan.wsFlags&WHERE_ROWID_EQ)==0 );
assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERBY)==0 );
assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 );
assert( pSrc->pIndex==0
|| pCost->plan.u.pIdx==0
|| pCost->plan.u.pIdx==pSrc->pIndex
|| p->cost.plan.u.pIdx==0
|| p->cost.plan.u.pIdx==pSrc->pIndex
);
WHERETRACE(("best index is: %s\n",
((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
((p->cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk")
));
bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
pCost->plan.wsFlags |= eqTermMask;
bestOrClauseIndex(p);
bestAutomaticIndex(p);
p->cost.plan.wsFlags |= eqTermMask;
}
/*
@@ -3395,26 +3397,20 @@ static void bestBtreeIndex(
** details will be reconsidered later if the optimization is found to be
** applicable.
*/
static void bestIndex(
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 */
){
static void bestIndex(WhereBestIdx *p){
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pSrc->pTab) ){
sqlite3_index_info *p = 0;
bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, 0, pCost, &p);
if( p->needToFreeIdxStr ){
sqlite3_free(p->idxStr);
if( IsVirtual(p->pSrc->pTab) ){
sqlite3_index_info *pIdxInfo = 0;
p->ppIdxInfo = &pIdxInfo;
bestVirtualIndex(p);
if( pIdxInfo->needToFreeIdxStr ){
sqlite3_free(pIdxInfo->idxStr);
}
sqlite3DbFree(pParse->db, p);
sqlite3DbFree(p->pParse->db, pIdxInfo);
}else
#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 */
Vdbe *v = pParse->pVdbe; /* The virtual database engine */
Bitmask notReady; /* Cursors that are not yet positioned */
WhereBestIdx sWBI; /* Best index search context */
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[] */
int iFrom; /* First unused FROM clause element */
WhereLevel *pLevel; /* A single level in pWInfo->a[] */
int iFrom; /* First unused FROM clause element */
int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */
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
** bits in a Bitmask
*/
@@ -4747,10 +4747,10 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->pWC = sWBI.pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pMaskSet = (WhereMaskSet*)&pWC[1];
pMaskSet = (WhereMaskSet*)&sWBI.pWC[1];
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
@@ -4760,9 +4760,9 @@ WhereInfo *sqlite3WhereBegin(
** subexpression is separated by an AND operator.
*/
initMaskSet(pMaskSet);
whereClauseInit(pWC, pParse, pMaskSet, wctrlFlags);
whereClauseInit(sWBI.pWC, pParse, pMaskSet, wctrlFlags);
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
** 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
** 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++){
createMask(pMaskSet, pTabList->a[i].iCursor);
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){
pWC->vmask |= ((Bitmask)1 << i);
sWBI.pWC->vmask |= ((Bitmask)1 << i);
}
#endif
}
@@ -4818,7 +4818,7 @@ WhereInfo *sqlite3WhereBegin(
** want to analyze these virtual terms, so start analyzing at the end
** and work forward so that the added virtual terms are never processed.
*/
exprAnalyzeAll(pTabList, pWC);
exprAnalyzeAll(pTabList, sWBI.pWC);
if( db->mallocFailed ){
goto whereBeginError;
}
@@ -4827,7 +4827,7 @@ WhereInfo *sqlite3WhereBegin(
** If it is, then set pDistinct to NULL and WhereInfo.eDistinct to
** 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;
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
@@ -4910,48 +4910,43 @@ WhereInfo *sqlite3WhereBegin(
nUnconstrained = 0;
notIndexed = 0;
for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
Bitmask mask; /* Mask of tables not yet ready */
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){
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;
m = getMask(pMaskSet, pTabItem->iCursor);
m = getMask(pMaskSet, sWBI.pSrc->iCursor);
if( (m & notReady)==0 ){
if( j==iFrom ) iFrom++;
continue;
}
mask = (isOptimal ? m : notReady);
pOB = (i==0) ? pOrderBy : 0;
pDist = (i==0 ? pDistinct : 0);
if( pTabItem->pIndex==0 ) nUnconstrained++;
sWBI.notValid = notReady;
sWBI.notReady = (isOptimal ? m : notReady);
sWBI.pOrderBy = (i==0) ? pOrderBy : 0;
sWBI.pDistinct = (i==0 ? pDistinct : 0);
if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
j, isOptimal));
assert( pTabItem->pTab );
assert( sWBI.pSrc->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTabItem->pTab) ){
sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOB,
&sCost, pp);
if( IsVirtual(sWBI.pSrc->pTab) ){
sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
bestVirtualIndex(&sWBI);
}else
#endif
{
bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOB,
pDist, &sCost);
bestBtreeIndex(&sWBI);
}
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
** index if it uses any index at all */
assert( pTabItem->pIndex==0
|| (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|| sCost.plan.u.pIdx==pTabItem->pIndex );
assert( sWBI.pSrc->pIndex==0
|| (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|| 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;
}
@@ -4975,20 +4970,20 @@ WhereInfo *sqlite3WhereBegin(
** (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.
*/
if( (sCost.used&notReady)==0 /* (1) */
&& (bestJ<0 || (notIndexed&m)!=0 /* (2) */
if( (sWBI.cost.used&notReady)==0 /* (1) */
&& (bestJ<0 || (notIndexed&m)!=0 /* (2) */
|| (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|| (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
&& (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */
|| NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
&& (bestJ<0 || sCost.rCost<bestPlan.rCost /* (4) */
|| (sCost.rCost<=bestPlan.rCost
&& sCost.plan.nRow<bestPlan.plan.nRow))
|| (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
&& (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
|| NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
&& (bestJ<0 || sWBI.cost.rCost<bestPlan.rCost /* (4) */
|| (sWBI.cost.rCost<=bestPlan.rCost
&& sWBI.cost.plan.nRow<bestPlan.plan.nRow))
){
WHERETRACE(("=== table %d is best so far"
" with cost=%g and nRow=%g\n",
j, sCost.rCost, sCost.plan.nRow));
bestPlan = sCost;
j, sWBI.cost.rCost, sWBI.cost.plan.nRow));
bestPlan = sWBI.cost;
bestJ = j;
}
if( doNotReorder ) break;
@@ -5077,6 +5072,7 @@ WhereInfo *sqlite3WhereBegin(
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
struct SrcList_item *pTabItem;
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
@@ -5112,7 +5108,7 @@ WhereInfo *sqlite3WhereBegin(
}
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
constructAutomaticIndex(pParse, sWBI.pWC, pTabItem, notReady, pLevel);
}else
#endif
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
@@ -5126,7 +5122,7 @@ WhereInfo *sqlite3WhereBegin(
VdbeComment((v, "%s", pIx->zName));
}
sqlite3CodeVerifySchema(pParse, iDb);
notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
notReady &= ~getMask(sWBI.pWC->pMaskSet, pTabItem->iCursor);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
if( db->mallocFailed ) goto whereBeginError;
@@ -5154,6 +5150,8 @@ WhereInfo *sqlite3WhereBegin(
char *z;
int n;
int w;
struct SrcList_item *pTabItem;
pLevel = &pWInfo->a[i];
w = pLevel->plan.wsFlags;
pTabItem = &pTabList->a[pLevel->iFrom];