Registerify the AUTOINCREMENT processing and the OP_IsNull and OP_NotNull
operators. (CVS 4692)

FossilOrigin-Name: aa48867cfa04da265b906e5b583bc7ac6b6a1157
diff --git a/src/expr.c b/src/expr.c
index 41d4fcc..d332e4f 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.335 2008/01/06 00:25:22 drh Exp $
+** $Id: expr.c,v 1.336 2008/01/07 19:20:25 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -2134,14 +2134,14 @@
     }
     case TK_ISNULL:
     case TK_NOTNULL: {
-      int dest;
+      int addr;
       assert( TK_ISNULL==OP_IsNull );
       assert( TK_NOTNULL==OP_NotNull );
       sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
       sqlite3ExprCode(pParse, pExpr->pLeft, 0);
-      dest = sqlite3VdbeCurrentAddr(v) + 2;
-      sqlite3VdbeAddOp2(v, op, 1, dest);
+      addr = sqlite3VdbeAddOp0(v, op);
       sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
+      sqlite3VdbeJumpHere(v, addr);
       stackChng = 0;
       inReg = target;
       break;
@@ -2222,11 +2222,10 @@
       break;
     }
     case TK_IN: {
-      int addr;
+      int j1, j2, j3, j4, j5;
       char affinity;
       int ckOffset = pParse->ckOffset;
       int eType;
-      int iLabel = sqlite3VdbeMakeLabel(v);
 
       eType = sqlite3FindInIndex(pParse, pExpr, 0);
 
@@ -2243,24 +2242,25 @@
       ** pExpr->iTable contains the values that make up the (...) set.
       */
       sqlite3ExprCode(pParse, pExpr->pLeft, 0);
-      addr = sqlite3VdbeCurrentAddr(v);
-      sqlite3VdbeAddOp2(v, OP_NotNull, -1, addr+4);            /* addr + 0 */
+      sqlite3VdbeAddOp0(v, OP_SCopy);
+      j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
       sqlite3VdbeAddOp1(v, OP_Pop, 2);
       sqlite3VdbeAddOp0(v, OP_Null);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, iLabel);
+      j2  = sqlite3VdbeAddOp0(v, OP_Goto);
+      sqlite3VdbeJumpHere(v, j1);
       if( eType==IN_INDEX_ROWID ){
-        int iAddr = sqlite3VdbeCurrentAddr(v)+3;
-        sqlite3VdbeAddOp2(v, OP_MustBeInt, 1, iAddr);
-        sqlite3VdbeAddOp2(v, OP_NotExists, pExpr->iTable, iAddr);
-        sqlite3VdbeAddOp2(v, OP_Goto, pExpr->iTable, iLabel);
+        j3 = sqlite3VdbeAddOp1(v, OP_MustBeInt, 1);
+        j4 = sqlite3VdbeAddOp1(v, OP_NotExists, pExpr->iTable);
+        j5 = sqlite3VdbeAddOp0(v, OP_Goto);
+        sqlite3VdbeJumpHere(v, j3);
+        sqlite3VdbeJumpHere(v, j4);
       }else{
-        sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0,
-                             &affinity, 1);   /* addr + 4 */
-        sqlite3VdbeAddOp2(v, OP_Found, pExpr->iTable, iLabel);
+        sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &affinity, 1);
+        j5 = sqlite3VdbeAddOp1(v, OP_Found, pExpr->iTable);
       }
-      sqlite3VdbeAddOp2(v, OP_AddImm, 0, -1);                  /* addr + 6 */
-      sqlite3VdbeResolveLabel(v, iLabel);
-
+      sqlite3VdbeAddOp2(v, OP_AddImm, 0, -1);
+      sqlite3VdbeJumpHere(v, j2);
+      sqlite3VdbeJumpHere(v, j5);
       break;
     }
 #endif
