【问题标题】:Get the calling package/procedure in Oracle在 Oracle 中获取调用包/过程
【发布时间】:2012-05-01 02:46:26
【问题描述】:

我正在 Oracle 10g 中编写一个日志记录过程,它使用以下插入写入表:

INSERT INTO EXEC_LOG VALUES (
  (SELECT SYS_CONTEXT('USERENV','SESSIONID') sessionid FROM dual),
  strPackage, strProcedure, strEventType, strEventLevel, SYSDATE, strMessage
);

此过程在多个不同的包/过程中重复使用,但现在的方式是,程序员必须将其包/过程名称传递给日志记录过程(strPackagestrProcedure)。

我想知道 Oracle 中是否有 av$ 视图或其他东西可以告诉我从哪个包/过程中调用了这个过程,从而消除了程序员传递strPackagestrProcedure 的需要。

示例:

如果我调用这两个程序:

BEGIN
  log_test.testproc1;
  log_test.testproc2;
END;

来自这个包:

CREATE OR REPLACE PACKAGE BODY log_test IS
  PROCEDURE TestProc1 IS
    BEGIN
      write_exec_log( ... );    
    END TestProc1;
  PROCEDURE TestProc2 IS
    BEGIN
      write_exec_log( ... );     
    END TestProc2;  
 END log_test; 

我希望能够从 write_exec_log 方法中评估 log_test/TestProc1log_test/TestProc2

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    从 Oracle 12c 开始,您可以使用内置包 UTL_CALL_STACK (http://docs.oracle.com/database/121/ARPLS/u_call_stack.htm)。

    如果您只对调用过程感兴趣,可以举个简短的例子: DBMS_OUTPUT.PUT_LINE(UTL_Call_Stack.Concatenate_Subprogram(UTL_Call_Stack.Subprogram(2)));

    或者打印完整的调用栈:

    FOR j IN REVERSE 1..UTL_Call_Stack.Dynamic_Depth() LOOP 
      DBMS_OUTPUT.PUT_LINE(UTL_Call_Stack.Concatenate_Subprogram(UTL_Call_Stack.Subprogram(j)));
    END LOOP;
    

    以您的包裹为例:

    CREATE OR REPLACE PACKAGE  log_test IS
     PROCEDURE write_exec_log(msg VARCHAR2);
     PROCEDURE TestProc1;
     PROCEDURE TestProc2;  
     PROCEDURE TestProc3;
    END log_test; 
    /
    
    CREATE OR REPLACE PACKAGE BODY log_test IS
     PROCEDURE write_exec_log(msg VARCHAR2) IS
      BEGIN
       DBMS_OUTPUT.PUT_LINE(msg);
       DBMS_OUTPUT.PUT_LINE('-- ');
       DBMS_OUTPUT.PUT_LINE('calling procedure/function: '
                          ||UTL_Call_Stack.Concatenate_Subprogram(
                                                                  UTL_Call_Stack.Subprogram(2)
                                                                 )
                           );
       DBMS_OUTPUT.PUT_LINE('-- ');
       DBMS_OUTPUT.PUT_LINE('Call Stack');
       FOR j IN REVERSE 1..UTL_Call_Stack.Dynamic_Depth() LOOP
        DBMS_OUTPUT.PUT_LINE(UTL_Call_Stack.Concatenate_Subprogram(
                                                                   UTL_Call_Stack.Subprogram(j)
                                                                  )
                            );
       END LOOP;
      END write_exec_log;
     PROCEDURE TestProc1 IS
      BEGIN
       write_exec_log( 'msg TestProc1' );    
      END TestProc1;
     PROCEDURE TestProc2 IS
      BEGIN
       write_exec_log( 'msg TestProc2' );     
      END TestProc2;  
     PROCEDURE TestProc3 IS
      BEGIN
       TestProc2;
      END TestProc3;  
    END log_test; 
    /
    
    exec log_test.TestProc1
    exec log_test.TestProc2
    exec log_test.TestProc3
    

    (抱歉,在撰写本文时没有 sqlfiddle,没有可用的 12c)

    【讨论】:

      【解决方案2】:

      【讨论】:

      • 这会给我包名,但不是程序名。我在问题中添加了一个示例。调用堆栈包含log_test,但不包含TestProc1
      • 可以从包中获取行号。够近了吗?
      • 不是真的,我也想将它用于性能指标,所以我想知道在调用 write_exec_log 时正在运行什么过程。
      • 为此需要查看每次调用的数据库字典。性能将急剧下降。此外,由于重载,过程/函数名称不明确。也许您可以事后获得过程/函数名称?
      • @AdamHawkes - 如果您将结果缓存在某种后备表中,查询字典可能会以可接受的速度运行,因此只有来自特定位置的第一次调用会支付字典查找惩罚。跨度>
      【解决方案3】:

      Here 是 Oracle 9 的 utl_call_stack 的实现(后向端口)。对于 Oracle 10 and 11

      另一种解决方案(使用p_stack 包):

      dbms_output.put_line( p_stack.getConcatenatedSubprograms( p_stack.whoCalledMe ) );
      

      使用GWu's example,它会输出:

      LOG_TEST.TESTPROC1
      LOG_TEST.TESTPROC2
      LOG_TEST.TESTPROC2
      

      那些只是最后的电话。或者,如果您需要完整的堆栈:

      dbms_output.put_line( p_stack.getCallStack );
      dbms_output.put_line( '' );
      

      这将输出:

      493: YOUR_SCHEMA.PACKAGE BODY P_STACK.FUNCTION GETCALLSTACK.FUNCTION GETCALLSTACK
      4: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE WRITE_EXEC_LOG
      9: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC1
      2: YOUR_SCHEMA.ANONYMOUS BLOCK
      
      493: YOUR_SCHEMA.PACKAGE BODY P_STACK.FUNCTION GETCALLSTACK.FUNCTION GETCALLSTACK
      4: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE WRITE_EXEC_LOG
      13: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC2
      3: YOUR_SCHEMA.ANONYMOUS BLOCK
      
      493: YOUR_SCHEMA.PACKAGE BODY P_STACK.FUNCTION GETCALLSTACK.FUNCTION GETCALLSTACK
      4: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE WRITE_EXEC_LOG
      13: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC2
      17: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC3
      4: YOUR_SCHEMA.ANONYMOUS BLOCK
      

      它适用于从 9 到 12 的 Oracle 版本。

      【讨论】:

        猜你喜欢
        • 2012-08-22
        • 1970-01-01
        • 1970-01-01
        • 2011-02-20
        • 2012-10-13
        • 2011-11-25
        • 2018-03-13
        • 2011-06-12
        • 2012-01-29
        相关资源
        最近更新 更多