Oracle:如何在“AFTER ALTER”触发器中确定对象的NEW名称?

时间:2009-11-27 17:04:30

标签: oracle triggers rename

假设我的Oracle数据库上有AFTER ALTER触发器,我重命名了一些数据库对象(ALTER ... RENAME TO ...)。在触发器中,如何确定数据库对象的名称?似乎ORA_DICT_OBJ_OWNERORA_DICT_OBJ_NAMEORA_DICT_OBJ_TYPE函数都返回数据库对象的值。

例如:

CREATE OR REPLACE TRIGGER ADAM_BEFORE_AFTER BEFORE ALTER ON DATABASE
BEGIN
  DBMS_OUTPUT.put_line('Before alter: ' || ora_dict_obj_owner || '.' || ora_dict_obj_name || ' (' || ora_dict_obj_type || ')');
END;

CREATE OR REPLACE TRIGGER ADAM_AFTER_ALTER AFTER ALTER ON DATABASE
BEGIN
  DBMS_OUTPUT.put_line('After alter: ' || ora_dict_obj_owner || '.' || ora_dict_obj_name || ' (' || ora_dict_obj_type || ')');
END;

假设我重命名一个表:

ALTER TABLE USELESS_TABLE9 RENAME TO USELESS_TABLE10

数据库输出:

Before alter: DEVELOPER.USELESS_TABLE9 (TABLE)
After alter: DEVELOPER.USELESS_TABLE9 (TABLE)

更新:不幸的是,我上面提到的输出不正确。输出实际上是由BEFORE DDL触发器和我之前创建的AFTER DDL触发器生成的,BEFORE RENAMEAFTER RENAME触发器。我将继续调查BEFORE RENAMEAFTER RENAME触发器未触发的原因......

更新BEFORE RENAMEAFTER RENAME触发器似乎拒绝触发,但BEFORE ALTERAFTER ALTER触发器会触发。我已相应更新了这个问题。

1 个答案:

答案 0 :(得分:6)

ALTER RENAME不会触发触发器,RENAME x TO y会。

关于你之前和之后名字的问题,我认为你必须解析DDL来检索它们,就像那样:

CREATE OR REPLACE TRIGGER MK_BEFORE_RENAME BEFORE RENAME ON SCHEMA 
DECLARE 
  sql_text ora_name_list_t;
  v_stmt VARCHAR2(2000);
  n PLS_INTEGER; 
BEGIN  
  n := ora_sql_txt(sql_text);
  FOR i IN 1..n LOOP
   v_stmt := v_stmt || sql_text(i);
  END LOOP;

  Dbms_Output.Put_Line( 'Before: ' || regexp_replace( v_stmt, 'rename[[:space:]]+([a-z0-9_]+)[[:space:]]+to.*', '\1', 1, 1, 'i' ) );
  Dbms_Output.Put_Line( 'After: ' || regexp_replace( v_stmt, 'rename[[:space:]]+.*[[:space:]]+to[[:space:]]+([a-z0-9_]+)', '\1', 1, 1, 'i' ) );
END;

正则表达式肯定会写得更清楚,但它有效:

RENAME 
mktestx
TO                 mktesty;

Before: mktestx
After: mktesty

更新为了适应您更改过的问题:

CREATE OR REPLACE TRIGGER MK_AFTER_ALTER AFTER ALTER ON SCHEMA 
DECLARE 
  sql_text ora_name_list_t;
  v_stmt VARCHAR2(2000);
  n PLS_INTEGER; 
BEGIN  
  n := ora_sql_txt(sql_text);
  FOR i IN 1..n LOOP
   v_stmt := v_stmt || sql_text(i);
  END LOOP;

  Dbms_Output.Put_Line( 'Before: ' || regexp_replace( v_stmt, 'alter[[:space:]]+table[[:space:]]+([a-z0-9_]+)[[:space:]]+rename[[:space:]]+to.*', '\1', 1, 1, 'i' ) );
  Dbms_Output.Put_Line( 'After: ' || regexp_replace( v_stmt, 'alter[[:space:]]+table[[:space:]]+.*to[[:space:]]+([a-z0-9_]+)', '\1', 1, 1, 'i' ) );
END;