8 MLE JavaScriptモジュールの実行後のデバッグ

コードを簡単にデバッグできる機能は、優れた開発者エクスペリエンスにとって重要です。MLEには、標準の出力デバッグに加えて、JavaScriptソース・コードに対して実行後のデバッグを行うオプションが用意されています。

実行後のデバッグでは、プログラムの実行中にランタイム状態を効率的に収集できます。コードの実行が完了したら、収集されたデータを使用してプログラムの動作を分析し、注意が必要なバグを検出できます。実行後のデバッグを行うには、収集されるデバッグ情報を識別するデバッグ仕様を指定します。デバッグ仕様はデバッグポイントのコレクションであり、それぞれが、ソース・コードのどこでどのようなデバッグ情報を収集するかを指定します。デバッグポイントは、条件付きまたは条件なしにできます。

ノート:

実行後のデバッグは、MLEモジュールとしてデプロイされたJavaScriptコードにのみ適用できます。現在このデバッグ機能は、動的実行を介してコードをデプロイしている場合には使用できません。

ノート:

MLE JavaScriptドライバやMLEバインドなどのMLE組込みモジュールは、実行後のデバッグではデバッグできません。組込みモジュールをデバッグしようとすると、ORA-04162エラーが発生します。

MLE組込みモジュールの詳細は、サーバー側JavaScript APIのドキュメントを参照してください。

モジュールのデバッグポイントは、動的なMLEソースからか別のMLEモジュールからかに関係なく、MLEコール仕様を介した実行やモジュール・インポートを介した実行など、モジュール・コードのすべての実行に適用されます。いったん有効にすると、デバッグ仕様は、無効にするか、新しいデバッグ仕様に置き換えるか、またはセッションが終了するまでアクティブのままになります。

トピック

デバッグポイントの指定

デバッグポイントは、データベース文字セットでエンコードされたJSONドキュメントを使用して指定します。

各デバッグポイントには次の要素が含まれます:
  • 情報が収集されるソース・コード内の場所

  • 収集する情報を説明するアクション

  • デバッグ情報を収集するタイミングを制御するオプションの条件

例8-1 デバッグポイントを指定するJSONテンプレート

{
at: <location-spec>,
action: [ <action-spec>, ... ],
[ condition: <condition-spec> ]
}

デバッグポイントの場所

デバッグポイントの場所は、デバッグするアプリケーションのソース・コードの行番号で指定します。

デバッグするMLEモジュールの名前は、nameフィールドで指定し、デバッグ情報が収集されるモジュール内の場所は、lineフィールドで指定します。例8-4に、サンプル値を含むJSONドキュメントの例を示します。

デバッグポイントのアクション

MLE実行後のデバッグでは、watchsnapshotの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)。depth1として指定されている場合、トラバースは最初のレベルで終了し、次の結果が生成されます。

x = {
"a": {
    "<unreachable>": true
};
"b": 3.14
}

framesLimitフィールドでは、記録するスタック・フレームの数を制御できます。デフォルトでは、すべてのスタック・フレームが記録されます。framesLimitsnapshotにのみ適用されます。たとえば、a()b()をコールし、b()c()をコールするコール階層について考えてみます。c()でスナップショットを取得すると、framesLimit=1では最下部のスタック・フレーム(この場合はc())のみが取得され、framesLimit=2では下部の2つ(この場合はc()およびb())が取得されるというようになります。

例8-2 ウォッチ・アクションを指定するためのJSONテンプレート

変数をウォッチするには、typewatchに設定する必要があります。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>] }
]

デバッグポイントの条件

watchsnapshotの両方を、conditionフィールドに指定した条件で制御できます。

式は、アプリケーションのコンテキストの、デバッグポイントで指定した場所で評価され、式の評価がtrueである場合にのみ、関連するアクションがトリガーされます。

conditionフィールドに含めることができる式のタイプに制限はありません。式を評価しても、デバッグ対象のプログラムの動作が変更されないようにする必要があります。

例8-4 MLEモジュール内の変数のウォッチ

