解析したいアプリケーションを選び、プロシージャ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_DEPENDENCYのSCANとCLEAR_CACHEを呼び出すボタンを作成します。また、CLEAR_CACHE_ALLとして、すべてのアプリケーションの解析結果を消去するボタンも作成します。
ボタンSCANについてはホットをオンにします。すべてのボタンについて、外観のテンプレート・オプションのWidthをStretchとし、ボタンの幅が画面に対して均等になるようにします。ボタンCLEAR_CACHEと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とします。
レポートの列から、あまり参照する必要のない、WORKSPACE、WORKSPACE_DISPLAY_NAME、APPLICATION_ID、APPLICATION_NAME、WORKING_COPY_NAME、PAGE_ID、PAGE_NAME、SERIAL_EXECUTION、CURRENT_PROCESS_ID、CURRENT_PROCESS_NAME、CURRENT_PROCESS_SEQUENCE、PROCESS_TYPE_PLUGIN_NAMEをコメント・アウトします。
識別の名前をRegion Selector、タイプとしてリージョン表示セレクタを選択します。外観のテンプレートにBlank with Attributesを選択します。
ビューAPEX_USED_DB_OBJECT_COMP_PROPS、APEX_USED_DB_OBJ_DEPENDENCIESおよびAPEX_USED_DB_OBJECTSをソースとした対話モード・レポートのリージョンを作成します。
リージョンのソースの表名にそれぞれのビュー名を設定し、識別の名前もソースとなるビュー名を設定します。ソースのWHERE句にapplication_id = :P1_APPLICATIONを設定し、直近の解析対象としたアプリケーションに限定して、依存関係を表示します。
関連した複数のアプリケーションが参照しているデータベース・オブジェクトを表示したい場合は、このWHERE句の条件は不要になります。
詳細のリージョン表示セレクタをオンにし、表示されるレポートをリージョン表示セレクタによる切り替えの対象にします。
以上で、画面については完成です。
続いて、ボタンSCAN、CLEAR_CACHE、CLEAR_CACHE_ALLをクリックしたときに実行されるプロセスを作成します。
SCAN処理をバックグラウンドで実行するために、実行チェーンを作成します。
プロセスを作成し、識別の名前をBackground SCAN、タイプを実行チェーンとします。設定の実行限度を1、即時に送信をオン、バックグラウンドで実行をオンにします。IDをアイテムに戻すにP1_EXECUTION_IDを指定します。
シリアライズをオフにします。実行限度は1なので、同時に実行できるバックグランド・プロセスは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を有効にして再コンパイルするページを作成します。
ページ作成ウィザードより、対話モード・レポートの作成を呼び出します。
ページ番号は2、名前はPackages、フォーム・ページを含めるをオンにします。フォーム・ページ番号は3、フォーム・ページ名はPL/Scopeとします。
データ・ソースのSQL SELECT文を入力として以下を記述します。
select * from all_plsql_object_settings where type = 'PACKAGE'
フォームのページでは、オブジェクトの作成や更新ではなく、パッケージの再コンパイルを実装します。
次へ進みます。
主キー列1にOWNER (Varchar2)、主キー列2にName (Varchar2)を選択します。
ページの作成をクリックします。
対話モード・レポートのページを開き、列OWNERとNAMEのタイプを非表示からプレーン・テキストに変更します。主キー列として選択された列は、レポートの表示対象から外されています。
ボタン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を実行します。
ホーム・ページに戻って、ApplicationにCustomersを選択してSCANを実行します。
Status CodeがENQUEUED、EXECUTINGと遷移し、最終的に(処理が成功すれば)SUCCESSに変わります。
ページを手動で再ロードして、現在のステータスを確認します。
SCAN処理が完了すると、それぞれのビューにAPEXアプリケーションを解析した情報が表示されます。
APEX_USED_DB_OBJECTSのリージョンを表示し、Referenced Ownerにワークスペース・スキーマ、Referenced TypeにPACKAGEを選択し、APEXアプリケーションCustomersが呼び出しているPL/SQLパッケージを確認します。
また、Referenced TypeにMETHODが含まれていないことを確認します。
パッケージのPlscope SettingsがIDENTIFIERS:ALLに変更されたことを、レポートから確認します。
ホーム・ページに戻り、再度Scanを実行します。
APEXアプリケーションが参照しているパッケージがIDENTIFIERS:ALLでコンパイルされているため、Referenced TypeにMETHODが現れ、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のアプリケーション作成の参考になれば幸いです。
完