DROP TRIGGER ADMIN.DYNAMIC_GRANT_TRG;
DROP ROLE DGIS_LAB_MOPDB_RO;
CREATE ROLE DGIS_LAB_MOPDB_RO;
GRANT DGIS_LAB_MOPDB_RO TO DGIS_LAB;
BEGIN
    EXECUTE IMMEDIATE 'REVOKE SELECT ANY TABLE FROM DGIS_LAB';
EXCEPTION
    WHEN OTHERS THEN
        NULL;
END;
/

DROP TABLE ADMIN.DYNAMIC_GRANT_LOG;
CREATE TABLE ADMIN.DYNAMIC_GRANT_LOG (
    log_id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    owner VARCHAR2(30),
    object_name VARCHAR2(128),
    status VARCHAR2(10), -- 'SUCCESS' or 'FAILURE'
    message VARCHAR2(4000),
    log_date TIMESTAMP DEFAULT SYSTIMESTAMP
);

CREATE OR REPLACE PACKAGE ADMIN.DYNAMIC_GRANT_CONFIG AS
    TYPE t_schema_list IS TABLE OF VARCHAR2(30) INDEX BY PLS_INTEGER;
    FUNCTION get_schemas RETURN t_schema_list;
    PROCEDURE grant_select(p_owner IN VARCHAR2, p_obj IN VARCHAR2);
    PROCEDURE grant_select_initial;
    c_role_name CONSTANT VARCHAR2(30) := 'DGIS_LAB_MOPDB_RO';
END DYNAMIC_GRANT_CONFIG;
/

CREATE OR REPLACE PACKAGE BODY ADMIN.DYNAMIC_GRANT_CONFIG AS

    FUNCTION get_schemas RETURN t_schema_list IS
        l_list t_schema_list;
    BEGIN
        l_list(1) := 'BIDDER';
        l_list(2) := 'BMI_LAB';
        l_list(3) := 'BMI_LAB_SHARED_USER';
        l_list(4) := 'BMI_SHARED';
        l_list(5) := 'C2D';
        l_list(6) := 'COLL_ADHOC';
        l_list(7) := 'COLLATERAL';
        l_list(8) := 'COLL_SHARED';
        l_list(9) := 'CSDB';
        l_list(10) := 'CT_MOPDB';
        l_list(11) := 'DALM';
        l_list(12) := 'DBO';
        l_list(13) := 'DGIS_LAB';
        l_list(14) := 'DGIS_LAB_SHARED_USER';
        l_list(15) := 'ELA';
        l_list(16) := 'FMCO_REPORTS';
        l_list(17) := 'FOS_LAB';
        l_list(18) := 'FOS_LAB_SHARED_USER';
        l_list(19) := 'FRO';
        l_list(20) := 'LEGACY_MFI_ARCHIVE';
        l_list(21) := 'LEGACY_MFI_FROM_C2DDB';
        l_list(22) := 'LM';
        l_list(23) := 'MFI';
        l_list(24) := 'MML_LAB';
        l_list(25) := 'MML_LAB_SHARED_USER';
        l_list(26) := 'MOA_LAB';
        l_list(27) := 'MOA_LAB_SHARED_USER';
        l_list(28) := 'MOMO_DBSPI_USER';
        l_list(29) := 'MOPDB';
        l_list(30) := 'MOPDBAPP';
        l_list(31) := 'MOS_LAB';
        l_list(32) := 'MOS_LAB_SHARED_USER';
        l_list(33) := 'MPEC';
        l_list(34) := 'MPIDS_HISTORY';
        l_list(35) := 'MRRNC';
        l_list(36) := 'PDBSOFA';
        l_list(37) := 'REFERENCE';
        l_list(38) := 'RIAD';
        l_list(39) := 'RIAD_INVESTIGATION';
        l_list(40) := 'RQSD';
        l_list(41) := 'SDW';
        l_list(42) := 'TEC_BMI_APP';
        l_list(43) := 'TEC_EXS_APP';
        l_list(44) := 'TEC_FOS_APP';
        l_list(45) := 'TECH_LOADER';
        l_list(46) := 'TEC_MML_APP';
        l_list(47) := 'TEC_MOA_APP';
        l_list(48) := 'TEC_MOAMOF_APP';
        l_list(49) := 'TEC_MOS_APP';
        l_list(50) := 'TLTRO';
        l_list(51) := 'TMS';
        l_list(52) := 'TMS_HIST';
        l_list(53) := 'TOP';
        l_list(54) := 'TOP_HISTORY';
        l_list(55) := 'WSS_PUBLIC';


        RETURN l_list;
    END;

    PROCEDURE log_grant(p_owner IN VARCHAR2, p_obj IN VARCHAR2, p_status IN VARCHAR2, p_message IN VARCHAR2) IS
    BEGIN
        INSERT INTO ADMIN.DYNAMIC_GRANT_LOG (owner, object_name, status, message)
        VALUES (p_owner, p_obj, p_status, p_message);
    END;

    PROCEDURE grant_select(p_owner IN VARCHAR2, p_obj IN VARCHAR2) IS
        l_sql VARCHAR2(1000);
    BEGIN
        l_sql := 'GRANT SELECT ON ' || p_owner || '.' || p_obj || ' TO ' || c_role_name;
        EXECUTE IMMEDIATE l_sql;
        --DBMS_OUTPUT.PUT_LINE('Granted SELECT on ' || p_owner || '.' || p_obj);
        log_grant(p_owner, p_obj, 'SUCCESS', 'Granted SELECT');
    EXCEPTION
        WHEN OTHERS THEN
            --DBMS_OUTPUT.PUT_LINE('Error in GRANT_SELECT for ' || p_owner || '.' || p_obj || ': ' || SQLERRM);
            log_grant(p_owner, p_obj, 'FAILURE', SQLERRM);
    END;

    PROCEDURE grant_select_initial IS
        l_schema_list t_schema_list := get_schemas;
        l_sql VARCHAR2(1000);
    BEGIN
        FOR i IN l_schema_list.FIRST .. l_schema_list.LAST LOOP
            FOR rec IN (
                SELECT object_name
                FROM dba_objects
                WHERE owner = l_schema_list(i)
                AND object_type IN ('TABLE', 'VIEW')
                AND status = 'VALID'
            ) LOOP
                BEGIN
                    l_sql := 'GRANT SELECT ON ' || l_schema_list(i) || '.' || rec.object_name || ' TO ' || c_role_name;
                    EXECUTE IMMEDIATE l_sql;
                    --DBMS_OUTPUT.PUT_LINE('Granted SELECT on ' || l_schema_list(i) || '.' || rec.object_name);
                    log_grant(l_schema_list(i), rec.object_name, 'SUCCESS', 'Granted SELECT');
                EXCEPTION
                    WHEN OTHERS THEN
                        --DBMS_OUTPUT.PUT_LINE('Error granting on ' || l_schema_list(i) || '.' || rec.object_name || ': ' || SQLERRM);
                        log_grant(l_schema_list(i), rec.object_name, 'FAILURE', SQLERRM);
                END;
            END LOOP;
        END LOOP;
    EXCEPTION
        WHEN OTHERS THEN
            --DBMS_OUTPUT.PUT_LINE('Error in GRANT_SELECT_INITIAL: ' || SQLERRM);
            log_grant(NULL, NULL, 'FAILURE', 'Error in GRANT_SELECT_INITIAL: ' || SQLERRM);
    END;

