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

Posted

技术标签:

【中文标题】Oracle:如何确定“AFTER ALTER”触发器中对象的新名称?【英文标题】:Oracle: How do I determine the NEW name of an object in an "AFTER ALTER" trigger? 【发布时间】:2010-12-21 01:18:42 【问题描述】:

假设我的 Oracle 数据库上有一个 AFTER ALTER 触发器,并且我重命名了某个数据库对象 (ALTER ... RENAME TO ...)。在触发器中,如何确定数据库对象的 new 名称? 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

数据库输出如下:

更改前:DEVELOPER.USELESS_TABLE9 (TABLE) 修改后:DEVELOPER.USELESS_TABLE9 (TABLE)

更新:不幸的是,我上面提供的输出不正确。输出实际上是由我之前创建的BEFORE DDL 触发器和AFTER DDL 触发器生成的,不是BEFORE RENAMEAFTER RENAME 触发器生成的。我会继续调查为什么BEFORE RENAMEAFTER RENAME 触发器没有触发...

更新:似乎BEFORE RENAMEAFTER RENAME 触发器拒绝触发,但BEFORE ALTERAFTER ALTER 触发器可以。我已经相应地更新了问题。

【问题讨论】:

【参考方案1】:

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;

【讨论】:

以上是关于Oracle:如何确定“AFTER ALTER”触发器中对象的新名称?的主要内容,如果未能解决你的问题,请参考以下文章

汇总报表过滤框触发带字段

onTouch 与多点触控和 SoundPool 运动事件

用于Java开发人员的Oracle数据库中的自动增量

Oracle 9i:如何使用元数据确定索引是不是是集群的?

Oracle:如何实现*几乎*确定性的功能? [复制]

如何在不访问源代码的情况下确定 Oracle 查询?