@@ -2485,7 +2485,7 @@
       assert( TK_ISNULL==OP_IsNull );
       assert( TK_NOTNULL==OP_NotNull );
       sqlite3ExprCode(pParse, pExpr->pLeft, 0);
-      sqlite3VdbeAddOp2(v, op, 1, dest);
+      sqlite3VdbeAddOp2(v, op, 0, dest);
       break;
     }
     case TK_BETWEEN: {
@@ -2597,7 +2597,7 @@
     case TK_ISNULL:
     case TK_NOTNULL: {
       sqlite3ExprCode(pParse, pExpr->pLeft, 0);
-      sqlite3VdbeAddOp2(v, op, 1, dest);
+      sqlite3VdbeAddOp2(v, op, 0, dest);
       break;
     }
     case TK_BETWEEN: {
diff --git a/src/insert.c b/src/insert.c
index c0ef2ae..c4fe107 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.214 2008/01/06 00:25:22 drh Exp $
+** $Id: insert.c,v 1.215 2008/01/07 19:20:25 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -138,44 +138,46 @@
 /*
 ** Write out code to initialize the autoincrement logic.  This code
 ** looks up the current autoincrement value in the sqlite_sequence
-** table and stores that value in a memory cell.  Code generated by
-** autoIncStep() will keep that memory cell holding the largest
+** table and stores that value in a register.  Code generated by
+** autoIncStep() will keep that register holding the largest
 ** rowid value.  Code generated by autoIncEnd() will write the new
 ** largest value of the counter back into the sqlite_sequence table.
 **
 ** This routine returns the index of the mem[] cell that contains
 ** the maximum rowid counter.
 **
-** Two memory cells are allocated.  The next memory cell befor the
-** one returned holds the rowid in sqlite_sequence where we will
-** write back the revised maximum rowid.
+** Three consecutive registers are allocated by this routine.  The
+** first two hold the name of the target table and the maximum rowid 
+** inserted into the target table, respectively.
+** The third holds the rowid in sqlite_sequence where we will
+** write back the revised maximum rowid.  This routine returns the
+** index of the second of these three registers.
 */
 static int autoIncBegin(
   Parse *pParse,      /* Parsing context */
   int iDb,            /* Index of the database holding pTab */
   Table *pTab         /* The table we are writing to */
 ){
-  int memId = 0;
+  int memId = 0;      /* Register holding maximum rowid */
   if( pTab->autoInc ){
     Vdbe *v = pParse->pVdbe;
     Db *pDb = &pParse->db->aDb[iDb];
     int iCur = pParse->nTab;
-    int addr;
+    int addr;               /* Address of the top of the loop */
     assert( v );
-    addr = sqlite3VdbeCurrentAddr(v);
-    pParse->nMem += 2;
-    memId = pParse->nMem;
+    pParse->nMem++;         /* Holds name of table */
+    memId = ++pParse->nMem;
+    pParse->nMem++;
     sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
-    sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+12);
+    addr = sqlite3VdbeCurrentAddr(v);
+    sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+8);
     sqlite3VdbeAddOp2(v, OP_Column, iCur, 0);
     sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0);
-    sqlite3VdbeAddOp2(v, OP_Ne, 0x100, addr+11);
-    sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0);
-    sqlite3VdbeAddOp2(v, OP_Move, 0, memId-1);
-    sqlite3VdbeAddOp2(v, OP_Column, iCur, 1);
-    sqlite3VdbeAddOp2(v, OP_Move, 0, memId);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+12);
-    sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+3);
+    sqlite3VdbeAddOp2(v, OP_Ne, 0x100, addr+7);
+    sqlite3VdbeAddOp2(v, OP_Rowid, iCur, memId+1);
+    sqlite3VdbeAddOp3(v, OP_Column, iCur, 1, memId);
+    sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+8);
+    sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1);
     sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
   }
   return memId;
@@ -189,15 +191,15 @@
 ** larger than the maximum rowid in the memId memory cell, then the
 ** memory cell is updated.  The stack is unchanged.
 */
