xref: /sqlite-3.40.0/src/trigger.c (revision 0be9df07)
1c3f9bad2Sdanielk1977 /*
2633ed08dSdanielk1977 **
3633ed08dSdanielk1977 ** The author disclaims copyright to this source code.  In place of
4633ed08dSdanielk1977 ** a legal notice, here is a blessing:
5633ed08dSdanielk1977 **
6633ed08dSdanielk1977 **    May you do good and not evil.
7633ed08dSdanielk1977 **    May you find forgiveness for yourself and forgive others.
8633ed08dSdanielk1977 **    May you share freely, never taking more than you give.
9633ed08dSdanielk1977 **
10633ed08dSdanielk1977 *************************************************************************
11633ed08dSdanielk1977 *
12c3f9bad2Sdanielk1977 */
13c3f9bad2Sdanielk1977 #include "sqliteInt.h"
149adf9ac4Sdrh 
15c3f9bad2Sdanielk1977 /*
164b59ab5eSdrh ** Delete a linked list of TriggerStep structures.
174b59ab5eSdrh */
184b59ab5eSdrh static void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
194b59ab5eSdrh   while( pTriggerStep ){
204b59ab5eSdrh     TriggerStep * pTmp = pTriggerStep;
214b59ab5eSdrh     pTriggerStep = pTriggerStep->pNext;
224b59ab5eSdrh 
238c74a8caSdrh     if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
244b59ab5eSdrh     sqliteExprDelete(pTmp->pWhere);
254b59ab5eSdrh     sqliteExprListDelete(pTmp->pExprList);
264b59ab5eSdrh     sqliteSelectDelete(pTmp->pSelect);
274b59ab5eSdrh     sqliteIdListDelete(pTmp->pIdList);
284b59ab5eSdrh 
294b59ab5eSdrh     sqliteFree(pTmp);
304b59ab5eSdrh   }
314b59ab5eSdrh }
324b59ab5eSdrh 
334b59ab5eSdrh /*
34633ed08dSdanielk1977 ** This is called by the parser when it sees a CREATE TRIGGER statement. See
35633ed08dSdanielk1977 ** comments surrounding struct Trigger in sqliteInt.h for a description of
36633ed08dSdanielk1977 ** how triggers are stored.
37c3f9bad2Sdanielk1977 */
389adf9ac4Sdrh void sqliteCreateTrigger(
39c3f9bad2Sdanielk1977   Parse *pParse,      /* The parse context of the CREATE TRIGGER statement */
40633ed08dSdanielk1977   Token *pName,       /* The name of the trigger */
41d702fccbSdanielk1977   int tr_tm,          /* One of TK_BEFORE, TK_AFTER , TK_INSTEAD */
42c3f9bad2Sdanielk1977   int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
43633ed08dSdanielk1977   IdList *pColumns,   /* column list if this is an UPDATE OF trigger */
44d24cc427Sdrh   SrcList *pTableName,/* The name of the table/view the trigger applies to */
45c3f9bad2Sdanielk1977   int foreach,        /* One of TK_ROW or TK_STATEMENT */
46c3f9bad2Sdanielk1977   Expr *pWhen,        /* WHEN clause */
47633ed08dSdanielk1977   TriggerStep *pStepList, /* The triggered program */
484b59ab5eSdrh   Token *pAll             /* Token that describes the complete CREATE TRIGGER */
499adf9ac4Sdrh ){
50c3f9bad2Sdanielk1977   Trigger *nt;
51c3f9bad2Sdanielk1977   Table   *tab;
52e5f9c644Sdrh   char *zName = 0;    /* Name of the trigger */
53d24cc427Sdrh   sqlite *db = pParse->db;
54ed6c8671Sdrh 
55c3f9bad2Sdanielk1977   /* Check that:
569adf9ac4Sdrh   ** 1. the trigger name does not already exist.
579adf9ac4Sdrh   ** 2. the table (or view) does exist.
58d702fccbSdanielk1977   ** 3. that we are not trying to create a trigger on the sqlite_master table
59d702fccbSdanielk1977   ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
60d702fccbSdanielk1977   ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
61c3f9bad2Sdanielk1977   */
62d24cc427Sdrh   if( sqlite_malloc_failed ) goto trigger_cleanup;
63d24cc427Sdrh   assert( pTableName->nSrc==1 );
64812d7a21Sdrh   tab = sqliteSrcListLookup(pParse, pTableName);
65d24cc427Sdrh   if( !tab ){
66d24cc427Sdrh     goto trigger_cleanup;
67d24cc427Sdrh   }
68d24cc427Sdrh   if( tab->iDb>=2 ){
69d24cc427Sdrh     sqliteSetString(&pParse->zErrMsg, "triggers may not be added to "
70d24cc427Sdrh        "auxiliary database \"", db->aDb[tab->iDb].zName, "\"", 0);
71d24cc427Sdrh     pParse->nErr++;
72d24cc427Sdrh     goto trigger_cleanup;
73d24cc427Sdrh   }
74d24cc427Sdrh 
75e5f9c644Sdrh   zName = sqliteStrNDup(pName->z, pName->n);
76d24cc427Sdrh   if( sqliteHashFind(&(db->aDb[tab->iDb].trigHash), zName,pName->n+1) ){
77c3f9bad2Sdanielk1977     sqliteSetNString(&pParse->zErrMsg, "trigger ", -1,
78633ed08dSdanielk1977         pName->z, pName->n, " already exists", -1, 0);
79c3f9bad2Sdanielk1977     pParse->nErr++;
80c3f9bad2Sdanielk1977     goto trigger_cleanup;
81c3f9bad2Sdanielk1977   }
82d24cc427Sdrh   if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
83d24cc427Sdrh     sqliteSetString(&pParse->zErrMsg,"cannot create trigger on system table",0);
84e0bc4048Sdrh     pParse->nErr++;
85e0bc4048Sdrh     goto trigger_cleanup;
86e0bc4048Sdrh   }
87d702fccbSdanielk1977   if( tab->pSelect && tr_tm != TK_INSTEAD ){
880951d703Sdrh     sqliteSetString(&pParse->zErrMsg, "cannot create ",
89d24cc427Sdrh         (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", " trigger on view: ",
90d24cc427Sdrh         pTableName->a[0].zName, 0);
91d702fccbSdanielk1977     goto trigger_cleanup;
92d702fccbSdanielk1977   }
93d702fccbSdanielk1977   if( !tab->pSelect && tr_tm == TK_INSTEAD ){
940951d703Sdrh     sqliteSetString(&pParse->zErrMsg, "cannot create INSTEAD OF",
950951d703Sdrh         " trigger on table: ", pTableName->a[0].zName, 0);
96d702fccbSdanielk1977     goto trigger_cleanup;
97d702fccbSdanielk1977   }
98e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
99e5f9c644Sdrh   {
100e5f9c644Sdrh     int code = SQLITE_CREATE_TRIGGER;
101d24cc427Sdrh     if( tab->iDb==1 ) code = SQLITE_CREATE_TEMP_TRIGGER;
102e5f9c644Sdrh     if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){
103ed6c8671Sdrh       goto trigger_cleanup;
104ed6c8671Sdrh     }
105d24cc427Sdrh     if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){
10677ad4e41Sdrh       goto trigger_cleanup;
10777ad4e41Sdrh     }
108d702fccbSdanielk1977   }
109e5f9c644Sdrh #endif
110d702fccbSdanielk1977 
111d702fccbSdanielk1977   if (tr_tm == TK_INSTEAD){
112d702fccbSdanielk1977     tr_tm = TK_BEFORE;
113c3f9bad2Sdanielk1977   }
114c3f9bad2Sdanielk1977 
115c3f9bad2Sdanielk1977   /* Build the Trigger object */
116c3f9bad2Sdanielk1977   nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
117e4697f5eSdrh   if( nt==0 ) goto trigger_cleanup;
118e5f9c644Sdrh   nt->name = zName;
119e5f9c644Sdrh   zName = 0;
120d24cc427Sdrh   nt->table = sqliteStrDup(pTableName->a[0].zName);
121e4697f5eSdrh   if( sqlite_malloc_failed ) goto trigger_cleanup;
122d24cc427Sdrh   nt->iDb = tab->iDb;
123c3f9bad2Sdanielk1977   nt->op = op;
124c3f9bad2Sdanielk1977   nt->tr_tm = tr_tm;
1254b59ab5eSdrh   nt->pWhen = sqliteExprDup(pWhen);
1264b59ab5eSdrh   sqliteExprDelete(pWhen);
1274b59ab5eSdrh   nt->pColumns = sqliteIdListDup(pColumns);
1284b59ab5eSdrh   sqliteIdListDelete(pColumns);
129c3f9bad2Sdanielk1977   nt->foreach = foreach;
130633ed08dSdanielk1977   nt->step_list = pStepList;
131c3f9bad2Sdanielk1977 
132c3f9bad2Sdanielk1977   /* if we are not initializing, and this trigger is not on a TEMP table,
1339adf9ac4Sdrh   ** build the sqlite_master entry
1349adf9ac4Sdrh   */
135e0bc4048Sdrh   if( !pParse->initFlag ){
136c977f7f5Sdrh     static VdbeOp insertTrig[] = {
137c977f7f5Sdrh       { OP_NewRecno,   0, 0,  0          },
138c977f7f5Sdrh       { OP_String,     0, 0,  "trigger"  },
139e0bc4048Sdrh       { OP_String,     0, 0,  0          },  /* 2: trigger name */
140e0bc4048Sdrh       { OP_String,     0, 0,  0          },  /* 3: table name */
141c977f7f5Sdrh       { OP_Integer,    0, 0,  0          },
142e0bc4048Sdrh       { OP_String,     0, 0,  0          },  /* 5: SQL */
143c977f7f5Sdrh       { OP_MakeRecord, 5, 0,  0          },
144c977f7f5Sdrh       { OP_PutIntKey,  0, 0,  0          },
145c977f7f5Sdrh     };
146c977f7f5Sdrh     int addr;
147c977f7f5Sdrh     Vdbe *v;
148c3f9bad2Sdanielk1977 
149c3f9bad2Sdanielk1977     /* Make an entry in the sqlite_master table */
150c977f7f5Sdrh     v = sqliteGetVdbe(pParse);
151e4697f5eSdrh     if( v==0 ) goto trigger_cleanup;
152cabb0819Sdrh     sqliteBeginWriteOperation(pParse, 0, 0);
153d24cc427Sdrh     sqliteOpenMasterTable(v, tab->iDb);
154c977f7f5Sdrh     addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
155d24cc427Sdrh     sqliteVdbeChangeP3(v, addr, tab->iDb ? TEMP_MASTER_NAME : MASTER_NAME,
156e0bc4048Sdrh                        P3_STATIC);
157e0bc4048Sdrh     sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
158e0bc4048Sdrh     sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
1594b59ab5eSdrh     sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
160d24cc427Sdrh     if( tab->iDb==0 ){
161d24cc427Sdrh       sqliteChangeCookie(db, v);
162e0bc4048Sdrh     }
163e0bc4048Sdrh     sqliteVdbeAddOp(v, OP_Close, 0, 0);
164c3f9bad2Sdanielk1977     sqliteEndWriteOperation(pParse);
165c3f9bad2Sdanielk1977   }
166c3f9bad2Sdanielk1977 
167c3f9bad2Sdanielk1977   if( !pParse->explain ){
168c3f9bad2Sdanielk1977     /* Stick it in the hash-table */
169d24cc427Sdrh     sqliteHashInsert(&(db->aDb[nt->iDb].trigHash), nt->name, pName->n + 1, nt);
170c3f9bad2Sdanielk1977 
171c3f9bad2Sdanielk1977     /* Attach it to the table object */
172c3f9bad2Sdanielk1977     nt->pNext = tab->pTrigger;
173c3f9bad2Sdanielk1977     tab->pTrigger = nt;
174*0be9df07Sdrh     sqliteSrcListDelete(pTableName);
175c3f9bad2Sdanielk1977     return;
176c3f9bad2Sdanielk1977   }else{
177c3f9bad2Sdanielk1977     sqliteFree(nt->name);
178c3f9bad2Sdanielk1977     sqliteFree(nt->table);
179c3f9bad2Sdanielk1977     sqliteFree(nt);
180c3f9bad2Sdanielk1977   }
181c3f9bad2Sdanielk1977 
182c3f9bad2Sdanielk1977 trigger_cleanup:
183c3f9bad2Sdanielk1977 
184e5f9c644Sdrh   sqliteFree(zName);
185d24cc427Sdrh   sqliteSrcListDelete(pTableName);
186633ed08dSdanielk1977   sqliteIdListDelete(pColumns);
187c3f9bad2Sdanielk1977   sqliteExprDelete(pWhen);
1884b59ab5eSdrh   sqliteDeleteTriggerStep(pStepList);
189c3f9bad2Sdanielk1977 }
1904b59ab5eSdrh 
1914b59ab5eSdrh /*
1924b59ab5eSdrh ** Make a copy of all components of the given trigger step.  This has
1934b59ab5eSdrh ** the effect of copying all Expr.token.z values into memory obtained
1944b59ab5eSdrh ** from sqliteMalloc().  As initially created, the Expr.token.z values
1954b59ab5eSdrh ** all point to the input string that was fed to the parser.  But that
1964b59ab5eSdrh ** string is ephemeral - it will go away as soon as the sqlite_exec()
1974b59ab5eSdrh ** call that started the parser exits.  This routine makes a persistent
1984b59ab5eSdrh ** copy of all the Expr.token.z strings so that the TriggerStep structure
1994b59ab5eSdrh ** will be valid even after the sqlite_exec() call returns.
2004b59ab5eSdrh */
2014b59ab5eSdrh static void sqlitePersistTriggerStep(TriggerStep *p){
2024b59ab5eSdrh   if( p->target.z ){
2034b59ab5eSdrh     p->target.z = sqliteStrNDup(p->target.z, p->target.n);
2044b59ab5eSdrh     p->target.dyn = 1;
2054b59ab5eSdrh   }
2064b59ab5eSdrh   if( p->pSelect ){
2074b59ab5eSdrh     Select *pNew = sqliteSelectDup(p->pSelect);
2084b59ab5eSdrh     sqliteSelectDelete(p->pSelect);
2094b59ab5eSdrh     p->pSelect = pNew;
2104b59ab5eSdrh   }
2114b59ab5eSdrh   if( p->pWhere ){
2124b59ab5eSdrh     Expr *pNew = sqliteExprDup(p->pWhere);
2134b59ab5eSdrh     sqliteExprDelete(p->pWhere);
2144b59ab5eSdrh     p->pWhere = pNew;
2154b59ab5eSdrh   }
2164b59ab5eSdrh   if( p->pExprList ){
2174b59ab5eSdrh     ExprList *pNew = sqliteExprListDup(p->pExprList);
2184b59ab5eSdrh     sqliteExprListDelete(p->pExprList);
2194b59ab5eSdrh     p->pExprList = pNew;
2204b59ab5eSdrh   }
2214b59ab5eSdrh   if( p->pIdList ){
2224b59ab5eSdrh     IdList *pNew = sqliteIdListDup(p->pIdList);
2234b59ab5eSdrh     sqliteIdListDelete(p->pIdList);
2244b59ab5eSdrh     p->pIdList = pNew;
225c3f9bad2Sdanielk1977   }
226c3f9bad2Sdanielk1977 }
227c3f9bad2Sdanielk1977 
228c977f7f5Sdrh /*
229c977f7f5Sdrh ** Turn a SELECT statement (that the pSelect parameter points to) into
230c977f7f5Sdrh ** a trigger step.  Return a pointer to a TriggerStep structure.
231c977f7f5Sdrh **
232c977f7f5Sdrh ** The parser calls this routine when it finds a SELECT statement in
233c977f7f5Sdrh ** body of a TRIGGER.
234c977f7f5Sdrh */
235c977f7f5Sdrh TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
236633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
237e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
238c3f9bad2Sdanielk1977 
239633ed08dSdanielk1977   pTriggerStep->op = TK_SELECT;
240633ed08dSdanielk1977   pTriggerStep->pSelect = pSelect;
241633ed08dSdanielk1977   pTriggerStep->orconf = OE_Default;
2424b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
243c3f9bad2Sdanielk1977 
244633ed08dSdanielk1977   return pTriggerStep;
245c3f9bad2Sdanielk1977 }
246c3f9bad2Sdanielk1977 
247c977f7f5Sdrh /*
248c977f7f5Sdrh ** Build a trigger step out of an INSERT statement.  Return a pointer
249c977f7f5Sdrh ** to the new trigger step.
250c977f7f5Sdrh **
251c977f7f5Sdrh ** The parser calls this routine when it sees an INSERT inside the
252c977f7f5Sdrh ** body of a trigger.
253c977f7f5Sdrh */
254633ed08dSdanielk1977 TriggerStep *sqliteTriggerInsertStep(
255c977f7f5Sdrh   Token *pTableName,  /* Name of the table into which we insert */
256c977f7f5Sdrh   IdList *pColumn,    /* List of columns in pTableName to insert into */
257c977f7f5Sdrh   ExprList *pEList,   /* The VALUE clause: a list of values to be inserted */
258c977f7f5Sdrh   Select *pSelect,    /* A SELECT statement that supplies values */
259c977f7f5Sdrh   int orconf          /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
260633ed08dSdanielk1977 ){
261633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
262e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
263c3f9bad2Sdanielk1977 
264633ed08dSdanielk1977   assert(pEList == 0 || pSelect == 0);
265633ed08dSdanielk1977   assert(pEList != 0 || pSelect != 0);
266c3f9bad2Sdanielk1977 
267633ed08dSdanielk1977   pTriggerStep->op = TK_INSERT;
268633ed08dSdanielk1977   pTriggerStep->pSelect = pSelect;
269633ed08dSdanielk1977   pTriggerStep->target  = *pTableName;
270633ed08dSdanielk1977   pTriggerStep->pIdList = pColumn;
271633ed08dSdanielk1977   pTriggerStep->pExprList = pEList;
272633ed08dSdanielk1977   pTriggerStep->orconf = orconf;
2734b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
274c3f9bad2Sdanielk1977 
275633ed08dSdanielk1977   return pTriggerStep;
276c3f9bad2Sdanielk1977 }
277c3f9bad2Sdanielk1977 
278c977f7f5Sdrh /*
279c977f7f5Sdrh ** Construct a trigger step that implements an UPDATE statement and return
280c977f7f5Sdrh ** a pointer to that trigger step.  The parser calls this routine when it
281c977f7f5Sdrh ** sees an UPDATE statement inside the body of a CREATE TRIGGER.
282c977f7f5Sdrh */
283633ed08dSdanielk1977 TriggerStep *sqliteTriggerUpdateStep(
284c977f7f5Sdrh   Token *pTableName,   /* Name of the table to be updated */
285c977f7f5Sdrh   ExprList *pEList,    /* The SET clause: list of column and new values */
286c977f7f5Sdrh   Expr *pWhere,        /* The WHERE clause */
287c977f7f5Sdrh   int orconf           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
288c977f7f5Sdrh ){
289633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
290e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
291c3f9bad2Sdanielk1977 
292633ed08dSdanielk1977   pTriggerStep->op = TK_UPDATE;
293633ed08dSdanielk1977   pTriggerStep->target  = *pTableName;
294633ed08dSdanielk1977   pTriggerStep->pExprList = pEList;
295633ed08dSdanielk1977   pTriggerStep->pWhere = pWhere;
296633ed08dSdanielk1977   pTriggerStep->orconf = orconf;
2974b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
298c3f9bad2Sdanielk1977 
299633ed08dSdanielk1977   return pTriggerStep;
300c3f9bad2Sdanielk1977 }
301c3f9bad2Sdanielk1977 
302c977f7f5Sdrh /*
303c977f7f5Sdrh ** Construct a trigger step that implements a DELETE statement and return
304c977f7f5Sdrh ** a pointer to that trigger step.  The parser calls this routine when it
305c977f7f5Sdrh ** sees a DELETE statement inside the body of a CREATE TRIGGER.
306c977f7f5Sdrh */
307c977f7f5Sdrh TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
308633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
309e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
310c3f9bad2Sdanielk1977 
311633ed08dSdanielk1977   pTriggerStep->op = TK_DELETE;
312633ed08dSdanielk1977   pTriggerStep->target  = *pTableName;
313633ed08dSdanielk1977   pTriggerStep->pWhere = pWhere;
314633ed08dSdanielk1977   pTriggerStep->orconf = OE_Default;
3154b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
316c3f9bad2Sdanielk1977 
317633ed08dSdanielk1977   return pTriggerStep;
318c3f9bad2Sdanielk1977 }
319c3f9bad2Sdanielk1977 
320c3f9bad2Sdanielk1977 /*
321633ed08dSdanielk1977 ** Recursively delete a Trigger structure
322c3f9bad2Sdanielk1977 */
3231d1f3055Sdrh void sqliteDeleteTrigger(Trigger *pTrigger){
3244b59ab5eSdrh   sqliteDeleteTriggerStep(pTrigger->step_list);
325633ed08dSdanielk1977   sqliteFree(pTrigger->name);
326633ed08dSdanielk1977   sqliteFree(pTrigger->table);
327633ed08dSdanielk1977   sqliteExprDelete(pTrigger->pWhen);
328633ed08dSdanielk1977   sqliteIdListDelete(pTrigger->pColumns);
329633ed08dSdanielk1977   sqliteFree(pTrigger);
330633ed08dSdanielk1977 }
331633ed08dSdanielk1977 
332633ed08dSdanielk1977 /*
333633ed08dSdanielk1977  * This function is called to drop a trigger from the database schema.
334633ed08dSdanielk1977  *
335633ed08dSdanielk1977  * This may be called directly from the parser, or from within
336633ed08dSdanielk1977  * sqliteDropTable(). In the latter case the "nested" argument is true.
337633ed08dSdanielk1977  *
338633ed08dSdanielk1977  * Note that this function does not delete the trigger entirely. Instead it
339633ed08dSdanielk1977  * removes it from the internal schema and places it in the trigDrop hash
340633ed08dSdanielk1977  * table. This is so that the trigger can be restored into the database schema
341633ed08dSdanielk1977  * if the transaction is rolled back.
342633ed08dSdanielk1977  */
343d24cc427Sdrh void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
344633ed08dSdanielk1977   Trigger *pTrigger;
345633ed08dSdanielk1977   Table   *pTable;
346e0bc4048Sdrh   Vdbe *v;
347d24cc427Sdrh   int i;
348d24cc427Sdrh   const char *zDb;
349d24cc427Sdrh   const char *zName;
350d24cc427Sdrh   int nName;
351d24cc427Sdrh   sqlite *db = pParse->db;
352633ed08dSdanielk1977 
353d24cc427Sdrh   if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
354d24cc427Sdrh   assert( pName->nSrc==1 );
355d24cc427Sdrh   zDb = pName->a[0].zDatabase;
356d24cc427Sdrh   zName = pName->a[0].zName;
357d24cc427Sdrh   nName = strlen(zName);
358d24cc427Sdrh   for(i=0; i<db->nDb; i++){
359812d7a21Sdrh     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
360812d7a21Sdrh     if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
361812d7a21Sdrh     pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
362d24cc427Sdrh     if( pTrigger ) break;
363c3f9bad2Sdanielk1977   }
364d24cc427Sdrh   if( !pTrigger ){
365d24cc427Sdrh     sqliteSetString(&pParse->zErrMsg, "no such trigger: ", zName, 0);
366d24cc427Sdrh     goto drop_trigger_cleanup;
367d24cc427Sdrh   }
368d24cc427Sdrh   assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb );
369d24cc427Sdrh   if( pTrigger->iDb>=2 ){
370d24cc427Sdrh     sqliteSetString(&pParse->zErrMsg, "triggers may not be removed from "
371d24cc427Sdrh        "auxiliary database \"", db->aDb[pTrigger->iDb].zName, "\"", 0);
372d24cc427Sdrh     pParse->nErr++;
373d24cc427Sdrh     goto drop_trigger_cleanup;
374d24cc427Sdrh   }
375d24cc427Sdrh   pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName);
376ed6c8671Sdrh   assert(pTable);
377d24cc427Sdrh   assert( pTable->iDb==pTrigger->iDb );
378e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
379e5f9c644Sdrh   {
380e5f9c644Sdrh     int code = SQLITE_DROP_TRIGGER;
381d24cc427Sdrh     if( pTable->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
382e5f9c644Sdrh     if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) ||
383d24cc427Sdrh       sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0) ){
384*0be9df07Sdrh       goto drop_trigger_cleanup;
385ed6c8671Sdrh     }
386e5f9c644Sdrh   }
387e5f9c644Sdrh #endif
388c3f9bad2Sdanielk1977 
389c3f9bad2Sdanielk1977   /*
390e0bc4048Sdrh    * If this is not an "explain", then delete the trigger structure.
391c3f9bad2Sdanielk1977    */
392c3f9bad2Sdanielk1977   if( !pParse->explain ){
393633ed08dSdanielk1977     if( pTable->pTrigger == pTrigger ){
394633ed08dSdanielk1977       pTable->pTrigger = pTrigger->pNext;
395633ed08dSdanielk1977     }else{
396633ed08dSdanielk1977       Trigger *cc = pTable->pTrigger;
397c3f9bad2Sdanielk1977       while( cc ){
398633ed08dSdanielk1977         if( cc->pNext == pTrigger ){
399c3f9bad2Sdanielk1977           cc->pNext = cc->pNext->pNext;
400c3f9bad2Sdanielk1977           break;
401c3f9bad2Sdanielk1977         }
402c3f9bad2Sdanielk1977         cc = cc->pNext;
403c3f9bad2Sdanielk1977       }
404c3f9bad2Sdanielk1977       assert(cc);
405c3f9bad2Sdanielk1977     }
406d24cc427Sdrh     sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
407e0bc4048Sdrh     sqliteDeleteTrigger(pTrigger);
408c3f9bad2Sdanielk1977   }
409c3f9bad2Sdanielk1977 
410e0bc4048Sdrh   /* Generate code to destroy the database record of the trigger.
411e0bc4048Sdrh   */
412e0bc4048Sdrh   if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
413c3f9bad2Sdanielk1977     int base;
414c3f9bad2Sdanielk1977     static VdbeOp dropTrigger[] = {
415e0bc4048Sdrh       { OP_Rewind,     0, ADDR(8),  0},
416e0bc4048Sdrh       { OP_String,     0, 0,        0}, /* 1 */
417c3f9bad2Sdanielk1977       { OP_MemStore,   1, 1,        0},
418e0bc4048Sdrh       { OP_MemLoad,    1, 0,        0}, /* 3 */
419c3f9bad2Sdanielk1977       { OP_Column,     0, 1,        0},
420e0bc4048Sdrh       { OP_Ne,         0, ADDR(7),  0},
421c3f9bad2Sdanielk1977       { OP_Delete,     0, 0,        0},
422e0bc4048Sdrh       { OP_Next,       0, ADDR(3),  0}, /* 7 */
423c3f9bad2Sdanielk1977     };
424c3f9bad2Sdanielk1977 
425cabb0819Sdrh     sqliteBeginWriteOperation(pParse, 0, 0);
426d24cc427Sdrh     sqliteOpenMasterTable(v, pTable->iDb);
427e0bc4048Sdrh     base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
428e0bc4048Sdrh     sqliteVdbeChangeP3(v, base+1, zName, 0);
429d24cc427Sdrh     if( pTable->iDb==0 ){
430d24cc427Sdrh       sqliteChangeCookie(db, v);
431dc379456Sdrh     }
432e0bc4048Sdrh     sqliteVdbeAddOp(v, OP_Close, 0, 0);
433c3f9bad2Sdanielk1977     sqliteEndWriteOperation(pParse);
434c3f9bad2Sdanielk1977   }
435c3f9bad2Sdanielk1977 
436d24cc427Sdrh drop_trigger_cleanup:
437d24cc427Sdrh   sqliteSrcListDelete(pName);
438c3f9bad2Sdanielk1977 }
439c3f9bad2Sdanielk1977 
440c977f7f5Sdrh /*
441c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement.  Each entry
442c977f7f5Sdrh ** in pEList is of the format <id>=<expr>.  If any of the entries
443c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList,
444c977f7f5Sdrh ** then return TRUE.  If pIdList==NULL, then it is considered a
445c977f7f5Sdrh ** wildcard that matches anything.  Likewise if pEList==NULL then
446c977f7f5Sdrh ** it matches anything so always return true.  Return false only
447c977f7f5Sdrh ** if there is no match.
448c977f7f5Sdrh */
449c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
450ad2d8307Sdrh   int e;
451ad2d8307Sdrh   if( !pIdList || !pEList ) return 1;
452f29ce559Sdanielk1977   for(e=0; e<pEList->nExpr; e++){
453ad2d8307Sdrh     if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
454f29ce559Sdanielk1977   }
455c3f9bad2Sdanielk1977   return 0;
456c3f9bad2Sdanielk1977 }
457c3f9bad2Sdanielk1977 
458c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for
459c3f9bad2Sdanielk1977  * for triggers, even if there are no triggers to code. This is used to test
460c3f9bad2Sdanielk1977  * how much overhead the triggers algorithm is causing.
461c3f9bad2Sdanielk1977  *
462c3f9bad2Sdanielk1977  * This flag can be set or cleared using the "trigger_overhead_test" pragma.
463c3f9bad2Sdanielk1977  * The pragma is not documented since it is not really part of the interface
464c3f9bad2Sdanielk1977  * to SQLite, just the test procedure.
465c3f9bad2Sdanielk1977 */
466c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0;
467c3f9bad2Sdanielk1977 
468c3f9bad2Sdanielk1977 /*
469c3f9bad2Sdanielk1977  * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
470c3f9bad2Sdanielk1977  * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
471c3f9bad2Sdanielk1977  * found in the list specified as pTrigger.
472c3f9bad2Sdanielk1977  */
473c3f9bad2Sdanielk1977 int sqliteTriggersExist(
474c977f7f5Sdrh   Parse *pParse,          /* Used to check for recursive triggers */
475c977f7f5Sdrh   Trigger *pTrigger,      /* A list of triggers associated with a table */
476c3f9bad2Sdanielk1977   int op,                 /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
477c3f9bad2Sdanielk1977   int tr_tm,              /* one of TK_BEFORE, TK_AFTER */
478c3f9bad2Sdanielk1977   int foreach,            /* one of TK_ROW or TK_STATEMENT */
479c977f7f5Sdrh   ExprList *pChanges      /* Columns that change in an UPDATE statement */
480c977f7f5Sdrh ){
481633ed08dSdanielk1977   Trigger * pTriggerCursor;
482c3f9bad2Sdanielk1977 
483633ed08dSdanielk1977   if( always_code_trigger_setup ){
484633ed08dSdanielk1977     return 1;
485633ed08dSdanielk1977   }
486c3f9bad2Sdanielk1977 
487633ed08dSdanielk1977   pTriggerCursor = pTrigger;
488633ed08dSdanielk1977   while( pTriggerCursor ){
489633ed08dSdanielk1977     if( pTriggerCursor->op == op &&
490633ed08dSdanielk1977 	pTriggerCursor->tr_tm == tr_tm &&
491633ed08dSdanielk1977 	pTriggerCursor->foreach == foreach &&
492633ed08dSdanielk1977 	checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
493c3f9bad2Sdanielk1977       TriggerStack * ss;
494c3f9bad2Sdanielk1977       ss = pParse->trigStack;
495f29ce559Sdanielk1977       while( ss && ss->pTrigger != pTrigger ){
496f29ce559Sdanielk1977 	ss = ss->pNext;
497f29ce559Sdanielk1977       }
498c3f9bad2Sdanielk1977       if( !ss )return 1;
499c3f9bad2Sdanielk1977     }
500633ed08dSdanielk1977     pTriggerCursor = pTriggerCursor->pNext;
501c3f9bad2Sdanielk1977   }
502c3f9bad2Sdanielk1977 
503c3f9bad2Sdanielk1977   return 0;
504c3f9bad2Sdanielk1977 }
505c3f9bad2Sdanielk1977 
506c977f7f5Sdrh /*
507c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a
508c977f7f5Sdrh ** trigger.
509c977f7f5Sdrh */
510c3f9bad2Sdanielk1977 static int codeTriggerProgram(
511c977f7f5Sdrh   Parse *pParse,            /* The parser context */
512c977f7f5Sdrh   TriggerStep *pStepList,   /* List of statements inside the trigger body */
513c977f7f5Sdrh   int orconfin              /* Conflict algorithm. (OE_Abort, etc) */
514633ed08dSdanielk1977 ){
515633ed08dSdanielk1977   TriggerStep * pTriggerStep = pStepList;
516c3f9bad2Sdanielk1977   int orconf;
517c3f9bad2Sdanielk1977 
518633ed08dSdanielk1977   while( pTriggerStep ){
519c3f9bad2Sdanielk1977     int saveNTab = pParse->nTab;
520633ed08dSdanielk1977     orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
521c3f9bad2Sdanielk1977     pParse->trigStack->orconf = orconf;
522633ed08dSdanielk1977     switch( pTriggerStep->op ){
523c3f9bad2Sdanielk1977       case TK_SELECT: {
5246f34903eSdanielk1977 	Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
5256f34903eSdanielk1977 	assert(ss);
5266f34903eSdanielk1977 	assert(ss->pSrc);
5276f34903eSdanielk1977 	sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
5286f34903eSdanielk1977 	sqliteSelectDelete(ss);
529c3f9bad2Sdanielk1977 	break;
530c3f9bad2Sdanielk1977       }
531c3f9bad2Sdanielk1977       case TK_UPDATE: {
532113088ecSdrh         SrcList *pSrc;
533113088ecSdrh         pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
534bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
535113088ecSdrh         sqliteUpdate(pParse, pSrc,
536633ed08dSdanielk1977 		sqliteExprListDup(pTriggerStep->pExprList),
537633ed08dSdanielk1977 		sqliteExprDup(pTriggerStep->pWhere), orconf);
538bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
539c3f9bad2Sdanielk1977         break;
540c3f9bad2Sdanielk1977       }
541c3f9bad2Sdanielk1977       case TK_INSERT: {
542113088ecSdrh         SrcList *pSrc;
543113088ecSdrh         pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
544113088ecSdrh         sqliteInsert(pParse, pSrc,
545633ed08dSdanielk1977           sqliteExprListDup(pTriggerStep->pExprList),
546633ed08dSdanielk1977           sqliteSelectDup(pTriggerStep->pSelect),
547633ed08dSdanielk1977           sqliteIdListDup(pTriggerStep->pIdList), orconf);
548c3f9bad2Sdanielk1977         break;
549c3f9bad2Sdanielk1977       }
550c3f9bad2Sdanielk1977       case TK_DELETE: {
551113088ecSdrh         SrcList *pSrc;
552bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
553113088ecSdrh         pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
554113088ecSdrh         sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
555bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
556c3f9bad2Sdanielk1977         break;
557c3f9bad2Sdanielk1977       }
558c3f9bad2Sdanielk1977       default:
559c3f9bad2Sdanielk1977         assert(0);
560c3f9bad2Sdanielk1977     }
561c3f9bad2Sdanielk1977     pParse->nTab = saveNTab;
562633ed08dSdanielk1977     pTriggerStep = pTriggerStep->pNext;
563c3f9bad2Sdanielk1977   }
564c3f9bad2Sdanielk1977 
565c3f9bad2Sdanielk1977   return 0;
566c3f9bad2Sdanielk1977 }
567c3f9bad2Sdanielk1977 
568633ed08dSdanielk1977 /*
569633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers.
570633ed08dSdanielk1977 **
571633ed08dSdanielk1977 ** When the code that this function generates is executed, the following
572633ed08dSdanielk1977 ** must be true:
573c977f7f5Sdrh **
574c977f7f5Sdrh ** 1. No cursors may be open in the main database.  (But newIdx and oldIdx
575c977f7f5Sdrh **    can be indices of cursors in temporary tables.  See below.)
576c977f7f5Sdrh **
577633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
578633ed08dSdanielk1977 **    a temporary vdbe cursor (index newIdx) must be open and pointing at
579633ed08dSdanielk1977 **    a row containing values to be substituted for new.* expressions in the
580633ed08dSdanielk1977 **    trigger program(s).
581c977f7f5Sdrh **
582633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
583633ed08dSdanielk1977 **    a temporary vdbe cursor (index oldIdx) must be open and pointing at
584633ed08dSdanielk1977 **    a row containing values to be substituted for old.* expressions in the
585633ed08dSdanielk1977 **    trigger program(s).
586633ed08dSdanielk1977 **
587633ed08dSdanielk1977 */
588c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger(
589c3f9bad2Sdanielk1977   Parse *pParse,       /* Parse context */
590c3f9bad2Sdanielk1977   int op,              /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
591633ed08dSdanielk1977   ExprList *pChanges,  /* Changes list for any UPDATE OF triggers */
592c3f9bad2Sdanielk1977   int tr_tm,           /* One of TK_BEFORE, TK_AFTER */
593633ed08dSdanielk1977   Table *pTab,         /* The table to code triggers from */
594633ed08dSdanielk1977   int newIdx,          /* The indice of the "new" row to access */
595633ed08dSdanielk1977   int oldIdx,          /* The indice of the "old" row to access */
5966f34903eSdanielk1977   int orconf,          /* ON CONFLICT policy */
5976f34903eSdanielk1977   int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
598c977f7f5Sdrh ){
599c3f9bad2Sdanielk1977   Trigger * pTrigger;
600c3f9bad2Sdanielk1977   TriggerStack * pTriggerStack;
601c3f9bad2Sdanielk1977 
602c3f9bad2Sdanielk1977   assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
603c3f9bad2Sdanielk1977   assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
604c3f9bad2Sdanielk1977 
605633ed08dSdanielk1977   assert(newIdx != -1 || oldIdx != -1);
606c3f9bad2Sdanielk1977 
607633ed08dSdanielk1977   pTrigger = pTab->pTrigger;
608c3f9bad2Sdanielk1977   while( pTrigger ){
609c3f9bad2Sdanielk1977     int fire_this = 0;
610c3f9bad2Sdanielk1977 
611c3f9bad2Sdanielk1977     /* determine whether we should code this trigger */
612c3f9bad2Sdanielk1977     if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
613c3f9bad2Sdanielk1977         pTrigger->foreach == TK_ROW ){
614c3f9bad2Sdanielk1977       fire_this = 1;
615c3f9bad2Sdanielk1977       pTriggerStack = pParse->trigStack;
616c3f9bad2Sdanielk1977       while( pTriggerStack ){
617f29ce559Sdanielk1977         if( pTriggerStack->pTrigger == pTrigger ){
618f29ce559Sdanielk1977 	  fire_this = 0;
619f29ce559Sdanielk1977 	}
620c3f9bad2Sdanielk1977         pTriggerStack = pTriggerStack->pNext;
621c3f9bad2Sdanielk1977       }
622c3f9bad2Sdanielk1977       if( op == TK_UPDATE && pTrigger->pColumns &&
623f29ce559Sdanielk1977           !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
624c3f9bad2Sdanielk1977         fire_this = 0;
625c3f9bad2Sdanielk1977       }
626f29ce559Sdanielk1977     }
627c3f9bad2Sdanielk1977 
628e4697f5eSdrh     if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
629c3f9bad2Sdanielk1977       int endTrigger;
630ad3cab52Sdrh       SrcList dummyTablist;
631c3f9bad2Sdanielk1977       Expr * whenExpr;
632c3f9bad2Sdanielk1977 
633ad3cab52Sdrh       dummyTablist.nSrc = 0;
634c3f9bad2Sdanielk1977 
635c3f9bad2Sdanielk1977       /* Push an entry on to the trigger stack */
636c3f9bad2Sdanielk1977       pTriggerStack->pTrigger = pTrigger;
637633ed08dSdanielk1977       pTriggerStack->newIdx = newIdx;
638633ed08dSdanielk1977       pTriggerStack->oldIdx = oldIdx;
639633ed08dSdanielk1977       pTriggerStack->pTab = pTab;
640c3f9bad2Sdanielk1977       pTriggerStack->pNext = pParse->trigStack;
6416f34903eSdanielk1977       pTriggerStack->ignoreJump = ignoreJump;
642c3f9bad2Sdanielk1977       pParse->trigStack = pTriggerStack;
643c3f9bad2Sdanielk1977 
644c3f9bad2Sdanielk1977       /* code the WHEN clause */
645c3f9bad2Sdanielk1977       endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
646c3f9bad2Sdanielk1977       whenExpr = sqliteExprDup(pTrigger->pWhen);
647c3f9bad2Sdanielk1977       if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
648c3f9bad2Sdanielk1977         pParse->trigStack = pParse->trigStack->pNext;
649c3f9bad2Sdanielk1977         sqliteFree(pTriggerStack);
650c3f9bad2Sdanielk1977         sqliteExprDelete(whenExpr);
651c3f9bad2Sdanielk1977         return 1;
652c3f9bad2Sdanielk1977       }
653f5905aa7Sdrh       sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
654c3f9bad2Sdanielk1977       sqliteExprDelete(whenExpr);
655c3f9bad2Sdanielk1977 
656633ed08dSdanielk1977       codeTriggerProgram(pParse, pTrigger->step_list, orconf);
657c3f9bad2Sdanielk1977 
658c3f9bad2Sdanielk1977       /* Pop the entry off the trigger stack */
659c3f9bad2Sdanielk1977       pParse->trigStack = pParse->trigStack->pNext;
660c3f9bad2Sdanielk1977       sqliteFree(pTriggerStack);
661c3f9bad2Sdanielk1977 
662c3f9bad2Sdanielk1977       sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
663c3f9bad2Sdanielk1977     }
664c3f9bad2Sdanielk1977     pTrigger = pTrigger->pNext;
665c3f9bad2Sdanielk1977   }
666c3f9bad2Sdanielk1977 
667c3f9bad2Sdanielk1977   return 0;
668c3f9bad2Sdanielk1977 }
669c3f9bad2Sdanielk1977 
670c3f9bad2Sdanielk1977 /*
671633ed08dSdanielk1977  * This function is called to code ON UPDATE and ON DELETE triggers on
672633ed08dSdanielk1977  * views.
673633ed08dSdanielk1977  *
674633ed08dSdanielk1977  * This function deletes the data pointed at by the pWhere and pChanges
675633ed08dSdanielk1977  * arguments before it completes.
676c3f9bad2Sdanielk1977  */
677633ed08dSdanielk1977 void sqliteViewTriggers(
678633ed08dSdanielk1977   Parse *pParse,
679633ed08dSdanielk1977   Table *pTab,         /* The view to code triggers on */
680633ed08dSdanielk1977   Expr *pWhere,        /* The WHERE clause of the statement causing triggers*/
681633ed08dSdanielk1977   int orconf,          /* The ON CONFLICT policy specified as part of the
682633ed08dSdanielk1977 			  statement causing these triggers */
683633ed08dSdanielk1977   ExprList *pChanges   /* If this is an statement causing triggers to fire
684633ed08dSdanielk1977 			  is an UPDATE, then this list holds the columns
685633ed08dSdanielk1977 			  to update and the expressions to update them to.
686633ed08dSdanielk1977 			  See comments for sqliteUpdate(). */
687633ed08dSdanielk1977 ){
688c3f9bad2Sdanielk1977   int oldIdx = -1;
689c3f9bad2Sdanielk1977   int newIdx = -1;
690c3f9bad2Sdanielk1977   int *aXRef = 0;
691c3f9bad2Sdanielk1977   Vdbe *v;
692c3f9bad2Sdanielk1977   int endOfLoop;
693c3f9bad2Sdanielk1977   int startOfLoop;
694c3f9bad2Sdanielk1977   Select theSelect;
695c3f9bad2Sdanielk1977   Token tblNameToken;
696c3f9bad2Sdanielk1977 
697c3f9bad2Sdanielk1977   assert(pTab->pSelect);
698c3f9bad2Sdanielk1977 
699c3f9bad2Sdanielk1977   tblNameToken.z = pTab->zName;
700c3f9bad2Sdanielk1977   tblNameToken.n = strlen(pTab->zName);
701c3f9bad2Sdanielk1977 
702c3f9bad2Sdanielk1977   theSelect.isDistinct = 0;
703c3f9bad2Sdanielk1977   theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
704113088ecSdrh   theSelect.pSrc   = sqliteSrcListAppend(0, &tblNameToken, 0);
705c3f9bad2Sdanielk1977   theSelect.pWhere = pWhere;    pWhere = 0;
706c3f9bad2Sdanielk1977   theSelect.pGroupBy = 0;
707c3f9bad2Sdanielk1977   theSelect.pHaving = 0;
708c3f9bad2Sdanielk1977   theSelect.pOrderBy = 0;
709c3f9bad2Sdanielk1977   theSelect.op = TK_SELECT; /* ?? */
710c3f9bad2Sdanielk1977   theSelect.pPrior = 0;
711c3f9bad2Sdanielk1977   theSelect.nLimit = -1;
712c3f9bad2Sdanielk1977   theSelect.nOffset = -1;
713c3f9bad2Sdanielk1977   theSelect.zSelect = 0;
714c3f9bad2Sdanielk1977   theSelect.base = 0;
715c3f9bad2Sdanielk1977 
716c3f9bad2Sdanielk1977   v = sqliteGetVdbe(pParse);
717c3f9bad2Sdanielk1977   assert(v);
718cabb0819Sdrh   sqliteBeginWriteOperation(pParse, 1, 0);
719c3f9bad2Sdanielk1977 
720c3f9bad2Sdanielk1977   /* Allocate temp tables */
721c3f9bad2Sdanielk1977   oldIdx = pParse->nTab++;
722c3f9bad2Sdanielk1977   sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
723c3f9bad2Sdanielk1977   if( pChanges ){
724c3f9bad2Sdanielk1977     newIdx = pParse->nTab++;
725c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
726c3f9bad2Sdanielk1977   }
727c3f9bad2Sdanielk1977 
728c3f9bad2Sdanielk1977   /* Snapshot the view */
729c3f9bad2Sdanielk1977   if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
730c3f9bad2Sdanielk1977     goto trigger_cleanup;
731c3f9bad2Sdanielk1977   }
732c3f9bad2Sdanielk1977 
733c3f9bad2Sdanielk1977   /* loop thru the view snapshot, executing triggers for each row */
734c3f9bad2Sdanielk1977   endOfLoop = sqliteVdbeMakeLabel(v);
735c3f9bad2Sdanielk1977   sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
736c3f9bad2Sdanielk1977 
737c3f9bad2Sdanielk1977   /* Loop thru the view snapshot, executing triggers for each row */
738c3f9bad2Sdanielk1977   startOfLoop = sqliteVdbeCurrentAddr(v);
739c3f9bad2Sdanielk1977 
740c3f9bad2Sdanielk1977   /* Build the updated row if required */
741c3f9bad2Sdanielk1977   if( pChanges ){
7421d1f3055Sdrh     int ii;
743c3f9bad2Sdanielk1977 
744c3f9bad2Sdanielk1977     aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
745c3f9bad2Sdanielk1977     if( aXRef==0 ) goto trigger_cleanup;
746633ed08dSdanielk1977     for(ii = 0; ii < pTab->nCol; ii++){
747c3f9bad2Sdanielk1977       aXRef[ii] = -1;
748633ed08dSdanielk1977     }
749c3f9bad2Sdanielk1977 
750c3f9bad2Sdanielk1977     for(ii=0; ii<pChanges->nExpr; ii++){
751c3f9bad2Sdanielk1977       int jj;
752c3f9bad2Sdanielk1977       if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
753f29ce559Sdanielk1977             pChanges->a[ii].pExpr) ){
754c3f9bad2Sdanielk1977         goto trigger_cleanup;
755f29ce559Sdanielk1977       }
756c3f9bad2Sdanielk1977 
757c3f9bad2Sdanielk1977       if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
758c3f9bad2Sdanielk1977         goto trigger_cleanup;
759c3f9bad2Sdanielk1977 
760c3f9bad2Sdanielk1977       for(jj=0; jj<pTab->nCol; jj++){
761c3f9bad2Sdanielk1977         if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
762c3f9bad2Sdanielk1977           aXRef[jj] = ii;
763c3f9bad2Sdanielk1977           break;
764c3f9bad2Sdanielk1977         }
765c3f9bad2Sdanielk1977       }
766c3f9bad2Sdanielk1977       if( jj>=pTab->nCol ){
767c3f9bad2Sdanielk1977         sqliteSetString(&pParse->zErrMsg, "no such column: ",
768c3f9bad2Sdanielk1977             pChanges->a[ii].zName, 0);
769c3f9bad2Sdanielk1977         pParse->nErr++;
770c3f9bad2Sdanielk1977         goto trigger_cleanup;
771c3f9bad2Sdanielk1977       }
772c3f9bad2Sdanielk1977     }
773c3f9bad2Sdanielk1977 
774c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_Integer, 13, 0);
775c3f9bad2Sdanielk1977 
776633ed08dSdanielk1977     for(ii = 0; ii<pTab->nCol; ii++){
777633ed08dSdanielk1977       if( aXRef[ii] < 0 ){
778c3f9bad2Sdanielk1977         sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
779633ed08dSdanielk1977       }else{
780c3f9bad2Sdanielk1977         sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
781633ed08dSdanielk1977       }
782633ed08dSdanielk1977     }
783c3f9bad2Sdanielk1977 
784c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
785c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
786c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
787c3f9bad2Sdanielk1977 
788c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
7896f34903eSdanielk1977         pTab, newIdx, oldIdx, orconf, endOfLoop);
790c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
7916f34903eSdanielk1977         pTab, newIdx, oldIdx, orconf, endOfLoop);
792c3f9bad2Sdanielk1977   }else{
793c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
7946f34903eSdanielk1977         orconf, endOfLoop);
795c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
7966f34903eSdanielk1977         orconf, endOfLoop);
797c3f9bad2Sdanielk1977   }
798c3f9bad2Sdanielk1977 
799c3f9bad2Sdanielk1977   sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
800c3f9bad2Sdanielk1977 
801c3f9bad2Sdanielk1977   sqliteVdbeResolveLabel(v, endOfLoop);
802c3f9bad2Sdanielk1977   sqliteEndWriteOperation(pParse);
803c3f9bad2Sdanielk1977 
804c3f9bad2Sdanielk1977 trigger_cleanup:
805c3f9bad2Sdanielk1977   sqliteFree(aXRef);
806c3f9bad2Sdanielk1977   sqliteExprListDelete(pChanges);
807c3f9bad2Sdanielk1977   sqliteExprDelete(pWhere);
808c3f9bad2Sdanielk1977   sqliteExprListDelete(theSelect.pEList);
809ad3cab52Sdrh   sqliteSrcListDelete(theSelect.pSrc);
810c3f9bad2Sdanielk1977   sqliteExprDelete(theSelect.pWhere);
811c3f9bad2Sdanielk1977   return;
812c3f9bad2Sdanielk1977 }
813