More work toward converting the VM into a register-based machine. (CVS 4704)

FossilOrigin-Name: 8cbd46517f407b3b1ce187b623db10f00aa415ea
diff --git a/src/analyze.c b/src/analyze.c
index 2560dd8..d1873f0 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.36 2008/01/09 23:04:12 drh Exp $
+** @(#) $Id: analyze.c,v 1.37 2008/01/10 23:50:11 drh Exp $
 */
 #ifndef SQLITE_OMIT_ANALYZE
 #include "sqliteInt.h"
@@ -120,6 +120,12 @@
   iIdxCur = pParse->nTab;
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+    int regFields;    /* Register block for building records */
+    int regRec;       /* Register holding completed record */
+    int regTemp;      /* Temporary use register */
+    int regCol;       /* Content of a column from the table being analyzed */
+    int regRowid;     /* Rowid for the inserted record */
+    int regF2;
 
     /* Open a cursor to the index to be analyzed
     */
@@ -128,8 +134,11 @@
         (char *)pKey, P4_KEYINFO_HANDOFF);
     VdbeComment((v, "%s", pIdx->zName));
     nCol = pIdx->nColumn;
-    if( iMem+nCol*2>=pParse->nMem ){
-      pParse->nMem = iMem+nCol*2+1;
+    regFields = iMem+nCol*2;
+    regTemp = regRowid = regCol = regFields+3;
+    regRec = regCol+1;
+    if( regRec>pParse->nMem ){
+      pParse->nMem = regRec;
     }
     sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, nCol+1);
 
@@ -160,15 +169,15 @@
     topOfLoop = sqlite3VdbeCurrentAddr(v);
     sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
     for(i=0; i<nCol; i++){
-      sqlite3VdbeAddOp2(v, OP_Column, iIdxCur, i);
-      sqlite3VdbeAddOp1(v, OP_SCopy, iMem+nCol+i+1);
-      sqlite3VdbeAddOp0(v, OP_Ne );  /* Use Collating sequence */
+      sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
+      sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
+      /**** TODO:  add collating sequence *****/
       sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
     }
     sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
     for(i=0; i<nCol; i++){
-      addr = sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
-      sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr);
+      sqlite3VdbeJumpHere(v, topOfLoop + 2*(i + 1));
+      sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
       sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
     }
     sqlite3VdbeResolveLabel(v, endOfLoop);
@@ -193,23 +202,24 @@
     ** If K>0 then it is always the case the D>0 so division by zero
     ** is never possible.
     */
-    sqlite3VdbeAddOp1(v, OP_SCopy, iMem);
-    addr = sqlite3VdbeAddOp0(v, OP_IfNot);
-    sqlite3VdbeAddOp1(v, OP_NewRowid, iStatCur);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pIdx->zName, 0);
-    sqlite3VdbeAddOp1(v, OP_SCopy, iMem);
+    addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
+    sqlite3VdbeAddOp4(v, OP_String8, 0, regFields, 0, pTab->zName, 0);
+    sqlite3VdbeAddOp4(v, OP_String8, 0, regFields+1, 0, pIdx->zName, 0);
+    regF2 = regFields+2;
+    sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regF2);
     for(i=0; i<nCol; i++){
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, " ", 0);
-      sqlite3VdbeAddOp0(v, OP_Concat);
-      sqlite3VdbeAddOp2(v, OP_Add, iMem, iMem+i+1);
-      sqlite3VdbeAddOp2(v, OP_AddImm, 0, -1);
-      sqlite3VdbeAddOp2(v, OP_Divide, iMem+i+1, 0);
-      sqlite3VdbeAddOp0(v, OP_ToInt);
-      sqlite3VdbeAddOp0(v, OP_Concat);
+      sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
+      sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
+      sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp);
+      sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1);
+      sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp);
+      sqlite3VdbeAddOp1(v, OP_ToInt, regTemp);
+      sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
     }
-    sqlite3VdbeAddOp4(v, OP_MakeRecord, 3, 0, 0, "aaa", 0);
-    sqlite3CodeInsert(pParse, iStatCur, OPFLAG_APPEND);
+    sqlite3VdbeAddOp4(v, OP_RegMakeRec, regFields, 3, regRec, "aaa", 0);
+    sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
+    sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
+    sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
     sqlite3VdbeJumpHere(v, addr);
   }
 }
diff --git a/src/build.c b/src/build.c
index f83a8ae..b11e203 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.462 2008/01/09 23:04:12 drh Exp $
+** $Id: build.c,v 1.463 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -2222,6 +2222,8 @@
   int tnum;                      /* Root page of index */
   Vdbe *v;                       /* Generate code into this virtual machine */
   KeyInfo *pKey;                 /* KeyInfo for index */
+  int regIdxKey;                 /* Registers containing the index key */
+  int regRecord;                 /* Register holding assemblied index record */
   sqlite3 *db = pParse->db;      /* The database connection */
   int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
 
@@ -2252,19 +2254,23 @@
   }
   sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
   addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
-  sqlite3GenerateIndexKey(v, pIndex, iTab);
+  regRecord = sqlite3GetTempReg(pParse);
+  regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord);
   if( pIndex->onError!=OE_None ){
-    int curaddr = sqlite3VdbeCurrentAddr(v);
-    int addr2 = curaddr+4;
-    sqlite3VdbeChangeP2(v, curaddr-1, addr2);
-    sqlite3VdbeAddOp1(v, OP_Rowid, iTab);
-    sqlite3VdbeAddOp2(v, OP_AddImm, 0, 1);
-    sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, addr2, 0, 0, P4_INT32);
+    int j1, j2;
+    int regRowid;
+
+    regRowid = regIdxKey + pIndex->nColumn;
+    j1 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdxKey, 0, pIndex->nColumn);
+    j2 = sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx,
+                           0, regRowid, (char*)regRecord, P4_INT32);
     sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, 0,
                     "indexed columns are not unique", P4_STATIC);
-    assert( db->mallocFailed || addr2==sqlite3VdbeCurrentAddr(v) );
+    sqlite3VdbeJumpHere(v, j1);
+    sqlite3VdbeJumpHere(v, j2);
   }
-  sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, 0);
+  sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
+  sqlite3ReleaseTempReg(pParse, regRecord);
   sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
   sqlite3VdbeJumpHere(v, addr1);
   sqlite3VdbeAddOp1(v, OP_Close, iTab);
diff --git a/src/delete.c b/src/delete.c
index 80c2ab4..18a16ed 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.155 2008/01/09 23:04:12 drh Exp $
+** $Id: delete.c,v 1.156 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -390,7 +390,7 @@
       }else
 #endif
       {
-        sqlite3GenerateRowDelete(db, v, pTab, iCur, iRowid, pParse->nested==0);
+        sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0);
       }
     }
 
@@ -455,16 +455,18 @@
 ** entries that point to that record.
 */
 void sqlite3GenerateRowDelete(
-  sqlite3 *db,       /* The database containing the index */
-  Vdbe *v,           /* Generate code into this VDBE */
+  Parse *pParse,     /* Parsing context */
   Table *pTab,       /* Table containing the row to be deleted */
   int iCur,          /* Cursor number for the table */
   int iRowid,        /* Memory cell that contains the rowid to delete */
   int count          /* Increment the row change counter */
 ){
   int addr;
+  Vdbe *v;
+
+  v = pParse->pVdbe;
   addr = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowid);
-  sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
+  sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
   sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
   if( count ){
     sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
@@ -489,7 +491,7 @@
 **       deleted.
 */
 void sqlite3GenerateRowIndexDelete(
-  Vdbe *v,           /* Generate code into this VDBE */
+  Parse *pParse,     /* Parsing and code generating context */
   Table *pTab,       /* Table containing the row to be deleted */
   int iCur,          /* Cursor number for the table */
   int *aRegIdx       /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
@@ -499,8 +501,8 @@
 
   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
     if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
-    sqlite3GenerateIndexKey(v, pIdx, iCur);
-    sqlite3VdbeAddOp1(v, OP_IdxDelete, iCur+i);
+    sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0);
+    sqlite3VdbeAddOp2(pParse->pVdbe, OP_IdxDelete, iCur+i, 0);
   }
 }
 
