blob: 079a4c2f85b7e0b97104dea1a88ebcc6453299e8 [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;
danielk1977c3f9bad2002-05-15 08:30:12 +000052
drhed6c8672003-01-12 18:02:16 +000053 if( sqliteAuthCommand(pParse, "CREATE", "TRIGGER") ) goto trigger_cleanup;
54
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 */
danielk1977c3f9bad2002-05-15 08:30:12 +000062 {
danielk1977633ed082002-05-17 00:05:58 +000063 char *tmp_str = sqliteStrNDup(pName->z, pName->n);
64 if( sqliteHashFind(&(pParse->db->trigHash), tmp_str, pName->n + 1) ){
danielk1977c3f9bad2002-05-15 08:30:12 +000065 sqliteSetNString(&pParse->zErrMsg, "trigger ", -1,
danielk1977633ed082002-05-17 00:05:58 +000066 pName->z, pName->n, " already exists", -1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +000067 sqliteFree(tmp_str);
68 pParse->nErr++;
69 goto trigger_cleanup;
70 }
71 sqliteFree(tmp_str);
72 }
73 {
danielk1977633ed082002-05-17 00:05:58 +000074 char *tmp_str = sqliteStrNDup(pTableName->z, pTableName->n);
drhe4697f52002-05-23 02:09:03 +000075 if( tmp_str==0 ) goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +000076 tab = sqliteFindTable(pParse->db, tmp_str);
77 sqliteFree(tmp_str);
drh9adf9ac2002-05-15 11:44:13 +000078 if( !tab ){
danielk1977c3f9bad2002-05-15 08:30:12 +000079 sqliteSetNString(&pParse->zErrMsg, "no such table: ", -1,
danielk1977633ed082002-05-17 00:05:58 +000080 pTableName->z, pTableName->n, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +000081 pParse->nErr++;
82 goto trigger_cleanup;
83 }
drh1873cd52002-05-23 00:30:31 +000084 if( sqliteStrICmp(tab->zName, MASTER_NAME)==0 ){
85 sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
86 "table: " MASTER_NAME, 0);
87 pParse->nErr++;
88 goto trigger_cleanup;
89 }
drhe0bc4042002-06-25 01:09:11 +000090 if( sqliteStrICmp(tab->zName, TEMP_MASTER_NAME)==0 ){
91 sqliteSetString(&pParse->zErrMsg, "cannot create trigger on system "
92 "table: " TEMP_MASTER_NAME, 0);
93 pParse->nErr++;
94 goto trigger_cleanup;
95 }
danielk1977d702fcc2002-05-26 23:24:40 +000096 if( tab->pSelect && tr_tm != TK_INSTEAD ){
97 sqliteSetNString(&pParse->zErrMsg, "cannot create ", -1,
98 (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", -1, " trigger on view: ", -1
99 , pTableName->z, pTableName->n, 0);
100 goto trigger_cleanup;
101 }
102 if( !tab->pSelect && tr_tm == TK_INSTEAD ){
103 sqliteSetNString(&pParse->zErrMsg, "cannot create INSTEAD OF", -1,
104 " trigger on table: ", -1, pTableName->z, pTableName->n, 0);
105 goto trigger_cleanup;
106 }
drhed6c8672003-01-12 18:02:16 +0000107 if( sqliteAuthInsert(pParse, SCHEMA_TABLE(tab->isTemp), 1) ){
108 goto trigger_cleanup;
109 }
danielk1977d702fcc2002-05-26 23:24:40 +0000110 }
111
112 if (tr_tm == TK_INSTEAD){
113 tr_tm = TK_BEFORE;
danielk1977c3f9bad2002-05-15 08:30:12 +0000114 }
115
116 /* Build the Trigger object */
drh9adf9ac2002-05-15 11:44:13 +0000117 nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
drhe4697f52002-05-23 02:09:03 +0000118 if( nt==0 ) goto trigger_cleanup;
danielk1977633ed082002-05-17 00:05:58 +0000119 nt->name = sqliteStrNDup(pName->z, pName->n);
120 nt->table = sqliteStrNDup(pTableName->z, pTableName->n);
drhe4697f52002-05-23 02:09:03 +0000121 if( sqlite_malloc_failed ) goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000122 nt->op = op;
123 nt->tr_tm = tr_tm;
drh4b59ab52002-08-24 18:24:51 +0000124 nt->pWhen = sqliteExprDup(pWhen);
125 sqliteExprDelete(pWhen);
126 nt->pColumns = sqliteIdListDup(pColumns);
127 sqliteIdListDelete(pColumns);
danielk1977c3f9bad2002-05-15 08:30:12 +0000128 nt->foreach = foreach;
danielk1977633ed082002-05-17 00:05:58 +0000129 nt->step_list = pStepList;
danielk1977c3f9bad2002-05-15 08:30:12 +0000130
131 /* if we are not initializing, and this trigger is not on a TEMP table,
drh9adf9ac2002-05-15 11:44:13 +0000132 ** build the sqlite_master entry
133 */
drhe0bc4042002-06-25 01:09:11 +0000134 if( !pParse->initFlag ){
drhc977f7f2002-05-21 11:38:11 +0000135 static VdbeOp insertTrig[] = {
drhc977f7f2002-05-21 11:38:11 +0000136 { OP_NewRecno, 0, 0, 0 },
137 { OP_String, 0, 0, "trigger" },
drhe0bc4042002-06-25 01:09:11 +0000138 { OP_String, 0, 0, 0 }, /* 2: trigger name */
139 { OP_String, 0, 0, 0 }, /* 3: table name */
drhc977f7f2002-05-21 11:38:11 +0000140 { OP_Integer, 0, 0, 0 },
drhe0bc4042002-06-25 01:09:11 +0000141 { OP_String, 0, 0, 0 }, /* 5: SQL */
drhc977f7f2002-05-21 11:38:11 +0000142 { OP_MakeRecord, 5, 0, 0 },
143 { OP_PutIntKey, 0, 0, 0 },
drhc977f7f2002-05-21 11:38:11 +0000144 };
145 int addr;
146 Vdbe *v;
danielk1977c3f9bad2002-05-15 08:30:12 +0000147
148 /* Make an entry in the sqlite_master table */
drhc977f7f2002-05-21 11:38:11 +0000149 v = sqliteGetVdbe(pParse);
drhe4697f52002-05-23 02:09:03 +0000150 if( v==0 ) goto trigger_cleanup;
drhcabb0812002-09-14 13:47:32 +0000151 sqliteBeginWriteOperation(pParse, 0, 0);
drhe0bc4042002-06-25 01:09:11 +0000152 sqliteOpenMasterTable(v, tab->isTemp);
drhc977f7f2002-05-21 11:38:11 +0000153 addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
drhe0bc4042002-06-25 01:09:11 +0000154 sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME,
155 P3_STATIC);
156 sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
157 sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
drh4b59ab52002-08-24 18:24:51 +0000158 sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
drhe0bc4042002-06-25 01:09:11 +0000159 if( !tab->isTemp ){
160 sqliteChangeCookie(pParse->db, v);
161 }
162 sqliteVdbeAddOp(v, OP_Close, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000163 sqliteEndWriteOperation(pParse);
164 }
165
danielk1977633ed082002-05-17 00:05:58 +0000166 if( !pParse->explain ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000167 /* Stick it in the hash-table */
danielk1977633ed082002-05-17 00:05:58 +0000168 sqliteHashInsert(&(pParse->db->trigHash), nt->name, pName->n + 1, nt);
danielk1977c3f9bad2002-05-15 08:30:12 +0000169
170 /* Attach it to the table object */
171 nt->pNext = tab->pTrigger;
172 tab->pTrigger = nt;
173 return;
danielk1977f29ce552002-05-19 23:43:12 +0000174 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000175 sqliteFree(nt->name);
176 sqliteFree(nt->table);
177 sqliteFree(nt);
178 }
179
180trigger_cleanup:
181
danielk1977633ed082002-05-17 00:05:58 +0000182 sqliteIdListDelete(pColumns);
danielk1977c3f9bad2002-05-15 08:30:12 +0000183 sqliteExprDelete(pWhen);
drh4b59ab52002-08-24 18:24:51 +0000184 sqliteDeleteTriggerStep(pStepList);
185}
danielk1977c3f9bad2002-05-15 08:30:12 +0000186
drh4b59ab52002-08-24 18:24:51 +0000187/*
188** Make a copy of all components of the given trigger step. This has
189** the effect of copying all Expr.token.z values into memory obtained
190** from sqliteMalloc(). As initially created, the Expr.token.z values
191** all point to the input string that was fed to the parser. But that
192** string is ephemeral - it will go away as soon as the sqlite_exec()
193** call that started the parser exits. This routine makes a persistent
194** copy of all the Expr.token.z strings so that the TriggerStep structure
195** will be valid even after the sqlite_exec() call returns.
196*/
197static void sqlitePersistTriggerStep(TriggerStep *p){
198 if( p->target.z ){
199 p->target.z = sqliteStrNDup(p->target.z, p->target.n);
200 p->target.dyn = 1;
201 }
202 if( p->pSelect ){
203 Select *pNew = sqliteSelectDup(p->pSelect);
204 sqliteSelectDelete(p->pSelect);
205 p->pSelect = pNew;
206 }
207 if( p->pWhere ){
208 Expr *pNew = sqliteExprDup(p->pWhere);
209 sqliteExprDelete(p->pWhere);
210 p->pWhere = pNew;
211 }
212 if( p->pExprList ){
213 ExprList *pNew = sqliteExprListDup(p->pExprList);
214 sqliteExprListDelete(p->pExprList);
215 p->pExprList = pNew;
216 }
217 if( p->pIdList ){
218 IdList *pNew = sqliteIdListDup(p->pIdList);
219 sqliteIdListDelete(p->pIdList);
220 p->pIdList = pNew;
danielk1977c3f9bad2002-05-15 08:30:12 +0000221 }
222}
223
drhc977f7f2002-05-21 11:38:11 +0000224/*
225** Turn a SELECT statement (that the pSelect parameter points to) into
226** a trigger step. Return a pointer to a TriggerStep structure.
227**
228** The parser calls this routine when it finds a SELECT statement in
229** body of a TRIGGER.
230*/
231TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
danielk1977633ed082002-05-17 00:05:58 +0000232 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000233 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000234
danielk1977633ed082002-05-17 00:05:58 +0000235 pTriggerStep->op = TK_SELECT;
236 pTriggerStep->pSelect = pSelect;
237 pTriggerStep->orconf = OE_Default;
drh4b59ab52002-08-24 18:24:51 +0000238 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000239
danielk1977633ed082002-05-17 00:05:58 +0000240 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000241}
242
drhc977f7f2002-05-21 11:38:11 +0000243/*
244** Build a trigger step out of an INSERT statement. Return a pointer
245** to the new trigger step.
246**
247** The parser calls this routine when it sees an INSERT inside the
248** body of a trigger.
249*/
danielk1977633ed082002-05-17 00:05:58 +0000250TriggerStep *sqliteTriggerInsertStep(
drhc977f7f2002-05-21 11:38:11 +0000251 Token *pTableName, /* Name of the table into which we insert */
252 IdList *pColumn, /* List of columns in pTableName to insert into */
253 ExprList *pEList, /* The VALUE clause: a list of values to be inserted */
254 Select *pSelect, /* A SELECT statement that supplies values */
255 int orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
danielk1977633ed082002-05-17 00:05:58 +0000256){
257 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000258 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000259
danielk1977633ed082002-05-17 00:05:58 +0000260 assert(pEList == 0 || pSelect == 0);
261 assert(pEList != 0 || pSelect != 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000262
danielk1977633ed082002-05-17 00:05:58 +0000263 pTriggerStep->op = TK_INSERT;
264 pTriggerStep->pSelect = pSelect;
265 pTriggerStep->target = *pTableName;
266 pTriggerStep->pIdList = pColumn;
267 pTriggerStep->pExprList = pEList;
268 pTriggerStep->orconf = orconf;
drh4b59ab52002-08-24 18:24:51 +0000269 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000270
danielk1977633ed082002-05-17 00:05:58 +0000271 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000272}
273
drhc977f7f2002-05-21 11:38:11 +0000274/*
275** Construct a trigger step that implements an UPDATE statement and return
276** a pointer to that trigger step. The parser calls this routine when it
277** sees an UPDATE statement inside the body of a CREATE TRIGGER.
278*/
danielk1977633ed082002-05-17 00:05:58 +0000279TriggerStep *sqliteTriggerUpdateStep(
drhc977f7f2002-05-21 11:38:11 +0000280 Token *pTableName, /* Name of the table to be updated */
281 ExprList *pEList, /* The SET clause: list of column and new values */
282 Expr *pWhere, /* The WHERE clause */
283 int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
284){
danielk1977633ed082002-05-17 00:05:58 +0000285 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
drhe4697f52002-05-23 02:09:03 +0000286 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000287
danielk1977633ed082002-05-17 00:05:58 +0000288 pTriggerStep->op = TK_UPDATE;
289 pTriggerStep->target = *pTableName;
290 pTriggerStep->pExprList = pEList;
291 pTriggerStep->pWhere = pWhere;
292 pTriggerStep->orconf = orconf;
drh4b59ab52002-08-24 18:24:51 +0000293 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000294
danielk1977633ed082002-05-17 00:05:58 +0000295 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000296}
297
drhc977f7f2002-05-21 11:38:11 +0000298/*
299** Construct a trigger step that implements a DELETE statement and return
300** a pointer to that trigger step. The parser calls this routine when it
301** sees a DELETE statement inside the body of a CREATE TRIGGER.
302*/
303TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
drhe4697f52002-05-23 02:09:03 +0000304 TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
305 if( pTriggerStep==0 ) return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000306
danielk1977633ed082002-05-17 00:05:58 +0000307 pTriggerStep->op = TK_DELETE;
308 pTriggerStep->target = *pTableName;
309 pTriggerStep->pWhere = pWhere;
310 pTriggerStep->orconf = OE_Default;
drh4b59ab52002-08-24 18:24:51 +0000311 sqlitePersistTriggerStep(pTriggerStep);
danielk1977c3f9bad2002-05-15 08:30:12 +0000312
danielk1977633ed082002-05-17 00:05:58 +0000313 return pTriggerStep;
danielk1977c3f9bad2002-05-15 08:30:12 +0000314}
315
danielk1977633ed082002-05-17 00:05:58 +0000316/*
317** Recursively delete a Trigger structure
318*/
drh1d1f3052002-05-21 13:18:25 +0000319void sqliteDeleteTrigger(Trigger *pTrigger){
drh4b59ab52002-08-24 18:24:51 +0000320 sqliteDeleteTriggerStep(pTrigger->step_list);
danielk1977633ed082002-05-17 00:05:58 +0000321 sqliteFree(pTrigger->name);
322 sqliteFree(pTrigger->table);
323 sqliteExprDelete(pTrigger->pWhen);
324 sqliteIdListDelete(pTrigger->pColumns);
danielk1977633ed082002-05-17 00:05:58 +0000325 sqliteFree(pTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000326}
327
328/*
danielk1977633ed082002-05-17 00:05:58 +0000329 * This function is called to drop a trigger from the database schema.
330 *
331 * This may be called directly from the parser, or from within
332 * sqliteDropTable(). In the latter case the "nested" argument is true.
333 *
334 * Note that this function does not delete the trigger entirely. Instead it
335 * removes it from the internal schema and places it in the trigDrop hash
336 * table. This is so that the trigger can be restored into the database schema
337 * if the transaction is rolled back.
danielk1977c3f9bad2002-05-15 08:30:12 +0000338 */
drhe0bc4042002-06-25 01:09:11 +0000339void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
danielk1977633ed082002-05-17 00:05:58 +0000340 char *zName;
341 Trigger *pTrigger;
342 Table *pTable;
drhe0bc4042002-06-25 01:09:11 +0000343 Vdbe *v;
danielk1977c3f9bad2002-05-15 08:30:12 +0000344
drhed6c8672003-01-12 18:02:16 +0000345 if( sqliteAuthCommand(pParse, "DROP", "TRIGGER") ) return;
danielk1977633ed082002-05-17 00:05:58 +0000346 zName = sqliteStrNDup(pName->z, pName->n);
danielk1977c3f9bad2002-05-15 08:30:12 +0000347
348 /* ensure that the trigger being dropped exists */
danielk1977633ed082002-05-17 00:05:58 +0000349 pTrigger = sqliteHashFind(&(pParse->db->trigHash), zName, pName->n + 1);
350 if( !pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000351 sqliteSetNString(&pParse->zErrMsg, "no such trigger: ", -1,
danielk1977633ed082002-05-17 00:05:58 +0000352 zName, -1, 0);
353 sqliteFree(zName);
danielk1977c3f9bad2002-05-15 08:30:12 +0000354 return;
355 }
drhed6c8672003-01-12 18:02:16 +0000356 pTable = sqliteFindTable(pParse->db, pTrigger->table);
357 assert(pTable);
358 if( sqliteAuthDelete(pParse, SCHEMA_TABLE(pTable->isTemp), 1) ){
359 sqliteFree(zName);
360 return;
361 }
362
danielk1977c3f9bad2002-05-15 08:30:12 +0000363
364 /*
drhe0bc4042002-06-25 01:09:11 +0000365 * If this is not an "explain", then delete the trigger structure.
danielk1977c3f9bad2002-05-15 08:30:12 +0000366 */
danielk1977633ed082002-05-17 00:05:58 +0000367 if( !pParse->explain ){
danielk1977633ed082002-05-17 00:05:58 +0000368 if( pTable->pTrigger == pTrigger ){
369 pTable->pTrigger = pTrigger->pNext;
danielk1977f29ce552002-05-19 23:43:12 +0000370 }else{
danielk1977633ed082002-05-17 00:05:58 +0000371 Trigger *cc = pTable->pTrigger;
372 while( cc ){
373 if( cc->pNext == pTrigger ){
drh9adf9ac2002-05-15 11:44:13 +0000374 cc->pNext = cc->pNext->pNext;
375 break;
376 }
377 cc = cc->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000378 }
379 assert(cc);
380 }
drhe0bc4042002-06-25 01:09:11 +0000381 sqliteHashInsert(&(pParse->db->trigHash), zName, pName->n + 1, NULL);
382 sqliteDeleteTrigger(pTrigger);
danielk1977c3f9bad2002-05-15 08:30:12 +0000383 }
384
drhe0bc4042002-06-25 01:09:11 +0000385 /* Generate code to destroy the database record of the trigger.
386 */
387 if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000388 int base;
389 static VdbeOp dropTrigger[] = {
drhe0bc4042002-06-25 01:09:11 +0000390 { OP_Rewind, 0, ADDR(8), 0},
391 { OP_String, 0, 0, 0}, /* 1 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000392 { OP_MemStore, 1, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000393 { OP_MemLoad, 1, 0, 0}, /* 3 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000394 { OP_Column, 0, 1, 0},
drhe0bc4042002-06-25 01:09:11 +0000395 { OP_Ne, 0, ADDR(7), 0},
danielk1977c3f9bad2002-05-15 08:30:12 +0000396 { OP_Delete, 0, 0, 0},
drhe0bc4042002-06-25 01:09:11 +0000397 { OP_Next, 0, ADDR(3), 0}, /* 7 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000398 };
399
drhcabb0812002-09-14 13:47:32 +0000400 sqliteBeginWriteOperation(pParse, 0, 0);
drhe0bc4042002-06-25 01:09:11 +0000401 sqliteOpenMasterTable(v, pTable->isTemp);
402 base = sqliteVdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger);
403 sqliteVdbeChangeP3(v, base+1, zName, 0);
404 if( !pTable->isTemp ){
405 sqliteChangeCookie(pParse->db, v);
drhdc379452002-05-15 12:45:43 +0000406 }
drhe0bc4042002-06-25 01:09:11 +0000407 sqliteVdbeAddOp(v, OP_Close, 0, 0);
408 sqliteEndWriteOperation(pParse);
danielk1977c3f9bad2002-05-15 08:30:12 +0000409 }
410
danielk1977633ed082002-05-17 00:05:58 +0000411 sqliteFree(zName);
danielk1977c3f9bad2002-05-15 08:30:12 +0000412}
413
drhc977f7f2002-05-21 11:38:11 +0000414/*
415** pEList is the SET clause of an UPDATE statement. Each entry
416** in pEList is of the format <id>=<expr>. If any of the entries
417** in pEList have an <id> which matches an identifier in pIdList,
418** then return TRUE. If pIdList==NULL, then it is considered a
419** wildcard that matches anything. Likewise if pEList==NULL then
420** it matches anything so always return true. Return false only
421** if there is no match.
422*/
423static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
drhad2d8302002-05-24 20:31:36 +0000424 int e;
425 if( !pIdList || !pEList ) return 1;
426 for(e=0; e<pEList->nExpr; e++){
427 if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
danielk1977f29ce552002-05-19 23:43:12 +0000428 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000429 return 0;
430}
431
432/* A global variable that is TRUE if we should always set up temp tables for
433 * for triggers, even if there are no triggers to code. This is used to test
434 * how much overhead the triggers algorithm is causing.
435 *
436 * This flag can be set or cleared using the "trigger_overhead_test" pragma.
437 * The pragma is not documented since it is not really part of the interface
438 * to SQLite, just the test procedure.
439*/
440int always_code_trigger_setup = 0;
441
442/*
443 * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
444 * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
445 * found in the list specified as pTrigger.
446 */
447int sqliteTriggersExist(
drhc977f7f2002-05-21 11:38:11 +0000448 Parse *pParse, /* Used to check for recursive triggers */
449 Trigger *pTrigger, /* A list of triggers associated with a table */
danielk1977633ed082002-05-17 00:05:58 +0000450 int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
451 int tr_tm, /* one of TK_BEFORE, TK_AFTER */
452 int foreach, /* one of TK_ROW or TK_STATEMENT */
drhc977f7f2002-05-21 11:38:11 +0000453 ExprList *pChanges /* Columns that change in an UPDATE statement */
454){
danielk1977633ed082002-05-17 00:05:58 +0000455 Trigger * pTriggerCursor;
danielk1977c3f9bad2002-05-15 08:30:12 +0000456
danielk1977633ed082002-05-17 00:05:58 +0000457 if( always_code_trigger_setup ){
458 return 1;
459 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000460
danielk1977633ed082002-05-17 00:05:58 +0000461 pTriggerCursor = pTrigger;
462 while( pTriggerCursor ){
463 if( pTriggerCursor->op == op &&
464 pTriggerCursor->tr_tm == tr_tm &&
465 pTriggerCursor->foreach == foreach &&
466 checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000467 TriggerStack * ss;
468 ss = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000469 while( ss && ss->pTrigger != pTrigger ){
470 ss = ss->pNext;
471 }
472 if( !ss )return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000473 }
danielk1977633ed082002-05-17 00:05:58 +0000474 pTriggerCursor = pTriggerCursor->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000475 }
476
477 return 0;
478}
479
drhc977f7f2002-05-21 11:38:11 +0000480/*
481** Generate VDBE code for zero or more statements inside the body of a
482** trigger.
483*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000484static int codeTriggerProgram(
drhc977f7f2002-05-21 11:38:11 +0000485 Parse *pParse, /* The parser context */
486 TriggerStep *pStepList, /* List of statements inside the trigger body */
487 int orconfin /* Conflict algorithm. (OE_Abort, etc) */
danielk1977633ed082002-05-17 00:05:58 +0000488){
489 TriggerStep * pTriggerStep = pStepList;
490 int orconf;
danielk1977c3f9bad2002-05-15 08:30:12 +0000491
danielk1977633ed082002-05-17 00:05:58 +0000492 while( pTriggerStep ){
493 int saveNTab = pParse->nTab;
494 orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
495 pParse->trigStack->orconf = orconf;
496 switch( pTriggerStep->op ){
497 case TK_SELECT: {
danielk19776f349032002-06-11 02:25:40 +0000498 Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
499 assert(ss);
500 assert(ss->pSrc);
501 sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
502 sqliteSelectDelete(ss);
danielk1977633ed082002-05-17 00:05:58 +0000503 break;
504 }
505 case TK_UPDATE: {
drhbd5a4512002-05-23 22:07:02 +0000506 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000507 sqliteUpdate(pParse, &pTriggerStep->target,
danielk19776f349032002-06-11 02:25:40 +0000508 sqliteExprListDup(pTriggerStep->pExprList),
509 sqliteExprDup(pTriggerStep->pWhere), orconf);
drhbd5a4512002-05-23 22:07:02 +0000510 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000511 break;
512 }
513 case TK_INSERT: {
514 sqliteInsert(pParse, &pTriggerStep->target,
515 sqliteExprListDup(pTriggerStep->pExprList),
516 sqliteSelectDup(pTriggerStep->pSelect),
517 sqliteIdListDup(pTriggerStep->pIdList), orconf);
518 break;
519 }
520 case TK_DELETE: {
drhbd5a4512002-05-23 22:07:02 +0000521 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000522 sqliteDeleteFrom(pParse, &pTriggerStep->target,
523 sqliteExprDup(pTriggerStep->pWhere));
drhbd5a4512002-05-23 22:07:02 +0000524 sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
danielk1977633ed082002-05-17 00:05:58 +0000525 break;
526 }
527 default:
528 assert(0);
529 }
530 pParse->nTab = saveNTab;
531 pTriggerStep = pTriggerStep->pNext;
532 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000533
danielk1977633ed082002-05-17 00:05:58 +0000534 return 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000535}
536
danielk1977633ed082002-05-17 00:05:58 +0000537/*
538** This is called to code FOR EACH ROW triggers.
539**
540** When the code that this function generates is executed, the following
541** must be true:
drhc977f7f2002-05-21 11:38:11 +0000542**
543** 1. No cursors may be open in the main database. (But newIdx and oldIdx
544** can be indices of cursors in temporary tables. See below.)
545**
danielk1977633ed082002-05-17 00:05:58 +0000546** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
547** a temporary vdbe cursor (index newIdx) must be open and pointing at
548** a row containing values to be substituted for new.* expressions in the
549** trigger program(s).
drhc977f7f2002-05-21 11:38:11 +0000550**
danielk1977633ed082002-05-17 00:05:58 +0000551** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
552** a temporary vdbe cursor (index oldIdx) must be open and pointing at
553** a row containing values to be substituted for old.* expressions in the
554** trigger program(s).
555**
556*/
danielk1977c3f9bad2002-05-15 08:30:12 +0000557int sqliteCodeRowTrigger(
danielk1977633ed082002-05-17 00:05:58 +0000558 Parse *pParse, /* Parse context */
559 int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
560 ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
561 int tr_tm, /* One of TK_BEFORE, TK_AFTER */
562 Table *pTab, /* The table to code triggers from */
563 int newIdx, /* The indice of the "new" row to access */
564 int oldIdx, /* The indice of the "old" row to access */
danielk19776f349032002-06-11 02:25:40 +0000565 int orconf, /* ON CONFLICT policy */
566 int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */
drhc977f7f2002-05-21 11:38:11 +0000567){
danielk1977c3f9bad2002-05-15 08:30:12 +0000568 Trigger * pTrigger;
569 TriggerStack * pTriggerStack;
570
danielk1977c3f9bad2002-05-15 08:30:12 +0000571 assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
572 assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
573
danielk1977633ed082002-05-17 00:05:58 +0000574 assert(newIdx != -1 || oldIdx != -1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000575
danielk1977633ed082002-05-17 00:05:58 +0000576 pTrigger = pTab->pTrigger;
danielk1977f29ce552002-05-19 23:43:12 +0000577 while( pTrigger ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000578 int fire_this = 0;
579
580 /* determine whether we should code this trigger */
danielk1977f29ce552002-05-19 23:43:12 +0000581 if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
582 pTrigger->foreach == TK_ROW ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000583 fire_this = 1;
584 pTriggerStack = pParse->trigStack;
danielk1977f29ce552002-05-19 23:43:12 +0000585 while( pTriggerStack ){
586 if( pTriggerStack->pTrigger == pTrigger ){
587 fire_this = 0;
588 }
drh9adf9ac2002-05-15 11:44:13 +0000589 pTriggerStack = pTriggerStack->pNext;
danielk1977c3f9bad2002-05-15 08:30:12 +0000590 }
danielk1977f29ce552002-05-19 23:43:12 +0000591 if( op == TK_UPDATE && pTrigger->pColumns &&
592 !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
drh9adf9ac2002-05-15 11:44:13 +0000593 fire_this = 0;
danielk1977f29ce552002-05-19 23:43:12 +0000594 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000595 }
596
drhe4697f52002-05-23 02:09:03 +0000597 if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000598 int endTrigger;
drhad3cab52002-05-24 02:04:32 +0000599 SrcList dummyTablist;
danielk1977c3f9bad2002-05-15 08:30:12 +0000600 Expr * whenExpr;
601
drhad3cab52002-05-24 02:04:32 +0000602 dummyTablist.nSrc = 0;
danielk1977c3f9bad2002-05-15 08:30:12 +0000603 dummyTablist.a = 0;
604
605 /* Push an entry on to the trigger stack */
danielk1977c3f9bad2002-05-15 08:30:12 +0000606 pTriggerStack->pTrigger = pTrigger;
danielk1977633ed082002-05-17 00:05:58 +0000607 pTriggerStack->newIdx = newIdx;
608 pTriggerStack->oldIdx = oldIdx;
609 pTriggerStack->pTab = pTab;
danielk1977c3f9bad2002-05-15 08:30:12 +0000610 pTriggerStack->pNext = pParse->trigStack;
danielk19776f349032002-06-11 02:25:40 +0000611 pTriggerStack->ignoreJump = ignoreJump;
danielk1977c3f9bad2002-05-15 08:30:12 +0000612 pParse->trigStack = pTriggerStack;
613
614 /* code the WHEN clause */
615 endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
616 whenExpr = sqliteExprDup(pTrigger->pWhen);
danielk1977f29ce552002-05-19 23:43:12 +0000617 if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000618 pParse->trigStack = pParse->trigStack->pNext;
619 sqliteFree(pTriggerStack);
620 sqliteExprDelete(whenExpr);
621 return 1;
danielk1977c3f9bad2002-05-15 08:30:12 +0000622 }
drhf5905aa2002-05-26 20:54:33 +0000623 sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
danielk1977c3f9bad2002-05-15 08:30:12 +0000624 sqliteExprDelete(whenExpr);
625
danielk1977633ed082002-05-17 00:05:58 +0000626 codeTriggerProgram(pParse, pTrigger->step_list, orconf);
danielk1977c3f9bad2002-05-15 08:30:12 +0000627
628 /* Pop the entry off the trigger stack */
629 pParse->trigStack = pParse->trigStack->pNext;
630 sqliteFree(pTriggerStack);
631
632 sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
633 }
634 pTrigger = pTrigger->pNext;
635 }
636
637 return 0;
638}
639
640/*
danielk1977633ed082002-05-17 00:05:58 +0000641 * This function is called to code ON UPDATE and ON DELETE triggers on
642 * views.
643 *
644 * This function deletes the data pointed at by the pWhere and pChanges
645 * arguments before it completes.
danielk1977c3f9bad2002-05-15 08:30:12 +0000646 */
danielk1977633ed082002-05-17 00:05:58 +0000647void sqliteViewTriggers(
648 Parse *pParse,
649 Table *pTab, /* The view to code triggers on */
650 Expr *pWhere, /* The WHERE clause of the statement causing triggers*/
651 int orconf, /* The ON CONFLICT policy specified as part of the
652 statement causing these triggers */
653 ExprList *pChanges /* If this is an statement causing triggers to fire
654 is an UPDATE, then this list holds the columns
655 to update and the expressions to update them to.
656 See comments for sqliteUpdate(). */
657){
danielk1977c3f9bad2002-05-15 08:30:12 +0000658 int oldIdx = -1;
659 int newIdx = -1;
660 int *aXRef = 0;
661 Vdbe *v;
662 int endOfLoop;
663 int startOfLoop;
664 Select theSelect;
665 Token tblNameToken;
666
667 assert(pTab->pSelect);
668
669 tblNameToken.z = pTab->zName;
670 tblNameToken.n = strlen(pTab->zName);
671
672 theSelect.isDistinct = 0;
673 theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
drhad3cab52002-05-24 02:04:32 +0000674 theSelect.pSrc = sqliteSrcListAppend(0, &tblNameToken);
danielk1977c3f9bad2002-05-15 08:30:12 +0000675 theSelect.pWhere = pWhere; pWhere = 0;
676 theSelect.pGroupBy = 0;
677 theSelect.pHaving = 0;
678 theSelect.pOrderBy = 0;
679 theSelect.op = TK_SELECT; /* ?? */
680 theSelect.pPrior = 0;
681 theSelect.nLimit = -1;
682 theSelect.nOffset = -1;
683 theSelect.zSelect = 0;
684 theSelect.base = 0;
685
686 v = sqliteGetVdbe(pParse);
687 assert(v);
drhcabb0812002-09-14 13:47:32 +0000688 sqliteBeginWriteOperation(pParse, 1, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000689
690 /* Allocate temp tables */
691 oldIdx = pParse->nTab++;
692 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
danielk1977633ed082002-05-17 00:05:58 +0000693 if( pChanges ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000694 newIdx = pParse->nTab++;
695 sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
696 }
697
698 /* Snapshot the view */
danielk1977633ed082002-05-17 00:05:58 +0000699 if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000700 goto trigger_cleanup;
701 }
702
703 /* loop thru the view snapshot, executing triggers for each row */
704 endOfLoop = sqliteVdbeMakeLabel(v);
705 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
706
707 /* Loop thru the view snapshot, executing triggers for each row */
708 startOfLoop = sqliteVdbeCurrentAddr(v);
709
710 /* Build the updated row if required */
danielk1977633ed082002-05-17 00:05:58 +0000711 if( pChanges ){
drh1d1f3052002-05-21 13:18:25 +0000712 int ii;
danielk1977c3f9bad2002-05-15 08:30:12 +0000713
714 aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
715 if( aXRef==0 ) goto trigger_cleanup;
danielk1977633ed082002-05-17 00:05:58 +0000716 for(ii = 0; ii < pTab->nCol; ii++){
danielk1977c3f9bad2002-05-15 08:30:12 +0000717 aXRef[ii] = -1;
danielk1977633ed082002-05-17 00:05:58 +0000718 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000719
720 for(ii=0; ii<pChanges->nExpr; ii++){
721 int jj;
722 if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
danielk1977f29ce552002-05-19 23:43:12 +0000723 pChanges->a[ii].pExpr) ){
drh9adf9ac2002-05-15 11:44:13 +0000724 goto trigger_cleanup;
danielk1977f29ce552002-05-19 23:43:12 +0000725 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000726
727 if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
drh9adf9ac2002-05-15 11:44:13 +0000728 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000729
730 for(jj=0; jj<pTab->nCol; jj++){
drh9adf9ac2002-05-15 11:44:13 +0000731 if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
732 aXRef[jj] = ii;
733 break;
734 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000735 }
736 if( jj>=pTab->nCol ){
drh9adf9ac2002-05-15 11:44:13 +0000737 sqliteSetString(&pParse->zErrMsg, "no such column: ",
738 pChanges->a[ii].zName, 0);
739 pParse->nErr++;
740 goto trigger_cleanup;
danielk1977c3f9bad2002-05-15 08:30:12 +0000741 }
742 }
743
744 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
745
danielk1977633ed082002-05-17 00:05:58 +0000746 for(ii = 0; ii<pTab->nCol; ii++){
747 if( aXRef[ii] < 0 ){
drh9adf9ac2002-05-15 11:44:13 +0000748 sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
danielk1977f29ce552002-05-19 23:43:12 +0000749 }else{
drh9adf9ac2002-05-15 11:44:13 +0000750 sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
danielk1977633ed082002-05-17 00:05:58 +0000751 }
752 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000753
754 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
755 sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
756 sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
757
758 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
danielk19776f349032002-06-11 02:25:40 +0000759 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000760 sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
danielk19776f349032002-06-11 02:25:40 +0000761 pTab, newIdx, oldIdx, orconf, endOfLoop);
danielk1977f29ce552002-05-19 23:43:12 +0000762 }else{
danielk1977c3f9bad2002-05-15 08:30:12 +0000763 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000764 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000765 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
danielk19776f349032002-06-11 02:25:40 +0000766 orconf, endOfLoop);
danielk1977c3f9bad2002-05-15 08:30:12 +0000767 }
768
769 sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
770
771 sqliteVdbeResolveLabel(v, endOfLoop);
772 sqliteEndWriteOperation(pParse);
773
774trigger_cleanup:
775 sqliteFree(aXRef);
776 sqliteExprListDelete(pChanges);
777 sqliteExprDelete(pWhere);
778 sqliteExprListDelete(theSelect.pEList);
drhad3cab52002-05-24 02:04:32 +0000779 sqliteSrcListDelete(theSelect.pSrc);
danielk1977c3f9bad2002-05-15 08:30:12 +0000780 sqliteExprDelete(theSelect.pWhere);
781 return;
782}