JavaScriptのマルチリンガル・エンジンの概要

MLEを使用すると、JavaScriptをOracle Database内で直接実行および格納できます。

MLEを使用すると、Oracle DatabaseのユーザーがJavaScriptで記述された次のものを実行できます。

  • ストアド・プロシージャ

  • ストアド・ファンクション

  • PL/SQLパッケージ・ネームスペースのコード

  • 匿名の動的コード・スニペット(DBMS_SQLと同様の方法)

MLEは、Linux x86-64またはLinux for Arm (aarch64)の専用サーバー接続を使用してデータベースに接続するときにサポートされます。特定のデータ型はサポートされていません。詳細は、「サポートされていないデータ型」を参照してください。

ノート:

共有サーバー接続およびデータベース常駐接続プール(DRCP)を使用している接続では、MLEを使用できません。

トピック

JavaScript実装の詳細

JavaScriptのMLE実装は、ECMAScript 2023に準拠しています。

このECMA標準に従って、MLEに見られるJavaScript実装は、純粋な実装として意識的に作成されます。ネイティブJavaScriptネットワークおよびファイルI/O操作は、セキュリティ上の理由からNode.jsおよびDenoと同じ方法ではサポートされていません。MLEではネットワークおよびファイルI/Oを使用できますが、UTL_HTTPUTL_FILEなどのPL/SQL APIを使用する必要があります。

WEB APIのFetchは、デフォルトではグローバル領域で使用できませんが、mle-js-fetchをインポートすることで有効にできます。

Windowオブジェクトなどのフロントエンド・コードで使用される共通オブジェクトを含め、ECMA標準に含まれていないオブジェクトもMLEでは使用できません。ただし、MLEでは、SQLへの簡単かつ効率的なアクセスが可能であり、それをデータの近くで実行できます。コンソール出力は、デフォルトではDBMS_OUTPUTに渡されますが、必要に応じてユーザー指定のCLOBにリダイレクトして格納できます。

ユーザーがMLEと対話するには、特定の権限が必要です。これらは、大まかに次のように分類できます:

  • MLEを使用し、JavaScriptコードを実行する権限

  • データベースでの動的JavaScriptの実行

  • JavaScriptモジュールの作成と、PL/SQLコードによるそれらの外部化

JavaScriptの使用に必要な十分な権限がない場合、データベース・エンジンはエラーをスローします。

データベースでのJavaScriptの起動

JavaScriptは、動的実行またはコール仕様(MLEモジュールまたはインラインJavaScriptファンクションを参照)を介して起動できます。

一般的に、サーバー側のJavaScriptコードは次の2つの方法で起動できます:

  • DBMS_MLEパッケージを介して動的に

  • JavaScriptモジュールでエクスポートされたファンクション(いわゆるMLEモジュール・コール)またはDDLで直接定義されたファンクションを参照するPL/SQLコードの使用

2つの方法のどちらを使用するかに関係なく、JavaScriptコードはすべて、実行コンテキストで実行されます。その目的は、JavaScriptコードの処理に関連するすべてのランタイム状態をカプセル化することです。MLE実行コンテキストは、JavaScriptのECMAScript実行コンテキストに対応しています。

データベースでJavaScriptを実行する前に、セッション、PDBまたはCDBでMLEが無効になっていないことを確認する必要があります。これを確認する方法の詳細は、「MLE_PROG_LANGUAGES初期化パラメータ」を参照してください。MLEを最大限に活用するには、JavaScript言語の実行、動的MLEの実行、MLEスキーマ・オブジェクトの作成などに必要な権限を持っている必要があります。

関連項目:

  • MLEでのJavaScriptの操作に必要なシステム権限およびオブジェクト権限

  • ECMAScript実行コンテキストの詳細は、Ecma-international.orgを参照してください

動的実行の概要

匿名JavaScriptコード・スニペットは、DBMS_MLE PL/SQLパッケージを介して実行できます。

動的MLEスニペットを実行するには、プロシージャDBMS_MLE.eval()を使用します。このプロシージャは次の引数を使用します:

引数名 オプションかどうか
CONTEXT_HANDLE RAW(16) いいえ
LANGUAGE_ID VARCHAR2(64) いいえ
SOURCE CLOB いいえ
RESULT CLOB はい
SOURCE_NAME VARCHAR2 はい

引数SOURCE_NAMEは、本来であればランダムに命名されるJavaScriptコード・ブロックの名前を指定するために、オプションで使用します。

JavaScriptコードは、次のコードに示すように、PL/SQLにインラインで指定できます:

SET SERVEROUTPUT ON;

DECLARE
    l_ctx DBMS_MLE.context_handle_t;
    l_jscode CLOB;
