Modify the code generated for a DELETE to use registers instead of the vdbe stack. (CVS 4675)

FossilOrigin-Name: 173f281334d340290e1978abea5d1ea804141910
diff --git a/src/delete.c b/src/delete.c
index a2c4da2..88a6ef5 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.144 2008/01/03 18:03:09 drh Exp $
+** $Id: delete.c,v 1.145 2008/01/04 13:24:29 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -299,6 +299,8 @@
   ** the table and pick which records to delete.
   */
   else{
+    int iRowid = ++pParse->nMem;    /* Used for storing value read from fifo */
+
     /* Begin the database scan
     */
     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);
@@ -342,44 +344,41 @@
     if( triggers_exist ){
       sqlite3VdbeResolveLabel(v, addr);
     }
-    addr = sqlite3VdbeAddOp2(v, OP_FifoRead, 0, end);
+    addr = sqlite3VdbeAddOp2(v, OP_FifoRead, iRowid, end);
     sqlite3VdbeAddOp1(v, OP_StackDepth, -1);
 
     if( triggers_exist ){
-      int mem1 = ++pParse->nMem;
-      if( !isView ){
-        sqlite3VdbeAddOp1(v, OP_MemStore, mem1);
-      }
-      sqlite3VdbeAddOp2(v, OP_NotExists, iCur, addr);
-      sqlite3VdbeAddOp1(v, OP_Rowid, iCur);
+      int iData = ++pParse->nMem;   /* For storing row data of OLD table */
+
+      /* If the record is no longer present in the table, jump to the
+      ** next iteration of the loop through the contents of the fifo.
+      */
+      sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid);
+
+      /* Populate the OLD.* pseudo-table */
       if( old_col_mask ){
-        sqlite3VdbeAddOp1(v, OP_RowData, iCur);
+        sqlite3VdbeAddOp3(v, OP_RowData, iCur, 0, iData);
       }else{
-        sqlite3VdbeAddOp0(v, OP_Null);
+        sqlite3VdbeAddOp2(v, OP_MemNull, 0, iData);
       }
-      sqlite3CodeInsert(pParse, oldIdx, 0);
+      sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, iData, iRowid);
 
       /* Jump back and run the BEFORE triggers */
       sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
       sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
-
-      if( !isView ){
-        sqlite3VdbeAddOp1(v, OP_MemLoad, mem1);
-      }
     }
 
     if( !isView ){
       /* Delete the row */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
       if( IsVirtual(pTab) ){
-        int iReg = sqlite3StackToReg(pParse, 1);
+        const char *pVtab = (const char *)pTab->pVtab;
         pParse->pVirtualLock = pTab;
-        sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iReg,
-                          (const char*)pTab->pVtab, P4_VTAB);
+        sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVtab, P4_VTAB);
       }else
 #endif
       {
-        sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0);
+        sqlite3GenerateRowDelete(db, v, pTab, iCur, iRowid, pParse->nested==0);
       }
     }
 
@@ -436,8 +435,8 @@
 **   2.  Read/write cursors for all indices of pTab must be open as
 **       cursor number base+i for the i-th index.
 **
-**   3.  The record number of the row to be deleted must be on the top
-**       of the stack.
+**   3.  The record number of the row to be deleted must be stored in
+**       memory cell iRowid.
 **
 ** This routine pops the top of the stack to remove the record number
 ** and then generates code to remove both the table record and all index
@@ -448,10 +447,11 @@
   Vdbe *v,           /* Generate code into this VDBE */
   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;
-  addr = sqlite3VdbeAddOp1(v, OP_NotExists, iCur);
+  addr = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowid);
   sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
   sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
   if( count ){
diff --git a/src/insert.c b/src/insert.c
index de74736..710175b 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.208 2008/01/03 23:44:53 drh Exp $
+** $Id: insert.c,v 1.209 2008/01/04 13:24:29 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -1176,7 +1176,8 @@
         break;
       }
       case OE_Replace: {
-        sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0);
+        int iRowid = sqlite3StackToReg(pParse, 1);
+        sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0);
         if( isUpdate ){
           sqlite3VdbeAddOp2(v, OP_Dup, nCol+extra+1+hasTwoRowids, 1);
           sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 3e75f1f..a59aeb8 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.636 2008/01/03 23:44:53 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.637 2008/01/04 13:24:29 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1768,7 +1768,7 @@
 int sqlite3ExprIsConstantOrFunction(Expr*);
 int sqlite3ExprIsInteger(Expr*, int*);
 int sqlite3IsRowid(const char*);
-void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
+void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int);
 void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, char*);
 void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
 void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
