SQL 防止数据库丢失的服务器触发器
SQL Server Trigger To Prevent Database Drop
我想放置一个服务器级触发器,以防止删除任何不是数据库快照的数据库。乍一看,下面的代码似乎应该可以工作,但从来没有。我试过颠倒逻辑,但没有帮助。有谁知道我做错了什么吗?
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 手动时,它总是 returns适当的数据。不幸的是,无论我做什么,这总是属于真实数据库及其数据库快照的“..已成功删除”部分。
这个条件永远成立..
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 子句移到上面的块
RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG;
ROLLBACK;
我也尝试让它工作,但是 运行 由于 sys.databases 只返回当前用户可见的值,权限障碍太多。 (而且我无法通过 "Executing As" 次尝试获得足够可靠的通用解决方案。)
最终我决定使用数据库名称作为过滤器。示例:
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;
我想放置一个服务器级触发器,以防止删除任何不是数据库快照的数据库。乍一看,下面的代码似乎应该可以工作,但从来没有。我试过颠倒逻辑,但没有帮助。有谁知道我做错了什么吗?
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 手动时,它总是 returns适当的数据。不幸的是,无论我做什么,这总是属于真实数据库及其数据库快照的“..已成功删除”部分。
这个条件永远成立..
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 子句移到上面的块
RAISERROR('[%s] cannot be deleted without first disabling the server trigger "tgr_prevent_db_drop".', 10, 1, @DBname) WITH LOG;
ROLLBACK;
我也尝试让它工作,但是 运行 由于 sys.databases 只返回当前用户可见的值,权限障碍太多。 (而且我无法通过 "Executing As" 次尝试获得足够可靠的通用解决方案。)
最终我决定使用数据库名称作为过滤器。示例:
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;