Finish registerizing the core logic of INSERT and UPDATE. (CVS 4696)

FossilOrigin-Name: 5fd1036788dbbc48ff1c746d2e1ba12b04a7e58c
diff --git a/src/insert.c b/src/insert.c
index a9ba0ea..26f5408 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.216 2008/01/08 02:57:56 drh Exp $
+** $Id: insert.c,v 1.217 2008/01/08 18:57:50 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -351,7 +351,7 @@
   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 baseCur = 0;      /* VDBE Cursor number for pTab */
   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 */
@@ -635,8 +635,8 @@
     int nIdx;
     int i;
 
-    base = pParse->nTab;
-    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
+    baseCur = pParse->nTab;
+    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, baseCur, OP_OpenWrite);
     aRegIdx = sqlite3DbMallocZero(db, sizeof(int)*(nIdx+1));
     if( aRegIdx==0 ){
       goto insert_cleanup;
@@ -766,7 +766,7 @@
         if( pOp && pOp->opcode==OP_Null ){
           appendFlag = 1;
           pOp->opcode = OP_NewRowid;
-          pOp->p1 = base;
+          pOp->p1 = baseCur;
           pOp->p2 = regRowid;
           pOp->p3 = regAutoinc;
         }else{
@@ -780,13 +780,13 @@
       if( !appendFlag ){
         sqlite3VdbeAddOp2(v, OP_IfMemNull, regRowid, sqlite3VdbeCurrentAddr(v)+2);
         sqlite3VdbeAddOp2(v, OP_Goto, -1, sqlite3VdbeCurrentAddr(v)+2);
-        sqlite3VdbeAddOp3(v, OP_NewRowid, base, regRowid, regAutoinc);
+        sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
         sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, regRowid);
       }
     }else if( IsVirtual(pTab) ){
       sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
     }else{
-      sqlite3VdbeAddOp3(v, OP_NewRowid, base, regRowid, regAutoinc);
+      sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
       appendFlag = 1;
     }
     autoIncStep(pParse, regAutoinc, regRowid);
@@ -840,12 +840,28 @@
     }else
 #endif
     {
-      sqlite3RegToStack(pParse, regIns, pTab->nCol+1);
-      sqlite3GenerateConstraintChecks(pParse, pTab, base, aRegIdx, keyColumn>=0,
-                                     0, onError, endOfLoop);
-      sqlite3CompleteInsertion(pParse, pTab, base, aRegIdx,0,0,
-                            (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
-                            appendFlag);
+      sqlite3GenerateConstraintChecks(
+          pParse,
+          pTab,
+          baseCur,
+          regIns,
+          aRegIdx,
+          keyColumn>=0,
+          0,
+          onError,
+          endOfLoop
+      );
+      sqlite3CompleteInsertion(
+          pParse,
+          pTab,
+          baseCur,
+          regIns,
+          aRegIdx,
+          0,
+          0,
+          (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
+          appendFlag
+       );
     }
   }
 
@@ -878,9 +894,9 @@
 
   if( !IsVirtual(pTab) && !isView ){
     /* Close all tables opened */
-    sqlite3VdbeAddOp2(v, OP_Close, base, 0);
+    sqlite3VdbeAddOp2(v, OP_Close, baseCur, 0);
     for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
-      sqlite3VdbeAddOp2(v, OP_Close, idx+base, 0);
+      sqlite3VdbeAddOp2(v, OP_Close, idx+baseCur, 0);
     }
   }
 