@@ -509,25 +511,38 @@
 ** of the tack.  The key with be for index pIdx which is an index on pTab.
 ** iCur is the index of a cursor open on the pTab table and pointing to
 ** the entry that needs indexing.
+**
+** Return a register number which is the first in a block of
+** registers that holds the elements of the index key.  The
+** block of registers has already been deallocated by the time
+** this routine returns.
 */
-void sqlite3GenerateIndexKey(
-  Vdbe *v,           /* Generate code into this VDBE */
+int sqlite3GenerateIndexKey(
+  Parse *pParse,     /* Parsing context */
   Index *pIdx,       /* The index for which to generate a key */
-  int iCur           /* Cursor number for the pIdx->pTable table */
+  int iCur,          /* Cursor number for the pIdx->pTable table */
+  int regOut         /* Write the new index key to this register */
 ){
+  Vdbe *v = pParse->pVdbe;
   int j;
   Table *pTab = pIdx->pTable;
+  int regBase;
+  int nCol;
 
-  sqlite3VdbeAddOp1(v, OP_Rowid, iCur);
-  for(j=0; j<pIdx->nColumn; j++){
+  nCol = pIdx->nColumn;
+  regBase = sqlite3GetTempRange(pParse, nCol+1);
+  sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol);
+  for(j=0; j<nCol; j++){
     int idx = pIdx->aiColumn[j];
     if( idx==pTab->iPKey ){
-      sqlite3VdbeAddOp1(v, OP_Copy, -j);
+      sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j);
     }else{
-      sqlite3VdbeAddOp2(v, OP_Column, iCur, idx);
+      sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j);
       sqlite3ColumnDefault(v, pTab, idx);
     }
   }
-  sqlite3VdbeAddOp1(v, OP_MakeIdxRec, pIdx->nColumn);
+  sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nCol+1, regOut);
   sqlite3IndexAffinityStr(v, pIdx);
+  sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
+  return regBase;
 }
diff --git a/src/expr.c b/src/expr.c
index c1cb722..8863641 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.341 2008/01/10 03:46:36 drh Exp $
+** $Id: expr.c,v 1.342 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1550,7 +1550,7 @@
 ** The returned value indicates the structure type, as follows:
 **
 **   IN_INDEX_ROWID - The cursor was opened on a database table.
-**   IN_INDEX_INDEX - The cursor was opened on a database indec.
+**   IN_INDEX_INDEX - The cursor was opened on a database index.
 **   IN_INDEX_EPH -   The cursor was opened on a specially created and
 **                    populated epheremal table.
 **
@@ -1765,6 +1765,7 @@
         int i;
         ExprList *pList = pExpr->pList;
         struct ExprList_item *pItem;
+        int r1, r2;
 
         if( !affinity ){
           affinity = SQLITE_AFF_NONE;
@@ -1772,6 +1773,8 @@
         keyInfo.aColl[0] = pExpr->pLeft->pColl;
 
         /* Loop through each expression in <exprlist>. */
+        r1 = sqlite3GetTempReg(pParse);
+        r2 = sqlite3GetTempReg(pParse);
         for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
           Expr *pE2 = pItem->pExpr;
 
@@ -1786,10 +1789,12 @@
           }
 
           /* Evaluate the expression and insert it into the temp table */
-          sqlite3ExprCode(pParse, pE2, 0);
-          sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &affinity, 1);
-          sqlite3VdbeAddOp1(v, OP_IdxInsert, pExpr->iTable);
+          sqlite3ExprCode(pParse, pE2, r1);
+          sqlite3VdbeAddOp4(v, OP_RegMakeRec, r1, 1, r2, &affinity, 1);
+          sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
         }
+        sqlite3ReleaseTempReg(pParse, r1);
+        sqlite3ReleaseTempReg(pParse, r2);
       }
       sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);
       break;
@@ -2230,6 +2235,7 @@
       int j1, j2, j3, j4, j5;
       char affinity;
       int eType;
+      int r1, r2, r3;
 
       eType = sqlite3FindInIndex(pParse, pExpr, 0);
 
@@ -2239,29 +2245,35 @@
       */
       affinity = comparisonAffinity(pExpr);
 
-      sqlite3VdbeAddOp1(v, OP_Integer, 1);
+      if( target ){
+        r1 = target;
+      }else{
+        r1 = sqlite3GetTempReg(pParse);
+      }
+      inReg = r1;
+      sqlite3VdbeAddOp2(v, OP_Integer, 1, r1);
 
       /* Code the <expr> from "<expr> IN (...)". The temporary table
       ** pExpr->iTable contains the values that make up the (...) set.
       */
-      sqlite3ExprCode(pParse, pExpr->pLeft, 0);
-      sqlite3VdbeAddOp0(v, OP_SCopy);
-      j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
-      sqlite3VdbeAddOp1(v, OP_Pop, 2);
-      sqlite3VdbeAddOp0(v, OP_Null);
+      r2 = sqlite3ExprCode(pParse, pExpr->pLeft, -1);
+      j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r2);
+      sqlite3VdbeAddOp2(v, OP_Null, 0, r1);
       j2  = sqlite3VdbeAddOp0(v, OP_Goto);
       sqlite3VdbeJumpHere(v, j1);
       if( eType==IN_INDEX_ROWID ){
-        j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, 1);
-        j4 = sqlite3VdbeAddOp1(v, OP_NotExists, pExpr->iTable);
+        j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r2, 0, 1);
+        j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r2);
         j5 = sqlite3VdbeAddOp0(v, OP_Goto);
         sqlite3VdbeJumpHere(v, j3);
         sqlite3VdbeJumpHere(v, j4);
       }else{
-        sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &affinity, 1);
-        j5 = sqlite3VdbeAddOp1(v, OP_Found, pExpr->iTable);
+        r3 = sqlite3GetTempReg(pParse);
+        sqlite3VdbeAddOp4(v, OP_RegMakeRec, r2, 1, r3, &affinity, 1);
+        j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r3);
+        sqlite3ReleaseTempReg(pParse, r3);
       }
-      sqlite3VdbeAddOp2(v, OP_AddImm, 0, -1);
+      sqlite3VdbeAddOp2(v, OP_AddImm, r1, -1);
       sqlite3VdbeJumpHere(v, j2);
       sqlite3VdbeJumpHere(v, j5);
       break;
@@ -2384,19 +2396,19 @@
 ** not cached.  If the expression is cached, its result is stored in a 
 ** memory location.
 */
-void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr){
+void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
   Vdbe *v = pParse->pVdbe;
   VdbeOp *pOp;
   int iMem;
   int addr1, addr2;
   if( v==0 ) return;
   addr1 = sqlite3VdbeCurrentAddr(v);
-  sqlite3ExprCode(pParse, pExpr, 0);
+  sqlite3ExprCode(pParse, pExpr, target);
   addr2 = sqlite3VdbeCurrentAddr(v);
   if( addr2>addr1+1
    || ((pOp = sqlite3VdbeGetOp(v, addr1))!=0 && pOp->opcode==OP_Function) ){
     iMem = pExpr->iTable = ++pParse->nMem;
-    sqlite3VdbeAddOp2(v, OP_Copy, 0, iMem);
+    sqlite3VdbeAddOp2(v, OP_Copy, target, iMem);
     pExpr->op = TK_REGISTER;
   }
 }
diff --git a/src/insert.c b/src/insert.c
index 7258570..7577f46 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.221 2008/01/10 03:46:36 drh Exp $
+** $Id: insert.c,v 1.222 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -28,6 +28,9 @@
 **  'c'            NUMERIC
 **  'd'            INTEGER
 **  'e'            REAL
