MLEでのJavaScriptモジュールの使用

JavaScriptモジュールは、様々な方法で使用でき、一連のデータ定義言語(DDL)コマンドを使用して管理できます。

MLEモジュールで提供されているJavaScriptコードは、次の方法で使用できます:

  • MLEモジュールによってエクスポートされたJavaScriptファンクションは、MLEモジュール・コールと呼ばれるコール仕様を作成することで公開できます。これにより、SQLおよびPL/SQLからファンクションを直接コールできます。

  • JavaScript MLEモジュールによってエクスポートされた機能は、他のMLE JavaScriptモジュールにインポートできます。

  • DBMS_MLEのコード・スニペットは、JavaScriptの動的起動用のモジュールをインポートできます。

ユーザーがMLEモジュールを作成および実行できるようにするには、複数の権限を付与する必要があります。

関連項目:

トピック

データベースでのJavaScriptモジュールの管理

必要な権限がある場合は、SQLでMLEモジュールをスキーマ・オブジェクトとして作成できます。

独自のスキーマでMLEモジュールを作成または置換するには、少なくともCREATE MLE MODULE権限が必要です。また、ターゲットのJavaScript言語オブジェクトに対する実行権限も必要です。

関連項目:

  • MLE固有の権限の詳細は、「MLEでのJavaScriptの操作に必要なシステム権限およびオブジェクト権限」を参照してください

  • Oracle Databaseの権限およびロールの詳細は、『Oracle Databaseセキュリティ・ガイド』を参照してください

トピック

JavaScriptモジュールの名前付け

各JavaScriptモジュールの名前は、それが作成されるスキーマ内で一意である必要があります。完全修飾名が使用されないかぎり、現在のユーザーのスキーマが使用されます。

他のスキーマ・オブジェクト識別子と同様に、二重引用符で囲まれたモジュール名は大/小文字が区別されます。引用符で囲まれていない場合、名前は暗黙的に大文字に変換されます。

一意の名前を選択する場合、MLEオブジェクトは、表、ビュー、マテリアライズド・ビュー、順序、プライベート・シノニム、PL/SQLパッケージ、ファンクション、プロシージャおよびキャッシュ・グループとネームスペースを共有することに注意してください。

データベースでのJavaScriptモジュールの作成

JavaScriptモジュールは、CREATE MLE MODULE DDL文を使用して、MLEモジュールの名前とソース・コードを指定してデータベースに作成されます。

MLEモジュールが作成されるとすぐに、データベース・ディクショナリに保持されます。これは、DBMS_MLEを使用したJavaScriptコードの動的実行と比較した場合の違いの1つです。

指定された名前のMLEモジュールがすでに存在する場合、CREATE MLE MODULE (OR REPLACE句なし)はエラーをスローします。CREATE OR REPLACE MLE MODULEでは、既存のモジュールが存在する場合は置換され、存在しない場合は新しいモジュールが作成されます。MLEモジュールが置換される場合、そのモジュールに対する権限を再付与する必要はありません。

PL/SQLの知識のある方は、これがPL/SQLプログラム・ユニットの動作とまったく同じであることに注意してください。

モジュール名がすでに使用されている場合に既存のモジュールを置換しない場合は、CREATE OR REPLACEではなくIF NOT EXISTS句を使用できます。このバリエーションの構文を例3-1に示します。IF NOT EXISTS句とOR REPLACE句は相互に排他的です。

関連項目:

例3-1 データベースでのJavaScriptモジュールの作成

この例は、MLEモジュールの作成および単純なJavaScriptファンクションのエクスポートを示しています。

CREATE MLE MODULE IF NOT EXISTS po_module LANGUAGE JAVASCRIPT AS

/**
* get the value of all line items in an order
* @param {array} lineItems - all the line items in a purchase order
* @returns {number} the total value of all line items in a purchase order
*/
export function orderValue(lineItems) {
    
    return lineItems
        .map( x => x.Part.UnitPrice * x.Quantity )
        .reduce( 
            (accumulator, currentValue) => accumulator + currentValue, 0
        );
}
/

このコード・ブロックの最初の行は、JavaScriptモジュール名をpo_moduleとして指定しています。残りの行は、実際のJavaScriptコードを定義します。ECMAScript標準に従い、exportキーワードは、モジュールの潜在的なコール元にエクスポートされるファンクションを示すことに注意してください。MLEは、ECMAScript 2023標準に準拠したコードを受け入れます。

