oracle - PL/SQL Who am I 函数类似于 T-SQL 的 OBJECT_NAME(@@PROCID)

标签 oracle plsql

在 T-SQL 中,以下命令将返回当前运行的存储过程的名称:

OBJECT_NAME(@@PROCID) 

在 PL/SQL 中,当我将以下代码放在包的存储过程中时,它返回父包的名称而不是正在执行的存储过程。
$$PLSQL_UNIT

有没有办法在 PL/SQL 中获取执行过程的名称?

最佳答案

是的,在 12 之前的版本中这是不可能的。但是您可以尝试一些技巧。

  • V$SESSION查看已PLSQL_ENTRY_SUBPROGRAM_IDPLSQL_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 上测试)。它将返回上面单行示例的第一次出现。

    更新:

    我已将此解决方案升级为用于调用堆栈控制的完整包。
    好处:
  • 在 Oracle 9 ( separate package version )、10 和 11 上测试。
  • 它真正解析源(即词法分析、标记化等)。
  • 纯PL/SQL。
  • 解析匿名块源代码(它们也可以包含内部过程)。
  • 包含类似于 utl_call_stack 的方法.
  • 方法 whoAmIwhoCalledMe .
  • 支持双引号名称。
  • 支持 q - 字符串的符号。
  • 跳过多行和单行注释。
  • 跳过没有定义的过程和函数声明。

  • Source code .

    UPD 2:
  • 添加了对条件编译的支持。

  • UPD 3:
  • 实现了 Oracle 12 包的反向移植 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/

    相关文章:

    oracle - 在 Tomcat 中使用 oracle 设置 JNDI 数据源

    oracle - 查找一列中长度超过 15 个字符的单词

    SQL 按日期复制行到今天

    sql - FORALL 与 FOR 批量更新

    Oracle 内部连接与集合?

    plsql - 字符串范围是正确的,为什么还是得到 PLS-00215 : String length constraints must be in range (1 . .32767)

    java - 错误: ORA-00923: FROM keyword not found where expected (JDBC)

    c# - 带有 Identity 2 和 EntityFramework 6 的 ASP.NET Core MVC(甲骨文)

    java - 来自 Java 的 Oracle 轮询

    sql - 如何始终在 PL/SQL 中的数字上显示两位小数