@@ -912,8 +928,7 @@
 /*
 ** 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:
+** The input is a range of consecutive registers as follows:
 **
 **    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
@@ -927,6 +942,8 @@
 **
 **    N.  The data in the last column of the entry after the update.
 **
+** The regRowid parameter is the index of the register containing (2).
+**
 ** The old rowid shown as entry (1) above is omitted unless both isUpdate
 ** and rowidChng are 1.  isUpdate is true for UPDATEs and false for
 ** INSERTs and rowidChng is true if the record number is being changed.
@@ -977,23 +994,24 @@
 ** for the constraint is used.
 **
 ** The calling routine must open a read/write cursor for pTab with
-** cursor number "base".  All indices of pTab must also have open
-** read/write cursors with cursor number base+i for the i-th cursor.
+** cursor number "baseCur".  All indices of pTab must also have open
+** read/write cursors with cursor number baseCur+i for the i-th cursor.
 ** Except, if there is no possibility of a REPLACE action then
 ** cursors do not need to be open for indices where aRegIdx[i]==0.
 **
-** If the isUpdate flag is true, it means that the "base" cursor is
+** If the isUpdate flag is true, it means that the "baseCur" cursor is
 ** initially pointing to an entry that is being updated.  The isUpdate
-** flag causes extra code to be generated so that the "base" cursor
+** flag causes extra code to be generated so that the "baseCur" cursor
 ** is still pointing at the same entry after the routine returns.
-** Without the isUpdate flag, the "base" cursor might be moved.
+** Without the isUpdate flag, the "baseCur" cursor might be moved.
 */
 void sqlite3GenerateConstraintChecks(
   Parse *pParse,      /* The parser context */
   Table *pTab,        /* the table into which we are inserting */
-  int base,           /* Index of a read/write cursor pointing at pTab */
+  int baseCur,        /* Index of a read/write cursor pointing at pTab */
+  int regRowid,       /* Index of the range of input registers */
   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
-  int rowidChng,      /* True if the record number will change */
+  int rowidChng,      /* True if the rowid will change */
   int isUpdate,       /* True for UPDATE, False for INSERT */
   int overrideError,  /* Override onError to this if not OE_Default */
   int ignoreDest      /* Jump to this label on an OE_Ignore resolution */
@@ -1003,24 +1021,18 @@
   int nCol;
   int onError;
   int j1, j2, j3;     /* Address of jump instructions */
+  int regData;        /* Register containing first data column */
   int iCur;
   Index *pIdx;
   int seenReplace = 0;
   int hasTwoRowids = (isUpdate && rowidChng);
 
-  int regRowid, regData;
-
   v = sqlite3GetVdbe(pParse);
   assert( v!=0 );
   assert( pTab->pSelect==0 );  /* This table is not a VIEW */
   nCol = pTab->nCol;
+  regData = regRowid + 1;
 
-  /* Copy rowids and data into registers 
-  */
-  regRowid = sqlite3StackToReg(pParse, nCol+1+hasTwoRowids);
-  sqlite3RegToStack(pParse, regRowid, nCol+1+hasTwoRowids);
-  if( hasTwoRowids ) regRowid++;
-  regData = regRowid+1;
 
   /* Test all NOT NULL constraints.
   */
@@ -1053,14 +1065,11 @@
         break;
       }
       case OE_Ignore: {
-        sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0);
         sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
         break;
       }
       case OE_Replace: {
-        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
-        sqlite3VdbeAddOp2(v, OP_Copy, 0, regData+i);
-        sqlite3VdbeAddOp1(v, OP_Push, nCol-i);
+        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regData+i);
         break;
       }
     }
@@ -1076,7 +1085,6 @@
     sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
     onError = overrideError!=OE_Default ? overrideError : OE_Abort;
     if( onError==OE_Ignore ){
-      sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0);
       sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
     }else{
       sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_CONSTRAINT, onError);
@@ -1102,7 +1110,7 @@
       sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
       j2 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0);
     }
-    j3 = sqlite3VdbeAddOp3(v, OP_NotExists, base, 0, regRowid);
+    j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid);
     switch( onError ){
       default: {
         onError = OE_Abort;
@@ -1116,17 +1124,16 @@
         break;
       }
       case OE_Replace: {
-        sqlite3GenerateRowIndexDelete(v, pTab, base, 0);
+        sqlite3GenerateRowIndexDelete(v, pTab, baseCur, 0);
         if( isUpdate ){
           sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
-          sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
+          sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
         }
         seenReplace = 1;
         break;
       }
       case OE_Ignore: {
         assert( seenReplace==0 );
-        sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0);
         sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
         break;
       }
