blob: 2b7d35a245caa7bd7e49865a1b0232d78ee1486c [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 */
drhd24cc422003-03-27 12:51:24 +000044 SrcList *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 */
drhd24cc422003-03-27 12:51:24 +000053 sqlite *db = pParse->db;
drhed6c8672003-01-12 18:02:16 +000054
danielk1977c3f9bad2002-05-15 08:30:12 +000055 /* Check that:
drh9adf9ac2002-05-15 11:44:13 +000056 ** 1. the trigger name does not already exist.
57 ** 2. the table (or view) does exist.
danielk1977d702fcc2002-05-26 23:24:40 +000058 ** 3. that we are not trying to create a trigger on the sqlite_master table
59 ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
60 ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
drh9adf9ac2002-05-15 11:44:13 +000061 */
drhd24cc422003-03-27 12:51:24 +000062 if( sqlite_malloc_failed ) goto trigger_cleanup;
63 assert( pTableName->nSrc==1 );
drh812d7a22003-03-27 13:50:00 +000064 tab = sqliteSrcListLookup(pParse, pTableName);
drhd24cc422003-03-27 12:51:24 +000065 if( !tab ){
66 goto trigger_cleanup;
67 }
68 if( tab->iDb>=2 ){
69 sqliteSetString(&pParse->zErrMsg, "triggers may not be added to "
70 "auxiliary database \"", db->aDb[tab->iDb].zName, "\"", 0);
71 pParse->nErr++;
72 goto trigger_cleanup;
73 }
74
drhe5f9c642003-01-13 23:27:31 +000075 zName = sqliteStrNDup(pName->z, pName->n);
drhd24cc422003-03-27 12:51:24 +000076 if( sqliteHashFind(&(db->aDb[tab->iDb].trigHash), zName,pName->n+1) ){
drhe5f9c642003-01-13 23:27:31 +000077 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1,
78 pName->z, pName->n, " already exists", -1, 0);
79 pParse->nErr++;
80 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +000081 }
drhd24cc422003-03-27 12:51:24 +000082 if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
83 sqliteSetString(&pParse->zErrMsg,"cannot create trigger on system table",0);
84 pParse->nErr++;
85 goto trigger_cleanup;
danielk1977d702fcc2002-05-26 23:24:40 +000086 }
drhd24cc422003-03-27 12:51:24 +000087 if( tab->pSelect && tr_tm != TK_INSTEAD ){
drh0951d702003-03-27 13:01:28 +000088 sqliteSetString(&pParse->zErrMsg, "cannot create ",
drhd24cc422003-03-27 12:51:24 +000089 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", " trigger on view: ",
90 pTableName->a[0].zName, 0);
91 goto trigger_cleanup;
92 }
93 if( !tab->pSelect && tr_tm == TK_INSTEAD ){
drh0951d702003-03-27 13:01:28 +000094 sqliteSetString(&pParse->zErrMsg, "cannot create INSTEAD OF",
95 " trigger on table: ", pTableName->a[0].zName, 0);
drhd24cc422003-03-27 12:51:24 +000096 goto trigger_cleanup;
97 }
98#ifndef SQLITE_OMIT_AUTHORIZATION
99 {
100 int code = SQLITE_CREATE_TRIGGER;
101 if( tab->iDb==1 ) code = SQLITE_CREATE_TEMP_TRIGGER;
102 if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){
103 goto trigger_cleanup;
104 }
105 if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){
106 goto trigger_cleanup;
107 }
108 }
109#endif
danielk1977d702fcc2002-05-26 23:24:40 +0000110
111 if (tr_tm == TK_INSTEAD){
112 tr_tm = TK_BEFORE;
danielk1977c3f9bad2002-05-15 08:30:12 +0000113 }
114
115 /* Build the Trigger object */
drh9adf9ac2002-05-15 11:44:13 +0000116 nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
drhe4697f52002-05-23 02:09:03 +0000117 if( nt==0 ) goto trigger_cleanup;
drhe5f9c642003-01-13 23:27:31 +0000118 nt->name = zName;
119 zName = 0;
drhd24cc422003-03-27 12:51:24 +0000120 nt->table = sqliteStrDup(pTableName->a[0].zName);
drhe4697f52002-05-23 02:09:03 +0000121 if( sqlite_malloc_failed ) goto trigger_cleanup;
drhd24cc422003-03-27 12:51:24 +0000122 nt->iDb = tab->iDb;
danielk1977c3f9bad2002-05-15 08:30:12 +0000123 nt->op = op;
124 nt->tr_tm = tr_tm;
drh4b59ab52002-08-24 18:24:51 +0000125 nt->pWhen = sqliteExprDup(pWhen);
126 sqliteExprDelete(pWhen);
127 nt->pColumns = sqliteIdListDup(pColumns);
128 sqliteIdListDelete(pColumns);
danielk1977c3f9bad2002-05-15 08:30:12 +0000129 nt->foreach = foreach;
danielk1977633ed082002-05-17 00:05:58 +0000130 nt->step_list = pStepList;
danielk1977c3f9bad2002-05-15 08:30:12 +0000131
132 /* if we are not initializing, and this trigger is not on a TEMP table,
drh9adf9ac2002-05-15 11:44:13 +0000133 ** build the sqlite_master entry
134 */
drhe0bc4042002-06-25 01:09:11 +0000135 if( !pParse->initFlag ){
drhc977f7f2002-05-21 11:38:11 +0000136 static VdbeOp insertTrig[] = {
drhc977f7f2002-05-21 11:38:11 +0000137 { OP_NewRecno, 0, 0, 0 },
138 { OP_String, 0, 0, "trigger" },
drhe0bc4042002-06-25 01:09:11 +0000139 { OP_String, 0, 0, 0 }, /* 2: trigger name */
140 { OP_String, 0, 0, 0 }, /* 3: table name */
drhc977f7f2002-05-21 11:38:11 +0000141 { OP_Integer, 0, 0, 0 },
drhe0bc4042002-06-25 01:09:11 +0000142 { OP_String, 0, 0, 0 }, /* 5: SQL */
drhc977f7f2002-05-21 11:38:11 +0000143 { OP_MakeRecord, 5, 0, 0 },
144 { OP_PutIntKey, 0, 0, 0 },
drhc977f7f2002-05-21 11:38:11 +0000145 };
146 int addr;
147 Vdbe *v;
danielk1977c3f9bad2002-05-15 08:30:12 +0000148
149 /* Make an entry in the sqlite_master table */
drhc977f7f2002-05-21 11:38:11 +0000150 v = sqliteGetVdbe(pParse);
drhe4697f52002-05-23 02:09:03 +0000151 if( v==0 ) goto trigger_cleanup;
drhcabb0812002-09-14 13:47:32 +0000152 sqliteBeginWriteOperation(pParse, 0, 0);
drhd24cc422003-03-27 12:51:24 +0000153 sqliteOpenMasterTable(v, tab->iDb);
drhc977f7f2002-05-21 11:38:11 +0000154 addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
drhd24cc422003-03-27 12:51:24 +0000155 sqliteVdbeChangeP3(v, addr, tab->iDb ? TEMP_MASTER_NAME : MASTER_NAME,
drhe0bc4042002-06-25 01:09:11 +0000156 P3_STATIC);
157 sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
158 sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
drh4b59ab52002-08-24 18:24:51 +0000159 sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
drhd24cc422003-03-27 12:51:24 +0000160 if( tab->iDb==0 ){
161 sqliteChangeCookie(db, v);
drhe0bc4042002-06-25 01:09:11 +0000162 }
163 sqliteVdbeAddOp(v, OP_Close, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000164 sqliteEndWriteOperation(pParse);
165 }
166
danielk1977633ed082002-05-17 00:05:58 +0000167 if( !pParse->explain ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000168 /* Stick it in the hash-table */
drhd24cc422003-03-27 12:51:24 +0000169 sqliteHashInsert(&(db->aDb[nt->iDb].trigHash), nt->name, pName->n + 1, nt);
danielk1977c3f9bad2002-05-15 08:30:12 +0000170
171 /* Attach it to the table object */
172 nt->pNext = tab->pTrigger;
173 tab->pTrigger = nt;
174 return;
danielk1977f29ce552002-05-19 23:43:12 +0000175 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000176 sqliteFree(nt->name);
177 sqliteFree(nt->table);
178 sqliteFree(nt);
179 }
180
181trigger_cleanup:
182
drhe5f9c642003-01-13 23:27:31 +0000183 sqliteFree(zName);
drhd24cc422003-03-27 12:51:24 +0000184 sqliteSrcListDelete(pTableName);
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 */
drhd24cc422003-03-27 12:51:24 +0000342void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
danielk1977633ed082002-05-17 00:05:58 +0000343 Trigger *pTrigger;
344 Table *pTable;
drhe0bc4042002-06-25 01:09:11 +0000345 Vdbe *v;
drhd24cc422003-03-27 12:51:24 +0000346 int i;
347 const char *zDb;
348 const char *zName;
349 int nName;
350 sqlite *db = pParse->db;
danielk1977c3f9bad2002-05-15 08:30:12 +0000351
drhd24cc422003-03-27 12:51:24 +0000352 if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
353 assert( pName->nSrc==1 );
354 zDb = pName->a[0].zDatabase;
355 zName = pName->a[0].zName;
356 nName = strlen(zName);
357 for(i=0; i<db->nDb; i++){
drh812d7a22003-03-27 13:50:00 +0000358 int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
359 if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
360 pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
drhd24cc422003-03-27 12:51:24 +0000361 if( pTrigger ) break;
danielk1977c3f9bad2002-05-15 08:30:12 +0000362 }
drhd24cc422003-03-27 12:51:24 +0000363 if( !pTrigger ){
364 sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0);
365 goto drop_trigger_cleanup;
366 }
367 assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb );
368 if( pTrigger->iDb>=2 ){
369 sqliteSetString(&pParse->zErrMsg, "triggers may not be removed from "
370 "auxiliary database \"", db->aDb[pTrigger->iDb].zName, "\"", 0);
371 pParse->nErr++;
372 goto drop_trigger_cleanup;
373 }
374 pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName);
drhed6c8672003-01-12 18:02:16 +0000375 assert(pTable);
drhd24cc422003-03-27 12:51:24 +0000376 assert( pTable->iDb==pTrigger->iDb );
drhe5f9c642003-01-13 23:27:31 +0000377#ifndef SQLITE_OMIT_AUTHORIZATION
378 {
379 int code = SQLITE_DROP_TRIGGER;
drhd24cc422003-03-27 12:51:24 +0000380 if( pTable->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
drhe5f9c642003-01-13 23:27:31 +0000381 if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) ||
drhd24cc422003-03-27 12:51:24 +0000382 sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0) ){
drhe5f9c642003-01-13 23:27:31 +0000383 return;
384 }
drhed6c8672003-01-12 18:02:16 +0000385 }
drhe5f9c642003-01-13 23:27:31 +0000386#endif
danielk1977c3f9bad2002-05-15 08:30:12 +0000387
388 /*
drhe0bc4042002-06-25 01:09:11 +0000389 * If this is not an "explain", then delete the trigger structure.
danielk1977c3f9bad2002-05-15 08:30:12 +0000390 */
danielk1977633ed082002-05-17 00:05:58 +0000391 if( !pParse->explain ){
danielk1977633ed082002-05-17 00:05:58 +0000392 if( pTable->pTrigger == pTrigger ){
393 pTable->pTrigger = pTrigger->pNext;
danielk1977f29ce552002-05-19 23:43:12 +0000394 }else{
danielk1977633ed082002-05-17 00:05:58 +0000395 Trigger *cc = pTable->pTrigger;
396 while( cc ){
397 if( cc->pNext == pTrigger ){
drh9adf9ac2002-05-15 11:44:13 +0000398 cc->pNext = cc->pNext->pNext;
399 break;
400 }
401 cc = cc->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000402 }
403 assert(cc);
404 }
drhd24cc422003-03-27 12:51:24 +0000405 sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
drhe0bc4042002-06-25 01:09:11 +0000406 sqliteDeleteTrigger(pTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000407 }
408
drhe0bc4042002-06-25 01:09:11 +0000409 /* Generate code to destroy the database record of the trigger.
410 */
411 if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000412 int base;
413 static VdbeOp dropTrigger[] = {
drhe0bc4042002-06-25 01:09:11 +0000414 { OP_Rewind, 0, ADDR(8), 0},
415 { OP_String, 0, 0, 0}, /* 1 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000416 { OP_MemStore, 1, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000417 { OP_MemLoad, 1, 0, 0}, /* 3 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000418 { OP_Column, 0, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000419 { OP_Ne, 0, ADDR(7), 0},
danielk1977c3f9bad2002-05-15 08:30:12 +0000420 { OP_Delete, 0, 0, 0},
drhe0bc4042002-06-25 01:09:11 +0000421 { OP_Next, 0, ADDR(3), 0}, /* 7 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000422 };
423
drhcabb0812002-09-14 13:47:32 +0000424 sqliteBeginWriteOperation(pParse, 0, 0);
drhd24cc422003-03-27 12:51:24 +0000425 sqliteOpenMasterTable(v, pTable->iDb);
drhe0bc4042002-06-25 01:09:11 +0000426 base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
427 sqliteVdbeChangeP3(v, base+1, zName, 0);
drhd24cc422003-03-27 12:51:24 +0000428 if( pTable->iDb==0 ){
429 sqliteChangeCookie(db, v);
drhdc379452002-05-15 12:45:43 +0000430 }
drhe0bc4042002-06-25 01:09:11 +0000431 sqliteVdbeAddOp(v, OP_Close, 0, 0);
432 sqliteEndWriteOperation(pParse);
danielk1977c3f9bad2002-05-15 08:30:12 +0000433 }
434
drhd24cc422003-03-27 12:51:24 +0000435drop_trigger_cleanup:
436 sqliteSrcListDelete(pName);
danielk1977c3f9bad2002-05-15 08:30:12 +0000437}
438
drhc977f7f2002-05-21 11:38:11 +0000439/*
440** pEList is the SET clause of an UPDATE statement. Each entry
441** in pEList is of the format <id>=<expr>. If any of the entries
442** in pEList have an <id> which matches an identifier in pIdList,
443** then return TRUE. If pIdList==NULL, then it is considered a
444** wildcard that matches anything. Likewise if pEList==NULL then
445** it matches anything so always return true. Return false only
446** if there is no match.
447*/
448static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
drhad2d8302002-05-24 20:31:36 +0000449 int e;
450 if( !pIdList || !pEList ) return 1;
451 for(e=0; e<pEList->nExpr; e++){
452 if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
danielk1977f29ce552002-05-19 23:43:12 +0000453 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000454 return 0;
455}
456
457/* A global variable that is TRUE if we should always set up temp tables for
458 * for triggers, even if there are no triggers to code. This is used to test
459 * how much overhead the triggers algorithm is causing.
460 *
461 * This flag can be set or cleared using the "trigger_overhead_test" pragma.
462 * The pragma is not documented since it is not really part of the interface
463 * to SQLite, just the test procedure.
464*/
465int always_code_trigger_setup = 0;
466
467/*
468 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
469 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
470 * found in the list specified as pTrigger.
471 */
472int sqliteTriggersExist(
drhc977f7f2002-05-21 11:38:11 +0000473 Parse *pParse, /* Used to check for recursive triggers */
474 Trigger *pTrigger, /* A list of triggers associated with a table */
danielk1977633ed082002-05-17 00:05:58 +0000475 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
476 int tr_tm, /* one of TK_BEFORE, TK_AFTER */
477 int foreach, /* one of TK_ROW or TK_STATEMENT */
drhc977f7f2002-05-21 11:38:11 +0000478 ExprList *pChanges /* Columns that change in an UPDATE statement */
479){
danielk1977633ed082002-05-17 00:05:58 +0000480 Trigger * pTriggerCursor;
danielk1977c3f9bad2002-05-15 08:30:12 +0000481
danielk1977633ed082002-05-17 00:05:58 +0000482 if( always_code_trigger_setup ){
483 return 1;
484 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000485
danielk1977633ed082002-05-17 00:05:58 +0000486 pTriggerCursor = pTrigger;
487 while( pTriggerCursor ){
488 if( pTriggerCursor->op == op &&
489 pTriggerCursor->tr_tm == tr_tm &&
490 pTriggerCursor->foreach == foreach &&
491 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000492 TriggerStack * ss;
493 ss = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000494 while( ss && ss->pTrigger != pTrigger ){
495 ss = ss->pNext;
496 }
497 if( !ss )return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000498 }
danielk1977633ed082002-05-17 00:05:58 +0000499 pTriggerCursor = pTriggerCursor->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000500 }
501
502 return 0;
503}
504
drhc977f7f2002-05-21 11:38:11 +0000505/*
506** Generate VDBE code for zero or more statements inside the body of a
507** trigger.
508*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000509static int codeTriggerProgram(
drhc977f7f2002-05-21 11:38:11 +0000510 Parse *pParse, /* The parser context */
511 TriggerStep *pStepList, /* List of statements inside the trigger body */
512 int orconfin /* Conflict algorithm. (OE_Abort, etc) */
danielk1977633ed082002-05-17 00:05:58 +0000513){
514 TriggerStep * pTriggerStep = pStepList;
515 int orconf;
danielk1977c3f9bad2002-05-15 08:30:12 +0000516
danielk1977633ed082002-05-17 00:05:58 +0000517 while( pTriggerStep ){
518 int saveNTab = pParse->nTab;
519 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
520 pParse->trigStack->orconf = orconf;
521 switch( pTriggerStep->op ){
522 case TK_SELECT: {
danielk19776f349032002-06-11 02:25:40 +0000523 Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
524 assert(ss);
525 assert(ss->pSrc);
526 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
527 sqliteSelectDelete(ss);
danielk1977633ed082002-05-17 00:05:58 +0000528 break;
529 }
530 case TK_UPDATE: {
drh113088e2003-03-20 01:16:58 +0000531 SrcList *pSrc;
532 pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
drhbd5a4512002-05-23 22:07:02 +0000533 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
drh113088e2003-03-20 01:16:58 +0000534 sqliteUpdate(pParse, pSrc,
danielk19776f349032002-06-11 02:25:40 +0000535 sqliteExprListDup(pTriggerStep->pExprList),
536 sqliteExprDup(pTriggerStep->pWhere), orconf);
drhbd5a4512002-05-23 22:07:02 +0000537 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000538 break;
539 }
540 case TK_INSERT: {
drh113088e2003-03-20 01:16:58 +0000541 SrcList *pSrc;
542 pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
543 sqliteInsert(pParse, pSrc,
544 sqliteExprListDup(pTriggerStep->pExprList),
545 sqliteSelectDup(pTriggerStep->pSelect),
546 sqliteIdListDup(pTriggerStep->pIdList), orconf);
danielk1977633ed082002-05-17 00:05:58 +0000547 break;
548 }
549 case TK_DELETE: {
drh113088e2003-03-20 01:16:58 +0000550 SrcList *pSrc;
drhbd5a4512002-05-23 22:07:02 +0000551 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
drh113088e2003-03-20 01:16:58 +0000552 pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
553 sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
drhbd5a4512002-05-23 22:07:02 +0000554 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000555 break;
556 }
557 default:
558 assert(0);
559 }
560 pParse->nTab = saveNTab;
561 pTriggerStep = pTriggerStep->pNext;
562 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000563
danielk1977633ed082002-05-17 00:05:58 +0000564 return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000565}
566
danielk1977633ed082002-05-17 00:05:58 +0000567/*
568** This is called to code FOR EACH ROW triggers.
569**
570** When the code that this function generates is executed, the following
571** must be true:
drhc977f7f2002-05-21 11:38:11 +0000572**
573** 1. No cursors may be open in the main database. (But newIdx and oldIdx
574** can be indices of cursors in temporary tables. See below.)
575**
danielk1977633ed082002-05-17 00:05:58 +0000576** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
577** a temporary vdbe cursor (index newIdx) must be open and pointing at
578** a row containing values to be substituted for new.* expressions in the
579** trigger program(s).
drhc977f7f2002-05-21 11:38:11 +0000580**
danielk1977633ed082002-05-17 00:05:58 +0000581** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
582** a temporary vdbe cursor (index oldIdx) must be open and pointing at
583** a row containing values to be substituted for old.* expressions in the
584** trigger program(s).
585**
586*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000587int sqliteCodeRowTrigger(
danielk1977633ed082002-05-17 00:05:58 +0000588 Parse *pParse, /* Parse context */
589 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
590 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
591 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
592 Table *pTab, /* The table to code triggers from */
593 int newIdx, /* The indice of the "new" row to access */
594 int oldIdx, /* The indice of the "old" row to access */
danielk19776f349032002-06-11 02:25:40 +0000595 int orconf, /* ON CONFLICT policy */
596 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
drhc977f7f2002-05-21 11:38:11 +0000597){
danielk1977c3f9bad2002-05-15 08:30:12 +0000598 Trigger * pTrigger;
599 TriggerStack * pTriggerStack;
600
danielk1977c3f9bad2002-05-15 08:30:12 +0000601 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
602 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
603
danielk1977633ed082002-05-17 00:05:58 +0000604 assert(newIdx != -1 || oldIdx != -1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000605
danielk1977633ed082002-05-17 00:05:58 +0000606 pTrigger = pTab->pTrigger;
danielk1977f29ce552002-05-19 23:43:12 +0000607 while( pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000608 int fire_this = 0;
609
610 /* determine whether we should code this trigger */
danielk1977f29ce552002-05-19 23:43:12 +0000611 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
612 pTrigger->foreach == TK_ROW ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000613 fire_this = 1;
614 pTriggerStack = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000615 while( pTriggerStack ){
616 if( pTriggerStack->pTrigger == pTrigger ){
617 fire_this = 0;
618 }
drh9adf9ac2002-05-15 11:44:13 +0000619 pTriggerStack = pTriggerStack->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000620 }
danielk1977f29ce552002-05-19 23:43:12 +0000621 if( op == TK_UPDATE && pTrigger->pColumns &&
622 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
drh9adf9ac2002-05-15 11:44:13 +0000623 fire_this = 0;
danielk1977f29ce552002-05-19 23:43:12 +0000624 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000625 }
626
drhe4697f52002-05-23 02:09:03 +0000627 if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000628 int endTrigger;
drhad3cab52002-05-24 02:04:32 +0000629 SrcList dummyTablist;
danielk1977c3f9bad2002-05-15 08:30:12 +0000630 Expr * whenExpr;
631
drhad3cab52002-05-24 02:04:32 +0000632 dummyTablist.nSrc = 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000633
634 /* Push an entry on to the trigger stack */
danielk1977c3f9bad2002-05-15 08:30:12 +0000635 pTriggerStack->pTrigger = pTrigger;
danielk1977633ed082002-05-17 00:05:58 +0000636 pTriggerStack->newIdx = newIdx;
637 pTriggerStack->oldIdx = oldIdx;
638 pTriggerStack->pTab = pTab;
danielk1977c3f9bad2002-05-15 08:30:12 +0000639 pTriggerStack->pNext = pParse->trigStack;
danielk19776f349032002-06-11 02:25:40 +0000640 pTriggerStack->ignoreJump = ignoreJump;
danielk1977c3f9bad2002-05-15 08:30:12 +0000641 pParse->trigStack = pTriggerStack;
642
643 /* code the WHEN clause */
644 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
645 whenExpr = sqliteExprDup(pTrigger->pWhen);
danielk1977f29ce552002-05-19 23:43:12 +0000646 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000647 pParse->trigStack = pParse->trigStack->pNext;
648 sqliteFree(pTriggerStack);
649 sqliteExprDelete(whenExpr);
650 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000651 }
drhf5905aa2002-05-26 20:54:33 +0000652 sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000653 sqliteExprDelete(whenExpr);
654
danielk1977633ed082002-05-17 00:05:58 +0000655 codeTriggerProgram(pParse, pTrigger->step_list, orconf);
danielk1977c3f9bad2002-05-15 08:30:12 +0000656
657 /* Pop the entry off the trigger stack */
658 pParse->trigStack = pParse->trigStack->pNext;
659 sqliteFree(pTriggerStack);
660
661 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
662 }
663 pTrigger = pTrigger->pNext;
664 }
665
666 return 0;
667}
668
669/*
danielk1977633ed082002-05-17 00:05:58 +0000670 * This function is called to code ON UPDATE and ON DELETE triggers on
671 * views.
672 *
673 * This function deletes the data pointed at by the pWhere and pChanges
674 * arguments before it completes.
danielk1977c3f9bad2002-05-15 08:30:12 +0000675 */
danielk1977633ed082002-05-17 00:05:58 +0000676void sqliteViewTriggers(
677 Parse *pParse,
678 Table *pTab, /* The view to code triggers on */
679 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/
680 int orconf, /* The ON CONFLICT policy specified as part of the
681 statement causing these triggers */
682 ExprList *pChanges /* If this is an statement causing triggers to fire
683 is an UPDATE, then this list holds the columns
684 to update and the expressions to update them to.
685 See comments for sqliteUpdate(). */
686){
danielk1977c3f9bad2002-05-15 08:30:12 +0000687 int oldIdx = -1;
688 int newIdx = -1;
689 int *aXRef = 0;
690 Vdbe *v;
691 int endOfLoop;
692 int startOfLoop;
693 Select theSelect;
694 Token tblNameToken;
695
696 assert(pTab->pSelect);
697
698 tblNameToken.z = pTab->zName;
699 tblNameToken.n = strlen(pTab->zName);
700
701 theSelect.isDistinct = 0;
702 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
drh113088e2003-03-20 01:16:58 +0000703 theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000704 theSelect.pWhere = pWhere; pWhere = 0;
705 theSelect.pGroupBy = 0;
706 theSelect.pHaving = 0;
707 theSelect.pOrderBy = 0;
708 theSelect.op = TK_SELECT; /* ?? */
709 theSelect.pPrior = 0;
710 theSelect.nLimit = -1;
711 theSelect.nOffset = -1;
712 theSelect.zSelect = 0;
713 theSelect.base = 0;
714
715 v = sqliteGetVdbe(pParse);
716 assert(v);
drhcabb0812002-09-14 13:47:32 +0000717 sqliteBeginWriteOperation(pParse, 1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000718
719 /* Allocate temp tables */
720 oldIdx = pParse->nTab++;
721 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
danielk1977633ed082002-05-17 00:05:58 +0000722 if( pChanges ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000723 newIdx = pParse->nTab++;
724 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
725 }
726
727 /* Snapshot the view */
danielk1977633ed082002-05-17 00:05:58 +0000728 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000729 goto trigger_cleanup;
730 }
731
732 /* loop thru the view snapshot, executing triggers for each row */
733 endOfLoop = sqliteVdbeMakeLabel(v);
734 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
735
736 /* Loop thru the view snapshot, executing triggers for each row */
737 startOfLoop = sqliteVdbeCurrentAddr(v);
738
739 /* Build the updated row if required */
danielk1977633ed082002-05-17 00:05:58 +0000740 if( pChanges ){
drh1d1f3052002-05-21 13:18:25 +0000741 int ii;
danielk1977c3f9bad2002-05-15 08:30:12 +0000742
743 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
744 if( aXRef==0 ) goto trigger_cleanup;
danielk1977633ed082002-05-17 00:05:58 +0000745 for(ii = 0; ii < pTab->nCol; ii++){
danielk1977c3f9bad2002-05-15 08:30:12 +0000746 aXRef[ii] = -1;
danielk1977633ed082002-05-17 00:05:58 +0000747 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000748
749 for(ii=0; ii<pChanges->nExpr; ii++){
750 int jj;
751 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
danielk1977f29ce552002-05-19 23:43:12 +0000752 pChanges->a[ii].pExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000753 goto trigger_cleanup;
danielk1977f29ce552002-05-19 23:43:12 +0000754 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000755
756 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
drh9adf9ac2002-05-15 11:44:13 +0000757 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000758
759 for(jj=0; jj<pTab->nCol; jj++){
drh9adf9ac2002-05-15 11:44:13 +0000760 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
761 aXRef[jj] = ii;
762 break;
763 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000764 }
765 if( jj>=pTab->nCol ){
drh9adf9ac2002-05-15 11:44:13 +0000766 sqliteSetString(&pParse->zErrMsg, "no such column: ",
767 pChanges->a[ii].zName, 0);
768 pParse->nErr++;
769 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000770 }
771 }
772
773 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
774
danielk1977633ed082002-05-17 00:05:58 +0000775 for(ii = 0; ii<pTab->nCol; ii++){
776 if( aXRef[ii] < 0 ){
drh9adf9ac2002-05-15 11:44:13 +0000777 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
danielk1977f29ce552002-05-19 23:43:12 +0000778 }else{
drh9adf9ac2002-05-15 11:44:13 +0000779 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
danielk1977633ed082002-05-17 00:05:58 +0000780 }
781 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000782
783 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
784 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
785 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
786
787 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
danielk19776f349032002-06-11 02:25:40 +0000788 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000789 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
danielk19776f349032002-06-11 02:25:40 +0000790 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977f29ce552002-05-19 23:43:12 +0000791 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000792 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000793 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000794 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000795 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000796 }
797
798 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
799
800 sqliteVdbeResolveLabel(v, endOfLoop);
801 sqliteEndWriteOperation(pParse);
802
803trigger_cleanup:
804 sqliteFree(aXRef);
805 sqliteExprListDelete(pChanges);
806 sqliteExprDelete(pWhere);
807 sqliteExprListDelete(theSelect.pEList);
drhad3cab52002-05-24 02:04:32 +0000808 sqliteSrcListDelete(theSelect.pSrc);
danielk1977c3f9bad2002-05-15 08:30:12 +0000809 sqliteExprDelete(theSelect.pWhere);
810 return;
811}