BEGIN
    l_ctx := DBMS_MLE.create_context;
    l_jscode := q'~
        console.log('Hello World, this is DBMS_MLE')
    ~';
    DBMS_MLE.eval(
        context_handle => l_ctx,
        language_id => 'JAVASCRIPT',
        source => l_jscode,
        source_name => 'My JS Snippet'
    );
END;
/

この例を実行すると、次のように出力されます:

Hello World, this is DBMS_MLE

前述のコードは、JavaScriptコードの動的な起動に関する次の概念を示しています:

  • 実行コンテキストは、明示的に作成する必要があります

  • JavaScriptコードは、キャラクタ・ラージ・オブジェクト(CLOB)またはVARCHAR2変数として指定します

  • コンテキストは、明示的に評価する必要があります

JavaScriptを動的に実行するときには、PL/SQLとJavaScriptの両方が存在します。指定されたコード・スニペットをネームスペースの外部で再使用することはできません。console.logへのコールの出力は、画面に出力するためにDBMS_OUTPUTに渡されます。

関連項目:

  • MLEを使用した動的実行の詳細は、「動的MLE実行の概要」を参照してください

  • プロシージャDBMS_MLE.eval()RESULT引数の詳細は、「最終実行の結果の戻し」を参照してください

MLEモジュール・コールの概要

データベース内に永続的に格納されるスキーマ・オブジェクトとしてJavaScriptモジュールを作成できます。

JavaScriptモジュールを定義したら、次に示すようにSQLおよびPL/SQLで使用できます:

CREATE OR REPLACE MLE MODULE helloWorld_module
LANGUAGE JAVASCRIPT AS
function helloWorld() {
    console.log('Hello World, this is a JS module');
}
export { helloWorld }
/

エクスポートされたJavaScriptファンクションを起動する前に、コール仕様を定義する必要があります。次のコード・スニペットは、PL/SQLでJavaScriptのhelloWorld()ファンクションのコール仕様を作成する方法を示しています:

CREATE OR REPLACE PROCEDURE helloWorld_proc
AS MLE MODULE helloWorld_module
SIGNATURE 'helloWorld()';
/

MLEモジュール・コールと呼ばれるコール仕様によって、JavaScriptファンクションhelloWorld()が公開されます。その後、他のPL/SQLプロシージャと同様にそれを使用できます。次のスニペットは、このファンクションを起動する方法とともにその結果を示しています:

SET SERVEROUTPUT ON

BEGIN
    helloWorld_proc;
END;
/

結果:

Hello World, this is a JS module

提供されたコードに示されているカスタム作成のJavaScriptモジュールに加えて、サードパーティのJavaScriptモジュールをデータベースにロードできます。業界のベスト・プラクティスに従ってサードパーティ・コードのセキュリティ・スクリーニングを実行することをお薦めします。

関連項目:

  • MLEモジュールおよび環境の詳細は、「MLE JavaScriptモジュールおよび環境」を参照してください

  • MLEのセキュリティ機能および推奨事項の詳細は、「MLEのセキュリティ」を参照してください

MLE実行コンテキストについて

MLE実行コンテキストは、分離されたスタンドアロンのランタイム環境であり、JavaScriptコードの実行に関連付けられたすべてのランタイム状態を含むように設計されています。ランタイム状態には、グローバル変数と、言語環境の状態が含まれます。

ノート:

MLE実行コンテキストは、JavaScriptのECMAScript実行コンテキストに対応しています。
MLEでは、次の2つの異なるシナリオで実行コンテキストが使用されます:
  • 動的MLEコンテキストを明示的に作成して使用できる、動的MLE実行

  • MLEモジュールによってエクスポートされたファンクションへのSQLおよびPL/SQLからのコール

動的実行

動的MLEコンテキストのプロパティは、実行コンテキストが作成された時点で使用されている環境によって決定されます。それぞれの動的MLEスニペットに使用される実行コンテキストを明示的に制御でき、それぞれの実行コンテキストで単一のユーザーの代理としてコードが実行されます。

1つのセッション内で作成できる動的MLE実行コンテキストの数や、異なるコード・スニペット間でそれらを共有する方法に制限はありません。JavaScriptのコード・スニペットは、同じ実行コンテキストで実行されている他のコード・スニペットとすべてのグローバル変数を共有します。

MLEモジュール

SQLまたはPL/SQLからのMLEモジュール・コールのコンテキストは、オンデマンドで暗黙的に作成されます。ここでは、コンテキストの作成時点でコール仕様で参照されているMLE環境によってプロパティが決定されます。環境を使用して、言語オプションを指定したり、MLEモジュールをインポート可能にしたりできます。

