Code cleanup and simplification.  Three new Mem opcodes added.
The sqlite3VdbeJumpHere function added. (CVS 2730)

FossilOrigin-Name: 2471957feee57538e5e1e50a704a337f0927d10e
diff --git a/src/analyze.c b/src/analyze.c
index 855f894..67d80d5 100644
--- a/src/analyze.c
+++ b/src/analyze.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code associated with the ANALYZE command.
 **
-** @(#) $Id: analyze.c,v 1.8 2005/09/10 22:40:54 drh Exp $
+** @(#) $Id: analyze.c,v 1.9 2005/09/20 17:42:23 drh Exp $
 */
 #ifndef SQLITE_OMIT_ANALYZE
 #include "sqliteInt.h"
@@ -127,13 +127,11 @@
     ** Cells iMem through iMem+nCol are initialized to 0.  The others
     ** are initialized to NULL.
     */
-    sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
     for(i=0; i<=nCol; i++){
-      sqlite3VdbeAddOp(v, OP_MemStore, iMem+i, i==nCol);
+      sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i);
     }
-    sqlite3VdbeAddOp(v, OP_Null, 0, 0);
     for(i=0; i<nCol; i++){
-      sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, i==nCol-1);
+      sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0);
     }
 
     /* Do the analysis.
@@ -198,7 +196,7 @@
     }
     sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0);
     sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
-    sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
+    sqlite3VdbeJumpHere(v, addr);
   }
 }
 
diff --git a/src/build.c b/src/build.c
index 117bdff..9857a8e 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.350 2005/09/16 02:48:02 drh Exp $
+** $Id: build.c,v 1.351 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -76,7 +76,7 @@
     if( pParse->cookieGoto>0 ){
       u32 mask;
       int iDb;
-      sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v));
+      sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
       for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
         if( (mask & pParse->cookieMask)==0 ) continue;
         sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
@@ -2002,7 +2002,7 @@
   }
   sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0);
   sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
-  sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v));
+  sqlite3VdbeJumpHere(v, addr1);
   sqlite3VdbeAddOp(v, OP_Close, iTab, 0);
   sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
 }
diff --git a/src/delete.c b/src/delete.c
index b472ddd..4f5b8a3 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.110 2005/09/08 01:58:43 drh Exp $
+** $Id: delete.c,v 1.111 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -380,7 +380,7 @@
   addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
   sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
   sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
-  sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
+  sqlite3VdbeJumpHere(v, addr);
 }
 
 /*
diff --git a/src/expr.c b/src/expr.c
index 6324068..c77c354 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.228 2005/09/16 02:38:10 drh Exp $
+** $Id: expr.c,v 1.229 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1292,8 +1292,7 @@
     sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
     testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
     assert( testAddr>0 || sqlite3_malloc_failed );
-    sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
-    sqlite3VdbeAddOp(v, OP_MemStore, mem, 1);
+    sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
   }
 
   switch( pExpr->op ){
@@ -1367,7 +1366,7 @@
           if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
             VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
             int i;
-            for(i=0; i<4; i++){
+            for(i=0; i<3; i++){
               aOp[i].opcode = OP_Noop;
             }
             testAddr = 0;
@@ -1409,7 +1408,7 @@
   }
 
   if( testAddr ){
-    sqlite3VdbeChangeP2(v, testAddr, sqlite3VdbeCurrentAddr(v));
+    sqlite3VdbeJumpHere(v, testAddr);
   }
   return;
 }
@@ -1709,7 +1708,6 @@
     case TK_CASE: {
       int expr_end_label;
       int jumpInst;
-      int addr;
       int nExpr;
       int i;
       ExprList *pEList;
@@ -1737,8 +1735,7 @@
         }
         sqlite3ExprCode(pParse, aListelem[i+1].pExpr);
         sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label);
-        addr = sqlite3VdbeCurrentAddr(v);
-        sqlite3VdbeChangeP2(v, jumpInst, addr);
+        sqlite3VdbeJumpHere(v, jumpInst);
       }
       if( pExpr->pLeft ){
         sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
@@ -1905,7 +1902,7 @@
       codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull);
 
       sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
-      sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
+      sqlite3VdbeJumpHere(v, addr);
       sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
       break;
     }
diff --git a/src/insert.c b/src/insert.c
index 428c8cd..e19aa7d 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.142 2005/07/21 18:23:20 drh Exp $
+** $Id: insert.c,v 1.143 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -372,13 +372,13 @@
       ** of the program jumps to it.  Create the temporary table, then jump
       ** back up and execute the SELECT code above.
       */
