Take advantage of the fact that b-tree cursors need not be closed while other cursors modify their tables to simplify trigger program generation code. (CVS 4654)

FossilOrigin-Name: f1966a8a47fca85f7862c0797a527ab01ac8b0c1
diff --git a/src/btree.c b/src/btree.c
index 4590bdd..7734de4 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.435 2008/01/01 06:19:02 danielk1977 Exp $
+** $Id: btree.c,v 1.436 2008/01/02 11:50:51 danielk1977 Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** See the header comment on "btreeInt.h" for additional information.
@@ -6229,7 +6229,9 @@
   /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call
   ** restoreOrClearCursorPosition() here.
   */
-  MemPage *pPage = pCur->pPage;
+  MemPage *pPage;
+  restoreOrClearCursorPosition(pCur);
+  pPage = pCur->pPage;
   assert( cursorHoldsMutex(pCur) );
   assert( pPage->pBt==pCur->pBt );
   return pPage ? pPage->aData[pPage->hdrOffset] : 0;
diff --git a/src/delete.c b/src/delete.c
index f2a63d5..6dd0902 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.136 2008/01/02 00:34:37 drh Exp $
+** $Id: delete.c,v 1.137 2008/01/02 11:50:51 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -175,6 +175,9 @@
   */
   assert( pTabList->nSrc==1 );
   iCur = pTabList->a[0].iCursor = pParse->nTab++;
+  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    pParse->nTab++;
+  }
   memset(&sNC, 0, sizeof(sNC));
   sNC.pParse = pParse;
   sNC.pSrcList = pTabList;
@@ -293,19 +296,26 @@
     */
     end = sqlite3VdbeMakeLabel(v);
 
-    /* This is the beginning of the delete loop when there are
-    ** row triggers.
+    if( !isView ){
+      /* Open cursors for the table we are deleting from and 
+      ** all its indices.
+      */
+      sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
+    }
+
+    /* This is the beginning of the delete loop. If a trigger encounters
+    ** an IGNORE constraint, it jumps back to here.
     */
     if( triggers_exist ){
-      int mem1 = pParse->nMem++;
-      int addr_rowdata;
-      u32 mask;
       sqlite3VdbeResolveLabel(v, addr);
-      addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
-      sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
-      sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
+    }
+    addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
+    sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
+
+    if( triggers_exist ){
+      int mem1 = pParse->nMem++;
       if( !isView ){
-        sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
+        sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
       }
       sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
       sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
@@ -329,21 +339,6 @@
     }
 
     if( !isView ){
-      /* Open cursors for the table we are deleting from and all its
-      ** indices.  If there are row triggers, this happens inside the
-      ** OP_FifoRead loop because the cursor have to all be closed
-      ** before the trigger fires.  If there are no row triggers, the
-      ** cursors are opened only once on the outside the loop.
-      */
-      sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
-
-      /* This is the beginning of the delete loop when there are no
-      ** row triggers */
-      if( !triggers_exist ){ 
-        addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end);
-        sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
-      }
-
       /* Delete the row */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
       if( IsVirtual(pTab) ){
@@ -360,13 +355,6 @@
     ** the AFTER triggers
     */
     if( triggers_exist ){
-      if( !isView ){
-        for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-          sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
-        }
-        sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
-      }
-
       /* Jump back and run the AFTER triggers */
       sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginAfterTrigger);
       sqlite3VdbeJumpHere(v, iEndAfterTrigger);
@@ -377,7 +365,7 @@
     sqlite3VdbeResolveLabel(v, end);
 
     /* Close the cursors after the loop if there are no row triggers */
-    if( !triggers_exist && !IsVirtual(pTab) ){
+    if( !isView  && !IsVirtual(pTab) ){
       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
         sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
       }
diff --git a/src/insert.c b/src/insert.c
index 6e3440d..26eb7a2 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.199 2008/01/02 00:34:37 drh Exp $
+** $Id: insert.c,v 1.200 2008/01/02 11:50:51 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -625,8 +625,8 @@
     sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem);
   }
 
-  /* Open tables and indices if there are no row triggers */
-  if( !triggers_exist ){
+  /* If this is not a view, open the table and and all indices */
+  if( !isView ){
     base = pParse->nTab;
     sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
   }
@@ -713,14 +713,6 @@
     }
   }
 
-  /* If any triggers exists, the opening of tables and indices is deferred
-  ** until now.
-  */
-  if( triggers_exist && !isView ){
-    base = pParse->nTab;
-    sqlite3OpenTableAndIndices(pParse, pTab, base, OP_OpenWrite);
-  }
-
   /* Push the record number for the new entry onto the stack.  The
   ** record number is a randomly generate integer created by NewRowid
   ** except when the table has an INTEGER PRIMARY KEY column, in which
@@ -827,14 +819,6 @@
   }
 
   if( triggers_exist ){
-    /* Close all tables opened */
-    if( !isView ){
-      sqlite3VdbeAddOp(v, OP_Close, base, 0);
-      for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
-        sqlite3VdbeAddOp(v, OP_Close, idx+base, 0);
-      }
-    }
-
     /* Code AFTER triggers */
     if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_AFTER, pTab,
           newIdx, -1, onError, endOfLoop, 0, 0) ){
@@ -855,7 +839,7 @@
     sqlite3VdbeResolveLabel(v, iCleanup);
   }
 
