

CREATE TABLE T_FGA_AUDIT_LOG
(
  TB_USER    VARCHAR2(30),
  TB_TABLE   VARCHAR2(30),
  ZEITPUNKT  TIMESTAMP(6),
  REMARK     VARCHAR2(80)
)
LOGGING 
NOCOMPRESS 
NOCACHE
NOPARALLEL
MONITORING
/

CREATE TABLE T_FGA_CONFIGUARTION
(
  "SCHEMA"            VARCHAR2(30),
  TABELLE             VARCHAR2(30),
  AUDIT_YN            VARCHAR2(1),
  STATUS              VARCHAR2(80),
  ZEITSTEMPEL_STATUS  DATE                      DEFAULT SYSDATE,
  REMARK              VARCHAR2(250),
  CONSTRAINT T_FGA_CONFIGUARTION_PK
  PRIMARY KEY
  ("SCHEMA", TABELLE)
  USING INDEX T_FGA_CONFIGUARTION_PK
)
LOGGING 
NOCOMPRESS 
NOCACHE
NOPARALLEL
MONITORING
/



CREATE OR REPLACE PACKAGE pkg_fga_audit AUTHID CURRENT_USER
AS
   
   PROCEDURE add_policy (p_schema IN VARCHAR2, p_table IN VARCHAR2);

   PROCEDURE drop_policy (p_schema IN VARCHAR2, p_table IN VARCHAR2);

   PROCEDURE setup;

   PROCEDURE watch;
END pkg_fga_audit;
/



CREATE OR REPLACE PACKAGE BODY pkg_fga_audit
AS
   
--   needs:
--      GRANT EXECUTE =>  DBMS_FGA
--      GRANT SELECT ON dba_fga_audit_trail;

  
   gv_sqlcode                    NUMBER;
   --
   --
   --
   policynotexist                EXCEPTION;
   PRAGMA EXCEPTION_INIT (policynotexist, -28102);

--------------------------------------------------------------------------------
   --
   -- add an new policy for: INSERT,UPDATE,DELETE,SELECT
   --
   PROCEDURE add_policy (p_schema IN VARCHAR2, p_table IN VARCHAR2)
   IS
      PRAGMA AUTONOMOUS_TRANSACTION;
   BEGIN
      --
      -- DBMS_FGA.DB = 2
      -- DBMS_FGA.any_columns = 0
      --
      DBMS_FGA.add_policy (object_schema          => p_schema
                         , object_name            => p_table
                         , policy_name            => p_table
                         , audit_condition        => NULL
                         , audit_column           => NULL
                         , handler_schema         => NULL
                         , handler_module         => NULL
                         , ENABLE                 => TRUE
                         , statement_types        => 'INSERT,UPDATE,DELETE,SELECT'
                         , audit_trail            => 2
                         , audit_column_opts      => 0
                          );

      INSERT INTO t_fga_audit_log
                  (tb_user, tb_table, remark, zeitpunkt
                  )
           VALUES (p_schema, p_table, 'add_policy ', SYSDATE
                  );

      COMMIT;
   EXCEPTION
      WHEN OTHERS
      THEN
         gv_sqlcode    := SQLCODE;

         INSERT INTO t_fga_audit_log
                     (tb_user, tb_table
                    , remark, zeitpunkt
                     )
              VALUES (p_schema, p_table
                    , 'Error ORA-' || TO_CHAR (gv_sqlcode), SYSDATE
                     );

         COMMIT;
         ROLLBACK;
   END;