シングルバイト文字セットの使用によるデータベースでのJavaScriptコードの格納

文字セット標準と、MLEでシングルバイト文字セットを使用する際の注意事項。

JavaScriptはUnicodeでエンコードされます。Unicode規格は、世界中で話されているほとんどの言語のあらゆる文字を定義する文字コード・システムです。これは、他の文字セット・エンコーディングの制限事項を克服するために開発されました。

データベースの作成には、AL32UTF8文字セットを使用することをお薦めします。データベースでAL32UTF8文字セットを使用すると、最新バージョンのUnicode標準が確実に使用され、文字セット変換エラーの可能性が最小限に抑えられます。

データベースで依然としてUS7ASCII、WE8ISO8859-n、WE8MSWIN1252などのシングルバイト文字セットが使用されている場合は、MLE JavaScriptコードでUnicode機能を使用しないように注意する必要があります。このことは、そのようなデータベースで他のタイプの入力データを処理する場合と変わりありません。

関連項目:

Unicode標準の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください

コード分析

JavaScript構文エラーには、MLEモジュールの作成時にフラグが付けられますが、CREATE MLE MODULEコマンドを実行する前に、選択したlintツールを使用して分析を実行してください。

MLEモジュールをデータベースに作成する場合は、他のJavaScriptプロジェクトを制御するのと同じ方法で、十分に確立されたツールチェーンを使用する必要があります。この意味では、CREATE MLE MODULEのコールは、サーバー・アプリケーションのデプロイと同様に、デプロイメント・ステップとみなすことができます。コード・チェックは、デプロイの前に、継続的インテグレーション/継続的デプロイメント(CI/CD)パイプラインなどによって、ビルド・ステップ中に実行する必要があります。

JavaScriptコードに構文エラーを含むCREATE MLE MODULEを使用してモジュールを作成すると、そのモジュールは作成されますが、無効な状態になります。このチェックはモジュール内で呼び出されたSQL文には適用されないため、コードが期待どおりに機能するように個別のテストを実行する必要があります。

コードをソース・コード・リポジトリにチェックインする前に、linterと呼ばれるツールでコードを処理することは、業界のベスト・プラクティスとみなされています。他の開発プロジェクトと同様に、自分自身とチームにとって最適なオプションを自由に選択できます。考えられるオプションには、ESLint、JSHint、JSLint、および静的コード分析を実行して構文エラー、バグ、その他の問題のあるコードにフラグを付けるものがあります。また、これらを使用して特定のコーディング・スタイルを適用することもできます。多くの統合開発環境(IDE)では組込み機能としてlintが提供され、ファイルがディスクに保存されるとすぐにこのツールを起動して、問題にフラグを付けます。

lintの動的実行に加えて、高度に自動化されたDevOps環境を使用してコード分析を自動化し、ビルド・パイプラインの一部としてlintを起動できます。通常、このステップは、JavaScriptモジュールをデータベースに送信する前に発生します。

この目的は、実行時に問題が発生する前に、できるだけ多くの潜在的な問題を検出することです。ユニット・テストはこれらのリスクをさらに軽減するために役立ち、開発プロセスへのユニット・テストの組込みは業界のベスト・プラクティスになっています。どの方法を選択しても、JavaScriptモジュールをデータベースに送信する前に、コード分析ステップが発生します。

MLEモジュール・コール用のJavaScriptコードの準備

MLEのJavaScriptモジュールは、モジュール用のECMAScript 6標準に従います。MLEモジュールのユーザーが使用すると予想されるファンクションと変数をエクスポートする必要があります。

エクスポートされない変数およびファンクションは、モジュール内でプライベートとみなされます。例3-3は、MLE JavaScriptモジュールでのパブリック・ファンクションとプライベート・ファンクションの両方の使用を示しています。

ECMAScriptモジュールは、インポート文または動的インポート・コールを使用して、他のECMAScriptモジュールをインポートできます。この機能は、MLEにもあります。MLE環境では、MLEモジュールを補完するメタデータが提供されます。

