diff options
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/trigger.c')
-rw-r--r-- | ext/pdo_sqlite/sqlite/src/trigger.c | 161 |
1 files changed, 88 insertions, 73 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/trigger.c b/ext/pdo_sqlite/sqlite/src/trigger.c index 348dfdd57..15992df38 100644 --- a/ext/pdo_sqlite/sqlite/src/trigger.c +++ b/ext/pdo_sqlite/sqlite/src/trigger.c @@ -11,7 +11,6 @@ * */ #include "sqliteInt.h" -#include "vdbe.h" #ifndef SQLITE_OMIT_TRIGGER /* @@ -59,10 +58,13 @@ void sqlite3BeginTrigger( int iDb; /* The database to store the trigger in */ Token *pName; /* The unqualified db name */ DbFixer sFix; + int iTabDb; + assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ + assert( pName2!=0 ); if( isTemp ){ /* If TEMP was specified, then the trigger name may not be qualified. */ - if( pName2 && pName2->n>0 ){ + if( pName2->n>0 ){ sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name"); goto trigger_cleanup; } @@ -81,14 +83,16 @@ void sqlite3BeginTrigger( ** If sqlite3SrcListLookup() returns 0, indicating the table does not ** exist, the error is caught by the block below. */ - if( !pTableName || sqlite3_malloc_failed ) goto trigger_cleanup; + if( !pTableName || sqlite3MallocFailed() ){ + goto trigger_cleanup; + } pTab = sqlite3SrcListLookup(pParse, pTableName); - if( pName2->n==0 && pTab && pTab->iDb==1 ){ + if( pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ iDb = 1; } /* Ensure the table name matches database name and that the table exists */ - if( sqlite3_malloc_failed ) goto trigger_cleanup; + if( sqlite3MallocFailed() ) goto trigger_cleanup; assert( pTableName->nSrc==1 ); if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && sqlite3FixSrcList(&sFix, pTableName) ){ @@ -99,6 +103,10 @@ void sqlite3BeginTrigger( /* The table does not exist. */ goto trigger_cleanup; } + if( IsVirtual(pTab) ){ + sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); + goto trigger_cleanup; + } /* Check that the trigger name is not reserved and that no trigger of the ** specified name exists */ @@ -106,7 +114,7 @@ void sqlite3BeginTrigger( if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto trigger_cleanup; } - if( sqlite3HashFind(&(db->aDb[iDb].trigHash), zName,pName->n+1) ){ + if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); goto trigger_cleanup; } @@ -131,17 +139,18 @@ void sqlite3BeginTrigger( " trigger on table: %S", pTableName, 0); goto trigger_cleanup; } + iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_CREATE_TRIGGER; - const char *zDb = db->aDb[pTab->iDb].zName; + const char *zDb = db->aDb[iTabDb].zName; const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb; - if( pTab->iDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; + if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER; if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){ goto trigger_cleanup; } - if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(pTab->iDb),0,zDb)){ + if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){ goto trigger_cleanup; } } @@ -162,8 +171,8 @@ void sqlite3BeginTrigger( pTrigger->name = zName; zName = 0; pTrigger->table = sqliteStrDup(pTableName->a[0].zName); - pTrigger->iDb = iDb; - pTrigger->iTabDb = pTab->iDb; + pTrigger->pSchema = db->aDb[iDb].pSchema; + pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; pTrigger->pWhen = sqlite3ExprDup(pWhen); @@ -197,16 +206,18 @@ void sqlite3FinishTrigger( Trigger *pTrig = 0; /* The trigger whose construction is finishing up */ sqlite3 *db = pParse->db; /* The database */ DbFixer sFix; + int iDb; /* Database containing the trigger */ pTrig = pParse->pNewTrigger; pParse->pNewTrigger = 0; - if( pParse->nErr || pTrig==0 ) goto triggerfinish_cleanup; + if( pParse->nErr || !pTrig ) goto triggerfinish_cleanup; + iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } - if( sqlite3FixInit(&sFix, pParse, pTrig->iDb, "trigger", &pTrig->nameToken) + if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &pTrig->nameToken) && sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){ goto triggerfinish_cleanup; } @@ -224,7 +235,7 @@ void sqlite3FinishTrigger( { OP_String8, 0, 0, "CREATE TRIGGER "}, { OP_String8, 0, 0, 0 }, /* 6: SQL */ { OP_Concat, 0, 0, 0 }, - { OP_MakeRecord, 5, 0, "tttit" }, + { OP_MakeRecord, 5, 0, "aaada" }, { OP_Insert, 0, 0, 0 }, }; int addr; @@ -233,28 +244,30 @@ void sqlite3FinishTrigger( /* Make an entry in the sqlite_master table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; - sqlite3BeginWriteOperation(pParse, 0, pTrig->iDb); - sqlite3OpenMasterTable(v, pTrig->iDb); + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3OpenMasterTable(pParse, iDb); addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig); sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0); sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0); - sqlite3VdbeChangeP3(v, addr+6, pAll->z, pAll->n); - sqlite3ChangeCookie(db, v, pTrig->iDb); + sqlite3VdbeChangeP3(v, addr+6, (char*)pAll->z, pAll->n); + sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); - sqlite3VdbeOp3(v, OP_ParseSchema, pTrig->iDb, 0, + sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, sqlite3MPrintf("type='trigger' AND name='%q'", pTrig->name), P3_DYNAMIC); } if( db->init.busy ){ + int n; Table *pTab; Trigger *pDel; - pDel = sqlite3HashInsert(&db->aDb[pTrig->iDb].trigHash, - pTrig->name, strlen(pTrig->name)+1, pTrig); + pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash, + pTrig->name, strlen(pTrig->name), pTrig); if( pDel ){ - assert( sqlite3_malloc_failed && pDel==pTrig ); + assert( sqlite3MallocFailed() && pDel==pTrig ); goto triggerfinish_cleanup; } - pTab = sqlite3LocateTable(pParse,pTrig->table,db->aDb[pTrig->iTabDb].zName); + n = strlen(pTrig->table) + 1; + pTab = sqlite3HashFind(&pTrig->pTabSchema->tblHash, pTrig->table, n); assert( pTab!=0 ); pTrig->pNext = pTab->pTrigger; pTab->pTrigger = pTrig; @@ -279,7 +292,7 @@ triggerfinish_cleanup: */ static void sqlitePersistTriggerStep(TriggerStep *p){ if( p->target.z ){ - p->target.z = sqliteStrNDup(p->target.z, p->target.n); + p->target.z = (u8*)sqliteStrNDup((char*)p->target.z, p->target.n); p->target.dyn = 1; } if( p->pSelect ){ @@ -313,7 +326,10 @@ static void sqlitePersistTriggerStep(TriggerStep *p){ */ TriggerStep *sqlite3TriggerSelectStep(Select *pSelect){ TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep)); - if( pTriggerStep==0 ) return 0; + if( pTriggerStep==0 ) { + sqlite3SelectDelete(pSelect); + return 0; + } pTriggerStep->op = TK_SELECT; pTriggerStep->pSelect = pSelect; @@ -431,7 +447,7 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){ int nName; sqlite3 *db = pParse->db; - if( sqlite3_malloc_failed ) goto drop_trigger_cleanup; + if( sqlite3MallocFailed() ) goto drop_trigger_cleanup; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto drop_trigger_cleanup; } @@ -443,14 +459,14 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){ for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue; - pTrigger = sqlite3HashFind(&(db->aDb[j].trigHash), zName, nName+1); + pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName); if( pTrigger ) break; } if( !pTrigger ){ sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); goto drop_trigger_cleanup; } - sqlite3DropTriggerPtr(pParse, pTrigger, 0); + sqlite3DropTriggerPtr(pParse, pTrigger); drop_trigger_cleanup: sqlite3SrcListDelete(pName); @@ -460,27 +476,26 @@ drop_trigger_cleanup: ** Return a pointer to the Table structure for the table that a trigger ** is set on. */ -static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){ - return sqlite3FindTable(db,pTrigger->table,db->aDb[pTrigger->iTabDb].zName); +static Table *tableOfTrigger(Trigger *pTrigger){ + int n = strlen(pTrigger->table) + 1; + return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n); } /* -** Drop a trigger given a pointer to that trigger. If nested is false, -** then also generate code to remove the trigger from the SQLITE_MASTER -** table. +** Drop a trigger given a pointer to that trigger. */ -void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ +void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){ Table *pTable; Vdbe *v; sqlite3 *db = pParse->db; int iDb; - iDb = pTrigger->iDb; + iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDb<db->nDb ); - pTable = tableOfTrigger(db, pTrigger); - assert(pTable); - assert( pTable->iDb==iDb || iDb==1 ); + pTable = tableOfTrigger(pTrigger); + assert( pTable ); + assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; @@ -496,7 +511,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ /* Generate code to destroy the database record of the trigger. */ - if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){ + assert( pTable!=0 ); + if( (v = sqlite3GetVdbe(pParse))!=0 ){ int base; static const VdbeOpList dropTrigger[] = { { OP_Rewind, 0, ADDR(9), 0}, @@ -511,7 +527,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ }; sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3OpenMasterTable(v, iDb); + sqlite3OpenMasterTable(pParse, iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0); sqlite3ChangeCookie(db, v, iDb); @@ -526,9 +542,10 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){ Trigger *pTrigger; int nName = strlen(zName); - pTrigger = sqlite3HashInsert(&(db->aDb[iDb].trigHash), zName, nName+1, 0); + pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash), + zName, nName, 0); if( pTrigger ){ - Table *pTable = tableOfTrigger(db, pTrigger); + Table *pTable = tableOfTrigger(pTrigger); assert( pTable!=0 ); if( pTable->pTrigger == pTrigger ){ pTable->pTrigger = pTrigger->pNext; @@ -581,19 +598,13 @@ int sqlite3TriggersExist( int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ ExprList *pChanges /* Columns that change in an UPDATE statement */ ){ - Trigger *pTrigger = pTab->pTrigger; + Trigger *pTrigger; int mask = 0; + pTrigger = IsVirtual(pTab) ? 0 : pTab->pTrigger; while( pTrigger ){ if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){ - TriggerStack *ss; - ss = pParse->trigStack; - while( ss && ss->pTrigger!=pTab->pTrigger ){ - ss = ss->pNext; - } - if( ss==0 ){ - mask |= pTrigger->tr_tm; - } + mask |= pTrigger->tr_tm; } pTrigger = pTrigger->pNext; } @@ -618,11 +629,11 @@ static SrcList *targetSrcList( int iDb; /* Index of the database to use */ SrcList *pSrc; /* SrcList to be returned */ - iDb = pStep->pTrig->iDb; + iDb = sqlite3SchemaToIndex(pParse->db, pStep->pTrig->pSchema); if( iDb==0 || iDb>=2 ){ assert( iDb<pParse->db->nDb ); - sDb.z = pParse->db->aDb[iDb].zName; - sDb.n = strlen(sDb.z); + sDb.z = (u8*)pParse->db->aDb[iDb].zName; + sDb.n = strlen((char*)sDb.z); pSrc = sqlite3SrcListAppend(0, &sDb, &pStep->target); } else { pSrc = sqlite3SrcListAppend(0, &pStep->target, 0); @@ -731,8 +742,7 @@ int sqlite3CodeRowTrigger( int orconf, /* ON CONFLICT policy */ int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ ){ - Trigger *pTrigger; - TriggerStack *pStack; + Trigger *p; TriggerStack trigStackEntry; assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE); @@ -740,22 +750,28 @@ int sqlite3CodeRowTrigger( assert(newIdx != -1 || oldIdx != -1); - pTrigger = pTab->pTrigger; - while( pTrigger ){ + for(p=pTab->pTrigger; p; p=p->pNext){ int fire_this = 0; - /* determine whether we should code this trigger */ - if( pTrigger->op == op && pTrigger->tr_tm == tr_tm ){ - fire_this = 1; - for(pStack=pParse->trigStack; pStack; pStack=pStack->pNext){ - if( pStack->pTrigger==pTrigger ){ - fire_this = 0; - } + /* Determine whether we should code this trigger */ + if( + p->op==op && + p->tr_tm==tr_tm && + (p->pSchema==p->pTabSchema || p->pSchema==pParse->db->aDb[1].pSchema) && + (op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges)) + ){ + TriggerStack *pS; /* Pointer to trigger-stack entry */ + for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext){} + if( !pS ){ + fire_this = 1; } - if( op == TK_UPDATE && pTrigger->pColumns && - !checkColumnOverLap(pTrigger->pColumns, pChanges) ){ - fire_this = 0; +#if 0 /* Give no warning for recursive triggers. Just do not do them */ + else{ + sqlite3ErrorMsg(pParse, "recursive triggers not supported (%s)", + p->name); + return SQLITE_ERROR; } +#endif } if( fire_this ){ @@ -768,18 +784,18 @@ int sqlite3CodeRowTrigger( sNC.pParse = pParse; /* Push an entry on to the trigger stack */ - trigStackEntry.pTrigger = pTrigger; + trigStackEntry.pTrigger = p; trigStackEntry.newIdx = newIdx; trigStackEntry.oldIdx = oldIdx; trigStackEntry.pTab = pTab; trigStackEntry.pNext = pParse->trigStack; trigStackEntry.ignoreJump = ignoreJump; pParse->trigStack = &trigStackEntry; - sqlite3AuthContextPush(pParse, &sContext, pTrigger->name); + sqlite3AuthContextPush(pParse, &sContext, p->name); /* code the WHEN clause */ endTrigger = sqlite3VdbeMakeLabel(pParse->pVdbe); - whenExpr = sqlite3ExprDup(pTrigger->pWhen); + whenExpr = sqlite3ExprDup(p->pWhen); if( sqlite3ExprResolveNames(&sNC, whenExpr) ){ pParse->trigStack = trigStackEntry.pNext; sqlite3ExprDelete(whenExpr); @@ -788,7 +804,7 @@ int sqlite3CodeRowTrigger( sqlite3ExprIfFalse(pParse, whenExpr, endTrigger, 1); sqlite3ExprDelete(whenExpr); - codeTriggerProgram(pParse, pTrigger->step_list, orconf); + codeTriggerProgram(pParse, p->step_list, orconf); /* Pop the entry off the trigger stack */ pParse->trigStack = trigStackEntry.pNext; @@ -796,7 +812,6 @@ int sqlite3CodeRowTrigger( sqlite3VdbeResolveLabel(pParse->pVdbe, endTrigger); } - pTrigger = pTrigger->pNext; } return 0; } |