diff --git a/src/vdbe.c b/src/vdbe.c
index 736d781..9c258f0 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.674 2008/01/04 11:01:04 danielk1977 Exp $
+** $Id: vdbe.c,v 1.675 2008/01/04 13:24:29 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -3344,12 +3344,14 @@
   break;
 }
 
-/* Opcode: NotExists P1 P2 *
+/* Opcode: NotExists P1 P2 P3
 **
-** Use the top of the stack as a integer key.  If a record with that key
-** does not exist in table of P1, then jump to P2.  If the record
-** does exist, then fall thru.  The cursor is left pointing to the
-** record if it exists.  The integer key is popped from the stack.
+** Use the top of the stack as a integer key. Or, if P3 is non-zero,
+** use the contents of memory cell P3 as an integer key. If a record 
+** with that key does not exist in table of P1, then jump to P2. 
+** If the record does exist, then fall thru.  The cursor is left 
+** pointing to the record if it exists. The integer key is popped 
+** from the stack (unless it was read from a memory cell).
 **
 ** The difference between this operation and NotFound is that this
 ** operation assumes the key is an integer and that P1 is a table whereas
@@ -3362,17 +3364,24 @@
   int i = pOp->p1;
   Cursor *pC;
   BtCursor *pCrsr;
-  assert( pTos>=p->aStack );
+  Mem *pKey;
+  if( pOp->p3 ){
+    assert( pOp->p3<=p->nMem );
+    pKey = &p->aMem[pOp->p3];
+  }else{
+    pKey = pTos;
+    assert( pTos>=p->aStack );
+  }
   assert( i>=0 && i<p->nCursor );
   assert( p->apCsr[i]!=0 );
   if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
     int res;
     u64 iKey;
-    assert( pTos->flags & MEM_Int );
+    assert( pKey->flags & MEM_Int );
     assert( p->apCsr[i]->isTable );
-    iKey = intToKey(pTos->u.i);
+    iKey = intToKey(pKey->u.i);
     rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, 0,&res);
-    pC->lastRowid = pTos->u.i;
+    pC->lastRowid = pKey->u.i;
     pC->rowidIsValid = res==0;
     pC->nullRow = 0;
     pC->cacheStatus = CACHE_STALE;
@@ -3386,8 +3395,10 @@
       pC->rowidIsValid = 0;
     }
   }
-  Release(pTos);
-  pTos--;
+  if( pOp->p3==0 ){
+    Release(pTos);
+    pTos--;
+  }
   break;
 }
 
@@ -3727,20 +3738,24 @@
   break;
 }
 
-/* Opcode: RowData P1 * *
+/* Opcode: RowData P1 * P3
 **
-** Push onto the stack the complete row data for cursor P1.
-** There is no interpretation of the data.  It is just copied
-** onto the stack exactly as it is found in the database file.
+** Push onto the stack the complete row data for cursor P1. Or if P3 
+** is a positive non-zero integer register number, then the value 
+** is written into that register. There is no interpretation of the data.  
+** It is just copied onto the stack or into the memory cell exactly as 
+** it is found in the database file.
 **
-** If the cursor is not pointing to a valid row, a NULL is pushed
-** onto the stack.
+** If the cursor is not pointing to a valid row, a NULL value is
+** pushed/inserted instead.
 */
-/* Opcode: RowKey P1 * *
+/* Opcode: RowKey P1 * P3
 **
-** Push onto the stack the complete row key for cursor P1.
-** There is no interpretation of the key.  It is just copied
-** onto the stack exactly as it is found in the database file.
+** Push onto the stack the complete row key for cursor P1. Or if P3 
+** is a positive non-zero integer register number, then the value 
+** is written into that register. There is no interpretation of the data.  
+** It is just copied onto the stack or into the memory cell exactly as 
+** it is found in the database file.
 **
 ** If the cursor is not pointing to a valid row, a NULL is pushed
 ** onto the stack.
@@ -3750,22 +3765,27 @@
   int i = pOp->p1;
   Cursor *pC;
   u32 n;
+  Mem *pOut;
 
   /* Note that RowKey and RowData are really exactly the same instruction */
