More fixes and comment updates.

FossilOrigin-Name: 38a9327bad1a01e3d7a47fad44ece2f6c7e88643
diff --git a/src/build.c b/src/build.c
index 06e5dd5..431d5b5 100644
--- a/src/build.c
+++ b/src/build.c
@@ -64,35 +64,32 @@
   u8 isWriteLock,    /* True for a write lock */
   const char *zName  /* Name of the table to be locked */
 ){
+  Parse *pToplevel = sqlite3ParseToplevel(pParse);
   int i;
   int nBytes;
   TableLock *p;
-
   assert( iDb>=0 );
 
-  if( pParse->pRoot ){
-    pParse = pParse->pRoot;
-  }
-  for(i=0; i<pParse->nTableLock; i++){
-    p = &pParse->aTableLock[i];
+  for(i=0; i<pToplevel->nTableLock; i++){
+    p = &pToplevel->aTableLock[i];
     if( p->iDb==iDb && p->iTab==iTab ){
       p->isWriteLock = (p->isWriteLock || isWriteLock);
       return;
     }
   }
 
-  nBytes = sizeof(TableLock) * (pParse->nTableLock+1);
-  pParse->aTableLock =
-      sqlite3DbReallocOrFree(pParse->db, pParse->aTableLock, nBytes);
-  if( pParse->aTableLock ){
-    p = &pParse->aTableLock[pParse->nTableLock++];
+  nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1);
+  pToplevel->aTableLock =
+      sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes);
+  if( pToplevel->aTableLock ){
+    p = &pToplevel->aTableLock[pToplevel->nTableLock++];
     p->iDb = iDb;
     p->iTab = iTab;
     p->isWriteLock = isWriteLock;
     p->zName = zName;
   }else{
-    pParse->nTableLock = 0;
-    pParse->db->mallocFailed = 1;
+    pToplevel->nTableLock = 0;
+    pToplevel->db->mallocFailed = 1;
   }
 }
 
@@ -198,7 +195,7 @@
 #endif
     assert( pParse->iCacheLevel==0 );  /* Disables and re-enables match */
     sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem,
