Prevent an infinite loop when deleting a table that has a TEMP trigger. (CVS 984)

FossilOrigin-Name: c8c823b068916711857fa67db10fb479999b55c2
diff --git a/src/build.c b/src/build.c
index b160a32..100b701 100644
--- a/src/build.c
+++ b/src/build.c
@@ -23,7 +23,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.153 2003/05/17 17:35:11 drh Exp $
+** $Id: build.c,v 1.154 2003/05/17 19:04:04 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1297,12 +1297,8 @@
     /* Drop all triggers associated with the table being dropped */
     pTrigger = pTable->pTrigger;
     while( pTrigger ){
-      SrcList *pNm;
       assert( pTrigger->iDb==pTable->iDb || pTrigger->iDb==1 );
-      pNm = sqliteSrcListAppend(0, 0, 0);
-      pNm->a[0].zName = sqliteStrDup(pTrigger->name);
-      pNm->a[0].zDatabase = sqliteStrDup(db->aDb[pTable->iDb].zName);
-      sqliteDropTrigger(pParse, pNm, 1);
+      sqliteDropTriggerPtr(pParse, pTrigger, 1);
       if( pParse->explain ){
         pTrigger = pTrigger->pNext;
       }else{
diff --git a/src/parse.y b/src/parse.y
index 8c183ce..f3b9795 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.97 2003/04/29 17:19:18 drh Exp $
+** @(#) $Id: parse.y,v 1.98 2003/05/17 19:04:04 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -848,7 +848,7 @@
 
 ////////////////////////  DROP TRIGGER statement //////////////////////////////
 cmd ::= DROP TRIGGER nm(X) dbnm(D). {
-  sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&X,&D),0);
+  sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&X,&D));
 }
 
 //////////////////////// ATTACH DATABASE file AS name /////////////////////////
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 93b4dcc..699facf 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.185 2003/05/17 17:35:12 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.186 2003/05/17 19:04:04 drh Exp $
 */
 #include "config.h"
 #include "sqlite.h"
@@ -893,6 +893,7 @@
   char *name;             /* The name of the trigger                        */
   char *table;            /* The table or view to which the trigger applies */
   u8 iDb;                 /* Database containing this trigger               */
+  u8 iTabDb;              /* Database containing Trigger.table              */
   u8 op;                  /* One of TK_DELETE, TK_UPDATE, TK_INSERT         */
   u8 tr_tm;               /* One of TK_BEFORE, TK_AFTER */
   Expr *pWhen;            /* The WHEN clause of the expresion (may be NULL) */
@@ -1135,7 +1136,8 @@
 void sqliteChangeCookie(sqlite*, Vdbe*);
 void sqliteBeginTrigger(Parse*, Token*,int,int,IdList*,SrcList*,int,Expr*,int);
 void sqliteFinishTrigger(Parse*, TriggerStep*, Token*);
-void sqliteDropTrigger(Parse*, SrcList*, int);
+void sqliteDropTrigger(Parse*, SrcList*);
+void sqliteDropTriggerPtr(Parse*, Trigger*, int);
 int sqliteTriggersExist(Parse* , Trigger* , int , int , int, ExprList*);
 int sqliteCodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int, 
                          int, int);
diff --git a/src/trigger.c b/src/trigger.c
index 227e471..6ac45fc 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -127,6 +127,7 @@
   nt->table = sqliteStrDup(pTableName->a[0].zName);
   if( sqlite_malloc_failed ) goto trigger_cleanup;
   nt->iDb = iDb;
+  nt->iTabDb = tab->iDb;
   nt->op = op;
   nt->tr_tm = tr_tm;
   nt->pWhen = sqliteExprDup(pWhen);
@@ -184,7 +185,7 @@
     v = sqliteGetVdbe(pParse);
     if( v==0 ) goto triggerfinish_cleanup;
     sqliteBeginWriteOperation(pParse, 0, 0);
-    sqliteOpenMasterTable(v, nt->iDb==1);
+    sqliteOpenMasterTable(v, nt->iDb);
     addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
     sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 
     sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 
@@ -359,18 +360,18 @@
 /*
  * This function is called to drop a trigger from the database schema. 
  *
- * This may be called directly from the parser, or from within 
- * sqliteDropTable(). In the latter case the "nested" argument is true.
+ * This may be called directly from the parser and therefore identifies
+ * the trigger by name.  The sqliteDropTriggerPtr() routine does the
+ * same job as this routine except it take a spointer to the trigger
+ * instead of the trigger name.
  *
  * Note that this function does not delete the trigger entirely. Instead it
  * removes it from the internal schema and places it in the trigDrop hash 
  * table. This is so that the trigger can be restored into the database schema
  * if the transaction is rolled back.
  */
-void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
+void sqliteDropTrigger(Parse *pParse, SrcList *pName){
   Trigger *pTrigger;
-  Table   *pTable;
-  Vdbe *v;
   int i;
   const char *zDb;
   const char *zName;
@@ -392,13 +393,29 @@
     sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0);
     goto drop_trigger_cleanup;
   }
+  sqliteDropTriggerPtr(pParse, pTrigger, 0);
+
+drop_trigger_cleanup:
+  sqliteSrcListDelete(pName);
+}
+
+/*
+** Drop a trigger given a pointer to that trigger.  If nested is false,
+** then also generate code to remove the trigger from the SQLITE_MASTER
+** table.
+*/
+void sqliteDropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
+  Table   *pTable;
+  Vdbe *v;
+  sqlite *db = pParse->db;
+
   assert( pTrigger->iDb<db->nDb );
   if( pTrigger->iDb>=2 ){
     sqliteErrorMsg(pParse, "triggers may not be removed from "
        "auxiliary database %s", db->aDb[pTrigger->iDb].zName);
-    goto drop_trigger_cleanup;
+    return;
   }
-  pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName);
+  pTable = sqliteFindTable(db, pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
   assert(pTable);
   assert( pTable->iDb==pTrigger->iDb || pTrigger->iDb==1 );
 #ifndef SQLITE_OMIT_AUTHORIZATION
@@ -409,7 +426,7 @@
     if( pTrigger->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
     if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
       sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
-      goto drop_trigger_cleanup;
+      return;
     }
   }
 #endif
@@ -432,7 +449,7 @@
     sqliteBeginWriteOperation(pParse, 0, 0);
     sqliteOpenMasterTable(v, pTrigger->iDb);
     base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
-    sqliteVdbeChangeP3(v, base+1, zName, 0);
+    sqliteVdbeChangeP3(v, base+1, pTrigger->name, 0);
     if( pTrigger->iDb==0 ){
       sqliteChangeCookie(db, v);
     }
@@ -444,6 +461,8 @@
    * If this is not an "explain", then delete the trigger structure.
    */
   if( !pParse->explain ){
+    const char *zName = pTrigger->name;
+    int nName = strlen(zName);
     if( pTable->pTrigger == pTrigger ){
       pTable->pTrigger = pTrigger->pNext;
     }else{
@@ -460,9 +479,6 @@
     sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
     sqliteDeleteTrigger(pTrigger);
   }
-
-drop_trigger_cleanup:
-  sqliteSrcListDelete(pName);
 }
 
 /*