@@ -1135,7 +1142,7 @@
     if( isUpdate ){
       sqlite3VdbeJumpHere(v, j2);
       sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-1);
-      sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
+      sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
     }
   }
 
@@ -1176,7 +1183,7 @@
     /* Check to see if the new index entry will be unique */
     sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]);
     sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
-    j3 = sqlite3VdbeAddOp2(v, OP_IsUnique, base+iCur+1, 0);
+    j3 = sqlite3VdbeAddOp2(v, OP_IsUnique, baseCur+iCur+1, 0);
 
     /* Generate code that executes if the new index entry is not unique */
     assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
@@ -1213,16 +1220,16 @@
       }
       case OE_Ignore: {
         assert( seenReplace==0 );
-        sqlite3VdbeAddOp2(v, OP_Pop, nCol+3+hasTwoRowids, 0);
+        sqlite3VdbeAddOp1(v, OP_Pop, 2+hasTwoRowids);
         sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
         break;
       }
       case OE_Replace: {
         int iRowid = sqlite3StackToReg(pParse, 1);
-        sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0);
+        sqlite3GenerateRowDelete(pParse->db, v, pTab, baseCur, iRowid, 0);
         if( isUpdate ){
           sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
-          sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
+          sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
         }
         seenReplace = 1;
         break;
@@ -1239,9 +1246,8 @@
 /*
 ** This routine generates code to finish the INSERT or UPDATE operation
 ** that was started by a prior call to sqlite3GenerateConstraintChecks.
-** The stack must contain keys for all active indices followed by data
-** and the rowid for the new entry.  This routine creates the new
-** entries in all indices and in the main table.
+** A consecutive range of registers starting at regRowid contains the
+** rowid and the content to be inserted.
 **
 ** The arguments to this routine should be the same as the first six
 ** arguments to sqlite3GenerateConstraintChecks.
@@ -1249,7 +1255,8 @@
 void sqlite3CompleteInsertion(
   Parse *pParse,      /* The parser context */
   Table *pTab,        /* the table into which we are inserting */
-  int base,           /* Index of a read/write cursor pointing at pTab */
+  int baseCur,        /* Index of a read/write cursor pointing at pTab */
+  int regRowid,       /* Range of content */
   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
   int rowidChng,      /* True if the record number will change */
   int isUpdate,       /* True for UPDATE, False for INSERT */
@@ -1261,6 +1268,7 @@
   int nIdx;
   Index *pIdx;
   int pik_flags;
+  int regData;
 
   v = sqlite3GetVdbe(pParse);
   assert( v!=0 );
@@ -1268,14 +1276,16 @@
   for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
   for(i=nIdx-1; i>=0; i--){
     if( aRegIdx[i]==0 ) continue;
-    sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, aRegIdx[i]);
+    sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
   }
-  sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0);
+  regData = regRowid + 1;
+  sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
+  sqlite3VdbeAddOp2(v, OP_RegMakeRec, regData, pTab->nCol);
   sqlite3TableAffinityStr(v, pTab);
 #ifndef SQLITE_OMIT_TRIGGER
   if( newIdx>=0 ){
-    sqlite3VdbeAddOp1(v, OP_Copy, -1);
-    sqlite3VdbeAddOp1(v, OP_Copy, -1);
+    sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
+    sqlite3VdbeAddOp1(v, OP_SCopy, -1);
     sqlite3CodeInsert(pParse, newIdx, 0);
   }
 #endif
@@ -1288,19 +1298,15 @@
   if( appendBias ){
     pik_flags |= OPFLAG_APPEND;
   }
-  sqlite3CodeInsert(pParse, base, pik_flags);
+  sqlite3CodeInsert(pParse, baseCur, pik_flags);
   if( !pParse->nested ){
     sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
   }
