2016-12-09 46 views
2

我想提出一个服务器级触发器,以防止这不是一个数据库快照任何数据库的下落。乍一看,下面看起来好像它应该工作,但它从来没有。我尝试了扭转逻辑,并没有帮助。有谁知道我做错了什么?SQL Server触发器,以防止数据库中删除

DECLARE @DBName NVARCHAR(100), 
     @eventData XML; 

SET @eventData = EVENTDATA();   
SELECT @DBName = @eventData.value('data(/EVENT_INSTANCE/DatabaseName)[1]', 'SYSNAME'); 

RAISERROR('Attempting delete of %s.', 10, 1, @DBName); 

IF @DBName IN (SELECT name 
       FROM sys.databases 
       WHERE source_database_id IS NOT NULL) 
    BEGIN 
     RAISERROR('[%s] was successfully dropped.', 10, 1, @DBname) WITH LOG; 
    END; 
ELSE   
    BEGIN 
     RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG; 
     ROLLBACK; 
    END; 

顶部的RAISERROR总是确认正确的数据库(例如,一个被删除),当我从sys.databases中运行SELECT手动它总是返回相应的数据。不幸的是,无论我做什么,它总是落入“真正的数据库及其数据库快照”的“..was successfully dropped”部分。

回答

1

我试图得到这个也可以工作,但由于sys.databases只返回当前用户可见的值,所以会遇到太多的权限限制。 (我不能得到与“执行作为”尝试一个足够可靠的通用的解决方案。)

最终我决定使用数据库的名称作为过滤器。例如:

DECLARE @DBName NVARCHAR(100), 
     @eventData XML; 

SET @eventData = EVENTDATA();   
SELECT @DBName = @eventData.value('data(/EVENT_INSTANCE/DatabaseName)[1]', 'SYSNAME'); 

RAISERROR('Attempting delete of %s.', 10, 1, @DBName); 

IF Right(@DBName, 9) <> '_SnapShot' --Checking via db name due to permissions affecting sys.databases 
    BEGIN 
     RAISERROR('[%s] was successfully dropped.', 10, 1, @DBname) WITH LOG; 
    END; 
ELSE   
    BEGIN 
     RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG; 
     ROLLBACK; 
    END; 
0

这个条件总是真..

IF @DBName IN (SELECT name 
       FROM sys.databases 
       WHERE source_database_id IS NOT NULL) 
    BEGIN 
     RAISERROR('[%s] was successfully dropped.', 10, 1, @DBname) WITH LOG; 
    END; 

所以,你的数据库将被丢弃不管what..Instead下面else子句移动到上述块

RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG; 
     ROLLBACK; 
+0

嗨@TheGameIswar,我没跟踪。如果数据库快照,它会在source_database_id列中的值,并出现在SELECT这样的条件应该永远是真的,那么。如果它不是一个快照,source_database_id必须为NULL,所以我期望它评估为false。如果我在DDL触发器之外运行它,它按预期工作。它只在DDL触发器内失败。最终,我想允许快照删除,但防止父数据库删除。 – PseudoToad

+0

@PseudoToad的sys.databases中具有基于用户的权限返回值的问题。如果触发器没有在sys.databases中看到快照数据库,那么触发器将作为无权访问的用户执行。 –