+**
+** An extra 'b' is appended to the end of the string to cover the
+** rowid that appears as the last column in every index.
 */
 void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
   if( !pIdx->zColAff ){
@@ -42,14 +45,15 @@
     int n;
     Table *pTab = pIdx->pTable;
     sqlite3 *db = sqlite3VdbeDb(v);
-    pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+1);
+    pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+2);
     if( !pIdx->zColAff ){
       return;
     }
     for(n=0; n<pIdx->nColumn; n++){
       pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
     }
-    pIdx->zColAff[pIdx->nColumn] = '\0';
+    pIdx->zColAff[n++] = SQLITE_AFF_NONE;
+    pIdx->zColAff[n] = 0;
   }
  
   sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);
@@ -679,6 +683,9 @@
   */
   endOfLoop = sqlite3VdbeMakeLabel(v);
   if( triggers_exist & TRIGGER_BEFORE ){
+    int regRowid;
+    int regCols;
+    int regRec;
 
     /* build the NEW.* reference row.  Note that if there is an INTEGER
     ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
@@ -686,20 +693,19 @@
     ** we do not know what the unique ID will be (because the insert has
     ** not happened yet) so we substitute a rowid of -1
     */
+    regRowid = sqlite3GetTempReg(pParse);
     if( keyColumn<0 ){
-      sqlite3VdbeAddOp2(v, OP_Integer, -1, 0);
+      sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
     }else if( useTempTable ){
-      sqlite3VdbeAddOp2(v, OP_Column, srcTab, keyColumn);
+      sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
     }else{
       int j1;
       assert( pSelect==0 );  /* Otherwise useTempTable is true */
-      sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
-      sqlite3VdbeAddOp0(v, OP_SCopy);
-      j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
-      sqlite3VdbeAddOp1(v, OP_Pop, 1);
-      sqlite3VdbeAddOp1(v, OP_Integer, -1);
+      sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
+      j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
+      sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
       sqlite3VdbeJumpHere(v, j1);
-      sqlite3VdbeAddOp0(v, OP_MustBeInt);
+      sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid);
     }
 
     /* Cannot have triggers on a virtual table. If it were possible,
@@ -709,6 +715,7 @@
 
     /* Create the new column data
     */
+    regCols = sqlite3GetTempRange(pParse, pTab->nCol);
     for(i=0; i<pTab->nCol; i++){
       if( pColumn==0 ){
         j = i;
@@ -718,15 +725,16 @@
         }
       }
       if( pColumn && j>=pColumn->nId ){
-        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
+        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i);
       }else if( useTempTable ){
-        sqlite3VdbeAddOp2(v, OP_Column, srcTab, j); 
+        sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i); 
       }else{
         assert( pSelect==0 ); /* Otherwise useTempTable is true */
-        sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr);
+        sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i);
       }
     }
-    sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0);
+    regRec = sqlite3GetTempReg(pParse);
+    sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRec);
 
     /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
     ** do not attempt any conversions before assembling the record.
@@ -736,7 +744,10 @@
     if( !isView ){
       sqlite3TableAffinityStr(v, pTab);
     }
-    sqlite3CodeInsert(pParse, newIdx, OPFLAG_APPEND);
+    sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid);
+    sqlite3ReleaseTempReg(pParse, regRec);
+    sqlite3ReleaseTempReg(pParse, regRowid);
+    sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
 
     /* Fire BEFORE or INSTEAD OF triggers */
     if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab, 
@@ -1123,7 +1134,7 @@
         break;
       }
       case OE_Replace: {
-        sqlite3GenerateRowIndexDelete(v, pTab, baseCur, 0);
+        sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
         if( isUpdate ){
           sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
         }
@@ -1148,20 +1159,25 @@
   ** Add the new records to the indices as we go.
   */
   for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
+    int regIdx;
+    int regR;
+
     if( aRegIdx[iCur]==0 ) continue;  /* Skip unused indices */
 
     /* Create a key for accessing the index entry */
-    sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
+    regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
     for(i=0; i<pIdx->nColumn; i++){
       int idx = pIdx->aiColumn[i];
       if( idx==pTab->iPKey ){
-        sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
+        sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
       }else{
-        sqlite3VdbeAddOp1(v, OP_SCopy, regData+idx);
+        sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i);
       }
     }
-    j2 = sqlite3VdbeAddOp3(v, OP_MakeIdxRec, pIdx->nColumn, 0, aRegIdx[iCur]);
+    sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
+    sqlite3VdbeAddOp3(v, OP_RegMakeRec, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
     sqlite3IndexAffinityStr(v, pIdx);
+    sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
 
     /* Find out what action to take in case there is an indexing conflict */
     onError = pIdx->onError;
@@ -1178,9 +1194,11 @@
     
 
     /* Check to see if the new index entry will be unique */
-    sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]);
-    sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
-    j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0, 0, 0, P4_INT32);
+    j2 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdx, 0, pIdx->nColumn);
+    regR = sqlite3GetTempReg(pParse);
+    sqlite3VdbeAddOp2(v, OP_SCopy, regRowid-hasTwoRowids, regR);
+    j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0,
+                           regR, (char*)aRegIdx[iCur], P4_INT32);
 
     /* Generate code that executes if the new index entry is not unique */
     assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
@@ -1217,26 +1235,21 @@
       }
       case OE_Ignore: {
         assert( seenReplace==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, baseCur, iRowid, 0);
+        sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0);
         if( isUpdate ){
-          sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
-          sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
+          sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
         }
         seenReplace = 1;
         break;
       }
     }
-    sqlite3VdbeJumpHere(v, j3);
-    sqlite3VdbeAddOp1(v, OP_Pop, 1);
-#if NULL_DISTINCT_FOR_UNIQUE
     sqlite3VdbeJumpHere(v, j2);
-#endif
+    sqlite3VdbeJumpHere(v, j3);
+    sqlite3ReleaseTempReg(pParse, regR);
   }
 }
 
diff --git a/src/pragma.c b/src/pragma.c
index 63c3dc3..9fffdff 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.164 2008/01/09 23:04:12 drh Exp $
+** $Id: pragma.c,v 1.165 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -252,6 +252,7 @@
   Db *pDb;
   Vdbe *v = sqlite3GetVdbe(pParse);
   if( v==0 ) return;
+  pParse->nMem = 1;
 
   /* Interpret the [database.] part of the pragma statement. iDb is the
   ** index of the database this pragma is being applied to in db.aDb[]. */
@@ -419,8 +420,8 @@
     }
     sqlite3VdbeSetNumCols(v, 1);
     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P4_STATIC);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, zRet, 0);
-    sqlite3VdbeAddOp2(v, OP_Callback, 1, 0);
+    sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0);
+    sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
   }else
 #endif /* SQLITE_OMIT_PAGER_PRAGMAS */
 
@@ -495,7 +496,7 @@
     sqlite3BeginWriteOperation(pParse, 0, iDb);
     sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
     addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb);
-    sqlite3VdbeAddOp0(v, OP_Callback);
+    sqlite3VdbeAddOp1(v, OP_ResultRow, 1);
     sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
     sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr);
     sqlite3VdbeJumpHere(v, addr);
@@ -564,8 +565,8 @@
         sqlite3VdbeSetNumCols(v, 1);
         sqlite3VdbeSetColName(v, 0, COLNAME_NAME, 
             "temp_store_directory", P4_STATIC);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, sqlite3_temp_directory, 0);
-        sqlite3VdbeAddOp2(v, OP_Callback, 1, 0);
+        sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
+        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
       }
     }else{
       if( zRight[0] 
@@ -643,6 +644,7 @@
       int nHidden = 0;
       Column *pCol;
       sqlite3VdbeSetNumCols(v, 6);
+      pParse->nMem = 6;
       sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P4_STATIC);
       sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
       sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P4_STATIC);
