2024年5月31日金曜日

NPMパッケージからOracle Datase 23aiのMLEモジュールを作成する

Oracle Database 23aiに追加されたMLE(Multilingual Engine - GraalVMのこと)により、データベースでJavaScriptを実行できるようになりました。Oracle APEXは以前からコードを記述する言語は選択可能で、データベースの対応待ちでした。

さて、JavaScriptでコードを記述しようと思っても、Node.jsのnpmで配布されているようなパッケージが無い、となると相当に大変な作業になってしまいます。

Oracle Database 23aiのMLEモジュールは、基本的にESモジュールです。npmのパッケージをESモジュールとして取得すれば、(原則的に)それをもとにMLEモジュールを作成できます。

CDNのjsDelivrでは、NPMパッケージを取得するURLの末尾に+esmを付加することにより、そのパッケージをESモジュールの形式で返してくれます。

今回はJavaScriptを清書するパッケージpretty-jsをデータベースにロードしてみます。

pretty-jsをESモジュールとして取得するURLは以下になります。


CDNからESモジュールを取得し、MLEモジュールとして作成するAPEXアプリケーションを作成しています。相当にやっつけ仕事ですが、何もないよりは遥かに良いです。エクスポートは以下に置きました。

https://github.com/ujnak/apexapps/blob/master/exports/mle-module-manager.zip

以下のGIF動画のように操作します。
  1. Module Namepretty-jsを指定し、Add Moduleをクリックします。jsDelivrからpretty-jsをESモジュールとして取得し、MLEモジュールの作成対象として追加します。
  2. Resolve Onceをクリックします。pretty-jsのESモジュールのコードを読んで、importされているESモジュールを、MLEモジュールの作成対象として追加します。
  3. 追加されたESモジュールを再帰的に解析するようにはしていないので、ESモジュールがすべて解析されるまで、Resolve Onceを複数回クリックします。
  4. Create Mle Modulesをクリックし、jsDelivrから取得したESモジュールを元にMLEモジュールを作成します。
  5. MLE Envに指定されているMLE環境(なければ新規作成)に、作成したMLEモジュールのインポートを追加します。
動作確認のために、以下のコードを実行しています。
const { default:prettyJs } = await import("/npm/pretty-js@0.2.2/+esm");
const { fetch } = await import("mle-js-fetch");

fetch('https://cdn.jsdelivr.net/npm/pretty-js@0.2.2/+esm')
.then(response => {
    return response.text();
})
.then(text => {
    console.log(prettyJs(text));
});


ほとんどの処理は、記事の末尾に添付したパッケージUTL_MLE_NPMに実装しています。APEXアプリケーションのボタンをクリックすると、対応したUTL_MLE_NPMのプロシージャを呼び出します(プロセスのタイプAPI呼出し)。
  • ボタンINITだけはUTL_MLE_NPMではなく、APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTIONを呼び出し、APEXコレクションMLE_MODULESを初期化します。
  • ボタンADD_ES_MODULEは、UTL_MLE_NPM.ADD_MODULEを呼び出します。
  • ボタンRESOLVE_ONCEは、UTL_MLE_NPM.RESOLVE_ONCEを呼び出します。
  • ボタンCREATE_MLE_MODULESは、UTL_MLE_NPM.CREATE_MLE_MODULESを呼び出します。
  • ボタンADD_IMPORTSは、UTL_MLE_NPM.ADD_IMPORTSを呼び出します。
  • ボタンDROP_MLE_ENVは、drop mle env MLE環境名を実行します。
  • ボタンDROP_MLE_MODULESは、UTL_MLE_NPM.DROP_MLE_MODULES_ESMを呼び出します。
すべての処理はホーム・ページに実装しています。


ボタンに対応したプロセスが作成されています。


上記の例ではpretty-jsをMLEモジュールとして作成しましたが、元々はjimpをロードするために、このアプリケーションを作成しました。

Module Namejimpを入力し、Add Es Moduleをクリックします。ESモジュールは以下のURLから取得しています。

https://cdn.jsdelivr.net/npm/jimp/+esm

バージョンを指定していないため、ESモジュールの内容からバージョンを取り出しています。

