SCHEMA TRIGGER 调用 DBMS_METADATA.get_ddl 在调用其他模式时失败

问题描述

我有一个触发器,每当架构发生 DDL 更改时都会触发。当它触发时,触发器调用 DBMS_METADATA.get_ddl 函数来获取正在更改的对象的新快照。

TRIGGER 位于 FDS_MAINT 模式中,如果有人更改了该模式中的对象,则可以正常工作。但是,如果在另一个模式中更改了对象,即使修改的表存在,DBMS_METADATA.get_ddl 也会失败并出现以下错误:

ORA-31603: object "JUNK" of type TABLE not found in schema "FDS_BASE"
ORA-06512: at "SYS.DBMS_METADATA",line 6078
ORA-06512: at "SYS.DBMS_METADATA",line 8686
ORA-06512: at line 1

问题 1:需要授予哪些权限才能使其发挥作用?

参考 CREATE TRIGGER 语句的第一三行,注意它说“ON MY_LAN_ID.SCHEMA”。我不确定我是否理解这的重要性。正如这个触发器一样,这个触发器会在我的架构或 FDS_BASE 或 FDS_MAINT 发生更改时触发,后者是 TRIGGER 所在的位置。这让我感到惊讶,因为我预计它只会在更改我的架构时触发。如果我删除“MY_LAN_ID”限定条件并将其设为“ON SCHEMA”,它只会为 FDS_MAINT(触发器所在的架构)触发。使用 MY_LAN_ID 引用时,它是否会在我有权访问的架构对象发生更改时触发?什么样的访问?这对我来说似乎不太可能。

问题 2:在此语句中添加 MY_LAN_ID 到底有什么作用?

  CREATE OR REPLACE EDITIONABLE TRIGGER "FDS_MAINT"."AUDIT_DDL_TRG" 
    AFTER DDL ON DATABASE    
DECLARE
    L_TEXT   CLOB;
    sql_text ora_name_list_t;
    n NUMBER;
BEGIN

    IF     ora_sysevent       != 'TRUNCATE'   AND 
           ora_dict_obj_owner  = 'FDS_MAINT'  AND
           ora_dict_obj_name  != 'AUDIT_DLL'
    THEN

        BEGIN

            n := ora_sql_txt(sql_text);
            
            DBMS_METADATA.SET_TRANSFORM_PARAM(
                                              DBMS_METADATA.SESSION_TRANSFORM,'SEGMENT_ATTRIBUTES',FALSE
                                             );

            SELECT DBMS_METADATA.get_ddl(
                                         ora_dict_obj_type,ora_dict_obj_name,ora_dict_obj_owner
                                        )
              INTO L_TEXT
              FROM DUAL;
        EXCEPTION
            WHEN OTHERS
            THEN
                L_TEXT := SQLERRM;                                                                                                                                                              --'No DDL TEXT Available';

        END;

        BEGIN

            INSERT INTO FDS_MAINT.audit_ddl(
                                            EVENT_TIME,osuser,current_user,HOST,terminal,owner,TYPE,name,sysevent,TEXT,COMMAND
                                           )
                 VALUES (
                         SYSDATE,SYS_CONTEXT(
                                     'USERENV','OS_USER'
                                    ),'CURRENT_USER'
                                    ),'HOST'
                                    ),'TERMINAL'
                                    ),ora_dict_obj_owner,ora_dict_obj_type,ora_sysevent,L_TEXT,sql_text(n) 
                        );
        EXCEPTION
            WHEN OTHERS
            THEN
                NULL;

        END;

    END IF;

END;

ALTER TRIGGER "FDS_MAINT"."AUDIT_DDL_TRG" ENABLE

问题 #3:我希望能够捕获为执行更改而执行的 DDL。我该怎么做?

  • 更新:

SQL 更新以在 COMMAND 列中存储触发 TRIGGER 的 DDL。

问题 4:有没有办法定义 TRIGGER 来触发指定模式列表?

是否涉及对某些用户的以下 GRANT?

将 select_catalog_role 授予 ??

我执行了

将 select_catalog_role 授予 FDS_BASE;

但这没有帮助。

此触发器在哪个用户上下文下运行? FDS_MAINT?

我尝试将“AUTHID CURRENT_USER”添加到触发器

CREATE OR REPLACE TRIGGER FDS_MAINT.AUDIT_DDL_TRG AUTHID CURRENT_USER 
    AFTER DDL
    ON SCHEMA 

但我收到此错误:

1 ORA-04071: missing BEFORE,AFTER or INSTEAD OF keyword SQL1.sql 6 51 

我还发现这个 TRIGGER 只有在我进行更改时才会触发,这是最糟糕的部分。我希望能够记录任何人对数据库所做的所有更改。

更新: 这已通过将“AFTER DDL”更改为“AFTER DDL ON DATABASE”而得到纠正

有关如何使此功能正常工作的任何想法将不胜感激!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)