Additional code cleanup resulting from a review of the new trigger code. (CVS 572)

FossilOrigin-Name: 37dbdd551e88440933066133ec9cc1e10b03fc1a
diff --git a/src/build.c b/src/build.c
index 5f89a71..23f55a6 100644
--- a/src/build.c
+++ b/src/build.c
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.91 2002/05/19 23:43:14 danielk1977 Exp $
+** $Id: build.c,v 1.92 2002/05/21 11:38:11 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -478,7 +478,7 @@
   ** now.
   */
   if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
-    sqliteBeginWriteOperation(pParse);
+    sqliteBeginWriteOperation(pParse, 0);
     if( !isTemp ){
       sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
       sqliteVdbeAddOp(v, OP_SetCookie, 0, 1);
@@ -1092,7 +1092,7 @@
       { OP_Close,      0, 0,        0},
     };
     Index *pIdx;
-    sqliteBeginWriteOperation(pParse);
+    sqliteBeginWriteOperation(pParse, 0);
     /* Drop all triggers associated with the table being dropped */
     while( pTable->pTrigger ){
       Token tt;
@@ -1355,7 +1355,7 @@
     v = sqliteGetVdbe(pParse);
     if( v==0 ) goto exit_create_index;
     if( pTable!=0 ){
-      sqliteBeginWriteOperation(pParse);
+      sqliteBeginWriteOperation(pParse, 0);
       if( !isTemp ){
         sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
         sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
@@ -1467,7 +1467,7 @@
     int base;
     Table *pTab = pIndex->pTable;
 
-    sqliteBeginWriteOperation(pParse);
+    sqliteBeginWriteOperation(pParse, 0);
     if( !pTab->isTemp ){
       base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
       sqliteVdbeChangeP3(v, base+2, pIndex->zName, P3_STATIC);
@@ -1588,7 +1588,7 @@
   v = sqliteGetVdbe(pParse);
   if( v ){
     int openOp;
-    sqliteBeginMultiWriteOperation(pParse);
+    sqliteBeginWriteOperation(pParse, 1);
     addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
     sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
     sqliteVdbeDequoteP3(v, addr);
@@ -1669,7 +1669,7 @@
   if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
   if( pParse->nErr || sqlite_malloc_failed ) return;
   if( db->flags & SQLITE_InTrans ) return;
-  sqliteBeginWriteOperation(pParse);
+  sqliteBeginWriteOperation(pParse, 0);
   db->flags |= SQLITE_InTrans;
   db->onError = onError;
 }
@@ -1708,32 +1708,18 @@
 
 /*
 ** Generate VDBE code that prepares for doing an operation that
-** might change the database.  The operation will be atomic in the
-** sense that it will either do its changes completely or not at
-** all.  So there is no need to set a checkpoint is a transaction
-** is already in effect.
+** might change the database.
+**
+** This routine starts a new transaction if we are not already within
+** a transaction.  If we are already within a transaction, then a checkpoint
+** is set if the setCheckpoint parameter is true.  A checkpoint should
+** be set for operations that might fail (due to a constraint) part of
+** the way through and which will need to undo some writes without having to
+** rollback the whole transaction.  For operations where all constraints
+** can be checked before any changes are made to the database, it is never
+** necessary to undo a write and the checkpoint should not be set.
 */
-void sqliteBeginWriteOperation(Parse *pParse){
-  Vdbe *v;
-  v = sqliteGetVdbe(pParse);
-  if( v==0 ) return;
-  if( pParse->trigStack ) return; /* if this is in a trigger */
-  if( (pParse->db->flags & SQLITE_InTrans)==0  ){
-    sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
-    sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
-    pParse->schemaVerified = 1;
-  }
-}
-
-/*
-** Generate VDBE code that prepares for doing an operation that
-** might change the database.  The operation might not be atomic in
-** the sense that an error may be discovered and the operation might
-** abort after some changes have been made.  If we are in the middle 
-** of a transaction, then this sets a checkpoint.  If we are not in
-** a transaction, then start a transaction.
-*/
-void sqliteBeginMultiWriteOperation(Parse *pParse){
+void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint){
   Vdbe *v;
   v = sqliteGetVdbe(pParse);
   if( v==0 ) return;
@@ -1742,7 +1728,7 @@
     sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
     sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
     pParse->schemaVerified = 1;
-  }else{
+  }else if( setCheckpoint ){
     sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
   }
 }
@@ -1844,7 +1830,7 @@
       int addr;
       int size = atoi(zRight);
       if( size<0 ) size = -size;
-      sqliteBeginWriteOperation(pParse);
+      sqliteBeginWriteOperation(pParse, 0);
       sqliteVdbeAddOp(v, OP_Integer, size, 0);
       sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
       addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
@@ -1935,7 +1921,7 @@
       int addr;
       int size = db->cache_size;
       if( size<0 ) size = -size;
-      sqliteBeginWriteOperation(pParse);
+      sqliteBeginWriteOperation(pParse, 0);
       sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
       addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
diff --git a/src/delete.c b/src/delete.c
index 417ed2f..bcbe5ea 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
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.33 2002/05/19 23:43:14 danielk1977 Exp $
+** $Id: delete.c,v 1.34 2002/05/21 11:38:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -75,6 +75,7 @@
 ){
   Vdbe *v;               /* The virtual database engine */
   Table *pTab;           /* The table from which records will be deleted */
+  char *zTab;            /* Name of the table from which we are deleting */
   IdList *pTabList;      /* An ID list holding pTab and nothing else */
   int end, addr;         /* A couple addresses of generated code */
   int i;                 /* Loop counter */
@@ -96,32 +97,28 @@
   /* Check for the special case of a VIEW with one or more ON DELETE triggers 
   ** defined 
   */
-  {
-    Table *pTab;
-    char *zTab = sqliteTableNameFromToken(pTableName);
-
-    if( zTab != 0 ){
-      pTab = sqliteFindTable(pParse->db, zTab);
-      if( pTab ){
-        row_triggers_exist = 
-          sqliteTriggersExist(pParse, pTab->pTrigger, 
-              TK_DELETE, TK_BEFORE, TK_ROW, 0) ||
-          sqliteTriggersExist(pParse, pTab->pTrigger, 
-              TK_DELETE, TK_AFTER, TK_ROW, 0);
-      }
-      sqliteFree(zTab);
-      if( row_triggers_exist &&  pTab->pSelect ){
-        /* Just fire VIEW triggers */
-        sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0);
-        return;
-      }
+  zTab = sqliteTableNameFromToken(pTableName);
+  if( zTab != 0 ){
+    pTab = sqliteFindTable(pParse->db, zTab);
+    if( pTab ){
+      row_triggers_exist = 
+        sqliteTriggersExist(pParse, pTab->pTrigger, 
+            TK_DELETE, TK_BEFORE, TK_ROW, 0) ||
+        sqliteTriggersExist(pParse, pTab->pTrigger, 
+            TK_DELETE, TK_AFTER, TK_ROW, 0);
+    }
+    sqliteFree(zTab);
+    if( row_triggers_exist &&  pTab->pSelect ){
+      /* Just fire VIEW triggers */
+      sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0);
+      return;
     }
   }
 
   /* Locate the table which we want to delete.  This table has to be
   ** put in an IdList structure because some of the subroutines we
   ** will be calling are designed to work with multiple tables and expect
-  ** an IdList* parameter instead of just a Table* parameger.
+  ** an IdList* parameter instead of just a Table* parameter.
   */
   pTabList = sqliteTableTokenToIdList(pParse, pTableName);
   if( pTabList==0 ) goto delete_from_cleanup;
@@ -129,6 +126,8 @@
   pTab = pTabList->a[0].pTab;
   assert( pTab->pSelect==0 );  /* This table is not a view */
 
+  /* Allocate a cursor used to store the old.* data for a trigger.
+  */
   if( row_triggers_exist ){ 
     oldIdx = pParse->nTab++;
   }
@@ -151,11 +150,7 @@
   if( v==0 ){
     goto delete_from_cleanup;
   }
-  if( row_triggers_exist ){ 
-    sqliteBeginMultiWriteOperation(pParse);
-  } else {
-    sqliteBeginWriteOperation(pParse);
-  }
+  sqliteBeginWriteOperation(pParse, row_triggers_exist);
 
   /* Initialize the counter of the number of rows deleted, if
   ** we are counting rows.
@@ -165,7 +160,8 @@
   }
 
   /* Special case: A DELETE without a WHERE clause deletes everything.
-  ** It is easier just to erase the whole table.
+  ** It is easier just to erase the whole table.  Note, however, that
+  ** this means that the row change count will be incorrect.
   */
   if( pWhere==0 && !row_triggers_exist ){
     if( db->flags & SQLITE_CountRows ){
@@ -215,8 +211,10 @@
     sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
     end = sqliteVdbeMakeLabel(v);
 
+    /* This is the beginning of the delete loop when there are
+    ** row triggers.
+    */
     if( row_triggers_exist ){
-      int ii;
       addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
 
@@ -226,11 +224,11 @@
       sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
 
       sqliteVdbeAddOp(v, OP_Integer, 13, 0);
-      for(ii = 0; ii<pTab->nCol; ii++){
-        if( ii==pTab->iPKey ){ 
+      for(i = 0; i<pTab->nCol; i++){
+        if( i==pTab->iPKey ){ 
           sqliteVdbeAddOp(v, OP_Recno, base, 0);
 	} else {
-          sqliteVdbeAddOp(v, OP_Column, base, ii);
+          sqliteVdbeAddOp(v, OP_Column, base, i);
 	}
       }
       sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
@@ -242,6 +240,12 @@
           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default);
     }
 
+    /* Open cursors for the table we are deleting from and all its
+    ** indices.  If there are row triggers, this happens inside the
+    ** OP_ListRead 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.
+    */
     pParse->nTab = base + 1;
     openOp = pTab->isTemp ? OP_OpenWrAux : OP_OpenWrite;
     sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
@@ -249,12 +253,18 @@
       sqliteVdbeAddOp(v, openOp, pParse->nTab++, pIdx->tnum);
     }
 
+    /* This is the beginning of the delete loop when there are no
+    ** row triggers */
     if( !row_triggers_exist ){ 
       addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
     }
 
-    sqliteGenerateRowDelete(v, pTab, base, pParse->trigStack?0:1);
+    /* Delete the row */
+    sqliteGenerateRowDelete(v, pTab, base, pParse->trigStack==0);
 
+    /* If there are row triggers, close all cursors then invoke
+    ** the AFTER triggers
+    */
     if( row_triggers_exist ){
       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
         sqliteVdbeAddOp(v, OP_Close, base + i, pIdx->tnum);
@@ -264,10 +274,12 @@
           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default);
     }
 
+    /* End of the delete loop */
     sqliteVdbeAddOp(v, OP_Goto, 0, addr);
     sqliteVdbeResolveLabel(v, end);
     sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
 
+    /* Close the cursors after the loop if there are no row triggers */
     if( !row_triggers_exist ){
       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
         sqliteVdbeAddOp(v, OP_Close, base + i, pIdx->tnum);
diff --git a/src/insert.c b/src/insert.c
index fab85ed..091ed75 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.55 2002/05/19 23:43:14 danielk1977 Exp $
+** $Id: insert.c,v 1.56 2002/05/21 11:38:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -95,11 +95,7 @@
   */
   v = sqliteGetVdbe(pParse);
   if( v==0 ) goto insert_cleanup;
-  if( pSelect || row_triggers_exist ){
-    sqliteBeginMultiWriteOperation(pParse);
-  }else{
-    sqliteBeginWriteOperation(pParse);
-  }
+  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist);
 
   /* if there are row triggers, allocate a temp table for new.* references. */
   if( row_triggers_exist ){
diff --git a/src/parse.y b/src/parse.y
index bc60a78..cffdce1 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.65 2002/05/15 14:17:45 drh Exp $
+** @(#) $Id: parse.y,v 1.66 2002/05/21 11:38:12 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -98,27 +98,32 @@
 
 // An IDENTIFIER can be a generic identifier, or one of several
 // keywords.  Any non-standard keyword can also be an identifier.
-// We also make DESC and identifier since it comes up so often (as
-// an abbreviation of "description").
 //
 %type id {Token}
 id(A) ::= ABORT(X).      {A = X;}
+id(A) ::= AFTER(X).      {A = X;}
 id(A) ::= ASC(X).        {A = X;}
+id(A) ::= BEFORE(X).     {A = X;}
 id(A) ::= BEGIN(X).      {A = X;}
 id(A) ::= CLUSTER(X).    {A = X;}
 id(A) ::= CONFLICT(X).   {A = X;}
 id(A) ::= COPY(X).       {A = X;}
 id(A) ::= DELIMITERS(X). {A = X;}
 id(A) ::= DESC(X).       {A = X;}
+id(A) ::= EACH(X).       {A = X;}
 id(A) ::= END(X).        {A = X;}
 id(A) ::= EXPLAIN(X).    {A = X;}
 id(A) ::= FAIL(X).       {A = X;}
+id(A) ::= FOR(X).        {A = X;}
 id(A) ::= ID(X).         {A = X;}
 id(A) ::= IGNORE(X).     {A = X;}
+id(A) ::= INSTEAD(X).    {A = X;}
 id(A) ::= KEY(X).        {A = X;}
+id(A) ::= OF(X).         {A = X;}
 id(A) ::= OFFSET(X).     {A = X;}
 id(A) ::= PRAGMA(X).     {A = X;}
 id(A) ::= REPLACE(X).    {A = X;}
+id(A) ::= ROW(X).        {A = X;}
 id(A) ::= TEMP(X).       {A = X;}
 id(A) ::= TRIGGER(X).    {A = X;}
 id(A) ::= VACUUM(X).     {A = X;}
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 9fd9b87..92716c6 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.110 2002/05/16 00:13:12 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.111 2002/05/21 11:38:12 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -798,8 +798,7 @@
 void sqliteGenerateRowIndexDelete(Vdbe*, Table*, int, char*);
 void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
 void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
-void sqliteBeginWriteOperation(Parse*);
-void sqliteBeginMultiWriteOperation(Parse*);
+void sqliteBeginWriteOperation(Parse*, int);
 void sqliteEndWriteOperation(Parse*);
 void sqliteExprMoveStrings(Expr*, int);
 void sqliteExprListMoveStrings(ExprList*, int);
diff --git a/src/trigger.c b/src/trigger.c
index d0141b0..d26ddb9 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -95,32 +95,32 @@
   ** build the sqlite_master entry
   */
   if( !pParse->initFlag && !tab->isTemp ){
+    static VdbeOp insertTrig[] = {
+      { OP_OpenWrite,  0, 2,  MASTER_NAME},
+      { OP_NewRecno,   0, 0,  0          },
+      { OP_String,     0, 0,  "trigger"  },
+      { OP_String,     0, 0,  0          },  /* 3: trigger name */
+      { OP_String,     0, 0,  0          },  /* 4: table name */
+      { OP_Integer,    0, 0,  0          },
+      { OP_String,     0, 0,  0          },  /* 6: SQL */
+      { OP_MakeRecord, 5, 0,  0          },
+      { OP_PutIntKey,  0, 0,  0          },
+      { OP_Integer,    0, 0,  0          },  /* 9: Next cookie */
+      { OP_SetCookie,  0, 0,  0          },
+      { OP_Close,      0, 0,  0          },
+    };
+    int addr;
+    Vdbe *v;
 
     /* Make an entry in the sqlite_master table */
-    sqliteBeginWriteOperation(pParse);
-
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_OpenWrite, 0, 2);
-    sqliteVdbeChangeP3(pParse->pVdbe, -1, MASTER_NAME,           P3_STATIC);
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_NewRecno,  0, 0);
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_String,    0, 0);
-    sqliteVdbeChangeP3(pParse->pVdbe, -1, "trigger",             P3_STATIC);
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_String,    0, 0);
-    sqliteVdbeChangeP3(pParse->pVdbe, -1, nt->name,        0); 
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_String,    0, 0);
-    sqliteVdbeChangeP3(pParse->pVdbe, -1, nt->table,        0); 
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_Integer,    0, 0);
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_String,    0, 0);
-    sqliteVdbeChangeP3(pParse->pVdbe, -1, nt->strings,     0);
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_MakeRecord, 5, 0);
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_PutIntKey, 0, 1);
-
-    /* Change the cookie, since the schema is changed */
+    v = sqliteGetVdbe(pParse);
+    sqliteBeginWriteOperation(pParse, 0);
+    addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
+    sqliteVdbeChangeP3(v, addr+3, nt->name, 0); 
+    sqliteVdbeChangeP3(v, addr+4, nt->table, 0); 
+    sqliteVdbeChangeP3(v, addr+6, nt->strings, 0);
     sqliteChangeCookie(pParse->db);
