2024年10月11日金曜日

APEX_APP_OBJECT_DEPENDENCYを使ってAPEXアプリケーションが参照しているデータベース・オブジェクトを確認する

Oracle APEX 24.1から新たにパッケージAPEX_APP_OBJECT_DEPENDENCYが追加されています。このパッケージに含まれているプロシージャSCANを呼び出すことで、APEXアプリケーションから参照されているデータベース・オブジェクトを確認することができます。

解析したいアプリケーションを選び、プロシージャAPEX_APP_OBJECT_DEPENDENCY.SCANを呼び出して、結果を確認するアプリケーションを作成してみました。SCANの結果は、ビューAPEX_USED_DB_OBJECT_COMP_PROPS、APEX_USED_DB_OBJECTSおよびAPEX_USED_DB_OBJ_DEPENDENCIESに保存されます。


ビューAPEX_USED_DB_OBJECT_COMP_PROPSは、解析対象のAPEXアプリケーションに設定されているデータベース・オブジェクト、SQLおよびPL/SQLコードを記録します。

ビューAPEX_USED_DB_OBJ_DEPENDENCIESは、APEX_USED_DB_OBJECT_COMP_PROPSとして取り出されたオブジェクトやコードが参照しているデータベース・オブジェクトを記録します。

ビューAPEX_USED_DB_OBJECTSは、ビューAPEX_USED_DB_OBJ_DEPENDENCIESの内容より、解析対象のAPEXアプリケーションが参照しているデータベース・オブジェクトを重複なしで記録します。

作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/application-object-dependency-scanner.zip

以降より、APEXアプリケーションの作成方法について簡単に紹介します。

最初に空のアプリケーションを作成します。名前Application Object Dependency Scannerとします。

アプリケーションの作成をクリックします。


アプリケーションが作成されます。パッケージAPEX_APP_OBJECT_DEPENDENCYを呼び出す処理は、すべてホーム・ページに実装します。


解析対象となるAPEXアプリケーションを選択するページ・アイテムP1_APPLICATIONを作成します。識別タイプは、APEX 24.1の新機能である1つ選択とします。ラベルApplicationとしています。

LOVタイプとしてSQL問合せを選択し、SQL問合せとして以下を記述します。

サインインしているワークスペースに含まれるAPEXアプリケーションの、どれかを解析対象として選びます。
select application_name d, application_id r from apex_applications where workspace_id = :WORKSPACE_ID


パッケージAPEX_APP_OBJECT_DEPENDENCYSCANCLEAR_CACHEを呼び出すボタンを作成します。また、CLEAR_CACHE_ALLとして、すべてのアプリケーションの解析結果を消去するボタンも作成します。

ボタンSCANについてはホットオンにします。すべてのボタンについて、外観テンプレート・オプションWidthStretchとし、ボタンの幅が画面に対して均等になるようにします。ボタンCLEAR_CACHECLEAR_CACHE_ALLについては、レイアウト新規行の開始オフにし、すべてのボタンを横一列に並べます。

動作アクションとしてページの送信を選択し、データベースの処理はページ・プロセスとして実装します。


ボタンCLEAR_CACHE_ALLは、動作確認の要求オンにして、確認メッセージとして本当に削除しますか?を設定します。スタイル危険を選択し、アプリケーションの解析結果を間違ってクリアしないようにします。


APEX_APP_OBJECT_DEPENDENCY.SCANの処理は、比較的時間がかかります。今回は、SCAN処理はバックグラウンドで実行することにします。

SCANを開始したバッググラウンド処理の実行IDを保存するページ・アイテムP1_EXECUTION_IDを作成します。識別タイプ非表示です。


バックグラウンド・プロセスの状態を表示するリージョンを作成します。

識別名前Scan Processタイプクラシック・レポートとします。ソース表名にバックグラウンド処理のステータスを保持するビューAPEX_APPL_PAGE_BG_PROC_STATUSを設定し、WHERE句execution_id = :P1_EXECUTION_IDを設定します。表示するバックグラウンド処理は、直近のSCANボタンのクリックで開始したバックグラウンド・プロセスに限定します。

外観テンプレートBlank with Attributesとします。

レポートのから、あまり参照する必要のない、WORKSPACEWORKSPACE_DISPLAY_NAMEAPPLICATION_IDAPPLICATION_NAMEWORKING_COPY_NAMEPAGE_IDPAGE_NAMESERIAL_EXECUTIONCURRENT_PROCESS_IDCURRENT_PROCESS_NAMECURRENT_PROCESS_SEQUENCEPROCESS_TYPE_PLUGIN_NAMEコメント・アウトします。


SCANの結果を表示するビューは対話モード・レポートで表示します。それぞれのビューをソースとした対話モード・レポートを、切り替えて表示できるようにリージョン表示セレクタを作成します。

