static RC GrowOps(Vdbe p) { int newLength = (p.OpsAlloc != 0 ? p.OpsAlloc * 2 : 1024 / 1); p.OpsAlloc = newLength; C._tagrealloc_or_create(p.Ctx, ref p.Ops.data, newLength); return (p.Ops.data != null ? RC.OK : RC.NOMEM); }
public static void SetSql(Vdbe p, string z, int n, bool isPrepareV2) { if (p == null) return; #if OMIT_TRACE && !ENABLE_SQLLOG if (isPrepareV2 == 0) return; #endif Debug.Assert(p.Sql_ == null); p.Sql_ = z.Substring(0, n); //: _tagstrndup(p->Ctx, z, n); p.IsPrepareV2 = isPrepareV2; }
public static Vdbe Create(Context ctx) { Vdbe p = new Vdbe(); if (p == null) return null; p.Ctx = ctx; if (ctx.Vdbes != null) ctx.Vdbes.Prev = p; p.Next = ctx.Vdbes; p.Prev = null; ctx.Vdbes = p; p.Magic = VDBE_MAGIC_INIT; return p; }
public static void Swap(Vdbe a, Vdbe b) { Vdbe tmp_ = new Vdbe(); a._memcpy(tmp_); b._memcpy(a); tmp_._memcpy(b); Vdbe tmp = tmp = a.Next; a.Next = b.Next; b.Next = tmp; tmp = a.Prev; a.Prev = b.Prev; b.Prev = tmp; string tmpSql = a.Sql_; a.Sql_ = b.Sql_; b.Sql_ = tmpSql; b.IsPrepareV2 = a.IsPrepareV2; }
static VdbeCursor AllocateCursor(Vdbe p, int curID, int fields, int db, bool isBtreeCursor) { // Find the memory cell that will be used to store the blob of memory required for this VdbeCursor structure. It is convenient to use a // vdbe memory cell to manage the memory allocation required for a VdbeCursor structure for the following reasons: // // * Sometimes cursor numbers are used for a couple of different purposes in a vdbe program. The different uses might require // different sized allocations. Memory cells provide growable allocations. // // * When using ENABLE_MEMORY_MANAGEMENT, memory cell buffers can be freed lazily via the sqlite3_release_memory() API. This // minimizes the number of malloc calls made by the system. // // Memory cells for cursors are allocated at the top of the address space. Memory cell (p->nMem) corresponds to cursor 0. Space for // cursor 1 is managed by memory cell (p->nMem-1), etc. VdbeCursor cx = null; Debug.Assert(curID < p.Cursors.length); if (p.Cursors[curID] != null) { p.FreeCursor(p.Cursors[curID]); p.Cursors[curID] = null; } //: if (Vdbe.MemGrow(mem, bytes, false) == RC.OK) { p.Cursors[curID] = cx = new VdbeCursor(); cx.Db = db; cx.Fields = fields; if (fields != 0) cx.Types = new uint[fields]; if (isBtreeCursor) { cx.Cursor = sqlite3MemMallocBtCursor(cx.Cursor); Btree.CursorZero(cx.Cursor); } } return cx; }
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); }
static void CodeOffset(Vdbe v, Select p, int continueId) { if (p.OffsetId != 0 && continueId != 0) { v.AddOp2(OP.AddImm, p.OffsetId, -1); int addr = v.AddOp1(OP.IfNeg, p.OffsetId); v.AddOp2(OP.Goto, 0, continueId); v.Comment("skip OFFSET records"); v.JumpHere(addr); } }
public int AddOp4(OP op, int p1, int p2, int p3, int[] p4, Vdbe.P4T p4t) // P4T_INTARRAY { Debug.Assert(p4 != null); int addr = AddOp3(op, p1, p2, p3); ChangeP4(addr, new P4_t { Is = p4 }, p4t); return addr; }
__device__ void sqlite3ExplainFinish(Vdbe *vdbe) { if (vdbe && vdbe->Explain) { _free(vdbe->ExplainString); sqlite3ExplainNL(vdbe); vdbe->ExplainString = vdbe->Explain->Str.ToString(); _free(vdbe->Explain); vdbe->Explain = nullptr; _benignalloc_end(); } }
__device__ void sqlite3ExplainPush(Vdbe *vdbe) { Explain *p; if (vdbe && (p = vdbe->Explain)!=0 ){ if (p->Str.zText && p->Indents.Length < _lengthof(p->Indents)) { const char *z = p->str.zText; int i = p->str.nChar-1; int x; while( i>=0 && z[i]!='\n' ){ i--; } x = (p->str.nChar - 1) - i; if( p->nIndent && x<p->aIndent[p->nIndent-1] ){ x = p->aIndent[p->nIndent-1]; } p->aIndent[p->nIndent] = x; } p->nIndent++; } }
public static void sqlite3ExplainPrintf(Vdbe vdbe, string format, params object[] args) { Explain p; if (vdbe != null && (p = vdbe.Explain) != null) { va_list ap; if (p->Indents && endsWithNL(p)) { int n = p->Indents; if (n > _lengthof(p->Indents)) n = _lengthof(p->Indents); sqlite3AppendSpace(&p->Str, p->Indents[n-1]); } va_start(ap, format); sqlite3VXPrintf(&p->Str, 1, zFormat, ap); va_end(ap); } }
public static RC Exec(Context ctx, string sql, Func <object, int, string[], string[], bool> callback, object arg, ref string errmsg) { RC rc = RC.OK; // Return code if (!SafetyCheckOk(ctx)) { return(SysEx.MISUSE_BKPT()); } if (sql == null) { sql = string.Empty; } MutexEx.Enter(ctx.Mutex); Error(ctx, RC.OK, null); Vdbe stmt = null; // The current SQL statement int retrys = 0; // Number of retry attempts string[] colsNames = null; // Names of result columns while ((rc == RC.OK || (rc == RC.SCHEMA && (++retrys) < 2)) && sql.Length > 0) { stmt = null; string leftover = null; // Tail of unprocessed SQL rc = Prepare.Prepare_(ctx, sql, -1, ref stmt, ref leftover); Debug.Assert(rc == RC.OK || stmt == null); if (rc != RC.OK) { continue; } if (stmt == null) { sql = leftover; // this happens for a comment or white-space continue; } bool callbackIsInit = false; // True if callback data is initialized int cols = Vdbe.Column_Count(stmt); while (true) { rc = stmt.Step(); // Invoke the callback function if required int i; if (callback != null && (rc == RC.ROW || (rc == RC.DONE && !callbackIsInit && (ctx.Flags & Context.FLAG.NullCallback) != 0))) { if (!callbackIsInit) { colsNames = new string[cols]; if (colsNames == null) { goto exec_out; } for (i = 0; i < cols; i++) { colsNames[i] = Vdbe.Column_Name(stmt, i); // Vdbe::SetColName() installs column names as UTF8 strings so there is no way for sqlite3_column_name() to fail. Debug.Assert(colsNames[i] != null); } callbackIsInit = true; } string[] colsValues = null; if (rc == RC.ROW) { colsValues = new string[cols]; for (i = 0; i < cols; i++) { colsValues[i] = Vdbe.Column_Text(stmt, i); if (colsValues[i] == null && Vdbe.Column_Type(stmt, i) != TYPE.NULL) { ctx.MallocFailed = true; goto exec_out; } } } if (callback(arg, cols, colsValues, colsNames)) { rc = RC.ABORT; stmt.Finalize(); stmt = null; Error(ctx, RC.ABORT, null); goto exec_out; } } if (rc != RC.ROW) { rc = stmt.Finalize(); stmt = null; if (rc != RC.SCHEMA) { retrys = 0; if ((sql = leftover) != string.Empty) { int idx = 0; while (idx < sql.Length && char.IsWhiteSpace(sql[idx])) { idx++; } if (idx != 0) { sql = (idx < sql.Length ? sql.Substring(idx) : string.Empty); } } } break; } } C._tagfree(ctx, ref colsNames); colsNames = null; } exec_out: if (stmt != null) { stmt.Finalize(); } C._tagfree(ctx, ref colsNames); rc = ApiExit(ctx, rc); if (rc != RC.OK && C._ALWAYS(rc == ErrCode(ctx)) && errmsg != null) { errmsg = ErrMsg(ctx); } else if (errmsg != null) { errmsg = null; } Debug.Assert((rc & (RC)ctx.ErrMask) == rc); MutexEx.Leave(ctx.Mutex); return(rc); }
static void VdbeInvokeSqllog(Vdbe p) { if (_Sqllog != null && p.RC_ == RC.OK && p.Sql_ != null && p.PC >= 0) { string expanded = p.ExpandSql(p.Sql_); Debug.Assert(!p.Ctx.Init.Busy); if (expanded != null) { _Sqllog(_SqllogArg, p.Ctx, expanded, 1); C._tagfree(p.Ctx, ref expanded); } } }
public int AddOp4(OP op, int p1, int p2, int p3, KeyInfo p4, Vdbe.P4T p4t) // KeyInfo { int addr = AddOp3(op, p1, p2, p3); ChangeP4(addr, new P4_t { KeyInfo = p4 }, p4t); return addr; }
public int AddOp4(OP op, int p1, int p2, int p3, CollSeq p4, Vdbe.P4T p4t) // CollSeq { int addr = AddOp3(op, p1, p2, p3); ChangeP4(addr, new P4_t { Coll = p4 }, p4t); return addr; }
public int AddOp4(OP op, int p1, int p2, int p3, FuncDef p4, Vdbe.P4T p4t) // FUNCDEF { int addr = AddOp3(op, p1, p2, p3); ChangeP4(addr, new P4_t { Func = p4 }, p4t); return addr; }
public int AddOp4(OP op, int p1, int p2, int p3, double p4, Vdbe.P4T p4t) // DOUBLE (REAL) { int addr = AddOp3(op, p1, p2, p3); ChangeP4(addr, new P4_t { Real = p4 }, p4t); return addr; }
public int AddOp4(OP op, int p1, int p2, int p3, long p4, Vdbe.P4T p4t) // P4T_INT64 { int addr = AddOp3(op, p1, p2, p3); ChangeP4(addr, new P4_t { I64 = p4 }, p4t); return addr; }
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 //: _scratchalloc(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._scratchfree(ctx, ref subParse); return(prg); }
static void VdbeInvokeSqllog(Vdbe p) { }
public static void ExplainBegin(Vdbe vdbe) { if (vdbe != null) { C._benignalloc_begin(); Explain p = new Explain(); if (p) { p.Vdbe = vdbe; vdbe.Explain = p; Text.StringBuilder.Init(p.Str, p.ZBase, sizeof(p.ZBase), MAX_LENGTH); p.Str.UseMalloc = 2; } else C._benignalloc_end(); } }
public int AddOp4(OP op, int p1, int p2, int p3, VTable p4, Vdbe.P4T p4t) // VTable { Debug.Assert(p4 != null); int addr = AddOp3(op, p1, p2, p3); ChangeP4(p, addr, new P4_t { VTable = p4 }, p4t); return addr; }
__device__ void sqlite3ExplainNL(Vdbe *vdbe) { Explain *p; if (vdbe && (p = vdbe->Explain) != nullptr && !endsWithNL(p)) p->Str.Append("\n", 1); }
public static void Delete(Vdbe p) { if (C._NEVER(p == null)) return; Context ctx = p.Ctx; p.ClearObject(ctx); if (p.Prev != null) p.Prev.Next = p.Next; else { Debug.Assert(ctx.Vdbes == p); ctx.Vdbes = p.Next; } if (p.Next != null) p.Next.Prev = p.Prev; p.Magic = VDBE_MAGIC_DEAD; p.Ctx = null; C._tagfree(ctx, ref p); }
__device__ void sqlite3ExplainPop(Vdbe *p) { if (p && p->Explain) p->Explain->Indents.Length--; }
static void REGISTER_TRACE(Vdbe p, int R, Mem M) { }
static void REGISTER_TRACE(Vdbe p, int R, Mem M) { if (p.Trace != null) RegisterTrace(p.Trace, R, M); }
public int AddOp4(OP op, int p1, int p2, int p3, byte[] p4, Vdbe.P4T p4t) // byte[] { Debug.Assert(op == OP.Null || p4 != null); int addr = AddOp3(op, p1, p2, p3); ChangeP4(p, addr, new P4_t { Z = Encoding.UTF8.GetString(p4, 0, p4.Length) }, p4t); return addr; }
static void ImportVtabErrMsg(Vdbe p, IVTable vtab) { Context db = p.Ctx; C._tagfree(db, ref p.ErrMsg); p.ErrMsg = vtab.ErrMsg; C._free(ref vtab.ErrMsg); vtab.ErrMsg = null; }
static void ResolveP2Values(Vdbe p, ref int maxFuncArgs) { int maxArgs = maxFuncArgs; int[] labels = p.Labels.data; p.ReadOnly = true; Vdbe.VdbeOp op; int i; for (i = 0; i < p.Ops.length; i++) { op = p.Ops[i]; OP opcode = op.Opcode; op.Opflags = E._opcodeProperty[(int)opcode]; if (opcode == OP.Function || opcode == OP.AggStep) { if (op.P5 > maxArgs) maxArgs = op.P5; } else if ((opcode == OP.Transaction && op.P2 != 0) || opcode == OP.Vacuum) { p.ReadOnly = false; } #if !OMIT_VIRTUALTABLE else if (opcode == OP.VUpdate) { if (op.P2 > maxArgs) maxArgs = op.P2; } else if (opcode == OP.VFilter) { Debug.Assert(p.Ops.length - i >= 3); Debug.Assert(p.Ops[i - 1].Opcode == OP.Integer); int n = p.Ops[i - 1].P1; if (n > maxArgs) maxArgs = n; } #endif else if (opcode == OP.Next || opcode == OP.SorterNext) { op.P4.Advance = Btree.Next_; op.P4Type = Vdbe.P4T.ADVANCE; } else if (opcode == OP.Prev) { op.P4.Advance = Btree.Previous; op.P4Type = Vdbe.P4T.ADVANCE; } if ((op.Opflags & OPFLG.JUMP) != 0 && op.P2 < 0) { Debug.Assert(-1 - op.P2 < p.Labels.length); op.P2 = labels[-1 - op.P2]; } } C._tagfree(p.Ctx, ref p.Labels.data); p.Labels.data = null; maxFuncArgs = maxArgs; }
static void MemAboutToChange(Vdbe p, Mem mem) { Mem x; int i; for (i = 1; i <= p.Mems.length; i++) { x = p.Mems[i]; if (x.ScopyFrom == mem) { x.Flags |= MEM.Invalid; x.ScopyFrom = null; } } mem.ScopyFrom = null; }
public static string Sql(Vdbe stmt) { Vdbe p = (Vdbe)stmt; return (p != null && p.IsPrepareV2 ? p.Sql_ : null); }
static void GenerateSortTail(Parse parse, Select p, Vdbe v, int columns, SelectDest dest) { int addrBreak = v.MakeLabel(); // Jump here to exit loop int addrContinue = v.MakeLabel(); // Jump here for next cycle ExprList orderBy = p.OrderBy; SRT dest2 = dest.Dest; int parmId = dest.SDParmId; int tabId = orderBy.ECursor; int regRow = Expr.GetTempReg(parse); int pseudoTab = 0; int regRowid; if (dest2 == SRT.Output || dest2 == SRT.Coroutine) { pseudoTab = parse.Tabs++; v.AddOp3(OP.OpenPseudo, pseudoTab, regRow, columns); regRowid = 0; } else regRowid = Expr.GetTempReg(parse); int addr; if ((p.SelFlags & SF.UseSorter) != 0) { int regSortOut = ++parse.Mems; int ptab2 = parse.Tabs++; v.AddOp3(OP.OpenPseudo, ptab2, regSortOut, orderBy.Exprs + 2); addr = 1 + v.AddOp2(OP.SorterSort, tabId, addrBreak); CodeOffset(v, p, addrContinue); v.AddOp2(OP.SorterData, tabId, regSortOut); v.AddOp3(OP.Column, ptab2, orderBy.Exprs + 1, regRow); v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE); } else { addr = 1 + v.AddOp2(OP.Sort, tabId, addrBreak); CodeOffset(v, p, addrContinue); v.AddOp3(OP.Column, tabId, orderBy.Exprs + 1, regRow); } switch (dest2) { case SRT.Table: case SRT.EphemTab: { C.ASSERTCOVERAGE(dest2 == SRT.Table); C.ASSERTCOVERAGE(dest2 == SRT.EphemTab); v.AddOp2(OP.NewRowid, parmId, regRowid); v.AddOp3(OP.Insert, parmId, regRow, regRowid); v.ChangeP5(Vdbe.OPFLAG.APPEND); break; } #if !OMIT_SUBQUERY case SRT.Set: { Debug.Assert(columns == 1); v.AddOp4(OP.MakeRecord, regRow, 1, regRowid, dest->AffSdst, 1); Expr.CacheAffinityChange(parse, regRow, 1); v.AddOp2(OP.IdxInsert, parmId, regRowid); break; } case SRT.Mem: { Debug.Assert(columns == 1); Expr.CodeMove(parse, regRow, parmId, 1); // The LIMIT clause will terminate the loop for us break; } #endif default: { Debug.Assert(dest2 == SRT.Output || dest2 == SRT.Coroutine); C.ASSERTCOVERAGE(dest2 == SRT.Output); C.ASSERTCOVERAGE(dest2 == SRT.Coroutine); for (int i = 0; i < columns; i++) { Debug.Assert(regRow != dest.SdstId + i); v.AddOp3(OP.Column, pseudoTab, i, dest.SdstId + i); if (i == 0) v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE); } if (dest2 == SRT.Output) { v.AddOp2(OP.ResultRow, dest.SdstId, columns); Expr.CacheAffinityChange(parse, dest.SdstId, columns); } else v.AddOp1(OP.Yield, dest.SDParmId); break; } } Expr.ReleaseTempReg(parse, regRow); Expr.ReleaseTempReg(parse, regRowid); // The bottom of the loop v.ResolveLabel(addrContinue); v.AddOp2(OP.Next, tabId, addr); v.ResolveLabel(addrBreak); if (dest2 == SRT.Output || dest2 == SRT.Coroutine) v.AddOp2(OP.Close, pseudoTab, 0); }
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); }