Beispiel #1
0
        public static void DropTriggerPtr(Parse parse, Trigger trigger)
        {
            Context ctx = parse.Ctx;
            int     db  = Prepare.SchemaToIndex(ctx, trigger.Schema);

            Debug.Assert(db >= 0 && db < ctx.DBs.length);
            Table table = TableOfTrigger(trigger);

            Debug.Assert(table != null);
            Debug.Assert(table.Schema == trigger.Schema || db == 1);
#if !OMIT_AUTHORIZATION
            {
                AUTH   code      = AUTH.DROP_TRIGGER;
                string dbName    = ctx.DBs[db].Name;
                string tableName = E.SCHEMA_TABLE(db);
                if (db == 1)
                {
                    code = AUTH.DROP_TEMP_TRIGGER;
                }
                if (Auth.Check(parse, code, trigger.Name, table.Name, dbName) || Auth.Check(parse, AUTH.DELETE, tableName, null, dbName))
                {
                    return;
                }
            }
#endif

            // Generate code to destroy the database record of the trigger.
            Debug.Assert(table != null);
            Vdbe v = parse.GetVdbe();
            if (v != null)
            {
                parse.BeginWriteOperation(0, db);
                parse.OpenMasterTable(db);
                int base_ = v.AddOpList(_dropTrigger.Length, _dropTrigger);
                v.ChangeP4(base_ + 1, trigger.Name, Vdbe.P4T.TRANSIENT);
                v.ChangeP4(base_ + 4, "trigger", Vdbe.P4T.STATIC);
                parse.ChangeCookie(db);
                v.AddOp2(Core.OP.Close, 0, 0);
                v.AddOp4(Core.OP.DropTrigger, db, 0, 0, trigger.Name, 0);
                if (parse.Mems < 3)
                {
                    parse.Mems = 3;
                }
            }
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }
Beispiel #4
0
        public static void DropTriggerPtr(Parse parse, Trigger trigger)
        {
            Context ctx = parse.Ctx;
            int db = Prepare.SchemaToIndex(ctx, trigger.Schema);
            Debug.Assert(db >= 0 && db < ctx.DBs.length);
            Table table = TableOfTrigger(trigger);
            Debug.Assert(table != null);
            Debug.Assert(table.Schema == trigger.Schema || db == 1);
#if !OMIT_AUTHORIZATION
            {
                AUTH code = AUTH.DROP_TRIGGER;
                string dbName = ctx.DBs[db].Name;
                string tableName = E.SCHEMA_TABLE(db);
                if (db == 1) code = AUTH.DROP_TEMP_TRIGGER;
                if (Auth.Check(parse, code, trigger.Name, table.Name, dbName) || Auth.Check(parse, AUTH.DELETE, tableName, null, dbName))
                    return;
            }
#endif

            // Generate code to destroy the database record of the trigger.
            Debug.Assert(table != null);
            Vdbe v = parse.GetVdbe();
            if (v != null)
            {
                parse.BeginWriteOperation(0, db);
                parse.OpenMasterTable(db);
                int base_ = v.AddOpList(_dropTrigger.Length, _dropTrigger);
                v.ChangeP4(base_ + 1, trigger.Name, Vdbe.P4T.TRANSIENT);
                v.ChangeP4(base_ + 4, "trigger", Vdbe.P4T.STATIC);
                parse.ChangeCookie(db);
                v.AddOp2(Core.OP.Close, 0, 0);
                v.AddOp4(Core.OP.DropTrigger, db, 0, 0, trigger.Name, 0);
                if (parse.Mems < 3)
                    parse.Mems = 3;
            }
        }
Beispiel #5
0
        public static void FinishParse(Parse parse, Token end)
        {
            Table   table = parse.NewTable; // The table being constructed
            Context ctx   = parse.Ctx;      // The database connection

            if (table == null)
            {
                return;
            }
            AddArgumentToVtab(parse);
            parse.Arg.data = null;
            if (table.ModuleArgs.length < 1)
            {
                return;
            }

            // If the CREATE VIRTUAL TABLE statement is being entered for the first time (in other words if the virtual table is actually being
            // created now instead of just being read out of sqlite_master) then do additional initialization work and store the statement text
            // in the sqlite_master table.
            if (!ctx.Init.Busy)
            {
                // Compute the complete text of the CREATE VIRTUAL TABLE statement
                if (end != null)
                {
                    parse.NameToken.length = (uint)parse.NameToken.data.Length;               //: (int)(end->data - parse->NameToken) + end->length;
                }
                string stmt = C._mtagprintf(ctx, "CREATE VIRTUAL TABLE %T", parse.NameToken); //.Z.Substring(0, parse.NameToken.length));

                // A slot for the record has already been allocated in the SQLITE_MASTER table.  We just need to update that slot with all
                // the information we've collected.
                //
                // The VM register number pParse->regRowid holds the rowid of an entry in the sqlite_master table tht was created for this vtab
                // by sqlite3StartTable().
                int db = Prepare.SchemaToIndex(ctx, table.Schema);
                parse.NestedParse("UPDATE %Q.%s SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q WHERE rowid=#%d",
                                  ctx.DBs[db].Name, E.SCHEMA_TABLE(db),
                                  table.Name, table.Name,
                                  stmt,
                                  parse.RegRowid
                                  );
                C._tagfree(ctx, ref stmt);
                Vdbe v = parse.GetVdbe();
                parse.ChangeCookie(db);

                v.AddOp2(OP.Expire, 0, 0);
                string where_ = C._mtagprintf(ctx, "name='%q' AND type='table'", table.Name);
                v.AddParseSchemaOp(db, where_);
                v.AddOp4(OP.VCreate, db, 0, 0, table.Name, (Vdbe.P4T)table.Name.Length + 1);
            }

            // If we are rereading the sqlite_master table create the in-memory record of the table. The xConnect() method is not called until
            // the first time the virtual table is used in an SQL statement. This allows a schema that contains virtual tables to be loaded before
            // the required virtual table implementations are registered.
            else
            {
                Schema schema     = table.Schema;
                string name       = table.Name;
                int    nameLength = name.Length;
                Debug.Assert(Btree.SchemaMutexHeld(ctx, 0, schema));
                Table oldTable = schema.TableHash.Insert(name, nameLength, table);
                if (oldTable != null)
                {
                    ctx.MallocFailed = true;
                    Debug.Assert(table == oldTable); // Malloc must have failed inside HashInsert()
                    return;
                }
                parse.NewTable = null;
            }
        }