xref: /sqlite-3.40.0/src/trigger.c (revision da93d238)
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 ){
69*da93d238Sdrh     sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
70*da93d238Sdrh        "database %s", db->aDb[tab->iDb].zName);
71d24cc427Sdrh     goto trigger_cleanup;
72d24cc427Sdrh   }
73d24cc427Sdrh 
74e5f9c644Sdrh   zName = sqliteStrNDup(pName->z, pName->n);
75d24cc427Sdrh   if( sqliteHashFind(&(db->aDb[tab->iDb].trigHash), zName,pName->n+1) ){
76*da93d238Sdrh     sqliteErrorMsg(pParse, "trigger %T already exists", pName);
77c3f9bad2Sdanielk1977     goto trigger_cleanup;
78c3f9bad2Sdanielk1977   }
79d24cc427Sdrh   if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
80*da93d238Sdrh     sqliteErrorMsg(pParse, "cannot create trigger on system table");
81e0bc4048Sdrh     pParse->nErr++;
82e0bc4048Sdrh     goto trigger_cleanup;
83e0bc4048Sdrh   }
84d702fccbSdanielk1977   if( tab->pSelect && tr_tm != TK_INSTEAD ){
85*da93d238Sdrh     sqliteErrorMsg(pParse, "cannot create %s trigger on view: %S",
86*da93d238Sdrh         (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
87d702fccbSdanielk1977     goto trigger_cleanup;
88d702fccbSdanielk1977   }
89d702fccbSdanielk1977   if( !tab->pSelect && tr_tm == TK_INSTEAD ){
90*da93d238Sdrh     sqliteErrorMsg(pParse, "cannot create INSTEAD OF"
91*da93d238Sdrh         " trigger on table: %S", pTableName, 0);
92d702fccbSdanielk1977     goto trigger_cleanup;
93d702fccbSdanielk1977   }
94e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
95e5f9c644Sdrh   {
96e5f9c644Sdrh     int code = SQLITE_CREATE_TRIGGER;
97d24cc427Sdrh     if( tab->iDb==1 ) code = SQLITE_CREATE_TEMP_TRIGGER;
98e5f9c644Sdrh     if( sqliteAuthCheck(pParse, code, zName, tab->zName) ){
99ed6c8671Sdrh       goto trigger_cleanup;
100ed6c8671Sdrh     }
101d24cc427Sdrh     if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0)){
10277ad4e41Sdrh       goto trigger_cleanup;
10377ad4e41Sdrh     }
104d702fccbSdanielk1977   }
105e5f9c644Sdrh #endif
106d702fccbSdanielk1977 
107d702fccbSdanielk1977   if (tr_tm == TK_INSTEAD){
108d702fccbSdanielk1977     tr_tm = TK_BEFORE;
109c3f9bad2Sdanielk1977   }
110c3f9bad2Sdanielk1977 
111c3f9bad2Sdanielk1977   /* Build the Trigger object */
112c3f9bad2Sdanielk1977   nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
113e4697f5eSdrh   if( nt==0 ) goto trigger_cleanup;
114e5f9c644Sdrh   nt->name = zName;
115e5f9c644Sdrh   zName = 0;
116d24cc427Sdrh   nt->table = sqliteStrDup(pTableName->a[0].zName);
117e4697f5eSdrh   if( sqlite_malloc_failed ) goto trigger_cleanup;
118d24cc427Sdrh   nt->iDb = tab->iDb;
119c3f9bad2Sdanielk1977   nt->op = op;
120c3f9bad2Sdanielk1977   nt->tr_tm = tr_tm;
1214b59ab5eSdrh   nt->pWhen = sqliteExprDup(pWhen);
1224b59ab5eSdrh   sqliteExprDelete(pWhen);
1234b59ab5eSdrh   nt->pColumns = sqliteIdListDup(pColumns);
1244b59ab5eSdrh   sqliteIdListDelete(pColumns);
125c3f9bad2Sdanielk1977   nt->foreach = foreach;
126633ed08dSdanielk1977   nt->step_list = pStepList;
127c3f9bad2Sdanielk1977 
128c3f9bad2Sdanielk1977   /* if we are not initializing, and this trigger is not on a TEMP table,
1299adf9ac4Sdrh   ** build the sqlite_master entry
1309adf9ac4Sdrh   */
131e0bc4048Sdrh   if( !pParse->initFlag ){
132c977f7f5Sdrh     static VdbeOp insertTrig[] = {
133c977f7f5Sdrh       { OP_NewRecno,   0, 0,  0          },
134c977f7f5Sdrh       { OP_String,     0, 0,  "trigger"  },
135e0bc4048Sdrh       { OP_String,     0, 0,  0          },  /* 2: trigger name */
136e0bc4048Sdrh       { OP_String,     0, 0,  0          },  /* 3: table name */
137c977f7f5Sdrh       { OP_Integer,    0, 0,  0          },
138e0bc4048Sdrh       { OP_String,     0, 0,  0          },  /* 5: SQL */
139c977f7f5Sdrh       { OP_MakeRecord, 5, 0,  0          },
140c977f7f5Sdrh       { OP_PutIntKey,  0, 0,  0          },
141c977f7f5Sdrh     };
142c977f7f5Sdrh     int addr;
143c977f7f5Sdrh     Vdbe *v;
144c3f9bad2Sdanielk1977 
145c3f9bad2Sdanielk1977     /* Make an entry in the sqlite_master table */
146c977f7f5Sdrh     v = sqliteGetVdbe(pParse);
147e4697f5eSdrh     if( v==0 ) goto trigger_cleanup;
148cabb0819Sdrh     sqliteBeginWriteOperation(pParse, 0, 0);
149d24cc427Sdrh     sqliteOpenMasterTable(v, tab->iDb);
150c977f7f5Sdrh     addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
151d24cc427Sdrh     sqliteVdbeChangeP3(v, addr, tab->iDb ? TEMP_MASTER_NAME : MASTER_NAME,
152e0bc4048Sdrh                        P3_STATIC);
153e0bc4048Sdrh     sqliteVdbeChangeP3(v, addr+2, nt->name, 0);
154e0bc4048Sdrh     sqliteVdbeChangeP3(v, addr+3, nt->table, 0);
1554b59ab5eSdrh     sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
156d24cc427Sdrh     if( tab->iDb==0 ){
157d24cc427Sdrh       sqliteChangeCookie(db, v);
158e0bc4048Sdrh     }
159e0bc4048Sdrh     sqliteVdbeAddOp(v, OP_Close, 0, 0);
160c3f9bad2Sdanielk1977     sqliteEndWriteOperation(pParse);
161c3f9bad2Sdanielk1977   }
162c3f9bad2Sdanielk1977 
163c3f9bad2Sdanielk1977   if( !pParse->explain ){
164c3f9bad2Sdanielk1977     /* Stick it in the hash-table */
165d24cc427Sdrh     sqliteHashInsert(&(db->aDb[nt->iDb].trigHash), nt->name, pName->n + 1, nt);
166c3f9bad2Sdanielk1977 
167c3f9bad2Sdanielk1977     /* Attach it to the table object */
168c3f9bad2Sdanielk1977     nt->pNext = tab->pTrigger;
169c3f9bad2Sdanielk1977     tab->pTrigger = nt;
1700be9df07Sdrh     sqliteSrcListDelete(pTableName);
171c3f9bad2Sdanielk1977     return;
172c3f9bad2Sdanielk1977   }else{
173c3f9bad2Sdanielk1977     sqliteFree(nt->name);
174c3f9bad2Sdanielk1977     sqliteFree(nt->table);
175c3f9bad2Sdanielk1977     sqliteFree(nt);
176c3f9bad2Sdanielk1977   }
177c3f9bad2Sdanielk1977 
178c3f9bad2Sdanielk1977 trigger_cleanup:
179c3f9bad2Sdanielk1977 
180e5f9c644Sdrh   sqliteFree(zName);
181d24cc427Sdrh   sqliteSrcListDelete(pTableName);
182633ed08dSdanielk1977   sqliteIdListDelete(pColumns);
183c3f9bad2Sdanielk1977   sqliteExprDelete(pWhen);
1844b59ab5eSdrh   sqliteDeleteTriggerStep(pStepList);
185c3f9bad2Sdanielk1977 }
1864b59ab5eSdrh 
1874b59ab5eSdrh /*
1884b59ab5eSdrh ** Make a copy of all components of the given trigger step.  This has
1894b59ab5eSdrh ** the effect of copying all Expr.token.z values into memory obtained
1904b59ab5eSdrh ** from sqliteMalloc().  As initially created, the Expr.token.z values
1914b59ab5eSdrh ** all point to the input string that was fed to the parser.  But that
1924b59ab5eSdrh ** string is ephemeral - it will go away as soon as the sqlite_exec()
1934b59ab5eSdrh ** call that started the parser exits.  This routine makes a persistent
1944b59ab5eSdrh ** copy of all the Expr.token.z strings so that the TriggerStep structure
1954b59ab5eSdrh ** will be valid even after the sqlite_exec() call returns.
1964b59ab5eSdrh */
1974b59ab5eSdrh static void sqlitePersistTriggerStep(TriggerStep *p){
1984b59ab5eSdrh   if( p->target.z ){
1994b59ab5eSdrh     p->target.z = sqliteStrNDup(p->target.z, p->target.n);
2004b59ab5eSdrh     p->target.dyn = 1;
2014b59ab5eSdrh   }
2024b59ab5eSdrh   if( p->pSelect ){
2034b59ab5eSdrh     Select *pNew = sqliteSelectDup(p->pSelect);
2044b59ab5eSdrh     sqliteSelectDelete(p->pSelect);
2054b59ab5eSdrh     p->pSelect = pNew;
2064b59ab5eSdrh   }
2074b59ab5eSdrh   if( p->pWhere ){
2084b59ab5eSdrh     Expr *pNew = sqliteExprDup(p->pWhere);
2094b59ab5eSdrh     sqliteExprDelete(p->pWhere);
2104b59ab5eSdrh     p->pWhere = pNew;
2114b59ab5eSdrh   }
2124b59ab5eSdrh   if( p->pExprList ){
2134b59ab5eSdrh     ExprList *pNew = sqliteExprListDup(p->pExprList);
2144b59ab5eSdrh     sqliteExprListDelete(p->pExprList);
2154b59ab5eSdrh     p->pExprList = pNew;
2164b59ab5eSdrh   }
2174b59ab5eSdrh   if( p->pIdList ){
2184b59ab5eSdrh     IdList *pNew = sqliteIdListDup(p->pIdList);
2194b59ab5eSdrh     sqliteIdListDelete(p->pIdList);
2204b59ab5eSdrh     p->pIdList = pNew;
221c3f9bad2Sdanielk1977   }
222c3f9bad2Sdanielk1977 }
223c3f9bad2Sdanielk1977 
224c977f7f5Sdrh /*
225c977f7f5Sdrh ** Turn a SELECT statement (that the pSelect parameter points to) into
226c977f7f5Sdrh ** a trigger step.  Return a pointer to a TriggerStep structure.
227c977f7f5Sdrh **
228c977f7f5Sdrh ** The parser calls this routine when it finds a SELECT statement in
229c977f7f5Sdrh ** body of a TRIGGER.
230c977f7f5Sdrh */
231c977f7f5Sdrh TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
232633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
233e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
234c3f9bad2Sdanielk1977 
235633ed08dSdanielk1977   pTriggerStep->op = TK_SELECT;
236633ed08dSdanielk1977   pTriggerStep->pSelect = pSelect;
237633ed08dSdanielk1977   pTriggerStep->orconf = OE_Default;
2384b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
239c3f9bad2Sdanielk1977 
240633ed08dSdanielk1977   return pTriggerStep;
241c3f9bad2Sdanielk1977 }
242c3f9bad2Sdanielk1977 
243c977f7f5Sdrh /*
244c977f7f5Sdrh ** Build a trigger step out of an INSERT statement.  Return a pointer
245c977f7f5Sdrh ** to the new trigger step.
246c977f7f5Sdrh **
247c977f7f5Sdrh ** The parser calls this routine when it sees an INSERT inside the
248c977f7f5Sdrh ** body of a trigger.
249c977f7f5Sdrh */
250633ed08dSdanielk1977 TriggerStep *sqliteTriggerInsertStep(
251c977f7f5Sdrh   Token *pTableName,  /* Name of the table into which we insert */
252c977f7f5Sdrh   IdList *pColumn,    /* List of columns in pTableName to insert into */
253c977f7f5Sdrh   ExprList *pEList,   /* The VALUE clause: a list of values to be inserted */
254c977f7f5Sdrh   Select *pSelect,    /* A SELECT statement that supplies values */
255c977f7f5Sdrh   int orconf          /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
256633ed08dSdanielk1977 ){
257633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
258e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
259c3f9bad2Sdanielk1977 
260633ed08dSdanielk1977   assert(pEList == 0 || pSelect == 0);
261633ed08dSdanielk1977   assert(pEList != 0 || pSelect != 0);
262c3f9bad2Sdanielk1977 
263633ed08dSdanielk1977   pTriggerStep->op = TK_INSERT;
264633ed08dSdanielk1977   pTriggerStep->pSelect = pSelect;
265633ed08dSdanielk1977   pTriggerStep->target  = *pTableName;
266633ed08dSdanielk1977   pTriggerStep->pIdList = pColumn;
267633ed08dSdanielk1977   pTriggerStep->pExprList = pEList;
268633ed08dSdanielk1977   pTriggerStep->orconf = orconf;
2694b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
270c3f9bad2Sdanielk1977 
271633ed08dSdanielk1977   return pTriggerStep;
272c3f9bad2Sdanielk1977 }
273c3f9bad2Sdanielk1977 
274c977f7f5Sdrh /*
275c977f7f5Sdrh ** Construct a trigger step that implements an UPDATE statement and return
276c977f7f5Sdrh ** a pointer to that trigger step.  The parser calls this routine when it
277c977f7f5Sdrh ** sees an UPDATE statement inside the body of a CREATE TRIGGER.
278c977f7f5Sdrh */
279633ed08dSdanielk1977 TriggerStep *sqliteTriggerUpdateStep(
280c977f7f5Sdrh   Token *pTableName,   /* Name of the table to be updated */
281c977f7f5Sdrh   ExprList *pEList,    /* The SET clause: list of column and new values */
282c977f7f5Sdrh   Expr *pWhere,        /* The WHERE clause */
283c977f7f5Sdrh   int orconf           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
284c977f7f5Sdrh ){
285633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
286e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
287c3f9bad2Sdanielk1977 
288633ed08dSdanielk1977   pTriggerStep->op = TK_UPDATE;
289633ed08dSdanielk1977   pTriggerStep->target  = *pTableName;
290633ed08dSdanielk1977   pTriggerStep->pExprList = pEList;
291633ed08dSdanielk1977   pTriggerStep->pWhere = pWhere;
292633ed08dSdanielk1977   pTriggerStep->orconf = orconf;
2934b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
294c3f9bad2Sdanielk1977 
295633ed08dSdanielk1977   return pTriggerStep;
296c3f9bad2Sdanielk1977 }
297c3f9bad2Sdanielk1977 
298c977f7f5Sdrh /*
299c977f7f5Sdrh ** Construct a trigger step that implements a DELETE statement and return
300c977f7f5Sdrh ** a pointer to that trigger step.  The parser calls this routine when it
301c977f7f5Sdrh ** sees a DELETE statement inside the body of a CREATE TRIGGER.
302c977f7f5Sdrh */
303c977f7f5Sdrh TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
304633ed08dSdanielk1977   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
305e4697f5eSdrh   if( pTriggerStep==0 ) return 0;
306c3f9bad2Sdanielk1977 
307633ed08dSdanielk1977   pTriggerStep->op = TK_DELETE;
308633ed08dSdanielk1977   pTriggerStep->target  = *pTableName;
309633ed08dSdanielk1977   pTriggerStep->pWhere = pWhere;
310633ed08dSdanielk1977   pTriggerStep->orconf = OE_Default;
3114b59ab5eSdrh   sqlitePersistTriggerStep(pTriggerStep);
312c3f9bad2Sdanielk1977 
313633ed08dSdanielk1977   return pTriggerStep;
314c3f9bad2Sdanielk1977 }
315c3f9bad2Sdanielk1977 
316c3f9bad2Sdanielk1977 /*
317633ed08dSdanielk1977 ** Recursively delete a Trigger structure
318c3f9bad2Sdanielk1977 */
3191d1f3055Sdrh void sqliteDeleteTrigger(Trigger *pTrigger){
3204b59ab5eSdrh   sqliteDeleteTriggerStep(pTrigger->step_list);
321633ed08dSdanielk1977   sqliteFree(pTrigger->name);
322633ed08dSdanielk1977   sqliteFree(pTrigger->table);
323633ed08dSdanielk1977   sqliteExprDelete(pTrigger->pWhen);
324633ed08dSdanielk1977   sqliteIdListDelete(pTrigger->pColumns);
325633ed08dSdanielk1977   sqliteFree(pTrigger);
326633ed08dSdanielk1977 }
327633ed08dSdanielk1977 
328633ed08dSdanielk1977 /*
329633ed08dSdanielk1977  * This function is called to drop a trigger from the database schema.
330633ed08dSdanielk1977  *
331633ed08dSdanielk1977  * This may be called directly from the parser, or from within
332633ed08dSdanielk1977  * sqliteDropTable(). In the latter case the "nested" argument is true.
333633ed08dSdanielk1977  *
334633ed08dSdanielk1977  * Note that this function does not delete the trigger entirely. Instead it
335633ed08dSdanielk1977  * removes it from the internal schema and places it in the trigDrop hash
336633ed08dSdanielk1977  * table. This is so that the trigger can be restored into the database schema
337633ed08dSdanielk1977  * if the transaction is rolled back.
338633ed08dSdanielk1977  */
339d24cc427Sdrh void sqliteDropTrigger(Parse *pParse, SrcList *pName, int nested){
340633ed08dSdanielk1977   Trigger *pTrigger;
341633ed08dSdanielk1977   Table   *pTable;
342e0bc4048Sdrh   Vdbe *v;
343d24cc427Sdrh   int i;
344d24cc427Sdrh   const char *zDb;
345d24cc427Sdrh   const char *zName;
346d24cc427Sdrh   int nName;
347d24cc427Sdrh   sqlite *db = pParse->db;
348633ed08dSdanielk1977 
349d24cc427Sdrh   if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
350d24cc427Sdrh   assert( pName->nSrc==1 );
351d24cc427Sdrh   zDb = pName->a[0].zDatabase;
352d24cc427Sdrh   zName = pName->a[0].zName;
353d24cc427Sdrh   nName = strlen(zName);
354d24cc427Sdrh   for(i=0; i<db->nDb; i++){
355812d7a21Sdrh     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
356812d7a21Sdrh     if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
357812d7a21Sdrh     pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
358d24cc427Sdrh     if( pTrigger ) break;
359c3f9bad2Sdanielk1977   }
360d24cc427Sdrh   if( !pTrigger ){
361*da93d238Sdrh     sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0);
362d24cc427Sdrh     goto drop_trigger_cleanup;
363d24cc427Sdrh   }
364d24cc427Sdrh   assert( pTrigger->iDb>=0 && pTrigger->iDb<db->nDb );
365d24cc427Sdrh   if( pTrigger->iDb>=2 ){
366*da93d238Sdrh     sqliteErrorMsg(pParse, "triggers may not be removed from "
367*da93d238Sdrh        "auxiliary database %s", db->aDb[pTrigger->iDb].zName);
368d24cc427Sdrh     goto drop_trigger_cleanup;
369d24cc427Sdrh   }
370d24cc427Sdrh   pTable = sqliteFindTable(db, pTrigger->table, db->aDb[pTrigger->iDb].zName);
371ed6c8671Sdrh   assert(pTable);
372d24cc427Sdrh   assert( pTable->iDb==pTrigger->iDb );
373e5f9c644Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
374e5f9c644Sdrh   {
375e5f9c644Sdrh     int code = SQLITE_DROP_TRIGGER;
376d24cc427Sdrh     if( pTable->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
377e5f9c644Sdrh     if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName) ||
378d24cc427Sdrh       sqliteAuthCheck(pParse, SQLITE_DELETE, SCHEMA_TABLE(pTable->iDb),0) ){
3790be9df07Sdrh       goto drop_trigger_cleanup;
380ed6c8671Sdrh     }
381e5f9c644Sdrh   }
382e5f9c644Sdrh #endif
383c3f9bad2Sdanielk1977 
384c3f9bad2Sdanielk1977   /*
385e0bc4048Sdrh    * If this is not an "explain", then delete the trigger structure.
386c3f9bad2Sdanielk1977    */
387c3f9bad2Sdanielk1977   if( !pParse->explain ){
388633ed08dSdanielk1977     if( pTable->pTrigger == pTrigger ){
389633ed08dSdanielk1977       pTable->pTrigger = pTrigger->pNext;
390633ed08dSdanielk1977     }else{
391633ed08dSdanielk1977       Trigger *cc = pTable->pTrigger;
392c3f9bad2Sdanielk1977       while( cc ){
393633ed08dSdanielk1977         if( cc->pNext == pTrigger ){
394c3f9bad2Sdanielk1977           cc->pNext = cc->pNext->pNext;
395c3f9bad2Sdanielk1977           break;
396c3f9bad2Sdanielk1977         }
397c3f9bad2Sdanielk1977         cc = cc->pNext;
398c3f9bad2Sdanielk1977       }
399c3f9bad2Sdanielk1977       assert(cc);
400c3f9bad2Sdanielk1977     }
401d24cc427Sdrh     sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
402e0bc4048Sdrh     sqliteDeleteTrigger(pTrigger);
403c3f9bad2Sdanielk1977   }
404c3f9bad2Sdanielk1977 
405e0bc4048Sdrh   /* Generate code to destroy the database record of the trigger.
406e0bc4048Sdrh   */
407e0bc4048Sdrh   if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
408c3f9bad2Sdanielk1977     int base;
409c3f9bad2Sdanielk1977     static VdbeOp dropTrigger[] = {
410e0bc4048Sdrh       { OP_Rewind,     0, ADDR(8),  0},
411e0bc4048Sdrh       { OP_String,     0, 0,        0}, /* 1 */
412c3f9bad2Sdanielk1977       { OP_MemStore,   1, 1,        0},
413e0bc4048Sdrh       { OP_MemLoad,    1, 0,        0}, /* 3 */
414c3f9bad2Sdanielk1977       { OP_Column,     0, 1,        0},
415e0bc4048Sdrh       { OP_Ne,         0, ADDR(7),  0},
416c3f9bad2Sdanielk1977       { OP_Delete,     0, 0,        0},
417e0bc4048Sdrh       { OP_Next,       0, ADDR(3),  0}, /* 7 */
418c3f9bad2Sdanielk1977     };
419c3f9bad2Sdanielk1977 
420cabb0819Sdrh     sqliteBeginWriteOperation(pParse, 0, 0);
421d24cc427Sdrh     sqliteOpenMasterTable(v, pTable->iDb);
422e0bc4048Sdrh     base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
423e0bc4048Sdrh     sqliteVdbeChangeP3(v, base+1, zName, 0);
424d24cc427Sdrh     if( pTable->iDb==0 ){
425d24cc427Sdrh       sqliteChangeCookie(db, v);
426dc379456Sdrh     }
427e0bc4048Sdrh     sqliteVdbeAddOp(v, OP_Close, 0, 0);
428c3f9bad2Sdanielk1977     sqliteEndWriteOperation(pParse);
429c3f9bad2Sdanielk1977   }
430c3f9bad2Sdanielk1977 
431d24cc427Sdrh drop_trigger_cleanup:
432d24cc427Sdrh   sqliteSrcListDelete(pName);
433c3f9bad2Sdanielk1977 }
434c3f9bad2Sdanielk1977 
435c977f7f5Sdrh /*
436c977f7f5Sdrh ** pEList is the SET clause of an UPDATE statement.  Each entry
437c977f7f5Sdrh ** in pEList is of the format <id>=<expr>.  If any of the entries
438c977f7f5Sdrh ** in pEList have an <id> which matches an identifier in pIdList,
439c977f7f5Sdrh ** then return TRUE.  If pIdList==NULL, then it is considered a
440c977f7f5Sdrh ** wildcard that matches anything.  Likewise if pEList==NULL then
441c977f7f5Sdrh ** it matches anything so always return true.  Return false only
442c977f7f5Sdrh ** if there is no match.
443c977f7f5Sdrh */
444c977f7f5Sdrh static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
445ad2d8307Sdrh   int e;
446ad2d8307Sdrh   if( !pIdList || !pEList ) return 1;
447f29ce559Sdanielk1977   for(e=0; e<pEList->nExpr; e++){
448ad2d8307Sdrh     if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
449f29ce559Sdanielk1977   }
450c3f9bad2Sdanielk1977   return 0;
451c3f9bad2Sdanielk1977 }
452c3f9bad2Sdanielk1977 
453c3f9bad2Sdanielk1977 /* A global variable that is TRUE if we should always set up temp tables for
454c3f9bad2Sdanielk1977  * for triggers, even if there are no triggers to code. This is used to test
455c3f9bad2Sdanielk1977  * how much overhead the triggers algorithm is causing.
456c3f9bad2Sdanielk1977  *
457c3f9bad2Sdanielk1977  * This flag can be set or cleared using the "trigger_overhead_test" pragma.
458c3f9bad2Sdanielk1977  * The pragma is not documented since it is not really part of the interface
459c3f9bad2Sdanielk1977  * to SQLite, just the test procedure.
460c3f9bad2Sdanielk1977 */
461c3f9bad2Sdanielk1977 int always_code_trigger_setup = 0;
462c3f9bad2Sdanielk1977 
463c3f9bad2Sdanielk1977 /*
464c3f9bad2Sdanielk1977  * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
465c3f9bad2Sdanielk1977  * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
466c3f9bad2Sdanielk1977  * found in the list specified as pTrigger.
467c3f9bad2Sdanielk1977  */
468c3f9bad2Sdanielk1977 int sqliteTriggersExist(
469c977f7f5Sdrh   Parse *pParse,          /* Used to check for recursive triggers */
470c977f7f5Sdrh   Trigger *pTrigger,      /* A list of triggers associated with a table */
471c3f9bad2Sdanielk1977   int op,                 /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
472c3f9bad2Sdanielk1977   int tr_tm,              /* one of TK_BEFORE, TK_AFTER */
473c3f9bad2Sdanielk1977   int foreach,            /* one of TK_ROW or TK_STATEMENT */
474c977f7f5Sdrh   ExprList *pChanges      /* Columns that change in an UPDATE statement */
475c977f7f5Sdrh ){
476633ed08dSdanielk1977   Trigger * pTriggerCursor;
477c3f9bad2Sdanielk1977 
478633ed08dSdanielk1977   if( always_code_trigger_setup ){
479633ed08dSdanielk1977     return 1;
480633ed08dSdanielk1977   }
481c3f9bad2Sdanielk1977 
482633ed08dSdanielk1977   pTriggerCursor = pTrigger;
483633ed08dSdanielk1977   while( pTriggerCursor ){
484633ed08dSdanielk1977     if( pTriggerCursor->op == op &&
485633ed08dSdanielk1977 	pTriggerCursor->tr_tm == tr_tm &&
486633ed08dSdanielk1977 	pTriggerCursor->foreach == foreach &&
487633ed08dSdanielk1977 	checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
488c3f9bad2Sdanielk1977       TriggerStack * ss;
489c3f9bad2Sdanielk1977       ss = pParse->trigStack;
490f29ce559Sdanielk1977       while( ss && ss->pTrigger != pTrigger ){
491f29ce559Sdanielk1977 	ss = ss->pNext;
492f29ce559Sdanielk1977       }
493c3f9bad2Sdanielk1977       if( !ss )return 1;
494c3f9bad2Sdanielk1977     }
495633ed08dSdanielk1977     pTriggerCursor = pTriggerCursor->pNext;
496c3f9bad2Sdanielk1977   }
497c3f9bad2Sdanielk1977 
498c3f9bad2Sdanielk1977   return 0;
499c3f9bad2Sdanielk1977 }
500c3f9bad2Sdanielk1977 
501c977f7f5Sdrh /*
502c977f7f5Sdrh ** Generate VDBE code for zero or more statements inside the body of a
503c977f7f5Sdrh ** trigger.
504c977f7f5Sdrh */
505c3f9bad2Sdanielk1977 static int codeTriggerProgram(
506c977f7f5Sdrh   Parse *pParse,            /* The parser context */
507c977f7f5Sdrh   TriggerStep *pStepList,   /* List of statements inside the trigger body */
508c977f7f5Sdrh   int orconfin              /* Conflict algorithm. (OE_Abort, etc) */
509633ed08dSdanielk1977 ){
510633ed08dSdanielk1977   TriggerStep * pTriggerStep = pStepList;
511c3f9bad2Sdanielk1977   int orconf;
512c3f9bad2Sdanielk1977 
513633ed08dSdanielk1977   while( pTriggerStep ){
514c3f9bad2Sdanielk1977     int saveNTab = pParse->nTab;
515633ed08dSdanielk1977     orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
516c3f9bad2Sdanielk1977     pParse->trigStack->orconf = orconf;
517633ed08dSdanielk1977     switch( pTriggerStep->op ){
518c3f9bad2Sdanielk1977       case TK_SELECT: {
5196f34903eSdanielk1977 	Select * ss = sqliteSelectDup(pTriggerStep->pSelect);
5206f34903eSdanielk1977 	assert(ss);
5216f34903eSdanielk1977 	assert(ss->pSrc);
5226f34903eSdanielk1977 	sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
5236f34903eSdanielk1977 	sqliteSelectDelete(ss);
524c3f9bad2Sdanielk1977 	break;
525c3f9bad2Sdanielk1977       }
526c3f9bad2Sdanielk1977       case TK_UPDATE: {
527113088ecSdrh         SrcList *pSrc;
528113088ecSdrh         pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
529bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
530113088ecSdrh         sqliteUpdate(pParse, pSrc,
531633ed08dSdanielk1977 		sqliteExprListDup(pTriggerStep->pExprList),
532633ed08dSdanielk1977 		sqliteExprDup(pTriggerStep->pWhere), orconf);
533bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
534c3f9bad2Sdanielk1977         break;
535c3f9bad2Sdanielk1977       }
536c3f9bad2Sdanielk1977       case TK_INSERT: {
537113088ecSdrh         SrcList *pSrc;
538113088ecSdrh         pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
539113088ecSdrh         sqliteInsert(pParse, pSrc,
540633ed08dSdanielk1977           sqliteExprListDup(pTriggerStep->pExprList),
541633ed08dSdanielk1977           sqliteSelectDup(pTriggerStep->pSelect),
542633ed08dSdanielk1977           sqliteIdListDup(pTriggerStep->pIdList), orconf);
543c3f9bad2Sdanielk1977         break;
544c3f9bad2Sdanielk1977       }
545c3f9bad2Sdanielk1977       case TK_DELETE: {
546113088ecSdrh         SrcList *pSrc;
547bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
548113088ecSdrh         pSrc = sqliteSrcListAppend(0, &pTriggerStep->target, 0);
549113088ecSdrh         sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
550bd5a451dSdrh         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
551c3f9bad2Sdanielk1977         break;
552c3f9bad2Sdanielk1977       }
553c3f9bad2Sdanielk1977       default:
554c3f9bad2Sdanielk1977         assert(0);
555c3f9bad2Sdanielk1977     }
556c3f9bad2Sdanielk1977     pParse->nTab = saveNTab;
557633ed08dSdanielk1977     pTriggerStep = pTriggerStep->pNext;
558c3f9bad2Sdanielk1977   }
559c3f9bad2Sdanielk1977 
560c3f9bad2Sdanielk1977   return 0;
561c3f9bad2Sdanielk1977 }
562c3f9bad2Sdanielk1977 
563633ed08dSdanielk1977 /*
564633ed08dSdanielk1977 ** This is called to code FOR EACH ROW triggers.
565633ed08dSdanielk1977 **
566633ed08dSdanielk1977 ** When the code that this function generates is executed, the following
567633ed08dSdanielk1977 ** must be true:
568c977f7f5Sdrh **
569c977f7f5Sdrh ** 1. No cursors may be open in the main database.  (But newIdx and oldIdx
570c977f7f5Sdrh **    can be indices of cursors in temporary tables.  See below.)
571c977f7f5Sdrh **
572633ed08dSdanielk1977 ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
573633ed08dSdanielk1977 **    a temporary vdbe cursor (index newIdx) must be open and pointing at
574633ed08dSdanielk1977 **    a row containing values to be substituted for new.* expressions in the
575633ed08dSdanielk1977 **    trigger program(s).
576c977f7f5Sdrh **
577633ed08dSdanielk1977 ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
578633ed08dSdanielk1977 **    a temporary vdbe cursor (index oldIdx) must be open and pointing at
579633ed08dSdanielk1977 **    a row containing values to be substituted for old.* expressions in the
580633ed08dSdanielk1977 **    trigger program(s).
581633ed08dSdanielk1977 **
582633ed08dSdanielk1977 */
583c3f9bad2Sdanielk1977 int sqliteCodeRowTrigger(
584c3f9bad2Sdanielk1977   Parse *pParse,       /* Parse context */
585c3f9bad2Sdanielk1977   int op,              /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
586633ed08dSdanielk1977   ExprList *pChanges,  /* Changes list for any UPDATE OF triggers */
587c3f9bad2Sdanielk1977   int tr_tm,           /* One of TK_BEFORE, TK_AFTER */
588633ed08dSdanielk1977   Table *pTab,         /* The table to code triggers from */
589633ed08dSdanielk1977   int newIdx,          /* The indice of the "new" row to access */
590633ed08dSdanielk1977   int oldIdx,          /* The indice of the "old" row to access */
5916f34903eSdanielk1977   int orconf,          /* ON CONFLICT policy */
5926f34903eSdanielk1977   int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
593c977f7f5Sdrh ){
594c3f9bad2Sdanielk1977   Trigger * pTrigger;
595c3f9bad2Sdanielk1977   TriggerStack * pTriggerStack;
596c3f9bad2Sdanielk1977 
597c3f9bad2Sdanielk1977   assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
598c3f9bad2Sdanielk1977   assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER);
599c3f9bad2Sdanielk1977 
600633ed08dSdanielk1977   assert(newIdx != -1 || oldIdx != -1);
601c3f9bad2Sdanielk1977 
602633ed08dSdanielk1977   pTrigger = pTab->pTrigger;
603c3f9bad2Sdanielk1977   while( pTrigger ){
604c3f9bad2Sdanielk1977     int fire_this = 0;
605c3f9bad2Sdanielk1977 
606c3f9bad2Sdanielk1977     /* determine whether we should code this trigger */
607c3f9bad2Sdanielk1977     if( pTrigger->op == op && pTrigger->tr_tm == tr_tm &&
608c3f9bad2Sdanielk1977         pTrigger->foreach == TK_ROW ){
609c3f9bad2Sdanielk1977       fire_this = 1;
610c3f9bad2Sdanielk1977       pTriggerStack = pParse->trigStack;
611c3f9bad2Sdanielk1977       while( pTriggerStack ){
612f29ce559Sdanielk1977         if( pTriggerStack->pTrigger == pTrigger ){
613f29ce559Sdanielk1977 	  fire_this = 0;
614f29ce559Sdanielk1977 	}
615c3f9bad2Sdanielk1977         pTriggerStack = pTriggerStack->pNext;
616c3f9bad2Sdanielk1977       }
617c3f9bad2Sdanielk1977       if( op == TK_UPDATE && pTrigger->pColumns &&
618f29ce559Sdanielk1977           !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
619c3f9bad2Sdanielk1977         fire_this = 0;
620c3f9bad2Sdanielk1977       }
621f29ce559Sdanielk1977     }
622c3f9bad2Sdanielk1977 
623e4697f5eSdrh     if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
624c3f9bad2Sdanielk1977       int endTrigger;
625ad3cab52Sdrh       SrcList dummyTablist;
626c3f9bad2Sdanielk1977       Expr * whenExpr;
627c3f9bad2Sdanielk1977 
628ad3cab52Sdrh       dummyTablist.nSrc = 0;
629c3f9bad2Sdanielk1977 
630c3f9bad2Sdanielk1977       /* Push an entry on to the trigger stack */
631c3f9bad2Sdanielk1977       pTriggerStack->pTrigger = pTrigger;
632633ed08dSdanielk1977       pTriggerStack->newIdx = newIdx;
633633ed08dSdanielk1977       pTriggerStack->oldIdx = oldIdx;
634633ed08dSdanielk1977       pTriggerStack->pTab = pTab;
635c3f9bad2Sdanielk1977       pTriggerStack->pNext = pParse->trigStack;
6366f34903eSdanielk1977       pTriggerStack->ignoreJump = ignoreJump;
637c3f9bad2Sdanielk1977       pParse->trigStack = pTriggerStack;
638c3f9bad2Sdanielk1977 
639c3f9bad2Sdanielk1977       /* code the WHEN clause */
640c3f9bad2Sdanielk1977       endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
641c3f9bad2Sdanielk1977       whenExpr = sqliteExprDup(pTrigger->pWhen);
642c3f9bad2Sdanielk1977       if( sqliteExprResolveIds(pParse, 0, &dummyTablist, 0, whenExpr) ){
643c3f9bad2Sdanielk1977         pParse->trigStack = pParse->trigStack->pNext;
644c3f9bad2Sdanielk1977         sqliteFree(pTriggerStack);
645c3f9bad2Sdanielk1977         sqliteExprDelete(whenExpr);
646c3f9bad2Sdanielk1977         return 1;
647c3f9bad2Sdanielk1977       }
648f5905aa7Sdrh       sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
649c3f9bad2Sdanielk1977       sqliteExprDelete(whenExpr);
650c3f9bad2Sdanielk1977 
651633ed08dSdanielk1977       codeTriggerProgram(pParse, pTrigger->step_list, orconf);
652c3f9bad2Sdanielk1977 
653c3f9bad2Sdanielk1977       /* Pop the entry off the trigger stack */
654c3f9bad2Sdanielk1977       pParse->trigStack = pParse->trigStack->pNext;
655c3f9bad2Sdanielk1977       sqliteFree(pTriggerStack);
656c3f9bad2Sdanielk1977 
657c3f9bad2Sdanielk1977       sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
658c3f9bad2Sdanielk1977     }
659c3f9bad2Sdanielk1977     pTrigger = pTrigger->pNext;
660c3f9bad2Sdanielk1977   }
661c3f9bad2Sdanielk1977 
662c3f9bad2Sdanielk1977   return 0;
663c3f9bad2Sdanielk1977 }
664c3f9bad2Sdanielk1977 
665c3f9bad2Sdanielk1977 /*
666633ed08dSdanielk1977  * This function is called to code ON UPDATE and ON DELETE triggers on
667633ed08dSdanielk1977  * views.
668633ed08dSdanielk1977  *
669633ed08dSdanielk1977  * This function deletes the data pointed at by the pWhere and pChanges
670633ed08dSdanielk1977  * arguments before it completes.
671c3f9bad2Sdanielk1977  */
672633ed08dSdanielk1977 void sqliteViewTriggers(
673633ed08dSdanielk1977   Parse *pParse,
674633ed08dSdanielk1977   Table *pTab,         /* The view to code triggers on */
675633ed08dSdanielk1977   Expr *pWhere,        /* The WHERE clause of the statement causing triggers*/
676633ed08dSdanielk1977   int orconf,          /* The ON CONFLICT policy specified as part of the
677633ed08dSdanielk1977 			  statement causing these triggers */
678633ed08dSdanielk1977   ExprList *pChanges   /* If this is an statement causing triggers to fire
679633ed08dSdanielk1977 			  is an UPDATE, then this list holds the columns
680633ed08dSdanielk1977 			  to update and the expressions to update them to.
681633ed08dSdanielk1977 			  See comments for sqliteUpdate(). */
682633ed08dSdanielk1977 ){
683c3f9bad2Sdanielk1977   int oldIdx = -1;
684c3f9bad2Sdanielk1977   int newIdx = -1;
685c3f9bad2Sdanielk1977   int *aXRef = 0;
686c3f9bad2Sdanielk1977   Vdbe *v;
687c3f9bad2Sdanielk1977   int endOfLoop;
688c3f9bad2Sdanielk1977   int startOfLoop;
689c3f9bad2Sdanielk1977   Select theSelect;
690c3f9bad2Sdanielk1977   Token tblNameToken;
691c3f9bad2Sdanielk1977 
692c3f9bad2Sdanielk1977   assert(pTab->pSelect);
693c3f9bad2Sdanielk1977 
694c3f9bad2Sdanielk1977   tblNameToken.z = pTab->zName;
695c3f9bad2Sdanielk1977   tblNameToken.n = strlen(pTab->zName);
696c3f9bad2Sdanielk1977 
697c3f9bad2Sdanielk1977   theSelect.isDistinct = 0;
698c3f9bad2Sdanielk1977   theSelect.pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL, 0, 0, 0), 0);
699113088ecSdrh   theSelect.pSrc   = sqliteSrcListAppend(0, &tblNameToken, 0);
700c3f9bad2Sdanielk1977   theSelect.pWhere = pWhere;    pWhere = 0;
701c3f9bad2Sdanielk1977   theSelect.pGroupBy = 0;
702c3f9bad2Sdanielk1977   theSelect.pHaving = 0;
703c3f9bad2Sdanielk1977   theSelect.pOrderBy = 0;
704c3f9bad2Sdanielk1977   theSelect.op = TK_SELECT; /* ?? */
705c3f9bad2Sdanielk1977   theSelect.pPrior = 0;
706c3f9bad2Sdanielk1977   theSelect.nLimit = -1;
707c3f9bad2Sdanielk1977   theSelect.nOffset = -1;
708c3f9bad2Sdanielk1977   theSelect.zSelect = 0;
709c3f9bad2Sdanielk1977   theSelect.base = 0;
710c3f9bad2Sdanielk1977 
711c3f9bad2Sdanielk1977   v = sqliteGetVdbe(pParse);
712c3f9bad2Sdanielk1977   assert(v);
713cabb0819Sdrh   sqliteBeginWriteOperation(pParse, 1, 0);
714c3f9bad2Sdanielk1977 
715c3f9bad2Sdanielk1977   /* Allocate temp tables */
716c3f9bad2Sdanielk1977   oldIdx = pParse->nTab++;
717c3f9bad2Sdanielk1977   sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
718c3f9bad2Sdanielk1977   if( pChanges ){
719c3f9bad2Sdanielk1977     newIdx = pParse->nTab++;
720c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
721c3f9bad2Sdanielk1977   }
722c3f9bad2Sdanielk1977 
723c3f9bad2Sdanielk1977   /* Snapshot the view */
724c3f9bad2Sdanielk1977   if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
725c3f9bad2Sdanielk1977     goto trigger_cleanup;
726c3f9bad2Sdanielk1977   }
727c3f9bad2Sdanielk1977 
728c3f9bad2Sdanielk1977   /* loop thru the view snapshot, executing triggers for each row */
729c3f9bad2Sdanielk1977   endOfLoop = sqliteVdbeMakeLabel(v);
730c3f9bad2Sdanielk1977   sqliteVdbeAddOp(v, OP_Rewind, oldIdx, endOfLoop);
731c3f9bad2Sdanielk1977 
732c3f9bad2Sdanielk1977   /* Loop thru the view snapshot, executing triggers for each row */
733c3f9bad2Sdanielk1977   startOfLoop = sqliteVdbeCurrentAddr(v);
734c3f9bad2Sdanielk1977 
735c3f9bad2Sdanielk1977   /* Build the updated row if required */
736c3f9bad2Sdanielk1977   if( pChanges ){
7371d1f3055Sdrh     int ii;
738c3f9bad2Sdanielk1977 
739c3f9bad2Sdanielk1977     aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
740c3f9bad2Sdanielk1977     if( aXRef==0 ) goto trigger_cleanup;
741633ed08dSdanielk1977     for(ii = 0; ii < pTab->nCol; ii++){
742c3f9bad2Sdanielk1977       aXRef[ii] = -1;
743633ed08dSdanielk1977     }
744c3f9bad2Sdanielk1977 
745c3f9bad2Sdanielk1977     for(ii=0; ii<pChanges->nExpr; ii++){
746c3f9bad2Sdanielk1977       int jj;
747c3f9bad2Sdanielk1977       if( sqliteExprResolveIds(pParse, oldIdx, theSelect.pSrc , 0,
748f29ce559Sdanielk1977             pChanges->a[ii].pExpr) ){
749c3f9bad2Sdanielk1977         goto trigger_cleanup;
750f29ce559Sdanielk1977       }
751c3f9bad2Sdanielk1977 
752c3f9bad2Sdanielk1977       if( sqliteExprCheck(pParse, pChanges->a[ii].pExpr, 0, 0) )
753c3f9bad2Sdanielk1977         goto trigger_cleanup;
754c3f9bad2Sdanielk1977 
755c3f9bad2Sdanielk1977       for(jj=0; jj<pTab->nCol; jj++){
756c3f9bad2Sdanielk1977         if( sqliteStrICmp(pTab->aCol[jj].zName, pChanges->a[ii].zName)==0 ){
757c3f9bad2Sdanielk1977           aXRef[jj] = ii;
758c3f9bad2Sdanielk1977           break;
759c3f9bad2Sdanielk1977         }
760c3f9bad2Sdanielk1977       }
761c3f9bad2Sdanielk1977       if( jj>=pTab->nCol ){
762*da93d238Sdrh         sqliteErrorMsg(pParse, "no such column: %s", pChanges->a[ii].zName);
763c3f9bad2Sdanielk1977         goto trigger_cleanup;
764c3f9bad2Sdanielk1977       }
765c3f9bad2Sdanielk1977     }
766c3f9bad2Sdanielk1977 
767c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_Integer, 13, 0);
768c3f9bad2Sdanielk1977 
769633ed08dSdanielk1977     for(ii = 0; ii<pTab->nCol; ii++){
770633ed08dSdanielk1977       if( aXRef[ii] < 0 ){
771c3f9bad2Sdanielk1977         sqliteVdbeAddOp(v, OP_Column, oldIdx, ii);
772633ed08dSdanielk1977       }else{
773c3f9bad2Sdanielk1977         sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);
774633ed08dSdanielk1977       }
775633ed08dSdanielk1977     }
776c3f9bad2Sdanielk1977 
777c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
778c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
779c3f9bad2Sdanielk1977     sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);
780c3f9bad2Sdanielk1977 
781c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE,
7826f34903eSdanielk1977         pTab, newIdx, oldIdx, orconf, endOfLoop);
783c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER,
7846f34903eSdanielk1977         pTab, newIdx, oldIdx, orconf, endOfLoop);
785c3f9bad2Sdanielk1977   }else{
786c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx,
7876f34903eSdanielk1977         orconf, endOfLoop);
788c3f9bad2Sdanielk1977     sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx,
7896f34903eSdanielk1977         orconf, endOfLoop);
790c3f9bad2Sdanielk1977   }
791c3f9bad2Sdanielk1977 
792c3f9bad2Sdanielk1977   sqliteVdbeAddOp(v, OP_Next, oldIdx, startOfLoop);
793c3f9bad2Sdanielk1977 
794c3f9bad2Sdanielk1977   sqliteVdbeResolveLabel(v, endOfLoop);
795c3f9bad2Sdanielk1977   sqliteEndWriteOperation(pParse);
796c3f9bad2Sdanielk1977 
797c3f9bad2Sdanielk1977 trigger_cleanup:
798c3f9bad2Sdanielk1977   sqliteFree(aXRef);
799c3f9bad2Sdanielk1977   sqliteExprListDelete(pChanges);
800c3f9bad2Sdanielk1977   sqliteExprDelete(pWhere);
801c3f9bad2Sdanielk1977   sqliteExprListDelete(theSelect.pEList);
802ad3cab52Sdrh   sqliteSrcListDelete(theSelect.pSrc);
803c3f9bad2Sdanielk1977   sqliteExprDelete(theSelect.pWhere);
804c3f9bad2Sdanielk1977   return;
805c3f9bad2Sdanielk1977 }
806