Oracle Database 23aiで追加されたMLE JavaScript Post-Execution Debuggingを試してみた

Oracle Database 23aiではMultilingual Engine(以下MLE)のJavaScriptに関する機能が大幅に強化されています。
今回はその中でもPost-Execution Debuggingと呼ばれるデバッグ機能について検証してみました。
こちらはMLE Moduleを実行した後に、JavaScriptコードの指定した箇所の状態を出力し、想定した結果になっているか確認できる機能です。
なおMLE JavaScriptの基本については以下の記事をご参照ください。
[Oracle Database 23aiで追加されたMLE JavaScriptの基本的な使い方紹介](https://qiita.com/ssfujita/items/5651d35ebbf0d27e6dc1)

## 事前準備

必要な権限を付与しておきます。
詳細は上述した別記事をご参照ください。
特にPost-Execution Debuggingの利用には以下の権限が必要です。

```sql
GRANT COLLECT DEBUG INFO ON <module> TO <ユーザ名>;
```

デバッグ対象のMLE Moduleを作成します。
以下はフィボナッチ数列を計算するJavaScriptファンクションです。

```sql
CREATE OR REPLACE MLE MODULE fib_mod LANGUAGE JAVASCRIPT AS

export function fib( n ) {
    if ( n == 0 || n == 1) return n;
    let n1 = { value : fib( n - 1 ), id : 'n1' };
    let n2 = { value : fib( n - 2 ), id : 'n2' };
    return n1.value + n2.value;
}
/
```

実行するためにMLE Module Callも作っておきます。

```sql
CREATE OR REPLACE PROCEDURE fib_proc(n number)
AS MLE MODULE fib_mod
SIGNATURE 'fib';
/
```

## Post-Execution Debuggingの実行

本題のデバッグ機能を使ってみます。
実行時の大まかな流れは次の通りです。

+ JSONフォーマットでデバッグ時の設定を記載
+ デバッグ機能を有効化
+ デバッグ対象MLE Moduleを実行
+ デバッグ結果を出力

詳細は下記マニュアルもご参照ください。
[Post-Execution Debugging of MLE JavaScript Modules](https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/post-execution-debugging.html#GUID-100D0D45-205A-44C7-BEF6-2A3241F41BF4)

コードは以下のようになります。

```sql
SET SERVEROUTPUT ON
DECLARE
    debugspec JSON;
    debugsink BLOB;
    debugtxt JSON;
BEGIN
    -- デバッグ設定をJSONフォーマットで記載
    debugspec := JSON (q'~
   {
        version : "1.0",
        debugpoints : [
            {
                at : {
                    name : "FIB_MOD",
                    line : 5
                },
                actions : [
                    { type : "snapshot"},
                ],
            },
        ]
    } 
    ~');
    -- デバッグ機能を有効化
    DBMS_LOB.CREATETEMPORARY(debugsink, TRUE);
    DBMS_MLE.ENABLE_DEBUGGING(debugspec, debugsink);
    -- デバッグ対象MLE Moduleを実行
    fib_proc(3);
    -- デバッグ結果を出力
    debugtxt := DBMS_MLE.PARSE_DEBUG_OUTPUT(debugsink);
    DBMS_OUTPUT.PUT_LINE( JSON_SERIALIZE(debugtxt PRETTY));
END;
/
```

JSONの内容について補足です。

+ name : "FIB_MOD"
    - デバッグ対象MLE Module名を大文字で指定
+ line : 5
    - JavaScriptファンクション内の状態確認したい箇所を行数で指定(本例は return を実行する行を指定)
+ { type : "snapshot"}
    - typeに watch/snapshot を指定
    - watchは指定した変数の値を確認
    - snapshotはスタックトレースを取得

トレースのためやや長いですが、デバッグ結果は以下のように出力されます。

```json
[
    [
        {
            "at" :
            {
                "name" : "TEST.FIB_MOD",
                "line"
                : 5
            },
            "values" :
            {
                "n1" :
                {
                    "id" :
                    "n1",
                    "value" : 1
                },
                "n2" :
                {
                    "id" :
                    "n2",
                    "value" : 0
                },
                "this" :
                {
                },


                "n" : 2
            }
        },
        {
            "at" :
            {
                "name" :
                "TEST.FIB_MOD",
                "line" : 3
            },
            "values" :
            {


                "this" :
                {
                },
                "n" : 3
            }
        }
    ],
    [
        {


            "at" :
            {
                "name" : "TEST.FIB_MOD",
                "line" : 5
            },


            "values" :
            {
                "n1" :
                {
                    "id" : "n1",


                    "value" : 1
                },
                "n2" :
                {
                    "id" : "n2",


                    "value" : 1
                },
                "this" :
                {
                },
                "n" : 3


            }
        }
    ]
]
```

以上がデバッグ機能の使用例です。
snapshot(スタックトレース)ではなくwatchをデバッグタイプに指定することで特定の変数のみ状態確認する機能もありますので、デバッグしたい内容に応じて使い分けて頂ければと思います。