識別名前Region Selectorタイプとしてリージョン表示セレクタを選択します。外観テンプレートBlank with Attributesを選択します。


ビューAPEX_USED_DB_OBJECT_COMP_PROPSAPEX_USED_DB_OBJ_DEPENDENCIESおよびAPEX_USED_DB_OBJECTSソースとした対話モード・レポートのリージョンを作成します。

リージョンのソース表名にそれぞれのビュー名を設定し、識別名前ソースとなるビュー名を設定します。ソースWHERE句application_id = :P1_APPLICATIONを設定し、直近の解析対象としたアプリケーションに限定して、依存関係を表示します。

関連した複数のアプリケーションが参照しているデータベース・オブジェクトを表示したい場合は、このWHERE句の条件は不要になります。

詳細リージョン表示セレクタオンにし、表示されるレポートをリージョン表示セレクタによる切り替えの対象にします。


以上で、画面については完成です。

続いて、ボタンSCANCLEAR_CACHECLEAR_CACHE_ALLをクリックしたときに実行されるプロセスを作成します。

SCAN処理をバックグラウンドで実行するために、実行チェーンを作成します。

プロセスを作成し、識別名前Background SCANタイプ実行チェーンとします。設定実行限度即時に送信オンバックグラウンドで実行オンにします。IDをアイテムに戻すP1_EXECUTION_IDを指定します。

シリアライズオフにします。実行限度なので、同時に実行できるバックグランド・プロセスは1つだけ、また、すでに実行しているバックグラウンド・プロセスがある場合は、待機せずにエラーになります。

サーバー側の条件ボタン押下時SCANを指定します。


実行チェーンBackground SCANに子プロセスを作成します。

識別名前Scanタイプコードを実行実行チェーンBackground SCANです。ソースPL/SQLコードとして以下を記述します。

apex_app_object_dependency.scan(:P1_APPLICATION);


アプリケーションごとにキャッシュをクリアするプロセスを作成します。

識別名前Clear Cacheタイプコードを実行です。ソースPL/SQLコードとして以下を記述します。

apex_app_object_dependency.clear_cache(:P1_APPLICATION);

サーバー側の条件ボタン押下時CLEAR_CACHEを指定します。


キャッシュされているすべてのアプリケーションの情報をクリアするプロセスを作成します。

識別名前Clear Cache ALLタイプコードを実行です。ソースPL/SQLコードとして以下を記述します。
begin
    for c in (select application_id from apex_applications where workspace_id = :WORKSPACE_ID)
    loop
        apex_app_object_dependency.clear_cache(c.application_id);
    end loop;
end;
サーバー側の条件ボタン押下時CLEAR_CACHE_ALLを指定します。


今までの作業で、APEX_APP_OBJECT_DEPENCENCYを使ってAPEXアプリケーションが参照しているデータベース・オブジェクトを確認する実装は完成です。

APIリファレンスのSCANプロシージャに、PL/Scopeの説明があります。

APEXアプリケーションが参照しているPL/SQLパッケージがPL/Scopeを有効にしてコンパイルされていると、APEX_APP_OBJECT_DEPENCENCY.SCANの結果に、APEXアプリケーションが呼び出しているパッケージ名の他に、プロシージャやファンクションも依存関係に含まれるようになります。

APIリファレンスには、PL/Scopeを有効にしてパッケージをコンパイルするコードとして、以下が記載されています。
alter session set plscope_settings='identifiers:all';
exec sys.dbms_utility.compile_schema(user, true);
alter session set plscope_settings='identifiers:none';
依存関係の確認は開発環境で実施し、本番環境では行わないことが推奨されています。そのため、PL/Scopeの設定としてidentifiers:allを設定し、スキーマをすべて再コンパイルしています。

今回作成するアプリケーションは機能の確認を目的としているため、もう少し細かい単位でPL/Scopeを有効化できるようにします。

パッケージを対話モード・レポートに一覧し、パッケージごとにPL/Scopeを有効にして再コンパイルするページを作成します。

ページ作成ウィザードより、対話モード・レポートの作成を呼び出します。

ページ番号名前Packagesフォーム・ページを含めるオンにします。フォーム・ページ番号フォーム・ページ名PL/Scopeとします。

データ・ソースSQL SELECT文を入力として以下を記述します。

select * from all_plsql_object_settings where type = 'PACKAGE'

フォームのページでは、オブジェクトの作成や更新ではなく、パッケージの再コンパイルを実装します。

へ進みます。


主キー列1OWNER (Varchar2)主キー列2Name (Varchar2)を選択します。

ページの作成をクリックします。


対話モード・レポートとフォームのページが作成されます。

対話モード・レポートのページを開き、列OWNERNAMEタイプを非表示からプレーン・テキストに変更します。主キー列として選択された列は、レポートの表示対象から外されています。

ボタンCREATEは不要なので、コメント・アウトします。


