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 ); 64d24cc427Sdrh tab = sqliteTableNameToTable(pParse, pTableName->a[0].zName, 65d24cc427Sdrh pTableName->a[0].zDatabase); 66d24cc427Sdrh if( !tab ){ 67d24cc427Sdrh goto trigger_cleanup; 68d24cc427Sdrh } 69d24cc427Sdrh if( tab->iDb>=2 ){ 70d24cc427Sdrh sqliteSetString(&pParse->zErrMsg, "triggers may not be added to " 71d24cc427Sdrh "auxiliary database \"", db->aDb[tab->iDb].zName, "\"", 0); 72d24cc427Sdrh pParse->nErr++; 73d24cc427Sdrh goto trigger_cleanup; 74d24cc427Sdrh } 75d24cc427Sdrh 76e5f9c644Sdrh zName = sqliteStrNDup(pName->z, pName->n); 77d24cc427Sdrh if( sqliteHashFind(&(db->aDb[tab->iDb].trigHash), zName,pName->n+1) ){ 78c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1, 79633ed08dSdanielk1977 pName->z, pName->n, " already exists", -1, 0); 80c3f9bad2Sdanielk1977 pParse->nErr++; 81c3f9bad2Sdanielk1977 goto trigger_cleanup; 82c3f9bad2Sdanielk1977 } 83d24cc427Sdrh if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){ 84d24cc427Sdrh sqliteSetString(&pParse->zErrMsg,"cannot create trigger on system table",0); 85e0bc4048Sdrh pParse->nErr++; 86e0bc4048Sdrh goto trigger_cleanup; 87e0bc4048Sdrh } 88d702fccbSdanielk1977 if( tab->pSelect && tr_tm != TK_INSTEAD ){ 89*0951d703Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create ", 90d24cc427Sdrh (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", " trigger on view: ", 91d24cc427Sdrh pTableName->a[0].zName, 0); 92d702fccbSdanielk1977 goto trigger_cleanup; 93d702fccbSdanielk1977 } 94d702fccbSdanielk1977 if( !tab->pSelect && tr_tm == TK_INSTEAD ){ 95*0951d703Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create INSTEAD OF", 96*0951d703Sdrh " trigger on table: ", pTableName->a[0].zName, 0); 97d702fccbSdanielk1977 goto trigger_cleanup; 98d702fccbSdanielk1977 } 99e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 100e5f9c644Sdrh { 101e5f9c644Sdrh int code = SQLITE_CREATE_TRIGGER; 102d24cc427Sdrh if( tab->iDb==1 ) code = SQLITE_CREATE_TEMP_TRIGGER; 103e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){ 104ed6c8671Sdrh goto trigger_cleanup; 105ed6c8671Sdrh } 106d24cc427Sdrh if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){ 10777ad4e41Sdrh goto trigger_cleanup; 10877ad4e41Sdrh } 109d702fccbSdanielk1977 } 110e5f9c644Sdrh #endif 111d702fccbSdanielk1977 112d702fccbSdanielk1977 if (tr_tm == TK_INSTEAD){ 113d702fccbSdanielk1977 tr_tm = TK_BEFORE; 114c3f9bad2Sdanielk1977 } 115c3f9bad2Sdanielk1977 116c3f9bad2Sdanielk1977 /* Build the Trigger object */ 117c3f9bad2Sdanielk1977 nt = (Trigger*)sqliteMalloc(sizeof(Trigger)); 118e4697f5eSdrh if( nt==0 ) goto trigger_cleanup; 119e5f9c644Sdrh nt->name = zName; 120e5f9c644Sdrh zName = 0; 121d24cc427Sdrh nt->table = sqliteStrDup(pTableName->a[0].zName); 122e4697f5eSdrh if( sqlite_malloc_failed ) goto trigger_cleanup; 123d24cc427Sdrh nt->iDb = tab->iDb; 124c3f9bad2Sdanielk1977 nt->op = op; 125c3f9bad2Sdanielk1977 nt->tr_tm = tr_tm; 1264b59ab5eSdrh nt->pWhen = sqliteExprDup(pWhen); 1274b59ab5eSdrh sqliteExprDelete(pWhen); 1284b59ab5eSdrh nt->pColumns = sqliteIdListDup(pColumns); 1294b59ab5eSdrh sqliteIdListDelete(pColumns); 130c3f9bad2Sdanielk1977 nt->foreach = foreach; 131633ed08dSdanielk1977 nt->step_list = pStepList; 132c3f9bad2Sdanielk1977 133c3f9bad2Sdanielk1977 /* if we are not initializing, and this trigger is not on a TEMP table, 1349adf9ac4Sdrh ** build the sqlite_master entry 1359adf9ac4Sdrh */ 136e0bc4048Sdrh if( !pParse->initFlag ){ 137c977f7f5Sdrh static VdbeOp insertTrig[] = { 138c977f7f5Sdrh { OP_NewRecno, 0, 0, 0 }, 139c977f7f5Sdrh { OP_String, 0, 0, "trigger" }, 140e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 2: trigger name */ 141e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 3: table name */ 142c977f7f5Sdrh { OP_Integer, 0, 0, 0 }, 143e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 5: SQL */ 144c977f7f5Sdrh { OP_MakeRecord, 5, 0, 0 }, 145c977f7f5Sdrh { OP_PutIntKey, 0, 0, 0 }, 146c977f7f5Sdrh }; 147c977f7f5Sdrh int addr; 148c977f7f5Sdrh Vdbe *v; 149c3f9bad2Sdanielk1977 150c3f9bad2Sdanielk1977 /* Make an entry in the sqlite_master table */ 151c977f7f5Sdrh v = sqliteGetVdbe(pParse); 152e4697f5eSdrh if( v==0 ) goto trigger_cleanup; 153cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 154d24cc427Sdrh sqliteOpenMasterTable(v, tab->iDb); 155c977f7f5Sdrh addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); 156d24cc427Sdrh sqliteVdbeChangeP3(v, addr, tab->iDb ? TEMP_MASTER_NAME : MASTER_NAME, 157e0bc4048Sdrh P3_STATIC); 158e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 159e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 1604b59ab5eSdrh sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n); 161d24cc427Sdrh if( tab->iDb==0 ){ 162d24cc427Sdrh sqliteChangeCookie(db, v); 163e0bc4048Sdrh } 164e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 165c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 166c3f9bad2Sdanielk1977 } 167c3f9bad2Sdanielk1977 168c3f9bad2Sdanielk1977 if( !pParse->explain ){ 169c3f9bad2Sdanielk1977 /* Stick it in the hash-table */ 170d24cc427Sdrh sqliteHashInsert(&(db->aDb[nt->iDb].trigHash), nt->name, pName->n + 1, nt); 171c3f9bad2Sdanielk1977 172c3f9bad2Sdanielk1977 /* Attach it to the table object */ 173c3f9bad2Sdanielk1977 nt->pNext = tab->pTrigger; 174c3f9bad2Sdanielk1977 tab->pTrigger = nt; 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++){ 359d24cc427Sdrh if( zDb && sqliteStrICmp(db->aDb[i].zName, zDb) ) continue; 360d24cc427Sdrh pTrigger = sqliteHashFind(&(db->aDb[i].trigHash), zName, nName+1); 361d24cc427Sdrh if( pTrigger ) break; 362c3f9bad2Sdanielk1977 } 363d24cc427Sdrh if( !pTrigger ){ 364d24cc427Sdrh sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0); 365d24cc427Sdrh goto drop_trigger_cleanup; 366d24cc427Sdrh } 367d24cc427Sdrh assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb ); 368d24cc427Sdrh if( pTrigger->iDb>=2 ){ 369d24cc427Sdrh sqliteSetString(&pParse->zErrMsg, "triggers may not be removed from " 370d24cc427Sdrh "auxiliary database \"", db->aDb[pTrigger->iDb].zName, "\"", 0); 371d24cc427Sdrh pParse->nErr++; 372d24cc427Sdrh goto drop_trigger_cleanup; 373d24cc427Sdrh } 374d24cc427Sdrh pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName); 375ed6c8671Sdrh assert(pTable); 376d24cc427Sdrh assert( pTable->iDb==pTrigger->iDb ); 377e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 378e5f9c644Sdrh { 379e5f9c644Sdrh int code = SQLITE_DROP_TRIGGER; 380d24cc427Sdrh if( pTable->iDb ) code = SQLITE_DROP_TEMP_TRIGGER; 381e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) || 382d24cc427Sdrh sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0) ){ 383ed6c8671Sdrh return; 384ed6c8671Sdrh } 385e5f9c644Sdrh } 386e5f9c644Sdrh #endif 387c3f9bad2Sdanielk1977 388c3f9bad2Sdanielk1977 /* 389e0bc4048Sdrh * If this is not an "explain", then delete the trigger structure. 390c3f9bad2Sdanielk1977 */ 391c3f9bad2Sdanielk1977 if( !pParse->explain ){ 392633ed08dSdanielk1977 if( pTable->pTrigger == pTrigger ){ 393633ed08dSdanielk1977 pTable->pTrigger = pTrigger->pNext; 394633ed08dSdanielk1977 }else{ 395633ed08dSdanielk1977 Trigger *cc = pTable->pTrigger; 396c3f9bad2Sdanielk1977 while( cc ){ 397633ed08dSdanielk1977 if( cc->pNext == pTrigger ){ 398c3f9bad2Sdanielk1977 cc->pNext = cc->pNext->pNext; 399c3f9bad2Sdanielk1977 break; 400c3f9bad2Sdanielk1977 } 401c3f9bad2Sdanielk1977 cc = cc->pNext; 402c3f9bad2Sdanielk1977 } 403c3f9bad2Sdanielk1977 assert(cc); 404c3f9bad2Sdanielk1977 } 405d24cc427Sdrh sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0); 406e0bc4048Sdrh sqliteDeleteTrigger(pTrigger); 407c3f9bad2Sdanielk1977 } 408c3f9bad2Sdanielk1977 409e0bc4048Sdrh /* Generate code to destroy the database record of the trigger. 410e0bc4048Sdrh */ 411e0bc4048Sdrh if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){ 412c3f9bad2Sdanielk1977 int base; 413c3f9bad2Sdanielk1977 static VdbeOp dropTrigger[] = { 414e0bc4048Sdrh { OP_Rewind, 0, ADDR(8), 0}, 415e0bc4048Sdrh { OP_String, 0, 0, 0}, /* 1 */ 416c3f9bad2Sdanielk1977 { OP_MemStore, 1, 1, 0}, 417e0bc4048Sdrh { OP_MemLoad, 1, 0, 0}, /* 3 */ 418c3f9bad2Sdanielk1977 { OP_Column, 0, 1, 0}, 419e0bc4048Sdrh { OP_Ne, 0, ADDR(7), 0}, 420c3f9bad2Sdanielk1977 { OP_Delete, 0, 0, 0}, 421e0bc4048Sdrh { OP_Next, 0, ADDR(3), 0}, /* 7 */ 422c3f9bad2Sdanielk1977 }; 423c3f9bad2Sdanielk1977 424cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 425d24cc427Sdrh sqliteOpenMasterTable(v, pTable->iDb); 426e0bc4048Sdrh base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); 427e0bc4048Sdrh sqliteVdbeChangeP3(v, base+1, zName, 0); 428d24cc427Sdrh if( pTable->iDb==0 ){ 429d24cc427Sdrh sqliteChangeCookie(db, v); 430dc379456Sdrh } 431e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 432c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 433c3f9bad2Sdanielk1977 } 434c3f9bad2Sdanielk1977 435d24cc427Sdrh drop_trigger_cleanup: 436d24cc427Sdrh sqliteSrcListDelete(pName); 437c3f9bad2Sdanielk1977 } 438c3f9bad2Sdanielk1977 439c977f7f5Sdrh /* 440c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement. Each entry 441c977f7f5Sdrh ** in pEList is of the format <id>=<expr>. If any of the entries 442c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList, 443c977f7f5Sdrh ** then return TRUE. If pIdList==NULL, then it is considered a 444c977f7f5Sdrh ** wildcard that matches anything. Likewise if pEList==NULL then 445c977f7f5Sdrh ** it matches anything so always return true. Return false only 446c977f7f5Sdrh ** if there is no match. 447c977f7f5Sdrh */ 448c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){ 449ad2d8307Sdrh int e; 450ad2d8307Sdrh if( !pIdList || !pEList ) return 1; 451f29ce559Sdanielk1977 for(e=0; e<pEList->nExpr; e++){ 452ad2d8307Sdrh if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; 453f29ce559Sdanielk1977 } 454c3f9bad2Sdanielk1977 return 0; 455c3f9bad2Sdanielk1977 } 456c3f9bad2Sdanielk1977 457c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for 458c3f9bad2Sdanielk1977 * for triggers, even if there are no triggers to code. This is used to test 459c3f9bad2Sdanielk1977 * how much overhead the triggers algorithm is causing. 460c3f9bad2Sdanielk1977 * 461c3f9bad2Sdanielk1977 * This flag can be set or cleared using the "trigger_overhead_test" pragma. 462c3f9bad2Sdanielk1977 * The pragma is not documented since it is not really part of the interface 463c3f9bad2Sdanielk1977 * to SQLite, just the test procedure. 464c3f9bad2Sdanielk1977 */ 465c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0; 466c3f9bad2Sdanielk1977 467c3f9bad2Sdanielk1977 /* 468c3f9bad2Sdanielk1977 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already 469c3f9bad2Sdanielk1977 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is 470c3f9bad2Sdanielk1977 * found in the list specified as pTrigger. 471c3f9bad2Sdanielk1977 */ 472c3f9bad2Sdanielk1977 int sqliteTriggersExist( 473c977f7f5Sdrh Parse *pParse, /* Used to check for recursive triggers */ 474c977f7f5Sdrh Trigger *pTrigger, /* A list of triggers associated with a table */ 475c3f9bad2Sdanielk1977 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ 476c3f9bad2Sdanielk1977 int tr_tm, /* one of TK_BEFORE, TK_AFTER */ 477c3f9bad2Sdanielk1977 int foreach, /* one of TK_ROW or TK_STATEMENT */ 478c977f7f5Sdrh ExprList *pChanges /* Columns that change in an UPDATE statement */ 479c977f7f5Sdrh ){ 480633ed08dSdanielk1977 Trigger * pTriggerCursor; 481c3f9bad2Sdanielk1977 482633ed08dSdanielk1977 if( always_code_trigger_setup ){ 483633ed08dSdanielk1977 return 1; 484633ed08dSdanielk1977 } 485c3f9bad2Sdanielk1977 486633ed08dSdanielk1977 pTriggerCursor = pTrigger; 487633ed08dSdanielk1977 while( pTriggerCursor ){ 488633ed08dSdanielk1977 if( pTriggerCursor->op == op && 489633ed08dSdanielk1977 pTriggerCursor->tr_tm == tr_tm && 490633ed08dSdanielk1977 pTriggerCursor->foreach == foreach && 491633ed08dSdanielk1977 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){ 492c3f9bad2Sdanielk1977 TriggerStack * ss; 493c3f9bad2Sdanielk1977 ss = pParse->trigStack; 494f29ce559Sdanielk1977 while( ss && ss->pTrigger != pTrigger ){ 495f29ce559Sdanielk1977 ss = ss->pNext; 496f29ce559Sdanielk1977 } 497c3f9bad2Sdanielk1977 if( !ss )return 1; 498c3f9bad2Sdanielk1977 } 499633ed08dSdanielk1977 pTriggerCursor = pTriggerCursor->pNext; 500c3f9bad2Sdanielk1977 } 501c3f9bad2Sdanielk1977 502c3f9bad2Sdanielk1977 return 0; 503c3f9bad2Sdanielk1977 } 504c3f9bad2Sdanielk1977 505c977f7f5Sdrh /* 506c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a 507c977f7f5Sdrh ** trigger. 508c977f7f5Sdrh */ 509c3f9bad2Sdanielk1977 static int codeTriggerProgram( 510c977f7f5Sdrh Parse *pParse, /* The parser context */ 511c977f7f5Sdrh TriggerStep *pStepList, /* List of statements inside the trigger body */ 512c977f7f5Sdrh int orconfin /* Conflict algorithm. (OE_Abort, etc) */ 513633ed08dSdanielk1977 ){ 514633ed08dSdanielk1977 TriggerStep * pTriggerStep = pStepList; 515c3f9bad2Sdanielk1977 int orconf; 516c3f9bad2Sdanielk1977 517633ed08dSdanielk1977 while( pTriggerStep ){ 518c3f9bad2Sdanielk1977 int saveNTab = pParse->nTab; 519633ed08dSdanielk1977 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; 520c3f9bad2Sdanielk1977 pParse->trigStack->orconf = orconf; 521633ed08dSdanielk1977 switch( pTriggerStep->op ){ 522c3f9bad2Sdanielk1977 case TK_SELECT: { 5236f34903eSdanielk1977 Select * ss = sqliteSelectDup(pTriggerStep->pSelect); 5246f34903eSdanielk1977 assert(ss); 5256f34903eSdanielk1977 assert(ss->pSrc); 5266f34903eSdanielk1977 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0); 5276f34903eSdanielk1977 sqliteSelectDelete(ss); 528c3f9bad2Sdanielk1977 break; 529c3f9bad2Sdanielk1977 } 530c3f9bad2Sdanielk1977 case TK_UPDATE: { 531113088ecSdrh SrcList *pSrc; 532113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 533bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 534113088ecSdrh sqliteUpdate(pParse, pSrc, 535633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 536633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere), orconf); 537bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 538c3f9bad2Sdanielk1977 break; 539c3f9bad2Sdanielk1977 } 540c3f9bad2Sdanielk1977 case TK_INSERT: { 541113088ecSdrh SrcList *pSrc; 542113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 543113088ecSdrh sqliteInsert(pParse, pSrc, 544633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 545633ed08dSdanielk1977 sqliteSelectDup(pTriggerStep->pSelect), 546633ed08dSdanielk1977 sqliteIdListDup(pTriggerStep->pIdList), orconf); 547c3f9bad2Sdanielk1977 break; 548c3f9bad2Sdanielk1977 } 549c3f9bad2Sdanielk1977 case TK_DELETE: { 550113088ecSdrh SrcList *pSrc; 551bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 552113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 553113088ecSdrh sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere)); 554bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 555c3f9bad2Sdanielk1977 break; 556c3f9bad2Sdanielk1977 } 557c3f9bad2Sdanielk1977 default: 558c3f9bad2Sdanielk1977 assert(0); 559c3f9bad2Sdanielk1977 } 560c3f9bad2Sdanielk1977 pParse->nTab = saveNTab; 561633ed08dSdanielk1977 pTriggerStep = pTriggerStep->pNext; 562c3f9bad2Sdanielk1977 } 563c3f9bad2Sdanielk1977 564c3f9bad2Sdanielk1977 return 0; 565c3f9bad2Sdanielk1977 } 566c3f9bad2Sdanielk1977 567633ed08dSdanielk1977 /* 568633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers. 569633ed08dSdanielk1977 ** 570633ed08dSdanielk1977 ** When the code that this function generates is executed, the following 571633ed08dSdanielk1977 ** must be true: 572c977f7f5Sdrh ** 573c977f7f5Sdrh ** 1. No cursors may be open in the main database. (But newIdx and oldIdx 574c977f7f5Sdrh ** can be indices of cursors in temporary tables. See below.) 575c977f7f5Sdrh ** 576633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then 577633ed08dSdanielk1977 ** a temporary vdbe cursor (index newIdx) must be open and pointing at 578633ed08dSdanielk1977 ** a row containing values to be substituted for new.* expressions in the 579633ed08dSdanielk1977 ** trigger program(s). 580c977f7f5Sdrh ** 581633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then 582633ed08dSdanielk1977 ** a temporary vdbe cursor (index oldIdx) must be open and pointing at 583633ed08dSdanielk1977 ** a row containing values to be substituted for old.* expressions in the 584633ed08dSdanielk1977 ** trigger program(s). 585633ed08dSdanielk1977 ** 586633ed08dSdanielk1977 */ 587c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger( 588c3f9bad2Sdanielk1977 Parse *pParse, /* Parse context */ 589c3f9bad2Sdanielk1977 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ 590633ed08dSdanielk1977 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ 591c3f9bad2Sdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER */ 592633ed08dSdanielk1977 Table *pTab, /* The table to code triggers from */ 593633ed08dSdanielk1977 int newIdx, /* The indice of the "new" row to access */ 594633ed08dSdanielk1977 int oldIdx, /* The indice of the "old" row to access */ 5956f34903eSdanielk1977 int orconf, /* ON CONFLICT policy */ 5966f34903eSdanielk1977 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ 597c977f7f5Sdrh ){ 598c3f9bad2Sdanielk1977 Trigger * pTrigger; 599c3f9bad2Sdanielk1977 TriggerStack * pTriggerStack; 600c3f9bad2Sdanielk1977 601c3f9bad2Sdanielk1977 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); 602c3f9bad2Sdanielk1977 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER); 603c3f9bad2Sdanielk1977 604633ed08dSdanielk1977 assert(newIdx != -1 || oldIdx != -1); 605c3f9bad2Sdanielk1977 606633ed08dSdanielk1977 pTrigger = pTab->pTrigger; 607c3f9bad2Sdanielk1977 while( pTrigger ){ 608c3f9bad2Sdanielk1977 int fire_this = 0; 609c3f9bad2Sdanielk1977 610c3f9bad2Sdanielk1977 /* determine whether we should code this trigger */ 611c3f9bad2Sdanielk1977 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 612c3f9bad2Sdanielk1977 pTrigger->foreach == TK_ROW ){ 613c3f9bad2Sdanielk1977 fire_this = 1; 614c3f9bad2Sdanielk1977 pTriggerStack = pParse->trigStack; 615c3f9bad2Sdanielk1977 while( pTriggerStack ){ 616f29ce559Sdanielk1977 if( pTriggerStack->pTrigger == pTrigger ){ 617f29ce559Sdanielk1977 fire_this = 0; 618f29ce559Sdanielk1977 } 619c3f9bad2Sdanielk1977 pTriggerStack = pTriggerStack->pNext; 620c3f9bad2Sdanielk1977 } 621c3f9bad2Sdanielk1977 if( op == TK_UPDATE && pTrigger->pColumns && 622f29ce559Sdanielk1977 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){ 623c3f9bad2Sdanielk1977 fire_this = 0; 624c3f9bad2Sdanielk1977 } 625f29ce559Sdanielk1977 } 626c3f9bad2Sdanielk1977 627e4697f5eSdrh if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){ 628c3f9bad2Sdanielk1977 int endTrigger; 629ad3cab52Sdrh SrcList dummyTablist; 630c3f9bad2Sdanielk1977 Expr * whenExpr; 631c3f9bad2Sdanielk1977 632ad3cab52Sdrh dummyTablist.nSrc = 0; 633c3f9bad2Sdanielk1977 634c3f9bad2Sdanielk1977 /* Push an entry on to the trigger stack */ 635c3f9bad2Sdanielk1977 pTriggerStack->pTrigger = pTrigger; 636633ed08dSdanielk1977 pTriggerStack->newIdx = newIdx; 637633ed08dSdanielk1977 pTriggerStack->oldIdx = oldIdx; 638633ed08dSdanielk1977 pTriggerStack->pTab = pTab; 639c3f9bad2Sdanielk1977 pTriggerStack->pNext = pParse->trigStack; 6406f34903eSdanielk1977 pTriggerStack->ignoreJump = ignoreJump; 641c3f9bad2Sdanielk1977 pParse->trigStack = pTriggerStack; 642c3f9bad2Sdanielk1977 643c3f9bad2Sdanielk1977 /* code the WHEN clause */ 644c3f9bad2Sdanielk1977 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); 645c3f9bad2Sdanielk1977 whenExpr = sqliteExprDup(pTrigger->pWhen); 646c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ 647c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 648c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 649c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 650c3f9bad2Sdanielk1977 return 1; 651c3f9bad2Sdanielk1977 } 652f5905aa7Sdrh sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); 653c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 654c3f9bad2Sdanielk1977 655633ed08dSdanielk1977 codeTriggerProgram(pParse, pTrigger->step_list, orconf); 656c3f9bad2Sdanielk1977 657c3f9bad2Sdanielk1977 /* Pop the entry off the trigger stack */ 658c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 659c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 660c3f9bad2Sdanielk1977 661c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger); 662c3f9bad2Sdanielk1977 } 663c3f9bad2Sdanielk1977 pTrigger = pTrigger->pNext; 664c3f9bad2Sdanielk1977 } 665c3f9bad2Sdanielk1977 666c3f9bad2Sdanielk1977 return 0; 667c3f9bad2Sdanielk1977 } 668c3f9bad2Sdanielk1977 669c3f9bad2Sdanielk1977 /* 670633ed08dSdanielk1977 * This function is called to code ON UPDATE and ON DELETE triggers on 671633ed08dSdanielk1977 * views. 672633ed08dSdanielk1977 * 673633ed08dSdanielk1977 * This function deletes the data pointed at by the pWhere and pChanges 674633ed08dSdanielk1977 * arguments before it completes. 675c3f9bad2Sdanielk1977 */ 676633ed08dSdanielk1977 void sqliteViewTriggers( 677633ed08dSdanielk1977 Parse *pParse, 678633ed08dSdanielk1977 Table *pTab, /* The view to code triggers on */ 679633ed08dSdanielk1977 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/ 680633ed08dSdanielk1977 int orconf, /* The ON CONFLICT policy specified as part of the 681633ed08dSdanielk1977 statement causing these triggers */ 682633ed08dSdanielk1977 ExprList *pChanges /* If this is an statement causing triggers to fire 683633ed08dSdanielk1977 is an UPDATE, then this list holds the columns 684633ed08dSdanielk1977 to update and the expressions to update them to. 685633ed08dSdanielk1977 See comments for sqliteUpdate(). */ 686633ed08dSdanielk1977 ){ 687c3f9bad2Sdanielk1977 int oldIdx = -1; 688c3f9bad2Sdanielk1977 int newIdx = -1; 689c3f9bad2Sdanielk1977 int *aXRef = 0; 690c3f9bad2Sdanielk1977 Vdbe *v; 691c3f9bad2Sdanielk1977 int endOfLoop; 692c3f9bad2Sdanielk1977 int startOfLoop; 693c3f9bad2Sdanielk1977 Select theSelect; 694c3f9bad2Sdanielk1977 Token tblNameToken; 695c3f9bad2Sdanielk1977 696c3f9bad2Sdanielk1977 assert(pTab->pSelect); 697c3f9bad2Sdanielk1977 698c3f9bad2Sdanielk1977 tblNameToken.z = pTab->zName; 699c3f9bad2Sdanielk1977 tblNameToken.n = strlen(pTab->zName); 700c3f9bad2Sdanielk1977 701c3f9bad2Sdanielk1977 theSelect.isDistinct = 0; 702c3f9bad2Sdanielk1977 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0); 703113088ecSdrh theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken, 0); 704c3f9bad2Sdanielk1977 theSelect.pWhere = pWhere; pWhere = 0; 705c3f9bad2Sdanielk1977 theSelect.pGroupBy = 0; 706c3f9bad2Sdanielk1977 theSelect.pHaving = 0; 707c3f9bad2Sdanielk1977 theSelect.pOrderBy = 0; 708c3f9bad2Sdanielk1977 theSelect.op = TK_SELECT; /* ?? */ 709c3f9bad2Sdanielk1977 theSelect.pPrior = 0; 710c3f9bad2Sdanielk1977 theSelect.nLimit = -1; 711c3f9bad2Sdanielk1977 theSelect.nOffset = -1; 712c3f9bad2Sdanielk1977 theSelect.zSelect = 0; 713c3f9bad2Sdanielk1977 theSelect.base = 0; 714c3f9bad2Sdanielk1977 715c3f9bad2Sdanielk1977 v = sqliteGetVdbe(pParse); 716c3f9bad2Sdanielk1977 assert(v); 717cabb0819Sdrh sqliteBeginWriteOperation(pParse, 1, 0); 718c3f9bad2Sdanielk1977 719c3f9bad2Sdanielk1977 /* Allocate temp tables */ 720c3f9bad2Sdanielk1977 oldIdx = pParse->nTab++; 721c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0); 722c3f9bad2Sdanielk1977 if( pChanges ){ 723c3f9bad2Sdanielk1977 newIdx = pParse->nTab++; 724c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0); 725c3f9bad2Sdanielk1977 } 726c3f9bad2Sdanielk1977 727c3f9bad2Sdanielk1977 /* Snapshot the view */ 728c3f9bad2Sdanielk1977 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){ 729c3f9bad2Sdanielk1977 goto trigger_cleanup; 730c3f9bad2Sdanielk1977 } 731c3f9bad2Sdanielk1977 732c3f9bad2Sdanielk1977 /* loop thru the view snapshot, executing triggers for each row */ 733c3f9bad2Sdanielk1977 endOfLoop = sqliteVdbeMakeLabel(v); 734c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop); 735c3f9bad2Sdanielk1977 736c3f9bad2Sdanielk1977 /* Loop thru the view snapshot, executing triggers for each row */ 737c3f9bad2Sdanielk1977 startOfLoop = sqliteVdbeCurrentAddr(v); 738c3f9bad2Sdanielk1977 739c3f9bad2Sdanielk1977 /* Build the updated row if required */ 740c3f9bad2Sdanielk1977 if( pChanges ){ 7411d1f3055Sdrh int ii; 742c3f9bad2Sdanielk1977 743c3f9bad2Sdanielk1977 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); 744c3f9bad2Sdanielk1977 if( aXRef==0 ) goto trigger_cleanup; 745633ed08dSdanielk1977 for(ii = 0; ii < pTab->nCol; ii++){ 746c3f9bad2Sdanielk1977 aXRef[ii] = -1; 747633ed08dSdanielk1977 } 748c3f9bad2Sdanielk1977 749c3f9bad2Sdanielk1977 for(ii=0; ii<pChanges->nExpr; ii++){ 750c3f9bad2Sdanielk1977 int jj; 751c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0, 752f29ce559Sdanielk1977 pChanges->a[ii].pExpr) ){ 753c3f9bad2Sdanielk1977 goto trigger_cleanup; 754f29ce559Sdanielk1977 } 755c3f9bad2Sdanielk1977 756c3f9bad2Sdanielk1977 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) ) 757c3f9bad2Sdanielk1977 goto trigger_cleanup; 758c3f9bad2Sdanielk1977 759c3f9bad2Sdanielk1977 for(jj=0; jj<pTab->nCol; jj++){ 760c3f9bad2Sdanielk1977 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){ 761c3f9bad2Sdanielk1977 aXRef[jj] = ii; 762c3f9bad2Sdanielk1977 break; 763c3f9bad2Sdanielk1977 } 764c3f9bad2Sdanielk1977 } 765c3f9bad2Sdanielk1977 if( jj>=pTab->nCol ){ 766c3f9bad2Sdanielk1977 sqliteSetString(&pParse->zErrMsg, "no such column: ", 767c3f9bad2Sdanielk1977 pChanges->a[ii].zName, 0); 768c3f9bad2Sdanielk1977 pParse->nErr++; 769c3f9bad2Sdanielk1977 goto trigger_cleanup; 770c3f9bad2Sdanielk1977 } 771c3f9bad2Sdanielk1977 } 772c3f9bad2Sdanielk1977 773c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Integer, 13, 0); 774c3f9bad2Sdanielk1977 775633ed08dSdanielk1977 for(ii = 0; ii<pTab->nCol; ii++){ 776633ed08dSdanielk1977 if( aXRef[ii] < 0 ){ 777c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii); 778633ed08dSdanielk1977 }else{ 779c3f9bad2Sdanielk1977 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr); 780633ed08dSdanielk1977 } 781633ed08dSdanielk1977 } 782c3f9bad2Sdanielk1977 783c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); 784c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); 785c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0); 786c3f9bad2Sdanielk1977 787c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, 7886f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 789c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, 7906f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 791c3f9bad2Sdanielk1977 }else{ 792c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, 7936f34903eSdanielk1977 orconf, endOfLoop); 794c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, 7956f34903eSdanielk1977 orconf, endOfLoop); 796c3f9bad2Sdanielk1977 } 797c3f9bad2Sdanielk1977 798c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop); 799c3f9bad2Sdanielk1977 800c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(v, endOfLoop); 801c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 802c3f9bad2Sdanielk1977 803c3f9bad2Sdanielk1977 trigger_cleanup: 804c3f9bad2Sdanielk1977 sqliteFree(aXRef); 805c3f9bad2Sdanielk1977 sqliteExprListDelete(pChanges); 806c3f9bad2Sdanielk1977 sqliteExprDelete(pWhere); 807c3f9bad2Sdanielk1977 sqliteExprListDelete(theSelect.pEList); 808ad3cab52Sdrh sqliteSrcListDelete(theSelect.pSrc); 809c3f9bad2Sdanielk1977 sqliteExprDelete(theSelect.pWhere); 810c3f9bad2Sdanielk1977 return; 811c3f9bad2Sdanielk1977 } 812