HOW TO AUDIT/TRACK ANY DATABASE TABLE BY USING TRIGGER?

Process:
1. First you need to grant 3 privileges in your system.
           grant dba,select any dictionary,select_catalog_role to hr;
2. Then connect your hr user.
3. After access your user you need to create 2 tables name LOGGING_DATA_HDR and
    LOGGING_DATA_DTL and also a SEQUENCE name SEQUENCE LOG_ID_SEQ

 CREATE TABLE LOGGING_DATA_HDR 
 ( 
   LOG_ID      NUMBER, 
   TABLE_NAME    VARCHAR2 (30 CHAR) NOT NULL, 
   PK_DATA     VARCHAR2 (500 BYTE), 
   ROW_ID      ROWID NOT NULL, 
   LOG_DATE     DATE NOT NULL, 
   OPERATION_TYPE  VARCHAR2 (1 BYTE) NOT NULL, 
   DB_USER     VARCHAR2 (100 BYTE), 
   CLIENT_IP    VARCHAR2 (40 BYTE), 
   CLIENT_HOST   VARCHAR2 (100 BYTE), 
   CLIENT_OS_USER  VARCHAR2 (100 BYTE), 
   APP_USER     VARCHAR2 (50 BYTE) 
 ); 
 ALTER TABLE LOGGING_DATA_HDR ADD ( 
  CONSTRAINT LOGGING_DATA_HDR_PK 
  PRIMARY KEY 
  (LOG_ID) 
  );  


 CREATE TABLE LOGGING_DATA_DTL 
 ( 
   LOG_ID    NUMBER, 
   COLUMN_NAME  VARCHAR2 (30 CHAR), 
   OLD_VALUE   VARCHAR2 (4000 BYTE), 
   NEW_VALUE   VARCHAR2 (4000 BYTE) 
 ); 
 ALTER TABLE LOGGING_DATA_DTL ADD ( 
  CONSTRAINT LOGGING_DATA_DTL_PK 
  PRIMARY KEY 
  (LOG_ID, COLUMN_NAME));  


 CREATE SEQUENCE LOG_ID_SEQ 
   START WITH 1 
   MAXVALUE 99999999999 
   MINVALUE 1 
   NOCYCLE 
   NOCACHE 
   NOORDER;   


4. Then you need to create this package and package body:

CREATE OR REPLACE PACKAGE DML_LOG
 AS 
   TYPE GT$LOGGING_DATA_DTL IS TABLE OF LOGGING_DATA_DTL%ROWTYPE; 
   GC$APP_USER  LOGGING_DATA_HDR.APP_USER%TYPE; 
   PROCEDURE ADD_LOG (IN_ARRAY      IN GT$LOGGING_DATA_DTL, 
            IN_TABLE_NAME     VARCHAR2, 
            IN_ROWID        ROWID, 
            IN_OPERATION_TYPE   VARCHAR2); 
   FUNCTION GENERATE_TRIGGER (IN_TABLE_NAME VARCHAR2) 
    RETURN VARCHAR2; 
   FUNCTION GET_COMPOSITE_KEY (IN_TABLE    VARCHAR2, 
                 IN_ROWID    ROWID, 
                 IN_DELIMETER  VARCHAR2 DEFAULT '-') 
    RETURN VARCHAR2; 
   PROCEDURE SET_APP_USER (IN_APP_USER LOGGING_DATA_HDR.APP_USER%TYPE); 
   FUNCTION GET_APP_USER 
    RETURN LOGGING_DATA_HDR.APP_USER%TYPE; 
 END DML_LOG; 
 / 



