public static TriggerStep TriggerDeleteStep(Context ctx, Token tableName, Expr where_) { TriggerStep triggerStep = TriggerStepAllocate(ctx, TK.DELETE, tableName); if (triggerStep != null) { triggerStep.Where = Expr.Dup(ctx, where_, E.EXPRDUP_REDUCE); triggerStep.Orconf = OE.Default; } Expr.Delete(ctx, ref where_); return(triggerStep); }
static void FKTriggerDelete(Context ctx, Trigger p) { if (p != null) { TriggerStep step = p.StepList; Expr.Delete(ctx, ref step.Where); Expr.ListDelete(ctx, ref step.ExprList); Select.Delete(ctx, ref step.Select); Expr.Delete(ctx, ref p.When); C._tagfree(ctx, ref p); } }
public bool FixTriggerStep(TriggerStep step) { while (step != null) { if (FixSelect(step.Select) || FixExpr(step.Where) || FixExprList(step.ExprList)) { return(true); } step = step.Next; } return(false); }
static TriggerStep TriggerStepAllocate(Context ctx, TK op, Token name) { TriggerStep triggerStep = new TriggerStep(); //: _tagalloc(ctx, sizeof(TriggerStep) + name->length, true); if (triggerStep != null) { string z = name.data; triggerStep.Target.data = z; triggerStep.Target.length = name.length; triggerStep.OP = op; } return(triggerStep); }
public static TriggerStep SelectStep(Context ctx, Select select) { TriggerStep triggerStep = new TriggerStep(); //: _tagalloc(ctx, sizeof(TriggerStep), true); if (triggerStep == null) { Select.Delete(ctx, ref select); return(null); } triggerStep.OP = TK.SELECT; triggerStep.Select = select; triggerStep.Orconf = OE.Default; return(triggerStep); }
public static TriggerStep TriggerUpdateStep(Context ctx, Token tableName, ExprList list, Expr where, OE orconf) { TriggerStep triggerStep = TriggerStepAllocate(ctx, TK.UPDATE, tableName); if (triggerStep != null) { triggerStep.ExprList = Expr.ListDup(ctx, list, E.EXPRDUP_REDUCE); triggerStep.Where = Expr.Dup(ctx, where, E.EXPRDUP_REDUCE); triggerStep.Orconf = orconf; } Expr.ListDelete(ctx, ref list); Expr.Delete(ctx, ref where); return(triggerStep); }
public static PlayerActionEvents ValidateStep( this TriggerStep triggerStep, PlayerActionEvents currentPlayerActions, PlayerActionEvents participatingPlayerActions ) { var stepPlayerActions = new PlayerActionEvents(); #pragma warning disable CS0219 // Variable is assigned but its value is never used bool contains; #pragma warning restore CS0219 // Variable is assigned but its value is never used foreach (var action in currentPlayerActions) { foreach (var rule in triggerStep.ActionOccurrenceRules) { if ( action.OccurredAt != null && rule.InsideOf.Contains(new Point( new Coordinate( action.OccurredAt.Coordinate.CoordinateValue.X, action.OccurredAt.Coordinate.CoordinateValue.Y ) ))) { contains = true; if (!stepPlayerActions.Exists(e => e.ActionRefId.Equals(action.ActionRefId))) { stepPlayerActions.Add(action); } } } } // logic to validate other than geofence // add stepPlayerActions to participatingPlayerActions foreach (var action in stepPlayerActions) { action.TriggerStepRefId = triggerStep.TriggerStepRefId; if (!participatingPlayerActions.Exists(e => e.ActionRefId.Equals(action.ActionRefId))) { participatingPlayerActions.Add(action); } } return(participatingPlayerActions); }
/* ** Turn a SELECT statement (that the pSelect parameter points to) into ** a trigger step. Return a pointer to a TriggerStep structure. ** ** The parser calls this routine when it finds a SELECT statement in ** body of a TRIGGER. */ static TriggerStep sqlite3TriggerSelectStep(sqlite3 db, Select pSelect) { TriggerStep pTriggerStep = new TriggerStep();// sqlite3DbMallocZero( db, sizeof(TriggerStep )) if (pTriggerStep == null) { sqlite3SelectDelete(db, ref pSelect); return(null); } pTriggerStep.op = TK_SELECT; pTriggerStep.pSelect = pSelect; pTriggerStep.orconf = OE_Default; return(pTriggerStep); }
/* ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** ** $Id: trigger.c,v 1.143 2009/08/10 03:57:58 shane Exp $ ** ************************************************************************* ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart ** C#-SQLite is an independent reimplementation of the SQLite software library ** ** $Header$ ************************************************************************* */ //#include "sqliteInt.h" #if !SQLITE_OMIT_TRIGGER /* ** Delete a linked list of TriggerStep structures. */ static void sqlite3DeleteTriggerStep(sqlite3 db, ref TriggerStep pTriggerStep) { while (pTriggerStep != null) { TriggerStep pTmp = pTriggerStep; pTriggerStep = pTriggerStep.pNext; sqlite3ExprDelete(db, ref pTmp.pWhere); sqlite3ExprListDelete(db, ref pTmp.pExprList); sqlite3SelectDelete(db, ref pTmp.pSelect); sqlite3IdListDelete(db, ref pTmp.pIdList); pTriggerStep = null;//sqlite3DbFree( db, ref pTmp ); } }
/* ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation for TRIGGERs ************************************************************************* ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart ** C#-SQLite is an independent reimplementation of the SQLite software library ** ** SQLITE_SOURCE_ID: 2010-03-09 19:31:43 4ae453ea7be69018d8c16eb8dabe05617397dc4d ** ** $Header: Community.CsharpSqlite/src/trigger_c.cs,v 6604176a7dbe 2010/03/12 23:35:36 Noah $ ************************************************************************* */ //#include "sqliteInt.h" #if !SQLITE_OMIT_TRIGGER /* ** Delete a linked list of TriggerStep structures. */ static void sqlite3DeleteTriggerStep( sqlite3 db, ref TriggerStep pTriggerStep ) { while ( pTriggerStep != null ) { TriggerStep pTmp = pTriggerStep; pTriggerStep = pTriggerStep.pNext; sqlite3ExprDelete( db, ref pTmp.pWhere ); sqlite3ExprListDelete( db, ref pTmp.pExprList ); sqlite3SelectDelete( db, ref pTmp.pSelect ); sqlite3IdListDelete( db, ref pTmp.pIdList ); pTriggerStep = null;sqlite3DbFree( db, ref pTmp ); } }
public static void DeleteTriggerStep(Context ctx, ref TriggerStep triggerStep) { while (triggerStep != null) { TriggerStep tmp = triggerStep; triggerStep = triggerStep.Next; Expr.Delete(ctx, ref tmp.Where); Expr.ListDelete(ctx, ref tmp.ExprList); Select.Delete(ctx, ref tmp.Select); Parse.IdListDelete(ctx, ref tmp.IdList); C._tagfree(ctx, ref tmp); triggerStep = null; //: C# } }
static SrcList TargetSrcList(Parse parse, TriggerStep step) { Context ctx = parse.Ctx; SrcList src = Parse.SrcListAppend(parse.Ctx, null, step.Target, null); // SrcList to be returned if (src != null) { Debug.Assert(src.Srcs > 0); Debug.Assert(src.Ids != null); int db = Prepare.SchemaToIndex(ctx, step.Trig.Schema); // Index of the database to use if (db == 0 || db >= 2) { Debug.Assert(db < ctx.DBs.length); src.Ids[src.Srcs - 1].Database = ctx.DBs[db].Name; //: _tagstrdup(ctx, ctx->DBs[db].Name); } } return(src); }
/* ** Allocate space to hold a new trigger step. The allocated space ** holds both the TriggerStep object and the TriggerStep.target.z string. ** ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep triggerStepAllocate( sqlite3 db, /* Database connection */ u8 op, /* Trigger opcode */ Token pName /* The target name */ ) { TriggerStep pTriggerStep; pTriggerStep = new TriggerStep();// sqlite3DbMallocZero( db, sizeof( TriggerStep ) + pName.n ); //if ( pTriggerStep != null ) //{ string z; // = (char*)&pTriggerStep[1]; z = pName.z; // memcpy( z, pName.z, pName.n ); pTriggerStep.target.z = z; pTriggerStep.target.n = pName.n; pTriggerStep.op = op; //} return(pTriggerStep); }
public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, ExprList list, Select select, OE orconf) { Debug.Assert(list == null || select == null); Debug.Assert(list != null || select != null || ctx.MallocFailed); TriggerStep triggerStep = TriggerStepAllocate(ctx, TK.INSERT, tableName); if (triggerStep != null) { triggerStep.Select = Select.Dup(ctx, select, E.EXPRDUP_REDUCE); triggerStep.IdList = column; triggerStep.ExprList = Expr.ListDup(ctx, list, E.EXPRDUP_REDUCE); triggerStep.Orconf = orconf; } else { Expr.IdListDelete(ctx, ref column); } Expr.ListDelete(ctx, ref list); Select.Delete(ctx, ref select); return(triggerStep); }
/* ** Convert the pStep.target token into a SrcList and return a pointer ** to that SrcList. ** ** This routine adds a specific database name, if needed, to the target when ** forming the SrcList. This prevents a trigger in one database from ** referring to a target in another database. An exception is when the ** trigger is in TEMP in which case it can refer to any other database it ** wants. */ static SrcList targetSrcList( Parse pParse, /* The parsing context */ TriggerStep pStep /* The trigger containing the target token */ ) { int iDb; /* Index of the database to use */ SrcList pSrc; /* SrcList to be returned */ pSrc = sqlite3SrcListAppend(pParse.db, 0, pStep.target, 0); //if ( pSrc != null ) //{ Debug.Assert(pSrc.nSrc > 0); Debug.Assert(pSrc.a != null); iDb = sqlite3SchemaToIndex(pParse.db, pStep.pTrig.pSchema); if (iDb == 0 || iDb >= 2) { sqlite3 db = pParse.db; Debug.Assert(iDb < pParse.db.nDb); pSrc.a[pSrc.nSrc - 1].zDatabase = db.aDb[iDb].zName;// sqlite3DbStrDup( db, db.aDb[iDb].zName ); } //} return(pSrc); }
static int sqlite3FixTriggerStep( DbFixer pFix, /* Context of the fixation */ TriggerStep pStep /* The trigger step be fixed to one database */ ) { while (pStep != null) { if (sqlite3FixSelect(pFix, pStep.pSelect) != 0) { return(1); } if (sqlite3FixExpr(pFix, pStep.pWhere) != 0) { return(1); } if (sqlite3FixExprList(pFix, pStep.pExprList) != 0) { return(1); } pStep = pStep.pNext; } return(0); }
static TriggerStep TriggerStepAllocate(Context ctx, TK op, Token name) { TriggerStep triggerStep = new TriggerStep(); //: _tagalloc(ctx, sizeof(TriggerStep) + name->length, true); if (triggerStep != null) { string z = name.data; triggerStep.Target.data = z; triggerStep.Target.length = name.length; triggerStep.OP = op; } return triggerStep; }
/* ** This routine is called after all of the trigger actions have been parsed ** in order to complete the process of building the trigger. */ static void sqlite3FinishTrigger( Parse pParse, /* Parser context */ TriggerStep pStepList, /* The triggered program */ Token pAll /* Token that describes the complete CREATE TRIGGER */ ) { Trigger pTrig = pParse.pNewTrigger; /* Trigger being finished */ string zName; /* Name of trigger */ sqlite3 db = pParse.db; /* The database */ DbFixer sFix = new DbFixer(); int iDb; /* Database containing the trigger */ Token nameToken = new Token(); /* Trigger name for error reporting */ pTrig = pParse.pNewTrigger; pParse.pNewTrigger = null; if (NEVER(pParse.nErr != 0) || pTrig == null) { goto triggerfinish_cleanup; } zName = pTrig.name; iDb = sqlite3SchemaToIndex(pParse.db, pTrig.pSchema); pTrig.step_list = pStepList; while (pStepList != null) { pStepList.pTrig = pTrig; pStepList = pStepList.pNext; } nameToken.z = pTrig.name; nameToken.n = sqlite3Strlen30(nameToken.z); if (sqlite3FixInit(sFix, pParse, iDb, "trigger", nameToken) != 0 && sqlite3FixTriggerStep(sFix, pTrig.step_list) != 0) { goto triggerfinish_cleanup; } /* if we are not initializing, and this trigger is not on a TEMP table, ** build the sqlite_master entry */ if (0 == db.init.busy) { Vdbe v; string z; /* Make an entry in the sqlite_master table */ v = sqlite3GetVdbe(pParse); if (v == null) { goto triggerfinish_cleanup; } sqlite3BeginWriteOperation(pParse, 0, iDb); z = pAll.z.Substring(0, pAll.n);//sqlite3DbStrNDup( db, (char*)pAll.z, pAll.n ); sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db.aDb[iDb].zName, SCHEMA_TABLE(iDb), zName, pTrig.table, z); //sqlite3DbFree( db, ref z ); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf( db, "type='trigger' AND name='%q'", zName), P4_DYNAMIC ); } if (db.init.busy != 0) { Trigger pLink = pTrig; Hash pHash = db.aDb[iDb].pSchema.trigHash; pTrig = (Trigger)sqlite3HashInsert(ref pHash, zName, sqlite3Strlen30(zName), pTrig); if (pTrig != null) { //db.mallocFailed = 1; } else if (pLink.pSchema == pLink.pTabSchema) { Table pTab; int n = sqlite3Strlen30(pLink.table); pTab = (Table)sqlite3HashFind(pLink.pTabSchema.tblHash, pLink.table, n); Debug.Assert(pTab != null); pLink.pNext = pTab.pTrigger; pTab.pTrigger = pLink; } } triggerfinish_cleanup: sqlite3DeleteTrigger(db, ref pTrig); Debug.Assert(pParse.pNewTrigger == null); sqlite3DeleteTriggerStep(db, ref pStepList); }
static int CodeTriggerProgram(Parse parse, TriggerStep stepList, OE orconf) { Vdbe v = parse.V; Context ctx = parse.Ctx; Debug.Assert(parse.TriggerTab != null && parse.Toplevel != null); Debug.Assert(stepList != null); Debug.Assert(v != null); for (TriggerStep step = stepList; step != null; step = step.Next) { // Figure out the ON CONFLICT policy that will be used for this step of the trigger program. If the statement that caused this trigger // to fire had an explicit ON CONFLICT, then use it. Otherwise, use the ON CONFLICT policy that was specified as part of the trigger // step statement. Example: // // CREATE TRIGGER AFTER INSERT ON t1 BEGIN; // INSERT OR REPLACE INTO t2 VALUES(new.a, new.b); // END; // // INSERT INTO t1 ... ; -- insert into t2 uses REPLACE policy // INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy parse.Orconf = (orconf == OE.Default ? step.Orconf : orconf); switch (step.OP) { case TK.UPDATE: Update(parse, TargetSrcList(parse, step), Expr.ListDup(ctx, step.ExprList, 0), Expr.Dup(ctx, step.Where, 0), parse.Orconf); break; case TK.INSERT: Insert(parse, TargetSrcList(parse, step), Expr.ListDup(ctx, step.ExprList, 0), Select.Dup(ctx, step.Select, 0), Expr.IdListDup(ctx, step.IdList), parse.Orconf); break; case TK.DELETE: DeleteFrom(parse, TargetSrcList(parse, step), Expr.Dup(ctx, step.Where, 0)); break; default: Debug.Assert(step.OP == TK.SELECT); SelectDest sDest = new SelectDest(); Select select = Expr.SelectDup(ctx, step.Select, 0); Select.DestInit(sDest, SRT.Discard, 0); Select.Select_(parse, select, ref sDest); Select.Delete(ctx, ref select); break; } if (step.OP != TK.SELECT) { v.AddOp0(OP.ResetCount); } } return(0); }
/* ** Generate VDBE code for zero or more statements inside the body of a ** trigger. */ static int codeTriggerProgram( Parse pParse, /* The parser context */ TriggerStep pStepList, /* List of statements inside the trigger body */ int orconfin /* Conflict algorithm. (OE_Abort, etc) */ ) { TriggerStep pTriggerStep = pStepList; int orconf; Vdbe v = pParse.pVdbe; sqlite3 db = pParse.db; Debug.Assert(pTriggerStep != null); Debug.Assert(v != null); sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0); #if SQLITE_DEBUG VdbeComment(v, "begin trigger %s", pStepList.pTrig.name); #endif while (pTriggerStep != null) { sqlite3ExprCacheClear(pParse); orconf = (orconfin == OE_Default) ? pTriggerStep.orconf : orconfin; pParse.trigStack.orconf = orconf; switch (pTriggerStep.op) { case TK_UPDATE: { SrcList pSrc; pSrc = targetSrcList(pParse, pTriggerStep); sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0); sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db, pTriggerStep.pExprList, 0), sqlite3ExprDup(db, pTriggerStep.pWhere, 0), orconf); sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0); break; } case TK_INSERT: { SrcList pSrc; pSrc = targetSrcList(pParse, pTriggerStep); sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0); sqlite3Insert(pParse, pSrc, sqlite3ExprListDup(db, pTriggerStep.pExprList, 0), sqlite3SelectDup(db, pTriggerStep.pSelect, 0), sqlite3IdListDup(db, pTriggerStep.pIdList), orconf); sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0); break; } case TK_DELETE: { SrcList pSrc; sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0); pSrc = targetSrcList(pParse, pTriggerStep); sqlite3DeleteFrom(pParse, pSrc, sqlite3ExprDup(db, pTriggerStep.pWhere, 0)); sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0); break; } default: Debug.Assert(pTriggerStep.op == TK_SELECT); { Select ss = sqlite3SelectDup(db, pTriggerStep.pSelect, 0); if (ss != null) { SelectDest dest = new SelectDest(); sqlite3SelectDestInit(dest, SRT_Discard, 0); sqlite3Select(pParse, ss, ref dest); sqlite3SelectDelete(db, ref ss); } break; } } pTriggerStep = pTriggerStep.pNext; } sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0); #if SQLITE_DEBUG VdbeComment(v, "end trigger %s", pStepList.pTrig.name); #endif return(0); }
static Trigger FKActionTrigger(Parse parse, Table table, FKey fkey, ExprList changes) { Context ctx = parse.Ctx; // Database handle int actionId = (changes != null ? 1 : 0); // 1 for UPDATE, 0 for DELETE OE action = fkey.Actions[actionId]; // One of OE_None, OE_Cascade etc. Trigger trigger = fkey.Triggers[actionId]; // Trigger definition to return if (action != OE.None && trigger == null) { Index index = null; // Parent key index for this FK int[] cols = null; // child table cols . parent key cols if (LocateFkeyIndex(parse, table, fkey, out index, out cols) != 0) { return(null); } Debug.Assert(cols != null || fkey.Cols.length == 1); Expr where_ = null; // WHERE clause of trigger step Expr when = null; // WHEN clause for the trigger ExprList list = null; // Changes list if ON UPDATE CASCADE for (int i = 0; i < fkey.Cols.length; i++) { Token oldToken = new Token("old", 3); // Literal "old" token Token newToken = new Token("new", 3); // Literal "new" token int fromColId = (cols != null ? cols[i] : fkey.Cols[0].From); // Idx of column in child table Debug.Assert(fromColId >= 0); Token fromCol = new Token(); // Name of column in child table Token toCol = new Token(); // Name of column in parent table toCol.data = (index != null ? table.Cols[index.Columns[i]].Name : "oid"); fromCol.data = fkey.From.Cols[fromColId].Name; toCol.length = (uint)toCol.data.Length; fromCol.length = (uint)fromCol.data.Length; // Create the expression "OLD.zToCol = zFromCol". It is important that the "OLD.zToCol" term is on the LHS of the = operator, so // that the affinity and collation sequence associated with the parent table are used for the comparison. Expr eq = Expr.PExpr(parse, TK.EQ, Expr.PExpr(parse, TK.DOT, Expr.PExpr(parse, TK.ID, null, null, oldToken), Expr.PExpr(parse, TK.ID, null, null, toCol) , 0), Expr.PExpr(parse, TK.ID, null, null, fromCol) , 0); // tFromCol = OLD.tToCol where_ = Expr.And(ctx, where_, eq); // For ON UPDATE, construct the next term of the WHEN clause. The final WHEN clause will be like this: // // WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN) if (changes != null) { eq = Expr.PExpr(parse, TK.IS, Expr.PExpr(parse, TK.DOT, Expr.PExpr(parse, TK.ID, null, null, oldToken), Expr.PExpr(parse, TK.ID, null, null, toCol), 0), Expr.PExpr(parse, TK.DOT, Expr.PExpr(parse, TK.ID, null, null, newToken), Expr.PExpr(parse, TK.ID, null, null, toCol), 0), 0); when = Expr.And(ctx, when, eq); } if (action != OE.Restrict && (action != OE.Cascade || changes != null)) { Expr newExpr; if (action == OE.Cascade) { newExpr = Expr.PExpr(parse, TK.DOT, Expr.PExpr(parse, TK.ID, null, null, newToken), Expr.PExpr(parse, TK.ID, null, null, toCol) , 0); } else if (action == OE.SetDflt) { Expr dfltExpr = fkey.From.Cols[fromColId].Dflt; if (dfltExpr != null) { newExpr = Expr.Dup(ctx, dfltExpr, 0); } else { newExpr = Expr.PExpr(parse, TK.NULL, 0, 0, 0); } } else { newExpr = Expr.PExpr(parse, TK.NULL, 0, 0, 0); } list = Expr.ListAppend(parse, list, newExpr); Expr.ListSetName(parse, list, fromCol, 0); } } C._tagfree(ctx, ref cols); string fromName = fkey.From.Name; // Name of child table int fromNameLength = fromName.Length; // Length in bytes of zFrom Select select = null; // If RESTRICT, "SELECT RAISE(...)" if (action == OE.Restrict) { Token from = new Token(); from.data = fromName; from.length = fromNameLength; Expr raise = Expr.Expr(ctx, TK.RAISE, "foreign key constraint failed"); if (raise != null) { raise.Affinity = OE.Abort; } select = Select.New(parse, Expr.ListAppend(parse, 0, raise), SrcListAppend(ctx, 0, from, null), where_, null, null, null, 0, null, null); where_ = null; } // Disable lookaside memory allocation bool enableLookaside = ctx.Lookaside.Enabled; // Copy of ctx->lookaside.bEnabled ctx.Lookaside.Enabled = false; trigger = new Trigger(); //: trigger = (Trigger *)_tagalloc(ctx, //: sizeof(Trigger) + // Trigger //: sizeof(TriggerStep) + // Single step in trigger program //: fromNameLength + 1 // Space for pStep->target.z //: , true); TriggerStep step = null; // First (only) step of trigger program if (trigger != null) { step = trigger.StepList = new TriggerStep(); //: (TriggerStep)trigger[1]; step.Target.data = fromName; //: (char *)&step[1]; step.Target.length = fromNameLength; //: _memcpy((const char *)step->Target.data, fromName, fromNameLength); step.Where = Expr.Dup(ctx, where_, EXPRDUP_REDUCE); step.ExprList = Expr.ListDup(ctx, list, EXPRDUP_REDUCE); step.Select = Select.Dup(ctx, select, EXPRDUP_REDUCE); if (when != null) { when = Expr.PExpr(parse, TK.NOT, when, 0, 0); trigger.When = Expr.Dup(ctx, when, EXPRDUP_REDUCE); } } // Re-enable the lookaside buffer, if it was disabled earlier. ctx.Lookaside.Enabled = enableLookaside; Expr.Delete(ctx, ref where_); Expr.Delete(ctx, ref when); Expr.ListDelete(ctx, ref list); Select.Delete(ctx, ref select); if (ctx.MallocFailed) { FKTriggerDelete(ctx, trigger); return(null); } switch (action) { case OE.Restrict: step.OP = TK.SELECT; break; case OE.Cascade: if (changes == null) { step.OP = TK.DELETE; break; } goto default; default: step.OP = TK.UPDATE; break; } step.Trigger = trigger; trigger.Schema = table.Schema; trigger.TabSchema = table.Schema; fkey.Triggers[actionId] = trigger; trigger.OP = (TK)(changes != null ? TK.UPDATE : TK.DELETE); } return(trigger); }
public bool FixTriggerStep(TriggerStep step) { while (step != null) { if (FixSelect(step.Select) || FixExpr(step.Where) || FixExprList(step.ExprList)) return true; step = step.Next; } return false; }
/* ** Convert the pStep.target token into a SrcList and return a pointer ** to that SrcList. ** ** This routine adds a specific database name, if needed, to the target when ** forming the SrcList. This prevents a trigger in one database from ** referring to a target in another database. An exception is when the ** trigger is in TEMP in which case it can refer to any other database it ** wants. */ static SrcList targetSrcList( Parse pParse, /* The parsing context */ TriggerStep pStep /* The trigger containing the target token */ ) { int iDb; /* Index of the database to use */ SrcList pSrc; /* SrcList to be returned */ pSrc = sqlite3SrcListAppend( pParse.db, 0, pStep.target, 0 ); //if ( pSrc != null ) //{ Debug.Assert( pSrc.nSrc > 0 ); Debug.Assert( pSrc.a != null ); iDb = sqlite3SchemaToIndex( pParse.db, pStep.pTrig.pSchema ); if ( iDb == 0 || iDb >= 2 ) { sqlite3 db = pParse.db; Debug.Assert( iDb < pParse.db.nDb ); pSrc.a[pSrc.nSrc - 1].zDatabase = db.aDb[iDb].zName;// sqlite3DbStrDup( db, db.aDb[iDb].zName ); } //} return pSrc; }
/* ** Turn a SELECT statement (that the pSelect parameter points to) into ** a trigger step. Return a pointer to a TriggerStep structure. ** ** The parser calls this routine when it finds a SELECT statement in ** body of a TRIGGER. */ static TriggerStep sqlite3TriggerSelectStep( sqlite3 db, Select pSelect ) { TriggerStep pTriggerStep = new TriggerStep();// sqlite3DbMallocZero( db, sizeof(TriggerStep )) if ( pTriggerStep == null ) { sqlite3SelectDelete( db, ref pSelect ); return null; } pTriggerStep.op = TK_SELECT; pTriggerStep.pSelect = pSelect; pTriggerStep.orconf = OE_Default; return pTriggerStep; }
public static void FinishTrigger(Parse parse, TriggerStep stepList, Token all) { Trigger trig = parse.NewTrigger; // Trigger being finished Context ctx = parse.Ctx; // The database Token nameToken = new Token(); // Trigger name for error reporting parse.NewTrigger = null; if (C._NEVER(parse.Errs != 0) || trig == null) goto triggerfinish_cleanup; string name = trig.Name; // Name of trigger int db = Prepare.SchemaToIndex(parse.Ctx, trig.Schema); // Database containing the trigger trig.StepList = stepList; while (stepList != null) { stepList.Trig = trig; stepList = stepList.Next; } nameToken.data = trig.Name; nameToken.length = (uint)nameToken.data.Length; DbFixer sFix = new DbFixer(); // Fixer object if (sFix.FixInit(parse, db, "trigger", nameToken) && sFix.FixTriggerStep(trig.StepList)) goto triggerfinish_cleanup; // if we are not initializing, build the sqlite_master entry if (ctx.Init.Busy) { // Make an entry in the sqlite_master table Vdbe v = parse.GetVdbe(); if (v == null) goto triggerfinish_cleanup; parse.BeginWriteOperation(0, db); string z = all.data.Substring(0, (int)all.length); //: _tagstrndup(ctx, (char *)all->data, all->length); parse.NestedParse("INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", ctx.DBs[db].Name, E.SCHEMA_TABLE(db), name, trig.Table, z); C._tagfree(ctx, ref z); parse.ChangeCookie(db); v.AddParseSchemaOp(db, C._mtagprintf(ctx, "type='trigger' AND name='%q'", name)); } if (!ctx.Init.Busy) { Trigger link = trig; Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null)); trig = ctx.DBs[db].Schema.TriggerHash.Insert(name, name.Length, trig); if (trig != null) ctx.MallocFailed = true; else if (link.Schema == link.TabSchema) { int tableLength = link.Table.Length; Table table = (Table)link.TabSchema.TableHash.Find(link.Table, tableLength, (Table)null); Debug.Assert(table != null); link.Next = table.Triggers; table.Triggers = link; } } triggerfinish_cleanup: DeleteTrigger(ctx, ref trig); Debug.Assert(parse.NewTrigger == null); DeleteTriggerStep(ctx, ref stepList); }
public static TriggerStep SelectStep(Context ctx, Select select) { TriggerStep triggerStep = new TriggerStep(); //: _tagalloc(ctx, sizeof(TriggerStep), true); if (triggerStep == null) { Select.Delete(ctx, ref select); return null; } triggerStep.OP = TK.SELECT; triggerStep.Select = select; triggerStep.Orconf = OE.Default; return triggerStep; }
static int sqlite3FixTriggerStep( DbFixer pFix, /* Context of the fixation */ TriggerStep pStep /* The trigger step be fixed to one database */ ) { while ( pStep != null ) { if ( sqlite3FixSelect( pFix, pStep.pSelect ) != 0 ) { return 1; } if ( sqlite3FixExpr( pFix, pStep.pWhere ) != 0 ) { return 1; } if ( sqlite3FixExprList( pFix, pStep.pExprList ) != 0 ) { return 1; } pStep = pStep.pNext; } return 0; }
static SrcList TargetSrcList(Parse parse, TriggerStep step) { Context ctx = parse.Ctx; SrcList src = Parse.SrcListAppend(parse.Ctx, null, step.Target, null); // SrcList to be returned if (src != null) { Debug.Assert(src.Srcs > 0); Debug.Assert(src.Ids != null); int db = Prepare.SchemaToIndex(ctx, step.Trig.Schema); // Index of the database to use if (db == 0 || db >= 2) { Debug.Assert(db < ctx.DBs.length); src.Ids[src.Srcs - 1].Database = ctx.DBs[db].Name; //: _tagstrdup(ctx, ctx->DBs[db].Name); } } return src; }
/* ** This routine is called after all of the trigger actions have been parsed ** in order to complete the process of building the trigger. */ static void sqlite3FinishTrigger( Parse pParse, /* Parser context */ TriggerStep pStepList, /* The triggered program */ Token pAll /* Token that describes the complete CREATE TRIGGER */ ) { Trigger pTrig = pParse.pNewTrigger; /* Trigger being finished */ string zName; /* Name of trigger */ sqlite3 db = pParse.db; /* The database */ DbFixer sFix = new DbFixer(); /* Fixer object */ int iDb; /* Database containing the trigger */ Token nameToken = new Token(); /* Trigger name for error reporting */ pParse.pNewTrigger = null; if ( NEVER( pParse.nErr != 0 ) || pTrig == null ) goto triggerfinish_cleanup; zName = pTrig.zName; iDb = sqlite3SchemaToIndex( pParse.db, pTrig.pSchema ); pTrig.step_list = pStepList; while ( pStepList != null ) { pStepList.pTrig = pTrig; pStepList = pStepList.pNext; } nameToken.z = pTrig.zName; nameToken.n = sqlite3Strlen30( nameToken.z ); if ( sqlite3FixInit( sFix, pParse, iDb, "trigger", nameToken ) != 0 && sqlite3FixTriggerStep( sFix, pTrig.step_list ) != 0 ) { goto triggerfinish_cleanup; } /* if we are not initializing, ** build the sqlite_master entry */ if ( 0 == db.init.busy ) { Vdbe v; string z; /* Make an entry in the sqlite_master table */ v = sqlite3GetVdbe( pParse ); if ( v == null ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation( pParse, 0, iDb ); z = pAll.z.Substring( 0, pAll.n );//sqlite3DbStrNDup( db, (char*)pAll.z, pAll.n ); sqlite3NestedParse( pParse, "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db.aDb[iDb].zName, SCHEMA_TABLE( iDb ), zName, pTrig.table, z ); sqlite3DbFree( db, ref z ); sqlite3ChangeCookie( pParse, iDb ); sqlite3VdbeAddParseSchemaOp( v, iDb, sqlite3MPrintf( db, "type='trigger' AND name='%q'", zName ) ); } if ( db.init.busy != 0 ) { Trigger pLink = pTrig; Hash pHash = db.aDb[iDb].pSchema.trigHash; Debug.Assert( sqlite3SchemaMutexHeld( db, iDb, null ) ); pTrig = sqlite3HashInsert( ref pHash, zName, sqlite3Strlen30( zName ), pTrig ); if ( pTrig != null ) { //db.mallocFailed = 1; } else if ( pLink.pSchema == pLink.pTabSchema ) { Table pTab; int n = sqlite3Strlen30( pLink.table ); pTab = sqlite3HashFind( pLink.pTabSchema.tblHash, pLink.table, n, (Table)null ); Debug.Assert( pTab != null ); pLink.pNext = pTab.pTrigger; pTab.pTrigger = pLink; } } triggerfinish_cleanup: sqlite3DeleteTrigger( db, ref pTrig ); Debug.Assert( pParse.pNewTrigger == null ); sqlite3DeleteTriggerStep( db, ref pStepList ); }
static int CodeTriggerProgram(Parse parse, TriggerStep stepList, OE orconf) { Vdbe v = parse.V; Context ctx = parse.Ctx; Debug.Assert(parse.TriggerTab != null && parse.Toplevel != null); Debug.Assert(stepList != null); Debug.Assert(v != null); for (TriggerStep step = stepList; step != null; step = step.Next) { // Figure out the ON CONFLICT policy that will be used for this step of the trigger program. If the statement that caused this trigger // to fire had an explicit ON CONFLICT, then use it. Otherwise, use the ON CONFLICT policy that was specified as part of the trigger // step statement. Example: // // CREATE TRIGGER AFTER INSERT ON t1 BEGIN; // INSERT OR REPLACE INTO t2 VALUES(new.a, new.b); // END; // // INSERT INTO t1 ... ; -- insert into t2 uses REPLACE policy // INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy parse.Orconf = (orconf == OE.Default ? step.Orconf : orconf); switch (step.OP) { case TK.UPDATE: Update(parse, TargetSrcList(parse, step), Expr.ListDup(ctx, step.ExprList, 0), Expr.Dup(ctx, step.Where, 0), parse.Orconf); break; case TK.INSERT: Insert(parse, TargetSrcList(parse, step), Expr.ListDup(ctx, step.ExprList, 0), Select.Dup(ctx, step.Select, 0), Expr.IdListDup(ctx, step.IdList), parse.Orconf); break; case TK.DELETE: DeleteFrom(parse, TargetSrcList(parse, step), Expr.Dup(ctx, step.Where, 0)); break; default: Debug.Assert(step.OP == TK.SELECT); SelectDest sDest = new SelectDest(); Select select = Expr.SelectDup(ctx, step.Select, 0); Select.DestInit(sDest, SRT.Discard, 0); Select.Select_(parse, select, ref sDest); Select.Delete(ctx, ref select); break; } if (step.OP != TK.SELECT) v.AddOp0(OP.ResetCount); } return 0; }
/* ** Allocate space to hold a new trigger step. The allocated space ** holds both the TriggerStep object and the TriggerStep.target.z string. ** ** If an OOM error occurs, NULL is returned and db.mallocFailed is set. */ static TriggerStep triggerStepAllocate( sqlite3 db, /* Database connection */ u8 op, /* Trigger opcode */ Token pName /* The target name */ ) { TriggerStep pTriggerStep; pTriggerStep = new TriggerStep();// sqlite3DbMallocZero( db, sizeof( TriggerStep ) + pName.n ); //if ( pTriggerStep != null ) //{ string z;// = (char*)&pTriggerStep[1]; z = pName.z;// memcpy( z, pName.z, pName.n ); pTriggerStep.target.z = z; pTriggerStep.target.n = pName.n; pTriggerStep.op = op; //} return pTriggerStep; }
public static void FinishTrigger(Parse parse, TriggerStep stepList, Token all) { Trigger trig = parse.NewTrigger; // Trigger being finished Context ctx = parse.Ctx; // The database Token nameToken = new Token(); // Trigger name for error reporting parse.NewTrigger = null; if (C._NEVER(parse.Errs != 0) || trig == null) { goto triggerfinish_cleanup; } string name = trig.Name; // Name of trigger int db = Prepare.SchemaToIndex(parse.Ctx, trig.Schema); // Database containing the trigger trig.StepList = stepList; while (stepList != null) { stepList.Trig = trig; stepList = stepList.Next; } nameToken.data = trig.Name; nameToken.length = (uint)nameToken.data.Length; DbFixer sFix = new DbFixer(); // Fixer object if (sFix.FixInit(parse, db, "trigger", nameToken) && sFix.FixTriggerStep(trig.StepList)) { goto triggerfinish_cleanup; } // if we are not initializing, build the sqlite_master entry if (ctx.Init.Busy) { // Make an entry in the sqlite_master table Vdbe v = parse.GetVdbe(); if (v == null) { goto triggerfinish_cleanup; } parse.BeginWriteOperation(0, db); string z = all.data.Substring(0, (int)all.length); //: _tagstrndup(ctx, (char *)all->data, all->length); parse.NestedParse("INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", ctx.DBs[db].Name, E.SCHEMA_TABLE(db), name, trig.Table, z); C._tagfree(ctx, ref z); parse.ChangeCookie(db); v.AddParseSchemaOp(db, C._mtagprintf(ctx, "type='trigger' AND name='%q'", name)); } if (!ctx.Init.Busy) { Trigger link = trig; Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null)); trig = ctx.DBs[db].Schema.TriggerHash.Insert(name, name.Length, trig); if (trig != null) { ctx.MallocFailed = true; } else if (link.Schema == link.TabSchema) { int tableLength = link.Table.Length; Table table = (Table)link.TabSchema.TableHash.Find(link.Table, tableLength, (Table)null); Debug.Assert(table != null); link.Next = table.Triggers; table.Triggers = link; } } triggerfinish_cleanup: DeleteTrigger(ctx, ref trig); Debug.Assert(parse.NewTrigger == null); DeleteTriggerStep(ctx, ref stepList); }
/* ** Generate VDBE code for the statements inside the body of a single ** trigger. */ static int codeTriggerProgram( Parse pParse, /* The parser context */ TriggerStep pStepList, /* List of statements inside the trigger body */ int orconf /* Conflict algorithm. (OE_Abort, etc) */ ) { TriggerStep pStep; Vdbe v = pParse.pVdbe; sqlite3 db = pParse.db; Debug.Assert( pParse.pTriggerTab != null && pParse.pToplevel != null ); Debug.Assert( pStepList != null ); Debug.Assert( v != null ); for ( pStep = pStepList; pStep != null; pStep = pStep.pNext ) { /* Figure out the ON CONFLICT policy that will be used for this step ** of the trigger program. If the statement that caused this trigger ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use ** the ON CONFLICT policy that was specified as part of the trigger ** step statement. Example: ** ** CREATE TRIGGER AFTER INSERT ON t1 BEGIN; ** INSERT OR REPLACE INTO t2 VALUES(new.a, new.b); ** END; ** ** INSERT INTO t1 ... ; -- insert into t2 uses REPLACE policy ** INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy */ pParse.eOrconf = ( orconf == OE_Default ) ? pStep.orconf : (u8)orconf; switch ( pStep.op ) { case TK_UPDATE: { sqlite3Update( pParse, targetSrcList( pParse, pStep ), sqlite3ExprListDup( db, pStep.pExprList, 0 ), sqlite3ExprDup( db, pStep.pWhere, 0 ), pParse.eOrconf ); break; } case TK_INSERT: { sqlite3Insert( pParse, targetSrcList( pParse, pStep ), sqlite3ExprListDup( db, pStep.pExprList, 0 ), sqlite3SelectDup( db, pStep.pSelect, 0 ), sqlite3IdListDup( db, pStep.pIdList ), pParse.eOrconf ); break; } case TK_DELETE: { sqlite3DeleteFrom( pParse, targetSrcList( pParse, pStep ), sqlite3ExprDup( db, pStep.pWhere, 0 ) ); break; } default: Debug.Assert( pStep.op == TK_SELECT ); { SelectDest sDest = new SelectDest(); Select pSelect = sqlite3SelectDup( db, pStep.pSelect, 0 ); sqlite3SelectDestInit( sDest, SRT_Discard, 0 ); sqlite3Select( pParse, pSelect, ref sDest ); sqlite3SelectDelete( db, ref pSelect ); break; } } if ( pStep.op != TK_SELECT ) { sqlite3VdbeAddOp0( v, OP_ResetCount ); } } return 0; }
/* ** Generate VDBE code for zero or more statements inside the body of a ** trigger. */ static int codeTriggerProgram( Parse pParse, /* The parser context */ TriggerStep pStepList, /* List of statements inside the trigger body */ int orconfin /* Conflict algorithm. (OE_Abort, etc) */ ) { TriggerStep pTriggerStep = pStepList; int orconf; Vdbe v = pParse.pVdbe; sqlite3 db = pParse.db; Debug.Assert( pTriggerStep != null ); Debug.Assert( v != null ); sqlite3VdbeAddOp2( v, OP_ContextPush, 0, 0 ); #if SQLITE_DEBUG VdbeComment( v, "begin trigger %s", pStepList.pTrig.name ); #endif while ( pTriggerStep != null ) { sqlite3ExprCacheClear( pParse ); orconf = ( orconfin == OE_Default ) ? pTriggerStep.orconf : orconfin; pParse.trigStack.orconf = orconf; switch ( pTriggerStep.op ) { case TK_UPDATE: { SrcList pSrc; pSrc = targetSrcList( pParse, pTriggerStep ); sqlite3VdbeAddOp2( v, OP_ResetCount, 0, 0 ); sqlite3Update( pParse, pSrc, sqlite3ExprListDup( db, pTriggerStep.pExprList, 0 ), sqlite3ExprDup( db, pTriggerStep.pWhere, 0 ), orconf ); sqlite3VdbeAddOp2( v, OP_ResetCount, 1, 0 ); break; } case TK_INSERT: { SrcList pSrc; pSrc = targetSrcList( pParse, pTriggerStep ); sqlite3VdbeAddOp2( v, OP_ResetCount, 0, 0 ); sqlite3Insert( pParse, pSrc, sqlite3ExprListDup( db, pTriggerStep.pExprList, 0 ), sqlite3SelectDup( db, pTriggerStep.pSelect, 0 ), sqlite3IdListDup( db, pTriggerStep.pIdList ), orconf ); sqlite3VdbeAddOp2( v, OP_ResetCount, 1, 0 ); break; } case TK_DELETE: { SrcList pSrc; sqlite3VdbeAddOp2( v, OP_ResetCount, 0, 0 ); pSrc = targetSrcList( pParse, pTriggerStep ); sqlite3DeleteFrom( pParse, pSrc, sqlite3ExprDup( db, pTriggerStep.pWhere, 0 ) ); sqlite3VdbeAddOp2( v, OP_ResetCount, 1, 0 ); break; } default: Debug.Assert( pTriggerStep.op == TK_SELECT ); { Select ss = sqlite3SelectDup( db, pTriggerStep.pSelect, 0 ); if ( ss != null ) { SelectDest dest = new SelectDest(); sqlite3SelectDestInit( dest, SRT_Discard, 0 ); sqlite3Select( pParse, ss, ref dest ); sqlite3SelectDelete( db, ref ss ); } break; } } pTriggerStep = pTriggerStep.pNext; } sqlite3VdbeAddOp2( v, OP_ContextPop, 0, 0 ); #if SQLITE_DEBUG VdbeComment( v, "end trigger %s", pStepList.pTrig.name ); #endif return 0; }