blob: ce00c2b057c32d3808f85d457f9a3ae398a61590 [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 }
drhed6c8672003-01-12 18:02:16 +0000109 }
drhe5f9c642003-01-13 23:27:31 +0000110#endif
danielk1977d702fcc2002-05-26 23:24:40 +0000111 }
112
113 if (tr_tm == TK_INSTEAD){
114 tr_tm = TK_BEFORE;
danielk1977c3f9bad2002-05-15 08:30:12 +0000115 }
116
117 /* Build the Trigger object */
drh9adf9ac2002-05-15 11:44:13 +0000118 nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
drhe4697f52002-05-23 02:09:03 +0000119 if( nt==0 ) goto trigger_cleanup;
drhe5f9c642003-01-13 23:27:31 +0000120 nt->name = zName;
121 zName = 0;
danielk1977633ed082002-05-17 00:05:58 +0000122 nt->table = sqliteStrNDup(pTableName->z, pTableName->n);
drhe4697f52002-05-23 02:09:03 +0000123 if( sqlite_malloc_failed ) goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000124 nt->op = op;
125 nt->tr_tm = tr_tm;
drh4b59ab52002-08-24 18:24:51 +0000126 nt->pWhen = sqliteExprDup(pWhen);
127 sqliteExprDelete(pWhen);
128 nt->pColumns = sqliteIdListDup(pColumns);
129 sqliteIdListDelete(pColumns);
danielk1977c3f9bad2002-05-15 08:30:12 +0000130 nt->foreach = foreach;
danielk1977633ed082002-05-17 00:05:58 +0000131 nt->step_list = pStepList;
danielk1977c3f9bad2002-05-15 08:30:12 +0000132
133 /* if we are not initializing, and this trigger is not on a TEMP table,
drh9adf9ac2002-05-15 11:44:13 +0000134 ** build the sqlite_master entry
135 */
drhe0bc4042002-06-25 01:09:11 +0000136 if( !pParse->initFlag ){
drhc977f7f2002-05-21 11:38:11 +0000137 static VdbeOp insertTrig[] = {
drhc977f7f2002-05-21 11:38:11 +0000138 { OP_NewRecno, 0, 0, 0 },
139 { OP_String, 0, 0, "trigger" },
drhe0bc4042002-06-25 01:09:11 +0000140 { OP_String, 0, 0, 0 }, /* 2: trigger name */
141 { OP_String, 0, 0, 0 }, /* 3: table name */
drhc977f7f2002-05-21 11:38:11 +0000142 { OP_Integer, 0, 0, 0 },
drhe0bc4042002-06-25 01:09:11 +0000143 { OP_String, 0, 0, 0 }, /* 5: SQL */
drhc977f7f2002-05-21 11:38:11 +0000144 { OP_MakeRecord, 5, 0, 0 },
145 { OP_PutIntKey, 0, 0, 0 },
drhc977f7f2002-05-21 11:38:11 +0000146 };
147 int addr;
148 Vdbe *v;
danielk1977c3f9bad2002-05-15 08:30:12 +0000149
150 /* Make an entry in the sqlite_master table */
drhc977f7f2002-05-21 11:38:11 +0000151 v = sqliteGetVdbe(pParse);
drhe4697f52002-05-23 02:09:03 +0000152 if( v==0 ) goto trigger_cleanup;
drhcabb0812002-09-14 13:47:32 +0000153 sqliteBeginWriteOperation(pParse, 0, 0);
drhe0bc4042002-06-25 01:09:11 +0000154 sqliteOpenMasterTable(v, tab->isTemp);
drhc977f7f2002-05-21 11:38:11 +0000155 addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
drhe0bc4042002-06-25 01:09:11 +0000156 sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME,
157 P3_STATIC);
158 sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
159 sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
drh4b59ab52002-08-24 18:24:51 +0000160 sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
drhe0bc4042002-06-25 01:09:11 +0000161 if( !tab->isTemp ){
162 sqliteChangeCookie(pParse->db, v);
163 }
164 sqliteVdbeAddOp(v, OP_Close, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000165 sqliteEndWriteOperation(pParse);
166 }
167
danielk1977633ed082002-05-17 00:05:58 +0000168 if( !pParse->explain ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000169 /* Stick it in the hash-table */
danielk1977633ed082002-05-17 00:05:58 +0000170 sqliteHashInsert(&(pParse->db->trigHash), nt->name, pName->n + 1, nt);
danielk1977c3f9bad2002-05-15 08:30:12 +0000171
172 /* Attach it to the table object */
173 nt->pNext = tab->pTrigger;
174 tab->pTrigger = nt;
175 return;
danielk1977f29ce552002-05-19 23:43:12 +0000176 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000177 sqliteFree(nt->name);
178 sqliteFree(nt->table);
179 sqliteFree(nt);
180 }
181
182trigger_cleanup:
183
drhe5f9c642003-01-13 23:27:31 +0000184 sqliteFree(zName);
danielk1977633ed082002-05-17 00:05:58 +0000185 sqliteIdListDelete(pColumns);
danielk1977c3f9bad2002-05-15 08:30:12 +0000186 sqliteExprDelete(pWhen);
drh4b59ab52002-08-24 18:24:51 +0000187 sqliteDeleteTriggerStep(pStepList);
188}
danielk1977c3f9bad2002-05-15 08:30:12 +0000189
drh4b59ab52002-08-24 18:24:51 +0000190/*
191** Make a copy of all components of the given trigger step. This has
192** the effect of copying all Expr.token.z values into memory obtained
193** from sqliteMalloc(). As initially created, the Expr.token.z values
194** all point to the input string that was fed to the parser. But that
195** string is ephemeral - it will go away as soon as the sqlite_exec()
196** call that started the parser exits. This routine makes a persistent
197** copy of all the Expr.token.z strings so that the TriggerStep structure
198** will be valid even after the sqlite_exec() call returns.
199*/
200static void sqlitePersistTriggerStep(TriggerStep *p){
201 if( p->target.z ){
202 p->target.z = sqliteStrNDup(p->target.z, p->target.n);
203 p->target.dyn = 1;
204 }
205 if( p->pSelect ){
206 Select *pNew = sqliteSelectDup(p->pSelect);
207 sqliteSelectDelete(p->pSelect);
208 p->pSelect = pNew;
209 }
210 if( p->pWhere ){
211 Expr *pNew = sqliteExprDup(p->pWhere);
212 sqliteExprDelete(p->pWhere);
213 p->pWhere = pNew;
214 }
215 if( p->pExprList ){
216 ExprList *pNew = sqliteExprListDup(p->pExprList);
217 sqliteExprListDelete(p->pExprList);
218 p->pExprList = pNew;
219 }
220 if( p->pIdList ){
221 IdList *pNew = sqliteIdListDup(p->pIdList);
222 sqliteIdListDelete(p->pIdList);
223 p->pIdList = pNew;
danielk1977c3f9bad2002-05-15 08:30:12 +0000224 }
225}
226
drhc977f7f2002-05-21 11:38:11 +0000227/*
228** Turn a SELECT statement (that the pSelect parameter points to) into
229** a trigger step. Return a pointer to a TriggerStep structure.
230**
231** The parser calls this routine when it finds a SELECT statement in
232** body of a TRIGGER.
233*/
234TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
danielk1977633ed082002-05-17 00:05:58 +0000235 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000236 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000237
danielk1977633ed082002-05-17 00:05:58 +0000238 pTriggerStep->op = TK_SELECT;
239 pTriggerStep->pSelect = pSelect;
240 pTriggerStep->orconf = OE_Default;
drh4b59ab52002-08-24 18:24:51 +0000241 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000242
danielk1977633ed082002-05-17 00:05:58 +0000243 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000244}
245
drhc977f7f2002-05-21 11:38:11 +0000246/*
247** Build a trigger step out of an INSERT statement. Return a pointer
248** to the new trigger step.
249**
250** The parser calls this routine when it sees an INSERT inside the
251** body of a trigger.
252*/
danielk1977633ed082002-05-17 00:05:58 +0000253TriggerStep *sqliteTriggerInsertStep(
drhc977f7f2002-05-21 11:38:11 +0000254 Token *pTableName, /* Name of the table into which we insert */
255 IdList *pColumn, /* List of columns in pTableName to insert into */
256 ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
257 Select *pSelect, /* A SELECT statement that supplies values */
258 int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
danielk1977633ed082002-05-17 00:05:58 +0000259){
260 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000261 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000262
danielk1977633ed082002-05-17 00:05:58 +0000263 assert(pEList == 0 || pSelect == 0);
264 assert(pEList != 0 || pSelect != 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000265
danielk1977633ed082002-05-17 00:05:58 +0000266 pTriggerStep->op = TK_INSERT;
267 pTriggerStep->pSelect = pSelect;
268 pTriggerStep->target = *pTableName;
269 pTriggerStep->pIdList = pColumn;
270 pTriggerStep->pExprList = pEList;
271 pTriggerStep->orconf = orconf;
drh4b59ab52002-08-24 18:24:51 +0000272 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000273
danielk1977633ed082002-05-17 00:05:58 +0000274 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000275}
276
drhc977f7f2002-05-21 11:38:11 +0000277/*
278** Construct a trigger step that implements an UPDATE statement and return
279** a pointer to that trigger step. The parser calls this routine when it
280** sees an UPDATE statement inside the body of a CREATE TRIGGER.
281*/
danielk1977633ed082002-05-17 00:05:58 +0000282TriggerStep *sqliteTriggerUpdateStep(
drhc977f7f2002-05-21 11:38:11 +0000283 Token *pTableName, /* Name of the table to be updated */
284 ExprList *pEList, /* The SET clause: list of column and new values */
285 Expr *pWhere, /* The WHERE clause */
286 int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
287){
danielk1977633ed082002-05-17 00:05:58 +0000288 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000289 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000290
danielk1977633ed082002-05-17 00:05:58 +0000291 pTriggerStep->op = TK_UPDATE;
292 pTriggerStep->target = *pTableName;
293 pTriggerStep->pExprList = pEList;
294 pTriggerStep->pWhere = pWhere;
295 pTriggerStep->orconf = orconf;
drh4b59ab52002-08-24 18:24:51 +0000296 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000297
danielk1977633ed082002-05-17 00:05:58 +0000298 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000299}
300
drhc977f7f2002-05-21 11:38:11 +0000301/*
302** Construct a trigger step that implements a DELETE statement and return
303** a pointer to that trigger step. The parser calls this routine when it
304** sees a DELETE statement inside the body of a CREATE TRIGGER.
305*/
306TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
drhe4697f52002-05-23 02:09:03 +0000307 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
308 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000309
danielk1977633ed082002-05-17 00:05:58 +0000310 pTriggerStep->op = TK_DELETE;
311 pTriggerStep->target = *pTableName;
312 pTriggerStep->pWhere = pWhere;
313 pTriggerStep->orconf = OE_Default;
drh4b59ab52002-08-24 18:24:51 +0000314 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000315
danielk1977633ed082002-05-17 00:05:58 +0000316 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000317}
318
danielk1977633ed082002-05-17 00:05:58 +0000319/*
320** Recursively delete a Trigger structure
321*/
drh1d1f3052002-05-21 13:18:25 +0000322void sqliteDeleteTrigger(Trigger *pTrigger){
drh4b59ab52002-08-24 18:24:51 +0000323 sqliteDeleteTriggerStep(pTrigger->step_list);
danielk1977633ed082002-05-17 00:05:58 +0000324 sqliteFree(pTrigger->name);
325 sqliteFree(pTrigger->table);
326 sqliteExprDelete(pTrigger->pWhen);
327 sqliteIdListDelete(pTrigger->pColumns);
danielk1977633ed082002-05-17 00:05:58 +0000328 sqliteFree(pTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000329}
330
331/*
danielk1977633ed082002-05-17 00:05:58 +0000332 * This function is called to drop a trigger from the database schema.
333 *
334 * This may be called directly from the parser, or from within
335 * sqliteDropTable(). In the latter case the "nested" argument is true.
336 *
337 * Note that this function does not delete the trigger entirely. Instead it
338 * removes it from the internal schema and places it in the trigDrop hash
339 * table. This is so that the trigger can be restored into the database schema
340 * if the transaction is rolled back.
danielk1977c3f9bad2002-05-15 08:30:12 +0000341 */
drhe0bc4042002-06-25 01:09:11 +0000342void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
danielk1977633ed082002-05-17 00:05:58 +0000343 char *zName;
344 Trigger *pTrigger;
345 Table *pTable;
drhe0bc4042002-06-25 01:09:11 +0000346 Vdbe *v;
danielk1977c3f9bad2002-05-15 08:30:12 +0000347
danielk1977633ed082002-05-17 00:05:58 +0000348 zName = sqliteStrNDup(pName->z, pName->n);
danielk1977c3f9bad2002-05-15 08:30:12 +0000349
350 /* ensure that the trigger being dropped exists */
danielk1977633ed082002-05-17 00:05:58 +0000351 pTrigger = sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1);
352 if( !pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000353 sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1,
danielk1977633ed082002-05-17 00:05:58 +0000354 zName, -1, 0);
355 sqliteFree(zName);
danielk1977c3f9bad2002-05-15 08:30:12 +0000356 return;
357 }
drhed6c8672003-01-12 18:02:16 +0000358 pTable = sqliteFindTable(pParse->db, pTrigger->table);
359 assert(pTable);
drhe5f9c642003-01-13 23:27:31 +0000360#ifndef SQLITE_OMIT_AUTHORIZATION
361 {
362 int code = SQLITE_DROP_TRIGGER;
363 if( pTable->isTemp ) code = SQLITE_DROP_TEMP_TRIGGER;
364 if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) ||
365 sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->isTemp),0) ){
366 sqliteFree(zName);
367 return;
368 }
drhed6c8672003-01-12 18:02:16 +0000369 }
drhe5f9c642003-01-13 23:27:31 +0000370#endif
danielk1977c3f9bad2002-05-15 08:30:12 +0000371
372 /*
drhe0bc4042002-06-25 01:09:11 +0000373 * If this is not an "explain", then delete the trigger structure.
danielk1977c3f9bad2002-05-15 08:30:12 +0000374 */
danielk1977633ed082002-05-17 00:05:58 +0000375 if( !pParse->explain ){
danielk1977633ed082002-05-17 00:05:58 +0000376 if( pTable->pTrigger == pTrigger ){
377 pTable->pTrigger = pTrigger->pNext;
danielk1977f29ce552002-05-19 23:43:12 +0000378 }else{
danielk1977633ed082002-05-17 00:05:58 +0000379 Trigger *cc = pTable->pTrigger;
380 while( cc ){
381 if( cc->pNext == pTrigger ){
drh9adf9ac2002-05-15 11:44:13 +0000382 cc->pNext = cc->pNext->pNext;
383 break;
384 }
385 cc = cc->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000386 }
387 assert(cc);
388 }
drhe0bc4042002-06-25 01:09:11 +0000389 sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL);
390 sqliteDeleteTrigger(pTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000391 }
392
drhe0bc4042002-06-25 01:09:11 +0000393 /* Generate code to destroy the database record of the trigger.
394 */
395 if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000396 int base;
397 static VdbeOp dropTrigger[] = {
drhe0bc4042002-06-25 01:09:11 +0000398 { OP_Rewind, 0, ADDR(8), 0},
399 { OP_String, 0, 0, 0}, /* 1 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000400 { OP_MemStore, 1, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000401 { OP_MemLoad, 1, 0, 0}, /* 3 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000402 { OP_Column, 0, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000403 { OP_Ne, 0, ADDR(7), 0},
danielk1977c3f9bad2002-05-15 08:30:12 +0000404 { OP_Delete, 0, 0, 0},
drhe0bc4042002-06-25 01:09:11 +0000405 { OP_Next, 0, ADDR(3), 0}, /* 7 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000406 };
407
drhcabb0812002-09-14 13:47:32 +0000408 sqliteBeginWriteOperation(pParse, 0, 0);
drhe0bc4042002-06-25 01:09:11 +0000409 sqliteOpenMasterTable(v, pTable->isTemp);
410 base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
411 sqliteVdbeChangeP3(v, base+1, zName, 0);
412 if( !pTable->isTemp ){
413 sqliteChangeCookie(pParse->db, v);
drhdc379452002-05-15 12:45:43 +0000414 }
drhe0bc4042002-06-25 01:09:11 +0000415 sqliteVdbeAddOp(v, OP_Close, 0, 0);
416 sqliteEndWriteOperation(pParse);
danielk1977c3f9bad2002-05-15 08:30:12 +0000417 }
418
danielk1977633ed082002-05-17 00:05:58 +0000419 sqliteFree(zName);
danielk1977c3f9bad2002-05-15 08:30:12 +0000420}
421
drhc977f7f2002-05-21 11:38:11 +0000422/*
423** pEList is the SET clause of an UPDATE statement. Each entry
424** in pEList is of the format <id>=<expr>. If any of the entries
425** in pEList have an <id> which matches an identifier in pIdList,
426** then return TRUE. If pIdList==NULL, then it is considered a
427** wildcard that matches anything. Likewise if pEList==NULL then
428** it matches anything so always return true. Return false only
429** if there is no match.
430*/
431static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
drhad2d8302002-05-24 20:31:36 +0000432 int e;
433 if( !pIdList || !pEList ) return 1;
434 for(e=0; e<pEList->nExpr; e++){
435 if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
danielk1977f29ce552002-05-19 23:43:12 +0000436 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000437 return 0;
438}
439
440/* A global variable that is TRUE if we should always set up temp tables for
441 * for triggers, even if there are no triggers to code. This is used to test
442 * how much overhead the triggers algorithm is causing.
443 *
444 * This flag can be set or cleared using the "trigger_overhead_test" pragma.
445 * The pragma is not documented since it is not really part of the interface
446 * to SQLite, just the test procedure.
447*/
448int always_code_trigger_setup = 0;
449
450/*
451 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
452 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
453 * found in the list specified as pTrigger.
454 */
455int sqliteTriggersExist(
drhc977f7f2002-05-21 11:38:11 +0000456 Parse *pParse, /* Used to check for recursive triggers */
457 Trigger *pTrigger, /* A list of triggers associated with a table */
danielk1977633ed082002-05-17 00:05:58 +0000458 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
459 int tr_tm, /* one of TK_BEFORE, TK_AFTER */
460 int foreach, /* one of TK_ROW or TK_STATEMENT */
drhc977f7f2002-05-21 11:38:11 +0000461 ExprList *pChanges /* Columns that change in an UPDATE statement */
462){
danielk1977633ed082002-05-17 00:05:58 +0000463 Trigger * pTriggerCursor;
danielk1977c3f9bad2002-05-15 08:30:12 +0000464
danielk1977633ed082002-05-17 00:05:58 +0000465 if( always_code_trigger_setup ){
466 return 1;
467 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000468
danielk1977633ed082002-05-17 00:05:58 +0000469 pTriggerCursor = pTrigger;
470 while( pTriggerCursor ){
471 if( pTriggerCursor->op == op &&
472 pTriggerCursor->tr_tm == tr_tm &&
473 pTriggerCursor->foreach == foreach &&
474 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000475 TriggerStack * ss;
476 ss = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000477 while( ss && ss->pTrigger != pTrigger ){
478 ss = ss->pNext;
479 }
480 if( !ss )return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000481 }
danielk1977633ed082002-05-17 00:05:58 +0000482 pTriggerCursor = pTriggerCursor->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000483 }
484
485 return 0;
486}
487
drhc977f7f2002-05-21 11:38:11 +0000488/*
489** Generate VDBE code for zero or more statements inside the body of a
490** trigger.
491*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000492static int codeTriggerProgram(
drhc977f7f2002-05-21 11:38:11 +0000493 Parse *pParse, /* The parser context */
494 TriggerStep *pStepList, /* List of statements inside the trigger body */
495 int orconfin /* Conflict algorithm. (OE_Abort, etc) */
danielk1977633ed082002-05-17 00:05:58 +0000496){
497 TriggerStep * pTriggerStep = pStepList;
498 int orconf;
danielk1977c3f9bad2002-05-15 08:30:12 +0000499
danielk1977633ed082002-05-17 00:05:58 +0000500 while( pTriggerStep ){
501 int saveNTab = pParse->nTab;
502 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
503 pParse->trigStack->orconf = orconf;
504 switch( pTriggerStep->op ){
505 case TK_SELECT: {
danielk19776f349032002-06-11 02:25:40 +0000506 Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
507 assert(ss);
508 assert(ss->pSrc);
509 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
510 sqliteSelectDelete(ss);
danielk1977633ed082002-05-17 00:05:58 +0000511 break;
512 }
513 case TK_UPDATE: {
drhbd5a4512002-05-23 22:07:02 +0000514 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000515 sqliteUpdate(pParse, &pTriggerStep->target,
danielk19776f349032002-06-11 02:25:40 +0000516 sqliteExprListDup(pTriggerStep->pExprList),
517 sqliteExprDup(pTriggerStep->pWhere), orconf);
drhbd5a4512002-05-23 22:07:02 +0000518 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000519 break;
520 }
521 case TK_INSERT: {
522 sqliteInsert(pParse, &pTriggerStep->target,
523 sqliteExprListDup(pTriggerStep->pExprList),
524 sqliteSelectDup(pTriggerStep->pSelect),
525 sqliteIdListDup(pTriggerStep->pIdList), orconf);
526 break;
527 }
528 case TK_DELETE: {
drhbd5a4512002-05-23 22:07:02 +0000529 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000530 sqliteDeleteFrom(pParse, &pTriggerStep->target,
531 sqliteExprDup(pTriggerStep->pWhere));
drhbd5a4512002-05-23 22:07:02 +0000532 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000533 break;
534 }
535 default:
536 assert(0);
537 }
538 pParse->nTab = saveNTab;
539 pTriggerStep = pTriggerStep->pNext;
540 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000541
danielk1977633ed082002-05-17 00:05:58 +0000542 return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000543}
544
danielk1977633ed082002-05-17 00:05:58 +0000545/*
546** This is called to code FOR EACH ROW triggers.
547**
548** When the code that this function generates is executed, the following
549** must be true:
drhc977f7f2002-05-21 11:38:11 +0000550**
551** 1. No cursors may be open in the main database. (But newIdx and oldIdx
552** can be indices of cursors in temporary tables. See below.)
553**
danielk1977633ed082002-05-17 00:05:58 +0000554** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
555** a temporary vdbe cursor (index newIdx) must be open and pointing at
556** a row containing values to be substituted for new.* expressions in the
557** trigger program(s).
drhc977f7f2002-05-21 11:38:11 +0000558**
danielk1977633ed082002-05-17 00:05:58 +0000559** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
560** a temporary vdbe cursor (index oldIdx) must be open and pointing at
561** a row containing values to be substituted for old.* expressions in the
562** trigger program(s).
563**
564*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000565int sqliteCodeRowTrigger(
danielk1977633ed082002-05-17 00:05:58 +0000566 Parse *pParse, /* Parse context */
567 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
568 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
569 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
570 Table *pTab, /* The table to code triggers from */
571 int newIdx, /* The indice of the "new" row to access */
572 int oldIdx, /* The indice of the "old" row to access */
danielk19776f349032002-06-11 02:25:40 +0000573 int orconf, /* ON CONFLICT policy */
574 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
drhc977f7f2002-05-21 11:38:11 +0000575){
danielk1977c3f9bad2002-05-15 08:30:12 +0000576 Trigger * pTrigger;
577 TriggerStack * pTriggerStack;
578
danielk1977c3f9bad2002-05-15 08:30:12 +0000579 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
580 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
581
danielk1977633ed082002-05-17 00:05:58 +0000582 assert(newIdx != -1 || oldIdx != -1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000583
danielk1977633ed082002-05-17 00:05:58 +0000584 pTrigger = pTab->pTrigger;
danielk1977f29ce552002-05-19 23:43:12 +0000585 while( pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000586 int fire_this = 0;
587
588 /* determine whether we should code this trigger */
danielk1977f29ce552002-05-19 23:43:12 +0000589 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
590 pTrigger->foreach == TK_ROW ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000591 fire_this = 1;
592 pTriggerStack = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000593 while( pTriggerStack ){
594 if( pTriggerStack->pTrigger == pTrigger ){
595 fire_this = 0;
596 }
drh9adf9ac2002-05-15 11:44:13 +0000597 pTriggerStack = pTriggerStack->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000598 }
danielk1977f29ce552002-05-19 23:43:12 +0000599 if( op == TK_UPDATE && pTrigger->pColumns &&
600 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
drh9adf9ac2002-05-15 11:44:13 +0000601 fire_this = 0;
danielk1977f29ce552002-05-19 23:43:12 +0000602 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000603 }
604
drhe4697f52002-05-23 02:09:03 +0000605 if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000606 int endTrigger;
drhad3cab52002-05-24 02:04:32 +0000607 SrcList dummyTablist;
danielk1977c3f9bad2002-05-15 08:30:12 +0000608 Expr * whenExpr;
609
drhad3cab52002-05-24 02:04:32 +0000610 dummyTablist.nSrc = 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000611 dummyTablist.a = 0;
612
613 /* Push an entry on to the trigger stack */
danielk1977c3f9bad2002-05-15 08:30:12 +0000614 pTriggerStack->pTrigger = pTrigger;
danielk1977633ed082002-05-17 00:05:58 +0000615 pTriggerStack->newIdx = newIdx;
616 pTriggerStack->oldIdx = oldIdx;
617 pTriggerStack->pTab = pTab;
danielk1977c3f9bad2002-05-15 08:30:12 +0000618 pTriggerStack->pNext = pParse->trigStack;
danielk19776f349032002-06-11 02:25:40 +0000619 pTriggerStack->ignoreJump = ignoreJump;
danielk1977c3f9bad2002-05-15 08:30:12 +0000620 pParse->trigStack = pTriggerStack;
621
622 /* code the WHEN clause */
623 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
624 whenExpr = sqliteExprDup(pTrigger->pWhen);
danielk1977f29ce552002-05-19 23:43:12 +0000625 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000626 pParse->trigStack = pParse->trigStack->pNext;
627 sqliteFree(pTriggerStack);
628 sqliteExprDelete(whenExpr);
629 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000630 }
drhf5905aa2002-05-26 20:54:33 +0000631 sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000632 sqliteExprDelete(whenExpr);
633
danielk1977633ed082002-05-17 00:05:58 +0000634 codeTriggerProgram(pParse, pTrigger->step_list, orconf);
danielk1977c3f9bad2002-05-15 08:30:12 +0000635
636 /* Pop the entry off the trigger stack */
637 pParse->trigStack = pParse->trigStack->pNext;
638 sqliteFree(pTriggerStack);
639
640 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
641 }
642 pTrigger = pTrigger->pNext;
643 }
644
645 return 0;
646}
647
648/*
danielk1977633ed082002-05-17 00:05:58 +0000649 * This function is called to code ON UPDATE and ON DELETE triggers on
650 * views.
651 *
652 * This function deletes the data pointed at by the pWhere and pChanges
653 * arguments before it completes.
danielk1977c3f9bad2002-05-15 08:30:12 +0000654 */
danielk1977633ed082002-05-17 00:05:58 +0000655void sqliteViewTriggers(
656 Parse *pParse,
657 Table *pTab, /* The view to code triggers on */
658 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/
659 int orconf, /* The ON CONFLICT policy specified as part of the
660 statement causing these triggers */
661 ExprList *pChanges /* If this is an statement causing triggers to fire
662 is an UPDATE, then this list holds the columns
663 to update and the expressions to update them to.
664 See comments for sqliteUpdate(). */
665){
danielk1977c3f9bad2002-05-15 08:30:12 +0000666 int oldIdx = -1;
667 int newIdx = -1;
668 int *aXRef = 0;
669 Vdbe *v;
670 int endOfLoop;
671 int startOfLoop;
672 Select theSelect;
673 Token tblNameToken;
674
675 assert(pTab->pSelect);
676
677 tblNameToken.z = pTab->zName;
678 tblNameToken.n = strlen(pTab->zName);
679
680 theSelect.isDistinct = 0;
681 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
drhad3cab52002-05-24 02:04:32 +0000682 theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken);
danielk1977c3f9bad2002-05-15 08:30:12 +0000683 theSelect.pWhere = pWhere; pWhere = 0;
684 theSelect.pGroupBy = 0;
685 theSelect.pHaving = 0;
686 theSelect.pOrderBy = 0;
687 theSelect.op = TK_SELECT; /* ?? */
688 theSelect.pPrior = 0;
689 theSelect.nLimit = -1;
690 theSelect.nOffset = -1;
691 theSelect.zSelect = 0;
692 theSelect.base = 0;
693
694 v = sqliteGetVdbe(pParse);
695 assert(v);
drhcabb0812002-09-14 13:47:32 +0000696 sqliteBeginWriteOperation(pParse, 1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000697
698 /* Allocate temp tables */
699 oldIdx = pParse->nTab++;
700 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
danielk1977633ed082002-05-17 00:05:58 +0000701 if( pChanges ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000702 newIdx = pParse->nTab++;
703 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
704 }
705
706 /* Snapshot the view */
danielk1977633ed082002-05-17 00:05:58 +0000707 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000708 goto trigger_cleanup;
709 }
710
711 /* loop thru the view snapshot, executing triggers for each row */
712 endOfLoop = sqliteVdbeMakeLabel(v);
713 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
714
715 /* Loop thru the view snapshot, executing triggers for each row */
716 startOfLoop = sqliteVdbeCurrentAddr(v);
717
718 /* Build the updated row if required */
danielk1977633ed082002-05-17 00:05:58 +0000719 if( pChanges ){
drh1d1f3052002-05-21 13:18:25 +0000720 int ii;
danielk1977c3f9bad2002-05-15 08:30:12 +0000721
722 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
723 if( aXRef==0 ) goto trigger_cleanup;
danielk1977633ed082002-05-17 00:05:58 +0000724 for(ii = 0; ii < pTab->nCol; ii++){
danielk1977c3f9bad2002-05-15 08:30:12 +0000725 aXRef[ii] = -1;
danielk1977633ed082002-05-17 00:05:58 +0000726 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000727
728 for(ii=0; ii<pChanges->nExpr; ii++){
729 int jj;
730 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
danielk1977f29ce552002-05-19 23:43:12 +0000731 pChanges->a[ii].pExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000732 goto trigger_cleanup;
danielk1977f29ce552002-05-19 23:43:12 +0000733 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000734
735 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
drh9adf9ac2002-05-15 11:44:13 +0000736 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000737
738 for(jj=0; jj<pTab->nCol; jj++){
drh9adf9ac2002-05-15 11:44:13 +0000739 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
740 aXRef[jj] = ii;
741 break;
742 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000743 }
744 if( jj>=pTab->nCol ){
drh9adf9ac2002-05-15 11:44:13 +0000745 sqliteSetString(&pParse->zErrMsg, "no such column: ",
746 pChanges->a[ii].zName, 0);
747 pParse->nErr++;
748 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000749 }
750 }
751
752 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
753
danielk1977633ed082002-05-17 00:05:58 +0000754 for(ii = 0; ii<pTab->nCol; ii++){
755 if( aXRef[ii] < 0 ){
drh9adf9ac2002-05-15 11:44:13 +0000756 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
danielk1977f29ce552002-05-19 23:43:12 +0000757 }else{
drh9adf9ac2002-05-15 11:44:13 +0000758 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
danielk1977633ed082002-05-17 00:05:58 +0000759 }
760 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000761
762 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
763 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
764 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
765
766 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
danielk19776f349032002-06-11 02:25:40 +0000767 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000768 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
danielk19776f349032002-06-11 02:25:40 +0000769 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977f29ce552002-05-19 23:43:12 +0000770 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000771 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000772 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000773 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000774 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000775 }
776
777 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
778
779 sqliteVdbeResolveLabel(v, endOfLoop);
780 sqliteEndWriteOperation(pParse);
781
782trigger_cleanup:
783 sqliteFree(aXRef);
784 sqliteExprListDelete(pChanges);
785 sqliteExprDelete(pWhere);
786 sqliteExprListDelete(theSelect.pEList);
drhad3cab52002-05-24 02:04:32 +0000787 sqliteSrcListDelete(theSelect.pSrc);
danielk1977c3f9bad2002-05-15 08:30:12 +0000788 sqliteExprDelete(theSelect.pWhere);
789 return;
790}