@@ -656,18 +658,18 @@
           nHidden++;
           continue;
         }
-        sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 0);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pCol->zName, 0);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0,
+        sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 1);
+        sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pCol->zName, 0);
+        sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
            pCol->zType ? pCol->zType : "", 0);
-        sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 0);
+        sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 4);
         if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, (char*)pDflt->z, pDflt->n);
+          sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
         }else{
-          sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
+          sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
         }
-        sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 0);
-        sqlite3VdbeAddOp2(v, OP_Callback, 6, 0);
+        sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 6);
+        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
       }
     }
   }else
@@ -681,16 +683,17 @@
       int i;
       pTab = pIdx->pTable;
       sqlite3VdbeSetNumCols(v, 3);
+      pParse->nMem = 3;
       sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P4_STATIC);
       sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P4_STATIC);
       sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P4_STATIC);
       for(i=0; i<pIdx->nColumn; i++){
         int cnum = pIdx->aiColumn[i];
-        sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
-        sqlite3VdbeAddOp2(v, OP_Integer, cnum, 0);
+        sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+        sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
         assert( pTab->nCol>cnum );
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->aCol[cnum].zName, 0);
-        sqlite3VdbeAddOp2(v, OP_Callback, 3, 0);
+        sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
+        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
       }
     }
   }else
@@ -706,14 +709,15 @@
       if( pIdx ){
         int i = 0; 
         sqlite3VdbeSetNumCols(v, 3);
+        pParse->nMem = 3;
         sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
         sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
         sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P4_STATIC);
         while(pIdx){
-          sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pIdx->zName, 0);
-          sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 0);
-          sqlite3VdbeAddOp2(v, OP_Callback, 3, 0);
+          sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+          sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
+          sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
+          sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
           ++i;
           pIdx = pIdx->pNext;
         }
@@ -725,17 +729,18 @@
     int i;
     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
     sqlite3VdbeSetNumCols(v, 3);
+    pParse->nMem = 3;
     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
     sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
     sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P4_STATIC);
     for(i=0; i<db->nDb; i++){
       if( db->aDb[i].pBt==0 ) continue;
       assert( db->aDb[i].zName!=0 );
-      sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, db->aDb[i].zName, 0);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0,
+      sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, db->aDb[i].zName, 0);
+      sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
            sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
-      sqlite3VdbeAddOp2(v, OP_Callback, 3, 0);
+      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
     }
   }else
 
@@ -743,13 +748,14 @@
     int i = 0;
     HashElem *p;
     sqlite3VdbeSetNumCols(v, 2);
+    pParse->nMem = 2;
     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
     sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
     for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
       CollSeq *pColl = (CollSeq *)sqliteHashData(p);
-      sqlite3VdbeAddOp2(v, OP_Integer, i++, 0);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pColl->zName, 0);
-      sqlite3VdbeAddOp2(v, OP_Callback, 2, 0);
+      sqlite3VdbeAddOp2(v, OP_Integer, i++, 1);
+      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0);
+      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
     }
   }else
 #endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
@@ -766,6 +772,7 @@
       if( pFK ){
         int i = 0; 
         sqlite3VdbeSetNumCols(v, 5);
+        pParse->nMem = 5;
         sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P4_STATIC);
         sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P4_STATIC);
         sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P4_STATIC);
@@ -775,13 +782,13 @@
           int j;
           for(j=0; j<pFK->nCol; j++){
             char *zCol = pFK->aCol[j].zCol;
-            sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
-            sqlite3VdbeAddOp2(v, OP_Integer, j, 0);
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pFK->zTo, 0);
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0,
+            sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
+            sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
+            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
+            sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
                               pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
-            sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 0, 0, zCol, 0);
-            sqlite3VdbeAddOp2(v, OP_Callback, 5, 0);
+            sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);
+            sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
           }
           ++i;
           pFK = pFK->pNextFrom;
@@ -831,17 +838,17 @@
     ** error message
     */
     static const VdbeOpList endCode[] = {
-      { OP_SCopy,       1, 0,        0},
-      { OP_Integer,     0, 0,        0},
-      { OP_Ne,          0, 0,        0},    /* 2 */
-      { OP_String8,     0, 0,        0},    /* 3 */
-      { OP_Callback,    1, 0,        0},
+      { OP_AddImm,      1, 0,        0},    /* 0 */
+      { OP_IfNeg,       1, 0,        0},    /* 1 */
+      { OP_String8,     0, 3,        0},    /* 2 */
+      { OP_ResultRow,   3, 1,        0},
     };
 
     int isQuick = (zLeft[0]=='q');
 
     /* Initialize the VDBE program */
     if( sqlite3ReadSchema(pParse) ) goto pragma_out;
+    pParse->nMem = 6;
     sqlite3VdbeSetNumCols(v, 1);
     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P4_STATIC);
 
@@ -853,8 +860,7 @@
         mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
       }
     }
-    sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);
-    pParse->nMem = 1;
+    sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);  /* reg[1] holds errors left */
 
     /* Do an integrity check on each database file */
     for(i=0; i<db->nDb; i++){
@@ -865,11 +871,14 @@
       if( OMIT_TEMPDB && i==1 ) continue;
 
       sqlite3CodeVerifySchema(pParse, i);
-      addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
+      addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
       sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
       sqlite3VdbeJumpHere(v, addr);
 
       /* Do an integrity check of the B-Tree
+      **
+      ** Begin by filling registers 2, 3, ... with the root pages numbers
+      ** for all tables and indices in the database.
       */
       pTbls = &db->aDb[i].pSchema->tblHash;
       for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
@@ -883,9 +892,13 @@
         }
       }
       if( cnt==0 ) continue;
+
+      /* Make sure sufficient number of registers have been allocated */
       if( pParse->nMem < cnt+3 ){
         pParse->nMem = cnt+3;
       }
+
+      /* Do the b-tree integrity checks */
       sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
       sqlite3VdbeChangeP5(v, i);
       addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2);
@@ -904,28 +917,28 @@
         int loopTop;
 
         if( pTab->pIndex==0 ) continue;
-        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
+        addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
         sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
         sqlite3VdbeJumpHere(v, addr);
         sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
-        sqlite3VdbeAddOp2(v, OP_Integer, 0, 2);
+        sqlite3VdbeAddOp2(v, OP_Integer, 0, 2);  /* reg(2) will count entries */
         loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
-        sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1);
+        sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1);   /* increment entry count */
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
           int jmp2;
           static const VdbeOpList idxErr[] = {
             { OP_AddImm,      1, -1,  0},
-            { OP_String8,     0,  0,  0},    /* 1 */
-            { OP_Rowid,       1,  0,  0},
-            { OP_String8,     0,  0,  0},    /* 3 */
-            { OP_String8,     0,  0,  0},    /* 4 */
-            { OP_Concat,      0,  0,  0},
-            { OP_Concat,      0,  0,  0},
-            { OP_Concat,      0,  0,  0},
-            { OP_Callback,    1,  0,  0},
+            { OP_String8,     0,  3,  0},    /* 1 */
+            { OP_Rowid,       1,  4,  0},
+            { OP_String8,     0,  5,  0},    /* 3 */
+            { OP_String8,     0,  6,  0},    /* 4 */
+            { OP_Concat,      4,  3,  3},
+            { OP_Concat,      5,  3,  3},
+            { OP_Concat,      6,  3,  3},
+            { OP_ResultRow,   3,  1,  0},
           };
-          sqlite3GenerateIndexKey(v, pIdx, 1);
-          jmp2 = sqlite3VdbeAddOp2(v, OP_Found, j+2, 0);
+          sqlite3GenerateIndexKey(pParse, pIdx, 1, 3);
+          jmp2 = sqlite3VdbeAddOp3(v, OP_Found, j+2, 0, 3);
           addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
           sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
           sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC);
