diff options
author | drh <drh@noemail.net> | 2019-05-11 19:36:03 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2019-05-11 19:36:03 +0000 |
commit | c51cf8642f867050c8cb9e330582605dabeff76c (patch) | |
tree | c9df800852234fe101762a275292a4a7f41cda62 /src/expr.c | |
parent | c6824c8d6c2def197044cad984481eb981d38998 (diff) | |
download | sqlite-c51cf8642f867050c8cb9e330582605dabeff76c.tar.gz sqlite-c51cf8642f867050c8cb9e330582605dabeff76c.zip |
A new implementation for the sqlite3ExprImpliesExpr() theorem prover that
does a better job of answering TRUE to "(NOT A) OR B" when B is a NOT NULL
expression.
FossilOrigin-Name: b3413197f57711f04102d8cc6ff1e8ddbe0f5f2bcb6e1989cf314fa97f0ff7f1
Diffstat (limited to 'src/expr.c')
-rw-r--r-- | src/expr.c | 80 |
1 files changed, 72 insertions, 8 deletions
diff --git a/src/expr.c b/src/expr.c index 05b50c1e6..a905c28c9 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4909,6 +4909,76 @@ int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ } /* +** Return non-zero if Expr p can only be true if pNN is not NULL. +*/ +static int exprImpliesNotNull( + Parse *pParse, /* Parsing context */ + Expr *p, /* The expression to be checked */ + Expr *pNN, /* The expression that is NOT NULL */ + int iTab, /* Table being evaluated */ + int seenNot /* True if p is an operand of NOT */ +){ + assert( p ); + assert( pNN ); + if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ) return 1; + switch( p->op ){ + case TK_IN: { + if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0; + assert( ExprHasProperty(p,EP_xIsSelect) + || (p->x.pList!=0 && p->x.pList->nExpr>0) ); + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_BETWEEN: { + ExprList *pList = p->x.pList; + assert( pList!=0 ); + assert( pList->nExpr==2 ); + if( seenNot ) return 0; + if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, seenNot) + || exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, seenNot) + ){ + return 1; + } + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_EQ: + case TK_NE: + case TK_LT: + case TK_LE: + case TK_GT: + case TK_GE: + case TK_PLUS: + case TK_MINUS: + case TK_STAR: + case TK_REM: + case TK_BITAND: + case TK_BITOR: + case TK_SLASH: + case TK_LSHIFT: + case TK_RSHIFT: + case TK_CONCAT: { + if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1; + /* Fall thru into the next case */ + } + case TK_SPAN: + case TK_COLLATE: + case TK_BITNOT: + case TK_UPLUS: + case TK_UMINUS: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_TRUTH: { + if( seenNot ) return 0; + if( p->op2!=TK_IS ) return 0; + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot); + } + case TK_NOT: { + return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 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: @@ -4944,15 +5014,9 @@ int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){ return 1; } if( pE2->op==TK_NOTNULL - && pE1->op!=TK_ISNULL - && pE1->op!=TK_IS - && pE1->op!=TK_ISNOT - && pE1->op!=TK_OR - && pE1->op!=TK_CASE + && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0) ){ - Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); - testcase( pX!=pE1->pLeft ); - if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1; + return 1; } return 0; } |