-                         pParse->nTab, pParse->nArg, pParse->explain);
+                         pParse->nTab, pParse->nMaxArg, pParse->explain);
     pParse->rc = SQLITE_DONE;
     pParse->colNamesSet = 0;
   }else if( pParse->rc==SQLITE_OK ){
@@ -3426,30 +3423,26 @@
 ** early in the code, before we know if any database tables will be used.
 */
 void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
-  sqlite3 *db;
-  Vdbe *v;
-  int mask;
-  Parse *pRoot = pParse->pRoot;        /* Root parse structure */
+  Parse *pToplevel = sqlite3ParseToplevel(pParse);
 
-  v = sqlite3GetVdbe(pParse);
-  if( v==0 ) return;  /* This only happens if there was a prior error */
-  db = pParse->db;
-  if( pParse->cookieGoto==0 && pRoot==0 ){
-    pParse->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
+  if( pToplevel->cookieGoto==0 ){
+    Vdbe *v = sqlite3GetVdbe(pToplevel);
+    if( v==0 ) return;  /* This only happens if there was a prior error */
+    pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
   }
   if( iDb>=0 ){
-    if( pRoot==0 ){
-      pRoot = pParse;
-    }
+    sqlite3 *db = pToplevel->db;
+    int mask;
+
     assert( iDb<db->nDb );
     assert( db->aDb[iDb].pBt!=0 || iDb==1 );
     assert( iDb<SQLITE_MAX_ATTACHED+2 );
     mask = 1<<iDb;
-    if( (pRoot->cookieMask & mask)==0 ){
-      pRoot->cookieMask |= mask;
-      pRoot->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
+    if( (pToplevel->cookieMask & mask)==0 ){
+      pToplevel->cookieMask |= mask;
+      pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
       if( !OMIT_TEMPDB && iDb==1 ){
-        sqlite3OpenTempDatabase(pRoot);
+        sqlite3OpenTempDatabase(pToplevel);
       }
     }
   }
@@ -3469,13 +3462,10 @@
 ** necessary to undo a write and the checkpoint should not be set.
 */
 void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
-  Parse *pRoot = pParse->pRoot;
+  Parse *pToplevel = sqlite3ParseToplevel(pParse);
   sqlite3CodeVerifySchema(pParse, iDb);
-  if( pRoot==0 ){
-    pRoot = pParse;
-  }
-  pRoot->writeMask |= 1<<iDb;
-  if( setStatement && pParse->nested==0 && pParse->pRoot==0 ){
+  pToplevel->writeMask |= 1<<iDb;
+  if( setStatement && pParse->nested==0 && pParse==pToplevel ){
     /* Every place where this routine is called with setStatement!=0 has
     ** already successfully created a VDBE. */
     assert( pParse->pVdbe );
diff --git a/src/expr.c b/src/expr.c
index c50a2c0..08c22ff 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1398,7 +1398,6 @@
     if( iCol<0 ){
       int iMem = ++pParse->nMem;
       int iAddr;
-      sqlite3VdbeUsesBtree(v, iDb);
 
       iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
       sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
@@ -1432,9 +1431,6 @@
           char *pKey;
   
           pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
-          iDb = sqlite3SchemaToIndex(db, pIdx->pSchema);
-          sqlite3VdbeUsesBtree(v, iDb);
-
           iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem);
           sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem);
   
@@ -2559,14 +2555,48 @@
     }
 
     case TK_TRIGGER: {
+      /* If the opcode is TK_TRIGGER, then the expression is a reference
+      ** to a column in the new.* or old.* pseudo-tables available to
+      ** trigger programs. In this case Expr.iTable is set to 1 for the
+      ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn
+      ** is set to the column of the pseudo-table to read, or to -1 to
+      ** read the rowid field.
+      **
+      ** The expression is implemented using an OP_Param opcode. The p1
+      ** parameter is set to 0 for an old.rowid reference, or to (i+1)
+      ** to reference another column of the old.* pseudo-table, where 
+      ** i is the index of the column. For a new.rowid reference, p1 is
+      ** set to (n+1), where n is the number of columns in each pseudo-table.
+      ** For a reference to any other column in the new.* pseudo-table, p1
+      ** is set to (n+2+i), where n and i are as defined previously. For
+      ** example, if the table on which triggers are being fired is
+      ** declared as:
+      **
+      **   CREATE TABLE t1(a, b);
+      **
+      ** Then p1 is interpreted as follows:
+      **
+      **   p1==0   ->    old.rowid     p1==3   ->    new.rowid
+      **   p1==1   ->    old.a         p1==4   ->    new.a
+      **   p1==2   ->    old.b         p1==5   ->    new.b       
+      */
       Table *pTab = pExpr->pTab;
-      int iVal = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn;
-      sqlite3VdbeAddOp2(v, OP_Param, iVal, target);
+      int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn;
+
+      assert( pExpr->iTable==0 || pExpr->iTable==1 );
+      assert( pExpr->iColumn>=-1 && pExpr->iColumn<pTab->nCol );
+      assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey );
+      assert( p1>=0 && p1<(pTab->nCol*2+2) );
+
+      sqlite3VdbeAddOp2(v, OP_Param, p1, target);
       VdbeComment((v, "%s.%s -> $%d",
         (pExpr->iTable ? "new" : "old"),
         (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName),
         target
       ));
+
+      /* If the column has REAL affinity, it may currently be stored as an
+      ** integer. Use OP_RealAffinity to make sure it is really real.  */
       if( pExpr->iColumn>=0 
        && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
       ){
diff --git a/src/insert.c b/src/insert.c
index 95da84e..d373a1d 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -197,21 +197,21 @@
 ){
   int memId = 0;      /* Register holding maximum rowid */
   if( pTab->tabFlags & TF_Autoincrement ){
-    Parse *pRoot = (pParse->pRoot ? pParse->pRoot : pParse);
+    Parse *pToplevel = sqlite3ParseToplevel(pParse);
     AutoincInfo *pInfo;
 
-    pInfo = pRoot->pAinc;
+    pInfo = pToplevel->pAinc;
     while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
     if( pInfo==0 ){
       pInfo = sqlite3DbMallocRaw(pParse->db, sizeof(*pInfo));
       if( pInfo==0 ) return 0;
-      pInfo->pNext = pRoot->pAinc;
-      pRoot->pAinc = pInfo;
+      pInfo->pNext = pToplevel->pAinc;
+      pToplevel->pAinc = pInfo;
       pInfo->pTab = pTab;
       pInfo->iDb = iDb;
-      pRoot->nMem++;                  /* Register to hold name of table */
-      pInfo->regCtr = ++pRoot->nMem;  /* Max rowid register */
-      pRoot->nMem++;                  /* Rowid in sqlite_sequence */
+      pToplevel->nMem++;                  /* Register to hold name of table */
+      pInfo->regCtr = ++pToplevel->nMem;  /* Max rowid register */
+      pToplevel->nMem++;                  /* Rowid in sqlite_sequence */
     }
     memId = pInfo->regCtr;
   }
@@ -454,7 +454,6 @@
   int addrCont = 0;     /* Top of insert loop. Label "C" in templates 3 and 4 */
   int addrSelect = 0;   /* Address of coroutine that implements the SELECT */
   SelectDest dest;      /* Destination for SELECT on rhs of INSERT */
-  int newIdx = -1;      /* Cursor for the NEW pseudo-table */
   int iDb;              /* Index of database holding TABLE */
   Db *pDb;              /* The database containing table being inserted into */
   int appendFlag = 0;   /* True if the insert is likely to be an append */
@@ -470,7 +469,6 @@
   int regEof = 0;       /* Register recording end of SELECT data */
   int *aRegIdx = 0;     /* One register allocated to each index */
 
-
 #ifndef SQLITE_OMIT_TRIGGER
   int isView;                 /* True if attempting to insert into a view */
   Trigger *pTrigger;          /* List of triggers on pTab, if required */
@@ -1050,26 +1048,24 @@
 **
 ** The input is a range of consecutive registers as follows:
 **
-**    1.  The rowid of the row to be updated before the update.  This
-**        value is omitted unless we are doing an UPDATE that involves a
-**        change to the record number or writing to a virtual table.
+**    1.  The rowid of the row after the update.
 **
-**    2.  The rowid of the row after the update.
-**
-**    3.  The data in the first column of the entry after the update.
+**    2.  The data in the first column of the entry after the update.
 **
 **    i.  Data from middle columns...
 **
 **    N.  The data in the last column of the entry after the update.
 **
-** The regRowid parameter is the index of the register containing (2).
+** The regRowid parameter is the index of the register containing (1).
 **
-** The old rowid shown as entry (1) above is omitted unless both isUpdate
-** and rowidChng are 1.  isUpdate is true for UPDATEs and false for
-** INSERTs.  RowidChng means that the new rowid is explicitly specified by
-** the update or insert statement.  If rowidChng is false, it means that
-** the rowid is computed automatically in an insert or that the rowid value
-** is not modified by the update.
+** If isUpdate is true and rowidChng is non-zero, then rowidChng contains
+** the address of a register containing the rowid before the update takes
+** place. isUpdate is true for UPDATEs and false for INSERTs. If isUpdate
+** is false, indicating an INSERT statement, then a non-zero rowidChng 
+** indicates that the rowid was explicitly specified as part of the
+** INSERT statement. If rowidChng is false, it means that  the rowid is
+** computed automatically in an insert or that the rowid value is not 
+** modified by an update.
 **
 ** The code generated by this routine store new index entries into
 ** registers identified by aRegIdx[].  No index entry is created for
@@ -1144,7 +1140,7 @@
   int iCur;           /* Table cursor number */
   Index *pIdx;         /* Pointer to one of the indices */
   int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
-  int hasTwoRowids = (isUpdate && rowidChng);
+  int regOldRowid = (rowidChng && isUpdate) ? rowidChng : regRowid;
 
   v = sqlite3GetVdbe(pParse);
   assert( v!=0 );
@@ -1304,7 +1300,7 @@
 
     /* Check to see if the new index entry will be unique */
     regR = sqlite3GetTempReg(pParse);
-    sqlite3VdbeAddOp2(v, OP_SCopy, regRowid-hasTwoRowids, regR);
+    sqlite3VdbeAddOp2(v, OP_SCopy, regOldRowid, regR);
     j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0,
                            regR, SQLITE_INT_TO_PTR(regIdx),
                            P4_INT32);
diff --git a/src/main.c b/src/main.c
index ee0e91b..38d4117 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1591,7 +1591,7 @@
 #ifdef SQLITE_ENABLE_LOAD_EXTENSION
                  | SQLITE_LoadExtension
 #endif
-#ifdef SQLITE_DISABLE_RECURSIVE_TRIGGERS
+#if 1 || defined(SQLITE_DISABLE_RECURSIVE_TRIGGERS)
                  | SQLITE_NoRecTriggers
 #endif
       ;
diff --git a/src/prepare.c b/src/prepare.c
index a1e5b3f..b4bb651 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -676,6 +676,7 @@
     sqlite3Error(db, rc, 0);
   }
 
+  /* Delete any TriggerPrg structures allocated while parsing this statement. */
   while( pParse->pTriggerPrg ){
     TriggerPrg *pT = pParse->pTriggerPrg;
     pParse->pTriggerPrg = pT->pNext;
diff --git a/src/resolve.c b/src/resolve.c
index b8e5202..857b67d 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -224,11 +224,13 @@
     ** it is a new.* or old.* trigger argument reference
     */
     if( zDb==0 && zTab!=0 && cnt==0 && pParse->pTriggerTab!=0 ){
+      int op = pParse->eTriggerOp;
       Table *pTab = 0;
-      if( pParse->triggerOp!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){
+      assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
+      if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){
         pExpr->iTable = 1;
         pTab = pParse->pTriggerTab;
-      }else if( pParse->triggerOp!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
+      }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
         pExpr->iTable = 0;
         pTab = pParse->pTriggerTab;
       }
diff --git a/src/select.c b/src/select.c
index c6940d7..dcc4374 100644
--- a/src/select.c
+++ b/src/select.c
@@ -2733,10 +2733,10 @@
   */
   if( ALWAYS(pSubitem->pTab!=0) ){
     Table *pTabToDel = pSubitem->pTab;
-    Parse *pRoot = (pParse->pRoot ? pParse->pRoot : pParse);
     if( pTabToDel->nRef==1 ){
-      pTabToDel->pNextZombie = pRoot->pZombieTab;
-      pRoot->pZombieTab = pTabToDel;
+      Parse *pToplevel = sqlite3ParseToplevel(pParse);
+      pTabToDel->pNextZombie = pToplevel->pZombieTab;
+      pToplevel->pZombieTab = pTabToDel;
     }else{
       pTabToDel->nRef--;
     }
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index c394e4a..9efb023 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -2029,6 +2029,10 @@
 ** TriggerPrg.orconf, is stored in the TriggerPrg.pProgram variable.
 ** The Parse.pTriggerPrg list never contains two entries with the same
 ** values for both pTrigger and orconf.
+**
+** The TriggerPrg.oldmask variable is set to a mask of old.* columns
+** accessed (or set to 0 for triggers fired as a result of INSERT 
+** statements).
 */
 struct TriggerPrg {
   Trigger *pTrigger;      /* Trigger this program was coded from */
@@ -2098,15 +2102,14 @@
   int regRowid;        /* Register holding rowid of CREATE TABLE entry */
   int regRoot;         /* Register holding root page number for new objects */
   AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
+  int nMaxArg;         /* Max args passed to user function by sub-program */
 
   /* Information used while coding trigger programs. */
-  Parse *pRoot;        /* Root Parse structure */
+  Parse *pToplevel;    /* Parse structure for main program (or NULL) */
   Table *pTriggerTab;  /* Table triggers are being coded for */
-  u32 oldmask; 
-  u32 newmask; 
-  int triggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
-  int nArg;
-  int orconf;          /* Default ON CONFLICT policy for trigger steps */
+  u32 oldmask;         /* Mask of old.* columns referenced */
+  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
+  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
 
   /* Above is constant between recursions.  Below is reset before and after
   ** each recursion */
@@ -2692,6 +2695,7 @@
   void sqlite3DeleteTrigger(sqlite3*, Trigger*);
   void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
   u32 sqlite3TriggerOldmask(Parse*,Trigger*,int,ExprList*,Table*,int);
+# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
 #else
 # define sqlite3TriggersExist(B,C,D,E,F) 0
 # define sqlite3DeleteTrigger(A,B)
@@ -2699,6 +2703,7 @@
 # define sqlite3UnlinkAndDeleteTrigger(A,B,C)
 # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J)
 # define sqlite3TriggerList(X, Y) 0
+# define sqlite3ParseToplevel(p) p
 #endif
 
 int sqlite3JoinType(Parse*, Token*, Token*, Token*);
diff --git a/src/trigger.c b/src/trigger.c
index 964db70..e17b48e 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -666,22 +666,22 @@
 }
 
 /*
-** Generate VDBE code for zero or more statements inside the body of a
-** trigger.  
+** Generate VDBE code for the statements inside the body of a single 
+** trigger.
 */
 static int codeTriggerProgram(
   Parse *pParse,            /* The parser context */
   TriggerStep *pStepList,   /* List of statements inside the trigger body */
-  int orconfin              /* Conflict algorithm. (OE_Abort, etc) */  
+  int orconf                /* Conflict algorithm. (OE_Abort, etc) */  
 ){
-  TriggerStep * pStep = pStepList;
+  TriggerStep *pStep;
   Vdbe *v = pParse->pVdbe;
   sqlite3 *db = pParse->db;
 
-  assert( pParse->pRoot );
-  assert( pStep!=0 );
+  assert( pParse->pTriggerTab && pParse->pToplevel );
+  assert( pStepList );
   assert( v!=0 );
-  while( pStep ){
+  for(pStep=pStepList; pStep; pStep=pStep->pNext){
     /* Figure out the ON CONFLICT policy that will be used for this step
     ** of the trigger program. If the statement that caused this trigger
     ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use
@@ -695,7 +695,7 @@
     **   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
     **   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
     */
-    pParse->orconf = (orconfin==OE_Default)?pStep->orconf:orconfin;
+    pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:orconf;
 
     switch( pStep->op ){
       case TK_UPDATE: {
@@ -703,7 +703,7 @@
           targetSrcList(pParse, pStep),
           sqlite3ExprListDup(db, pStep->pExprList, 0), 
           sqlite3ExprDup(db, pStep->pWhere, 0), 
-          pParse->orconf
+          pParse->eOrconf
         );
         break;
       }
@@ -713,7 +713,7 @@
           sqlite3ExprListDup(db, pStep->pExprList, 0), 
           sqlite3SelectDup(db, pStep->pSelect, 0), 
           sqlite3IdListDup(db, pStep->pIdList), 
-          pParse->orconf
+          pParse->eOrconf
         );
         break;
       }
@@ -736,7 +736,6 @@
     if( pStep->op!=TK_SELECT ){
       sqlite3VdbeAddOp1(v, OP_ResetCount, 1);
     }
-    pStep = pStep->pNext;
   }
 
   return 0;
@@ -776,16 +775,19 @@
   }
 }
 
+/*
+** Create and populate a new TriggerPrg object with a sub-program 
+** implementing trigger pTrigger with ON CONFLICT policy orconf.
+*/
 static TriggerPrg *codeRowTrigger(
-  Parse *pRoot,        /* Root parse context */
   Parse *pParse,       /* Current parse context */
   Trigger *pTrigger,   /* Trigger to code */
-  int op,              /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
-  Table *pTab,         /* The table to code triggers from */
-  int orconf
+  Table *pTab,         /* The table pTrigger is attached to */
+  int orconf           /* ON CONFLICT policy to code trigger program with */
 ){
-  sqlite3 *db = pParse->db;
-  TriggerPrg *pPrg;
+  Parse *pTop = sqlite3ParseToplevel(pParse);
+  sqlite3 *db = pParse->db;   /* Database handle */
+  TriggerPrg *pPrg;           /* Value to return */
   Expr *pWhen = 0;            /* Duplicate of trigger WHEN expression */
   Vdbe *v;                    /* Temporary VM */
   NameContext sNC;            /* Name context for sub-vdbe */
@@ -793,35 +795,41 @@
   Parse *pSubParse;           /* Parse context for sub-vdbe */
   int iEndTrigger = 0;        /* Label to jump to if WHEN is false */
 
+  assert( pTab==tableOfTrigger(pTrigger) );
+
+  /* Allocate the TriggerPrg and SubProgram objects. To ensure that they
+  ** are freed if an error occurs, link them into the Parse.pTriggerPrg 
+  ** list of the top-level Parse object sooner rather than later.  */
   pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg));
   if( !pPrg ) return 0;
-  pPrg->pNext = pRoot->pTriggerPrg;
-  pRoot->pTriggerPrg = pPrg;
+  pPrg->pNext = pTop->pTriggerPrg;
+  pTop->pTriggerPrg = pPrg;
   pPrg->pProgram = pProgram = sqlite3DbMallocZero(db, sizeof(SubProgram));
   if( !pProgram ) return 0;
   pProgram->nRef = 1;
-  pSubParse = sqlite3StackAllocZero(db, sizeof(Parse));
-  if( !pSubParse ) return 0;
-
-  pPrg->pProgram = pProgram;
   pPrg->pTrigger = pTrigger;
   pPrg->orconf = orconf;
 
+  /* Allocate and populate a new Parse context to use for coding the 
+  ** trigger sub-program.  */
+  pSubParse = sqlite3StackAllocZero(db, sizeof(Parse));
+  if( !pSubParse ) return 0;
   memset(&sNC, 0, sizeof(sNC));
   sNC.pParse = pSubParse;
   pSubParse->db = db;
   pSubParse->pTriggerTab = pTab;
-  pSubParse->pRoot = pRoot;
+  pSubParse->pToplevel = pTop;
   pSubParse->zAuthContext = pTrigger->zName;
+  pSubParse->eTriggerOp = pTrigger->op;
 
   v = sqlite3GetVdbe(pSubParse);
   if( v ){
     VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", 
       pTrigger->zName, onErrorText(orconf),
       (pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
-        (op==TK_UPDATE ? "UPDATE" : ""),
-        (op==TK_INSERT ? "INSERT" : ""),
-        (op==TK_DELETE ? "DELETE" : ""),
+        (pTrigger->op==TK_UPDATE ? "UPDATE" : ""),
+        (pTrigger->op==TK_INSERT ? "INSERT" : ""),
+        (pTrigger->op==TK_DELETE ? "DELETE" : ""),
       pTab->zName
     ));
 #ifndef SQLITE_OMIT_TRACE
@@ -830,9 +838,10 @@
     );
 #endif
 
