2024年7月3日水曜日

DBMS_PIPEのシングルトン・パイプを使ってAPEXアプリに掲示板を付ける

Oracle Database 23aiで提供されているパッケージDBMS_PIPEにて、シングルトン・パイプという機能がサポートされています。最大32,767バイトのカスタム・メッセージをキャッシュでき、高速にメッセージを取得できます。

シングルトン・パイプについては、Oracleの以下のドキュメントで説明されています。
https://docs.public.oneportal.content.oci.oraclecloud.com/ja-jp/iaas/autonomous-database-serverless/doc/autonomous-singleton-pipe.html

上記のドキュメントからはAutonomous Databaseでの23aiに限定されているように見えますが、シングルトン・パイプについてはOracle Database 23ai Free上でも動作することが確認できています。Oracle Database 23aiのDBMS_PIPEのもう一つの拡張機能、永続メッセージングに対するパイプの使用については、(パッケージDBMS_CLOUDに依存しているため)Autonomous Databaseの23aiに限定された機能のようです。

サンプル・データセットEMP/DEPTをインストールして、APEXアプリケーションを作成します。そのアプリケーションのすべてのページに掲示板のリージョンを作成し、メンテナンスの通知を表示します。


今回の機能はグローバル・ページと新たに追加したページに実装するため、どのようなアプリケーションを選んでも同じように作業ができます。

本記事での説明には、SQLワークショップサンプル・データセットに含まれるEMP/DEPTをインストールしたときに作成できるアプリケーションを使います。


データセットのインストールまたは更新を行うと、最後にアプリケーションの作成を呼び出すことができます。


アプリケーションの作成をクリックすると、アプリケーション作成ウィザードが開きます。機能は使わないため、すべてをチェックをクリックしてチェックをすべて外します

ページの追加をクリックし、空白ページを追加します。ページ名Noticeとします。

以上でアプリケーションの作成を行います。


アプリケーションが作成されます。


今回はコードの色々な箇所でパイプ名の指定があるため、アプリケーション定義置換文字列PIPE_NAMEとして、DBMS_PIPE.CREATE_PIPEを呼び出して作成するパイプの名前を設定します。

今回はパイプ名をBULLETIN_BOARDとします。


グローバル・ページ(ページ番号)に掲示板となるリージョンを作成します。

識別名前掲示板タイプとして動的コンテンツを選択します。ソースCLOBを返すPL/SQLファンクション本体として、以下を記述します。

DBMS_PIPE.RECEIVE_MESSAGEのtimeout0を指定し、メッセージの待機時間を0秒にします。l_statusに0が返されるときはキャッシュされたメッセージが存在します。待機時間は0秒ですがメッセージが存在しないときは、タイムアウトを意味する1が返されます。エラーの場合は1より大きい値が返されます。

l_statusが0のとき、キャッシュされたメッセージをunpackしリージョンに表示します。

レイアウトスロットBannerを選択し、掲示板をページの一番上に表示させます。外観テンプレートに装飾の無いBlack with Attributesを選択し、掲示板の見え方はシングルトン・パイプにキャッシュしたメッセージで決めるようにします。

サーバー側の条件タイプ言語PL/SQLを選択し、PL/SQL式として以下を記述します。

0 = dbms_pipe.receive_message(pipename => :PIPE_NAME,timeout => 0)

シングルトン・パイプにキャッシュされたメッセージが存在するときに限り、掲示板を表示します。


シングルトン・パイプにメッセージをキャッシュする、または、キャッシュをパージする機能を、ページNoticeに実装します。

掲示板に表示するメッセージを設定するボタンを作成します。

識別ボタン名SET_MESSAGEラベルSet Messageです。動作アクションはデフォルトのページの送信とします。


キャッシュされたメッセージをパージするボタンを作成します。

識別ボタン名PURGEラベルPurgeです。動作アクションはデフォルトのページの送信とします。レイアウト新規行の開始オフにし、ボタンSET_MESSAGEの右横に配置します。


メッセージを書き込むページ・アイテムを作成します。

識別名前P7_MESSAGEタイプテキスト領域を選択します。セッション・ステートストレージセッションごと(永続)を選択します。

掲示板に表示するメッセージはHTMLを想定しているため、このページ・アイテムにはHTMLを直接記述します。タイプリッチ・テキスト・エディタとして書式HTMLを選択すると、メッセージの記述にリッチ・テキスト・エディタを使うことができます。


すでにキャッシュされたメッセージがあれば、ページ・アイテムP7_MESSAGEをそのメッセージで初期化するプロセスを作成します。

レンダリング前ヘッダーの前にプロセスInitを作成します。ソースPL/SQLコードとして、以下を記述します。



プロセス・ビューを開きます。

メッセージをシングルトン・パイプにキャッシュするプロセスを作成します。

識別名前Set MessageソースPL/SQLコードとして、以下を記述します。
declare
    l_status integer;
begin
    dbms_pipe.pack_message(:P7_MESSAGE);
    l_status := dbms_pipe.send_message(:PIPE_NAME);
end;
サーバー側の条件ボタン押下時SET_MESSAGEを指定します。


シングルトン・パイプにキャッシュしたメッセージをパージするプロセスを作成します。

識別名前PurgeソースPL/SQLコードとして、以下を記述します。
begin
    dbms_pipe.purge(:PIPE_NAME);
end;
サーバー側の条件ボタン押下時PURGEを指定します。


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

作成したアプリケーションを実行する前に、メッセージをキャッシュするシングルトン・パイプを作成します。pipenameBULLETIN_BOARDです。キャッシュの有効期限として引数shelflife3600秒を設定しています。
declare
    l_status integer;
begin
    l_status := dbms_pipe.create_pipe(
        pipename => 'BULLETIN_BOARD'
        ,private => true
        ,singleton => true
        ,shelflife => 3600
    );
end;

作成済みのパイプはv$db_pipesから確認できます。デフォルトではAPEXワークスペースにSELECT権限が与えられていないため、ユーザーADMINでSELECT権限を与えておく必要があります。

select * from v$db_pipes


DBMS_PIPE.CREATE_PIPEを再度呼び出すことにより、キャッシュの有効期限を変更することができます。すでにシングルトン・パイプが作成済みでもエラーは発生しないようです。

記事の先頭のGIF画像で設定しているメッセージは以下です。
<div style="background-color: var(--u-color-6)">
    <div class="u-flex u-align-items-center">
        <div class="margin-auto u-bold  margin-top-sm margin-bottom-sm">今晩、メンテナンスが予定されています。</div>
    </div>
</div>
今回の記事は以上になります。

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

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