レポートの列C001モジュール名C002バージョンです。列C007MLEモジュール名です。ESモジュールの名前は記号(例えば)で始まることもあるため、MLEモジュール名は必ずESM_で開始するようにしています。また、MLEモジュールにはバージョン情報を付けることができますが、同じモジュール名でバージョンが異なるモジュールは作成できないようです。同じモジュールでもバージョンが異なるものを別のMLEモジュールとして作成できるように、MLEモジュール名にはバージョンを付加しています。

N0010の場合は、MLEモジュールとして未作成1の場合は作成済み、列N0020の場合はソースコードは未解析の場合は解析済み(インポートしているESモジュールがAPEXコレクションに追加済み)です。


ボタンResolve Onceをクリックします。

C001jimpの列N0021になり(つまり解析済み)、@jimp/custom@jimp/types@jimp/pluginsが行として追加されます。これらの列N0020で、まだ解析されていません。


再度Resolve Onceをクリックします。@jimp/custom@jimp/types@jimp/pluginsの内容が解析され(列N0021になります)、インポートされていたESモジュールがAPEXコレクションに追加されます。


同じ操作(Resolve Onceのクリック)を、列N002の値がすべて1(ESモジュールの取得に失敗しているものを除く)になるまで繰り返します。

C002(バージョン)が空白のESモジュールが2つあります。@jimp/coregifwrapです。


バージョンが取れないのは、jsDelivrの側でESモジュールのコード生成に失敗しているためです。生成されたコードを確認します。

https://cdn.jsdelivr.net/npm/@jimp/core/+esm
https://cdn.jsdelivr.net/npm/gifwrap/+esm

両方ともに以下のような出力になっています。どのようなNPMでも、ESモジュールにできるわけではないようです。
/**
 * Failed to bundle using Rollup v2.79.1: the file imports a not supported node.js built-in module "fs".
 * If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr
 */

 throw new Error('Failed to bundle using Rollup v2.79.1: the file imports a not supported node.js built-in module "fs". If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr');
また、MLEモジュールとして作成できていても、インポートして使おうとするとエラーが発生する場合もあります。

MLE環境に追加されたインポート名より、MLEモジュールをインポートする文を生成します。MLE環境はMYENVとしてます。
select '// const e' || rownum || ' = await import("' || import_name || '");' from user_mle_env_imports where env_name = 'MYENV'

以下のインポートを実行してみます。

const e5 = await import("/npm/@jimp/custom@0.22.12/+esm");

以下のエラーが発生します。モジュール@jimp/coreはESモジュールの生成に失敗しているため、MLEモジュールとして作成できていません。@jimp/coreのコードを修正する以外に対応方法は無いと思われます。

ORA-04161: Error: Cannot load ES module: /npm/@jimp/core@0.22.12/+esm

以下のインポートを実行してみます。

const e49 = await import("/npm/xml-parse-from-string@1.0.1/+esm");

以下のエラーが発生しました。

ORA-04161: ReferenceError: self is not defined 
ORA-06512: "APEX_230200.WWV_FLOW_CODE_EXEC_MLE", 行728 
ORA-04171: 場所:module:eval (WKSP_APEXDEV.ESM_XML_PARSE_FROM_STRING_1_0_1:7:16)

ESモジュールのコードを確認してみます。

https://cdn.jsdelivr.net/npm/xml-parse-from-string@1.0.1/+esm

コード中でMicrosoft.XMLDOMを参照している模様です。Oracle Database上ではエラーが発生するのは仕方がなさそうです。
/**
 * Bundled by jsDelivr using Rollup v2.79.1 and Terser v5.19.2.
 * Original file: /npm/xml-parse-from-string@1.0.1/index.js
 *
 * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
 */
var e=void 0!==self.DOMParser?function(e){return(new self.DOMParser).parseFromString(e,"application/xml")}:void 0!==self.ActiveXObject&&new self.ActiveXObject("Microsoft.XMLDOM")?function(e){var r=new self.ActiveXObject("Microsoft.XMLDOM");return r.async="false",r.loadXML(e),r}:function(e){var r=document.createElement("div");return r.innerHTML=e,r};export{e as default};
//# sourceMappingURL=/sm/be5cb35a93829eb0b811add8f6983796069c4d7086c8acebcc12b0d69a3be01d.map
最終的にjimpはロードできなかったのは残念ですが、依存関係のあるNPMモジュールからMLEモジュールを作成する作業は、それなりに効率的にできるようになりました。

今回の記事は以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。


UTL_MLE_NPMパッケージ

