blob: 044ef254d42a810550e257a0d79dca8df4bb54a7 [file] [log] [blame]
danielk1977c3f9bad2002-05-15 08:30:12 +00001/*
drh9adf9ac2002-05-15 11:44:13 +00002** All copyright on this work is disclaimed by the author.
3*/
danielk1977c3f9bad2002-05-15 08:30:12 +00004#include "sqliteInt.h"
drh9adf9ac2002-05-15 11:44:13 +00005
danielk1977c3f9bad2002-05-15 08:30:12 +00006/*
drh9adf9ac2002-05-15 11:44:13 +00007** This is called by the parser when it sees a CREATE TRIGGER statement
8*/
9void sqliteCreateTrigger(
10 Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
11 Token *nm, /* The name of the trigger */
12 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
13 int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
14 IdList *cols, /* column list if this is an UPDATE OF trigger */
15 Token *tbl, /* The name of the table/view the trigger applies to */
16 int foreach, /* One of TK_ROW or TK_STATEMENT */
17 Expr *pWhen, /* WHEN clause */
18 TriggerStep *steps, /* The triggered program */
19 char const *cc, /* The string data to make persistent */
20 int len
21){
22 Trigger *nt;
23 Table *tab;
danielk1977c3f9bad2002-05-15 08:30:12 +000024 int offset;
drh9adf9ac2002-05-15 11:44:13 +000025 TriggerStep *ss;
danielk1977c3f9bad2002-05-15 08:30:12 +000026
27 /* Check that:
drh9adf9ac2002-05-15 11:44:13 +000028 ** 1. the trigger name does not already exist.
29 ** 2. the table (or view) does exist.
30 */
danielk1977c3f9bad2002-05-15 08:30:12 +000031 {
drh9adf9ac2002-05-15 11:44:13 +000032 char *tmp_str = sqliteStrNDup(nm->z, nm->n);
33 if( sqliteHashFind(&(pParse->db->trigHash), tmp_str, nm->n + 1) ){
danielk1977c3f9bad2002-05-15 08:30:12 +000034 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1,
drh9adf9ac2002-05-15 11:44:13 +000035 nm->z, nm->n, " already exists", -1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +000036 sqliteFree(tmp_str);
37 pParse->nErr++;
38 goto trigger_cleanup;
39 }
40 sqliteFree(tmp_str);
41 }
42 {
drh9adf9ac2002-05-15 11:44:13 +000043 char *tmp_str = sqliteStrNDup(tbl->z, tbl->n);
danielk1977c3f9bad2002-05-15 08:30:12 +000044 tab = sqliteFindTable(pParse->db, tmp_str);
45 sqliteFree(tmp_str);
drh9adf9ac2002-05-15 11:44:13 +000046 if( !tab ){
danielk1977c3f9bad2002-05-15 08:30:12 +000047 sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1,
drh9adf9ac2002-05-15 11:44:13 +000048 tbl->z, tbl->n, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +000049 pParse->nErr++;
50 goto trigger_cleanup;
51 }
52 }
53
54 /* Build the Trigger object */
drh9adf9ac2002-05-15 11:44:13 +000055 nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
danielk1977c3f9bad2002-05-15 08:30:12 +000056 nt->name = sqliteStrNDup(nm->z, nm->n);
57 nt->table = sqliteStrNDup(tbl->z, tbl->n);
58 nt->op = op;
59 nt->tr_tm = tr_tm;
60 nt->pWhen = pWhen;
61 nt->pColumns = cols;
62 nt->foreach = foreach;
63 nt->step_list = steps;
64 nt->isCommit = 0;
65
66 nt->strings = sqliteStrNDup(cc, len);
67 offset = (int)(nt->strings - cc);
68
69 sqliteExprMoveStrings(nt->pWhen, offset);
70
71 ss = nt->step_list;
72 while (ss) {
73 sqliteSelectMoveStrings(ss->pSelect, offset);
74 if (ss->target.z) ss->target.z += offset;
75 sqliteExprMoveStrings(ss->pWhere, offset);
76 sqliteExprListMoveStrings(ss->pExprList, offset);
77
78 ss = ss->pNext;
79 }
80
81 /* if we are not initializing, and this trigger is not on a TEMP table,
drh9adf9ac2002-05-15 11:44:13 +000082 ** build the sqlite_master entry
83 */
84 if( !pParse->initFlag && !tab->isTemp ){
danielk1977c3f9bad2002-05-15 08:30:12 +000085
86 /* Make an entry in the sqlite_master table */
87 sqliteBeginWriteOperation(pParse);
88
89 sqliteVdbeAddOp(pParse->pVdbe, OP_OpenWrite, 0, 2);
90 sqliteVdbeChangeP3(pParse->pVdbe, -1, MASTER_NAME, P3_STATIC);
91 sqliteVdbeAddOp(pParse->pVdbe, OP_NewRecno, 0, 0);
92 sqliteVdbeAddOp(pParse->pVdbe, OP_String, 0, 0);
93 sqliteVdbeChangeP3(pParse->pVdbe, -1, "trigger", P3_STATIC);
94 sqliteVdbeAddOp(pParse->pVdbe, OP_String, 0, 0);
95 sqliteVdbeChangeP3(pParse->pVdbe, -1, nt->name, 0);
96 sqliteVdbeAddOp(pParse->pVdbe, OP_String, 0, 0);
97 sqliteVdbeChangeP3(pParse->pVdbe, -1, nt->table, 0);
98 sqliteVdbeAddOp(pParse->pVdbe, OP_Integer, 0, 0);
99 sqliteVdbeAddOp(pParse->pVdbe, OP_String, 0, 0);
100 sqliteVdbeChangeP3(pParse->pVdbe, -1, nt->strings, 0);
101 sqliteVdbeAddOp(pParse->pVdbe, OP_MakeRecord, 5, 0);
102 sqliteVdbeAddOp(pParse->pVdbe, OP_PutIntKey, 0, 1);
103
104 /* Change the cookie, since the schema is changed */
105 changeCookie(pParse->db);
106 sqliteVdbeAddOp(pParse->pVdbe, OP_Integer, pParse->db->next_cookie, 0);
107 sqliteVdbeAddOp(pParse->pVdbe, OP_SetCookie, 0, 0);
108
109 sqliteVdbeAddOp(pParse->pVdbe, OP_Close, 0, 0);
110
111 sqliteEndWriteOperation(pParse);
112 }
113
114 if (!pParse->explain) {
115 /* Stick it in the hash-table */
116 sqliteHashInsert(&(pParse->db->trigHash), nt->name, nm->n + 1, nt);
117
118 /* Attach it to the table object */
119 nt->pNext = tab->pTrigger;
120 tab->pTrigger = nt;
121 return;
122 } else {
123 sqliteFree(nt->strings);
124 sqliteFree(nt->name);
125 sqliteFree(nt->table);
126 sqliteFree(nt);
127 }
128
129trigger_cleanup:
130
131 sqliteIdListDelete(cols);
132 sqliteExprDelete(pWhen);
133 {
134 TriggerStep * pp;
135 TriggerStep * nn;
136
137 pp = steps;
138 while (pp) {
139 nn = pp->pNext;
140 sqliteExprDelete(pp->pWhere);
141 sqliteExprListDelete(pp->pExprList);
142 sqliteSelectDelete(pp->pSelect);
143 sqliteIdListDelete(pp->pIdList);
144 sqliteFree(pp);
145 pp = nn;
146 }
147 }
148}
149
150 TriggerStep *
151sqliteTriggerSelectStep(Select * s)
152{
153 TriggerStep * tt = sqliteMalloc(sizeof(TriggerStep));
154
155 tt->op = TK_SELECT;
156 tt->pSelect = s;
157 tt->orconf = OE_Default;
158
159 return tt;
160}
161
162TriggerStep *
163sqliteTriggerInsertStep(Token * tbl, IdList * col, ExprList * val, Select * s, int orconf)
164{
165 TriggerStep * tt = sqliteMalloc(sizeof(TriggerStep));
166
167 assert(val == 0 || s == 0);
168 assert(val != 0 || s != 0);
169
170 tt->op = TK_INSERT;
171 tt->pSelect = s;
172 tt->target = *tbl;
173 tt->pIdList = col;
174 tt->pExprList = val;
175 tt->orconf = orconf;
176
177 return tt;
178}
179
180TriggerStep *
181sqliteTriggerUpdateStep(Token * tbl, ExprList * val, Expr * w, int orconf)
182{
183 TriggerStep * tt = sqliteMalloc(sizeof(TriggerStep));
184
185 tt->op = TK_UPDATE;
186 tt->target = *tbl;
187 tt->pExprList = val;
188 tt->pWhere = w;
189 tt->orconf = orconf;
190
191 return tt;
192}
193
194TriggerStep *
195sqliteTriggerDeleteStep(Token * tbl, Expr * w)
196{
197 TriggerStep * tt = sqliteMalloc(sizeof(TriggerStep));
198
199 tt->op = TK_DELETE;
200 tt->target = *tbl;
201 tt->pWhere = w;
202 tt->orconf = OE_Default;
203
204 return tt;
205}
206
207
208/* This does a recursive delete of the trigger structure */
209void sqliteDeleteTrigger(Trigger * tt)
210{
211 TriggerStep * ts, * tc;
212 ts = tt->step_list;
213
214 while (ts) {
215 tc = ts;
216 ts = ts->pNext;
217
218 sqliteExprDelete(tc->pWhere);
219 sqliteExprListDelete(tc->pExprList);
220 sqliteSelectDelete(tc->pSelect);
221 sqliteIdListDelete(tc->pIdList);
222
223 sqliteFree(tc);
224 }
225
226 sqliteFree(tt->name);
227 sqliteFree(tt->table);
228 sqliteExprDelete(tt->pWhen);
229 sqliteIdListDelete(tt->pColumns);
230 sqliteFree(tt->strings);
231 sqliteFree(tt);
232}
233
234/*
235 * "nested" is true if this is begin called as the result of a DROP TABLE
236 */
237void sqliteDropTrigger(Parse *pParse, Token * trigname, int nested)
238{
239 char * tmp_name;
240 Trigger * trig;
241 Table * tbl;
242
243 tmp_name = sqliteStrNDup(trigname->z, trigname->n);
244
245 /* ensure that the trigger being dropped exists */
246 trig = sqliteHashFind(&(pParse->db->trigHash), tmp_name, trigname->n + 1);
247 if (!trig) {
248 sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1,
drh9adf9ac2002-05-15 11:44:13 +0000249 tmp_name, -1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000250 sqliteFree(tmp_name);
251 return;
252 }
253
254 /*
255 * If this is not an "explain", do the following:
256 * 1. Remove the trigger from its associated table structure
257 * 2. Move the trigger from the trigHash hash to trigDrop
258 */
259 if (!pParse->explain) {
260 /* 1 */
261 tbl = sqliteFindTable(pParse->db, trig->table);
262 assert(tbl);
263 if (tbl->pTrigger == trig)
264 tbl->pTrigger = trig->pNext;
265 else {
266 Trigger * cc = tbl->pTrigger;
267 while (cc) {
drh9adf9ac2002-05-15 11:44:13 +0000268 if (cc->pNext == trig) {
269 cc->pNext = cc->pNext->pNext;
270 break;
271 }
272 cc = cc->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000273 }
274 assert(cc);
275 }
276
277 /* 2 */
278 sqliteHashInsert(&(pParse->db->trigHash), tmp_name,
drh9adf9ac2002-05-15 11:44:13 +0000279 trigname->n + 1, NULL);
danielk1977c3f9bad2002-05-15 08:30:12 +0000280 sqliteHashInsert(&(pParse->db->trigDrop), trig->name,
drh9adf9ac2002-05-15 11:44:13 +0000281 trigname->n + 1, trig);
danielk1977c3f9bad2002-05-15 08:30:12 +0000282 }
283
284 /* Unless this is a trigger on a TEMP TABLE, generate code to destroy the
285 * database record of the trigger */
286 if (!tbl->isTemp) {
287 int base;
288 static VdbeOp dropTrigger[] = {
289 { OP_OpenWrite, 0, 2, MASTER_NAME},
290 { OP_Rewind, 0, ADDR(9), 0},
291 { OP_String, 0, 0, 0}, /* 2 */
292 { OP_MemStore, 1, 1, 0},
293 { OP_MemLoad, 1, 0, 0}, /* 4 */
294 { OP_Column, 0, 1, 0},
295 { OP_Ne, 0, ADDR(8), 0},
296 { OP_Delete, 0, 0, 0},
297 { OP_Next, 0, ADDR(4), 0}, /* 8 */
298 { OP_Integer, 0, 0, 0}, /* 9 */
299 { OP_SetCookie, 0, 0, 0},
300 { OP_Close, 0, 0, 0},
301 };
302
303 if (!nested)
304 sqliteBeginWriteOperation(pParse);
305
306 base = sqliteVdbeAddOpList(pParse->pVdbe,
drh9adf9ac2002-05-15 11:44:13 +0000307 ArraySize(dropTrigger), dropTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000308 sqliteVdbeChangeP3(pParse->pVdbe, base+2, tmp_name, 0);
309
310 if (!nested)
311 changeCookie(pParse->db);
312
313 sqliteVdbeChangeP1(pParse->pVdbe, base+9, pParse->db->next_cookie);
314
315 if (!nested)
316 sqliteEndWriteOperation(pParse);
317 }
318
319 sqliteFree(tmp_name);
320}
321
322static int checkColumnOverLap(IdList * ii, ExprList * ee)
323{
324 int i, e;
325 if (!ii) return 1;
326 if (!ee) return 1;
327
328 for (i = 0; i < ii->nId; i++)
329 for (e = 0; e < ee->nExpr; e++)
330 if (!sqliteStrICmp(ii->a[i].zName, ee->a[e].zName))
drh9adf9ac2002-05-15 11:44:13 +0000331 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000332
333 return 0;
334}
335
336/* A global variable that is TRUE if we should always set up temp tables for
337 * for triggers, even if there are no triggers to code. This is used to test
338 * how much overhead the triggers algorithm is causing.
339 *
340 * This flag can be set or cleared using the "trigger_overhead_test" pragma.
341 * The pragma is not documented since it is not really part of the interface
342 * to SQLite, just the test procedure.
343*/
344int always_code_trigger_setup = 0;
345
346/*
347 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
348 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
349 * found in the list specified as pTrigger.
350 */
351int sqliteTriggersExist(
352 Parse * pParse,
353 Trigger * pTrigger,
354 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
355 int tr_tm, /* one of TK_BEFORE, TK_AFTER */
356 int foreach, /* one of TK_ROW or TK_STATEMENT */
357 ExprList * pChanges)
358{
359 Trigger * tt;
360
361 if (always_code_trigger_setup) return 1;
362
363 tt = pTrigger;
364 while (tt) {
365 if (tt->op == op && tt->tr_tm == tr_tm && tt->foreach == foreach &&
drh9adf9ac2002-05-15 11:44:13 +0000366 checkColumnOverLap(tt->pColumns, pChanges)) {
danielk1977c3f9bad2002-05-15 08:30:12 +0000367 TriggerStack * ss;
368 ss = pParse->trigStack;
369 while (ss && ss->pTrigger != pTrigger) ss = ss->pNext;
370 if (!ss) return 1;
371 }
372 tt = tt->pNext;
373 }
374
375 return 0;
376}
377
378static int codeTriggerProgram(
drh9adf9ac2002-05-15 11:44:13 +0000379 Parse *pParse,
380 TriggerStep * program,
381 int onError)
danielk1977c3f9bad2002-05-15 08:30:12 +0000382{
383 TriggerStep * step = program;
384 int orconf;
385
386 while (step) {
drh9adf9ac2002-05-15 11:44:13 +0000387 int saveNTab = pParse->nTab;
388 orconf = (onError == OE_Default)?step->orconf:onError;
389 pParse->trigStack->orconf = orconf;
390 switch(step->op) {
391 case TK_SELECT: {
danielk1977c3f9bad2002-05-15 08:30:12 +0000392 int tmp_tbl = pParse->nTab++;
drh9adf9ac2002-05-15 11:44:13 +0000393 sqliteVdbeAddOp(pParse->pVdbe, OP_OpenTemp, tmp_tbl, 0);
394 sqliteVdbeAddOp(pParse->pVdbe, OP_KeyAsData, tmp_tbl, 1);
395 sqliteSelect(pParse, step->pSelect,
396 SRT_Union, tmp_tbl, 0, 0, 0);
397 sqliteVdbeAddOp(pParse->pVdbe, OP_Close, tmp_tbl, 0);
398 pParse->nTab--;
399 break;
400 }
401 case TK_UPDATE: {
danielk1977c3f9bad2002-05-15 08:30:12 +0000402 sqliteVdbeAddOp(pParse->pVdbe, OP_PushList, 0, 0);
drh9adf9ac2002-05-15 11:44:13 +0000403 sqliteUpdate(pParse, &step->target,
404 sqliteExprListDup(step->pExprList),
405 sqliteExprDup(step->pWhere), orconf);
danielk1977c3f9bad2002-05-15 08:30:12 +0000406 sqliteVdbeAddOp(pParse->pVdbe, OP_PopList, 0, 0);
drh9adf9ac2002-05-15 11:44:13 +0000407 break;
408 }
409 case TK_INSERT: {
danielk1977c3f9bad2002-05-15 08:30:12 +0000410 sqliteInsert(pParse, &step->target,
drh9adf9ac2002-05-15 11:44:13 +0000411 sqliteExprListDup(step->pExprList),
412 sqliteSelectDup(step->pSelect),
413 sqliteIdListDup(step->pIdList), orconf);
414 break;
415 }
416 case TK_DELETE: {
417 sqliteVdbeAddOp(pParse->pVdbe, OP_PushList, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000418 sqliteDeleteFrom(pParse, &step->target,
drh9adf9ac2002-05-15 11:44:13 +0000419 sqliteExprDup(step->pWhere)
420 );
421 sqliteVdbeAddOp(pParse->pVdbe, OP_PopList, 0, 0);
422 break;
423 }
424 default:
425 assert(0);
426 }
427 pParse->nTab = saveNTab;
428 step = step->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000429 }
430
431 return 0;
432}
433
434int sqliteCodeRowTrigger(
drh9adf9ac2002-05-15 11:44:13 +0000435 Parse * pParse, /* Parse context */
436 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
437 ExprList * changes, /* Changes list for any UPDATE OF triggers */
438 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
439 Table * tbl, /* The table to code triggers from */
440 int newTable, /* The indice of the "new" row to access */
441 int oldTable, /* The indice of the "old" row to access */
442 int onError) /* ON CONFLICT policy */
danielk1977c3f9bad2002-05-15 08:30:12 +0000443{
444 Trigger * pTrigger;
445 TriggerStack * pTriggerStack;
446
447
448 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
449 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
450
451 assert(newTable != -1 || oldTable != -1);
452
453 pTrigger = tbl->pTrigger;
454 while (pTrigger) {
455 int fire_this = 0;
456
457 /* determine whether we should code this trigger */
458 if (pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
drh9adf9ac2002-05-15 11:44:13 +0000459 pTrigger->foreach == TK_ROW) {
danielk1977c3f9bad2002-05-15 08:30:12 +0000460 fire_this = 1;
461 pTriggerStack = pParse->trigStack;
462 while (pTriggerStack) {
drh9adf9ac2002-05-15 11:44:13 +0000463 if (pTriggerStack->pTrigger == pTrigger) fire_this = 0;
464 pTriggerStack = pTriggerStack->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000465 }
466 if (op == TK_UPDATE && pTrigger->pColumns &&
drh9adf9ac2002-05-15 11:44:13 +0000467 !checkColumnOverLap(pTrigger->pColumns, changes))
468 fire_this = 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000469 }
470
471 if (fire_this) {
472 int endTrigger;
473 IdList dummyTablist;
474 Expr * whenExpr;
475
476 dummyTablist.nId = 0;
477 dummyTablist.a = 0;
478
479 /* Push an entry on to the trigger stack */
480 pTriggerStack = sqliteMalloc(sizeof(TriggerStack));
481 pTriggerStack->pTrigger = pTrigger;
482 pTriggerStack->newIdx = newTable;
483 pTriggerStack->oldIdx = oldTable;
484 pTriggerStack->pTab = tbl;
485 pTriggerStack->pNext = pParse->trigStack;
486 pParse->trigStack = pTriggerStack;
487
488 /* code the WHEN clause */
489 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
490 whenExpr = sqliteExprDup(pTrigger->pWhen);
491 if (sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr)) {
drh9adf9ac2002-05-15 11:44:13 +0000492 pParse->trigStack = pParse->trigStack->pNext;
493 sqliteFree(pTriggerStack);
494 sqliteExprDelete(whenExpr);
495 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000496 }
497 sqliteExprIfFalse(pParse, whenExpr, endTrigger);
498 sqliteExprDelete(whenExpr);
499
500 codeTriggerProgram(pParse, pTrigger->step_list, onError);
501
502 /* Pop the entry off the trigger stack */
503 pParse->trigStack = pParse->trigStack->pNext;
504 sqliteFree(pTriggerStack);
505
506 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
507 }
508 pTrigger = pTrigger->pNext;
509 }
510
511 return 0;
512}
513
514/*
515 * Handle UPDATE and DELETE triggers on views
516 */
517void sqliteViewTriggers(Parse *pParse, Table *pTab,
518 Expr * pWhere, int onError, ExprList * pChanges)
519{
520 int oldIdx = -1;
521 int newIdx = -1;
522 int *aXRef = 0;
523 Vdbe *v;
524 int endOfLoop;
525 int startOfLoop;
526 Select theSelect;
527 Token tblNameToken;
528
529 assert(pTab->pSelect);
530
531 tblNameToken.z = pTab->zName;
532 tblNameToken.n = strlen(pTab->zName);
533
534 theSelect.isDistinct = 0;
535 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
536 theSelect.pSrc = sqliteIdListAppend(0, &tblNameToken);
537 theSelect.pWhere = pWhere; pWhere = 0;
538 theSelect.pGroupBy = 0;
539 theSelect.pHaving = 0;
540 theSelect.pOrderBy = 0;
541 theSelect.op = TK_SELECT; /* ?? */
542 theSelect.pPrior = 0;
543 theSelect.nLimit = -1;
544 theSelect.nOffset = -1;
545 theSelect.zSelect = 0;
546 theSelect.base = 0;
547
548 v = sqliteGetVdbe(pParse);
549 assert(v);
550 sqliteBeginMultiWriteOperation(pParse);
551
552 /* Allocate temp tables */
553 oldIdx = pParse->nTab++;
554 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
555 if (pChanges) {
556 newIdx = pParse->nTab++;
557 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
558 }
559
560 /* Snapshot the view */
561 if (sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0)) {
562 goto trigger_cleanup;
563 }
564
565 /* loop thru the view snapshot, executing triggers for each row */
566 endOfLoop = sqliteVdbeMakeLabel(v);
567 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
568
569 /* Loop thru the view snapshot, executing triggers for each row */
570 startOfLoop = sqliteVdbeCurrentAddr(v);
571
572 /* Build the updated row if required */
573 if (pChanges) {
574 int ii, jj;
575
576 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
577 if( aXRef==0 ) goto trigger_cleanup;
578 for (ii = 0; ii < pTab->nCol; ii++)
579 aXRef[ii] = -1;
580
581 for(ii=0; ii<pChanges->nExpr; ii++){
582 int jj;
583 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
drh9adf9ac2002-05-15 11:44:13 +0000584 pChanges->a[ii].pExpr) )
585 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000586
587 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
drh9adf9ac2002-05-15 11:44:13 +0000588 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000589
590 for(jj=0; jj<pTab->nCol; jj++){
drh9adf9ac2002-05-15 11:44:13 +0000591 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
592 aXRef[jj] = ii;
593 break;
594 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000595 }
596 if( jj>=pTab->nCol ){
drh9adf9ac2002-05-15 11:44:13 +0000597 sqliteSetString(&pParse->zErrMsg, "no such column: ",
598 pChanges->a[ii].zName, 0);
599 pParse->nErr++;
600 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000601 }
602 }
603
604 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
605
606 for (ii = 0; ii < pTab->nCol; ii++)
607 if( aXRef[ii] < 0 )
drh9adf9ac2002-05-15 11:44:13 +0000608 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
danielk1977c3f9bad2002-05-15 08:30:12 +0000609 else
drh9adf9ac2002-05-15 11:44:13 +0000610 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
danielk1977c3f9bad2002-05-15 08:30:12 +0000611
612 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
613 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
614 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
615
616 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
drh9adf9ac2002-05-15 11:44:13 +0000617 pTab, newIdx, oldIdx, onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000618 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
drh9adf9ac2002-05-15 11:44:13 +0000619 pTab, newIdx, oldIdx, onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000620 } else {
621 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
drh9adf9ac2002-05-15 11:44:13 +0000622 onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000623 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
drh9adf9ac2002-05-15 11:44:13 +0000624 onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000625 }
626
627 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
628
629 sqliteVdbeResolveLabel(v, endOfLoop);
630 sqliteEndWriteOperation(pParse);
631
632trigger_cleanup:
633 sqliteFree(aXRef);
634 sqliteExprListDelete(pChanges);
635 sqliteExprDelete(pWhere);
636 sqliteExprListDelete(theSelect.pEList);
637 sqliteIdListDelete(theSelect.pSrc);
638 sqliteExprDelete(theSelect.pWhere);
639 return;
640}