@@ -940,14 +953,12 @@
              { OP_Rewind,       0,  0,  0},  /* 1 */
              { OP_AddImm,       3,  1,  0},
              { OP_Next,         0,  0,  0},  /* 3 */
-             { OP_SCopy,        2,  0,  0},
-             { OP_SCopy,        3,  0,  0},
-             { OP_Eq,           0,  0,  0},  /* 6 */
+             { OP_Eq,           2,  0,  3},  /* 4 */
              { OP_AddImm,       1, -1,  0},
-             { OP_String8,      0,  0,  0},  /* 8 */
-             { OP_String8,      0,  0,  0},  /* 9 */
-             { OP_Concat,       0,  0,  0},
-             { OP_Callback,     1,  0,  0},
+             { OP_String8,      0,  2,  0},  /* 6 */
+             { OP_String8,      0,  3,  0},  /* 7 */
+             { OP_Concat,       3,  2,  2},
+             { OP_ResultRow,    2,  1,  0},
           };
           if( pIdx->tnum==0 ) continue;
           addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
@@ -958,17 +969,17 @@
           sqlite3VdbeChangeP2(v, addr+1, addr+4);
           sqlite3VdbeChangeP1(v, addr+3, j+2);
           sqlite3VdbeChangeP2(v, addr+3, addr+2);
-          sqlite3VdbeJumpHere(v, addr+6);
-          sqlite3VdbeChangeP4(v, addr+8, 
+          sqlite3VdbeJumpHere(v, addr+4);
+          sqlite3VdbeChangeP4(v, addr+6, 
                      "wrong # of entries in index ", P4_STATIC);
-          sqlite3VdbeChangeP4(v, addr+9, pIdx->zName, P4_STATIC);
+          sqlite3VdbeChangeP4(v, addr+7, pIdx->zName, P4_STATIC);
         }
       } 
     }
     addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
-    sqlite3VdbeChangeP1(v, addr+1, mxErr);
-    sqlite3VdbeChangeP4(v, addr+3, "ok", P4_STATIC);
-    sqlite3VdbeJumpHere(v, addr+2);
+    sqlite3VdbeChangeP2(v, addr, -mxErr);
+    sqlite3VdbeJumpHere(v, addr+1);
+    sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
   }else
 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
 
@@ -1015,14 +1026,14 @@
       if( sqlite3ReadSchema(pParse) ) goto pragma_out;
       sqlite3VdbeSetNumCols(v, 1);
       sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P4_STATIC);
-      sqlite3VdbeAddOp2(v, OP_String8, 0, 0);
+      sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
       for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
         if( pEnc->enc==ENC(pParse->db) ){
           sqlite3VdbeChangeP4(v, -1, pEnc->zName, P4_STATIC);
           break;
         }
       }
-      sqlite3VdbeAddOp2(v, OP_Callback, 1, 0);
+      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
     }else{                        /* "PRAGMA encoding = XXX" */
       /* Only change the value of sqlite.enc if the database handle is not
       ** initialized. If the main database exists, the new sqlite.enc value
@@ -1109,8 +1120,8 @@
     }else{
       /* Read the specified cookie value */
       static const VdbeOpList readCookie[] = {
-        { OP_ReadCookie,      0,  0,  0},    /* 0 */
-        { OP_Callback,        1,  0,  0}
+        { OP_ReadCookie,      0,  1,  0},    /* 0 */
+        { OP_ResultRow,       1,  1,  0}
       };
       int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
       sqlite3VdbeChangeP1(v, addr, iDb);
@@ -1132,6 +1143,7 @@
     int i;
     Vdbe *v = sqlite3GetVdbe(pParse);
     sqlite3VdbeSetNumCols(v, 2);
+    pParse->nMem = 2;
     sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P4_STATIC);
     sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P4_STATIC);
     for(i=0; i<db->nDb; i++){
@@ -1140,7 +1152,7 @@
       const char *zState = "unknown";
       int j;
       if( db->aDb[i].zName==0 ) continue;
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, db->aDb[i].zName, P4_STATIC);
+      sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
       pBt = db->aDb[i].pBt;
       if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
         zState = "closed";
@@ -1148,8 +1160,8 @@
                                      SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
          zState = azLockName[j];
       }
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, zState, P4_STATIC);
-      sqlite3VdbeAddOp2(v, OP_Callback, 2, 0);
+      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
+      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
     }
   }else
 #endif
diff --git a/src/select.c b/src/select.c
index f7ab87c..65aa362 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.396 2008/01/10 03:46:36 drh Exp $
+** $Id: select.c,v 1.397 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -769,6 +769,9 @@
   int eDest = pDest->eDest;
   int iParm = pDest->iParm;
 
+  int regRow;
+  int regRowid;
+
   iTab = pOrderBy->iECursor;
   if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
     pseudoTab = pParse->nTab++;
@@ -777,35 +780,30 @@
   }
   addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk);
   codeOffset(v, p, cont, 0);
-  if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
-    sqlite3VdbeAddOp2(v, OP_Integer, 1, 0);
-  }
-  sqlite3VdbeAddOp2(v, OP_Column, iTab, pOrderBy->nExpr + 1);
+  regRow = sqlite3GetTempReg(pParse);
+  regRowid = sqlite3GetTempReg(pParse);
+  sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow);
   switch( eDest ){
     case SRT_Table:
     case SRT_EphemTab: {
-      sqlite3VdbeAddOp1(v, OP_NewRowid, iParm);
-      sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
-      sqlite3CodeInsert(pParse, iParm, OPFLAG_APPEND);
+      sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
+      sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
+      sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
       break;
     }
 #ifndef SQLITE_OMIT_SUBQUERY
     case SRT_Set: {
-      int j1, j2;
+      int j1;
       assert( nColumn==1 );
-      sqlite3VdbeAddOp0(v, OP_SCopy);
-      j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
-      sqlite3VdbeAddOp1(v, OP_Pop, 1);
-      j2 = sqlite3VdbeAddOp0(v, OP_Goto);
+      j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow);
+      sqlite3VdbeAddOp4(v, OP_RegMakeRec, regRow, 1, regRow, &p->affinity, 1);
+      sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow);
       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: {
       assert( nColumn==1 );
-      sqlite3VdbeAddOp2(v, OP_Move, 0, iParm);
+      sqlite3VdbeAddOp2(v, OP_Move, regRow, iParm);
       /* The LIMIT clause will terminate the loop for us */
       break;
     }
@@ -813,7 +811,8 @@
     case SRT_Callback:
     case SRT_Subroutine: {
       int i;
-      sqlite3CodeInsert(pParse, pseudoTab, 0);
+      sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid);
+      sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid);
       for(i=0; i<nColumn; i++){
         sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iMem+i);
       }
@@ -829,6 +828,8 @@
       break;
     }
   }
+  sqlite3ReleaseTempReg(pParse, regRow);
+  sqlite3ReleaseTempReg(pParse, regRowid);
 
   /* Jump to the end of the loop when the LIMIT is reached
   */
