Sử dụng UTL_CALL_STACK hỗ trợ cho DBMS_UTILITY

Từ rất lâu rồi, các “chuyên gia” oracle thường sử dụng package DBMS_UTILITY để lấy stack gọi hiện tại đang được thực thi. Ví dụ như sau:

SQL> create or replace
  2  procedure old_style_call_stack is
  3  begin
  4     dbms_output.put_line(
  5       dbms_utility.format_call_stack
  6       );
  7  end;
  8  /

Procedure created.

SQL> create or replace package pkg
  2  is
  3     procedure main_proc;
  4  end;
  5  /

Package created.

SQL>
SQL> create or replace package body pkg
  2  is
  3    procedure proc_in_pkg is
  4      procedure inline_proc2 is
  5        procedure inline_proc3 is x int;
  6        begin
  7           old_style_call_stack;
  8           
  9        end;
 10      begin
 11        inline_proc3;
 12      end;
 13    begin
 14      inline_proc2;
 15    end;
 16
 17     procedure main_proc is
 18        procedure inline_proc1 is
 19        begin
 20          proc_in_pkg;
 21        end;
 22     begin
 23        inline_proc1;
 24     end;
 25  end;
 26  /

Package body created.

SQL>
SQL> set serverout on
SQL> begin
  2     pkg.main_proc;
  3  end;
  4  /
----- PL/SQL Call Stack -----
  object      line  object
  handle    number  name
0x11e168060         3  procedure MCDONAC.OLD_STYLE_CALL_STACK
0x11e472ac0         7  package body MCDONAC.PKG
0x11e472ac0        11  package body MCDONAC.PKG
0x11e472ac0        14  package body MCDONAC.PKG
0x11e472ac0        20  package body MCDONAC.PKG
0x11e472ac0        23  package body MCDONAC.PKG
0x11e3efb20         2  anonymous block


PL/SQL procedure successfully completed.

Như chúng ta thấy FORMAT_CALL_STACK chỉ trả về một chuỗi đơn giản các row theo stack thực thi. Chúng ta có thể sửa đổi một chút như sau để thấy được chuỗi lệnh trông thực sự như thế nào:

SQL> create or replace
  2  procedure old_style_call_stack is
  3  begin
  4     dbms_output.put_line(
  5       replace(dbms_utility.format_call_stack,chr(10))
  6       );
  7  end;
  8  /

Procedure created.

SQL> create or replace package pkg
  2  is
  3     procedure main_proc;
  4  end;
  5  /

Package created.

SQL>
SQL> create or replace package body pkg
  2  is
  3    procedure proc_in_pkg is
  4      procedure inline_proc2 is
  5        procedure inline_proc3 is x int;
  6        begin
  7           old_style_call_stack;
  8           
  9        end;
 10      begin
 11        inline_proc3;
 12      end;
 13    begin
 14      inline_proc2;
 15    end;
 16
 17     procedure main_proc is
 18        procedure inline_proc1 is
 19        begin
 20          proc_in_pkg;
 21        end;
 22     begin
 23        inline_proc1;
 24     end;
 25  end;
 26  /

Package body created.

SQL>
SQL> set serverout on
SQL> begin
  2     pkg.main_proc;
  3  end;
  4  /
----- PL/SQL Call Stack -----  object      line  object  handle    number  name 0x11e168060         3  procedure MCDONAC.OLD_STYLE_CALL_STACK0x11e472ac0         
7  package body MCDONAC.PKG0x11e472ac0        11  package body MCDONAC.PKG0x11e472ac0        14  package body MCDONAC.PKG0x11e472ac0        20  package 
body MCDONAC.PKG0x11e472ac0        23  package body MCDONAC.PKG0x11e3efb20         2  anonymous block


PL/SQL procedure successfully completed.

Package UTL_CALL_STACK đã cải thiện điều này bằng cách lưu trữ thông tin stack thực thi trong một cấu trúc mảng, và ở mỗi mức chúng ta có thể lấy được các thông tin theo yêu cầu:

