blob: 03032fe259b2ea973e2c297c27e1d6038f113f86 [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: {
drhbd5a4512002-05-23 22:07:02 +0000517 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000518 sqliteUpdate(pParse, &pTriggerStep->target,
danielk19776f349032002-06-11 02:25:40 +0000519 sqliteExprListDup(pTriggerStep->pExprList),
520 sqliteExprDup(pTriggerStep->pWhere), orconf);
drhbd5a4512002-05-23 22:07:02 +0000521 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000522 break;
523 }
524 case TK_INSERT: {
525 sqliteInsert(pParse, &pTriggerStep->target,
526 sqliteExprListDup(pTriggerStep->pExprList),
527 sqliteSelectDup(pTriggerStep->pSelect),
528 sqliteIdListDup(pTriggerStep->pIdList), orconf);
529 break;
530 }
531 case TK_DELETE: {
drhbd5a4512002-05-23 22:07:02 +0000532 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000533 sqliteDeleteFrom(pParse, &pTriggerStep->target,
534 sqliteExprDup(pTriggerStep->pWhere));
drhbd5a4512002-05-23 22:07:02 +0000535 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000536 break;
537 }
538 default:
539 assert(0);
540 }
541 pParse->nTab = saveNTab;
542 pTriggerStep = pTriggerStep->pNext;
543 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000544
danielk1977633ed082002-05-17 00:05:58 +0000545 return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000546}
547
danielk1977633ed082002-05-17 00:05:58 +0000548/*
549** This is called to code FOR EACH ROW triggers.
550**
551** When the code that this function generates is executed, the following
552** must be true:
drhc977f7f2002-05-21 11:38:11 +0000553**
554** 1. No cursors may be open in the main database. (But newIdx and oldIdx
555** can be indices of cursors in temporary tables. See below.)
556**
danielk1977633ed082002-05-17 00:05:58 +0000557** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
558** a temporary vdbe cursor (index newIdx) must be open and pointing at
559** a row containing values to be substituted for new.* expressions in the
560** trigger program(s).
drhc977f7f2002-05-21 11:38:11 +0000561**
danielk1977633ed082002-05-17 00:05:58 +0000562** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
563** a temporary vdbe cursor (index oldIdx) must be open and pointing at
564** a row containing values to be substituted for old.* expressions in the
565** trigger program(s).
566**
567*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000568int sqliteCodeRowTrigger(
danielk1977633ed082002-05-17 00:05:58 +0000569 Parse *pParse, /* Parse context */
570 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
571 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
572 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
573 Table *pTab, /* The table to code triggers from */
574 int newIdx, /* The indice of the "new" row to access */
575 int oldIdx, /* The indice of the "old" row to access */
danielk19776f349032002-06-11 02:25:40 +0000576 int orconf, /* ON CONFLICT policy */
577 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
drhc977f7f2002-05-21 11:38:11 +0000578){
danielk1977c3f9bad2002-05-15 08:30:12 +0000579 Trigger * pTrigger;
580 TriggerStack * pTriggerStack;
581
danielk1977c3f9bad2002-05-15 08:30:12 +0000582 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
583 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
584
danielk1977633ed082002-05-17 00:05:58 +0000585 assert(newIdx != -1 || oldIdx != -1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000586
danielk1977633ed082002-05-17 00:05:58 +0000587 pTrigger = pTab->pTrigger;
danielk1977f29ce552002-05-19 23:43:12 +0000588 while( pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000589 int fire_this = 0;
590
591 /* determine whether we should code this trigger */
danielk1977f29ce552002-05-19 23:43:12 +0000592 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
593 pTrigger->foreach == TK_ROW ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000594 fire_this = 1;
595 pTriggerStack = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000596 while( pTriggerStack ){
597 if( pTriggerStack->pTrigger == pTrigger ){
598 fire_this = 0;
599 }
drh9adf9ac2002-05-15 11:44:13 +0000600 pTriggerStack = pTriggerStack->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000601 }
danielk1977f29ce552002-05-19 23:43:12 +0000602 if( op == TK_UPDATE && pTrigger->pColumns &&
603 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
drh9adf9ac2002-05-15 11:44:13 +0000604 fire_this = 0;
danielk1977f29ce552002-05-19 23:43:12 +0000605 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000606 }
607
drhe4697f52002-05-23 02:09:03 +0000608 if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000609 int endTrigger;
drhad3cab52002-05-24 02:04:32 +0000610 SrcList dummyTablist;
danielk1977c3f9bad2002-05-15 08:30:12 +0000611 Expr * whenExpr;
612
drhad3cab52002-05-24 02:04:32 +0000613 dummyTablist.nSrc = 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000614 dummyTablist.a = 0;
615
616 /* Push an entry on to the trigger stack */
danielk1977c3f9bad2002-05-15 08:30:12 +0000617 pTriggerStack->pTrigger = pTrigger;
danielk1977633ed082002-05-17 00:05:58 +0000618 pTriggerStack->newIdx = newIdx;
619 pTriggerStack->oldIdx = oldIdx;
620 pTriggerStack->pTab = pTab;
danielk1977c3f9bad2002-05-15 08:30:12 +0000621 pTriggerStack->pNext = pParse->trigStack;
danielk19776f349032002-06-11 02:25:40 +0000622 pTriggerStack->ignoreJump = ignoreJump;
danielk1977c3f9bad2002-05-15 08:30:12 +0000623 pParse->trigStack = pTriggerStack;
624
625 /* code the WHEN clause */
626 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
627 whenExpr = sqliteExprDup(pTrigger->pWhen);
danielk1977f29ce552002-05-19 23:43:12 +0000628 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000629 pParse->trigStack = pParse->trigStack->pNext;
630 sqliteFree(pTriggerStack);
631 sqliteExprDelete(whenExpr);
632 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000633 }
drhf5905aa2002-05-26 20:54:33 +0000634 sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000635 sqliteExprDelete(whenExpr);
636
danielk1977633ed082002-05-17 00:05:58 +0000637 codeTriggerProgram(pParse, pTrigger->step_list, orconf);
danielk1977c3f9bad2002-05-15 08:30:12 +0000638
639 /* Pop the entry off the trigger stack */
640 pParse->trigStack = pParse->trigStack->pNext;
641 sqliteFree(pTriggerStack);
642
643 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
644 }
645 pTrigger = pTrigger->pNext;
646 }
647
648 return 0;
649}
650
651/*
danielk1977633ed082002-05-17 00:05:58 +0000652 * This function is called to code ON UPDATE and ON DELETE triggers on
653 * views.
654 *
655 * This function deletes the data pointed at by the pWhere and pChanges
656 * arguments before it completes.
danielk1977c3f9bad2002-05-15 08:30:12 +0000657 */
danielk1977633ed082002-05-17 00:05:58 +0000658void sqliteViewTriggers(
659 Parse *pParse,
660 Table *pTab, /* The view to code triggers on */
661 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/
662 int orconf, /* The ON CONFLICT policy specified as part of the
663 statement causing these triggers */
664 ExprList *pChanges /* If this is an statement causing triggers to fire
665 is an UPDATE, then this list holds the columns
666 to update and the expressions to update them to.
667 See comments for sqliteUpdate(). */
668){
danielk1977c3f9bad2002-05-15 08:30:12 +0000669 int oldIdx = -1;
670 int newIdx = -1;
671 int *aXRef = 0;
672 Vdbe *v;
673 int endOfLoop;
674 int startOfLoop;
675 Select theSelect;
676 Token tblNameToken;
677
678 assert(pTab->pSelect);
679
680 tblNameToken.z = pTab->zName;
681 tblNameToken.n = strlen(pTab->zName);
682
683 theSelect.isDistinct = 0;
684 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
drhad3cab52002-05-24 02:04:32 +0000685 theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken);
danielk1977c3f9bad2002-05-15 08:30:12 +0000686 theSelect.pWhere = pWhere; pWhere = 0;
687 theSelect.pGroupBy = 0;
688 theSelect.pHaving = 0;
689 theSelect.pOrderBy = 0;
690 theSelect.op = TK_SELECT; /* ?? */
691 theSelect.pPrior = 0;
692 theSelect.nLimit = -1;
693 theSelect.nOffset = -1;
694 theSelect.zSelect = 0;
695 theSelect.base = 0;
696
697 v = sqliteGetVdbe(pParse);
698 assert(v);
drhcabb0812002-09-14 13:47:32 +0000699 sqliteBeginWriteOperation(pParse, 1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000700
701 /* Allocate temp tables */
702 oldIdx = pParse->nTab++;
703 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
danielk1977633ed082002-05-17 00:05:58 +0000704 if( pChanges ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000705 newIdx = pParse->nTab++;
706 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
707 }
708
709 /* Snapshot the view */
danielk1977633ed082002-05-17 00:05:58 +0000710 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000711 goto trigger_cleanup;
712 }
713
714 /* loop thru the view snapshot, executing triggers for each row */
715 endOfLoop = sqliteVdbeMakeLabel(v);
716 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
717
718 /* Loop thru the view snapshot, executing triggers for each row */
719 startOfLoop = sqliteVdbeCurrentAddr(v);
720
721 /* Build the updated row if required */
danielk1977633ed082002-05-17 00:05:58 +0000722 if( pChanges ){
drh1d1f3052002-05-21 13:18:25 +0000723 int ii;
danielk1977c3f9bad2002-05-15 08:30:12 +0000724
725 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
726 if( aXRef==0 ) goto trigger_cleanup;
danielk1977633ed082002-05-17 00:05:58 +0000727 for(ii = 0; ii < pTab->nCol; ii++){
danielk1977c3f9bad2002-05-15 08:30:12 +0000728 aXRef[ii] = -1;
danielk1977633ed082002-05-17 00:05:58 +0000729 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000730
731 for(ii=0; ii<pChanges->nExpr; ii++){
732 int jj;
733 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
danielk1977f29ce552002-05-19 23:43:12 +0000734 pChanges->a[ii].pExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000735 goto trigger_cleanup;
danielk1977f29ce552002-05-19 23:43:12 +0000736 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000737
738 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
drh9adf9ac2002-05-15 11:44:13 +0000739 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000740
741 for(jj=0; jj<pTab->nCol; jj++){
drh9adf9ac2002-05-15 11:44:13 +0000742 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
743 aXRef[jj] = ii;
744 break;
745 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000746 }
747 if( jj>=pTab->nCol ){
drh9adf9ac2002-05-15 11:44:13 +0000748 sqliteSetString(&pParse->zErrMsg, "no such column: ",
749 pChanges->a[ii].zName, 0);
750 pParse->nErr++;
751 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000752 }
753 }
754
755 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
756
danielk1977633ed082002-05-17 00:05:58 +0000757 for(ii = 0; ii<pTab->nCol; ii++){
758 if( aXRef[ii] < 0 ){
drh9adf9ac2002-05-15 11:44:13 +0000759 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
danielk1977f29ce552002-05-19 23:43:12 +0000760 }else{
drh9adf9ac2002-05-15 11:44:13 +0000761 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
danielk1977633ed082002-05-17 00:05:58 +0000762 }
763 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000764
765 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
766 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
767 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
768
769 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
danielk19776f349032002-06-11 02:25:40 +0000770 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000771 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
danielk19776f349032002-06-11 02:25:40 +0000772 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977f29ce552002-05-19 23:43:12 +0000773 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000774 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000775 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000776 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000777 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000778 }
779
780 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
781
782 sqliteVdbeResolveLabel(v, endOfLoop);
783 sqliteEndWriteOperation(pParse);
784
785trigger_cleanup:
786 sqliteFree(aXRef);
787 sqliteExprListDelete(pChanges);
788 sqliteExprDelete(pWhere);
789 sqliteExprListDelete(theSelect.pEList);
drhad3cab52002-05-24 02:04:32 +0000790 sqliteSrcListDelete(theSelect.pSrc);
danielk1977c3f9bad2002-05-15 08:30:12 +0000791 sqliteExprDelete(theSelect.pWhere);
792 return;
793}