@@ -2652,165 +2653,6 @@
 }
 
 /*
-** Analyze the SELECT statement passed in as an argument to see if it
-** is a simple min() or max() query.  If it is and this query can be
-** satisfied using a single seek to the beginning or end of an index,
-** then generate the code for this SELECT and return 1.  If this is not a 
-** simple min() or max() query, then return 0;
-**
-** A simply min() or max() query looks like this:
-**
-**    SELECT min(a) FROM table;
-**    SELECT max(a) FROM table;
-**
-** The query may have only a single table in its FROM argument.  There
-** can be no GROUP BY or HAVING or WHERE clauses.  The result set must
-** be the min() or max() of a single column of the table.  The column
-** in the min() or max() function must be indexed.
-**
-** The parameters to this routine are the same as for sqlite3Select().
-** See the header comment on that routine for additional information.
-*/
-#if 0
-static int simpleMinMaxQuery(Parse *pParse, Select *p, SelectDest *pDest){
-  Expr *pExpr;
-  int iCol;
-  Table *pTab;
-  Index *pIdx;
-  int base;
-  Vdbe *v;
-  int seekOp;
-  ExprList *pEList, *pList, eList;
-  struct ExprList_item eListItem;
-  SrcList *pSrc;
-  int brk;
-  int iDb;
-
-  /* Check to see if this query is a simple min() or max() query.  Return
-  ** zero if it is  not.
-  */
-  if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
-  pSrc = p->pSrc;
-  if( pSrc->nSrc!=1 ) return 0;
-  pEList = p->pEList;
-  if( pEList->nExpr!=1 ) return 0;
-  pExpr = pEList->a[0].pExpr;
-  if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
-  pList = pExpr->pList;
-  if( pList==0 || pList->nExpr!=1 ) return 0;
-  if( pExpr->token.n!=3 ) return 0;
-  if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
-    seekOp = OP_Rewind;
-  }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
-    seekOp = OP_Last;
-  }else{
-    return 0;
-  }
-  pExpr = pList->a[0].pExpr;
-  if( pExpr->op!=TK_COLUMN ) return 0;
-  iCol = pExpr->iColumn;
-  pTab = pSrc->a[0].pTab;
-
-  /* This optimization cannot be used with virtual tables. */
-  if( IsVirtual(pTab) ) return 0;
-
-  /* If we get to here, it means the query is of the correct form.
-  ** Check to make sure we have an index and make pIdx point to the
-  ** appropriate index.  If the min() or max() is on an INTEGER PRIMARY
-  ** key column, no index is necessary so set pIdx to NULL.  If no
-  ** usable index is found, return 0.
-  */
-  if( iCol<0 ){
-    pIdx = 0;
-  }else{
-    CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
-    if( pColl==0 ) return 0;
-    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-      assert( pIdx->nColumn>=1 );
-      if( pIdx->aiColumn[0]==iCol && 
-          0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){
-        break;
-      }
-    }
-    if( pIdx==0 ) return 0;
-  }
-
-  /* Identify column types if we will be using the callback.  This
-  ** step is skipped if the output is going to a table or a memory cell.
-  ** The column names have already been generated in the calling function.
-  */
-  v = sqlite3GetVdbe(pParse);
-  if( v==0 ) return 0;
-
-  /* If the output is destined for a temporary table, open that table.
-  */
-  if( pDest->eDest==SRT_EphemTab ){
-    sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iParm, 1);
-  }
-
-  /* Generating code to find the min or the max.  Basically all we have
-  ** to do is find the first or the last entry in the chosen index.  If
-  ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
-  ** or last entry in the main table.
-  */
-  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
-  assert( iDb>=0 || pTab->isEphem );
-  sqlite3CodeVerifySchema(pParse, iDb);
-  sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
-  base = pSrc->a[0].iCursor;
-  brk = sqlite3VdbeMakeLabel(v);
-  computeLimitRegisters(pParse, p, brk);
-  if( pSrc->a[0].pSelect==0 ){
-    sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead);
-  }
-  if( pIdx==0 ){
-    sqlite3VdbeAddOp2(v, seekOp, base, 0);
-  }else{
-    /* Even though the cursor used to open the index here is closed
-    ** as soon as a single value has been read from it, allocate it
-    ** using (pParse->nTab++) to prevent the cursor id from being 
-    ** reused. This is important for statements of the form 
-    ** "INSERT INTO x SELECT max() FROM x".
-    */
-    int iIdx;
-    KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
-    iIdx = pParse->nTab++;
-    assert( pIdx->pSchema==pTab->pSchema );
-    sqlite3VdbeAddOp4(v, OP_OpenRead, iIdx, pIdx->tnum, iDb,
-        (char*)pKey, P4_KEYINFO_HANDOFF);
-    if( seekOp==OP_Rewind ){
-      sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
-      sqlite3VdbeAddOp2(v, OP_MakeRecord, 1, 0);
-      seekOp = OP_MoveGt;
-    }
-    if( pIdx->aSortOrder[0]==SQLITE_SO_DESC ){
-      /* Ticket #2514: invert the seek operator if we are using
-      ** a descending index. */
-      if( seekOp==OP_Last ){
-        seekOp = OP_Rewind;
-      }else{
-        assert( seekOp==OP_MoveGt );
-        seekOp = OP_MoveLt;
-      }
-    }
-    sqlite3VdbeAddOp2(v, seekOp, iIdx, 0);
-    sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdx, 0);
-    sqlite3VdbeAddOp2(v, OP_Close, iIdx, 0);
-    sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
-  }
-  eList.nExpr = 1;
-  memset(&eListItem, 0, sizeof(eListItem));
-  eList.a = &eListItem;
-  eList.a[0].pExpr = pExpr;
-  selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, pDest, brk, brk, 0);
-  sqlite3VdbeResolveLabel(v, brk);
-  sqlite3VdbeAddOp2(v, OP_Close, base, 0);
-  
-  return 1;
-}
-#endif 
-
-/*
 ** This routine resolves any names used in the result set of the
 ** supplied SELECT statement. If the SELECT statement being resolved
 ** is a sub-select, then pOuterNC is a pointer to the NameContext 
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 6f6842a..52ee5db 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.646 2008/01/10 03:46:36 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.647 2008/01/10 23:50:11 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1766,7 +1766,7 @@
 void sqlite3WhereEnd(WhereInfo*);
 void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
 int sqlite3ExprCode(Parse*, Expr*, int);
-void sqlite3ExprCodeAndCache(Parse*, Expr*);
+void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
 int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
 void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
 void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
@@ -1795,9 +1795,9 @@
 int sqlite3ExprIsConstantOrFunction(Expr*);
 int sqlite3ExprIsInteger(Expr*, int*);
 int sqlite3IsRowid(const char*);
-void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int);
-void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*);
-void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
+void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int);
+void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
+int sqlite3GenerateIndexKey(Parse*, Index*, int, int);
 void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
                                      int*,int,int,int,int);
 void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int);
diff --git a/src/trigger.c b/src/trigger.c
index bd92891..0204cae 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -227,43 +227,20 @@
   ** build the sqlite_master entry
   */
   if( !db->init.busy ){
-    static const VdbeOpList insertTrig[] = {
-      { OP_NewRowid,   0, 0,  0          },
-      { OP_String8,    0, 0,  0          },  /* 1: "trigger" */
-      { OP_String8,    0, 0,  0          },  /* 2: trigger name */
-      { OP_String8,    0, 0,  0          },  /* 3: table name */
-      { OP_Integer,    0, 0,  0          },
-      { OP_String8,    0, 0,  0          },  /* 5: "CREATE TRIGGER " */
-      { OP_String8,    0, 0,  0          },  /* 6: SQL */
-      { OP_Concat,     0, 0,  0          }, 
-      { OP_MakeRecord, 5, 0,  0          },  /* 8: "aaada" */
-      { OP_Move,       0, 0,  0          },  /* 9: Store data */
-      { OP_Move,       0, 0,  0          },  /* 10: Store key */
-      { OP_Insert,     0, 0,  0          },
-    };
-    int addr;
     Vdbe *v;
-    int iKey = ++pParse->nMem;
-    int iData = ++pParse->nMem;
+    char *z;
 
     /* Make an entry in the sqlite_master table */
     v = sqlite3GetVdbe(pParse);
     if( v==0 ) goto triggerfinish_cleanup;
     sqlite3BeginWriteOperation(pParse, 0, iDb);
-    sqlite3OpenMasterTable(pParse, iDb);
-    addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
-    sqlite3VdbeChangeP4(v, addr+1, "trigger", P4_STATIC);
-    sqlite3VdbeChangeP4(v, addr+2, pTrig->name, 0); 
-    sqlite3VdbeChangeP4(v, addr+3, pTrig->table, 0);
-    sqlite3VdbeChangeP4(v, addr+5, "CREATE TRIGGER ", P4_STATIC); 
-    sqlite3VdbeChangeP4(v, addr+6, (char*)pAll->z, pAll->n);
-    sqlite3VdbeChangeP4(v, addr+8, "aaada", P4_STATIC);
-    sqlite3VdbeChangeP2(v, addr+9, iData);
-    sqlite3VdbeChangeP2(v, addr+10, iKey);
-    sqlite3VdbeChangeP2(v, addr+11, iData);
-    sqlite3VdbeChangeP3(v, addr+11, iKey);
+    z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
+    sqlite3NestedParse(pParse,
+       "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
+       db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name,
+       pTrig->table, z);
+    sqlite3_free(z);
     sqlite3ChangeCookie(db, v, iDb);
-    sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
     sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
         db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC
     );