フォームのページを開き、ボタンSAVEラベル有効化に変更します。


ボタンDELETEのラベルを無効化に変更します。


ページ・アイテムP3_OWNERタイプ表示のみに変更します。ラベルOwnerとします。


ページ・アイテムP3_NAMEタイプ表示のみに変更します。ラベルNameとします。


左ペインでプロセス・ビューを開き、PL/Scopeを設定して再コンパイルするプロセスを作成します。デフォルトで作成されているプロセス・フォームPL/Scopeコメント・アウトします。

PL/Scopeの設定をIDENTIFIERS:ALLとして再コンパイルするプロセスを作成します。

識別名前Enableとします。タイプコードを実行ソースPL/SQLコードとして以下を記述します。
execute immediate 'ALTER SESSION SET PLSCOPE_SETTINGS=''IDENTIFIERS:ALL''';
execute immediate 'alter package ' || :P3_OWNER || '.' || :P3_NAME || ' compile package';
execute immediate 'ALTER SESSION SET PLSCOPE_SETTINGS=''IDENTIFIERS:NONE''';
サーバー側の条件ボタン押下時SAVEを指定します。


PL/Scopeを無効にするプロセスを作成します。

識別名前Disableとします。タイプコードを実行ソースPL/SQLコードとして以下を記述します。
execute immediate 'ALTER SESSION SET PLSCOPE_SETTINGS=''IDENTIFIERS:NONE''';
execute immediate 'alter package ' || :P3_OWNER || '.' || :P3_NAME || ' compile package';
サーバー側の条件ボタン押下時DELETEを指定します。


以上でパッケージの状態を確認して、PL/Scopeを有効/無効にして再コンパイルするページが追加できました。

ギャラリスターター・アプリケーションに含まれるCustomersをインストールして、今までの実装を確認してみます。

アプリケーションを実行し、ホーム・ページを開きます。最初にClear Cache ALLを実行します。


Packagesのページを開き、列Ownerワークスペース・スキーマで絞り込みます。ワークスペースにあるPL/SQLパッケージのPL/Scopeの設定(列Plscope Settings)がIDENTIFIERS:NONEであることを確認します。スターター・アプリケーションのCustomersは、パッケージEBA_CUSTEBA_CUST_EMAILEBA_CUST_FWEBA_CUST_SAMPLE_DATAを参照しています。

ホーム・ページに戻って、ApplicationCustomersを選択してSCANを実行します。

Status CodeENQUEUEDEXECUTINGと遷移し、最終的に(処理が成功すれば)SUCCESSに変わります。

ページを手動で再ロードして、現在のステータスを確認します。


SCAN処理が完了すると、それぞれのビューにAPEXアプリケーションを解析した情報が表示されます。


APEX_USED_DB_OBJECTSのリージョンを表示し、Referenced Ownerワークスペース・スキーマReferenced TypePACKAGEを選択し、APEXアプリケーションCustomersが呼び出しているPL/SQLパッケージを確認します。


また、Referenced TypeMETHODが含まれていないことを確認します。


Packagesの一覧を開き、パッケージEBA_CUSTEBA_CUST_EMAILEBA_CUST_FWEBA_CUST_SAMPLE_DATAのフォームを開いて、有効化を実行します。


パッケージのPlscope SettingsIDENTIFIERS:ALLに変更されたことを、レポートから確認します。


ホーム・ページに戻り、再度Scanを実行します。

APEXアプリケーションが参照しているパッケージがIDENTIFIERS:ALLでコンパイルされているため、Referenced TypeMETHODが現れ、Referenced Nameパッケージ名Referenced Sub Nameプロシージャ名またはファンクション名が表示されます。


最後にAPEXアプリケーションが参照しているデータベース・オブジェクトから、ビューALL_DEPENDENCIESを検索するページを追加します。

ページ作成ウィザードを呼び出し対話モード・レポートを選択します。

ページ番号4名前all_dependenciesとします。データ・ソースソース・タイプSQL問合せを選択し、SQL SELECT文を入力に以下を記述します。
select * from all_dependencies where (owner, type, name) in (select referenced_owner owner, referenced_type type, referenced_name name from apex_used_db_objects)
以上でページの作成を実行します。


APEX_APP_OBJECT_DEPENDENCY.SCANにより検出したデータベース・オブジェクトが参照しているデータベース・オブジェクトを、ビューALL_DEPENDENCIESより確認することができます。


以上ではアプリケーションは完成です。

APIリファレンスにKnown Limitationsとして制限事項が記載されています。検出対象外の設定もいくつかあるようです。ビューAPEX_USED_DB_OBJECTSだけでなく、ビューAPEX_USED_DB_OBJECT_COMP_PROPSやAPEX_USED_DB_OBJ_DEPENDENCIESも確認することにより、検出対象となっていない設定を確認することができます。

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

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