-static void autoIncStep(Parse *pParse, int memId, int iRowid){
+static void autoIncStep(Parse *pParse, int memId, int regRowid){
   if( memId>0 ){
-    sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, iRowid);
+    sqlite3VdbeAddOp2(pParse->pVdbe, OP_MemMax, memId, regRowid);
   }
 }
 
 /*
 ** After doing one or more inserts, the maximum rowid is stored
-** in mem[memId].  Generate code to write this value back into the
+** in reg[memId].  Generate code to write this value back into the
 ** the sqlite_sequence table.
 */
 static void autoIncEnd(
@@ -210,19 +212,18 @@
     int iCur = pParse->nTab;
     Vdbe *v = pParse->pVdbe;
     Db *pDb = &pParse->db->aDb[iDb];
-    int addr;
+    int j1;
+
     assert( v );
-    addr = sqlite3VdbeCurrentAddr(v);
     sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
-    sqlite3VdbeAddOp2(v, OP_SCopy, memId-1, 0);
-    sqlite3VdbeAddOp2(v, OP_NotNull, -1, addr+6);
-    sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
-    sqlite3VdbeAddOp1(v, OP_NewRowid, iCur);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0);
-    sqlite3VdbeAddOp2(v, OP_SCopy, memId, 0);
-    sqlite3VdbeAddOp2(v, OP_MakeRecord, 2, 0);
-    sqlite3CodeInsert(pParse, iCur, OPFLAG_APPEND);
-    sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);
+    j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1);
+    sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1);
+    sqlite3VdbeJumpHere(v, j1);
+    sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0);
+    sqlite3VdbeAddOp3(v, OP_RegMakeRec, memId-1, 2, memId-1);
+    sqlite3VdbeAddOp3(v, OP_Insert, iCur, memId-1, memId+1);
+    sqlite3VdbeChangeP5(v, -1, OPFLAG_APPEND);
+    sqlite3VdbeAddOp1(v, OP_Close, iCur);
   }
 }
 #else
