Ejemplo n.º 1
0
        public static int GenerateIndexKey(Parse parse, Index index, int curId, int regOut, bool doMakeRec)
        {
            Vdbe v = parse.V;
            Table table = index.Table;

            int cols = index.Columns.length;
            int regBase = Expr.GetTempRange(parse, cols + 1);
            v.AddOp2(OP.Rowid, curId, regBase + cols);
            for (int j = 0; j < cols; j++)
            {
                int idx = index.Columns[j];
                if (idx == table.PKey)
                    v.AddOp2(OP.SCopy, regBase + cols, regBase + j);
                else
                {
                    v.AddOp3(OP.Column, curId, idx, regBase + j);
                    v.ColumnDefault(table, idx, -1);
                }
            }
            if (doMakeRec)
            {
                string affName = (table.Select != null || E.CtxOptimizationDisabled(parse.Ctx, SQLITE.IdxRealAsInt) ? null : sqlite3IndexAffinityStr(v, index));
                v.AddOp3(OP.MakeRecord, regBase, cols + 1, regOut);
                v.ChangeP4(-1, affName, Vdbe.P4T.TRANSIENT);
            }
            Expr.ReleaseTempRange(parse, regBase, cols + 1);
            return regBase;
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        static void OpenStatTable(Parse parse, int db, int statCur, string where_, string whereType)
        {
            int[]  roots      = new int[] { 0, 0 };
            byte[] createTbls = new byte[] { 0, 0 };

            Context ctx = parse.Ctx;
            Vdbe    v   = parse.GetVdbe();

            if (v == null)
            {
                return;
            }
            Debug.Assert(Btree.HoldsAllMutexes(ctx));
            Debug.Assert(v.Ctx == ctx);
            Context.DB dbObj = ctx.DBs[db];

            for (int i = 0; i < _tables.Length; i++)
            {
                string tableName = _tables[i].Name;
                Table  stat;
                if ((stat = Parse.FindTable(ctx, tableName, dbObj.Name)) == null)
                {
                    // The sqlite_stat[12] table does not exist. Create it. Note that a side-effect of the CREATE TABLE statement is to leave the rootpage
                    // of the new table in register pParse.regRoot. This is important because the OpenWrite opcode below will be needing it.
                    parse.NestedParse("CREATE TABLE %Q.%s(%s)", dbObj.Name, tableName, _tables[i].Cols);
                    roots[i]      = parse.RegRoot;
                    createTbls[i] = Vdbe::OPFLAG_P2ISREG;
                }
                else
                {
                    // The table already exists. If zWhere is not NULL, delete all entries associated with the table zWhere. If zWhere is NULL, delete the
                    // entire contents of the table.
                    roots[i] = stat.Id;
                    sqlite3TableLock(parse, db, roots[i], 1, tableName);
                    if (where_ == null)
                    {
                        parse.NestedParse("DELETE FROM %Q.%s WHERE %s=%Q", dbObj.Name, tableName, whereType, where_);
                    }
                    else
                    {
                        v.AddOp2(OP.Clear, roots[i], db); // The sqlite_stat[12] table already exists.  Delete all rows.
                    }
                }
            }

            // Open the sqlite_stat[12] tables for writing.
            for (int i = 0; i < _tables.Length; i++)
            {
                v.AddOp3(OP.OpenWrite, statCur + i, roots[i], db);
                v.ChangeP4(-1, 3, Vdbe.P4T.INT32);
                v.ChangeP5(createTbls[i]);
            }
        }
Ejemplo n.º 4
0
        static void CodeAttach(Parse parse, AUTH type, FuncDef func, Expr authArg, Expr filename, Expr dbName, Expr key)
        {
            Context ctx = parse.Ctx;

            NameContext sName;

            sName       = new NameContext();
            sName.Parse = parse;

            if (ResolveAttachExpr(sName, filename) != RC.OK || ResolveAttachExpr(sName, dbName) != RC.OK || ResolveAttachExpr(sName, key) != RC.OK)
            {
                parse.Errs++;
                goto attach_end;
            }

#if !OMIT_AUTHORIZATION
            if (authArg != null)
            {
                string authArgToken = (authArg.OP == TK.STRING ? authArg.u.Token : null);
                ARC    arc          = Auth.Check(parse, type, authArgToken, null, null);
                if (arc != ARC.OK)
                {
                    goto attach_end;
                }
            }
#endif
            Vdbe v       = parse.GetVdbe();
            int  regArgs = Expr.GetTempRange(parse, 4);
            Expr.Code(parse, filename, regArgs);
            Expr.Code(parse, dbName, regArgs + 1);
            Expr.Code(parse, key, regArgs + 2);

            Debug.Assert(v != null || ctx.MallocFailed);
            if (v != null)
            {
                v.AddOp3(OP.Function, 0, regArgs + 3 - func.Args, regArgs + 3);
                Debug.Assert(func.Args == -1 || (func.Args & 0xff) == func.Args);
                v.ChangeP5((byte)(func.Args));
                v.ChangeP4(-1, func, Vdbe.P4T.FUNCDEF);

                // Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this statement only). For DETACH, set it to false (expire all existing statements).
                v.AddOp1(OP.Expire, (type == AUTH.ATTACH ? 1 : 0));
            }

attach_end:
            Expr.Delete(ctx, ref filename);
            Expr.Delete(ctx, ref dbName);
            Expr.Delete(ctx, ref key);
        }
Ejemplo n.º 5
0
        public static void sqlite3ColumnDefault(Vdbe v, Table table, int i, int regId)
        {
            Debug.Assert(table != null);
            if (table.Select == null)
            {
                TEXTENCODE encode = Context.CTXENCODE(v.Ctx);
                Column     col    = table.Cols[i];
                v.VdbeComment("%s.%s", table.Name, col.Name);
                Debug.Assert(i < table.Cols.length);
                Mem value = new Mem();
                sqlite3ValueFromExpr(v.Ctx, col.Dflt, encode, col.Affinity, ref value);
                if (value != null)
                {
                    v.ChangeP4(-1, value, Vdbe.P4T.MEM);
                }
#if !OMIT_FLOATING_POINT
                if (regId >= 0 && table.Cols[i].Affinity == AFF.REAL)
                {
                    v.AddOp1(OP.RealAffinity, regId);
                }
#endif
            }
        }