create or replace package utl_mle_npm
as
/**
* ESモジュールのロードからMLEモジュールの作成までに取り得る状態。
*/
C_MODULE_NA constant varchar2(8) := 'NA';
C_MODULE_LOADED constant varchar2(8) := 'LOADED';
C_MODULE_RESOLVED constant varchar2(8) := 'RESOLVED';
C_MODULE_VALID constant varchar2(8) := 'VALID';
C_MODULE_INVALID constant varchar2(8) := 'INVALID';
/**
* MLEモジュールとして作成する予定のESモジュールを、APEXコレクションに追加する。
*/
procedure add_module(
p_collection_name in varchar2
,p_module_name in varchar2
,p_module_version in varchar2 default null
,p_module_path in varchar2 default null
,p_parent_module_name in varchar2 default null
,p_parent_module_version in varchar2 default null
,p_parent_module_path in varchar2 default null
);
/**
* APEXコレクションに含まれているESモジュールで、そのモジュールがインポートしている
* ESモジュールの解析が終わっていないものを対象にして解析する。
*/
procedure resolve_once(
p_collection_name in varchar2
);
/**
* APEXコレクションに追加されているESモジュールより、MLEモジュールを作成する。
*/
procedure create_mle_modules(
p_collection_name in varchar2
,p_replace in boolean
);
/**
* MLE環境にインポートを追加する。
*/
procedure add_imports_to_mle_env(
p_collection_name in varchar2
,p_mle_env in varchar2
);
/**
* drop all MLE modules if the name start with 'ESM__'
*/
procedure drop_mle_modules_esm;
end utl_mle_npm;
/
view raw utl_mle_npm.sql hosted with ❤ by GitHub

jsdelivr向け実装

