none
Trigger umgehen RRS feed

  • Frage

  • Hallo,

    Trigger einer Tabelle verhindert, dass Datensätze, die mit einen bestimmten Status gekennzeichnet sind, geändert oder gelöscht werden dürfen. Nun gibt es aber Situation - z.B. bei der Bereinigung der Datenbank um sehr alte Datensätze -, dass diese Trigger vorübergehend abgeschaltet werden müssen. Dies geschieht dann über die entsprechende ALTER TABLE-Anweisung.  Das Problem ist nun, dass hierfür mindestens DDL-Admin-Rechte vorliegen müssen.

    Leider werden die beiden Mitarbeiter, die derlei Aktivitäten bisher ausführen, nach dem 'Outsourcing' der Datenbank in ein externes Rechenzentrum diese Rechte nicht mehr haben, d.h. ALTER TABLE xxx DISABLE/ENABLE TRIGGER ... läuft dann nicht mehr.

    Ich bin daher auf der Suche nach einer einigermaßen simplen Umgehung dieses Problems. Es sollte m.E. mit einer eigenen Anwendungsrolle funktionieren, für die der Trigger Ändern und Löschen an der Tabelle zulässt. Hat jemaden vielleicht noch eine andere, einfachere Idee?

    Das ganze findet unter SQL Server 2005 SP 3 statt. Mehr hat das Rechenzentrum nicht zu bieten.


    Grüße aus Köln am Rhein Klaus Trapp

    Donnerstag, 6. September 2012 07:54

Antworten

  • Hallo Stefan und Georg,

    ich weiß noch nicht genau, wie ich's umsetzen werde. Ich habe noch ewas Zeit. Allerdings scheint mit die Idee von Georg doch recht aufwending.

    danke für die Tipps!


    Grüße aus Köln am Rhein Klaus Trapp

    • Als Antwort markiert Klaus Trapp Mittwoch, 12. September 2012 20:00
    Mittwoch, 12. September 2012 20:00