diff --git a/src/update.c b/src/update.c
index 0457075..6d1a21f 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.166 2008/01/09 23:04:12 drh Exp $
+** $Id: update.c,v 1.167 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -404,50 +404,60 @@
   sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
 
   if( triggers_exist ){
+    int regRowid;
+    int regRow;
+    int regCols;
+
     /* Make cursor iCur point to the record that is being updated.
     */
     sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
 
     /* Generate the OLD table
     */
-    sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0);
+    regRowid = sqlite3GetTempReg(pParse);
+    regRow = sqlite3GetTempReg(pParse);
+    sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
     if( !old_col_mask ){
-      sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
+      sqlite3VdbeAddOp2(v, OP_Null, 0, regRow);
     }else{
-      sqlite3VdbeAddOp1(v, OP_RowData, iCur);
+      sqlite3VdbeAddOp2(v, OP_RowData, iCur, regRow);
     }
-    sqlite3CodeInsert(pParse, oldIdx, 0);
+    sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, regRow, regRowid);
 
     /* Generate the NEW table
     */
     if( chngRowid ){
-      sqlite3ExprCodeAndCache(pParse, pRowidExpr);
+      sqlite3ExprCodeAndCache(pParse, pRowidExpr, regRowid);
     }else{
-      sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0);
+      sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
     }
+    regCols = sqlite3GetTempRange(pParse, pTab->nCol);
     for(i=0; i<pTab->nCol; i++){
       if( i==pTab->iPKey ){
-        sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
+        sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
         continue;
       }
       j = aXRef[i];
       if( new_col_mask&((u32)1<<i) || new_col_mask==0xffffffff ){
         if( j<0 ){
-          sqlite3VdbeAddOp2(v, OP_Column, iCur, i);
+          sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regCols+i);
           sqlite3ColumnDefault(v, pTab, i);
         }else{
-          sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
+          sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i);
         }
       }else{
-        sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
+        sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
       }
     }
-    sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0);
+    sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRow);
     if( !isView ){
       sqlite3TableAffinityStr(v, pTab);
     }
+    sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
     if( pParse->nErr ) goto update_cleanup;
-    sqlite3CodeInsert(pParse, newIdx, 0);
+    sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRow, regRowid);
+    sqlite3ReleaseTempReg(pParse, regRowid);
+    sqlite3ReleaseTempReg(pParse, regRow);
 
     sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
     sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
@@ -495,7 +505,7 @@
 
     /* Delete the old indices for the current record.
     */
-    sqlite3GenerateRowIndexDelete(v, pTab, iCur, aRegIdx);
+    sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
 
     /* If changing the record number, delete the old record.
     */
diff --git a/src/vdbe.c b/src/vdbe.c
index b5063fb..66c49af 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.691 2008/01/09 23:04:12 drh Exp $
+** $Id: vdbe.c,v 1.692 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1121,10 +1121,12 @@
     assert( pOp->p2<=p->nMem );
     pOut = &p->aMem[pOp->p2];
   }
+  assert( pOut!=pIn1 );
   if( pOp->opcode==OP_Move ){
     rc = sqlite3VdbeMemMove(pOut, pIn1);
     if( pOp->p1==0 ) pTos--;
   }else{
+    Release(pOut);
     sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
     if( pOp->opcode==OP_Copy ){
       Deephemeralize(pOut);
@@ -1168,56 +1170,6 @@
   break;
 }
 
-/* Opcode: Callback P1 * *
-**
-** The top P1 values on the stack represent a single result row from
-** a query.  This opcode causes the sqlite3_step() call to terminate
-** with an SQLITE_ROW return code and it sets up the sqlite3_stmt
-** structure to provide access to the top P1 values as the result
-** row.  When the sqlite3_step() function is run again, the top P1
-** values will be automatically popped from the stack before the next
-** instruction executes.
-*/
-case OP_Callback: {            /* no-push */
-  Mem *pMem;
-  Mem *pFirstColumn;
-  assert( p->nResColumn==pOp->p1 );
-
-  /* Data in the pager might be moved or changed out from under us
-  ** in between the return from this sqlite3_step() call and the
-  ** next call to sqlite3_step().  So deephermeralize everything on 
-  ** the stack.  Note that ephemeral data is never stored in memory 
-  ** cells so we do not have to worry about them.
-  */
-  pFirstColumn = &pTos[1-pOp->p1];
-  for(pMem = p->aStack; pMem<pFirstColumn; pMem++){
-    Deephemeralize(pMem);
-  }
-
-  /* Invalidate all ephemeral cursor row caches */
-  p->cacheCtr = (p->cacheCtr + 2)|1;
-
-  /* Make sure the results of the current row are \000 terminated
-  ** and have an assigned type.  The results are deephemeralized as
-  ** as side effect.
-  */
-  for(; pMem<=pTos; pMem++ ){
-    sqlite3VdbeMemNulTerminate(pMem);
-    storeTypeInfo(pMem, encoding);
-  }
-
-  /* Set up the statement structure so that it will pop the current
-  ** results from the stack when the statement returns.
-  */
-  p->pResultSet = pFirstColumn;
-  p->nCallback++;
-  p->popStack = pOp->p1;
-  p->pc = pc + 1;
-  p->pTos = pTos;
-  rc = SQLITE_ROW;
-  goto vdbe_return;
-}
-
 /* Opcode: ResultRow P1 P2 *
 **
 ** The registers P1 throught P1+P2-1 contain a single row of
@@ -1988,9 +1940,8 @@
   nPop = 0;
   if( pIn1->flags & MEM_Null ) break;  /* Do nothing to NULLs */
   sqlite3VdbeMemIntegerify(pIn1);
-  assert( (pIn1->flags & MEM_Dyn)==0 );
   pIn1->u.i = !pIn1->u.i;
-  pIn1->flags = MEM_Int;
+  assert( pIn1->flags==MEM_Int );
   break;
 }
 
@@ -2004,9 +1955,8 @@
   nPop = 0;
   if( pIn1->flags & MEM_Null ) break;  /* Do nothing to NULLs */
   sqlite3VdbeMemIntegerify(pIn1);
-  assert( (pIn1->flags & MEM_Dyn)==0 );
   pIn1->u.i = ~pIn1->u.i;
-  pIn1->flags = MEM_Int;
+  assert( pIn1->flags==MEM_Int );
   break;
 }
 
@@ -2078,17 +2028,25 @@
   break;
 }
 
-/* Opcode: IsNull P1 P2 * * *
+/* Opcode: IsNull P1 P2 P3 * *
 **
-** Jump to P2 if the value in register P1 is NULL.
+** Jump to P2 if the value in register P1 is NULL.  If P3 is greater
+** than zero, then check all values reg(P1), reg(P1+1), 
+** reg(P1+2), ..., reg(P1+P3-1).
 **
 ** 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_IsNull: {            /* same as TK_ISNULL, no-push, jump, in1 */