-    sqliteVdbeAddOp(pParse->pVdbe, OP_Integer, pParse->db->next_cookie, 0);
-    sqliteVdbeAddOp(pParse->pVdbe, OP_SetCookie, 0, 0);
-
-    sqliteVdbeAddOp(pParse->pVdbe,        OP_Close,     0, 0);
-
+    sqliteVdbeChangeP1(v, addr+9, pParse->db->next_cookie);
     sqliteEndWriteOperation(pParse);
   }
 
@@ -160,8 +160,14 @@
   }
 }
 
-TriggerStep *sqliteTriggerSelectStep(Select * pSelect)
-{
+/*
+** Turn a SELECT statement (that the pSelect parameter points to) into
+** a trigger step.  Return a pointer to a TriggerStep structure.
+**
+** The parser calls this routine when it finds a SELECT statement in
+** body of a TRIGGER.  
+*/
+TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
 
   pTriggerStep->op = TK_SELECT;
@@ -171,12 +177,19 @@
   return pTriggerStep;
 }
 
+/*
+** Build a trigger step out of an INSERT statement.  Return a pointer
+** to the new trigger step.
+**
+** The parser calls this routine when it sees an INSERT inside the
+** body of a trigger.
+*/
 TriggerStep *sqliteTriggerInsertStep(
-  Token *pTableName,
-  IdList *pColumn,
-  ExprList *pEList,
-  Select *pSelect,
-  int orconf
+  Token *pTableName,  /* Name of the table into which we insert */
+  IdList *pColumn,    /* List of columns in pTableName to insert into */
+  ExprList *pEList,   /* The VALUE clause: a list of values to be inserted */
+  Select *pSelect,    /* A SELECT statement that supplies values */
+  int orconf          /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
 ){
   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
 
@@ -193,12 +206,17 @@
   return pTriggerStep;
 }
 