-  
-  if( isUpdate && rowidChng ){
-    sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
-  }
 }
 
 /*
 ** Generate code that will open cursors for a table and for all
-** indices of that table.  The "base" parameter is the cursor number used
+** indices of that table.  The "baseCur" parameter is the cursor number used
 ** for the table.  Indices are opened on subsequent cursors.
 **
 ** Return the number of indices on the table.
@@ -1308,7 +1314,7 @@
 int sqlite3OpenTableAndIndices(
   Parse *pParse,   /* Parsing context */
   Table *pTab,     /* Table to be opened */
-  int base,        /* Cursor number assigned to the table */
+  int baseCur,        /* Cursor number assigned to the table */
   int op           /* OP_OpenRead or OP_OpenWrite */
 ){
   int i;
@@ -1320,16 +1326,16 @@
   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
   v = sqlite3GetVdbe(pParse);
   assert( v!=0 );
-  sqlite3OpenTable(pParse, base, iDb, pTab, op);
+  sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);
   for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
     KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
     assert( pIdx->pSchema==pTab->pSchema );
-    sqlite3VdbeAddOp4(v, op, i+base, pIdx->tnum, iDb,
+    sqlite3VdbeAddOp4(v, op, i+baseCur, pIdx->tnum, iDb,
                       (char*)pKey, P4_KEYINFO_HANDOFF);
     VdbeComment((v, "%s", pIdx->zName));
   }
-  if( pParse->nTab<=base+i ){
-    pParse->nTab = base+i;
+  if( pParse->nTab<=baseCur+i ){
+    pParse->nTab = baseCur+i;
   }
   return i-1;
 }
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b4e236c..ec6da6d 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.642 2008/01/08 02:57:56 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.643 2008/01/08 18:57:50 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1776,8 +1776,9 @@
 void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int);
 void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*);
 void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
-void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int*,int,int,int,int);
-void sqlite3CompleteInsertion(Parse*, Table*, int, int*, int, int, int, int);
+void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
+                                     int*,int,int,int,int);
+void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int);
 int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
 void sqlite3BeginWriteOperation(Parse*, int, int);
 Expr *sqlite3ExprDup(sqlite3*,Expr*);
diff --git a/src/update.c b/src/update.c
index afb5e89..89ececa 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.163 2008/01/08 02:57:56 drh Exp $
+** $Id: update.c,v 1.164 2008/01/08 18:57:50 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -102,9 +102,6 @@
   AuthContext sContext;  /* The authorization context */
   NameContext sNC;       /* The name-context to resolve expressions in */
   int iDb;               /* Database containing the table being updated */
-  int memCnt = 0;        /* Memory cell used for counting rows changed */
-  int mem1;      /* Memory address storing the rowid for next row to update */
-  int iRowid;            /* Memory address storing rowids */
 
 #ifndef SQLITE_OMIT_TRIGGER
   int isView;                  /* Trying to update a view */
@@ -120,6 +117,12 @@
   int newIdx      = -1;  /* index of trigger "new" temp table       */
   int oldIdx      = -1;  /* index of trigger "old" temp table       */
 
+  /* Register Allocations */
+  int regRowCount = 0;   /* A count of rows changed */
+  int regOldRowid;       /* The old rowid */
+  int regNewRowid;       /* The new rowid */
+  int regData;           /* New data for the row */
+
   sContext.pParse = 0;
   db = pParse->db;
   if( pParse->nErr || db->mallocFailed ){
@@ -251,13 +254,28 @@
     aRegIdx[j] = reg;
   }
 
+  /* Allocate a block of register used to store the change record
+  ** sent to sqlite3GenerateConstraintChecks().  There are either
+  ** one or two registers for holding the rowid.  One rowid register
+  ** is used if chngRowid is false and two are used if chngRowid is
+  ** true.  Following these are pTab->nCol register holding column
+  ** data.
+  */
+  regOldRowid = regNewRowid = pParse->nMem + 1;
+  pParse->nMem += pTab->nCol + 1;
+  if( chngRowid ){
+    regNewRowid++;
+    pParse->nMem++;
+  }
+  regData = regNewRowid+1;
+ 
+
   /* Begin generating code.
   */
   v = sqlite3GetVdbe(pParse);
   if( v==0 ) goto update_cleanup;
   if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
   sqlite3BeginWriteOperation(pParse, 1, iDb);