+    /* If one was specified, code the WHEN clause. If it evaluates to false
+    ** (or NULL) the sub-vdbe is immediately halted by jumping to the 
+    ** OP_Halt inserted at the end of the program.  */
     if( pTrigger->pWhen ){
-      /* Code the WHEN clause. If it evaluates to false (or NULL) the 
-      ** sub-vdbe is immediately halted.  */
       pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0);
       if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) 
        && db->mallocFailed==0 
@@ -845,6 +854,8 @@
 
     /* Code the trigger program into the sub-vdbe. */
     codeTriggerProgram(pSubParse, pTrigger->step_list, orconf);
+
+    /* Insert an OP_Halt at the end of the sub-program. */
     if( iEndTrigger ){
       sqlite3VdbeResolveLabel(v, iEndTrigger);
     }
@@ -853,49 +864,51 @@
 
     transferParseError(pParse, pSubParse);
     if( db->mallocFailed==0 ){
-      pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pParse->nArg);
+      pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
     }
     pProgram->nMem = pSubParse->nMem;
     pProgram->nCsr = pSubParse->nTab;
     pProgram->token = (void *)pTrigger;
     pPrg->oldmask = pSubParse->oldmask;
     sqlite3VdbeDelete(v);
-
-    while( pSubParse->pAinc ){
-      AutoincInfo *p = pSubParse->pAinc;
-      pSubParse->pAinc = p->pNext;
-      sqlite3DbFree(db, p);
-    }
   }
