2026年9月4日金曜日

Oracle Databaseの問合せ結果変更通知(QRCN)の動作を確認する

Oracle Backend for Firebaseではサーバー側で発生した変更をクライアントに通知する際に、Oracle Databaseの機能のひとつである連続問合せ通知(CQN - Continuous Query Notification)を使用しています。

データベース開発ガイド, リリース26
20 連続問合せ通知(CQN)の使用

通知の種類には、オブジェクト変更通知(OCN - Object Change Notification)と問合せ結果変更通知(Query Result Change Notification)の2種類があります。表に保存されているデータを対象とした場合、データの新規作成、変更、削除を正確に捉えるにはトリガーを使います。ただし、トリガーを作成するとデータを操作するトランザクションに影響を与えます。連続問合せ通知は、登録したオブジェクトまたは問い合わせ結果の変更がコミットされたときに通知が行われます。PL/SQLによる実装では、登録したコールバック・プロシージャが通知として呼び出されます。トリガーとは異なり、データを変更したトランザクションの外でコールバック・プロシージャの処理が行われるため、通知を登録しても元のトランザクションに影響を与えません。

問合せ結果変更通知とトリガーの違いを説明します。

問合せ結果変更通知には、通知を発生させたトランザクションのトランザクションIDと、変更された行のROWIDが含まれます。問合せ結果変更通知では、以下の状況が発生しえます。
  1. 表EMPの列SALの値を3000から4000に変更し、コミットします。
  2. 上記のトランザクションIDと変更された行のROWIDを含んだデータが、通知として呼び出されたPL/SQLのコールバック・プロシージャに渡されます。
  3. コールバック・プロシージャ内で表EMPの列SALの値を、渡されたROWIDを条件として検索できます。しかし、列SALの値は4000であるとは限りません。
  4. 上記1と3の間に、列SALの値が更新されている可能性があります。
  5. 通知が発生した時点での列SALの値を求めるには、渡されたトランザクションIDを条件としてFlashback Queryを実行して求める必要があります。そこまでする必要があるなら、トリガーを使ったほうが簡単でしょう。
従って、問合せ結果変更通知は名前の通り、データが変更されたことを通知するために使用します。変更された時点でのデータが重要な場合は、トリガーを使用します。

連続問合せ通知(CQN - Continuous Query Notification)はOracle Database 11gからある機能のようですが、まったく聞いたことありませんでした。そのため、APEXアプリケーションを作成して簡単な動作確認をしてみました。

結論を先にいうと、Oracle AI Database 26ai Free 23.26.3.0では不具合があり、動作確認以上のことはできませんでした。

テストに使用したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/APEXlang-exports/tree/main/continuous-query-notification-test

以下のサイトを使うと、APEXにインポート可能なZIPファイルとしてダウンロードできます。
https://download-directory.github.io/

APEXアプリケーションをインポートする前に、APEXのワークスペース・スキーマで連続問合せ通知を使用するための権限を与えます。

GRANT CHANGE NOTIFICATION TO <スキーマ名>;
GRANT EXECUTE ON DBMS_CQ_NOTIFICATION TO <スキーマ名>;


DBAユーザーで実行します。

SQL> GRANT CHANGE NOTIFICATION TO apexdev;


Grantが正常に実行されました。


SQL> GRANT EXECUTE ON DBMS_CQ_NOTIFICATION TO apexdev;


Grantが正常に実行されました。


SQL> 


動作確認に、APEXのサンプル・データセットのEMP/DEPTを使用します。このデータセットに含まれる表EMPに問合せ結果変更通知を設定します。

サンプル・データセットのEMP/DEPTを、あらかじめAPEXワークスペースにインストールしておきます。

以上で準備は完了です。ダウンロードしたAPEXアプリケーションを、APEXワークスペースにインポートします。サポート・オブジェクトをインストールすると、アプリケーションが使用する表、パッケージおよびプロシージャが作成されます。

インポートされたアプリケーションには、以下の機能が実装されています。

Employees - 表EMPを編集します。問合せ結果変更通知を発生させるために使用します。
Definitions - 問合せ結果変更通知の登録と削除を行います。
Notifications - 発生した通知を確認します。
Official Example - 公式ドキュメントにある表NFEVENTS、NFQUERIES、NFTABLECHANGES、NFROWCHANGESに保存されたデータを一覧します。


最初にDefinitionsのページをより、問合せ結果変更通知を設定します。

設定の際に呼び出されるコードは以下です。

Ownerに指定した従業員の給与と手当の変更が通知の対象になります。


OwnerにSCOTTを指定した場合、検知対象のSELECT文として、以下の2行が登録されます。

SELECT APEXDEV.EMP.SAL FROM APEXDEV.EMP WHERE APEXDEV.EMP.ENAME = 'SCOTT'
SELECT APEXDEV.EMP.COMM FROM APEXDEV.EMP WHERE APEXDEV.EMP.ENAME = 'SCOTT'