-      sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
+      sqlite3VdbeJumpHere(v, iInitCode);
       sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0);
       sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
       sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
       sqlite3VdbeResolveLabel(v, iCleanup);
     }else{
-      sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
+      sqlite3VdbeJumpHere(v, iInitCode);
     }
   }else{
     /* This is the case if the data for the INSERT is coming from a VALUES
@@ -470,8 +470,7 @@
   */
   if( db->flags & SQLITE_CountRows ){
     iCntMem = pParse->nMem++;
-    sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
-    sqlite3VdbeAddOp(v, OP_MemStore, iCntMem, 1);
+    sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem);
   }
 
   /* Open tables and indices if there are no row triggers */
@@ -817,7 +816,6 @@
   Index *pIdx;
   int seenReplace = 0;
   int jumpInst1=0, jumpInst2;
-  int contAddr;
   int hasTwoRowids = (isUpdate && rowidChng);
 
   v = sqlite3GetVdbe(pParse);
@@ -867,7 +865,7 @@
         break;
       }
     }
-    sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
+    sqlite3VdbeJumpHere(v, addr);
   }
 
   /* Test all CHECK constraints
@@ -921,10 +919,9 @@
         break;
       }
     }
-    contAddr = sqlite3VdbeCurrentAddr(v);
-    sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
+    sqlite3VdbeJumpHere(v, jumpInst2);
     if( isUpdate ){
-      sqlite3VdbeChangeP2(v, jumpInst1, contAddr);
+      sqlite3VdbeJumpHere(v, jumpInst1);
       sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
       sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
     }
@@ -1018,11 +1015,10 @@
         break;
       }
     }
-    contAddr = sqlite3VdbeCurrentAddr(v);
 #if NULL_DISTINCT_FOR_UNIQUE
-    sqlite3VdbeChangeP2(v, jumpInst1, contAddr);
+    sqlite3VdbeJumpHere(v, jumpInst1);
 #endif
-    sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
+    sqlite3VdbeJumpHere(v, jumpInst2);
   }
 }
 
diff --git a/src/pragma.c b/src/pragma.c
index 6179548..445ff36 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -11,7 +11,7 @@
 *************************************************************************
 ** This file contains code used to implement the PRAGMA command.
 **
-** $Id: pragma.c,v 1.99 2005/09/17 16:36:56 drh Exp $
+** $Id: pragma.c,v 1.100 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -626,14 +626,6 @@
   if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
     int i, j, addr;
 
-    /* Code that initializes the integrity check program.  Set the
-    ** error count 0
-    */
-    static const VdbeOpList initCode[] = {
-      { OP_Integer,     0, 0,        0},
-      { OP_MemStore,    0, 1,        0},
-    };
-
     /* Code that appears at the end of the integrity check.  If no error
     ** messages have been generated, output OK.  Otherwise output the
     ** error message
@@ -650,7 +642,7 @@
     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
     sqlite3VdbeSetNumCols(v, 1);
     sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
-    sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode);
+    sqlite3VdbeAddOp(v, OP_MemInt, 0, 0);  /* Initialize error count to 0 */
 
     /* Do an integrity check on each database file */
     for(i=0; i<db->nDb; i++){
@@ -696,8 +688,7 @@
 
         if( pTab->pIndex==0 ) continue;
         sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
-        sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
-        sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
+        sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
         loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
         sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
@@ -715,39 +706,38 @@
           jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
           addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
           sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
-          sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v));
+          sqlite3VdbeJumpHere(v, jmp2);
         }
         sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
-        sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(v));
+        sqlite3VdbeJumpHere(v, loopTop);
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
           static const VdbeOpList cntIdx[] = {
-             { OP_Integer,      0,  0,  0},
-             { OP_MemStore,     2,  1,  0},
-             { OP_Rewind,       0,  0,  0},  /* 2 */
+             { OP_MemInt,       0,  2,  0},
+             { OP_Rewind,       0,  0,  0},  /* 1 */
              { OP_MemIncr,      2,  0,  0},
-             { OP_Next,         0,  0,  0},  /* 4 */
+             { OP_Next,         0,  0,  0},  /* 3 */
              { OP_MemLoad,      1,  0,  0},
              { OP_MemLoad,      2,  0,  0},
-             { OP_Eq,           0,  0,  0},  /* 7 */
+             { OP_Eq,           0,  0,  0},  /* 6 */
              { OP_MemIncr,      0,  0,  0},
              { OP_String8,      0,  0,  "wrong # of entries in index "},
-             { OP_String8,      0,  0,  0},  /* 10 */
+             { OP_String8,      0,  0,  0},  /* 9 */
              { OP_Concat,       0,  0,  0},
              { OP_Callback,     1,  0,  0},
           };
           if( pIdx->tnum==0 ) continue;
           addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
