aboutsummaryrefslogtreecommitdiff
path: root/src/expr.c
diff options
context:
space:
mode:
authordan <dan@noemail.net>2017-06-24 18:10:29 +0000
committerdan <dan@noemail.net>2017-06-24 18:10:29 +0000
commit5aa550cf3b257cd1e62812a8784caca440908ed8 (patch)
tree7963960302b060c9fbc35d675e521975af44e6ff /src/expr.c
parent7f2d1cd2b0c2583c5a472982701b66d97c4528d0 (diff)
downloadsqlite-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.c81
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;
}
}