MLEモジュールは、他のモジュールや動的MLEスニペットと実行コンテキストを共有することはありません。また、同じMLEモジュールのコードが異なるユーザーの代理として実行されるときには、別個の実行コンテキストが使用されます。MLEは、MLEモジュールと環境の組合せごとに専用の実行コンテキストを作成します。異なるモジュールまたは異なる環境を指定する2つのコール仕様は、別個のモジュール・コンテキストで実行されます。

関連項目:

  • MLE環境の詳細は、「MLEモジュールの環境の指定」を参照してください

  • 実行コンテキストを使用してランタイム状態の分離を強制する方法の詳細は、「実行コンテキスト」を参照してください

制限された実行コンテキストについて

PUREキーワードは、MLE環境およびJavaScriptインライン・コール仕様で指定して、制限されたJavaScript実行コンテキストを作成できます。

データベース内のJavaScriptコードでは、MLE JavaScript SQLドライバやSODAなどのAPIを使用して、SQL実行などのデータベース機能を利用できます。PUREでの実行では、JavaScript内のステートフル・データベースAPIへのアクセスは許可されません。つまり、完全に権限がない状態で実行されます。PURE環境では、JavaScriptコードは、表、プロシージャ、オブジェクトなどのデータベース状態を読取りまたは書込みできません。

PUREでの実行中にデータベースとやり取りできるのは、JavaScriptコードへの入力と出力を介してのみです。これは、コール仕様のユーザー定義関数の引数を介してデータベースからMLEに提供されるデータの形式、およびDBMS_MLE.EXPORT_TO_MLEを使用してエクスポートされた記号の形式です。MLEに渡されるLOBなどの参照タイプは、PUREでの実行中にアクセス(読取りまたは書込み)できます。また、PUREでの実行では、サポートされているデータ型へのアクセスは制限されません。

多くの場合、JavaScriptユーザー定義関数は純粋に計算であり、MLE JavaScript SQLドライバや外部関数インタフェース(FFI)などの強力なAPIにアクセスする必要はありません。PUREでの実行は、サード・パーティのJavaScriptライブラリなどの特定のコードをデータベース自体から分離する方法として機能します。この分離により、データベース状態へのアクセスがセキュリティ上の問題となる、サプライ・チェーン攻撃の攻撃対象領域が減少します。また、PUREでの実行を使用すると、権限の低い開発者は、データベース状態またはネットワークへの追加のアクセスまたは権限を必要とせずに、これらの制限されたユーザー定義関数を作成できます。

次のJavaScript API、グローバル・クラスおよび関数は、PUREでの実行中は使用できません:

  • JavaScript API:
    • mle-js-oracledb
    • mle-js-plsql-ffi
    • mle-js-fetch
  • グローバル・クラスおよび関数:
    • session
    • soda
    • plsffi
    • oracledb
    • require

mle-js-plsqltypesmle-js-encodingsなどのデータベース状態をやり取りしないJavaScript APIには、PUREでの実行中も引き続きアクセスできます。

PUREキーワードは、インライン・コール仕様、モジュール・コール仕様、およびDBMS_MLEを使用して指定できます。各ケースの構文の例を次に示します:

  • モジュール・コール仕様:

    CREATE OR REPLACE MLE MODULE pure_mod
    LANGUAGE JAVASCRIPT AS
    export function helloWorld() {
        console.log('Hello World, this is a JS module');
    }
    /
    
    CREATE OR REPLACE MLE ENV pure_env
    IMPORTS( 'pure_mod' MODULE pure_mod) PURE;
    
    CREATE OR REPLACE PROCEDURE helloWorld
    AS MLE MODULE pure_mod ENV pure_env SIGNATURE 'helloWorld';
    /
  • インライン・コール仕様:

    CREATE OR REPLACE PROCEDURE helloWorld 
    AS MLE LANGUAGE JAVASCRIPT PURE
    {{
        console.log('Hello World, this is a JS inlined call specification');
    }};
    /
  • DBMS_MLEの使用:

    SET SERVEROUTPUT ON;
    DECLARE
        l_ctx     dbms_mle.context_handle_t; 
        l_snippet CLOB; 
    BEGIN
        -- to specify PURE execution with DBMS_MLE, use an environment 
        -- that has been created with the PURE keyword
        l_ctx := dbms_mle.create_context(environment => 'PURE_ENV'); 
        l_snippet := q'~
            console.log('Hello World, this is dynamic MLE execution');
        ~'; 
        dbms_mle.eval(l_ctx, 'JAVASCRIPT', l_snippet); 
        dbms_mle.drop_context(l_ctx); 
    EXCEPTION 
        WHEN OTHERS THEN 
            dbms_mle.drop_context(l_ctx); 
            RAISE; 
    END; 
    /