-          sqlite3VdbeChangeP1(v, addr+2, j+2);
-          sqlite3VdbeChangeP2(v, addr+2, addr+5);
-          sqlite3VdbeChangeP1(v, addr+4, j+2);
-          sqlite3VdbeChangeP2(v, addr+4, addr+3);
-          sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
-          sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
+          sqlite3VdbeChangeP1(v, addr+1, j+2);
+          sqlite3VdbeChangeP2(v, addr+1, addr+4);
+          sqlite3VdbeChangeP1(v, addr+3, j+2);
+          sqlite3VdbeChangeP2(v, addr+3, addr+2);
+          sqlite3VdbeJumpHere(v, addr+6);
+          sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
         }
       } 
     }
     addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
-    sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
+    sqlite3VdbeJumpHere(v, addr+2);
   }else
 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
 
diff --git a/src/select.c b/src/select.c
index 118bc3b..5065be8 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.274 2005/09/20 13:55:18 drh Exp $
+** $Id: select.c,v 1.275 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -543,7 +543,7 @@
         sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1);
         sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
       }
-      sqlite3VdbeChangeP2(v, addr2, sqlite3VdbeCurrentAddr(v));
+      sqlite3VdbeJumpHere(v, addr2);
       break;
     }
 
@@ -2448,17 +2448,15 @@
 static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
   Vdbe *v = pParse->pVdbe;
   int i;
-  int addr;
   struct AggInfo_func *pFunc;
   if( pAggInfo->nFunc+pAggInfo->nColumn==0 ){
     return;
   }
-  sqlite3VdbeAddOp(v, OP_Null, 0, 0);
   for(i=0; i<pAggInfo->nColumn; i++){
-    addr = sqlite3VdbeAddOp(v, OP_MemStore, pAggInfo->aCol[i].iMem, 0);
+    sqlite3VdbeAddOp(v, OP_MemNull, pAggInfo->aCol[i].iMem, 0);
   }
   for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
-    addr = sqlite3VdbeAddOp(v, OP_MemStore, pFunc->iMem, 0);
+    sqlite3VdbeAddOp(v, OP_MemNull, pFunc->iMem, 0);
     if( pFunc->iDistinct>=0 ){
       Expr *pE = pFunc->pExpr;
       if( pE->pList==0 || pE->pList->nExpr!=1 ){
@@ -2472,7 +2470,6 @@
       }
     }
   }
-  sqlite3VdbeChangeP2(v, addr, 1);
 }
 
 /*
@@ -2786,9 +2783,10 @@
 
   /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists
   */
-  if( eDest==SRT_Mem || eDest==SRT_Exists ){
-    sqlite3VdbeAddOp(v, eDest==SRT_Mem ? OP_Null : OP_Integer, 0, 0);
-    sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1);
+  if( eDest==SRT_Mem ){
+    sqlite3VdbeAddOp(v, OP_MemNull, iParm, 0);
+  }else if( eDest==SRT_Exists ){
+    sqlite3VdbeAddOp(v, OP_MemInt, 0, iParm);
   }
 
   /* Open a virtual index to use for the distinct set.
@@ -2916,11 +2914,9 @@
       pParse->nMem += pGroupBy->nExpr;
       iBMem = pParse->nMem;
       pParse->nMem += pGroupBy->nExpr;
-      sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
-      sqlite3VdbeAddOp(v, OP_MemStore, iAbortFlag, 0);
-      sqlite3VdbeAddOp(v, OP_MemStore, iUseFlag, 1);
-      sqlite3VdbeAddOp(v, OP_Null, 0, 0);
-      sqlite3VdbeAddOp(v, OP_MemStore, iAMem, 1);
+      sqlite3VdbeAddOp(v, OP_MemInt, 0, iAbortFlag);
+      sqlite3VdbeAddOp(v, OP_MemInt, 0, iUseFlag);
+      sqlite3VdbeAddOp(v, OP_MemNull, iAMem, 0);
       sqlite3VdbeAddOp(v, OP_Goto, 0, addrInitializeLoop);
 
       /* Generate a subroutine that outputs a single row of the result
@@ -3036,8 +3032,7 @@
       */
       sqlite3VdbeResolveLabel(v, addrGroupByChange);
       for(j=0; j<pGroupBy->nExpr; j++){
-        sqlite3VdbeAddOp(v, OP_MemLoad, iBMem+j, 0);
-        sqlite3VdbeAddOp(v, OP_MemStore, iAMem+j, 1);
+        sqlite3VdbeAddOp(v, OP_MemMove, iAMem+j, iBMem+j);
       }
       sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
       sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd);
