在 T-SQL 中,以下命令将返回当前运行的存储过程的名称:
OBJECT_NAME(@@PROCID)
在 PL/SQL 中,当我将以下代码放在包的存储过程中时,它返回父包的名称而不是正在执行的存储过程。
$$PLSQL_UNIT
有没有办法在 PL/SQL 中获取执行过程的名称?
最佳答案
是的,在 12 之前的版本中这是不可能的。但是您可以尝试一些技巧。
V$SESSION
查看已PLSQL_ENTRY_SUBPROGRAM_ID
和 PLSQL_SUBPROGRAM_ID
可以引导您当前正在执行的过程的字段。 当前 session 是:
select PLSQL_ENTRY_OBJECT_ID,
PLSQL_ENTRY_SUBPROGRAM_ID,
PLSQL_OBJECT_ID,
PLSQL_SUBPROGRAM_ID
from V$SESSION
where AUDSID = sys_context( 'userenv', 'sessionid' )
然后通过查询 View 找到过程名
ALL_PROCEDURES
:select PROCEDURE_NAME
from ALL_PROCEDURES
where OBJECT_ID = :objectId
and SUBPROGRAM_ID = :subprogramId
此 View 包含在包中声明的函数和过程,但不包含在包体中声明的函数和过程。
dbms_utility.format_call_stack
显示行号和源名称。解析输出可以通过 owa_util.who_called_me
获得.原始输出还包含 object handle
它可以让您访问匿名块的源代码。 dbms_utility.format_call_stack
示例输出:----- PL/SQL Call Stack -----
object line object
handle number name
B87FEF1C 1 anonymous block
进而:
select SQL_FULLTEXT from V$SQL where CHILD_ADDRESS = 'B87FEF1C'
存储过程源代码可从
ALL_SOURCE
获得.唯一不好的例子是单线。但这是一种罕见的情况。
procedure outer is procedure inner is begin whoami; end; begin whoami; end;
您有信息
whoami
在这条线上被调用。但你不知道这是第一次出现还是第二次出现。因此,即使解析源代码也无法引导您找到确切的解决方案。其他情况可以通过解析源码来处理。 Here是我的尝试。示例用法:
create package APCKG is
procedure PROC;
end;
/
create package body APCKG is
procedure PROC is
procedure "INNER/proc" is
begin
dbms_output.put_line( p_stack.whoAmI );
end;
begin
"INNER/proc";
end;
end;
/
begin
APCKG.PROC;
end;
输出:
5: YOUR_SCHEMA.PACKAGE BODY APCKG.PROCEDURE PROC.PROCEDURE "INNER/proc"
输出格式:
Line number + ': ' + Owner + [ '.' + Type + ' ' + Name ]*
所以它只返回最后一个调用者及其层次结构。一个过程在另一个过程中,而另一个过程在位于包体中的函数内。
使用
utl_call_stack
如果您需要精确的解决方案并拥有 Oracle 12。此解决方案适用于以前的版本(在 10.2 上测试)。它将返回上面单行示例的第一次出现。更新:
我已将此解决方案升级为用于调用堆栈控制的完整包。
好处:
utl_call_stack
的方法. whoAmI
和 whoCalledMe
. q
- 字符串的符号。 Source code .
UPD 2:
UPD 3:
utl_call_stack
对于版本 9, 10 and 11 . 关于oracle - PL/SQL Who am I 函数类似于 T-SQL 的 OBJECT_NAME(@@PROCID),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29081031/