http://tkyte.blogspot.jp/2013/06/12c-utlcallstack.html
来る数ヶ月にわたって、Oracle Database 12cの小さいけれどクールな新機能について執筆することになるでしょう。おそらくOracle.comのフロントページにはならないと思います。新しいパッケージ、UTL_CALL_STACKについて始めましょう。
Oracle® Database PL/SQL Packages and Types Reference 12c Release 1 (12.1)以前、開発者は次の3個のファンクションにアクセスして「いったいコードのどこにいるんだ?」と実行中のコードの場所を把握していました。
UTL_CALL_STACK
http://docs.oracle.com/cd/E16655_01/appdev.121/e17602/u_call_stack.htm#ARPLS74078
- dbms_utility.format_call_stack
http://docs.oracle.com/cd/E16655_01/appdev.121/e17602/d_util.htm#i997163 - dbms_utility.format_error_backtrace
http://docs.oracle.com/cd/E16655_01/appdev.121/e17602/d_util.htm#i1003874 - dbms_utility.format_error_stack
http://docs.oracle.com/cd/E16655_01/appdev.121/e17602/d_util.htm#i1002463
さて、ネストされたファンクションと重複したファンクション名を持つパッケージがある場合…ops$tkyte%ORA12CR1> create or replace 2 procedure Print_Call_Stack 3 is 4 begin 5 DBMS_Output.Put_Line(DBMS_Utility.Format_Call_Stack()); 6 end; 7 / Procedure created.
PKG.Pプロシージャを実行すると、結果は以下のようになるでしょう。ops$tkyte%ORA12CR1> create or replace 2 package body Pkg is 3 procedure p 4 is 5 procedure q 6 is 7 procedure r 8 is 9 procedure p is 10 begin 11 Print_Call_Stack(); 12 raise program_error; 13 end p; 14 begin 15 p(); 16 end r; 17 begin 18 r(); 19 end q; 20 begin 21 q(); 22 end p; 23 end Pkg; 24 / Package body created.
赤の部分はformat_call_stackからの出力で、黒の部分はクライアントアプリケーションからのエラーメッセージです(format_error_backtraceというAPIを呼び出しても得られるでしょう)。おわかりのように、有用な情報が含まれていますが、利用するためには構文解析が必要で、思っているよりもトリッキーな可能性があります。これらの文字列の形式は固定ではなく、長年にわたって変化してきました(私は"who_am_i"、 "who_called_me"ファンクションを書きましたが、これらの文字列を構文解析することによって実現しました。信じて下さい、時間と共に変化するのです!)。ops$tkyte%ORA12CR1> exec pkg.p----- PL/SQL Call Stack -----
object line object
handle number name
0x6e891528 4 procedure OPS$TKYTE.PRINT_CALL_STACK
0x6ec4a7c0 10 package body OPS$TKYTE.PKG
0x6ec4a7c0 14 package body OPS$TKYTE.PKG
0x6ec4a7c0 17 package body OPS$TKYTE.PKG
0x6ec4a7c0 20 package body OPS$TKYTE.PKG
0x76439070 1 anonymous block
BEGIN pkg.p; END;
*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "OPS$TKYTE.PKG", line 11
ORA-06512: at "OPS$TKYTE.PKG", line 14
ORA-06512: at "OPS$TKYTE.PKG", line 17
ORA-06512: at "OPS$TKYTE.PKG", line 20
ORA-06512: at line 1
12cからは、コールスタックや一連のAPIコールへのアクセスが構造化され、この構造を問い合わせるようになりました。以下のようにprint_call_stackファンクションを書き換えてみましょう。
ここで、コードのどの「位置(深さ)」にいるのか(utl_call_stack.dynamic_depth)がわかるので、ループを使ってスタックを上っていくことができます。lexical_depthと、実行していたユニット内の行番号に加えて、ユニット名も出力します。そして、任意のユニット名だけではなく、完全修飾されたユニット名で、パッケージ内のサブプログラム名を辿ることができます。しかし、それだけではなく、サブプログラム名の中のサブプログラム名の中のサブプログラム名も辿ることができます。例えば - 再びPKG.Pプロシージャを実行すると、その結果は以下のようになります。ops$tkyte%ORA12CR1> create or replace 2 procedure Print_Call_Stack 3 as 4 Depth pls_integer := UTL_Call_Stack.Dynamic_Depth(); 5 6 procedure headers 7 is 8 begin 9 dbms_output.put_line( 'Lexical Depth Line Name' ); 10 dbms_output.put_line( 'Depth Number ' ); 11 dbms_output.put_line( '------- ----- ---- ----' ); 12 end headers; 13 procedure print 14 is 15 begin 16 headers; 17 for j in reverse 1..Depth loop 18 DBMS_Output.Put_Line( 19 rpad( utl_call_stack.lexical_depth(j), 10 ) || 20 rpad( j, 7) || 21 rpad( To_Char(UTL_Call_Stack.Unit_Line(j), '99'), 9 ) || 22 UTL_Call_Stack.Concatenate_Subprogram 23 (UTL_Call_Stack.Subprogram(j))); 24 end loop; 25 end; 26 begin 27 print; 28 end; 29 /
今度は、以前format_call_stackを使って出力した行番号とパッケージ名よりも多くの情報を得ています。行番号とパッケージ(ユニット)名(サブプログラムの名前)を得るだけでなく、PがQを呼び、QがRを呼び、RがPを呼ぶというようなネストされたサブプログラムを把握することができます。また、我々は字句の深さを持つ、「本物の」呼び出しレベルを確認できること、パッケージからprint_call_stackにステップアウトし、順番に別のネストされたサブプログラムを呼び出していることが確認できることにご注目下さい。ops$tkyte%ORA12CR1> exec pkg.p
Lexical Depth Line Name
Depth Number
------- ----- ---- ----
1 6 20 PKG.P
2 5 17 PKG.P.Q
3 4 14 PKG.P.Q.R
4 3 10 PKG.P.Q.R.P
0 2 26 PRINT_CALL_STACK
1 1 17 PRINT_CALL_STACK.PRINT
BEGIN pkg.p; END; * ERROR at line 1: ORA-06501: PL/SQL: program error ORA-06512: at "OPS$TKYTE.PKG", line 11 ORA-06512: at "OPS$TKYTE.PKG", line 14 ORA-06512: at "OPS$TKYTE.PKG", line 17 ORA-06512: at "OPS$TKYTE.PKG", line 20 ORA-06512: at line 1
この新しいパッケージはみなさんのエラーロギングパッケージへのすばらしい追加機能になるでしょう。もちろん、所有者名、コード実行時に効力のあるエディションなどを入手するためのその他のファンクションも含まれています。詳細情報はPL/SQL Packages and Types ReferenceのUTL_CALL_STACKの項をご覧下さい。
Oracle® Database PL/SQL Packages and Types Reference 12c Release 1 (12.1)
UTL_CALL_STACK
http://docs.oracle.com/cd/E16655_01/appdev.121/e17602/u_call_stack.htm#ARPLS74078
0 件のコメント:
コメントを投稿