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 */ 44633ed08dSdanielk1977 Token *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; 52c3f9bad2Sdanielk1977 53c3f9bad2Sdanielk1977 /* Check that: 549adf9ac4Sdrh ** 1. the trigger name does not already exist. 559adf9ac4Sdrh ** 2. the table (or view) does exist. 56d702fccbSdanielk1977 ** 3. that we are not trying to create a trigger on the sqlite_master table 57d702fccbSdanielk1977 ** 4. That we are not trying to create an INSTEAD OF trigger on a table. 58d702fccbSdanielk1977 ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view. 59c3f9bad2Sdanielk1977 */ 60c3f9bad2Sdanielk1977 { 61633ed08dSdanielk1977 char *tmp_str = sqliteStrNDup(pName->z, pName->n); 62633ed08dSdanielk1977 if( sqliteHashFind(&(pParse->db->trigHash), tmp_str, pName->n + 1) ){ 63c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1, 64633ed08dSdanielk1977 pName->z, pName->n, " already exists", -1, 0); 65c3f9bad2Sdanielk1977 sqliteFree(tmp_str); 66c3f9bad2Sdanielk1977 pParse->nErr++; 67c3f9bad2Sdanielk1977 goto trigger_cleanup; 68c3f9bad2Sdanielk1977 } 69c3f9bad2Sdanielk1977 sqliteFree(tmp_str); 70c3f9bad2Sdanielk1977 } 71c3f9bad2Sdanielk1977 { 72633ed08dSdanielk1977 char *tmp_str = sqliteStrNDup(pTableName->z, pTableName->n); 73e4697f5eSdrh if( tmp_str==0 ) goto trigger_cleanup; 74c3f9bad2Sdanielk1977 tab = sqliteFindTable(pParse->db, tmp_str); 75c3f9bad2Sdanielk1977 sqliteFree(tmp_str); 76c3f9bad2Sdanielk1977 if( !tab ){ 77c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1, 78633ed08dSdanielk1977 pTableName->z, pTableName->n, 0); 79c3f9bad2Sdanielk1977 pParse->nErr++; 80c3f9bad2Sdanielk1977 goto trigger_cleanup; 81c3f9bad2Sdanielk1977 } 821873cd50Sdrh if( sqliteStrICmp(tab->zName, MASTER_NAME)==0 ){ 831873cd50Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system " 841873cd50Sdrh "table: " MASTER_NAME, 0); 851873cd50Sdrh pParse->nErr++; 861873cd50Sdrh goto trigger_cleanup; 871873cd50Sdrh } 88e0bc4048Sdrh if( sqliteStrICmp(tab->zName, TEMP_MASTER_NAME)==0 ){ 89e0bc4048Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system " 90e0bc4048Sdrh "table: " TEMP_MASTER_NAME, 0); 91e0bc4048Sdrh pParse->nErr++; 92e0bc4048Sdrh goto trigger_cleanup; 93e0bc4048Sdrh } 94d702fccbSdanielk1977 if( tab->pSelect && tr_tm != TK_INSTEAD ){ 95d702fccbSdanielk1977 sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1, 96d702fccbSdanielk1977 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1 97d702fccbSdanielk1977 , pTableName->z, pTableName->n, 0); 98d702fccbSdanielk1977 goto trigger_cleanup; 99d702fccbSdanielk1977 } 100d702fccbSdanielk1977 if( !tab->pSelect && tr_tm == TK_INSTEAD ){ 101d702fccbSdanielk1977 sqliteSetNString(&pParse->zErrMsg, "cannot create INSTEAD OF", -1, 102d702fccbSdanielk1977 " trigger on table: ", -1, pTableName->z, pTableName->n, 0); 103d702fccbSdanielk1977 goto trigger_cleanup; 104d702fccbSdanielk1977 } 105d702fccbSdanielk1977 } 106d702fccbSdanielk1977 107d702fccbSdanielk1977 if (tr_tm == TK_INSTEAD){ 108d702fccbSdanielk1977 tr_tm = TK_BEFORE; 109c3f9bad2Sdanielk1977 } 110c3f9bad2Sdanielk1977 111c3f9bad2Sdanielk1977 /* Build the Trigger object */ 112c3f9bad2Sdanielk1977 nt = (Trigger*)sqliteMalloc(sizeof(Trigger)); 113e4697f5eSdrh if( nt==0 ) goto trigger_cleanup; 114633ed08dSdanielk1977 nt->name = sqliteStrNDup(pName->z, pName->n); 115633ed08dSdanielk1977 nt->table = sqliteStrNDup(pTableName->z, pTableName->n); 116e4697f5eSdrh if( sqlite_malloc_failed ) goto trigger_cleanup; 117c3f9bad2Sdanielk1977 nt->op = op; 118c3f9bad2Sdanielk1977 nt->tr_tm = tr_tm; 1194b59ab5eSdrh nt->pWhen = sqliteExprDup(pWhen); 1204b59ab5eSdrh sqliteExprDelete(pWhen); 1214b59ab5eSdrh nt->pColumns = sqliteIdListDup(pColumns); 1224b59ab5eSdrh sqliteIdListDelete(pColumns); 123c3f9bad2Sdanielk1977 nt->foreach = foreach; 124633ed08dSdanielk1977 nt->step_list = pStepList; 125c3f9bad2Sdanielk1977 126c3f9bad2Sdanielk1977 /* if we are not initializing, and this trigger is not on a TEMP table, 1279adf9ac4Sdrh ** build the sqlite_master entry 1289adf9ac4Sdrh */ 129e0bc4048Sdrh if( !pParse->initFlag ){ 130c977f7f5Sdrh static VdbeOp insertTrig[] = { 131c977f7f5Sdrh { OP_NewRecno, 0, 0, 0 }, 132c977f7f5Sdrh { OP_String, 0, 0, "trigger" }, 133e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 2: trigger name */ 134e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 3: table name */ 135c977f7f5Sdrh { OP_Integer, 0, 0, 0 }, 136e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 5: SQL */ 137c977f7f5Sdrh { OP_MakeRecord, 5, 0, 0 }, 138c977f7f5Sdrh { OP_PutIntKey, 0, 0, 0 }, 139c977f7f5Sdrh }; 140c977f7f5Sdrh int addr; 141c977f7f5Sdrh Vdbe *v; 142c3f9bad2Sdanielk1977 143c3f9bad2Sdanielk1977 /* Make an entry in the sqlite_master table */ 144c977f7f5Sdrh v = sqliteGetVdbe(pParse); 145e4697f5eSdrh if( v==0 ) goto trigger_cleanup; 146*cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 147e0bc4048Sdrh sqliteOpenMasterTable(v, tab->isTemp); 148c977f7f5Sdrh addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); 149e0bc4048Sdrh sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME, 150e0bc4048Sdrh P3_STATIC); 151e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 152e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 1534b59ab5eSdrh sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n); 154e0bc4048Sdrh if( !tab->isTemp ){ 155e0bc4048Sdrh sqliteChangeCookie(pParse->db, v); 156e0bc4048Sdrh } 157e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 158c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 159c3f9bad2Sdanielk1977 } 160c3f9bad2Sdanielk1977 161c3f9bad2Sdanielk1977 if( !pParse->explain ){ 162c3f9bad2Sdanielk1977 /* Stick it in the hash-table */ 163633ed08dSdanielk1977 sqliteHashInsert(&(pParse->db->trigHash), nt->name, pName->n + 1, nt); 164c3f9bad2Sdanielk1977 165c3f9bad2Sdanielk1977 /* Attach it to the table object */ 166c3f9bad2Sdanielk1977 nt->pNext = tab->pTrigger; 167c3f9bad2Sdanielk1977 tab->pTrigger = nt; 168c3f9bad2Sdanielk1977 return; 169c3f9bad2Sdanielk1977 }else{ 170c3f9bad2Sdanielk1977 sqliteFree(nt->name); 171c3f9bad2Sdanielk1977 sqliteFree(nt->table); 172c3f9bad2Sdanielk1977 sqliteFree(nt); 173c3f9bad2Sdanielk1977 } 174c3f9bad2Sdanielk1977 175c3f9bad2Sdanielk1977 trigger_cleanup: 176c3f9bad2Sdanielk1977 177633ed08dSdanielk1977 sqliteIdListDelete(pColumns); 178c3f9bad2Sdanielk1977 sqliteExprDelete(pWhen); 1794b59ab5eSdrh sqliteDeleteTriggerStep(pStepList); 180c3f9bad2Sdanielk1977 } 1814b59ab5eSdrh 1824b59ab5eSdrh /* 1834b59ab5eSdrh ** Make a copy of all components of the given trigger step. This has 1844b59ab5eSdrh ** the effect of copying all Expr.token.z values into memory obtained 1854b59ab5eSdrh ** from sqliteMalloc(). As initially created, the Expr.token.z values 1864b59ab5eSdrh ** all point to the input string that was fed to the parser. But that 1874b59ab5eSdrh ** string is ephemeral - it will go away as soon as the sqlite_exec() 1884b59ab5eSdrh ** call that started the parser exits. This routine makes a persistent 1894b59ab5eSdrh ** copy of all the Expr.token.z strings so that the TriggerStep structure 1904b59ab5eSdrh ** will be valid even after the sqlite_exec() call returns. 1914b59ab5eSdrh */ 1924b59ab5eSdrh static void sqlitePersistTriggerStep(TriggerStep *p){ 1934b59ab5eSdrh if( p->target.z ){ 1944b59ab5eSdrh p->target.z = sqliteStrNDup(p->target.z, p->target.n); 1954b59ab5eSdrh p->target.dyn = 1; 1964b59ab5eSdrh } 1974b59ab5eSdrh if( p->pSelect ){ 1984b59ab5eSdrh Select *pNew = sqliteSelectDup(p->pSelect); 1994b59ab5eSdrh sqliteSelectDelete(p->pSelect); 2004b59ab5eSdrh p->pSelect = pNew; 2014b59ab5eSdrh } 2024b59ab5eSdrh if( p->pWhere ){ 2034b59ab5eSdrh Expr *pNew = sqliteExprDup(p->pWhere); 2044b59ab5eSdrh sqliteExprDelete(p->pWhere); 2054b59ab5eSdrh p->pWhere = pNew; 2064b59ab5eSdrh } 2074b59ab5eSdrh if( p->pExprList ){ 2084b59ab5eSdrh ExprList *pNew = sqliteExprListDup(p->pExprList); 2094b59ab5eSdrh sqliteExprListDelete(p->pExprList); 2104b59ab5eSdrh p->pExprList = pNew; 2114b59ab5eSdrh } 2124b59ab5eSdrh if( p->pIdList ){ 2134b59ab5eSdrh IdList *pNew = sqliteIdListDup(p->pIdList); 2144b59ab5eSdrh sqliteIdListDelete(p->pIdList); 2154b59ab5eSdrh p->pIdList = pNew; 216c3f9bad2Sdanielk1977 } 217c3f9bad2Sdanielk1977 } 218c3f9bad2Sdanielk1977 219c977f7f5Sdrh /* 220c977f7f5Sdrh ** Turn a SELECT statement (that the pSelect parameter points to) into 221c977f7f5Sdrh ** a trigger step. Return a pointer to a TriggerStep structure. 222c977f7f5Sdrh ** 223c977f7f5Sdrh ** The parser calls this routine when it finds a SELECT statement in 224c977f7f5Sdrh ** body of a TRIGGER. 225c977f7f5Sdrh */ 226c977f7f5Sdrh TriggerStep *sqliteTriggerSelectStep(Select *pSelect){ 227633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 228e4697f5eSdrh if( pTriggerStep==0 ) return 0; 229c3f9bad2Sdanielk1977 230633ed08dSdanielk1977 pTriggerStep->op = TK_SELECT; 231633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 232633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 2334b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 234c3f9bad2Sdanielk1977 235633ed08dSdanielk1977 return pTriggerStep; 236c3f9bad2Sdanielk1977 } 237c3f9bad2Sdanielk1977 238c977f7f5Sdrh /* 239c977f7f5Sdrh ** Build a trigger step out of an INSERT statement. Return a pointer 240c977f7f5Sdrh ** to the new trigger step. 241c977f7f5Sdrh ** 242c977f7f5Sdrh ** The parser calls this routine when it sees an INSERT inside the 243c977f7f5Sdrh ** body of a trigger. 244c977f7f5Sdrh */ 245633ed08dSdanielk1977 TriggerStep *sqliteTriggerInsertStep( 246c977f7f5Sdrh Token *pTableName, /* Name of the table into which we insert */ 247c977f7f5Sdrh IdList *pColumn, /* List of columns in pTableName to insert into */ 248c977f7f5Sdrh ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ 249c977f7f5Sdrh Select *pSelect, /* A SELECT statement that supplies values */ 250c977f7f5Sdrh int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ 251633ed08dSdanielk1977 ){ 252633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 253e4697f5eSdrh if( pTriggerStep==0 ) return 0; 254c3f9bad2Sdanielk1977 255633ed08dSdanielk1977 assert(pEList == 0 || pSelect == 0); 256633ed08dSdanielk1977 assert(pEList != 0 || pSelect != 0); 257c3f9bad2Sdanielk1977 258633ed08dSdanielk1977 pTriggerStep->op = TK_INSERT; 259633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 260633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 261633ed08dSdanielk1977 pTriggerStep->pIdList = pColumn; 262633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 263633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2644b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 265c3f9bad2Sdanielk1977 266633ed08dSdanielk1977 return pTriggerStep; 267c3f9bad2Sdanielk1977 } 268c3f9bad2Sdanielk1977 269c977f7f5Sdrh /* 270c977f7f5Sdrh ** Construct a trigger step that implements an UPDATE statement and return 271c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 272c977f7f5Sdrh ** sees an UPDATE statement inside the body of a CREATE TRIGGER. 273c977f7f5Sdrh */ 274633ed08dSdanielk1977 TriggerStep *sqliteTriggerUpdateStep( 275c977f7f5Sdrh Token *pTableName, /* Name of the table to be updated */ 276c977f7f5Sdrh ExprList *pEList, /* The SET clause: list of column and new values */ 277c977f7f5Sdrh Expr *pWhere, /* The WHERE clause */ 278c977f7f5Sdrh int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ 279c977f7f5Sdrh ){ 280633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 281e4697f5eSdrh if( pTriggerStep==0 ) return 0; 282c3f9bad2Sdanielk1977 283633ed08dSdanielk1977 pTriggerStep->op = TK_UPDATE; 284633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 285633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 286633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 287633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2884b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 289c3f9bad2Sdanielk1977 290633ed08dSdanielk1977 return pTriggerStep; 291c3f9bad2Sdanielk1977 } 292c3f9bad2Sdanielk1977 293c977f7f5Sdrh /* 294c977f7f5Sdrh ** Construct a trigger step that implements a DELETE statement and return 295c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 296c977f7f5Sdrh ** sees a DELETE statement inside the body of a CREATE TRIGGER. 297c977f7f5Sdrh */ 298c977f7f5Sdrh TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){ 299633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 300e4697f5eSdrh if( pTriggerStep==0 ) return 0; 301c3f9bad2Sdanielk1977 302633ed08dSdanielk1977 pTriggerStep->op = TK_DELETE; 303633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 304633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 305633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 3064b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 307c3f9bad2Sdanielk1977 308633ed08dSdanielk1977 return pTriggerStep; 309c3f9bad2Sdanielk1977 } 310c3f9bad2Sdanielk1977 311c3f9bad2Sdanielk1977 /* 312633ed08dSdanielk1977 ** Recursively delete a Trigger structure 313c3f9bad2Sdanielk1977 */ 3141d1f3055Sdrh void sqliteDeleteTrigger(Trigger *pTrigger){ 3154b59ab5eSdrh sqliteDeleteTriggerStep(pTrigger->step_list); 316633ed08dSdanielk1977 sqliteFree(pTrigger->name); 317633ed08dSdanielk1977 sqliteFree(pTrigger->table); 318633ed08dSdanielk1977 sqliteExprDelete(pTrigger->pWhen); 319633ed08dSdanielk1977 sqliteIdListDelete(pTrigger->pColumns); 320633ed08dSdanielk1977 sqliteFree(pTrigger); 321633ed08dSdanielk1977 } 322633ed08dSdanielk1977 323633ed08dSdanielk1977 /* 324633ed08dSdanielk1977 * This function is called to drop a trigger from the database schema. 325633ed08dSdanielk1977 * 326633ed08dSdanielk1977 * This may be called directly from the parser, or from within 327633ed08dSdanielk1977 * sqliteDropTable(). In the latter case the "nested" argument is true. 328633ed08dSdanielk1977 * 329633ed08dSdanielk1977 * Note that this function does not delete the trigger entirely. Instead it 330633ed08dSdanielk1977 * removes it from the internal schema and places it in the trigDrop hash 331633ed08dSdanielk1977 * table. This is so that the trigger can be restored into the database schema 332633ed08dSdanielk1977 * if the transaction is rolled back. 333633ed08dSdanielk1977 */ 334e0bc4048Sdrh void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){ 335633ed08dSdanielk1977 char *zName; 336633ed08dSdanielk1977 Trigger *pTrigger; 337633ed08dSdanielk1977 Table *pTable; 338e0bc4048Sdrh Vdbe *v; 339633ed08dSdanielk1977 340633ed08dSdanielk1977 zName = sqliteStrNDup(pName->z, pName->n); 341c3f9bad2Sdanielk1977 342c3f9bad2Sdanielk1977 /* ensure that the trigger being dropped exists */ 343633ed08dSdanielk1977 pTrigger = sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1); 344633ed08dSdanielk1977 if( !pTrigger ){ 345c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1, 346633ed08dSdanielk1977 zName, -1, 0); 347633ed08dSdanielk1977 sqliteFree(zName); 348c3f9bad2Sdanielk1977 return; 349c3f9bad2Sdanielk1977 } 350c3f9bad2Sdanielk1977 351c3f9bad2Sdanielk1977 /* 352e0bc4048Sdrh * If this is not an "explain", then delete the trigger structure. 353c3f9bad2Sdanielk1977 */ 354c3f9bad2Sdanielk1977 if( !pParse->explain ){ 355633ed08dSdanielk1977 pTable = sqliteFindTable(pParse->db, pTrigger->table); 356633ed08dSdanielk1977 assert(pTable); 357633ed08dSdanielk1977 if( pTable->pTrigger == pTrigger ){ 358633ed08dSdanielk1977 pTable->pTrigger = pTrigger->pNext; 359633ed08dSdanielk1977 }else{ 360633ed08dSdanielk1977 Trigger *cc = pTable->pTrigger; 361c3f9bad2Sdanielk1977 while( cc ){ 362633ed08dSdanielk1977 if( cc->pNext == pTrigger ){ 363c3f9bad2Sdanielk1977 cc->pNext = cc->pNext->pNext; 364c3f9bad2Sdanielk1977 break; 365c3f9bad2Sdanielk1977 } 366c3f9bad2Sdanielk1977 cc = cc->pNext; 367c3f9bad2Sdanielk1977 } 368c3f9bad2Sdanielk1977 assert(cc); 369c3f9bad2Sdanielk1977 } 370e0bc4048Sdrh sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL); 371e0bc4048Sdrh sqliteDeleteTrigger(pTrigger); 372c3f9bad2Sdanielk1977 } 373c3f9bad2Sdanielk1977 374e0bc4048Sdrh /* Generate code to destroy the database record of the trigger. 375e0bc4048Sdrh */ 376e0bc4048Sdrh if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){ 377c3f9bad2Sdanielk1977 int base; 378c3f9bad2Sdanielk1977 static VdbeOp dropTrigger[] = { 379e0bc4048Sdrh { OP_Rewind, 0, ADDR(8), 0}, 380e0bc4048Sdrh { OP_String, 0, 0, 0}, /* 1 */ 381c3f9bad2Sdanielk1977 { OP_MemStore, 1, 1, 0}, 382e0bc4048Sdrh { OP_MemLoad, 1, 0, 0}, /* 3 */ 383c3f9bad2Sdanielk1977 { OP_Column, 0, 1, 0}, 384e0bc4048Sdrh { OP_Ne, 0, ADDR(7), 0}, 385c3f9bad2Sdanielk1977 { OP_Delete, 0, 0, 0}, 386e0bc4048Sdrh { OP_Next, 0, ADDR(3), 0}, /* 7 */ 387c3f9bad2Sdanielk1977 }; 388c3f9bad2Sdanielk1977 389*cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 390e0bc4048Sdrh sqliteOpenMasterTable(v, pTable->isTemp); 391e0bc4048Sdrh base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); 392e0bc4048Sdrh sqliteVdbeChangeP3(v, base+1, zName, 0); 393e0bc4048Sdrh if( !pTable->isTemp ){ 394e0bc4048Sdrh sqliteChangeCookie(pParse->db, v); 395dc379456Sdrh } 396e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 397c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 398c3f9bad2Sdanielk1977 } 399c3f9bad2Sdanielk1977 400633ed08dSdanielk1977 sqliteFree(zName); 401c3f9bad2Sdanielk1977 } 402c3f9bad2Sdanielk1977 403c977f7f5Sdrh /* 404c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement. Each entry 405c977f7f5Sdrh ** in pEList is of the format <id>=<expr>. If any of the entries 406c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList, 407c977f7f5Sdrh ** then return TRUE. If pIdList==NULL, then it is considered a 408c977f7f5Sdrh ** wildcard that matches anything. Likewise if pEList==NULL then 409c977f7f5Sdrh ** it matches anything so always return true. Return false only 410c977f7f5Sdrh ** if there is no match. 411c977f7f5Sdrh */ 412c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){ 413ad2d8307Sdrh int e; 414ad2d8307Sdrh if( !pIdList || !pEList ) return 1; 415f29ce559Sdanielk1977 for(e=0; e<pEList->nExpr; e++){ 416ad2d8307Sdrh if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; 417f29ce559Sdanielk1977 } 418c3f9bad2Sdanielk1977 return 0; 419c3f9bad2Sdanielk1977 } 420c3f9bad2Sdanielk1977 421c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for 422c3f9bad2Sdanielk1977 * for triggers, even if there are no triggers to code. This is used to test 423c3f9bad2Sdanielk1977 * how much overhead the triggers algorithm is causing. 424c3f9bad2Sdanielk1977 * 425c3f9bad2Sdanielk1977 * This flag can be set or cleared using the "trigger_overhead_test" pragma. 426c3f9bad2Sdanielk1977 * The pragma is not documented since it is not really part of the interface 427c3f9bad2Sdanielk1977 * to SQLite, just the test procedure. 428c3f9bad2Sdanielk1977 */ 429c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0; 430c3f9bad2Sdanielk1977 431c3f9bad2Sdanielk1977 /* 432c3f9bad2Sdanielk1977 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already 433c3f9bad2Sdanielk1977 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is 434c3f9bad2Sdanielk1977 * found in the list specified as pTrigger. 435c3f9bad2Sdanielk1977 */ 436c3f9bad2Sdanielk1977 int sqliteTriggersExist( 437c977f7f5Sdrh Parse *pParse, /* Used to check for recursive triggers */ 438c977f7f5Sdrh Trigger *pTrigger, /* A list of triggers associated with a table */ 439c3f9bad2Sdanielk1977 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ 440c3f9bad2Sdanielk1977 int tr_tm, /* one of TK_BEFORE, TK_AFTER */ 441c3f9bad2Sdanielk1977 int foreach, /* one of TK_ROW or TK_STATEMENT */ 442c977f7f5Sdrh ExprList *pChanges /* Columns that change in an UPDATE statement */ 443c977f7f5Sdrh ){ 444633ed08dSdanielk1977 Trigger * pTriggerCursor; 445c3f9bad2Sdanielk1977 446633ed08dSdanielk1977 if( always_code_trigger_setup ){ 447633ed08dSdanielk1977 return 1; 448633ed08dSdanielk1977 } 449c3f9bad2Sdanielk1977 450633ed08dSdanielk1977 pTriggerCursor = pTrigger; 451633ed08dSdanielk1977 while( pTriggerCursor ){ 452633ed08dSdanielk1977 if( pTriggerCursor->op == op && 453633ed08dSdanielk1977 pTriggerCursor->tr_tm == tr_tm && 454633ed08dSdanielk1977 pTriggerCursor->foreach == foreach && 455633ed08dSdanielk1977 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){ 456c3f9bad2Sdanielk1977 TriggerStack * ss; 457c3f9bad2Sdanielk1977 ss = pParse->trigStack; 458f29ce559Sdanielk1977 while( ss && ss->pTrigger != pTrigger ){ 459f29ce559Sdanielk1977 ss = ss->pNext; 460f29ce559Sdanielk1977 } 461c3f9bad2Sdanielk1977 if( !ss )return 1; 462c3f9bad2Sdanielk1977 } 463633ed08dSdanielk1977 pTriggerCursor = pTriggerCursor->pNext; 464c3f9bad2Sdanielk1977 } 465c3f9bad2Sdanielk1977 466c3f9bad2Sdanielk1977 return 0; 467c3f9bad2Sdanielk1977 } 468c3f9bad2Sdanielk1977 469c977f7f5Sdrh /* 470c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a 471c977f7f5Sdrh ** trigger. 472c977f7f5Sdrh */ 473c3f9bad2Sdanielk1977 static int codeTriggerProgram( 474c977f7f5Sdrh Parse *pParse, /* The parser context */ 475c977f7f5Sdrh TriggerStep *pStepList, /* List of statements inside the trigger body */ 476c977f7f5Sdrh int orconfin /* Conflict algorithm. (OE_Abort, etc) */ 477633ed08dSdanielk1977 ){ 478633ed08dSdanielk1977 TriggerStep * pTriggerStep = pStepList; 479c3f9bad2Sdanielk1977 int orconf; 480c3f9bad2Sdanielk1977 481633ed08dSdanielk1977 while( pTriggerStep ){ 482c3f9bad2Sdanielk1977 int saveNTab = pParse->nTab; 483633ed08dSdanielk1977 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; 484c3f9bad2Sdanielk1977 pParse->trigStack->orconf = orconf; 485633ed08dSdanielk1977 switch( pTriggerStep->op ){ 486c3f9bad2Sdanielk1977 case TK_SELECT: { 4876f34903eSdanielk1977 Select * ss = sqliteSelectDup(pTriggerStep->pSelect); 4886f34903eSdanielk1977 assert(ss); 4896f34903eSdanielk1977 assert(ss->pSrc); 4906f34903eSdanielk1977 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0); 4916f34903eSdanielk1977 sqliteSelectDelete(ss); 492c3f9bad2Sdanielk1977 break; 493c3f9bad2Sdanielk1977 } 494c3f9bad2Sdanielk1977 case TK_UPDATE: { 495bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 496633ed08dSdanielk1977 sqliteUpdate(pParse, &pTriggerStep->target, 497633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 498633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere), orconf); 499bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 500c3f9bad2Sdanielk1977 break; 501c3f9bad2Sdanielk1977 } 502c3f9bad2Sdanielk1977 case TK_INSERT: { 503633ed08dSdanielk1977 sqliteInsert(pParse, &pTriggerStep->target, 504633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 505633ed08dSdanielk1977 sqliteSelectDup(pTriggerStep->pSelect), 506633ed08dSdanielk1977 sqliteIdListDup(pTriggerStep->pIdList), orconf); 507c3f9bad2Sdanielk1977 break; 508c3f9bad2Sdanielk1977 } 509c3f9bad2Sdanielk1977 case TK_DELETE: { 510bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 511633ed08dSdanielk1977 sqliteDeleteFrom(pParse, &pTriggerStep->target, 512633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere)); 513bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 514c3f9bad2Sdanielk1977 break; 515c3f9bad2Sdanielk1977 } 516c3f9bad2Sdanielk1977 default: 517c3f9bad2Sdanielk1977 assert(0); 518c3f9bad2Sdanielk1977 } 519c3f9bad2Sdanielk1977 pParse->nTab = saveNTab; 520633ed08dSdanielk1977 pTriggerStep = pTriggerStep->pNext; 521c3f9bad2Sdanielk1977 } 522c3f9bad2Sdanielk1977 523c3f9bad2Sdanielk1977 return 0; 524c3f9bad2Sdanielk1977 } 525c3f9bad2Sdanielk1977 526633ed08dSdanielk1977 /* 527633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers. 528633ed08dSdanielk1977 ** 529633ed08dSdanielk1977 ** When the code that this function generates is executed, the following 530633ed08dSdanielk1977 ** must be true: 531c977f7f5Sdrh ** 532c977f7f5Sdrh ** 1. No cursors may be open in the main database. (But newIdx and oldIdx 533c977f7f5Sdrh ** can be indices of cursors in temporary tables. See below.) 534c977f7f5Sdrh ** 535633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then 536633ed08dSdanielk1977 ** a temporary vdbe cursor (index newIdx) must be open and pointing at 537633ed08dSdanielk1977 ** a row containing values to be substituted for new.* expressions in the 538633ed08dSdanielk1977 ** trigger program(s). 539c977f7f5Sdrh ** 540633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then 541633ed08dSdanielk1977 ** a temporary vdbe cursor (index oldIdx) must be open and pointing at 542633ed08dSdanielk1977 ** a row containing values to be substituted for old.* expressions in the 543633ed08dSdanielk1977 ** trigger program(s). 544633ed08dSdanielk1977 ** 545633ed08dSdanielk1977 */ 546c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger( 547c3f9bad2Sdanielk1977 Parse *pParse, /* Parse context */ 548c3f9bad2Sdanielk1977 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ 549633ed08dSdanielk1977 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ 550c3f9bad2Sdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER */ 551633ed08dSdanielk1977 Table *pTab, /* The table to code triggers from */ 552633ed08dSdanielk1977 int newIdx, /* The indice of the "new" row to access */ 553633ed08dSdanielk1977 int oldIdx, /* The indice of the "old" row to access */ 5546f34903eSdanielk1977 int orconf, /* ON CONFLICT policy */ 5556f34903eSdanielk1977 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ 556c977f7f5Sdrh ){ 557c3f9bad2Sdanielk1977 Trigger * pTrigger; 558c3f9bad2Sdanielk1977 TriggerStack * pTriggerStack; 559c3f9bad2Sdanielk1977 560c3f9bad2Sdanielk1977 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); 561c3f9bad2Sdanielk1977 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER); 562c3f9bad2Sdanielk1977 563633ed08dSdanielk1977 assert(newIdx != -1 || oldIdx != -1); 564c3f9bad2Sdanielk1977 565633ed08dSdanielk1977 pTrigger = pTab->pTrigger; 566c3f9bad2Sdanielk1977 while( pTrigger ){ 567c3f9bad2Sdanielk1977 int fire_this = 0; 568c3f9bad2Sdanielk1977 569c3f9bad2Sdanielk1977 /* determine whether we should code this trigger */ 570c3f9bad2Sdanielk1977 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 571c3f9bad2Sdanielk1977 pTrigger->foreach == TK_ROW ){ 572c3f9bad2Sdanielk1977 fire_this = 1; 573c3f9bad2Sdanielk1977 pTriggerStack = pParse->trigStack; 574c3f9bad2Sdanielk1977 while( pTriggerStack ){ 575f29ce559Sdanielk1977 if( pTriggerStack->pTrigger == pTrigger ){ 576f29ce559Sdanielk1977 fire_this = 0; 577f29ce559Sdanielk1977 } 578c3f9bad2Sdanielk1977 pTriggerStack = pTriggerStack->pNext; 579c3f9bad2Sdanielk1977 } 580c3f9bad2Sdanielk1977 if( op == TK_UPDATE && pTrigger->pColumns && 581f29ce559Sdanielk1977 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){ 582c3f9bad2Sdanielk1977 fire_this = 0; 583c3f9bad2Sdanielk1977 } 584f29ce559Sdanielk1977 } 585c3f9bad2Sdanielk1977 586e4697f5eSdrh if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){ 587c3f9bad2Sdanielk1977 int endTrigger; 588ad3cab52Sdrh SrcList dummyTablist; 589c3f9bad2Sdanielk1977 Expr * whenExpr; 590c3f9bad2Sdanielk1977 591ad3cab52Sdrh dummyTablist.nSrc = 0; 592c3f9bad2Sdanielk1977 dummyTablist.a = 0; 593c3f9bad2Sdanielk1977 594c3f9bad2Sdanielk1977 /* Push an entry on to the trigger stack */ 595c3f9bad2Sdanielk1977 pTriggerStack->pTrigger = pTrigger; 596633ed08dSdanielk1977 pTriggerStack->newIdx = newIdx; 597633ed08dSdanielk1977 pTriggerStack->oldIdx = oldIdx; 598633ed08dSdanielk1977 pTriggerStack->pTab = pTab; 599c3f9bad2Sdanielk1977 pTriggerStack->pNext = pParse->trigStack; 6006f34903eSdanielk1977 pTriggerStack->ignoreJump = ignoreJump; 601c3f9bad2Sdanielk1977 pParse->trigStack = pTriggerStack; 602c3f9bad2Sdanielk1977 603c3f9bad2Sdanielk1977 /* code the WHEN clause */ 604c3f9bad2Sdanielk1977 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); 605c3f9bad2Sdanielk1977 whenExpr = sqliteExprDup(pTrigger->pWhen); 606c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ 607c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 608c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 609c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 610c3f9bad2Sdanielk1977 return 1; 611c3f9bad2Sdanielk1977 } 612f5905aa7Sdrh sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); 613c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 614c3f9bad2Sdanielk1977 615633ed08dSdanielk1977 codeTriggerProgram(pParse, pTrigger->step_list, orconf); 616c3f9bad2Sdanielk1977 617c3f9bad2Sdanielk1977 /* Pop the entry off the trigger stack */ 618c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 619c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 620c3f9bad2Sdanielk1977 621c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger); 622c3f9bad2Sdanielk1977 } 623c3f9bad2Sdanielk1977 pTrigger = pTrigger->pNext; 624c3f9bad2Sdanielk1977 } 625c3f9bad2Sdanielk1977 626c3f9bad2Sdanielk1977 return 0; 627c3f9bad2Sdanielk1977 } 628c3f9bad2Sdanielk1977 629c3f9bad2Sdanielk1977 /* 630633ed08dSdanielk1977 * This function is called to code ON UPDATE and ON DELETE triggers on 631633ed08dSdanielk1977 * views. 632633ed08dSdanielk1977 * 633633ed08dSdanielk1977 * This function deletes the data pointed at by the pWhere and pChanges 634633ed08dSdanielk1977 * arguments before it completes. 635c3f9bad2Sdanielk1977 */ 636633ed08dSdanielk1977 void sqliteViewTriggers( 637633ed08dSdanielk1977 Parse *pParse, 638633ed08dSdanielk1977 Table *pTab, /* The view to code triggers on */ 639633ed08dSdanielk1977 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/ 640633ed08dSdanielk1977 int orconf, /* The ON CONFLICT policy specified as part of the 641633ed08dSdanielk1977 statement causing these triggers */ 642633ed08dSdanielk1977 ExprList *pChanges /* If this is an statement causing triggers to fire 643633ed08dSdanielk1977 is an UPDATE, then this list holds the columns 644633ed08dSdanielk1977 to update and the expressions to update them to. 645633ed08dSdanielk1977 See comments for sqliteUpdate(). */ 646633ed08dSdanielk1977 ){ 647c3f9bad2Sdanielk1977 int oldIdx = -1; 648c3f9bad2Sdanielk1977 int newIdx = -1; 649c3f9bad2Sdanielk1977 int *aXRef = 0; 650c3f9bad2Sdanielk1977 Vdbe *v; 651c3f9bad2Sdanielk1977 int endOfLoop; 652c3f9bad2Sdanielk1977 int startOfLoop; 653c3f9bad2Sdanielk1977 Select theSelect; 654c3f9bad2Sdanielk1977 Token tblNameToken; 655c3f9bad2Sdanielk1977 656c3f9bad2Sdanielk1977 assert(pTab->pSelect); 657c3f9bad2Sdanielk1977 658c3f9bad2Sdanielk1977 tblNameToken.z = pTab->zName; 659c3f9bad2Sdanielk1977 tblNameToken.n = strlen(pTab->zName); 660c3f9bad2Sdanielk1977 661c3f9bad2Sdanielk1977 theSelect.isDistinct = 0; 662c3f9bad2Sdanielk1977 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0); 663ad3cab52Sdrh theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken); 664c3f9bad2Sdanielk1977 theSelect.pWhere = pWhere; pWhere = 0; 665c3f9bad2Sdanielk1977 theSelect.pGroupBy = 0; 666c3f9bad2Sdanielk1977 theSelect.pHaving = 0; 667c3f9bad2Sdanielk1977 theSelect.pOrderBy = 0; 668c3f9bad2Sdanielk1977 theSelect.op = TK_SELECT; /* ?? */ 669c3f9bad2Sdanielk1977 theSelect.pPrior = 0; 670c3f9bad2Sdanielk1977 theSelect.nLimit = -1; 671c3f9bad2Sdanielk1977 theSelect.nOffset = -1; 672c3f9bad2Sdanielk1977 theSelect.zSelect = 0; 673c3f9bad2Sdanielk1977 theSelect.base = 0; 674c3f9bad2Sdanielk1977 675c3f9bad2Sdanielk1977 v = sqliteGetVdbe(pParse); 676c3f9bad2Sdanielk1977 assert(v); 677*cabb0819Sdrh sqliteBeginWriteOperation(pParse, 1, 0); 678c3f9bad2Sdanielk1977 679c3f9bad2Sdanielk1977 /* Allocate temp tables */ 680c3f9bad2Sdanielk1977 oldIdx = pParse->nTab++; 681c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0); 682c3f9bad2Sdanielk1977 if( pChanges ){ 683c3f9bad2Sdanielk1977 newIdx = pParse->nTab++; 684c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0); 685c3f9bad2Sdanielk1977 } 686c3f9bad2Sdanielk1977 687c3f9bad2Sdanielk1977 /* Snapshot the view */ 688c3f9bad2Sdanielk1977 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){ 689c3f9bad2Sdanielk1977 goto trigger_cleanup; 690c3f9bad2Sdanielk1977 } 691c3f9bad2Sdanielk1977 692c3f9bad2Sdanielk1977 /* loop thru the view snapshot, executing triggers for each row */ 693c3f9bad2Sdanielk1977 endOfLoop = sqliteVdbeMakeLabel(v); 694c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop); 695c3f9bad2Sdanielk1977 696c3f9bad2Sdanielk1977 /* Loop thru the view snapshot, executing triggers for each row */ 697c3f9bad2Sdanielk1977 startOfLoop = sqliteVdbeCurrentAddr(v); 698c3f9bad2Sdanielk1977 699c3f9bad2Sdanielk1977 /* Build the updated row if required */ 700c3f9bad2Sdanielk1977 if( pChanges ){ 7011d1f3055Sdrh int ii; 702c3f9bad2Sdanielk1977 703c3f9bad2Sdanielk1977 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); 704c3f9bad2Sdanielk1977 if( aXRef==0 ) goto trigger_cleanup; 705633ed08dSdanielk1977 for(ii = 0; ii < pTab->nCol; ii++){ 706c3f9bad2Sdanielk1977 aXRef[ii] = -1; 707633ed08dSdanielk1977 } 708c3f9bad2Sdanielk1977 709c3f9bad2Sdanielk1977 for(ii=0; ii<pChanges->nExpr; ii++){ 710c3f9bad2Sdanielk1977 int jj; 711c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0, 712f29ce559Sdanielk1977 pChanges->a[ii].pExpr) ){ 713c3f9bad2Sdanielk1977 goto trigger_cleanup; 714f29ce559Sdanielk1977 } 715c3f9bad2Sdanielk1977 716c3f9bad2Sdanielk1977 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) ) 717c3f9bad2Sdanielk1977 goto trigger_cleanup; 718c3f9bad2Sdanielk1977 719c3f9bad2Sdanielk1977 for(jj=0; jj<pTab->nCol; jj++){ 720c3f9bad2Sdanielk1977 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){ 721c3f9bad2Sdanielk1977 aXRef[jj] = ii; 722c3f9bad2Sdanielk1977 break; 723c3f9bad2Sdanielk1977 } 724c3f9bad2Sdanielk1977 } 725c3f9bad2Sdanielk1977 if( jj>=pTab->nCol ){ 726c3f9bad2Sdanielk1977 sqliteSetString(&pParse->zErrMsg, "no such column: ", 727c3f9bad2Sdanielk1977 pChanges->a[ii].zName, 0); 728c3f9bad2Sdanielk1977 pParse->nErr++; 729c3f9bad2Sdanielk1977 goto trigger_cleanup; 730c3f9bad2Sdanielk1977 } 731c3f9bad2Sdanielk1977 } 732c3f9bad2Sdanielk1977 733c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Integer, 13, 0); 734c3f9bad2Sdanielk1977 735633ed08dSdanielk1977 for(ii = 0; ii<pTab->nCol; ii++){ 736633ed08dSdanielk1977 if( aXRef[ii] < 0 ){ 737c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii); 738633ed08dSdanielk1977 }else{ 739c3f9bad2Sdanielk1977 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr); 740633ed08dSdanielk1977 } 741633ed08dSdanielk1977 } 742c3f9bad2Sdanielk1977 743c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); 744c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); 745c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0); 746c3f9bad2Sdanielk1977 747c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, 7486f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 749c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, 7506f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 751c3f9bad2Sdanielk1977 }else{ 752c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, 7536f34903eSdanielk1977 orconf, endOfLoop); 754c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, 7556f34903eSdanielk1977 orconf, endOfLoop); 756c3f9bad2Sdanielk1977 } 757c3f9bad2Sdanielk1977 758c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop); 759c3f9bad2Sdanielk1977 760c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(v, endOfLoop); 761c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 762c3f9bad2Sdanielk1977 763c3f9bad2Sdanielk1977 trigger_cleanup: 764c3f9bad2Sdanielk1977 sqliteFree(aXRef); 765c3f9bad2Sdanielk1977 sqliteExprListDelete(pChanges); 766c3f9bad2Sdanielk1977 sqliteExprDelete(pWhere); 767c3f9bad2Sdanielk1977 sqliteExprListDelete(theSelect.pEList); 768ad3cab52Sdrh sqliteSrcListDelete(theSelect.pSrc); 769c3f9bad2Sdanielk1977 sqliteExprDelete(theSelect.pWhere); 770c3f9bad2Sdanielk1977 return; 771c3f9bad2Sdanielk1977 } 772