-  mem1 = ++pParse->nMem;
 
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   /* Virtual tables must be handled separately */
@@ -333,9 +351,8 @@
 
   /* Remember the rowid of every item to be updated.
   */
-  iRowid = ++pParse->nMem;
-  sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, iRowid);
-  sqlite3VdbeAddOp2(v, OP_FifoWrite, iRowid, 0);
+  sqlite3VdbeAddOp2(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid,iCur,regOldRowid);
+  sqlite3VdbeAddOp2(v, OP_FifoWrite, regOldRowid, 0);
 
   /* End the database scan loop.
   */
@@ -344,8 +361,8 @@
   /* Initialize the count of updated rows
   */
   if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
-    memCnt = ++pParse->nMem;
-    sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
+    regRowCount = ++pParse->nMem;
+    sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
   }
 
   if( !isView && !IsVirtual(pTab) ){
@@ -383,13 +400,13 @@
   }
 
   /* Top of the update loop */
-  addr = sqlite3VdbeAddOp2(v, OP_FifoRead, iRowid, 0);
+  addr = sqlite3VdbeAddOp2(v, OP_FifoRead, regOldRowid, 0);
   sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
 
   if( triggers_exist ){
     /* Make cursor iCur point to the record that is being updated.
     */
-    sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);
+    sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
 
     /* Generate the OLD table
     */
@@ -437,45 +454,44 @@
   }
 
   if( !isView && !IsVirtual(pTab) ){
-
     /* Loop over every record that needs updating.  We have to load
     ** the old data for each record to be updated because some columns
     ** might not change and we will need to copy the old value.
     ** Also, the old data is needed to delete the old index entries.
     ** So make the cursor point at the old record.
     */
-    sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);
-    sqlite3VdbeAddOp2(v, OP_SCopy, iRowid, 0);
+    sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
 
     /* If the record number will change, push the record number as it
     ** will be after the update. (The old record number is currently
     ** on top of the stack.)
     */
     if( chngRowid ){
-      sqlite3ExprCode(pParse, pRowidExpr, 0);
-      sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0);
+      sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
+      sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, regNewRowid);
     }
 
     /* Compute new data for this record.  
     */
     for(i=0; i<pTab->nCol; i++){
       if( i==pTab->iPKey ){
-        sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
+        sqlite3VdbeAddOp2(v, OP_Null, 0, regData+i);
         continue;
       }
       j = aXRef[i];
       if( j<0 ){
-        sqlite3VdbeAddOp2(v, OP_Column, iCur, i);
+        sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regData+i);
         sqlite3ColumnDefault(v, pTab, i);
       }else{
-        sqlite3ExprCode(pParse, pChanges->a[j].pExpr, 0);
+        sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regData+i);
       }
     }
 
     /* Do constraint checks
     */
-    sqlite3GenerateConstraintChecks(pParse, pTab, iCur, aRegIdx, chngRowid, 1,
-                                   onError, addr);
+    sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
+                                    aRegIdx, chngRowid, 1,
+                                    onError, addr);
 
     /* Delete the old indices for the current record.
     */
@@ -489,13 +505,14 @@
 
     /* Create the new index entries and the new record.
     */
-    sqlite3CompleteInsertion(pParse, pTab, iCur, aRegIdx, chngRowid, 1, -1, 0);
+    sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, 
+                             aRegIdx, chngRowid, 1, -1, 0);
   }
 
   /* Increment the row counter 
   */
   if( db->flags & SQLITE_CountRows && !pParse->trigStack){
-    sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
+    sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
   }
 
   /* If there are triggers, close all the cursors after each iteration
@@ -530,7 +547,7 @@
   ** invoke the callback function.
   */
   if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
-    sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
+    sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
     sqlite3VdbeSetNumCols(v, 1);
     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P4_STATIC);
   }