2016-12-09 74 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中看到快照數據庫,那麼觸發器將作爲無權訪問的用戶執行。 –