+
+  assert( !pSubParse->pAinc       && !pSubParse->pZombieTab );
+  assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
   sqlite3StackFree(db, pSubParse);
 
   return pPrg;
 }
     
+/*
+** Return a pointer to a TriggerPrg object containing the sub-program for
+** trigger pTrigger with default ON CONFLICT algorithm orconf. If no such
+** TriggerPrg object exists, a new object is allocated and populated before
+** being returned.
+*/
 static TriggerPrg *getRowTrigger(
-  Parse *pParse,
+  Parse *pParse,       /* Current parse context */
   Trigger *pTrigger,   /* Trigger to code */
-  int op,              /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
-  Table *pTab,         /* The table to code triggers from */
-  int orconf
+  Table *pTab,         /* The table trigger pTrigger is attached to */
+  int orconf           /* ON CONFLICT algorithm. */
 ){
+  Parse *pRoot = sqlite3ParseToplevel(pParse);
   TriggerPrg *pPrg;
-  Parse *pRoot = pParse;
+
+  assert( pTab==tableOfTrigger(pTrigger) );
 
   /* It may be that this trigger has already been coded (or is in the
   ** process of being coded). If this is the case, then an entry with
   ** a matching TriggerPrg.pTrigger field will be present somewhere
   ** in the Parse.pTriggerPrg list. Search for such an entry.  */
-  if( pParse->pRoot ){
-    pRoot = pParse->pRoot;
-  }
   for(pPrg=pRoot->pTriggerPrg; 
       pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); 
       pPrg=pPrg->pNext
   );
 
