oracle 包中当前正在执行的过程名称

pxyaymoc  于 2023-04-29  发布在  Oracle
关注(0)|答案(4)|浏览(136)

有没有办法获取包中当前正在执行的过程的名称?

create or replace package test_pkg
as
    procedure proc1;
end test_pkg;

create or replace package body test_pkg
as
    procedure proc1 
    is
        -- // Get the Procedure Name here?? //
    end proc1;
end test_pkg;
ssgvzors

ssgvzors1#

在12c中,当前的子程序名称只是:

utl_call_stack.subprogram(1)(2);

目前的套餐也可以从

utl_call_stack.subprogram(1)(1);

但通常更容易仅使用$$plsql_unit。您也可以获得限定名(package.procedure):

utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(1));

然而,我想不出任何情况下,一个过程或函数(或对象方法)会想要自己的名字。此功能在日志记录过程中最有用,在这种情况下 '谁叫我?' 代码应该在日志记录器中,而不是在调用它的每个事物中重复。因此,我强烈建议避免任何 '我是谁?' 程序中的逻辑。相反,将类似这样的东西放在日志记录器中(需要12个。1或更高版本):

create or replace procedure logdemo
as
    -- This is a package name, standalone function name, standalone procedure name,
    --   or "__anonymous_block".
    k_calling_subprogram1 varchar2(128);
    -- This is a package procedure name or package function name, and it is NULL if
    --   the parent is a standalone function, standalone procedure, or anonymous block.
    k_calling_subprogram2 varchar2(128);
begin
    k_calling_subprogram1 := utl_call_stack.subprogram(2)(1);
    begin
        k_calling_subprogram2 := utl_call_stack.subprogram(2)(2);
    exception when subscript_beyond_count then
        k_calling_subprogram2 := null;
    end;

    dbms_output.put_line
    ( $$plsql_unit ||
      ' called from subprogram1 '||k_calling_subprogram1
      ||', subprogram2 '||k_calling_subprogram2 );
end logdemo;
/

不幸的是,在11g中它有点复杂,因为你必须解析dbms_utility.format_call_stack,并且因为这只给你包名和行号(在换行符分隔的文本字符串中),然后你必须查询all_source来找到子程序名。
我可以张贴一些11g代码,如果你澄清它的用途。在我的11g logger中,我发现根据sqlcode等捕获dbms_utility.format_error_backtracedbms_utility.format_call_stack很有用,所以有一堆特定于日志记录的逻辑,如果你只是想捕获当前过程名,你可能不需要这些逻辑。

bq9c1y66

bq9c1y662#

如果它是一个独立的程序(i.即不是包内的那个),你会很容易得到答案:

SQL> create or replace procedure p_test is
  2  begin
  3    dbms_output.put_line('I am ' || $$plsql_unit);
  4    null;
  5  end;
  6  /

Procedure created.

SQL> exec p_test
I am P_TEST

PL/SQL procedure successfully completed.

SQL>

对于包来说,事情不再那么简单了。上面的选项(使用$$plsql_unit)返回的是包体名称,而不是过程名称:

SQL> create or replace package pkg_test as
  2    procedure p_test_in_pkg;
  3  end;
  4  /

Package created.

SQL> create or replace package body pkg_test as
  2    procedure p_test_in_pkg is
  3    begin
  4      dbms_output.put_line('Packaged procedure whose name is ' || $$plsql_unit);
  5      null;
  6    end;
  7  end;
  8  /

Package body created.

SQL> exec pkg_test.p_test_in_pkg;
Packaged procedure whose name is PKG_TEST     --> should have been "p_test_in_pkg"

PL/SQL procedure successfully completed.

以下功能似乎正在工作。作者是 garbuya,来源是OTN论坛的讨论Efficient WHO_AM_I and WHO_CALLED_ME讨论(2010年)。