@@ -341,32 +342,38 @@
   IdList *pColumn,      /* Column names corresponding to IDLIST. */
   int onError           /* How to handle constraint errors */
 ){
-  Table *pTab;          /* The table to insert into */
+  sqlite3 *db;          /* The main database structure */
+  Table *pTab;          /* The table to insert into.  aka TABLE */
   char *zTab;           /* Name of the table into which we are inserting */
   const char *zDb;      /* Name of the database holding this table */
   int i, j, idx;        /* Loop counters */
   Vdbe *v;              /* Generate code into this virtual machine */
   Index *pIdx;          /* For looping over indices of the table */
   int nColumn;          /* Number of columns in the data */
+  int nHidden = 0;      /* Number of hidden columns if TABLE is virtual */
   int base = 0;         /* VDBE Cursor number for pTab */
-  int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */
-  sqlite3 *db;          /* The main database structure */
   int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */
   int endOfLoop;        /* Label for the end of the insertion loop */
   int useTempTable = 0; /* Store SELECT results in intermediate table */
   int srcTab = 0;       /* Data comes from this temporary cursor if >=0 */
+  int iCont=0,iBreak=0; /* Beginning and end of the loop over srcTab */
   int iSelectLoop = 0;  /* Address of code that implements the SELECT */
   int iCleanup = 0;     /* Address of the cleanup code */
   int iInsertBlock = 0; /* Address of the subroutine used to insert data */
-  int iCntMem = 0;      /* Memory cell used for the row counter */
-  int iBaseReg;         /* Base register for data */
-  int newIdx = -1;      /* Cursor for the NEW table */
+  int newIdx = -1;      /* Cursor for the NEW pseudo-table */
+  int iDb;              /* Index of database holding TABLE */
   Db *pDb;              /* The database containing table being inserted into */
-  int counterMem = 0;   /* Memory cell holding AUTOINCREMENT counter */
   int appendFlag = 0;   /* True if the insert is likely to be an append */
-  int iDb;
 
-  int nHidden = 0;
+  /* Register allocations */
+  int regFromSelect;    /* Base register for data coming from SELECT */
+  int regAutoinc = 0;   /* Register holding the AUTOINCREMENT counter */
+  int regRowCount = 0;  /* Memory cell used for the row counter */
+  int regIns;           /* Block of regs holding rowid+data being inserted */
+  int regRowid;         /* registers holding insert rowid */
+  int regData;          /* register holding first column to insert */
+  int regRecord;        /* Holds the assemblied row record */
+
 
 #ifndef SQLITE_OMIT_TRIGGER
   int isView;                 /* True if attempting to insert into a view */
@@ -455,11 +462,9 @@
 #endif /* SQLITE_OMIT_XFER_OPT */
 
   /* If this is an AUTOINCREMENT table, look up the sequence number in the
-  ** sqlite_sequence table and store it in memory cell counterMem.  Also
-  ** remember the rowid of the sqlite_sequence table entry in memory cell
-  ** counterRowid.
+  ** sqlite_sequence table and store it in memory cell regAutoinc.
   */
-  counterMem = autoIncBegin(pParse, iDb, pTab);
+  regAutoinc = autoIncBegin(pParse, iDb, pTab);
 
   /* Figure out how many columns of data are supplied.  If the data
   ** is coming from a SELECT statement, then this step also generates
@@ -486,7 +491,7 @@
       goto insert_cleanup;
     }
 
-    iBaseReg = dest.iMem;
+    regFromSelect = dest.iMem;
     iCleanup = sqlite3VdbeMakeLabel(v);
     sqlite3VdbeAddOp2(v, OP_Goto, 0, iCleanup);
     assert( pSelect->pEList );
@@ -510,7 +515,7 @@
       */
       srcTab = pParse->nTab++;
       sqlite3VdbeResolveLabel(v, iInsertBlock);
-      sqlite3VdbeAddOp2(v, OP_RegMakeRec, iBaseReg, nColumn);
+      sqlite3VdbeAddOp2(v, OP_RegMakeRec, regFromSelect, nColumn);
       sqlite3VdbeAddOp1(v, OP_NewRowid, srcTab);
       sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
       sqlite3CodeInsert(pParse, srcTab, OPFLAG_APPEND);
@@ -620,8 +625,8 @@
   /* Initialize the count of rows to be inserted
   */
   if( db->flags & SQLITE_CountRows ){
-    iCntMem = ++pParse->nMem;
-    sqlite3VdbeAddOp2(v, OP_Integer, 0, iCntMem);
+    regRowCount = ++pParse->nMem;
+    sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
   }
 
   /* If this is not a view, open the table and and all indices */
@@ -642,10 +647,22 @@
   }else if( pSelect ){
     sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
     sqlite3VdbeResolveLabel(v, iInsertBlock);
-    sqlite3RegToStack(pParse, iBaseReg, nColumn);
+    sqlite3RegToStack(pParse, regFromSelect, nColumn);
     sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
   }
 
+  /* Allocate registers for holding the rowid of the new row,
+  ** the content of the new row, and the assemblied row record.
+  */
+  regRecord = ++pParse->nMem;
+  regRowid = regIns = pParse->nMem+1;
+  pParse->nMem += pTab->nCol + 1;
+  if( IsVirtual(pTab) ){
+    regRowid++;
+    pParse->nMem++;
+  }
+  regData = regRowid+1;
+
   /* Run the BEFORE and INSTEAD OF triggers, if there are any
   */
   endOfLoop = sqlite3VdbeMakeLabel(v);