-  if( (pIn1->flags & MEM_Null)!=0 ){
-    pc = pOp->p2 - 1;
-  }
+  int n = pOp->p3;
+  assert( pOp->p3==0 || pOp->p1>0 );
+  do{
+    if( (pIn1->flags & MEM_Null)!=0 ){
+      pc = pOp->p2 - 1;
+      break;
+    }
+    pIn1++;
+  }while( --n > 0 );
   break;
 }
 
@@ -2409,15 +2367,6 @@
 ** macros defined in sqliteInt.h.
 **
 ** If P4 is NULL then all index fields have the affinity NONE.
-**
-** See also OP_MakeIdxRec
-*/
-/* Opcode: MakeIdxRec P1 P2 P4
-**
-** This opcode works just OP_MakeRecord except that it reads an extra
-** integer from the stack (thus reading a total of abs(P1+1) entries)
-** and appends that extra integer to the end of the record as a varint.
-** This results in an index key.
 */
 /*
 ** Opcode: RegMakeRec P1 P2 P3 P4 *
@@ -2428,17 +2377,7 @@
 ** There is no jump on NULL - that can be done with a separate
 ** OP_AnyNull opcode.
 */
-/*
-** Opcode: RegMakeIRec P1 P2 P4
-**
-** Works like OP_MakeIdxRec except data is taken from registers
-** rather than from the stack.  The P1 register is an integer which
-** is the number of register to use in building the new record.
-** Data is taken from P1+1, P1+2, ..., P1+mem[P1].
-*/
 case OP_RegMakeRec:
-case OP_RegMakeIRec:
-case OP_MakeIdxRec:          /* jump */
 case OP_MakeRecord: {        /* jump */
   /* Assuming the record contains N fields, the record format looks
   ** like this:
@@ -2457,7 +2396,6 @@
   */
   u8 *zNewRecord;        /* A buffer to hold the data for the new record */
   Mem *pRec;             /* The new record */
-  Mem *pRowid = 0;       /* Rowid appended to the new record */
   u64 nData = 0;         /* Number of bytes of data space */
   int nHdr = 0;          /* Number of bytes of header space */
   u64 nByte = 0;         /* Data space required for this record */
@@ -2470,24 +2408,22 @@
   int leaveOnStack;      /* If true, leave the entries on the stack */
   int nField;            /* Number of fields in the record */
   int jumpIfNull;        /* Jump here if non-zero and any entries are NULL. */
-  int addRowid;          /* True to append a rowid column at the end */
   char *zAffinity;       /* The affinity string for the record */
   int file_format;       /* File format to use for encoding */
   int i;                 /* Space used in zNewRecord[] */
   char zTemp[NBFS];      /* Space to hold small records */
 
   if( pOp->p1<0 ){
-    assert( pOp->opcode==OP_MakeRecord || pOp->opcode==OP_MakeIdxRec );
+    assert( pOp->opcode==OP_MakeRecord );
     leaveOnStack = 1;
     nField = -pOp->p1;
   }else{
     leaveOnStack = 0;
     nField = pOp->p1;
   }
-  addRowid = pOp->opcode==OP_MakeIdxRec || pOp->opcode==OP_RegMakeIRec;
   zAffinity = pOp->p4.z;
 
-  if( pOp->opcode==OP_RegMakeRec || pOp->opcode==OP_RegMakeIRec ){
+  if( pOp->opcode==OP_RegMakeRec ){
     assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
     pData0 = &p->aMem[nField];
     nField = pOp->p2;
@@ -2530,20 +2466,6 @@
     }
   }
 
-  /* If we have to append a varint rowid to this record, set pRowid
-  ** to the value of the rowid and increase nByte by the amount of space
-  ** required to store it.
-  */
-  if( addRowid ){
-    pRowid = &pData0[-1];
-    assert( pRowid>=p->aStack );
-    sqlite3VdbeMemIntegerify(pRowid);
-    serial_type = sqlite3VdbeSerialType(pRowid, 0);
-    nData += sqlite3VdbeSerialTypeLen(serial_type);
-    nHdr += sqlite3VarintLen(serial_type);
-    nZero = 0;
-  }
-
   /* Add the initial header varint and total the size */
   nHdr += nVarint = sqlite3VarintLen(nHdr);
   if( nVarint<sqlite3VarintLen(nHdr) ){
@@ -2570,20 +2492,14 @@
     serial_type = sqlite3VdbeSerialType(pRec, file_format);
     i += sqlite3PutVarint(&zNewRecord[i], serial_type);      /* serial type */
   }
-  if( addRowid ){
-    i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0));
-  }
   for(pRec=pData0; pRec<=pLast; pRec++){  /* serial data */
     i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format);
   }
-  if( addRowid ){
-    i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRowid, 0);
-  }
   assert( i==nByte );
 
   /* Pop entries off the stack if required. Push the new record on. */
   if( !leaveOnStack ){
-    popStack(&pTos, nField+addRowid);
+    popStack(&pTos, nField);
   }
   if( pOp->p3==0 ){
     pOut = ++pTos;
@@ -3434,7 +3350,7 @@
     */
     nPop = 0;
     pIn3->u.i = v;
-    pIn3->flags = MEM_Int;
+    assert( pIn3->flags==MEM_Int );
   }
   break;
 }
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 296e8e7..39bbcd0 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -395,7 +395,6 @@
 ** This routine is useful for setting a jump destination.
 */
 void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
-  assert( val>=0 );
   assert( p==0 || p->magic==VDBE_MAGIC_INIT );
   if( p && addr>=0 && p->nOp>addr && p->aOp ){
     p->aOp[addr].p2 = val;
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index 864aadd..1fa71f1 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -12,7 +12,7 @@
 **
 ** This file contains code used to implement incremental BLOB I/O.
 **
-** $Id: vdbeblob.c,v 1.17 2008/01/03 07:54:24 danielk1977 Exp $
+** $Id: vdbeblob.c,v 1.18 2008/01/10 23:50:11 drh Exp $
 */
 
 #include "sqliteInt.h"
@@ -54,7 +54,7 @@
   ** vdbe program will take advantage of the various transaction,
   ** locking and error handling infrastructure built into the vdbe.
   **
-  ** After seeking the cursor, the vdbe executes an OP_Callback.
+  ** After seeking the cursor, the vdbe executes an OP_ResultRow.
   ** Code external to the Vdbe then "borrows" the b-tree cursor and
   ** uses it to implement the blob_read(), blob_write() and 
   ** blob_bytes() functions.
@@ -74,10 +74,10 @@
     {OP_OpenWrite, 0, 0, 0},       /* 3: Open cursor 0 for read/write */
     {OP_SetNumColumns, 0, 0, 0},   /* 4: Num cols for cursor */
 
-    {OP_Variable, 1, 0, 0},        /* 5: Push the rowid to the stack */
-    {OP_NotExists, 0, 10, 0},      /* 6: Seek the cursor */
-    {OP_Column, 0, 0, 0},          /* 7  */
-    {OP_Callback, 0, 0, 0},        /* 8  */
+    {OP_Variable, 1, 1, 0},        /* 5: Push the rowid to the stack */
+    {OP_NotExists, 0, 10, 1},      /* 6: Seek the cursor */
+    {OP_Column, 0, 0, 1},          /* 7  */
+    {OP_ResultRow, 1, 0, 0},       /* 8  */
     {OP_Close, 0, 0, 0},           /* 9  */
     {OP_Halt, 0, 0, 0},            /* 10 */
   };
@@ -181,7 +181,7 @@
       */
       sqlite3VdbeChangeP2(v, 4, pTab->nCol+1);
       if( !db->mallocFailed ){
-        sqlite3VdbeMakeReady(v, 1, 0, 1, 0);
+        sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
       }
     }