diff options
author | dan <dan@noemail.net> | 2017-06-24 18:10:29 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2017-06-24 18:10:29 +0000 |
commit | 5aa550cf3b257cd1e62812a8784caca440908ed8 (patch) | |
tree | 7963960302b060c9fbc35d675e521975af44e6ff /src/expr.c | |
parent | 7f2d1cd2b0c2583c5a472982701b66d97c4528d0 (diff) | |
download | sqlite-5aa550cf3b257cd1e62812a8784caca440908ed8.tar.gz sqlite-5aa550cf3b257cd1e62812a8784caca440908ed8.zip |
Consider the values bound to SQL variables when determining whether or not a
partial index may be used.
FossilOrigin-Name: 7b59c353b805c64689b4ae9df347705acbb5f116346ad77af8ce087da7893747
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 81 |
1 files changed, 66 insertions, 15 deletions
diff --git a/src/expr.c b/src/expr.c index 27cebdb83..89a4adddb 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1829,7 +1829,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ ** it constant. */ for(i=0; i<pGroupBy->nExpr; i++){ Expr *p = pGroupBy->a[i].pExpr; - if( sqlite3ExprCompare(pExpr, p, -1)<2 ){ + if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){ CollSeq *pColl = sqlite3ExprCollSeq(pWalker->pParse, p); if( pColl==0 || sqlite3_stricmp("BINARY", pColl->zName)==0 ){ return WRC_Prune; @@ -4105,7 +4105,7 @@ int sqlite3ExprCodeAtInit( struct ExprList_item *pItem; int i; for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){ - if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){ + if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){ return pItem->u.iConstExprReg; } } @@ -4660,6 +4660,48 @@ void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){ sqlite3ExprDelete(db, pCopy); } +/* +** Expression pVar is guaranteed to be an SQL variable. pExpr may be any +** type of expression. +** +** If pExpr is a simple SQL value - an integer, real, string, blob +** or NULL value - then the VDBE currently being prepared is configured +** to re-prepare each time a new value is bound to variable pVar. +** +** Additionally, if pExpr is a simple SQL value and the value is the +** same as that currently bound to variable pVar, non-zero is returned. +** Otherwise, if the values are not the same or if pExpr is not a simple +** SQL value, zero is returned. +*/ +static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){ + int res = 0; + int iVar = pVar->iColumn; + Expr *p = pExpr; + + while( p->op==TK_UMINUS ) p = p->pLeft; + if( p->op==TK_NULL || p->op==TK_INTEGER + || p->op==TK_FLOAT || p->op==TK_STRING + || p->op==TK_BLOB + ){ + sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); + sqlite3_value *pL; + pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB); + if( pL ){ + sqlite3_value *pR = 0; + sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB,&pR); + assert( pR || pParse->db->mallocFailed ); + if( pR && 0==sqlite3MemCompare(pL, pR, 0) ){ + res = 1; + } + sqlite3ValueFree(pR); + sqlite3ValueFree(pL); + }else if( p->op==TK_NULL ){ + res = 1; + } + } + + return res; +} /* ** Do a deep comparison of two expression trees. Return 0 if the two @@ -4682,12 +4724,21 @@ void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){ ** this routine is used, it does not hurt to get an extra 2 - that ** just might result in some slightly slower code. But returning ** an incorrect 0 or 1 could lead to a malfunction. +** +** Argument pParse should normally be NULL. If it is not NULL and +** expression pA contains SQL variable references, then the values +** currently bound to those variable references may be compared to +** simple SQL values in pB. See comments above function exprCompareVariable() +** for details. */ -int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ +int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ u32 combinedFlags; if( pA==0 || pB==0 ){ return pB==pA ? 0 : 2; } + if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){ + return 0; + } combinedFlags = pA->flags | pB->flags; if( combinedFlags & EP_IntValue ){ if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){ @@ -4696,10 +4747,10 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ return 2; } if( pA->op!=pB->op ){ - if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){ + if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){ return 1; } - if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){ + if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){ return 1; } return 2; @@ -4714,8 +4765,8 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; - if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2; - if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2; + if( sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; + if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2; if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){ if( pA->iColumn!=pB->iColumn ) return 2; @@ -4750,7 +4801,7 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; - if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1; + if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1; } return 0; } @@ -4760,7 +4811,7 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){ ** are ignored. */ int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ - return sqlite3ExprCompare( + return sqlite3ExprCompare(0, sqlite3ExprSkipCollate(pA), sqlite3ExprSkipCollate(pB), iTab); @@ -4786,20 +4837,20 @@ int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ ** improvement. Returning false might cause a performance reduction, but ** it will always give the correct answer and is hence always safe. */ -int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){ - if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){ +int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){ + if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){ return 1; } if( pE2->op==TK_OR - && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab) - || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) ) + && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab) + || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) ) ){ return 1; } if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){ Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); testcase( pX!=pE1->pLeft ); - if( sqlite3ExprCompare(pX, pE2->pLeft, iTab)==0 ) return 1; + if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1; } return 0; } @@ -5040,7 +5091,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ */ struct AggInfo_func *pItem = pAggInfo->aFunc; for(i=0; i<pAggInfo->nFunc; i++, pItem++){ - if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){ + if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){ break; } } |