private void cb_NifEmpresa_SelectedIndexChanged(object sender, EventArgs e) { RE = RD.ProcuraEmpresa(Convert.ToInt32(cb_NifEmpresa.SelectedItem)); foreach (OrientadorEmpresa OE in RE.GetListaOrientadoresEmpresa()) { cb_Orientador.Items.Add(OE.GetNumOrientador()); } }
private void button1_Click_1(object sender, EventArgs e) { switch (cb_tipoUtilizador.Text) { case "Aluno": foreach (Aluno A in RD.GetListaPessoa().OfType <Aluno>()) { if (A.GetUser() == txt_username.Text && A.GetPass() == txt_Password.Text) { RD.SetLogin(A.GetNome()); this.DialogResult = DialogResult.Yes; } } break; case "Docente": foreach (Docente D in RD.GetListaPessoa().OfType <Docente>()) { if (D.GetUser() == txt_username.Text && D.GetPass() == txt_Password.Text) { RD.SetLogin(D.GetNome()); this.DialogResult = DialogResult.Yes; } } break; case "Orientador": foreach (OrientadorEmpresa OE in RD.GetListaPessoa().OfType <OrientadorEmpresa>()) { if (OE.GetUser() == txt_username.Text && OE.GetPass() == txt_Password.Text) { RD.SetLogin(OE.GetNome()); this.DialogResult = DialogResult.Yes; } } break; case "Empresa": foreach (Empresa EM in RD.GetListaEmpresa()) { if (EM.GetUser() == txt_username.Text && EM.GetPass() == txt_Password.Text) { RD.SetLogin(EM.GetNome()); this.DialogResult = DialogResult.Yes; } } break; } }
private static string GetTextContents(OE oe) { var t = oe.Items.OfType <TextRange>().FirstOrDefault()?.Value ?? "[No text]"; if (t.StartsWith("<")) { var m = _simpleTagStripper.Match(t); if (m.Success) { t = m.Groups[1].Value; } } return(t); }
static string OnErrorText(OE onError) { switch (onError) { case OE.Abort: return("abort"); case OE.Rollback: return("rollback"); case OE.Fail: return("fail"); case OE.Replace: return("replace"); case OE.Ignore: return("ignore"); case OE.Default: return("default"); } return("n/a"); }
static TriggerPrg GetRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf) { Parse root = E.Parse_Toplevel(parse); Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger)); // It may be that this trigger has already been coded (or is in the process of being coded). If this is the case, then an entry with // a matching TriggerPrg.pTrigger field will be present somewhere in the Parse.pTriggerPrg list. Search for such an entry. TriggerPrg prg; for (prg = root.TriggerPrg; prg != null && (prg.Trigger != trigger || prg.Orconf != orconf); prg = prg.Next) { ; } // If an existing TriggerPrg could not be located, create a new one. if (prg == null) { prg = CodeRowTrigger(parse, trigger, table, orconf); } return(prg); }
public void CodeRowTriggerDirect(Parse parse, Table table, int reg, OE orconf, int ignoreJump) { Vdbe v = parse.GetVdbe(); // Main VM TriggerPrg prg = GetRowTrigger(parse, this, table, orconf); Debug.Assert(prg != null || parse.Errs != 0 || parse.Ctx.MallocFailed); // Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program is a pointer to the sub-vdbe containing the trigger program. if (prg != null) { bool recursive = (Name != null && (parse.Ctx.Flags & Context.FLAG.RecTriggers) == 0); v.AddOp3(Core.OP.Program, reg, ignoreJump, ++parse.Mems); v.ChangeP4(-1, prg.Program, Vdbe.P4T.SUBPROGRAM); #if DEBUG v.Comment("Call: %s.%s", (!string.IsNullOrEmpty(p.Name) ? p.Name : "fkey"), OnErrorText(orconf)); #endif // Set the P5 operand of the OP_Program instruction to non-zero if recursive invocation of this trigger program is disallowed. Recursive // invocation is disallowed if (a) the sub-program is really a trigger, not a foreign key action, and (b) the flag to enable recursive triggers is clear. v.ChangeP5((int)(recursive ? 1 : 0)); } }
public HeadingTreeItem(int index, IDictionary <string, QuickStyleDef> styleDefs, OE element) : base(element.objectID, index) { _styleDefs = styleDefs; _element = element; Title = element.Items.OfType <TextRange>().FirstOrDefault()?.Value ?? "[Unknown title]"; var qsd = styleDefs[element.quickStyleIndex]; if (qsd.name.StartsWith("h")) { HeadingLevel = int.Parse(qsd.name.Substring(1)); } this.WhenAnyValue(x => x.HeadingLevel) .Select(x => x > 1) .ToProperty(this, x => x.CanPromote, out _canPromote); this.WhenAnyValue(x => x.HeadingLevel).Select(x => x < 6) .ToProperty(this, x => x.CanDemote, out _canDemote); _canCreateChild = _canDemote; }
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 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); }
public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, int null_4, Select select, OE orconf) { return(TriggerInsertStep(ctx, tableName, column, null, select, orconf)); }
public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, ExprList list, int null_5, OE orconf) { return(TriggerInsertStep(ctx, tableName, column, list, null, orconf)); }
public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, int null_4, Select select, OE orconf) { return TriggerInsertStep(ctx, tableName, column, null, select, orconf); }
static TriggerPrg CodeRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf) { Parse top = E.Parse_Toplevel(parse); Context ctx = parse.Ctx; // Database handle Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger)); Debug.Assert(top.V != null); // Allocate the TriggerPrg and SubProgram objects. To ensure that they are freed if an error occurs, link them into the Parse.pTriggerPrg // list of the top-level Parse object sooner rather than later. TriggerPrg prg = new TriggerPrg(); // Value to return //: _tagalloc(ctx, sizeof(TriggerPrg), true); if (prg == null) { return(null); } prg.Next = top.TriggerPrg; top.TriggerPrg = prg; Vdbe.SubProgram program; // Sub-vdbe for trigger program prg.Program = program = new Vdbe.SubProgram(); // sqlite3DbMallocZero( db, sizeof( SubProgram ) ); if (program == null) { return(null); } top.V.LinkSubProgram(program); prg.Trigger = trigger; prg.Orconf = orconf; prg.Colmasks[0] = 0xffffffff; prg.Colmasks[1] = 0xffffffff; // Allocate and populate a new Parse context to use for coding the trigger sub-program. Parse subParse = new Parse(); // Parse context for sub-vdbe //: _stackalloc(ctx, sizeof(Parse), true); if (subParse == null) { return(null); } NameContext sNC = new NameContext(); // Name context for sub-vdbe sNC.Parse = subParse; subParse.Ctx = ctx; subParse.TriggerTab = table; subParse.Toplevel = top; subParse.AuthContext = trigger.Name; subParse.TriggerOp = trigger.OP; subParse.QueryLoops = parse.QueryLoops; int endTrigger = 0; // Label to jump to if WHEN is false Vdbe v = subParse.GetVdbe(); // Temporary VM if (v != null) { #if DEBUG v.Comment("Start: %s.%s (%s %s%s%s ON %s)", trigger.Name, OnErrorText(orconf), (trigger.TRtm == TRIGGER.BEFORE ? "BEFORE" : "AFTER"), (trigger.OP == TK.UPDATE ? "UPDATE" : string.Empty), (trigger.OP == TK.INSERT ? "INSERT" : string.Empty), (trigger.OP == TK.DELETE ? "DELETE" : string.Empty), table.Name); #endif #if !OMIT_TRACE v.ChangeP4(-1, C._mtagprintf(ctx, "-- TRIGGER %s", trigger.Name), Vdbe.P4T.DYNAMIC); #endif // If one was specified, code the WHEN clause. If it evaluates to false (or NULL) the sub-vdbe is immediately halted by jumping to the // OP_Halt inserted at the end of the program. if (trigger.When != null) { Expr when = Expr.Dup(ctx, trigger.When, 0); // Duplicate of trigger WHEN expression if (ResolveExprNames(sNC, ref when) == RC.OK && !ctx.MallocFailed) { endTrigger = v.MakeLabel(); subParse.IfFalse(when, endTrigger, RC_JUMPIFNULL); } Expr.Delete(ctx, ref when); } // Code the trigger program into the sub-vdbe. CodeTriggerProgram(subParse, trigger.StepList, orconf); // Insert an OP_Halt at the end of the sub-program. if (endTrigger != 0) { v.ResolveLabel(endTrigger); } v.AddOp0(Core.OP.Halt); #if DEBUG v.Comment("End: %s.%s", trigger.Name, OnErrorText(orconf)); #endif TransferParseError(parse, subParse); if (!ctx.MallocFailed) { program.Ops.data = v.TakeOpArray(ref program.Ops.length, ref top.MaxArgs); } program.Mems = subParse.Mems; program.Csrs = subParse.Tabs; program.Token = trigger.GetHashCode(); prg.Colmasks[0] = subParse.Oldmask; prg.Colmasks[1] = subParse.Newmask; Vdbe.Delete(v); } Debug.Assert(subParse.Ainc == null && subParse.ZombieTab == null); Debug.Assert(subParse.TriggerPrg == null && subParse.MaxArgs == 0); C._stackfree(ctx, ref subParse); return(prg); }
static string OnErrorText(OE onError) { switch (onError) { case OE.Abort: return "abort"; case OE.Rollback: return "rollback"; case OE.Fail: return "fail"; case OE.Replace: return "replace"; case OE.Ignore: return "ignore"; case OE.Default: return "default"; } return "n/a"; }
static TriggerPrg CodeRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf) { Parse top = E.Parse_Toplevel(parse); Context ctx = parse.Ctx; // Database handle Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger)); Debug.Assert(top.V != null); // Allocate the TriggerPrg and SubProgram objects. To ensure that they are freed if an error occurs, link them into the Parse.pTriggerPrg // list of the top-level Parse object sooner rather than later. TriggerPrg prg = new TriggerPrg(); // Value to return //: _tagalloc(ctx, sizeof(TriggerPrg), true); if (prg == null) return null; prg.Next = top.TriggerPrg; top.TriggerPrg = prg; Vdbe.SubProgram program; // Sub-vdbe for trigger program prg.Program = program = new Vdbe.SubProgram();// sqlite3DbMallocZero( db, sizeof( SubProgram ) ); if (program == null) return null; top.V.LinkSubProgram(program); prg.Trigger = trigger; prg.Orconf = orconf; prg.Colmasks[0] = 0xffffffff; prg.Colmasks[1] = 0xffffffff; // Allocate and populate a new Parse context to use for coding the trigger sub-program. Parse subParse = new Parse(); // Parse context for sub-vdbe //: _stackalloc(ctx, sizeof(Parse), true); if (subParse == null) return null; NameContext sNC = new NameContext(); // Name context for sub-vdbe sNC.Parse = subParse; subParse.Ctx = ctx; subParse.TriggerTab = table; subParse.Toplevel = top; subParse.AuthContext = trigger.Name; subParse.TriggerOp = trigger.OP; subParse.QueryLoops = parse.QueryLoops; int endTrigger = 0; // Label to jump to if WHEN is false Vdbe v = subParse.GetVdbe(); // Temporary VM if (v != null) { #if DEBUG v.Comment("Start: %s.%s (%s %s%s%s ON %s)", trigger.Name, OnErrorText(orconf), (trigger.TRtm == TRIGGER.BEFORE ? "BEFORE" : "AFTER"), (trigger.OP == TK.UPDATE ? "UPDATE" : string.Empty), (trigger.OP == TK.INSERT ? "INSERT" : string.Empty), (trigger.OP == TK.DELETE ? "DELETE" : string.Empty), table.Name); #endif #if !OMIT_TRACE v.ChangeP4(-1, C._mtagprintf(ctx, "-- TRIGGER %s", trigger.Name), Vdbe.P4T.DYNAMIC); #endif // If one was specified, code the WHEN clause. If it evaluates to false (or NULL) the sub-vdbe is immediately halted by jumping to the // OP_Halt inserted at the end of the program. if (trigger.When != null) { Expr when = Expr.Dup(ctx, trigger.When, 0); // Duplicate of trigger WHEN expression if (ResolveExprNames(sNC, ref when) == RC.OK && !ctx.MallocFailed) { endTrigger = v.MakeLabel(); subParse.IfFalse(when, endTrigger, RC_JUMPIFNULL); } Expr.Delete(ctx, ref when); } // Code the trigger program into the sub-vdbe. CodeTriggerProgram(subParse, trigger.StepList, orconf); // Insert an OP_Halt at the end of the sub-program. if (endTrigger != 0) v.ResolveLabel(endTrigger); v.AddOp0(Core.OP.Halt); #if DEBUG v.Comment("End: %s.%s", trigger.Name, OnErrorText(orconf)); #endif TransferParseError(parse, subParse); if (!ctx.MallocFailed) program.Ops.data = v.TakeOpArray(ref program.Ops.length, ref top.MaxArgs); program.Mems = subParse.Mems; program.Csrs = subParse.Tabs; program.Token = trigger.GetHashCode(); prg.Colmasks[0] = subParse.Oldmask; prg.Colmasks[1] = subParse.Newmask; Vdbe.Delete(v); } Debug.Assert(subParse.Ainc == null && subParse.ZombieTab == null); Debug.Assert(subParse.TriggerPrg == null && subParse.MaxArgs == 0); C._stackfree(ctx, ref subParse); return prg; }
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; }
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 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; }
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); }
public uint TriggerColmask(Parse parse, ExprList changes, bool isNew, TRIGGER trtm, Table table, OE orconf) { TK op = (changes != null ? TK.UPDATE : TK.DELETE); int isNewId = (isNew ? 1 : 0); uint mask = 0; for (Trigger p = this; p != null; p = p.Next) { if (p.OP == op && (trtm & p.TRtm) != 0 && CheckColumnOverlap(p.Columns, changes)) { TriggerPrg prg = GetRowTrigger(parse, p, table, orconf); if (prg != null) { mask |= prg.Colmasks[isNewId]; } } } return(mask); }
public static void sqlite3Update(Parse parse, SrcList tabList, ExprList changes, Expr where_, OE onError) { int i, j; // Loop counters AuthContext sContext = new AuthContext(); // The authorization context Context ctx = parse.Ctx; // The database structure if (parse.Errs != 0 || ctx.MallocFailed) { goto update_cleanup; } Debug.Assert(tabList.Srcs == 1); // Locate the table which we want to update. Table table = sqlite3SrcListLookup(parse, tabList); // The table to be updated if (table == null) { goto update_cleanup; } int db = sqlite3SchemaToIndex(ctx, table.Schema); // Database containing the table being updated // Figure out if we have any triggers and if the table being updated is a view. #if !OMIT_TRIGGER int tmask = 0; // Mask of TRIGGER_BEFORE|TRIGGER_AFTER Trigger trigger = sqlite3TriggersExist(parse, table, TK.UPDATE, changes, out tmask); // List of triggers on pTab, if required #if OMIT_VIEW const bool isView = false; #else bool isView = (table.Select != null); // True when updating a view (INSTEAD OF trigger) #endif Debug.Assert(trigger != null || tmask == 0); #else const Trigger trigger = null; const int tmask = 0; const bool isView = false; #endif if (sqlite3ViewGetColumnNames(parse, table) != 0 || sqlite3IsReadOnly(parse, table, tmask)) { goto update_cleanup; } int[] xrefs = new int[table.Cols.length]; // xrefs[i] is the index in pChanges->a[] of the an expression for the i-th column of the table. xrefs[i]==-1 if the i-th column is not changed. if (xrefs == null) { goto update_cleanup; } for (i = 0; i < table.Cols.length; i++) { xrefs[i] = -1; } // Allocate a cursors for the main database table and for all indices. The index cursors might not be used, but if they are used they // need to occur right after the database cursor. So go ahead and allocate enough space, just in case. int curId; // VDBE Cursor number of pTab tabList.Ids[0].Cursor = curId = parse.Tabs++; Index idx; // For looping over indices for (idx = table.Index; idx != null; idx = idx.Next) { parse.Tabs++; } // Initialize the name-context NameContext sNC = new NameContext(); // The name-context to resolve expressions in sNC.Parse = parse; sNC.SrcList = tabList; // Resolve the column names in all the expressions of the of the UPDATE statement. Also find the column index // for each column to be updated in the pChanges array. For each column to be updated, make sure we have authorization to change that column. bool chngRowid = false; // True if the record number is being changed Expr rowidExpr = null; // Expression defining the new record number for (i = 0; i < changes.Exprs; i++) { if (sqlite3ResolveExprNames(sNC, ref changes.Ids[i].Expr) != 0) { goto update_cleanup; } for (j = 0; j < table.Cols.length; j++) { if (string.Equals(table.Cols[j].Name, changes.Ids[i].Name, StringComparison.OrdinalIgnoreCase)) { if (j == table.PKey) { chngRowid = true; rowidExpr = changes.Ids[i].Expr; } xrefs[j] = i; break; } } if (j >= table.Cols.length) { if (Expr::IsRowid(changes.Ids[i].Name)) { chngRowid = true; rowidExpr = changes.Ids[i].Expr; } else { parse.ErrorMsg("no such column: %s", changes.Ids[i].Name); parse.CheckSchema = 1; goto update_cleanup; } } #if !OMIT_AUTHORIZATION { ARC rc = Auth.Check(parse, AUTH.UPDATE, table.Name, table.Cols[j].Name, ctx.DBs[db].Name); if (rc == ARC.DENY) { goto update_cleanup; } else if (rc == ARC.IGNORE) { xrefs[j] = -1; } } #endif } bool hasFK = sqlite3FkRequired(parse, table, xrefs, chngRowid ? 1 : 0); // True if foreign key processing is required // Allocate memory for the array aRegIdx[]. There is one entry in the array for each index associated with table being updated. Fill in // the value with a register number for indices that are to be used and with zero for unused indices. int idxLength; // Number of indices that need updating for (idxLength = 0, idx = table.Index; idx != null; idx = idx.Next, idxLength++) { ; } int[] regIdxs = null; // One register assigned to each index to be updated if (idxLength > 0) { regIdxs = new int[idxLength]; if (regIdxs == null) { goto update_cleanup; } } for (j = 0, idx = table.Index; idx != null; idx = idx.Next, j++) { int regId; if (hasFK || chngRowid) { regId = ++parse.Mems; } else { regId = 0; for (i = 0; i < idx.Columns.length; i++) { if (xrefs[idx.Columns[i]] >= 0) { regId = ++parse.Mems; break; } } } regIdxs[j] = regId; } // Begin generating code. Vdbe v = parse.GetVdbe(); // The virtual database engine if (v == null) { goto update_cleanup; } if (parse.Nested == 0) { v.CountChanges(); } parse.BeginWriteOperation(1, db); #if !OMIT_VIRTUALTABLE // Virtual tables must be handled separately if (IsVirtual(table)) { UpdateVirtualTable(parse, tabList, table, changes, rowidExpr, xrefs, where_, onError); where_ = null; tabList = null; goto update_cleanup; } #endif // Register Allocations int regRowCount = 0; // A count of rows changed int regOldRowid; // The old rowid int regNewRowid; // The new rowid int regNew; int regOld = 0; int regRowSet = 0; // Rowset of rows to be updated // Allocate required registers. regOldRowid = regNewRowid = ++parse.Mems; if (trigger != null || hasFK) { regOld = parse.Mems + 1; parse.Mems += table.Cols.length; } if (chngRowid || trigger != null || hasFK) { regNewRowid = ++parse.Mems; } regNew = parse.Mems + 1; parse.Mems += table.Cols.length; // Start the view context. if (isView) { Auth.ContextPush(parse, sContext, table.Name); } // If we are trying to update a view, realize that view into a ephemeral table. #if !OMIT_VIEW && !OMIT_TRIGGER if (isView) { sqlite3MaterializeView(parse, table, where_, curId); } #endif // Resolve the column names in all the expressions in the WHERE clause. if (sqlite3ResolveExprNames(sNC, ref where_) != 0) { goto update_cleanup; } // Begin the database scan v.AddOp2(OP.Null, 0, regOldRowid); ExprList dummy = null; WhereInfo winfo = Where.Begin(parse, tabList, where_, ref dummy, WHERE.ONEPASS_DESIRED); // Information about the WHERE clause if (winfo == null) { goto update_cleanup; } bool okOnePass = winfo.OkOnePass; // True for one-pass algorithm without the FIFO // Remember the rowid of every item to be updated. v.AddOp2(OP.Rowid, curId, regOldRowid); if (!okOnePass) { v.AddOp2(OP.RowSetAdd, regRowSet, regOldRowid); } // End the database scan loop. Where.End(winfo); // Initialize the count of updated rows if ((ctx.Flags & Context.FLAG.CountRows) != 0 && parse.TriggerTab == null) { regRowCount = ++parse.Mems; v.AddOp2(OP.Integer, 0, regRowCount); } bool openAll = false; // True if all indices need to be opened if (!isView) { // Open every index that needs updating. Note that if any index could potentially invoke a REPLACE conflict resolution // action, then we need to open all indices because we might need to be deleting some records. if (!okOnePass) { sqlite3OpenTable(parse, curId, db, table, OP.OpenWrite); } if (onError == OE.Replace) { openAll = true; } else { openAll = false; for (idx = table.Index; idx != null; idx = idx.Next) { if (idx.OnError == OE.Replace) { openAll = true; break; } } } for (i = 0, idx = table.Index; idx != null; idx = idx.Next, i++) { if (openAll || regIdxs[i] > 0) { KeyInfo key = sqlite3IndexKeyinfo(parse, idx); v.AddOp4(OP.OpenWrite, curId + i + 1, idx.Id, db, key, Vdbe.P4T.KEYINFO_HANDOFF); Debug.Assert(parse.Tabs > curId + i + 1); } } } // Top of the update loop int addr = 0; // VDBE instruction address of the start of the loop if (okOnePass) { int a1 = v.AddOp1(OP.NotNull, regOldRowid); addr = v.AddOp0(OP.Goto); v.JumpHere(a1); } else { addr = v.AddOp3(OP.RowSetRead, regRowSet, 0, regOldRowid); } // Make cursor iCur point to the record that is being updated. If this record does not exist for some reason (deleted by a trigger, // for example, then jump to the next iteration of the RowSet loop. v.AddOp3(OP.NotExists, curId, addr, regOldRowid); // If the record number will change, set register regNewRowid to contain the new value. If the record number is not being modified, // then regNewRowid is the same register as regOldRowid, which is already populated. Debug.Assert(chngRowid || trigger != null || hasFK || regOldRowid == regNewRowid); if (chngRowid) { Expr.Code(parse, rowidExpr, regNewRowid); v.AddOp1(OP.MustBeInt, regNewRowid); } // If there are triggers on this table, populate an array of registers with the required old.* column data. if (hasFK || trigger != null) { uint oldmask = (hasFK ? sqlite3FkOldmask(parse, table) : 0); oldmask |= sqlite3TriggerColmask(parse, trigger, changes, 0, TRIGGER_BEFORE | TRIGGER_AFTER, table, onError); for (i = 0; i < table.Cols.length; i++) { if (xrefs[i] < 0 || oldmask == 0xffffffff || (i < 32 && 0 != (oldmask & (1 << i)))) { Expr.CodeGetColumnOfTable(v, table, curId, i, regOld + i); } else { v.AddOp2(OP.Null, 0, regOld + i); } } if (!chngRowid) { v.AddOp2(OP.Copy, regOldRowid, regNewRowid); } } // Populate the array of registers beginning at regNew with the new row data. This array is used to check constaints, create the new // table and index records, and as the values for any new.* references made by triggers. // // If there are one or more BEFORE triggers, then do not populate the registers associated with columns that are (a) not modified by // this UPDATE statement and (b) not accessed by new.* references. The values for registers not modified by the UPDATE must be reloaded from // the database after the BEFORE triggers are fired anyway (as the trigger may have modified them). So not loading those that are not going to // be used eliminates some redundant opcodes. int newmask = (int)sqlite3TriggerColmask(parse, trigger, changes, 1, TRIGGER_BEFORE, table, onError); // Mask of NEW.* columns accessed by BEFORE triggers for (i = 0; i < table.Cols.length; i++) { if (i == table.PKey) { //v.AddOp2(OP.Null, 0, regNew + i); } else { j = xrefs[i]; if (j >= 0) { Expr.Code(parse, changes.Ids[j].Expr, regNew + i); } else if ((tmask & TRIGGER_BEFORE) == 0 || i > 31 || (newmask & (1 << i)) != 0) { // This branch loads the value of a column that will not be changed into a register. This is done if there are no BEFORE triggers, or // if there are one or more BEFORE triggers that use this value via a new.* reference in a trigger program. C.ASSERTCOVERAGE(i == 31); C.ASSERTCOVERAGE(i == 32); v.AddOp3(OP.Column, curId, i, regNew + i); v.ColumnDefault(table, i, regNew + i); } } } // Fire any BEFORE UPDATE triggers. This happens before constraints are verified. One could argue that this is wrong. if ((tmask & TRIGGER_BEFORE) != 0) { v.AddOp2(OP.Affinity, regNew, table.Cols.length); sqlite3TableAffinityStr(v, table); sqlite3CodeRowTrigger(parse, trigger, TK.UPDATE, changes, TRIGGER_BEFORE, table, regOldRowid, onError, addr); // The row-trigger may have deleted the row being updated. In this case, jump to the next row. No updates or AFTER triggers are // required. This behavior - what happens when the row being updated is deleted or renamed by a BEFORE trigger - is left undefined in the documentation. v.AddOp3(OP.NotExists, curId, addr, regOldRowid); // If it did not delete it, the row-trigger may still have modified some of the columns of the row being updated. Load the values for // all columns not modified by the update statement into their registers in case this has happened. for (i = 0; i < table.Cols.length; i++) { if (xrefs[i] < 0 && i != table.PKey) { v.AddOp3(OP.Column, curId, i, regNew + i); v.ColumnDefault(table, i, regNew + i); } } } if (!isView) { // Do constraint checks. int dummy2; sqlite3GenerateConstraintChecks(parse, table, curId, regNewRowid, regIdxs, (chngRowid ? regOldRowid : 0), true, onError, addr, out dummy2); // Do FK constraint checks. if (hasFK) { sqlite3FkCheck(parse, table, regOldRowid, 0); } // Delete the index entries associated with the current record. int j1 = v.AddOp3(OP.NotExists, curId, 0, regOldRowid); // Address of jump instruction sqlite3GenerateRowIndexDelete(parse, table, curId, regIdxs); // If changing the record number, delete the old record. if (hasFK || chngRowid) { v.AddOp2(OP.Delete, curId, 0); } v.JumpHere(j1); if (hasFK) { sqlite3FkCheck(parse, table, 0, regNewRowid); } // Insert the new index entries and the new record. sqlite3CompleteInsertion(parse, table, curId, regNewRowid, regIdxs, true, false, false); // Do any ON CASCADE, SET NULL or SET DEFAULT operations required to handle rows (possibly in other tables) that refer via a foreign key // to the row just updated. if (hasFK) { sqlite3FkActions(parse, table, changes, regOldRowid); } } // Increment the row counter if ((ctx.Flags & Context.FLAG.CountRows) != 0 && parse.TriggerTab == null) { v.AddOp2(OP.AddImm, regRowCount, 1); } sqlite3CodeRowTrigger(parse, trigger, TK.UPDATE, changes, TRIGGER_AFTER, table, regOldRowid, onError, addr); // Repeat the above with the next record to be updated, until all record selected by the WHERE clause have been updated. v.AddOp2(OP.Goto, 0, addr); v.JumpHere(addr); // Close all tables Debug.Assert(regIdxs != null); for (i = 0, idx = table.Index; idx != null; idx = idx.Next, i++) { if (openAll || regIdxs[i] > 0) { v.AddOp2(OP.Close, curId + i + 1, 0); } } v.AddOp2(OP.Close, curId, 0); // Update the sqlite_sequence table by storing the content of the maximum rowid counter values recorded while inserting into // autoincrement tables. if (parse.Nested == 0 && parse.TriggerTab == null) { sqlite3AutoincrementEnd(parse); } // Return the number of rows that were changed. If this routine is generating code because of a call to sqlite3NestedParse(), do not // invoke the callback function. if ((ctx.Flags & Context.FLAG.CountRows) != 0 && parse.TriggerTab == null && parse.Nested == 0) { v.AddOp2(OP.ResultRow, regRowCount, 1); v.SetNumCols(1); v.SetColName(0, COLNAME_NAME, "rows updated", SQLITE_STATIC); } update_cleanup: #if !OMIT_AUTHORIZATION Auth.ContextPop(sContext); #endif C._tagfree(ctx, ref regIdxs); C._tagfree(ctx, ref xrefs); SrcList.Delete(ctx, ref tabList); ExprList.Delete(ctx, ref changes); Expr.Delete(ctx, ref where_); return; }
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); }
static TriggerPrg GetRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf) { Parse root = E.Parse_Toplevel(parse); Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger)); // It may be that this trigger has already been coded (or is in the process of being coded). If this is the case, then an entry with // a matching TriggerPrg.pTrigger field will be present somewhere in the Parse.pTriggerPrg list. Search for such an entry. TriggerPrg prg; for (prg = root.TriggerPrg; prg != null && (prg.Trigger != trigger || prg.Orconf != orconf); prg = prg.Next) ; // If an existing TriggerPrg could not be located, create a new one. if (prg == null) prg = CodeRowTrigger(parse, trigger, table, orconf); return prg; }
public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, ExprList list, int null_5, OE orconf) { return TriggerInsertStep(ctx, tableName, column, list, null, orconf); }
public void CodeRowTrigger(Parse parse, TK op, ExprList changes, TRIGGER trtm, Table table, int reg, OE orconf, int ignoreJump) { Debug.Assert(op == TK.UPDATE || op == TK.INSERT || op == TK.DELETE); Debug.Assert(trtm == TRIGGER.BEFORE || trtm == TRIGGER.AFTER); Debug.Assert((op == TK.UPDATE) == (changes != null)); for (Trigger p = this; p != null; p = p.Next) { // Sanity checking: The schema for the trigger and for the table are always defined. The trigger must be in the same schema as the table or else it must be a TEMP trigger. Debug.Assert(p.Schema != null); Debug.Assert(p.TabSchema != null); Debug.Assert(p.Schema == p.TabSchema || p.Schema == parse.Ctx.DBs[1].Schema); // Determine whether we should code this trigger if (p.OP == op && p.TRtm == trtm && CheckColumnOverlap(p.Columns, changes)) { p.CodeRowTriggerDirect(parse, table, reg, orconf, ignoreJump); } } }
protected void Page_Load(object sender, EventArgs e) { Label2.Text = DateTime.Now.ToString("D"); Label14.Text = ""; Label16.Text = ""; Label33.Text = ""; Label34.Text = ""; Label35.Text = ""; Label36.Text = ""; Label24.Text = ""; Label47.Text = ""; DataView dv = (DataView)SqlDataSource1.Select(DataSourceSelectArguments.Empty); foreach (DataRow dr in dv.Table.Rows) { Cname = (string)dv.Table.Rows[x][0]; Cadd = (string)dv.Table.Rows[x][1]; Ccomp = (string)dv.Table.Rows[x][2]; Label14.Text = Label14.Text + Cname; Label33.Text = Label33.Text + Cadd; Label34.Text = Label34.Text + Ccomp; Label16.Text = Label16.Text + Cname; Label35.Text = Label35.Text + Cadd; Label36.Text = Label36.Text + Ccomp; Label24.Text = Label24.Text + Cname; } Venue.Text = ""; VAdd.Text = ""; N.Text = ""; Label37.Text = ""; DataView dv1 = (DataView)SqlDataSource2.Select(DataSourceSelectArguments.Empty); foreach (DataRow dr in dv1.Table.Rows) { Vname = (string)dv1.Table.Rows[x][0]; Vadd = (string)dv1.Table.Rows[x][1]; Ename = (string)dv1.Table.Rows[x][2]; Edate = (DateTime)dv1.Table.Rows[x][3]; Venue.Text = Venue.Text + Vname; VAdd.Text = VAdd.Text + Vadd; N.Text = N.Text + Ename; Label37.Text = Edate.ToString("D"); } Label40.Text = ""; Label41.Text = ""; Label43.Text = ""; Label44.Text = ""; Label42.Text = ""; Label1.Text = ""; DataView dv2 = (DataView)SqlDataSource3.Select(DataSourceSelectArguments.Empty); foreach (DataRow dr in dv2.Table.Rows) { RF = (double)dv2.Table.Rows[x][0]; Total = (double)dv2.Table.Rows[x][4]; OE = (double)dv2.Table.Rows[x][1]; PB = (double)dv2.Table.Rows[x][2]; RPH = (double)dv2.Table.Rows[x][3]; DL = (DateTime)dv2.Table.Rows[x][5]; Label40.Text = Label40.Text + RF.ToString("n2"); Label41.Text = Label41.Text + Total.ToString("n2"); Label43.Text = Label43.Text + OE.ToString("n2"); Label44.Text = Label44.Text + PB.ToString("n2"); Label42.Text = Label42.Text + RPH.ToString("n2"); Label1.Text = DL.ToString("D"); } Label45.Text = ""; DataView dv3 = (DataView)SqlDataSource4.Select(DataSourceSelectArguments.Empty); foreach (DataRow dr in dv3.Table.Rows) { Edate = (DateTime)dv3.Table.Rows[x][0]; Estime = (TimeSpan)dv3.Table.Rows[x][1]; Eetime = (TimeSpan)dv3.Table.Rows[x][2]; Label45.Text = Edate.ToString("D") + ' ' + ConvertMode(Estime.ToString()) + ' ' + '-' + ' ' + ConvertMode(Eetime.ToString()); } Label46.Text = ""; DataView dv4 = (DataView)SqlDataSource5.Select(DataSourceSelectArguments.Empty); foreach (DataRow dr in dv4.Table.Rows) { Aname = (string)dv4.Table.Rows[x][0]; Ades = (string)dv4.Table.Rows[x][3]; qty = (int)dv4.Table.Rows[x][1]; Label46.Text = Label46.Text + ' ' + Ades + ' ' + qty.ToString() + ' ' + "pcs" + ", "; x++; } Label3.Text = ""; Label4.Text = ""; string check = Label46.Text; int lg = check.Length; if (x > 0) { Label3.Text = "<li> Amenity- "; check = check.Substring(0, lg - 2); Label46.Text = check + ";"; Label4.Text = "</li>"; } Label47.Text = ""; DataView dv5 = (DataView)SqlDataSource6.Select(DataSourceSelectArguments.Empty); foreach (DataRow dr in dv5.Table.Rows) { Fname = (string)dv5.Table.Rows[y][0]; Fdes = (string)dv5.Table.Rows[y][1]; Label47.Text = Label47.Text + Fname + ' ' + Fdes + ", "; y++; } string check2 = Label47.Text; int lg2 = check2.Length; Label5.Text = ""; Label6.Text = ""; if (y > 0) { Label5.Text = "<li> Facility- "; check2 = check2.Substring(0, lg2 - 2); Label47.Text = check2 + ";"; Label6.Text = "</li>"; } Label48.Text = ""; DataView dv6 = (DataView)SqlDataSource7.Select(DataSourceSelectArguments.Empty); foreach (DataRow dr in dv6.Table.Rows) { Fname = (string)dv6.Table.Rows[z][0]; Fdes = (string)dv6.Table.Rows[z][1]; Label48.Text = Label48.Text + Mname + ' ' + Mdes + ", "; z++; } string check3 = Label48.Text; int lg3 = check3.Length; if (lg3 != 0) { check3 = check3.Substring(0, lg3 - 2); Label48.Text = check3 + ";"; } }
public void CodeRowTrigger(Parse parse, TK op, ExprList changes, TRIGGER trtm, Table table, int reg, OE orconf, int ignoreJump) { Debug.Assert(op == TK.UPDATE || op == TK.INSERT || op == TK.DELETE); Debug.Assert(trtm == TRIGGER.BEFORE || trtm == TRIGGER.AFTER); Debug.Assert((op == TK.UPDATE) == (changes != null)); for (Trigger p = this; p != null; p = p.Next) { // Sanity checking: The schema for the trigger and for the table are always defined. The trigger must be in the same schema as the table or else it must be a TEMP trigger. Debug.Assert(p.Schema != null); Debug.Assert(p.TabSchema != null); Debug.Assert(p.Schema == p.TabSchema || p.Schema == parse.Ctx.DBs[1].Schema); // Determine whether we should code this trigger if (p.OP == op && p.TRtm == trtm && CheckColumnOverlap(p.Columns, changes)) p.CodeRowTriggerDirect(parse, table, reg, orconf, ignoreJump); } }
public uint TriggerColmask(Parse parse, ExprList changes, bool isNew, TRIGGER trtm, Table table, OE orconf) { TK op = (changes != null ? TK.UPDATE : TK.DELETE); int isNewId = (isNew ? 1 : 0); uint mask = 0; for (Trigger p = this; p != null; p = p.Next) if (p.OP == op && (trtm & p.TRtm) != 0 && CheckColumnOverlap(p.Columns, changes)) { TriggerPrg prg = GetRowTrigger(parse, p, table, orconf); if (prg != null) mask |= prg.Colmasks[isNewId]; } return mask; }
public static void GenerateRowDelete(Parse parse, Table table, int curId, int rowid, int count, Trigger trigger, OE onconf) { // Vdbe is guaranteed to have been allocated by this stage. Vdbe v = parse.V; Debug.Assert(v != null); // Seek cursor iCur to the row to delete. If this row no longer exists (this can happen if a trigger program has already deleted it), do // not attempt to delete it or fire any DELETE triggers. int label = v.MakeLabel(); // Label resolved to end of generated code v.AddOp3(OP.NotExists, curId, label, rowid); // If there are any triggers to fire, allocate a range of registers to use for the old.* references in the triggers. if (FKey.FkRequired(parse, table, null, 0) != 0 || trigger != null) { // TODO: Could use temporary registers here. Also could attempt to avoid copying the contents of the rowid register. uint mask = sqlite3TriggerColmask(parse, trigger, null, 0, TRIGGER.BEFORE | TRIGGER.AFTER, table, onconf); // Mask of OLD.* columns in use mask |= sqlite3FkOldmask(parse, table); int oldId = parse.Mems + 1; // First register in OLD.* array parse.Mems += (1 + table.Cols.length); // Populate the OLD.* pseudo-table register array. These values will be used by any BEFORE and AFTER triggers that exist. v.AddOp2(OP.Copy, rowid, oldId); for (int col = 0; col < table.Cols.length; col++) // Iterator used while populating OLD.* if (mask == 0xffffffff || (mask & (1 << col)) != 0) Expr.CodeGetColumnOfTable(v, table, curId, col, oldId + col + 1); // Invoke BEFORE DELETE trigger programs. sqlite3CodeRowTrigger(parse, trigger, TK.DELETE, null, TRIGGER.BEFORE, table, oldId, onconf, label); // Seek the cursor to the row to be deleted again. It may be that the BEFORE triggers coded above have already removed the row // being deleted. Do not attempt to delete the row a second time, and do not fire AFTER triggers. v.AddOp3(OP.NotExists, curId, label, rowid); // Do FK processing. This call checks that any FK constraints that refer to this table (i.e. constraints attached to other tables) are not violated by deleting this row. FKey.FkCheck(parse, table, oldId, 0); } // Delete the index and table entries. Skip this step if table is really a view (in which case the only effect of the DELETE statement is to fire the INSTEAD OF triggers). if (table.Select == null) { GenerateRowIndexDelete(parse, table, curId, null); v.AddOp2(OP.Delete, curId, (count != 0 ? (int)OPFLAG.NCHANGE : 0)); if (count != 0) v.ChangeP4(-1, table.Name, Vdbe.P4T.TRANSIENT); } // Do any ON CASCADE, SET NULL or SET DEFAULT operations required to handle rows (possibly in other tables) that refer via a foreign key to the row just deleted. FKey.FkActions(parse, table, null, oldId); // Invoke AFTER DELETE trigger programs. sqlite3CodeRowTrigger(parse, trigger, TK.DELETE, null, TRIGGER.AFTER, table, oldId, onconf, label); // Jump here if the row had already been deleted before any BEFORE trigger programs were invoked. Or if a trigger program throws a RAISE(IGNORE) exception. v.ResolveLabel(label); }