--------------------------------------------------------------------------------
--
--
--
   PROCEDURE drop_policy (p_schema IN VARCHAR2, p_table IN VARCHAR2)
   IS
      PRAGMA AUTONOMOUS_TRANSACTION;
   BEGIN
      DBMS_FGA.drop_policy (object_schema      => p_schema
                          , object_name        => p_table
                          , policy_name        => p_table
                           );

      INSERT INTO t_fga_audit_log
                  (tb_user, tb_table, remark, zeitpunkt
                  )
           VALUES (p_schema, p_table, 'drop_policy ', SYSDATE
                  );

      COMMIT;
   EXCEPTION
      WHEN policynotexist
      THEN
         --
         -- EXCEPTION for : ORA-28102: policy does not exist
         --
         INSERT INTO t_fga_audit_log
                     (tb_user, tb_table
                    , remark, zeitpunkt
                     )
              VALUES (p_schema, p_table
                    , 'policy to drop does not exist ORA-28102', SYSDATE
                     );

         COMMIT;
      WHEN OTHERS
      THEN
         gv_sqlcode    := SQLCODE;

         INSERT INTO t_fga_audit_log
                     (tb_user, tb_table
                    , remark, zeitpunkt
                     )
              VALUES (p_schema, p_table
                    , 'Error ORA-' || TO_CHAR (gv_sqlcode), SYSDATE
                     );

         COMMIT;
   END;

--------------------------------------------------------------------------------
--
-- setup
--
   PROCEDURE setup
   IS
      CURSOR c_config
      IS
         SELECT        *
                  FROM t_fga_configuartion
                 WHERE audit_yn IN ('Y', 'N')
         FOR UPDATE OF audit_yn
              ORDER BY SCHEMA, tabelle;
   --
   --
   BEGIN
      --
      FOR rec IN c_config
      LOOP
         IF rec.audit_yn = 'Y'
         THEN
            add_policy (rec.SCHEMA, rec.tabelle);

            UPDATE t_fga_configuartion
               SET audit_yn = '+'
                 , status = 'watched'
             WHERE CURRENT OF c_config;
         ELSIF rec.audit_yn = 'N'
         THEN
            drop_policy (rec.SCHEMA, rec.tabelle);

            UPDATE t_fga_configuartion
               SET audit_yn = '-'
                 , status = 'deactivated'
                 , zeitstempel_status = SYSDATE
             WHERE CURRENT OF c_config;
         END IF;
      END LOOP;

      COMMIT;
   END;

--------------------------------------------------------------------------------
--
--
--
   PROCEDURE watch
   IS
      CURSOR c_watch
      IS
         SELECT     *
               FROM t_fga_configuartion
              WHERE audit_yn = '+'
         FOR UPDATE;

      lv_zeitstempel                DATE;
   BEGIN
      INSERT INTO t_fga_audit_log
                  (tb_user, tb_table, remark, zeitpunkt
                  )
           VALUES ('INTERNAL', 'INTERNAL', 'watch runing', SYSDATE
                  );

      FOR rec IN c_watch
      LOOP
         BEGIN
            SELECT MAX (TIMESTAMP)
              INTO lv_zeitstempel
              FROM SYS.dba_fga_audit_trail
             WHERE TIMESTAMP > rec.zeitstempel_status
               AND object_schema = rec.SCHEMA
               AND object_name = rec.tabelle;
         EXCEPTION
            WHEN NO_DATA_FOUND
            THEN
               NULL;
         END;

         IF lv_zeitstempel IS NOT NULL
         THEN
            UPDATE t_fga_configuartion
               SET audit_yn = '-'
                 , status = 'used'
                 , zeitstempel_status = lv_zeitstempel
             WHERE CURRENT OF c_watch;

            --
            INSERT INTO t_fga_audit_log
                        (tb_user, tb_table
                       , remark, zeitpunkt
                        )
                 VALUES (rec.SCHEMA, rec.tabelle
                       , 'used - not monitored anymore', lv_zeitstempel
                        );

            --
            drop_policy (rec.SCHEMA, rec.tabelle);
         --
         ELSE
            --
            INSERT INTO t_fga_audit_log
                        (tb_user, tb_table, remark, zeitpunkt
                        )
                 VALUES (rec.SCHEMA, rec.tabelle, 'checked', SYSDATE
                        );
         END IF;
      END LOOP;

      COMMIT;
   END;
END;
/