Alle Antworten

  • Das Abschalten der Trigger ist immer ein Lösung mit schalem Geschmack, da es erfordert, das nur eine Benutzer genau eine bestimmte Aktion ausführt. Die Sache mit der Rolle ist ok und kann mit IS_MEMBER() abgefragt werden.

    Eine einfachere Idee schon, sie sollte aber nur als letzte Mittel genutzt werden: Nutze SET CONTEXT_INFO. Schreibe einen magic value rein und frage diesen Wert im Trigger ab und überspringe dessen Aktionen.

    Donnerstag, 6. September 2012 08:19
  • Hallo Klaus

    Eine Lösung ist noch, Triggers gezielt über eine temporäre Tabelle auszuschalten. Die Lösung hat aber auch einen gewissen Aufwand, weil alle (betroffenen) Trigger angepasst werden müssen.

    Vorteil ist, dass Trigger einzeln oder gesamthaft ausgeschaltet werden können und dass die Prüfung nur für die aktuelle Connection gilt. Für andere Benutzer/Connections bleiben die Trigger aktiv.

    Unten ist ein Beispiel mit einer Stored Procedure, die prüft, ob die Trigger-Logik ausgeschaltet werden soll sowie ein Beispiel-Trigger, der die SP benutzt.
    Bei den Test-Inserts wird ein Error ausgegeben, wenn der Trigger aktiv ist.

    USE [tempdb]
    GO
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[prcDisableTrigger]') AND type in (N'P', N'PC'))
    DROP PROCEDURE [dbo].[prcDisableTrigger]
    GO
    CREATE PROCEDURE [dbo].[prcDisableTrigger]
    (
    	@triggerName SYSNAME, 
    	@disableTrigger BIT OUTPUT
    )
    AS
    BEGIN
    	SET NOCOUNT ON;
    
    	-- Default
    	SET @disableTrigger = 0;
    
    
    	IF OBJECT_ID(N'tempdb..#tempDisableTrigger') IS NULL
    	BEGIN
    		SET @disableTrigger = 0;
    		RETURN;
    	END
    
    	IF EXISTS 
    	(
    		SELECT * 
    		FROM #tempDisableTrigger AS t
    		WHERE t.trigger_name IN (@triggerName, N'ALL')
    	)
    	BEGIN
    		SET @disableTrigger = 1;
    		RETURN;
    	END
    END
    GO
    
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TestForTrigger]') AND type in (N'U'))
    DROP TABLE [dbo].[TestForTrigger];
    GO
    CREATE TABLE dbo.TestForTrigger (id INTEGER NOT NULL);
    GO
    
    
    IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[trgTestTriggerDisable]'))
    DROP TRIGGER [dbo].[trgTestTriggerDisable]
    GO
    CREATE TRIGGER trgTestTriggerDisable ON dbo.TestForTrigger
    FOR INSERT
    AS
    BEGIN
    	-- Return if no rows were affected
    	IF @@ROWCOUNT = 0 RETURN;
    
    	SET NOCOUNT ON;
    
    	-- Check for manually disabled trigger
    	DECLARE
    		@disable BIT,
    		@trigger SYSNAME;
    	SET @trigger = OBJECT_NAME(@@PROCID);
    
    	EXECUTE [dbo].[prcDisableTrigger] 
    		@triggerName = @trigger,
    		@disableTrigger = @disable OUTPUT;
    
    	IF @disable = 1 RETURN;
    
    
    	-- Restliche Trigger-Logik
    	RAISERROR ('Trigger active', 16, 1);
    END
    GO
    
    
    PRINT N'Trigger ist aktiv';
    SET NOCOUNT ON;
    IF OBJECT_ID(N'tempdb..#tempDisableTrigger') IS NOT NULL
    BEGIN
    	DROP TABLE #tempDisableTrigger;
    END
    INSERT INTO dbo.TestForTrigger (id) VALUES (1);
    GO
    
    
    PRINT N'Alle Trigger deaktivieren';
    SET NOCOUNT ON;
    IF OBJECT_ID(N'tempdb..#tempDisableTrigger') IS NOT NULL
    BEGIN
    	DROP TABLE #tempDisableTrigger;
    END
    CREATE TABLE #tempDisableTrigger (trigger_name SYSNAME NOT NULL);
    INSERT INTO #tempDisableTrigger VALUES (N'ALL');
    
    INSERT INTO dbo.TestForTrigger (id) VALUES (1);
    GO
    
    PRINT N'Trigger aktivieren';
    SET NOCOUNT ON;
    IF OBJECT_ID(N'tempdb..#tempDisableTrigger') IS NOT NULL
    BEGIN
    	DROP TABLE #tempDisableTrigger;
    END
    
    INSERT INTO dbo.TestForTrigger (id) VALUES (1);
    GO
    
    PRINT N'Spezifischen Trigger deaktivieren';
    SET NOCOUNT ON;
    IF OBJECT_ID(N'tempdb..#tempDisableTrigger') IS NOT NULL
    BEGIN
    	DROP TABLE #tempDisableTrigger;
    END
    CREATE TABLE #tempDisableTrigger (trigger_name SYSNAME NOT NULL);
    INSERT INTO #tempDisableTrigger VALUES (N'trgTestTriggerDisable');
    
    INSERT INTO dbo.TestForTrigger (id) VALUES (1);
    GO


    Gruss Georg


    Donnerstag, 6. September 2012 14:38
  • Zwar sind Semaphoren eine generelle Lösung, aber hier sicher nicht schön. Zumindest schlechter als CONTEXT_INFO.

    Just my 2 cents..

    Donnerstag, 6. September 2012 15:00
  • Hallo Stefan und Georg,

    ich weiß noch nicht genau, wie ich's umsetzen werde. Ich habe noch ewas Zeit. Allerdings scheint mit die Idee von Georg doch recht aufwending.

    danke für die Tipps!


    Grüße aus Köln am Rhein Klaus Trapp

    • Als Antwort markiert Klaus Trapp Mittwoch, 12. September 2012 20:00
    Mittwoch, 12. September 2012 20:00