@@ -662,12 +679,15 @@
     }else if( useTempTable ){
       sqlite3VdbeAddOp2(v, OP_Column, srcTab, keyColumn);
     }else{
+      int j1;
       assert( pSelect==0 );  /* Otherwise useTempTable is true */
       sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
-      sqlite3VdbeAddOp2(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
-      sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
-      sqlite3VdbeAddOp2(v, OP_Integer, -1, 0);
-      sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0);
+      sqlite3VdbeAddOp0(v, OP_SCopy);
+      j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
+      sqlite3VdbeAddOp1(v, OP_Pop, 1);
+      sqlite3VdbeAddOp1(v, OP_Integer, -1);
+      sqlite3VdbeJumpHere(v, j1);
+      sqlite3VdbeAddOp0(v, OP_MustBeInt);
     }
 
     /* Cannot have triggers on a virtual table. If it were possible,
@@ -719,19 +739,15 @@
   ** case the record number is the same as that column. 
   */
   if( !isView ){
-    int iReg = pParse->nMem+1;
-    int iRowid = iReg+(IsVirtual(pTab)?1:0);
-    pParse->nMem += pTab->nCol + (IsVirtual(pTab)?2:1);
-
     if( IsVirtual(pTab) ){
       /* The row that the VUpdate opcode will delete: none */
-      sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
+      sqlite3VdbeAddOp2(v, OP_Null, 0, regIns);
     }
     if( keyColumn>=0 ){
       if( useTempTable ){
-        sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, iRowid);
+        sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
       }else if( pSelect ){
-        sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn - keyColumn - 1), iRowid);
+        sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn - keyColumn - 1), regRowid);
       }else{
         VdbeOp *pOp;
         sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
@@ -740,36 +756,36 @@
           appendFlag = 1;
           pOp->opcode = OP_NewRowid;
           pOp->p1 = base;
-          pOp->p2 = iRowid;
-          pOp->p3 = counterMem;
+          pOp->p2 = regRowid;
+          pOp->p3 = regAutoinc;
         }else{
           /* TODO: Avoid this use of the stack. */
-          sqlite3VdbeAddOp2(v, OP_Move, 0, iRowid);
+          sqlite3VdbeAddOp2(v, OP_Move, 0, regRowid);
         }
       }
       /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
       ** to generate a unique primary key value.
       */
       if( !appendFlag ){
-        sqlite3VdbeAddOp2(v, OP_IfMemNull, iRowid, sqlite3VdbeCurrentAddr(v)+2);
+        sqlite3VdbeAddOp2(v, OP_IfMemNull, regRowid, sqlite3VdbeCurrentAddr(v)+2);
         sqlite3VdbeAddOp2(v, OP_Goto, -1, sqlite3VdbeCurrentAddr(v)+2);
-        sqlite3VdbeAddOp3(v, OP_NewRowid, base, iRowid, counterMem);
-        sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, iRowid);
+        sqlite3VdbeAddOp3(v, OP_NewRowid, base, regRowid, regAutoinc);
+        sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, regRowid);
       }
     }else if( IsVirtual(pTab) ){
-      sqlite3VdbeAddOp2(v, OP_Null, 0, iRowid);
+      sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
     }else{
-      sqlite3VdbeAddOp3(v, OP_NewRowid, base, iRowid, counterMem);
+      sqlite3VdbeAddOp3(v, OP_NewRowid, base, regRowid, regAutoinc);
       appendFlag = 1;
     }