+  /* If an existing TriggerPrg could not be located, create a new one. */
   if( !pPrg ){
-    pPrg = codeRowTrigger(pRoot, pParse, pTrigger, op, pTab, orconf);
+    pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf);
   }
 
   return pPrg;
@@ -962,7 +975,7 @@
     ){
       Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */
       TriggerPrg *pPrg;
-      pPrg = getRowTrigger(pParse, p, op, pTab, orconf);
+      pPrg = getRowTrigger(pParse, p, pTab, orconf);
       assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
 
       /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program 
@@ -1011,7 +1024,7 @@
   for(p=pTrigger; p; p=p->pNext){
     if( p->op==op && checkColumnOverlap(p->pColumns,pChanges) ){
       TriggerPrg *pPrg;
-      pPrg = getRowTrigger(pParse, p, op, pTab, orconf);
+      pPrg = getRowTrigger(pParse, p, pTab, orconf);
       if( pPrg ){
         mask |= pPrg->oldmask;
       }
diff --git a/src/vdbe.c b/src/vdbe.c
index bd51386..600b88a 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -4772,9 +4772,17 @@
 ** P4 is a pointer to the VM containing the trigger program.
 */
 case OP_Program: {        /* jump */
-  VdbeFrame *pFrame;
-  SubProgram *pProgram = pOp->p4.pProgram;
-  Mem *pRt = &p->aMem[pOp->p3];        /* Register to allocate runtime space */
+  int nMem;               /* Number of memory registers for sub-program */
+  int nByte;              /* Bytes of runtime space required for sub-program */
+  Mem *pRt;               /* Register to allocate runtime space */
+  Mem *pMem;              /* Used to iterate through memory cells */
+  Mem *pEnd;              /* Last memory cell in new array */
+  VdbeFrame *pFrame;      /* New vdbe frame to execute in */
+  SubProgram *pProgram;   /* Sub-program to execute */
+  void *t;                /* Token identifying trigger */
+
+  pProgram = pOp->p4.pProgram;
+  pRt = &p->aMem[pOp->p3];
   assert( pProgram->nOp>0 );
   
   /* If the SQLITE_NoRecTriggers flag it set, then recursive invocation of
@@ -4789,7 +4797,7 @@
   ** variable.
   */
   if( db->flags&SQLITE_NoRecTriggers ){
-    void *t = pProgram->token;
+    t = pProgram->token;
     for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent);
     if( pFrame ) break;
   }
@@ -4806,16 +4814,13 @@
   ** the trigger program. If this trigger has been fired before, then pRt 
   ** is already allocated. Otherwise, it must be initialized.  */
   if( (pRt->flags&MEM_Frame)==0 ){
-    Mem *pMem;
-    Mem *pEnd;
-
     /* SubProgram.nMem is set to the number of memory cells used by the 
     ** program stored in SubProgram.aOp. As well as these, one memory
     ** cell is required for each cursor used by the program. Set local
     ** variable nMem (and later, VdbeFrame.nChildMem) to this value.
     */
-    int nMem = pProgram->nMem + pProgram->nCsr;
-    int nByte = ROUND8(sizeof(VdbeFrame))
+    nMem = pProgram->nMem + pProgram->nCsr;
+    nByte = ROUND8(sizeof(VdbeFrame))
               + nMem * sizeof(Mem)
               + pProgram->nCsr * sizeof(VdbeCursor *);
     pFrame = sqlite3DbMallocZero(db, nByte);
@@ -4880,8 +4885,10 @@
 ** calling OP_Program instruction.
 */
 case OP_Param: {           /* out2-prerelease */
-  VdbeFrame *pFrame = p->pFrame;
-  Mem *pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];   
+  VdbeFrame *pFrame;
+  Mem *pIn;
+  pFrame = p->pFrame;
+  pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];   
   sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
   break;
 }
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index c2c19be..40aab1a 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -89,6 +89,19 @@
 };
 typedef struct VdbeCursor VdbeCursor;
 
+/*
+** When a sub-program is executed (OP_Program), a structure of this type
+** is allocated to store the current value of the program counter, as
+** well as the current memory cell array and various other frame specific
+** values stored in the Vdbe struct. When the sub-program is finished, 
+** these values are copied back to the Vdbe from the VdbeFrame structure,
+** restoring the state of the VM to as it was before the sub-program
+** began executing.
+**
+** Frames are stored in a linked list headed at Vdbe.pParent. Vdbe.pParent
+** is the parent of the current frame, or zero if the current frame
+** is the main Vdbe program.
+*/
 typedef struct VdbeFrame VdbeFrame;
 struct VdbeFrame {
   Vdbe *v;                /* VM this frame belongs to */
@@ -99,12 +112,12 @@
   int nMem;               /* Number of entries in aMem */
   VdbeCursor **apCsr;     /* Element of Vdbe cursors */
   u16 nCursor;            /* Number of entries in apCsr */
-  VdbeFrame *pParent;     /* Parent of this frame */
   void *token;            /* Copy of SubProgram.token */
   int nChildMem;          /* Number of memory cells for child frame */
   int nChildCsr;          /* Number of cursors for child frame */
-  i64 lastRowid;    /* Last insert rowid (sqlite3.lastRowid) */
-  int nChange;      /* Statement changes (Vdbe.nChanges)     */
+  i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
+  int nChange;            /* Statement changes (Vdbe.nChanges)     */
+  VdbeFrame *pParent;     /* Parent of this frame */
 };
 
 #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
@@ -308,7 +321,6 @@
 #endif
   VdbeFrame *pFrame;      /* Parent frame */
   int nFrame;             /* Number of frames in pFrame list */
-  u8 noRecTrigger;        /* True to disable recursive triggers */
 };
 
 /*
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index f48c415..546c16f 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -339,9 +339,24 @@
   return p->nOp;
 }
 
+/*
+** This function returns a pointer to the array of opcodes associated with
+** the Vdbe passed as the first argument. It is the callers responsibility
+** to arrange for the returned array to be eventually freed using the 
+** vdbeFreeOpArray() function.
+**
+** Before returning, *pnOp is set to the number of entries in the returned
+** array. Also, *pnMaxArg is set to the larger of its current value and 
+** the number of entries in the Vdbe.apArg[] array required to execute the 
+** returned program.
+*/
 VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
   VdbeOp *aOp = p->aOp;
   assert( aOp && !p->db->mallocFailed );
