FirebirdSQL logo

DDL-Trigger

DDL-Trigger ermöglichen Einschränkungen für Benutzer, die versuchen, ein DDL-Objekt zu erstellen, zu ändern oder zu löschen.Ihr anderer Zweck besteht darin, ein Metadatenänderungsprotokoll zu führen.

DDL-Trigger lösen bei bestimmten Metadatenänderungsereignissen in einer bestimmten Phase aus.BEFORE-Trigger werden vor Änderungen an Systemtabellen ausgeführt.AFTER-Trigger werden nach Änderungen in Systemtabellen ausgeführt.

Important

Der Ereignistyp [BEFORE | AFTER] eines DDL-Triggers kann nicht geändert werden.

In gewisser Weise sind DDL-Trigger ein Untertyp von Datenbank-Triggern.

Wer kann einen DDL-Trigger erstellen?

DDL-Trigger können erstellt werden durch:

docnext count = 13

Unterdrücken von DDL-Triggern

Ein DDL-Trigger ist eine Art Datenbank-Trigger.Siehe auch [fblangref40-ddl-trgr-dbtrigger-notrgr-de] wie man Datenbank- und DDL-Trigger unterdrückt.

Beispiele für DDL-Trigger

  1. So können Sie einen DDL-Trigger verwenden, um ein konsistentes Benennungsschema zu erzwingen. In diesem Fall sollten die Namen der gespeicherten Prozeduren mit dem Präfix “SP_” beginnen:

    set auto on;
    create exception e_invalid_sp_name 'Invalid SP name (should start with SP_)';
    
    set term !;
    
    create trigger trig_ddl_sp before CREATE PROCEDURE
    as
    begin
      if (rdb$get_context('DDL_TRIGGER', 'OBJECT_NAME') not starting 'SP_') then
        exception e_invalid_sp_name;
    end!

    Test

    create procedure sp_test
    as
    begin
    end!
    
    create procedure test
    as
    begin
    end!
    
    -- Der letzte Befehl löst diese Ausnahme aus und die Prozedur TEST wird nicht erstellt:
    -- Statement failed, SQLSTATE = 42000
    -- exception 1
    -- -E_INVALID_SP_NAME
    -- -Invalid SP name (should start with SP_)
    -- -At trigger 'TRIG_DDL_SP' line: 4, col: 5
    
    set term ;!
  2. Implementieren Sie benutzerdefinierte DDL-Sicherheit, indem Sie in diesem Fall die Ausführung von DDL-Befehlen auf bestimmte Benutzer beschränken:

    create exception e_access_denied 'Access denied';
    
    set term !;
    
    create trigger trig_ddl before any ddl statement
    as
    begin
      if (current_user <> 'SUPER_USER') then
        exception e_access_denied;
    end!

    Test

    create procedure sp_test
    as
    begin
    end!
    
    -- Der letzte Befehl löst diese Ausnahme aus und die Prozedur SP_TEST wird nicht erstellt
    -- Statement failed, SQLSTATE = 42000
    -- exception 1
    -- -E_ACCESS_DENIED
    -- -Access denied
    -- -At trigger 'TRIG_DDL' line: 4, col: 5
    
    set term ;!
    Note

    Firebird hat Berechtigungen zum Ausführen von DDL-Anweisungen, daher sollte das Schreiben eines DDL-Triggers dafür der letzte Ausweg sein, wenn der gleiche Effekt nicht mit Berechtigungen erzielt werden kann.

  3. Verwenden eines Triggers, um DDL-Aktionen und -Versuche zu protokollieren:

    create sequence ddl_seq;
    
    create table ddl_log (
      id bigint not null primary key,
      moment timestamp not null,
      user_name varchar(63) not null,
      event_type varchar(25) not null,
      object_type varchar(25) not null,
      ddl_event varchar(25) not null,
      object_name varchar(63) not null,
      sql_text blob sub_type text not null,
      ok char(1) not null
    );
    
    set term !;
    
    create trigger trig_ddl_log_before before any ddl statement
    as
      declare id type of column ddl_log.id;
    begin
      -- Wir nehmen die Änderungen in einer AUTONOMEN TRANSAKTION vor. Wenn also eine Ausnahme auftritt und
      -- der Befehl nicht ausgeführt wurde, bleibt das Protokoll erhalten.
      in autonomous transaction do
      begin
        insert into ddl_log (id, moment, user_name, event_type, object_type,
                             ddl_event, object_name, sql_text, ok)
          values (next value for ddl_seq, current_timestamp, current_user,
                  rdb$get_context('DDL_TRIGGER', 'EVENT_TYPE'),
                  rdb$get_context('DDL_TRIGGER', 'OBJECT_TYPE'),
                  rdb$get_context('DDL_TRIGGER', 'DDL_EVENT'),
                  rdb$get_context('DDL_TRIGGER', 'OBJECT_NAME'),
                  rdb$get_context('DDL_TRIGGER', 'SQL_TEXT'),
                  'N')
          returning id into id;
        rdb$set_context('USER_SESSION', 'trig_ddl_log_id', id);
      end
    end!

    Der obige Trigger wird für diesen DDL-Befehl ausgelöst.Es ist eine gute Idee, -nodbtriggers zu verwenden, wenn Sie mit ihnen arbeiten!

    create trigger trig_ddl_log_after after any ddl statement
    as
    begin
      -- Hier benötigen wir eine AUTONOME TRANSACTION, da die ursprüngliche Transaktion den Datensatz
      -- nicht sehen wird, der in den BEFORE-Trigger der
      -- autonomen Transaktion eingefügt wurde, wenn die Benutzertransaktion nicht READ COMMITTED ist.
      in autonomous transaction do
         update ddl_log set ok = 'Y'
         where id = rdb$get_context('USER_SESSION', 'trig_ddl_log_id');
    end!
    
    commit!
    
    set term ;!
    
    -- Löschen Sie den Datensatz über trig_ddl_log_after
    delete from ddl_log;
    commit;

    Test

    -- Dies wird einmalig protokolliert
    -- (da T1 nicht existierte, fungiert RECREATE als CREATE) mit OK = Y.
    recreate table t1 (
      n1 integer,
      n2 integer
    );
    
    -- Dies schlägt fehl, da T1 bereits existiert, also ist OK N.
    create table t1 (
      n1 integer,
      n2 integer
    );
    
    -- T2 existiert nicht. Es wird kein Protokoll geben.
    drop table t2;
    
    -- Dies wird zweimal protokolliert
    -- (da T1 existiert, fungiert RECREATE als DROP und CREATE) mit OK = Y.
    recreate table t1 (
      n integer
    );
    
    commit;
    select id, ddl_event, object_name, sql_text, ok
      from ddl_log order by id;
    
     ID DDL_EVENT                 OBJECT_NAME                      SQL_TEXT OK
    === ========================= ======================= ================= ======
      2 CREATE TABLE              T1                                   80:3 Y
    ====================================================
    SQL_TEXT:
    recreate table t1 (
        n1 integer,
        n2 integer
    )
    ====================================================
      3 CREATE TABLE              T1                                   80:2 N
    ====================================================
    SQL_TEXT:
    create table t1 (
        n1 integer,
        n2 integer
    )
    ====================================================
      4 DROP TABLE                T1                                   80:6 Y
    ====================================================
    SQL_TEXT:
    recreate table t1 (
        n integer
    )
    ====================================================
      5 CREATE TABLE              T1                                   80:9 Y
    ====================================================
    SQL_TEXT:
    recreate table t1 (
        n integer
    )
    ====================================================

