db2db2-luw

DB2 Logging exception in table inside a trigger


I want to make some detailed output when a trigger violation occurs. In the trigger below it should be some columns of obj that should be logged. So what will the best way to do it?, inserting into LOG_TABLE does not work, because the transaction is rolled back in case of an exception.

CREATE OR REPLACE TRIGGER XYZ 
    NO CASCADE BEFORE UPDATE OF NAME ON MY_TABLE
    REFERENCING NEW AS OBJ
    FOR EACH ROW MODE DB2SQL 
    BEGIN
    DECLARE ERROR_TEXT VARCHAR(1000);
    IF
    OBJ.NAME = ‘Z’
    THEN
    --Insert into MY_SCHEMA.LOG_TABLE(....);
    SET ERROR_TEXT = 'Name not allowed';
    SIGNAL SQLSTATE '7010101' SET MESSAGE_TEXT = ERROR_TEXT;
    END IF;
    END

Solution

  • You may use an autonomous procedure for that.

    An autonomous procedure is a procedure that, when called, executes inside a new transaction independent of the original transaction. When the autonomous procedure successfully completes, it will commit the work performed within the procedure, but if it is unsuccessful, the procedure rolls back any work it performed. Whatever the result of the autonomic procedure, the transaction which called the autonomic procedure is unaffected. To specify a procedure as autonomous, specify the AUTONOMOUS keyword on the CREATE PROCEDURE statement.

    Look at the example below.

    Notes:

    CREATE TABLE LOG_TABLE
    (
      ID            INT NOT NULL GENERATED BY DEFAULT AS IDENTITY
    , ERROR_TEXT    VARCHAR(1000) NOT NULL
    , TS            TIMESTAMP NOT NULL DEFAULT CURRENT TIMESTAMP
    , OBJ           XML NOT NULL
    )
    
    CREATE TABLE MY_TABLE 
    (
      ID    INT NOT NULL GENERATED BY DEFAULT AS IDENTITY
    , NAME  VARCHAR(10) NOT NULL
    )
    
    CREATE OR REPLACE PROCEDURE LOG_TABLE
    (
      P_ERROR_TEXT  VARCHAR(1000)
    , P_OBJ         BLOB(10K)
    )
    AUTONOMOUS 
    BEGIN
        INSERT INTO LOG_TABLE (ERROR_TEXT, OBJ) VALUES (P_ERROR_TEXT, XMLPARSE(DOCUMENT P_OBJ));
    END 
    
    CREATE OR REPLACE TRIGGER MY_TABLE_BUR
    NO CASCADE BEFORE UPDATE OF NAME ON MY_TABLE
    REFERENCING NEW AS OBJ
    FOR EACH ROW MODE DB2SQL 
    BEGIN
      DECLARE ERROR_TEXT VARCHAR(1000);
      IF
        OBJ.NAME = 'Z'
        THEN
        --Insert into MY_SCHEMA.LOG_TABLE(....);
        CALL LOG_TABLE('Name not allowed: ' || OBJ.NAME, XMLSERIALIZE(XMLROW(OBJ.ID AS "ID", OBJ.NAME AS "NAME") AS BLOB(10K)));
        SET ERROR_TEXT = 'Name not allowed';
        SIGNAL SQLSTATE '70001' SET MESSAGE_TEXT = ERROR_TEXT;
      END IF;
    END
    
    INSERT INTO MY_TABLE(NAME) VALUES ('X')
    
    UPDATE MY_TABLE SET NAME = 'Z'
    
    [IBM][CLI Driver][DB2/LINUXX8664] SQL0438N  Application raised error or warning with diagnostic text: "Name not allowed".  SQLSTATE=70001 SQLCODE=-438
    
    SELECT * FROM MY_TABLE
    
    ID NAME
    1 X
    SELECT * FROM LOG_TABLE
    
    ID ERROR_TEXT TS OBJ
    1 Name not allowed: Z 2024-12-11 07:51:02.850763 <?xml version="1.0" encoding="UTF-8" ?><row><ID>1</ID><NAME>Z</NAME></row>

    fiddle