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_IDPLSQL_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的方法。 方法whoAmIwhoCalledMe。 支持双引号名称。 支持字符串的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 中声明和使用变量?

Oracle 存储过程

类似于 PL/SQL 中的 += 或 .= 的运算符?

在 PL/SQL Oracle 中需要此 T-Sql 函数的等效函数。如果有其他解决方案,那么流水线

如何在 PL/SQL 的 LIKE 子句中使用变量