ALTER TRIGGER

Verwendet für

Ändern und Deaktivieren eines bestehenden Triggers

Verfügbar in

DSQL, ESQL

Syntax
ALTER TRIGGER trigname
  [ACTIVE | INACTIVE]
  [{BEFORE | AFTER} <mutation_list>]
  [POSITION number]
  {<psql_trigger> | <external-module-body>}

<psql_trigger> ::=
  [<sql_security>]
  [<psql-module-body>]

<sql_security> ::=
    SQL SECURITY {INVOKER | DEFINER}
  | DROP SQL SECURITY

!! Vgl. auch die Syntax CREATE TRIGGER für weitere Regeln!!

Die ALTER TRIGGER-Anweisung erlaubt nur bestimmte Änderungen am Header und Body eines Triggers.

Zulässige Änderungen an Triggern

  • Status (ACTIVE | INACTIVE)

  • Phase (BEFORE | AFTER) (bei DML-Triggern)

  • Ereignisse (bei DML-Triggern)

  • Position in der Ausführungsfolge

  • Änderungen am Code im Trigger-Body

Wenn ein Element nicht angegeben wird, bleibt es unverändert.

Note

Ein DML-Trigger kann nicht in einen Datenbank- (oder DDL-)Trigger geändert werden.

Es ist nicht möglich, das/die Ereignis(e) oder die Phase eines Datenbank- (oder DDL-)Triggers zu ändern.

Note
Merken Sie sich

Das Schlüsselwort BEFORE weist an, dass der Trigger ausgeführt wird, bevor das zugehörige Ereignis eintritt;das Schlüsselwort AFTER weist an, dass es nach dem Ereignis ausgeführt wird.

Mehrere DML-Ereignisse – INSERT, UPDATE, DELETE – können in einem einzigen Trigger abgedeckt werden.Die Ereignisse sollten mit dem Schlüsselwort OR getrennt werden.Kein Ereignis sollte mehr als einmal erwähnt werden.

Das Schlüsselwort POSITION ermöglicht die Angabe einer optionalen Ausführungsreihenfolge (“firing order”) für eine Reihe von Triggern, die die gleiche Phase und das gleiche Ereignis wie ihr Ziel haben.Die Standardposition ist 0.Wenn keine Positionen angegeben sind oder mehrere Trigger eine einzige Positionsnummer haben, werden die Trigger in alphabetischer Reihenfolge ihrer Namen ausgeführt.====

