I need to ensure that tables are not dropped from my database. Should I..
Create DDL(or DML ?) trigger that contains COMMIT or create DDL (or DML ?) trigger that contains ROLLBACK ?
Assuming SQL Server there is an example of doing this in BOL
CREATE TRIGGER safety
ON DATABASE
FOR DROP_TABLE, ALTER_TABLE
AS
PRINT 'You must disable Trigger "safety" to drop or alter tables!'
ROLLBACK
;
You would be better off removing permissions from anyone that might DROP the tables inappropriately however. DDL triggers are after triggers, not instead of triggers so a drop table statement might still cause problems even if eventually rolled back.
You can use a DDL trigger to ROLLBACK. DDL is itself a transaction, the trigger is pasrt of the transaction, so you can roll it back.
A better way would be to remove permissions so folk can't delete objects in the first place. With rights to drop objects comes the right to drop triggers too (usually)
Related
I have a DDL trigger that logs database schema changes to a table for auditing purposes. I noticed that some changes I made were missed (like creating a type - CREATE_TYPE) and need to update it.
My understanding is that DDL events are always triggered by a human. Is that true? Is there any chance of a trigger like this causing queries to fail?
This trigger is defined like this:
ALTER TRIGGER [name_of_trigger]
ON DATABASE
FOR CREATE_TABLE, ALTER_TABLE, DROP_TABLE, CREATE_INDEX, ALTER_INDEX, DROP_INDEX, ...
Are there any risks to just using the catch-all DDL_DATABASE_LEVEL_EVENTS like this?
ALTER TRIGGER [name_of_trigger]
ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
or is it safer or better practice to specify all the types I know I need?
I am using such a trigger (for DDL_DATABASE_LEVEL_EVENTS) and I am specifically excepting the event type UPDATE_STATISTICS. You may want to also avoid ALTER INDEX ... REBUILD and ALTER INDEX ... REORGANIZE.
CREATE TRIGGER DEMO_DBLEVELTRIGGER
ON DATABASE
AFTER CREATE_TABLE
AS
BEGIN
PRINT 'CREATION OF NEW TABLES NOT ALLOWED'
ROLLBACK TRANSACTION
END
GO
if it is a database level trigger and you want to disable specifically one trigger then use
DISABLE TRIGGER triggername ON DATABASE;
GO
if it is a database level trigger and you want to disable all triggers on one table, then use
DISABLE TRIGGER ALL ON schemaname.tablename;
GO
if it is a database level trigger and you want to disable all the triggers in that particular database, then use
DISABLE TRIGGER ALL ON DATABASE;
GO
If trigger has server scope then use below
DISABLE TRIGGER triggername ON ALL SERVER
If you want to disable all triggers which have server scope,then use
DISABLE TRIGGER ALL ON ALL SERVER
you have to use ALL with caution ..Docs state..
SQL Server creates triggers in databases that are published for merge replication. Specifying ALL in published databases disables these triggers, which disrupts replication. Verify that the current database is not published for merge replication before specifying ALL.
NOTE:
Changing the trigger by using the ALTER TRIGGER statement enables the trigger
References:
DISABLE TRIGGER
Since it's a Database level trigger, you have to specify that you're dropping the trigger on the database.
so instead of...
drop trigger DEMO_DBLEVELTRIGGER
do
drop trigger DEMO_DBLEVELTRIGGER on database
of course from the context of whatever database you created it on.
Sometimes I try test scenarios between several schemas , deleting/modifying tables , inserting/updating/deleting queries , some schemas are testing and the others are Important for production. so sometimes by accident I run queries in wrong schemas. so the commit functionality does really help in this scenario.
however Truncate table tab1 doesnt need commit, and if I execute it in a wrong schema .. well you know the scneario.
My question: Is there a workarround like the commit for truncate table like the DML Statment ? If you delete a statment you have to include a commit, or in plsql you have to click the green button to commit.
I use such check , its really annoying every time I want to truncate I have to modify the condition.
select count(1) into cnt from tab1 if cnt =0 then execute'Truncate table tab1'; end if;
I am not searching for flashback. I need a checking on truncate table
As #Boneist said, truncate is DDL statement which implicitly commits. If you are not sure of the action you do in a schema, and want to commit only after a manual verification, then do not TRUNCATE, use DELETE instead.
With DELETE statement, you could control the commit. Having said that, TRUNCATE resets the high watermark back to zero, however, DELETE doesn't. Even if you delete all the rows from the table, Oracle would scan all the blocks under the HWM. Have a look at this AskTom link.
If you are looking to bring back the truncated data, and if you are on 11gR2 and up, you could use the Flashback support for DDL statements.
TRUNCATE is a DDL statement, not DML, and DDL statements automatically include commits. See https://asktom.oracle.com/pls/asktom/f?p=100:11:0%3A%3A%3A%3AP11_QUESTION_ID:7072180788422 for more info.
I'm not entirely sure I understand what it is you're trying to do - you could, as Tom suggests, perhaps use an autonomous transaction to keep the truncate separate? If you're after the ability to separate the commit part from the truncate part (ie. to rollback the truncate if you decide you called it in error), then I'm afraid you're out of luck.
How to Fire a trigger when you do TRUNCATE (instead deleted) in MSSQL
From msdn:
TRUNCATE TABLE cannot activate a trigger because the operation does not log individual row deletions.
You can't do this on SQL server.
From MSDN
TRUNCATE TABLE cannot activate a
trigger because the operation does not
log individual row deletions. For more
information, see CREATE TRIGGER
(Transact-SQL).
Are you letting users run TRUNCATE TABLE ad hoc / willy nilly? If not, instead of worrying about using a trigger, why not wrap the TRUNCATE command in a stored procedure that also deals with whatever the trigger would have done after the truncate finished? (But you'd have to do it in the opposite order, of course.)
I need to do this from an ASP.NET web app:
Alter Table Contacts Disable Trigger All
-- Do some stuff
Alter Table Contacts Enable Trigger All
In some situations the Disable Trigger statement hangs. Where should I start looking to figure out what's causing this? If I restart SQL server it goes back to behaving normally.
Look into the Activity Monitor from SSMS to see why it blocks. Or you can look into blocking_session_id column is sys.dm_exec_requests.
My guess: schema changes require a schema modification lock on the table. Any operation (like SELECT, UPDATE etc) will place a schema stability lock on the table, blocking any ALTER until the SELECT completes. So the Disable Trigger ALTER is blcoked by all the pending table access (SELECT) statement.