+/*
+** Construct a trigger step that implements an UPDATE statement and return
+** a pointer to that trigger step.  The parser calls this routine when it
+** sees an UPDATE statement inside the body of a CREATE TRIGGER.
+*/
 TriggerStep *sqliteTriggerUpdateStep(
-  Token *pTableName, 
-  ExprList *pEList, 
-  Expr *pWhere, 
-  int orconf)
-{
+  Token *pTableName,   /* Name of the table to be updated */
+  ExprList *pEList,    /* The SET clause: list of column and new values */
+  Expr *pWhere,        /* The WHERE clause */
+  int orconf           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
+){
   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
 
   pTriggerStep->op = TK_UPDATE;
@@ -210,8 +228,12 @@
   return pTriggerStep;
 }
 
-TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere)
-{
+/*
+** Construct a trigger step that implements a DELETE statement and return
+** a pointer to that trigger step.  The parser calls this routine when it
+** sees a DELETE statement inside the body of a CREATE TRIGGER.
+*/
+TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
   TriggerStep * pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
 
   pTriggerStep->op = TK_DELETE;
@@ -328,7 +350,7 @@
     };
 
     if( !nested ){
-      sqliteBeginWriteOperation(pParse);
+      sqliteBeginWriteOperation(pParse, 0);
     }
     base = sqliteVdbeAddOpList(pParse->pVdbe, 
         ArraySize(dropTrigger), dropTrigger);