MLEのコンソール出力は、コンソール・オブジェクトを使用することで容易になることに注意してください。デフォルトでは、console.log()に書き込まれたものはすべてDBMS_OUTPUTにルーティングされ、最終的に画面に表示されます。

例3-1のようなJavaScriptコードは、コール仕様なしでSQLまたはPL/SQLからアクセスすることはできません。コール仕様は、PL/SQLプログラム・ユニット(ファンクション、プロシージャまたはパッケージ)と考えることができます。ここで、例3-2に示すように、そのPL/SQL本体がJavaScriptモジュールおよびファンクションへの参照に置き換えられます。コール仕様の詳細は、「MLE JavaScriptファンクション」を参照してください。

例3-2 パブリック・ファンクションのコール仕様の作成

この例では、例3-1で作成したモジュールpo_moduleを使用します。po_moduleでエクスポートされる唯一のファンクションであるorderValue()のコール仕様は、次のように記述できます:


CREATE OR REPLACE FUNCTION order_value(
    p_line_items JSON
) RETURN NUMBER AS
MLE MODULE po_module
SIGNATURE 'orderValue';
/

ファンクションを作成すると、特定の購買オーダーの値を計算できます:


SELECT
    po.po_document.PONumber,
    order_value(po.po_document.LineItems[*]) order_value
FROM
    j_purchaseorder po;

結果:


PONUMBER   ORDER_VALUE
---------- -----------
1600             279.3
672              359.5

例3-3 JavaScriptモジュールのパブリック・ファンクションとプライベート・ファンクション

パブリック(エクスポート済)ファンクションに加えて、モジュールにプライベートなファンクションを追加できます。この例では、値の計算はmap()ファンクションから取り出され、別のファンクションに移動されます(リファクタリング)。

次のコードの最初のファンクションlineItemValue()はプライベートとみなされ、2番目のファンクションorderValue()はパブリックです。exportキーワードは、このコード・リストの最後に指定されていますが、例3-1に示すように、変数およびファンクションの接頭辞として出現することもあります。どちらのバリエーションも有効なJavaScript構文です。


CREATE OR REPLACE MLE MODULE po_module LANGUAGE JAVASCRIPT AS

/**
* calculate the value of a given line item. Factored out of the public 
* function to allow for currency conversions in a later step
* @param {number} unitPrice - the price of a single article
* @param {number} quantity - the quantity of articles ordered
* @returns {number} the monetary value of the line item
*/
function lineItemValue(unitPrice, quantity) {
    return unitPrice * quantity;
}

/**
* get the value of all line items in an order
* @param {array} lineItems - all the line items in a purchase order
* @returns {number} the total value of all line items in a purchase order
*/
function orderValue(lineItems) {
    
    return lineItems
                .map( x => lineItemValue(x.Part.UnitPrice, x.Quantity) )
                .reduce( 
                    (accumulator, currentValue) => accumulator + currentValue, 0 
                );
}

export { orderValue }
/

MLEにJavaScriptコードを指定するための追加オプション

MLEモジュールのJavaScriptソース・コードは、PL/SQLを使用してインラインで指定できますが、BFILE、BLOBまたはCLOBを使用して指定することもできます。この場合、ソース・ファイルはUTF8でエンコードする必要があります。

BFILE句を使用してMLEモジュールを作成すると、GoldenGateなどの論理レプリケーションで問題が発生する可能性があります。DDLコマンドがターゲット・データベースで成功するには、ターゲット・データベースに同じディレクトリが存在する必要があります。さらに、このディレクトリに同じJavaScriptファイルが存在する必要があります。これらの条件が満たされないと、ターゲット・データベースでMLEモジュールを作成するコールが失敗します。

BFILEを使用するかわりに、BLOBまたはCLOBを使用して、MLEモジュールを作成することもできます。例3-5に、CLOBを使用してJavaScriptモジュールを作成する方法を示します。BLOBを使用する場合、構文は同じですが、BLOBの値はCLOBの値とは異なります。

例3-4 BFILEを使用したJavaScriptソース・コードの指定

この例では、JS_SRC_DIRは、myJavaScriptModule.jsというファイルにモジュールのソース・コードを含むローカル・ファイル・システム上の場所にマッピングするデータベース・ディレクトリ・オブジェクトです。ディレクトリの場所からファイルをロードすると、MLEはソース・コードをディクショナリに格納します。それ以降MLEモジュールをコールしても、ソース・コードがディスクからリフレッシュされることはありません。myJavaScriptModule.jsに新しいバージョンのモジュールが格納されている場合は、別のCREATE OR REPLACE MLE MODULEのコールを使用してデプロイする必要があります。

