Annotation of embedaddon/php/ext/sqlite/libsqlite/src/trigger.c, revision 1.1

1.1     ! misho       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: void sqliteDeleteTriggerStep(TriggerStep *pTriggerStep){
        !            19:   while( pTriggerStep ){
        !            20:     TriggerStep * pTmp = pTriggerStep;
        !            21:     pTriggerStep = pTriggerStep->pNext;
        !            22: 
        !            23:     if( pTmp->target.dyn ) sqliteFree((char*)pTmp->target.z);
        !            24:     sqliteExprDelete(pTmp->pWhere);
        !            25:     sqliteExprListDelete(pTmp->pExprList);
        !            26:     sqliteSelectDelete(pTmp->pSelect);
        !            27:     sqliteIdListDelete(pTmp->pIdList);
        !            28: 
        !            29:     sqliteFree(pTmp);
        !            30:   }
        !            31: }
        !            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: ){
        !            52:   Trigger *nt;
        !            53:   Table   *tab;
        !            54:   char *zName = 0;        /* Name of the trigger */
        !            55:   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:   if( sqlite_malloc_failed ) goto trigger_cleanup;
        !            67:   assert( pTableName->nSrc==1 );
        !            68:   if( db->init.busy
        !            69:    && sqliteFixInit(&sFix, pParse, db->init.iDb, "trigger", pName)
        !            70:    && sqliteFixSrcList(&sFix, pTableName)
        !            71:   ){
        !            72:     goto trigger_cleanup;
        !            73:   }
        !            74:   tab = sqliteSrcListLookup(pParse, pTableName);
        !            75:   if( !tab ){
        !            76:     goto trigger_cleanup;
        !            77:   }
        !            78:   iDb = isTemp ? 1 : tab->iDb;
        !            79:   if( iDb>=2 && !db->init.busy ){
        !            80:     sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
        !            81:        "database %s", db->aDb[tab->iDb].zName);
        !            82:     goto trigger_cleanup;
        !            83:   }
        !            84: 
        !            85:   zName = sqliteStrNDup(pName->z, pName->n);
        !            86:   sqliteDequote(zName);
        !            87:   if( sqliteHashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){
        !            88:     sqliteErrorMsg(pParse, "trigger %T already exists", pName);
        !            89:     goto trigger_cleanup;
        !            90:   }
        !            91:   if( sqliteStrNICmp(tab->zName, "sqlite_", 7)==0 ){
        !            92:     sqliteErrorMsg(pParse, "cannot create trigger on system table");
        !            93:     pParse->nErr++;
        !            94:     goto trigger_cleanup;
        !            95:   }
        !            96:   if( tab->pSelect && tr_tm != TK_INSTEAD ){
        !            97:     sqliteErrorMsg(pParse, "cannot create %s trigger on view: %S", 
        !            98:         (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
        !            99:     goto trigger_cleanup;
        !           100:   }
        !           101:   if( !tab->pSelect && tr_tm == TK_INSTEAD ){
        !           102:     sqliteErrorMsg(pParse, "cannot create INSTEAD OF"
        !           103:         " trigger on table: %S", pTableName, 0);
        !           104:     goto trigger_cleanup;
        !           105:   }
        !           106: #ifndef SQLITE_OMIT_AUTHORIZATION
        !           107:   {
        !           108:     int code = SQLITE_CREATE_TRIGGER;
        !           109:     const char *zDb = db->aDb[tab->iDb].zName;
        !           110:     const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
        !           111:     if( tab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
        !           112:     if( sqliteAuthCheck(pParse, code, zName, tab->zName, zDbTrig) ){
        !           113:       goto trigger_cleanup;
        !           114:     }
        !           115:     if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(tab->iDb), 0, zDb)){
        !           116:       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:   if (tr_tm == TK_INSTEAD){
        !           127:     tr_tm = TK_BEFORE;
        !           128:   }
        !           129: 
        !           130:   /* Build the Trigger object */
        !           131:   nt = (Trigger*)sqliteMalloc(sizeof(Trigger));
        !           132:   if( nt==0 ) goto trigger_cleanup;
        !           133:   nt->name = zName;
        !           134:   zName = 0;
        !           135:   nt->table = sqliteStrDup(pTableName->a[0].zName);
        !           136:   if( sqlite_malloc_failed ) goto trigger_cleanup;
        !           137:   nt->iDb = iDb;
        !           138:   nt->iTabDb = tab->iDb;
        !           139:   nt->op = op;
        !           140:   nt->tr_tm = tr_tm;
        !           141:   nt->pWhen = sqliteExprDup(pWhen);
        !           142:   nt->pColumns = sqliteIdListDup(pColumns);
        !           143:   nt->foreach = foreach;
        !           144:   sqliteTokenCopy(&nt->nameToken,pName);
        !           145:   assert( pParse->pNewTrigger==0 );
        !           146:   pParse->pNewTrigger = nt;
        !           147: 
        !           148: trigger_cleanup:
        !           149:   sqliteFree(zName);
        !           150:   sqliteSrcListDelete(pTableName);
        !           151:   sqliteIdListDelete(pColumns);
        !           152:   sqliteExprDelete(pWhen);
        !           153: }
        !           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: ){
        !           164:   Trigger *nt = 0;          /* The trigger whose construction is finishing up */
        !           165:   sqlite *db = pParse->db;  /* The database */
        !           166:   DbFixer sFix;
        !           167: 
        !           168:   if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
        !           169:   nt = pParse->pNewTrigger;
        !           170:   pParse->pNewTrigger = 0;
        !           171:   nt->step_list = pStepList;
        !           172:   while( pStepList ){
        !           173:     pStepList->pTrig = nt;
        !           174:     pStepList = pStepList->pNext;
        !           175:   }
        !           176:   if( sqliteFixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken) 
        !           177:           && sqliteFixTriggerStep(&sFix, nt->step_list) ){
        !           178:     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:   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:     v = sqliteGetVdbe(pParse);
        !           200:     if( v==0 ) goto triggerfinish_cleanup;
        !           201:     sqliteBeginWriteOperation(pParse, 0, 0);
        !           202:     sqliteOpenMasterTable(v, nt->iDb);
        !           203:     addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
        !           204:     sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 
        !           205:     sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 
        !           206:     sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
        !           207:     if( nt->iDb==0 ){
        !           208:       sqliteChangeCookie(db, v);
        !           209:     }
        !           210:     sqliteVdbeAddOp(v, OP_Close, 0, 0);
        !           211:     sqliteEndWriteOperation(pParse);
        !           212:   }
        !           213: 
        !           214:   if( !pParse->explain ){
        !           215:     Table *pTab;
        !           216:     sqliteHashInsert(&db->aDb[nt->iDb].trigHash, 
        !           217:                      nt->name, strlen(nt->name)+1, nt);
        !           218:     pTab = sqliteLocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
        !           219:     assert( pTab!=0 );
        !           220:     nt->pNext = pTab->pTrigger;
        !           221:     pTab->pTrigger = nt;
        !           222:     nt = 0;
        !           223:   }
        !           224: 
        !           225: triggerfinish_cleanup:
        !           226:   sqliteDeleteTrigger(nt);
        !           227:   sqliteDeleteTrigger(pParse->pNewTrigger);
        !           228:   pParse->pNewTrigger = 0;
        !           229:   sqliteDeleteTriggerStep(pStepList);
        !           230: }
        !           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: static void sqlitePersistTriggerStep(TriggerStep *p){
        !           243:   if( p->target.z ){
        !           244:     p->target.z = sqliteStrNDup(p->target.z, p->target.n);
        !           245:     p->target.dyn = 1;
        !           246:   }
        !           247:   if( p->pSelect ){
        !           248:     Select *pNew = sqliteSelectDup(p->pSelect);
        !           249:     sqliteSelectDelete(p->pSelect);
        !           250:     p->pSelect = pNew;
        !           251:   }
        !           252:   if( p->pWhere ){
        !           253:     Expr *pNew = sqliteExprDup(p->pWhere);
        !           254:     sqliteExprDelete(p->pWhere);
        !           255:     p->pWhere = pNew;
        !           256:   }
        !           257:   if( p->pExprList ){
        !           258:     ExprList *pNew = sqliteExprListDup(p->pExprList);
        !           259:     sqliteExprListDelete(p->pExprList);
        !           260:     p->pExprList = pNew;
        !           261:   }
        !           262:   if( p->pIdList ){
        !           263:     IdList *pNew = sqliteIdListDup(p->pIdList);
        !           264:     sqliteIdListDelete(p->pIdList);
        !           265:     p->pIdList = pNew;
        !           266:   }
        !           267: }
        !           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: TriggerStep *sqliteTriggerSelectStep(Select *pSelect){
        !           277:   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
        !           278:   if( pTriggerStep==0 ) return 0;
        !           279: 
        !           280:   pTriggerStep->op = TK_SELECT;
        !           281:   pTriggerStep->pSelect = pSelect;
        !           282:   pTriggerStep->orconf = OE_Default;
        !           283:   sqlitePersistTriggerStep(pTriggerStep);
        !           284: 
        !           285:   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: ){
        !           302:   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
        !           303:   if( pTriggerStep==0 ) return 0;
        !           304: 
        !           305:   assert(pEList == 0 || pSelect == 0);
        !           306:   assert(pEList != 0 || pSelect != 0);
        !           307: 
        !           308:   pTriggerStep->op = TK_INSERT;
        !           309:   pTriggerStep->pSelect = pSelect;
        !           310:   pTriggerStep->target  = *pTableName;
        !           311:   pTriggerStep->pIdList = pColumn;
        !           312:   pTriggerStep->pExprList = pEList;
        !           313:   pTriggerStep->orconf = orconf;
        !           314:   sqlitePersistTriggerStep(pTriggerStep);
        !           315: 
        !           316:   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: ){
        !           330:   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
        !           331:   if( pTriggerStep==0 ) return 0;
        !           332: 
        !           333:   pTriggerStep->op = TK_UPDATE;
        !           334:   pTriggerStep->target  = *pTableName;
        !           335:   pTriggerStep->pExprList = pEList;
        !           336:   pTriggerStep->pWhere = pWhere;
        !           337:   pTriggerStep->orconf = orconf;
        !           338:   sqlitePersistTriggerStep(pTriggerStep);
        !           339: 
        !           340:   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: TriggerStep *sqliteTriggerDeleteStep(Token *pTableName, Expr *pWhere){
        !           349:   TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
        !           350:   if( pTriggerStep==0 ) return 0;
        !           351: 
        !           352:   pTriggerStep->op = TK_DELETE;
        !           353:   pTriggerStep->target  = *pTableName;
        !           354:   pTriggerStep->pWhere = pWhere;
        !           355:   pTriggerStep->orconf = OE_Default;
        !           356:   sqlitePersistTriggerStep(pTriggerStep);
        !           357: 
        !           358:   return pTriggerStep;
        !           359: }
        !           360: 
        !           361: /* 
        !           362: ** Recursively delete a Trigger structure
        !           363: */
        !           364: void sqliteDeleteTrigger(Trigger *pTrigger){
        !           365:   if( pTrigger==0 ) return;
        !           366:   sqliteDeleteTriggerStep(pTrigger->step_list);
        !           367:   sqliteFree(pTrigger->name);
        !           368:   sqliteFree(pTrigger->table);
        !           369:   sqliteExprDelete(pTrigger->pWhen);
        !           370:   sqliteIdListDelete(pTrigger->pColumns);
        !           371:   if( pTrigger->nameToken.dyn ) sqliteFree((char*)pTrigger->nameToken.z);
        !           372:   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: void sqliteDropTrigger(Parse *pParse, SrcList *pName){
        !           389:   Trigger *pTrigger;
        !           390:   int i;
        !           391:   const char *zDb;
        !           392:   const char *zName;
        !           393:   int nName;
        !           394:   sqlite *db = pParse->db;
        !           395: 
        !           396:   if( sqlite_malloc_failed ) goto drop_trigger_cleanup;
        !           397:   assert( pName->nSrc==1 );
        !           398:   zDb = pName->a[0].zDatabase;
        !           399:   zName = pName->a[0].zName;
        !           400:   nName = strlen(zName);
        !           401:   for(i=0; i<db->nDb; i++){
        !           402:     int j = (i<2) ? i^1 : i;  /* Search TEMP before MAIN */
        !           403:     if( zDb && sqliteStrICmp(db->aDb[j].zName, zDb) ) continue;
        !           404:     pTrigger = sqliteHashFind(&(db->aDb[j].trigHash), zName, nName+1);
        !           405:     if( pTrigger ) break;
        !           406:   }
        !           407:   if( !pTrigger ){
        !           408:     sqliteErrorMsg(pParse, "no such trigger: %S", pName, 0);
        !           409:     goto drop_trigger_cleanup;
        !           410:   }
        !           411:   sqliteDropTriggerPtr(pParse, pTrigger, 0);
        !           412: 
        !           413: drop_trigger_cleanup:
        !           414:   sqliteSrcListDelete(pName);
        !           415: }
        !           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: void sqliteDropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
        !           423:   Table   *pTable;
        !           424:   Vdbe *v;
        !           425:   sqlite *db = pParse->db;
        !           426: 
        !           427:   assert( pTrigger->iDb<db->nDb );
        !           428:   if( pTrigger->iDb>=2 ){
        !           429:     sqliteErrorMsg(pParse, "triggers may not be removed from "
        !           430:        "auxiliary database %s", db->aDb[pTrigger->iDb].zName);
        !           431:     return;
        !           432:   }
        !           433:   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:     int code = SQLITE_DROP_TRIGGER;
        !           439:     const char *zDb = db->aDb[pTrigger->iDb].zName;
        !           440:     const char *zTab = SCHEMA_TABLE(pTrigger->iDb);
        !           441:     if( pTrigger->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
        !           442:     if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
        !           443:       sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
        !           444:       return;
        !           445:     }
        !           446:   }
        !           447: #endif
        !           448: 
        !           449:   /* Generate code to destroy the database record of the trigger.
        !           450:   */
        !           451:   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:     sqliteBeginWriteOperation(pParse, 0, 0);
        !           466:     sqliteOpenMasterTable(v, pTrigger->iDb);
        !           467:     base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
        !           468:     sqliteVdbeChangeP3(v, base+1, pTrigger->name, 0);
        !           469:     if( pTrigger->iDb==0 ){
        !           470:       sqliteChangeCookie(db, v);
        !           471:     }
        !           472:     sqliteVdbeAddOp(v, OP_Close, 0, 0);
        !           473:     sqliteEndWriteOperation(pParse);
        !           474:   }
        !           475: 
        !           476:   /*
        !           477:    * If this is not an "explain", then delete the trigger structure.
        !           478:    */
        !           479:   if( !pParse->explain ){
        !           480:     const char *zName = pTrigger->name;
        !           481:     int nName = strlen(zName);
        !           482:     if( pTable->pTrigger == pTrigger ){
        !           483:       pTable->pTrigger = pTrigger->pNext;
        !           484:     }else{
        !           485:       Trigger *cc = pTable->pTrigger;
        !           486:       while( cc ){ 
        !           487:         if( cc->pNext == pTrigger ){
        !           488:           cc->pNext = cc->pNext->pNext;
        !           489:           break;
        !           490:         }
        !           491:         cc = cc->pNext;
        !           492:       }
        !           493:       assert(cc);
        !           494:     }
        !           495:     sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
        !           496:     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: static int checkColumnOverLap(IdList *pIdList, ExprList *pEList){
        !           510:   int e;
        !           511:   if( !pIdList || !pEList ) return 1;
        !           512:   for(e=0; e<pEList->nExpr; e++){
        !           513:     if( sqliteIdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
        !           514:   }
        !           515:   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: ){
        !           541:   Trigger * pTriggerCursor;
        !           542: 
        !           543:   if( always_code_trigger_setup ){
        !           544:     return 1;
        !           545:   }
        !           546: 
        !           547:   pTriggerCursor = pTrigger;
        !           548:   while( pTriggerCursor ){
        !           549:     if( pTriggerCursor->op == op && 
        !           550:        pTriggerCursor->tr_tm == tr_tm && 
        !           551:        pTriggerCursor->foreach == foreach &&
        !           552:        checkColumnOverLap(pTriggerCursor->pColumns, pChanges) ){
        !           553:       TriggerStack * ss;
        !           554:       ss = pParse->trigStack;
        !           555:       while( ss && ss->pTrigger != pTrigger ){
        !           556:        ss = ss->pNext;
        !           557:       }
        !           558:       if( !ss )return 1;
        !           559:     }
        !           560:     pTriggerCursor = pTriggerCursor->pNext;
        !           561:   }
        !           562: 
        !           563:   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: ){
        !           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:   iDb = pStep->pTrig->iDb;
        !           585:   if( iDb==0 || iDb>=2 ){
        !           586:     assert( iDb<pParse->db->nDb );
        !           587:     sDb.z = pParse->db->aDb[iDb].zName;
        !           588:     sDb.n = strlen(sDb.z);
        !           589:     pSrc = sqliteSrcListAppend(0, &sDb, &pStep->target);
        !           590:   } else {
        !           591:     pSrc = sqliteSrcListAppend(0, &pStep->target, 0);
        !           592:   }
        !           593:   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: ){
        !           605:   TriggerStep * pTriggerStep = pStepList;
        !           606:   int orconf;
        !           607: 
        !           608:   while( pTriggerStep ){
        !           609:     int saveNTab = pParse->nTab;
        !           610:  
        !           611:     orconf = (orconfin == OE_Default)?pTriggerStep->orconf:orconfin;
        !           612:     pParse->trigStack->orconf = orconf;
        !           613:     switch( pTriggerStep->op ){
        !           614:       case TK_SELECT: {
        !           615:        Select * ss = sqliteSelectDup(pTriggerStep->pSelect);             
        !           616:        assert(ss);
        !           617:        assert(ss->pSrc);
        !           618:        sqliteSelect(pParse, ss, SRT_Discard, 0, 0, 0, 0);
        !           619:        sqliteSelectDelete(ss);
        !           620:        break;
        !           621:       }
        !           622:       case TK_UPDATE: {
        !           623:         SrcList *pSrc;
        !           624:         pSrc = targetSrcList(pParse, pTriggerStep);
        !           625:         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
        !           626:         sqliteUpdate(pParse, pSrc,
        !           627:                sqliteExprListDup(pTriggerStep->pExprList), 
        !           628:                sqliteExprDup(pTriggerStep->pWhere), orconf);
        !           629:         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
        !           630:         break;
        !           631:       }
        !           632:       case TK_INSERT: {
        !           633:         SrcList *pSrc;
        !           634:         pSrc = targetSrcList(pParse, pTriggerStep);
        !           635:         sqliteInsert(pParse, pSrc,
        !           636:           sqliteExprListDup(pTriggerStep->pExprList), 
        !           637:           sqliteSelectDup(pTriggerStep->pSelect), 
        !           638:           sqliteIdListDup(pTriggerStep->pIdList), orconf);
        !           639:         break;
        !           640:       }
        !           641:       case TK_DELETE: {
        !           642:         SrcList *pSrc;
        !           643:         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPush, 0, 0);
        !           644:         pSrc = targetSrcList(pParse, pTriggerStep);
        !           645:         sqliteDeleteFrom(pParse, pSrc, sqliteExprDup(pTriggerStep->pWhere));
        !           646:         sqliteVdbeAddOp(pParse->pVdbe, OP_ListPop, 0, 0);
        !           647:         break;
        !           648:       }
        !           649:       default:
        !           650:         assert(0);
        !           651:     } 
        !           652:     pParse->nTab = saveNTab;
        !           653:     pTriggerStep = pTriggerStep->pNext;
        !           654:   }
        !           655: 
        !           656:   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: ){
        !           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:   pTrigger = pTab->pTrigger;
        !           699:   while( pTrigger ){
        !           700:     int fire_this = 0;
        !           701: 
        !           702:     /* determine whether we should code this trigger */
        !           703:     if( pTrigger->op == op && pTrigger->tr_tm == tr_tm && 
        !           704:         pTrigger->foreach == TK_ROW ){
        !           705:       fire_this = 1;
        !           706:       pTriggerStack = pParse->trigStack;
        !           707:       while( pTriggerStack ){
        !           708:         if( pTriggerStack->pTrigger == pTrigger ){
        !           709:          fire_this = 0;
        !           710:        }
        !           711:         pTriggerStack = pTriggerStack->pNext;
        !           712:       }
        !           713:       if( op == TK_UPDATE && pTrigger->pColumns &&
        !           714:           !checkColumnOverLap(pTrigger->pColumns, pChanges) ){
        !           715:         fire_this = 0;
        !           716:       }
        !           717:     }
        !           718: 
        !           719:     if( fire_this && (pTriggerStack = sqliteMalloc(sizeof(TriggerStack)))!=0 ){
        !           720:       int endTrigger;
        !           721:       SrcList dummyTablist;
        !           722:       Expr * whenExpr;
        !           723:       AuthContext sContext;
        !           724: 
        !           725:       dummyTablist.nSrc = 0;
        !           726: 
        !           727:       /* Push an entry on to the trigger stack */
        !           728:       pTriggerStack->pTrigger = pTrigger;
        !           729:       pTriggerStack->newIdx = newIdx;
        !           730:       pTriggerStack->oldIdx = oldIdx;
        !           731:       pTriggerStack->pTab = pTab;
        !           732:       pTriggerStack->pNext = pParse->trigStack;
        !           733:       pTriggerStack->ignoreJump = ignoreJump;
        !           734:       pParse->trigStack = pTriggerStack;
        !           735:       sqliteAuthContextPush(pParse, &sContext, pTrigger->name);
        !           736: 
        !           737:       /* code the WHEN clause */
        !           738:       endTrigger = sqliteVdbeMakeLabel(pParse->pVdbe);
        !           739:       whenExpr = sqliteExprDup(pTrigger->pWhen);
        !           740:       if( sqliteExprResolveIds(pParse, &dummyTablist, 0, whenExpr) ){
        !           741:         pParse->trigStack = pParse->trigStack->pNext;
        !           742:         sqliteFree(pTriggerStack);
        !           743:         sqliteExprDelete(whenExpr);
        !           744:         return 1;
        !           745:       }
        !           746:       sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
        !           747:       sqliteExprDelete(whenExpr);
        !           748: 
        !           749:       sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPush, 0, 0);
        !           750:       codeTriggerProgram(pParse, pTrigger->step_list, orconf); 
        !           751:       sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPop, 0, 0);
        !           752: 
        !           753:       /* Pop the entry off the trigger stack */
        !           754:       pParse->trigStack = pParse->trigStack->pNext;
        !           755:       sqliteAuthContextPop(&sContext);
        !           756:       sqliteFree(pTriggerStack);
        !           757: 
        !           758:       sqliteVdbeResolveLabel(pParse->pVdbe, endTrigger);
        !           759:     }
        !           760:     pTrigger = pTrigger->pNext;
        !           761:   }
        !           762: 
        !           763:   return 0;
        !           764: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>