CREATE OR REPLACE PACKAGE BODY DML_LOG 
 AS 
   PROCEDURE ADD_LOG (IN_ARRAY      IN GT$LOGGING_DATA_DTL, 
            IN_TABLE_NAME     VARCHAR2, 
            IN_ROWID        ROWID, 
            IN_OPERATION_TYPE   VARCHAR2) 
   IS 
    LN$LOG_ID  LOGGING_DATA_HDR.LOG_ID%TYPE; 
   BEGIN 
    SELECT LOG_ID_SEQ.NEXTVAL INTO LN$LOG_ID FROM DUAL; 
    INSERT INTO LOGGING_DATA_HDR (LOG_ID, 
                   TABLE_NAME, 
                   PK_DATA, 
                   ROW_ID, 
                   LOG_DATE, 
                   OPERATION_TYPE, 
                   DB_USER, 
                   CLIENT_IP, 
                   CLIENT_HOST, 
                   CLIENT_OS_USER, 
                   APP_USER) 
       VALUES (LN$LOG_ID, 
           IN_TABLE_NAME, 
           GET_COMPOSITE_KEY (IN_TABLE_NAME, IN_ROWID), 
           IN_ROWID, 
           SYSDATE, 
           IN_OPERATION_TYPE, 
           SYS_CONTEXT ('USERENV', 'CURRENT_USER'), 
           SYS_CONTEXT ('USERENV', 'ip_address'), 
           SYS_CONTEXT ('USERENV', 'host'), 
           SYS_CONTEXT ('USERENV', 'os_user'), 
           GET_APP_USER); 
    IF IN_ARRAY IS NOT NULL AND IN_ARRAY.COUNT > 0 
    THEN 
      FOR INDX IN IN_ARRAY.FIRST .. IN_ARRAY.LAST 
      LOOP 
       IF IN_ARRAY (INDX).COLUMN_NAME IS NOT NULL 
         AND (IN_ARRAY (INDX).OLD_VALUE IS NOT NULL 
           OR IN_ARRAY (INDX).NEW_VALUE IS NOT NULL) 
       THEN 
         INSERT INTO LOGGING_DATA_DTL (LOG_ID, 
                        COLUMN_NAME, 
                        OLD_VALUE, 
                        NEW_VALUE) 
           VALUES (LN$LOG_ID, 
               IN_ARRAY (INDX).COLUMN_NAME, 
               IN_ARRAY (INDX).OLD_VALUE, 
               IN_ARRAY (INDX).NEW_VALUE); 
       END IF; 
      END LOOP; 
    END IF; 
   END ADD_LOG; 
   FUNCTION GENERATE_TRIGGER (IN_TABLE_NAME VARCHAR2) 
    RETURN VARCHAR2 
   IS 
    LC$TRIGGER_STMT  VARCHAR2 (4000); 
    CURSOR LCUR$COLUMNS 
    IS 
       SELECT COLUMN_NAME 
        FROM USER_TAB_COLS 
       WHERE TABLE_NAME = IN_TABLE_NAME 
      ORDER BY COLUMN_ID; 
   BEGIN 
    LC$TRIGGER_STMT := 
       'CREATE OR REPLACE TRIGGER ' 
      || SUBSTR (IN_TABLE_NAME, 1, 23) 
      || '_LOGTRG ' 
      || CHR (10) 
      || 'AFTER INSERT OR UPDATE OR DELETE' 
      || CHR (10) 
      || 'ON ' 
      || IN_TABLE_NAME 
      || ' FOR EACH ROW ' 
      || CHR (10) 
      || 'DECLARE ' 
      || CHR (10) 
      || 'LT$LOGGING_DATA_DTL  DML_LOG.GT$LOGGING_DATA_DTL;' 
      || CHR (10) 
      || 'LC$OPERATION     VARCHAR2 (1);' 
      || CHR (10) 
      || 'PROCEDURE ADD_ELEMENT (' 
      || CHR (10) 
      || 'IN_OPERATION   VARCHAR2,' 
      || CHR (10) 
      || 'IN_COLUMN_NAME  LOGGING_DATA_DTL.COLUMN_NAME%TYPE,' 
      || CHR (10) 
      || 'IN_OLD_VALUE   LOGGING_DATA_DTL.OLD_VALUE%TYPE,' 
      || CHR (10) 
      || 'IN_NEW_VALUE   LOGGING_DATA_DTL.NEW_VALUE%TYPE)' 
      || CHR (10) 
      || 'IS' 
      || CHR (10) 
      || 'LR$LOGGING_DATA_DTL  LOGGING_DATA_DTL%ROWTYPE;' 
      || CHR (10) 
      || 'BEGIN' 
      || CHR (10) 
      || ' IF NOT (IN_OPERATION = ''U'' AND IN_NEW_VALUE = IN_OLD_VALUE)' 
      || CHR (10) 
      || 'THEN' 
      || CHR (10) 
      || 'LR$LOGGING_DATA_DTL.COLUMN_NAME := IN_COLUMN_NAME;' 
      || CHR (10) 
      || 'LR$LOGGING_DATA_DTL.OLD_VALUE :=IN_OLD_VALUE;' 
      || CHR (10) 
      || 'LR$LOGGING_DATA_DTL.NEW_VALUE := IN_NEW_VALUE;' 
      || CHR (10) 
      || 'LT$LOGGING_DATA_DTL.EXTEND;' 
      || CHR (10) 
      || 'LT$LOGGING_DATA_DTL (LT$LOGGING_DATA_DTL.LAST) := LR$LOGGING_DATA_DTL;' 
      || CHR (10) 
      || 'END IF;' 
      || CHR (10) 
      || 'END ADD_ELEMENT;' 
      || CHR (10) 
      || 'BEGIN' 
      || CHR (10) 
      || 'LT$LOGGING_DATA_DTL := DML_LOG.GT$LOGGING_DATA_DTL ();' 
      || CHR (10) 
      || 'LC$OPERATION :=' 
      || CHR (10) 
      || 'CASE WHEN INSERTING THEN ''I'' WHEN UPDATING THEN ''U'' ELSE ''D'' END;' 
      || CHR (10); 
    FOR LREC$COLUMNS IN LCUR$COLUMNS 
    LOOP 
      LC$TRIGGER_STMT := 
         LC$TRIGGER_STMT 
       || ' ADD_ELEMENT (LC$OPERATION,''' 
       || LREC$COLUMNS.COLUMN_NAME 
       || ''',:OLD.' 
       || LREC$COLUMNS.COLUMN_NAME 
       || ',:NEW.' 
       || LREC$COLUMNS.COLUMN_NAME 
       || ');' 
       || CHR (10); 
    END LOOP; 
    LC$TRIGGER_STMT := 
       LC$TRIGGER_STMT 
      || ' DML_LOG.ADD_LOG (LT$LOGGING_DATA_DTL,''' 
      || IN_TABLE_NAME 
      || ''',:NEW.ROWID,LC$OPERATION);' 
      || CHR (10) 
      || 'END ' 
      || SUBSTR (IN_TABLE_NAME, 1, 23) 
      || '_LOGTRG ;'; 
    RETURN LC$TRIGGER_STMT; 
   END GENERATE_TRIGGER; 
   FUNCTION GET_COMPOSITE_KEY (IN_TABLE    VARCHAR2, 
                 IN_ROWID    ROWID, 
                 IN_DELIMETER  VARCHAR2 DEFAULT '-') 
    RETURN VARCHAR2 
   IS 
    PRAGMA AUTONOMOUS_TRANSACTION; 
    LC$COLUMNS  VARCHAR2 (512) := ''; 
    LC$KEY    VARCHAR2 (512); 
    CURSOR LCUR$COLUMNS ( 
      IN_TABLE_NAME VARCHAR2) 
    IS 
       SELECT CON_C.COLUMN_NAME 
        FROM USER_CONS_COLUMNS CON_C, USER_CONSTRAINTS CON 
       WHERE   CON.CONSTRAINT_NAME = CON_C.CONSTRAINT_NAME 
          AND CON.CONSTRAINT_TYPE = 'P' 
          AND CON.TABLE_NAME = IN_TABLE_NAME 
      ORDER BY POSITION; 
   BEGIN 
    FOR LREC$COLUMNS IN LCUR$COLUMNS (IN_TABLE) 
    LOOP 
      LC$COLUMNS := 
         LC$COLUMNS 
       || LREC$COLUMNS.COLUMN_NAME 
       || '||''' 
       || IN_DELIMETER 
       || '''||'; 
    END LOOP; 
    LC$COLUMNS := RTRIM (LC$COLUMNS, '||''' || IN_DELIMETER || '''||'); 
    EXECUTE IMMEDIATE 
       'SELECT ' 
      || LC$COLUMNS 
      || ' FROM ' 
      || IN_TABLE 
      || ' WHERE ROWID=''' 
      || IN_ROWID 
      || '''' 
      INTO LC$KEY; 
    RETURN LC$KEY; 
   END GET_COMPOSITE_KEY; 
   PROCEDURE SET_APP_USER (IN_APP_USER LOGGING_DATA_HDR.APP_USER%TYPE) 
   IS 
   BEGIN 
    GC$APP_USER := IN_APP_USER; 
   END SET_APP_USER; 
   FUNCTION GET_APP_USER 
    RETURN LOGGING_DATA_HDR.APP_USER%TYPE 
   IS 
   BEGIN 
    RETURN GC$APP_USER; 
   END GET_APP_USER; 
 END DML_LOG; 
 /


5. Then create this trigger to generate automatically log register trigger.

set serveroutput on
BEGIN 
   DBMS_OUTPUT.PUT_LINE (DML_LOG.GENERATE_TRIGGER ('DEPARTMENTS')); 
END;
/


6. Copy the trigger and paste it in SQL command line for createing this trigger.
7. After that genarate a DML statement.
8. commit the DML. 

No comments:

Post a Comment