-    autoIncStep(pParse, counterMem, iRowid);
+    autoIncStep(pParse, regAutoinc, regRowid);
 
     /* Push onto the stack, data for all columns of the new entry, beginning
     ** with the first column.
     */
     nHidden = 0;
     for(i=0; i<pTab->nCol; i++){
-      int iRegStore = iRowid+1+i;
+      int iRegStore = regRowid+1+i;
       if( i==pTab->iPKey ){
         /* The value of the INTEGER PRIMARY KEY column is always a NULL.
         ** Whenever this column is read, the record number will be substituted
@@ -808,12 +824,12 @@
 #ifndef SQLITE_OMIT_VIRTUALTABLE
     if( IsVirtual(pTab) ){
       pParse->pVirtualLock = pTab;
-      sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, iReg,
+      sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns,
                      (const char*)pTab->pVtab, P4_VTAB);
     }else
 #endif
     {
-      sqlite3RegToStack(pParse, iReg, pTab->nCol+1);
+      sqlite3RegToStack(pParse, regIns, pTab->nCol+1);
       sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
                                      0, onError, endOfLoop);
       sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
@@ -825,7 +841,7 @@
   /* Update the count of rows that are inserted
   */
   if( (db->flags & SQLITE_CountRows)!=0 ){
-    sqlite3VdbeAddOp2(v, OP_AddImm, iCntMem, 1);
+    sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
   }
 
   if( triggers_exist ){
@@ -858,10 +874,10 @@
   }
 
   /* Update the sqlite_sequence table by storing the content of the
-  ** counter value in memory counterMem back into the sqlite_sequence
+  ** counter value in memory regAutoinc back into the sqlite_sequence
   ** table.
   */
-  autoIncEnd(pParse, iDb, pTab, counterMem);
+  autoIncEnd(pParse, iDb, pTab, regAutoinc);
 
   /*
   ** Return the number of rows inserted. If this routine is 
@@ -869,7 +885,7 @@
   ** invoke the callback function.
   */
   if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
-    sqlite3VdbeAddOp2(v, OP_ResultRow, iCntMem, 1);
+    sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
     sqlite3VdbeSetNumCols(v, 1);
     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", P4_STATIC);
   }
@@ -882,14 +898,14 @@
 }
 
 /*
-** Generate code to do a constraint check prior to an INSERT or an UPDATE.
+** Generate code to do constraint checks prior to an INSERT or an UPDATE.
 **
 ** When this routine is called, the stack contains (from bottom to top)
 ** the following values:
 **
 **    1.  The rowid of the row to be updated before the update.  This
 **        value is omitted unless we are doing an UPDATE that involves a
-**        change to the record number.
+**        change to the record number. (Or writing to a virtual table.)
 **
 **    2.  The rowid of the row after the update.
 **
@@ -1004,7 +1020,7 @@
       onError = OE_Abort;
     }
     sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol-1-i));
-    addr = sqlite3VdbeAddOp2(v, OP_NotNull, 1, 0);
+    addr = sqlite3VdbeAddOp0(v, OP_NotNull);
     assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
         || onError==OE_Ignore || onError==OE_Replace );
     switch( onError ){
@@ -1413,7 +1429,7 @@
   int emptySrcTest;                /* Address of test for empty pSrc */
   Vdbe *v;                         /* The VDBE we are building */
   KeyInfo *pKey;                   /* Key information for an index */
