从触发器捕获包/过程/函数名称

时间:2013-01-28 03:05:56

标签: oracle stored-procedures plsql triggers

我有一个表(Oracle 11g),其中多个包/存储过程运行DML语句。我想捕获使用触发器在表上发出DML的包/过程名称,并将其记录到日志记录表中。

例如:

MY_PACK.MY_PROC()为表insert into...发出mytab。我会在mytab上设计一个触发器,它应该能够捕获发出insert into..的包/过程名称,并将此信息存储在另一个表my_tab_log中。

我做了一些搜索,发现$$PLSQL_UNIT$$PLSQL_LINE可以指出过程名称,但是如果在触发器中使用这些变量,则会捕获触发器名称而不是包发出DML语句的/ procedure name。

喜欢 -

CREATE OR REPLACE TRIGGER my_trg
AFTER INSERT OR UPDATE OR DELETE
ON MY_TAB
FOR EACH ROW
BEGIN
    IF INSERTING THEN
         insert into my_tab_log values('INSERTED A ROW'
                                       sysdate,
                                       $$PLSQL_UNIT); 
    END IF;
    -- This would capture Trigger name but I would like to capture `MY_PACK.MY_PROC()`
    -- which issued the insert statement
    ...
END;

现在因为$$ PLSQL_UNIT是一个条件编译指令。在编译/重新编译PL / SQL代码时解决了这个问题。所以不幸的是,触发器中的$$ PLSQL_UNIT只是触发器名称,并在触发器编译时解析。

我还找到了程序owa_util.who_called_me,但无法解决我如何使用它来满足我的需求。甚至可以实现我想要的而不需要更改发出DML语句的实际包/存储过程?我无法修改这些程序,这是一个严格的限制,所以这不是一个选项。

1 个答案:

答案 0 :(得分:6)

$$PLSQL_UNIT只提供包名称,而不是包中的过程名称。 who_called_me也是如此。

owa_util.who_called_me基于一个不可估量的Kyte先生所写的小实用程序。如果您查看his source code here,您将看到例程从调用堆栈中获取其信息。因此,它提供的信息是:

  • 节目所有者
  • 程序名称(包或独立程序)
  • 程序类型
  • 行号

这些令人沮丧的限制归结为重载:我们可以创建具有相同名称但签名不同的打包过程。因此,当识别哪一段代码正在运行时,“过程名称”对系统并不是特别有用。

无论如何,如果你想玩who_called_me游戏,它需要四个这样的参数:

create or replace trigger my_trg 
before insert or update on my_tab
for each row
declare
  l_owner varchar2(30);
  l_name varchar2(30);
  l_line pls_integer;
  l_type varchar2(30);
begin
  owa_util.who_called_me(l_owner,l_name,l_line,l_type);
  IF INSERTING THEN
     insert into my_tab_log values('INSERTED A ROW'
                                   sysdate,
                                   l_owner||'.'||l_name); 
  END IF;
end;
/