mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Prevent an infinite loop when deleting a table that has a TEMP trigger. (CVS 984)
FossilOrigin-Name: c8c823b068916711857fa67db10fb479999b55c2
This commit is contained in:
@ -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 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
|
||||
/* 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{
|
||||
|
@ -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 @@ expr(A) ::= RAISE(X) LP FAIL COMMA nm(Z) RP(Y). {
|
||||
|
||||
//////////////////////// 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 /////////////////////////
|
||||
|
@ -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 @@ struct Trigger {
|
||||
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 @@ int sqliteSafetyCheck(sqlite*);
|
||||
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);
|
||||
|
@ -127,6 +127,7 @@ void sqliteBeginTrigger(
|
||||
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 @@ void sqliteFinishTrigger(
|
||||
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 @@ void sqliteDeleteTrigger(Trigger *pTrigger){
|
||||
/*
|
||||
* 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 @@ void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
|
||||
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 @@ void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
|
||||
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 @@ void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
|
||||
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 @@ void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
|
||||
* 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 @@ void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
|
||||
sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
|
||||
sqliteDeleteTrigger(pTrigger);
|
||||
}
|
||||
|
||||
drop_trigger_cleanup:
|
||||
sqliteSrcListDelete(pName);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user