@@ -345,8 +367,16 @@
   sqliteFree(zName);
 }
 
-static int checkColumnOverLap(IdList * pIdList, ExprList * pEList)
-{
+/*
+** pEList is the SET clause of an UPDATE statement.  Each entry
+** in pEList is of the format <id>=<expr>.  If any of the entries
+** in pEList have an <id> which matches an identifier in pIdList,
+** then return TRUE.  If pIdList==NULL, then it is considered a
+** wildcard that matches anything.  Likewise if pEList==NULL then
+** it matches anything so always return true.  Return false only
+** if there is no match.
+*/
+static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
   int i, e;
   if( !pIdList )return 1;
   if( !pEList )return 1;
@@ -378,13 +408,13 @@
  * found in the list specified as pTrigger.
  */
 int sqliteTriggersExist(
-  Parse *pParse, 
-  Trigger *pTrigger,
+  Parse *pParse,          /* Used to check for recursive triggers */
+  Trigger *pTrigger,      /* A list of triggers associated with a table */
   int op,                 /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
   int tr_tm,              /* one of TK_BEFORE, TK_AFTER */
   int foreach,            /* one of TK_ROW or TK_STATEMENT */
-  ExprList *pChanges)
-{
+  ExprList *pChanges      /* Columns that change in an UPDATE statement */
+){
   Trigger * pTriggerCursor;
 
   if( always_code_trigger_setup ){
@@ -410,10 +440,14 @@
   return 0;
 }
 
+/*
+** Generate VDBE code for zero or more statements inside the body of a
+** trigger.  
+*/
 static int codeTriggerProgram(
-  Parse *pParse, 
-  TriggerStep *pStepList, 
-  int orconfin
+  Parse *pParse,            /* The parser context */
+  TriggerStep *pStepList,   /* List of statements inside the trigger body */
+  int orconfin              /* Conflict algorithm. (OE_Abort, etc) */  
 ){
   TriggerStep * pTriggerStep = pStepList;
   int orconf;
@@ -470,11 +504,15 @@
 **
 ** When the code that this function generates is executed, the following 
 ** must be true:
-** 1. NO vdbe cursors must be open.
+**
+** 1. No cursors may be open in the main database.  (But newIdx and oldIdx
+**    can be indices of cursors in temporary tables.  See below.)
+**
 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
 **    a temporary vdbe cursor (index newIdx) must be open and pointing at
 **    a row containing values to be substituted for new.* expressions in the
 **    trigger program(s).
+**
 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
 **    a temporary vdbe cursor (index oldIdx) must be open and pointing at
 **    a row containing values to be substituted for old.* expressions in the
@@ -489,8 +527,8 @@
   Table *pTab,         /* The table to code triggers from */
   int newIdx,          /* The indice of the "new" row to access */
   int oldIdx,          /* The indice of the "old" row to access */
-  int orconf)          /* ON CONFLICT policy */
-{
+  int orconf           /* ON CONFLICT policy */
+){
   Trigger * pTrigger;
   TriggerStack * pTriggerStack;
 
@@ -611,7 +649,7 @@
 
   v = sqliteGetVdbe(pParse);
   assert(v);
-  sqliteBeginMultiWriteOperation(pParse);
+  sqliteBeginWriteOperation(pParse, 1);
 
   /* Allocate temp tables */
   oldIdx = pParse->nTab++;
diff --git a/src/update.c b/src/update.c
index 48ea1b9..95923ec 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.39 2002/05/19 23:43:14 danielk1977 Exp $
+** $Id: update.c,v 1.40 2002/05/21 11:38:12 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -177,7 +177,7 @@
   */
   v = sqliteGetVdbe(pParse);
   if( v==0 ) goto update_cleanup;
-  sqliteBeginMultiWriteOperation(pParse);
+  sqliteBeginWriteOperation(pParse, 1);
 
   /* Begin the database scan
   */