-  if( !triggers_exist && !IsVirtual(pTab) ){
+  if( !IsVirtual(pTab) && !isView ){
     /* Close all tables opened */
     sqlite3VdbeAddOp(v, OP_Close, base, 0);
     for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
diff --git a/src/update.c b/src/update.c
index 0edc861..7c6017a 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.146 2008/01/02 00:34:37 drh Exp $
+** $Id: update.c,v 1.147 2008/01/02 11:50:51 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -298,7 +298,16 @@
   /* Generate the code for triggers.
   */
   if( triggers_exist ){
-    int iGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+    int iGoto;
+
+    /* Create pseudo-tables for NEW and OLD
+    */
+    sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
+    sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
+    sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
+    sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
+
+    iGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
     addr = sqlite3VdbeMakeLabel(v);
     iBeginBeforeTrigger = sqlite3VdbeCurrentAddr(v);
     if( sqlite3CodeRowTrigger(pParse, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab,
@@ -347,27 +356,50 @@
     sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
   }
 
-  if( triggers_exist ){
-    /* Create pseudo-tables for NEW and OLD
+  if( !isView && !IsVirtual(pTab) ){
+    /* 
+    ** Open every index that needs updating.  Note that if any
+    ** index could potentially invoke a REPLACE conflict resolution 
+    ** action, then we need to open all indices because we might need
+    ** to be deleting some records.
     */
-    sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
-    sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol);
-    sqlite3VdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
-    sqlite3VdbeAddOp(v, OP_SetNumColumns, newIdx, pTab->nCol);
-
-    /* The top of the update loop for when there are triggers.
-    */
-    sqlite3VdbeResolveLabel(v, addr);
-    addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
-    sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
-    sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
-    
-    if( !isView ){
-      /* Open a cursor and make it point to the record that is
-      ** being updated.
-      */
-      sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
+    sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); 
+    if( onError==OE_Replace ){
+      openAll = 1;
+    }else{
+      openAll = 0;
+      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+        if( pIdx->onError==OE_Replace ){
+          openAll = 1;
+          break;
+        }
+      }
     }
+    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+      if( openAll || aIdxUsed[i] ){
+        KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+        sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
+        sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
+                       (char*)pKey, P3_KEYINFO_HANDOFF);
+        assert( pParse->nTab>iCur+i+1 );
+      }
+    }
+
+  }
+  
+  /* Jump back to this point if a trigger encounters an IGNORE constraint. */
+  if( triggers_exist ){
+    sqlite3VdbeResolveLabel(v, addr);
+  }
+
+  /* Top of the update loop */
+  addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
+  sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
+  sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
+
+  if( triggers_exist ){
+    /* Make cursor iCur point to the record that is being updated.
+    */
     sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
 
     /* Generate the OLD table
@@ -410,9 +442,6 @@
     }
     if( pParse->nErr ) goto update_cleanup;
     sqlite3VdbeAddOp(v, OP_Insert, newIdx, 0);
-    if( !isView ){
-      sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
-    }
 
     sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginBeforeTrigger);
     sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
@@ -423,33 +452,6 @@
   }
 
   if( !isView && !IsVirtual(pTab) ){
-    /* 
-    ** Open every index that needs updating.  Note that if any
-    ** index could potentially invoke a REPLACE conflict resolution 
-    ** action, then we need to open all indices because we might need
-    ** to be deleting some records.
-    */
-    sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); 
-    if( onError==OE_Replace ){
-      openAll = 1;
-    }else{
-      openAll = 0;
-      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-        if( pIdx->onError==OE_Replace ){
-          openAll = 1;
-          break;
-        }
-      }
-    }
-    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
-      if( openAll || aIdxUsed[i] ){
-        KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
-        sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);
-        sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum,
-                       (char*)pKey, P3_KEYINFO_HANDOFF);
-        assert( pParse->nTab>iCur+i+1 );
-      }
-    }
 
     /* Loop over every record that needs updating.  We have to load
     ** the old data for each record to be updated because some columns
@@ -457,11 +459,6 @@
     ** Also, the old data is needed to delete the old index entries.
     ** So make the cursor point at the old record.
     */
-    if( !triggers_exist ){
-      addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, 0);
-      sqlite3VdbeAddOp(v, OP_StackDepth, -1, 0);
-      sqlite3VdbeAddOp(v, OP_MemStore, mem1, 0);
-    }
     sqlite3VdbeAddOp(v, OP_NotExists, iCur, addr);
     sqlite3VdbeAddOp(v, OP_MemLoad, mem1, 0);
 
@@ -520,13 +517,6 @@
   ** through the loop.  The fire the after triggers.
   */
   if( triggers_exist ){
-    if( !isView ){
-      for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
-        if( openAll || aIdxUsed[i] )
-          sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
-      }
-      sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
-    }
     sqlite3VdbeAddOp(v, OP_Goto, 0, iBeginAfterTrigger);
     sqlite3VdbeJumpHere(v, iEndAfterTrigger);
   }
@@ -537,15 +527,14 @@
   sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
   sqlite3VdbeJumpHere(v, addr);
 
-  /* Close all tables if there were no FOR EACH ROW triggers */
-  if( !triggers_exist ){
-    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
-      if( openAll || aIdxUsed[i] ){
-        sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
-      }
+  /* Close all tables */
+  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+    if( openAll || aIdxUsed[i] ){
+      sqlite3VdbeAddOp(v, OP_Close, iCur+i+1, 0);
     }
-    sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
-  }else{
+  }
+  sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+  if( triggers_exist ){
     sqlite3VdbeAddOp(v, OP_Close, newIdx, 0);
     sqlite3VdbeAddOp(v, OP_Close, oldIdx, 0);
   }
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 69d1612..fbcb881 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -701,10 +701,12 @@
     }
   }
   assert( zP3!=0 );
+#ifdef SQLITE_DEBUG
   if( pOp->zComment && zP3==zTemp && (nP3 = strlen(zP3))<nTemp ){
     sqlite3_snprintf(nTemp-nP3, &zP3[nP3], "%s# %s",
                      nP3>0 ? " " : "", pOp->zComment);
   }
+#endif
   return zP3;
 }
 #endif