summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/where.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/where.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/where.c681
1 files changed, 586 insertions, 95 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/where.c b/ext/pdo_sqlite/sqlite/src/where.c
index d057acd0f..bdbac8112 100644
--- a/ext/pdo_sqlite/sqlite/src/where.c
+++ b/ext/pdo_sqlite/sqlite/src/where.c
@@ -83,7 +83,7 @@ struct WhereTerm {
i16 iParent; /* Disable pWC->a[iParent] when this term disabled */
i16 leftCursor; /* Cursor number of X in "X <op> <expr>" */
i16 leftColumn; /* Column number of X in "X <op> <expr>" */
- u16 operator; /* A WO_xx value describing <op> */
+ u16 eOperator; /* A WO_xx value describing <op> */
u8 flags; /* Bit flags. See below */
u8 nChild; /* Number of children that must disable us */
WhereClause *pWC; /* The clause this term is part of */
@@ -156,6 +156,7 @@ struct ExprMaskSet {
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
+#define WO_MATCH 64
/*
** Value for flags returned by bestIndex()
@@ -171,6 +172,7 @@ struct ExprMaskSet {
#define WHERE_ORDERBY 0x1000 /* Output will appear in correct order */
#define WHERE_REVERSE 0x2000 /* Scan in reverse order */
#define WHERE_UNIQUE 0x4000 /* Selects no more than one row */
+#define WHERE_VIRTUALTABLE 0x8000 /* Use virtual-table processing */
/*
** Initialize a preallocated WhereClause structure.
@@ -418,13 +420,13 @@ static WhereTerm *findTerm(
if( pTerm->leftCursor==iCur
&& (pTerm->prereqRight & notReady)==0
&& pTerm->leftColumn==iColumn
- && (pTerm->operator & op)!=0
+ && (pTerm->eOperator & op)!=0
){
if( iCur>=0 && pIdx ){
Expr *pX = pTerm->pExpr;
CollSeq *pColl;
char idxaff;
- int k;
+ int j;
Parse *pParse = pWC->pParse;
idxaff = pIdx->pTable->aCol[iColumn].affinity;
@@ -438,9 +440,9 @@ static WhereTerm *findTerm(
pColl = pParse->db->pDfltColl;
}
}
- for(k=0; k<pIdx->nColumn && pIdx->aiColumn[k]!=iColumn; k++){}
- assert( k<pIdx->nColumn );
- if( pColl!=pIdx->keyInfo.aColl[k] ) continue;
+ for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){}
+ assert( j<pIdx->nColumn );
+ if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
}
return pTerm;
}
@@ -511,7 +513,7 @@ static int isLikeOrGlob(
return 0;
}
sqlite3DequoteExpr(pRight);
- z = pRight->token.z;
+ z = (char *)pRight->token.z;
for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
if( cnt==0 || 255==(u8)z[cnt] ){
return 0;
@@ -522,6 +524,48 @@ static int isLikeOrGlob(
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Check to see if the given expression is of the form
+**
+** column MATCH expr
+**
+** If it is then return TRUE. If not, return FALSE.
+*/
+static int isMatchOfColumn(
+ Expr *pExpr /* Test this expression */
+){
+ ExprList *pList;
+
+ if( pExpr->op!=TK_FUNCTION ){
+ return 0;
+ }
+ if( pExpr->token.n!=5 ||
+ sqlite3StrNICmp((const char*)pExpr->token.z,"match",5)!=0 ){
+ return 0;
+ }
+ pList = pExpr->pList;
+ if( pList->nExpr!=2 ){
+ return 0;
+ }
+ if( pList->a[1].pExpr->op != TK_COLUMN ){
+ return 0;
+ }
+ return 1;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/*
+** If the pBase expression originated in the ON or USING clause of
+** a join, then transfer the appropriate markings over to derived.
+*/
+static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
+ pDerived->flags |= pBase->flags & EP_FromJoin;
+ pDerived->iRightJoinTable = pBase->iRightJoinTable;
+}
+
+
/*
** The input to this routine is an WhereTerm structure with only the
** "pExpr" field filled in. The job of this routine is to analyze the
@@ -547,7 +591,7 @@ static void exprAnalyze(
int nPattern;
int isComplete;
- if( sqlite3_malloc_failed ) return;
+ if( sqlite3MallocFailed() ) return;
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
if( pExpr->op==TK_IN ){
assert( pExpr->pRight==0 );
@@ -563,14 +607,14 @@ static void exprAnalyze(
pTerm->prereqAll = prereqAll;
pTerm->leftCursor = -1;
pTerm->iParent = -1;
- pTerm->operator = 0;
+ pTerm->eOperator = 0;
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable;
pTerm->leftColumn = pLeft->iColumn;
- pTerm->operator = operatorMask(pExpr->op);
+ pTerm->eOperator = operatorMask(pExpr->op);
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
@@ -595,7 +639,7 @@ static void exprAnalyze(
pNew->leftColumn = pLeft->iColumn;
pNew->prereqRight = prereqLeft;
pNew->prereqAll = prereqAll;
- pNew->operator = operatorMask(pDup->op);
+ pNew->eOperator = operatorMask(pDup->op);
}
}
@@ -623,7 +667,7 @@ static void exprAnalyze(
}
#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */
-#ifndef SQLITE_OMIT_OR_OPTIMIZATION
+#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
/* Attempt to convert OR-connected terms into an IN operator so that
** they can make use of indices. Example:
**
@@ -632,6 +676,9 @@ static void exprAnalyze(
** is converted into
**
** x IN (expr1,expr2,expr3)
+ **
+ ** This optimization must be omitted if OMIT_SUBQUERY is defined because
+ ** the compiler for the the IN operator is part of sub-queries.
*/
else if( pExpr->op==TK_OR ){
int ok;
@@ -651,7 +698,7 @@ static void exprAnalyze(
iCursor = sOr.a[j].leftCursor;
ok = iCursor>=0;
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
- if( pOrTerm->operator!=WO_EQ ){
+ if( pOrTerm->eOperator!=WO_EQ ){
goto or_not_possible;
}
if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
@@ -680,14 +727,17 @@ static void exprAnalyze(
}
pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
if( pNew ){
+ int idxNew;
+ transferJoinMarkings(pNew, pExpr);
pNew->pList = pList;
+ idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
+ exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
+ pTerm = &pWC->a[idxTerm];
+ pWC->a[idxNew].iParent = idxTerm;
+ pTerm->nChild = 1;
}else{
sqlite3ExprListDelete(pList);
}
- pTerm->pExpr = pNew;
- pTerm->flags |= TERM_DYNAMIC;
- exprAnalyze(pSrc, pMaskSet, pWC, idxTerm);
- pTerm = &pWC->a[idxTerm];
}
or_not_possible:
whereClauseClear(&sOr);
@@ -730,6 +780,41 @@ or_not_possible:
}
}
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Add a WO_MATCH auxiliary term to the constraint set if the
+ ** current expression is of the form: column MATCH expr.
+ ** This information is used by the xBestIndex methods of
+ ** virtual tables. The native query optimizer does not attempt
+ ** to do anything with MATCH functions.
+ */
+ if( isMatchOfColumn(pExpr) ){
+ int idxNew;
+ Expr *pRight, *pLeft;
+ WhereTerm *pNewTerm;
+ Bitmask prereqColumn, prereqExpr;
+
+ pRight = pExpr->pList->a[0].pExpr;
+ pLeft = pExpr->pList->a[1].pExpr;
+ prereqExpr = exprTableUsage(pMaskSet, pRight);
+ prereqColumn = exprTableUsage(pMaskSet, pLeft);
+ if( (prereqExpr & prereqColumn)==0 ){
+ Expr *pNewExpr;
+ pNewExpr = sqlite3Expr(TK_MATCH, 0, sqlite3ExprDup(pRight), 0);
+ idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
+ pNewTerm = &pWC->a[idxNew];
+ pNewTerm->prereqRight = prereqExpr;
+ pNewTerm->leftCursor = pLeft->iTable;
+ pNewTerm->leftColumn = pLeft->iColumn;
+ pNewTerm->eOperator = WO_MATCH;
+ pNewTerm->iParent = idxTerm;
+ pTerm = &pWC->a[idxTerm];
+ pTerm->nChild = 1;
+ pTerm->flags |= TERM_COPIED;
+ pNewTerm->prereqAll = pTerm->prereqAll;
+ }
+ }
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
}
@@ -755,14 +840,13 @@ or_not_possible:
static int isSortingIndex(
Parse *pParse, /* Parsing context */
Index *pIdx, /* The index we are testing */
- Table *pTab, /* The table to be sorted */
- int base, /* Cursor number for pTab */
+ 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 *pbRev /* Set to 1 if ORDER BY is DESC */
){
int i, j; /* Loop counters */
- int sortOrder = SQLITE_SO_ASC; /* Which direction we are sorting */
+ int sortOrder = 0; /* XOR of index and ORDER BY sort direction */
int nTerm; /* Number of ORDER BY terms */
struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
sqlite3 *db = pParse->db;
@@ -777,6 +861,7 @@ static int isSortingIndex(
for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
Expr *pExpr; /* The expression of the ORDER BY pTerm */
CollSeq *pColl; /* The collating sequence of pExpr */
+ int termSortOrder; /* Sort order for this term */
pExpr = pTerm->pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
@@ -786,7 +871,8 @@ static int isSortingIndex(
}
pColl = sqlite3ExprCollSeq(pParse, pExpr);
if( !pColl ) pColl = db->pDfltColl;
- if( pExpr->iColumn!=pIdx->aiColumn[i] || pColl!=pIdx->keyInfo.aColl[i] ){
+ if( pExpr->iColumn!=pIdx->aiColumn[i] ||
+ sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
/* Term j of the ORDER BY clause does not match column i of the index */
if( i<nEqCol ){
/* If an index column that is constrained by == fails to match an
@@ -800,14 +886,18 @@ static int isSortingIndex(
return 0;
}
}
+ assert( pIdx->aSortOrder!=0 );
+ assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
+ assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 );
+ termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder;
if( i>nEqCol ){
- if( pTerm->sortOrder!=sortOrder ){
+ if( termSortOrder!=sortOrder ){
/* Indices can only be used if all ORDER BY terms past the
** equality constraints are all either DESC or ASC. */
return 0;
}
}else{
- sortOrder = pTerm->sortOrder;
+ sortOrder = termSortOrder;
}
j++;
pTerm++;
@@ -817,7 +907,7 @@ static int isSortingIndex(
** are covered.
*/
if( j>=nTerm ){
- *pbRev = sortOrder==SQLITE_SO_DESC;
+ *pbRev = sortOrder!=0;
return 1;
}
return 0;
@@ -854,16 +944,257 @@ static int sortableByRowid(
** logN is a little off.
*/
static double estLog(double N){
- double logN = 1.0;
- double x = 10.0;
+ double logN = 1;
+ double x = 10;
while( N>x ){
- logN += 1.0;
+ logN += 1;
x *= 10;
}
return logN;
}
/*
+** Two routines for printing the content of an sqlite3_index_info
+** structure. Used for testing and debugging only. If neither
+** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
+** are no-ops.
+*/
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && \
+ (defined(SQLITE_TEST) || defined(SQLITE_DEBUG))
+static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
+ int i;
+ if( !sqlite3_where_trace ) return;
+ for(i=0; i<p->nConstraint; i++){
+ sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n",
+ i,
+ p->aConstraint[i].iColumn,
+ p->aConstraint[i].iTermOffset,
+ p->aConstraint[i].op,
+ p->aConstraint[i].usable);
+ }
+ for(i=0; i<p->nOrderBy; i++){
+ sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n",
+ i,
+ p->aOrderBy[i].iColumn,
+ p->aOrderBy[i].desc);
+ }
+}
+static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
+ int i;
+ if( !sqlite3_where_trace ) return;
+ for(i=0; i<p->nConstraint; i++){
+ sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n",
+ i,
+ p->aConstraintUsage[i].argvIndex,
+ p->aConstraintUsage[i].omit);
+ }
+ sqlite3DebugPrintf(" idxNum=%d\n", p->idxNum);
+ sqlite3DebugPrintf(" idxStr=%s\n", p->idxStr);
+ sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed);
+ sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost);
+}
+#else
+#define TRACE_IDX_INPUTS(A)
+#define TRACE_IDX_OUTPUTS(A)
+#endif
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Compute the best index for a virtual table.
+**
+** The best index is computed by the xBestIndex method of the virtual
+** table module. This routine is really just a wrapper that sets up
+** the sqlite3_index_info structure that is used to communicate with
+** xBestIndex.
+**
+** In a join, this routine might be called multiple times for the
+** same virtual table. The sqlite3_index_info structure is created
+** and initialized on the first invocation and reused on all subsequent
+** invocations. The sqlite3_index_info structure is also used when
+** code is generated to access the virtual table. The whereInfoDelete()
+** routine takes care of freeing the sqlite3_index_info structure after
+** everybody has finished with it.
+*/
+static double 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 */
+ ExprList *pOrderBy, /* The order by clause */
+ int orderByUsable, /* True if we can potential sort */
+ sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */
+){
+ Table *pTab = pSrc->pTab;
+ sqlite3_index_info *pIdxInfo;
+ struct sqlite3_index_constraint *pIdxCons;
+ struct sqlite3_index_orderby *pIdxOrderBy;
+ struct sqlite3_index_constraint_usage *pUsage;
+ WhereTerm *pTerm;
+ int i, j;
+ int nOrderBy;
+ int rc;
+
+ /* If the sqlite3_index_info structure has not been previously
+ ** allocated and initialized for this virtual table, then allocate
+ ** and initialize it now
+ */
+ pIdxInfo = *ppIdxInfo;
+ if( pIdxInfo==0 ){
+ WhereTerm *pTerm;
+ int nTerm;
+ TRACE(("Recomputing index info for %s...\n", pTab->zName));
+
+ /* Count the number of possible WHERE clause constraints referring
+ ** to this virtual table */
+ for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+ if( pTerm->leftCursor != pSrc->iCursor ) continue;
+ if( pTerm->eOperator==WO_IN ) continue;
+ nTerm++;
+ }
+
+ /* If the ORDER BY clause contains only columns in the current
+ ** virtual table then allocate space for the aOrderBy part of
+ ** the sqlite3_index_info structure.
+ */
+ nOrderBy = 0;
+ if( pOrderBy ){
+ for(i=0; i<pOrderBy->nExpr; i++){
+ Expr *pExpr = pOrderBy->a[i].pExpr;
+ if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
+ }
+ if( i==pOrderBy->nExpr ){
+ nOrderBy = pOrderBy->nExpr;
+ }
+ }
+
+ /* Allocate the sqlite3_index_info structure
+ */
+ pIdxInfo = sqliteMalloc( sizeof(*pIdxInfo)
+ + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
+ + sizeof(*pIdxOrderBy)*nOrderBy );
+ if( pIdxInfo==0 ){
+ sqlite3ErrorMsg(pParse, "out of memory");
+ return 0.0;
+ }
+ *ppIdxInfo = pIdxInfo;
+
+ /* Initialize the structure. The sqlite3_index_info structure contains
+ ** many fields that are declared "const" to prevent xBestIndex from
+ ** changing them. We have to do some funky casting in order to
+ ** initialize those fields.
+ */
+ pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1];
+ pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
+ pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
+ *(int*)&pIdxInfo->nConstraint = nTerm;
+ *(int*)&pIdxInfo->nOrderBy = nOrderBy;
+ *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
+ *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
+ *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
+ pUsage;
+
+ for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+ if( pTerm->leftCursor != pSrc->iCursor ) continue;
+ if( pTerm->eOperator==WO_IN ) continue;
+ pIdxCons[j].iColumn = pTerm->leftColumn;
+ pIdxCons[j].iTermOffset = i;
+ pIdxCons[j].op = pTerm->eOperator;
+ /* The direct assignment in the previous line is possible only because
+ ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
+ ** following asserts verify this fact. */
+ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
+ assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
+ assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
+ assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
+ assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
+ assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
+ assert( pTerm->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
+ j++;
+ }
+ for(i=0; i<nOrderBy; i++){
+ Expr *pExpr = pOrderBy->a[i].pExpr;
+ pIdxOrderBy[i].iColumn = pExpr->iColumn;
+ pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
+ }
+ }
+
+ /* At this point, the sqlite3_index_info structure that pIdxInfo points
+ ** to will have been initialized, either during the current invocation or
+ ** during some prior invocation. Now we just have to customize the
+ ** details of pIdxInfo for the current invocation and pass it to
+ ** xBestIndex.
+ */
+
+ /* The module name must be defined */
+ assert( pTab->azModuleArg && pTab->azModuleArg[0] );
+ if( pTab->pVtab==0 ){
+ sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
+ pTab->azModuleArg[0], pTab->zName);
+ return 0.0;
+ }
+
+ /* Set the aConstraint[].usable fields and initialize all
+ ** output variables to zero.
+ **
+ ** aConstraint[].usable is true for constraints where the right-hand
+ ** side contains only references to tables to the left of the current
+ ** table. In other words, if the constraint is of the form:
+ **
+ ** column = expr
+ **
+ ** and we are evaluating a join, then the constraint on column is
+ ** only valid if all tables referenced in expr occur to the left
+ ** of the table containing column.
+ **
+ ** The aConstraints[] array contains entries for all constraints
+ ** on the current table. That way we only have to compute it once
+ ** even though we might try to pick the best index multiple times.
+ ** For each attempt at picking an index, the order of tables in the
+ ** join might be different so we have to recompute the usable flag
+ ** each time.
+ */
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ pUsage = pIdxInfo->aConstraintUsage;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
+ j = pIdxCons->iTermOffset;
+ pTerm = &pWC->a[j];
+ pIdxCons->usable = (pTerm->prereqRight & notReady)==0;
+ }
+ memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
+ if( pIdxInfo->needToFreeIdxStr ){
+ sqlite3_free(pIdxInfo->idxStr);
+ }
+ pIdxInfo->idxStr = 0;
+ pIdxInfo->idxNum = 0;
+ pIdxInfo->needToFreeIdxStr = 0;
+ pIdxInfo->orderByConsumed = 0;
+ pIdxInfo->estimatedCost = SQLITE_BIG_DBL / 2.0;
+ nOrderBy = pIdxInfo->nOrderBy;
+ if( pIdxInfo->nOrderBy && !orderByUsable ){
+ *(int*)&pIdxInfo->nOrderBy = 0;
+ }
+
+ sqlite3SafetyOff(pParse->db);
+ TRACE(("xBestIndex for %s\n", pTab->zName));
+ TRACE_IDX_INPUTS(pIdxInfo);
+ rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
+ TRACE_IDX_OUTPUTS(pIdxInfo);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_NOMEM ){
+ sqlite3FailedMalloc();
+ }else {
+ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
+ }
+ sqlite3SafetyOn(pParse->db);
+ }else{
+ rc = sqlite3SafetyOn(pParse->db);
+ }
+ *(int*)&pIdxInfo->nOrderBy = nOrderBy;
+ return pIdxInfo->estimatedCost;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/*
** Find the best index for accessing a particular table. Return a pointer
** to the index, flags that describe how the index should be used, the
** number of equality constraints, and the "cost" for this index.
@@ -893,7 +1224,7 @@ static double bestIndex(
){
WhereTerm *pTerm;
Index *bestIdx = 0; /* Index that gives the lowest cost */
- double lowestCost = 1.0e99; /* The cost of using bestIdx */
+ double lowestCost; /* The cost of using bestIdx */
int bestFlags = 0; /* Flags associated with bestIdx */
int bestNEq = 0; /* Best value for nEq */
int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */
@@ -904,6 +1235,23 @@ static double bestIndex(
double cost; /* Cost of using pProbe */
TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
+ lowestCost = SQLITE_BIG_DBL;
+ pProbe = pSrc->pTab->pIndex;
+
+ /* If the table has no indices and there are no terms in the where
+ ** clause that refer to the ROWID, then we will never be able to do
+ ** anything other than a full table scan on this table. We might as
+ ** well put it first in the join order. That way, perhaps it can be
+ ** referenced by other tables in the join.
+ */
+ if( pProbe==0 &&
+ findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IN|WO_LT|WO_LE|WO_GT|WO_GE,0)==0 &&
+ (pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, &rev)) ){
+ *pFlags = 0;
+ *ppIndex = 0;
+ *pnEq = 0;
+ return 0.0;
+ }
/* Check for a rowid=EXPR or rowid IN (...) constraints
*/
@@ -912,7 +1260,7 @@ static double bestIndex(
Expr *pExpr;
*ppIndex = 0;
bestFlags = WHERE_ROWID_EQ;
- if( pTerm->operator & WO_EQ ){
+ if( pTerm->eOperator & WO_EQ ){
/* Rowid== is always the best pick. Look no further. Because only
** a single row is generated, output is always in sorted order */
*pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
@@ -928,7 +1276,7 @@ static double bestIndex(
/* Rowid IN (SELECT): cost is NlogN where N is the number of rows
** in the result of the inner select. We have no way to estimate
** that value so make a wild guess. */
- lowestCost = 200.0;
+ lowestCost = 200;
}
TRACE(("... rowid IN cost: %.9g\n", lowestCost));
}
@@ -936,8 +1284,7 @@ static double bestIndex(
/* Estimate the cost of a table scan. If we do not know how many
** entries are in the table, use 1 million as a guess.
*/
- pProbe = pSrc->pTab->pIndex;
- cost = pProbe ? pProbe->aiRowEst[0] : 1000000.0;
+ cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
TRACE(("... table scan base cost: %.9g\n", cost));
flags = WHERE_ROWID_RANGE;
@@ -947,11 +1294,11 @@ static double bestIndex(
if( pTerm ){
if( findTerm(pWC, iCur, -1, notReady, WO_LT|WO_LE, 0) ){
flags |= WHERE_TOP_LIMIT;
- cost *= 0.333; /* Guess that rowid<EXPR eliminates two-thirds or rows */
+ cost /= 3; /* Guess that rowid<EXPR eliminates two-thirds or rows */
}
if( findTerm(pWC, iCur, -1, notReady, WO_GT|WO_GE, 0) ){
flags |= WHERE_BTM_LIMIT;
- cost *= 0.333; /* Guess that rowid>EXPR eliminates two-thirds of rows */
+ cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
}
TRACE(("... rowid range reduces cost to %.9g\n", cost));
}else{
@@ -980,7 +1327,7 @@ static double bestIndex(
*/
for(; pProbe; pProbe=pProbe->pNext){
int i; /* Loop counter */
- double inMultiplier = 1.0;
+ double inMultiplier = 1;
TRACE(("... index %s:\n", pProbe->zName));
@@ -993,13 +1340,13 @@ static double bestIndex(
pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
if( pTerm==0 ) break;
flags |= WHERE_COLUMN_EQ;
- if( pTerm->operator & WO_IN ){
+ if( pTerm->eOperator & WO_IN ){
Expr *pExpr = pTerm->pExpr;
flags |= WHERE_COLUMN_IN;
if( pExpr->pSelect!=0 ){
- inMultiplier *= 100.0;
+ inMultiplier *= 25;
}else if( pExpr->pList!=0 ){
- inMultiplier *= pExpr->pList->nExpr + 1.0;
+ inMultiplier *= pExpr->pList->nExpr + 1;
}
}
}
@@ -1020,11 +1367,11 @@ static double bestIndex(
flags |= WHERE_COLUMN_RANGE;
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pProbe) ){
flags |= WHERE_TOP_LIMIT;
- cost *= 0.333;
+ cost /= 3;
}
if( findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pProbe) ){
flags |= WHERE_BTM_LIMIT;
- cost *= 0.333;
+ cost /= 3;
}
TRACE(("...... range reduces cost to %.9g\n", cost));
}
@@ -1034,7 +1381,7 @@ static double bestIndex(
*/
if( pOrderBy ){
if( (flags & WHERE_COLUMN_IN)==0 &&
- isSortingIndex(pParse,pProbe,pSrc->pTab,iCur,pOrderBy,nEq,&rev) ){
+ isSortingIndex(pParse,pProbe,iCur,pOrderBy,nEq,&rev) ){
if( flags==0 ){
flags = WHERE_COLUMN_RANGE;
}
@@ -1063,7 +1410,7 @@ static double bestIndex(
}
if( m==0 ){
flags |= WHERE_IDX_ONLY;
- cost *= 0.5;
+ cost /= 2;
TRACE(("...... idx-only reduces cost to %.9g\n", cost));
}
}
@@ -1134,14 +1481,24 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
** * Check the top nColumn entries on the stack. If any
** of those entries are NULL, jump immediately to brk,
** which is the loop exit, since no index entry will match
-** if any part of the key is NULL.
+** if any part of the key is NULL. Pop (nColumn+nExtra)
+** elements from the stack.
**
** * Construct a probe entry from the top nColumn entries in
-** the stack with affinities appropriate for index pIdx.
+** the stack with affinities appropriate for index pIdx.
+** Only nColumn elements are popped from the stack in this case
+** (by OP_MakeRecord).
+**
*/
-static void buildIndexProbe(Vdbe *v, int nColumn, int brk, Index *pIdx){
+static void buildIndexProbe(
+ Vdbe *v,
+ int nColumn,
+ int nExtra,
+ int brk,
+ Index *pIdx
+){
sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0);
+ sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx);
@@ -1177,17 +1534,16 @@ static void codeEqualityTerm(
sqlite3CodeSubselect(pParse, pX);
iTab = pX->iTable;
- sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
+ sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
pLevel->nIn++;
- sqlite3ReallocOrFree((void**)&pLevel->aInLoop,
- sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
+ sqliteReallocOrFree((void**)&pLevel->aInLoop,
+ sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
aIn = pLevel->aInLoop;
if( aIn ){
- aIn += pLevel->nIn*3 - 3;
- aIn[0] = OP_Next;
- aIn[1] = iTab;
- aIn[2] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+ aIn += pLevel->nIn*2 - 2;
+ aIn[0] = iTab;
+ aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
}else{
pLevel->nIn = 0;
}
@@ -1281,6 +1637,25 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */
#endif /* SQLITE_TEST */
+/*
+** Free a WhereInfo structure
+*/
+static void whereInfoFree(WhereInfo *pWInfo){
+ if( pWInfo ){
+ int i;
+ for(i=0; i<pWInfo->nLevel; i++){
+ sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
+ if( pInfo ){
+ if( pInfo->needToFreeIdxStr ){
+ sqlite3_free(pInfo->idxStr);
+ }
+ sqliteFree(pInfo);
+ }
+ }
+ sqliteFree(pWInfo);
+ }
+}
+
/*
** Generate the beginning of the loop used for WHERE clause processing.
@@ -1408,9 +1783,10 @@ WhereInfo *sqlite3WhereBegin(
** return value.
*/
pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
goto whereBeginNoMem;
}
+ pWInfo->nLevel = pTabList->nSrc;
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
@@ -1432,7 +1808,7 @@ WhereInfo *sqlite3WhereBegin(
createMask(&maskSet, pTabList->a[i].iCursor);
}
exprAnalyzeAll(pTabList, &maskSet, &wc);
- if( sqlite3_malloc_failed ){
+ if( sqlite3MallocFailed() ){
goto whereBeginNoMem;
}
@@ -1464,31 +1840,56 @@ WhereInfo *sqlite3WhereBegin(
Index *pBest = 0; /* The best index seen so far */
int bestFlags = 0; /* Flags associated with pBest */
int bestNEq = 0; /* nEq associated with pBest */
- double lowestCost = 1.0e99; /* Cost of the pBest */
- int bestJ; /* The value of j */
+ double lowestCost; /* Cost of the pBest */
+ int bestJ = 0; /* The value of j */
Bitmask m; /* Bitmask value for j or bestJ */
+ int once = 0; /* True when first table is seen */
+ sqlite3_index_info *pIndex; /* Current virtual index */
+ lowestCost = SQLITE_BIG_DBL;
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
+ int doNotReorder; /* True if this table should not be reordered */
+
+ doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
+ || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0);
+ if( once && doNotReorder ) break;
m = getMask(&maskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){
if( j==iFrom ) iFrom++;
continue;
}
- cost = bestIndex(pParse, &wc, pTabItem, notReady,
- (i==0 && ppOrderBy) ? *ppOrderBy : 0,
- &pIdx, &flags, &nEq);
+ assert( pTabItem->pTab );
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTabItem->pTab) ){
+ sqlite3_index_info **ppIdxInfo = &pWInfo->a[j].pIdxInfo;
+ cost = bestVirtualIndex(pParse, &wc, pTabItem, notReady,
+ ppOrderBy ? *ppOrderBy : 0, i==0,
+ ppIdxInfo);
+ flags = WHERE_VIRTUALTABLE;
+ pIndex = *ppIdxInfo;
+ if( pIndex && pIndex->orderByConsumed ){
+ flags = WHERE_VIRTUALTABLE | WHERE_ORDERBY;
+ }
+ pIdx = 0;
+ nEq = 0;
+ }else
+#endif
+ {
+ cost = bestIndex(pParse, &wc, pTabItem, notReady,
+ (i==0 && ppOrderBy) ? *ppOrderBy : 0,
+ &pIdx, &flags, &nEq);
+ pIndex = 0;
+ }
if( cost<lowestCost ){
+ once = 1;
lowestCost = cost;
pBest = pIdx;
bestFlags = flags;
bestNEq = nEq;
bestJ = j;
+ pLevel->pBestIdx = pIndex;
}
- if( (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
- || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0)
- ){
- break;
- }
+ if( doNotReorder ) break;
}
TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
pLevel-pWInfo->a));
@@ -1522,10 +1923,10 @@ WhereInfo *sqlite3WhereBegin(
** searching those tables.
*/
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
- pLevel = pWInfo->a;
for(i=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
- Table *pTab;
- Index *pIx;
+ Table *pTab; /* Table to open */
+ Index *pIx; /* Index used to access pTab (if any) */
+ int iDb; /* Index of database containing table/index */
int iIdxCur = pLevel->iIdxCur;
#ifndef SQLITE_OMIT_EXPLAIN
@@ -1538,27 +1939,57 @@ WhereInfo *sqlite3WhereBegin(
}
if( (pIx = pLevel->pIdx)!=0 ){
zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
+ }else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
+ zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ else if( pLevel->pBestIdx ){
+ sqlite3_index_info *pBestIdx = pLevel->pBestIdx;
+ zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %d:%s", zMsg,
+ pBestIdx->idxNum, pBestIdx->idxStr);
+ }
+#endif
+ if( pLevel->flags & WHERE_ORDERBY ){
+ zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
}
sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
}
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
- if( pTab->isTransient || pTab->pSelect ) continue;
+ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ if( pTab->isEphem || pTab->pSelect ) continue;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pLevel->pBestIdx ){
+ int iCur = pTabItem->iCursor;
+ sqlite3VdbeOp3(v, OP_VOpen, iCur, 0, (const char*)pTab->pVtab, P3_VTAB);
+ }else
+#endif
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
- sqlite3OpenTableForReading(v, pTabItem->iCursor, pTab);
+ sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead);
+ if( pTab->nCol<(sizeof(Bitmask)*8) ){
+ Bitmask b = pTabItem->colUsed;
+ int n = 0;
+ for(; b; b=b>>1, n++){}
+ sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-1, n);
+ assert( n<=pTab->nCol );
+ }
+ }else{
+ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
pLevel->iTabCur = pTabItem->iCursor;
if( (pIx = pLevel->pIdx)!=0 ){
- sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
+ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
+ assert( pIx->pSchema==pTab->pSchema );
+ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
VdbeComment((v, "# %s", pIx->zName));
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
- (char*)&pIx->keyInfo, P3_KEYINFO);
+ (char*)pKey, P3_KEYINFO_HANDOFF);
}
if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
}
- sqlite3CodeVerifySchema(pParse, pTab->iDb);
+ sqlite3CodeVerifySchema(pParse, iDb);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
@@ -1601,6 +2032,47 @@ WhereInfo *sqlite3WhereBegin(
VdbeComment((v, "# init LEFT JOIN no-match flag"));
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pLevel->pBestIdx ){
+ /* Case 0: The table is a virtual-table. Use the VFilter and VNext
+ ** to access the data.
+ */
+ int j;
+ sqlite3_index_info *pBestIdx = pLevel->pBestIdx;
+ int nConstraint = pBestIdx->nConstraint;
+ struct sqlite3_index_constraint_usage *aUsage =
+ pBestIdx->aConstraintUsage;
+ const struct sqlite3_index_constraint *aConstraint =
+ pBestIdx->aConstraint;
+
+ for(j=1; j<=nConstraint; j++){
+ int k;
+ for(k=0; k<nConstraint; k++){
+ if( aUsage[k].argvIndex==j ){
+ int iTerm = aConstraint[k].iTermOffset;
+ sqlite3ExprCode(pParse, wc.a[iTerm].pExpr->pRight);
+ break;
+ }
+ }
+ if( k==nConstraint ) break;
+ }
+ sqlite3VdbeAddOp(v, OP_Integer, j-1, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, pBestIdx->idxNum, 0);
+ sqlite3VdbeOp3(v, OP_VFilter, iCur, brk, pBestIdx->idxStr,
+ pBestIdx->needToFreeIdxStr ? P3_MPRINTF : P3_STATIC);
+ pBestIdx->needToFreeIdxStr = 0;
+ for(j=0; j<pBestIdx->nConstraint; j++){
+ if( aUsage[j].omit ){
+ int iTerm = aConstraint[j].iTermOffset;
+ disableTerm(pLevel, &wc.a[iTerm]);
+ }
+ }
+ pLevel->op = OP_VNext;
+ pLevel->p1 = iCur;
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+ }else
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
if( pLevel->flags & WHERE_ROWID_EQ ){
/* Case 1: We can directly reference a single row using an
** equality comparison against the ROWID field. Or
@@ -1667,7 +2139,7 @@ WhereInfo *sqlite3WhereBegin(
if( testOp!=OP_Noop ){
sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, 'n', brk);
+ sqlite3VdbeAddOp(v, testOp, SQLITE_AFF_NUMERIC, brk);
}
}else if( pLevel->flags & WHERE_COLUMN_RANGE ){
/* Case 3: The WHERE clause term that refers to the right-most
@@ -1683,8 +2155,11 @@ WhereInfo *sqlite3WhereBegin(
*/
int start;
int nEq = pLevel->nEq;
- int leFlag=0, geFlag=0;
+ int topEq=0; /* True if top limit uses ==. False is strictly < */
+ int btmEq=0; /* True if btm limit uses ==. False if strictly > */
+ int topOp, btmOp; /* Operators for the top and bottom search bounds */
int testOp;
+ int nNotNull; /* Number of rows of index that must be non-NULL */
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
@@ -1701,6 +2176,21 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0);
}
+ /* Figure out what comparison operators to use for top and bottom
+ ** search bounds. For an ascending index, the bottom bound is a > or >=
+ ** operator and the top bound is a < or <= operator. For a descending
+ ** index the operators are reversed.
+ */
+ nNotNull = nEq + topLimit;
+ if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){
+ topOp = WO_LT|WO_LE;
+ btmOp = WO_GT|WO_GE;
+ }else{
+ topOp = WO_GT|WO_GE;
+ btmOp = WO_LT|WO_LE;
+ SWAP(int, topLimit, btmLimit);
+ }
+
/* Generate the termination key. This is the key value that
** will end the search. There is no termination key if there
** are no equality terms and no "X<..." term.
@@ -1711,24 +2201,24 @@ WhereInfo *sqlite3WhereBegin(
if( topLimit ){
Expr *pX;
int k = pIdx->aiColumn[j];
- pTerm = findTerm(&wc, iCur, k, notReady, WO_LT|WO_LE, pIdx);
+ pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight);
- leFlag = pX->op==TK_LE;
+ topEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
testOp = OP_IdxGE;
}else{
testOp = nEq>0 ? OP_IdxGE : OP_Noop;
- leFlag = 1;
+ topEq = 1;
}
if( testOp!=OP_Noop ){
int nCol = nEq + topLimit;
pLevel->iMem = pParse->nMem++;
- buildIndexProbe(v, nCol, brk, pIdx);
+ buildIndexProbe(v, nCol, nEq, brk, pIdx);
if( bRev ){
- int op = leFlag ? OP_MoveLe : OP_MoveLt;
+ int op = topEq ? OP_MoveLe : OP_MoveLt;
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
}else{
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
@@ -1749,25 +2239,25 @@ WhereInfo *sqlite3WhereBegin(
if( btmLimit ){
Expr *pX;
int k = pIdx->aiColumn[j];
- pTerm = findTerm(&wc, iCur, k, notReady, WO_GT|WO_GE, pIdx);
+ pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight);
- geFlag = pX->op==TK_GE;
+ btmEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
}else{
- geFlag = 1;
+ btmEq = 1;
}
if( nEq>0 || btmLimit ){
int nCol = nEq + btmLimit;
- buildIndexProbe(v, nCol, brk, pIdx);
+ buildIndexProbe(v, nCol, 0, brk, pIdx);
if( bRev ){
pLevel->iMem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
testOp = OP_IdxLT;
}else{
- int op = geFlag ? OP_MoveGe : OP_MoveGt;
+ int op = btmEq ? OP_MoveGe : OP_MoveGt;
sqlite3VdbeAddOp(v, op, iIdxCur, brk);
}
}else if( bRev ){
@@ -1784,12 +2274,12 @@ WhereInfo *sqlite3WhereBegin(
if( testOp!=OP_Noop ){
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
- if( (leFlag && !bRev) || (!geFlag && bRev) ){
+ if( (topEq && !bRev) || (!btmEq && bRev) ){
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
}
}
sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq + topLimit, cont);
+ sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
if( !omitTable ){
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
@@ -1815,7 +2305,7 @@ WhereInfo *sqlite3WhereBegin(
/* Generate a single key that will be used to both start and terminate
** the search
*/
- buildIndexProbe(v, nEq, brk, pIdx);
+ buildIndexProbe(v, nEq, 0, brk, pIdx);
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
/* Generate code (1) to move to the first matching element of the table.
@@ -1946,7 +2436,7 @@ WhereInfo *sqlite3WhereBegin(
/* Jump here if malloc fails */
whereBeginNoMem:
whereClauseClear(&wc);
- sqliteFree(pWInfo);
+ whereInfoFree(pWInfo);
return 0;
}
@@ -1972,8 +2462,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
if( pLevel->nIn ){
int *a;
int j;
- for(j=pLevel->nIn, a=&pLevel->aInLoop[j*3-3]; j>0; j--, a-=3){
- sqlite3VdbeAddOp(v, a[0], a[1], a[2]);
+ for(j=pLevel->nIn, a=&pLevel->aInLoop[j*2-2]; j>0; j--, a-=2){
+ sqlite3VdbeAddOp(v, OP_Next, a[0], a[1]);
+ sqlite3VdbeJumpHere(v, a[1]-1);
}
sqliteFree(pLevel->aInLoop);
}
@@ -2000,7 +2491,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
- if( pTab->isTransient || pTab->pSelect ) continue;
+ if( pTab->isEphem || pTab->pSelect ) continue;
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0);
}
@@ -2018,14 +2509,14 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
** reference the index.
*/
if( pLevel->flags & WHERE_IDX_ONLY ){
- int i, j, last;
+ int k, j, last;
VdbeOp *pOp;
Index *pIdx = pLevel->pIdx;
assert( pIdx!=0 );
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
last = sqlite3VdbeCurrentAddr(v);
- for(i=pWInfo->iTop; i<last; i++, pOp++){
+ for(k=pWInfo->iTop; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
pOp->p1 = pLevel->iIdxCur;
@@ -2047,6 +2538,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
/* Final cleanup
*/
- sqliteFree(pWInfo);
+ whereInfoFree(pWInfo);
return;
}