MLEでのエラー処理
MLEのJavaScriptコードの実行中に発生したエラーは、データベース・エラーとして報告されます。
発生するデータベース・エラーは、発生したエラーのタイプによって異なります。たとえば、構文エラーではORA-04160
が発生し、実行時エラー(捕捉されない例外など)ではORA-04161
が発生します。各データベース・エラーのエラー・メッセージには、発生したエラーの簡単な説明が表示されます。また、DBMS_MLE
PL/SQLパッケージには、動的MLE実行コンテキストまたは現在のセッションのMLEモジュールで発生した最後のエラーについて、MLE JavaScriptスタック・トレースを問い合せるプロシージャが用意されています。
DBMS_MLE.get_ctx_error_stack()
をコールすると、DBMS_MLE.eval()
をコールする場合と同じセキュリティ・チェックが行われます。したがって、他のユーザーが作成した動的MLE実行コンテキストで実行しているMLE JavaScriptコードのエラー・スタックは取得できません。
DBMS_MLE
には、MLEモジュールの実行中に発生したアプリケーション・エラーについて、MLE JavaScriptスタック・トレースにアクセスする同様のファンクションDBMS_MLE.get_error_stack()
が用意されています。このファンクションは、モジュール名と、オプションで環境名をパラメータとして使用し、コール仕様の指定された引数に基づいて、最新のアプリケーション・エラーのスタック・トレースを戻します。モジュール名または環境名が有効な識別子でない場合は、ORA-04170
エラーが発生します。
MLEモジュールでは、コール元ユーザーに関連付けられたモジュール・コンテキストのエラー・スタックのみを取得できます。この制限により、エラー・スタックを介してユーザー間で機密情報が漏洩する可能性が回避されます。この制限の当然の結果として、他のユーザーが所有する定義者権限のMLEコール仕様を実行したときに発生したエラーのスタック・トレースは取得できません。
例9-7 ORA-04161
エラーのスローとスタック・トレースの問合せ
次のコードを実行すると、ORA-04161
エラーがスローされます:
CREATE OR REPLACE MLE MODULE catch_and_print_error_stack
LANGUAGE JAVASCRIPT AS
export function f(){
g();
}
function g(){
h();
}
function h(){
throw Error("An error occurred in h()");
}
/
CREATE OR REPLACE PROCEDURE not_getting_entire_error_stack
AS MLE MODULE catch_and_print_error_stack
SIGNATURE 'f()';
/
BEGIN
not_getting_entire_error_stack;
END;
/
結果:
BEGIN
*
ERROR at line 1:
ORA-04161: Error: An error occurred in h()
ORA-04171: at h (USER1.CATCHING_AND_PRINTING_ERROR_STACK:10:11)
ORA-06512: at "USER1.NOT_GETTING_THE_ENTIRE_ERROR_STACK", line 1
ORA-06512: at line 2
*/
プロシージャDBMS_MLE.get_error_stack()
を使用して、このエラーについてスタック・トレースを問い合せることができます:
CREATE OR REPLACE PACKAGE get_entire_error_stack_pkg AS
PROCEDURE get_entire_error_stack;
END get_entire_error_stack_pkg;
/
CREATE OR REPLACE PACKAGE BODY get_entire_error_stack_pkg AS
PROCEDURE print_stack_trace( p_frames IN DBMS_MLE.error_frames_t ) AS
BEGIN
FOR i in 1 .. p_frames.count LOOP
DBMS_OUTPUT.PUT_LINE( p_frames(i).func || '(' ||
p_frames(i).source || ':' || p_frames(i).line || ')');
END LOOP;
END print_stack_trace;
PROCEDURE do_the_work
AS MLE MODULE catch_and_print_error_stack
SIGNATURE 'f()';
PROCEDURE get_entire_error_stack AS
l_frames DBMS_MLE.error_frames_t;
BEGIN
do_the_work;
EXCEPTION
WHEN OTHERS THEN
l_frames := DBMS_MLE.get_error_stack(
'CATCH_AND_PRINT_ERROR_STACK'
);
print_stack_trace(l_frames);
raise;
END;
END get_entire_error_stack_pkg;
/
BEGIN
get_entire_error_stack_pkg.get_entire_error_stack;
END;
/
前述のコードでは、元のエラーを発生させる前に、MLE JavaScript例外スタック・トレースを出力しています:
h(USER1.CATCH_AND_PRINT_ERROR_STACK:10)
g(USER1.CATCH_AND_PRINT_ERROR_STACK:6)
f(USER1.CATCH_AND_PRINT_ERROR_STACK:2)
BEGIN
*
ERROR at line 1:
ORA-04161: Error: An error occurred in h()
ORA-06512: at "USER1.GET_ENTIRE_ERROR_STACK_PKG", line 25
ORA-04171: at h (USER1.CATCH_AND_PRINT_ERROR_STACK:10:11)
ORA-06512: at "USER1.GET_ENTIRE_ERROR_STACK_PKG", line 11
ORA-06512: at "USER1.GET_ENTIRE_ERROR_STACK_PKG", line 18
ORA-06512: at line 2
- コールアウトのエラー
MLE SQLドライバを介したSQLおよびPL/SQLへのコールアウト中に発生したデータベース・エラーは、自動的にJavaScript例外に変換されます。 - JavaScriptからのstdoutおよびstderrへのアクセス
MLEでは、JavaScriptコードから標準出力およびエラー・ストリームに書き込まれたデータにアクセスする機能が提供されます。
親トピック: MLE JavaScriptモジュールの実行後のデバッグ
コールアウトのエラー
MLE SQLドライバを介したSQLおよびPL/SQLへのコールアウト中に発生したデータベース・エラーは、自動的にJavaScript例外に変換されます。
-
内部データベース・エラー(
ORA-0600
) -
致命的なデータベース・エラー(
ORA-0603
) -
リソース制限を超えたためにトリガーされたエラー(
ORA-04036
) -
ユーザー割込み(
ORA-01013
) -
システム・エラー(
ORA-7445
)
捕捉されていないか再署名されたデータベース・エラーによって発生する例外により、MLEランタイム・エラー(ORA-04161
)に加えて、元のデータベース・エラーが発生します。このような例外のJavaScriptスタック・トレースは、他のランタイム・エラーと同様にDBMS_MLE.get_error_stack()
を使用して取得できます。
親トピック: MLEでのエラー処理
JavaScriptからのstdoutおよびstderrへのアクセス
MLEでは、JavaScriptコードから標準出力およびエラー・ストリームに書き込まれたデータにアクセスする機能が提供されます。
-
無効化、
-
DBMS_OUTPUT
にリダイレクト、または -
ユーザーが指定したCLOBにリダイレクト
- MLEモジュールのstdoutおよびstderrへのアクセス
DBMS_MLE
PL/SQLパッケージには、各MLEモジュール・コンテキストの標準出力およびエラー・ストリームを制御するプロシージャset_stdout()
およびset_stderr()
が用意されています。 - 動的MLEのstdoutおよびstderrへのアクセス
プロシージャDBMS_MLE.set_ctx_stdout()
およびDBMS_MLE.set_ctx_stderr()
を使用して、動的MLEコンテキストのstdout
およびstderr
をリダイレクトします。
親トピック: MLEでのエラー処理
MLEモジュールのstdoutおよびstderrへのアクセス
DBMS_MLE
PL/SQLパッケージには、各MLEモジュール・コンテキストの標準出力およびエラー・ストリームを制御するプロシージャset_stdout()
およびset_stderr()
が用意されています。
また、ファンクションDBMS_MLE.set_stdout_to_dbms_output()
を使用して、stdout
をDBMS_OUTPUT
にリダイレクトできます。DBMS_MLE
パッケージには、stderr
をリダイレクトする類似のファンクションDBMS_MLE.set_stderr_to_dbms_output()
が用意されています。
stdout
およびstderr
は、それぞれDBMS_MLE.disable_stdout()
およびDBMS_MLE.disable_stderr()
をコールすることで、いつでもモジュールに対して無効にできます。
デフォルトでは、stdout
およびstderr
はDBMS_OUTPUT
にリダイレクトされます。
指定されたMLEモジュールによってエクスポートされるMLEファンクションのCURRENT_USER
は、ファンクションがコールされたときのCURRENT_USER
、およびファンクションが実行者権限であるか定義者権限であるかによって変化する場合があります。データベース・ユーザー(user1
など)によるDBMS_MLE.set_stdout()
またはDBMS_MLE.set_stderr()
のコールでは、MLEモジュール内のコードがuser1
の権限で実行されたときにのみ、適切なストリームがリダイレクトされます。
つまり、通常、あるデータベース・ユーザーが他のユーザーの代理としてMLEモジュールのコードの実行に関するstdout
およびstderr
の動作を制御することはできません。
これらのプロシージャはすべてモジュール名と、オプションで環境名を第1引数および第2引数として使用します。これにより、出力をリダイレクトする必要がある実行コンテキストが識別されます。環境名を省略すると、ベース環境を使用しているコンテキストが対象になります。また、set_stdout
およびset_stderr
は、ユーザー指定のCLOBを最後の引数として使用し、これにより出力の書込み先が指定されます。
例9-8 MLEモジュールのstdoutのCLOBおよびDBMS_OUTPUTへのリダイレクト
次のJavaScriptモジュールについて考えてみます:
CREATE OR REPLACE MLE MODULE hello_mod
LANGUAGE JAVASCRIPT AS
export function hello() {
console.log('Hello, World from MLE!');
}
/
次のコール仕様により、エクスポートされたファンクションhello()
をPL/SQLコードからのコールに使用できるようになります。
CREATE OR REPLACE PROCEDURE MLE_HELLO_PROC
AS MLE MODULE hello_mod SIGNATURE 'hello';
/
次のコードは、モジュールhello_mod
のstdout
を、後で確認可能なCLOB
にリダイレクトします:
SET SERVEROUTPUT ON;
DECLARE
l_output_buffer CLOB;
BEGIN
-- create a temporary LOB to hold the output
DBMS_LOB.CREATETEMPORARY(l_output_buffer, false);
-- redirect stdout to a CLOB
DBMS_MLE.SET_STDOUT('HELLO_MOD', l_output_buffer);
-- run the code
MLE_HELLO_PROC();
-- retrieve the output buffer
DBMS_OUTPUT.PUT_LINE(l_output_buffer);
END;
/
この実行により、次の出力が生成されます:
Hello, World from MLE!
また、ファンクションDBMS_MLE.SET_STDOUT_TO_DBMS_OUTPUT()
を使用して、stdout
をDBMS_OUTPUT
にリダイレクトできます:
SET SERVEROUTPUT ON;
BEGIN
DBMS_MLE.SET_STDOUT_TO_DBMS_OUTPUT('HELLO_MOD');
MLE_HELLO_PROC();
END;
/
これにより、以前と同じ出力が生成されます:
Hello, World from MLE!
動的MLEのstdoutおよびstderrへのアクセス
プロシージャDBMS_MLE.set_ctx_stdout()
およびDBMS_MLE.set_ctx_stderr()
を使用して、動的MLEコンテキストのstdout
およびstderr
をリダイレクトします。
同様に、DBMS_MLE
パッケージにはプロシージャset_ctx_stdout_to_dbms_output()
およびset_ctx_stderr_to_dbms_output()
が用意されており、動的MLEコンテキストのstdout
およびstderr
をDBMS_OUTPUT
にリダイレクトします。
これらのファンクションのいずれかをコールすると、コンテキスト内で実行されているすべての動的MLEコードについて適切なストリームがリダイレクトされます。ただし、MLE SQLドライバを介したMLEファンクションのコールでは、そのファンクションを実装しているMLEモジュールのリダイレクト効果が使用されます。
例9-9 動的MLEのstdout
のCLOB
およびDBMS_OUTPUT
へのリダイレクト
SET SERVEROUTPUT ON;
DECLARE
l_ctx DBMS_MLE.context_handle_t;
l_snippet CLOB;
l_output_buffer CLOB;
BEGIN
-- allocate the execution context and the output buffer
l_ctx := DBMS_MLE.create_context();
DBMS_LOB.CREATETEMPORARY(l_output_buffer, false);
-- redirect stdout to a CLOB
DBMS_MLE.SET_CTX_STDOUT(l_ctx, l_output_buffer);
-- a bit of JavaScript code printing to the console
l_snippet := 'console.log( "Hello, World from dynamic MLE!" )';
-- execute the code snippet
DBMS_MLE.eval(l_ctx, 'JAVASCRIPT', l_snippet);
-- drop the execution context and print the output
DBMS_MLE.drop_context(l_ctx);
DBMS_OUTPUT.PUT_LINE(l_output_buffer);
END;
/
これによって、次の出力が生成されます。
Hello, World from dynamic MLE!