create or replace package body utl_mle_npm
as
C_PROVIDER_URL constant varchar2(80) := 'https://cdn.jsdelivr.net/npm/%s/+esm';
C_IMPORT_PRE constant varchar2(20) := '/npm/';
C_IMPORT_POST constant varchar2(8) := '/+esm';
C_ORIGINAL_FILE_LINE constant varchar2(20) := 'Original file: /npm/';
C_MLE_ENV_FOR_PRETTY_PRINT constant varchar2(30) := 'MLE_ENV_FOR_PRETTY_PRINT';
/**
* Pretty print the moudle source.
*
* Prerequisites:
* - An MLE module named '/npm/pretty-js@0.2.2/+esm' must exist.
* - An MLE Environment containing this module must be defined in the
* Application Setting 'MLE_ENV_FOR_PRETTY_PRINT'.
*
* Note: This functionality is currently only applicable to jsdelivr.
*/
function make_pretty(
p_source in clob
,p_module in varchar2 default '/npm/pretty-js@0.2.2/+esm'
)
return clob
as
l_ctx dbms_mle.context_handle_t;
C_CODE constant clob := q'~
(async() => {
const bindings = await import("mle-js-bindings");
const { default:prettyJs } = await import("#MODULE#");
const source = bindings.importValue("source");
const pretty = prettyJs(source.getData());
bindings.exportValue("pretty", pretty);
})();
~';
l_code clob;
l_pretty clob;
l_environment varchar2(80);
begin
l_environment := apex_app_setting.get_value(
p_name => C_MLE_ENV_FOR_PRETTY_PRINT
);
-- apex_debug.info('MLE Env for Pretty Print, %s', l_environment);
/*
* Do nothing without Application Setting.
*/
if l_environment is null then
return p_source;
end if;
/*
* Do pretty print by calling pretty-js.
*/
l_ctx := dbms_mle.create_context(
environment => l_environment
);
l_code := replace(C_CODE, '#MODULE#', p_module);
-- apex_debug.info('Code for Pretty Print, %s', l_code);
dbms_mle.export_to_mle(l_ctx, 'source', p_source);
dbms_mle.eval(l_ctx, 'JAVASCRIPT', l_code);
dbms_mle.import_from_mle(l_ctx, 'pretty', l_pretty);
dbms_mle.drop_context(l_ctx);
return l_pretty;
exception
when others then
/* preserve the orignal source when pretty-print is failed.  */
return p_source;
end make_pretty;
/**
* Retrieve module version from the source code of ES module.
* If version could not be retrieved, mainly because jsdelivr failed to generate ES module.
*/
function get_version_from_source(
p_source clob
)
return varchar2
as
l_start integer;
l_end integer;
l_file varchar2(80);
l_version varchar2(80);
begin
l_start := dbms_lob.instr(
lob_loc => p_source
,pattern => C_ORIGINAL_FILE_LINE
);
l_end := dbms_lob.instr(
lob_loc => p_source
,pattern => apex_application.LF
,offset => l_start
);
l_file := dbms_lob.substr(
lob_loc => p_source
,amount => (l_end - l_start - length(C_ORIGINAL_FILE_LINE))
,offset => (l_start + length(C_ORIGINAL_FILE_LINE))
);
-- dbms_output.put_line(apex_string.format('start %s end %s file %s', l_start, l_end, l_file));
/*
* separator between module name and version is '@' but the module name
* could start with '@'.
* When module name is stared with '@', it is not treated as a separator.
*/
if l_file like '@%' then
l_start := instr(l_file, '@', 1, 2);
else
l_start := instr(l_file, '@', 1, 1);
end if;
l_end := instr(l_file, '/', l_start, 1);
l_version := substr(l_file, (l_start + 1), (l_end - l_start - 1));
return l_version;
end get_version_from_source;
/**
* Extracts module names, versions, and paths from import statements within ES module source code.
* Valid only with ES modules generated by jsDelivr.
*/
procedure get_name_and_version_from_import(
p_import in varchar2
,p_module_name out varchar2
,p_module_version out varchar2
,p_module_path out varchar2
)
as
l_start integer;
l_end integer;
l_line varchar2(32767);
begin
l_start := instr(p_import, C_IMPORT_PRE);
if l_start = 0 then
p_module_name := null;
p_module_version := null;
return;
end if;
l_line := substr(p_import, (l_start + length(C_IMPORT_PRE)));
if l_line like '@%' then
l_end := instr(l_line, '@', 1, 2);
else
l_end := instr(l_line, '@', 1, 1);
end if;
if l_end = 0 then
p_module_name := null;
p_module_version := null;
return;
end if;
p_module_name := substr(l_line, 1, (l_end - 1));
l_line := substr(l_line, (l_end + 1));
l_end := instr(l_line, C_IMPORT_POST);
if l_end = 0 then
p_module_name := null;
p_module_version := null;
return;
end if;
l_line := substr(l_line, 1, (l_end - 1));
l_start := instr(l_line, '/');
if l_start > 0 then
/* version and path exists */
p_module_version := substr(l_line, 1, (l_start - 1));
p_module_path := substr(l_line, (l_start + 1));
else
/* version only */
p_module_version := l_line;
p_module_path := null;
end if;
end get_name_and_version_from_import;
/**
* Generate the name for MLE module based on the ES module name, version, and path.
*/
function generate_mle_module_name(
p_module_name in varchar2
,p_module_version in varchar2
,p_module_path in varchar2
)
return varchar2
as
l_module_name varchar2(128);
begin
/*
* ES module name might start with '@' but MLE module name should begin with A-Z.
* Prepend ESM_ to all MLE module name to ensure the name begin with A-Z.
*/
l_module_name := 'ESM_' || p_module_name || '@' || p_module_version;
if p_module_path is not null then
l_module_name := l_module_name || '_' || p_module_path;
end if;
l_module_name := upper(translate(l_module_name, '@./-', '____'));
return l_module_name;
end generate_mle_module_name;
/**
* Generates the name of an MLE module based on the ES module name, version, and path.
*/
procedure add_module(
p_collection_name in varchar2
,p_module_name in varchar2
,p_module_version in varchar2 default null
,p_module_path in varchar2 default null
,p_parent_module_name in varchar2 default null
,p_parent_module_version in varchar2 default null
,p_parent_module_path in varchar2 default null
)
as
l_provider_url varchar2(200);
l_source clob;
l_module_version varchar2(80);
l_mle_module_name varchar2(128);
l_module_status varchar2(8) := C_MODULE_NA;
l_seq_id number;
begin
/*
* If no version is specified, the latest version is fetched. The version number is extracted from the source code.
*/
if p_module_version is null then
l_provider_url := apex_string.format(C_PROVIDER_URL, p_module_name);
elsif p_module_path is null then
l_provider_url := apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version);
else
l_provider_url := apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version || '/' || p_module_path);
end if;
-- dbms_output.put_line(l_jsdelivr_url);
/*
* Get module source as ES moudle by calling jsDelivr.
*/
apex_web_service.clear_request_headers();
apex_debug.info('Request to get source: %s', l_provider_url);
l_source := apex_web_service.make_rest_request(
p_url => l_provider_url
,p_http_method => 'GET'
);
apex_debug.info('Response: %s', apex_web_service.g_status_code);
if apex_web_service.g_status_code = 200 then
l_module_version := get_version_from_source(
p_source => l_source
);
l_mle_module_name := generate_mle_module_name(
p_module_name => p_module_name
,p_module_version => l_module_version
,p_module_path => p_module_path
);
if l_module_version is not null then
l_module_status := C_MODULE_LOADED;
end if;
end if;
if l_module_status = C_MODULE_LOADED then
begin
select status into l_module_status from user_objects
where object_type = 'MLE MODULE' and object_name = l_mle_module_name;
exception
when no_data_found then
null;
end;
end if;
-- update mle module status if module is in the apex collection.
begin
select seq_id into l_seq_id from apex_collections
where 1=1
and collection_name = p_collection_name
and c001 = p_module_name
and c002 = l_module_version
and (
(p_module_path is null and c003 is null)
or
(c003 = p_module_path)
);
exception
when no_data_found then
l_seq_id := -1;
end;
if l_seq_id >= 0 then
apex_collection.update_member(
p_collection_name => p_collection_name
,p_seq => l_seq_id
,p_c001 => p_module_name
,p_c002 => l_module_version
,p_c003 => p_module_path
,p_c004 => p_parent_module_name
,p_c005 => p_parent_module_version
,p_c006 => p_parent_module_path
,p_c007 => l_mle_module_name
,p_c008 => l_module_status
,p_clob001 => l_source
);
else
apex_collection.add_member(
p_collection_name => p_collection_name
,p_c001 => p_module_name
,p_c002 => l_module_version
,p_c003 => p_module_path
,p_c004 => p_parent_module_name
,p_c005 => p_parent_module_version
,p_c006 => p_parent_module_path
,p_c007 => l_mle_module_name
,p_c008 => l_module_status
,p_clob001 => l_source
);
end if;
end add_module;
/**
* Extracts imported ES modules from ES module source code and adds them to an APEX collection.
*/
procedure resolve_imported_modules(
p_collection_name in varchar2
,p_module_name in varchar2
,p_module_version in varchar2
,p_module_path in varchar2
)
as
l_source clob;
l_start integer;
l_end integer;
l_line varchar2(32767);
l_module_name varchar2(80);
l_module_version varchar2(80);
l_module_path varchar2(80);
begin
if p_collection_name is null then
/* work without APEX collection, debugging purpose only. */
apex_web_service.clear_request_headers();
l_source := apex_web_service.make_rest_request(
p_url => (
case when p_module_path is null then
apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version)
else
apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version || '/' || p_module_path)
end)
,p_http_method => 'GET'
);
else
select clob001 into l_source
from apex_collections
where 1=1
and collection_name = p_collection_name
and c001 = p_module_name
and c002 = p_module_version
and (
(p_module_path is null and c003 is null)
or
(p_module_path = c003)
)
and c008 = C_MODULE_LOADED;
end if;
l_end := 1;
loop
l_start := dbms_lob.instr(
lob_loc => l_source
,pattern => 'import'
,offset => l_end
);
exit when l_start = 0;
l_end := dbms_lob.instr(
lob_loc => l_source
,pattern => ';'
,offset => l_start
);
l_line := dbms_lob.substr(
lob_loc => l_source
,amount => (l_end - l_start)
,offset => l_start
);
/*
* Extract module name, version and path from the import statement.
*/
get_name_and_version_from_import(
p_import => l_line
,p_module_name => l_module_name
,p_module_version => l_module_version
,p_module_path => l_module_path
);
/*
* Add extracted module to APEX collection if both module name and version are successfully extracted.
*/
if l_module_name is not null and l_module_version is not null then
add_module(
p_collection_name => p_collection_name
,p_module_name => l_module_name
,p_module_version => l_module_version
,p_module_path => l_module_path
,p_parent_module_name => p_module_name
,p_parent_module_version => p_module_version
,p_parent_module_path => p_module_path
);
end if;
l_end := l_start + 1;
end loop;
end resolve_imported_modules;
/**
* Resolve ES modules included in the APEX collection that have not yet been analyzed for their imported ES modules.
*/
procedure resolve_once(
p_collection_name in varchar2
)
as
begin
for r in (
select seq_id,c001,c002,c003,c004,c005,c006,c007,c008,clob001
from apex_collections
where collection_name = p_collection_name
and c008 = C_MODULE_LOADED
)
loop
resolve_imported_modules(
p_collection_name => p_collection_name
,p_module_name => r.c001
,p_module_version => r.c002
,p_module_path => r.c003
);
apex_collection.update_member(
p_collection_name => p_collection_name
,p_seq => r.seq_id
,p_c001 => r.c001
,p_c002 => r.c002
,p_c003 => r.c003
,p_c004 => r.c004
,p_c005 => r.c005
,p_c006 => r.c006
,p_c007 => r.c007
,p_c008 => C_MODULE_RESOLVED
,p_clob001 => r.clob001
);
end loop;
end resolve_once;
/**
* Create MLE Module from ES module stored in APEX Collection.
*/
procedure create_mle_modules(
p_collection_name in varchar2
,p_replace in boolean
)
as
l_sql clob;
l_source clob;
l_module_status varchar2(8);
begin
for r in (
select seq_id,c001,c002,c003,c004,c005,c006,c007,c008,clob001
from apex_collections
where collection_name = p_collection_name
and c008 in (C_MODULE_RESOLVED,C_MODULE_VALID,C_MODULE_INVALID)
)
loop
l_source := r.clob001;
/*
* ES module from jsdelivr is minified, not human readable.
* if APEX application setting MLE_ENV_FOR_PRETTY_PRINT is set, do pretty print.
*/
l_source := make_pretty(l_source);
/*
* Create MLE module from ES module.
*/
l_sql := 'create or replace mle module ' || r.c007 || ' language javascript version ''' || r.c002 || ''' as ' || l_source || '/';
-- apex_debug.info(l_sql);
if r.c008 = C_MODULE_RESOLVED or p_replace then -- create only if MLE module is not exist or force flag is set to true.
begin
execute immediate l_sql;
exception
when others then
-- module status is set from user_objects
null;
end;
end if;
/*
* Verify if MLE module exists and VALID.
*/
begin
select status into l_module_status from user_objects
where object_name = r.c007 and object_type = 'MLE MODULE';
exception
when no_data_found then
l_module_status := C_MODULE_NA;
end;
/*
* Update collection status.
*/
apex_collection.update_member(
p_collection_name => p_collection_name
,p_seq => r.seq_id
,p_c001 => r.c001
,p_c002 => r.c002
,p_c003 => r.c003
,p_c004 => r.c004
,p_c005 => r.c005
,p_c006 => r.c006
,p_c007 => r.c007
,p_c008 => l_module_status
,p_clob001 => l_source
);
end loop;
end create_mle_modules;
/**
* drop all MLE modules if the name start with 'ESM__'
*/
procedure drop_mle_modules_esm
as
l_sql varchar2(4000);
begin
for r in (
select module_name from user_mle_modules where substr(module_name, 1, 4) = 'ESM_'
)
loop
l_sql := 'drop mle module ' || r.module_name;
dbms_output.put_line(l_sql);
execute immediate l_sql;
end loop;
end drop_mle_modules_esm;
/**
* Add imports to MLE Environment.
*/
procedure add_imports_to_mle_env(
p_collection_name in varchar2
,p_mle_env in varchar2
)
as
l_sql varchar2(4000);
l_exist number;
begin
l_sql := 'create mle env if not exists ' || p_mle_env;
execute immediate l_sql;
for r in (
select
case when c003 is null then
C_IMPORT_PRE || c001 || '@' || c002 || C_IMPORT_POST
else
C_IMPORT_PRE || c001 || '@' || c002 || '/' || c003 || C_IMPORT_POST
end import_name
,c007 module_name
from apex_collections
where 1=1
and collection_name = p_collection_name
and c008 = 'VALID'
and c002 is not null
)
loop
begin
select 1 into l_exist from user_mle_env_imports
where 1=1
and import_name = r.import_name
and module_name = r.module_name;
exception
when no_data_found then
l_sql := 'alter mle env ' || p_mle_env || ' add imports(''' || r.import_name || ''' module ' || r.module_name || ')';
execute immediate l_sql;
end;
end loop;
end add_imports_to_mle_env;
end utl_mle_npm;
/