-  int counterMem;                  /* Memory register used by AUTOINC */
+  int regAutoinc;                  /* Memory register used by AUTOINC */
   int destHasUniqueIdx = 0;        /* True if pDest has a UNIQUE index */
 
   if( pSelect==0 ){
@@ -1541,7 +1557,7 @@
   sqlite3CodeVerifySchema(pParse, iDbSrc);
   iSrc = pParse->nTab++;
   iDest = pParse->nTab++;
-  counterMem = autoIncBegin(pParse, iDbDest, pDest);
+  regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
   sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
   if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){
     /* If tables do not have an INTEGER PRIMARY KEY and there
@@ -1569,7 +1585,7 @@
     sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
                       "PRIMARY KEY must be unique", P4_STATIC);
     sqlite3VdbeJumpHere(v, addr2);
-    autoIncStep(pParse, counterMem, 0);
+    autoIncStep(pParse, regAutoinc, 0);
   }else if( pDest->pIndex==0 ){
     addr1 = sqlite3VdbeAddOp1(v, OP_NewRowid, iDest);
   }else{
@@ -1580,7 +1596,7 @@
   sqlite3CodeInsert(pParse,iDest,OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
   sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
   sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
-  autoIncEnd(pParse, iDbDest, pDest, counterMem);
+  autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
   for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
     for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
       if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
diff --git a/src/pragma.c b/src/pragma.c
index 50e3f9c..b4b4059 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.161 2008/01/05 16:29:28 drh Exp $
+** $Id: pragma.c,v 1.162 2008/01/07 19:20:25 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -882,7 +882,7 @@
       }
       if( cnt==0 ) continue;
       sqlite3VdbeAddOp2(v, OP_IntegrityCk, 1, i);
-      addr = sqlite3VdbeAddOp2(v, OP_IsNull, -1, 0);
+      addr = sqlite3VdbeAddOp2(v, OP_StackIsNull, -1, 0);
       sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0,
          sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
          P4_DYNAMIC);
diff --git a/src/select.c b/src/select.c
index e818218..4e39192 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.391 2008/01/07 10:16:41 danielk1977 Exp $
+** $Id: select.c,v 1.392 2008/01/07 19:20:25 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -809,12 +809,16 @@
     }
 #ifndef SQLITE_OMIT_SUBQUERY
     case SRT_Set: {
+      int j1, j2;
       assert( nColumn==1 );
-      sqlite3VdbeAddOp2(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
-      sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
+      sqlite3VdbeAddOp0(v, OP_SCopy);
+      j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
+      sqlite3VdbeAddOp1(v, OP_Pop, 1);
+      j2 = sqlite3VdbeAddOp0(v, OP_Goto);
+      sqlite3VdbeJumpHere(v, j1);
       sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &p->affinity, 1);
       sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0);
+      sqlite3VdbeJumpHere(v, j2);
       break;
     }
     case SRT_Mem: {
diff --git a/src/vdbe.c b/src/vdbe.c
index a8643d9..58b1b14 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.686 2008/01/06 00:25:22 drh Exp $
+** $Id: vdbe.c,v 1.687 2008/01/07 19:20:25 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -2110,7 +2110,7 @@
   break;
 }
 
-/* Opcode: IsNull P1 P2 *
+/* Opcode: StackIsNull P1 P2 *
 **
 ** Check the top of the stack and jump to P2 if the top of the stack
 ** is NULL.  If P1 is positive, then pop P1 elements from the stack
@@ -2118,7 +2118,7 @@
 ** pop -P1 elements from the stack only if the jump is taken and leave
 ** the stack unchanged if the jump is not taken.
 */
-case OP_IsNull: {            /* same as TK_ISNULL, no-push, jump */
+case OP_StackIsNull: {            /* no-push, jump */
   if( pTos->flags & MEM_Null ){
     pc = pOp->p2-1;
     if( pOp->p1<0 ){
@@ -2131,40 +2131,31 @@
   break;
 }
 
-/* Opcode: AnyNull P1 P2 P3 * *
+/* Opcode: IsNull P1 P2 *
 **
-** Check P3 registers beginning with P1.  If any are NULL then jump
-** to P2.
+** Jump to P2 if the value in register P1 is NULL.
+**
+** If P1 is 0 then use the top of the stack instead of a register
+** and pop the stack regardless of whether or not the jump is taken.
 */
-case OP_AnyNull: {            /* no-push, jump, in1 */
-  int n = pOp->p3;
-  assert( n>0 && pOp->p1+n<=p->nMem );
-  while( n>0 ){
-    if( pIn1->flags & MEM_Null ){
-      pc = pOp->p2-1;
-      break;
-    }
-    n--;
-    pIn1++;
+case OP_IsNull: {            /* same as TK_ISNULL, no-push, jump, in1 */
+  if( (pIn1->flags & MEM_Null)!=0 ){
+    pc = pOp->p2 - 1;
   }
   break;
 }
 
 /* Opcode: NotNull P1 P2 *
 **
-** Jump to P2 if the top abs(P1) values on the stack are all not NULL.  
-** Regardless of whether or not the jump is taken, pop the stack
-** P1 times if P1 is greater than zero.  But if P1 is negative,
-** leave the stack unchanged.
+** Jump to P2 if the value in register P1 is not NULL.  
+**
+** If P1 is 0 then use the top of the stack instead of a register
+** and pop the stack regardless of whether or not the jump is taken.
 */
-case OP_NotNull: {            /* same as TK_NOTNULL, no-push, jump */
-  int i, cnt;
-  cnt = pOp->p1;
-  if( cnt<0 ) cnt = -cnt;
-  assert( &pTos[1-cnt] >= p->aStack );
-  for(i=0; i<cnt && (pTos[1+i-cnt].flags & MEM_Null)==0; i++){}
-  if( i>=cnt ) pc = pOp->p2-1;
-  if( pOp->p1>0 ) popStack(&pTos, cnt);
+case OP_NotNull: {            /* same as TK_NOTNULL, no-push, jump, in1 */
+  if( (pIn1->flags & MEM_Null)==0 ){
+    pc = pOp->p2 - 1;
+  }
   break;
 }
 
diff --git a/src/where.c b/src/where.c
index 360e191..4d9454f 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.276 2008/01/05 17:39:30 danielk1977 Exp $
+** $Id: where.c,v 1.277 2008/01/07 19:20:25 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1757,7 +1757,7 @@
       pIn += pLevel->nIn - 1;
       pIn->iCur = iTab;
       pIn->topAddr = sqlite3VdbeAddOp2(v, op, iTab, 0);
-      sqlite3VdbeAddOp2(v, OP_IsNull, -1, 0);
+      sqlite3VdbeAddOp2(v, OP_StackIsNull, -1, 0);
     }else{
       pLevel->nIn = 0;
     }
@@ -1824,7 +1824,7 @@
     assert( (pTerm->flags & TERM_CODED)==0 );
     codeEqualityTerm(pParse, pTerm, pLevel);
     if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
-      sqlite3VdbeAddOp2(v, OP_IsNull, termsInMem ? -1 : -(j+1), pLevel->brk);
+      sqlite3VdbeAddOp2(v, OP_StackIsNull, termsInMem ? -1 : -(j+1), pLevel->brk);
     }
     if( termsInMem ){
       sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem+j+1);
@@ -2467,7 +2467,7 @@
         pX = pTerm->pExpr;
         assert( (pTerm->flags & TERM_CODED)==0 );
         sqlite3ExprCode(pParse, pX->pRight, 0);
-        sqlite3VdbeAddOp2(v, OP_IsNull, -(nEq*2+1), nxt);
+        sqlite3VdbeAddOp2(v, OP_StackIsNull, -(nEq*2+1), nxt);
         topEq = pTerm->eOperator & (WO_LE|WO_GE);
         disableTerm(pLevel, pTerm);
         testOp = OP_IdxGE;
@@ -2511,7 +2511,7 @@
         pX = pTerm->pExpr;
         assert( (pTerm->flags & TERM_CODED)==0 );
         sqlite3ExprCode(pParse, pX->pRight, 0);
-        sqlite3VdbeAddOp2(v, OP_IsNull, -(nEq+1), nxt);
+        sqlite3VdbeAddOp2(v, OP_StackIsNull, -(nEq+1), nxt);
         btmEq = pTerm->eOperator & (WO_LE|WO_GE);
         disableTerm(pLevel, pTerm);
       }else{
@@ -2553,7 +2553,7 @@
       }
       if( topLimit | btmLimit ){
         sqlite3VdbeAddOp2(v, OP_Column, iIdxCur, nEq);
-        sqlite3VdbeAddOp2(v, OP_IsNull, 1, cont);
+        sqlite3VdbeAddOp2(v, OP_StackIsNull, 1, cont);
       }
       if( !omitTable ){
         sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, 0);