diff options
author | drh <drh@noemail.net> | 2007-02-23 23:13:33 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2007-02-23 23:13:33 +0000 |
commit | 3e35580779f5313ecfaa3e9ef83383cb5bf7223e (patch) | |
tree | 4c3e689f52f47e4e2dd73e65328cb1066da5b45e /src | |
parent | b0988dead76bca654e010215f5979d6ed9895111 (diff) | |
download | sqlite-3e35580779f5313ecfaa3e9ef83383cb5bf7223e.tar.gz sqlite-3e35580779f5313ecfaa3e9ef83383cb5bf7223e.zip |
Disable the OR optimization if it would conflict with column
affinity coercions. Ticket #2249. Additional cleanup and testing
of the OR optimization. (CVS 3658)
FossilOrigin-Name: 908daaa9ab86e0bd1da6d0807d6aaba240c3cee0
Diffstat (limited to 'src')
-rw-r--r-- | src/where.c | 99 |
1 files changed, 92 insertions, 7 deletions
diff --git a/src/where.c b/src/where.c index a364ce0e1..ad7e12c88 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.237 2007/02/06 13:26:33 drh Exp $ +** $Id: where.c,v 1.238 2007/02/23 23:13:34 drh Exp $ */ #include "sqliteInt.h" @@ -582,6 +582,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 @@ -716,9 +802,10 @@ static void exprAnalyze( whereClauseInit(&sOr, pWC->pParse, pMaskSet); whereSplit(&sOr, pExpr, TK_OR); exprAnalyzeAll(pSrc, &sOr); - assert( sOr.nTerm>0 ); + assert( sOr.nTerm>=2 ); j = 0; do{ + assert( j<sOr.nTerm ); iColumn = sOr.a[j].leftColumn; iCursor = sOr.a[j].leftCursor; ok = iCursor>=0; @@ -726,17 +813,15 @@ 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; |