diff --git a/src/update.c b/src/update.c
index 704775d..007d525 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.111 2005/09/08 01:58:43 drh Exp $
+** $Id: update.c,v 1.112 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -469,7 +469,7 @@
   ** all record selected by the WHERE clause have been updated.
   */
   sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
-  sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
+  sqlite3VdbeJumpHere(v, addr);
 
   /* Close all tables if there were no FOR EACH ROW triggers */
   if( !triggers_exist ){
diff --git a/src/vdbe.c b/src/vdbe.c
index 1410176..d7af8f0 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.490 2005/09/20 13:55:18 drh Exp $
+** $Id: vdbe.c,v 1.491 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4177,6 +4177,39 @@
   break;
 }
 
+/* Opcode: MemNull P1 * *
+**
+** Store a NULL in memory cell P1
+*/
+case OP_MemNull: {
+  assert( pOp->p1>=0 && pOp->p1<p->nMem );
+  sqlite3VdbeMemSetNull(&p->aMem[pOp->p1]);
+  break;
+}
+
+/* Opcode: MemInt P1 P2 *
+**
+** Store the integer value P1 in memory cell P2.
+*/
+case OP_MemInt: {
+  assert( pOp->p2>=0 && pOp->p2<p->nMem );
+  sqlite3VdbeMemSetInt64(&p->aMem[pOp->p2], pOp->p1);
+  break;
+}
+
+/* Opcode: MemMove P1 P2 *
+**
+** Move the content of memory cell P2 over to memory cell P1.
+** Any prior content of P1 is erased.  Memory cell P2 is left
+** containing a NULL.
+*/
+case OP_MemMove: {
+  assert( pOp->p1>=0 && pOp->p1<p->nMem );
+  assert( pOp->p2>=0 && pOp->p2<p->nMem );
+  rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], &p->aMem[pOp->p2]);
+  break;
+}
+
 /* Opcode: AggStep P1 P2 P3
 **
 ** Execute the step function for an aggregate.  The
diff --git a/src/vdbe.h b/src/vdbe.h
index 6e39174..bef16fd 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.98 2005/09/07 21:22:47 drh Exp $
+** $Id: vdbe.h,v 1.99 2005/09/20 17:42:23 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -104,6 +104,7 @@
 int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
 void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
 void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
+void sqlite3VdbeJumpHere(Vdbe*, int addr);
 void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
 VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
 int sqlite3VdbeMakeLabel(Vdbe*);
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 008be0b..cba9c09 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -351,6 +351,13 @@
   }
 }
 
+/*
+** Change teh P2 operand of instruction addr so that it points to
+** the address of the next instruction to be coded.
+*/
+void sqlite3VdbeJumpHere(Vdbe *p, int addr){
+  sqlite3VdbeChangeP2(p, addr, p->nOp);
+}
 
 /*
 ** Delete a P3 value if necessary.
diff --git a/src/vdbemem.c b/src/vdbemem.c
index 05d9c88..0b7e193 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -317,6 +317,7 @@
   sqlite3VdbeMemRelease(pMem);
   pMem->flags = MEM_Null;
   pMem->type = SQLITE_NULL;
+  pMem->n = 0;
 }
 
 /*
diff --git a/src/where.c b/src/where.c
index d9ddef0..e3b0e19 100644
--- a/src/where.c
+++ b/src/where.c
@@ -16,7 +16,7 @@
 ** so is applicable.  Because this module is responsible for selecting
 ** indices, you might also think of this module as the "query optimizer".
 **
-** $Id: where.c,v 1.178 2005/09/20 08:47:20 drh Exp $
+** $Id: where.c,v 1.179 2005/09/20 17:42:23 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1597,8 +1597,7 @@
     if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
       if( !pParse->nMem ) pParse->nMem++;
       pLevel->iLeftJoin = pParse->nMem++;
-      sqlite3VdbeAddOp(v, OP_Null, 0, 0);
-      sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
+      sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
       VdbeComment((v, "# init LEFT JOIN no-match flag"));
     }
 
@@ -1878,8 +1877,7 @@
     */
     if( pLevel->iLeftJoin ){
       pLevel->top = sqlite3VdbeCurrentAddr(v);
-      sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
-      sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
+      sqlite3VdbeAddOp(v, OP_MemInt, 1, pLevel->iLeftJoin);
       VdbeComment((v, "# record LEFT JOIN hit"));
       for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
         if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
@@ -1981,13 +1979,13 @@
     }
     if( pLevel->iLeftJoin ){
       int addr;
-      addr = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0);
-      sqlite3VdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iIdxCur>=0));
+      addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0);
       sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
       if( pLevel->iIdxCur>=0 ){
         sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0);
       }
       sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);
+      sqlite3VdbeJumpHere(v, addr);
     }
   }