mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Enhancements to sqlite3ExprImpliesExpr() so that it realizes that
"iif(A,B)" implies "A". FossilOrigin-Name: d96ecbee59b50eca25447456dfff2c168e8eade7a68e542932d5829f97debb31
This commit is contained in:
90
src/expr.c
90
src/expr.c
@@ -6180,16 +6180,20 @@ void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){
|
||||
** 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.
|
||||
**
|
||||
** If the SQLITE_EnableQPSG flag is set on the database connection, then
|
||||
** this routine always returns false.
|
||||
*/
|
||||
static int exprCompareVariable(
|
||||
static SQLITE_NOINLINE int exprCompareVariable(
|
||||
const Parse *pParse,
|
||||
const Expr *pVar,
|
||||
const Expr *pExpr
|
||||
){
|
||||
int res = 0;
|
||||
int res = 2;
|
||||
int iVar;
|
||||
sqlite3_value *pL, *pR = 0;
|
||||
|
||||
if( (pParse->db->flags & SQLITE_EnableQPSG)!=0 ) return 2;
|
||||
sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
|
||||
if( pR ){
|
||||
iVar = pVar->iColumn;
|
||||
@@ -6199,12 +6203,11 @@ static int exprCompareVariable(
|
||||
if( sqlite3_value_type(pL)==SQLITE_TEXT ){
|
||||
sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
|
||||
}
|
||||
res = 0==sqlite3MemCompare(pL, pR, 0);
|
||||
res = sqlite3MemCompare(pL, pR, 0) ? 2 : 0;
|
||||
}
|
||||
sqlite3ValueFree(pR);
|
||||
sqlite3ValueFree(pL);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -6230,12 +6233,10 @@ static int exprCompareVariable(
|
||||
** just might result in some slightly slower code. But returning
|
||||
** an incorrect 0 or 1 could lead to a malfunction.
|
||||
**
|
||||
** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
|
||||
** pParse->pReprepare can be matched against literals in pB. The
|
||||
** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
|
||||
** If pParse is NULL (the normal case) then any TK_VARIABLE term in
|
||||
** Argument pParse should normally be NULL. If it is not NULL and pA or
|
||||
** pB causes a return value of 2.
|
||||
** If pParse is not NULL and SQLITE_EnableQPSG is off then TK_VARIABLE
|
||||
** terms in pA with bindings in pParse->pReprepare can be matched against
|
||||
** literals in pB. The pParse->pVdbe->expmask bitmask is updated for
|
||||
** each variable referenced.
|
||||
*/
|
||||
int sqlite3ExprCompare(
|
||||
const Parse *pParse,
|
||||
@@ -6247,8 +6248,8 @@ int sqlite3ExprCompare(
|
||||
if( pA==0 || pB==0 ){
|
||||
return pB==pA ? 0 : 2;
|
||||
}
|
||||
if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
|
||||
return 0;
|
||||
if( pParse && pA->op==TK_VARIABLE ){
|
||||
return exprCompareVariable(pParse, pA, pB);
|
||||
}
|
||||
combinedFlags = pA->flags | pB->flags;
|
||||
if( combinedFlags & EP_IntValue ){
|
||||
@@ -6443,18 +6444,66 @@ static int exprImpliesNotNull(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the boolean value of the expression is always either
|
||||
** FALSE or NULL.
|
||||
*/
|
||||
static int sqlite3ExprIsNotTrue(Expr *pExpr){
|
||||
int v;
|
||||
if( pExpr->op==TK_NULL ) return 1;
|
||||
if( pExpr->op==TK_TRUEFALSE && sqlite3ExprTruthValue(pExpr)==0 ) return 1;
|
||||
v = 1;
|
||||
if( sqlite3ExprIsInteger(pExpr, &v, 0) && v==0 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the expression is one of the following:
|
||||
**
|
||||
** CASE WHEN x THEN y END
|
||||
** CASE WHEN x THEN y ELSE NULL END
|
||||
** CASE WHEN x THEN y ELSE false END
|
||||
** iif(x,y)
|
||||
** iif(x,y,NULL)
|
||||
** iif(x,y,false)
|
||||
*/
|
||||
static int sqlite3ExprIsIIF(sqlite3 *db, const Expr *pExpr){
|
||||
ExprList *pList;
|
||||
if( pExpr->op==TK_FUNCTION ){
|
||||
const char *z = pExpr->u.zToken;
|
||||
FuncDef *pDef;
|
||||
if( (z[0]!='i' && z[0]!='I') ) return 0;
|
||||
if( pExpr->x.pList==0 ) return 0;
|
||||
pDef = sqlite3FindFunction(db, z, pExpr->x.pList->nExpr, ENC(db), 0);
|
||||
if( pDef==0 ) return 0;
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_INLINE)==0 ) return 0;
|
||||
if( SQLITE_PTR_TO_INT(pDef->pUserData)!=INLINEFUNC_iif ) return 0;
|
||||
}else if( pExpr->op==TK_CASE ){
|
||||
if( pExpr->pLeft!=0 ) return 0;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
pList = pExpr->x.pList;
|
||||
assert( pList!=0 );
|
||||
if( pList->nExpr==2 ) return 1;
|
||||
if( pList->nExpr==3 && sqlite3ExprIsNotTrue(pList->a[2].pExpr) ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if we can prove the pE2 will always be true if pE1 is
|
||||
** true. Return false if we cannot complete the proof or if pE2 might
|
||||
** be false. Examples:
|
||||
**
|
||||
** pE1: x==5 pE2: x==5 Result: true
|
||||
** pE1: x>0 pE2: x==5 Result: false
|
||||
** pE1: x=21 pE2: x=21 OR y=43 Result: true
|
||||
** pE1: x!=123 pE2: x IS NOT NULL Result: true
|
||||
** pE1: x!=?1 pE2: x IS NOT NULL Result: true
|
||||
** pE1: x IS NULL pE2: x IS NOT NULL Result: false
|
||||
** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
|
||||
** pE1: x==5 pE2: x==5 Result: true
|
||||
** pE1: x>0 pE2: x==5 Result: false
|
||||
** pE1: x=21 pE2: x=21 OR y=43 Result: true
|
||||
** pE1: x!=123 pE2: x IS NOT NULL Result: true
|
||||
** pE1: x!=?1 pE2: x IS NOT NULL Result: true
|
||||
** pE1: x IS NULL pE2: x IS NOT NULL Result: false
|
||||
** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
|
||||
** pE1: iif(x,y) pE2: x Result: true
|
||||
** PE1: iif(x,y,0) pE2: x Result: true
|
||||
**
|
||||
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
|
||||
** Expr.iTable<0 then assume a table number given by iTab.
|
||||
@@ -6488,6 +6537,9 @@ int sqlite3ExprImpliesExpr(
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3ExprIsIIF(pParse->db, pE1) ){
|
||||
return sqlite3ExprImpliesExpr(pParse,pE1->x.pList->a[0].pExpr,pE2,iTab);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user