PL/SQL 我是谁功能类似于 T-SQL 的 OBJECT_NAME(@@PROCID)
Posted
技术标签:
【中文标题】PL/SQL 我是谁功能类似于 T-SQL 的 OBJECT_NAME(@@PROCID)【英文标题】:PL/SQL Who am I function similar to T-SQL's OBJECT_NAME(@@PROCID) 【发布时间】:2015-03-16 15:43:46 【问题描述】:在 T-SQL 中,以下命令将返回当前运行的存储过程的名称:
OBJECT_NAME(@@PROCID)
在 PL/SQL 中,当我将以下代码放在包的存储过程中时,它返回父包的名称,而不是正在执行的存储过程。
$$PLSQL_UNIT
有没有办法在PL/SQL中获取执行过程的名称?
【问题讨论】:
Oracle 的哪个版本?您也许可以在 12c 中使用 utl_callstack 做一些事情;否则不是真的,除非你有包源代码并想从行号中找出你在哪里...... Oracle Database 11g Enterprise Edition 11.2.0.3.0 64bit Production,但很快我们将使用 12c 你见过***.com/questions/286549/…吗? @ChaaD,我已经更新了我的答案。有一个调用堆栈控制包。您可以通过调用dbms_output.put_line( p_stack.getSubprogram( p_stack.whoAmI ) );
轻松获取当前过程名称。
【参考方案1】:
是的,在 12 之前的版本中是不可能的。但是您可以尝试一些技巧。
V$SESSION
视图有 PLSQL_ENTRY_SUBPROGRAM_ID
和 PLSQL_SUBPROGRAM_ID
字段,可以引导您进入当前正在执行的过程。
当前会话是:
select PLSQL_ENTRY_OBJECT_ID,
PLSQL_ENTRY_SUBPROGRAM_ID,
PLSQL_OBJECT_ID,
PLSQL_SUBPROGRAM_ID
from V$SESSION
where AUDSID = sys_context( 'userenv', 'sessionid' )
然后通过查询一个视图ALL_PROCEDURES
找到一个过程名:
select PROCEDURE_NAME
from ALL_PROCEDURES
where OBJECT_ID = :objectId
and SUBPROGRAM_ID = :subprogramId
此视图包含在包中声明的函数和过程,但不包含在包主体中声明的函数和过程。
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 ]*
所以它只返回最后一个调用者及其层次结构。一个过程在另一个过程中,在位于包体中的函数内部。
如果您需要精确的解决方案并拥有 Oracle 12,请使用 utl_call_stack
。此解决方案适用于以前的版本(在 10.2 上测试)。它将返回上面单行示例的第一次出现。
UPD:
我已将此解决方案升级为用于调用堆栈控制的完整包。 好处:
在 Oracle 9 (separate package version)、10 和 11 上测试。 它确实解析源代码(即词法分析、标记化等)。 纯 PL/SQL。 解析匿名块源代码(它们也可以包含内部过程)。 包含类似于utl_call_stack
的方法。
方法whoAmI
和whoCalledMe
。
支持双引号名称。
支持字符串的q
-notation。
跳过多行和单行 cmets。
跳过没有定义的过程和函数声明。
Source code.
UPD 2:
添加了对条件编译的支持。UPD 3:
为版本 9, 10 and 11 实现了 Oracle 12 软件包utl_call_stack
的反向移植。
【讨论】:
【参考方案2】:只需在 DECLARE 部分定义一个带有过程名称的常量
whoami CONSTANT VARCHAR2(100) := 'MY_PROCEDURE';
【讨论】:
当您投反对票时,请发表评论;顺便提一句。这个解决方案比调用函数有更好的性能;我们已经使用了 Oracle 6 中的这个解决方案 ...以上是关于PL/SQL 我是谁功能类似于 T-SQL 的 OBJECT_NAME(@@PROCID)的主要内容,如果未能解决你的问题,请参考以下文章
SQL 非过程性语言 T-SQL PL/SQL 过程性语言;区别是啥?
如何像在 T-SQL 中一样在 PL/SQL 中声明和使用变量?