PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - sqlite/libsqlite/src - trigger.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 319
Code covered: 1.6 % Executed lines: 5
Legend: not executed executed

       1                 : /*
       2                 : **
       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                 : *
      12                 : */
      13                 : #include "sqliteInt.h"
      14                 : 
      15                 : /*
      16                 : ** Delete a linked list of TriggerStep structures.
      17                 : */
      18               0 : void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
      19               0 :   while( pTriggerStep ){
      20               0 :     TriggerStep * pTmp = pTriggerStep;
      21               0 :     pTriggerStep = pTriggerStep->pNext;
      22                 : 
      23               0 :     if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
      24               0 :     sqliteExprDelete(pTmp->pWhere);
      25               0 :     sqliteExprListDelete(pTmp->pExprList);
      26               0 :     sqliteSelectDelete(pTmp->pSelect);
      27               0 :     sqliteIdListDelete(pTmp->pIdList);
      28                 : 
      29               0 :     sqliteFree(pTmp);
      30                 :   }
      31               0 : }
      32                 : 
      33                 : /*
      34                 : ** This is called by the parser when it sees a CREATE TRIGGER statement
      35                 : ** up to the point of the BEGIN before the trigger actions.  A Trigger
      36                 : ** structure is generated based on the information available and stored
      37                 : ** in pParse->pNewTrigger.  After the trigger actions have been parsed, the
      38                 : ** sqliteFinishTrigger() function is called to complete the trigger
      39                 : ** construction process.
      40                 : */
      41                 : void sqliteBeginTrigger(
      42                 :   Parse *pParse,      /* The parse context of the CREATE TRIGGER statement */
      43                 :   Token *pName,       /* The name of the trigger */
      44                 :   int tr_tm,          /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
      45                 :   int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
      46                 :   IdList *pColumns,   /* column list if this is an UPDATE OF trigger */
      47                 :   SrcList *pTableName,/* The name of the table/view the trigger applies to */
      48                 :   int foreach,        /* One of TK_ROW or TK_STATEMENT */
      49                 :   Expr *pWhen,        /* WHEN clause */
      50                 :   int isTemp          /* True if the TEMPORARY keyword is present */
      51               0 : ){
      52                 :   Trigger *nt;
      53                 :   Table   *tab;
      54               0 :   char *zName = 0;        /* Name of the trigger */
      55               0 :   sqlite *db = pParse->db;
      56                 :   int iDb;                /* When database to store the trigger in */
      57                 :   DbFixer sFix;
      58                 : 
      59                 :   /* Check that: 
      60                 :   ** 1. the trigger name does not already exist.
      61                 :   ** 2. the table (or view) does exist in the same database as the trigger.
      62                 :   ** 3. that we are not trying to create a trigger on the sqlite_master table
      63                 :   ** 4. That we are not trying to create an INSTEAD OF trigger on a table.
      64                 :   ** 5. That we are not trying to create a BEFORE or AFTER trigger on a view.
      65                 :   */
      66               0 :   if( sqlite_malloc_failed ) goto trigger_cleanup;
      67                 :   assert( pTableName->nSrc==1 );
      68               0 :   if( db->init.busy
      69                 :    && sqliteFixInit(&sFix, pParse, db->init.iDb, "trigger", pName)
      70                 :    && sqliteFixSrcList(&sFix, pTableName)
      71                 :   ){
      72               0 :     goto trigger_cleanup;
      73                 :   }
      74               0 :   tab = sqliteSrcListLookup(pParse, pTableName);
      75               0 :   if( !tab ){
      76               0 :     goto trigger_cleanup;
      77                 :   }
      78               0 :   iDb = isTemp ? 1 : tab->iDb;
      79               0 :   if( iDb>=2 && !db->init.busy ){
      80               0 :     sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
      81                 :        "database %s", db->aDb[tab->iDb].zName);
      82               0 :     goto trigger_cleanup;
      83                 :   }
      84                 : 
      85               0 :   zName = sqliteStrNDup(pName->z, pName->n);
      86               0 :   sqliteDequote(zName);
      87               0 :   if( sqliteHashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
      88               0 :     sqliteErrorMsg(pParse, "trigger %T already exists", pName);
      89               0 :     goto trigger_cleanup;
      90                 :   }
      91               0 :   if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
      92               0 :     sqliteErrorMsg(pParse, "cannot create trigger on system table");
      93               0 :     pParse->nErr++;
      94               0 :     goto trigger_cleanup;
      95                 :   }
      96               0 :   if( tab->pSelect && tr_tm != TK_INSTEAD ){
      97               0 :     sqliteErrorMsg(pParse, "cannot create %s trigger on view: %S", 
      98                 :         (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
      99               0 :     goto trigger_cleanup;
     100                 :   }
     101               0 :   if( !tab->pSelect && tr_tm == TK_INSTEAD ){
     102               0 :     sqliteErrorMsg(pParse, "cannot create INSTEAD OF"
     103                 :         " trigger on table: %S", pTableName, 0);
     104               0 :     goto trigger_cleanup;
     105                 :   }
     106                 : #ifndef SQLITE_OMIT_AUTHORIZATION
     107                 :   {
     108               0 :     int code = SQLITE_CREATE_TRIGGER;
     109               0 :     const char *zDb = db->aDb[tab->iDb].zName;
     110               0 :     const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
     111               0 :     if( tab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
     112               0 :     if( sqliteAuthCheck(pParse, code, zName, tab->zName, zDbTrig) ){
     113               0 :       goto trigger_cleanup;
     114                 :     }
     115               0 :     if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0, zDb)){
     116               0 :       goto trigger_cleanup;
     117                 :     }
     118                 :   }
     119                 : #endif
     120                 : 
     121                 :   /* INSTEAD OF triggers can only appear on views and BEGIN triggers
     122                 :   ** cannot appear on views.  So we might as well translate every
     123                 :   ** INSTEAD OF trigger into a BEFORE trigger.  It simplifies code
     124                 :   ** elsewhere.
     125                 :   */
     126               0 :   if (tr_tm == TK_INSTEAD){
     127               0 :     tr_tm = TK_BEFORE;
     128                 :   }
     129                 : 
     130                 :   /* Build the Trigger object */
     131               0 :   nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
     132               0 :   if( nt==0 ) goto trigger_cleanup;
     133               0 :   nt->name = zName;
     134               0 :   zName = 0;
     135               0 :   nt->table = sqliteStrDup(pTableName->a[0].zName);
     136               0 :   if( sqlite_malloc_failed ) goto trigger_cleanup;
     137               0 :   nt->iDb = iDb;
     138               0 :   nt->iTabDb = tab->iDb;
     139               0 :   nt->op = op;
     140               0 :   nt->tr_tm = tr_tm;
     141               0 :   nt->pWhen = sqliteExprDup(pWhen);
     142               0 :   nt->pColumns = sqliteIdListDup(pColumns);
     143               0 :   nt->foreach = foreach;
     144               0 :   sqliteTokenCopy(&nt->nameToken,pName);
     145                 :   assert( pParse->pNewTrigger==0 );
     146               0 :   pParse->pNewTrigger = nt;
     147                 : 
     148               0 : trigger_cleanup:
     149               0 :   sqliteFree(zName);
     150               0 :   sqliteSrcListDelete(pTableName);
     151               0 :   sqliteIdListDelete(pColumns);
     152               0 :   sqliteExprDelete(pWhen);
     153               0 : }
     154                 : 
     155                 : /*
     156                 : ** This routine is called after all of the trigger actions have been parsed
     157                 : ** in order to complete the process of building the trigger.
     158                 : */
     159                 : void sqliteFinishTrigger(
     160                 :   Parse *pParse,          /* Parser context */
     161                 :   TriggerStep *pStepList, /* The triggered program */
     162                 :   Token *pAll             /* Token that describes the complete CREATE TRIGGER */
     163               0 : ){
     164               0 :   Trigger *nt = 0;          /* The trigger whose construction is finishing up */
     165               0 :   sqlite *db = pParse->db;  /* The database */
     166                 :   DbFixer sFix;
     167                 : 
     168               0 :   if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
     169               0 :   nt = pParse->pNewTrigger;
     170               0 :   pParse->pNewTrigger = 0;
     171               0 :   nt->step_list = pStepList;
     172               0 :   while( pStepList ){
     173               0 :     pStepList->pTrig = nt;
     174               0 :     pStepList = pStepList->pNext;
     175                 :   }
     176               0 :   if( sqliteFixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken) 
     177                 :           && sqliteFixTriggerStep(&sFix, nt->step_list) ){
     178               0 :     goto triggerfinish_cleanup;
     179                 :   }
     180                 : 
     181                 :   /* if we are not initializing, and this trigger is not on a TEMP table, 
     182                 :   ** build the sqlite_master entry
     183                 :   */
     184               0 :   if( !db->init.busy ){
     185                 :     static VdbeOpList insertTrig[] = {
     186                 :       { OP_NewRecno,   0, 0,  0          },
     187                 :       { OP_String,     0, 0,  "trigger"  },
     188                 :       { OP_String,     0, 0,  0          },  /* 2: trigger name */
     189                 :       { OP_String,     0, 0,  0          },  /* 3: table name */
     190                 :       { OP_Integer,    0, 0,  0          },
     191                 :       { OP_String,     0, 0,  0          },  /* 5: SQL */
     192                 :       { OP_MakeRecord, 5, 0,  0          },
     193                 :       { OP_PutIntKey,  0, 0,  0          },
     194                 :     };
     195                 :     int addr;
     196                 :     Vdbe *v;
     197                 : 
     198                 :     /* Make an entry in the sqlite_master table */
     199               0 :     v = sqliteGetVdbe(pParse);
     200               0 :     if( v==0 ) goto triggerfinish_cleanup;
     201               0 :     sqliteBeginWriteOperation(pParse, 0, 0);
     202               0 :     sqliteOpenMasterTable(v, nt->iDb);
     203               0 :     addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
     204               0 :     sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 
     205               0 :     sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 
     206               0 :     sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
     207               0 :     if( nt->iDb==0 ){
     208               0 :       sqliteChangeCookie(db, v);
     209                 :     }
     210               0 :     sqliteVdbeAddOp(v, OP_Close, 0, 0);
     211               0 :     sqliteEndWriteOperation(pParse);
     212                 :   }
     213                 : 
     214               0 :   if( !pParse->explain ){
     215                 :     Table *pTab;
     216               0 :     sqliteHashInsert(&db->aDb[nt->iDb].trigHash, 
     217                 :                      nt->name, strlen(nt->name)+1, nt);
     218               0 :     pTab = sqliteLocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
     219                 :     assert( pTab!=0 );
     220               0 :     nt->pNext = pTab->pTrigger;
     221               0 :     pTab->pTrigger = nt;
     222               0 :     nt = 0;
     223                 :   }
     224                 : 
     225               0 : triggerfinish_cleanup:
     226               0 :   sqliteDeleteTrigger(nt);
     227               0 :   sqliteDeleteTrigger(pParse->pNewTrigger);
     228               0 :   pParse->pNewTrigger = 0;
     229               0 :   sqliteDeleteTriggerStep(pStepList);
     230               0 : }
     231                 : 
     232                 : /*
     233                 : ** Make a copy of all components of the given trigger step.  This has
     234                 : ** the effect of copying all Expr.token.z values into memory obtained
     235                 : ** from sqliteMalloc().  As initially created, the Expr.token.z values
     236                 : ** all point to the input string that was fed to the parser.  But that
     237                 : ** string is ephemeral - it will go away as soon as the sqlite_exec()
     238                 : ** call that started the parser exits.  This routine makes a persistent
     239                 : ** copy of all the Expr.token.z strings so that the TriggerStep structure
     240                 : ** will be valid even after the sqlite_exec() call returns.
     241                 : */
     242               0 : static void sqlitePersistTriggerStep(TriggerStep *p){
     243               0 :   if( p->target.z ){
     244               0 :     p->target.z = sqliteStrNDup(p->target.z, p->target.n);
     245               0 :     p->target.dyn = 1;
     246                 :   }
     247               0 :   if( p->pSelect ){
     248               0 :     Select *pNew = sqliteSelectDup(p->pSelect);
     249               0 :     sqliteSelectDelete(p->pSelect);
     250               0 :     p->pSelect = pNew;
     251                 :   }
     252               0 :   if( p->pWhere ){
     253               0 :     Expr *pNew = sqliteExprDup(p->pWhere);
     254               0 :     sqliteExprDelete(p->pWhere);
     255               0 :     p->pWhere = pNew;
     256                 :   }
     257               0 :   if( p->pExprList ){
     258               0 :     ExprList *pNew = sqliteExprListDup(p->pExprList);
     259               0 :     sqliteExprListDelete(p->pExprList);
     260               0 :     p->pExprList = pNew;
     261                 :   }
     262               0 :   if( p->pIdList ){
     263               0 :     IdList *pNew = sqliteIdListDup(p->pIdList);
     264               0 :     sqliteIdListDelete(p->pIdList);
     265               0 :     p->pIdList = pNew;
     266                 :   }
     267               0 : }
     268                 : 
     269                 : /*
     270                 : ** Turn a SELECT statement (that the pSelect parameter points to) into
     271                 : ** a trigger step.  Return a pointer to a TriggerStep structure.
     272                 : **
     273                 : ** The parser calls this routine when it finds a SELECT statement in
     274                 : ** body of a TRIGGER.  
     275                 : */
     276               0 : TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
     277               0 :   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
     278               0 :   if( pTriggerStep==0 ) return 0;
     279                 : 
     280               0 :   pTriggerStep->op = TK_SELECT;
     281               0 :   pTriggerStep->pSelect = pSelect;
     282               0 :   pTriggerStep->orconf = OE_Default;
     283               0 :   sqlitePersistTriggerStep(pTriggerStep);
     284                 : 
     285               0 :   return pTriggerStep;
     286                 : }
     287                 : 
     288                 : /*
     289                 : ** Build a trigger step out of an INSERT statement.  Return a pointer
     290                 : ** to the new trigger step.
     291                 : **
     292                 : ** The parser calls this routine when it sees an INSERT inside the
     293                 : ** body of a trigger.
     294                 : */
     295                 : TriggerStep *sqliteTriggerInsertStep(
     296                 :   Token *pTableName,  /* Name of the table into which we insert */
     297                 :   IdList *pColumn,    /* List of columns in pTableName to insert into */
     298                 :   ExprList *pEList,   /* The VALUE clause: a list of values to be inserted */
     299                 :   Select *pSelect,    /* A SELECT statement that supplies values */
     300                 :   int orconf          /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
     301               0 : ){
     302               0 :   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
     303               0 :   if( pTriggerStep==0 ) return 0;
     304                 : 
     305                 :   assert(pEList == 0 || pSelect == 0);
     306                 :   assert(pEList != 0 || pSelect != 0);
     307                 : 
     308               0 :   pTriggerStep->op = TK_INSERT;
     309               0 :   pTriggerStep->pSelect = pSelect;
     310               0 :   pTriggerStep->target  = *pTableName;
     311               0 :   pTriggerStep->pIdList = pColumn;
     312               0 :   pTriggerStep->pExprList = pEList;
     313               0 :   pTriggerStep->orconf = orconf;
     314               0 :   sqlitePersistTriggerStep(pTriggerStep);
     315                 : 
     316               0 :   return pTriggerStep;
     317                 : }
     318                 : 
     319                 : /*
     320                 : ** Construct a trigger step that implements an UPDATE statement and return
     321                 : ** a pointer to that trigger step.  The parser calls this routine when it
     322                 : ** sees an UPDATE statement inside the body of a CREATE TRIGGER.
     323                 : */
     324                 : TriggerStep *sqliteTriggerUpdateStep(
     325                 :   Token *pTableName,   /* Name of the table to be updated */
     326                 :   ExprList *pEList,    /* The SET clause: list of column and new values */
     327                 :   Expr *pWhere,        /* The WHERE clause */
     328                 :   int orconf           /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
     329               0 : ){
     330               0 :   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
     331               0 :   if( pTriggerStep==0 ) return 0;
     332                 : 
     333               0 :   pTriggerStep->op = TK_UPDATE;
     334               0 :   pTriggerStep->target  = *pTableName;
     335               0 :   pTriggerStep->pExprList = pEList;
     336               0 :   pTriggerStep->pWhere = pWhere;
     337               0 :   pTriggerStep->orconf = orconf;
     338               0 :   sqlitePersistTriggerStep(pTriggerStep);
     339                 : 
     340               0 :   return pTriggerStep;
     341                 : }
     342                 : 
     343                 : /*
     344                 : ** Construct a trigger step that implements a DELETE statement and return
     345                 : ** a pointer to that trigger step.  The parser calls this routine when it
     346                 : ** sees a DELETE statement inside the body of a CREATE TRIGGER.
     347                 : */
     348               0 : TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
     349               0 :   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
     350               0 :   if( pTriggerStep==0 ) return 0;
     351                 : 
     352               0 :   pTriggerStep->op = TK_DELETE;
     353               0 :   pTriggerStep->target  = *pTableName;
     354               0 :   pTriggerStep->pWhere = pWhere;
     355               0 :   pTriggerStep->orconf = OE_Default;
     356               0 :   sqlitePersistTriggerStep(pTriggerStep);
     357                 : 
     358               0 :   return pTriggerStep;
     359                 : }
     360                 : 
     361                 : /* 
     362                 : ** Recursively delete a Trigger structure
     363                 : */
     364               0 : void sqliteDeleteTrigger(Trigger *pTrigger){
     365               0 :   if( pTrigger==0 ) return;
     366               0 :   sqliteDeleteTriggerStep(pTrigger->step_list);
     367               0 :   sqliteFree(pTrigger->name);
     368               0 :   sqliteFree(pTrigger->table);
     369               0 :   sqliteExprDelete(pTrigger->pWhen);
     370               0 :   sqliteIdListDelete(pTrigger->pColumns);
     371               0 :   if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
     372               0 :   sqliteFree(pTrigger);
     373                 : }
     374                 : 
     375                 : /*
     376                 :  * This function is called to drop a trigger from the database schema. 
     377                 :  *
     378                 :  * This may be called directly from the parser and therefore identifies
     379                 :  * the trigger by name.  The sqliteDropTriggerPtr() routine does the
     380                 :  * same job as this routine except it take a spointer to the trigger
     381                 :  * instead of the trigger name.
     382                 :  *
     383                 :  * Note that this function does not delete the trigger entirely. Instead it
     384                 :  * removes it from the internal schema and places it in the trigDrop hash 
     385                 :  * table. This is so that the trigger can be restored into the database schema
     386                 :  * if the transaction is rolled back.
     387                 :  */
     388               0 : void sqliteDropTrigger(Parse *pParse, SrcList *pName){
     389                 :   Trigger *pTrigger;
     390                 :   int i;
     391                 :   const char *zDb;
     392                 :   const char *zName;
     393                 :   int nName;
     394               0 :   sqlite *db = pParse->db;
     395                 : 
     396               0 :   if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
     397                 :   assert( pName->nSrc==1 );
     398               0 :   zDb = pName->a[0].zDatabase;
     399               0 :   zName = pName->a[0].zName;
     400               0 :   nName = strlen(zName);
     401               0 :   for(i=0; i<db->nDb; i++){
     402               0 :     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
     403               0 :     if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
     404               0 :     pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
     405               0 :     if( pTrigger ) break;
     406                 :   }
     407               0 :   if( !pTrigger ){
     408               0 :     sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0);
     409               0 :     goto drop_trigger_cleanup;
     410                 :   }
     411               0 :   sqliteDropTriggerPtr(pParse, pTrigger, 0);
     412                 : 
     413               0 : drop_trigger_cleanup:
     414               0 :   sqliteSrcListDelete(pName);
     415               0 : }
     416                 : 
     417                 : /*
     418                 : ** Drop a trigger given a pointer to that trigger.  If nested is false,
     419                 : ** then also generate code to remove the trigger from the SQLITE_MASTER
     420                 : ** table.
     421                 : */
     422               0 : void sqliteDropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
     423                 :   Table   *pTable;
     424                 :   Vdbe *v;
     425               0 :   sqlite *db = pParse->db;
     426                 : 
     427                 :   assert( pTrigger->iDb<db->nDb );
     428               0 :   if( pTrigger->iDb>=2 ){
     429               0 :     sqliteErrorMsg(pParse, "triggers may not be removed from "
     430                 :        "auxiliary database %s", db->aDb[pTrigger->iDb].zName);
     431               0 :     return;
     432                 :   }
     433               0 :   pTable = sqliteFindTable(db, pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
     434                 :   assert(pTable);
     435                 :   assert( pTable->iDb==pTrigger->iDb || pTrigger->iDb==1 );
     436                 : #ifndef SQLITE_OMIT_AUTHORIZATION
     437                 :   {
     438               0 :     int code = SQLITE_DROP_TRIGGER;
     439               0 :     const char *zDb = db->aDb[pTrigger->iDb].zName;
     440               0 :     const char *zTab = SCHEMA_TABLE(pTrigger->iDb);
     441               0 :     if( pTrigger->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
     442               0 :     if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
     443                 :       sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
     444               0 :       return;
     445                 :     }
     446                 :   }
     447                 : #endif
     448                 : 
     449                 :   /* Generate code to destroy the database record of the trigger.
     450                 :   */
     451               0 :   if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
     452                 :     int base;
     453                 :     static VdbeOpList dropTrigger[] = {
     454                 :       { OP_Rewind,     0, ADDR(9),  0},
     455                 :       { OP_String,     0, 0,        0}, /* 1 */
     456                 :       { OP_Column,     0, 1,        0},
     457                 :       { OP_Ne,         0, ADDR(8),  0},
     458                 :       { OP_String,     0, 0,        "trigger"},
     459                 :       { OP_Column,     0, 0,        0},
     460                 :       { OP_Ne,         0, ADDR(8),  0},
     461                 :       { OP_Delete,     0, 0,        0},
     462                 :       { OP_Next,       0, ADDR(1),  0}, /* 8 */
     463                 :     };
     464                 : 
     465               0 :     sqliteBeginWriteOperation(pParse, 0, 0);
     466               0 :     sqliteOpenMasterTable(v, pTrigger->iDb);
     467               0 :     base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
     468               0 :     sqliteVdbeChangeP3(v, base+1, pTrigger->name, 0);
     469               0 :     if( pTrigger->iDb==0 ){
     470               0 :       sqliteChangeCookie(db, v);
     471                 :     }
     472               0 :     sqliteVdbeAddOp(v, OP_Close, 0, 0);
     473               0 :     sqliteEndWriteOperation(pParse);
     474                 :   }
     475                 : 
     476                 :   /*
     477                 :    * If this is not an "explain", then delete the trigger structure.
     478                 :    */
     479               0 :   if( !pParse->explain ){
     480               0 :     const char *zName = pTrigger->name;
     481               0 :     int nName = strlen(zName);
     482               0 :     if( pTable->pTrigger == pTrigger ){
     483               0 :       pTable->pTrigger = pTrigger->pNext;
     484                 :     }else{
     485               0 :       Trigger *cc = pTable->pTrigger;
     486               0 :       while( cc ){ 
     487               0 :         if( cc->pNext == pTrigger ){
     488               0 :           cc->pNext = cc->pNext->pNext;
     489               0 :           break;
     490                 :         }
     491               0 :         cc = cc->pNext;
     492                 :       }
     493                 :       assert(cc);
     494                 :     }
     495               0 :     sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
     496               0 :     sqliteDeleteTrigger(pTrigger);
     497                 :   }
     498                 : }
     499                 : 
     500                 : /*
     501                 : ** pEList is the SET clause of an UPDATE statement.  Each entry
     502                 : ** in pEList is of the format <id>=<expr>.  If any of the entries
     503                 : ** in pEList have an <id> which matches an identifier in pIdList,
     504                 : ** then return TRUE.  If pIdList==NULL, then it is considered a
     505                 : ** wildcard that matches anything.  Likewise if pEList==NULL then
     506                 : ** it matches anything so always return true.  Return false only
     507                 : ** if there is no match.
     508                 : */
     509               0 : static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
     510                 :   int e;
     511               0 :   if( !pIdList || !pEList ) return 1;
     512               0 :   for(e=0; e<pEList->nExpr; e++){
     513               0 :     if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
     514                 :   }
     515               0 :   return 0; 
     516                 : }
     517                 : 
     518                 : /* A global variable that is TRUE if we should always set up temp tables for
     519                 :  * for triggers, even if there are no triggers to code. This is used to test 
     520                 :  * how much overhead the triggers algorithm is causing.
     521                 :  *
     522                 :  * This flag can be set or cleared using the "trigger_overhead_test" pragma.
     523                 :  * The pragma is not documented since it is not really part of the interface
     524                 :  * to SQLite, just the test procedure.
     525                 : */
     526                 : int always_code_trigger_setup = 0;
     527                 : 
     528                 : /*
     529                 :  * Returns true if a trigger matching op, tr_tm and foreach that is NOT already
     530                 :  * on the Parse objects trigger-stack (to prevent recursive trigger firing) is
     531                 :  * found in the list specified as pTrigger.
     532                 :  */
     533                 : int sqliteTriggersExist(
     534                 :   Parse *pParse,          /* Used to check for recursive triggers */
     535                 :   Trigger *pTrigger,      /* A list of triggers associated with a table */
     536                 :   int op,                 /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
     537                 :   int tr_tm,              /* one of TK_BEFORE, TK_AFTER */
     538                 :   int foreach,            /* one of TK_ROW or TK_STATEMENT */
     539                 :   ExprList *pChanges      /* Columns that change in an UPDATE statement */
     540             530 : ){
     541                 :   Trigger * pTriggerCursor;
     542                 : 
     543             530 :   if( always_code_trigger_setup ){
     544               0 :     return 1;
     545                 :   }
     546                 : 
     547             530 :   pTriggerCursor = pTrigger;
     548            1060 :   while( pTriggerCursor ){
     549               0 :     if( pTriggerCursor->op == op && 
     550                 :         pTriggerCursor->tr_tm == tr_tm && 
     551                 :         pTriggerCursor->foreach == foreach &&
     552                 :         checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
     553                 :       TriggerStack * ss;
     554               0 :       ss = pParse->trigStack;
     555               0 :       while( ss && ss->pTrigger != pTrigger ){
     556               0 :         ss = ss->pNext;
     557                 :       }
     558               0 :       if( !ss )return 1;
     559                 :     }
     560               0 :     pTriggerCursor = pTriggerCursor->pNext;
     561                 :   }
     562                 : 
     563             530 :   return 0;
     564                 : }
     565                 : 
     566                 : /*
     567                 : ** Convert the pStep->target token into a SrcList and return a pointer
     568                 : ** to that SrcList.
     569                 : **
     570                 : ** This routine adds a specific database name, if needed, to the target when
     571                 : ** forming the SrcList.  This prevents a trigger in one database from
     572                 : ** referring to a target in another database.  An exception is when the
     573                 : ** trigger is in TEMP in which case it can refer to any other database it
     574                 : ** wants.
     575                 : */
     576                 : static SrcList *targetSrcList(
     577                 :   Parse *pParse,       /* The parsing context */
     578                 :   TriggerStep *pStep   /* The trigger containing the target token */
     579               0 : ){
     580                 :   Token sDb;           /* Dummy database name token */
     581                 :   int iDb;             /* Index of the database to use */
     582                 :   SrcList *pSrc;       /* SrcList to be returned */
     583                 : 
     584               0 :   iDb = pStep->pTrig->iDb;
     585               0 :   if( iDb==0 || iDb>=2 ){
     586                 :     assert( iDb<pParse->db->nDb );
     587               0 :     sDb.z = pParse->db->aDb[iDb].zName;
     588               0 :     sDb.n = strlen(sDb.z);
     589               0 :     pSrc = sqliteSrcListAppend(0, &sDb, &pStep->target);
     590                 :   } else {
     591               0 :     pSrc = sqliteSrcListAppend(0, &pStep->target, 0);
     592                 :   }
     593               0 :   return pSrc;
     594                 : }
     595                 : 
     596                 : /*
     597                 : ** Generate VDBE code for zero or more statements inside the body of a
     598                 : ** trigger.  
     599                 : */
     600                 : static int codeTriggerProgram(
     601                 :   Parse *pParse,            /* The parser context */
     602                 :   TriggerStep *pStepList,   /* List of statements inside the trigger body */
     603                 :   int orconfin              /* Conflict algorithm. (OE_Abort, etc) */  
     604               0 : ){
     605               0 :   TriggerStep * pTriggerStep = pStepList;
     606                 :   int orconf;
     607                 : 
     608               0 :   while( pTriggerStep ){
     609               0 :     int saveNTab = pParse->nTab;
     610                 :  
     611               0 :     orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
     612               0 :     pParse->trigStack->orconf = orconf;
     613               0 :     switch( pTriggerStep->op ){
     614                 :       case TK_SELECT: {
     615               0 :         Select * ss = sqliteSelectDup(pTriggerStep->pSelect);                  
     616                 :         assert(ss);
     617                 :         assert(ss->pSrc);
     618               0 :         sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
     619               0 :         sqliteSelectDelete(ss);
     620               0 :         break;
     621                 :       }
     622                 :       case TK_UPDATE: {
     623                 :         SrcList *pSrc;
     624               0 :         pSrc = targetSrcList(pParse, pTriggerStep);
     625               0 :         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
     626               0 :         sqliteUpdate(pParse, pSrc,
     627                 :                 sqliteExprListDup(pTriggerStep->pExprList), 
     628                 :                 sqliteExprDup(pTriggerStep->pWhere), orconf);
     629               0 :         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
     630               0 :         break;
     631                 :       }
     632                 :       case TK_INSERT: {
     633                 :         SrcList *pSrc;
     634               0 :         pSrc = targetSrcList(pParse, pTriggerStep);
     635               0 :         sqliteInsert(pParse, pSrc,
     636                 :           sqliteExprListDup(pTriggerStep->pExprList), 
     637                 :           sqliteSelectDup(pTriggerStep->pSelect), 
     638                 :           sqliteIdListDup(pTriggerStep->pIdList), orconf);
     639               0 :         break;
     640                 :       }
     641                 :       case TK_DELETE: {
     642                 :         SrcList *pSrc;
     643               0 :         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
     644               0 :         pSrc = targetSrcList(pParse, pTriggerStep);
     645               0 :         sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
     646               0 :         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
     647                 :         break;
     648                 :       }
     649                 :       default:
     650                 :         assert(0);
     651                 :     } 
     652               0 :     pParse->nTab = saveNTab;
     653               0 :     pTriggerStep = pTriggerStep->pNext;
     654                 :   }
     655                 : 
     656               0 :   return 0;
     657                 : }
     658                 : 
     659                 : /*
     660                 : ** This is called to code FOR EACH ROW triggers.
     661                 : **
     662                 : ** When the code that this function generates is executed, the following 
     663                 : ** must be true:
     664                 : **
     665                 : ** 1. No cursors may be open in the main database.  (But newIdx and oldIdx
     666                 : **    can be indices of cursors in temporary tables.  See below.)
     667                 : **
     668                 : ** 2. If the triggers being coded are ON INSERT or ON UPDATE triggers, then
     669                 : **    a temporary vdbe cursor (index newIdx) must be open and pointing at
     670                 : **    a row containing values to be substituted for new.* expressions in the
     671                 : **    trigger program(s).
     672                 : **
     673                 : ** 3. If the triggers being coded are ON DELETE or ON UPDATE triggers, then
     674                 : **    a temporary vdbe cursor (index oldIdx) must be open and pointing at
     675                 : **    a row containing values to be substituted for old.* expressions in the
     676                 : **    trigger program(s).
     677                 : **
     678                 : */
     679                 : int sqliteCodeRowTrigger(
     680                 :   Parse *pParse,       /* Parse context */
     681                 :   int op,              /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
     682                 :   ExprList *pChanges,  /* Changes list for any UPDATE OF triggers */
     683                 :   int tr_tm,           /* One of TK_BEFORE, TK_AFTER */
     684                 :   Table *pTab,         /* The table to code triggers from */
     685                 :   int newIdx,          /* The indice of the "new" row to access */
     686                 :   int oldIdx,          /* The indice of the "old" row to access */
     687                 :   int orconf,          /* ON CONFLICT policy */
     688                 :   int ignoreJump       /* Instruction to jump to for RAISE(IGNORE) */
     689               0 : ){
     690                 :   Trigger * pTrigger;
     691                 :   TriggerStack * pTriggerStack;
     692                 : 
     693                 :   assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
     694                 :   assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
     695                 : 
     696                 :   assert(newIdx != -1 || oldIdx != -1);
     697                 : 
     698               0 :   pTrigger = pTab->pTrigger;
     699               0 :   while( pTrigger ){
     700               0 :     int fire_this = 0;
     701                 : 
     702                 :     /* determine whether we should code this trigger */
     703               0 :     if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 
     704                 :         pTrigger->foreach == TK_ROW ){
     705               0 :       fire_this = 1;
     706               0 :       pTriggerStack = pParse->trigStack;
     707               0 :       while( pTriggerStack ){
     708               0 :         if( pTriggerStack->pTrigger == pTrigger ){
     709               0 :           fire_this = 0;
     710                 :         }
     711               0 :         pTriggerStack = pTriggerStack->pNext;
     712                 :       }
     713               0 :       if( op == TK_UPDATE && pTrigger->pColumns &&
     714                 :           !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
     715               0 :         fire_this = 0;
     716                 :       }
     717                 :     }
     718                 : 
     719               0 :     if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
     720                 :       int endTrigger;
     721                 :       SrcList dummyTablist;
     722                 :       Expr * whenExpr;
     723                 :       AuthContext sContext;
     724                 : 
     725               0 :       dummyTablist.nSrc = 0;
     726                 : 
     727                 :       /* Push an entry on to the trigger stack */
     728               0 :       pTriggerStack->pTrigger = pTrigger;
     729               0 :       pTriggerStack->newIdx = newIdx;
     730               0 :       pTriggerStack->oldIdx = oldIdx;
     731               0 :       pTriggerStack->pTab = pTab;
     732               0 :       pTriggerStack->pNext = pParse->trigStack;
     733               0 :       pTriggerStack->ignoreJump = ignoreJump;
     734               0 :       pParse->trigStack = pTriggerStack;
     735               0 :       sqliteAuthContextPush(pParse, &sContext, pTrigger->name);
     736                 : 
     737                 :       /* code the WHEN clause */
     738               0 :       endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
     739               0 :       whenExpr = sqliteExprDup(pTrigger->pWhen);
     740               0 :       if( sqliteExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
     741               0 :         pParse->trigStack = pParse->trigStack->pNext;
     742               0 :         sqliteFree(pTriggerStack);
     743               0 :         sqliteExprDelete(whenExpr);
     744               0 :         return 1;
     745                 :       }
     746               0 :       sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
     747               0 :       sqliteExprDelete(whenExpr);
     748                 : 
     749               0 :       sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPush, 0, 0);
     750               0 :       codeTriggerProgram(pParse, pTrigger->step_list, orconf); 
     751               0 :       sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPop, 0, 0);
     752                 : 
     753                 :       /* Pop the entry off the trigger stack */
     754               0 :       pParse->trigStack = pParse->trigStack->pNext;
     755               0 :       sqliteAuthContextPop(&sContext);
     756               0 :       sqliteFree(pTriggerStack);
     757                 : 
     758               0 :       sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
     759                 :     }
     760               0 :     pTrigger = pTrigger->pNext;
     761                 :   }
     762                 : 
     763               0 :   return 0;
     764                 : }

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:20 +0000 (5 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.