-  pTos++;
+  if( pOp->p3 ){
+    pOut = &p->aMem[pOp->p3];
+  }else{
+    pOut = ++pTos;
+  }
   assert( i>=0 && i<p->nCursor );
   pC = p->apCsr[i];
   assert( pC->isTable || pOp->opcode==OP_RowKey );
   assert( pC->isIndex || pOp->opcode==OP_RowData );
   assert( pC!=0 );
   if( pC->nullRow ){
-    pTos->flags = MEM_Null;
+    pOut->flags = MEM_Null;
   }else if( pC->pCursor!=0 ){
     BtCursor *pCrsr = pC->pCursor;
     rc = sqlite3VdbeCursorMoveto(pC);
     if( rc ) goto abort_due_to_error;
     if( pC->nullRow ){
-      pTos->flags = MEM_Null;
+      pOut->flags = MEM_Null;
       break;
     }else if( pC->isIndex ){
       i64 n64;
@@ -3781,31 +3801,31 @@
     if( n>SQLITE_MAX_LENGTH ){
       goto too_big;
     }
-    pTos->n = n;
+    pOut->n = n;
     if( n<=NBFS ){
-      pTos->flags = MEM_Blob | MEM_Short;
-      pTos->z = pTos->zShort;
+      pOut->flags = MEM_Blob | MEM_Short;
+      pOut->z = pOut->zShort;
     }else{
       char *z = sqlite3_malloc( n );
       if( z==0 ) goto no_mem;
-      pTos->flags = MEM_Blob | MEM_Dyn;
-      pTos->xDel = 0;
-      pTos->z = z;
+      pOut->flags = MEM_Blob | MEM_Dyn;
+      pOut->xDel = 0;
+      pOut->z = z;
     }
     if( pC->isIndex ){
-      rc = sqlite3BtreeKey(pCrsr, 0, n, pTos->z);
+      rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
     }else{
-      rc = sqlite3BtreeData(pCrsr, 0, n, pTos->z);
+      rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
     }
   }else if( pC->pseudoTable ){
-    pTos->n = pC->nData;
+    pOut->n = pC->nData;
     assert( pC->nData<=SQLITE_MAX_LENGTH );
-    pTos->z = pC->pData;
-    pTos->flags = MEM_Blob|MEM_Ephem;
+    pOut->z = pC->pData;
+    pOut->flags = MEM_Blob|MEM_Ephem;
   }else{
-    pTos->flags = MEM_Null;
+    pOut->flags = MEM_Null;
   }
-  pTos->enc = SQLITE_UTF8;  /* In case the blob is ever cast to text */
+  pOut->enc = SQLITE_UTF8;  /* In case the blob is ever cast to text */
   break;
 }
 
@@ -4505,8 +4525,7 @@
 
 /* Opcode: FifoWrite * * *
 **
-** Write the integer on the top of the stack
-** into the Fifo.
+** Write the integer on the top of the stack into the Fifo.
 */
 case OP_FifoWrite: {        /* no-push */
   assert( pTos>=p->aStack );
@@ -4519,11 +4538,14 @@
   break;
 }
 
-/* Opcode: FifoRead * P2 *
+/* Opcode: FifoRead P1 P2 *
 **
-** Attempt to read a single integer from the Fifo
-** and push it onto the stack.  If the Fifo is empty
-** push nothing but instead jump to P2.
+** Attempt to read a single integer from the Fifo. If P1 is zero,
+** push the result onto the stack. Otherwise, store the read integer 
+** in register P1.
+** 
+** If the Fifo is empty do not push an entry onto the stack or set
+** a memory register but instead jump to P2.
 */
 case OP_FifoRead: {
   i64 v;
@@ -4531,9 +4553,13 @@
   if( sqlite3VdbeFifoPop(&p->sFifo, &v)==SQLITE_DONE ){
     pc = pOp->p2 - 1;
   }else{
-    pTos++;
-    pTos->u.i = v;
-    pTos->flags = MEM_Int;
+    Mem *pOut;
+    if( pOp->p1 ){
+      pOut = &p->aMem[pOp->p1];
+    }else{
+      pOut = ++pTos;
+    }
+    sqlite3VdbeMemSetInt64(pOut, v);
   }
   break;
 }