END DYNAMIC_GRANT_CONFIG;
/
show errors

CREATE OR REPLACE TRIGGER ADMIN.DYNAMIC_GRANT_TRG
AFTER CREATE ON DATABASE
DECLARE
  l_owner      VARCHAR2(30);
  l_obj_name   VARCHAR2(128);
  l_job_name   VARCHAR2(1000);
  l_sql_block  VARCHAR2(2000);
  l_schema_list ADMIN.DYNAMIC_GRANT_CONFIG.t_schema_list := ADMIN.DYNAMIC_GRANT_CONFIG.get_schemas;
BEGIN
  l_owner    := ora_dict_obj_owner;
  l_obj_name := ora_dict_obj_name;

  -- Check if the created object belongs to one of our configured schemas
  IF ora_dict_obj_type IN ('TABLE', 'VIEW') THEN
    FOR i IN l_schema_list.FIRST .. l_schema_list.LAST LOOP
      IF l_schema_list(i) = l_owner THEN
         -- Generate a unique job name
         l_job_name := 'GRANT_JOB_' || l_owner || '_' || l_obj_name || '_' ||
                       TO_CHAR(SYSTIMESTAMP, 'YYYYMMDDHH24MISSFF3');

         -- Build the anonymous PL/SQL block to execute the grant procedure
         l_sql_block := 'BEGIN ADMIN.DYNAMIC_GRANT_CONFIG.GRANT_SELECT(''' || l_owner || ''', ''' ||
                        l_obj_name || '''); END;';

         -- Schedule an immediate one-off job using DBMS_SCHEDULER
         DBMS_SCHEDULER.CREATE_JOB(
            job_name        => l_job_name,
            job_type        => 'PLSQL_BLOCK',
            job_action      => l_sql_block,
            start_date      => SYSTIMESTAMP,
            enabled         => TRUE,
            auto_drop       => TRUE,
            comments        => 'Job created by DDL trigger to grant SELECT privilege.'
         );
         --DBMS_OUTPUT.PUT_LINE('Scheduled grant job: ' || l_sql_block);
         EXIT; -- no need to loop further once a match is found
      END IF;
    END LOOP;
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    --DBMS_OUTPUT.PUT_LINE('Error in trigger: ' || SQLERRM);
    -- Optionally insert into an error log table
    RAISE;
END;
/
EXEC ADMIN.DYNAMIC_GRANT_CONFIG.GRANT_SELECT_INITIAL;
SELECT COUNT(*) FROM DBA_TAB_PRIVS WHERE GRANTEE = 'DGIS_LAB_MOPDB_RO';
