1c3f9bad2Sdanielk1977 /* 2633ed08dSdanielk1977 ** 3633ed08dSdanielk1977 ** The author disclaims copyright to this source code. In place of 4633ed08dSdanielk1977 ** a legal notice, here is a blessing: 5633ed08dSdanielk1977 ** 6633ed08dSdanielk1977 ** May you do good and not evil. 7633ed08dSdanielk1977 ** May you find forgiveness for yourself and forgive others. 8633ed08dSdanielk1977 ** May you share freely, never taking more than you give. 9633ed08dSdanielk1977 ** 10633ed08dSdanielk1977 ************************************************************************* 11633ed08dSdanielk1977 * 12c3f9bad2Sdanielk1977 */ 13c3f9bad2Sdanielk1977 #include "sqliteInt.h" 149adf9ac4Sdrh 15c3f9bad2Sdanielk1977 /* 164b59ab5eSdrh ** Delete a linked list of TriggerStep structures. 174b59ab5eSdrh */ 184b59ab5eSdrh static void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){ 194b59ab5eSdrh while( pTriggerStep ){ 204b59ab5eSdrh TriggerStep * pTmp = pTriggerStep; 214b59ab5eSdrh pTriggerStep = pTriggerStep->pNext; 224b59ab5eSdrh 238c74a8caSdrh if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z); 244b59ab5eSdrh sqliteExprDelete(pTmp->pWhere); 254b59ab5eSdrh sqliteExprListDelete(pTmp->pExprList); 264b59ab5eSdrh sqliteSelectDelete(pTmp->pSelect); 274b59ab5eSdrh sqliteIdListDelete(pTmp->pIdList); 284b59ab5eSdrh 294b59ab5eSdrh sqliteFree(pTmp); 304b59ab5eSdrh } 314b59ab5eSdrh } 324b59ab5eSdrh 334b59ab5eSdrh /* 34633ed08dSdanielk1977 ** This is called by the parser when it sees a CREATE TRIGGER statement. See 35633ed08dSdanielk1977 ** comments surrounding struct Trigger in sqliteInt.h for a description of 36633ed08dSdanielk1977 ** how triggers are stored. 37c3f9bad2Sdanielk1977 */ 389adf9ac4Sdrh void sqliteCreateTrigger( 39c3f9bad2Sdanielk1977 Parse *pParse, /* The parse context of the CREATE TRIGGER statement */ 40633ed08dSdanielk1977 Token *pName, /* The name of the trigger */ 41d702fccbSdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER , TK_INSTEAD */ 42c3f9bad2Sdanielk1977 int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ 43633ed08dSdanielk1977 IdList *pColumns, /* column list if this is an UPDATE OF trigger */ 44d24cc427Sdrh SrcList *pTableName,/* The name of the table/view the trigger applies to */ 45c3f9bad2Sdanielk1977 int foreach, /* One of TK_ROW or TK_STATEMENT */ 46c3f9bad2Sdanielk1977 Expr *pWhen, /* WHEN clause */ 47633ed08dSdanielk1977 TriggerStep *pStepList, /* The triggered program */ 484b59ab5eSdrh Token *pAll /* Token that describes the complete CREATE TRIGGER */ 499adf9ac4Sdrh ){ 50c3f9bad2Sdanielk1977 Trigger *nt; 51c3f9bad2Sdanielk1977 Table *tab; 52e5f9c644Sdrh char *zName = 0; /* Name of the trigger */ 53d24cc427Sdrh sqlite *db = pParse->db; 54ed6c8671Sdrh 55c3f9bad2Sdanielk1977 /* Check that: 569adf9ac4Sdrh ** 1. the trigger name does not already exist. 579adf9ac4Sdrh ** 2. the table (or view) does exist. 58d702fccbSdanielk1977 ** 3. that we are not trying to create a trigger on the sqlite_master table 59d702fccbSdanielk1977 ** 4. That we are not trying to create an INSTEAD OF trigger on a table. 60d702fccbSdanielk1977 ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view. 61c3f9bad2Sdanielk1977 */ 62d24cc427Sdrh if( sqlite_malloc_failed ) goto trigger_cleanup; 63d24cc427Sdrh assert( pTableName->nSrc==1 ); 64812d7a21Sdrh tab = sqliteSrcListLookup(pParse, pTableName); 65d24cc427Sdrh if( !tab ){ 66d24cc427Sdrh goto trigger_cleanup; 67d24cc427Sdrh } 68d24cc427Sdrh if( tab->iDb>=2 ){ 69d24cc427Sdrh sqliteSetString(&pParse->zErrMsg, "triggers may not be added to " 70d24cc427Sdrh "auxiliary database \"", db->aDb[tab->iDb].zName, "\"", 0); 71d24cc427Sdrh pParse->nErr++; 72d24cc427Sdrh goto trigger_cleanup; 73d24cc427Sdrh } 74d24cc427Sdrh 75e5f9c644Sdrh zName = sqliteStrNDup(pName->z, pName->n); 76d24cc427Sdrh if( sqliteHashFind(&(db->aDb[tab->iDb].trigHash), zName,pName->n+1) ){ 77c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1, 78633ed08dSdanielk1977 pName->z, pName->n, " already exists", -1, 0); 79c3f9bad2Sdanielk1977 pParse->nErr++; 80c3f9bad2Sdanielk1977 goto trigger_cleanup; 81c3f9bad2Sdanielk1977 } 82d24cc427Sdrh if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){ 83d24cc427Sdrh sqliteSetString(&pParse->zErrMsg,"cannot create trigger on system table",0); 84e0bc4048Sdrh pParse->nErr++; 85e0bc4048Sdrh goto trigger_cleanup; 86e0bc4048Sdrh } 87d702fccbSdanielk1977 if( tab->pSelect && tr_tm != TK_INSTEAD ){ 880951d703Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create ", 89d24cc427Sdrh (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", " trigger on view: ", 90d24cc427Sdrh pTableName->a[0].zName, 0); 91d702fccbSdanielk1977 goto trigger_cleanup; 92d702fccbSdanielk1977 } 93d702fccbSdanielk1977 if( !tab->pSelect && tr_tm == TK_INSTEAD ){ 940951d703Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create INSTEAD OF", 950951d703Sdrh " trigger on table: ", pTableName->a[0].zName, 0); 96d702fccbSdanielk1977 goto trigger_cleanup; 97d702fccbSdanielk1977 } 98e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 99e5f9c644Sdrh { 100e5f9c644Sdrh int code = SQLITE_CREATE_TRIGGER; 101d24cc427Sdrh if( tab->iDb==1 ) code = SQLITE_CREATE_TEMP_TRIGGER; 102e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){ 103ed6c8671Sdrh goto trigger_cleanup; 104ed6c8671Sdrh } 105d24cc427Sdrh if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){ 10677ad4e41Sdrh goto trigger_cleanup; 10777ad4e41Sdrh } 108d702fccbSdanielk1977 } 109e5f9c644Sdrh #endif 110d702fccbSdanielk1977 111d702fccbSdanielk1977 if (tr_tm == TK_INSTEAD){ 112d702fccbSdanielk1977 tr_tm = TK_BEFORE; 113c3f9bad2Sdanielk1977 } 114c3f9bad2Sdanielk1977 115c3f9bad2Sdanielk1977 /* Build the Trigger object */ 116c3f9bad2Sdanielk1977 nt = (Trigger*)sqliteMalloc(sizeof(Trigger)); 117e4697f5eSdrh if( nt==0 ) goto trigger_cleanup; 118e5f9c644Sdrh nt->name = zName; 119e5f9c644Sdrh zName = 0; 120d24cc427Sdrh nt->table = sqliteStrDup(pTableName->a[0].zName); 121e4697f5eSdrh if( sqlite_malloc_failed ) goto trigger_cleanup; 122d24cc427Sdrh nt->iDb = tab->iDb; 123c3f9bad2Sdanielk1977 nt->op = op; 124c3f9bad2Sdanielk1977 nt->tr_tm = tr_tm; 1254b59ab5eSdrh nt->pWhen = sqliteExprDup(pWhen); 1264b59ab5eSdrh sqliteExprDelete(pWhen); 1274b59ab5eSdrh nt->pColumns = sqliteIdListDup(pColumns); 1284b59ab5eSdrh sqliteIdListDelete(pColumns); 129c3f9bad2Sdanielk1977 nt->foreach = foreach; 130633ed08dSdanielk1977 nt->step_list = pStepList; 131c3f9bad2Sdanielk1977 132c3f9bad2Sdanielk1977 /* if we are not initializing, and this trigger is not on a TEMP table, 1339adf9ac4Sdrh ** build the sqlite_master entry 1349adf9ac4Sdrh */ 135e0bc4048Sdrh if( !pParse->initFlag ){ 136c977f7f5Sdrh static VdbeOp insertTrig[] = { 137c977f7f5Sdrh { OP_NewRecno, 0, 0, 0 }, 138c977f7f5Sdrh { OP_String, 0, 0, "trigger" }, 139e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 2: trigger name */ 140e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 3: table name */ 141c977f7f5Sdrh { OP_Integer, 0, 0, 0 }, 142e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 5: SQL */ 143c977f7f5Sdrh { OP_MakeRecord, 5, 0, 0 }, 144c977f7f5Sdrh { OP_PutIntKey, 0, 0, 0 }, 145c977f7f5Sdrh }; 146c977f7f5Sdrh int addr; 147c977f7f5Sdrh Vdbe *v; 148c3f9bad2Sdanielk1977 149c3f9bad2Sdanielk1977 /* Make an entry in the sqlite_master table */ 150c977f7f5Sdrh v = sqliteGetVdbe(pParse); 151e4697f5eSdrh if( v==0 ) goto trigger_cleanup; 152cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 153d24cc427Sdrh sqliteOpenMasterTable(v, tab->iDb); 154c977f7f5Sdrh addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); 155d24cc427Sdrh sqliteVdbeChangeP3(v, addr, tab->iDb ? TEMP_MASTER_NAME : MASTER_NAME, 156e0bc4048Sdrh P3_STATIC); 157e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 158e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 1594b59ab5eSdrh sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n); 160d24cc427Sdrh if( tab->iDb==0 ){ 161d24cc427Sdrh sqliteChangeCookie(db, v); 162e0bc4048Sdrh } 163e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 164c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 165c3f9bad2Sdanielk1977 } 166c3f9bad2Sdanielk1977 167c3f9bad2Sdanielk1977 if( !pParse->explain ){ 168c3f9bad2Sdanielk1977 /* Stick it in the hash-table */ 169d24cc427Sdrh sqliteHashInsert(&(db->aDb[nt->iDb].trigHash), nt->name, pName->n + 1, nt); 170c3f9bad2Sdanielk1977 171c3f9bad2Sdanielk1977 /* Attach it to the table object */ 172c3f9bad2Sdanielk1977 nt->pNext = tab->pTrigger; 173c3f9bad2Sdanielk1977 tab->pTrigger = nt; 174*0be9df07Sdrh sqliteSrcListDelete(pTableName); 175c3f9bad2Sdanielk1977 return; 176c3f9bad2Sdanielk1977 }else{ 177c3f9bad2Sdanielk1977 sqliteFree(nt->name); 178c3f9bad2Sdanielk1977 sqliteFree(nt->table); 179c3f9bad2Sdanielk1977 sqliteFree(nt); 180c3f9bad2Sdanielk1977 } 181c3f9bad2Sdanielk1977 182c3f9bad2Sdanielk1977 trigger_cleanup: 183c3f9bad2Sdanielk1977 184e5f9c644Sdrh sqliteFree(zName); 185d24cc427Sdrh sqliteSrcListDelete(pTableName); 186633ed08dSdanielk1977 sqliteIdListDelete(pColumns); 187c3f9bad2Sdanielk1977 sqliteExprDelete(pWhen); 1884b59ab5eSdrh sqliteDeleteTriggerStep(pStepList); 189c3f9bad2Sdanielk1977 } 1904b59ab5eSdrh 1914b59ab5eSdrh /* 1924b59ab5eSdrh ** Make a copy of all components of the given trigger step. This has 1934b59ab5eSdrh ** the effect of copying all Expr.token.z values into memory obtained 1944b59ab5eSdrh ** from sqliteMalloc(). As initially created, the Expr.token.z values 1954b59ab5eSdrh ** all point to the input string that was fed to the parser. But that 1964b59ab5eSdrh ** string is ephemeral - it will go away as soon as the sqlite_exec() 1974b59ab5eSdrh ** call that started the parser exits. This routine makes a persistent 1984b59ab5eSdrh ** copy of all the Expr.token.z strings so that the TriggerStep structure 1994b59ab5eSdrh ** will be valid even after the sqlite_exec() call returns. 2004b59ab5eSdrh */ 2014b59ab5eSdrh static void sqlitePersistTriggerStep(TriggerStep *p){ 2024b59ab5eSdrh if( p->target.z ){ 2034b59ab5eSdrh p->target.z = sqliteStrNDup(p->target.z, p->target.n); 2044b59ab5eSdrh p->target.dyn = 1; 2054b59ab5eSdrh } 2064b59ab5eSdrh if( p->pSelect ){ 2074b59ab5eSdrh Select *pNew = sqliteSelectDup(p->pSelect); 2084b59ab5eSdrh sqliteSelectDelete(p->pSelect); 2094b59ab5eSdrh p->pSelect = pNew; 2104b59ab5eSdrh } 2114b59ab5eSdrh if( p->pWhere ){ 2124b59ab5eSdrh Expr *pNew = sqliteExprDup(p->pWhere); 2134b59ab5eSdrh sqliteExprDelete(p->pWhere); 2144b59ab5eSdrh p->pWhere = pNew; 2154b59ab5eSdrh } 2164b59ab5eSdrh if( p->pExprList ){ 2174b59ab5eSdrh ExprList *pNew = sqliteExprListDup(p->pExprList); 2184b59ab5eSdrh sqliteExprListDelete(p->pExprList); 2194b59ab5eSdrh p->pExprList = pNew; 2204b59ab5eSdrh } 2214b59ab5eSdrh if( p->pIdList ){ 2224b59ab5eSdrh IdList *pNew = sqliteIdListDup(p->pIdList); 2234b59ab5eSdrh sqliteIdListDelete(p->pIdList); 2244b59ab5eSdrh p->pIdList = pNew; 225c3f9bad2Sdanielk1977 } 226c3f9bad2Sdanielk1977 } 227c3f9bad2Sdanielk1977 228c977f7f5Sdrh /* 229c977f7f5Sdrh ** Turn a SELECT statement (that the pSelect parameter points to) into 230c977f7f5Sdrh ** a trigger step. Return a pointer to a TriggerStep structure. 231c977f7f5Sdrh ** 232c977f7f5Sdrh ** The parser calls this routine when it finds a SELECT statement in 233c977f7f5Sdrh ** body of a TRIGGER. 234c977f7f5Sdrh */ 235c977f7f5Sdrh TriggerStep *sqliteTriggerSelectStep(Select *pSelect){ 236633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 237e4697f5eSdrh if( pTriggerStep==0 ) return 0; 238c3f9bad2Sdanielk1977 239633ed08dSdanielk1977 pTriggerStep->op = TK_SELECT; 240633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 241633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 2424b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 243c3f9bad2Sdanielk1977 244633ed08dSdanielk1977 return pTriggerStep; 245c3f9bad2Sdanielk1977 } 246c3f9bad2Sdanielk1977 247c977f7f5Sdrh /* 248c977f7f5Sdrh ** Build a trigger step out of an INSERT statement. Return a pointer 249c977f7f5Sdrh ** to the new trigger step. 250c977f7f5Sdrh ** 251c977f7f5Sdrh ** The parser calls this routine when it sees an INSERT inside the 252c977f7f5Sdrh ** body of a trigger. 253c977f7f5Sdrh */ 254633ed08dSdanielk1977 TriggerStep *sqliteTriggerInsertStep( 255c977f7f5Sdrh Token *pTableName, /* Name of the table into which we insert */ 256c977f7f5Sdrh IdList *pColumn, /* List of columns in pTableName to insert into */ 257c977f7f5Sdrh ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ 258c977f7f5Sdrh Select *pSelect, /* A SELECT statement that supplies values */ 259c977f7f5Sdrh int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ 260633ed08dSdanielk1977 ){ 261633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 262e4697f5eSdrh if( pTriggerStep==0 ) return 0; 263c3f9bad2Sdanielk1977 264633ed08dSdanielk1977 assert(pEList == 0 || pSelect == 0); 265633ed08dSdanielk1977 assert(pEList != 0 || pSelect != 0); 266c3f9bad2Sdanielk1977 267633ed08dSdanielk1977 pTriggerStep->op = TK_INSERT; 268633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 269633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 270633ed08dSdanielk1977 pTriggerStep->pIdList = pColumn; 271633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 272633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2734b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 274c3f9bad2Sdanielk1977 275633ed08dSdanielk1977 return pTriggerStep; 276c3f9bad2Sdanielk1977 } 277c3f9bad2Sdanielk1977 278c977f7f5Sdrh /* 279c977f7f5Sdrh ** Construct a trigger step that implements an UPDATE statement and return 280c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 281c977f7f5Sdrh ** sees an UPDATE statement inside the body of a CREATE TRIGGER. 282c977f7f5Sdrh */ 283633ed08dSdanielk1977 TriggerStep *sqliteTriggerUpdateStep( 284c977f7f5Sdrh Token *pTableName, /* Name of the table to be updated */ 285c977f7f5Sdrh ExprList *pEList, /* The SET clause: list of column and new values */ 286c977f7f5Sdrh Expr *pWhere, /* The WHERE clause */ 287c977f7f5Sdrh int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ 288c977f7f5Sdrh ){ 289633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 290e4697f5eSdrh if( pTriggerStep==0 ) return 0; 291c3f9bad2Sdanielk1977 292633ed08dSdanielk1977 pTriggerStep->op = TK_UPDATE; 293633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 294633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 295633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 296633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2974b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 298c3f9bad2Sdanielk1977 299633ed08dSdanielk1977 return pTriggerStep; 300c3f9bad2Sdanielk1977 } 301c3f9bad2Sdanielk1977 302c977f7f5Sdrh /* 303c977f7f5Sdrh ** Construct a trigger step that implements a DELETE statement and return 304c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 305c977f7f5Sdrh ** sees a DELETE statement inside the body of a CREATE TRIGGER. 306c977f7f5Sdrh */ 307c977f7f5Sdrh TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){ 308633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 309e4697f5eSdrh if( pTriggerStep==0 ) return 0; 310c3f9bad2Sdanielk1977 311633ed08dSdanielk1977 pTriggerStep->op = TK_DELETE; 312633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 313633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 314633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 3154b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 316c3f9bad2Sdanielk1977 317633ed08dSdanielk1977 return pTriggerStep; 318c3f9bad2Sdanielk1977 } 319c3f9bad2Sdanielk1977 320c3f9bad2Sdanielk1977 /* 321633ed08dSdanielk1977 ** Recursively delete a Trigger structure 322c3f9bad2Sdanielk1977 */ 3231d1f3055Sdrh void sqliteDeleteTrigger(Trigger *pTrigger){ 3244b59ab5eSdrh sqliteDeleteTriggerStep(pTrigger->step_list); 325633ed08dSdanielk1977 sqliteFree(pTrigger->name); 326633ed08dSdanielk1977 sqliteFree(pTrigger->table); 327633ed08dSdanielk1977 sqliteExprDelete(pTrigger->pWhen); 328633ed08dSdanielk1977 sqliteIdListDelete(pTrigger->pColumns); 329633ed08dSdanielk1977 sqliteFree(pTrigger); 330633ed08dSdanielk1977 } 331633ed08dSdanielk1977 332633ed08dSdanielk1977 /* 333633ed08dSdanielk1977 * This function is called to drop a trigger from the database schema. 334633ed08dSdanielk1977 * 335633ed08dSdanielk1977 * This may be called directly from the parser, or from within 336633ed08dSdanielk1977 * sqliteDropTable(). In the latter case the "nested" argument is true. 337633ed08dSdanielk1977 * 338633ed08dSdanielk1977 * Note that this function does not delete the trigger entirely. Instead it 339633ed08dSdanielk1977 * removes it from the internal schema and places it in the trigDrop hash 340633ed08dSdanielk1977 * table. This is so that the trigger can be restored into the database schema 341633ed08dSdanielk1977 * if the transaction is rolled back. 342633ed08dSdanielk1977 */ 343d24cc427Sdrh void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){ 344633ed08dSdanielk1977 Trigger *pTrigger; 345633ed08dSdanielk1977 Table *pTable; 346e0bc4048Sdrh Vdbe *v; 347d24cc427Sdrh int i; 348d24cc427Sdrh const char *zDb; 349d24cc427Sdrh const char *zName; 350d24cc427Sdrh int nName; 351d24cc427Sdrh sqlite *db = pParse->db; 352633ed08dSdanielk1977 353d24cc427Sdrh if( sqlite_malloc_failed ) goto drop_trigger_cleanup; 354d24cc427Sdrh assert( pName->nSrc==1 ); 355d24cc427Sdrh zDb = pName->a[0].zDatabase; 356d24cc427Sdrh zName = pName->a[0].zName; 357d24cc427Sdrh nName = strlen(zName); 358d24cc427Sdrh for(i=0; i<db->nDb; i++){ 359812d7a21Sdrh int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ 360812d7a21Sdrh if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue; 361812d7a21Sdrh pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1); 362d24cc427Sdrh if( pTrigger ) break; 363c3f9bad2Sdanielk1977 } 364d24cc427Sdrh if( !pTrigger ){ 365d24cc427Sdrh sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0); 366d24cc427Sdrh goto drop_trigger_cleanup; 367d24cc427Sdrh } 368d24cc427Sdrh assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb ); 369d24cc427Sdrh if( pTrigger->iDb>=2 ){ 370d24cc427Sdrh sqliteSetString(&pParse->zErrMsg, "triggers may not be removed from " 371d24cc427Sdrh "auxiliary database \"", db->aDb[pTrigger->iDb].zName, "\"", 0); 372d24cc427Sdrh pParse->nErr++; 373d24cc427Sdrh goto drop_trigger_cleanup; 374d24cc427Sdrh } 375d24cc427Sdrh pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName); 376ed6c8671Sdrh assert(pTable); 377d24cc427Sdrh assert( pTable->iDb==pTrigger->iDb ); 378e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 379e5f9c644Sdrh { 380e5f9c644Sdrh int code = SQLITE_DROP_TRIGGER; 381d24cc427Sdrh if( pTable->iDb ) code = SQLITE_DROP_TEMP_TRIGGER; 382e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) || 383d24cc427Sdrh sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0) ){ 384*0be9df07Sdrh goto drop_trigger_cleanup; 385ed6c8671Sdrh } 386e5f9c644Sdrh } 387e5f9c644Sdrh #endif 388c3f9bad2Sdanielk1977 389c3f9bad2Sdanielk1977 /* 390e0bc4048Sdrh * If this is not an "explain", then delete the trigger structure. 391c3f9bad2Sdanielk1977 */ 392c3f9bad2Sdanielk1977 if( !pParse->explain ){ 393633ed08dSdanielk1977 if( pTable->pTrigger == pTrigger ){ 394633ed08dSdanielk1977 pTable->pTrigger = pTrigger->pNext; 395633ed08dSdanielk1977 }else{ 396633ed08dSdanielk1977 Trigger *cc = pTable->pTrigger; 397c3f9bad2Sdanielk1977 while( cc ){ 398633ed08dSdanielk1977 if( cc->pNext == pTrigger ){ 399c3f9bad2Sdanielk1977 cc->pNext = cc->pNext->pNext; 400c3f9bad2Sdanielk1977 break; 401c3f9bad2Sdanielk1977 } 402c3f9bad2Sdanielk1977 cc = cc->pNext; 403c3f9bad2Sdanielk1977 } 404c3f9bad2Sdanielk1977 assert(cc); 405c3f9bad2Sdanielk1977 } 406d24cc427Sdrh sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0); 407e0bc4048Sdrh sqliteDeleteTrigger(pTrigger); 408c3f9bad2Sdanielk1977 } 409c3f9bad2Sdanielk1977 410e0bc4048Sdrh /* Generate code to destroy the database record of the trigger. 411e0bc4048Sdrh */ 412e0bc4048Sdrh if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){ 413c3f9bad2Sdanielk1977 int base; 414c3f9bad2Sdanielk1977 static VdbeOp dropTrigger[] = { 415e0bc4048Sdrh { OP_Rewind, 0, ADDR(8), 0}, 416e0bc4048Sdrh { OP_String, 0, 0, 0}, /* 1 */ 417c3f9bad2Sdanielk1977 { OP_MemStore, 1, 1, 0}, 418e0bc4048Sdrh { OP_MemLoad, 1, 0, 0}, /* 3 */ 419c3f9bad2Sdanielk1977 { OP_Column, 0, 1, 0}, 420e0bc4048Sdrh { OP_Ne, 0, ADDR(7), 0}, 421c3f9bad2Sdanielk1977 { OP_Delete, 0, 0, 0}, 422e0bc4048Sdrh { OP_Next, 0, ADDR(3), 0}, /* 7 */ 423c3f9bad2Sdanielk1977 }; 424c3f9bad2Sdanielk1977 425cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 426d24cc427Sdrh sqliteOpenMasterTable(v, pTable->iDb); 427e0bc4048Sdrh base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); 428e0bc4048Sdrh sqliteVdbeChangeP3(v, base+1, zName, 0); 429d24cc427Sdrh if( pTable->iDb==0 ){ 430d24cc427Sdrh sqliteChangeCookie(db, v); 431dc379456Sdrh } 432e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 433c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 434c3f9bad2Sdanielk1977 } 435c3f9bad2Sdanielk1977 436d24cc427Sdrh drop_trigger_cleanup: 437d24cc427Sdrh sqliteSrcListDelete(pName); 438c3f9bad2Sdanielk1977 } 439c3f9bad2Sdanielk1977 440c977f7f5Sdrh /* 441c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement. Each entry 442c977f7f5Sdrh ** in pEList is of the format <id>=<expr>. If any of the entries 443c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList, 444c977f7f5Sdrh ** then return TRUE. If pIdList==NULL, then it is considered a 445c977f7f5Sdrh ** wildcard that matches anything. Likewise if pEList==NULL then 446c977f7f5Sdrh ** it matches anything so always return true. Return false only 447c977f7f5Sdrh ** if there is no match. 448c977f7f5Sdrh */ 449c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){ 450ad2d8307Sdrh int e; 451ad2d8307Sdrh if( !pIdList || !pEList ) return 1; 452f29ce559Sdanielk1977 for(e=0; e<pEList->nExpr; e++){ 453ad2d8307Sdrh if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; 454f29ce559Sdanielk1977 } 455c3f9bad2Sdanielk1977 return 0; 456c3f9bad2Sdanielk1977 } 457c3f9bad2Sdanielk1977 458c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for 459c3f9bad2Sdanielk1977 * for triggers, even if there are no triggers to code. This is used to test 460c3f9bad2Sdanielk1977 * how much overhead the triggers algorithm is causing. 461c3f9bad2Sdanielk1977 * 462c3f9bad2Sdanielk1977 * This flag can be set or cleared using the "trigger_overhead_test" pragma. 463c3f9bad2Sdanielk1977 * The pragma is not documented since it is not really part of the interface 464c3f9bad2Sdanielk1977 * to SQLite, just the test procedure. 465c3f9bad2Sdanielk1977 */ 466c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0; 467c3f9bad2Sdanielk1977 468c3f9bad2Sdanielk1977 /* 469c3f9bad2Sdanielk1977 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already 470c3f9bad2Sdanielk1977 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is 471c3f9bad2Sdanielk1977 * found in the list specified as pTrigger. 472c3f9bad2Sdanielk1977 */ 473c3f9bad2Sdanielk1977 int sqliteTriggersExist( 474c977f7f5Sdrh Parse *pParse, /* Used to check for recursive triggers */ 475c977f7f5Sdrh Trigger *pTrigger, /* A list of triggers associated with a table */ 476c3f9bad2Sdanielk1977 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ 477c3f9bad2Sdanielk1977 int tr_tm, /* one of TK_BEFORE, TK_AFTER */ 478c3f9bad2Sdanielk1977 int foreach, /* one of TK_ROW or TK_STATEMENT */ 479c977f7f5Sdrh ExprList *pChanges /* Columns that change in an UPDATE statement */ 480c977f7f5Sdrh ){ 481633ed08dSdanielk1977 Trigger * pTriggerCursor; 482c3f9bad2Sdanielk1977 483633ed08dSdanielk1977 if( always_code_trigger_setup ){ 484633ed08dSdanielk1977 return 1; 485633ed08dSdanielk1977 } 486c3f9bad2Sdanielk1977 487633ed08dSdanielk1977 pTriggerCursor = pTrigger; 488633ed08dSdanielk1977 while( pTriggerCursor ){ 489633ed08dSdanielk1977 if( pTriggerCursor->op == op && 490633ed08dSdanielk1977 pTriggerCursor->tr_tm == tr_tm && 491633ed08dSdanielk1977 pTriggerCursor->foreach == foreach && 492633ed08dSdanielk1977 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){ 493c3f9bad2Sdanielk1977 TriggerStack * ss; 494c3f9bad2Sdanielk1977 ss = pParse->trigStack; 495f29ce559Sdanielk1977 while( ss && ss->pTrigger != pTrigger ){ 496f29ce559Sdanielk1977 ss = ss->pNext; 497f29ce559Sdanielk1977 } 498c3f9bad2Sdanielk1977 if( !ss )return 1; 499c3f9bad2Sdanielk1977 } 500633ed08dSdanielk1977 pTriggerCursor = pTriggerCursor->pNext; 501c3f9bad2Sdanielk1977 } 502c3f9bad2Sdanielk1977 503c3f9bad2Sdanielk1977 return 0; 504c3f9bad2Sdanielk1977 } 505c3f9bad2Sdanielk1977 506c977f7f5Sdrh /* 507c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a 508c977f7f5Sdrh ** trigger. 509c977f7f5Sdrh */ 510c3f9bad2Sdanielk1977 static int codeTriggerProgram( 511c977f7f5Sdrh Parse *pParse, /* The parser context */ 512c977f7f5Sdrh TriggerStep *pStepList, /* List of statements inside the trigger body */ 513c977f7f5Sdrh int orconfin /* Conflict algorithm. (OE_Abort, etc) */ 514633ed08dSdanielk1977 ){ 515633ed08dSdanielk1977 TriggerStep * pTriggerStep = pStepList; 516c3f9bad2Sdanielk1977 int orconf; 517c3f9bad2Sdanielk1977 518633ed08dSdanielk1977 while( pTriggerStep ){ 519c3f9bad2Sdanielk1977 int saveNTab = pParse->nTab; 520633ed08dSdanielk1977 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; 521c3f9bad2Sdanielk1977 pParse->trigStack->orconf = orconf; 522633ed08dSdanielk1977 switch( pTriggerStep->op ){ 523c3f9bad2Sdanielk1977 case TK_SELECT: { 5246f34903eSdanielk1977 Select * ss = sqliteSelectDup(pTriggerStep->pSelect); 5256f34903eSdanielk1977 assert(ss); 5266f34903eSdanielk1977 assert(ss->pSrc); 5276f34903eSdanielk1977 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0); 5286f34903eSdanielk1977 sqliteSelectDelete(ss); 529c3f9bad2Sdanielk1977 break; 530c3f9bad2Sdanielk1977 } 531c3f9bad2Sdanielk1977 case TK_UPDATE: { 532113088ecSdrh SrcList *pSrc; 533113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 534bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 535113088ecSdrh sqliteUpdate(pParse, pSrc, 536633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 537633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere), orconf); 538bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 539c3f9bad2Sdanielk1977 break; 540c3f9bad2Sdanielk1977 } 541c3f9bad2Sdanielk1977 case TK_INSERT: { 542113088ecSdrh SrcList *pSrc; 543113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 544113088ecSdrh sqliteInsert(pParse, pSrc, 545633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 546633ed08dSdanielk1977 sqliteSelectDup(pTriggerStep->pSelect), 547633ed08dSdanielk1977 sqliteIdListDup(pTriggerStep->pIdList), orconf); 548c3f9bad2Sdanielk1977 break; 549c3f9bad2Sdanielk1977 } 550c3f9bad2Sdanielk1977 case TK_DELETE: { 551113088ecSdrh SrcList *pSrc; 552bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 553113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 554113088ecSdrh sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere)); 555bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 556c3f9bad2Sdanielk1977 break; 557c3f9bad2Sdanielk1977 } 558c3f9bad2Sdanielk1977 default: 559c3f9bad2Sdanielk1977 assert(0); 560c3f9bad2Sdanielk1977 } 561c3f9bad2Sdanielk1977 pParse->nTab = saveNTab; 562633ed08dSdanielk1977 pTriggerStep = pTriggerStep->pNext; 563c3f9bad2Sdanielk1977 } 564c3f9bad2Sdanielk1977 565c3f9bad2Sdanielk1977 return 0; 566c3f9bad2Sdanielk1977 } 567c3f9bad2Sdanielk1977 568633ed08dSdanielk1977 /* 569633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers. 570633ed08dSdanielk1977 ** 571633ed08dSdanielk1977 ** When the code that this function generates is executed, the following 572633ed08dSdanielk1977 ** must be true: 573c977f7f5Sdrh ** 574c977f7f5Sdrh ** 1. No cursors may be open in the main database. (But newIdx and oldIdx 575c977f7f5Sdrh ** can be indices of cursors in temporary tables. See below.) 576c977f7f5Sdrh ** 577633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then 578633ed08dSdanielk1977 ** a temporary vdbe cursor (index newIdx) must be open and pointing at 579633ed08dSdanielk1977 ** a row containing values to be substituted for new.* expressions in the 580633ed08dSdanielk1977 ** trigger program(s). 581c977f7f5Sdrh ** 582633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then 583633ed08dSdanielk1977 ** a temporary vdbe cursor (index oldIdx) must be open and pointing at 584633ed08dSdanielk1977 ** a row containing values to be substituted for old.* expressions in the 585633ed08dSdanielk1977 ** trigger program(s). 586633ed08dSdanielk1977 ** 587633ed08dSdanielk1977 */ 588c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger( 589c3f9bad2Sdanielk1977 Parse *pParse, /* Parse context */ 590c3f9bad2Sdanielk1977 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ 591633ed08dSdanielk1977 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ 592c3f9bad2Sdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER */ 593633ed08dSdanielk1977 Table *pTab, /* The table to code triggers from */ 594633ed08dSdanielk1977 int newIdx, /* The indice of the "new" row to access */ 595633ed08dSdanielk1977 int oldIdx, /* The indice of the "old" row to access */ 5966f34903eSdanielk1977 int orconf, /* ON CONFLICT policy */ 5976f34903eSdanielk1977 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ 598c977f7f5Sdrh ){ 599c3f9bad2Sdanielk1977 Trigger * pTrigger; 600c3f9bad2Sdanielk1977 TriggerStack * pTriggerStack; 601c3f9bad2Sdanielk1977 602c3f9bad2Sdanielk1977 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); 603c3f9bad2Sdanielk1977 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER); 604c3f9bad2Sdanielk1977 605633ed08dSdanielk1977 assert(newIdx != -1 || oldIdx != -1); 606c3f9bad2Sdanielk1977 607633ed08dSdanielk1977 pTrigger = pTab->pTrigger; 608c3f9bad2Sdanielk1977 while( pTrigger ){ 609c3f9bad2Sdanielk1977 int fire_this = 0; 610c3f9bad2Sdanielk1977 611c3f9bad2Sdanielk1977 /* determine whether we should code this trigger */ 612c3f9bad2Sdanielk1977 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 613c3f9bad2Sdanielk1977 pTrigger->foreach == TK_ROW ){ 614c3f9bad2Sdanielk1977 fire_this = 1; 615c3f9bad2Sdanielk1977 pTriggerStack = pParse->trigStack; 616c3f9bad2Sdanielk1977 while( pTriggerStack ){ 617f29ce559Sdanielk1977 if( pTriggerStack->pTrigger == pTrigger ){ 618f29ce559Sdanielk1977 fire_this = 0; 619f29ce559Sdanielk1977 } 620c3f9bad2Sdanielk1977 pTriggerStack = pTriggerStack->pNext; 621c3f9bad2Sdanielk1977 } 622c3f9bad2Sdanielk1977 if( op == TK_UPDATE && pTrigger->pColumns && 623f29ce559Sdanielk1977 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){ 624c3f9bad2Sdanielk1977 fire_this = 0; 625c3f9bad2Sdanielk1977 } 626f29ce559Sdanielk1977 } 627c3f9bad2Sdanielk1977 628e4697f5eSdrh if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){ 629c3f9bad2Sdanielk1977 int endTrigger; 630ad3cab52Sdrh SrcList dummyTablist; 631c3f9bad2Sdanielk1977 Expr * whenExpr; 632c3f9bad2Sdanielk1977 633ad3cab52Sdrh dummyTablist.nSrc = 0; 634c3f9bad2Sdanielk1977 635c3f9bad2Sdanielk1977 /* Push an entry on to the trigger stack */ 636c3f9bad2Sdanielk1977 pTriggerStack->pTrigger = pTrigger; 637633ed08dSdanielk1977 pTriggerStack->newIdx = newIdx; 638633ed08dSdanielk1977 pTriggerStack->oldIdx = oldIdx; 639633ed08dSdanielk1977 pTriggerStack->pTab = pTab; 640c3f9bad2Sdanielk1977 pTriggerStack->pNext = pParse->trigStack; 6416f34903eSdanielk1977 pTriggerStack->ignoreJump = ignoreJump; 642c3f9bad2Sdanielk1977 pParse->trigStack = pTriggerStack; 643c3f9bad2Sdanielk1977 644c3f9bad2Sdanielk1977 /* code the WHEN clause */ 645c3f9bad2Sdanielk1977 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); 646c3f9bad2Sdanielk1977 whenExpr = sqliteExprDup(pTrigger->pWhen); 647c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ 648c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 649c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 650c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 651c3f9bad2Sdanielk1977 return 1; 652c3f9bad2Sdanielk1977 } 653f5905aa7Sdrh sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); 654c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 655c3f9bad2Sdanielk1977 656633ed08dSdanielk1977 codeTriggerProgram(pParse, pTrigger->step_list, orconf); 657c3f9bad2Sdanielk1977 658c3f9bad2Sdanielk1977 /* Pop the entry off the trigger stack */ 659c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 660c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 661c3f9bad2Sdanielk1977 662c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger); 663c3f9bad2Sdanielk1977 } 664c3f9bad2Sdanielk1977 pTrigger = pTrigger->pNext; 665c3f9bad2Sdanielk1977 } 666c3f9bad2Sdanielk1977 667c3f9bad2Sdanielk1977 return 0; 668c3f9bad2Sdanielk1977 } 669c3f9bad2Sdanielk1977 670c3f9bad2Sdanielk1977 /* 671633ed08dSdanielk1977 * This function is called to code ON UPDATE and ON DELETE triggers on 672633ed08dSdanielk1977 * views. 673633ed08dSdanielk1977 * 674633ed08dSdanielk1977 * This function deletes the data pointed at by the pWhere and pChanges 675633ed08dSdanielk1977 * arguments before it completes. 676c3f9bad2Sdanielk1977 */ 677633ed08dSdanielk1977 void sqliteViewTriggers( 678633ed08dSdanielk1977 Parse *pParse, 679633ed08dSdanielk1977 Table *pTab, /* The view to code triggers on */ 680633ed08dSdanielk1977 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/ 681633ed08dSdanielk1977 int orconf, /* The ON CONFLICT policy specified as part of the 682633ed08dSdanielk1977 statement causing these triggers */ 683633ed08dSdanielk1977 ExprList *pChanges /* If this is an statement causing triggers to fire 684633ed08dSdanielk1977 is an UPDATE, then this list holds the columns 685633ed08dSdanielk1977 to update and the expressions to update them to. 686633ed08dSdanielk1977 See comments for sqliteUpdate(). */ 687633ed08dSdanielk1977 ){ 688c3f9bad2Sdanielk1977 int oldIdx = -1; 689c3f9bad2Sdanielk1977 int newIdx = -1; 690c3f9bad2Sdanielk1977 int *aXRef = 0; 691c3f9bad2Sdanielk1977 Vdbe *v; 692c3f9bad2Sdanielk1977 int endOfLoop; 693c3f9bad2Sdanielk1977 int startOfLoop; 694c3f9bad2Sdanielk1977 Select theSelect; 695c3f9bad2Sdanielk1977 Token tblNameToken; 696c3f9bad2Sdanielk1977 697c3f9bad2Sdanielk1977 assert(pTab->pSelect); 698c3f9bad2Sdanielk1977 699c3f9bad2Sdanielk1977 tblNameToken.z = pTab->zName; 700c3f9bad2Sdanielk1977 tblNameToken.n = strlen(pTab->zName); 701c3f9bad2Sdanielk1977 702c3f9bad2Sdanielk1977 theSelect.isDistinct = 0; 703c3f9bad2Sdanielk1977 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0); 704113088ecSdrh theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken, 0); 705c3f9bad2Sdanielk1977 theSelect.pWhere = pWhere; pWhere = 0; 706c3f9bad2Sdanielk1977 theSelect.pGroupBy = 0; 707c3f9bad2Sdanielk1977 theSelect.pHaving = 0; 708c3f9bad2Sdanielk1977 theSelect.pOrderBy = 0; 709c3f9bad2Sdanielk1977 theSelect.op = TK_SELECT; /* ?? */ 710c3f9bad2Sdanielk1977 theSelect.pPrior = 0; 711c3f9bad2Sdanielk1977 theSelect.nLimit = -1; 712c3f9bad2Sdanielk1977 theSelect.nOffset = -1; 713c3f9bad2Sdanielk1977 theSelect.zSelect = 0; 714c3f9bad2Sdanielk1977 theSelect.base = 0; 715c3f9bad2Sdanielk1977 716c3f9bad2Sdanielk1977 v = sqliteGetVdbe(pParse); 717c3f9bad2Sdanielk1977 assert(v); 718cabb0819Sdrh sqliteBeginWriteOperation(pParse, 1, 0); 719c3f9bad2Sdanielk1977 720c3f9bad2Sdanielk1977 /* Allocate temp tables */ 721c3f9bad2Sdanielk1977 oldIdx = pParse->nTab++; 722c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0); 723c3f9bad2Sdanielk1977 if( pChanges ){ 724c3f9bad2Sdanielk1977 newIdx = pParse->nTab++; 725c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0); 726c3f9bad2Sdanielk1977 } 727c3f9bad2Sdanielk1977 728c3f9bad2Sdanielk1977 /* Snapshot the view */ 729c3f9bad2Sdanielk1977 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){ 730c3f9bad2Sdanielk1977 goto trigger_cleanup; 731c3f9bad2Sdanielk1977 } 732c3f9bad2Sdanielk1977 733c3f9bad2Sdanielk1977 /* loop thru the view snapshot, executing triggers for each row */ 734c3f9bad2Sdanielk1977 endOfLoop = sqliteVdbeMakeLabel(v); 735c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop); 736c3f9bad2Sdanielk1977 737c3f9bad2Sdanielk1977 /* Loop thru the view snapshot, executing triggers for each row */ 738c3f9bad2Sdanielk1977 startOfLoop = sqliteVdbeCurrentAddr(v); 739c3f9bad2Sdanielk1977 740c3f9bad2Sdanielk1977 /* Build the updated row if required */ 741c3f9bad2Sdanielk1977 if( pChanges ){ 7421d1f3055Sdrh int ii; 743c3f9bad2Sdanielk1977 744c3f9bad2Sdanielk1977 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); 745c3f9bad2Sdanielk1977 if( aXRef==0 ) goto trigger_cleanup; 746633ed08dSdanielk1977 for(ii = 0; ii < pTab->nCol; ii++){ 747c3f9bad2Sdanielk1977 aXRef[ii] = -1; 748633ed08dSdanielk1977 } 749c3f9bad2Sdanielk1977 750c3f9bad2Sdanielk1977 for(ii=0; ii<pChanges->nExpr; ii++){ 751c3f9bad2Sdanielk1977 int jj; 752c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0, 753f29ce559Sdanielk1977 pChanges->a[ii].pExpr) ){ 754c3f9bad2Sdanielk1977 goto trigger_cleanup; 755f29ce559Sdanielk1977 } 756c3f9bad2Sdanielk1977 757c3f9bad2Sdanielk1977 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) ) 758c3f9bad2Sdanielk1977 goto trigger_cleanup; 759c3f9bad2Sdanielk1977 760c3f9bad2Sdanielk1977 for(jj=0; jj<pTab->nCol; jj++){ 761c3f9bad2Sdanielk1977 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){ 762c3f9bad2Sdanielk1977 aXRef[jj] = ii; 763c3f9bad2Sdanielk1977 break; 764c3f9bad2Sdanielk1977 } 765c3f9bad2Sdanielk1977 } 766c3f9bad2Sdanielk1977 if( jj>=pTab->nCol ){ 767c3f9bad2Sdanielk1977 sqliteSetString(&pParse->zErrMsg, "no such column: ", 768c3f9bad2Sdanielk1977 pChanges->a[ii].zName, 0); 769c3f9bad2Sdanielk1977 pParse->nErr++; 770c3f9bad2Sdanielk1977 goto trigger_cleanup; 771c3f9bad2Sdanielk1977 } 772c3f9bad2Sdanielk1977 } 773c3f9bad2Sdanielk1977 774c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Integer, 13, 0); 775c3f9bad2Sdanielk1977 776633ed08dSdanielk1977 for(ii = 0; ii<pTab->nCol; ii++){ 777633ed08dSdanielk1977 if( aXRef[ii] < 0 ){ 778c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii); 779633ed08dSdanielk1977 }else{ 780c3f9bad2Sdanielk1977 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr); 781633ed08dSdanielk1977 } 782633ed08dSdanielk1977 } 783c3f9bad2Sdanielk1977 784c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); 785c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); 786c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0); 787c3f9bad2Sdanielk1977 788c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, 7896f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 790c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, 7916f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 792c3f9bad2Sdanielk1977 }else{ 793c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, 7946f34903eSdanielk1977 orconf, endOfLoop); 795c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, 7966f34903eSdanielk1977 orconf, endOfLoop); 797c3f9bad2Sdanielk1977 } 798c3f9bad2Sdanielk1977 799c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop); 800c3f9bad2Sdanielk1977 801c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(v, endOfLoop); 802c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 803c3f9bad2Sdanielk1977 804c3f9bad2Sdanielk1977 trigger_cleanup: 805c3f9bad2Sdanielk1977 sqliteFree(aXRef); 806c3f9bad2Sdanielk1977 sqliteExprListDelete(pChanges); 807c3f9bad2Sdanielk1977 sqliteExprDelete(pWhere); 808c3f9bad2Sdanielk1977 sqliteExprListDelete(theSelect.pEList); 809ad3cab52Sdrh sqliteSrcListDelete(theSelect.pSrc); 810c3f9bad2Sdanielk1977 sqliteExprDelete(theSelect.pWhere); 811c3f9bad2Sdanielk1977 return; 812c3f9bad2Sdanielk1977 } 813