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 ){ 69*da93d238Sdrh sqliteErrorMsg(pParse, "triggers may not be added to auxiliary " 70*da93d238Sdrh "database %s", db->aDb[tab->iDb].zName); 71d24cc427Sdrh goto trigger_cleanup; 72d24cc427Sdrh } 73d24cc427Sdrh 74e5f9c644Sdrh zName = sqliteStrNDup(pName->z, pName->n); 75d24cc427Sdrh if( sqliteHashFind(&(db->aDb[tab->iDb].trigHash), zName,pName->n+1) ){ 76*da93d238Sdrh sqliteErrorMsg(pParse, "trigger %T already exists", pName); 77c3f9bad2Sdanielk1977 goto trigger_cleanup; 78c3f9bad2Sdanielk1977 } 79d24cc427Sdrh if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){ 80*da93d238Sdrh sqliteErrorMsg(pParse, "cannot create trigger on system table"); 81e0bc4048Sdrh pParse->nErr++; 82e0bc4048Sdrh goto trigger_cleanup; 83e0bc4048Sdrh } 84d702fccbSdanielk1977 if( tab->pSelect && tr_tm != TK_INSTEAD ){ 85*da93d238Sdrh sqliteErrorMsg(pParse, "cannot create %s trigger on view: %S", 86*da93d238Sdrh (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); 87d702fccbSdanielk1977 goto trigger_cleanup; 88d702fccbSdanielk1977 } 89d702fccbSdanielk1977 if( !tab->pSelect && tr_tm == TK_INSTEAD ){ 90*da93d238Sdrh sqliteErrorMsg(pParse, "cannot create INSTEAD OF" 91*da93d238Sdrh " trigger on table: %S", pTableName, 0); 92d702fccbSdanielk1977 goto trigger_cleanup; 93d702fccbSdanielk1977 } 94e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 95e5f9c644Sdrh { 96e5f9c644Sdrh int code = SQLITE_CREATE_TRIGGER; 97d24cc427Sdrh if( tab->iDb==1 ) code = SQLITE_CREATE_TEMP_TRIGGER; 98e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){ 99ed6c8671Sdrh goto trigger_cleanup; 100ed6c8671Sdrh } 101d24cc427Sdrh if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){ 10277ad4e41Sdrh goto trigger_cleanup; 10377ad4e41Sdrh } 104d702fccbSdanielk1977 } 105e5f9c644Sdrh #endif 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; 114e5f9c644Sdrh nt->name = zName; 115e5f9c644Sdrh zName = 0; 116d24cc427Sdrh nt->table = sqliteStrDup(pTableName->a[0].zName); 117e4697f5eSdrh if( sqlite_malloc_failed ) goto trigger_cleanup; 118d24cc427Sdrh nt->iDb = tab->iDb; 119c3f9bad2Sdanielk1977 nt->op = op; 120c3f9bad2Sdanielk1977 nt->tr_tm = tr_tm; 1214b59ab5eSdrh nt->pWhen = sqliteExprDup(pWhen); 1224b59ab5eSdrh sqliteExprDelete(pWhen); 1234b59ab5eSdrh nt->pColumns = sqliteIdListDup(pColumns); 1244b59ab5eSdrh sqliteIdListDelete(pColumns); 125c3f9bad2Sdanielk1977 nt->foreach = foreach; 126633ed08dSdanielk1977 nt->step_list = pStepList; 127c3f9bad2Sdanielk1977 128c3f9bad2Sdanielk1977 /* if we are not initializing, and this trigger is not on a TEMP table, 1299adf9ac4Sdrh ** build the sqlite_master entry 1309adf9ac4Sdrh */ 131e0bc4048Sdrh if( !pParse->initFlag ){ 132c977f7f5Sdrh static VdbeOp insertTrig[] = { 133c977f7f5Sdrh { OP_NewRecno, 0, 0, 0 }, 134c977f7f5Sdrh { OP_String, 0, 0, "trigger" }, 135e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 2: trigger name */ 136e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 3: table name */ 137c977f7f5Sdrh { OP_Integer, 0, 0, 0 }, 138e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 5: SQL */ 139c977f7f5Sdrh { OP_MakeRecord, 5, 0, 0 }, 140c977f7f5Sdrh { OP_PutIntKey, 0, 0, 0 }, 141c977f7f5Sdrh }; 142c977f7f5Sdrh int addr; 143c977f7f5Sdrh Vdbe *v; 144c3f9bad2Sdanielk1977 145c3f9bad2Sdanielk1977 /* Make an entry in the sqlite_master table */ 146c977f7f5Sdrh v = sqliteGetVdbe(pParse); 147e4697f5eSdrh if( v==0 ) goto trigger_cleanup; 148cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 149d24cc427Sdrh sqliteOpenMasterTable(v, tab->iDb); 150c977f7f5Sdrh addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); 151d24cc427Sdrh sqliteVdbeChangeP3(v, addr, tab->iDb ? TEMP_MASTER_NAME : MASTER_NAME, 152e0bc4048Sdrh P3_STATIC); 153e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 154e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 1554b59ab5eSdrh sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n); 156d24cc427Sdrh if( tab->iDb==0 ){ 157d24cc427Sdrh sqliteChangeCookie(db, v); 158e0bc4048Sdrh } 159e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 160c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 161c3f9bad2Sdanielk1977 } 162c3f9bad2Sdanielk1977 163c3f9bad2Sdanielk1977 if( !pParse->explain ){ 164c3f9bad2Sdanielk1977 /* Stick it in the hash-table */ 165d24cc427Sdrh sqliteHashInsert(&(db->aDb[nt->iDb].trigHash), nt->name, pName->n + 1, nt); 166c3f9bad2Sdanielk1977 167c3f9bad2Sdanielk1977 /* Attach it to the table object */ 168c3f9bad2Sdanielk1977 nt->pNext = tab->pTrigger; 169c3f9bad2Sdanielk1977 tab->pTrigger = nt; 1700be9df07Sdrh sqliteSrcListDelete(pTableName); 171c3f9bad2Sdanielk1977 return; 172c3f9bad2Sdanielk1977 }else{ 173c3f9bad2Sdanielk1977 sqliteFree(nt->name); 174c3f9bad2Sdanielk1977 sqliteFree(nt->table); 175c3f9bad2Sdanielk1977 sqliteFree(nt); 176c3f9bad2Sdanielk1977 } 177c3f9bad2Sdanielk1977 178c3f9bad2Sdanielk1977 trigger_cleanup: 179c3f9bad2Sdanielk1977 180e5f9c644Sdrh sqliteFree(zName); 181d24cc427Sdrh sqliteSrcListDelete(pTableName); 182633ed08dSdanielk1977 sqliteIdListDelete(pColumns); 183c3f9bad2Sdanielk1977 sqliteExprDelete(pWhen); 1844b59ab5eSdrh sqliteDeleteTriggerStep(pStepList); 185c3f9bad2Sdanielk1977 } 1864b59ab5eSdrh 1874b59ab5eSdrh /* 1884b59ab5eSdrh ** Make a copy of all components of the given trigger step. This has 1894b59ab5eSdrh ** the effect of copying all Expr.token.z values into memory obtained 1904b59ab5eSdrh ** from sqliteMalloc(). As initially created, the Expr.token.z values 1914b59ab5eSdrh ** all point to the input string that was fed to the parser. But that 1924b59ab5eSdrh ** string is ephemeral - it will go away as soon as the sqlite_exec() 1934b59ab5eSdrh ** call that started the parser exits. This routine makes a persistent 1944b59ab5eSdrh ** copy of all the Expr.token.z strings so that the TriggerStep structure 1954b59ab5eSdrh ** will be valid even after the sqlite_exec() call returns. 1964b59ab5eSdrh */ 1974b59ab5eSdrh static void sqlitePersistTriggerStep(TriggerStep *p){ 1984b59ab5eSdrh if( p->target.z ){ 1994b59ab5eSdrh p->target.z = sqliteStrNDup(p->target.z, p->target.n); 2004b59ab5eSdrh p->target.dyn = 1; 2014b59ab5eSdrh } 2024b59ab5eSdrh if( p->pSelect ){ 2034b59ab5eSdrh Select *pNew = sqliteSelectDup(p->pSelect); 2044b59ab5eSdrh sqliteSelectDelete(p->pSelect); 2054b59ab5eSdrh p->pSelect = pNew; 2064b59ab5eSdrh } 2074b59ab5eSdrh if( p->pWhere ){ 2084b59ab5eSdrh Expr *pNew = sqliteExprDup(p->pWhere); 2094b59ab5eSdrh sqliteExprDelete(p->pWhere); 2104b59ab5eSdrh p->pWhere = pNew; 2114b59ab5eSdrh } 2124b59ab5eSdrh if( p->pExprList ){ 2134b59ab5eSdrh ExprList *pNew = sqliteExprListDup(p->pExprList); 2144b59ab5eSdrh sqliteExprListDelete(p->pExprList); 2154b59ab5eSdrh p->pExprList = pNew; 2164b59ab5eSdrh } 2174b59ab5eSdrh if( p->pIdList ){ 2184b59ab5eSdrh IdList *pNew = sqliteIdListDup(p->pIdList); 2194b59ab5eSdrh sqliteIdListDelete(p->pIdList); 2204b59ab5eSdrh p->pIdList = pNew; 221c3f9bad2Sdanielk1977 } 222c3f9bad2Sdanielk1977 } 223c3f9bad2Sdanielk1977 224c977f7f5Sdrh /* 225c977f7f5Sdrh ** Turn a SELECT statement (that the pSelect parameter points to) into 226c977f7f5Sdrh ** a trigger step. Return a pointer to a TriggerStep structure. 227c977f7f5Sdrh ** 228c977f7f5Sdrh ** The parser calls this routine when it finds a SELECT statement in 229c977f7f5Sdrh ** body of a TRIGGER. 230c977f7f5Sdrh */ 231c977f7f5Sdrh TriggerStep *sqliteTriggerSelectStep(Select *pSelect){ 232633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 233e4697f5eSdrh if( pTriggerStep==0 ) return 0; 234c3f9bad2Sdanielk1977 235633ed08dSdanielk1977 pTriggerStep->op = TK_SELECT; 236633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 237633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 2384b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 239c3f9bad2Sdanielk1977 240633ed08dSdanielk1977 return pTriggerStep; 241c3f9bad2Sdanielk1977 } 242c3f9bad2Sdanielk1977 243c977f7f5Sdrh /* 244c977f7f5Sdrh ** Build a trigger step out of an INSERT statement. Return a pointer 245c977f7f5Sdrh ** to the new trigger step. 246c977f7f5Sdrh ** 247c977f7f5Sdrh ** The parser calls this routine when it sees an INSERT inside the 248c977f7f5Sdrh ** body of a trigger. 249c977f7f5Sdrh */ 250633ed08dSdanielk1977 TriggerStep *sqliteTriggerInsertStep( 251c977f7f5Sdrh Token *pTableName, /* Name of the table into which we insert */ 252c977f7f5Sdrh IdList *pColumn, /* List of columns in pTableName to insert into */ 253c977f7f5Sdrh ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ 254c977f7f5Sdrh Select *pSelect, /* A SELECT statement that supplies values */ 255c977f7f5Sdrh int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ 256633ed08dSdanielk1977 ){ 257633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 258e4697f5eSdrh if( pTriggerStep==0 ) return 0; 259c3f9bad2Sdanielk1977 260633ed08dSdanielk1977 assert(pEList == 0 || pSelect == 0); 261633ed08dSdanielk1977 assert(pEList != 0 || pSelect != 0); 262c3f9bad2Sdanielk1977 263633ed08dSdanielk1977 pTriggerStep->op = TK_INSERT; 264633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 265633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 266633ed08dSdanielk1977 pTriggerStep->pIdList = pColumn; 267633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 268633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2694b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 270c3f9bad2Sdanielk1977 271633ed08dSdanielk1977 return pTriggerStep; 272c3f9bad2Sdanielk1977 } 273c3f9bad2Sdanielk1977 274c977f7f5Sdrh /* 275c977f7f5Sdrh ** Construct a trigger step that implements an UPDATE statement and return 276c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 277c977f7f5Sdrh ** sees an UPDATE statement inside the body of a CREATE TRIGGER. 278c977f7f5Sdrh */ 279633ed08dSdanielk1977 TriggerStep *sqliteTriggerUpdateStep( 280c977f7f5Sdrh Token *pTableName, /* Name of the table to be updated */ 281c977f7f5Sdrh ExprList *pEList, /* The SET clause: list of column and new values */ 282c977f7f5Sdrh Expr *pWhere, /* The WHERE clause */ 283c977f7f5Sdrh int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ 284c977f7f5Sdrh ){ 285633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 286e4697f5eSdrh if( pTriggerStep==0 ) return 0; 287c3f9bad2Sdanielk1977 288633ed08dSdanielk1977 pTriggerStep->op = TK_UPDATE; 289633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 290633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 291633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 292633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2934b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 294c3f9bad2Sdanielk1977 295633ed08dSdanielk1977 return pTriggerStep; 296c3f9bad2Sdanielk1977 } 297c3f9bad2Sdanielk1977 298c977f7f5Sdrh /* 299c977f7f5Sdrh ** Construct a trigger step that implements a DELETE statement and return 300c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 301c977f7f5Sdrh ** sees a DELETE statement inside the body of a CREATE TRIGGER. 302c977f7f5Sdrh */ 303c977f7f5Sdrh TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){ 304633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 305e4697f5eSdrh if( pTriggerStep==0 ) return 0; 306c3f9bad2Sdanielk1977 307633ed08dSdanielk1977 pTriggerStep->op = TK_DELETE; 308633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 309633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 310633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 3114b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 312c3f9bad2Sdanielk1977 313633ed08dSdanielk1977 return pTriggerStep; 314c3f9bad2Sdanielk1977 } 315c3f9bad2Sdanielk1977 316c3f9bad2Sdanielk1977 /* 317633ed08dSdanielk1977 ** Recursively delete a Trigger structure 318c3f9bad2Sdanielk1977 */ 3191d1f3055Sdrh void sqliteDeleteTrigger(Trigger *pTrigger){ 3204b59ab5eSdrh sqliteDeleteTriggerStep(pTrigger->step_list); 321633ed08dSdanielk1977 sqliteFree(pTrigger->name); 322633ed08dSdanielk1977 sqliteFree(pTrigger->table); 323633ed08dSdanielk1977 sqliteExprDelete(pTrigger->pWhen); 324633ed08dSdanielk1977 sqliteIdListDelete(pTrigger->pColumns); 325633ed08dSdanielk1977 sqliteFree(pTrigger); 326633ed08dSdanielk1977 } 327633ed08dSdanielk1977 328633ed08dSdanielk1977 /* 329633ed08dSdanielk1977 * This function is called to drop a trigger from the database schema. 330633ed08dSdanielk1977 * 331633ed08dSdanielk1977 * This may be called directly from the parser, or from within 332633ed08dSdanielk1977 * sqliteDropTable(). In the latter case the "nested" argument is true. 333633ed08dSdanielk1977 * 334633ed08dSdanielk1977 * Note that this function does not delete the trigger entirely. Instead it 335633ed08dSdanielk1977 * removes it from the internal schema and places it in the trigDrop hash 336633ed08dSdanielk1977 * table. This is so that the trigger can be restored into the database schema 337633ed08dSdanielk1977 * if the transaction is rolled back. 338633ed08dSdanielk1977 */ 339d24cc427Sdrh void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){ 340633ed08dSdanielk1977 Trigger *pTrigger; 341633ed08dSdanielk1977 Table *pTable; 342e0bc4048Sdrh Vdbe *v; 343d24cc427Sdrh int i; 344d24cc427Sdrh const char *zDb; 345d24cc427Sdrh const char *zName; 346d24cc427Sdrh int nName; 347d24cc427Sdrh sqlite *db = pParse->db; 348633ed08dSdanielk1977 349d24cc427Sdrh if( sqlite_malloc_failed ) goto drop_trigger_cleanup; 350d24cc427Sdrh assert( pName->nSrc==1 ); 351d24cc427Sdrh zDb = pName->a[0].zDatabase; 352d24cc427Sdrh zName = pName->a[0].zName; 353d24cc427Sdrh nName = strlen(zName); 354d24cc427Sdrh for(i=0; i<db->nDb; i++){ 355812d7a21Sdrh int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ 356812d7a21Sdrh if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue; 357812d7a21Sdrh pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1); 358d24cc427Sdrh if( pTrigger ) break; 359c3f9bad2Sdanielk1977 } 360d24cc427Sdrh if( !pTrigger ){ 361*da93d238Sdrh sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0); 362d24cc427Sdrh goto drop_trigger_cleanup; 363d24cc427Sdrh } 364d24cc427Sdrh assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb ); 365d24cc427Sdrh if( pTrigger->iDb>=2 ){ 366*da93d238Sdrh sqliteErrorMsg(pParse, "triggers may not be removed from " 367*da93d238Sdrh "auxiliary database %s", db->aDb[pTrigger->iDb].zName); 368d24cc427Sdrh goto drop_trigger_cleanup; 369d24cc427Sdrh } 370d24cc427Sdrh pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName); 371ed6c8671Sdrh assert(pTable); 372d24cc427Sdrh assert( pTable->iDb==pTrigger->iDb ); 373e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 374e5f9c644Sdrh { 375e5f9c644Sdrh int code = SQLITE_DROP_TRIGGER; 376d24cc427Sdrh if( pTable->iDb ) code = SQLITE_DROP_TEMP_TRIGGER; 377e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) || 378d24cc427Sdrh sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0) ){ 3790be9df07Sdrh goto drop_trigger_cleanup; 380ed6c8671Sdrh } 381e5f9c644Sdrh } 382e5f9c644Sdrh #endif 383c3f9bad2Sdanielk1977 384c3f9bad2Sdanielk1977 /* 385e0bc4048Sdrh * If this is not an "explain", then delete the trigger structure. 386c3f9bad2Sdanielk1977 */ 387c3f9bad2Sdanielk1977 if( !pParse->explain ){ 388633ed08dSdanielk1977 if( pTable->pTrigger == pTrigger ){ 389633ed08dSdanielk1977 pTable->pTrigger = pTrigger->pNext; 390633ed08dSdanielk1977 }else{ 391633ed08dSdanielk1977 Trigger *cc = pTable->pTrigger; 392c3f9bad2Sdanielk1977 while( cc ){ 393633ed08dSdanielk1977 if( cc->pNext == pTrigger ){ 394c3f9bad2Sdanielk1977 cc->pNext = cc->pNext->pNext; 395c3f9bad2Sdanielk1977 break; 396c3f9bad2Sdanielk1977 } 397c3f9bad2Sdanielk1977 cc = cc->pNext; 398c3f9bad2Sdanielk1977 } 399c3f9bad2Sdanielk1977 assert(cc); 400c3f9bad2Sdanielk1977 } 401d24cc427Sdrh sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0); 402e0bc4048Sdrh sqliteDeleteTrigger(pTrigger); 403c3f9bad2Sdanielk1977 } 404c3f9bad2Sdanielk1977 405e0bc4048Sdrh /* Generate code to destroy the database record of the trigger. 406e0bc4048Sdrh */ 407e0bc4048Sdrh if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){ 408c3f9bad2Sdanielk1977 int base; 409c3f9bad2Sdanielk1977 static VdbeOp dropTrigger[] = { 410e0bc4048Sdrh { OP_Rewind, 0, ADDR(8), 0}, 411e0bc4048Sdrh { OP_String, 0, 0, 0}, /* 1 */ 412c3f9bad2Sdanielk1977 { OP_MemStore, 1, 1, 0}, 413e0bc4048Sdrh { OP_MemLoad, 1, 0, 0}, /* 3 */ 414c3f9bad2Sdanielk1977 { OP_Column, 0, 1, 0}, 415e0bc4048Sdrh { OP_Ne, 0, ADDR(7), 0}, 416c3f9bad2Sdanielk1977 { OP_Delete, 0, 0, 0}, 417e0bc4048Sdrh { OP_Next, 0, ADDR(3), 0}, /* 7 */ 418c3f9bad2Sdanielk1977 }; 419c3f9bad2Sdanielk1977 420cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 421d24cc427Sdrh sqliteOpenMasterTable(v, pTable->iDb); 422e0bc4048Sdrh base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); 423e0bc4048Sdrh sqliteVdbeChangeP3(v, base+1, zName, 0); 424d24cc427Sdrh if( pTable->iDb==0 ){ 425d24cc427Sdrh sqliteChangeCookie(db, v); 426dc379456Sdrh } 427e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 428c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 429c3f9bad2Sdanielk1977 } 430c3f9bad2Sdanielk1977 431d24cc427Sdrh drop_trigger_cleanup: 432d24cc427Sdrh sqliteSrcListDelete(pName); 433c3f9bad2Sdanielk1977 } 434c3f9bad2Sdanielk1977 435c977f7f5Sdrh /* 436c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement. Each entry 437c977f7f5Sdrh ** in pEList is of the format <id>=<expr>. If any of the entries 438c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList, 439c977f7f5Sdrh ** then return TRUE. If pIdList==NULL, then it is considered a 440c977f7f5Sdrh ** wildcard that matches anything. Likewise if pEList==NULL then 441c977f7f5Sdrh ** it matches anything so always return true. Return false only 442c977f7f5Sdrh ** if there is no match. 443c977f7f5Sdrh */ 444c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){ 445ad2d8307Sdrh int e; 446ad2d8307Sdrh if( !pIdList || !pEList ) return 1; 447f29ce559Sdanielk1977 for(e=0; e<pEList->nExpr; e++){ 448ad2d8307Sdrh if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; 449f29ce559Sdanielk1977 } 450c3f9bad2Sdanielk1977 return 0; 451c3f9bad2Sdanielk1977 } 452c3f9bad2Sdanielk1977 453c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for 454c3f9bad2Sdanielk1977 * for triggers, even if there are no triggers to code. This is used to test 455c3f9bad2Sdanielk1977 * how much overhead the triggers algorithm is causing. 456c3f9bad2Sdanielk1977 * 457c3f9bad2Sdanielk1977 * This flag can be set or cleared using the "trigger_overhead_test" pragma. 458c3f9bad2Sdanielk1977 * The pragma is not documented since it is not really part of the interface 459c3f9bad2Sdanielk1977 * to SQLite, just the test procedure. 460c3f9bad2Sdanielk1977 */ 461c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0; 462c3f9bad2Sdanielk1977 463c3f9bad2Sdanielk1977 /* 464c3f9bad2Sdanielk1977 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already 465c3f9bad2Sdanielk1977 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is 466c3f9bad2Sdanielk1977 * found in the list specified as pTrigger. 467c3f9bad2Sdanielk1977 */ 468c3f9bad2Sdanielk1977 int sqliteTriggersExist( 469c977f7f5Sdrh Parse *pParse, /* Used to check for recursive triggers */ 470c977f7f5Sdrh Trigger *pTrigger, /* A list of triggers associated with a table */ 471c3f9bad2Sdanielk1977 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ 472c3f9bad2Sdanielk1977 int tr_tm, /* one of TK_BEFORE, TK_AFTER */ 473c3f9bad2Sdanielk1977 int foreach, /* one of TK_ROW or TK_STATEMENT */ 474c977f7f5Sdrh ExprList *pChanges /* Columns that change in an UPDATE statement */ 475c977f7f5Sdrh ){ 476633ed08dSdanielk1977 Trigger * pTriggerCursor; 477c3f9bad2Sdanielk1977 478633ed08dSdanielk1977 if( always_code_trigger_setup ){ 479633ed08dSdanielk1977 return 1; 480633ed08dSdanielk1977 } 481c3f9bad2Sdanielk1977 482633ed08dSdanielk1977 pTriggerCursor = pTrigger; 483633ed08dSdanielk1977 while( pTriggerCursor ){ 484633ed08dSdanielk1977 if( pTriggerCursor->op == op && 485633ed08dSdanielk1977 pTriggerCursor->tr_tm == tr_tm && 486633ed08dSdanielk1977 pTriggerCursor->foreach == foreach && 487633ed08dSdanielk1977 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){ 488c3f9bad2Sdanielk1977 TriggerStack * ss; 489c3f9bad2Sdanielk1977 ss = pParse->trigStack; 490f29ce559Sdanielk1977 while( ss && ss->pTrigger != pTrigger ){ 491f29ce559Sdanielk1977 ss = ss->pNext; 492f29ce559Sdanielk1977 } 493c3f9bad2Sdanielk1977 if( !ss )return 1; 494c3f9bad2Sdanielk1977 } 495633ed08dSdanielk1977 pTriggerCursor = pTriggerCursor->pNext; 496c3f9bad2Sdanielk1977 } 497c3f9bad2Sdanielk1977 498c3f9bad2Sdanielk1977 return 0; 499c3f9bad2Sdanielk1977 } 500c3f9bad2Sdanielk1977 501c977f7f5Sdrh /* 502c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a 503c977f7f5Sdrh ** trigger. 504c977f7f5Sdrh */ 505c3f9bad2Sdanielk1977 static int codeTriggerProgram( 506c977f7f5Sdrh Parse *pParse, /* The parser context */ 507c977f7f5Sdrh TriggerStep *pStepList, /* List of statements inside the trigger body */ 508c977f7f5Sdrh int orconfin /* Conflict algorithm. (OE_Abort, etc) */ 509633ed08dSdanielk1977 ){ 510633ed08dSdanielk1977 TriggerStep * pTriggerStep = pStepList; 511c3f9bad2Sdanielk1977 int orconf; 512c3f9bad2Sdanielk1977 513633ed08dSdanielk1977 while( pTriggerStep ){ 514c3f9bad2Sdanielk1977 int saveNTab = pParse->nTab; 515633ed08dSdanielk1977 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; 516c3f9bad2Sdanielk1977 pParse->trigStack->orconf = orconf; 517633ed08dSdanielk1977 switch( pTriggerStep->op ){ 518c3f9bad2Sdanielk1977 case TK_SELECT: { 5196f34903eSdanielk1977 Select * ss = sqliteSelectDup(pTriggerStep->pSelect); 5206f34903eSdanielk1977 assert(ss); 5216f34903eSdanielk1977 assert(ss->pSrc); 5226f34903eSdanielk1977 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0); 5236f34903eSdanielk1977 sqliteSelectDelete(ss); 524c3f9bad2Sdanielk1977 break; 525c3f9bad2Sdanielk1977 } 526c3f9bad2Sdanielk1977 case TK_UPDATE: { 527113088ecSdrh SrcList *pSrc; 528113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 529bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 530113088ecSdrh sqliteUpdate(pParse, pSrc, 531633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 532633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere), orconf); 533bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 534c3f9bad2Sdanielk1977 break; 535c3f9bad2Sdanielk1977 } 536c3f9bad2Sdanielk1977 case TK_INSERT: { 537113088ecSdrh SrcList *pSrc; 538113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 539113088ecSdrh sqliteInsert(pParse, pSrc, 540633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 541633ed08dSdanielk1977 sqliteSelectDup(pTriggerStep->pSelect), 542633ed08dSdanielk1977 sqliteIdListDup(pTriggerStep->pIdList), orconf); 543c3f9bad2Sdanielk1977 break; 544c3f9bad2Sdanielk1977 } 545c3f9bad2Sdanielk1977 case TK_DELETE: { 546113088ecSdrh SrcList *pSrc; 547bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 548113088ecSdrh pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0); 549113088ecSdrh sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere)); 550bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 551c3f9bad2Sdanielk1977 break; 552c3f9bad2Sdanielk1977 } 553c3f9bad2Sdanielk1977 default: 554c3f9bad2Sdanielk1977 assert(0); 555c3f9bad2Sdanielk1977 } 556c3f9bad2Sdanielk1977 pParse->nTab = saveNTab; 557633ed08dSdanielk1977 pTriggerStep = pTriggerStep->pNext; 558c3f9bad2Sdanielk1977 } 559c3f9bad2Sdanielk1977 560c3f9bad2Sdanielk1977 return 0; 561c3f9bad2Sdanielk1977 } 562c3f9bad2Sdanielk1977 563633ed08dSdanielk1977 /* 564633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers. 565633ed08dSdanielk1977 ** 566633ed08dSdanielk1977 ** When the code that this function generates is executed, the following 567633ed08dSdanielk1977 ** must be true: 568c977f7f5Sdrh ** 569c977f7f5Sdrh ** 1. No cursors may be open in the main database. (But newIdx and oldIdx 570c977f7f5Sdrh ** can be indices of cursors in temporary tables. See below.) 571c977f7f5Sdrh ** 572633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then 573633ed08dSdanielk1977 ** a temporary vdbe cursor (index newIdx) must be open and pointing at 574633ed08dSdanielk1977 ** a row containing values to be substituted for new.* expressions in the 575633ed08dSdanielk1977 ** trigger program(s). 576c977f7f5Sdrh ** 577633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then 578633ed08dSdanielk1977 ** a temporary vdbe cursor (index oldIdx) must be open and pointing at 579633ed08dSdanielk1977 ** a row containing values to be substituted for old.* expressions in the 580633ed08dSdanielk1977 ** trigger program(s). 581633ed08dSdanielk1977 ** 582633ed08dSdanielk1977 */ 583c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger( 584c3f9bad2Sdanielk1977 Parse *pParse, /* Parse context */ 585c3f9bad2Sdanielk1977 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ 586633ed08dSdanielk1977 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ 587c3f9bad2Sdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER */ 588633ed08dSdanielk1977 Table *pTab, /* The table to code triggers from */ 589633ed08dSdanielk1977 int newIdx, /* The indice of the "new" row to access */ 590633ed08dSdanielk1977 int oldIdx, /* The indice of the "old" row to access */ 5916f34903eSdanielk1977 int orconf, /* ON CONFLICT policy */ 5926f34903eSdanielk1977 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ 593c977f7f5Sdrh ){ 594c3f9bad2Sdanielk1977 Trigger * pTrigger; 595c3f9bad2Sdanielk1977 TriggerStack * pTriggerStack; 596c3f9bad2Sdanielk1977 597c3f9bad2Sdanielk1977 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); 598c3f9bad2Sdanielk1977 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER); 599c3f9bad2Sdanielk1977 600633ed08dSdanielk1977 assert(newIdx != -1 || oldIdx != -1); 601c3f9bad2Sdanielk1977 602633ed08dSdanielk1977 pTrigger = pTab->pTrigger; 603c3f9bad2Sdanielk1977 while( pTrigger ){ 604c3f9bad2Sdanielk1977 int fire_this = 0; 605c3f9bad2Sdanielk1977 606c3f9bad2Sdanielk1977 /* determine whether we should code this trigger */ 607c3f9bad2Sdanielk1977 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 608c3f9bad2Sdanielk1977 pTrigger->foreach == TK_ROW ){ 609c3f9bad2Sdanielk1977 fire_this = 1; 610c3f9bad2Sdanielk1977 pTriggerStack = pParse->trigStack; 611c3f9bad2Sdanielk1977 while( pTriggerStack ){ 612f29ce559Sdanielk1977 if( pTriggerStack->pTrigger == pTrigger ){ 613f29ce559Sdanielk1977 fire_this = 0; 614f29ce559Sdanielk1977 } 615c3f9bad2Sdanielk1977 pTriggerStack = pTriggerStack->pNext; 616c3f9bad2Sdanielk1977 } 617c3f9bad2Sdanielk1977 if( op == TK_UPDATE && pTrigger->pColumns && 618f29ce559Sdanielk1977 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){ 619c3f9bad2Sdanielk1977 fire_this = 0; 620c3f9bad2Sdanielk1977 } 621f29ce559Sdanielk1977 } 622c3f9bad2Sdanielk1977 623e4697f5eSdrh if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){ 624c3f9bad2Sdanielk1977 int endTrigger; 625ad3cab52Sdrh SrcList dummyTablist; 626c3f9bad2Sdanielk1977 Expr * whenExpr; 627c3f9bad2Sdanielk1977 628ad3cab52Sdrh dummyTablist.nSrc = 0; 629c3f9bad2Sdanielk1977 630c3f9bad2Sdanielk1977 /* Push an entry on to the trigger stack */ 631c3f9bad2Sdanielk1977 pTriggerStack->pTrigger = pTrigger; 632633ed08dSdanielk1977 pTriggerStack->newIdx = newIdx; 633633ed08dSdanielk1977 pTriggerStack->oldIdx = oldIdx; 634633ed08dSdanielk1977 pTriggerStack->pTab = pTab; 635c3f9bad2Sdanielk1977 pTriggerStack->pNext = pParse->trigStack; 6366f34903eSdanielk1977 pTriggerStack->ignoreJump = ignoreJump; 637c3f9bad2Sdanielk1977 pParse->trigStack = pTriggerStack; 638c3f9bad2Sdanielk1977 639c3f9bad2Sdanielk1977 /* code the WHEN clause */ 640c3f9bad2Sdanielk1977 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); 641c3f9bad2Sdanielk1977 whenExpr = sqliteExprDup(pTrigger->pWhen); 642c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ 643c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 644c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 645c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 646c3f9bad2Sdanielk1977 return 1; 647c3f9bad2Sdanielk1977 } 648f5905aa7Sdrh sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); 649c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 650c3f9bad2Sdanielk1977 651633ed08dSdanielk1977 codeTriggerProgram(pParse, pTrigger->step_list, orconf); 652c3f9bad2Sdanielk1977 653c3f9bad2Sdanielk1977 /* Pop the entry off the trigger stack */ 654c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 655c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 656c3f9bad2Sdanielk1977 657c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger); 658c3f9bad2Sdanielk1977 } 659c3f9bad2Sdanielk1977 pTrigger = pTrigger->pNext; 660c3f9bad2Sdanielk1977 } 661c3f9bad2Sdanielk1977 662c3f9bad2Sdanielk1977 return 0; 663c3f9bad2Sdanielk1977 } 664c3f9bad2Sdanielk1977 665c3f9bad2Sdanielk1977 /* 666633ed08dSdanielk1977 * This function is called to code ON UPDATE and ON DELETE triggers on 667633ed08dSdanielk1977 * views. 668633ed08dSdanielk1977 * 669633ed08dSdanielk1977 * This function deletes the data pointed at by the pWhere and pChanges 670633ed08dSdanielk1977 * arguments before it completes. 671c3f9bad2Sdanielk1977 */ 672633ed08dSdanielk1977 void sqliteViewTriggers( 673633ed08dSdanielk1977 Parse *pParse, 674633ed08dSdanielk1977 Table *pTab, /* The view to code triggers on */ 675633ed08dSdanielk1977 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/ 676633ed08dSdanielk1977 int orconf, /* The ON CONFLICT policy specified as part of the 677633ed08dSdanielk1977 statement causing these triggers */ 678633ed08dSdanielk1977 ExprList *pChanges /* If this is an statement causing triggers to fire 679633ed08dSdanielk1977 is an UPDATE, then this list holds the columns 680633ed08dSdanielk1977 to update and the expressions to update them to. 681633ed08dSdanielk1977 See comments for sqliteUpdate(). */ 682633ed08dSdanielk1977 ){ 683c3f9bad2Sdanielk1977 int oldIdx = -1; 684c3f9bad2Sdanielk1977 int newIdx = -1; 685c3f9bad2Sdanielk1977 int *aXRef = 0; 686c3f9bad2Sdanielk1977 Vdbe *v; 687c3f9bad2Sdanielk1977 int endOfLoop; 688c3f9bad2Sdanielk1977 int startOfLoop; 689c3f9bad2Sdanielk1977 Select theSelect; 690c3f9bad2Sdanielk1977 Token tblNameToken; 691c3f9bad2Sdanielk1977 692c3f9bad2Sdanielk1977 assert(pTab->pSelect); 693c3f9bad2Sdanielk1977 694c3f9bad2Sdanielk1977 tblNameToken.z = pTab->zName; 695c3f9bad2Sdanielk1977 tblNameToken.n = strlen(pTab->zName); 696c3f9bad2Sdanielk1977 697c3f9bad2Sdanielk1977 theSelect.isDistinct = 0; 698c3f9bad2Sdanielk1977 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0); 699113088ecSdrh theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken, 0); 700c3f9bad2Sdanielk1977 theSelect.pWhere = pWhere; pWhere = 0; 701c3f9bad2Sdanielk1977 theSelect.pGroupBy = 0; 702c3f9bad2Sdanielk1977 theSelect.pHaving = 0; 703c3f9bad2Sdanielk1977 theSelect.pOrderBy = 0; 704c3f9bad2Sdanielk1977 theSelect.op = TK_SELECT; /* ?? */ 705c3f9bad2Sdanielk1977 theSelect.pPrior = 0; 706c3f9bad2Sdanielk1977 theSelect.nLimit = -1; 707c3f9bad2Sdanielk1977 theSelect.nOffset = -1; 708c3f9bad2Sdanielk1977 theSelect.zSelect = 0; 709c3f9bad2Sdanielk1977 theSelect.base = 0; 710c3f9bad2Sdanielk1977 711c3f9bad2Sdanielk1977 v = sqliteGetVdbe(pParse); 712c3f9bad2Sdanielk1977 assert(v); 713cabb0819Sdrh sqliteBeginWriteOperation(pParse, 1, 0); 714c3f9bad2Sdanielk1977 715c3f9bad2Sdanielk1977 /* Allocate temp tables */ 716c3f9bad2Sdanielk1977 oldIdx = pParse->nTab++; 717c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0); 718c3f9bad2Sdanielk1977 if( pChanges ){ 719c3f9bad2Sdanielk1977 newIdx = pParse->nTab++; 720c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0); 721c3f9bad2Sdanielk1977 } 722c3f9bad2Sdanielk1977 723c3f9bad2Sdanielk1977 /* Snapshot the view */ 724c3f9bad2Sdanielk1977 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){ 725c3f9bad2Sdanielk1977 goto trigger_cleanup; 726c3f9bad2Sdanielk1977 } 727c3f9bad2Sdanielk1977 728c3f9bad2Sdanielk1977 /* loop thru the view snapshot, executing triggers for each row */ 729c3f9bad2Sdanielk1977 endOfLoop = sqliteVdbeMakeLabel(v); 730c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop); 731c3f9bad2Sdanielk1977 732c3f9bad2Sdanielk1977 /* Loop thru the view snapshot, executing triggers for each row */ 733c3f9bad2Sdanielk1977 startOfLoop = sqliteVdbeCurrentAddr(v); 734c3f9bad2Sdanielk1977 735c3f9bad2Sdanielk1977 /* Build the updated row if required */ 736c3f9bad2Sdanielk1977 if( pChanges ){ 7371d1f3055Sdrh int ii; 738c3f9bad2Sdanielk1977 739c3f9bad2Sdanielk1977 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); 740c3f9bad2Sdanielk1977 if( aXRef==0 ) goto trigger_cleanup; 741633ed08dSdanielk1977 for(ii = 0; ii < pTab->nCol; ii++){ 742c3f9bad2Sdanielk1977 aXRef[ii] = -1; 743633ed08dSdanielk1977 } 744c3f9bad2Sdanielk1977 745c3f9bad2Sdanielk1977 for(ii=0; ii<pChanges->nExpr; ii++){ 746c3f9bad2Sdanielk1977 int jj; 747c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0, 748f29ce559Sdanielk1977 pChanges->a[ii].pExpr) ){ 749c3f9bad2Sdanielk1977 goto trigger_cleanup; 750f29ce559Sdanielk1977 } 751c3f9bad2Sdanielk1977 752c3f9bad2Sdanielk1977 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) ) 753c3f9bad2Sdanielk1977 goto trigger_cleanup; 754c3f9bad2Sdanielk1977 755c3f9bad2Sdanielk1977 for(jj=0; jj<pTab->nCol; jj++){ 756c3f9bad2Sdanielk1977 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){ 757c3f9bad2Sdanielk1977 aXRef[jj] = ii; 758c3f9bad2Sdanielk1977 break; 759c3f9bad2Sdanielk1977 } 760c3f9bad2Sdanielk1977 } 761c3f9bad2Sdanielk1977 if( jj>=pTab->nCol ){ 762*da93d238Sdrh sqliteErrorMsg(pParse, "no such column: %s", pChanges->a[ii].zName); 763c3f9bad2Sdanielk1977 goto trigger_cleanup; 764c3f9bad2Sdanielk1977 } 765c3f9bad2Sdanielk1977 } 766c3f9bad2Sdanielk1977 767c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Integer, 13, 0); 768c3f9bad2Sdanielk1977 769633ed08dSdanielk1977 for(ii = 0; ii<pTab->nCol; ii++){ 770633ed08dSdanielk1977 if( aXRef[ii] < 0 ){ 771c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii); 772633ed08dSdanielk1977 }else{ 773c3f9bad2Sdanielk1977 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr); 774633ed08dSdanielk1977 } 775633ed08dSdanielk1977 } 776c3f9bad2Sdanielk1977 777c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); 778c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); 779c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0); 780c3f9bad2Sdanielk1977 781c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, 7826f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 783c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, 7846f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 785c3f9bad2Sdanielk1977 }else{ 786c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, 7876f34903eSdanielk1977 orconf, endOfLoop); 788c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, 7896f34903eSdanielk1977 orconf, endOfLoop); 790c3f9bad2Sdanielk1977 } 791c3f9bad2Sdanielk1977 792c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop); 793c3f9bad2Sdanielk1977 794c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(v, endOfLoop); 795c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 796c3f9bad2Sdanielk1977 797c3f9bad2Sdanielk1977 trigger_cleanup: 798c3f9bad2Sdanielk1977 sqliteFree(aXRef); 799c3f9bad2Sdanielk1977 sqliteExprListDelete(pChanges); 800c3f9bad2Sdanielk1977 sqliteExprDelete(pWhere); 801c3f9bad2Sdanielk1977 sqliteExprListDelete(theSelect.pEList); 802ad3cab52Sdrh sqliteSrcListDelete(theSelect.pSrc); 803c3f9bad2Sdanielk1977 sqliteExprDelete(theSelect.pWhere); 804c3f9bad2Sdanielk1977 return; 805c3f9bad2Sdanielk1977 } 806