それぞれ異なるQueryIDが割り振られます。通知として呼び出されるPL/SQLのコールバック・プロシージャにQueryIDも渡されるため、QueryIDから変更されたのが列SALなのか列COMMなのかが判別できます。


従業員SCOTTを変更通知の対象としています。

ナビゲーション・メニューよりEmployeesを開き、従業員SCOTTの給与と手当を更新します。


通知の際に呼び出されるPL/SQLプロシージャTCQ_CALLBACKのコードは以下です。


ナビゲーション・メニューNotificationsを開き、コールバック内で生成した通知メッセージを一覧します。

今回の操作で生成されたメッセージは以下です。列SALおよびCOMMは1つのトランザクションで更新していますが、問合せ結果変更通知として設定したSELECT文は2行なので、通知も2行になります。メッセージにCurrent value is ...と記述していますが、これは通知が参照した値であって、通知の元となったトランザクションで変更された値とは限りません。

SAL query result changed. Current value is 4000.
COMM query result changed. Current value is 200.


ここまでは、問合せ結果変更通知としての動作を確認できます。

この状態から問合せ結果変更通知を追加しようとすると、エラーが発生することがあります。


OpenAI Codexに以下を指示して、障害解析をしてもらいました。


Codexから色々と解析した結果が報告されましたが、最終的にORA-7445が発生しているのでオラクルの不具合だろう、との結論が返されました。

実際に行われた確認作業が分からなかったので、Codexに確認しました。正解といっていいでしょう。


adrciについても、指示通りに実行すると以下の結果が得られました。

adrci> show incident -mode detail -p "incident_id=21599"


ADR Home = /opt/oracle/diag/rdbms/free/FREE:

*************************************************************************


**********************************************************

INCIDENT INFO RECORD 1

**********************************************************

   INCIDENT_ID                   21599

   STATUS                        ready

   CREATE_TIME                   2026-09-04 04:38:50.580000 +00:00

   PROBLEM_ID                    2

   CLOSE_TIME                    <NULL>

   FLOOD_CONTROLLED              none

   ERROR_FACILITY                ORA

   ERROR_NUMBER                  7445

   ERROR_ARG1                    ktcn_is_safe_plsql

   ERROR_ARG2                    SIGSEGV

   ERROR_ARG3                    ADDR:0xFD33BC7E9918

   ERROR_ARG4                    PC:0x2B75020

   ERROR_ARG5                    Address not mapped to object

   ERROR_ARG6                    <NULL>

   ERROR_ARG7                    <NULL>

   ERROR_ARG8                    <NULL>

   ERROR_ARG9                    <NULL>

   ERROR_ARG10                   <NULL>

   ERROR_ARG11                   <NULL>

   ERROR_ARG12                   <NULL>

   SIGNALLING_COMPONENT          Transactions

   SIGNALLING_SUBCOMPONENT       <NULL>

   SUSPECT_COMPONENT             <NULL>

   SUSPECT_SUBCOMPONENT          <NULL>

   ECID                          <NULL>

   IMPACTS                       0

   CON_UID                       3461734982

   PROBLEM_KEY                   ORA 7445 [ktcn_is_safe_plsql]

   FIRST_INCIDENT                12071

   FIRSTINC_TIME                 2026-09-04 01:52:57.428000 +00:00

   LAST_INCIDENT                 21599

   LASTINC_TIME                  2026-09-04 04:38:50.580000 +00:00

   IMPACT1                       0

   IMPACT2                       0

   IMPACT3                       0

   IMPACT4                       0

   KEY_NAME                      PdbName

   KEY_VALUE                     FREEPDB1

   KEY_NAME                      Client ProcId

   KEY_VALUE                     oracle@5f1c1e0baa79 (TNS V1-V3).56677_247037836460048

   KEY_NAME                      SID

   KEY_VALUE                     72.31772

   KEY_NAME                      ECID

   KEY_VALUE                     G6pjTKaG1v3V07ocxodqlg.17

   KEY_NAME                      Service

   KEY_VALUE                     freepdb1

   KEY_NAME                      Module

   KEY_VALUE                     APEXDEV/APEX:APP 100:5

   KEY_NAME                      PQ

   KEY_VALUE                     (16777219, 1788496729)

   KEY_NAME                      Action

   KEY_VALUE                     Processes - point: AFTER_SUBMIT,

   KEY_NAME                      ProcId

   KEY_VALUE                     96.5

   OWNER_ID                      1

   INCIDENT_FILE                 /opt/oracle/diag/rdbms/free/FREE/trace/FREE_ora_56677_1.trc

   OWNER_ID                      1

   INCIDENT_FILE                 /opt/oracle/diag/rdbms/free/FREE/incident/incdir_21599/FREE_ora_56677_i21599.trc

1 row fetched


adrci> 


現在のAIは、適切なツール連携と必要な権限があれば、Oracle Databaseで発生したバグのトリアージに必要な情報を能動的に収集し、分析を進めることができるようです。

問合せ結果変更通知の不具合については残念でしたが、Oracle Databaseの障害調査でAI(OpenAI Codex)が使えるのが分かったことは収穫でした。

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

完