diff options
author | drh <drh@noemail.net> | 2002-05-26 20:54:33 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2002-05-26 20:54:33 +0000 |
commit | f5905aa7be3a44909f108583ad07a54eeb60f37c (patch) | |
tree | 93fb95609d340f184aec2b23561de1d2dbbd3bcd /src | |
parent | 195e6967fb489401471c7ab99e3c4042d07347f4 (diff) | |
download | sqlite-f5905aa7be3a44909f108583ad07a54eeb60f37c.tar.gz sqlite-f5905aa7be3a44909f108583ad07a54eeb60f37c.zip |
NULL values are distinct. A comparison involving a NULL is always false.
Operations on a NULL value yield a NULL result. This change makes SQLite
operate more like the SQL spec, but it may break existing applications that
assumed the old behavior. All the old tests pass but we still need to add
new tests to better verify the new behavior. Fix for ticket #44. (CVS 589)
FossilOrigin-Name: 9051173742f1b0e15a809d12a0c9c98fd2c4614d
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 164 | ||||
-rw-r--r-- | src/insert.c | 26 | ||||
-rw-r--r-- | src/select.c | 18 | ||||
-rw-r--r-- | src/sqliteInt.h | 6 | ||||
-rw-r--r-- | src/trigger.c | 2 | ||||
-rw-r--r-- | src/vdbe.c | 257 | ||||
-rw-r--r-- | src/vdbe.h | 97 | ||||
-rw-r--r-- | src/where.c | 6 |
8 files changed, 375 insertions, 201 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; } } diff --git a/src/insert.c b/src/insert.c index 53c3e7696..1c9b9b4cb 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.58 2002/05/24 02:04:33 drh Exp $ +** $Id: insert.c,v 1.59 2002/05/26 20:54:33 drh Exp $ */ #include "sqliteInt.h" @@ -290,14 +290,12 @@ void sqliteInsert( if( srcTab>=0 ){ sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn); }else{ - int addr; sqliteExprCode(pParse, pList->a[keyColumn].pExpr); /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno ** to generate a unique primary key value. */ - addr = sqliteVdbeAddOp(v, OP_Dup, 0, 1); - sqliteVdbeAddOp(v, OP_NotNull, 0, addr+4); + sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_NewRecno, base, 0); } @@ -499,7 +497,7 @@ void sqliteGenerateConstraintChecks( int iCur; Index *pIdx; int seenReplace = 0; - int jumpInst; + int jumpInst1, jumpInst2; int contAddr; int hasTwoRecnos = (isUpdate && recnoChng); @@ -527,7 +525,7 @@ void sqliteGenerateConstraintChecks( onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1); - addr = sqliteVdbeAddOp(v, OP_NotNull, 0, 0); + addr = sqliteVdbeAddOp(v, OP_NotNull, 1, 0); switch( onError ){ case OE_Rollback: case OE_Abort: @@ -565,14 +563,13 @@ void sqliteGenerateConstraintChecks( if( onError==OE_Default ) onError = OE_Abort; } if( onError!=OE_Replace ){ - int jumpInst2; if( isUpdate ){ sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); - jumpInst2 = sqliteVdbeAddOp(v, OP_Eq, 0, 0); + jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0); } sqliteVdbeAddOp(v, OP_Dup, nCol, 1); - jumpInst = sqliteVdbeAddOp(v, OP_NotExists, base, 0); + jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0); switch( onError ){ case OE_Rollback: case OE_Abort: @@ -588,9 +585,9 @@ void sqliteGenerateConstraintChecks( default: assert(0); } contAddr = sqliteVdbeCurrentAddr(v); - sqliteVdbeChangeP2(v, jumpInst, contAddr); + sqliteVdbeChangeP2(v, jumpInst2, contAddr); if( isUpdate ){ - sqliteVdbeChangeP2(v, jumpInst2, contAddr); + sqliteVdbeChangeP2(v, jumpInst1, contAddr); sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1); sqliteVdbeAddOp(v, OP_MoveTo, base, 0); } @@ -609,7 +606,7 @@ void sqliteGenerateConstraintChecks( sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1); } } - sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); + jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); onError = pIdx->onError; if( onError==OE_None ) continue; if( overrideError!=OE_Default ){ @@ -619,7 +616,7 @@ void sqliteGenerateConstraintChecks( if( onError==OE_Default ) onError = OE_Abort; } sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1); - jumpInst = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); + jumpInst2 = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0); switch( onError ){ case OE_Rollback: case OE_Abort: @@ -645,7 +642,8 @@ void sqliteGenerateConstraintChecks( default: assert(0); } contAddr = sqliteVdbeCurrentAddr(v); - sqliteVdbeChangeP2(v, jumpInst, contAddr); + sqliteVdbeChangeP2(v, jumpInst1, contAddr); + sqliteVdbeChangeP2(v, jumpInst2, contAddr); } } diff --git a/src/select.c b/src/select.c index e4117f9d6..3be8650ce 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.85 2002/05/25 00:18:21 drh Exp $ +** $Id: select.c,v 1.86 2002/05/26 20:54:34 drh Exp $ */ #include "sqliteInt.h" @@ -325,13 +325,12 @@ static int selectInnerLoop( ** and this row has been seen before, then do not make this row ** part of the result. */ - if( distinct>=0 ){ - int lbl = sqliteVdbeMakeLabel(v); + if( distinct>=0 && pEList && pEList->nExpr>0 ){ + sqliteVdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqliteVdbeCurrentAddr(v)+7); sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1); - sqliteVdbeAddOp(v, OP_Distinct, distinct, lbl); + sqliteVdbeAddOp(v, OP_Distinct, distinct, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); - sqliteVdbeResolveLabel(v, lbl); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, distinct, 0); } @@ -359,8 +358,8 @@ static int selectInnerLoop( ** table iParm. */ if( eDest==SRT_Union ){ - sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); - sqliteVdbeAddOp(v, OP_String, iParm, 0); + sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 1); + sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); }else @@ -378,7 +377,7 @@ static int selectInnerLoop( ** the temporary table iParm. */ if( eDest==SRT_Except ){ - int addr = sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); + int addr = sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 1); sqliteVdbeAddOp(v, OP_NotFound, iParm, addr+3); sqliteVdbeAddOp(v, OP_Delete, iParm, 0); }else @@ -389,6 +388,7 @@ static int selectInnerLoop( */ if( eDest==SRT_Set ){ assert( nColumn==1 ); + sqliteVdbeAddOp(v, OP_IsNull, -1, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); }else @@ -1738,7 +1738,7 @@ int sqliteSelect( startagg = sqliteVdbeAddOp(v, OP_AggNext, 0, endagg); pParse->useAgg = 1; if( pHaving ){ - sqliteExprIfFalse(pParse, pHaving, startagg); + sqliteExprIfFalse(pParse, pHaving, startagg, 1); } if( selectInnerLoop(pParse, pEList, 0, 0, pOrderBy, distinct, eDest, iParm, startagg, endagg) ){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 77cfe6282..4fec92231 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.116 2002/05/25 00:18:21 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.117 2002/05/26 20:54:34 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -817,8 +817,8 @@ void sqliteUpdate(Parse*, Token*, ExprList*, Expr*, int); WhereInfo *sqliteWhereBegin(Parse*, int, SrcList*, Expr*, int); void sqliteWhereEnd(WhereInfo*); void sqliteExprCode(Parse*, Expr*); -void sqliteExprIfTrue(Parse*, Expr*, int); -void sqliteExprIfFalse(Parse*, Expr*, int); +void sqliteExprIfTrue(Parse*, Expr*, int, int); +void sqliteExprIfFalse(Parse*, Expr*, int, int); Table *sqliteFindTable(sqlite*,const char*); Index *sqliteFindIndex(sqlite*,const char*); void sqliteUnlinkAndDeleteIndex(sqlite*,Index*); diff --git a/src/trigger.c b/src/trigger.c index 48e7ecf79..82ba258a0 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -587,7 +587,7 @@ int sqliteCodeRowTrigger( sqliteExprDelete(whenExpr); return 1; } - sqliteExprIfFalse(pParse, whenExpr, endTrigger); + sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); sqliteExprDelete(whenExpr); codeTriggerProgram(pParse, pTrigger->step_list, orconf); diff --git a/src/vdbe.c b/src/vdbe.c index af42f9b52..fa558eb7c 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -30,7 +30,7 @@ ** But other routines are also provided to help in building up ** a program instruction by instruction. ** -** $Id: vdbe.c,v 1.148 2002/05/24 20:31:37 drh Exp $ +** $Id: vdbe.c,v 1.149 2002/05/26 20:54:34 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1068,17 +1068,17 @@ static char *zOpName[] = { 0, "AggFunc", "AggInit", "AggPush", "AggPop", "SetInsert", "SetFound", "SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey", "Goto", - "If", "Halt", "ColumnCount", "ColumnName", - "Callback", "NullCallback", "Integer", "String", - "Pop", "Dup", "Pull", "Push", - "MustBeInt", "Add", "AddImm", "Subtract", - "Multiply", "Divide", "Remainder", "BitAnd", - "BitOr", "BitNot", "ShiftLeft", "ShiftRight", - "AbsValue", "Eq", "Ne", "Lt", - "Le", "Gt", "Ge", "IsNull", - "NotNull", "Negative", "And", "Or", - "Not", "Concat", "Noop", "Function", - "Limit", + "If", "IfNot", "Halt", "ColumnCount", + "ColumnName", "Callback", "NullCallback", "Integer", + "String", "Pop", "Dup", "Pull", + "Push", "MustBeInt", "Add", "AddImm", + "Subtract", "Multiply", "Divide", "Remainder", + "BitAnd", "BitOr", "BitNot", "ShiftLeft", + "ShiftRight", "AbsValue", "Eq", "Ne", + "Lt", "Le", "Gt", "Ge", + "IsNull", "NotNull", "Negative", "And", + "Or", "Not", "Concat", "Noop", + "Function", "Limit", }; /* @@ -1280,6 +1280,7 @@ int sqliteVdbeExec( sqlite *db = p->db; /* The database */ char **zStack; /* Text stack */ Stack *aStack; /* Additional stack information */ + unsigned uniqueCnt = 0; /* Used by OP_MakeRecord when P2!=0 */ int errorAction = OE_Abort; /* Recovery action to do in case of an error */ int undoTransOnError = 0; /* If error, either ROLLBACK or COMMIT */ char zBuf[100]; /* Space to sprintf() an integer */ @@ -1719,6 +1720,7 @@ case OP_Concat: { ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the addition. +** If either operand is NULL, the result is NULL. */ /* Opcode: Multiply * * * ** @@ -1726,6 +1728,7 @@ case OP_Concat: { ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the multiplication. +** If either operand is NULL, the result is NULL. */ /* Opcode: Subtract * * * ** @@ -1735,6 +1738,7 @@ case OP_Concat: { ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the subtraction. +** If either operand is NULL, the result is NULL. */ /* Opcode: Divide * * * ** @@ -1744,6 +1748,7 @@ case OP_Concat: { ** and push the result back onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the division. Division by zero returns NULL. +** If either operand is NULL, the result is NULL. */ /* Opcode: Remainder * * * ** @@ -1753,6 +1758,7 @@ case OP_Concat: { ** and push the remainder after division onto the stack. If either element ** is a string then it is converted to a double using the atof() ** function before the division. Division by zero returns NULL. +** If either operand is NULL, the result is NULL. */ case OP_Add: case OP_Subtract: @@ -1762,7 +1768,11 @@ case OP_Remainder: { int tos = p->tos; int nos = tos - 1; VERIFY( if( nos<0 ) goto not_enough_stack; ) - if( (aStack[tos].flags & aStack[nos].flags & STK_Int)==STK_Int ){ + if( ((aStack[tos].flags | aStack[nos].flags) & STK_Null)!=0 ){ + POPSTACK; + Release(p, nos); + aStack[nos].flags = STK_Null; + }else if( (aStack[tos].flags & aStack[nos].flags & STK_Int)==STK_Int ){ int a, b; a = aStack[tos].i; b = aStack[nos].i; @@ -1838,7 +1848,9 @@ case OP_Function: { VERIFY( if( n<0 ) goto bad_instruction; ) VERIFY( if( p->tos+1<n ) goto not_enough_stack; ) for(i=p->tos-n+1; i<=p->tos; i++){ - if( (aStack[i].flags & STK_Null)==0 ){ + if( aStack[i].flags & STK_Null ){ + zStack[i] = 0; + }else{ if( Stringify(p, i) ) goto no_mem; } } @@ -1872,24 +1884,28 @@ case OP_Function: { ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the bit-wise AND of the ** two elements. +** If either operand is NULL, the result is NULL. */ /* Opcode: BitOr * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the bit-wise OR of the ** two elements. +** If either operand is NULL, the result is NULL. */ /* Opcode: ShiftLeft * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the top element shifted ** left by N bits where N is the second element on the stack. +** If either operand is NULL, the result is NULL. */ /* Opcode: ShiftRight * * * ** ** Pop the top two elements from the stack. Convert both elements ** to integers. Push back onto the stack the top element shifted ** right by N bits where N is the second element on the stack. +** If either operand is NULL, the result is NULL. */ case OP_BitAnd: case OP_BitOr: @@ -1899,6 +1915,12 @@ case OP_ShiftRight: { int nos = tos - 1; int a, b; VERIFY( if( nos<0 ) goto not_enough_stack; ) + if( (aStack[tos].flags | aStack[nos].flags) & STK_Null ){ + POPSTACK; + Release(p,nos); + aStack[nos].flags = STK_Null; + break; + } Integerify(p, tos); Integerify(p, nos); a = aStack[tos].i; @@ -1973,40 +1995,82 @@ mismatch: break; } -/* Opcode: Eq * P2 * +/* Opcode: Eq P1 P2 * ** ** Pop the top two elements from the stack. If they are equal, then ** jump to instruction P2. Otherwise, continue to the next instruction. +** +** If either operand is NULL (and thus if the result is unknown) then +** take the jump if P1 is true. +** +** If P2 is zero, do not jump. Instead, push an integer 1 onto the +** stack if the jump would have been taken, or a 0 if not. Push a +** NULL if either operand was NULL. */ -/* Opcode: Ne * P2 * +/* Opcode: Ne P1 P2 * ** ** Pop the top two elements from the stack. If they are not equal, then ** jump to instruction P2. Otherwise, continue to the next instruction. +** +** If either operand is NULL (and thus if the result is unknown) then +** take the jump if P1 is true. +** +** If P2 is zero, do not jump. Instead, push an integer 1 onto the +** stack if the jump would have been taken, or a 0 if not. Push a +** NULL if either operand was NULL. */ -/* Opcode: Lt * P2 * +/* Opcode: Lt P1 P2 * ** ** Pop the top two elements from the stack. If second element (the ** next on stack) is less than the first (the top of stack), then ** jump to instruction P2. Otherwise, continue to the next instruction. ** In other words, jump if NOS<TOS. +** +** If either operand is NULL (and thus if the result is unknown) then +** take the jump if P1 is true. +** +** If P2 is zero, do not jump. Instead, push an integer 1 onto the +** stack if the jump would have been taken, or a 0 if not. Push a +** NULL if either operand was NULL. */ -/* Opcode: Le * P2 * +/* Opcode: Le P1 P2 * ** ** Pop the top two elements from the stack. If second element (the ** next on stack) is less than or equal to the first (the top of stack), ** then jump to instruction P2. In other words, jump if NOS<=TOS. +** +** If either operand is NULL (and thus if the result is unknown) then +** take the jump if P1 is true. +** +** If P2 is zero, do not jump. Instead, push an integer 1 onto the +** stack if the jump would have been taken, or a 0 if not. Push a +** NULL if either operand was NULL. */ -/* Opcode: Gt * P2 * +/* Opcode: Gt P1 P2 * ** ** Pop the top two elements from the stack. If second element (the ** next on stack) is greater than the first (the top of stack), ** then jump to instruction P2. In other words, jump if NOS>TOS. +** +** If either operand is NULL (and thus if the result is unknown) then +** take the jump if P1 is true. +** +** If P2 is zero, do not jump. Instead, push an integer 1 onto the +** stack if the jump would have been taken, or a 0 if not. Push a +** NULL if either operand was NULL. */ -/* Opcode: Ge * P2 * +/* Opcode: Ge P1 P2 * ** ** Pop the top two elements from the stack. If second element (the next ** on stack) is greater than or equal to the first (the top of stack), ** then jump to instruction P2. In other words, jump if NOS>=TOS. +** +** If either operand is NULL (and thus if the result is unknown) then +** take the jump if P1 is true. +** +** If P2 is zero, do not jump. Instead, push an integer 1 onto the +** stack if the jump would have been taken, or a 0 if not. Push a +** NULL if either operand was NULL. */ case OP_Eq: case OP_Ne: @@ -2021,7 +2085,17 @@ case OP_Ge: { VERIFY( if( nos<0 ) goto not_enough_stack; ) ft = aStack[tos].flags; fn = aStack[nos].flags; - if( (ft & fn & STK_Int)==STK_Int ){ + if( (ft | fn) & STK_Null ){ + POPSTACK; + POPSTACK; + if( pOp->p2 ){ + if( pOp->p1 ) pc = pOp->p2-1; + }else{ + p->tos++; + aStack[nos].flags = STK_Null; + } + break; + }else if( (ft & fn & STK_Int)==STK_Int ){ c = aStack[nos].i - aStack[tos].i; }else if( (ft & STK_Int)!=0 && (fn & STK_Str)!=0 && isInteger(zStack[nos]) ){ Integerify(p, nos); @@ -2043,7 +2117,13 @@ case OP_Ge: { } POPSTACK; POPSTACK; - if( c ) pc = pOp->p2-1; + if( pOp->p2 ){ + if( c ) pc = pOp->p2-1; + }else{ + p->tos++; + aStack[nos].flags = STK_Int; + aStack[nos].i = c; + } break; } @@ -2052,12 +2132,14 @@ case OP_Ge: { ** Pop two values off the stack. Take the logical AND of the ** two values and push the resulting boolean value back onto the ** stack. +** If either operand is NULL, the result is NULL. */ /* Opcode: Or * * * ** ** Pop two values off the stack. Take the logical OR of the ** two values and push the resulting boolean value back onto the ** stack. +** If either operand is NULL, the result is NULL. */ case OP_And: case OP_Or: { @@ -2065,6 +2147,12 @@ case OP_Or: { int nos = tos - 1; int c; VERIFY( if( nos<0 ) goto not_enough_stack; ) + if( (aStack[tos].flags | aStack[nos].flags) & STK_Null ){ + POPSTACK; + Release(p, nos); + aStack[nos].flags = STK_Null; + break; + } Integerify(p, tos); Integerify(p, nos); if( pOp->opcode==OP_And ){ @@ -2082,12 +2170,14 @@ case OP_Or: { /* Opcode: Negative * * * ** ** Treat the top of the stack as a numeric quantity. Replace it -** with its additive inverse. +** with its additive inverse. If the top of the stack is NULL +** its value is unchanged. */ /* Opcode: AbsValue * * * ** ** Treat the top of the stack as a numeric quantity. Replace it -** with its absolute value. +** with its absolute value. If the top of the stack is NULL +** its value is unchanged. */ case OP_Negative: case OP_AbsValue: { @@ -2105,6 +2195,8 @@ case OP_AbsValue: { aStack[tos].i = -aStack[tos].i; } aStack[tos].flags = STK_Int; + }else if( aStack[tos].flags & STK_Null ){ + /* Do nothing */ }else{ Realify(p, tos); Release(p, tos); @@ -2119,11 +2211,13 @@ case OP_AbsValue: { /* Opcode: Not * * * ** ** Interpret the top of the stack as a boolean value. Replace it -** with its complement. +** with its complement. If the top of the stack is NULL its value +** is unchanged. */ case OP_Not: { int tos = p->tos; VERIFY( if( p->tos<0 ) goto not_enough_stack; ) + if( aStack[tos].flags & STK_Null ) break; /* Do nothing to NULLs */ Integerify(p, tos); Release(p, tos); aStack[tos].i = !aStack[tos].i; @@ -2134,11 +2228,13 @@ case OP_Not: { /* Opcode: BitNot * * * ** ** Interpret the top of the stack as an value. Replace it -** with its ones-complement. +** with its ones-complement. If the top of the stack is NULL its +** value is unchanged. */ case OP_BitNot: { int tos = p->tos; VERIFY( if( p->tos<0 ) goto not_enough_stack; ) + if( aStack[tos].flags & STK_Null ) break; /* Do nothing to NULLs */ Integerify(p, tos); Release(p, tos); aStack[tos].i = ~aStack[tos].i; @@ -2155,60 +2251,92 @@ case OP_Noop: { break; } -/* Opcode: If * P2 * +/* Opcode: If P1 P2 * ** ** Pop a single boolean from the stack. If the boolean popped is ** true, then jump to p2. Otherwise continue to the next instruction. ** An integer is false if zero and true otherwise. A string is ** false if it has zero length and true otherwise. +** +** If the value popped of the stack is NULL, then take the jump if P1 +** is true and fall through if P1 is false. +*/ +/* Opcode: IfNot P1 P2 * +** +** Pop a single boolean from the stack. If the boolean popped is +** false, then jump to p2. Otherwise continue to the next instruction. +** An integer is false if zero and true otherwise. A string is +** false if it has zero length and true otherwise. +** +** If the value popped of the stack is NULL, then take the jump if P1 +** is true and fall through if P1 is false. */ -case OP_If: { +case OP_If: +case OP_IfNot: { int c; VERIFY( if( p->tos<0 ) goto not_enough_stack; ) - Integerify(p, p->tos); - c = aStack[p->tos].i; + if( aStack[p->tos].flags & STK_Null ){ + c = pOp->p1; + }else{ + Integerify(p, p->tos); + c = aStack[p->tos].i; + if( pOp->opcode==OP_IfNot ) c = !c; + } POPSTACK; if( c ) pc = pOp->p2-1; break; } -/* Opcode: IsNull * P2 * +/* Opcode: IsNull P1 P2 * ** -** Pop a single value from the stack. If the value popped is NULL -** then jump to p2. Otherwise continue to the next -** instruction. +** If any of the top abs(P1) values on the stack are NULL, then jump +** to P2. The stack is popped P1 times if P1>0. If P1<0 then all values +** are left unchanged on the stack. */ case OP_IsNull: { - int c; - VERIFY( if( p->tos<0 ) goto not_enough_stack; ) - c = (aStack[p->tos].flags & STK_Null)!=0; - POPSTACK; - if( c ) pc = pOp->p2-1; + int i, cnt; + cnt = pOp->p1; + if( cnt<0 ) cnt = -cnt; + VERIFY( if( p->tos+1-cnt<0 ) goto not_enough_stack; ) + for(i=0; i<cnt; i++){ + if( aStack[p->tos-i].flags & STK_Null ){ + pc = pOp->p2-1; + break; + } + } + if( pOp->p1>0 ) PopStack(p, cnt); break; } -/* Opcode: NotNull * P2 * +/* Opcode: NotNull P1 P2 * ** -** Pop a single value from the stack. If the value popped is not -** NULL, then jump to p2. Otherwise continue to the next -** instruction. +** Jump to P2 if the top value on the stack is not NULL. Pop the +** stack if P1 is greater than zero. If P1 is less than or equal to +** zero then leave the value on the stack. */ case OP_NotNull: { - int c; VERIFY( if( p->tos<0 ) goto not_enough_stack; ) - c = (aStack[p->tos].flags & STK_Null)==0; - POPSTACK; - if( c ) pc = pOp->p2-1; + if( (aStack[p->tos].flags & STK_Null)==0 ) pc = pOp->p2-1; + if( pOp->p1>0 ){ POPSTACK; } break; } -/* Opcode: MakeRecord P1 * * +/* Opcode: MakeRecord P1 P2 * ** ** Convert the top P1 entries of the stack into a single entry ** suitable for use as a data record in a database table. The ** details of the format are irrelavant as long as the OP_Column ** opcode can decode the record later. Refer to source code ** comments for the details of the record format. +** +** If P2 is true (non-zero) and one or more of the P1 entries +** that go into building the record is NULL, then add some extra +** bytes to the record to make it distinct for other entries created +** during the same run of the VDBE. The extra bytes added are a +** counter that is reset with each run of the VDBE, so records +** created this way will not necessarily be distinct across runs. +** But they should be distinct for transient tables (created using +** OP_OpenTemp) which is what they are intended for. */ case OP_MakeRecord: { char *zNewRecord; @@ -2217,6 +2345,8 @@ case OP_MakeRecord: { int i, j; int idxWidth; u32 addr; + int addUnique = 0; /* True to cause bytes to be added to make the + ** generated record distinct */ /* Assuming the record contains N fields, the record format looks ** like this: @@ -2240,11 +2370,14 @@ case OP_MakeRecord: { VERIFY( if( p->tos+1<nField ) goto not_enough_stack; ) nByte = 0; for(i=p->tos-nField+1; i<=p->tos; i++){ - if( (aStack[i].flags & STK_Null)==0 ){ + if( (aStack[i].flags & STK_Null) ){ + addUnique = pOp->p2; + }else{ if( Stringify(p, i) ) goto no_mem; nByte += aStack[i].n; } } + if( addUnique ) nByte += sizeof(uniqueCnt); if( nByte + nField + 1 < 256 ){ idxWidth = 1; }else if( nByte + 2*nField + 2 < 65536 ){ @@ -2260,7 +2393,7 @@ case OP_MakeRecord: { zNewRecord = sqliteMalloc( nByte ); if( zNewRecord==0 ) goto no_mem; j = 0; - addr = idxWidth*(nField+1); + addr = idxWidth*(nField+1) + addUnique*sizeof(uniqueCnt); for(i=p->tos-nField+1; i<=p->tos; i++){ zNewRecord[j++] = addr & 0xff; if( idxWidth>1 ){ @@ -2280,6 +2413,11 @@ case OP_MakeRecord: { zNewRecord[j++] = (addr>>16)&0xff; } } + if( addUnique ){ + memcpy(&zNewRecord[j], &uniqueCnt, sizeof(uniqueCnt)); + uniqueCnt++; + j += sizeof(uniqueCnt); + } for(i=p->tos-nField+1; i<=p->tos; i++){ if( (aStack[i].flags & STK_Null)==0 ){ memcpy(&zNewRecord[j], zStack[i], aStack[i].n); @@ -2311,7 +2449,7 @@ case OP_MakeRecord: { ** ** See also: MakeIdxKey, SortMakeKey */ -/* Opcode: MakeIdxKey P1 * * +/* Opcode: MakeIdxKey P1 P2 * ** ** Convert the top P1 entries of the stack into a single entry suitable ** for use as the key in an index. In addition, take one additional integer @@ -2327,6 +2465,12 @@ case OP_MakeRecord: { ** in the stack is the first field and the top of the stack becomes the ** last. ** +** If P2 is not zero and one or more of the P1 entries that go into the +** generated key is NULL, then jump to P2 after the new key has been +** pushed on the stack. In other words, jump to P2 if the key is +** guaranteed to be unique. This jump can be used to skip a subsequent +** uniqueness test. +** ** See also: MakeKey, SortMakeKey */ case OP_MakeIdxKey: @@ -2336,6 +2480,7 @@ case OP_MakeKey: { int nField; int addRowid; int i, j; + int containsNull = 0; addRowid = pOp->opcode==OP_MakeIdxKey; nField = pOp->p1; @@ -2347,6 +2492,7 @@ case OP_MakeKey: { char *z; if( flags & STK_Null ){ nByte += 2; + containsNull = 1; }else if( flags & STK_Real ){ z = aStack[i].z; sqliteRealToSortable(aStack[i].r, &z[1]); @@ -2406,8 +2552,11 @@ case OP_MakeKey: { Integerify(p, p->tos-nField); iKey = intToKey(aStack[p->tos-nField].i); memcpy(&zNewKey[j], &iKey, sizeof(u32)); + PopStack(p, nField+1); + if( pOp->p2 && containsNull ) pc = pOp->p2 - 1; + }else{ + if( pOp->p2==0 ) PopStack(p, nField+addRowid); } - if( pOp->p2==0 ) PopStack(p, nField+addRowid); VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].n = nByte; @@ -4373,7 +4522,9 @@ case OP_AggFunc: { VERIFY( if( p->tos+1<n ) goto not_enough_stack; ) VERIFY( if( aStack[p->tos].flags!=STK_Int ) goto bad_instruction; ) for(i=p->tos-n; i<p->tos; i++){ - if( (aStack[i].flags & STK_Null)==0 ){ + if( aStack[i].flags & STK_Null ){ + zStack[i] = 0; + }else{ if( Stringify(p, i) ) goto no_mem; } } diff --git a/src/vdbe.h b/src/vdbe.h index 23410437e..42e9a07b0 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.52 2002/05/23 22:07:03 drh Exp $ +** $Id: vdbe.h,v 1.53 2002/05/26 20:54:34 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -157,53 +157,54 @@ typedef struct VdbeOp VdbeOp; #define OP_Goto 76 #define OP_If 77 -#define OP_Halt 78 - -#define OP_ColumnCount 79 -#define OP_ColumnName 80 -#define OP_Callback 81 -#define OP_NullCallback 82 - -#define OP_Integer 83 -#define OP_String 84 -#define OP_Pop 85 -#define OP_Dup 86 -#define OP_Pull 87 -#define OP_Push 88 -#define OP_MustBeInt 89 - -#define OP_Add 90 -#define OP_AddImm 91 -#define OP_Subtract 92 -#define OP_Multiply 93 -#define OP_Divide 94 -#define OP_Remainder 95 -#define OP_BitAnd 96 -#define OP_BitOr 97 -#define OP_BitNot 98 -#define OP_ShiftLeft 99 -#define OP_ShiftRight 100 -#define OP_AbsValue 101 -#define OP_Eq 102 -#define OP_Ne 103 -#define OP_Lt 104 -#define OP_Le 105 -#define OP_Gt 106 -#define OP_Ge 107 -#define OP_IsNull 108 -#define OP_NotNull 109 -#define OP_Negative 110 -#define OP_And 111 -#define OP_Or 112 -#define OP_Not 113 -#define OP_Concat 114 -#define OP_Noop 115 -#define OP_Function 116 - -#define OP_Limit 117 - - -#define OP_MAX 117 +#define OP_IfNot 78 +#define OP_Halt 79 + +#define OP_ColumnCount 80 +#define OP_ColumnName 81 +#define OP_Callback 82 +#define OP_NullCallback 83 + +#define OP_Integer 84 +#define OP_String 85 +#define OP_Pop 86 +#define OP_Dup 87 +#define OP_Pull 88 +#define OP_Push 89 +#define OP_MustBeInt 90 + +#define OP_Add 91 +#define OP_AddImm 92 +#define OP_Subtract 93 +#define OP_Multiply 94 +#define OP_Divide 95 +#define OP_Remainder 96 +#define OP_BitAnd 97 +#define OP_BitOr 98 +#define OP_BitNot 99 +#define OP_ShiftLeft 100 +#define OP_ShiftRight 101 +#define OP_AbsValue 102 +#define OP_Eq 103 +#define OP_Ne 104 +#define OP_Lt 105 +#define OP_Le 106 +#define OP_Gt 107 +#define OP_Ge 108 +#define OP_IsNull 109 +#define OP_NotNull 110 +#define OP_Negative 111 +#define OP_And 112 +#define OP_Or 113 +#define OP_Not 114 +#define OP_Concat 115 +#define OP_Noop 116 +#define OP_Function 117 + +#define OP_Limit 118 + + +#define OP_MAX 118 /* ** Prototypes for the VDBE interface. See comments on the implementation diff --git a/src/where.c b/src/where.c index a3576cae4..0f14df9de 100644 --- a/src/where.c +++ b/src/where.c @@ -13,7 +13,7 @@ ** the WHERE clause of SQL statements. Also found here are subroutines ** to generate VDBE code to evaluate expressions. ** -** $Id: where.c,v 1.47 2002/05/24 20:31:38 drh Exp $ +** $Id: where.c,v 1.48 2002/05/26 20:54:34 drh Exp $ */ #include "sqliteInt.h" @@ -199,7 +199,7 @@ WhereInfo *sqliteWhereBegin( ** expression and either jump over all of the code or fall thru. */ if( pWhere && sqliteExprIsConstant(pWhere) ){ - sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak); + sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1); } /* Split the WHERE clause into as many as 32 separate subexpressions @@ -795,7 +795,7 @@ WhereInfo *sqliteWhereBegin( haveKey = 0; sqliteVdbeAddOp(v, OP_MoveTo, base+idx, 0); } - sqliteExprIfFalse(pParse, aExpr[j].p, cont); + sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1); aExpr[j].p = 0; } brk = cont; |