8 MLE JavaScriptモジュールの実行後のデバッグ
コードを簡単にデバッグできる機能は、優れた開発者エクスペリエンスにとって重要です。MLEには、標準の出力デバッグに加えて、JavaScriptソース・コードに対して実行後のデバッグを行うオプションが用意されています。
実行後のデバッグでは、プログラムの実行中にランタイム状態を効率的に収集できます。コードの実行が完了したら、収集されたデータを使用してプログラムの動作を分析し、注意が必要なバグを検出できます。実行後のデバッグを行うには、収集されるデバッグ情報を識別するデバッグ仕様を指定します。デバッグ仕様はデバッグポイントのコレクションであり、それぞれが、ソース・コードのどこでどのようなデバッグ情報を収集するかを指定します。デバッグポイントは、条件付きまたは条件なしにできます。
ノート:
実行後のデバッグは、MLEモジュールとしてデプロイされたJavaScriptコードにのみ適用できます。現在このデバッグ機能は、動的実行を介してコードをデプロイしている場合には使用できません。ノート:
MLE JavaScriptドライバやMLEバインドなどのMLE組込みモジュールは、実行後のデバッグではデバッグできません。組込みモジュールをデバッグしようとすると、ORA-04162
エラーが発生します。
MLE組込みモジュールの詳細は、サーバー側JavaScript APIのドキュメントを参照してください。
モジュールのデバッグポイントは、動的なMLEソースからか別のMLEモジュールからかに関係なく、MLEコール仕様を介した実行やモジュール・インポートを介した実行など、モジュール・コードのすべての実行に適用されます。いったん有効にすると、デバッグ仕様は、無効にするか、新しいデバッグ仕様に置き換えるか、またはセッションが終了するまでアクティブのままになります。
トピック
- デバッグポイントの指定
デバッグポイントは、データベース文字セットでエンコードされたJSONドキュメントを使用して指定します。 - デバッグポイントの管理
デバッグは、デバッグ仕様を指定してプロシージャdbms_mle.enable_debugging
をコールすることで、セッション内で有効にできます。 - デバッグ出力の分析
デバッグポイントからの出力は、Javaプロファイラ・ヒープ・ダンプ・バージョン1.0.2形式で格納されます。 - MLEでのエラー処理
MLEのJavaScriptコードの実行中に発生したエラーは、データベース・エラーとして報告されます。
デバッグポイントの指定
デバッグポイントは、データベース文字セットでエンコードされたJSONドキュメントを使用して指定します。
-
情報が収集されるソース・コード内の場所
-
収集する情報を説明するアクション
- デバッグ情報を収集するタイミングを制御するオプションの条件
例8-1 デバッグポイントを指定するJSONテンプレート
{
at: <location-spec>,
action: [ <action-spec>, ... ],
[ condition: <condition-spec> ]
}
- デバッグポイントの場所
デバッグポイントの場所は、デバッグするアプリケーションのソース・コードの行番号で指定します。 - デバッグポイントのアクション
MLE実行後のデバッグでは、watch
とsnapshot
の2種類のアクションがサポートされます。 - デバッグポイントの条件
watch
とsnapshot
の両方を、condition
フィールドに指定した条件で制御できます。
親トピック: MLE JavaScriptモジュールの実行後のデバッグ
デバッグポイントの場所
デバッグポイントの場所は、デバッグするアプリケーションのソース・コードの行番号で指定します。
デバッグするMLEモジュールの名前は、name
フィールドで指定し、デバッグ情報が収集されるモジュール内の場所は、line
フィールドで指定します。例8-4に、サンプル値を含むJSONドキュメントの例を示します。
親トピック: デバッグポイントの指定
デバッグポイントのアクション
MLE実行後のデバッグでは、watch
とsnapshot
の2種類のアクションがサポートされます。
watch
アクションを使用すると、id
フィールドに指定された変数の値を記録できます。オプションのdepth
フィールドでは、コンポジット型変数の値を記録する深さを制御できます。
snapshot
アクションは、snapshot
アクションが呼び出された時点のスタック・トレースと、各スタック・フレームのローカル変数の値を記録します。snapshot
では、watch
と比較してより高い実行コストが必要になりますが、より深い情報が得られます。watch
アクションと同様に、オプションのdepth
フィールドを使用して、各変数のロギングの深さを制御できます。snapshot
アクションのdepth
パラメータは、アクションによって取得されるすべての変数に適用されます。
より正確には、depth
パラメータは、変数の値を取得するためにオブジェクト・ツリーをどの程度深くトラバースするかを制御します。たとえば、ネストされたオブジェクトを含む次の変数を考えます。
let x = {
a: {
val: 42
},
b: 3.14
};
depth
フィールドが2
として定義されている場合は、オブジェクト・ツリーがトラバースされ、ネストされたオブジェクトa
の値が取得されます(この場合は42
)。depth
が1
として指定されている場合、トラバースは最初のレベルで終了し、次の結果が生成されます。
x = {
"a": {
"<unreachable>": true
};
"b": 3.14
}
framesLimit
フィールドでは、記録するスタック・フレームの数を制御できます。デフォルトでは、すべてのスタック・フレームが記録されます。framesLimit
はsnapshot
にのみ適用されます。たとえば、a()
がb()
をコールし、b()
がc()
をコールするコール階層について考えてみます。c()
でスナップショットを取得すると、framesLimit=1
では最下部のスタック・フレーム(この場合はc()
)のみが取得され、framesLimit=2
では下部の2つ(この場合はc()
およびb()
)が取得されるというようになります。
例8-2 ウォッチ・アクションを指定するためのJSONテンプレート
変数をウォッチするには、type
をwatch
に設定する必要があります。id
パラメータは、ウォッチする変数を識別するために使用され、文字列または文字列の配列として指定する必要があります。depth
パラメータはオプションで、数値で定義されます。
actions: [
{ type: "watch",
id: <string[]> | <string>,
[depth : <number>] }
]
例8-3 スナップショット・アクションを指定するためのJSONテンプレート
snapshot
アクションを使用するには、type
パラメータをsnapshot
に設定する必要があります。framesLimit
およびdepth
フィールドはオプションで、数値として指定します。
actions: [
{ type: "snapshot",
[framesLimit: <number>],
[depth : <number>] }
]
親トピック: デバッグポイントの指定
デバッグポイントの条件
watch
とsnapshot
の両方を、condition
フィールドに指定した条件で制御できます。
式は、アプリケーションのコンテキストの、デバッグポイントで指定した場所で評価され、式の評価がtrue
である場合にのみ、関連するアクションがトリガーされます。
conditionフィールドに含めることができる式のタイプに制限はありません。式を評価しても、デバッグ対象のプログラムの動作が変更されないようにする必要があります。
例8-4 MLEモジュール内の変数のウォッチ
次のコードでは、モジュールmyModule1
のデバッグポイントと2つの関連アクションを指定しています。ロギングの深度が3
に制限された変数x
のwatch
アクションと、ロギングの深度に制限のない変数y
のwatch
アクションです。デバッグポイントには、条件(x.id>100
)が満たされた場合にのみデバッグポイント・アクションがトリガーされるように、condition
も関連付けられています。
{
at : {
name : "myModule1",
line : 314
},
actions : [
{ type : "watch", id : "x", depth : 3 },
{ type: "watch", id : "y" }
],
condition : 'x.id > 100'
}
親トピック: デバッグポイントの指定
デバッグポイントの管理
デバッグは、デバッグ仕様を指定してプロシージャdbms_mle.enable_debugging
をコールすることで、セッション内で有効にできます。
デバッグ仕様には、debugpoints
フィールドで指定したデバッグポイントの配列に加えて、version
フィールドで指定したバージョン識別子も含まれます。version
フィールドは、値"1.0"
に設定する必要があります。デバッグ仕様には、複数のMLEモジュールのデバッグポイントを含めることができます。
ノート:
デバッグ仕様では、モジュール名は、ディクショナリに格納されているものと同じ大/小文字で指定する必要があります。デフォルトでは、モジュールの作成時に名前が二重引用符で囲まれていないかぎり、モジュール名は大文字で格納されます。
プロシージャdbms_mle.enable_debugging
は、デバッグ出力が書き込まれるBLOB sink
も受け入れます。
dbms_mle.enable_debugging
のコール後、デバッグ仕様に含まれるすべてのデバッグポイントがアクティブになります。いずれかのデバッグポイントがヒットするたびに、関連するデバッグ情報が記録されます。デバッグ情報は、制御がMLEからPL/SQLに最後に戻ったときにBLOB sink
に書き込まれますが、この時点より前に一部または全部を書き込むことができます:
-
動的MLE評価の場合、
dbms_mle.eval
へのコールが戻されたときに、MLEからPL/SQLに制御が渡されます。 -
MLEコール仕様の場合、MLEコール仕様へのコールが戻されたときに、MLEからPL/SQLに制御が渡されます。
設定されたデバッグポイントは、MLEコードを実行するユーザーの権限に関係なく、MLEモジュールのすべての実行でアクティブになります。
同じセッションで再度dbms_mle.enable_debugging
をコールすると、既存のデバッグポイントのセットが置き換えられます。デバッグポイントは、セッションが終了するまでまたはユーザーがdbms_mle.disable_debugging
をコールして明示的にデバッグを無効にするまで、アクティブのままになります。
例8-5 MLEモジュールのデバッグの有効化
この例のデバッグ仕様では、例5-4の最初に作成されたモジュールcount_module
および例5-6で作成されたモジュールin_out_example_mod
を参照します。
DECLARE
debugspec json;
sink blob;
BEGIN
debugspec:= json('
{
"version": "1.0",
"debugpoints": [
{
"at": {
"name": "COUNT_MODULE",
"line": 7
},
"actions": [
{ "type": "watch", id: "myCounter", depth: 1 }
],
"condition": "myCounter > 0"
},
{
"at": {
"name": "IN_OUT_EXAMPLE_MOD",
"line": 16
},
"actions": [
{ "type": "snapshot" }
],
}
]
}
');
dbms_lob.createtemporary(sink, false);
dbms_mle.enable_debugging(debugspec, sink);
--run application to debug
END;
/
- デバッグのセキュリティに関する考慮事項
ユーザーは、デバッグ対象のMLEモジュールを所有しているかデバッグ権限を持っている必要があります。デバッグ機能によってMLEコードのランタイム状態を監視できるようになるため、こうしたことが必要です。 - MLEモジュールのCOLLECT DEBUG INFO権限
MLEモジュールのCOLLECT DEBUG INFO
オブジェクト権限は、モジュールを所有していないがEXECUTE
権限を持つユーザーが、そのモジュールでデバッグを実行できるかどうかを制御します。
親トピック: MLE JavaScriptモジュールの実行後のデバッグ
デバッグのセキュリティに関する考慮事項
ユーザーは、デバッグ対象のMLEモジュールを所有しているかデバッグ権限を持っている必要があります。デバッグ機能によってMLEコードのランタイム状態を監視できるようになるため、こうしたことが必要です。
condition
フィールドを使用すると任意のコードを実行できるため、デバッグするコードの実行時の動作を変更するためにこれを使用できる可能性があります。具体的には、次の場合に、MLEモジュールに対して実行後のデバッグを使用できます。
-
MLEモジュールを所有している、または
-
MLEモジュールに対する
COLLECT DEBUG INFO
オブジェクト権限がある。
1つ以上のアクティブなデバッグポイントを含むMLEモジュールのコードが実行されるたびに、権限がチェックされます。必要な権限がない状態でデバッグポイントを設定しようとすると、ORA-04164
エラーが発生します。
ORA-04164
が検出された場合、次のいずれかを実行します
-
デバッグポイントを設定したユーザーに、対象のモジュールに対する
COLLECT DEBUG INFO
権限を付与する必要があるか、または -
そのセッションでモジュール内のコードの実行を続行するには、モジュールのデバッグポイントを無効にする必要があります。
親トピック: デバッグポイントの管理
MLEモジュールのCOLLECT DEBUG INFO権限
MLEモジュールのCOLLECT DEBUG INFO
オブジェクト権限は、モジュールを所有していないがEXECUTE
権限を持つユーザーが、そのモジュールでデバッグを実行できるかどうかを制御します。
たとえば、ユーザーW
が所有するMLEモジュールModuleA
について考えてみます。ユーザーW
は、ModuleA
のファンクションに対する実行者権限のコール仕様を作成し、ユーザーV
に対してこのコール仕様のEXECUTE
を付与します。ユーザーV
がこのコール仕様をコールしたときにModuleA
のコードをデバッグできるようにするには、ユーザーW
がModuleA
に対するCOLLECT DEBUG INFO
権限も付与する必要があります。
ユーザーW
は、次の文を使用して、V
にModuleA
をデバッグする権限を付与できます:
GRANT COLLECT DEBUG INFO ON ModuleA TO V;
COLLECT DEBUG INFO
権限は、必要に応じて後で取り消すことができます:
REVOKE COLLECT DEBUG INFO ON ModuleA FROM V;
親トピック: デバッグポイントの管理
デバッグ出力の分析
デバッグポイントからの出力は、Javaプロファイラ・ヒープ・ダンプ・バージョン1.0.2形式で格納されます。
-
dbms_mle.parse_debug_output
ファンクションによって取得したデバッグ情報のテキスト表現を使用します。 -
デバッグ出力を含む
BLOB sink
をhprof
ファイルにエクスポートし、既存のいくつかの開発者ツールを使用して情報を分析します。
トピック
- デバッグ出力のテキスト表現
ファンクションdbms_mle.parse_debug_output
は、ヒープ・ダンプ形式のデバッグ情報を含むBLOB
を入力として使用し、デバッグ情報のJSON表現を戻します。 - 開発者ツールを使用したデバッグ出力の分析
デバッグ出力のテキスト表現を分析するかわりに、JDeveloper、NetBeans、Oracle Database Actionsなどのツールを利用することもできます。
親トピック: MLE JavaScriptモジュールの実行後のデバッグ
デバッグ出力のテキスト表現
ファンクションdbms_mle.parse_debug_output
は、ヒープ・ダンプ形式のデバッグ情報を含むBLOB
を入力として使用し、デバッグ情報のJSON表現を戻します。
dbms_mle.parse_debug_output
の出力は、DebugPointData
オブジェクトの配列です。DebugPointData
は、デバッグポイントがヒットするたびに記録されるデバッグ情報を表し、Frame
オブジェクトの配列で構成されます。各Frame
には、情報が収集されたソース・コードの場所(at
フィールド)と、その場所で記録されたローカル変数の名前および値(values
フィールド)が含まれます。Frame.values
のキーは記録された変数の名前であり、値はそれらの変数の値であることに注意してください。
例8-6に、サンプルのJavaScriptプログラムでデバッグポイントを指定した後、ファンクションdbms_mle.parse_debug_output
を使用してデバッグ出力のテキスト表現を生成する方法を示します。
例8-6 デバッグ出力のテキスト表現の取得
この例の後半で示すデバッグは、モジュールfibunacci_module
で定義されたJavaScriptファンクションfib
に対して実行されます:
CREATE OR REPLACE MLE MODULE fibunacci_module
LANGUAGE JAVASCRIPT AS
export function fib( n ) {
if (n < 0) {
throw Error("must provide a positive number to fib()");
}
if (n < 2) {
return n;
} else {
return fib(n-1) + fib(n-2);
}
}
/
CREATE OR REPLACE FUNCTION fib( p_value number)
RETURN NUMBER
AS MLE MODULE fibunacci_module
SIGNATURE 'fib(number)';
/
デバッグポイントは行9に配置され、DBMS_MLE.PARSE_DEBUG_OUTPUT
ファンクションを使用してデバッグ情報を表示します:
SET SERVEROUTPUT ON;
DECLARE
l_debugspec JSON;
l_debugsink BLOB;
l_debuginfo JSON;
l_value NUMBER;
BEGIN
l_debugspec := JSON ('
{
version : "1.0",
debugpoints : [
{
at : {
name : "FIBUNACCI_MODULE",
line : 9
},
actions : [
{ type : "watch", id : "n" }
],
},
]
}
');
-- create a temporary lob to store the raw
-- debug output
DBMS_LOB.CREATETEMPORARY( l_debugsink, false );
DBMS_MLE.ENABLE_DEBUGGING( l_debugspec, l_debugsink );
-- run the application code
l_value := fib(4);
DBMS_MLE.DISABLE_DEBUGGING;
-- retrieve a textual representation of the debug
-- output
l_debuginfo := DBMS_MLE.PARSE_DEBUG_OUTPUT( l_debugsink );
DBMS_OUTPUT.PUT_LINE(
json_serialize(l_debuginfo pretty)
);
END;
/
結果:
[
[
{
"at": {
"name": "USER1.FIBUNACCI_MODULE",
"line": 9
},
"values": {
"n": 4
}
}
],
[
{
"at": {
"name": "USER1.FIBUNACCI_MODULE",
"line": 9
},
"values": {
"n": 3
}
}
],
[
{
"at": {
"name": "USER1.FIBUNACCI_MODULE",
"line": 9
},
"values": {
"n": 2
}
}
],
[
{
"at": {
"name": "USER1.FIBUNACCI_MODULE",
"line": 9
},
"values": {
"n": 2
}
}
]
]
親トピック: デバッグ出力の分析
開発者ツールを使用したデバッグ出力の分析
デバッグ出力のテキスト表現を分析するかわりに、JDeveloper、NetBeans、Oracle Database Actionsなどのツールを利用することもできます。
実行が終了したら、選択したツールを使用してローカル変数の値を検査したり、各時点での変数のグラフを検査できます。
必要に応じて、新しいツールとの統合(Chrome開発ツールなど)を開発し、MLEのユース・ケースに特化したUIを設計できます。
ノート:
Oracle Database Actionsでは、Oracle Databaseリリース23c、バージョン23.1.2以降、MLE実行後のデバッグがサポートされています。
関連項目:
MLEでのデータベース・アクションの使用の詳細は、Oracle SQL Developer Webの使用を参照してください
親トピック: デバッグ出力の分析
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コール仕様を実行したときに発生したエラーのスタック・トレースは取得できません。
例8-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を最後の引数として使用し、これにより出力の書込み先が指定されます。
例8-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モジュールのリダイレクト効果が使用されます。
例8-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!