CREATE MLE MODULE mod_from_bfile
LANGUAGE JAVASCRIPT
USING BFILE(JS_SRC_DIR,'myJavaScriptModule.js');
/

例3-5 CLOBを使用したJavaScriptソース・コードの指定

CREATE OR REPLACE MLE MODULE mod_from_clob_inline
LANGUAGE JAVASCRIPT USING CLOB (
    SELECT q'~
    export function clob_hello(who){
        return `hello, ${who}`;
}
~')
/

別の方法として、表に格納されているJavaScriptソース・コードを使用することもできます。このバリエーションの例では、スキーマに、src列のJavaScriptソース・コードを含むjavascript_srcという名前の表と、追加のメタデータがあると想定しています。次の文は、CLOBをフェッチしてモジュールを作成します。

CREATE OR REPLACE MLE MODULE mod_from_clob_table
LANGUAGE JAVASCRIPT USING CLOB (
    SELECT src
    FROM javascript_src
    WHERE 
        id = 1 AND 
        commit_hash = 'ac1fd40'
)
/

このようなステージング表は、継続的インテグレーション(CI)パイプラインを使用してJavaScriptコードをデータベースにデプロイする環境にあります。

モジュール・バージョン情報の指定およびJSONメタデータの指定

MLEモジュールでは、オプションのメタデータをバージョン文字列および自由形式のJSON値メタデータの形式で保持できます。

どちらの種類のメタデータも純粋に情報を提供し、MLEの動作には影響しません。これらは、モジュールとともにデータ・ディクショナリに格納されます。

VERSIONフラグは、デプロイされているコードのバージョンに関する内部リマインダとして使用できます。VERSIONフィールドに格納された情報により、開発者および管理者は、バージョン管理システムでコードを識別できます。

JSONメタデータの形式はスキーマにバインドされません。開発者は有用なものや参考になるものを追加できます。MLEモジュールがrollup.jsやwebpackなどのツールで作成されたソースの集合である場合、関連するpackage-lock.jsonファイルをモジュールとともに格納すると便利です。

メタデータ・フィールドを使用して、ソフトウェア部品構成表(SBOM)を作成できます。これにより、セキュリティ・チームおよび管理者は、特にサードパーティ・モジュールが使用されている場合に、デプロイ済パッケージに関する情報を追跡できます。

アップストリーム・リポジトリの依存関係および脆弱性を追跡することにより、セキュリティの脆弱性がレポートされた後に更新が必要なコンポーネントを簡単に識別できます。

関連項目:

例3-6 CREATE MLE MODULEでのVERSION文字列の指定

CREATE OR REPLACE MLE MODULE version_mod
 LANGUAGE JAVASCRIPT
 VERSION '1.0.0.1.0' 
AS
export function sq(num) {
  return num * num;
}
/

例3-7 MLEモジュールへのJSONメタデータの追加

この例では、例3-6で作成したモジュールversion_modを使用します。

ALTER MLE MODULE version_mod
SET METADATA USING CLOB 
(SELECT 
  '{
    "name": "devel",
    "lockfileVersion": 2,
    "requires": true,
    "packages": {}
  }'
)
/

JavaScriptモジュールの削除

DROP MLE MODULE DDL文を使用して、MLEモジュールを削除します。

DROP文は、削除するモジュールの名前およびオプションでスキーマを指定します。スキーマが指定されていない場合は、現在のユーザーのスキーマとみなされます。

存在しないMLEモジュールを削除しようとすると、エラーがスローされます。これが望ましくない場合は、IF EXISTS句を使用できます。指定されたMLEモジュールが存在しない場合、DROP MLE MODULEコマンドは暗黙的にスキップされます。

例3-8 MLEモジュールの削除

DROP MLE MODULE unused_mod;

例3-9 IF EXISTSを使用したMLEモジュールの削除

DROP MLE MODULE IF EXISTS unused_mod;

JavaScriptモジュールの変更

MLEモジュールの属性は、ALTER MLE MODULE文を使用して割り当てまたは変更できます。

