aboutsummaryrefslogtreecommitdiff
path: root/src/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/expr.c')
-rw-r--r--src/expr.c81
1 files changed, 59 insertions, 22 deletions
diff --git a/src/expr.c b/src/expr.c
index 0484f3b45..874a044d7 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1808,6 +1808,33 @@ int sqlite3ExprTruthValue(const Expr *pExpr){
return pExpr->u.zToken[4]==0;
}
+/*
+** If pExpr is an AND or OR expression, try to simplify it by eliminating
+** terms that are always true or false. Return the simplified expression.
+** Or return the original expression if no simplification is possible.
+**
+** Examples:
+**
+** (x<10) AND true => (x<10)
+** (x<10) AND false => false
+** (x<10) AND (y=22 OR false) => (x<10) AND (y=22)
+** (x<10) AND (y=22 OR true) => (x<10)
+** (y=22) OR true => true
+*/
+Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
+ assert( pExpr!=0 );
+ if( pExpr->op==TK_AND || pExpr->op==TK_OR ){
+ Expr *pRight = sqlite3ExprSimplifiedAndOr(pExpr->pRight);
+ Expr *pLeft = sqlite3ExprSimplifiedAndOr(pExpr->pLeft);
+ if( ExprAlwaysTrue(pLeft) || ExprAlwaysFalse(pRight) ){
+ pExpr = pExpr->op==TK_AND ? pRight : pLeft;
+ }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){
+ pExpr = pExpr->op==TK_AND ? pLeft : pRight;
+ }
+ }
+ return pExpr;
+}
+
/*
** These routines are Walker callbacks used to check expressions to
@@ -4399,18 +4426,23 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
if( NEVER(pExpr==0) ) return; /* No way this can happen */
op = pExpr->op;
switch( op ){
- case TK_AND: {
- int d2 = sqlite3VdbeMakeLabel(pParse);
- testcase( jumpIfNull==0 );
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
- sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3VdbeResolveLabel(v, d2);
- break;
- }
+ case TK_AND:
case TK_OR: {
- testcase( jumpIfNull==0 );
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
- sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
+ Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr);
+ if( pAlt!=pExpr ){
+ sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull);
+ }else if( op==TK_AND ){
+ int d2 = sqlite3VdbeMakeLabel(pParse);
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,
+ jumpIfNull^SQLITE_JUMPIFNULL);
+ sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
+ sqlite3VdbeResolveLabel(v, d2);
+ }else{
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
+ sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
+ }
break;
}
case TK_NOT: {
@@ -4566,18 +4598,23 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
assert( pExpr->op!=TK_GE || op==OP_Lt );
switch( pExpr->op ){
- case TK_AND: {
- testcase( jumpIfNull==0 );
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
- sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- break;
- }
+ case TK_AND:
case TK_OR: {
- int d2 = sqlite3VdbeMakeLabel(pParse);
- testcase( jumpIfNull==0 );
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
- sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3VdbeResolveLabel(v, d2);
+ Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr);
+ if( pAlt!=pExpr ){
+ sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull);
+ }else if( pExpr->op==TK_AND ){
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
+ sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
+ }else{
+ int d2 = sqlite3VdbeMakeLabel(pParse);
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2,
+ jumpIfNull^SQLITE_JUMPIFNULL);
+ sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
+ sqlite3VdbeResolveLabel(v, d2);
+ }
break;
}
case TK_NOT: {