aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c164
-rw-r--r--src/insert.c26
-rw-r--r--src/select.c18
-rw-r--r--src/sqliteInt.h6
-rw-r--r--src/trigger.c2
-rw-r--r--src/vdbe.c257
-rw-r--r--src/vdbe.h97
-rw-r--r--src/where.c6
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;