| Index: third_party/sqlite/src/src/where.c
|
| diff --git a/third_party/sqlite/src/src/where.c b/third_party/sqlite/src/src/where.c
|
| index 702bdaf0355c14315d42036587b768b869fede6f..cf30d94d671bb81ef361cb6ac5b7a1aae392f395 100644
|
| --- a/third_party/sqlite/src/src/where.c
|
| +++ b/third_party/sqlite/src/src/where.c
|
| @@ -15,11 +15,10 @@
|
| ** rows. Indices are selected and used to speed the search when doing
|
| ** 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.411 2009/07/31 06:14:52 danielk1977 Exp $
|
| */
|
| #include "sqliteInt.h"
|
|
|
| +
|
| /*
|
| ** Trace output macros
|
| */
|
| @@ -119,6 +118,11 @@ struct WhereTerm {
|
| #define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */
|
| #define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */
|
| #define TERM_OR_OK 0x40 /* Used during OR-clause processing */
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| +# define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */
|
| +#else
|
| +# define TERM_VNULL 0x00 /* Disabled if not using stat2 */
|
| +#endif
|
|
|
| /*
|
| ** An instance of the following structure holds all information about a
|
| @@ -194,7 +198,6 @@ struct WhereMaskSet {
|
| struct WhereCost {
|
| WherePlan plan; /* The lookup strategy */
|
| double rCost; /* Overall cost of pursuing this search strategy */
|
| - double nRow; /* Estimated number of output rows */
|
| Bitmask used; /* Bitmask of cursors used by this plan */
|
| };
|
|
|
| @@ -213,6 +216,7 @@ struct WhereCost {
|
| #define WO_ISNULL 0x080
|
| #define WO_OR 0x100 /* Two or more OR-connected terms */
|
| #define WO_AND 0x200 /* Two or more AND-connected terms */
|
| +#define WO_NOOP 0x800 /* This term does not restrict search space */
|
|
|
| #define WO_ALL 0xfff /* Mask of all possible WO_* values */
|
| #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */
|
| @@ -237,15 +241,18 @@ struct WhereCost {
|
| #define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */
|
| #define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
|
| #define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
|
| +#define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */
|
| #define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */
|
| #define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
|
| #define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
|
| +#define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */
|
| #define WHERE_IDX_ONLY 0x00800000 /* Use index only - omit table */
|
| #define WHERE_ORDERBY 0x01000000 /* Output will appear in correct order */
|
| #define WHERE_REVERSE 0x02000000 /* Scan in reverse order */
|
| #define WHERE_UNIQUE 0x04000000 /* Selects no more than one row */
|
| #define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
|
| #define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
|
| +#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
|
|
|
| /*
|
| ** Initialize a preallocated WhereClause structure.
|
| @@ -327,6 +334,7 @@ static void whereClauseClear(WhereClause *pWC){
|
| static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
|
| WhereTerm *pTerm;
|
| int idx;
|
| + testcase( wtFlags & TERM_VIRTUAL ); /* EV: R-00211-15100 */
|
| if( pWC->nTerm>=pWC->nSlot ){
|
| WhereTerm *pOld = pWC->a;
|
| sqlite3 *db = pWC->pParse->db;
|
| @@ -391,7 +399,7 @@ static void whereSplit(WhereClause *pWC, Expr *pExpr, int op){
|
| */
|
| static Bitmask getMask(WhereMaskSet *pMaskSet, int iCursor){
|
| int i;
|
| - assert( pMaskSet->n<=sizeof(Bitmask)*8 );
|
| + assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 );
|
| for(i=0; i<pMaskSet->n; i++){
|
| if( pMaskSet->ix[i]==iCursor ){
|
| return ((Bitmask)1)<<i;
|
| @@ -472,6 +480,13 @@ static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){
|
| ** Return TRUE if the given operator is one of the operators that is
|
| ** allowed for an indexable WHERE clause term. The allowed operators are
|
| ** "=", "<", ">", "<=", ">=", and "IN".
|
| +**
|
| +** IMPLEMENTATION-OF: R-59926-26393 To be usable by an index a term must be
|
| +** of one of the following forms: column = expression column > expression
|
| +** column >= expression column < expression column <= expression
|
| +** expression = column expression > column expression >= column
|
| +** expression < column expression <= column column IN
|
| +** (expression-list) column IN (subquery) column IS NULL
|
| */
|
| static int allowedOp(int op){
|
| assert( TK_GT>TK_EQ && TK_GT<TK_GE );
|
| @@ -625,18 +640,19 @@ static void exprAnalyzeAll(
|
| static int isLikeOrGlob(
|
| Parse *pParse, /* Parsing and code generating context */
|
| Expr *pExpr, /* Test this expression */
|
| - int *pnPattern, /* Number of non-wildcard prefix characters */
|
| + Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */
|
| int *pisComplete, /* True if the only wildcard is % in the last character */
|
| int *pnoCase /* True if uppercase is equivalent to lowercase */
|
| ){
|
| - const char *z; /* String on RHS of LIKE operator */
|
| + const char *z = 0; /* String on RHS of LIKE operator */
|
| Expr *pRight, *pLeft; /* Right and left size of LIKE operator */
|
| ExprList *pList; /* List of operands to the LIKE operator */
|
| int c; /* One character in z[] */
|
| int cnt; /* Number of non-wildcard prefix characters */
|
| char wc[3]; /* Wildcard characters */
|
| - CollSeq *pColl; /* Collating sequence for LHS */
|
| sqlite3 *db = pParse->db; /* Database connection */
|
| + sqlite3_value *pVal = 0;
|
| + int op; /* Opcode of pRight */
|
|
|
| if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
|
| return 0;
|
| @@ -645,35 +661,65 @@ static int isLikeOrGlob(
|
| if( *pnoCase ) return 0;
|
| #endif
|
| pList = pExpr->x.pList;
|
| - pRight = pList->a[0].pExpr;
|
| - if( pRight->op!=TK_STRING ){
|
| - return 0;
|
| - }
|
| pLeft = pList->a[1].pExpr;
|
| - if( pLeft->op!=TK_COLUMN ){
|
| + if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT ){
|
| + /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
|
| + ** be the name of an indexed column with TEXT affinity. */
|
| return 0;
|
| }
|
| - pColl = sqlite3ExprCollSeq(pParse, pLeft);
|
| - assert( pColl!=0 || pLeft->iColumn==-1 );
|
| - if( pColl==0 ) return 0;
|
| - if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) &&
|
| - (pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
|
| - return 0;
|
| + assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
|
| +
|
| + pRight = pList->a[0].pExpr;
|
| + op = pRight->op;
|
| + if( op==TK_REGISTER ){
|
| + op = pRight->op2;
|
| + }
|
| + if( op==TK_VARIABLE ){
|
| + Vdbe *pReprepare = pParse->pReprepare;
|
| + int iCol = pRight->iColumn;
|
| + pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE);
|
| + if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
|
| + z = (char *)sqlite3_value_text(pVal);
|
| + }
|
| + sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); /* IMP: R-23257-02778 */
|
| + assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
|
| + }else if( op==TK_STRING ){
|
| + z = pRight->u.zToken;
|
| }
|
| - if( sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT ) return 0;
|
| - z = pRight->u.zToken;
|
| - if( ALWAYS(z) ){
|
| + if( z ){
|
| cnt = 0;
|
| while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
|
| cnt++;
|
| }
|
| - if( cnt!=0 && c!=0 && 255!=(u8)z[cnt-1] ){
|
| - *pisComplete = z[cnt]==wc[0] && z[cnt+1]==0;
|
| - *pnPattern = cnt;
|
| - return 1;
|
| + if( cnt!=0 && 255!=(u8)z[cnt-1] ){
|
| + Expr *pPrefix;
|
| + *pisComplete = c==wc[0] && z[cnt+1]==0;
|
| + pPrefix = sqlite3Expr(db, TK_STRING, z);
|
| + if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
|
| + *ppPrefix = pPrefix;
|
| + if( op==TK_VARIABLE ){
|
| + Vdbe *v = pParse->pVdbe;
|
| + sqlite3VdbeSetVarmask(v, pRight->iColumn); /* IMP: R-23257-02778 */
|
| + if( *pisComplete && pRight->u.zToken[1] ){
|
| + /* If the rhs of the LIKE expression is a variable, and the current
|
| + ** value of the variable means there is no need to invoke the LIKE
|
| + ** function, then no OP_Variable will be added to the program.
|
| + ** This causes problems for the sqlite3_bind_parameter_name()
|
| + ** API. To workaround them, add a dummy OP_Variable here.
|
| + */
|
| + int r1 = sqlite3GetTempReg(pParse);
|
| + sqlite3ExprCodeTarget(pParse, pRight, r1);
|
| + sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0);
|
| + sqlite3ReleaseTempReg(pParse, r1);
|
| + }
|
| + }
|
| + }else{
|
| + z = 0;
|
| }
|
| }
|
| - return 0;
|
| +
|
| + sqlite3ValueFree(pVal);
|
| + return (z!=0);
|
| }
|
| #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
|
|
|
| @@ -986,6 +1032,8 @@ static void exprAnalyzeOrTerm(
|
| /* At this point, okToChngToIN is true if original pTerm satisfies
|
| ** case 1. In that case, construct a new virtual term that is
|
| ** pTerm converted into an IN operator.
|
| + **
|
| + ** EV: R-00211-15100
|
| */
|
| if( okToChngToIN ){
|
| Expr *pDup; /* A transient duplicate expression */
|
| @@ -1019,7 +1067,7 @@ static void exprAnalyzeOrTerm(
|
| }else{
|
| sqlite3ExprListDelete(db, pList);
|
| }
|
| - pTerm->eOperator = 0; /* case 1 trumps case 2 */
|
| + pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */
|
| }
|
| }
|
| }
|
| @@ -1054,10 +1102,10 @@ static void exprAnalyze(
|
| Expr *pExpr; /* The expression to be analyzed */
|
| Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
|
| Bitmask prereqAll; /* Prerequesites of pExpr */
|
| - Bitmask extraRight = 0;
|
| - int nPattern;
|
| - int isComplete;
|
| - int noCase;
|
| + Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
|
| + Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
|
| + int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
|
| + int noCase = 0; /* LIKE/GLOB distinguishes case */
|
| int op; /* Top-level operator. pExpr->op */
|
| Parse *pParse = pWC->pParse; /* Parsing context */
|
| sqlite3 *db = pParse->db; /* Database connection */
|
| @@ -1126,7 +1174,8 @@ static void exprAnalyze(
|
| pLeft = pDup->pLeft;
|
| pNew->leftCursor = pLeft->iTable;
|
| pNew->u.leftColumn = pLeft->iColumn;
|
| - pNew->prereqRight = prereqLeft;
|
| + testcase( (prereqLeft | extraRight) != prereqLeft );
|
| + pNew->prereqRight = prereqLeft | extraRight;
|
| pNew->prereqAll = prereqAll;
|
| pNew->eOperator = operatorMask(pDup->op);
|
| }
|
| @@ -1192,21 +1241,22 @@ static void exprAnalyze(
|
| ** The last character of the prefix "abc" is incremented to form the
|
| ** termination condition "abd".
|
| */
|
| - if( isLikeOrGlob(pParse, pExpr, &nPattern, &isComplete, &noCase)
|
| - && pWC->op==TK_AND ){
|
| - Expr *pLeft, *pRight;
|
| - Expr *pStr1, *pStr2;
|
| - Expr *pNewExpr1, *pNewExpr2;
|
| - int idxNew1, idxNew2;
|
| + if( pWC->op==TK_AND
|
| + && isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
|
| + ){
|
| + Expr *pLeft; /* LHS of LIKE/GLOB operator */
|
| + Expr *pStr2; /* Copy of pStr1 - RHS of LIKE/GLOB operator */
|
| + Expr *pNewExpr1;
|
| + Expr *pNewExpr2;
|
| + int idxNew1;
|
| + int idxNew2;
|
| + CollSeq *pColl; /* Collating sequence to use */
|
|
|
| pLeft = pExpr->x.pList->a[1].pExpr;
|
| - pRight = pExpr->x.pList->a[0].pExpr;
|
| - pStr1 = sqlite3Expr(db, TK_STRING, pRight->u.zToken);
|
| - if( pStr1 ) pStr1->u.zToken[nPattern] = 0;
|
| pStr2 = sqlite3ExprDup(db, pStr1, 0);
|
| if( !db->mallocFailed ){
|
| u8 c, *pC; /* Last character before the first wildcard */
|
| - pC = (u8*)&pStr2->u.zToken[nPattern-1];
|
| + pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1];
|
| c = *pC;
|
| if( noCase ){
|
| /* The point is to increment the last character before the first
|
| @@ -1215,17 +1265,23 @@ static void exprAnalyze(
|
| ** inequality. To avoid this, make sure to also run the full
|
| ** LIKE on all candidate expressions by clearing the isComplete flag
|
| */
|
| - if( c=='A'-1 ) isComplete = 0;
|
| + if( c=='A'-1 ) isComplete = 0; /* EV: R-64339-08207 */
|
| +
|
|
|
| c = sqlite3UpperToLower[c];
|
| }
|
| *pC = c + 1;
|
| }
|
| - pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft,0),pStr1,0);
|
| + pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, noCase ? "NOCASE" : "BINARY",0);
|
| + pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
|
| + sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
|
| + pStr1, 0);
|
| idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
|
| testcase( idxNew1==0 );
|
| exprAnalyze(pSrc, pWC, idxNew1);
|
| - pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft,0),pStr2,0);
|
| + pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
|
| + sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
|
| + pStr2, 0);
|
| idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
|
| testcase( idxNew2==0 );
|
| exprAnalyze(pSrc, pWC, idxNew2);
|
| @@ -1275,6 +1331,47 @@ static void exprAnalyze(
|
| }
|
| #endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| + /* When sqlite_stat2 histogram data is available an operator of the
|
| + ** form "x IS NOT NULL" can sometimes be evaluated more efficiently
|
| + ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
|
| + ** virtual term of that form.
|
| + **
|
| + ** Note that the virtual term must be tagged with TERM_VNULL. This
|
| + ** TERM_VNULL tag will suppress the not-null check at the beginning
|
| + ** of the loop. Without the TERM_VNULL flag, the not-null check at
|
| + ** the start of the loop will prevent any results from being returned.
|
| + */
|
| + if( pExpr->op==TK_NOTNULL
|
| + && pExpr->pLeft->op==TK_COLUMN
|
| + && pExpr->pLeft->iColumn>=0
|
| + ){
|
| + Expr *pNewExpr;
|
| + Expr *pLeft = pExpr->pLeft;
|
| + int idxNew;
|
| + WhereTerm *pNewTerm;
|
| +
|
| + pNewExpr = sqlite3PExpr(pParse, TK_GT,
|
| + sqlite3ExprDup(db, pLeft, 0),
|
| + sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0);
|
| +
|
| + idxNew = whereClauseInsert(pWC, pNewExpr,
|
| + TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
|
| + if( idxNew ){
|
| + pNewTerm = &pWC->a[idxNew];
|
| + pNewTerm->prereqRight = 0;
|
| + pNewTerm->leftCursor = pLeft->iTable;
|
| + pNewTerm->u.leftColumn = pLeft->iColumn;
|
| + pNewTerm->eOperator = WO_GT;
|
| + pNewTerm->iParent = idxTerm;
|
| + pTerm = &pWC->a[idxTerm];
|
| + pTerm->nChild = 1;
|
| + pTerm->wtFlags |= TERM_COPIED;
|
| + pNewTerm->prereqAll = pTerm->prereqAll;
|
| + }
|
| + }
|
| +#endif /* SQLITE_ENABLE_STAT2 */
|
| +
|
| /* Prevent ON clause terms of a LEFT JOIN from being used to drive
|
| ** an index for tables to the left of the join.
|
| */
|
| @@ -1327,6 +1424,7 @@ static int isSortingIndex(
|
| int base, /* Cursor number for the table to be sorted */
|
| ExprList *pOrderBy, /* The ORDER BY clause */
|
| int nEqCol, /* Number of index columns with == constraints */
|
| + int wsFlags, /* Index usages flags */
|
| int *pbRev /* Set to 1 if ORDER BY is DESC */
|
| ){
|
| int i, j; /* Loop counters */
|
| @@ -1432,11 +1530,14 @@ static int isSortingIndex(
|
| return 1;
|
| }
|
| if( pIdx->onError!=OE_None && i==pIdx->nColumn
|
| + && (wsFlags & WHERE_COLUMN_NULL)==0
|
| && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
|
| /* All terms of this index match some prefix of the ORDER BY clause
|
| ** and the index is UNIQUE and no terms on the tail of the ORDER BY
|
| ** clause reference other tables in a join. If this is all true then
|
| - ** the order by clause is superfluous. */
|
| + ** the order by clause is superfluous. Not that if the matching
|
| + ** condition is IS NULL then the result is not necessarily unique
|
| + ** even on a UNIQUE index, so disallow those cases. */
|
| return 1;
|
| }
|
| return 0;
|
| @@ -1507,7 +1608,8 @@ 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, ExprList*, WhereCost*);
|
| + Parse*, WhereClause*, struct SrcList_item*,
|
| + Bitmask, Bitmask, ExprList*, WhereCost*);
|
|
|
| /*
|
| ** This routine attempts to find an scanning strategy that can be used
|
| @@ -1520,7 +1622,8 @@ 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 that are not available */
|
| + 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 */
|
| ){
|
| @@ -1530,6 +1633,12 @@ static void bestOrClauseIndex(
|
| WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
|
| WhereTerm *pTerm; /* A single term of the WHERE clause */
|
|
|
| + /* No OR-clause optimization allowed if the INDEXED BY or NOT INDEXED clauses
|
| + ** are used */
|
| + if( pSrc->notIndexed || pSrc->pIndex!=0 ){
|
| + return;
|
| + }
|
| +
|
| /* Search the WHERE clause terms for a usable WO_OR term. */
|
| for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
| if( pTerm->eOperator==WO_OR
|
| @@ -1551,7 +1660,7 @@ static void bestOrClauseIndex(
|
| ));
|
| if( pOrTerm->eOperator==WO_AND ){
|
| WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
|
| - bestIndex(pParse, pAndWC, pSrc, notReady, 0, &sTermCost);
|
| + bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost);
|
| }else if( pOrTerm->leftCursor==iCur ){
|
| WhereClause tempWC;
|
| tempWC.pParse = pWC->pParse;
|
| @@ -1559,12 +1668,12 @@ static void bestOrClauseIndex(
|
| tempWC.op = TK_AND;
|
| tempWC.a = pOrTerm;
|
| tempWC.nTerm = 1;
|
| - bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost);
|
| + bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
|
| }else{
|
| continue;
|
| }
|
| rTotal += sTermCost.rCost;
|
| - nRow += sTermCost.nRow;
|
| + nRow += sTermCost.plan.nRow;
|
| used |= sTermCost.used;
|
| if( rTotal>=pCost->rCost ) break;
|
| }
|
| @@ -1572,8 +1681,9 @@ static void bestOrClauseIndex(
|
| /* If there is an ORDER BY clause, increase the scan cost to account
|
| ** for the cost of the sort. */
|
| if( pOrderBy!=0 ){
|
| + WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
|
| + rTotal, rTotal+nRow*estLog(nRow)));
|
| rTotal += nRow*estLog(nRow);
|
| - WHERETRACE(("... sorting increases OR cost to %.9g\n", rTotal));
|
| }
|
|
|
| /* If the cost of scanning using this OR term for optimization is
|
| @@ -1582,8 +1692,8 @@ static void bestOrClauseIndex(
|
| WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
|
| if( rTotal<pCost->rCost ){
|
| pCost->rCost = rTotal;
|
| - pCost->nRow = nRow;
|
| pCost->used = used;
|
| + pCost->plan.nRow = nRow;
|
| pCost->plan.wsFlags = flags;
|
| pCost->plan.u.pTerm = pTerm;
|
| }
|
| @@ -1592,6 +1702,247 @@ static void bestOrClauseIndex(
|
| #endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
| }
|
|
|
| +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
| +/*
|
| +** Return TRUE if the WHERE clause term pTerm is of a form where it
|
| +** could be used with an index to access pSrc, assuming an appropriate
|
| +** index existed.
|
| +*/
|
| +static int termCanDriveIndex(
|
| + WhereTerm *pTerm, /* WHERE clause term to check */
|
| + struct SrcList_item *pSrc, /* Table we are trying to access */
|
| + Bitmask notReady /* Tables in outer loops of the join */
|
| +){
|
| + char aff;
|
| + if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
|
| + if( pTerm->eOperator!=WO_EQ ) return 0;
|
| + if( (pTerm->prereqRight & notReady)!=0 ) return 0;
|
| + aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
|
| + if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
|
| + return 1;
|
| +}
|
| +#endif
|
| +
|
| +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
| +/*
|
| +** If the query plan for pSrc specified in pCost is a full table scan
|
| +** and indexing is allows (if there is no NOT INDEXED clause) and it
|
| +** possible to construct a transient index that would perform better
|
| +** than a full table scan even when the cost of constructing the index
|
| +** 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) */
|
| + double costTempIdx; /* per-query cost of the transient index */
|
| + WhereTerm *pTerm; /* A single term of the WHERE clause */
|
| + WhereTerm *pWCEnd; /* End of pWC->a[] */
|
| + Table *pTable; /* Table tht might be indexed */
|
| +
|
| + if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){
|
| + /* Automatic indices are disabled at run-time */
|
| + return;
|
| + }
|
| + if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
|
| + /* We already have some kind of index in use for this query. */
|
| + return;
|
| + }
|
| + if( pSrc->notIndexed ){
|
| + /* The NOT INDEXED clause appears in the SQL. */
|
| + return;
|
| + }
|
| +
|
| + assert( pParse->nQueryLoop >= (double)1 );
|
| + pTable = pSrc->pTab;
|
| + nTableRow = pTable->nRowEst;
|
| + logN = estLog(nTableRow);
|
| + costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
|
| + if( costTempIdx>=pCost->rCost ){
|
| + /* The cost of creating the transient table would be greater than
|
| + ** doing the full table scan */
|
| + return;
|
| + }
|
| +
|
| + /* Search for any equality comparison term */
|
| + pWCEnd = &pWC->a[pWC->nTerm];
|
| + for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
| + if( termCanDriveIndex(pTerm, pSrc, 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;
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +#else
|
| +# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
|
| +#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
|
| +
|
| +
|
| +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
| +/*
|
| +** Generate code to construct the Index object for an automatic index
|
| +** and to set up the WhereLevel object pLevel so that the code generator
|
| +** makes use of the automatic index.
|
| +*/
|
| +static void constructAutomaticIndex(
|
| + Parse *pParse, /* The parsing context */
|
| + WhereClause *pWC, /* The WHERE clause */
|
| + struct SrcList_item *pSrc, /* The FROM clause term to get the next index */
|
| + Bitmask notReady, /* Mask of cursors that are not available */
|
| + WhereLevel *pLevel /* Write new index here */
|
| +){
|
| + int nColumn; /* Number of columns in the constructed index */
|
| + WhereTerm *pTerm; /* A single term of the WHERE clause */
|
| + WhereTerm *pWCEnd; /* End of pWC->a[] */
|
| + int nByte; /* Byte of memory needed for pIdx */
|
| + Index *pIdx; /* Object describing the transient index */
|
| + Vdbe *v; /* Prepared statement under construction */
|
| + int regIsInit; /* Register set by initialization */
|
| + int addrInit; /* Address of the initialization bypass jump */
|
| + Table *pTable; /* The table being indexed */
|
| + KeyInfo *pKeyinfo; /* Key information for the index */
|
| + int addrTop; /* Top of the index fill loop */
|
| + int regRecord; /* Register holding an index record */
|
| + int n; /* Column counter */
|
| + int i; /* Loop counter */
|
| + int mxBitCol; /* Maximum column in pSrc->colUsed */
|
| + CollSeq *pColl; /* Collating sequence to on a column */
|
| + Bitmask idxCols; /* Bitmap of columns used for indexing */
|
| + Bitmask extraCols; /* Bitmap of additional columns */
|
| +
|
| + /* Generate code to skip over the creation and initialization of the
|
| + ** transient index on 2nd and subsequent iterations of the loop. */
|
| + v = pParse->pVdbe;
|
| + assert( v!=0 );
|
| + regIsInit = ++pParse->nMem;
|
| + addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit);
|
| + sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit);
|
| +
|
| + /* Count the number of columns that will be added to the index
|
| + ** and used to match WHERE clause constraints */
|
| + nColumn = 0;
|
| + pTable = pSrc->pTab;
|
| + pWCEnd = &pWC->a[pWC->nTerm];
|
| + idxCols = 0;
|
| + for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
| + if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
| + int iCol = pTerm->u.leftColumn;
|
| + Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
|
| + testcase( iCol==BMS );
|
| + testcase( iCol==BMS-1 );
|
| + if( (idxCols & cMask)==0 ){
|
| + nColumn++;
|
| + idxCols |= cMask;
|
| + }
|
| + }
|
| + }
|
| + assert( nColumn>0 );
|
| + pLevel->plan.nEq = nColumn;
|
| +
|
| + /* Count the number of additional columns needed to create a
|
| + ** covering index. A "covering index" is an index that contains all
|
| + ** columns that are needed by the query. With a covering index, the
|
| + ** original table never needs to be accessed. Automatic indices must
|
| + ** be a covering index because the index will not be updated if the
|
| + ** original table changes and the index and table cannot both be used
|
| + ** if they go out of sync.
|
| + */
|
| + extraCols = pSrc->colUsed & (~idxCols | (((Bitmask)1)<<(BMS-1)));
|
| + mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
|
| + testcase( pTable->nCol==BMS-1 );
|
| + testcase( pTable->nCol==BMS-2 );
|
| + for(i=0; i<mxBitCol; i++){
|
| + if( extraCols & (((Bitmask)1)<<i) ) nColumn++;
|
| + }
|
| + if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
|
| + nColumn += pTable->nCol - BMS + 1;
|
| + }
|
| + pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WO_EQ;
|
| +
|
| + /* Construct the Index object to describe this index */
|
| + nByte = sizeof(Index);
|
| + nByte += nColumn*sizeof(int); /* Index.aiColumn */
|
| + nByte += nColumn*sizeof(char*); /* Index.azColl */
|
| + nByte += nColumn; /* Index.aSortOrder */
|
| + pIdx = sqlite3DbMallocZero(pParse->db, nByte);
|
| + if( pIdx==0 ) return;
|
| + pLevel->plan.u.pIdx = pIdx;
|
| + pIdx->azColl = (char**)&pIdx[1];
|
| + pIdx->aiColumn = (int*)&pIdx->azColl[nColumn];
|
| + pIdx->aSortOrder = (u8*)&pIdx->aiColumn[nColumn];
|
| + pIdx->zName = "auto-index";
|
| + pIdx->nColumn = nColumn;
|
| + pIdx->pTable = pTable;
|
| + n = 0;
|
| + idxCols = 0;
|
| + for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
| + if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
| + int iCol = pTerm->u.leftColumn;
|
| + Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
|
| + if( (idxCols & cMask)==0 ){
|
| + Expr *pX = pTerm->pExpr;
|
| + idxCols |= cMask;
|
| + pIdx->aiColumn[n] = pTerm->u.leftColumn;
|
| + pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
|
| + pIdx->azColl[n] = ALWAYS(pColl) ? pColl->zName : "BINARY";
|
| + n++;
|
| + }
|
| + }
|
| + }
|
| + assert( (u32)n==pLevel->plan.nEq );
|
| +
|
| + /* Add additional columns needed to make the automatic index into
|
| + ** a covering index */
|
| + for(i=0; i<mxBitCol; i++){
|
| + if( extraCols & (((Bitmask)1)<<i) ){
|
| + pIdx->aiColumn[n] = i;
|
| + pIdx->azColl[n] = "BINARY";
|
| + n++;
|
| + }
|
| + }
|
| + if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
|
| + for(i=BMS-1; i<pTable->nCol; i++){
|
| + pIdx->aiColumn[n] = i;
|
| + pIdx->azColl[n] = "BINARY";
|
| + n++;
|
| + }
|
| + }
|
| + assert( n==nColumn );
|
| +
|
| + /* Create the automatic index */
|
| + pKeyinfo = sqlite3IndexKeyinfo(pParse, pIdx);
|
| + assert( pLevel->iIdxCur>=0 );
|
| + sqlite3VdbeAddOp4(v, OP_OpenAutoindex, pLevel->iIdxCur, nColumn+1, 0,
|
| + (char*)pKeyinfo, P4_KEYINFO_HANDOFF);
|
| + VdbeComment((v, "for %s", pTable->zName));
|
| +
|
| + /* Fill the automatic index with content */
|
| + addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
|
| + regRecord = sqlite3GetTempReg(pParse);
|
| + sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1);
|
| + sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
|
| + sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
| + sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
|
| + sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
|
| + sqlite3VdbeJumpHere(v, addrTop);
|
| + sqlite3ReleaseTempReg(pParse, regRecord);
|
| +
|
| + /* Jump here when skipping the initialization */
|
| + sqlite3VdbeJumpHere(v, addrInit);
|
| +}
|
| +#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
|
| +
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| /*
|
| ** Allocate and populate an sqlite3_index_info structure. It is the
|
| @@ -1716,12 +2067,10 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
| int i;
|
| int rc;
|
|
|
| - (void)sqlite3SafetyOff(pParse->db);
|
| WHERETRACE(("xBestIndex for %s\n", pTab->zName));
|
| TRACE_IDX_INPUTS(p);
|
| rc = pVtab->pModule->xBestIndex(pVtab, p);
|
| TRACE_IDX_OUTPUTS(p);
|
| - (void)sqlite3SafetyOn(pParse->db);
|
|
|
| if( rc!=SQLITE_OK ){
|
| if( rc==SQLITE_NOMEM ){
|
| @@ -1732,7 +2081,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
| sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
|
| }
|
| }
|
| - sqlite3DbFree(pParse->db, pVtab->zErrMsg);
|
| + sqlite3_free(pVtab->zErrMsg);
|
| pVtab->zErrMsg = 0;
|
|
|
| for(i=0; i<p->nConstraint; i++){
|
| @@ -1766,7 +2115,8 @@ 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 that are not available */
|
| + 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 */
|
| @@ -1778,6 +2128,7 @@ static void bestVirtualIndex(
|
| WhereTerm *pTerm;
|
| int i, j;
|
| int nOrderBy;
|
| + double rCost;
|
|
|
| /* Make sure wsFlags is initialized to some sane value. Otherwise, if the
|
| ** malloc in allocateIndexInfo() fails and this function returns leaving
|
| @@ -1864,6 +2215,15 @@ static void bestVirtualIndex(
|
| }
|
| }
|
|
|
| + /* If there is an ORDER BY clause, and the selected virtual table index
|
| + ** does not satisfy it, increase the cost of the scan accordingly. This
|
| + ** matches the processing for non-virtual tables in bestBtreeIndex().
|
| + */
|
| + rCost = pIdxInfo->estimatedCost;
|
| + if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
|
| + rCost += estLog(rCost)*rCost;
|
| + }
|
| +
|
| /* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
|
| ** inital value of lowestCost in this loop. If it is, then the
|
| ** (cost<lowestCost) test below will never be true.
|
| @@ -1871,10 +2231,10 @@ static void bestVirtualIndex(
|
| ** Use "(double)2" instead of "2.0" in case OMIT_FLOATING_POINT
|
| ** is defined.
|
| */
|
| - if( (SQLITE_BIG_DBL/((double)2))<pIdxInfo->estimatedCost ){
|
| + if( (SQLITE_BIG_DBL/((double)2))<rCost ){
|
| pCost->rCost = (SQLITE_BIG_DBL/((double)2));
|
| }else{
|
| - pCost->rCost = pIdxInfo->estimatedCost;
|
| + pCost->rCost = rCost;
|
| }
|
| pCost->plan.u.pVtabIdx = pIdxInfo;
|
| if( pIdxInfo->orderByConsumed ){
|
| @@ -1886,18 +2246,25 @@ static void bestVirtualIndex(
|
| /* 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, pOrderBy, pCost);
|
| + bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
|
| }
|
| #endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
| /*
|
| ** Argument pIdx is a pointer to an index structure that has an array of
|
| ** SQLITE_INDEX_SAMPLES evenly spaced samples of the first indexed column
|
| -** stored in Index.aSample. The domain of values stored in said column
|
| -** may be thought of as divided into (SQLITE_INDEX_SAMPLES+1) regions.
|
| -** Region 0 contains all values smaller than the first sample value. Region
|
| -** 1 contains values larger than or equal to the value of the first sample,
|
| -** but smaller than the value of the second. And so on.
|
| +** stored in Index.aSample. These samples divide the domain of values stored
|
| +** the index into (SQLITE_INDEX_SAMPLES+1) regions.
|
| +** Region 0 contains all values less than the first sample value. Region
|
| +** 1 contains values between the first and second samples. Region 2 contains
|
| +** values between samples 2 and 3. And so on. Region SQLITE_INDEX_SAMPLES
|
| +** contains values larger than the last sample.
|
| +**
|
| +** If the index contains many duplicates of a single value, then it is
|
| +** possible that two or more adjacent samples can hold the same value.
|
| +** When that is the case, the smallest possible region code is returned
|
| +** when roundUp is false and the largest possible region code is returned
|
| +** when roundUp is true.
|
| **
|
| ** If successful, this function determines which of the regions value
|
| ** pVal lies in, sets *piRegion to the region index (a value between 0
|
| @@ -1910,8 +2277,10 @@ static int whereRangeRegion(
|
| Parse *pParse, /* Database connection */
|
| Index *pIdx, /* Index to consider domain of */
|
| sqlite3_value *pVal, /* Value to consider */
|
| + int roundUp, /* Return largest valid region if true */
|
| int *piRegion /* OUT: Region of domain in which value lies */
|
| ){
|
| + assert( roundUp==0 || roundUp==1 );
|
| if( ALWAYS(pVal) ){
|
| IndexSample *aSample = pIdx->aSample;
|
| int i = 0;
|
| @@ -1921,7 +2290,17 @@ static int whereRangeRegion(
|
| double r = sqlite3_value_double(pVal);
|
| for(i=0; i<SQLITE_INDEX_SAMPLES; i++){
|
| if( aSample[i].eType==SQLITE_NULL ) continue;
|
| - if( aSample[i].eType>=SQLITE_TEXT || aSample[i].u.r>r ) break;
|
| + if( aSample[i].eType>=SQLITE_TEXT ) break;
|
| + if( roundUp ){
|
| + if( aSample[i].u.r>r ) break;
|
| + }else{
|
| + if( aSample[i].u.r>=r ) break;
|
| + }
|
| + }
|
| + }else if( eType==SQLITE_NULL ){
|
| + i = 0;
|
| + if( roundUp ){
|
| + while( i<SQLITE_INDEX_SAMPLES && aSample[i].eType==SQLITE_NULL ) i++;
|
| }
|
| }else{
|
| sqlite3 *db = pParse->db;
|
| @@ -1952,13 +2331,12 @@ static int whereRangeRegion(
|
| n = sqlite3ValueBytes(pVal, pColl->enc);
|
|
|
| for(i=0; i<SQLITE_INDEX_SAMPLES; i++){
|
| - int r;
|
| + int c;
|
| int eSampletype = aSample[i].eType;
|
| if( eSampletype==SQLITE_NULL || eSampletype<eType ) continue;
|
| if( (eSampletype!=eType) ) break;
|
| - if( pColl->enc==SQLITE_UTF8 ){
|
| - r = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
|
| - }else{
|
| +#ifndef SQLITE_OMIT_UTF16
|
| + if( pColl->enc!=SQLITE_UTF8 ){
|
| int nSample;
|
| char *zSample = sqlite3Utf8to16(
|
| db, pColl->enc, aSample[i].u.z, aSample[i].nByte, &nSample
|
| @@ -1967,10 +2345,14 @@ static int whereRangeRegion(
|
| assert( db->mallocFailed );
|
| return SQLITE_NOMEM;
|
| }
|
| - r = pColl->xCmp(pColl->pUser, nSample, zSample, n, z);
|
| + c = pColl->xCmp(pColl->pUser, nSample, zSample, n, z);
|
| sqlite3DbFree(db, zSample);
|
| + }else
|
| +#endif
|
| + {
|
| + c = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
|
| }
|
| - if( r>0 ) break;
|
| + if( c-roundUp>=0 ) break;
|
| }
|
| }
|
|
|
| @@ -1982,6 +2364,41 @@ static int whereRangeRegion(
|
| #endif /* #ifdef SQLITE_ENABLE_STAT2 */
|
|
|
| /*
|
| +** If expression pExpr represents a literal value, set *pp to point to
|
| +** an sqlite3_value structure containing the same value, with affinity
|
| +** aff applied to it, before returning. It is the responsibility of the
|
| +** caller to eventually release this structure by passing it to
|
| +** sqlite3ValueFree().
|
| +**
|
| +** If the current parse is a recompile (sqlite3Reprepare()) and pExpr
|
| +** is an SQL variable that currently has a non-NULL value bound to it,
|
| +** create an sqlite3_value structure containing this value, again with
|
| +** affinity aff applied to it, instead.
|
| +**
|
| +** If neither of the above apply, set *pp to NULL.
|
| +**
|
| +** If an error occurs, return an error code. Otherwise, SQLITE_OK.
|
| +*/
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| +static int valueFromExpr(
|
| + Parse *pParse,
|
| + Expr *pExpr,
|
| + u8 aff,
|
| + sqlite3_value **pp
|
| +){
|
| + if( pExpr->op==TK_VARIABLE
|
| + || (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
| + ){
|
| + int iVar = pExpr->iColumn;
|
| + sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); /* IMP: R-23257-02778 */
|
| + *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
|
| + return SQLITE_OK;
|
| + }
|
| + return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
|
| +}
|
| +#endif
|
| +
|
| +/*
|
| ** This function is used to estimate the number of rows that will be visited
|
| ** by scanning an index for a range of values. The range may have an upper
|
| ** bound, a lower bound, or both. The WHERE clause terms that set the upper
|
| @@ -2018,9 +2435,9 @@ static int whereRangeRegion(
|
| ** constraints.
|
| **
|
| ** In the absence of sqlite_stat2 ANALYZE data, each range inequality
|
| -** reduces the search space by 2/3rds. Hence a single constraint (x>?)
|
| -** results in a return of 33 and a range constraint (x>? AND x<?) results
|
| -** in a return of 11.
|
| +** reduces the search space by 3/4ths. Hence a single constraint (x>?)
|
| +** results in a return of 25 and a range constraint (x>? AND x<?) results
|
| +** in a return of 6.
|
| */
|
| static int whereRangeScanEst(
|
| Parse *pParse, /* Parsing & code generating context */
|
| @@ -2033,23 +2450,28 @@ static int whereRangeScanEst(
|
| int rc = SQLITE_OK;
|
|
|
| #ifdef SQLITE_ENABLE_STAT2
|
| - sqlite3 *db = pParse->db;
|
| - sqlite3_value *pLowerVal = 0;
|
| - sqlite3_value *pUpperVal = 0;
|
|
|
| if( nEq==0 && p->aSample ){
|
| + sqlite3_value *pLowerVal = 0;
|
| + sqlite3_value *pUpperVal = 0;
|
| int iEst;
|
| int iLower = 0;
|
| int iUpper = SQLITE_INDEX_SAMPLES;
|
| - u8 aff = p->pTable->aCol[0].affinity;
|
| + int roundUpUpper = 0;
|
| + int roundUpLower = 0;
|
| + u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
|
|
|
| if( pLower ){
|
| Expr *pExpr = pLower->pExpr->pRight;
|
| - rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pLowerVal);
|
| + rc = valueFromExpr(pParse, pExpr, aff, &pLowerVal);
|
| + assert( pLower->eOperator==WO_GT || pLower->eOperator==WO_GE );
|
| + roundUpLower = (pLower->eOperator==WO_GT) ?1:0;
|
| }
|
| if( rc==SQLITE_OK && pUpper ){
|
| Expr *pExpr = pUpper->pExpr->pRight;
|
| - rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pUpperVal);
|
| + rc = valueFromExpr(pParse, pExpr, aff, &pUpperVal);
|
| + assert( pUpper->eOperator==WO_LT || pUpper->eOperator==WO_LE );
|
| + roundUpUpper = (pUpper->eOperator==WO_LE) ?1:0;
|
| }
|
|
|
| if( rc!=SQLITE_OK || (pLowerVal==0 && pUpperVal==0) ){
|
| @@ -2057,28 +2479,29 @@ static int whereRangeScanEst(
|
| sqlite3ValueFree(pUpperVal);
|
| goto range_est_fallback;
|
| }else if( pLowerVal==0 ){
|
| - rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper);
|
| + rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper);
|
| if( pLower ) iLower = iUpper/2;
|
| }else if( pUpperVal==0 ){
|
| - rc = whereRangeRegion(pParse, p, pLowerVal, &iLower);
|
| + rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower);
|
| if( pUpper ) iUpper = (iLower + SQLITE_INDEX_SAMPLES + 1)/2;
|
| }else{
|
| - rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper);
|
| + rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper);
|
| if( rc==SQLITE_OK ){
|
| - rc = whereRangeRegion(pParse, p, pLowerVal, &iLower);
|
| + rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower);
|
| }
|
| }
|
| + WHERETRACE(("range scan regions: %d..%d\n", iLower, iUpper));
|
|
|
| iEst = iUpper - iLower;
|
| testcase( iEst==SQLITE_INDEX_SAMPLES );
|
| assert( iEst<=SQLITE_INDEX_SAMPLES );
|
| if( iEst<1 ){
|
| - iEst = 1;
|
| + *piEst = 50/SQLITE_INDEX_SAMPLES;
|
| + }else{
|
| + *piEst = (iEst*100)/SQLITE_INDEX_SAMPLES;
|
| }
|
| -
|
| sqlite3ValueFree(pLowerVal);
|
| sqlite3ValueFree(pUpperVal);
|
| - *piEst = (iEst * 100)/SQLITE_INDEX_SAMPLES;
|
| return rc;
|
| }
|
| range_est_fallback:
|
| @@ -2088,22 +2511,156 @@ range_est_fallback:
|
| UNUSED_PARAMETER(nEq);
|
| #endif
|
| assert( pLower || pUpper );
|
| - if( pLower && pUpper ){
|
| - *piEst = 11;
|
| + *piEst = 100;
|
| + if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *piEst /= 4;
|
| + if( pUpper ) *piEst /= 4;
|
| + return rc;
|
| +}
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| +/*
|
| +** Estimate the number of rows that will be returned based on
|
| +** an equality constraint x=VALUE and where that VALUE occurs in
|
| +** the histogram data. This only works when x is the left-most
|
| +** column of an index and sqlite_stat2 histogram data is available
|
| +** for that index. When pExpr==NULL that means the constraint is
|
| +** "x IS NULL" instead of "x=VALUE".
|
| +**
|
| +** Write the estimated row count into *pnRow and return SQLITE_OK.
|
| +** If unable to make an estimate, leave *pnRow unchanged and return
|
| +** non-zero.
|
| +**
|
| +** This routine can fail if it is unable to load a collating sequence
|
| +** required for string comparison, or if unable to allocate memory
|
| +** for a UTF conversion required for comparison. The error is stored
|
| +** in the pParse structure.
|
| +*/
|
| +static int whereEqualScanEst(
|
| + Parse *pParse, /* Parsing & code generating context */
|
| + Index *p, /* The index whose left-most column is pTerm */
|
| + Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */
|
| + double *pnRow /* Write the revised row estimate here */
|
| +){
|
| + sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */
|
| + int iLower, iUpper; /* Range of histogram regions containing pRhs */
|
| + u8 aff; /* Column affinity */
|
| + int rc; /* Subfunction return code */
|
| + double nRowEst; /* New estimate of the number of rows */
|
| +
|
| + assert( p->aSample!=0 );
|
| + aff = p->pTable->aCol[p->aiColumn[0]].affinity;
|
| + if( pExpr ){
|
| + rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
|
| + if( rc ) goto whereEqualScanEst_cancel;
|
| + }else{
|
| + pRhs = sqlite3ValueNew(pParse->db);
|
| + }
|
| + if( pRhs==0 ) return SQLITE_NOTFOUND;
|
| + rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower);
|
| + if( rc ) goto whereEqualScanEst_cancel;
|
| + rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper);
|
| + if( rc ) goto whereEqualScanEst_cancel;
|
| + WHERETRACE(("equality scan regions: %d..%d\n", iLower, iUpper));
|
| + if( iLower>=iUpper ){
|
| + nRowEst = p->aiRowEst[0]/(SQLITE_INDEX_SAMPLES*2);
|
| + if( nRowEst<*pnRow ) *pnRow = nRowEst;
|
| }else{
|
| - *piEst = 33;
|
| + nRowEst = (iUpper-iLower)*p->aiRowEst[0]/SQLITE_INDEX_SAMPLES;
|
| + *pnRow = nRowEst;
|
| }
|
| +
|
| +whereEqualScanEst_cancel:
|
| + sqlite3ValueFree(pRhs);
|
| return rc;
|
| }
|
| +#endif /* defined(SQLITE_ENABLE_STAT2) */
|
| +
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| +/*
|
| +** Estimate the number of rows that will be returned based on
|
| +** an IN constraint where the right-hand side of the IN operator
|
| +** is a list of values. Example:
|
| +**
|
| +** WHERE x IN (1,2,3,4)
|
| +**
|
| +** Write the estimated row count into *pnRow and return SQLITE_OK.
|
| +** If unable to make an estimate, leave *pnRow unchanged and return
|
| +** non-zero.
|
| +**
|
| +** This routine can fail if it is unable to load a collating sequence
|
| +** required for string comparison, or if unable to allocate memory
|
| +** for a UTF conversion required for comparison. The error is stored
|
| +** in the pParse structure.
|
| +*/
|
| +static int whereInScanEst(
|
| + Parse *pParse, /* Parsing & code generating context */
|
| + Index *p, /* The index whose left-most column is pTerm */
|
| + ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */
|
| + double *pnRow /* Write the revised row estimate here */
|
| +){
|
| + sqlite3_value *pVal = 0; /* One value from list */
|
| + int iLower, iUpper; /* Range of histogram regions containing pRhs */
|
| + u8 aff; /* Column affinity */
|
| + int rc = SQLITE_OK; /* Subfunction return code */
|
| + double nRowEst; /* New estimate of the number of rows */
|
| + int nSpan = 0; /* Number of histogram regions spanned */
|
| + int nSingle = 0; /* Histogram regions hit by a single value */
|
| + int nNotFound = 0; /* Count of values that are not constants */
|
| + int i; /* Loop counter */
|
| + u8 aSpan[SQLITE_INDEX_SAMPLES+1]; /* Histogram regions that are spanned */
|
| + u8 aSingle[SQLITE_INDEX_SAMPLES+1]; /* Histogram regions hit once */
|
| +
|
| + assert( p->aSample!=0 );
|
| + aff = p->pTable->aCol[p->aiColumn[0]].affinity;
|
| + memset(aSpan, 0, sizeof(aSpan));
|
| + memset(aSingle, 0, sizeof(aSingle));
|
| + for(i=0; i<pList->nExpr; i++){
|
| + sqlite3ValueFree(pVal);
|
| + rc = valueFromExpr(pParse, pList->a[i].pExpr, aff, &pVal);
|
| + if( rc ) break;
|
| + if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){
|
| + nNotFound++;
|
| + continue;
|
| + }
|
| + rc = whereRangeRegion(pParse, p, pVal, 0, &iLower);
|
| + if( rc ) break;
|
| + rc = whereRangeRegion(pParse, p, pVal, 1, &iUpper);
|
| + if( rc ) break;
|
| + if( iLower>=iUpper ){
|
| + aSingle[iLower] = 1;
|
| + }else{
|
| + assert( iLower>=0 && iUpper<=SQLITE_INDEX_SAMPLES );
|
| + while( iLower<iUpper ) aSpan[iLower++] = 1;
|
| + }
|
| + }
|
| + if( rc==SQLITE_OK ){
|
| + for(i=nSpan=0; i<=SQLITE_INDEX_SAMPLES; i++){
|
| + if( aSpan[i] ){
|
| + nSpan++;
|
| + }else if( aSingle[i] ){
|
| + nSingle++;
|
| + }
|
| + }
|
| + nRowEst = (nSpan*2+nSingle)*p->aiRowEst[0]/(2*SQLITE_INDEX_SAMPLES)
|
| + + nNotFound*p->aiRowEst[1];
|
| + if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0];
|
| + *pnRow = nRowEst;
|
| + WHERETRACE(("IN row estimate: nSpan=%d, nSingle=%d, nNotFound=%d, est=%g\n",
|
| + nSpan, nSingle, nNotFound, nRowEst));
|
| + }
|
| + sqlite3ValueFree(pVal);
|
| + return rc;
|
| +}
|
| +#endif /* defined(SQLITE_ENABLE_STAT2) */
|
|
|
|
|
| /*
|
| -** Find the 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
|
| ** last parameter.
|
| **
|
| ** The lowest cost plan wins. The cost is an estimate of the amount of
|
| -** CPU and disk I/O need to process the request using the selected plan.
|
| +** CPU and disk I/O needed to process the requested result.
|
| ** Factors that influence cost include:
|
| **
|
| ** * The estimated number of rows that will be retrieved. (The
|
| @@ -2122,14 +2679,15 @@ range_est_fallback:
|
| **
|
| ** If a NOT INDEXED clause (pSrc->notIndexed!=0) was attached to the table
|
| ** in the SELECT statement, then no indexes are considered. However, the
|
| -** selected plan may still take advantage of the tables built-in rowid
|
| +** 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 that are not available */
|
| + 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 */
|
| ){
|
| @@ -2164,30 +2722,25 @@ static void bestBtreeIndex(
|
| wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE);
|
| eqTermMask = idxEqTermMask;
|
| }else{
|
| - /* There is no INDEXED BY clause. Create a fake Index object to
|
| - ** represent the primary key */
|
| - Index *pFirst; /* Any other index on the table */
|
| + /* There is no INDEXED BY clause. Create a fake Index object in local
|
| + ** variable sPk to represent the rowid primary key index. Make this
|
| + ** fake index the first in a chain of Index objects with all of the real
|
| + ** indices to follow */
|
| + Index *pFirst; /* First of real indices on the table */
|
| memset(&sPk, 0, sizeof(Index));
|
| sPk.nColumn = 1;
|
| sPk.aiColumn = &aiColumnPk;
|
| sPk.aiRowEst = aiRowEstPk;
|
| - aiRowEstPk[1] = 1;
|
| sPk.onError = OE_Replace;
|
| sPk.pTable = pSrc->pTab;
|
| + aiRowEstPk[0] = pSrc->pTab->nRowEst;
|
| + aiRowEstPk[1] = 1;
|
| pFirst = pSrc->pTab->pIndex;
|
| if( pSrc->notIndexed==0 ){
|
| + /* The real indices of the table are only considered if the
|
| + ** NOT INDEXED qualifier is omitted from the FROM clause */
|
| sPk.pNext = pFirst;
|
| }
|
| - /* The aiRowEstPk[0] is an estimate of the total number of rows in the
|
| - ** table. Get this information from the ANALYZE information if it is
|
| - ** available. If not available, assume the table 1 million rows in size.
|
| - */
|
| - if( pFirst ){
|
| - assert( pFirst->aiRowEst!=0 ); /* Allocated together with pFirst */
|
| - aiRowEstPk[0] = pFirst->aiRowEst[0];
|
| - }else{
|
| - aiRowEstPk[0] = 1000000;
|
| - }
|
| pProbe = &sPk;
|
| wsFlagMask = ~(
|
| WHERE_COLUMN_IN|WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_RANGE
|
| @@ -2202,16 +2755,19 @@ static void bestBtreeIndex(
|
| const unsigned int * const aiRowEst = pProbe->aiRowEst;
|
| double cost; /* Cost of using pProbe */
|
| double nRow; /* Estimated number of rows in result set */
|
| + double log10N; /* base-10 logarithm of nRow (inexact) */
|
| int rev; /* True to scan in reverse order */
|
| int wsFlags = 0;
|
| Bitmask used = 0;
|
|
|
| /* The following variables are populated based on the properties of
|
| - ** scan being evaluated. They are then used to determine the expected
|
| + ** index being evaluated. They are then used to determine the expected
|
| ** cost and number of rows returned.
|
| **
|
| ** nEq:
|
| ** Number of equality terms that can be implemented using the index.
|
| + ** In other words, the number of initial fields in the index that
|
| + ** are used in == or IN or NOT NULL constraints of the WHERE clause.
|
| **
|
| ** nInMul:
|
| ** The "in-multiplier". This is an estimate of how many seek operations
|
| @@ -2235,16 +2791,18 @@ static void bestBtreeIndex(
|
| **
|
| ** bInEst:
|
| ** Set to true if there was at least one "x IN (SELECT ...)" term used
|
| - ** in determining the value of nInMul.
|
| + ** in determining the value of nInMul. Note that the RHS of the
|
| + ** IN operator must be a SELECT, not a value list, for this variable
|
| + ** to be true.
|
| **
|
| - ** nBound:
|
| + ** estBound:
|
| ** An estimate on the amount of the table that must be searched. A
|
| ** value of 100 means the entire table is searched. Range constraints
|
| ** might reduce this to a value less than 100 to indicate that only
|
| ** a fraction of the table needs searching. In the absence of
|
| ** sqlite_stat2 ANALYZE data, a single inequality reduces the search
|
| - ** space to 1/3rd its original size. So an x>? constraint reduces
|
| - ** nBound to 33. Two constraints (x>? AND x<?) reduce nBound to 11.
|
| + ** space to 1/4rd its original size. So an x>? constraint reduces
|
| + ** estBound to 25. Two constraints (x>? AND x<?) reduce estBound to 6.
|
| **
|
| ** bSort:
|
| ** Boolean. True if there is an ORDER BY clause that will require an
|
| @@ -2252,27 +2810,34 @@ static void bestBtreeIndex(
|
| ** correctly order records).
|
| **
|
| ** bLookup:
|
| - ** Boolean. True if for each index entry visited a lookup on the
|
| - ** corresponding table b-tree is required. This is always false
|
| - ** for the rowid index. For other indexes, it is true unless all the
|
| - ** columns of the table used by the SELECT statement are present in
|
| - ** the index (such an index is sometimes described as a covering index).
|
| + ** Boolean. True if a table lookup is required for each index entry
|
| + ** visited. In other words, true if this is not a covering index.
|
| + ** This is always false for the rowid primary key index of a table.
|
| + ** For other indexes, it is true unless all the columns of the table
|
| + ** used by the SELECT statement are present in the index (such an
|
| + ** index is sometimes described as a covering index).
|
| ** For example, given the index on (a, b), the second of the following
|
| - ** two queries requires table b-tree lookups, but the first does not.
|
| + ** two queries requires table b-tree lookups in order to find the value
|
| + ** of column c, but the first does not because columns a and b are
|
| + ** both available in the index.
|
| **
|
| ** SELECT a, b FROM tbl WHERE a = 1;
|
| ** SELECT a, b, c FROM tbl WHERE a = 1;
|
| */
|
| - int nEq;
|
| - int bInEst = 0;
|
| - int nInMul = 1;
|
| - int nBound = 100;
|
| - int bSort = 0;
|
| - int bLookup = 0;
|
| + int nEq; /* Number of == or IN terms matching index */
|
| + int bInEst = 0; /* True if "x IN (SELECT...)" seen */
|
| + int nInMul = 1; /* Number of distinct equalities to lookup */
|
| + int estBound = 100; /* Estimated reduction in search space */
|
| + int nBound = 0; /* Number of range constraints seen */
|
| + int bSort = 0; /* True if external sort required */
|
| + int bLookup = 0; /* True if not a covering index */
|
| + WhereTerm *pTerm; /* A single term of the WHERE clause */
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| + WhereTerm *pFirstTerm = 0; /* First term matching the index */
|
| +#endif
|
|
|
| /* Determine the values of nEq and nInMul */
|
| for(nEq=0; nEq<pProbe->nColumn; nEq++){
|
| - WhereTerm *pTerm; /* A single term of the WHERE clause */
|
| int j = pProbe->aiColumn[nEq];
|
| pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
|
| if( pTerm==0 ) break;
|
| @@ -2281,29 +2846,36 @@ static void bestBtreeIndex(
|
| Expr *pExpr = pTerm->pExpr;
|
| wsFlags |= WHERE_COLUMN_IN;
|
| if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
| + /* "x IN (SELECT ...)": Assume the SELECT returns 25 rows */
|
| nInMul *= 25;
|
| bInEst = 1;
|
| - }else if( pExpr->x.pList ){
|
| - nInMul *= pExpr->x.pList->nExpr + 1;
|
| + }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
|
| + /* "x IN (value, value, ...)" */
|
| + nInMul *= pExpr->x.pList->nExpr;
|
| }
|
| }else if( pTerm->eOperator & WO_ISNULL ){
|
| wsFlags |= WHERE_COLUMN_NULL;
|
| }
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| + if( nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
|
| +#endif
|
| used |= pTerm->prereqRight;
|
| }
|
|
|
| - /* Determine the value of nBound. */
|
| - if( nEq<pProbe->nColumn ){
|
| + /* Determine the value of estBound. */
|
| + if( nEq<pProbe->nColumn && pProbe->bUnordered==0 ){
|
| int j = 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);
|
| - whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
|
| + whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound);
|
| if( pTop ){
|
| + nBound = 1;
|
| wsFlags |= WHERE_TOP_LIMIT;
|
| used |= pTop->prereqRight;
|
| }
|
| if( pBtm ){
|
| + nBound++;
|
| wsFlags |= WHERE_BTM_LIMIT;
|
| used |= pBtm->prereqRight;
|
| }
|
| @@ -2322,8 +2894,10 @@ 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( pOrderBy ){
|
| - if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0
|
| - && isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev)
|
| + if( (wsFlags & WHERE_COLUMN_IN)==0
|
| + && pProbe->bUnordered==0
|
| + && isSortingIndex(pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy,
|
| + nEq, wsFlags, &rev)
|
| ){
|
| wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY;
|
| wsFlags |= (rev ? WHERE_REVERSE : 0);
|
| @@ -2334,7 +2908,7 @@ static void bestBtreeIndex(
|
|
|
| /* If currently calculating the cost of using an index (not the IPK
|
| ** index), determine if all required column data may be obtained without
|
| - ** seeking to entries in the main table (i.e. if the index is a covering
|
| + ** using the main table (i.e. if the index is a covering
|
| ** index for this query). If it is, set the WHERE_IDX_ONLY flag in
|
| ** wsFlags. Otherwise, set the bLookup variable to true. */
|
| if( pIdx && wsFlags ){
|
| @@ -2353,10 +2927,9 @@ static void bestBtreeIndex(
|
| }
|
| }
|
|
|
| - /**** Begin adding up the cost of using this index (Needs improvements)
|
| - **
|
| - ** Estimate the number of rows of output. For an IN operator,
|
| - ** do not let the estimate exceed half the rows in the table.
|
| + /*
|
| + ** Estimate the number of rows of output. For an "x IN (SELECT...)"
|
| + ** constraint, do not let the estimate exceed half the rows in the table.
|
| */
|
| nRow = (double)(aiRowEst[nEq] * nInMul);
|
| if( bInEst && nRow*2>aiRowEst[0] ){
|
| @@ -2364,47 +2937,168 @@ static void bestBtreeIndex(
|
| nInMul = (int)(nRow / aiRowEst[nEq]);
|
| }
|
|
|
| - /* Assume constant cost to access a row and logarithmic cost to
|
| - ** do a binary search. Hence, the initial cost is the number of output
|
| - ** rows plus log2(table-size) times the number of binary searches.
|
| +#ifdef SQLITE_ENABLE_STAT2
|
| + /* If the constraint is of the form x=VALUE and histogram
|
| + ** data is available for column x, then it might be possible
|
| + ** to get a better estimate on the number of rows based on
|
| + ** VALUE and how common that value is according to the histogram.
|
| */
|
| - cost = nRow + nInMul*estLog(aiRowEst[0]);
|
| + if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 ){
|
| + if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
|
| + testcase( pFirstTerm->eOperator==WO_EQ );
|
| + testcase( pFirstTerm->eOperator==WO_ISNULL );
|
| + whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow);
|
| + }else if( pFirstTerm->eOperator==WO_IN && bInEst==0 ){
|
| + whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow);
|
| + }
|
| + }
|
| +#endif /* SQLITE_ENABLE_STAT2 */
|
|
|
| - /* Adjust the number of rows and the cost downward to reflect rows
|
| + /* Adjust the number of output rows and downward to reflect rows
|
| ** that are excluded by range constraints.
|
| */
|
| - nRow = (nRow * (double)nBound) / (double)100;
|
| - cost = (cost * (double)nBound) / (double)100;
|
| + nRow = (nRow * (double)estBound) / (double)100;
|
| + if( nRow<1 ) nRow = 1;
|
| +
|
| + /* Experiments run on real SQLite databases show that the time needed
|
| + ** to do a binary search to locate a row in a table or index is roughly
|
| + ** log10(N) times the time to move from one row to the next row within
|
| + ** a table or index. The actual times can vary, with the size of
|
| + ** records being an important factor. Both moves and searches are
|
| + ** slower with larger records, presumably because fewer records fit
|
| + ** on one page and hence more pages have to be fetched.
|
| + **
|
| + ** The ANALYZE command and the sqlite_stat1 and sqlite_stat2 tables do
|
| + ** not give us data on the relative sizes of table and index records.
|
| + ** So this computation assumes table records are about twice as big
|
| + ** as index records
|
| + */
|
| + if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ){
|
| + /* The cost of a full table scan is a number of move operations equal
|
| + ** to the number of rows in the table.
|
| + **
|
| + ** We add an additional 4x penalty to full table scans. This causes
|
| + ** the cost function to err on the side of choosing an index over
|
| + ** choosing a full scan. This 4x full-scan penalty is an arguable
|
| + ** decision and one which we expect to revisit in the future. But
|
| + ** it seems to be working well enough at the moment.
|
| + */
|
| + cost = aiRowEst[0]*4;
|
| + }else{
|
| + log10N = estLog(aiRowEst[0]);
|
| + cost = nRow;
|
| + if( pIdx ){
|
| + if( bLookup ){
|
| + /* For an index lookup followed by a table lookup:
|
| + ** nInMul index searches to find the start of each index range
|
| + ** + nRow steps through the index
|
| + ** + nRow table searches to lookup the table entry using the rowid
|
| + */
|
| + cost += (nInMul + nRow)*log10N;
|
| + }else{
|
| + /* For a covering index:
|
| + ** nInMul index searches to find the initial entry
|
| + ** + nRow steps through the index
|
| + */
|
| + cost += nInMul*log10N;
|
| + }
|
| + }else{
|
| + /* For a rowid primary key lookup:
|
| + ** nInMult table searches to find the initial entry for each range
|
| + ** + nRow steps through the table
|
| + */
|
| + cost += nInMul*log10N;
|
| + }
|
| + }
|
|
|
| - /* Add in the estimated cost of sorting the result
|
| + /* Add in the estimated cost of sorting the result. Actual experimental
|
| + ** measurements of sorting performance in SQLite show that sorting time
|
| + ** adds C*N*log10(N) to the cost, where N is the number of rows to be
|
| + ** sorted and C is a factor between 1.95 and 4.3. We will split the
|
| + ** difference and select C of 3.0.
|
| */
|
| if( bSort ){
|
| - cost += cost*estLog(cost);
|
| + cost += nRow*estLog(nRow)*3;
|
| }
|
|
|
| - /* If all information can be taken directly from the index, we avoid
|
| - ** doing table lookups. This reduces the cost by half. (Not really -
|
| - ** this needs to be fixed.)
|
| + /**** Cost of using this index has now been computed ****/
|
| +
|
| + /* If there are additional constraints on this table that cannot
|
| + ** be used with the current index, but which might lower the number
|
| + ** of output rows, adjust the nRow value accordingly. This only
|
| + ** matters if the current index is the least costly, so do not bother
|
| + ** with this step if we already know this index will not be chosen.
|
| + ** Also, never reduce the output row count below 2 using this step.
|
| + **
|
| + ** It is critical that the notValid mask be used here instead of
|
| + ** the notReady mask. When computing an "optimal" index, the notReady
|
| + ** mask will only have one bit set - the bit for the current table.
|
| + ** The notValid mask, on the other hand, always has all bits set for
|
| + ** tables that are not in outer loops. If notReady is used here instead
|
| + ** of notValid, then a optimal index that depends on inner joins loops
|
| + ** might be selected even when there exists an optimal index that has
|
| + ** no such dependency.
|
| */
|
| - if( pIdx && bLookup==0 ){
|
| - cost /= (double)2;
|
| + if( nRow>2 && cost<=pCost->rCost ){
|
| + int k; /* Loop counter */
|
| + int nSkipEq = nEq; /* Number of == constraints to skip */
|
| + int nSkipRange = nBound; /* Number of < constraints to skip */
|
| + Bitmask thisTab; /* Bitmap for pSrc */
|
| +
|
| + 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->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
|
| + if( nSkipEq ){
|
| + /* Ignore the first nEq equality matches since the index
|
| + ** has already accounted for these */
|
| + nSkipEq--;
|
| + }else{
|
| + /* Assume each additional equality match reduces the result
|
| + ** set size by a factor of 10 */
|
| + nRow /= 10;
|
| + }
|
| + }else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){
|
| + if( nSkipRange ){
|
| + /* Ignore the first nSkipRange range constraints since the index
|
| + ** has already accounted for these */
|
| + nSkipRange--;
|
| + }else{
|
| + /* Assume each additional range constraint reduces the result
|
| + ** set size by a factor of 3. Indexed range constraints reduce
|
| + ** the search space by a larger factor: 4. We make indexed range
|
| + ** more selective intentionally because of the subjective
|
| + ** observation that indexed range constraints really are more
|
| + ** selective in practice, on average. */
|
| + nRow /= 3;
|
| + }
|
| + }else if( pTerm->eOperator!=WO_NOOP ){
|
| + /* Any other expression lowers the output row count by half */
|
| + nRow /= 2;
|
| + }
|
| + }
|
| + if( nRow<2 ) nRow = 2;
|
| }
|
| - /**** Cost of using this index has now been computed ****/
|
| +
|
|
|
| WHERETRACE((
|
| - "tbl=%s idx=%s nEq=%d nInMul=%d nBound=%d bSort=%d bLookup=%d"
|
| - " wsFlags=%d (nRow=%.2f cost=%.2f)\n",
|
| + "%s(%s): nEq=%d nInMul=%d estBound=%d bSort=%d bLookup=%d wsFlags=0x%x\n"
|
| + " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f used=0x%llx\n",
|
| pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
|
| - nEq, nInMul, nBound, bSort, bLookup, wsFlags, nRow, cost
|
| + nEq, nInMul, estBound, bSort, bLookup, wsFlags,
|
| + 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 ){
|
| + if( (!pIdx || wsFlags)
|
| + && (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->plan.nRow))
|
| + ){
|
| pCost->rCost = cost;
|
| - pCost->nRow = nRow;
|
| pCost->used = used;
|
| + pCost->plan.nRow = nRow;
|
| pCost->plan.wsFlags = (wsFlags&wsFlagMask);
|
| pCost->plan.nEq = nEq;
|
| pCost->plan.u.pIdx = pIdx;
|
| @@ -2436,10 +3130,12 @@ static void bestBtreeIndex(
|
| );
|
|
|
| WHERETRACE(("best index is: %s\n",
|
| - (pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
|
| + ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
|
| + pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
|
| ));
|
|
|
| - bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
|
| + bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
|
| + bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
|
| pCost->plan.wsFlags |= eqTermMask;
|
| }
|
|
|
| @@ -2453,14 +3149,15 @@ 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 that are not available */
|
| + 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_VIRTUALTABLE
|
| if( IsVirtual(pSrc->pTab) ){
|
| sqlite3_index_info *p = 0;
|
| - bestVirtualIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost, &p);
|
| + bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p);
|
| if( p->needToFreeIdxStr ){
|
| sqlite3_free(p->idxStr);
|
| }
|
| @@ -2468,7 +3165,7 @@ static void bestIndex(
|
| }else
|
| #endif
|
| {
|
| - bestBtreeIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
|
| + bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
|
| }
|
| }
|
|
|
| @@ -2487,6 +3184,9 @@ static void bestIndex(
|
| ** in the ON clause. The term is disabled in (3) because it is not part
|
| ** of a LEFT OUTER JOIN. In (1), the term is not disabled.
|
| **
|
| +** IMPLEMENTATION-OF: R-24597-58655 No tests are done for terms that are
|
| +** completely satisfied by indices.
|
| +**
|
| ** Disabling a term causes that term to not be tested in the inner loop
|
| ** of the join. Disabling is an optimization. When terms are satisfied
|
| ** by indices, we disable them to prevent redundant tests in the inner
|
| @@ -2497,7 +3197,7 @@ static void bestIndex(
|
| */
|
| static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
| if( pTerm
|
| - && ALWAYS((pTerm->wtFlags & TERM_CODED)==0)
|
| + && (pTerm->wtFlags & TERM_CODED)==0
|
| && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
| ){
|
| pTerm->wtFlags |= TERM_CODED;
|
| @@ -2514,16 +3214,39 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
| ** Code an OP_Affinity opcode to apply the column affinity string zAff
|
| ** to the n registers starting at base.
|
| **
|
| -** Buffer zAff was allocated using sqlite3DbMalloc(). It is the
|
| -** responsibility of this function to arrange for it to be eventually
|
| -** freed using sqlite3DbFree().
|
| +** As an optimization, SQLITE_AFF_NONE entries (which are no-ops) at the
|
| +** beginning and end of zAff are ignored. If all entries in zAff are
|
| +** SQLITE_AFF_NONE, then no code gets generated.
|
| +**
|
| +** This routine makes its own copy of zAff so that the caller is free
|
| +** to modify zAff after this routine returns.
|
| */
|
| static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
|
| Vdbe *v = pParse->pVdbe;
|
| + if( zAff==0 ){
|
| + assert( pParse->db->mallocFailed );
|
| + return;
|
| + }
|
| assert( v!=0 );
|
| - sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
|
| - sqlite3VdbeChangeP4(v, -1, zAff, P4_DYNAMIC);
|
| - sqlite3ExprCacheAffinityChange(pParse, base, n);
|
| +
|
| + /* Adjust base and n to skip over SQLITE_AFF_NONE entries at the beginning
|
| + ** and end of the affinity string.
|
| + */
|
| + while( n>0 && zAff[0]==SQLITE_AFF_NONE ){
|
| + n--;
|
| + base++;
|
| + zAff++;
|
| + }
|
| + while( n>1 && zAff[n-1]==SQLITE_AFF_NONE ){
|
| + n--;
|
| + }
|
| +
|
| + /* Code the OP_Affinity opcode if there is anything left to do. */
|
| + if( n>0 ){
|
| + sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
|
| + sqlite3VdbeChangeP4(v, -1, zAff, n);
|
| + sqlite3ExprCacheAffinityChange(pParse, base, n);
|
| + }
|
| }
|
|
|
|
|
| @@ -2594,7 +3317,7 @@ static int codeEqualityTerm(
|
|
|
| /*
|
| ** Generate code that will evaluate all == and IN constraints for an
|
| -** index. The values for all constraints are left on the stack.
|
| +** index.
|
| **
|
| ** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c).
|
| ** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10
|
| @@ -2606,7 +3329,8 @@ static int codeEqualityTerm(
|
| **
|
| ** In the example above nEq==2. But this subroutine works for any value
|
| ** of nEq including 0. If nEq==0, this routine is nearly a no-op.
|
| -** The only thing it does is allocate the pLevel->iMem memory cell.
|
| +** The only thing it does is allocate the pLevel->iMem memory cell and
|
| +** compute the affinity string.
|
| **
|
| ** This routine always allocates at least one memory cell and returns
|
| ** the index of that memory cell. The code that
|
| @@ -2671,7 +3395,10 @@ static int codeAllEqualityTerms(
|
| int k = pIdx->aiColumn[j];
|
| pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx);
|
| if( NEVER(pTerm==0) ) break;
|
| - assert( (pTerm->wtFlags & TERM_CODED)==0 );
|
| + /* The following true for indices with redundant columns.
|
| + ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
| + testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
|
| + testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
| r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
|
| if( r1!=regBase+j ){
|
| if( nReg==1 ){
|
| @@ -2684,11 +3411,15 @@ static int codeAllEqualityTerms(
|
| testcase( pTerm->eOperator & WO_ISNULL );
|
| testcase( pTerm->eOperator & WO_IN );
|
| if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
|
| - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
|
| - if( zAff
|
| - && sqlite3CompareAffinity(pTerm->pExpr->pRight, zAff[j])==SQLITE_AFF_NONE
|
| - ){
|
| - zAff[j] = SQLITE_AFF_NONE;
|
| + Expr *pRight = pTerm->pExpr->pRight;
|
| + sqlite3ExprCodeIsNullJump(v, pRight, regBase+j, pLevel->addrBrk);
|
| + if( zAff ){
|
| + if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_NONE ){
|
| + zAff[j] = SQLITE_AFF_NONE;
|
| + }
|
| + if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){
|
| + zAff[j] = SQLITE_AFF_NONE;
|
| + }
|
| }
|
| }
|
| }
|
| @@ -2696,6 +3427,161 @@ static int codeAllEqualityTerms(
|
| return regBase;
|
| }
|
|
|
| +#ifndef SQLITE_OMIT_EXPLAIN
|
| +/*
|
| +** This routine is a helper for explainIndexRange() below
|
| +**
|
| +** pStr holds the text of an expression that we are building up one term
|
| +** at a time. This routine adds a new term to the end of the expression.
|
| +** Terms are separated by AND so add the "AND" text for second and subsequent
|
| +** terms only.
|
| +*/
|
| +static void explainAppendTerm(
|
| + StrAccum *pStr, /* The text expression being built */
|
| + int iTerm, /* Index of this term. First is zero */
|
| + const char *zColumn, /* Name of the column */
|
| + const char *zOp /* Name of the operator */
|
| +){
|
| + if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5);
|
| + sqlite3StrAccumAppend(pStr, zColumn, -1);
|
| + sqlite3StrAccumAppend(pStr, zOp, 1);
|
| + sqlite3StrAccumAppend(pStr, "?", 1);
|
| +}
|
| +
|
| +/*
|
| +** Argument pLevel describes a strategy for scanning table pTab. This
|
| +** function returns a pointer to a string buffer containing a description
|
| +** of the subset of table rows scanned by the strategy in the form of an
|
| +** SQL expression. Or, if all rows are scanned, NULL is returned.
|
| +**
|
| +** For example, if the query:
|
| +**
|
| +** SELECT * FROM t1 WHERE a=1 AND b>2;
|
| +**
|
| +** is run and there is an index on (a, b), then this function returns a
|
| +** string similar to:
|
| +**
|
| +** "a=? AND b>?"
|
| +**
|
| +** The returned pointer points to memory obtained from sqlite3DbMalloc().
|
| +** It is the responsibility of the caller to free the buffer when it is
|
| +** no longer required.
|
| +*/
|
| +static char *explainIndexRange(sqlite3 *db, WhereLevel *pLevel, Table *pTab){
|
| + WherePlan *pPlan = &pLevel->plan;
|
| + Index *pIndex = pPlan->u.pIdx;
|
| + int nEq = pPlan->nEq;
|
| + int i, j;
|
| + Column *aCol = pTab->aCol;
|
| + int *aiColumn = pIndex->aiColumn;
|
| + StrAccum txt;
|
| +
|
| + if( nEq==0 && (pPlan->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ){
|
| + return 0;
|
| + }
|
| + sqlite3StrAccumInit(&txt, 0, 0, SQLITE_MAX_LENGTH);
|
| + txt.db = db;
|
| + sqlite3StrAccumAppend(&txt, " (", 2);
|
| + for(i=0; i<nEq; i++){
|
| + explainAppendTerm(&txt, i, aCol[aiColumn[i]].zName, "=");
|
| + }
|
| +
|
| + j = i;
|
| + if( pPlan->wsFlags&WHERE_BTM_LIMIT ){
|
| + explainAppendTerm(&txt, i++, aCol[aiColumn[j]].zName, ">");
|
| + }
|
| + if( pPlan->wsFlags&WHERE_TOP_LIMIT ){
|
| + explainAppendTerm(&txt, i, aCol[aiColumn[j]].zName, "<");
|
| + }
|
| + sqlite3StrAccumAppend(&txt, ")", 1);
|
| + return sqlite3StrAccumFinish(&txt);
|
| +}
|
| +
|
| +/*
|
| +** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
|
| +** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single
|
| +** record is added to the output to describe the table scan strategy in
|
| +** pLevel.
|
| +*/
|
| +static void explainOneScan(
|
| + Parse *pParse, /* Parse context */
|
| + SrcList *pTabList, /* Table list this loop refers to */
|
| + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
|
| + int iLevel, /* Value for "level" column of output */
|
| + int iFrom, /* Value for "from" column of output */
|
| + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
|
| +){
|
| + if( pParse->explain==2 ){
|
| + u32 flags = pLevel->plan.wsFlags;
|
| + struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
|
| + Vdbe *v = pParse->pVdbe; /* VM being constructed */
|
| + sqlite3 *db = pParse->db; /* Database handle */
|
| + char *zMsg; /* Text to add to EQP output */
|
| + sqlite3_int64 nRow; /* Expected number of rows visited by scan */
|
| + int iId = pParse->iSelectId; /* Select id (left-most output column) */
|
| + int isSearch; /* True for a SEARCH. False for SCAN. */
|
| +
|
| + if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;
|
| +
|
| + isSearch = (pLevel->plan.nEq>0)
|
| + || (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
|
| + || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
|
| +
|
| + zMsg = sqlite3MPrintf(db, "%s", isSearch?"SEARCH":"SCAN");
|
| + if( pItem->pSelect ){
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s SUBQUERY %d", zMsg,pItem->iSelectId);
|
| + }else{
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s TABLE %s", zMsg, pItem->zName);
|
| + }
|
| +
|
| + if( pItem->zAlias ){
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
|
| + }
|
| + if( (flags & WHERE_INDEXED)!=0 ){
|
| + char *zWhere = explainIndexRange(db, pLevel, pItem->pTab);
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg,
|
| + ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""),
|
| + ((flags & WHERE_IDX_ONLY)?"COVERING ":""),
|
| + ((flags & WHERE_TEMP_INDEX)?"":" "),
|
| + ((flags & WHERE_TEMP_INDEX)?"": pLevel->plan.u.pIdx->zName),
|
| + zWhere
|
| + );
|
| + sqlite3DbFree(db, zWhere);
|
| + }else if( flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg);
|
| +
|
| + if( flags&WHERE_ROWID_EQ ){
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg);
|
| + }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>? AND rowid<?)", zMsg);
|
| + }else if( flags&WHERE_BTM_LIMIT ){
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid>?)", zMsg);
|
| + }else if( flags&WHERE_TOP_LIMIT ){
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid<?)", zMsg);
|
| + }
|
| + }
|
| +#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| + else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
|
| + sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
|
| + pVtabIdx->idxNum, pVtabIdx->idxStr);
|
| + }
|
| +#endif
|
| + if( wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ){
|
| + testcase( wctrlFlags & WHERE_ORDERBY_MIN );
|
| + nRow = 1;
|
| + }else{
|
| + nRow = (sqlite3_int64)pLevel->plan.nRow;
|
| + }
|
| + zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow);
|
| + sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
|
| + }
|
| +}
|
| +#else
|
| +# define explainOneScan(u,v,w,x,y,z)
|
| +#endif /* SQLITE_OMIT_EXPLAIN */
|
| +
|
| +
|
| /*
|
| ** Generate code for the start of the iLevel-th loop in the WHERE clause
|
| ** implementation described by pWInfo.
|
| @@ -2768,6 +3654,7 @@ static Bitmask codeOneLoopStart(
|
| const struct sqlite3_index_constraint *aConstraint =
|
| pVtabIdx->aConstraint;
|
|
|
| + sqlite3ExprCachePush(pParse);
|
| iReg = sqlite3GetTempRange(pParse, nConstraint+2);
|
| for(j=1; j<=nConstraint; j++){
|
| for(k=0; k<nConstraint; k++){
|
| @@ -2794,6 +3681,7 @@ static Bitmask codeOneLoopStart(
|
| pLevel->p1 = iCur;
|
| pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
| sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
|
| + sqlite3ExprCachePop(pParse, 1);
|
| }else
|
| #endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
| @@ -2809,6 +3697,7 @@ static Bitmask codeOneLoopStart(
|
| assert( pTerm->pExpr!=0 );
|
| assert( pTerm->leftCursor==iCur );
|
| assert( omitTable==0 );
|
| + testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
| iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
|
| addrNxt = pLevel->addrNxt;
|
| sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
|
| @@ -2849,6 +3738,7 @@ static Bitmask codeOneLoopStart(
|
| assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
|
| assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
|
|
|
| + testcase( pStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
| pX = pStart->pExpr;
|
| assert( pX!=0 );
|
| assert( pStart->leftCursor==iCur );
|
| @@ -2866,6 +3756,7 @@ static Bitmask codeOneLoopStart(
|
| pX = pEnd->pExpr;
|
| assert( pX!=0 );
|
| assert( pEnd->leftCursor==iCur );
|
| + testcase( pEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
| memEndValue = ++pParse->nMem;
|
| sqlite3ExprCode(pParse, pX->pRight, memEndValue);
|
| if( pX->op==TK_LT || pX->op==TK_GT ){
|
| @@ -2879,7 +3770,11 @@ static Bitmask codeOneLoopStart(
|
| pLevel->op = bRev ? OP_Prev : OP_Next;
|
| pLevel->p1 = iCur;
|
| pLevel->p2 = start;
|
| - pLevel->p5 = (pStart==0 && pEnd==0) ?1:0;
|
| + if( pStart==0 && pEnd==0 ){
|
| + pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
| + }else{
|
| + assert( pLevel->p5==0 );
|
| + }
|
| if( testOp!=OP_Noop ){
|
| iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
|
| sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
|
| @@ -2919,7 +3814,7 @@ static Bitmask codeOneLoopStart(
|
| ** constraints but an index is selected anyway, in order
|
| ** to force the output order to conform to an ORDER BY.
|
| */
|
| - int aStartOp[] = {
|
| + static const u8 aStartOp[] = {
|
| 0,
|
| 0,
|
| OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */
|
| @@ -2929,12 +3824,12 @@ static Bitmask codeOneLoopStart(
|
| OP_SeekGe, /* 6: (start_constraints && startEq && !bRev) */
|
| OP_SeekLe /* 7: (start_constraints && startEq && bRev) */
|
| };
|
| - int aEndOp[] = {
|
| + static const u8 aEndOp[] = {
|
| OP_Noop, /* 0: (!end_constraints) */
|
| OP_IdxGE, /* 1: (end_constraints && !bRev) */
|
| OP_IdxLT /* 2: (end_constraints && bRev) */
|
| };
|
| - int nEq = pLevel->plan.nEq;
|
| + int nEq = pLevel->plan.nEq; /* Number of == or IN terms */
|
| int isMinQuery = 0; /* If this is an optimized SELECT min(x).. */
|
| int regBase; /* Base register holding constraint values */
|
| int r1; /* Temp register */
|
| @@ -2944,11 +3839,12 @@ static Bitmask codeOneLoopStart(
|
| int endEq; /* True if range end uses ==, >= or <= */
|
| int start_constraints; /* Start of range is constrained */
|
| int nConstraint; /* Number of constraint terms */
|
| - Index *pIdx; /* The index we will be using */
|
| - int iIdxCur; /* The VDBE cursor for the index */
|
| - int nExtraReg = 0; /* Number of extra registers needed */
|
| - int op; /* Instruction opcode */
|
| - char *zAff;
|
| + Index *pIdx; /* The index we will be using */
|
| + int iIdxCur; /* The VDBE cursor for the index */
|
| + int nExtraReg = 0; /* Number of extra registers needed */
|
| + int op; /* Instruction opcode */
|
| + char *zStartAff; /* Affinity for start of range constraint */
|
| + char *zEndAff; /* Affinity for end of range constraint */
|
|
|
| pIdx = pLevel->plan.u.pIdx;
|
| iIdxCur = pLevel->iIdxCur;
|
| @@ -2989,15 +3885,16 @@ static Bitmask codeOneLoopStart(
|
| ** starting at regBase.
|
| */
|
| regBase = codeAllEqualityTerms(
|
| - pParse, pLevel, pWC, notReady, nExtraReg, &zAff
|
| + pParse, pLevel, pWC, notReady, nExtraReg, &zStartAff
|
| );
|
| + zEndAff = sqlite3DbStrDup(pParse->db, zStartAff);
|
| addrNxt = pLevel->addrNxt;
|
|
|
| /* If we are doing a reverse order scan on an ascending index, or
|
| ** a forward order scan on a descending index, interchange the
|
| ** start and end terms (pRangeStart and pRangeEnd).
|
| */
|
| - if( bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
|
| + if( nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){
|
| SWAP(WhereTerm *, pRangeEnd, pRangeStart);
|
| }
|
|
|
| @@ -3014,23 +3911,29 @@ static Bitmask codeOneLoopStart(
|
| if( pRangeStart ){
|
| Expr *pRight = pRangeStart->pExpr->pRight;
|
| sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
| - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
| - if( zAff
|
| - && sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE
|
| - ){
|
| - /* Since the comparison is to be performed with no conversions applied
|
| - ** to the operands, set the affinity to apply to pRight to
|
| - ** SQLITE_AFF_NONE. */
|
| - zAff[nConstraint] = SQLITE_AFF_NONE;
|
| + if( (pRangeStart->wtFlags & TERM_VNULL)==0 ){
|
| + sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
|
| }
|
| + if( zStartAff ){
|
| + if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){
|
| + /* Since the comparison is to be performed with no conversions
|
| + ** applied to the operands, set the affinity to apply to pRight to
|
| + ** SQLITE_AFF_NONE. */
|
| + zStartAff[nEq] = SQLITE_AFF_NONE;
|
| + }
|
| + if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
|
| + zStartAff[nEq] = SQLITE_AFF_NONE;
|
| + }
|
| + }
|
| nConstraint++;
|
| + testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
| }else if( isMinQuery ){
|
| sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
| nConstraint++;
|
| startEq = 0;
|
| start_constraints = 1;
|
| }
|
| - codeApplyAffinity(pParse, regBase, nConstraint, zAff);
|
| + codeApplyAffinity(pParse, regBase, nConstraint, zStartAff);
|
| op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
|
| assert( op!=0 );
|
| testcase( op==OP_Rewind );
|
| @@ -3039,8 +3942,7 @@ static Bitmask codeOneLoopStart(
|
| testcase( op==OP_SeekGe );
|
| testcase( op==OP_SeekLe );
|
| testcase( op==OP_SeekLt );
|
| - sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase,
|
| - SQLITE_INT_TO_PTR(nConstraint), P4_INT32);
|
| + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
|
|
|
| /* Load the value for the inequality constraint at the end of the
|
| ** range (if any).
|
| @@ -3048,21 +3950,28 @@ static Bitmask codeOneLoopStart(
|
| nConstraint = nEq;
|
| if( pRangeEnd ){
|
| Expr *pRight = pRangeEnd->pExpr->pRight;
|
| - sqlite3ExprCacheRemove(pParse, regBase+nEq);
|
| + sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
|
| sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
| - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
| - zAff = sqlite3DbStrDup(pParse->db, zAff);
|
| - if( zAff
|
| - && sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE
|
| - ){
|
| - /* Since the comparison is to be performed with no conversions applied
|
| - ** to the operands, set the affinity to apply to pRight to
|
| - ** SQLITE_AFF_NONE. */
|
| - zAff[nConstraint] = SQLITE_AFF_NONE;
|
| + if( (pRangeEnd->wtFlags & TERM_VNULL)==0 ){
|
| + sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
|
| }
|
| - codeApplyAffinity(pParse, regBase, nEq+1, zAff);
|
| + if( zEndAff ){
|
| + if( sqlite3CompareAffinity(pRight, zEndAff[nEq])==SQLITE_AFF_NONE){
|
| + /* Since the comparison is to be performed with no conversions
|
| + ** applied to the operands, set the affinity to apply to pRight to
|
| + ** SQLITE_AFF_NONE. */
|
| + zEndAff[nEq] = SQLITE_AFF_NONE;
|
| + }
|
| + if( sqlite3ExprNeedsNoAffinityChange(pRight, zEndAff[nEq]) ){
|
| + zEndAff[nEq] = SQLITE_AFF_NONE;
|
| + }
|
| + }
|
| + codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
|
| nConstraint++;
|
| + testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
| }
|
| + sqlite3DbFree(pParse->db, zStartAff);
|
| + sqlite3DbFree(pParse->db, zEndAff);
|
|
|
| /* Top of the loop body */
|
| pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
| @@ -3073,8 +3982,7 @@ static Bitmask codeOneLoopStart(
|
| testcase( op==OP_IdxGE );
|
| testcase( op==OP_IdxLT );
|
| if( op!=OP_Noop ){
|
| - sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase,
|
| - SQLITE_INT_TO_PTR(nConstraint), P4_INT32);
|
| + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
|
| sqlite3VdbeChangeP5(v, endEq!=bRev ?1:0);
|
| }
|
|
|
| @@ -3085,7 +3993,7 @@ static Bitmask codeOneLoopStart(
|
| r1 = sqlite3GetTempReg(pParse);
|
| testcase( pLevel->plan.wsFlags & WHERE_BTM_LIMIT );
|
| testcase( pLevel->plan.wsFlags & WHERE_TOP_LIMIT );
|
| - if( pLevel->plan.wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT) ){
|
| + if( (pLevel->plan.wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 ){
|
| sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
|
| sqlite3VdbeAddOp2(v, OP_IsNull, r1, addrCont);
|
| }
|
| @@ -3104,7 +4012,13 @@ static Bitmask codeOneLoopStart(
|
| /* Record the instruction used to terminate the loop. Disable
|
| ** WHERE clause terms made redundant by the index range scan.
|
| */
|
| - pLevel->op = bRev ? OP_Prev : OP_Next;
|
| + if( pLevel->plan.wsFlags & WHERE_UNIQUE ){
|
| + pLevel->op = OP_Noop;
|
| + }else if( bRev ){
|
| + pLevel->op = OP_Prev;
|
| + }else{
|
| + pLevel->op = OP_Next;
|
| + }
|
| pLevel->p1 = iIdxCur;
|
| }else
|
|
|
| @@ -3150,14 +4064,14 @@ static Bitmask codeOneLoopStart(
|
| **
|
| */
|
| WhereClause *pOrWc; /* The OR-clause broken out into subterms */
|
| - WhereTerm *pFinal; /* Final subterm within the OR-clause. */
|
| - SrcList oneTab; /* Shortened table list */
|
| + SrcList *pOrTab; /* Shortened table list or OR-clause generation */
|
|
|
| int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
|
| int regRowset = 0; /* Register for RowSet object */
|
| int regRowid = 0; /* Register holding rowid */
|
| int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
|
| int iRetInit; /* Address of regReturn init */
|
| + int untestedTerms = 0; /* Some terms not completely tested */
|
| int ii;
|
|
|
| pTerm = pLevel->plan.u.pTerm;
|
| @@ -3165,12 +4079,30 @@ static Bitmask codeOneLoopStart(
|
| assert( pTerm->eOperator==WO_OR );
|
| assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
|
| pOrWc = &pTerm->u.pOrInfo->wc;
|
| - pFinal = &pOrWc->a[pOrWc->nTerm-1];
|
| + pLevel->op = OP_Return;
|
| + pLevel->p1 = regReturn;
|
|
|
| - /* Set up a SrcList containing just the table being scanned by this loop. */
|
| - oneTab.nSrc = 1;
|
| - oneTab.nAlloc = 1;
|
| - oneTab.a[0] = *pTabItem;
|
| + /* Set up a new SrcList ni pOrTab containing the table being scanned
|
| + ** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
|
| + ** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
|
| + */
|
| + if( pWInfo->nLevel>1 ){
|
| + int nNotReady; /* The number of notReady tables */
|
| + struct SrcList_item *origSrc; /* Original list of tables */
|
| + nNotReady = pWInfo->nLevel - iLevel - 1;
|
| + pOrTab = sqlite3StackAllocRaw(pParse->db,
|
| + sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
|
| + if( pOrTab==0 ) return notReady;
|
| + pOrTab->nAlloc = (i16)(nNotReady + 1);
|
| + pOrTab->nSrc = pOrTab->nAlloc;
|
| + memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
|
| + origSrc = pWInfo->pTabList->a;
|
| + for(k=1; k<=nNotReady; k++){
|
| + memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
|
| + }
|
| + }else{
|
| + pOrTab = pWInfo->pTabList;
|
| + }
|
|
|
| /* Initialize the rowset register to contain NULL. An SQL NULL is
|
| ** equivalent to an empty rowset.
|
| @@ -3195,33 +4127,41 @@ static Bitmask codeOneLoopStart(
|
| if( pOrTerm->leftCursor==iCur || pOrTerm->eOperator==WO_AND ){
|
| WhereInfo *pSubWInfo; /* Info for single OR-term scan */
|
| /* Loop through table entries that match term pOrTerm. */
|
| - pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
|
| - WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE | WHERE_FORCE_TABLE);
|
| + pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrTerm->pExpr, 0,
|
| + WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE |
|
| + WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
|
| if( pSubWInfo ){
|
| + explainOneScan(
|
| + pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
|
| + );
|
| if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
|
| int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
|
| int r;
|
| r = sqlite3ExprCodeGetColumn(pParse, pTabItem->pTab, -1, iCur,
|
| - regRowid, 0);
|
| - sqlite3VdbeAddOp4(v, OP_RowSetTest, regRowset,
|
| - sqlite3VdbeCurrentAddr(v)+2,
|
| - r, SQLITE_INT_TO_PTR(iSet), P4_INT32);
|
| + regRowid);
|
| + sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset,
|
| + sqlite3VdbeCurrentAddr(v)+2, r, iSet);
|
| }
|
| sqlite3VdbeAddOp2(v, OP_Gosub, regReturn, iLoopBody);
|
|
|
| + /* The pSubWInfo->untestedTerms flag means that this OR term
|
| + ** contained one or more AND term from a notReady table. The
|
| + ** terms from the notReady table could not be tested and will
|
| + ** need to be tested later.
|
| + */
|
| + if( pSubWInfo->untestedTerms ) untestedTerms = 1;
|
| +
|
| /* Finish the loop through table entries that match term pOrTerm. */
|
| sqlite3WhereEnd(pSubWInfo);
|
| }
|
| }
|
| }
|
| sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
|
| - /* sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset); */
|
| sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
|
| sqlite3VdbeResolveLabel(v, iLoopBody);
|
|
|
| - pLevel->op = OP_Return;
|
| - pLevel->p1 = regReturn;
|
| - disableTerm(pLevel, pTerm);
|
| + if( pWInfo->nLevel>1 ) sqlite3StackFree(pParse->db, pOrTab);
|
| + if( !untestedTerms ) disableTerm(pLevel, pTerm);
|
| }else
|
| #endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
|
|
| @@ -3242,21 +4182,28 @@ static Bitmask codeOneLoopStart(
|
|
|
| /* Insert code to test every subexpression that can be completely
|
| ** computed using the current set of tables.
|
| + **
|
| + ** IMPLEMENTATION-OF: R-49525-50935 Terms that cannot be satisfied through
|
| + ** the use of indices become tests that are evaluated against each row of
|
| + ** the relevant input tables.
|
| */
|
| - k = 0;
|
| for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
| Expr *pE;
|
| - testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
| + testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
|
| testcase( pTerm->wtFlags & TERM_CODED );
|
| if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
| - if( (pTerm->prereqAll & notReady)!=0 ) continue;
|
| + if( (pTerm->prereqAll & notReady)!=0 ){
|
| + testcase( pWInfo->untestedTerms==0
|
| + && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
|
| + pWInfo->untestedTerms = 1;
|
| + continue;
|
| + }
|
| pE = pTerm->pExpr;
|
| assert( pE!=0 );
|
| if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
|
| continue;
|
| }
|
| sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
| - k = 1;
|
| pTerm->wtFlags |= TERM_CODED;
|
| }
|
|
|
| @@ -3269,10 +4216,13 @@ static Bitmask codeOneLoopStart(
|
| VdbeComment((v, "record LEFT JOIN hit"));
|
| sqlite3ExprCacheClear(pParse);
|
| for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
|
| - testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
| + testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
|
| testcase( pTerm->wtFlags & TERM_CODED );
|
| if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
| - if( (pTerm->prereqAll & notReady)!=0 ) continue;
|
| + if( (pTerm->prereqAll & notReady)!=0 ){
|
| + assert( pWInfo->untestedTerms );
|
| + continue;
|
| + }
|
| assert( pTerm->pExpr );
|
| sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
| pTerm->wtFlags |= TERM_CODED;
|
| @@ -3300,7 +4250,7 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */
|
| ** Free a WhereInfo structure
|
| */
|
| static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
| - if( pWInfo ){
|
| + if( ALWAYS(pWInfo) ){
|
| int i;
|
| for(i=0; i<pWInfo->nLevel; i++){
|
| sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
|
| @@ -3311,6 +4261,13 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
| }
|
| sqlite3DbFree(db, pInfo);
|
| }
|
| + if( pWInfo->a[i].plan.wsFlags & WHERE_TEMP_INDEX ){
|
| + Index *pIdx = pWInfo->a[i].plan.u.pIdx;
|
| + if( pIdx ){
|
| + sqlite3DbFree(db, pIdx->zColAff);
|
| + sqlite3DbFree(db, pIdx);
|
| + }
|
| + }
|
| }
|
| whereClauseClear(pWInfo->pWC);
|
| sqlite3DbFree(db, pWInfo);
|
| @@ -3415,6 +4372,7 @@ WhereInfo *sqlite3WhereBegin(
|
| ){
|
| int i; /* Loop counter */
|
| int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
|
| + int nTabList; /* Number of elements in pTabList */
|
| 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 */
|
| @@ -3429,11 +4387,19 @@ WhereInfo *sqlite3WhereBegin(
|
| /* The number of tables in the FROM clause is limited by the number of
|
| ** bits in a Bitmask
|
| */
|
| + testcase( pTabList->nSrc==BMS );
|
| if( pTabList->nSrc>BMS ){
|
| sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
|
| return 0;
|
| }
|
|
|
| + /* This function normally generates a nested loop for all tables in
|
| + ** pTabList. But if the WHERE_ONETABLE_ONLY flag is set, then we should
|
| + ** only generate code for the first table in pTabList and assume that
|
| + ** any cursors associated with subsequent tables are uninitialized.
|
| + */
|
| + nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc;
|
| +
|
| /* Allocate and initialize the WhereInfo structure that will become the
|
| ** return value. A single allocation is used to store the WhereInfo
|
| ** struct, the contents of WhereInfo.a[], the WhereClause structure
|
| @@ -3442,21 +4408,24 @@ WhereInfo *sqlite3WhereBegin(
|
| ** some architectures. Hence the ROUND8() below.
|
| */
|
| db = pParse->db;
|
| - nByteWInfo = ROUND8(sizeof(WhereInfo)+(pTabList->nSrc-1)*sizeof(WhereLevel));
|
| + nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
|
| pWInfo = sqlite3DbMallocZero(db,
|
| nByteWInfo +
|
| sizeof(WhereClause) +
|
| sizeof(WhereMaskSet)
|
| );
|
| if( db->mallocFailed ){
|
| + sqlite3DbFree(db, pWInfo);
|
| + pWInfo = 0;
|
| goto whereBeginError;
|
| }
|
| - pWInfo->nLevel = pTabList->nSrc;
|
| + pWInfo->nLevel = nTabList;
|
| pWInfo->pParse = pParse;
|
| pWInfo->pTabList = pTabList;
|
| pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
|
| pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
|
| pWInfo->wctrlFlags = wctrlFlags;
|
| + pWInfo->savedNQueryLoop = pParse->nQueryLoop;
|
| pMaskSet = (WhereMaskSet*)&pWC[1];
|
|
|
| /* Split the WHERE clause into separate subexpressions where each
|
| @@ -3465,12 +4434,12 @@ WhereInfo *sqlite3WhereBegin(
|
| initMaskSet(pMaskSet);
|
| whereClauseInit(pWC, pParse, pMaskSet);
|
| sqlite3ExprCodeConstants(pParse, pWhere);
|
| - whereSplit(pWC, pWhere, TK_AND);
|
| + whereSplit(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.
|
| */
|
| - if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
|
| + if( pWhere && (nTabList==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
|
| sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL);
|
| pWhere = 0;
|
| }
|
| @@ -3490,6 +4459,11 @@ WhereInfo *sqlite3WhereBegin(
|
| ** to virtual table cursors are set. This is used to selectively disable
|
| ** the OR-to-IN transformation in exprAnalyzeOrTerm(). It is not helpful
|
| ** with virtual tables.
|
| + **
|
| + ** Note that bitmasks are created for all pTabList->nSrc tables in
|
| + ** pTabList, not just the first nTabList tables. nTabList is normally
|
| + ** 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 );
|
| for(i=0; i<pTabList->nSrc; i++){
|
| @@ -3537,36 +4511,48 @@ WhereInfo *sqlite3WhereBegin(
|
| ** clause.
|
| */
|
| notReady = ~(Bitmask)0;
|
| - pTabItem = pTabList->a;
|
| - pLevel = pWInfo->a;
|
| andFlags = ~0;
|
| WHERETRACE(("*** Optimizer Start ***\n"));
|
| - for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
| + for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
|
| WhereCost bestPlan; /* Most efficient plan seen so far */
|
| Index *pIdx; /* Index for FROM table at pTabItem */
|
| int j; /* For looping over FROM tables */
|
| int bestJ = -1; /* The value of j */
|
| Bitmask m; /* Bitmask value for j or bestJ */
|
| int isOptimal; /* Iterator for optimal/non-optimal search */
|
| + int nUnconstrained; /* Number tables without INDEXED BY */
|
| + Bitmask notIndexed; /* Mask of tables that cannot use an index */
|
|
|
| memset(&bestPlan, 0, sizeof(bestPlan));
|
| bestPlan.rCost = SQLITE_BIG_DBL;
|
| + WHERETRACE(("*** Begin search for loop %d ***\n", i));
|
|
|
| /* Loop through the remaining entries in the FROM clause to find the
|
| - ** next nested loop. The FROM clause entries may be iterated through
|
| + ** next nested loop. The loop tests all FROM clause entries
|
| ** either once or twice.
|
| **
|
| - ** The first iteration, which is always performed, searches for the
|
| - ** FROM clause entry that permits the lowest-cost, "optimal" scan. In
|
| + ** The first test is always performed if there are two or more entries
|
| + ** remaining and never performed if there is only one FROM clause entry
|
| + ** to choose from. The first test looks for an "optimal" scan. In
|
| ** this context an optimal scan is one that uses the same strategy
|
| ** for the given FROM clause entry as would be selected if the entry
|
| ** were used as the innermost nested loop. In other words, a table
|
| ** is chosen such that the cost of running that table cannot be reduced
|
| - ** by waiting for other tables to run first.
|
| + ** by waiting for other tables to run first. This "optimal" test works
|
| + ** by first assuming that the FROM clause is on the inner loop and finding
|
| + ** its query plan, then checking to see if that query plan uses any
|
| + ** other FROM clause terms that are notReady. If no notReady terms are
|
| + ** used then the "optimal" query plan works.
|
| + **
|
| + ** Note that the WhereCost.nRow parameter for an optimal scan might
|
| + ** not be as small as it would be if the table really were the innermost
|
| + ** join. The nRow value can be reduced by WHERE clause constraints
|
| + ** that do not use indices. But this nRow reduction only happens if the
|
| + ** table really is the innermost join.
|
| **
|
| - ** The second iteration is only performed if no optimal scan strategies
|
| - ** were found by the first. This iteration is used to search for the
|
| - ** lowest cost scan overall.
|
| + ** The second loop iteration is only performed if no optimal scan
|
| + ** strategies were found by the first iteration. This second iteration
|
| + ** is used to search for the lowest cost scan overall.
|
| **
|
| ** Previous versions of SQLite performed only the second iteration -
|
| ** the next outermost loop was always that with the lowest overall
|
| @@ -3579,15 +4565,16 @@ WhereInfo *sqlite3WhereBegin(
|
| **
|
| ** The best strategy is to iterate through table t1 first. However it
|
| ** is not possible to determine this with a simple greedy algorithm.
|
| - ** However, since the cost of a linear scan through table t2 is the same
|
| + ** Since the cost of a linear scan through table t2 is the same
|
| ** as the cost of a linear scan through table t1, a simple greedy
|
| ** algorithm may choose to use t2 for the outer loop, which is a much
|
| ** costlier approach.
|
| */
|
| - for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
|
| - Bitmask mask = (isOptimal ? 0 : notReady);
|
| - assert( (pTabList->nSrc-iFrom)>1 || isOptimal );
|
| - for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
|
| + 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++){
|
| int doNotReorder; /* True if this table should not be reordered */
|
| WhereCost sCost; /* Cost information from best[Virtual]Index() */
|
| ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
|
| @@ -3599,23 +4586,69 @@ WhereInfo *sqlite3WhereBegin(
|
| if( j==iFrom ) iFrom++;
|
| continue;
|
| }
|
| + mask = (isOptimal ? m : notReady);
|
| pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
|
| + if( pTabItem->pIndex==0 ) nUnconstrained++;
|
|
|
| + WHERETRACE(("=== trying table %d with isOptimal=%d ===\n",
|
| + j, isOptimal));
|
| assert( pTabItem->pTab );
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| if( IsVirtual(pTabItem->pTab) ){
|
| sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
|
| - bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp);
|
| + bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
|
| + &sCost, pp);
|
| }else
|
| #endif
|
| {
|
| - bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost);
|
| + bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
|
| + &sCost);
|
| }
|
| assert( isOptimal || (sCost.used¬Ready)==0 );
|
|
|
| - if( (sCost.used¬Ready)==0
|
| - && (j==iFrom || sCost.rCost<bestPlan.rCost)
|
| + /* 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 );
|
| +
|
| + if( isOptimal && (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
|
| + notIndexed |= m;
|
| + }
|
| +
|
| + /* Conditions under which this table becomes the best so far:
|
| + **
|
| + ** (1) The table must not depend on other tables that have not
|
| + ** yet run.
|
| + **
|
| + ** (2) A full-table-scan plan cannot supercede indexed plan unless
|
| + ** the full-table-scan is an "optimal" plan as defined above.
|
| + **
|
| + ** (3) All tables have an INDEXED BY clause or this table lacks an
|
| + ** INDEXED BY clause or this table uses the specific
|
| + ** index specified by its INDEXED BY clause. This rule ensures
|
| + ** that a best-so-far is always selected even if an impossible
|
| + ** combination of INDEXED BY clauses are given. The error
|
| + ** will be detected and relayed back to the application later.
|
| + ** The NEVER() comes about because rule (2) above prevents
|
| + ** An indexable full-table-scan from reaching rule (3).
|
| + **
|
| + ** (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¬Ready)==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))
|
| ){
|
| + WHERETRACE(("=== table %d is best so far"
|
| + " with cost=%g and nRow=%g\n",
|
| + j, sCost.rCost, sCost.plan.nRow));
|
| bestPlan = sCost;
|
| bestJ = j;
|
| }
|
| @@ -3624,20 +4657,26 @@ WhereInfo *sqlite3WhereBegin(
|
| }
|
| assert( bestJ>=0 );
|
| assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) );
|
| - WHERETRACE(("*** Optimizer selects table %d for loop %d\n", bestJ,
|
| - pLevel-pWInfo->a));
|
| + WHERETRACE(("*** Optimizer selects table %d for loop %d"
|
| + " with cost=%g and nRow=%g\n",
|
| + bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow));
|
| if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){
|
| *ppOrderBy = 0;
|
| }
|
| andFlags &= bestPlan.plan.wsFlags;
|
| pLevel->plan = bestPlan.plan;
|
| - if( bestPlan.plan.wsFlags & WHERE_INDEXED ){
|
| + testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
|
| + testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
|
| + if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
|
| pLevel->iIdxCur = pParse->nTab++;
|
| }else{
|
| pLevel->iIdxCur = -1;
|
| }
|
| notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
|
| pLevel->iFrom = (u8)bestJ;
|
| + if( bestPlan.plan.nRow>=(double)1 ){
|
| + pParse->nQueryLoop *= bestPlan.plan.nRow;
|
| + }
|
|
|
| /* Check that if the table scanned by this loop iteration had an
|
| ** INDEXED BY clause attached to it, that the named index is being
|
| @@ -3684,43 +4723,20 @@ WhereInfo *sqlite3WhereBegin(
|
| ** searching those tables.
|
| */
|
| sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
|
| - for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
| + notReady = ~(Bitmask)0;
|
| + pWInfo->nRowOut = (double)1;
|
| + for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
|
| Table *pTab; /* Table to open */
|
| int iDb; /* Index of database containing table/index */
|
|
|
| -#ifndef SQLITE_OMIT_EXPLAIN
|
| - if( pParse->explain==2 ){
|
| - char *zMsg;
|
| - struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
|
| - zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName);
|
| - if( pItem->zAlias ){
|
| - zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
|
| - }
|
| - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
| - zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s",
|
| - zMsg, pLevel->plan.u.pIdx->zName);
|
| - }else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
|
| - zMsg = sqlite3MAppendf(db, zMsg, "%s VIA MULTI-INDEX UNION", zMsg);
|
| - }else if( pLevel->plan.wsFlags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
|
| - zMsg = sqlite3MAppendf(db, zMsg, "%s USING PRIMARY KEY", zMsg);
|
| - }
|
| -#ifndef SQLITE_OMIT_VIRTUALTABLE
|
| - else if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
| - sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx;
|
| - zMsg = sqlite3MAppendf(db, zMsg, "%s VIRTUAL TABLE INDEX %d:%s", zMsg,
|
| - pVtabIdx->idxNum, pVtabIdx->idxStr);
|
| - }
|
| -#endif
|
| - if( pLevel->plan.wsFlags & WHERE_ORDERBY ){
|
| - zMsg = sqlite3MAppendf(db, zMsg, "%s ORDER BY", zMsg);
|
| - }
|
| - sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC);
|
| - }
|
| -#endif /* SQLITE_OMIT_EXPLAIN */
|
| pTabItem = &pTabList->a[pLevel->iFrom];
|
| pTab = pTabItem->pTab;
|
| + pLevel->iTabCur = pTabItem->iCursor;
|
| + pWInfo->nRowOut *= pLevel->plan.nRow;
|
| iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
| - if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
| + if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
|
| + /* Do nothing */
|
| + }else
|
| #ifndef SQLITE_OMIT_VIRTUALTABLE
|
| if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
| const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
| @@ -3732,17 +4748,24 @@ WhereInfo *sqlite3WhereBegin(
|
| && (wctrlFlags & WHERE_OMIT_OPEN)==0 ){
|
| int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
|
| sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
|
| + testcase( pTab->nCol==BMS-1 );
|
| + testcase( pTab->nCol==BMS );
|
| if( !pWInfo->okOnePass && pTab->nCol<BMS ){
|
| Bitmask b = pTabItem->colUsed;
|
| int n = 0;
|
| for(; b; b=b>>1, n++){}
|
| - sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1, SQLITE_INT_TO_PTR(n), P4_INT32);
|
| + sqlite3VdbeChangeP4(v, sqlite3VdbeCurrentAddr(v)-1,
|
| + SQLITE_INT_TO_PTR(n), P4_INT32);
|
| assert( n<=pTab->nCol );
|
| }
|
| }else{
|
| sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
| }
|
| - pLevel->iTabCur = pTabItem->iCursor;
|
| +#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
| + if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
|
| + constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
|
| + }else
|
| +#endif
|
| if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
| Index *pIx = pLevel->plan.u.pIdx;
|
| KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
|
| @@ -3754,17 +4777,21 @@ WhereInfo *sqlite3WhereBegin(
|
| VdbeComment((v, "%s", pIx->zName));
|
| }
|
| sqlite3CodeVerifySchema(pParse, iDb);
|
| + notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
|
| }
|
| pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
|
| + if( db->mallocFailed ) goto whereBeginError;
|
|
|
| /* 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;
|
| - for(i=0; i<pTabList->nSrc; i++){
|
| + for(i=0; i<nTabList; i++){
|
| + pLevel = &pWInfo->a[i];
|
| + explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
|
| notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
|
| - pWInfo->iContinue = pWInfo->a[i].addrCont;
|
| + pWInfo->iContinue = pLevel->addrCont;
|
| }
|
|
|
| #ifdef SQLITE_TEST /* For testing and debugging use only */
|
| @@ -3774,7 +4801,7 @@ WhereInfo *sqlite3WhereBegin(
|
| ** the index is listed as "{}". If the primary key is used the
|
| ** index name is '*'.
|
| */
|
| - for(i=0; i<pTabList->nSrc; i++){
|
| + for(i=0; i<nTabList; i++){
|
| char *z;
|
| int n;
|
| pLevel = &pWInfo->a[i];
|
| @@ -3823,7 +4850,10 @@ WhereInfo *sqlite3WhereBegin(
|
|
|
| /* Jump here if malloc fails */
|
| whereBeginError:
|
| - whereInfoFree(db, pWInfo);
|
| + if( pWInfo ){
|
| + pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
| + whereInfoFree(db, pWInfo);
|
| + }
|
| return 0;
|
| }
|
|
|
| @@ -3842,7 +4872,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
| /* Generate loop termination code.
|
| */
|
| sqlite3ExprCacheClear(pParse);
|
| - for(i=pTabList->nSrc-1; i>=0; i--){
|
| + for(i=pWInfo->nLevel-1; i>=0; i--){
|
| pLevel = &pWInfo->a[i];
|
| sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
| if( pLevel->op!=OP_Noop ){
|
| @@ -3864,7 +4894,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
| if( pLevel->iLeftJoin ){
|
| int addr;
|
| addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin);
|
| - sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
|
| + assert( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
|
| + || (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 );
|
| + if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
|
| + sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
|
| + }
|
| if( pLevel->iIdxCur>=0 ){
|
| sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
|
| }
|
| @@ -3884,16 +4918,20 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
|
| /* Close all of the cursors that were opened by sqlite3WhereBegin.
|
| */
|
| - for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
| + assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc );
|
| + for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
| struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
| Table *pTab = pTabItem->pTab;
|
| assert( pTab!=0 );
|
| - if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
| - if( (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 ){
|
| - if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
|
| + if( (pTab->tabFlags & TF_Ephemeral)==0
|
| + && pTab->pSelect==0
|
| + && (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0
|
| + ){
|
| + int ws = pLevel->plan.wsFlags;
|
| + if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
|
| sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
| }
|
| - if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
|
| + if( (ws & WHERE_INDEXED)!=0 && (ws & WHERE_TEMP_INDEX)==0 ){
|
| sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
| }
|
| }
|
| @@ -3915,7 +4953,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
| int k, j, last;
|
| VdbeOp *pOp;
|
| Index *pIdx = pLevel->plan.u.pIdx;
|
| - int useIndexOnly = pLevel->plan.wsFlags & WHERE_IDX_ONLY;
|
|
|
| assert( pIdx!=0 );
|
| pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
|
| @@ -3930,12 +4967,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
| break;
|
| }
|
| }
|
| - assert(!useIndexOnly || j<pIdx->nColumn);
|
| + assert( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
|
| + || j<pIdx->nColumn );
|
| }else if( pOp->opcode==OP_Rowid ){
|
| pOp->p1 = pLevel->iIdxCur;
|
| pOp->opcode = OP_IdxRowid;
|
| - }else if( pOp->opcode==OP_NullRow && useIndexOnly ){
|
| - pOp->opcode = OP_Noop;
|
| }
|
| }
|
| }
|
| @@ -3943,6 +4979,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
|
| /* Final cleanup
|
| */
|
| + pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
| whereInfoFree(db, pWInfo);
|
| return;
|
| }
|
|
|