1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-12 13:01:09 +03:00

Consider the values bound to SQL variables when determining whether or not a

partial index may be used.

FossilOrigin-Name: 7b59c353b805c64689b4ae9df347705acbb5f116346ad77af8ce087da7893747
This commit is contained in:
dan
2017-06-24 18:10:29 +00:00
parent 7f2d1cd2b0
commit 5aa550cf3b
11 changed files with 183 additions and 43 deletions

View File

@@ -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;
}
}