summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src/where.c
diff options
context:
space:
mode:
authorScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
committerScott MacVicar <scottmac@php.net>2008-03-07 10:55:14 +0000
commit31dade5280849135b00fd1c5e53d057732a72776 (patch)
tree564b9f0f9d8cf89d7df9a9c12147ba8a5da6506f /ext/pdo_sqlite/sqlite/src/where.c
parent7abf0787ad9fd613ddde880c9bc163161d7bf4ff (diff)
downloadphp-git-31dade5280849135b00fd1c5e53d057732a72776.tar.gz
MFB: Update bundled SQLite to 3.5.6
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/where.c')
-rw-r--r--ext/pdo_sqlite/sqlite/src/where.c956
1 files changed, 628 insertions, 328 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/where.c b/ext/pdo_sqlite/sqlite/src/where.c
index bdbac8112c..b753d5edd5 100644
--- a/ext/pdo_sqlite/sqlite/src/where.c
+++ b/ext/pdo_sqlite/sqlite/src/where.c
@@ -26,23 +26,19 @@
#define BMS (sizeof(Bitmask)*8)
/*
-** Determine the number of elements in an array.
-*/
-#define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0]))
-
-/*
** Trace output macros
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
int sqlite3_where_trace = 0;
-# define TRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
+# define WHERETRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
#else
-# define TRACE(X)
+# define WHERETRACE(X)
#endif
/* Forward reference
*/
typedef struct WhereClause WhereClause;
+typedef struct ExprMaskSet ExprMaskSet;
/*
** The query generator uses an array of instances of this structure to
@@ -106,6 +102,7 @@ struct WhereTerm {
*/
struct WhereClause {
Parse *pParse; /* The parser context */
+ ExprMaskSet *pMaskSet; /* Mapping of table indices to bitmasks */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
@@ -138,7 +135,6 @@ struct WhereClause {
** numbers all get mapped into bit numbers that begin with 0 and contain
** no gaps.
*/
-typedef struct ExprMaskSet ExprMaskSet;
struct ExprMaskSet {
int n; /* Number of assigned cursor values */
int ix[sizeof(Bitmask)*8]; /* Cursor assigned to each bit */
@@ -157,30 +153,44 @@ struct ExprMaskSet {
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
#define WO_MATCH 64
+#define WO_ISNULL 128
/*
-** Value for flags returned by bestIndex()
+** Value for flags returned by bestIndex().
+**
+** The least significant byte is reserved as a mask for WO_ values above.
+** The WhereLevel.flags field is usually set to WO_IN|WO_EQ|WO_ISNULL.
+** But if the table is the right table of a left join, WhereLevel.flags
+** is set to WO_IN|WO_EQ. The WhereLevel.flags field can then be used as
+** the "op" parameter to findTerm when we are resolving equality constraints.
+** ISNULL constraints will then not be used on the right table of a left
+** join. Tickets #2177 and #2189.
*/
-#define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */
-#define WHERE_ROWID_RANGE 0x0002 /* rowid<EXPR and/or rowid>EXPR */
-#define WHERE_COLUMN_EQ 0x0010 /* x=EXPR or x IN (...) */
-#define WHERE_COLUMN_RANGE 0x0020 /* x<EXPR and/or x>EXPR */
-#define WHERE_COLUMN_IN 0x0040 /* x IN (...) */
-#define WHERE_TOP_LIMIT 0x0100 /* x<EXPR or x<=EXPR constraint */
-#define WHERE_BTM_LIMIT 0x0200 /* x>EXPR or x>=EXPR constraint */
-#define WHERE_IDX_ONLY 0x0800 /* Use index only - omit table */
-#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 */
+#define WHERE_ROWID_EQ 0x000100 /* rowid=EXPR or rowid IN (...) */
+#define WHERE_ROWID_RANGE 0x000200 /* rowid<EXPR and/or rowid>EXPR */
+#define WHERE_COLUMN_EQ 0x001000 /* x=EXPR or x IN (...) */
+#define WHERE_COLUMN_RANGE 0x002000 /* x<EXPR and/or x>EXPR */
+#define WHERE_COLUMN_IN 0x004000 /* x IN (...) */
+#define WHERE_TOP_LIMIT 0x010000 /* x<EXPR or x<=EXPR constraint */
+#define WHERE_BTM_LIMIT 0x020000 /* x>EXPR or x>=EXPR constraint */
+#define WHERE_IDX_ONLY 0x080000 /* Use index only - omit table */
+#define WHERE_ORDERBY 0x100000 /* Output will appear in correct order */
+#define WHERE_REVERSE 0x200000 /* Scan in reverse order */
+#define WHERE_UNIQUE 0x400000 /* Selects no more than one row */
+#define WHERE_VIRTUALTABLE 0x800000 /* Use virtual-table processing */
/*
** Initialize a preallocated WhereClause structure.
*/
-static void whereClauseInit(WhereClause *pWC, Parse *pParse){
+static void whereClauseInit(
+ WhereClause *pWC, /* The WhereClause to be initialized */
+ Parse *pParse, /* The parsing context */
+ ExprMaskSet *pMaskSet /* Mapping from table indices to bitmasks */
+){
pWC->pParse = pParse;
+ pWC->pMaskSet = pMaskSet;
pWC->nTerm = 0;
- pWC->nSlot = ARRAYSIZE(pWC->aStatic);
+ pWC->nSlot = ArraySize(pWC->aStatic);
pWC->a = pWC->aStatic;
}
@@ -197,7 +207,7 @@ static void whereClauseClear(WhereClause *pWC){
}
}
if( pWC->a!=pWC->aStatic ){
- sqliteFree(pWC->a);
+ sqlite3_free(pWC->a);
}
}
@@ -205,6 +215,9 @@ static void whereClauseClear(WhereClause *pWC){
** Add a new entries to the WhereClause structure. Increase the allocated
** space as necessary.
**
+** If the flags argument includes TERM_DYNAMIC, then responsibility
+** for freeing the expression p is assumed by the WhereClause object.
+**
** WARNING: This routine might reallocate the space used to store
** WhereTerms. All pointers to WhereTerms should be invalided after
** calling this routine. Such pointers may be reinitialized by referencing
@@ -215,11 +228,18 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
int idx;
if( pWC->nTerm>=pWC->nSlot ){
WhereTerm *pOld = pWC->a;
- pWC->a = sqliteMalloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
- if( pWC->a==0 ) return 0;
+ pWC->a = sqlite3_malloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
+ if( pWC->a==0 ){
+ pWC->pParse->db->mallocFailed = 1;
+ if( flags & TERM_DYNAMIC ){
+ sqlite3ExprDelete(p);
+ }
+ pWC->a = pOld;
+ return 0;
+ }
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
if( pOld!=pWC->aStatic ){
- sqliteFree(pOld);
+ sqlite3_free(pOld);
}
pWC->nSlot *= 2;
}
@@ -287,7 +307,7 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
** array will never overflow.
*/
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
- assert( pMaskSet->n < ARRAYSIZE(pMaskSet->ix) );
+ assert( pMaskSet->n < ArraySize(pMaskSet->ix) );
pMaskSet->ix[pMaskSet->n++] = iCursor;
}
@@ -331,15 +351,14 @@ static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
return mask;
}
static Bitmask exprSelectTableUsage(ExprMaskSet *pMaskSet, Select *pS){
- Bitmask mask;
- if( pS==0 ){
- mask = 0;
- }else{
- mask = exprListTableUsage(pMaskSet, pS->pEList);
+ Bitmask mask = 0;
+ while( pS ){
+ mask |= exprListTableUsage(pMaskSet, pS->pEList);
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
mask |= exprTableUsage(pMaskSet, pS->pWhere);
mask |= exprTableUsage(pMaskSet, pS->pHaving);
+ pS = pS->pPrior;
}
return mask;
}
@@ -354,7 +373,7 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE);
+ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
}
/*
@@ -365,10 +384,22 @@ static int allowedOp(int op){
/*
** Commute a comparision operator. Expressions of the form "X op Y"
** are converted into "Y op X".
+**
+** If a collation sequence is associated with either the left or right
+** side of the comparison, it remains associated with the same side after
+** the commutation. So "Y collate NOCASE op X" becomes
+** "X collate NOCASE op Y". This is because any collation sequence on
+** the left hand side of a comparison overrides any collation sequence
+** attached to the right. For the same reason the EP_ExpCollate flag
+** is not commuted.
*/
static void exprCommute(Expr *pExpr){
+ u16 expRight = (pExpr->pRight->flags & EP_ExpCollate);
+ u16 expLeft = (pExpr->pLeft->flags & EP_ExpCollate);
assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
SWAP(CollSeq*,pExpr->pRight->pColl,pExpr->pLeft->pColl);
+ pExpr->pRight->flags = (pExpr->pRight->flags & ~EP_ExpCollate) | expLeft;
+ pExpr->pLeft->flags = (pExpr->pLeft->flags & ~EP_ExpCollate) | expRight;
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
if( pExpr->op>=TK_GT ){
assert( TK_LT==TK_GT+2 );
@@ -388,9 +419,12 @@ static int operatorMask(int op){
assert( allowedOp(op) );
if( op==TK_IN ){
c = WO_IN;
+ }else if( op==TK_ISNULL ){
+ c = WO_ISNULL;
}else{
c = WO_EQ<<(op-TK_EQ);
}
+ assert( op!=TK_ISNULL || c==WO_ISNULL );
assert( op!=TK_IN || c==WO_IN );
assert( op!=TK_EQ || c==WO_EQ );
assert( op!=TK_LT || c==WO_LT );
@@ -422,7 +456,7 @@ static WhereTerm *findTerm(
&& pTerm->leftColumn==iColumn
&& (pTerm->eOperator & op)!=0
){
- if( iCur>=0 && pIdx ){
+ if( iCur>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
Expr *pX = pTerm->pExpr;
CollSeq *pColl;
char idxaff;
@@ -431,15 +465,17 @@ static WhereTerm *findTerm(
idxaff = pIdx->pTable->aCol[iColumn].affinity;
if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
- pColl = sqlite3ExprCollSeq(pParse, pX->pLeft);
+
+ /* Figure out the collation sequence required from an index for
+ ** it to be useful for optimising expression pX. Store this
+ ** value in variable pColl.
+ */
+ assert(pX->pLeft);
+ pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
if( !pColl ){
- if( pX->pRight ){
- pColl = sqlite3ExprCollSeq(pParse, pX->pRight);
- }
- if( !pColl ){
- pColl = pParse->db->pDfltColl;
- }
+ pColl = pParse->db->pDfltColl;
}
+
for(j=0; j<pIdx->nColumn && pIdx->aiColumn[j]!=iColumn; j++){}
assert( j<pIdx->nColumn );
if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
@@ -451,7 +487,7 @@ static WhereTerm *findTerm(
}
/* Forward reference */
-static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
+static void exprAnalyze(SrcList*, WhereClause*, int);
/*
** Call exprAnalyze on all terms in a WHERE clause.
@@ -460,12 +496,11 @@ static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
*/
static void exprAnalyzeAll(
SrcList *pTabList, /* the FROM clause */
- ExprMaskSet *pMaskSet, /* table masks */
WhereClause *pWC /* the WHERE clause to be analyzed */
){
int i;
for(i=pWC->nTerm-1; i>=0; i--){
- exprAnalyze(pTabList, pMaskSet, pWC, i);
+ exprAnalyze(pTabList, pWC, i);
}
}
@@ -505,16 +540,21 @@ static int isLikeOrGlob(
return 0;
}
pColl = pLeft->pColl;
+ assert( pColl!=0 || pLeft->iColumn==-1 );
if( pColl==0 ){
+ /* No collation is defined for the ROWID. Use the default. */
pColl = db->pDfltColl;
}
if( (pColl->type!=SQLITE_COLL_BINARY || noCase) &&
(pColl->type!=SQLITE_COLL_NOCASE || !noCase) ){
return 0;
}
- sqlite3DequoteExpr(pRight);
+ sqlite3DequoteExpr(db, pRight);
z = (char *)pRight->token.z;
- for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
+ cnt = 0;
+ if( z ){
+ while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; }
+ }
if( cnt==0 || 255==(u8)z[cnt] ){
return 0;
}
@@ -565,6 +605,92 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
pDerived->iRightJoinTable = pBase->iRightJoinTable;
}
+#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
+/*
+** Return TRUE if the given term of an OR clause can be converted
+** into an IN clause. The iCursor and iColumn define the left-hand
+** side of the IN clause.
+**
+** The context is that we have multiple OR-connected equality terms
+** like this:
+**
+** a=<expr1> OR a=<expr2> OR b=<expr3> OR ...
+**
+** The pOrTerm input to this routine corresponds to a single term of
+** this OR clause. In order for the term to be a condidate for
+** conversion to an IN operator, the following must be true:
+**
+** * The left-hand side of the term must be the column which
+** is identified by iCursor and iColumn.
+**
+** * If the right-hand side is also a column, then the affinities
+** of both right and left sides must be such that no type
+** conversions are required on the right. (Ticket #2249)
+**
+** If both of these conditions are true, then return true. Otherwise
+** return false.
+*/
+static int orTermIsOptCandidate(WhereTerm *pOrTerm, int iCursor, int iColumn){
+ int affLeft, affRight;
+ assert( pOrTerm->eOperator==WO_EQ );
+ if( pOrTerm->leftCursor!=iCursor ){
+ return 0;
+ }
+ if( pOrTerm->leftColumn!=iColumn ){
+ return 0;
+ }
+ affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight);
+ if( affRight==0 ){
+ return 1;
+ }
+ affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft);
+ if( affRight!=affLeft ){
+ return 0;
+ }
+ return 1;
+}
+
+/*
+** Return true if the given term of an OR clause can be ignored during
+** a check to make sure all OR terms are candidates for optimization.
+** In other words, return true if a call to the orTermIsOptCandidate()
+** above returned false but it is not necessary to disqualify the
+** optimization.
+**
+** Suppose the original OR phrase was this:
+**
+** a=4 OR a=11 OR a=b
+**
+** During analysis, the third term gets flipped around and duplicate
+** so that we are left with this:
+**
+** a=4 OR a=11 OR a=b OR b=a
+**
+** Since the last two terms are duplicates, only one of them
+** has to qualify in order for the whole phrase to qualify. When
+** this routine is called, we know that pOrTerm did not qualify.
+** This routine merely checks to see if pOrTerm has a duplicate that
+** might qualify. If there is a duplicate that has not yet been
+** disqualified, then return true. If there are no duplicates, or
+** the duplicate has also been disqualifed, return false.
+*/
+static int orTermHasOkDuplicate(WhereClause *pOr, WhereTerm *pOrTerm){
+ if( pOrTerm->flags & TERM_COPIED ){
+ /* This is the original term. The duplicate is to the left had
+ ** has not yet been analyzed and thus has not yet been disqualified. */
+ return 1;
+ }
+ if( (pOrTerm->flags & TERM_VIRTUAL)!=0
+ && (pOr->a[pOrTerm->iParent].flags & TERM_OR_OK)!=0 ){
+ /* This is a duplicate term. The original qualified so this one
+ ** does not have to. */
+ return 1;
+ }
+ /* This is either a singleton term or else it is a duplicate for
+ ** which the original did not qualify. Either way we are done for. */
+ return 0;
+}
+#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
/*
** The input to this routine is an WhereTerm structure with only the
@@ -580,23 +706,34 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
*/
static void exprAnalyze(
SrcList *pSrc, /* the FROM clause */
- ExprMaskSet *pMaskSet, /* table masks */
WhereClause *pWC, /* the WHERE clause */
int idxTerm /* Index of the term to be analyzed */
){
- WhereTerm *pTerm = &pWC->a[idxTerm];
- Expr *pExpr = pTerm->pExpr;
+ WhereTerm *pTerm;
+ ExprMaskSet *pMaskSet;
+ Expr *pExpr;
Bitmask prereqLeft;
Bitmask prereqAll;
int nPattern;
int isComplete;
+ int op;
+ Parse *pParse = pWC->pParse;
+ sqlite3 *db = pParse->db;
- if( sqlite3MallocFailed() ) return;
+ if( db->mallocFailed ){
+ return;
+ }
+ pTerm = &pWC->a[idxTerm];
+ pMaskSet = pWC->pMaskSet;
+ pExpr = pTerm->pExpr;
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
- if( pExpr->op==TK_IN ){
+ op = pExpr->op;
+ if( op==TK_IN ){
assert( pExpr->pRight==0 );
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
+ }else if( op==TK_ISNULL ){
+ pTerm->prereqRight = 0;
}else{
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
}
@@ -608,20 +745,24 @@ static void exprAnalyze(
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->eOperator = 0;
- if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
+ if( allowedOp(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->eOperator = operatorMask(pExpr->op);
+ pTerm->eOperator = operatorMask(op);
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
Expr *pDup;
if( pTerm->leftCursor>=0 ){
int idxNew;
- pDup = sqlite3ExprDup(pExpr);
+ pDup = sqlite3ExprDup(db, pExpr);
+ if( db->mallocFailed ){
+ sqlite3ExprDelete(pDup);
+ return;
+ }
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
if( idxNew==0 ) return;
pNew = &pWC->a[idxNew];
@@ -656,10 +797,10 @@ static void exprAnalyze(
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
- pNewExpr = sqlite3Expr(ops[i], sqlite3ExprDup(pExpr->pLeft),
- sqlite3ExprDup(pList->a[i].pExpr), 0);
+ pNewExpr = sqlite3Expr(db, ops[i], sqlite3ExprDup(db, pExpr->pLeft),
+ sqlite3ExprDup(db, pList->a[i].pExpr), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
+ exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
}
@@ -688,12 +829,13 @@ static void exprAnalyze(
WhereTerm *pOrTerm;
assert( (pTerm->flags & TERM_DYNAMIC)==0 );
- whereClauseInit(&sOr, pWC->pParse);
+ whereClauseInit(&sOr, pWC->pParse, pMaskSet);
whereSplit(&sOr, pExpr, TK_OR);
- exprAnalyzeAll(pSrc, pMaskSet, &sOr);
- assert( sOr.nTerm>0 );
+ exprAnalyzeAll(pSrc, &sOr);
+ assert( sOr.nTerm>=2 );
j = 0;
do{
+ assert( j<sOr.nTerm );
iColumn = sOr.a[j].leftColumn;
iCursor = sOr.a[j].leftCursor;
ok = iCursor>=0;
@@ -701,37 +843,34 @@ static void exprAnalyze(
if( pOrTerm->eOperator!=WO_EQ ){
goto or_not_possible;
}
- if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
+ if( orTermIsOptCandidate(pOrTerm, iCursor, iColumn) ){
pOrTerm->flags |= TERM_OR_OK;
- }else if( (pOrTerm->flags & TERM_COPIED)!=0 ||
- ((pOrTerm->flags & TERM_VIRTUAL)!=0 &&
- (sOr.a[pOrTerm->iParent].flags & TERM_OR_OK)!=0) ){
+ }else if( orTermHasOkDuplicate(&sOr, pOrTerm) ){
pOrTerm->flags &= ~TERM_OR_OK;
}else{
ok = 0;
}
}
- }while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<sOr.nTerm );
+ }while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<2 );
if( ok ){
ExprList *pList = 0;
Expr *pNew, *pDup;
+ Expr *pLeft = 0;
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue;
- pDup = sqlite3ExprDup(pOrTerm->pExpr->pRight);
- pList = sqlite3ExprListAppend(pList, pDup, 0);
- }
- pDup = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( pDup ){
- pDup->iTable = iCursor;
- pDup->iColumn = iColumn;
+ pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight);
+ pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup, 0);
+ pLeft = pOrTerm->pExpr->pLeft;
}
- pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
+ assert( pLeft!=0 );
+ pDup = sqlite3ExprDup(db, pLeft);
+ pNew = sqlite3Expr(db, 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);
+ exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
pTerm->nChild = 1;
@@ -748,7 +887,7 @@ or_not_possible:
/* Add constraints to reduce the search space on a LIKE or GLOB
** operator.
*/
- if( isLikeOrGlob(pWC->pParse->db, pExpr, &nPattern, &isComplete) ){
+ if( isLikeOrGlob(db, pExpr, &nPattern, &isComplete) ){
Expr *pLeft, *pRight;
Expr *pStr1, *pStr2;
Expr *pNewExpr1, *pNewExpr2;
@@ -756,22 +895,23 @@ or_not_possible:
pLeft = pExpr->pList->a[1].pExpr;
pRight = pExpr->pList->a[0].pExpr;
- pStr1 = sqlite3Expr(TK_STRING, 0, 0, 0);
+ pStr1 = sqlite3PExpr(pParse, TK_STRING, 0, 0, 0);
if( pStr1 ){
- sqlite3TokenCopy(&pStr1->token, &pRight->token);
+ sqlite3TokenCopy(db, &pStr1->token, &pRight->token);
pStr1->token.n = nPattern;
+ pStr1->flags = EP_Dequoted;
}
- pStr2 = sqlite3ExprDup(pStr1);
- if( pStr2 ){
+ pStr2 = sqlite3ExprDup(db, pStr1);
+ if( !db->mallocFailed ){
assert( pStr2->token.dyn );
++*(u8*)&pStr2->token.z[nPattern-1];
}
- pNewExpr1 = sqlite3Expr(TK_GE, sqlite3ExprDup(pLeft), pStr1, 0);
+ pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft), pStr1, 0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew1);
- pNewExpr2 = sqlite3Expr(TK_LT, sqlite3ExprDup(pLeft), pStr2, 0);
+ exprAnalyze(pSrc, pWC, idxNew1);
+ pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft), pStr2, 0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew2);
+ exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
pWC->a[idxNew1].iParent = idxTerm;
@@ -800,7 +940,7 @@ or_not_possible:
prereqColumn = exprTableUsage(pMaskSet, pLeft);
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
- pNewExpr = sqlite3Expr(TK_MATCH, 0, sqlite3ExprDup(pRight), 0);
+ pNewExpr = sqlite3Expr(db, TK_MATCH, 0, sqlite3ExprDup(db, pRight), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
pNewTerm = &pWC->a[idxNew];
pNewTerm->prereqRight = prereqExpr;
@@ -817,6 +957,25 @@ or_not_possible:
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}
+/*
+** Return TRUE if any of the expressions in pList->a[iFirst...] contain
+** a reference to any table other than the iBase table.
+*/
+static int referencesOtherTables(
+ ExprList *pList, /* Search expressions in ths list */
+ ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
+ int iFirst, /* Be searching with the iFirst-th expression */
+ int iBase /* Ignore references to this table */
+){
+ Bitmask allowed = ~getMask(pMaskSet, iBase);
+ while( iFirst<pList->nExpr ){
+ if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
** This routine decides if pIdx can be used to satisfy the ORDER BY
@@ -839,6 +998,7 @@ or_not_possible:
*/
static int isSortingIndex(
Parse *pParse, /* Parsing context */
+ ExprMaskSet *pMaskSet, /* Mapping from table indices to bitmaps */
Index *pIdx, /* The index we are testing */
int base, /* Cursor number for the table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
@@ -857,22 +1017,43 @@ static int isSortingIndex(
/* Match terms of the ORDER BY clause against columns of
** the index.
+ **
+ ** Note that indices have pIdx->nColumn regular columns plus
+ ** one additional column containing the rowid. The rowid column
+ ** of the index is also allowed to match against the ORDER BY
+ ** clause.
*/
- for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
+ 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 */
+ int iColumn; /* The i-th column of the index. -1 for rowid */
+ int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
+ const char *zColl; /* Name of the collating sequence for i-th index term */
pExpr = pTerm->pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
/* Can not use an index sort on anything that is not a column in the
** left-most table of the FROM clause */
- return 0;
+ break;
}
pColl = sqlite3ExprCollSeq(pParse, pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- if( pExpr->iColumn!=pIdx->aiColumn[i] ||
- sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
+ if( !pColl ){
+ pColl = db->pDfltColl;
+ }
+ if( i<pIdx->nColumn ){
+ iColumn = pIdx->aiColumn[i];
+ if( iColumn==pIdx->pTable->iPKey ){
+ iColumn = -1;
+ }
+ iSortOrder = pIdx->aSortOrder[i];
+ zColl = pIdx->azColl[i];
+ }else{
+ iColumn = -1;
+ iSortOrder = 0;
+ zColl = pColl->zName;
+ }
+ if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
/* 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
@@ -888,8 +1069,8 @@ static int isSortingIndex(
}
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;
+ assert( iSortOrder==0 || iSortOrder==1 );
+ termSortOrder = iSortOrder ^ pTerm->sortOrder;
if( i>nEqCol ){
if( termSortOrder!=sortOrder ){
/* Indices can only be used if all ORDER BY terms past the
@@ -901,13 +1082,29 @@ static int isSortingIndex(
}
j++;
pTerm++;
+ if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
+ /* If the indexed column is the primary key and everything matches
+ ** so far and none of the ORDER BY terms to the right reference other
+ ** tables in the join, then we are assured that the index can be used
+ ** to sort because the primary key is unique and so none of the other
+ ** columns will make any difference
+ */
+ j = nTerm;
+ }
}
- /* The index can be used for sorting if all terms of the ORDER BY clause
- ** are covered.
- */
+ *pbRev = sortOrder!=0;
if( j>=nTerm ){
- *pbRev = sortOrder!=0;
+ /* All terms of the ORDER BY clause are covered by this index so
+ ** this index can be used for sorting. */
+ return 1;
+ }
+ if( pIdx->onError!=OE_None && i==pIdx->nColumn
+ && !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. */
return 1;
}
return 0;
@@ -921,6 +1118,7 @@ static int isSortingIndex(
static int sortableByRowid(
int base, /* Cursor number for table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
+ ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
int *pbRev /* Set to 1 if ORDER BY is DESC */
){
Expr *p;
@@ -928,8 +1126,8 @@ static int sortableByRowid(
assert( pOrderBy!=0 );
assert( pOrderBy->nExpr>0 );
p = pOrderBy->a[0].pExpr;
- if( pOrderBy->nExpr==1 && p->op==TK_COLUMN && p->iTable==base
- && p->iColumn==-1 ){
+ if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1
+ && !referencesOtherTables(pOrderBy, pMaskSet, 1, base) ){
*pbRev = pOrderBy->a[0].sortOrder;
return 1;
}
@@ -959,8 +1157,7 @@ static double estLog(double N){
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
** are no-ops.
*/
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && \
- (defined(SQLITE_TEST) || defined(SQLITE_DEBUG))
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_DEBUG)
static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
int i;
if( !sqlite3_where_trace ) return;
@@ -1042,13 +1239,14 @@ static double bestVirtualIndex(
if( pIdxInfo==0 ){
WhereTerm *pTerm;
int nTerm;
- TRACE(("Recomputing index info for %s...\n", pTab->zName));
+ WHERETRACE(("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;
+ if( pTerm->eOperator==WO_ISNULL ) continue;
nTerm++;
}
@@ -1069,7 +1267,7 @@ static double bestVirtualIndex(
/* Allocate the sqlite3_index_info structure
*/
- pIdxInfo = sqliteMalloc( sizeof(*pIdxInfo)
+ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
+ sizeof(*pIdxOrderBy)*nOrderBy );
if( pIdxInfo==0 ){
@@ -1096,6 +1294,7 @@ static double bestVirtualIndex(
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->eOperator==WO_IN ) continue;
+ if( pTerm->eOperator==WO_ISNULL ) continue;
pIdxCons[j].iColumn = pTerm->leftColumn;
pIdxCons[j].iTermOffset = i;
pIdxCons[j].op = pTerm->eOperator;
@@ -1125,13 +1324,19 @@ static double bestVirtualIndex(
** xBestIndex.
*/
- /* The module name must be defined */
+ /* The module name must be defined. Also, by this point there must
+ ** be a pointer to an sqlite3_vtab structure. Otherwise
+ ** sqlite3ViewGetColumnNames() would have picked up the error.
+ */
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
+ assert( pTab->pVtab );
+#if 0
if( pTab->pVtab==0 ){
sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
pTab->azModuleArg[0], pTab->zName);
return 0.0;
}
+#endif
/* Set the aConstraint[].usable fields and initialize all
** output variables to zero.
@@ -1174,22 +1379,21 @@ static double bestVirtualIndex(
*(int*)&pIdxInfo->nOrderBy = 0;
}
- sqlite3SafetyOff(pParse->db);
- TRACE(("xBestIndex for %s\n", pTab->zName));
+ (void)sqlite3SafetyOff(pParse->db);
+ WHERETRACE(("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();
+ pParse->db->mallocFailed = 1;
}else {
sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc));
}
- sqlite3SafetyOn(pParse->db);
- }else{
- rc = sqlite3SafetyOn(pParse->db);
}
+ (void)sqlite3SafetyOn(pParse->db);
*(int*)&pIdxInfo->nOrderBy = nOrderBy;
+
return pIdxInfo->estimatedCost;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -1232,9 +1436,10 @@ static double bestIndex(
int rev; /* True to scan in reverse order */
int flags; /* Flags associated with pProbe */
int nEq; /* Number of == or IN constraints */
+ int eqTermMask; /* Mask of valid equality operators */
double cost; /* Cost of using pProbe */
- TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
+ WHERETRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
lowestCost = SQLITE_BIG_DBL;
pProbe = pSrc->pTab->pIndex;
@@ -1246,7 +1451,7 @@ static double bestIndex(
*/
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)) ){
+ (pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev)) ){
*pFlags = 0;
*ppIndex = 0;
*pnEq = 0;
@@ -1265,7 +1470,7 @@ static double bestIndex(
** a single row is generated, output is always in sorted order */
*pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
*pnEq = 1;
- TRACE(("... best is rowid\n"));
+ WHERETRACE(("... best is rowid\n"));
return 0.0;
}else if( (pExpr = pTerm->pExpr)->pList!=0 ){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
@@ -1278,14 +1483,14 @@ static double bestIndex(
** that value so make a wild guess. */
lowestCost = 200;
}
- TRACE(("... rowid IN cost: %.9g\n", lowestCost));
+ WHERETRACE(("... rowid IN cost: %.9g\n", lowestCost));
}
/* 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.
*/
cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
- TRACE(("... table scan base cost: %.9g\n", cost));
+ WHERETRACE(("... table scan base cost: %.9g\n", cost));
flags = WHERE_ROWID_RANGE;
/* Check for constraints on a range of rowids in a table scan.
@@ -1300,7 +1505,7 @@ static double bestIndex(
flags |= WHERE_BTM_LIMIT;
cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
}
- TRACE(("... rowid range reduces cost to %.9g\n", cost));
+ WHERETRACE(("... rowid range reduces cost to %.9g\n", cost));
}else{
flags = 0;
}
@@ -1308,14 +1513,14 @@ static double bestIndex(
/* If the table scan does not satisfy the ORDER BY clause, increase
** the cost by NlogN to cover the expense of sorting. */
if( pOrderBy ){
- if( sortableByRowid(iCur, pOrderBy, &rev) ){
+ if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){
flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE;
if( rev ){
flags |= WHERE_REVERSE;
}
}else{
cost += cost*estLog(cost);
- TRACE(("... sorting increases cost to %.9g\n", cost));
+ WHERETRACE(("... sorting increases cost to %.9g\n", cost));
}
}
if( cost<lowestCost ){
@@ -1323,13 +1528,24 @@ static double bestIndex(
bestFlags = flags;
}
+ /* If the pSrc table is the right table of a LEFT JOIN then we may not
+ ** use an index to satisfy IS NULL constraints on that table. This is
+ ** because columns might end up being NULL if the table does not match -
+ ** a circumstance which the index cannot help us discover. Ticket #2177.
+ */
+ if( (pSrc->jointype & JT_LEFT)!=0 ){
+ eqTermMask = WO_EQ|WO_IN;
+ }else{
+ eqTermMask = WO_EQ|WO_IN|WO_ISNULL;
+ }
+
/* Look at each index.
*/
for(; pProbe; pProbe=pProbe->pNext){
int i; /* Loop counter */
double inMultiplier = 1;
- TRACE(("... index %s:\n", pProbe->zName));
+ WHERETRACE(("... index %s:\n", pProbe->zName));
/* Count the number of columns in the index that are satisfied
** by x=EXPR constraints or x IN (...) constraints.
@@ -1337,7 +1553,7 @@ static double bestIndex(
flags = 0;
for(i=0; i<pProbe->nColumn; i++){
int j = pProbe->aiColumn[i];
- pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
+ pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pProbe);
if( pTerm==0 ) break;
flags |= WHERE_COLUMN_EQ;
if( pTerm->eOperator & WO_IN ){
@@ -1356,7 +1572,7 @@ static double bestIndex(
&& nEq==pProbe->nColumn ){
flags |= WHERE_UNIQUE;
}
- TRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n", nEq, inMultiplier, cost));
+ WHERETRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n",nEq,inMultiplier,cost));
/* Look for range constraints
*/
@@ -1373,7 +1589,7 @@ static double bestIndex(
flags |= WHERE_BTM_LIMIT;
cost /= 3;
}
- TRACE(("...... range reduces cost to %.9g\n", cost));
+ WHERETRACE(("...... range reduces cost to %.9g\n", cost));
}
}
@@ -1381,7 +1597,7 @@ static double bestIndex(
*/
if( pOrderBy ){
if( (flags & WHERE_COLUMN_IN)==0 &&
- isSortingIndex(pParse,pProbe,iCur,pOrderBy,nEq,&rev) ){
+ isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev) ){
if( flags==0 ){
flags = WHERE_COLUMN_RANGE;
}
@@ -1391,7 +1607,7 @@ static double bestIndex(
}
}else{
cost += cost*estLog(cost);
- TRACE(("...... orderby increases cost to %.9g\n", cost));
+ WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
}
}
@@ -1411,16 +1627,15 @@ static double bestIndex(
if( m==0 ){
flags |= WHERE_IDX_ONLY;
cost /= 2;
- TRACE(("...... idx-only reduces cost to %.9g\n", cost));
+ WHERETRACE(("...... idx-only reduces cost to %.9g\n", cost));
}
}
/* If this index has achieved the lowest cost so far, then use it.
*/
- if( cost < lowestCost ){
+ if( flags && cost < lowestCost ){
bestIdx = pProbe;
lowestCost = cost;
- assert( flags!=0 );
bestFlags = flags;
bestNEq = nEq;
}
@@ -1429,9 +1644,9 @@ static double bestIndex(
/* Report the best result
*/
*ppIndex = bestIdx;
- TRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
+ WHERETRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq));
- *pFlags = bestFlags;
+ *pFlags = bestFlags | eqTermMask;
*pnEq = bestNEq;
return lowestCost;
}
@@ -1476,31 +1691,23 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
}
/*
-** Generate code that builds a probe for an index. Details:
-**
-** * 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. 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.
-** Only nColumn elements are popped from the stack in this case
-** (by OP_MakeRecord).
+** Generate code that builds a probe for an index.
**
+** There should be nColumn values on the stack. The index
+** to be probed is pIdx. Pop the values from the stack and
+** replace them all with a single record that is the index
+** problem.
*/
static void buildIndexProbe(
- Vdbe *v,
- int nColumn,
- int nExtra,
- int brk,
- Index *pIdx
+ Vdbe *v, /* Generate code into this VM */
+ int nColumn, /* The number of columns to check for NULL */
+ Index *pIdx, /* Index that we will be searching */
+ int regSrc, /* Take values from this register */
+ int regDest /* Write the result into this register */
){
- sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
- sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
+ assert( regSrc>0 );
+ assert( regDest>0 );
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regSrc, nColumn, regDest);
sqlite3IndexAffinityStr(v, pIdx);
}
@@ -1510,7 +1717,7 @@ static void buildIndexProbe(
** term can be either X=expr or X IN (...). pTerm is the term to be
** coded.
**
-** The current value for the constraint is left on the top of the stack.
+** The current value for the constraint is left in register iReg.
**
** For a constraint of the form X=expr, the expression is evaluated and its
** result is left on the stack. For constraints of the form X IN (...)
@@ -1519,31 +1726,44 @@ static void buildIndexProbe(
static void codeEqualityTerm(
Parse *pParse, /* The parsing context */
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
- int brk, /* Jump here to abandon the loop */
- WhereLevel *pLevel /* When level of the FROM clause we are working on */
+ WhereLevel *pLevel, /* When level of the FROM clause we are working on */
+ int iReg /* Leave results in this register */
){
Expr *pX = pTerm->pExpr;
- if( pX->op!=TK_IN ){
- assert( pX->op==TK_EQ );
- sqlite3ExprCode(pParse, pX->pRight);
+ Vdbe *v = pParse->pVdbe;
+
+ assert( iReg>0 && iReg<=pParse->nMem );
+ if( pX->op==TK_EQ ){
+ sqlite3ExprCode(pParse, pX->pRight, iReg);
+ }else if( pX->op==TK_ISNULL ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
+ int eType;
int iTab;
- int *aIn;
- Vdbe *v = pParse->pVdbe;
+ struct InLoop *pIn;
- sqlite3CodeSubselect(pParse, pX);
+ assert( pX->op==TK_IN );
+ eType = sqlite3FindInIndex(pParse, pX, 1);
iTab = pX->iTable;
- sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
- VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
+ sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
+ VdbeComment((v, "%.*s", pX->span.n, pX->span.z));
+ if( pLevel->nIn==0 ){
+ pLevel->nxt = sqlite3VdbeMakeLabel(v);
+ }
pLevel->nIn++;
- sqliteReallocOrFree((void**)&pLevel->aInLoop,
- sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
- aIn = pLevel->aInLoop;
- if( aIn ){
- aIn += pLevel->nIn*2 - 2;
- aIn[0] = iTab;
- aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+ pLevel->aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->aInLoop,
+ sizeof(pLevel->aInLoop[0])*pLevel->nIn);
+ pIn = pLevel->aInLoop;
+ if( pIn ){
+ pIn += pLevel->nIn - 1;
+ pIn->iCur = iTab;
+ if( eType==IN_INDEX_ROWID ){
+ pIn->topAddr = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
+ }else{
+ pIn->topAddr = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
+ }
+ sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
}else{
pLevel->nIn = 0;
}
@@ -1575,53 +1795,44 @@ static void codeEqualityTerm(
** this routine allocates an additional nEq memory cells for internal
** use.
*/
-static void codeAllEqualityTerms(
+static int codeAllEqualityTerms(
Parse *pParse, /* Parsing context */
WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
WhereClause *pWC, /* The WHERE clause */
Bitmask notReady, /* Which parts of FROM have not yet been coded */
- int brk /* Jump here to end the loop */
+ int nExtraReg /* Number of extra registers to allocate */
){
int nEq = pLevel->nEq; /* The number of == or IN constraints to code */
- int termsInMem = 0; /* If true, store value in mem[] cells */
Vdbe *v = pParse->pVdbe; /* The virtual machine under construction */
Index *pIdx = pLevel->pIdx; /* The index being used for this loop */
int iCur = pLevel->iTabCur; /* The cursor of the table */
WhereTerm *pTerm; /* A single constraint term */
int j; /* Loop counter */
+ int regBase; /* Base register */
/* Figure out how many memory cells we will need then allocate them.
** We always need at least one used to store the loop terminator
** value. If there are IN operators we'll need one for each == or
** IN constraint.
*/
- pLevel->iMem = pParse->nMem++;
- if( pLevel->flags & WHERE_COLUMN_IN ){
- pParse->nMem += pLevel->nEq;
- termsInMem = 1;
- }
+ pLevel->iMem = pParse->nMem + 1;
+ regBase = pParse->nMem + 2;
+ pParse->nMem += pLevel->nEq + 2 + nExtraReg;
/* Evaluate the equality constraints
*/
- for(j=0; j<pIdx->nColumn; j++){
+ assert( pIdx->nColumn>=nEq );
+ for(j=0; j<nEq; j++){
int k = pIdx->aiColumn[j];
- pTerm = findTerm(pWC, iCur, k, notReady, WO_EQ|WO_IN, pIdx);
+ pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
if( pTerm==0 ) break;
assert( (pTerm->flags & TERM_CODED)==0 );
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
- if( termsInMem ){
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1);
- }
- }
- assert( j==nEq );
-
- /* Make sure all the constraint values are on the top of the stack
- */
- if( termsInMem ){
- for(j=0; j<nEq; j++){
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem+j+1, 0);
+ codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
+ if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk);
}
}
+ return regBase;
}
#if defined(SQLITE_TEST)
@@ -1646,13 +1857,11 @@ static void whereInfoFree(WhereInfo *pWInfo){
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);
+ assert( pInfo->needToFreeIdxStr==0 );
+ sqlite3_free(pInfo);
}
}
- sqliteFree(pWInfo);
+ sqlite3_free(pWInfo);
}
}
@@ -1749,7 +1958,8 @@ WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
- ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
+ ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
+ u8 obflag /* One of ORDERBY_MIN, ORDERBY_MAX or ORDERBY_NORMAL */
){
int i; /* Loop counter */
WhereInfo *pWInfo; /* Will become the return value of this function */
@@ -1763,6 +1973,8 @@ WhereInfo *sqlite3WhereBegin(
WhereLevel *pLevel; /* A single level in the pWInfo list */
int iFrom; /* First unused FROM clause element */
int andFlags; /* AND-ed combination of all wc.a[].flags */
+ sqlite3 *db; /* Database connection */
+ ExprList *pOrderBy = 0;
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
@@ -1772,18 +1984,24 @@ WhereInfo *sqlite3WhereBegin(
return 0;
}
+ if( ppOrderBy ){
+ pOrderBy = *ppOrderBy;
+ }
+
/* Split the WHERE clause into separate subexpressions where each
** subexpression is separated by an AND operator.
*/
initMaskSet(&maskSet);
- whereClauseInit(&wc, pParse);
+ whereClauseInit(&wc, pParse, &maskSet);
whereSplit(&wc, pWhere, TK_AND);
/* Allocate and initialize the WhereInfo structure that will become the
** return value.
*/
- pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
- if( sqlite3MallocFailed() ){
+ db = pParse->db;
+ pWInfo = sqlite3DbMallocZero(db,
+ sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
+ if( db->mallocFailed ){
goto whereBeginNoMem;
}
pWInfo->nLevel = pTabList->nSrc;
@@ -1794,8 +2012,8 @@ WhereInfo *sqlite3WhereBegin(
/* 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 || sqlite3ExprIsConstant(pWhere)) ){
- sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
+ if( pWhere && (pTabList->nSrc==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){
+ sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pWhere = 0;
}
@@ -1807,8 +2025,8 @@ WhereInfo *sqlite3WhereBegin(
for(i=0; i<pTabList->nSrc; i++){
createMask(&maskSet, pTabList->a[i].iCursor);
}
- exprAnalyzeAll(pTabList, &maskSet, &wc);
- if( sqlite3MallocFailed() ){
+ exprAnalyzeAll(pTabList, &wc);
+ if( db->mallocFailed ){
goto whereBeginNoMem;
}
@@ -1830,7 +2048,7 @@ WhereInfo *sqlite3WhereBegin(
pTabItem = pTabList->a;
pLevel = pWInfo->a;
andFlags = ~0;
- TRACE(("*** Optimizer Start ***\n"));
+ WHERETRACE(("*** Optimizer Start ***\n"));
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
Index *pIdx; /* Index for FROM table at pTabItem */
int flags; /* Flags asssociated with pIdx */
@@ -1850,8 +2068,7 @@ WhereInfo *sqlite3WhereBegin(
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);
+ doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
if( once && doNotReorder ) break;
m = getMask(&maskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){
@@ -1872,6 +2089,14 @@ WhereInfo *sqlite3WhereBegin(
}
pIdx = 0;
nEq = 0;
+ if( (SQLITE_BIG_DBL/2.0)<cost ){
+ /* 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 and
+ ** pLevel->pBestIdx never set.
+ */
+ cost = (SQLITE_BIG_DBL/2.0);
+ }
}else
#endif
{
@@ -1891,7 +2116,7 @@ WhereInfo *sqlite3WhereBegin(
}
if( doNotReorder ) break;
}
- TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
+ WHERETRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
pLevel-pWInfo->a));
if( (bestFlags & WHERE_ORDERBY)!=0 ){
*ppOrderBy = 0;
@@ -1910,7 +2135,7 @@ WhereInfo *sqlite3WhereBegin(
notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = bestJ;
}
- TRACE(("*** Optimizer Finished ***\n"));
+ WHERETRACE(("*** Optimizer Finished ***\n"));
/* If the total query only selects a single row, then the ORDER BY
** clause is irrelevant.
@@ -1933,26 +2158,26 @@ WhereInfo *sqlite3WhereBegin(
if( pParse->explain==2 ){
char *zMsg;
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
- zMsg = sqlite3MPrintf("TABLE %s", pItem->zName);
+ zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName);
if( pItem->zAlias ){
- zMsg = sqlite3MPrintf("%z AS %s", zMsg, pItem->zAlias);
+ zMsg = sqlite3MPrintf(db, "%z AS %s", zMsg, pItem->zAlias);
}
if( (pIx = pLevel->pIdx)!=0 ){
- zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
+ zMsg = sqlite3MPrintf(db, "%z WITH INDEX %s", zMsg, pIx->zName);
}else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
- zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
+ zMsg = sqlite3MPrintf(db, "%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,
+ zMsg = sqlite3MPrintf(db, "%z VIRTUAL TABLE INDEX %d:%s", zMsg,
pBestIdx->idxNum, pBestIdx->idxStr);
}
#endif
if( pLevel->flags & WHERE_ORDERBY ){
- zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
+ zMsg = sqlite3MPrintf(db, "%z ORDER BY", zMsg);
}
- sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC);
}
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
@@ -1962,7 +2187,8 @@ WhereInfo *sqlite3WhereBegin(
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pLevel->pBestIdx ){
int iCur = pTabItem->iCursor;
- sqlite3VdbeOp3(v, OP_VOpen, iCur, 0, (const char*)pTab->pVtab, P3_VTAB);
+ sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0,
+ (const char*)pTab->pVtab, P4_VTAB);
}else
#endif
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
@@ -1981,13 +2207,10 @@ WhereInfo *sqlite3WhereBegin(
if( (pIx = pLevel->pIdx)!=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*)pKey, P3_KEYINFO_HANDOFF);
- }
- if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
- sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
+ sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIx->tnum, iDb,
+ (char*)pKey, P4_KEYINFO_HANDOFF);
+ VdbeComment((v, "%s", pIx->zName));
+ sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
}
sqlite3CodeVerifySchema(pParse, iDb);
}
@@ -2002,6 +2225,7 @@ WhereInfo *sqlite3WhereBegin(
int j;
int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */
Index *pIdx; /* The index we will be using */
+ int nxt; /* Where to jump to continue with the next IN case */
int iIdxCur; /* The VDBE cursor for the index */
int omitTable; /* True if we use the index only */
int bRev; /* True if we need to scan in reverse order */
@@ -2017,19 +2241,23 @@ WhereInfo *sqlite3WhereBegin(
** for the current loop. Jump to brk to break out of a loop.
** Jump to cont to go immediately to the next iteration of the
** loop.
+ **
+ ** When there is an IN operator, we also have a "nxt" label that
+ ** means to continue with the next IN value combination. When
+ ** there are no IN operators in the constraints, the "nxt" label
+ ** is the same as "brk".
*/
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
+ brk = pLevel->brk = pLevel->nxt = sqlite3VdbeMakeLabel(v);
cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
/* If this is the right table of a LEFT OUTER JOIN, allocate and
** initialize a memory cell that records if this table matches any
** row of the left table of the join.
*/
- if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
- if( !pParse->nMem ) pParse->nMem++;
- pLevel->iLeftJoin = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
- VdbeComment((v, "# init LEFT JOIN no-match flag"));
+ if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){
+ pLevel->iLeftJoin = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
+ VdbeComment((v, "init LEFT JOIN no-match flag"));
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -2038,6 +2266,7 @@ WhereInfo *sqlite3WhereBegin(
** to access the data.
*/
int j;
+ int iReg; /* P3 Value for OP_VFilter */
sqlite3_index_info *pBestIdx = pLevel->pBestIdx;
int nConstraint = pBestIdx->nConstraint;
struct sqlite3_index_constraint_usage *aUsage =
@@ -2045,21 +2274,23 @@ WhereInfo *sqlite3WhereBegin(
const struct sqlite3_index_constraint *aConstraint =
pBestIdx->aConstraint;
+ iReg = sqlite3GetTempRange(pParse, nConstraint+2);
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);
+ sqlite3ExprCode(pParse, wc.a[iTerm].pExpr->pRight, iReg+j+1);
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);
+ sqlite3VdbeAddOp2(v, OP_Integer, pBestIdx->idxNum, iReg);
+ sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1);
+ sqlite3VdbeAddOp4(v, OP_VFilter, iCur, brk, iReg, pBestIdx->idxStr,
+ pBestIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC);
+ sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
pBestIdx->needToFreeIdxStr = 0;
for(j=0; j<pBestIdx->nConstraint; j++){
if( aUsage[j].omit ){
@@ -2079,15 +2310,19 @@ WhereInfo *sqlite3WhereBegin(
** we reference multiple rows using a "rowid IN (...)"
** construct.
*/
+ int r1;
pTerm = findTerm(&wc, iCur, -1, notReady, WO_EQ|WO_IN, 0);
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
assert( pTerm->leftCursor==iCur );
assert( omitTable==0 );
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk);
- sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk);
+ r1 = sqlite3GetTempReg(pParse);
+ codeEqualityTerm(pParse, pTerm, pLevel, r1);
+ nxt = pLevel->nxt;
+ sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, nxt, 1);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, nxt, r1);
VdbeComment((v, "pk"));
+ sqlite3ReleaseTempReg(pParse, r1);
pLevel->op = OP_Noop;
}else if( pLevel->flags & WHERE_ROWID_RANGE ){
/* Case 2: We have an inequality comparison against the ROWID field.
@@ -2106,25 +2341,27 @@ WhereInfo *sqlite3WhereBegin(
}
if( pStart ){
Expr *pX;
+ int r1, regFree1;
pX = pStart->pExpr;
assert( pX!=0 );
assert( pStart->leftCursor==iCur );
- sqlite3ExprCode(pParse, pX->pRight);
- sqlite3VdbeAddOp(v, OP_ForceInt, pX->op==TK_LE || pX->op==TK_GT, brk);
- sqlite3VdbeAddOp(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk);
+ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &regFree1);
+ sqlite3VdbeAddOp3(v, OP_ForceInt, r1, brk,
+ pX->op==TK_LE || pX->op==TK_GT);
+ sqlite3VdbeAddOp3(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk, r1);
VdbeComment((v, "pk"));
+ sqlite3ReleaseTempReg(pParse, regFree1);
disableTerm(pLevel, pStart);
}else{
- sqlite3VdbeAddOp(v, bRev ? OP_Last : OP_Rewind, iCur, brk);
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, brk);
}
if( pEnd ){
Expr *pX;
pX = pEnd->pExpr;
assert( pX!=0 );
assert( pEnd->leftCursor==iCur );
- sqlite3ExprCode(pParse, pX->pRight);
- pLevel->iMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ pLevel->iMem = ++pParse->nMem;
+ sqlite3ExprCode(pParse, pX->pRight, pLevel->iMem);
if( pX->op==TK_LT || pX->op==TK_GT ){
testOp = bRev ? OP_Le : OP_Ge;
}else{
@@ -2137,9 +2374,12 @@ WhereInfo *sqlite3WhereBegin(
pLevel->p1 = iCur;
pLevel->p2 = start;
if( testOp!=OP_Noop ){
- sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, SQLITE_AFF_NUMERIC, brk);
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
+ /* sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); */
+ sqlite3VdbeAddOp3(v, testOp, pLevel->iMem, brk, r1);
+ sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL);
+ sqlite3ReleaseTempReg(pParse, r1);
}
}else if( pLevel->flags & WHERE_COLUMN_RANGE ){
/* Case 3: The WHERE clause term that refers to the right-most
@@ -2159,29 +2399,22 @@ WhereInfo *sqlite3WhereBegin(
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;
+ int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */
+ int regBase; /* Base register holding constraint values */
+ int r1; /* Temp register */
/* Generate code to evaluate all constraint terms using == or IN
** and level the values of those terms on the stack.
*/
- codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
-
- /* Duplicate the equality term values because they will all be
- ** used twice: once to make the termination key and once to make the
- ** start key.
- */
- for(j=0; j<nEq; j++){
- sqlite3VdbeAddOp(v, OP_Dup, nEq-1, 0);
- }
+ regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 2);
/* 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;
@@ -2191,6 +2424,22 @@ WhereInfo *sqlite3WhereBegin(
SWAP(int, topLimit, btmLimit);
}
+ /* If this loop satisfies a sort order (pOrderBy) request that
+ ** was passed to this function to implement a "SELECT min(x) ..."
+ ** query, then the caller will only allow the loop to run for
+ ** a single iteration. This means that the first row returned
+ ** should not have a NULL value stored in 'x'. If column 'x' is
+ ** the first one after the nEq equality constraints in the index,
+ ** this requires some special handling.
+ */
+ if( (obflag==ORDERBY_MIN)
+ && (pLevel->flags&WHERE_ORDERBY)
+ && (pIdx->nColumn>nEq)
+ && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
+ ){
+ isMinQuery = 1;
+ }
+
/* 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.
@@ -2198,14 +2447,16 @@ WhereInfo *sqlite3WhereBegin(
** 2002-Dec-04: On a reverse-order scan, the so-called "termination"
** key computed here really ends up being the start key.
*/
+ nxt = pLevel->nxt;
if( topLimit ){
Expr *pX;
- int k = pIdx->aiColumn[j];
+ int k = pIdx->aiColumn[nEq];
pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
- sqlite3ExprCode(pParse, pX->pRight);
+ sqlite3ExprCode(pParse, pX->pRight, regBase+nEq);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
topEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
testOp = OP_IdxGE;
@@ -2213,20 +2464,22 @@ WhereInfo *sqlite3WhereBegin(
testOp = nEq>0 ? OP_IdxGE : OP_Noop;
topEq = 1;
}
- if( testOp!=OP_Noop ){
+ if( testOp!=OP_Noop || (isMinQuery&&bRev) ){
int nCol = nEq + topLimit;
- pLevel->iMem = pParse->nMem++;
- buildIndexProbe(v, nCol, nEq, brk, pIdx);
+ if( isMinQuery && !topLimit ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol);
+ nCol++;
+ topEq = 0;
+ }
+ buildIndexProbe(v, nCol, pIdx, regBase, pLevel->iMem);
if( bRev ){
int op = topEq ? OP_MoveLe : OP_MoveLt;
- sqlite3VdbeAddOp(v, op, iIdxCur, brk);
- }else{
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, pLevel->iMem);
}
}else if( bRev ){
- sqlite3VdbeAddOp(v, OP_Last, iIdxCur, brk);
+ sqlite3VdbeAddOp2(v, OP_Last, iIdxCur, brk);
}
-
+
/* Generate the start key. This is the key that defines the lower
** bound on the search. There is no start key if there are no
** equality terms and if there is no "X>..." term. In
@@ -2238,32 +2491,41 @@ WhereInfo *sqlite3WhereBegin(
*/
if( btmLimit ){
Expr *pX;
- int k = pIdx->aiColumn[j];
+ int k = pIdx->aiColumn[nEq];
pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx);
assert( pTerm!=0 );
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
- sqlite3ExprCode(pParse, pX->pRight);
+ sqlite3ExprCode(pParse, pX->pRight, regBase+nEq);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt);
btmEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
}else{
btmEq = 1;
}
- if( nEq>0 || btmLimit ){
+ if( nEq>0 || btmLimit || (isMinQuery&&!bRev) ){
int nCol = nEq + btmLimit;
- buildIndexProbe(v, nCol, 0, brk, pIdx);
+ if( isMinQuery && !btmLimit ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol);
+ nCol++;
+ btmEq = 0;
+ }
if( bRev ){
- pLevel->iMem = pParse->nMem++;
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
+ r1 = pLevel->iMem;
testOp = OP_IdxLT;
}else{
+ r1 = sqlite3GetTempReg(pParse);
+ }
+ buildIndexProbe(v, nCol, pIdx, regBase, r1);
+ if( !bRev ){
int op = btmEq ? OP_MoveGe : OP_MoveGt;
- sqlite3VdbeAddOp(v, op, iIdxCur, brk);
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
+ sqlite3ReleaseTempReg(pParse, r1);
}
}else if( bRev ){
testOp = OP_Noop;
}else{
- sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, brk);
+ sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, brk);
}
/* Generate the the top of the loop. If there is a termination
@@ -2272,18 +2534,21 @@ WhereInfo *sqlite3WhereBegin(
*/
start = sqlite3VdbeCurrentAddr(v);
if( testOp!=OP_Noop ){
- sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
+ sqlite3VdbeAddOp3(v, testOp, iIdxCur, nxt, pLevel->iMem);
if( (topEq && !bRev) || (!btmEq && bRev) ){
- sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
+ sqlite3VdbeChangeP5(v, 1);
}
}
- sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
+ r1 = sqlite3GetTempReg(pParse);
+ if( topLimit | btmLimit ){
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont);
+ }
if( !omitTable ){
- sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
+ sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */
}
+ sqlite3ReleaseTempReg(pParse, r1);
/* Record the instruction used to terminate the loop.
*/
@@ -2296,41 +2561,68 @@ WhereInfo *sqlite3WhereBegin(
*/
int start;
int nEq = pLevel->nEq;
+ int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */
+ int regBase; /* Base register of array holding constraints */
+ int r1;
/* Generate code to evaluate all constraint terms using == or IN
** and leave the values of those terms on the stack.
*/
- codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
-
- /* Generate a single key that will be used to both start and terminate
- ** the search
- */
- buildIndexProbe(v, nEq, 0, brk, pIdx);
- sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
+ regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 1);
+ nxt = pLevel->nxt;
+
+ if( (obflag==ORDERBY_MIN)
+ && (pLevel->flags&WHERE_ORDERBY)
+ && (pIdx->nColumn>nEq)
+ && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq])
+ ){
+ isMinQuery = 1;
+ buildIndexProbe(v, nEq, pIdx, regBase, pLevel->iMem);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
+ r1 = ++pParse->nMem;
+ buildIndexProbe(v, nEq+1, pIdx, regBase, r1);
+ }else{
+ /* Generate a single key that will be used to both start and
+ ** terminate the search
+ */
+ r1 = pLevel->iMem;
+ buildIndexProbe(v, nEq, pIdx, regBase, r1);
+ }
/* Generate code (1) to move to the first matching element of the table.
- ** Then generate code (2) that jumps to "brk" after the cursor is past
+ ** Then generate code (2) that jumps to "nxt" after the cursor is past
** the last matching element of the table. The code (1) is executed
** once to initialize the search, the code (2) is executed before each
** iteration of the scan to see if the scan has finished. */
if( bRev ){
/* Scan in reverse order */
- sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk);
- start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, brk);
+ int op;
+ if( isMinQuery ){
+ op = OP_MoveLt;
+ }else{
+ op = OP_MoveLe;
+ }
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
+ start = sqlite3VdbeAddOp3(v, OP_IdxLT, iIdxCur, nxt, pLevel->iMem);
pLevel->op = OP_Prev;
}else{
/* Scan in the forward order */
- sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, brk);
- start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC);
+ int op;
+ if( isMinQuery ){
+ op = OP_MoveGt;
+ }else{
+ op = OP_MoveGe;
+ }
+ sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1);
+ start = sqlite3VdbeAddOp3(v, OP_IdxGE, iIdxCur, nxt, pLevel->iMem);
+ sqlite3VdbeChangeP5(v, 1);
pLevel->op = OP_Next;
}
- sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq, cont);
if( !omitTable ){
- sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
+ r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1);
+ sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */
+ sqlite3ReleaseTempReg(pParse, r1);
}
pLevel->p1 = iIdxCur;
pLevel->p2 = start;
@@ -2342,7 +2634,7 @@ WhereInfo *sqlite3WhereBegin(
assert( bRev==0 );
pLevel->op = OP_Next;
pLevel->p1 = iCur;
- pLevel->p2 = 1 + sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk);
+ pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, OP_Rewind, iCur, brk);
}
notReady &= ~getMask(&maskSet, iCur);
@@ -2358,7 +2650,7 @@ WhereInfo *sqlite3WhereBegin(
if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
continue;
}
- sqlite3ExprIfFalse(pParse, pE, cont, 1);
+ sqlite3ExprIfFalse(pParse, pE, cont, SQLITE_JUMPIFNULL);
pTerm->flags |= TERM_CODED;
}
@@ -2367,13 +2659,13 @@ WhereInfo *sqlite3WhereBegin(
*/
if( pLevel->iLeftJoin ){
pLevel->top = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp(v, OP_MemInt, 1, pLevel->iLeftJoin);
- VdbeComment((v, "# record LEFT JOIN hit"));
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
+ VdbeComment((v, "record LEFT JOIN hit"));
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & notReady)!=0 ) continue;
assert( pTerm->pExpr );
- sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, 1);
+ sqlite3ExprIfFalse(pParse, pTerm->pExpr, cont, SQLITE_JUMPIFNULL);
pTerm->flags |= TERM_CODED;
}
}
@@ -2396,24 +2688,24 @@ WhereInfo *sqlite3WhereBegin(
n = strlen(z);
if( n+nQPlan < sizeof(sqlite3_query_plan)-10 ){
if( pLevel->flags & WHERE_IDX_ONLY ){
- strcpy(&sqlite3_query_plan[nQPlan], "{}");
+ memcpy(&sqlite3_query_plan[nQPlan], "{}", 2);
nQPlan += 2;
}else{
- strcpy(&sqlite3_query_plan[nQPlan], z);
+ memcpy(&sqlite3_query_plan[nQPlan], z, n);
nQPlan += n;
}
sqlite3_query_plan[nQPlan++] = ' ';
}
if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
- strcpy(&sqlite3_query_plan[nQPlan], "* ");
+ memcpy(&sqlite3_query_plan[nQPlan], "* ", 2);
nQPlan += 2;
}else if( pLevel->pIdx==0 ){
- strcpy(&sqlite3_query_plan[nQPlan], "{} ");
+ memcpy(&sqlite3_query_plan[nQPlan], "{} ", 3);
nQPlan += 3;
}else{
n = strlen(pLevel->pIdx->zName);
if( n+nQPlan < sizeof(sqlite3_query_plan)-2 ){
- strcpy(&sqlite3_query_plan[nQPlan], pLevel->pIdx->zName);
+ memcpy(&sqlite3_query_plan[nQPlan], pLevel->pIdx->zName, n);
nQPlan += n;
sqlite3_query_plan[nQPlan++] = ' ';
}
@@ -2456,26 +2748,28 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
pLevel = &pWInfo->a[i];
sqlite3VdbeResolveLabel(v, pLevel->cont);
if( pLevel->op!=OP_Noop ){
- sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
+ sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2);
}
- sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->nIn ){
- int *a;
+ struct InLoop *pIn;
int j;
- 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);
+ sqlite3VdbeResolveLabel(v, pLevel->nxt);
+ for(j=pLevel->nIn, pIn=&pLevel->aInLoop[j-1]; j>0; j--, pIn--){
+ sqlite3VdbeJumpHere(v, pIn->topAddr+1);
+ sqlite3VdbeAddOp2(v, OP_Next, pIn->iCur, pIn->topAddr);
+ sqlite3VdbeJumpHere(v, pIn->topAddr-1);
}
- sqliteFree(pLevel->aInLoop);
+ sqlite3_free(pLevel->aInLoop);
}
+ sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->iLeftJoin ){
int addr;
- addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0);
- sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
+ addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin);
+ sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
if( pLevel->iIdxCur>=0 ){
- sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0);
+ sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
}
- sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->top);
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -2493,14 +2787,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
assert( pTab!=0 );
if( pTab->isEphem || pTab->pSelect ) continue;
if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){
- sqlite3VdbeAddOp(v, OP_Close, pTabItem->iCursor, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
if( pLevel->pIdx!=0 ){
- sqlite3VdbeAddOp(v, OP_Close, pLevel->iIdxCur, 0);
+ sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
- /* Make cursor substitutions for cases where we want to use
- ** just the index and never reference the table.
+ /* If this scan uses an index, make code substitutions to read data
+ ** from the index in preference to the table. Sometimes, this means
+ ** the table need never be read from. This is a performance boost,
+ ** as the vdbe level waits until the table is read before actually
+ ** seeking the table cursor to the record corresponding to the current
+ ** position in the index.
**
** Calls to the code generator in between sqlite3WhereBegin and
** sqlite3WhereEnd will have created code that references the table
@@ -2508,10 +2806,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
** that reference the table and converts them into opcodes that
** reference the index.
*/
- if( pLevel->flags & WHERE_IDX_ONLY ){
+ if( pLevel->pIdx ){
int k, j, last;
VdbeOp *pOp;
Index *pIdx = pLevel->pIdx;
+ int useIndexOnly = pLevel->flags & WHERE_IDX_ONLY;
assert( pIdx!=0 );
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
@@ -2519,17 +2818,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
for(k=pWInfo->iTop; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
- pOp->p1 = pLevel->iIdxCur;
for(j=0; j<pIdx->nColumn; j++){
if( pOp->p2==pIdx->aiColumn[j] ){
pOp->p2 = j;
+ pOp->p1 = pLevel->iIdxCur;
break;
}
}
+ assert(!useIndexOnly || j<pIdx->nColumn);
}else if( pOp->opcode==OP_Rowid ){
pOp->p1 = pLevel->iIdxCur;
pOp->opcode = OP_IdxRowid;
- }else if( pOp->opcode==OP_NullRow ){
+ }else if( pOp->opcode==OP_NullRow && useIndexOnly ){
pOp->opcode = OP_Noop;
}
}