blob: 76bdc77ba87a7639f9ac5d355d1aaf0e359a1ab7 [file] [log] [blame]
danielk1977c3f9bad2002-05-15 08:30:12 +00001/*
danielk1977633ed082002-05-17 00:05:58 +00002**
3** The author disclaims copyright to this source code. In place of
4** a legal notice, here is a blessing:
5**
6** May you do good and not evil.
7** May you find forgiveness for yourself and forgive others.
8** May you share freely, never taking more than you give.
9**
10*************************************************************************
11*
drh9adf9ac2002-05-15 11:44:13 +000012*/
danielk1977c3f9bad2002-05-15 08:30:12 +000013#include "sqliteInt.h"
drh9adf9ac2002-05-15 11:44:13 +000014
danielk1977c3f9bad2002-05-15 08:30:12 +000015/*
drh4b59ab52002-08-24 18:24:51 +000016** Delete a linked list of TriggerStep structures.
17*/
18static void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
19 while( pTriggerStep ){
20 TriggerStep * pTmp = pTriggerStep;
21 pTriggerStep = pTriggerStep->pNext;
22
drh8c74a8c2002-08-25 19:20:40 +000023 if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
drh4b59ab52002-08-24 18:24:51 +000024 sqliteExprDelete(pTmp->pWhere);
25 sqliteExprListDelete(pTmp->pExprList);
26 sqliteSelectDelete(pTmp->pSelect);
27 sqliteIdListDelete(pTmp->pIdList);
28
29 sqliteFree(pTmp);
30 }
31}
32
33/*
danielk1977633ed082002-05-17 00:05:58 +000034** This is called by the parser when it sees a CREATE TRIGGER statement. See
35** comments surrounding struct Trigger in sqliteInt.h for a description of
36** how triggers are stored.
drh9adf9ac2002-05-15 11:44:13 +000037*/
38void sqliteCreateTrigger(
39 Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
danielk1977633ed082002-05-17 00:05:58 +000040 Token *pName, /* The name of the trigger */
danielk1977d702fcc2002-05-26 23:24:40 +000041 int tr_tm, /* One of TK_BEFORE, TK_AFTER , TK_INSTEAD */
drh9adf9ac2002-05-15 11:44:13 +000042 int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
danielk1977633ed082002-05-17 00:05:58 +000043 IdList *pColumns, /* column list if this is an UPDATE OF trigger */
44 Token *pTableName, /* The name of the table/view the trigger applies to */
drh9adf9ac2002-05-15 11:44:13 +000045 int foreach, /* One of TK_ROW or TK_STATEMENT */
46 Expr *pWhen, /* WHEN clause */
danielk1977633ed082002-05-17 00:05:58 +000047 TriggerStep *pStepList, /* The triggered program */
drh4b59ab52002-08-24 18:24:51 +000048 Token *pAll /* Token that describes the complete CREATE TRIGGER */
drh9adf9ac2002-05-15 11:44:13 +000049){
50 Trigger *nt;
51 Table *tab;
drhe5f9c642003-01-13 23:27:31 +000052 char *zName = 0; /* Name of the trigger */
drhed6c8672003-01-12 18:02:16 +000053
danielk1977c3f9bad2002-05-15 08:30:12 +000054 /* Check that:
drh9adf9ac2002-05-15 11:44:13 +000055 ** 1. the trigger name does not already exist.
56 ** 2. the table (or view) does exist.
danielk1977d702fcc2002-05-26 23:24:40 +000057 ** 3. that we are not trying to create a trigger on the sqlite_master table
58 ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
59 ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
drh9adf9ac2002-05-15 11:44:13 +000060 */
drhe5f9c642003-01-13 23:27:31 +000061 zName = sqliteStrNDup(pName->z, pName->n);
62 if( sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1) ){
63 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1,
64 pName->z, pName->n, " already exists", -1, 0);
65 pParse->nErr++;
66 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +000067 }
68 {
danielk1977633ed082002-05-17 00:05:58 +000069 char *tmp_str = sqliteStrNDup(pTableName->z, pTableName->n);
drhe4697f52002-05-23 02:09:03 +000070 if( tmp_str==0 ) goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +000071 tab = sqliteFindTable(pParse->db, tmp_str);
72 sqliteFree(tmp_str);
drh9adf9ac2002-05-15 11:44:13 +000073 if( !tab ){
danielk1977c3f9bad2002-05-15 08:30:12 +000074 sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1,
danielk1977633ed082002-05-17 00:05:58 +000075 pTableName->z, pTableName->n, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +000076 pParse->nErr++;
77 goto trigger_cleanup;
78 }
drh1873cd52002-05-23 00:30:31 +000079 if( sqliteStrICmp(tab->zName, MASTER_NAME)==0 ){
80 sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
81 "table: " MASTER_NAME, 0);
82 pParse->nErr++;
83 goto trigger_cleanup;
84 }
drhe0bc4042002-06-25 01:09:11 +000085 if( sqliteStrICmp(tab->zName, TEMP_MASTER_NAME)==0 ){
86 sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
87 "table: " TEMP_MASTER_NAME, 0);
88 pParse->nErr++;
89 goto trigger_cleanup;
90 }
danielk1977d702fcc2002-05-26 23:24:40 +000091 if( tab->pSelect && tr_tm != TK_INSTEAD ){
92 sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1,
93 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1
94 , pTableName->z, pTableName->n, 0);
95 goto trigger_cleanup;
96 }
97 if( !tab->pSelect && tr_tm == TK_INSTEAD ){
98 sqliteSetNString(&pParse->zErrMsg, "cannot create INSTEAD OF", -1,
99 " trigger on table: ", -1, pTableName->z, pTableName->n, 0);
100 goto trigger_cleanup;
101 }
drhe5f9c642003-01-13 23:27:31 +0000102#ifndef SQLITE_OMIT_AUTHORIZATION
103 {
104 int code = SQLITE_CREATE_TRIGGER;
105 if( tab->isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
106 if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){
107 goto trigger_cleanup;
108 }
drh77ad4e42003-01-14 02:49:27 +0000109 if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->isTemp), 0)){
110 goto trigger_cleanup;
111 }
drhed6c8672003-01-12 18:02:16 +0000112 }
drhe5f9c642003-01-13 23:27:31 +0000113#endif
danielk1977d702fcc2002-05-26 23:24:40 +0000114 }
115
116 if (tr_tm == TK_INSTEAD){
117 tr_tm = TK_BEFORE;
danielk1977c3f9bad2002-05-15 08:30:12 +0000118 }
119
120 /* Build the Trigger object */
drh9adf9ac2002-05-15 11:44:13 +0000121 nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
drhe4697f52002-05-23 02:09:03 +0000122 if( nt==0 ) goto trigger_cleanup;
drhe5f9c642003-01-13 23:27:31 +0000123 nt->name = zName;
124 zName = 0;
danielk1977633ed082002-05-17 00:05:58 +0000125 nt->table = sqliteStrNDup(pTableName->z, pTableName->n);
drhe4697f52002-05-23 02:09:03 +0000126 if( sqlite_malloc_failed ) goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000127 nt->op = op;
128 nt->tr_tm = tr_tm;
drh4b59ab52002-08-24 18:24:51 +0000129 nt->pWhen = sqliteExprDup(pWhen);
130 sqliteExprDelete(pWhen);
131 nt->pColumns = sqliteIdListDup(pColumns);
132 sqliteIdListDelete(pColumns);
danielk1977c3f9bad2002-05-15 08:30:12 +0000133 nt->foreach = foreach;
danielk1977633ed082002-05-17 00:05:58 +0000134 nt->step_list = pStepList;
danielk1977c3f9bad2002-05-15 08:30:12 +0000135
136 /* if we are not initializing, and this trigger is not on a TEMP table,
drh9adf9ac2002-05-15 11:44:13 +0000137 ** build the sqlite_master entry
138 */
drhe0bc4042002-06-25 01:09:11 +0000139 if( !pParse->initFlag ){
drhc977f7f2002-05-21 11:38:11 +0000140 static VdbeOp insertTrig[] = {
drhc977f7f2002-05-21 11:38:11 +0000141 { OP_NewRecno, 0, 0, 0 },
142 { OP_String, 0, 0, "trigger" },
drhe0bc4042002-06-25 01:09:11 +0000143 { OP_String, 0, 0, 0 }, /* 2: trigger name */
144 { OP_String, 0, 0, 0 }, /* 3: table name */
drhc977f7f2002-05-21 11:38:11 +0000145 { OP_Integer, 0, 0, 0 },
drhe0bc4042002-06-25 01:09:11 +0000146 { OP_String, 0, 0, 0 }, /* 5: SQL */
drhc977f7f2002-05-21 11:38:11 +0000147 { OP_MakeRecord, 5, 0, 0 },
148 { OP_PutIntKey, 0, 0, 0 },
drhc977f7f2002-05-21 11:38:11 +0000149 };
150 int addr;
151 Vdbe *v;
danielk1977c3f9bad2002-05-15 08:30:12 +0000152
153 /* Make an entry in the sqlite_master table */
drhc977f7f2002-05-21 11:38:11 +0000154 v = sqliteGetVdbe(pParse);
drhe4697f52002-05-23 02:09:03 +0000155 if( v==0 ) goto trigger_cleanup;
drhcabb0812002-09-14 13:47:32 +0000156 sqliteBeginWriteOperation(pParse, 0, 0);
drhe0bc4042002-06-25 01:09:11 +0000157 sqliteOpenMasterTable(v, tab->isTemp);
drhc977f7f2002-05-21 11:38:11 +0000158 addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
drhe0bc4042002-06-25 01:09:11 +0000159 sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME,
160 P3_STATIC);
161 sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
162 sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
drh4b59ab52002-08-24 18:24:51 +0000163 sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
drhe0bc4042002-06-25 01:09:11 +0000164 if( !tab->isTemp ){
165 sqliteChangeCookie(pParse->db, v);
166 }
167 sqliteVdbeAddOp(v, OP_Close, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000168 sqliteEndWriteOperation(pParse);
169 }
170
danielk1977633ed082002-05-17 00:05:58 +0000171 if( !pParse->explain ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000172 /* Stick it in the hash-table */
danielk1977633ed082002-05-17 00:05:58 +0000173 sqliteHashInsert(&(pParse->db->trigHash), nt->name, pName->n + 1, nt);
danielk1977c3f9bad2002-05-15 08:30:12 +0000174
175 /* Attach it to the table object */
176 nt->pNext = tab->pTrigger;
177 tab->pTrigger = nt;
178 return;
danielk1977f29ce552002-05-19 23:43:12 +0000179 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000180 sqliteFree(nt->name);
181 sqliteFree(nt->table);
182 sqliteFree(nt);
183 }
184
185trigger_cleanup:
186
drhe5f9c642003-01-13 23:27:31 +0000187 sqliteFree(zName);
danielk1977633ed082002-05-17 00:05:58 +0000188 sqliteIdListDelete(pColumns);
danielk1977c3f9bad2002-05-15 08:30:12 +0000189 sqliteExprDelete(pWhen);
drh4b59ab52002-08-24 18:24:51 +0000190 sqliteDeleteTriggerStep(pStepList);
191}
danielk1977c3f9bad2002-05-15 08:30:12 +0000192
drh4b59ab52002-08-24 18:24:51 +0000193/*
194** Make a copy of all components of the given trigger step. This has
195** the effect of copying all Expr.token.z values into memory obtained
196** from sqliteMalloc(). As initially created, the Expr.token.z values
197** all point to the input string that was fed to the parser. But that
198** string is ephemeral - it will go away as soon as the sqlite_exec()
199** call that started the parser exits. This routine makes a persistent
200** copy of all the Expr.token.z strings so that the TriggerStep structure
201** will be valid even after the sqlite_exec() call returns.
202*/
203static void sqlitePersistTriggerStep(TriggerStep *p){
204 if( p->target.z ){
205 p->target.z = sqliteStrNDup(p->target.z, p->target.n);
206 p->target.dyn = 1;
207 }
208 if( p->pSelect ){
209 Select *pNew = sqliteSelectDup(p->pSelect);
210 sqliteSelectDelete(p->pSelect);
211 p->pSelect = pNew;
212 }
213 if( p->pWhere ){
214 Expr *pNew = sqliteExprDup(p->pWhere);
215 sqliteExprDelete(p->pWhere);
216 p->pWhere = pNew;
217 }
218 if( p->pExprList ){
219 ExprList *pNew = sqliteExprListDup(p->pExprList);
220 sqliteExprListDelete(p->pExprList);
221 p->pExprList = pNew;
222 }
223 if( p->pIdList ){
224 IdList *pNew = sqliteIdListDup(p->pIdList);
225 sqliteIdListDelete(p->pIdList);
226 p->pIdList = pNew;
danielk1977c3f9bad2002-05-15 08:30:12 +0000227 }
228}
229
drhc977f7f2002-05-21 11:38:11 +0000230/*
231** Turn a SELECT statement (that the pSelect parameter points to) into
232** a trigger step. Return a pointer to a TriggerStep structure.
233**
234** The parser calls this routine when it finds a SELECT statement in
235** body of a TRIGGER.
236*/
237TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
danielk1977633ed082002-05-17 00:05:58 +0000238 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000239 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000240
danielk1977633ed082002-05-17 00:05:58 +0000241 pTriggerStep->op = TK_SELECT;
242 pTriggerStep->pSelect = pSelect;
243 pTriggerStep->orconf = OE_Default;
drh4b59ab52002-08-24 18:24:51 +0000244 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000245
danielk1977633ed082002-05-17 00:05:58 +0000246 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000247}
248
drhc977f7f2002-05-21 11:38:11 +0000249/*
250** Build a trigger step out of an INSERT statement. Return a pointer
251** to the new trigger step.
252**
253** The parser calls this routine when it sees an INSERT inside the
254** body of a trigger.
255*/
danielk1977633ed082002-05-17 00:05:58 +0000256TriggerStep *sqliteTriggerInsertStep(
drhc977f7f2002-05-21 11:38:11 +0000257 Token *pTableName, /* Name of the table into which we insert */
258 IdList *pColumn, /* List of columns in pTableName to insert into */
259 ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
260 Select *pSelect, /* A SELECT statement that supplies values */
261 int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
danielk1977633ed082002-05-17 00:05:58 +0000262){
263 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000264 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000265
danielk1977633ed082002-05-17 00:05:58 +0000266 assert(pEList == 0 || pSelect == 0);
267 assert(pEList != 0 || pSelect != 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000268
danielk1977633ed082002-05-17 00:05:58 +0000269 pTriggerStep->op = TK_INSERT;
270 pTriggerStep->pSelect = pSelect;
271 pTriggerStep->target = *pTableName;
272 pTriggerStep->pIdList = pColumn;
273 pTriggerStep->pExprList = pEList;
274 pTriggerStep->orconf = orconf;
drh4b59ab52002-08-24 18:24:51 +0000275 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000276
danielk1977633ed082002-05-17 00:05:58 +0000277 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000278}
279
drhc977f7f2002-05-21 11:38:11 +0000280/*
281** Construct a trigger step that implements an UPDATE statement and return
282** a pointer to that trigger step. The parser calls this routine when it
283** sees an UPDATE statement inside the body of a CREATE TRIGGER.
284*/
danielk1977633ed082002-05-17 00:05:58 +0000285TriggerStep *sqliteTriggerUpdateStep(
drhc977f7f2002-05-21 11:38:11 +0000286 Token *pTableName, /* Name of the table to be updated */
287 ExprList *pEList, /* The SET clause: list of column and new values */
288 Expr *pWhere, /* The WHERE clause */
289 int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
290){
danielk1977633ed082002-05-17 00:05:58 +0000291 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000292 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000293
danielk1977633ed082002-05-17 00:05:58 +0000294 pTriggerStep->op = TK_UPDATE;
295 pTriggerStep->target = *pTableName;
296 pTriggerStep->pExprList = pEList;
297 pTriggerStep->pWhere = pWhere;
298 pTriggerStep->orconf = orconf;
drh4b59ab52002-08-24 18:24:51 +0000299 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000300
danielk1977633ed082002-05-17 00:05:58 +0000301 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000302}
303
drhc977f7f2002-05-21 11:38:11 +0000304/*
305** Construct a trigger step that implements a DELETE statement and return
306** a pointer to that trigger step. The parser calls this routine when it
307** sees a DELETE statement inside the body of a CREATE TRIGGER.
308*/
309TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
drhe4697f52002-05-23 02:09:03 +0000310 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
311 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000312
danielk1977633ed082002-05-17 00:05:58 +0000313 pTriggerStep->op = TK_DELETE;
314 pTriggerStep->target = *pTableName;
315 pTriggerStep->pWhere = pWhere;
316 pTriggerStep->orconf = OE_Default;
drh4b59ab52002-08-24 18:24:51 +0000317 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000318
danielk1977633ed082002-05-17 00:05:58 +0000319 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000320}
321
danielk1977633ed082002-05-17 00:05:58 +0000322/*
323** Recursively delete a Trigger structure
324*/
drh1d1f3052002-05-21 13:18:25 +0000325void sqliteDeleteTrigger(Trigger *pTrigger){
drh4b59ab52002-08-24 18:24:51 +0000326 sqliteDeleteTriggerStep(pTrigger->step_list);
danielk1977633ed082002-05-17 00:05:58 +0000327 sqliteFree(pTrigger->name);
328 sqliteFree(pTrigger->table);
329 sqliteExprDelete(pTrigger->pWhen);
330 sqliteIdListDelete(pTrigger->pColumns);
danielk1977633ed082002-05-17 00:05:58 +0000331 sqliteFree(pTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000332}
333
334/*
danielk1977633ed082002-05-17 00:05:58 +0000335 * This function is called to drop a trigger from the database schema.
336 *
337 * This may be called directly from the parser, or from within
338 * sqliteDropTable(). In the latter case the "nested" argument is true.
339 *
340 * Note that this function does not delete the trigger entirely. Instead it
341 * removes it from the internal schema and places it in the trigDrop hash
342 * table. This is so that the trigger can be restored into the database schema
343 * if the transaction is rolled back.
danielk1977c3f9bad2002-05-15 08:30:12 +0000344 */
drhe0bc4042002-06-25 01:09:11 +0000345void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
danielk1977633ed082002-05-17 00:05:58 +0000346 char *zName;
347 Trigger *pTrigger;
348 Table *pTable;
drhe0bc4042002-06-25 01:09:11 +0000349 Vdbe *v;
danielk1977c3f9bad2002-05-15 08:30:12 +0000350
danielk1977633ed082002-05-17 00:05:58 +0000351 zName = sqliteStrNDup(pName->z, pName->n);
danielk1977c3f9bad2002-05-15 08:30:12 +0000352
353 /* ensure that the trigger being dropped exists */
danielk1977633ed082002-05-17 00:05:58 +0000354 pTrigger = sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1);
355 if( !pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000356 sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1,
danielk1977633ed082002-05-17 00:05:58 +0000357 zName, -1, 0);
358 sqliteFree(zName);
danielk1977c3f9bad2002-05-15 08:30:12 +0000359 return;
360 }
drhed6c8672003-01-12 18:02:16 +0000361 pTable = sqliteFindTable(pParse->db, pTrigger->table);
362 assert(pTable);
drhe5f9c642003-01-13 23:27:31 +0000363#ifndef SQLITE_OMIT_AUTHORIZATION
364 {
365 int code = SQLITE_DROP_TRIGGER;
366 if( pTable->isTemp ) code = SQLITE_DROP_TEMP_TRIGGER;
367 if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) ||
368 sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->isTemp),0) ){
369 sqliteFree(zName);
370 return;
371 }
drhed6c8672003-01-12 18:02:16 +0000372 }
drhe5f9c642003-01-13 23:27:31 +0000373#endif
danielk1977c3f9bad2002-05-15 08:30:12 +0000374
375 /*
drhe0bc4042002-06-25 01:09:11 +0000376 * If this is not an "explain", then delete the trigger structure.
danielk1977c3f9bad2002-05-15 08:30:12 +0000377 */
danielk1977633ed082002-05-17 00:05:58 +0000378 if( !pParse->explain ){
danielk1977633ed082002-05-17 00:05:58 +0000379 if( pTable->pTrigger == pTrigger ){
380 pTable->pTrigger = pTrigger->pNext;
danielk1977f29ce552002-05-19 23:43:12 +0000381 }else{
danielk1977633ed082002-05-17 00:05:58 +0000382 Trigger *cc = pTable->pTrigger;
383 while( cc ){
384 if( cc->pNext == pTrigger ){
drh9adf9ac2002-05-15 11:44:13 +0000385 cc->pNext = cc->pNext->pNext;
386 break;
387 }
388 cc = cc->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000389 }
390 assert(cc);
391 }
drhe0bc4042002-06-25 01:09:11 +0000392 sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL);
393 sqliteDeleteTrigger(pTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000394 }
395
drhe0bc4042002-06-25 01:09:11 +0000396 /* Generate code to destroy the database record of the trigger.
397 */
398 if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000399 int base;
400 static VdbeOp dropTrigger[] = {
drhe0bc4042002-06-25 01:09:11 +0000401 { OP_Rewind, 0, ADDR(8), 0},
402 { OP_String, 0, 0, 0}, /* 1 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000403 { OP_MemStore, 1, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000404 { OP_MemLoad, 1, 0, 0}, /* 3 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000405 { OP_Column, 0, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000406 { OP_Ne, 0, ADDR(7), 0},
danielk1977c3f9bad2002-05-15 08:30:12 +0000407 { OP_Delete, 0, 0, 0},
drhe0bc4042002-06-25 01:09:11 +0000408 { OP_Next, 0, ADDR(3), 0}, /* 7 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000409 };
410
drhcabb0812002-09-14 13:47:32 +0000411 sqliteBeginWriteOperation(pParse, 0, 0);
drhe0bc4042002-06-25 01:09:11 +0000412 sqliteOpenMasterTable(v, pTable->isTemp);
413 base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
414 sqliteVdbeChangeP3(v, base+1, zName, 0);
415 if( !pTable->isTemp ){
416 sqliteChangeCookie(pParse->db, v);
drhdc379452002-05-15 12:45:43 +0000417 }
drhe0bc4042002-06-25 01:09:11 +0000418 sqliteVdbeAddOp(v, OP_Close, 0, 0);
419 sqliteEndWriteOperation(pParse);
danielk1977c3f9bad2002-05-15 08:30:12 +0000420 }
421
danielk1977633ed082002-05-17 00:05:58 +0000422 sqliteFree(zName);
danielk1977c3f9bad2002-05-15 08:30:12 +0000423}
424
drhc977f7f2002-05-21 11:38:11 +0000425/*
426** pEList is the SET clause of an UPDATE statement. Each entry
427** in pEList is of the format <id>=<expr>. If any of the entries
428** in pEList have an <id> which matches an identifier in pIdList,
429** then return TRUE. If pIdList==NULL, then it is considered a
430** wildcard that matches anything. Likewise if pEList==NULL then
431** it matches anything so always return true. Return false only
432** if there is no match.
433*/
434static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
drhad2d8302002-05-24 20:31:36 +0000435 int e;
436 if( !pIdList || !pEList ) return 1;
437 for(e=0; e<pEList->nExpr; e++){
438 if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
danielk1977f29ce552002-05-19 23:43:12 +0000439 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000440 return 0;
441}
442
443/* A global variable that is TRUE if we should always set up temp tables for
444 * for triggers, even if there are no triggers to code. This is used to test
445 * how much overhead the triggers algorithm is causing.
446 *
447 * This flag can be set or cleared using the "trigger_overhead_test" pragma.
448 * The pragma is not documented since it is not really part of the interface
449 * to SQLite, just the test procedure.
450*/
451int always_code_trigger_setup = 0;
452
453/*
454 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
455 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
456 * found in the list specified as pTrigger.
457 */
458int sqliteTriggersExist(
drhc977f7f2002-05-21 11:38:11 +0000459 Parse *pParse, /* Used to check for recursive triggers */
460 Trigger *pTrigger, /* A list of triggers associated with a table */
danielk1977633ed082002-05-17 00:05:58 +0000461 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
462 int tr_tm, /* one of TK_BEFORE, TK_AFTER */
463 int foreach, /* one of TK_ROW or TK_STATEMENT */
drhc977f7f2002-05-21 11:38:11 +0000464 ExprList *pChanges /* Columns that change in an UPDATE statement */
465){
danielk1977633ed082002-05-17 00:05:58 +0000466 Trigger * pTriggerCursor;
danielk1977c3f9bad2002-05-15 08:30:12 +0000467
danielk1977633ed082002-05-17 00:05:58 +0000468 if( always_code_trigger_setup ){
469 return 1;
470 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000471
danielk1977633ed082002-05-17 00:05:58 +0000472 pTriggerCursor = pTrigger;
473 while( pTriggerCursor ){
474 if( pTriggerCursor->op == op &&
475 pTriggerCursor->tr_tm == tr_tm &&
476 pTriggerCursor->foreach == foreach &&
477 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000478 TriggerStack * ss;
479 ss = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000480 while( ss && ss->pTrigger != pTrigger ){
481 ss = ss->pNext;
482 }
483 if( !ss )return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000484 }
danielk1977633ed082002-05-17 00:05:58 +0000485 pTriggerCursor = pTriggerCursor->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000486 }
487
488 return 0;
489}
490
drhc977f7f2002-05-21 11:38:11 +0000491/*
492** Generate VDBE code for zero or more statements inside the body of a
493** trigger.
494*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000495static int codeTriggerProgram(
drhc977f7f2002-05-21 11:38:11 +0000496 Parse *pParse, /* The parser context */
497 TriggerStep *pStepList, /* List of statements inside the trigger body */
498 int orconfin /* Conflict algorithm. (OE_Abort, etc) */
danielk1977633ed082002-05-17 00:05:58 +0000499){
500 TriggerStep * pTriggerStep = pStepList;
501 int orconf;
danielk1977c3f9bad2002-05-15 08:30:12 +0000502
danielk1977633ed082002-05-17 00:05:58 +0000503 while( pTriggerStep ){
504 int saveNTab = pParse->nTab;
505 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
506 pParse->trigStack->orconf = orconf;
507 switch( pTriggerStep->op ){
508 case TK_SELECT: {
danielk19776f349032002-06-11 02:25:40 +0000509 Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
510 assert(ss);
511 assert(ss->pSrc);
512 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
513 sqliteSelectDelete(ss);
danielk1977633ed082002-05-17 00:05:58 +0000514 break;
515 }
516 case TK_UPDATE: {
drh113088e2003-03-20 01:16:58 +0000517 SrcList *pSrc;
518 pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
drhbd5a4512002-05-23 22:07:02 +0000519 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
drh113088e2003-03-20 01:16:58 +0000520 sqliteUpdate(pParse, pSrc,
danielk19776f349032002-06-11 02:25:40 +0000521 sqliteExprListDup(pTriggerStep->pExprList),
522 sqliteExprDup(pTriggerStep->pWhere), orconf);
drhbd5a4512002-05-23 22:07:02 +0000523 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000524 break;
525 }
526 case TK_INSERT: {
drh113088e2003-03-20 01:16:58 +0000527 SrcList *pSrc;
528 pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
529 sqliteInsert(pParse, pSrc,
530 sqliteExprListDup(pTriggerStep->pExprList),
531 sqliteSelectDup(pTriggerStep->pSelect),
532 sqliteIdListDup(pTriggerStep->pIdList), orconf);
danielk1977633ed082002-05-17 00:05:58 +0000533 break;
534 }
535 case TK_DELETE: {
drh113088e2003-03-20 01:16:58 +0000536 SrcList *pSrc;
drhbd5a4512002-05-23 22:07:02 +0000537 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
drh113088e2003-03-20 01:16:58 +0000538 pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
539 sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
drhbd5a4512002-05-23 22:07:02 +0000540 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000541 break;
542 }
543 default:
544 assert(0);
545 }
546 pParse->nTab = saveNTab;
547 pTriggerStep = pTriggerStep->pNext;
548 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000549
danielk1977633ed082002-05-17 00:05:58 +0000550 return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000551}
552
danielk1977633ed082002-05-17 00:05:58 +0000553/*
554** This is called to code FOR EACH ROW triggers.
555**
556** When the code that this function generates is executed, the following
557** must be true:
drhc977f7f2002-05-21 11:38:11 +0000558**
559** 1. No cursors may be open in the main database. (But newIdx and oldIdx
560** can be indices of cursors in temporary tables. See below.)
561**
danielk1977633ed082002-05-17 00:05:58 +0000562** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
563** a temporary vdbe cursor (index newIdx) must be open and pointing at
564** a row containing values to be substituted for new.* expressions in the
565** trigger program(s).
drhc977f7f2002-05-21 11:38:11 +0000566**
danielk1977633ed082002-05-17 00:05:58 +0000567** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
568** a temporary vdbe cursor (index oldIdx) must be open and pointing at
569** a row containing values to be substituted for old.* expressions in the
570** trigger program(s).
571**
572*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000573int sqliteCodeRowTrigger(
danielk1977633ed082002-05-17 00:05:58 +0000574 Parse *pParse, /* Parse context */
575 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
576 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
577 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
578 Table *pTab, /* The table to code triggers from */
579 int newIdx, /* The indice of the "new" row to access */
580 int oldIdx, /* The indice of the "old" row to access */
danielk19776f349032002-06-11 02:25:40 +0000581 int orconf, /* ON CONFLICT policy */
582 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
drhc977f7f2002-05-21 11:38:11 +0000583){
danielk1977c3f9bad2002-05-15 08:30:12 +0000584 Trigger * pTrigger;
585 TriggerStack * pTriggerStack;
586
danielk1977c3f9bad2002-05-15 08:30:12 +0000587 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
588 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
589
danielk1977633ed082002-05-17 00:05:58 +0000590 assert(newIdx != -1 || oldIdx != -1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000591
danielk1977633ed082002-05-17 00:05:58 +0000592 pTrigger = pTab->pTrigger;
danielk1977f29ce552002-05-19 23:43:12 +0000593 while( pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000594 int fire_this = 0;
595
596 /* determine whether we should code this trigger */
danielk1977f29ce552002-05-19 23:43:12 +0000597 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
598 pTrigger->foreach == TK_ROW ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000599 fire_this = 1;
600 pTriggerStack = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000601 while( pTriggerStack ){
602 if( pTriggerStack->pTrigger == pTrigger ){
603 fire_this = 0;
604 }
drh9adf9ac2002-05-15 11:44:13 +0000605 pTriggerStack = pTriggerStack->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000606 }
danielk1977f29ce552002-05-19 23:43:12 +0000607 if( op == TK_UPDATE && pTrigger->pColumns &&
608 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
drh9adf9ac2002-05-15 11:44:13 +0000609 fire_this = 0;
danielk1977f29ce552002-05-19 23:43:12 +0000610 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000611 }
612
drhe4697f52002-05-23 02:09:03 +0000613 if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000614 int endTrigger;
drhad3cab52002-05-24 02:04:32 +0000615 SrcList dummyTablist;
danielk1977c3f9bad2002-05-15 08:30:12 +0000616 Expr * whenExpr;
617
drhad3cab52002-05-24 02:04:32 +0000618 dummyTablist.nSrc = 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000619
620 /* Push an entry on to the trigger stack */
danielk1977c3f9bad2002-05-15 08:30:12 +0000621 pTriggerStack->pTrigger = pTrigger;
danielk1977633ed082002-05-17 00:05:58 +0000622 pTriggerStack->newIdx = newIdx;
623 pTriggerStack->oldIdx = oldIdx;
624 pTriggerStack->pTab = pTab;
danielk1977c3f9bad2002-05-15 08:30:12 +0000625 pTriggerStack->pNext = pParse->trigStack;
danielk19776f349032002-06-11 02:25:40 +0000626 pTriggerStack->ignoreJump = ignoreJump;
danielk1977c3f9bad2002-05-15 08:30:12 +0000627 pParse->trigStack = pTriggerStack;
628
629 /* code the WHEN clause */
630 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
631 whenExpr = sqliteExprDup(pTrigger->pWhen);
danielk1977f29ce552002-05-19 23:43:12 +0000632 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000633 pParse->trigStack = pParse->trigStack->pNext;
634 sqliteFree(pTriggerStack);
635 sqliteExprDelete(whenExpr);
636 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000637 }
drhf5905aa2002-05-26 20:54:33 +0000638 sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000639 sqliteExprDelete(whenExpr);
640
danielk1977633ed082002-05-17 00:05:58 +0000641 codeTriggerProgram(pParse, pTrigger->step_list, orconf);
danielk1977c3f9bad2002-05-15 08:30:12 +0000642
643 /* Pop the entry off the trigger stack */
644 pParse->trigStack = pParse->trigStack->pNext;
645 sqliteFree(pTriggerStack);
646
647 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
648 }
649 pTrigger = pTrigger->pNext;
650 }
651
652 return 0;
653}
654
655/*
danielk1977633ed082002-05-17 00:05:58 +0000656 * This function is called to code ON UPDATE and ON DELETE triggers on
657 * views.
658 *
659 * This function deletes the data pointed at by the pWhere and pChanges
660 * arguments before it completes.
danielk1977c3f9bad2002-05-15 08:30:12 +0000661 */
danielk1977633ed082002-05-17 00:05:58 +0000662void sqliteViewTriggers(
663 Parse *pParse,
664 Table *pTab, /* The view to code triggers on */
665 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/
666 int orconf, /* The ON CONFLICT policy specified as part of the
667 statement causing these triggers */
668 ExprList *pChanges /* If this is an statement causing triggers to fire
669 is an UPDATE, then this list holds the columns
670 to update and the expressions to update them to.
671 See comments for sqliteUpdate(). */
672){
danielk1977c3f9bad2002-05-15 08:30:12 +0000673 int oldIdx = -1;
674 int newIdx = -1;
675 int *aXRef = 0;
676 Vdbe *v;
677 int endOfLoop;
678 int startOfLoop;
679 Select theSelect;
680 Token tblNameToken;
681
682 assert(pTab->pSelect);
683
684 tblNameToken.z = pTab->zName;
685 tblNameToken.n = strlen(pTab->zName);
686
687 theSelect.isDistinct = 0;
688 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
drh113088e2003-03-20 01:16:58 +0000689 theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000690 theSelect.pWhere = pWhere; pWhere = 0;
691 theSelect.pGroupBy = 0;
692 theSelect.pHaving = 0;
693 theSelect.pOrderBy = 0;
694 theSelect.op = TK_SELECT; /* ?? */
695 theSelect.pPrior = 0;
696 theSelect.nLimit = -1;
697 theSelect.nOffset = -1;
698 theSelect.zSelect = 0;
699 theSelect.base = 0;
700
701 v = sqliteGetVdbe(pParse);
702 assert(v);
drhcabb0812002-09-14 13:47:32 +0000703 sqliteBeginWriteOperation(pParse, 1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000704
705 /* Allocate temp tables */
706 oldIdx = pParse->nTab++;
707 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
danielk1977633ed082002-05-17 00:05:58 +0000708 if( pChanges ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000709 newIdx = pParse->nTab++;
710 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
711 }
712
713 /* Snapshot the view */
danielk1977633ed082002-05-17 00:05:58 +0000714 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000715 goto trigger_cleanup;
716 }
717
718 /* loop thru the view snapshot, executing triggers for each row */
719 endOfLoop = sqliteVdbeMakeLabel(v);
720 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
721
722 /* Loop thru the view snapshot, executing triggers for each row */
723 startOfLoop = sqliteVdbeCurrentAddr(v);
724
725 /* Build the updated row if required */
danielk1977633ed082002-05-17 00:05:58 +0000726 if( pChanges ){
drh1d1f3052002-05-21 13:18:25 +0000727 int ii;
danielk1977c3f9bad2002-05-15 08:30:12 +0000728
729 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
730 if( aXRef==0 ) goto trigger_cleanup;
danielk1977633ed082002-05-17 00:05:58 +0000731 for(ii = 0; ii < pTab->nCol; ii++){
danielk1977c3f9bad2002-05-15 08:30:12 +0000732 aXRef[ii] = -1;
danielk1977633ed082002-05-17 00:05:58 +0000733 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000734
735 for(ii=0; ii<pChanges->nExpr; ii++){
736 int jj;
737 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
danielk1977f29ce552002-05-19 23:43:12 +0000738 pChanges->a[ii].pExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000739 goto trigger_cleanup;
danielk1977f29ce552002-05-19 23:43:12 +0000740 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000741
742 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
drh9adf9ac2002-05-15 11:44:13 +0000743 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000744
745 for(jj=0; jj<pTab->nCol; jj++){
drh9adf9ac2002-05-15 11:44:13 +0000746 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
747 aXRef[jj] = ii;
748 break;
749 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000750 }
751 if( jj>=pTab->nCol ){
drh9adf9ac2002-05-15 11:44:13 +0000752 sqliteSetString(&pParse->zErrMsg, "no such column: ",
753 pChanges->a[ii].zName, 0);
754 pParse->nErr++;
755 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000756 }
757 }
758
759 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
760
danielk1977633ed082002-05-17 00:05:58 +0000761 for(ii = 0; ii<pTab->nCol; ii++){
762 if( aXRef[ii] < 0 ){
drh9adf9ac2002-05-15 11:44:13 +0000763 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
danielk1977f29ce552002-05-19 23:43:12 +0000764 }else{
drh9adf9ac2002-05-15 11:44:13 +0000765 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
danielk1977633ed082002-05-17 00:05:58 +0000766 }
767 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000768
769 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
770 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
771 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
772
773 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
danielk19776f349032002-06-11 02:25:40 +0000774 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000775 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
danielk19776f349032002-06-11 02:25:40 +0000776 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977f29ce552002-05-19 23:43:12 +0000777 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000778 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000779 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000780 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000781 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000782 }
783
784 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
785
786 sqliteVdbeResolveLabel(v, endOfLoop);
787 sqliteEndWriteOperation(pParse);
788
789trigger_cleanup:
790 sqliteFree(aXRef);
791 sqliteExprListDelete(pChanges);
792 sqliteExprDelete(pWhere);
793 sqliteExprListDelete(theSelect.pEList);
drhad3cab52002-05-24 02:04:32 +0000794 sqliteSrcListDelete(theSelect.pSrc);
danielk1977c3f9bad2002-05-15 08:30:12 +0000795 sqliteExprDelete(theSelect.pWhere);
796 return;
797}