blob: e4c78bf386ace29f63f8fa3abd1eb2bbc62342de [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 */
drhdc379452002-05-15 12:45:43 +0000105 sqliteChangeCookie(pParse->db);
danielk1977c3f9bad2002-05-15 08:30:12 +0000106 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
drhdc379452002-05-15 12:45:43 +0000303 if( !nested ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000304 sqliteBeginWriteOperation(pParse);
drhdc379452002-05-15 12:45:43 +0000305 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000306 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);
drhdc379452002-05-15 12:45:43 +0000309 if( !nested ){
310 sqliteChangeCookie(pParse->db);
311 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000312 sqliteVdbeChangeP1(pParse->pVdbe, base+9, pParse->db->next_cookie);
drhdc379452002-05-15 12:45:43 +0000313 if( !nested ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000314 sqliteEndWriteOperation(pParse);
drhdc379452002-05-15 12:45:43 +0000315 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000316 }
317
318 sqliteFree(tmp_name);
319}
320
321static int checkColumnOverLap(IdList * ii, ExprList * ee)
322{
323 int i, e;
324 if (!ii) return 1;
325 if (!ee) return 1;
326
327 for (i = 0; i < ii->nId; i++)
328 for (e = 0; e < ee->nExpr; e++)
329 if (!sqliteStrICmp(ii->a[i].zName, ee->a[e].zName))
drh9adf9ac2002-05-15 11:44:13 +0000330 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000331
332 return 0;
333}
334
335/* A global variable that is TRUE if we should always set up temp tables for
336 * for triggers, even if there are no triggers to code. This is used to test
337 * how much overhead the triggers algorithm is causing.
338 *
339 * This flag can be set or cleared using the "trigger_overhead_test" pragma.
340 * The pragma is not documented since it is not really part of the interface
341 * to SQLite, just the test procedure.
342*/
343int always_code_trigger_setup = 0;
344
345/*
346 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
347 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
348 * found in the list specified as pTrigger.
349 */
350int sqliteTriggersExist(
351 Parse * pParse,
352 Trigger * pTrigger,
353 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
354 int tr_tm, /* one of TK_BEFORE, TK_AFTER */
355 int foreach, /* one of TK_ROW or TK_STATEMENT */
356 ExprList * pChanges)
357{
358 Trigger * tt;
359
360 if (always_code_trigger_setup) return 1;
361
362 tt = pTrigger;
363 while (tt) {
364 if (tt->op == op && tt->tr_tm == tr_tm && tt->foreach == foreach &&
drh9adf9ac2002-05-15 11:44:13 +0000365 checkColumnOverLap(tt->pColumns, pChanges)) {
danielk1977c3f9bad2002-05-15 08:30:12 +0000366 TriggerStack * ss;
367 ss = pParse->trigStack;
368 while (ss && ss->pTrigger != pTrigger) ss = ss->pNext;
369 if (!ss) return 1;
370 }
371 tt = tt->pNext;
372 }
373
374 return 0;
375}
376
377static int codeTriggerProgram(
drh9adf9ac2002-05-15 11:44:13 +0000378 Parse *pParse,
379 TriggerStep * program,
380 int onError)
danielk1977c3f9bad2002-05-15 08:30:12 +0000381{
382 TriggerStep * step = program;
383 int orconf;
384
385 while (step) {
drh9adf9ac2002-05-15 11:44:13 +0000386 int saveNTab = pParse->nTab;
387 orconf = (onError == OE_Default)?step->orconf:onError;
388 pParse->trigStack->orconf = orconf;
389 switch(step->op) {
390 case TK_SELECT: {
danielk1977c3f9bad2002-05-15 08:30:12 +0000391 int tmp_tbl = pParse->nTab++;
drh9adf9ac2002-05-15 11:44:13 +0000392 sqliteVdbeAddOp(pParse->pVdbe, OP_OpenTemp, tmp_tbl, 0);
393 sqliteVdbeAddOp(pParse->pVdbe, OP_KeyAsData, tmp_tbl, 1);
394 sqliteSelect(pParse, step->pSelect,
395 SRT_Union, tmp_tbl, 0, 0, 0);
396 sqliteVdbeAddOp(pParse->pVdbe, OP_Close, tmp_tbl, 0);
397 pParse->nTab--;
398 break;
399 }
400 case TK_UPDATE: {
danielk1977c3f9bad2002-05-15 08:30:12 +0000401 sqliteVdbeAddOp(pParse->pVdbe, OP_PushList, 0, 0);
drh9adf9ac2002-05-15 11:44:13 +0000402 sqliteUpdate(pParse, &step->target,
403 sqliteExprListDup(step->pExprList),
404 sqliteExprDup(step->pWhere), orconf);
danielk1977c3f9bad2002-05-15 08:30:12 +0000405 sqliteVdbeAddOp(pParse->pVdbe, OP_PopList, 0, 0);
drh9adf9ac2002-05-15 11:44:13 +0000406 break;
407 }
408 case TK_INSERT: {
danielk1977c3f9bad2002-05-15 08:30:12 +0000409 sqliteInsert(pParse, &step->target,
drh9adf9ac2002-05-15 11:44:13 +0000410 sqliteExprListDup(step->pExprList),
411 sqliteSelectDup(step->pSelect),
412 sqliteIdListDup(step->pIdList), orconf);
413 break;
414 }
415 case TK_DELETE: {
416 sqliteVdbeAddOp(pParse->pVdbe, OP_PushList, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000417 sqliteDeleteFrom(pParse, &step->target,
drh9adf9ac2002-05-15 11:44:13 +0000418 sqliteExprDup(step->pWhere)
419 );
420 sqliteVdbeAddOp(pParse->pVdbe, OP_PopList, 0, 0);
421 break;
422 }
423 default:
424 assert(0);
425 }
426 pParse->nTab = saveNTab;
427 step = step->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000428 }
429
430 return 0;
431}
432
433int sqliteCodeRowTrigger(
drh9adf9ac2002-05-15 11:44:13 +0000434 Parse * pParse, /* Parse context */
435 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
436 ExprList * changes, /* Changes list for any UPDATE OF triggers */
437 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
438 Table * tbl, /* The table to code triggers from */
439 int newTable, /* The indice of the "new" row to access */
440 int oldTable, /* The indice of the "old" row to access */
441 int onError) /* ON CONFLICT policy */
danielk1977c3f9bad2002-05-15 08:30:12 +0000442{
443 Trigger * pTrigger;
444 TriggerStack * pTriggerStack;
445
446
447 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
448 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
449
450 assert(newTable != -1 || oldTable != -1);
451
452 pTrigger = tbl->pTrigger;
453 while (pTrigger) {
454 int fire_this = 0;
455
456 /* determine whether we should code this trigger */
457 if (pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
drh9adf9ac2002-05-15 11:44:13 +0000458 pTrigger->foreach == TK_ROW) {
danielk1977c3f9bad2002-05-15 08:30:12 +0000459 fire_this = 1;
460 pTriggerStack = pParse->trigStack;
461 while (pTriggerStack) {
drh9adf9ac2002-05-15 11:44:13 +0000462 if (pTriggerStack->pTrigger == pTrigger) fire_this = 0;
463 pTriggerStack = pTriggerStack->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000464 }
465 if (op == TK_UPDATE && pTrigger->pColumns &&
drh9adf9ac2002-05-15 11:44:13 +0000466 !checkColumnOverLap(pTrigger->pColumns, changes))
467 fire_this = 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000468 }
469
470 if (fire_this) {
471 int endTrigger;
472 IdList dummyTablist;
473 Expr * whenExpr;
474
475 dummyTablist.nId = 0;
476 dummyTablist.a = 0;
477
478 /* Push an entry on to the trigger stack */
479 pTriggerStack = sqliteMalloc(sizeof(TriggerStack));
480 pTriggerStack->pTrigger = pTrigger;
481 pTriggerStack->newIdx = newTable;
482 pTriggerStack->oldIdx = oldTable;
483 pTriggerStack->pTab = tbl;
484 pTriggerStack->pNext = pParse->trigStack;
485 pParse->trigStack = pTriggerStack;
486
487 /* code the WHEN clause */
488 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
489 whenExpr = sqliteExprDup(pTrigger->pWhen);
490 if (sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr)) {
drh9adf9ac2002-05-15 11:44:13 +0000491 pParse->trigStack = pParse->trigStack->pNext;
492 sqliteFree(pTriggerStack);
493 sqliteExprDelete(whenExpr);
494 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000495 }
496 sqliteExprIfFalse(pParse, whenExpr, endTrigger);
497 sqliteExprDelete(whenExpr);
498
499 codeTriggerProgram(pParse, pTrigger->step_list, onError);
500
501 /* Pop the entry off the trigger stack */
502 pParse->trigStack = pParse->trigStack->pNext;
503 sqliteFree(pTriggerStack);
504
505 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
506 }
507 pTrigger = pTrigger->pNext;
508 }
509
510 return 0;
511}
512
513/*
514 * Handle UPDATE and DELETE triggers on views
515 */
516void sqliteViewTriggers(Parse *pParse, Table *pTab,
517 Expr * pWhere, int onError, ExprList * pChanges)
518{
519 int oldIdx = -1;
520 int newIdx = -1;
521 int *aXRef = 0;
522 Vdbe *v;
523 int endOfLoop;
524 int startOfLoop;
525 Select theSelect;
526 Token tblNameToken;
527
528 assert(pTab->pSelect);
529
530 tblNameToken.z = pTab->zName;
531 tblNameToken.n = strlen(pTab->zName);
532
533 theSelect.isDistinct = 0;
534 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
535 theSelect.pSrc = sqliteIdListAppend(0, &tblNameToken);
536 theSelect.pWhere = pWhere; pWhere = 0;
537 theSelect.pGroupBy = 0;
538 theSelect.pHaving = 0;
539 theSelect.pOrderBy = 0;
540 theSelect.op = TK_SELECT; /* ?? */
541 theSelect.pPrior = 0;
542 theSelect.nLimit = -1;
543 theSelect.nOffset = -1;
544 theSelect.zSelect = 0;
545 theSelect.base = 0;
546
547 v = sqliteGetVdbe(pParse);
548 assert(v);
549 sqliteBeginMultiWriteOperation(pParse);
550
551 /* Allocate temp tables */
552 oldIdx = pParse->nTab++;
553 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
554 if (pChanges) {
555 newIdx = pParse->nTab++;
556 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
557 }
558
559 /* Snapshot the view */
560 if (sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0)) {
561 goto trigger_cleanup;
562 }
563
564 /* loop thru the view snapshot, executing triggers for each row */
565 endOfLoop = sqliteVdbeMakeLabel(v);
566 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
567
568 /* Loop thru the view snapshot, executing triggers for each row */
569 startOfLoop = sqliteVdbeCurrentAddr(v);
570
571 /* Build the updated row if required */
572 if (pChanges) {
573 int ii, jj;
574
575 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
576 if( aXRef==0 ) goto trigger_cleanup;
577 for (ii = 0; ii < pTab->nCol; ii++)
578 aXRef[ii] = -1;
579
580 for(ii=0; ii<pChanges->nExpr; ii++){
581 int jj;
582 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
drh9adf9ac2002-05-15 11:44:13 +0000583 pChanges->a[ii].pExpr) )
584 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000585
586 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
drh9adf9ac2002-05-15 11:44:13 +0000587 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000588
589 for(jj=0; jj<pTab->nCol; jj++){
drh9adf9ac2002-05-15 11:44:13 +0000590 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
591 aXRef[jj] = ii;
592 break;
593 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000594 }
595 if( jj>=pTab->nCol ){
drh9adf9ac2002-05-15 11:44:13 +0000596 sqliteSetString(&pParse->zErrMsg, "no such column: ",
597 pChanges->a[ii].zName, 0);
598 pParse->nErr++;
599 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000600 }
601 }
602
603 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
604
605 for (ii = 0; ii < pTab->nCol; ii++)
606 if( aXRef[ii] < 0 )
drh9adf9ac2002-05-15 11:44:13 +0000607 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
danielk1977c3f9bad2002-05-15 08:30:12 +0000608 else
drh9adf9ac2002-05-15 11:44:13 +0000609 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
danielk1977c3f9bad2002-05-15 08:30:12 +0000610
611 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
612 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
613 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
614
615 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
drh9adf9ac2002-05-15 11:44:13 +0000616 pTab, newIdx, oldIdx, onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000617 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
drh9adf9ac2002-05-15 11:44:13 +0000618 pTab, newIdx, oldIdx, onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000619 } else {
620 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
drh9adf9ac2002-05-15 11:44:13 +0000621 onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000622 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
drh9adf9ac2002-05-15 11:44:13 +0000623 onError);
danielk1977c3f9bad2002-05-15 08:30:12 +0000624 }
625
626 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
627
628 sqliteVdbeResolveLabel(v, endOfLoop);
629 sqliteEndWriteOperation(pParse);
630
631trigger_cleanup:
632 sqliteFree(aXRef);
633 sqliteExprListDelete(pChanges);
634 sqliteExprDelete(pWhere);
635 sqliteExprListDelete(theSelect.pEList);
636 sqliteIdListDelete(theSelect.pSrc);
637 sqliteExprDelete(theSelect.pWhere);
638 return;
639}