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 /* 16633ed08dSdanielk1977 ** This is called by the parser when it sees a CREATE TRIGGER statement. See 17633ed08dSdanielk1977 ** comments surrounding struct Trigger in sqliteInt.h for a description of 18633ed08dSdanielk1977 ** how triggers are stored. 19c3f9bad2Sdanielk1977 */ 209adf9ac4Sdrh void sqliteCreateTrigger( 21c3f9bad2Sdanielk1977 Parse *pParse, /* The parse context of the CREATE TRIGGER statement */ 22633ed08dSdanielk1977 Token *pName, /* The name of the trigger */ 23c3f9bad2Sdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER */ 24c3f9bad2Sdanielk1977 int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ 25633ed08dSdanielk1977 IdList *pColumns, /* column list if this is an UPDATE OF trigger */ 26633ed08dSdanielk1977 Token *pTableName, /* The name of the table/view the trigger applies to */ 27c3f9bad2Sdanielk1977 int foreach, /* One of TK_ROW or TK_STATEMENT */ 28c3f9bad2Sdanielk1977 Expr *pWhen, /* WHEN clause */ 29633ed08dSdanielk1977 TriggerStep *pStepList, /* The triggered program */ 30633ed08dSdanielk1977 char const *zData, /* The string data to make persistent */ 31633ed08dSdanielk1977 int zDataLen 329adf9ac4Sdrh ){ 33c3f9bad2Sdanielk1977 Trigger *nt; 34c3f9bad2Sdanielk1977 Table *tab; 35c3f9bad2Sdanielk1977 int offset; 36c3f9bad2Sdanielk1977 TriggerStep *ss; 37c3f9bad2Sdanielk1977 38c3f9bad2Sdanielk1977 /* Check that: 399adf9ac4Sdrh ** 1. the trigger name does not already exist. 409adf9ac4Sdrh ** 2. the table (or view) does exist. 41c3f9bad2Sdanielk1977 */ 42c3f9bad2Sdanielk1977 { 43633ed08dSdanielk1977 char *tmp_str = sqliteStrNDup(pName->z, pName->n); 44633ed08dSdanielk1977 if( sqliteHashFind(&(pParse->db->trigHash), tmp_str, pName->n + 1) ){ 45c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1, 46633ed08dSdanielk1977 pName->z, pName->n, " already exists", -1, 0); 47c3f9bad2Sdanielk1977 sqliteFree(tmp_str); 48c3f9bad2Sdanielk1977 pParse->nErr++; 49c3f9bad2Sdanielk1977 goto trigger_cleanup; 50c3f9bad2Sdanielk1977 } 51c3f9bad2Sdanielk1977 sqliteFree(tmp_str); 52c3f9bad2Sdanielk1977 } 53c3f9bad2Sdanielk1977 { 54633ed08dSdanielk1977 char *tmp_str = sqliteStrNDup(pTableName->z, pTableName->n); 55e4697f5eSdrh if( tmp_str==0 ) goto trigger_cleanup; 56c3f9bad2Sdanielk1977 tab = sqliteFindTable(pParse->db, tmp_str); 57c3f9bad2Sdanielk1977 sqliteFree(tmp_str); 58c3f9bad2Sdanielk1977 if( !tab ){ 59c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1, 60633ed08dSdanielk1977 pTableName->z, pTableName->n, 0); 61c3f9bad2Sdanielk1977 pParse->nErr++; 62c3f9bad2Sdanielk1977 goto trigger_cleanup; 63c3f9bad2Sdanielk1977 } 641873cd50Sdrh if( sqliteStrICmp(tab->zName, MASTER_NAME)==0 ){ 651873cd50Sdrh sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system " 661873cd50Sdrh "table: " MASTER_NAME, 0); 671873cd50Sdrh pParse->nErr++; 681873cd50Sdrh goto trigger_cleanup; 691873cd50Sdrh } 70c3f9bad2Sdanielk1977 } 71c3f9bad2Sdanielk1977 72c3f9bad2Sdanielk1977 /* Build the Trigger object */ 73c3f9bad2Sdanielk1977 nt = (Trigger*)sqliteMalloc(sizeof(Trigger)); 74e4697f5eSdrh if( nt==0 ) goto trigger_cleanup; 75633ed08dSdanielk1977 nt->name = sqliteStrNDup(pName->z, pName->n); 76633ed08dSdanielk1977 nt->table = sqliteStrNDup(pTableName->z, pTableName->n); 77e4697f5eSdrh nt->strings = sqliteStrNDup(zData, zDataLen); 78e4697f5eSdrh if( sqlite_malloc_failed ) goto trigger_cleanup; 79c3f9bad2Sdanielk1977 nt->op = op; 80c3f9bad2Sdanielk1977 nt->tr_tm = tr_tm; 81c3f9bad2Sdanielk1977 nt->pWhen = pWhen; 82633ed08dSdanielk1977 nt->pColumns = pColumns; 83c3f9bad2Sdanielk1977 nt->foreach = foreach; 84633ed08dSdanielk1977 nt->step_list = pStepList; 85c3f9bad2Sdanielk1977 nt->isCommit = 0; 86633ed08dSdanielk1977 offset = (int)(nt->strings - zData); 87c3f9bad2Sdanielk1977 sqliteExprMoveStrings(nt->pWhen, offset); 88c3f9bad2Sdanielk1977 89c3f9bad2Sdanielk1977 ss = nt->step_list; 90c3f9bad2Sdanielk1977 while( ss ){ 91c3f9bad2Sdanielk1977 sqliteSelectMoveStrings(ss->pSelect, offset); 92f29ce559Sdanielk1977 if( ss->target.z ){ 93f29ce559Sdanielk1977 ss->target.z += offset; 94f29ce559Sdanielk1977 } 95c3f9bad2Sdanielk1977 sqliteExprMoveStrings(ss->pWhere, offset); 96c3f9bad2Sdanielk1977 sqliteExprListMoveStrings(ss->pExprList, offset); 97c3f9bad2Sdanielk1977 98c3f9bad2Sdanielk1977 ss = ss->pNext; 99c3f9bad2Sdanielk1977 } 100c3f9bad2Sdanielk1977 101c3f9bad2Sdanielk1977 /* if we are not initializing, and this trigger is not on a TEMP table, 1029adf9ac4Sdrh ** build the sqlite_master entry 1039adf9ac4Sdrh */ 104c3f9bad2Sdanielk1977 if( !pParse->initFlag && !tab->isTemp ){ 105c977f7f5Sdrh static VdbeOp insertTrig[] = { 106c977f7f5Sdrh { OP_OpenWrite, 0, 2, MASTER_NAME}, 107c977f7f5Sdrh { OP_NewRecno, 0, 0, 0 }, 108c977f7f5Sdrh { OP_String, 0, 0, "trigger" }, 109c977f7f5Sdrh { OP_String, 0, 0, 0 }, /* 3: trigger name */ 110c977f7f5Sdrh { OP_String, 0, 0, 0 }, /* 4: table name */ 111c977f7f5Sdrh { OP_Integer, 0, 0, 0 }, 112c977f7f5Sdrh { OP_String, 0, 0, 0 }, /* 6: SQL */ 113c977f7f5Sdrh { OP_MakeRecord, 5, 0, 0 }, 114c977f7f5Sdrh { OP_PutIntKey, 0, 0, 0 }, 115c977f7f5Sdrh { OP_Integer, 0, 0, 0 }, /* 9: Next cookie */ 116c977f7f5Sdrh { OP_SetCookie, 0, 0, 0 }, 117c977f7f5Sdrh { OP_Close, 0, 0, 0 }, 118c977f7f5Sdrh }; 119c977f7f5Sdrh int addr; 120c977f7f5Sdrh Vdbe *v; 121c3f9bad2Sdanielk1977 122c3f9bad2Sdanielk1977 /* Make an entry in the sqlite_master table */ 123c977f7f5Sdrh v = sqliteGetVdbe(pParse); 124e4697f5eSdrh if( v==0 ) goto trigger_cleanup; 125c977f7f5Sdrh sqliteBeginWriteOperation(pParse, 0); 126c977f7f5Sdrh addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig); 127c977f7f5Sdrh sqliteVdbeChangeP3(v, addr+3, nt->name, 0); 128c977f7f5Sdrh sqliteVdbeChangeP3(v, addr+4, nt->table, 0); 129c977f7f5Sdrh sqliteVdbeChangeP3(v, addr+6, nt->strings, 0); 130dc379456Sdrh sqliteChangeCookie(pParse->db); 131c977f7f5Sdrh sqliteVdbeChangeP1(v, addr+9, pParse->db->next_cookie); 132c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 133c3f9bad2Sdanielk1977 } 134c3f9bad2Sdanielk1977 135c3f9bad2Sdanielk1977 if( !pParse->explain ){ 136c3f9bad2Sdanielk1977 /* Stick it in the hash-table */ 137633ed08dSdanielk1977 sqliteHashInsert(&(pParse->db->trigHash), nt->name, pName->n + 1, nt); 138c3f9bad2Sdanielk1977 139c3f9bad2Sdanielk1977 /* Attach it to the table object */ 140c3f9bad2Sdanielk1977 nt->pNext = tab->pTrigger; 141c3f9bad2Sdanielk1977 tab->pTrigger = nt; 142c3f9bad2Sdanielk1977 return; 143c3f9bad2Sdanielk1977 }else{ 144c3f9bad2Sdanielk1977 sqliteFree(nt->strings); 145c3f9bad2Sdanielk1977 sqliteFree(nt->name); 146c3f9bad2Sdanielk1977 sqliteFree(nt->table); 147c3f9bad2Sdanielk1977 sqliteFree(nt); 148c3f9bad2Sdanielk1977 } 149c3f9bad2Sdanielk1977 150c3f9bad2Sdanielk1977 trigger_cleanup: 151c3f9bad2Sdanielk1977 152633ed08dSdanielk1977 sqliteIdListDelete(pColumns); 153c3f9bad2Sdanielk1977 sqliteExprDelete(pWhen); 154c3f9bad2Sdanielk1977 { 155c3f9bad2Sdanielk1977 TriggerStep * pp; 156c3f9bad2Sdanielk1977 TriggerStep * nn; 157c3f9bad2Sdanielk1977 158633ed08dSdanielk1977 pp = pStepList; 159c3f9bad2Sdanielk1977 while( pp ){ 160c3f9bad2Sdanielk1977 nn = pp->pNext; 161c3f9bad2Sdanielk1977 sqliteExprDelete(pp->pWhere); 162c3f9bad2Sdanielk1977 sqliteExprListDelete(pp->pExprList); 163c3f9bad2Sdanielk1977 sqliteSelectDelete(pp->pSelect); 164c3f9bad2Sdanielk1977 sqliteIdListDelete(pp->pIdList); 165c3f9bad2Sdanielk1977 sqliteFree(pp); 166c3f9bad2Sdanielk1977 pp = nn; 167c3f9bad2Sdanielk1977 } 168c3f9bad2Sdanielk1977 } 169c3f9bad2Sdanielk1977 } 170c3f9bad2Sdanielk1977 171c977f7f5Sdrh /* 172c977f7f5Sdrh ** Turn a SELECT statement (that the pSelect parameter points to) into 173c977f7f5Sdrh ** a trigger step. Return a pointer to a TriggerStep structure. 174c977f7f5Sdrh ** 175c977f7f5Sdrh ** The parser calls this routine when it finds a SELECT statement in 176c977f7f5Sdrh ** body of a TRIGGER. 177c977f7f5Sdrh */ 178c977f7f5Sdrh TriggerStep *sqliteTriggerSelectStep(Select *pSelect){ 179633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 180e4697f5eSdrh if( pTriggerStep==0 ) return 0; 181c3f9bad2Sdanielk1977 182633ed08dSdanielk1977 pTriggerStep->op = TK_SELECT; 183633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 184633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 185c3f9bad2Sdanielk1977 186633ed08dSdanielk1977 return pTriggerStep; 187c3f9bad2Sdanielk1977 } 188c3f9bad2Sdanielk1977 189c977f7f5Sdrh /* 190c977f7f5Sdrh ** Build a trigger step out of an INSERT statement. Return a pointer 191c977f7f5Sdrh ** to the new trigger step. 192c977f7f5Sdrh ** 193c977f7f5Sdrh ** The parser calls this routine when it sees an INSERT inside the 194c977f7f5Sdrh ** body of a trigger. 195c977f7f5Sdrh */ 196633ed08dSdanielk1977 TriggerStep *sqliteTriggerInsertStep( 197c977f7f5Sdrh Token *pTableName, /* Name of the table into which we insert */ 198c977f7f5Sdrh IdList *pColumn, /* List of columns in pTableName to insert into */ 199c977f7f5Sdrh ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ 200c977f7f5Sdrh Select *pSelect, /* A SELECT statement that supplies values */ 201c977f7f5Sdrh int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ 202633ed08dSdanielk1977 ){ 203633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 204e4697f5eSdrh if( pTriggerStep==0 ) return 0; 205c3f9bad2Sdanielk1977 206633ed08dSdanielk1977 assert(pEList == 0 || pSelect == 0); 207633ed08dSdanielk1977 assert(pEList != 0 || pSelect != 0); 208c3f9bad2Sdanielk1977 209633ed08dSdanielk1977 pTriggerStep->op = TK_INSERT; 210633ed08dSdanielk1977 pTriggerStep->pSelect = pSelect; 211633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 212633ed08dSdanielk1977 pTriggerStep->pIdList = pColumn; 213633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 214633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 215c3f9bad2Sdanielk1977 216633ed08dSdanielk1977 return pTriggerStep; 217c3f9bad2Sdanielk1977 } 218c3f9bad2Sdanielk1977 219c977f7f5Sdrh /* 220c977f7f5Sdrh ** Construct a trigger step that implements an UPDATE statement and return 221c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 222c977f7f5Sdrh ** sees an UPDATE statement inside the body of a CREATE TRIGGER. 223c977f7f5Sdrh */ 224633ed08dSdanielk1977 TriggerStep *sqliteTriggerUpdateStep( 225c977f7f5Sdrh Token *pTableName, /* Name of the table to be updated */ 226c977f7f5Sdrh ExprList *pEList, /* The SET clause: list of column and new values */ 227c977f7f5Sdrh Expr *pWhere, /* The WHERE clause */ 228c977f7f5Sdrh int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ 229c977f7f5Sdrh ){ 230633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 231e4697f5eSdrh if( pTriggerStep==0 ) return 0; 232c3f9bad2Sdanielk1977 233633ed08dSdanielk1977 pTriggerStep->op = TK_UPDATE; 234633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 235633ed08dSdanielk1977 pTriggerStep->pExprList = pEList; 236633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 237633ed08dSdanielk1977 pTriggerStep->orconf = orconf; 238c3f9bad2Sdanielk1977 239633ed08dSdanielk1977 return pTriggerStep; 240c3f9bad2Sdanielk1977 } 241c3f9bad2Sdanielk1977 242c977f7f5Sdrh /* 243c977f7f5Sdrh ** Construct a trigger step that implements a DELETE statement and return 244c977f7f5Sdrh ** a pointer to that trigger step. The parser calls this routine when it 245c977f7f5Sdrh ** sees a DELETE statement inside the body of a CREATE TRIGGER. 246c977f7f5Sdrh */ 247c977f7f5Sdrh TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){ 248633ed08dSdanielk1977 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); 249e4697f5eSdrh if( pTriggerStep==0 ) return 0; 250c3f9bad2Sdanielk1977 251633ed08dSdanielk1977 pTriggerStep->op = TK_DELETE; 252633ed08dSdanielk1977 pTriggerStep->target = *pTableName; 253633ed08dSdanielk1977 pTriggerStep->pWhere = pWhere; 254633ed08dSdanielk1977 pTriggerStep->orconf = OE_Default; 255c3f9bad2Sdanielk1977 256633ed08dSdanielk1977 return pTriggerStep; 257c3f9bad2Sdanielk1977 } 258c3f9bad2Sdanielk1977 259c3f9bad2Sdanielk1977 /* 260633ed08dSdanielk1977 ** Recursively delete a Trigger structure 261c3f9bad2Sdanielk1977 */ 2621d1f3055Sdrh void sqliteDeleteTrigger(Trigger *pTrigger){ 263633ed08dSdanielk1977 TriggerStep *pTriggerStep; 264c3f9bad2Sdanielk1977 265633ed08dSdanielk1977 pTriggerStep = pTrigger->step_list; 266633ed08dSdanielk1977 while( pTriggerStep ){ 267633ed08dSdanielk1977 TriggerStep * pTmp = pTriggerStep; 268633ed08dSdanielk1977 pTriggerStep = pTriggerStep->pNext; 269633ed08dSdanielk1977 270633ed08dSdanielk1977 sqliteExprDelete(pTmp->pWhere); 271633ed08dSdanielk1977 sqliteExprListDelete(pTmp->pExprList); 272633ed08dSdanielk1977 sqliteSelectDelete(pTmp->pSelect); 273633ed08dSdanielk1977 sqliteIdListDelete(pTmp->pIdList); 274633ed08dSdanielk1977 275633ed08dSdanielk1977 sqliteFree(pTmp); 276633ed08dSdanielk1977 } 277633ed08dSdanielk1977 278633ed08dSdanielk1977 sqliteFree(pTrigger->name); 279633ed08dSdanielk1977 sqliteFree(pTrigger->table); 280633ed08dSdanielk1977 sqliteExprDelete(pTrigger->pWhen); 281633ed08dSdanielk1977 sqliteIdListDelete(pTrigger->pColumns); 282633ed08dSdanielk1977 sqliteFree(pTrigger->strings); 283633ed08dSdanielk1977 sqliteFree(pTrigger); 284633ed08dSdanielk1977 } 285633ed08dSdanielk1977 286633ed08dSdanielk1977 /* 287633ed08dSdanielk1977 * This function is called to drop a trigger from the database schema. 288633ed08dSdanielk1977 * 289633ed08dSdanielk1977 * This may be called directly from the parser, or from within 290633ed08dSdanielk1977 * sqliteDropTable(). In the latter case the "nested" argument is true. 291633ed08dSdanielk1977 * 292633ed08dSdanielk1977 * Note that this function does not delete the trigger entirely. Instead it 293633ed08dSdanielk1977 * removes it from the internal schema and places it in the trigDrop hash 294633ed08dSdanielk1977 * table. This is so that the trigger can be restored into the database schema 295633ed08dSdanielk1977 * if the transaction is rolled back. 296633ed08dSdanielk1977 */ 297633ed08dSdanielk1977 void sqliteDropTrigger(Parse *pParse, Token *pName, int nested) 298633ed08dSdanielk1977 { 299633ed08dSdanielk1977 char *zName; 300633ed08dSdanielk1977 Trigger *pTrigger; 301633ed08dSdanielk1977 Table *pTable; 302633ed08dSdanielk1977 303633ed08dSdanielk1977 zName = sqliteStrNDup(pName->z, pName->n); 304c3f9bad2Sdanielk1977 305c3f9bad2Sdanielk1977 /* ensure that the trigger being dropped exists */ 306633ed08dSdanielk1977 pTrigger = sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1); 307633ed08dSdanielk1977 if( !pTrigger ){ 308c3f9bad2Sdanielk1977 sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1, 309633ed08dSdanielk1977 zName, -1, 0); 310633ed08dSdanielk1977 sqliteFree(zName); 311c3f9bad2Sdanielk1977 return; 312c3f9bad2Sdanielk1977 } 313c3f9bad2Sdanielk1977 314c3f9bad2Sdanielk1977 /* 315c3f9bad2Sdanielk1977 * If this is not an "explain", do the following: 316c3f9bad2Sdanielk1977 * 1. Remove the trigger from its associated table structure 317c3f9bad2Sdanielk1977 * 2. Move the trigger from the trigHash hash to trigDrop 318c3f9bad2Sdanielk1977 */ 319c3f9bad2Sdanielk1977 if( !pParse->explain ){ 320c3f9bad2Sdanielk1977 /* 1 */ 321633ed08dSdanielk1977 pTable = sqliteFindTable(pParse->db, pTrigger->table); 322633ed08dSdanielk1977 assert(pTable); 323633ed08dSdanielk1977 if( pTable->pTrigger == pTrigger ){ 324633ed08dSdanielk1977 pTable->pTrigger = pTrigger->pNext; 325633ed08dSdanielk1977 }else{ 326633ed08dSdanielk1977 Trigger *cc = pTable->pTrigger; 327c3f9bad2Sdanielk1977 while( cc ){ 328633ed08dSdanielk1977 if( cc->pNext == pTrigger ){ 329c3f9bad2Sdanielk1977 cc->pNext = cc->pNext->pNext; 330c3f9bad2Sdanielk1977 break; 331c3f9bad2Sdanielk1977 } 332c3f9bad2Sdanielk1977 cc = cc->pNext; 333c3f9bad2Sdanielk1977 } 334c3f9bad2Sdanielk1977 assert(cc); 335c3f9bad2Sdanielk1977 } 336c3f9bad2Sdanielk1977 337c3f9bad2Sdanielk1977 /* 2 */ 338633ed08dSdanielk1977 sqliteHashInsert(&(pParse->db->trigHash), zName, 339633ed08dSdanielk1977 pName->n + 1, NULL); 340633ed08dSdanielk1977 sqliteHashInsert(&(pParse->db->trigDrop), pTrigger->name, 341633ed08dSdanielk1977 pName->n + 1, pTrigger); 342c3f9bad2Sdanielk1977 } 343c3f9bad2Sdanielk1977 344c3f9bad2Sdanielk1977 /* Unless this is a trigger on a TEMP TABLE, generate code to destroy the 345c3f9bad2Sdanielk1977 * database record of the trigger */ 346633ed08dSdanielk1977 if( !pTable->isTemp ){ 347c3f9bad2Sdanielk1977 int base; 348c3f9bad2Sdanielk1977 static VdbeOp dropTrigger[] = { 349c3f9bad2Sdanielk1977 { OP_OpenWrite, 0, 2, MASTER_NAME}, 350c3f9bad2Sdanielk1977 { OP_Rewind, 0, ADDR(9), 0}, 351c3f9bad2Sdanielk1977 { OP_String, 0, 0, 0}, /* 2 */ 352c3f9bad2Sdanielk1977 { OP_MemStore, 1, 1, 0}, 353c3f9bad2Sdanielk1977 { OP_MemLoad, 1, 0, 0}, /* 4 */ 354c3f9bad2Sdanielk1977 { OP_Column, 0, 1, 0}, 355c3f9bad2Sdanielk1977 { OP_Ne, 0, ADDR(8), 0}, 356c3f9bad2Sdanielk1977 { OP_Delete, 0, 0, 0}, 357c3f9bad2Sdanielk1977 { OP_Next, 0, ADDR(4), 0}, /* 8 */ 358c3f9bad2Sdanielk1977 { OP_Integer, 0, 0, 0}, /* 9 */ 359c3f9bad2Sdanielk1977 { OP_SetCookie, 0, 0, 0}, 360c3f9bad2Sdanielk1977 { OP_Close, 0, 0, 0}, 361c3f9bad2Sdanielk1977 }; 362c3f9bad2Sdanielk1977 363dc379456Sdrh if( !nested ){ 364c977f7f5Sdrh sqliteBeginWriteOperation(pParse, 0); 365dc379456Sdrh } 366c3f9bad2Sdanielk1977 base = sqliteVdbeAddOpList(pParse->pVdbe, 367c3f9bad2Sdanielk1977 ArraySize(dropTrigger), dropTrigger); 368633ed08dSdanielk1977 sqliteVdbeChangeP3(pParse->pVdbe, base+2, zName, 0); 369dc379456Sdrh if( !nested ){ 370dc379456Sdrh sqliteChangeCookie(pParse->db); 371dc379456Sdrh } 372c3f9bad2Sdanielk1977 sqliteVdbeChangeP1(pParse->pVdbe, base+9, pParse->db->next_cookie); 373dc379456Sdrh if( !nested ){ 374c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 375c3f9bad2Sdanielk1977 } 376dc379456Sdrh } 377c3f9bad2Sdanielk1977 378633ed08dSdanielk1977 sqliteFree(zName); 379c3f9bad2Sdanielk1977 } 380c3f9bad2Sdanielk1977 381c977f7f5Sdrh /* 382c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement. Each entry 383c977f7f5Sdrh ** in pEList is of the format <id>=<expr>. If any of the entries 384c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList, 385c977f7f5Sdrh ** then return TRUE. If pIdList==NULL, then it is considered a 386c977f7f5Sdrh ** wildcard that matches anything. Likewise if pEList==NULL then 387c977f7f5Sdrh ** it matches anything so always return true. Return false only 388c977f7f5Sdrh ** if there is no match. 389c977f7f5Sdrh */ 390c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){ 391ad2d8307Sdrh int e; 392ad2d8307Sdrh if( !pIdList || !pEList ) return 1; 393f29ce559Sdanielk1977 for(e=0; e<pEList->nExpr; e++){ 394ad2d8307Sdrh if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1; 395f29ce559Sdanielk1977 } 396c3f9bad2Sdanielk1977 return 0; 397c3f9bad2Sdanielk1977 } 398c3f9bad2Sdanielk1977 399c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for 400c3f9bad2Sdanielk1977 * for triggers, even if there are no triggers to code. This is used to test 401c3f9bad2Sdanielk1977 * how much overhead the triggers algorithm is causing. 402c3f9bad2Sdanielk1977 * 403c3f9bad2Sdanielk1977 * This flag can be set or cleared using the "trigger_overhead_test" pragma. 404c3f9bad2Sdanielk1977 * The pragma is not documented since it is not really part of the interface 405c3f9bad2Sdanielk1977 * to SQLite, just the test procedure. 406c3f9bad2Sdanielk1977 */ 407c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0; 408c3f9bad2Sdanielk1977 409c3f9bad2Sdanielk1977 /* 410c3f9bad2Sdanielk1977 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already 411c3f9bad2Sdanielk1977 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is 412c3f9bad2Sdanielk1977 * found in the list specified as pTrigger. 413c3f9bad2Sdanielk1977 */ 414c3f9bad2Sdanielk1977 int sqliteTriggersExist( 415c977f7f5Sdrh Parse *pParse, /* Used to check for recursive triggers */ 416c977f7f5Sdrh Trigger *pTrigger, /* A list of triggers associated with a table */ 417c3f9bad2Sdanielk1977 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ 418c3f9bad2Sdanielk1977 int tr_tm, /* one of TK_BEFORE, TK_AFTER */ 419c3f9bad2Sdanielk1977 int foreach, /* one of TK_ROW or TK_STATEMENT */ 420c977f7f5Sdrh ExprList *pChanges /* Columns that change in an UPDATE statement */ 421c977f7f5Sdrh ){ 422633ed08dSdanielk1977 Trigger * pTriggerCursor; 423c3f9bad2Sdanielk1977 424633ed08dSdanielk1977 if( always_code_trigger_setup ){ 425633ed08dSdanielk1977 return 1; 426633ed08dSdanielk1977 } 427c3f9bad2Sdanielk1977 428633ed08dSdanielk1977 pTriggerCursor = pTrigger; 429633ed08dSdanielk1977 while( pTriggerCursor ){ 430633ed08dSdanielk1977 if( pTriggerCursor->op == op && 431633ed08dSdanielk1977 pTriggerCursor->tr_tm == tr_tm && 432633ed08dSdanielk1977 pTriggerCursor->foreach == foreach && 433633ed08dSdanielk1977 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){ 434c3f9bad2Sdanielk1977 TriggerStack * ss; 435c3f9bad2Sdanielk1977 ss = pParse->trigStack; 436f29ce559Sdanielk1977 while( ss && ss->pTrigger != pTrigger ){ 437f29ce559Sdanielk1977 ss = ss->pNext; 438f29ce559Sdanielk1977 } 439c3f9bad2Sdanielk1977 if( !ss )return 1; 440c3f9bad2Sdanielk1977 } 441633ed08dSdanielk1977 pTriggerCursor = pTriggerCursor->pNext; 442c3f9bad2Sdanielk1977 } 443c3f9bad2Sdanielk1977 444c3f9bad2Sdanielk1977 return 0; 445c3f9bad2Sdanielk1977 } 446c3f9bad2Sdanielk1977 447c977f7f5Sdrh /* 448c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a 449c977f7f5Sdrh ** trigger. 450c977f7f5Sdrh */ 451c3f9bad2Sdanielk1977 static int codeTriggerProgram( 452c977f7f5Sdrh Parse *pParse, /* The parser context */ 453c977f7f5Sdrh TriggerStep *pStepList, /* List of statements inside the trigger body */ 454c977f7f5Sdrh int orconfin /* Conflict algorithm. (OE_Abort, etc) */ 455633ed08dSdanielk1977 ){ 456633ed08dSdanielk1977 TriggerStep * pTriggerStep = pStepList; 457c3f9bad2Sdanielk1977 int orconf; 458c3f9bad2Sdanielk1977 459633ed08dSdanielk1977 while( pTriggerStep ){ 460c3f9bad2Sdanielk1977 int saveNTab = pParse->nTab; 461633ed08dSdanielk1977 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin; 462c3f9bad2Sdanielk1977 pParse->trigStack->orconf = orconf; 463633ed08dSdanielk1977 switch( pTriggerStep->op ){ 464c3f9bad2Sdanielk1977 case TK_SELECT: { 465c3f9bad2Sdanielk1977 int tmp_tbl = pParse->nTab++; 466c3f9bad2Sdanielk1977 sqliteVdbeAddOp(pParse->pVdbe, OP_OpenTemp, tmp_tbl, 0); 467c3f9bad2Sdanielk1977 sqliteVdbeAddOp(pParse->pVdbe, OP_KeyAsData, tmp_tbl, 1); 468633ed08dSdanielk1977 sqliteSelect(pParse, pTriggerStep->pSelect, SRT_Union, 469633ed08dSdanielk1977 tmp_tbl, 0, 0, 0); 470c3f9bad2Sdanielk1977 sqliteVdbeAddOp(pParse->pVdbe, OP_Close, tmp_tbl, 0); 471c3f9bad2Sdanielk1977 pParse->nTab--; 472c3f9bad2Sdanielk1977 break; 473c3f9bad2Sdanielk1977 } 474c3f9bad2Sdanielk1977 case TK_UPDATE: { 475bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 476633ed08dSdanielk1977 sqliteUpdate(pParse, &pTriggerStep->target, 477633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 478633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere), orconf); 479bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 480c3f9bad2Sdanielk1977 break; 481c3f9bad2Sdanielk1977 } 482c3f9bad2Sdanielk1977 case TK_INSERT: { 483633ed08dSdanielk1977 sqliteInsert(pParse, &pTriggerStep->target, 484633ed08dSdanielk1977 sqliteExprListDup(pTriggerStep->pExprList), 485633ed08dSdanielk1977 sqliteSelectDup(pTriggerStep->pSelect), 486633ed08dSdanielk1977 sqliteIdListDup(pTriggerStep->pIdList), orconf); 487c3f9bad2Sdanielk1977 break; 488c3f9bad2Sdanielk1977 } 489c3f9bad2Sdanielk1977 case TK_DELETE: { 490bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0); 491633ed08dSdanielk1977 sqliteDeleteFrom(pParse, &pTriggerStep->target, 492633ed08dSdanielk1977 sqliteExprDup(pTriggerStep->pWhere)); 493bd5a451dSdrh sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0); 494c3f9bad2Sdanielk1977 break; 495c3f9bad2Sdanielk1977 } 496c3f9bad2Sdanielk1977 default: 497c3f9bad2Sdanielk1977 assert(0); 498c3f9bad2Sdanielk1977 } 499c3f9bad2Sdanielk1977 pParse->nTab = saveNTab; 500633ed08dSdanielk1977 pTriggerStep = pTriggerStep->pNext; 501c3f9bad2Sdanielk1977 } 502c3f9bad2Sdanielk1977 503c3f9bad2Sdanielk1977 return 0; 504c3f9bad2Sdanielk1977 } 505c3f9bad2Sdanielk1977 506633ed08dSdanielk1977 /* 507633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers. 508633ed08dSdanielk1977 ** 509633ed08dSdanielk1977 ** When the code that this function generates is executed, the following 510633ed08dSdanielk1977 ** must be true: 511c977f7f5Sdrh ** 512c977f7f5Sdrh ** 1. No cursors may be open in the main database. (But newIdx and oldIdx 513c977f7f5Sdrh ** can be indices of cursors in temporary tables. See below.) 514c977f7f5Sdrh ** 515633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then 516633ed08dSdanielk1977 ** a temporary vdbe cursor (index newIdx) must be open and pointing at 517633ed08dSdanielk1977 ** a row containing values to be substituted for new.* expressions in the 518633ed08dSdanielk1977 ** trigger program(s). 519c977f7f5Sdrh ** 520633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then 521633ed08dSdanielk1977 ** a temporary vdbe cursor (index oldIdx) must be open and pointing at 522633ed08dSdanielk1977 ** a row containing values to be substituted for old.* expressions in the 523633ed08dSdanielk1977 ** trigger program(s). 524633ed08dSdanielk1977 ** 525633ed08dSdanielk1977 */ 526c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger( 527c3f9bad2Sdanielk1977 Parse *pParse, /* Parse context */ 528c3f9bad2Sdanielk1977 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ 529633ed08dSdanielk1977 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ 530c3f9bad2Sdanielk1977 int tr_tm, /* One of TK_BEFORE, TK_AFTER */ 531633ed08dSdanielk1977 Table *pTab, /* The table to code triggers from */ 532633ed08dSdanielk1977 int newIdx, /* The indice of the "new" row to access */ 533633ed08dSdanielk1977 int oldIdx, /* The indice of the "old" row to access */ 534c977f7f5Sdrh int orconf /* ON CONFLICT policy */ 535c977f7f5Sdrh ){ 536c3f9bad2Sdanielk1977 Trigger * pTrigger; 537c3f9bad2Sdanielk1977 TriggerStack * pTriggerStack; 538c3f9bad2Sdanielk1977 539c3f9bad2Sdanielk1977 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); 540c3f9bad2Sdanielk1977 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER); 541c3f9bad2Sdanielk1977 542633ed08dSdanielk1977 assert(newIdx != -1 || oldIdx != -1); 543c3f9bad2Sdanielk1977 544633ed08dSdanielk1977 pTrigger = pTab->pTrigger; 545c3f9bad2Sdanielk1977 while( pTrigger ){ 546c3f9bad2Sdanielk1977 int fire_this = 0; 547c3f9bad2Sdanielk1977 548c3f9bad2Sdanielk1977 /* determine whether we should code this trigger */ 549c3f9bad2Sdanielk1977 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 550c3f9bad2Sdanielk1977 pTrigger->foreach == TK_ROW ){ 551c3f9bad2Sdanielk1977 fire_this = 1; 552c3f9bad2Sdanielk1977 pTriggerStack = pParse->trigStack; 553c3f9bad2Sdanielk1977 while( pTriggerStack ){ 554f29ce559Sdanielk1977 if( pTriggerStack->pTrigger == pTrigger ){ 555f29ce559Sdanielk1977 fire_this = 0; 556f29ce559Sdanielk1977 } 557c3f9bad2Sdanielk1977 pTriggerStack = pTriggerStack->pNext; 558c3f9bad2Sdanielk1977 } 559c3f9bad2Sdanielk1977 if( op == TK_UPDATE && pTrigger->pColumns && 560f29ce559Sdanielk1977 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){ 561c3f9bad2Sdanielk1977 fire_this = 0; 562c3f9bad2Sdanielk1977 } 563f29ce559Sdanielk1977 } 564c3f9bad2Sdanielk1977 565e4697f5eSdrh if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){ 566c3f9bad2Sdanielk1977 int endTrigger; 567ad3cab52Sdrh SrcList dummyTablist; 568c3f9bad2Sdanielk1977 Expr * whenExpr; 569c3f9bad2Sdanielk1977 570ad3cab52Sdrh dummyTablist.nSrc = 0; 571c3f9bad2Sdanielk1977 dummyTablist.a = 0; 572c3f9bad2Sdanielk1977 573c3f9bad2Sdanielk1977 /* Push an entry on to the trigger stack */ 574c3f9bad2Sdanielk1977 pTriggerStack->pTrigger = pTrigger; 575633ed08dSdanielk1977 pTriggerStack->newIdx = newIdx; 576633ed08dSdanielk1977 pTriggerStack->oldIdx = oldIdx; 577633ed08dSdanielk1977 pTriggerStack->pTab = pTab; 578c3f9bad2Sdanielk1977 pTriggerStack->pNext = pParse->trigStack; 579c3f9bad2Sdanielk1977 pParse->trigStack = pTriggerStack; 580c3f9bad2Sdanielk1977 581c3f9bad2Sdanielk1977 /* code the WHEN clause */ 582c3f9bad2Sdanielk1977 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe); 583c3f9bad2Sdanielk1977 whenExpr = sqliteExprDup(pTrigger->pWhen); 584c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){ 585c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 586c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 587c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 588c3f9bad2Sdanielk1977 return 1; 589c3f9bad2Sdanielk1977 } 590*f5905aa7Sdrh sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1); 591c3f9bad2Sdanielk1977 sqliteExprDelete(whenExpr); 592c3f9bad2Sdanielk1977 593633ed08dSdanielk1977 codeTriggerProgram(pParse, pTrigger->step_list, orconf); 594c3f9bad2Sdanielk1977 595c3f9bad2Sdanielk1977 /* Pop the entry off the trigger stack */ 596c3f9bad2Sdanielk1977 pParse->trigStack = pParse->trigStack->pNext; 597c3f9bad2Sdanielk1977 sqliteFree(pTriggerStack); 598c3f9bad2Sdanielk1977 599c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger); 600c3f9bad2Sdanielk1977 } 601c3f9bad2Sdanielk1977 pTrigger = pTrigger->pNext; 602c3f9bad2Sdanielk1977 } 603c3f9bad2Sdanielk1977 604c3f9bad2Sdanielk1977 return 0; 605c3f9bad2Sdanielk1977 } 606c3f9bad2Sdanielk1977 607c3f9bad2Sdanielk1977 /* 608633ed08dSdanielk1977 * This function is called to code ON UPDATE and ON DELETE triggers on 609633ed08dSdanielk1977 * views. 610633ed08dSdanielk1977 * 611633ed08dSdanielk1977 * This function deletes the data pointed at by the pWhere and pChanges 612633ed08dSdanielk1977 * arguments before it completes. 613c3f9bad2Sdanielk1977 */ 614633ed08dSdanielk1977 void sqliteViewTriggers( 615633ed08dSdanielk1977 Parse *pParse, 616633ed08dSdanielk1977 Table *pTab, /* The view to code triggers on */ 617633ed08dSdanielk1977 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/ 618633ed08dSdanielk1977 int orconf, /* The ON CONFLICT policy specified as part of the 619633ed08dSdanielk1977 statement causing these triggers */ 620633ed08dSdanielk1977 ExprList *pChanges /* If this is an statement causing triggers to fire 621633ed08dSdanielk1977 is an UPDATE, then this list holds the columns 622633ed08dSdanielk1977 to update and the expressions to update them to. 623633ed08dSdanielk1977 See comments for sqliteUpdate(). */ 624633ed08dSdanielk1977 ){ 625c3f9bad2Sdanielk1977 int oldIdx = -1; 626c3f9bad2Sdanielk1977 int newIdx = -1; 627c3f9bad2Sdanielk1977 int *aXRef = 0; 628c3f9bad2Sdanielk1977 Vdbe *v; 629c3f9bad2Sdanielk1977 int endOfLoop; 630c3f9bad2Sdanielk1977 int startOfLoop; 631c3f9bad2Sdanielk1977 Select theSelect; 632c3f9bad2Sdanielk1977 Token tblNameToken; 633c3f9bad2Sdanielk1977 634c3f9bad2Sdanielk1977 assert(pTab->pSelect); 635c3f9bad2Sdanielk1977 636c3f9bad2Sdanielk1977 tblNameToken.z = pTab->zName; 637c3f9bad2Sdanielk1977 tblNameToken.n = strlen(pTab->zName); 638c3f9bad2Sdanielk1977 639c3f9bad2Sdanielk1977 theSelect.isDistinct = 0; 640c3f9bad2Sdanielk1977 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0); 641ad3cab52Sdrh theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken); 642c3f9bad2Sdanielk1977 theSelect.pWhere = pWhere; pWhere = 0; 643c3f9bad2Sdanielk1977 theSelect.pGroupBy = 0; 644c3f9bad2Sdanielk1977 theSelect.pHaving = 0; 645c3f9bad2Sdanielk1977 theSelect.pOrderBy = 0; 646c3f9bad2Sdanielk1977 theSelect.op = TK_SELECT; /* ?? */ 647c3f9bad2Sdanielk1977 theSelect.pPrior = 0; 648c3f9bad2Sdanielk1977 theSelect.nLimit = -1; 649c3f9bad2Sdanielk1977 theSelect.nOffset = -1; 650c3f9bad2Sdanielk1977 theSelect.zSelect = 0; 651c3f9bad2Sdanielk1977 theSelect.base = 0; 652c3f9bad2Sdanielk1977 653c3f9bad2Sdanielk1977 v = sqliteGetVdbe(pParse); 654c3f9bad2Sdanielk1977 assert(v); 655c977f7f5Sdrh sqliteBeginWriteOperation(pParse, 1); 656c3f9bad2Sdanielk1977 657c3f9bad2Sdanielk1977 /* Allocate temp tables */ 658c3f9bad2Sdanielk1977 oldIdx = pParse->nTab++; 659c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0); 660c3f9bad2Sdanielk1977 if( pChanges ){ 661c3f9bad2Sdanielk1977 newIdx = pParse->nTab++; 662c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0); 663c3f9bad2Sdanielk1977 } 664c3f9bad2Sdanielk1977 665c3f9bad2Sdanielk1977 /* Snapshot the view */ 666c3f9bad2Sdanielk1977 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){ 667c3f9bad2Sdanielk1977 goto trigger_cleanup; 668c3f9bad2Sdanielk1977 } 669c3f9bad2Sdanielk1977 670c3f9bad2Sdanielk1977 /* loop thru the view snapshot, executing triggers for each row */ 671c3f9bad2Sdanielk1977 endOfLoop = sqliteVdbeMakeLabel(v); 672c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop); 673c3f9bad2Sdanielk1977 674c3f9bad2Sdanielk1977 /* Loop thru the view snapshot, executing triggers for each row */ 675c3f9bad2Sdanielk1977 startOfLoop = sqliteVdbeCurrentAddr(v); 676c3f9bad2Sdanielk1977 677c3f9bad2Sdanielk1977 /* Build the updated row if required */ 678c3f9bad2Sdanielk1977 if( pChanges ){ 6791d1f3055Sdrh int ii; 680c3f9bad2Sdanielk1977 681c3f9bad2Sdanielk1977 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol ); 682c3f9bad2Sdanielk1977 if( aXRef==0 ) goto trigger_cleanup; 683633ed08dSdanielk1977 for(ii = 0; ii < pTab->nCol; ii++){ 684c3f9bad2Sdanielk1977 aXRef[ii] = -1; 685633ed08dSdanielk1977 } 686c3f9bad2Sdanielk1977 687c3f9bad2Sdanielk1977 for(ii=0; ii<pChanges->nExpr; ii++){ 688c3f9bad2Sdanielk1977 int jj; 689c3f9bad2Sdanielk1977 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0, 690f29ce559Sdanielk1977 pChanges->a[ii].pExpr) ){ 691c3f9bad2Sdanielk1977 goto trigger_cleanup; 692f29ce559Sdanielk1977 } 693c3f9bad2Sdanielk1977 694c3f9bad2Sdanielk1977 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) ) 695c3f9bad2Sdanielk1977 goto trigger_cleanup; 696c3f9bad2Sdanielk1977 697c3f9bad2Sdanielk1977 for(jj=0; jj<pTab->nCol; jj++){ 698c3f9bad2Sdanielk1977 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){ 699c3f9bad2Sdanielk1977 aXRef[jj] = ii; 700c3f9bad2Sdanielk1977 break; 701c3f9bad2Sdanielk1977 } 702c3f9bad2Sdanielk1977 } 703c3f9bad2Sdanielk1977 if( jj>=pTab->nCol ){ 704c3f9bad2Sdanielk1977 sqliteSetString(&pParse->zErrMsg, "no such column: ", 705c3f9bad2Sdanielk1977 pChanges->a[ii].zName, 0); 706c3f9bad2Sdanielk1977 pParse->nErr++; 707c3f9bad2Sdanielk1977 goto trigger_cleanup; 708c3f9bad2Sdanielk1977 } 709c3f9bad2Sdanielk1977 } 710c3f9bad2Sdanielk1977 711c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Integer, 13, 0); 712c3f9bad2Sdanielk1977 713633ed08dSdanielk1977 for(ii = 0; ii<pTab->nCol; ii++){ 714633ed08dSdanielk1977 if( aXRef[ii] < 0 ){ 715c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii); 716633ed08dSdanielk1977 }else{ 717c3f9bad2Sdanielk1977 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr); 718633ed08dSdanielk1977 } 719633ed08dSdanielk1977 } 720c3f9bad2Sdanielk1977 721c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0); 722c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0); 723c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0); 724c3f9bad2Sdanielk1977 725c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, 726633ed08dSdanielk1977 pTab, newIdx, oldIdx, orconf); 727c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, 728633ed08dSdanielk1977 pTab, newIdx, oldIdx, orconf); 729c3f9bad2Sdanielk1977 }else{ 730c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, 731633ed08dSdanielk1977 orconf); 732c3f9bad2Sdanielk1977 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, 733633ed08dSdanielk1977 orconf); 734c3f9bad2Sdanielk1977 } 735c3f9bad2Sdanielk1977 736c3f9bad2Sdanielk1977 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop); 737c3f9bad2Sdanielk1977 738c3f9bad2Sdanielk1977 sqliteVdbeResolveLabel(v, endOfLoop); 739c3f9bad2Sdanielk1977 sqliteEndWriteOperation(pParse); 740c3f9bad2Sdanielk1977 741c3f9bad2Sdanielk1977 trigger_cleanup: 742c3f9bad2Sdanielk1977 sqliteFree(aXRef); 743c3f9bad2Sdanielk1977 sqliteExprListDelete(pChanges); 744c3f9bad2Sdanielk1977 sqliteExprDelete(pWhere); 745c3f9bad2Sdanielk1977 sqliteExprListDelete(theSelect.pEList); 746ad3cab52Sdrh sqliteSrcListDelete(theSelect.pSrc); 747c3f9bad2Sdanielk1977 sqliteExprDelete(theSelect.pWhere); 748c3f9bad2Sdanielk1977 return; 749c3f9bad2Sdanielk1977 } 750