ALTER MLE MODULE文は、変更するモジュールの名前およびオプションでスキーマを指定します。モジュール名にスキーマの接頭辞が付けられていない場合は、現在のユーザーのスキーマとみなされます。

例3-10 MLEモジュールの変更

ALTER MLE MODULE change_mod
  SET METADATA USING CLOB(SELECT'{...}');

組込みJavaScriptモジュールの概要

MLEには、任意の実行コンテキストでインポートできる一連の組込みJavaScriptモジュールが用意されています。

組込みモジュールは、ユーザー定義のMLEモジュールとしてデータベースにデプロイされませんが、MLEランタイムの一部として含まれます。特に、MLEは、次の3つの組込みJavaScriptモジュールを提供します:

  • mle-js-oracledbは、JavaScript MLE SQLドライバです。

  • mle-js-bindingsは、PL/SQLエンジンから値をインポートおよびエクスポートする機能を提供します。

  • mle-js-plsqltypesは、PL/SQLラッパー型の定義を提供します。たとえば、PL/SQLをラップするJavaScript型と、OracleNumberなどのSQL型です。

  • mle-js-fetchには、フェッチAPIポリフィルの一部が提供されており、開発者は外部リソースを起動できます。

  • mle-encode-base64には、base64でエンコードされたデータを操作するためのコードが含まれます。

  • mle-js-encodingsは、UTF-8およびUTF-16エンコーディングのテキストを処理する機能を提供します。
  • mle-js-plsql-ffiは、PL/SQLパッケージ、ファンクションおよびプロシージャをJavaScriptオブジェクトとして処理する機能を提供します。

これらのモジュールを使用して、データベースと対話し、JavaScriptエンジンとデータベース・エンジンの間の型変換を提供します。

関連項目:

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

MLE JavaScriptモジュールに関連するディクショナリ・ビュー

データ・ディクショナリには、JavaScriptモジュールの詳細が含まれます。

トピック

USER_SOURCE

各JavaScriptモジュールのソース・コードは、[USER | ALL | DBA | CDB]_SOURCEディクショナリ・ビューを使用して外部化されます。

BFILE演算子を使用してファイル・システムを参照して作成されたモジュールには、モジュールの作成時のコードが表示されます。

*_SOURCEの詳細は、『Oracle Databaseリファレンス』を参照してください。

例3-11 JavaScriptモジュールのソース・コードの外部化

SELECT
    line,
    text
FROM
    USER_SOURCE
WHERE
    name = 'PO_MODULE';

出力例:

   
 LINE TEXT
----- -------------------------------------------------------------
    1 /**
    2  * calculate the value of a given line item. Factored out of the public
    3  * function to allow for currency conversions in a later step
    4  * @param {number} unitPrice - the price of a single article
    5  * @param {number} quantity - the quantity of articles ordered
    6  * @returns {number} the monetary value of the line item
    7  */
    8 function lineItemValue(unitPrice, quantity) {
    9     return unitPrice * quantity;
   10 }
   11
   12
   13 /**
   14  * get the value of all line items in an order
   15  * @param {array} lineItems - all the line items in a purchase order
   16  * @returns {number} the total value of all line items in a purchase order
   17  */
   18 export function orderValue(lineItems) {
   19
   20     return lineItems
   21                 .map( x => lineItemValue(x.Part.UnitPrice, x.Quantity) )
   22                 .reduce(
   23                     (accumulator, currentValue) => accumulator + currentValue, 0
   24                 );
   25 }

USER_MLE_MODULES

JavaScript MLEモジュールに関連するメタデータは、[USER | ALL | DBA | CDB]_MLE_MODULESにあります。

指定されたJSONメタデータ、バージョン情報、言語、名前および所有者は、このビューで確認できます。

*_MLE_MODULESの詳細は、『Oracle Databaseリファレンス』を参照してください。

例3-12 スキーマに定義されているMLEモジュールの検索

SELECT MODULE_NAME, VERSION, METADATA
FROM USER_MLE_MODULES
WHERE LANGUAGE_NAME='JAVASCRIPT'
/

出力例:

MODULE_NAME                    VERSION    METADATA
------------------------------ ---------- -----------
MY_MOD01                       1.0.0.1
MY_MOD02                       1.0.1.1
MY_MOD03