Пример #1
0
 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);
 }
Пример #2
0
        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;
        }
Пример #3
0
 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;
 }
Пример #4
0
 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;
 }
Пример #5
0
        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;
        }
Пример #6
0
        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);
        }
Пример #7
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);
     }
 }
Пример #8
0
 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;
 }
Пример #9
0
	__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();
		}
	}
Пример #10
0
	__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++;
		}
	}
Пример #11
0
	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);
		}
	}
Пример #12
0
        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);
        }
Пример #13
0
 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);
         }
     }
 }
Пример #14
0
 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;
 }
Пример #15
0
 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;
 }
Пример #16
0
 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;
 }
Пример #17
0
 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;
 }
Пример #18
0
 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;
 }
Пример #19
0
        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);
        }
Пример #20
0
 static void VdbeInvokeSqllog(Vdbe p) { }
Пример #21
0
	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();
		}
	}
Пример #22
0
 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;
 }
Пример #23
0
	__device__ void sqlite3ExplainNL(Vdbe *vdbe)
	{
		Explain *p;
		if (vdbe && (p = vdbe->Explain) != nullptr && !endsWithNL(p))
			p->Str.Append("\n", 1);
	}
Пример #24
0
 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);
 }
Пример #25
0
	__device__ void sqlite3ExplainPop(Vdbe *p)
	{
		if (p && p->Explain) p->Explain->Indents.Length--;
	}
Пример #26
0
 static void REGISTER_TRACE(Vdbe p, int R, Mem M) { }
Пример #27
0
 static void REGISTER_TRACE(Vdbe p, int R, Mem M) { if (p.Trace != null) RegisterTrace(p.Trace, R, M); }
Пример #28
0
 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;
 }
Пример #29
0
 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;
 }
Пример #30
0
        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;
        }
Пример #31
0
 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;
 }
Пример #32
0
 public static string Sql(Vdbe stmt)
 {
     Vdbe p = (Vdbe)stmt;
     return (p != null && p.IsPrepareV2 ? p.Sql_ : null);
 }
Пример #33
0
        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);
        }
Пример #34
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);
        }