次のコードでは、モジュールmyModule1のデバッグポイントと2つの関連アクションを指定しています。ロギングの深度が3に制限された変数xwatchアクションと、ロギングの深度に制限のない変数ywatchアクションです。デバッグポイントには、条件(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コードのランタイム状態を監視できるようになるため、こうしたことが必要です。

また、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のコードをデバッグできるようにするには、ユーザーWModuleAに対するCOLLECT DEBUG INFO権限も付与する必要があります。

ユーザーWは、次の文を使用して、VModuleAをデバッグする権限を付与できます:

GRANT COLLECT DEBUG INFO ON ModuleA TO V;

COLLECT DEBUG INFO権限は、必要に応じて後で取り消すことができます:

REVOKE COLLECT DEBUG INFO ON ModuleA FROM V;

デバッグ出力の分析

デバッグポイントからの出力は、Javaプロファイラ・ヒープ・ダンプ・バージョン1.0.2形式で格納されます。

実行中にデバッグポイントがヒットするたびに、デバッグ情報はヒープ・ダンプ・セグメントとして保存されます。実行が終了した後に、デバッグ出力を分析するためのオプションとしては、次の2つがあります:
  • dbms_mle.parse_debug_outputファンクションによって取得したデバッグ情報のテキスト表現を使用します。

  • デバッグ出力を含むBLOB sinkhprofファイルにエクスポートし、既存のいくつかの開発者ツールを使用して情報を分析します。

トピック

デバッグ出力のテキスト表現

ファンクション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コードでこれらの例外を捕捉して処理できます。ただし、重要なデータベース・エラーによる例外は捕捉できません。これには、次のものが含まれます:
  • 内部データベース・エラー(ORA-0600)

  • 致命的なデータベース・エラー(ORA-0603)

  • リソース制限を超えたためにトリガーされたエラー(ORA-04036)

  • ユーザー割込み(ORA-01013)

  • システム・エラー(ORA-7445)

捕捉されていないか再署名されたデータベース・エラーによって発生する例外により、MLEランタイム・エラー(ORA-04161)に加えて、元のデータベース・エラーが発生します。このような例外のJavaScriptスタック・トレースは、他のランタイム・エラーと同様にDBMS_MLE.get_error_stack()を使用して取得できます。

JavaScriptからのstdoutおよびstderrへのアクセス

MLEでは、JavaScriptコードから標準出力およびエラー・ストリームに書き込まれたデータにアクセスする機能が提供されます。

これらのストリームは、データベース・セッション内で、データベース・ユーザー、MLEモジュールおよび動的MLEコンテキストごとに個別に制御できます。いずれの場合も、ストリームは次のようにできます:
  • 無効化、

  • DBMS_OUTPUTにリダイレクト、または

  • ユーザーが指定したCLOBにリダイレクト

MLEモジュールのstdoutおよびstderrへのアクセス

DBMS_MLE PL/SQLパッケージには、各MLEモジュール・コンテキストの標準出力およびエラー・ストリームを制御するプロシージャset_stdout()およびset_stderr()が用意されています。

また、ファンクションDBMS_MLE.set_stdout_to_dbms_output()を使用して、stdoutDBMS_OUTPUTにリダイレクトできます。DBMS_MLEパッケージには、stderrをリダイレクトする類似のファンクションDBMS_MLE.set_stderr_to_dbms_output()が用意されています。

stdoutおよびstderrは、それぞれDBMS_MLE.disable_stdout()およびDBMS_MLE.disable_stderr()をコールすることで、いつでもモジュールに対して無効にできます。

デフォルトでは、stdoutおよびstderrDBMS_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_modstdoutを、後で確認可能な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()を使用して、stdoutDBMS_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およびstderrDBMS_OUTPUTにリダイレクトします。

これらのファンクションのいずれかをコールすると、コンテキスト内で実行されているすべての動的MLEコードについて適切なストリームがリダイレクトされます。ただし、MLE SQLドライバを介したMLEファンクションのコールでは、そのファンクションを実装しているMLEモジュールのリダイレクト効果が使用されます。

例8-9 動的MLEstdoutCLOBおよび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!