aboutsummaryrefslogtreecommitdiff
path: root/src/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/expr.c')
-rw-r--r--src/expr.c164
1 files changed, 94 insertions, 70 deletions
diff --git a/src/expr.c b/src/expr.c
index 94aa06df5..89508d26c 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.63 2002/05/24 02:04:33 drh Exp $
+** $Id: expr.c,v 1.64 2002/05/26 20:54:33 drh Exp $
*/
#include "sqliteInt.h"
@@ -818,7 +818,13 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
case TK_REM:
case TK_BITAND:
case TK_BITOR:
- case TK_SLASH: {
+ case TK_SLASH:
+ case TK_LT:
+ case TK_LE:
+ case TK_GT:
+ case TK_GE:
+ case TK_NE:
+ case TK_EQ: {
sqliteExprCode(pParse, pExpr->pLeft);
sqliteExprCode(pParse, pExpr->pRight);
sqliteVdbeAddOp(v, op, 0, 0);
@@ -837,21 +843,6 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_Concat, 2, 0);
break;
}
- case TK_LT:
- case TK_LE:
- case TK_GT:
- case TK_GE:
- case TK_NE:
- case TK_EQ: {
- int dest;
- sqliteVdbeAddOp(v, OP_Integer, 1, 0);
- sqliteExprCode(pParse, pExpr->pLeft);
- sqliteExprCode(pParse, pExpr->pRight);
- dest = sqliteVdbeCurrentAddr(v) + 2;
- sqliteVdbeAddOp(v, op, 0, dest);
- sqliteVdbeAddOp(v, OP_AddImm, -1, 0);
- break;
- }
case TK_UMINUS: {
assert( pExpr->pLeft );
if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){
@@ -881,7 +872,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_Integer, 1, 0);
sqliteExprCode(pParse, pExpr->pLeft);
dest = sqliteVdbeCurrentAddr(v) + 2;
- sqliteVdbeAddOp(v, op, 0, dest);
+ sqliteVdbeAddOp(v, op, 1, dest);
sqliteVdbeAddOp(v, OP_AddImm, -1, 0);
break;
}
@@ -913,20 +904,27 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_Integer, 1, 0);
sqliteExprCode(pParse, pExpr->pLeft);
addr = sqliteVdbeCurrentAddr(v);
+ sqliteVdbeAddOp(v, OP_NotNull, -1, addr+4);
+ sqliteVdbeAddOp(v, OP_Pop, 1, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0);
+ sqliteVdbeAddOp(v, OP_Goto, 0, addr+6);
if( pExpr->pSelect ){
- sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, addr+2);
+ sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, addr+6);
}else{
- sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+2);
+ sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+6);
}
sqliteVdbeAddOp(v, OP_AddImm, -1, 0);
break;
}
case TK_BETWEEN: {
- int lbl = sqliteVdbeMakeLabel(v);
- sqliteVdbeAddOp(v, OP_Integer, 0, 0);
- sqliteExprIfFalse(pParse, pExpr, lbl);
- sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
- sqliteVdbeResolveLabel(v, lbl);
+ sqliteExprCode(pParse, pExpr->pLeft);
+ sqliteVdbeAddOp(v, OP_Dup, 0, 0);
+ sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
+ sqliteVdbeAddOp(v, OP_Ge, 0, 0);
+ sqliteVdbeAddOp(v, OP_Pull, 1, 0);
+ sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
+ sqliteVdbeAddOp(v, OP_Le, 0, 0);
+ sqliteVdbeAddOp(v, OP_And, 0, 0);
break;
}
case TK_AS: {
@@ -935,44 +933,54 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
}
case TK_CASE: {
int expr_end_label;
- int next_when_label;
+ int null_result_label;
+ int jumpInst;
+ int addr;
+ int nExpr;
int i;
assert(pExpr->pList);
assert((pExpr->pList->nExpr % 2) == 0);
assert(pExpr->pList->nExpr > 0);
- expr_end_label = sqliteVdbeMakeLabel(pParse->pVdbe);
+ nExpr = pExpr->pList->nExpr;
+ expr_end_label = sqliteVdbeMakeLabel(v);
+ null_result_label = sqliteVdbeMakeLabel(v);
if( pExpr->pLeft ){
sqliteExprCode(pParse, pExpr->pLeft);
+ sqliteVdbeAddOp(v, OP_IsNull, -1, expr_end_label);
}
- for(i=0; i<pExpr->pList->nExpr; i=i+2){
- if( i!=0 ){
- sqliteVdbeResolveLabel(pParse->pVdbe, next_when_label);
- }
- next_when_label = sqliteVdbeMakeLabel(pParse->pVdbe);
+ for(i=0; i<nExpr; i=i+2){
+ sqliteExprCode(pParse, pExpr->pList->a[i].pExpr);
+ sqliteVdbeAddOp(v, OP_IsNull, -1, null_result_label);
if( pExpr->pLeft ){
- sqliteVdbeAddOp(pParse->pVdbe, OP_Dup, 0, 1);
- sqliteExprCode(pParse, pExpr->pList->a[i].pExpr);
- sqliteVdbeAddOp(pParse->pVdbe, OP_Ne, 0, next_when_label);
+ sqliteVdbeAddOp(v, OP_Dup, 1, 1);
+ jumpInst = sqliteVdbeAddOp(v, OP_Ne, 0, 0);
}else{
- sqliteExprIfFalse(pParse, pExpr->pList->a[i].pExpr, next_when_label);
- }
- if( pExpr->pLeft ){
- sqliteVdbeAddOp(pParse->pVdbe, OP_Pop, 1, 0);
+ jumpInst = sqliteVdbeAddOp(v, OP_IfNot, 0, 0);
}
sqliteExprCode(pParse, pExpr->pList->a[i+1].pExpr);
- sqliteVdbeAddOp(pParse->pVdbe, OP_Goto, 0, expr_end_label);
- }
- sqliteVdbeResolveLabel(pParse->pVdbe, next_when_label);
- if( pExpr->pLeft ){
- sqliteVdbeAddOp(pParse->pVdbe, OP_Pop, 1, 0);
+ sqliteVdbeAddOp(v, OP_Goto, 0, expr_end_label);
+ if( i>=nExpr-2 ){
+ sqliteVdbeResolveLabel(v, null_result_label);
+ sqliteVdbeAddOp(v, OP_Pop, 1, 0);
+ if( pExpr->pRight!=0 ){
+ sqliteVdbeAddOp(v, OP_String, 0, 0);
+ sqliteVdbeAddOp(v, OP_Goto, 0, expr_end_label);
+ }
+ }
+ addr = sqliteVdbeCurrentAddr(v);
+ sqliteVdbeChangeP2(v, jumpInst, addr);
}
if( pExpr->pRight ){
sqliteExprCode(pParse, pExpr->pRight);
}else{
- sqliteVdbeAddOp(pParse->pVdbe, OP_String, 0, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0);
+ }
+ sqliteVdbeResolveLabel(v, expr_end_label);
+ if( pExpr->pLeft ){
+ sqliteVdbeAddOp(v, OP_Pull, 1, 0);
+ sqliteVdbeAddOp(v, OP_Pop, 1, 0);
}
- sqliteVdbeResolveLabel(pParse->pVdbe, expr_end_label);
}
break;
}
@@ -982,8 +990,11 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
** Generate code for a boolean expression such that a jump is made
** to the label "dest" if the expression is true but execution
** continues straight thru if the expression is false.
+**
+** If the expression evaluates to NULL (neither true nor false), then
+** take the jump if the jumpIfNull flag is true.
*/
-void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
+void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
if( v==0 || pExpr==0 ) return;
@@ -1001,18 +1012,18 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
switch( pExpr->op ){
case TK_AND: {
int d2 = sqliteVdbeMakeLabel(v);
- sqliteExprIfFalse(pParse, pExpr->pLeft, d2);
- sqliteExprIfTrue(pParse, pExpr->pRight, dest);
+ sqliteExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull);
+ sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
sqliteVdbeResolveLabel(v, d2);
break;
}
case TK_OR: {
- sqliteExprIfTrue(pParse, pExpr->pLeft, dest);
- sqliteExprIfTrue(pParse, pExpr->pRight, dest);
+ sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
+ sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
break;
}
case TK_NOT: {
- sqliteExprIfFalse(pParse, pExpr->pLeft, dest);
+ sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
case TK_LT:
@@ -1023,17 +1034,22 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
case TK_EQ: {
sqliteExprCode(pParse, pExpr->pLeft);
sqliteExprCode(pParse, pExpr->pRight);
- sqliteVdbeAddOp(v, op, 0, dest);
+ sqliteVdbeAddOp(v, op, jumpIfNull, dest);
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
sqliteExprCode(pParse, pExpr->pLeft);
- sqliteVdbeAddOp(v, op, 0, dest);
+ sqliteVdbeAddOp(v, op, 1, dest);
break;
}
case TK_IN: {
+ int addr;
sqliteExprCode(pParse, pExpr->pLeft);
+ addr = sqliteVdbeCurrentAddr(v);
+ sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3);
+ sqliteVdbeAddOp(v, OP_Pop, 1, 0);
+ sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4);
if( pExpr->pSelect ){
sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, dest);
}else{
@@ -1042,21 +1058,21 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
break;
}
case TK_BETWEEN: {
- int lbl = sqliteVdbeMakeLabel(v);
+ int addr;
sqliteExprCode(pParse, pExpr->pLeft);
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
- sqliteVdbeAddOp(v, OP_Lt, 0, lbl);
+ addr = sqliteVdbeAddOp(v, OP_Lt, !jumpIfNull, 0);
sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
- sqliteVdbeAddOp(v, OP_Le, 0, dest);
+ sqliteVdbeAddOp(v, OP_Le, jumpIfNull, dest);
sqliteVdbeAddOp(v, OP_Integer, 0, 0);
- sqliteVdbeResolveLabel(v, lbl);
+ sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
break;
}
default: {
sqliteExprCode(pParse, pExpr);
- sqliteVdbeAddOp(v, OP_If, 0, dest);
+ sqliteVdbeAddOp(v, OP_If, jumpIfNull, dest);
break;
}
}
@@ -1066,8 +1082,11 @@ void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest){
** Generate code for a boolean expression such that a jump is made
** to the label "dest" if the expression is false but execution
** continues straight thru if the expression is true.
+**
+** If the expression evaluates to NULL (neither true nor false) then
+** jump if jumpIfNull is true or fall through if jumpIfNull is false.
*/
-void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
+void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
Vdbe *v = pParse->pVdbe;
int op = 0;
if( v==0 || pExpr==0 ) return;
@@ -1084,19 +1103,19 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
}
switch( pExpr->op ){
case TK_AND: {
- sqliteExprIfFalse(pParse, pExpr->pLeft, dest);
- sqliteExprIfFalse(pParse, pExpr->pRight, dest);
+ sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
+ sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
break;
}
case TK_OR: {
int d2 = sqliteVdbeMakeLabel(v);
- sqliteExprIfTrue(pParse, pExpr->pLeft, d2);
- sqliteExprIfFalse(pParse, pExpr->pRight, dest);
+ sqliteExprIfTrue(pParse, pExpr->pLeft, d2, !jumpIfNull);
+ sqliteExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
sqliteVdbeResolveLabel(v, d2);
break;
}
case TK_NOT: {
- sqliteExprIfTrue(pParse, pExpr->pLeft, dest);
+ sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
case TK_LT:
@@ -1107,17 +1126,22 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
case TK_EQ: {
sqliteExprCode(pParse, pExpr->pLeft);
sqliteExprCode(pParse, pExpr->pRight);
- sqliteVdbeAddOp(v, op, 0, dest);
+ sqliteVdbeAddOp(v, op, jumpIfNull, dest);
break;
}
case TK_ISNULL:
case TK_NOTNULL: {
sqliteExprCode(pParse, pExpr->pLeft);
- sqliteVdbeAddOp(v, op, 0, dest);
+ sqliteVdbeAddOp(v, op, 1, dest);
break;
}
case TK_IN: {
+ int addr;
sqliteExprCode(pParse, pExpr->pLeft);
+ addr = sqliteVdbeCurrentAddr(v);
+ sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3);
+ sqliteVdbeAddOp(v, OP_Pop, 1, 0);
+ sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4);
if( pExpr->pSelect ){
sqliteVdbeAddOp(v, OP_NotFound, pExpr->iTable, dest);
}else{
@@ -1131,17 +1155,17 @@ void sqliteExprIfFalse(Parse *pParse, Expr *pExpr, int dest){
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
addr = sqliteVdbeCurrentAddr(v);
- sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
+ sqliteVdbeAddOp(v, OP_Ge, !jumpIfNull, addr+3);
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, dest);
sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
- sqliteVdbeAddOp(v, OP_Gt, 0, dest);
+ sqliteVdbeAddOp(v, OP_Gt, jumpIfNull, dest);
break;
}
default: {
sqliteExprCode(pParse, pExpr);
sqliteVdbeAddOp(v, OP_Not, 0, 0);
- sqliteVdbeAddOp(v, OP_If, 0, dest);
+ sqliteVdbeAddOp(v, OP_If, jumpIfNull, dest);
break;
}
}