+
+  /* Check that sqlite3VdbeUsesBtree() was not called on this VM */
+  assert( p->aMutex.nMutex==0 );
+
   resolveP2Values(p, pnMaxArg);
   *pnOp = p->nOp;
   p->aOp = 0;
@@ -499,6 +514,11 @@
   }
 }
 
+/*
+** Free the space allocated for aOp and any p4 values allocated for the
+** opcodes contained within. If aOp is not NULL it is assumed to contain 
+** nOp entries. 
+*/
 static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
   if( aOp ){
     Op *pOp;
@@ -512,6 +532,19 @@
   sqlite3DbFree(db, aOp);
 }
 
+/*
+** Decrement the ref-count on the SubProgram structure passed as the
+** second argument. If the ref-count reaches zero, free the structure.
+**
+** The array of VDBE opcodes stored as SubProgram.aOp is freed if
+** either the ref-count reaches zero or parameter freeop is non-zero.
+**
+** Since the array of opcodes pointed to by SubProgram.aOp may directly
+** or indirectly contain a reference to the SubProgram structure itself.
+** By passing a non-zero freeop parameter, the caller may ensure that all
+** SubProgram structures and their aOp arrays are freed, even when there
+** are such circular references.
+*/
 void sqlite3VdbeProgramDelete(sqlite3 *db, SubProgram *p, int freeop){
   if( p ){
     assert( p->nRef>0 );
@@ -815,7 +848,6 @@
 
 /*
 ** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
-**
 */
 void sqlite3VdbeUsesBtree(Vdbe *p, int i){
   int mask;
@@ -887,6 +919,10 @@
   }
 }
 
+/*
+** Delete a VdbeFrame object and its contents. VdbeFrame objects are
+** allocated by the OP_Program opcode in sqlite3VdbeExec().
+*/
 void sqlite3VdbeFrameDelete(VdbeFrame *p){
   int i;
   Mem *aMem = VdbeFrameMem(p);
@@ -1334,6 +1370,11 @@
   }
 }
 