SQL> create or replace
  2  procedure better_call_stack is
  3  begin
  4     for i in reverse 1 .. utl_call_stack.dynamic_depth()
  5     loop
  6        dbms_output.put_line(
  7              rpad(utl_call_stack.lexical_depth(i),9)
  8           || rpad(to_char(utl_call_stack.unit_line(i),'99'),8)
  9           || utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(i)));
 10     end loop;
 11  end;
 12  /

Procedure created.

SQL>
SQL> create or replace package pkg
  2  is
  3     procedure main_proc;
  4  end;
  5  /

Package created.

SQL>
SQL> create or replace package body pkg
  2  is
  3    procedure proc_in_pkg is
  4      procedure inline_proc2 is
  5        procedure inline_proc3 is x int;
  6        begin
  7           --old_style_call_stack;
  8           better_call_stack;
  9        end;
 10      begin
 11        inline_proc3;
 12      end;
 13    begin
 14      inline_proc2;
 15    end;
 16
 17     procedure main_proc is
 18        procedure inline_proc1 is
 19        begin
 20          proc_in_pkg;
 21        end;
 22     begin
 23        inline_proc1;
 24     end;
 25  end;
 26  /

Package body created.

SQL>
SQL> set serverout on
SQL> begin
  2     pkg.main_proc;
  3  end;
  4  /
0          2     __anonymous_block
1         23     PKG.MAIN_PROC
2         20     PKG.MAIN_PROC.INLINE_PROC1
1         14     PKG.PROC_IN_PKG
2         11     PKG.PROC_IN_PKG.INLINE_PROC2
3          8     PKG.PROC_IN_PKG.INLINE_PROC2.INLINE_PROC3
0          5     BETTER_CALL_STACK

PL/SQL procedure successfully completed.

Nhưng hiệu quả lớn nhất của UTL_CALL_STACK không chỉ là việc làm rõ ràng hơn cấu trúc dữ liệu. Bạn hãy nhìn vào kết quả bên trên và bạn sẽ thấy một cải tiến quan trọng mà UTL_CALL_STACK cung cấp so với DBMS_UTILITY.

Đối với những package dùng DBMS_UTILITY, có một cách để có thể sử dụng package UTL_CALL_STACK cung cấp thêm các thông tin mong muốn như sau:

SQL> create or replace
  2  procedure old_style_call_stack is
  3  begin
  4     dbms_output.put_line(dbms_utility.format_call_stack);
  5  end;
  6  /

Procedure created.

SQL> create or replace package pkg
  2  is
  3     procedure main_proc;
  4  end;
  5  /

Package created.

SQL>
SQL> create or replace package body pkg
  2  is
  3    procedure proc_in_pkg is
  4      procedure inline_proc2 is
  5        procedure inline_proc3 is x int;
  6        begin
  7           old_style_call_stack;
  8           
  9        end;
 10      begin
 11        inline_proc3;
 12      end;
 13    begin
 14      inline_proc2;
 15    end;
 16
 17     procedure main_proc is
 18        procedure inline_proc1 is
 19        begin
 20          proc_in_pkg;
 21        end;
 22     begin
 23        inline_proc1;
 24     end;
 25  end;
 26  /

Package body created.

SQL>
SQL> set serverout on
SQL> begin
  2     pkg.main_proc;
  3  end;
  4  /
----- PL/SQL Call Stack -----
  object      line  object
  handle    number  name
00007FFE00CFA088         3  procedure MCDONAC.OLD_STYLE_CALL_STACK
00007FFE00ED34E8         7  package body MCDONAC.PKG.PROC_IN_PKG.INLINE_PROC2.INLINE_PROC3
00007FFE00ED34E8        11  package body MCDONAC.PKG.PROC_IN_PKG.INLINE_PROC2
00007FFE00ED34E8        14  package body MCDONAC.PKG.PROC_IN_PKG
00007FFE00ED34E8        20  package body MCDONAC.PKG.MAIN_PROC.INLINE_PROC1
00007FFE00ED34E8        23  package body MCDONAC.PKG.MAIN_PROC
00007FFE00D12C88         2  anonymous block


PL/SQL procedure successfully completed.