APEXアプリケーションを開発していると、フロントエンドに実装するJavaScriptやCSS、またはバックエンドで実行するSQLやPL/SQLを少し変更して、アプリケーションを実行したいということがあります。
APEXアプリケーションにコードを埋め込んでいる場合は、アプリケーションのコピーを作成してコードを改変することで対応できます。ただし、アプリケーションにコードを埋め込んでいると、単体テストはほぼできません。また、そのままでもCI/CDに乗せるのは大変なのに、さらに大変になります。
海外のパートナーさんでは、レポートのソースとして必ずビューを作りSQLの埋め込みは禁止する、PL/SQLは必ずパッケージを作りコードの埋め込みは禁止する、といった開発標準を採用しているところもあります。
以下よりGitHub、VS Code、APEXのセッション・オーバーライド、Oracle Databaseのエディションの機能を使って、バージョンの異なるコードをAPEXアプリケーションで実行してみます。
初期状態のmainブランチ
以下のアプリケーションを作成します。APEXアプリケーションの作成には、Always FreeのAutonomous Databaseを使用します。
上記のアプリケーションのエクスポートは以下にあります。
https://github.com/ujnak/apexapps/blob/master/exports/edition_app.zip
アプリケーションを作ること自体が目的ではないので、作り方は省略します。
ボタンSet Text をクリックすると、テキスト・フィールドText にThis is MAIN という文字列を挿入します。
これは静的アプリケーション・ファイル に作成したアクションset-my-text を呼び出しています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*
* ボタンSet Textをクリックしたときに、文字列を指定したテキスト・フィールドに設定する。
*/
const SET_MY_TEXT = {
name: "set-my-text",
action: (event, element, args) => {
apex.item(args.target).setValue("This is MAIN");
}
};
/*
* アクションの初期化。
*/
apex.jQuery(window).on('theme42ready', () => {
apex.actions.add([SET_MY_TEXT]);
});
この静的アプリケーション・ファイル は、ページ・プロパティ のJavaScript のファイルURL に設定しています。
ボタンSET_TEXT の詳細 のカスタム属性 として以下を記述し、アクションset-my-text を呼び出します。
data-action="#action$set-my-text?target=P1_TEXT"
動的アクションとしても実装できますが、コード埋め込みを避けています。
ボタン
Set Edition をクリックすると、テキスト・フィールド
Edition に
MAIN という文字列を挿入します。
これはパッケージTEST_PACKAGE に実装したファンクションSHOW_EDITION を実行しています。パッケージのソースは以下になります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create or replace editionable package test_package
/**
* パッケージ本体が作成されているエディション毎に
* 返すメッセージが異なる。
*/
as
function show_edition
return varchar2;
end test_package;
/
show error
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create or replace editionable package body test_package
/**
* mainブランチでの実装。
*/
as
function show_edition
return varchar2
as
begin
return 'MAIN';
end show_edition;
end test_package;
/
show error
このファンクションは、ボタンSET_EDITION を押したときに実行されるプロセス に設定します。プロセス・タイプ はAPIの呼出し です。
パラメータ の
ファンクションの結果 をページ・アイテム
P1_EDITION に設定します。
この場合も、コードの埋め込みは避けています。
クラシック・レポート のソース としてビューEMP_V を使用します。ビューの定義は以下になります。サンプル・データセットのEMP/DEPTに含まれる表EMPを、そのままビューにしています。
ここでも、直接SELECT文を記述しないようにしています。
ビュー定義にeditonable と付けていますが(デフォルトでeditonableなので付けなくても良い)、エディショニング・ビュー(これにはeditioning と付ける)ではありません。異なるオブジェクト・タイプなので注意が必要です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create or replace editionable view emp_v
as
select * from emp;
以上の3つの実装、フロント・エンドのJavaScript、バックエンドのパッケージTEST_PACKAGE、ビューEMP_Vをブランチmainの実装を維持しつつ、新しくブランチを作って改変してみます。
VS Codeの設定
開発にはVS Codeを使用します。以下の拡張機能をインストールします。
Oracle Developer Tools for VS Code (SQL and PLSQL)
Minify
Live Server
GitHub Repositories
および上記に依存関係のある拡張機能をインストールします。
普段VS Codeを使っていないので、ほとんどの時間はVS Codeの使い方を調べること費やしてしまいました。SQL DeveloperのPMのJeff Smithさんが昨年アナウンスしていた、
VS CodeベースのSQL Developerの次世代版 が早くリリースされることを祈るばかりです。
VS Codeを使おうと思ったのは、そうすればGitHub Copilotといった生成AIの恩恵に預かるチャンスがあると思ったためです。特にSQLのSELECT文は、生成AIと相性が良いように思います。PL/SQLはマイナーな言語なので恩恵は少なそうですが、DB 23cからはサーバー側もJavaScriptでコーディングできます。
接続先をAutonomous Databaseとした場合、インスタンス・ウォレットのファイルをダウンロードします。ダウンロードしたウォレットはWallet_インスタンス名.zip となります。このZIPファイルを展開すると、以下のようにTNSエイリアスが定義されているtnsnames.ora 、および自動ログイン・ウォレット・ファイルcwallet.sso が含まれています。
APEXDEV2 % ls -l
total 96
-rw-r--r--@ 1 ********** staff 3029 5 16 06:23 README
-rw-r--r--@ 1 ********** staff 6701 5 16 06:23 cwallet.sso
-rw-r--r--@ 1 ********** staff 6656 5 16 06:23 ewallet.p12
-rw-r--r--@ 1 ********** staff 7475 5 16 06:23 ewallet.pem
-rw-r--r--@ 1 ********** staff 3190 5 16 06:23 keystore.jks
-rw-r--r--@ 1 ********** staff 691 5 16 06:23 ojdbc.properties
-rw-r--r--@ 1 ********** staff 114 5 16 06:23 sqlnet.ora
-rw-r--r--@ 1 ********** staff 1290 5 16 06:23 tnsnames.ora
-rw-r--r--@ 1 ********** staff 3378 5 16 06:23 truststore.jks
APEXDEV2 %
TNS Admin Location およびWallet File Location に、Wallet_インスタンス名.zipを展開したディレクトリ を指定します。また、Use Wallet File (ここでいうWallet Fileはcwallet.ssoのこと)にチェック を入れます。
接続に使用するユーザー名 (User name )およびパスワード (Password )は、APEXのワークスペース・スキーマのものを指定します。
APEXのワークスペースを作成した時点では、ワークスペース・スキーマは外部から接続できるように構成されていません。
ワークスペース・スキーマWKSP_APEXDEV にパスワードを設定し、RESTfulサービスを有効化する必要があります。
alter user wksp_apexdev identified by <パスワード>; begin ords_admin.enable_schema( p_schema => 'WKSP_APEXDEV' ); end; / SQL> alter user wksp_apexdev identified by <パスワード>;
User WKSP_APEXDEVが変更されました。
SQL> begin
2 ords_admin.enable_schema(
3 p_schema => 'WKSP_APEXDEV'
4 );
5 end;
6* /
PL/SQLプロシージャが正常に完了しました。
SQL>
以上の設定で、Oracle Developer Tools for VS Codeの拡張機能を使って、Autonomous Databaseに接続できるようになります。
ブランチed_hanakoとエディションED_HANAKOの準備
ブランチとしてed_hanako を作成し、ブランチmain のアプリケーションを修正します。
ブランチの名前を
ed_hanako とします。
これ以降のGitHubへのコミットが、ブランチ
ed_hanako に対して行われるようになりました。
APEXアプリケーションをホストしているAutonomous Databaseに、管理者ユーザーADMIN で接続します。APEXのワークスペースのスキーマがWKSP_APEXDEV と仮定します。
以下のコマンドを実行し、スキーマをエディションを有効にします。
alter user wksp_apexdev enable editions; SQL> alter user wksp_apexdev enable editions;
User WKSP_APEXDEVが変更されました。
SQL>
エディションED_HANAKO を作成し、スキーマWKSP_APEXDEV で利用可能にします。
create edition ed_hanako as child of ora$base; grant use on edition ed_hanako to wksp_apexdev;
SQL> create edition ed_hanako as child of ora$base;
Edition ED_HANAKOは作成されました。
SQL> grant use on edition ed_hanako to wksp_apexdev;
Grantが正常に実行されました。
SQL>
Oracle Developer Tools for VS CodeでのAutonomous Databaseの接続情報に、ログイン・スクリプト(Login Script )を設定します。
ログイン・スクリプトとして指定するファイルには、以下の行を含めます。データベース接続時にエディションをED_HAHAKO に設定します。
alter session set edition = ED_HANAKO;
作成されているAPEXアプリケーションのコピーを作成し、エディションED_HANAKOで動作するように設定します。
アプリケーションのコピー は
タスク から実行します。
花子さん用のアプリケーションということで、新規アプリケーション名 をEdition App (hanako) とします。
次 へ進みます。
アプリケーションのコピー を実行します。
アプリケーションが作成されたら、
アプリケーション定義 の
セキュリティ の
データベース・セッション を開きます。
初期化PL/SQLコード として以下を記述します。APEXのページ・プロセスは常に、エディションED_HANAKO で動作するようになります。
begin
apex_util.set_edition('ED_HANAKO');
end;
フロントエンドのJavaScriptの修正
APEXアプリケーションには5つの静的アプリケーション・ファイル が含まれており、ボタンSet Textで実行されるアクションはactions.js に記述されています。
GitHubリポジトリのローカル・コピーでは、ディレクトリfrontend 以下にactions.js を作成しています。
EditionApp % ls -lR frontend
total 16
-rw-rw-rw-@ 1 ********** staff 415 5 17 00:33 actions.js
-rw-rw-rw-@ 1 ********** staff 179 5 17 10:29 actions.min.js
drwxr-xr-x@ 5 ********** staff 160 5 17 09:34 icons
frontend/icons:
total 40
-rw-rw-rw-@ 1 ********** staff 2076 5 17 00:33 app-icon-192.png
-rw-rw-rw-@ 1 ********** staff 347 5 17 00:33 app-icon-32.png
-rw-rw-rw-@ 1 ********** staff 10219 5 17 00:33 app-icon-512.png
EditionApp %
Live Server を起動するために、ディレクトリfrontend 以下にファイルindex.html を作成します。以下の内容を記述します。
<html><body>Hanako</body></html>
作成したindex.html を対象にして、Live Server を起動します。
HTTPサーバーがローカルホストの5500番ポートに起動し、index.html およびactions.js 、actions.min.js といったファイルへアクセスできるようになります。
http://127.0.0.1:5500/frontend/ index.html
コピーしたアプリケーションにアクセスします。
Current Edition Name がED_HANAKO であることを確認します。続いて開発者ツール・バー のセッション より、セッション・オーバーライド を実行します。
セッション・オーバーライドの有効化 をオン に変更します。
ファイル・パス のアプリケーション・ファイル#APP_FILES# をオン に変更し、Live ServerのURLであるhttp://127.0.0.1/frontend/ を設定します。
以上の変更を行い、保存 します。
VS Codeでactions.js を変更します。This is MAINをThis is HANAKO に書き換え、保存します。
Command+Shift+P (macOSの場合)を入力しコマンド・パレット を表示し、Minify を実行します。actions.js からactions.min.js を生成します。APEXアプリケーションではデバッグ・モードでない場合はミニファイされたファイルにアクセスします。
ミニファイされたファイル
actions.min.js も変更されたことを確認します。
フラグ が
M に変わります。
アプリケーションをリロードし、ボタンSet Text をクリックします。
テキスト・フィールドText にThis is HANAKO と表示されることを確認します。
この変更は、オリジナルのアプリケーション(ブランチmain、エディションORA$BASE)には影響を与えていません。
拡張機能の
ソース管理 を開き、
actions.js と
actions.min.js をステージします。
+ サインをクリックします。
メッセージ を入力して、変更 をコミットします。
JavaScriptのコードの修正についての説明は、ここまでにします。
バックエンドのPL/SQLパッケージの修正
接続済みのOracle Database を選択し、Open New SQL File を呼び出します。
以下のSELECT文を実行し、設定されているエディションを確認します。
SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') FROM DUAL; 結果がED_HANAKO であることを確認します。
ディレクトリbackend 以下のtest_package.sql (本当は拡張子は.plbにしたかったのだけど、どうしてもVSCodeで上手く扱えなかったので.sqlにしています)を開きます。
ファンクションSHOW_EDITION の戻り値をMAINからHANAKO に変更し、ファイルを保存します。
接続済みデータベースを選択し、Open Existing SQL File を呼び出します。
パッケージ定義test_package.pls を開き、スクリプトを実行 します。
実行結果にエラーがないことを確認します。
同様にパッケージ本体test_package.sql を開き、スクリプトの実行 を行います。
なぜかNot connectedというエラーが発生することがあります。再度実行すると成功するので、原因はよくわかりません。
以下のコードを実行し、コードの変更を確認します。
begin
dbms_output.put_line(test_package.show_edition);
end;
結果が
HANAKO であれば、エディションED_HANAKOでのパッケージの変更は完了です。
エディションHANAKOで動作するアプリケーションを使って、パッケージの変更を確認します。
ボタンSet Edition をクリックすると、Edition にHANAKO と表示されます。
オリジナルのアプリケーションは影響を受けません。
パッケージの修正は以上になります。
バックエンドのビューEMP_Vの修正
パッケージの修正と同じ作業になります。
Open Existing SQL File を呼び出しemp_v.sql を開きます。
ビュー定義に条件句を追加し保存します。その後、スクリプトを実行します。
create or replace editionable view emp_v
as
select * from emp
where deptno = 10;
エディションHANAKOで動作するアプリケーションのページをリロードします。レポートの表示が変わっていることを確認します。
ビューの修正は以上になります。
複数のブランチ/エディションを使う
例えば太郎さんのためにブランチed_taro を作成します。これはブランチmain から派生させます。GitHub側は特別な操作ではありませんが、データベースのエディションの扱いは難しい部分があります。
Oracle Databaseのエディションは、親となるエディションに作成できる子のエディションは1つという制約があります。また、エディションの削除はリーフとなるエディション、つまり最後のエディションしか削除できない、という制限があります。
今までの作業を継続してエディションED_TARO を作成するために、GitHubのブランチmain からed_taro を作成したように、ベース・エディションであるORA$BASE から作成しようとすると、以下のようなエラーが発生します。
SQL> create edition ed_taro as child of ora$base;
次のコマンドの開始中にエラーが発生しました : 行 1 -
create edition ed_taro as child of ora$base
エラー・レポート -
ORA-38807: 実装制限: エディションが持てる子は1つのみです
38807. 00000 - "Implementation restriction: an edition can have only one child"
*Cause: This error occurred because an attempt was made to create more
than one child edition for a parent edition.
*Action: Create the edition as a child of the leaf edition.
SQL>
そのため、エディションED_TARO はED_HANAKO の子エディションとして作成する必要があります。
create edition ed_taro as child of ed_hanako;
SQL> create edition ed_taro as child of ed_hanako;
Edition ED_TAROは作成されました。
SQL>
ワークスペース・スキーマにエディション
ED_TARO を利用する権限を与えます。
grant use on edition ed_taro to wksp_apexdev; そのため、親のエディション(ベース・エディションであるORA$BASE以外)でオブジェクト定義が変更されているものは、対応するSQLファイルを実行してベース・エディションで定義されているオブジェクトを作成する必要があります。
リーフ・エディションのED_TAROを削除し、続いてED_HANAKOを削除します。そしてED_TAROを再度作成します。エディションED_TAROを作成したのち、ブランチed_taroにあるSQLファイルをすべて実行し直し、そのブランチのパッケージやビューを作り直します。
ビューやパッケージの新規作成、ビューの列数の変更、パッケージのサブプログラムの追加、引数の変更などは、ベースであるエディションORA$BASEで実施する必要があります。
スキーマに対してエディションを有効にすると、元に戻すことができません。また、11gから実装されている機能とはいえ、事例が豊富ということは無いようです。環境として、テスト、ステージ、本番があるときに、エディションを活用するのはテスト環境に限定した方が良いように思います。