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; 52e5f9c644Sdrh char *zName = 0; /* Name of the trigger */ 53ed6c8671Sdrh 54c3f9bad2Sdanielk1977 /* Check that: 559adf9ac4Sdrh ** 1. the trigger name does not already exist. 569adf9ac4Sdrh ** 2. the table (or view) does exist. 57d702fccbSdanielk1977 ** 3. that we are not trying to create a trigger on the sqlite_master table 58d702fccbSdanielk1977 ** 4. That we are not trying to create an INSTEAD OF trigger on a table. 59d702fccbSdanielk1977 ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view. 60c3f9bad2Sdanielk1977 */ 61e5f9c644Sdrh zName = sqliteStrNDup(pName->z, pName->n); 62e5f9c644Sdrh if( sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1) ){ 63c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1, 64633ed08dSdanielk1977 pName->z, pName->n, " already exists", -1, 0); 65c3f9bad2Sdanielk1977 pParse->nErr++; 66c3f9bad2Sdanielk1977 goto trigger_cleanup; 67c3f9bad2Sdanielk1977 } 68c3f9bad2Sdanielk1977 { 69633ed08dSdanielk1977 char *tmp_str = sqliteStrNDup(pTableName->z, pTableName->n); 70e4697f5eSdrh if( tmp_str==0 ) goto trigger_cleanup; 71c3f9bad2Sdanielk1977 tab = sqliteFindTable(pParse->db, tmp_str); 72c3f9bad2Sdanielk1977 sqliteFree(tmp_str); 73c3f9bad2Sdanielk1977 if( !tab ){ 74c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1, 75633ed08dSdanielk1977 pTableName->z, pTableName->n, 0); 76c3f9bad2Sdanielk1977 pParse->nErr++; 77c3f9bad2Sdanielk1977 goto trigger_cleanup; 78c3f9bad2Sdanielk1977 } 791873cd50Sdrh if( sqliteStrICmp(tab->zName, MASTER_NAME)==0 ){ 801873cd50Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system " 811873cd50Sdrh "table: " MASTER_NAME, 0); 821873cd50Sdrh pParse->nErr++; 831873cd50Sdrh goto trigger_cleanup; 841873cd50Sdrh } 85e0bc4048Sdrh if( sqliteStrICmp(tab->zName, TEMP_MASTER_NAME)==0 ){ 86e0bc4048Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system " 87e0bc4048Sdrh "table: " TEMP_MASTER_NAME, 0); 88e0bc4048Sdrh pParse->nErr++; 89e0bc4048Sdrh goto trigger_cleanup; 90e0bc4048Sdrh } 91d702fccbSdanielk1977 if( tab->pSelect && tr_tm != TK_INSTEAD ){ 92d702fccbSdanielk1977 sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1, 93d702fccbSdanielk1977 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1 94d702fccbSdanielk1977 , pTableName->z, pTableName->n, 0); 95d702fccbSdanielk1977 goto trigger_cleanup; 96d702fccbSdanielk1977 } 97d702fccbSdanielk1977 if( !tab->pSelect && tr_tm == TK_INSTEAD ){ 98d702fccbSdanielk1977 sqliteSetNString(&pParse->zErrMsg, "cannot create INSTEAD OF", -1, 99d702fccbSdanielk1977 " trigger on table: ", -1, pTableName->z, pTableName->n, 0); 100d702fccbSdanielk1977 goto trigger_cleanup; 101d702fccbSdanielk1977 } 102e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 103e5f9c644Sdrh { 104e5f9c644Sdrh int code = SQLITE_CREATE_TRIGGER; 105e5f9c644Sdrh if( tab->isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; 106e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){ 107ed6c8671Sdrh goto trigger_cleanup; 108ed6c8671Sdrh } 109*77ad4e41Sdrh if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->isTemp), 0)){ 110*77ad4e41Sdrh goto trigger_cleanup; 111*77ad4e41Sdrh } 112d702fccbSdanielk1977 } 113e5f9c644Sdrh #endif 114e5f9c644Sdrh } 115d702fccbSdanielk1977 116d702fccbSdanielk1977 if (tr_tm == TK_INSTEAD){ 117d702fccbSdanielk1977 tr_tm = TK_BEFORE; 118c3f9bad2Sdanielk1977 } 119c3f9bad2Sdanielk1977 120c3f9bad2Sdanielk1977 /* Build the Trigger object */ 121c3f9bad2Sdanielk1977 nt = (Trigger*)sqliteMalloc(sizeof(Trigger)); 122e4697f5eSdrh if( nt==0 ) goto trigger_cleanup; 123e5f9c644Sdrh nt->name = zName; 124e5f9c644Sdrh zName = 0; 125633ed08dSdanielk1977 nt->table = sqliteStrNDup(pTableName->z, pTableName->n); 126e4697f5eSdrh if( sqlite_malloc_failed ) goto trigger_cleanup; 127c3f9bad2Sdanielk1977 nt->op = op; 128c3f9bad2Sdanielk1977 nt->tr_tm = tr_tm; 1294b59ab5eSdrh nt->pWhen = sqliteExprDup(pWhen); 1304b59ab5eSdrh sqliteExprDelete(pWhen); 1314b59ab5eSdrh nt->pColumns = sqliteIdListDup(pColumns); 1324b59ab5eSdrh sqliteIdListDelete(pColumns); 133c3f9bad2Sdanielk1977 nt->foreach = foreach; 134633ed08dSdanielk1977 nt->step_list = pStepList; 135c3f9bad2Sdanielk1977 136c3f9bad2Sdanielk1977 /* if we are not initializing, and this trigger is not on a TEMP table, 1379adf9ac4Sdrh ** build the sqlite_master entry 1389adf9ac4Sdrh */ 139e0bc4048Sdrh if( !pParse->initFlag ){ 140c977f7f5Sdrh static VdbeOp insertTrig[] = { 141c977f7f5Sdrh { OP_NewRecno, 0, 0, 0 }, 142c977f7f5Sdrh { OP_String, 0, 0, "trigger" }, 143e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 2: trigger name */ 144e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 3: table name */ 145c977f7f5Sdrh { OP_Integer, 0, 0, 0 }, 146e0bc4048Sdrh { OP_String, 0, 0, 0 }, /* 5: SQL */ 147c977f7f5Sdrh { OP_MakeRecord, 5, 0, 0 }, 148c977f7f5Sdrh { OP_PutIntKey, 0, 0, 0 }, 149c977f7f5Sdrh }; 150c977f7f5Sdrh int addr; 151c977f7f5Sdrh Vdbe *v; 152c3f9bad2Sdanielk1977 153c3f9bad2Sdanielk1977 /* Make an entry in the sqlite_master table */ 154c977f7f5Sdrh v = sqliteGetVdbe(pParse); 155e4697f5eSdrh if( v==0 ) goto trigger_cleanup; 156cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 157e0bc4048Sdrh sqliteOpenMasterTable(v, tab->isTemp); 158c977f7f5Sdrh addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); 159e0bc4048Sdrh sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME, 160e0bc4048Sdrh P3_STATIC); 161e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 162e0bc4048Sdrh sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 1634b59ab5eSdrh sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n); 164e0bc4048Sdrh if( !tab->isTemp ){ 165e0bc4048Sdrh sqliteChangeCookie(pParse->db, v); 166e0bc4048Sdrh } 167e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 168c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 169c3f9bad2Sdanielk1977 } 170c3f9bad2Sdanielk1977 171c3f9bad2Sdanielk1977 if( !pParse->explain ){ 172c3f9bad2Sdanielk1977 /* Stick it in the hash-table */ 173633ed08dSdanielk1977 sqliteHashInsert(&(pParse->db->trigHash), nt->name, pName->n + 1, nt); 174c3f9bad2Sdanielk1977 175c3f9bad2Sdanielk1977 /* Attach it to the table object */ 176c3f9bad2Sdanielk1977 nt->pNext = tab->pTrigger; 177c3f9bad2Sdanielk1977 tab->pTrigger = nt; 178c3f9bad2Sdanielk1977 return; 179c3f9bad2Sdanielk1977 }else{ 180c3f9bad2Sdanielk1977 sqliteFree(nt->name); 181c3f9bad2Sdanielk1977 sqliteFree(nt->table); 182c3f9bad2Sdanielk1977 sqliteFree(nt); 183c3f9bad2Sdanielk1977 } 184c3f9bad2Sdanielk1977 185c3f9bad2Sdanielk1977 trigger_cleanup: 186c3f9bad2Sdanielk1977 187e5f9c644Sdrh sqliteFree(zName); 188633ed08dSdanielk1977 sqliteIdListDelete(pColumns); 189c3f9bad2Sdanielk1977 sqliteExprDelete(pWhen); 1904b59ab5eSdrh sqliteDeleteTriggerStep(pStepList); 191c3f9bad2Sdanielk1977 } 1924b59ab5eSdrh 1934b59ab5eSdrh /* 1944b59ab5eSdrh ** Make a copy of all components of the given trigger step. This has 1954b59ab5eSdrh ** the effect of copying all Expr.token.z values into memory obtained 1964b59ab5eSdrh ** from sqliteMalloc(). As initially created, the Expr.token.z values 1974b59ab5eSdrh ** all point to the input string that was fed to the parser. But that 1984b59ab5eSdrh ** string is ephemeral - it will go away as soon as the sqlite_exec() 1994b59ab5eSdrh ** call that started the parser exits. This routine makes a persistent 2004b59ab5eSdrh ** copy of all the Expr.token.z strings so that the TriggerStep structure 2014b59ab5eSdrh ** will be valid even after the sqlite_exec() call returns. 2024b59ab5eSdrh */ 2034b59ab5eSdrh static void sqlitePersistTriggerStep(TriggerStep *p){ 2044b59ab5eSdrh if( p->target.z ){ 2054b59ab5eSdrh p->target.z = sqliteStrNDup(p->target.z, p->target.n); 2064b59ab5eSdrh p->target.dyn = 1; 2074b59ab5eSdrh } 2084b59ab5eSdrh if( p->pSelect ){ 2094b59ab5eSdrh Select *pNew = sqliteSelectDup(p->pSelect); 2104b59ab5eSdrh sqliteSelectDelete(p->pSelect); 2114b59ab5eSdrh p->pSelect = pNew; 2124b59ab5eSdrh } 2134b59ab5eSdrh if( p->pWhere ){ 2144b59ab5eSdrh Expr *pNew = sqliteExprDup(p->pWhere); 2154b59ab5eSdrh sqliteExprDelete(p->pWhere); 2164b59ab5eSdrh p->pWhere = pNew; 2174b59ab5eSdrh } 2184b59ab5eSdrh if( p->pExprList ){ 2194b59ab5eSdrh ExprList *pNew = sqliteExprListDup(p->pExprList); 2204b59ab5eSdrh sqliteExprListDelete(p->pExprList); 2214b59ab5eSdrh p->pExprList = pNew; 2224b59ab5eSdrh } 2234b59ab5eSdrh if( p->pIdList ){ 2244b59ab5eSdrh IdList *pNew = sqliteIdListDup(p->pIdList); 2254b59ab5eSdrh sqliteIdListDelete(p->pIdList); 2264b59ab5eSdrh p->pIdList = pNew; 227c3f9bad2Sdanielk1977 } 228c3f9bad2Sdanielk1977 } 229c3f9bad2Sdanielk1977 230c977f7f5Sdrh /* 231c977f7f5Sdrh ** Turn a SELECT statement (that the pSelect parameter points to) into 232c977f7f5Sdrh ** a trigger step. Return a pointer to a TriggerStep structure. 233c977f7f5Sdrh ** 234c977f7f5Sdrh ** The parser calls this routine when it finds a SELECT statement in 235c977f7f5Sdrh ** body of a TRIGGER. 236c977f7f5Sdrh */ 237c977f7f5Sdrh TriggerStep *sqliteTriggerSelectStep(Select *pSelect){ 238633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 239e4697f5eSdrh if( pTriggerStep==0 ) return 0; 240c3f9bad2Sdanielk1977 241633ed08dSdanielk1977 pTriggerStep->op = TK_SELECT; 242633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 243633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 2444b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 245c3f9bad2Sdanielk1977 246633ed08dSdanielk1977 return pTriggerStep; 247c3f9bad2Sdanielk1977 } 248c3f9bad2Sdanielk1977 249c977f7f5Sdrh /* 250c977f7f5Sdrh ** Build a trigger step out of an INSERT statement. Return a pointer 251c977f7f5Sdrh ** to the new trigger step. 252c977f7f5Sdrh ** 253c977f7f5Sdrh ** The parser calls this routine when it sees an INSERT inside the 254c977f7f5Sdrh ** body of a trigger. 255c977f7f5Sdrh */ 256633ed08dSdanielk1977 TriggerStep *sqliteTriggerInsertStep( 257c977f7f5Sdrh Token *pTableName, /* Name of the table into which we insert */ 258c977f7f5Sdrh IdList *pColumn, /* List of columns in pTableName to insert into */ 259c977f7f5Sdrh ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ 260c977f7f5Sdrh Select *pSelect, /* A SELECT statement that supplies values */ 261c977f7f5Sdrh int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ 262633ed08dSdanielk1977 ){ 263633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 264e4697f5eSdrh if( pTriggerStep==0 ) return 0; 265c3f9bad2Sdanielk1977 266633ed08dSdanielk1977 assert(pEList == 0 || pSelect == 0); 267633ed08dSdanielk1977 assert(pEList != 0 || pSelect != 0); 268c3f9bad2Sdanielk1977 269633ed08dSdanielk1977 pTriggerStep->op = TK_INSERT; 270633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 271633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 272633ed08dSdanielk1977 pTriggerStep->pIdList = pColumn; 273633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 274633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2754b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 276c3f9bad2Sdanielk1977 277633ed08dSdanielk1977 return pTriggerStep; 278c3f9bad2Sdanielk1977 } 279c3f9bad2Sdanielk1977 280c977f7f5Sdrh /* 281c977f7f5Sdrh ** Construct a trigger step that implements an UPDATE statement and return 282c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 283c977f7f5Sdrh ** sees an UPDATE statement inside the body of a CREATE TRIGGER. 284c977f7f5Sdrh */ 285633ed08dSdanielk1977 TriggerStep *sqliteTriggerUpdateStep( 286c977f7f5Sdrh Token *pTableName, /* Name of the table to be updated */ 287c977f7f5Sdrh ExprList *pEList, /* The SET clause: list of column and new values */ 288c977f7f5Sdrh Expr *pWhere, /* The WHERE clause */ 289c977f7f5Sdrh int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ 290c977f7f5Sdrh ){ 291633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 292e4697f5eSdrh if( pTriggerStep==0 ) return 0; 293c3f9bad2Sdanielk1977 294633ed08dSdanielk1977 pTriggerStep->op = TK_UPDATE; 295633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 296633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 297633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 298633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 2994b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 300c3f9bad2Sdanielk1977 301633ed08dSdanielk1977 return pTriggerStep; 302c3f9bad2Sdanielk1977 } 303c3f9bad2Sdanielk1977 304c977f7f5Sdrh /* 305c977f7f5Sdrh ** Construct a trigger step that implements a DELETE statement and return 306c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 307c977f7f5Sdrh ** sees a DELETE statement inside the body of a CREATE TRIGGER. 308c977f7f5Sdrh */ 309c977f7f5Sdrh TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){ 310633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 311e4697f5eSdrh if( pTriggerStep==0 ) return 0; 312c3f9bad2Sdanielk1977 313633ed08dSdanielk1977 pTriggerStep->op = TK_DELETE; 314633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 315633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 316633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 3174b59ab5eSdrh sqlitePersistTriggerStep(pTriggerStep); 318c3f9bad2Sdanielk1977 319633ed08dSdanielk1977 return pTriggerStep; 320c3f9bad2Sdanielk1977 } 321c3f9bad2Sdanielk1977 322c3f9bad2Sdanielk1977 /* 323633ed08dSdanielk1977 ** Recursively delete a Trigger structure 324c3f9bad2Sdanielk1977 */ 3251d1f3055Sdrh void sqliteDeleteTrigger(Trigger *pTrigger){ 3264b59ab5eSdrh sqliteDeleteTriggerStep(pTrigger->step_list); 327633ed08dSdanielk1977 sqliteFree(pTrigger->name); 328633ed08dSdanielk1977 sqliteFree(pTrigger->table); 329633ed08dSdanielk1977 sqliteExprDelete(pTrigger->pWhen); 330633ed08dSdanielk1977 sqliteIdListDelete(pTrigger->pColumns); 331633ed08dSdanielk1977 sqliteFree(pTrigger); 332633ed08dSdanielk1977 } 333633ed08dSdanielk1977 334633ed08dSdanielk1977 /* 335633ed08dSdanielk1977 * This function is called to drop a trigger from the database schema. 336633ed08dSdanielk1977 * 337633ed08dSdanielk1977 * This may be called directly from the parser, or from within 338633ed08dSdanielk1977 * sqliteDropTable(). In the latter case the "nested" argument is true. 339633ed08dSdanielk1977 * 340633ed08dSdanielk1977 * Note that this function does not delete the trigger entirely. Instead it 341633ed08dSdanielk1977 * removes it from the internal schema and places it in the trigDrop hash 342633ed08dSdanielk1977 * table. This is so that the trigger can be restored into the database schema 343633ed08dSdanielk1977 * if the transaction is rolled back. 344633ed08dSdanielk1977 */ 345e0bc4048Sdrh void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){ 346633ed08dSdanielk1977 char *zName; 347633ed08dSdanielk1977 Trigger *pTrigger; 348633ed08dSdanielk1977 Table *pTable; 349e0bc4048Sdrh Vdbe *v; 350633ed08dSdanielk1977 351633ed08dSdanielk1977 zName = sqliteStrNDup(pName->z, pName->n); 352c3f9bad2Sdanielk1977 353c3f9bad2Sdanielk1977 /* ensure that the trigger being dropped exists */ 354633ed08dSdanielk1977 pTrigger = sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1); 355633ed08dSdanielk1977 if( !pTrigger ){ 356c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1, 357633ed08dSdanielk1977 zName, -1, 0); 358633ed08dSdanielk1977 sqliteFree(zName); 359c3f9bad2Sdanielk1977 return; 360c3f9bad2Sdanielk1977 } 361ed6c8671Sdrh pTable = sqliteFindTable(pParse->db, pTrigger->table); 362ed6c8671Sdrh assert(pTable); 363e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 364e5f9c644Sdrh { 365e5f9c644Sdrh int code = SQLITE_DROP_TRIGGER; 366e5f9c644Sdrh if( pTable->isTemp ) code = SQLITE_DROP_TEMP_TRIGGER; 367e5f9c644Sdrh if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) || 368e5f9c644Sdrh sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->isTemp),0) ){ 369ed6c8671Sdrh sqliteFree(zName); 370ed6c8671Sdrh return; 371ed6c8671Sdrh } 372e5f9c644Sdrh } 373e5f9c644Sdrh #endif 374c3f9bad2Sdanielk1977 375c3f9bad2Sdanielk1977 /* 376e0bc4048Sdrh * If this is not an "explain", then delete the trigger structure. 377c3f9bad2Sdanielk1977 */ 378c3f9bad2Sdanielk1977 if( !pParse->explain ){ 379633ed08dSdanielk1977 if( pTable->pTrigger == pTrigger ){ 380633ed08dSdanielk1977 pTable->pTrigger = pTrigger->pNext; 381633ed08dSdanielk1977 }else{ 382633ed08dSdanielk1977 Trigger *cc = pTable->pTrigger; 383c3f9bad2Sdanielk1977 while( cc ){ 384633ed08dSdanielk1977 if( cc->pNext == pTrigger ){ 385c3f9bad2Sdanielk1977 cc->pNext = cc->pNext->pNext; 386c3f9bad2Sdanielk1977 break; 387c3f9bad2Sdanielk1977 } 388c3f9bad2Sdanielk1977 cc = cc->pNext; 389c3f9bad2Sdanielk1977 } 390c3f9bad2Sdanielk1977 assert(cc); 391c3f9bad2Sdanielk1977 } 392e0bc4048Sdrh sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL); 393e0bc4048Sdrh sqliteDeleteTrigger(pTrigger); 394c3f9bad2Sdanielk1977 } 395c3f9bad2Sdanielk1977 396e0bc4048Sdrh /* Generate code to destroy the database record of the trigger. 397e0bc4048Sdrh */ 398e0bc4048Sdrh if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){ 399c3f9bad2Sdanielk1977 int base; 400c3f9bad2Sdanielk1977 static VdbeOp dropTrigger[] = { 401e0bc4048Sdrh { OP_Rewind, 0, ADDR(8), 0}, 402e0bc4048Sdrh { OP_String, 0, 0, 0}, /* 1 */ 403c3f9bad2Sdanielk1977 { OP_MemStore, 1, 1, 0}, 404e0bc4048Sdrh { OP_MemLoad, 1, 0, 0}, /* 3 */ 405c3f9bad2Sdanielk1977 { OP_Column, 0, 1, 0}, 406e0bc4048Sdrh { OP_Ne, 0, ADDR(7), 0}, 407c3f9bad2Sdanielk1977 { OP_Delete, 0, 0, 0}, 408e0bc4048Sdrh { OP_Next, 0, ADDR(3), 0}, /* 7 */ 409c3f9bad2Sdanielk1977 }; 410c3f9bad2Sdanielk1977 411cabb0819Sdrh sqliteBeginWriteOperation(pParse, 0, 0); 412e0bc4048Sdrh sqliteOpenMasterTable(v, pTable->isTemp); 413e0bc4048Sdrh base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); 414e0bc4048Sdrh sqliteVdbeChangeP3(v, base+1, zName, 0); 415e0bc4048Sdrh if( !pTable->isTemp ){ 416e0bc4048Sdrh sqliteChangeCookie(pParse->db, v); 417dc379456Sdrh } 418e0bc4048Sdrh sqliteVdbeAddOp(v, OP_Close, 0, 0); 419c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 420c3f9bad2Sdanielk1977 } 421c3f9bad2Sdanielk1977 422633ed08dSdanielk1977 sqliteFree(zName); 423c3f9bad2Sdanielk1977 } 424c3f9bad2Sdanielk1977 425c977f7f5Sdrh /* 426c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement. Each entry 427c977f7f5Sdrh ** in pEList is of the format <id>=<expr>. If any of the entries 428c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList, 429c977f7f5Sdrh ** then return TRUE. If pIdList==NULL, then it is considered a 430c977f7f5Sdrh ** wildcard that matches anything. Likewise if pEList==NULL then 431c977f7f5Sdrh ** it matches anything so always return true. Return false only 432c977f7f5Sdrh ** if there is no match. 433c977f7f5Sdrh */ 434c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){ 435ad2d8307Sdrh int e; 436ad2d8307Sdrh if( !pIdList || !pEList ) return 1; 437f29ce559Sdanielk1977 for(e=0; e<pEList->nExpr; e++){ 438ad2d8307Sdrh if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; 439f29ce559Sdanielk1977 } 440c3f9bad2Sdanielk1977 return 0; 441c3f9bad2Sdanielk1977 } 442c3f9bad2Sdanielk1977 443c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for 444c3f9bad2Sdanielk1977 * for triggers, even if there are no triggers to code. This is used to test 445c3f9bad2Sdanielk1977 * how much overhead the triggers algorithm is causing. 446c3f9bad2Sdanielk1977 * 447c3f9bad2Sdanielk1977 * This flag can be set or cleared using the "trigger_overhead_test" pragma. 448c3f9bad2Sdanielk1977 * The pragma is not documented since it is not really part of the interface 449c3f9bad2Sdanielk1977 * to SQLite, just the test procedure. 450c3f9bad2Sdanielk1977 */ 451c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0; 452c3f9bad2Sdanielk1977 453c3f9bad2Sdanielk1977 /* 454c3f9bad2Sdanielk1977 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already 455c3f9bad2Sdanielk1977 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is 456c3f9bad2Sdanielk1977 * found in the list specified as pTrigger. 457c3f9bad2Sdanielk1977 */ 458c3f9bad2Sdanielk1977 int sqliteTriggersExist( 459c977f7f5Sdrh Parse *pParse, /* Used to check for recursive triggers */ 460c977f7f5Sdrh Trigger *pTrigger, /* A list of triggers associated with a table */ 461c3f9bad2Sdanielk1977 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ 462c3f9bad2Sdanielk1977 int tr_tm, /* one of TK_BEFORE, TK_AFTER */ 463c3f9bad2Sdanielk1977 int foreach, /* one of TK_ROW or TK_STATEMENT */ 464c977f7f5Sdrh ExprList *pChanges /* Columns that change in an UPDATE statement */ 465c977f7f5Sdrh ){ 466633ed08dSdanielk1977 Trigger * pTriggerCursor; 467c3f9bad2Sdanielk1977 468633ed08dSdanielk1977 if( always_code_trigger_setup ){ 469633ed08dSdanielk1977 return 1; 470633ed08dSdanielk1977 } 471c3f9bad2Sdanielk1977 472633ed08dSdanielk1977 pTriggerCursor = pTrigger; 473633ed08dSdanielk1977 while( pTriggerCursor ){ 474633ed08dSdanielk1977 if( pTriggerCursor->op == op && 475633ed08dSdanielk1977 pTriggerCursor->tr_tm == tr_tm && 476633ed08dSdanielk1977 pTriggerCursor->foreach == foreach && 477633ed08dSdanielk1977 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){ 478c3f9bad2Sdanielk1977 TriggerStack * ss; 479c3f9bad2Sdanielk1977 ss = pParse->trigStack; 480f29ce559Sdanielk1977 while( ss && ss->pTrigger != pTrigger ){ 481f29ce559Sdanielk1977 ss = ss->pNext; 482f29ce559Sdanielk1977 } 483c3f9bad2Sdanielk1977 if( !ss )return 1; 484c3f9bad2Sdanielk1977 } 485633ed08dSdanielk1977 pTriggerCursor = pTriggerCursor->pNext; 486c3f9bad2Sdanielk1977 } 487c3f9bad2Sdanielk1977 488c3f9bad2Sdanielk1977 return 0; 489c3f9bad2Sdanielk1977 } 490c3f9bad2Sdanielk1977 491c977f7f5Sdrh /* 492c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a 493c977f7f5Sdrh ** trigger. 494c977f7f5Sdrh */ 495c3f9bad2Sdanielk1977 static int codeTriggerProgram( 496c977f7f5Sdrh Parse *pParse, /* The parser context */ 497c977f7f5Sdrh TriggerStep *pStepList, /* List of statements inside the trigger body */ 498c977f7f5Sdrh int orconfin /* Conflict algorithm. (OE_Abort, etc) */ 499633ed08dSdanielk1977 ){ 500633ed08dSdanielk1977 TriggerStep * pTriggerStep = pStepList; 501c3f9bad2Sdanielk1977 int orconf; 502c3f9bad2Sdanielk1977 503633ed08dSdanielk1977 while( pTriggerStep ){ 504c3f9bad2Sdanielk1977 int saveNTab = pParse->nTab; 505633ed08dSdanielk1977 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; 506c3f9bad2Sdanielk1977 pParse->trigStack->orconf = orconf; 507633ed08dSdanielk1977 switch( pTriggerStep->op ){ 508c3f9bad2Sdanielk1977 case TK_SELECT: { 5096f34903eSdanielk1977 Select * ss = sqliteSelectDup(pTriggerStep->pSelect); 5106f34903eSdanielk1977 assert(ss); 5116f34903eSdanielk1977 assert(ss->pSrc); 5126f34903eSdanielk1977 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0); 5136f34903eSdanielk1977 sqliteSelectDelete(ss); 514c3f9bad2Sdanielk1977 break; 515c3f9bad2Sdanielk1977 } 516c3f9bad2Sdanielk1977 case TK_UPDATE: { 517bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 518633ed08dSdanielk1977 sqliteUpdate(pParse, &pTriggerStep->target, 519633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 520633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere), orconf); 521bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 522c3f9bad2Sdanielk1977 break; 523c3f9bad2Sdanielk1977 } 524c3f9bad2Sdanielk1977 case TK_INSERT: { 525633ed08dSdanielk1977 sqliteInsert(pParse, &pTriggerStep->target, 526633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 527633ed08dSdanielk1977 sqliteSelectDup(pTriggerStep->pSelect), 528633ed08dSdanielk1977 sqliteIdListDup(pTriggerStep->pIdList), orconf); 529c3f9bad2Sdanielk1977 break; 530c3f9bad2Sdanielk1977 } 531c3f9bad2Sdanielk1977 case TK_DELETE: { 532bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 533633ed08dSdanielk1977 sqliteDeleteFrom(pParse, &pTriggerStep->target, 534633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere)); 535bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 536c3f9bad2Sdanielk1977 break; 537c3f9bad2Sdanielk1977 } 538c3f9bad2Sdanielk1977 default: 539c3f9bad2Sdanielk1977 assert(0); 540c3f9bad2Sdanielk1977 } 541c3f9bad2Sdanielk1977 pParse->nTab = saveNTab; 542633ed08dSdanielk1977 pTriggerStep = pTriggerStep->pNext; 543c3f9bad2Sdanielk1977 } 544c3f9bad2Sdanielk1977 545c3f9bad2Sdanielk1977 return 0; 546c3f9bad2Sdanielk1977 } 547c3f9bad2Sdanielk1977 548633ed08dSdanielk1977 /* 549633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers. 550633ed08dSdanielk1977 ** 551633ed08dSdanielk1977 ** When the code that this function generates is executed, the following 552633ed08dSdanielk1977 ** must be true: 553c977f7f5Sdrh ** 554c977f7f5Sdrh ** 1. No cursors may be open in the main database. (But newIdx and oldIdx 555c977f7f5Sdrh ** can be indices of cursors in temporary tables. See below.) 556c977f7f5Sdrh ** 557633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then 558633ed08dSdanielk1977 ** a temporary vdbe cursor (index newIdx) must be open and pointing at 559633ed08dSdanielk1977 ** a row containing values to be substituted for new.* expressions in the 560633ed08dSdanielk1977 ** trigger program(s). 561c977f7f5Sdrh ** 562633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then 563633ed08dSdanielk1977 ** a temporary vdbe cursor (index oldIdx) must be open and pointing at 564633ed08dSdanielk1977 ** a row containing values to be substituted for old.* expressions in the 565633ed08dSdanielk1977 ** trigger program(s). 566633ed08dSdanielk1977 ** 567633ed08dSdanielk1977 */ 568c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger( 569c3f9bad2Sdanielk1977 Parse *pParse, /* Parse context */ 570c3f9bad2Sdanielk1977 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ 571633ed08dSdanielk1977 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ 572c3f9bad2Sdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER */ 573633ed08dSdanielk1977 Table *pTab, /* The table to code triggers from */ 574633ed08dSdanielk1977 int newIdx, /* The indice of the "new" row to access */ 575633ed08dSdanielk1977 int oldIdx, /* The indice of the "old" row to access */ 5766f34903eSdanielk1977 int orconf, /* ON CONFLICT policy */ 5776f34903eSdanielk1977 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ 578c977f7f5Sdrh ){ 579c3f9bad2Sdanielk1977 Trigger * pTrigger; 580c3f9bad2Sdanielk1977 TriggerStack * pTriggerStack; 581c3f9bad2Sdanielk1977 582c3f9bad2Sdanielk1977 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); 583c3f9bad2Sdanielk1977 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER); 584c3f9bad2Sdanielk1977 585633ed08dSdanielk1977 assert(newIdx != -1 || oldIdx != -1); 586c3f9bad2Sdanielk1977 587633ed08dSdanielk1977 pTrigger = pTab->pTrigger; 588c3f9bad2Sdanielk1977 while( pTrigger ){ 589c3f9bad2Sdanielk1977 int fire_this = 0; 590c3f9bad2Sdanielk1977 591c3f9bad2Sdanielk1977 /* determine whether we should code this trigger */ 592c3f9bad2Sdanielk1977 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 593c3f9bad2Sdanielk1977 pTrigger->foreach == TK_ROW ){ 594c3f9bad2Sdanielk1977 fire_this = 1; 595c3f9bad2Sdanielk1977 pTriggerStack = pParse->trigStack; 596c3f9bad2Sdanielk1977 while( pTriggerStack ){ 597f29ce559Sdanielk1977 if( pTriggerStack->pTrigger == pTrigger ){ 598f29ce559Sdanielk1977 fire_this = 0; 599f29ce559Sdanielk1977 } 600c3f9bad2Sdanielk1977 pTriggerStack = pTriggerStack->pNext; 601c3f9bad2Sdanielk1977 } 602c3f9bad2Sdanielk1977 if( op == TK_UPDATE && pTrigger->pColumns && 603f29ce559Sdanielk1977 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){ 604c3f9bad2Sdanielk1977 fire_this = 0; 605c3f9bad2Sdanielk1977 } 606f29ce559Sdanielk1977 } 607c3f9bad2Sdanielk1977 608e4697f5eSdrh if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){ 609c3f9bad2Sdanielk1977 int endTrigger; 610ad3cab52Sdrh SrcList dummyTablist; 611c3f9bad2Sdanielk1977 Expr * whenExpr; 612c3f9bad2Sdanielk1977 613ad3cab52Sdrh dummyTablist.nSrc = 0; 614c3f9bad2Sdanielk1977 dummyTablist.a = 0; 615c3f9bad2Sdanielk1977 616c3f9bad2Sdanielk1977 /* Push an entry on to the trigger stack */ 617c3f9bad2Sdanielk1977 pTriggerStack->pTrigger = pTrigger; 618633ed08dSdanielk1977 pTriggerStack->newIdx = newIdx; 619633ed08dSdanielk1977 pTriggerStack->oldIdx = oldIdx; 620633ed08dSdanielk1977 pTriggerStack->pTab = pTab; 621c3f9bad2Sdanielk1977 pTriggerStack->pNext = pParse->trigStack; 6226f34903eSdanielk1977 pTriggerStack->ignoreJump = ignoreJump; 623c3f9bad2Sdanielk1977 pParse->trigStack = pTriggerStack; 624c3f9bad2Sdanielk1977 625c3f9bad2Sdanielk1977 /* code the WHEN clause */ 626c3f9bad2Sdanielk1977 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); 627c3f9bad2Sdanielk1977 whenExpr = sqliteExprDup(pTrigger->pWhen); 628c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ 629c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 630c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 631c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 632c3f9bad2Sdanielk1977 return 1; 633c3f9bad2Sdanielk1977 } 634f5905aa7Sdrh sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); 635c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 636c3f9bad2Sdanielk1977 637633ed08dSdanielk1977 codeTriggerProgram(pParse, pTrigger->step_list, orconf); 638c3f9bad2Sdanielk1977 639c3f9bad2Sdanielk1977 /* Pop the entry off the trigger stack */ 640c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 641c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 642c3f9bad2Sdanielk1977 643c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger); 644c3f9bad2Sdanielk1977 } 645c3f9bad2Sdanielk1977 pTrigger = pTrigger->pNext; 646c3f9bad2Sdanielk1977 } 647c3f9bad2Sdanielk1977 648c3f9bad2Sdanielk1977 return 0; 649c3f9bad2Sdanielk1977 } 650c3f9bad2Sdanielk1977 651c3f9bad2Sdanielk1977 /* 652633ed08dSdanielk1977 * This function is called to code ON UPDATE and ON DELETE triggers on 653633ed08dSdanielk1977 * views. 654633ed08dSdanielk1977 * 655633ed08dSdanielk1977 * This function deletes the data pointed at by the pWhere and pChanges 656633ed08dSdanielk1977 * arguments before it completes. 657c3f9bad2Sdanielk1977 */ 658633ed08dSdanielk1977 void sqliteViewTriggers( 659633ed08dSdanielk1977 Parse *pParse, 660633ed08dSdanielk1977 Table *pTab, /* The view to code triggers on */ 661633ed08dSdanielk1977 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/ 662633ed08dSdanielk1977 int orconf, /* The ON CONFLICT policy specified as part of the 663633ed08dSdanielk1977 statement causing these triggers */ 664633ed08dSdanielk1977 ExprList *pChanges /* If this is an statement causing triggers to fire 665633ed08dSdanielk1977 is an UPDATE, then this list holds the columns 666633ed08dSdanielk1977 to update and the expressions to update them to. 667633ed08dSdanielk1977 See comments for sqliteUpdate(). */ 668633ed08dSdanielk1977 ){ 669c3f9bad2Sdanielk1977 int oldIdx = -1; 670c3f9bad2Sdanielk1977 int newIdx = -1; 671c3f9bad2Sdanielk1977 int *aXRef = 0; 672c3f9bad2Sdanielk1977 Vdbe *v; 673c3f9bad2Sdanielk1977 int endOfLoop; 674c3f9bad2Sdanielk1977 int startOfLoop; 675c3f9bad2Sdanielk1977 Select theSelect; 676c3f9bad2Sdanielk1977 Token tblNameToken; 677c3f9bad2Sdanielk1977 678c3f9bad2Sdanielk1977 assert(pTab->pSelect); 679c3f9bad2Sdanielk1977 680c3f9bad2Sdanielk1977 tblNameToken.z = pTab->zName; 681c3f9bad2Sdanielk1977 tblNameToken.n = strlen(pTab->zName); 682c3f9bad2Sdanielk1977 683c3f9bad2Sdanielk1977 theSelect.isDistinct = 0; 684c3f9bad2Sdanielk1977 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0); 685ad3cab52Sdrh theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken); 686c3f9bad2Sdanielk1977 theSelect.pWhere = pWhere; pWhere = 0; 687c3f9bad2Sdanielk1977 theSelect.pGroupBy = 0; 688c3f9bad2Sdanielk1977 theSelect.pHaving = 0; 689c3f9bad2Sdanielk1977 theSelect.pOrderBy = 0; 690c3f9bad2Sdanielk1977 theSelect.op = TK_SELECT; /* ?? */ 691c3f9bad2Sdanielk1977 theSelect.pPrior = 0; 692c3f9bad2Sdanielk1977 theSelect.nLimit = -1; 693c3f9bad2Sdanielk1977 theSelect.nOffset = -1; 694c3f9bad2Sdanielk1977 theSelect.zSelect = 0; 695c3f9bad2Sdanielk1977 theSelect.base = 0; 696c3f9bad2Sdanielk1977 697c3f9bad2Sdanielk1977 v = sqliteGetVdbe(pParse); 698c3f9bad2Sdanielk1977 assert(v); 699cabb0819Sdrh sqliteBeginWriteOperation(pParse, 1, 0); 700c3f9bad2Sdanielk1977 701c3f9bad2Sdanielk1977 /* Allocate temp tables */ 702c3f9bad2Sdanielk1977 oldIdx = pParse->nTab++; 703c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0); 704c3f9bad2Sdanielk1977 if( pChanges ){ 705c3f9bad2Sdanielk1977 newIdx = pParse->nTab++; 706c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0); 707c3f9bad2Sdanielk1977 } 708c3f9bad2Sdanielk1977 709c3f9bad2Sdanielk1977 /* Snapshot the view */ 710c3f9bad2Sdanielk1977 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){ 711c3f9bad2Sdanielk1977 goto trigger_cleanup; 712c3f9bad2Sdanielk1977 } 713c3f9bad2Sdanielk1977 714c3f9bad2Sdanielk1977 /* loop thru the view snapshot, executing triggers for each row */ 715c3f9bad2Sdanielk1977 endOfLoop = sqliteVdbeMakeLabel(v); 716c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop); 717c3f9bad2Sdanielk1977 718c3f9bad2Sdanielk1977 /* Loop thru the view snapshot, executing triggers for each row */ 719c3f9bad2Sdanielk1977 startOfLoop = sqliteVdbeCurrentAddr(v); 720c3f9bad2Sdanielk1977 721c3f9bad2Sdanielk1977 /* Build the updated row if required */ 722c3f9bad2Sdanielk1977 if( pChanges ){ 7231d1f3055Sdrh int ii; 724c3f9bad2Sdanielk1977 725c3f9bad2Sdanielk1977 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); 726c3f9bad2Sdanielk1977 if( aXRef==0 ) goto trigger_cleanup; 727633ed08dSdanielk1977 for(ii = 0; ii < pTab->nCol; ii++){ 728c3f9bad2Sdanielk1977 aXRef[ii] = -1; 729633ed08dSdanielk1977 } 730c3f9bad2Sdanielk1977 731c3f9bad2Sdanielk1977 for(ii=0; ii<pChanges->nExpr; ii++){ 732c3f9bad2Sdanielk1977 int jj; 733c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0, 734f29ce559Sdanielk1977 pChanges->a[ii].pExpr) ){ 735c3f9bad2Sdanielk1977 goto trigger_cleanup; 736f29ce559Sdanielk1977 } 737c3f9bad2Sdanielk1977 738c3f9bad2Sdanielk1977 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) ) 739c3f9bad2Sdanielk1977 goto trigger_cleanup; 740c3f9bad2Sdanielk1977 741c3f9bad2Sdanielk1977 for(jj=0; jj<pTab->nCol; jj++){ 742c3f9bad2Sdanielk1977 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){ 743c3f9bad2Sdanielk1977 aXRef[jj] = ii; 744c3f9bad2Sdanielk1977 break; 745c3f9bad2Sdanielk1977 } 746c3f9bad2Sdanielk1977 } 747c3f9bad2Sdanielk1977 if( jj>=pTab->nCol ){ 748c3f9bad2Sdanielk1977 sqliteSetString(&pParse->zErrMsg, "no such column: ", 749c3f9bad2Sdanielk1977 pChanges->a[ii].zName, 0); 750c3f9bad2Sdanielk1977 pParse->nErr++; 751c3f9bad2Sdanielk1977 goto trigger_cleanup; 752c3f9bad2Sdanielk1977 } 753c3f9bad2Sdanielk1977 } 754c3f9bad2Sdanielk1977 755c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Integer, 13, 0); 756c3f9bad2Sdanielk1977 757633ed08dSdanielk1977 for(ii = 0; ii<pTab->nCol; ii++){ 758633ed08dSdanielk1977 if( aXRef[ii] < 0 ){ 759c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii); 760633ed08dSdanielk1977 }else{ 761c3f9bad2Sdanielk1977 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr); 762633ed08dSdanielk1977 } 763633ed08dSdanielk1977 } 764c3f9bad2Sdanielk1977 765c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); 766c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); 767c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0); 768c3f9bad2Sdanielk1977 769c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, 7706f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 771c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, 7726f34903eSdanielk1977 pTab, newIdx, oldIdx, orconf, endOfLoop); 773c3f9bad2Sdanielk1977 }else{ 774c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, 7756f34903eSdanielk1977 orconf, endOfLoop); 776c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, 7776f34903eSdanielk1977 orconf, endOfLoop); 778c3f9bad2Sdanielk1977 } 779c3f9bad2Sdanielk1977 780c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop); 781c3f9bad2Sdanielk1977 782c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(v, endOfLoop); 783c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 784c3f9bad2Sdanielk1977 785c3f9bad2Sdanielk1977 trigger_cleanup: 786c3f9bad2Sdanielk1977 sqliteFree(aXRef); 787c3f9bad2Sdanielk1977 sqliteExprListDelete(pChanges); 788c3f9bad2Sdanielk1977 sqliteExprDelete(pWhere); 789c3f9bad2Sdanielk1977 sqliteExprListDelete(theSelect.pEList); 790ad3cab52Sdrh sqliteSrcListDelete(theSelect.pSrc); 791c3f9bad2Sdanielk1977 sqliteExprDelete(theSelect.pWhere); 792c3f9bad2Sdanielk1977 return; 793c3f9bad2Sdanielk1977 } 794