Wer kann einen Trigger ändern?

DML-Trigger können geändert werden durch:

  • Administratoren

  • Der Besitzer der Tabelle (oder Ansicht)

  • Benutzer mit dem ALTER ANY TABLE- oder — für eine Ansicht — ALTER ANY VIEW-Privileg

Datenbank- und DDL-Trigger können geändert werden durch:

Beispiele mit ALTER TRIGGER

  1. Den Trigger set_cust_no deaktivieren (in den inaktiven Zustand schalten).

    ALTER TRIGGER set_cust_no INACTIVE;
  2. Ändern der Position der Zündreihenfolge des Triggers set_cust_no.

    ALTER TRIGGER set_cust_no POSITION 14;
  3. Den Trigger TR_CUST_LOG in den inaktiven Zustand schalten und die Ereignisliste ändern.

    ALTER TRIGGER TR_CUST_LOG
    INACTIVE AFTER INSERT OR UPDATE;
  4. Den tr_log_connect Trigger in den aktiven Status schalten, seine Position und seinen Körper ändern.

    ALTER TRIGGER tr_log_connect
    ACTIVE POSITION 1
    AS
    BEGIN
      INSERT INTO LOG_CONNECT (ID,
                               USERNAME,
                               ROLENAME,
                               ATIME)
      VALUES (NEXT VALUE FOR SEQ_LOG_CONNECT,
              CURRENT_USER,
              CURRENT_ROLE,
              CURRENT_TIMESTAMP);
    END

CREATE OR ALTER TRIGGER

Verwendet für

Erstellen eines neuen Triggers oder Ändern eines bestehenden Triggers

Verfügbar in

DSQL

Syntax
CREATE OR ALTER TRIGGER trigname
  { <relation_trigger_legacy>
  | <relation_trigger_sql2003>
  | <database_trigger>
  | <ddl_trigger> }
  {<psql_trigger> | <external-module-body>}

!!Vgl. auch die Syntax CREATE TRIGGER für weitere Regeln !!

Die Anweisung CREATE OR ALTER TRIGGER erstellt einen neuen Trigger, falls dieser nicht existiert;andernfalls ändert und kompiliert es sie mit den intakten Privilegien und unberührten Abhängigkeiten.

Beispiel für CREATE OR ALTER TRIGGER

Neuen Trigger erstellen, wenn er nicht existiert, oder ihn ändern, falls vorhanden
CREATE OR ALTER TRIGGER set_cust_no
ACTIVE BEFORE INSERT ON customer POSITION 0
AS
BEGIN
  IF (NEW.cust_no IS NULL) THEN
    NEW.cust_no = GEN_ID(cust_no_gen, 1);
END

DROP TRIGGER

Verwendet für

Löschen eines vorhandenen Triggers

Verfügbar in

DSQL, ESQL

Syntax
DROP TRIGGER trigname
Table 1. DROP TRIGGER-Anweisgungsparameter
Parameter Beschreibung

trigname

Triggername

Die Anweisung DROP TRIGGER verwirft (löscht) einen vorhandenen Trigger.

Wer kann einen Trigger fallen lassen?

DML-Trigger können gelöscht werden durch:

  • Administratoren

  • Der Besitzer der Tabelle (oder Ansicht)

  • Benutzer mit dem ALTER ANY TABLE- oder — für eine Ansicht — ALTER ANY VIEW-Privileg

Datenbank- und DDL-Trigger können gelöscht werden durch:

Beispiel für DROP TRIGGER

Löschen des Triggers set_cust_no
DROP TRIGGER set_cust_no;

RECREATE TRIGGER

Verwendet für

Erstellen eines neuen Triggers oder Neuerstellen eines vorhandenen Triggers

Verfügbar in

DSQL

Syntax
RECREATE TRIGGER trigname
  { <relation_trigger_legacy>
  | <relation_trigger_sql2003>
  | <database_trigger>
  | <ddl_trigger> }
  {<psql_trigger> | <external-module-body>}

!! Vgl. auch die Syntax CREATE TRIGGER für weitere Regeln !!

Die Anweisung RECREATE TRIGGER erstellt einen neuen Trigger, wenn kein Trigger mit dem angegebenen Namen existiert;andernfalls versucht die Anweisung RECREATE TRIGGER, den vorhandenen Trigger zu löschen und einen neuen zu erstellen.Die Operation schlägt bei COMMIT fehl, wenn der Trigger verwendet wird.

Warning

Beachten Sie, dass Abhängigkeitsfehler erst in der COMMIT-Phase dieser Operation erkannt werden.

Beispiel für RECREATE TRIGGER

Erstellen oder erneutes Erstellen des Triggers set_cust_no.

RECREATE TRIGGER set_cust_no
ACTIVE BEFORE INSERT ON customer POSITION 0
AS
BEGIN
  IF (NEW.cust_no IS NULL) THEN
    NEW.cust_no = GEN_ID(cust_no_gen, 1);
END