create or replace
FUNCTION FN_WHO_AM_I ( p_lvl  NUMBER DEFAULT 0) RETURN VARCHAR2
IS
/***********************************************************************************************
FN_WHO_AM_I returns the full ORACLE name of your object including schema and package names
--
FN_WHO_AM_I(0) - returns the name of your object
FN_WHO_AM_I(1) - returns the name of calling object
FN_WHO_AM_I(2) - returns the name of object, who called calling object
etc., etc., etc.... Up to to he highest level
-------------------------------------------------------------------------------------------------
Copyrigth GARBUYA 2010
*************************************************************************************************/
TYPE str_varr_t   IS VARRAY(2) OF CHAR(1);
TYPE str_table_t  IS TABLE OF VARCHAR2(256);
TYPE num_table_t  IS TABLE OF NUMBER;
v_stack           VARCHAR2(2048) DEFAULT UPPER(dbms_utility.format_call_stack);
v_tmp_1           VARCHAR2(1024);
v_tmp_2           VARCHAR2(1024);
v_pkg_name        VARCHAR2(32);
v_obj_type        VARCHAR2(32);
v_owner           VARCHAR2(32);
v_idx             NUMBER := 0;
v_pos1            NUMBER := 0;
v_pos2            NUMBER := 0;
v_line_nbr        NUMBER := 0;
v_blk_cnt         NUMBER := 0;
v_str_len         NUMBER := 0;
v_bgn_cnt         NUMBER := 0;
v_end_cnt         NUMBER := 0;
it_is_comment     BOOLEAN := FALSE;
it_is_literal     BOOLEAN := FALSE;
v_literal_arr     str_varr_t := str_varr_t ('''', '"');
v_blk_bgn_tbl     str_table_t := str_table_t (' IF '   , ' LOOP '   , ' CASE ', ' BEGIN ');
v_tbl             str_table_t := str_table_t();
v_blk_bgn_len_tbl num_table_t := num_table_t();

BEGIN

   v_stack := SUBSTR(v_stack,INSTR(v_stack,CHR(10),INSTR(v_stack,'FN_WHO_AM_I'))+1)||'ORACLE'; -- skip myself

   FOR v_pos2 in 1 .. p_lvl LOOP  -- advance to the input level
      v_pos1 := INSTR(v_stack, CHR(10));
      v_stack := SUBSTR(v_stack, INSTR(v_stack, CHR(10)) + 1);
   END LOOP;

   v_pos1 := INSTR(v_stack, CHR(10));
   IF v_pos1 = 0 THEN
      RETURN (v_stack);
   END IF;

   v_stack := SUBSTR(v_stack, 1, v_pos1 - 1);  -- get only current level
   v_stack := TRIM(SUBSTR(v_stack, instr(v_stack, ' ')));  -- cut object handle
   v_line_nbr := TO_NUMBER(SUBSTR(v_stack, 1, instr(v_stack, ' ') - 1));  -- get line number
   v_stack := TRIM(SUBSTR(v_stack, instr(v_stack, ' ')));  -- cut line number
   v_pos1 := INSTR(v_stack, ' BODY');
   IF v_pos1  = 0 THEN
      RETURN (v_stack);
   END IF;

   v_pos1 := INSTR(v_stack, ' ', v_pos1 + 2);  -- find end of object type
   v_obj_type := SUBSTR(v_stack, 1, v_pos1 - 1);  -- get object type
   v_stack := TRIM(SUBSTR(v_stack, v_pos1 + 1));  -- get package name
   v_pos1 := INSTR(v_stack, '.');
   v_owner := SUBSTR(v_stack, 1, v_pos1 - 1);  -- get owner
   v_pkg_name  := SUBSTR(v_stack, v_pos1 + 1);  -- get package name
   v_blk_cnt := 0;
   it_is_literal := FALSE;
   --
   FOR v_idx in v_blk_bgn_tbl.FIRST .. v_blk_bgn_tbl.LAST
   LOOP
      v_blk_bgn_len_tbl.EXTEND(1);
      v_blk_bgn_len_tbl (v_blk_bgn_len_tbl.last) := LENGTH(v_blk_bgn_tbl(v_idx));
   END LOOP;
   --
   FOR src
   IN ( SELECT ' '||REPLACE(TRANSLATE(UPPER(text), ';('||CHR(10), '   '),'''''',' ') ||' ' text
        FROM all_source
        where owner = v_owner
        and name    = v_pkg_name
        and type    = v_obj_type
        and line    < v_line_nbr
        ORDER  BY line
      )
   LOOP
      v_stack := src.text;
      IF it_is_comment THEN
         v_pos1 :=  INSTR (v_stack, '*/');
         IF v_pos1 > 0 THEN
            v_stack := SUBSTR (v_stack, v_pos1 + 2);
            it_is_comment := FALSE;
         ELSE
            v_stack := ' ';
         END IF;
      END IF;
      --
      IF v_stack != ' ' THEN
      --
         v_pos1 := INSTR (v_stack, '/*');
         WHILE v_pos1 > 0 LOOP
            v_tmp_1 := SUBSTR (v_stack, 1, v_pos1 - 1);
            v_pos2 := INSTR (v_stack, '*/');
            IF v_pos2 > 0 THEN
               v_tmp_2 := SUBSTR (v_stack, v_pos2 + 2);
               v_stack := v_tmp_1||v_tmp_2;
            ELSE
               v_stack := v_tmp_1;
               it_is_comment := TRUE;
            END IF;
            v_pos1 := INSTR (v_stack, '/*');
         END LOOP;
         --
         IF v_stack != ' ' THEN
            v_pos1 := INSTR (v_stack, '--');
            IF v_pos1 > 0 THEN
               v_stack := SUBSTR (v_stack, 1, v_pos1 - 1);
            END IF;
            --
            IF v_stack != ' ' THEN
               FOR v_idx in v_literal_arr.FIRST .. v_literal_arr.LAST
               LOOP
                  v_pos1 := INSTR (v_stack, v_literal_arr (v_idx) );
                  WHILE v_pos1 > 0  LOOP
                     v_pos2 := INSTR (v_stack, v_literal_arr (v_idx), v_pos1 + 1);
                     IF v_pos2 > 0 THEN
                        v_tmp_1 := SUBSTR (v_stack, 1, v_pos1 - 1);
                        v_tmp_2 := SUBSTR (v_stack, v_pos2 + 1);
                        v_stack := v_tmp_1||v_tmp_2;
                     ELSE
                        IF it_is_literal THEN
                           v_stack := SUBSTR (v_stack, v_pos1 + 1);
                           it_is_literal := FALSE;
                        ELSE
                           v_stack := SUBSTR (v_stack, 1, v_pos1 - 1);
                           it_is_literal := TRUE;
                        END IF;
                     END IF;
                     v_pos1 := INSTR (v_stack, v_literal_arr (v_idx) );
                  END LOOP;
               END LOOP;
               --
               IF v_stack != ' ' THEN
                  WHILE INSTR (v_stack, '  ') > 0
                  LOOP
                     v_stack := REPLACE(v_stack, '  ', ' ');
                  END LOOP;
                  v_stack := REPLACE(v_stack, ' END IF ', ' END ');
                  v_stack := REPLACE(v_stack, ' END LOOP ', ' END ');
                  --
                  IF v_stack != ' ' THEN
                     v_stack := ' '||v_stack;
                     v_pos1 := INSTR(v_stack, ' FUNCTION ') + INSTR(v_stack, ' PROCEDURE ');
                     IF v_pos1 > 0 THEN
                        v_obj_type := TRIM(SUBSTR(v_stack, v_pos1 + 1, 9));  -- get object type
                        v_stack := TRIM(SUBSTR(v_stack, v_pos1 + 10))||'  ';  -- cut object type
                        v_stack := SUBSTR(v_stack, 1,  INSTR(v_stack, ' ') - 1 );  -- get object name
                        v_tbl.EXTEND(1);
                        v_tbl (v_tbl.last) := v_obj_type||' '||v_owner||'.'||v_pkg_name||'.'||v_stack;
                     END IF;
                  --
                     v_pos1 := 0;
                     v_pos2 := 0;
                     v_tmp_1 := v_stack;
                     v_tmp_2 := v_stack;
                     FOR v_idx in v_blk_bgn_tbl.FIRST .. v_blk_bgn_tbl.LAST
                     LOOP
                        v_str_len := NVL(LENGTH(v_tmp_1),0);
                        v_tmp_1 := REPLACE(v_tmp_1,v_blk_bgn_tbl(v_idx), NULL);
                        v_bgn_cnt := NVL(LENGTH(v_tmp_1), 0);
                        v_pos1 := v_pos1 + (v_str_len - v_bgn_cnt)/v_blk_bgn_len_tbl(v_idx);
                        v_str_len := NVL(LENGTH(v_tmp_2),0);
                        v_tmp_2 := REPLACE(v_tmp_2,' END ', NULL);
                        v_end_cnt := NVL(LENGTH(v_tmp_2), 0);
                        v_pos2 := v_pos2 + (v_str_len - v_end_cnt)/5; --- 5 is the length(' END ') 
                     END LOOP;
                     IF v_pos1 > v_pos2 THEN
                        v_blk_cnt := v_blk_cnt + 1;
                     ELSIF v_pos1 < v_pos2 THEN
                        v_blk_cnt := v_blk_cnt - 1;
                        IF v_blk_cnt = 0 AND v_tbl.COUNT > 0 THEN
                           v_tbl.DELETE(v_tbl.last);
                        END IF;
                     END IF;
                  END IF;
               END IF;
            END IF;
         END IF;
      END IF;
   END LOOP;

   RETURN CASE v_tbl.COUNT WHEN 0 THEN 'UNKNOWN' ELSE v_tbl(v_tbl.LAST) END;

END;
/

测试:

SQL> create or replace package body pkg_test as
  2    procedure p_test_in_pkg is
  3    begin
  4      dbms_output.put_line('Packaged procedure, using $$plsql_unit = ' || $$plsql_unit);
  5      dbms_output.put_line('FN_WHO_AM_I = ' || fn_who_am_i);
  6      null;
  7    end;
  8  end;
  9  /

Package body created.

SQL> exec pkg_test.p_test_in_pkg;
Packaged procedure, using $$plsql_unit = PKG_TEST        --> this one is wrong (package body name) ...
FN_WHO_AM_I = PROCEDURE SCOTT.PKG_TEST.P_TEST_IN_PKG     --> ... but this one is OK

PL/SQL procedure successfully completed.

SQL>
jgovgodb

jgovgodb3#

一种方法使用从这里借用的想法:http://www.orafaq.com/forum/t/173023/

注意:这只适用于Oracle 12c。对于11g,它只给出了包名称。

创建一个名为show_caller的过程。这使用了OWA_UTIL.WHO_CALLED_ME过程。

create or replace procedure show_caller
as
   l_owner  varchar2(200);
   l_name   varchar2(200); 
   l_lineno number;
   l_caller varchar2(200);
begin 
   OWA_UTIL.WHO_CALLED_ME (l_owner, l_name,l_lineno,l_caller);
   dbms_output.put_line('Inside '||l_name);

end;
/

现在,你可以把你的包写成:

CREATE OR replace PACKAGE test_pkg 
AS 
  PROCEDURE proc1; 
END test_pkg; 

/ 
CREATE OR replace PACKAGE BODY test_pkg 
AS 
  PROCEDURE Proc1 
  AS 
  BEGIN 
      show_caller;  -- proc1 calls show_caller 
  END proc1; 
END test_pkg; 

/

处决

SET SERVEROUTPUT ON
BEGIN
   Test_pkg.Proc1;
END;
/
Inside TEST_PKG.PROC1

请注意,这将打印过程的名称。如果要将其作为变量使用,则将l_name(如果需要,还可以与其他变量沿着)作为OUT变量从show_caller传递
Live SQL Demo(需要免费OTN帐户)
另一种选择是在过程中使用OWA_UTIL.GET_PROCEDURE函数:但在这种情况下似乎不适合我我很乐意从Maven那里了解更多。

suzh9iv8

suzh9iv84#

我的快速样本:

create or replace package body MyPackage as

    procedure PrintMethodName is
        ThisMethod#FullName varchar2(128) := regexp_substr(
            dbms_utility.format_call_stack, 
            'package\s+body\s+([^[:space:]]+)',
            1,1,'i',1); -- schema.package.method
        ThisMethod#CurrentSchemaName varchar2(128) := regexp_substr(
            regexp_substr(
                dbms_utility.format_call_stack, 
                'package\s+body\s+([^[:space:]]+)',
                1,1,'i',1), 
            '[^.]+[.][^.]+$'); -- package.method
        ThisMethod#MethodName varchar2(128) := regexp_substr(
            regexp_substr(
                dbms_utility.format_call_stack, 
                'package\s+body\s+([^[:space:]]+)',
                1,1,'i',1), 
            '[^.]+$'); -- method
    begin
        dbms_output.put_line(dbms_utility.format_call_stack);
        dbms_output.put_line(ThisMethod#FullName);
        dbms_output.put_line(ThisMethod#CurrentSchemaName);
        dbms_output.put_line(ThisMethod#MethodName);
    end;

end;
/

相关问题