+/*
+** Copy the values stored in the VdbeFrame structure to its Vdbe. This
+** is used, for example, when a trigger sub-program is halted to restore
+** control to the main program.
+*/
 int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
   Vdbe *v = pFrame->v;
   v->aOp = pFrame->aOp;
diff --git a/src/vtab.c b/src/vtab.c
index 12fa2f0..117f361 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -941,21 +941,21 @@
 ** is a no-op.
 */
 void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
+  Parse *pToplevel = sqlite3ParseToplevel(pParse);
   int i, n;
   Table **apVtabLock;
-  Parse *pRoot = (pParse->pRoot ? pParse->pRoot : pParse);
 
   assert( IsVirtual(pTab) );
-  for(i=0; i<pRoot->nVtabLock; i++){
-    if( pTab==pRoot->apVtabLock[i] ) return;
+  for(i=0; i<pToplevel->nVtabLock; i++){
+    if( pTab==pToplevel->apVtabLock[i] ) return;
   }
-  n = (pRoot->nVtabLock+1)*sizeof(pRoot->apVtabLock[0]);
-  apVtabLock = sqlite3_realloc(pRoot->apVtabLock, n);
+  n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
+  apVtabLock = sqlite3_realloc(pToplevel->apVtabLock, n);
   if( apVtabLock ){
-    pRoot->apVtabLock = apVtabLock;
-    pRoot->apVtabLock[pRoot->nVtabLock++] = pTab;
+    pToplevel->apVtabLock = apVtabLock;
+    pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
   }else{
-    pRoot->db->mallocFailed = 1;
+    pToplevel->db->mallocFailed = 1;
   }
 }