ヘッダーをスキップ
Oracle Call Interfaceプログラマーズ・ガイド
11g リリース1(11.1)
E05677-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

10 OCIに関する高度なトピック

この章は、次の項目で構成されています。

連続問合せ通知

連続問合せ通知を使用すると、クライアント・アプリケーションがデータベースに問合せを登録し、オブジェクトでのDMLまたはDDL変更に応じて、あるいは問合せに関連付けられた結果セット変更に応じて通知を受信できます。通知は、DMLまたはDDLトランザクションがコミットされるときにデータベースによってパブリッシュされます。

登録時に、アプリケーションは通知ハンドラを指定し、登録する一連の問合せを通知ハンドラに関連付けます。通知ハンドラは、サーバー側のPL/SQLプロシージャでも、クライアント側のC言語のコールバックでもかまいません。登録は、オブジェクト・レベルまたは問合せレベルで作成されます。登録がオブジェクト・レベルにある場合、トランザクションで登録済オブジェクトのいずれかが変更されてコミットされると常に、通知ハンドラが起動されます。登録が問合せレベルにある場合、トランザクションで問合せの結果セットを変更する変更内容がコミットされると常に、通知ハンドラが起動されます。ただし、変更内容が問合せの結果セットに影響しない場合、通知ハンドラは起動されません。


関連項目:


この機能の概念の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』の第13章「連続問合せ通知の使用」を参照してください。

この機能は、その用途の1つとして中間層アプリケーションで使用できます。中間層アプリケーションでは、データをキャッシュし、そのキャッシュをバックエンド・データベースについてできるだけ最新の状態で維持する必要があるためです。

通知の内容として、次の情報が含まれます。

問合せ結果セット通知の使用

連続問合せ(CQ)通知固有のQOS(サービス品質フラグ)を記録するには、サブスクリプション・ハンドルOCI_HTYPE_SUBSCRに属性OCI_ATTR_SUBSCR_CQ_QOSFLAGSを設定します。オブジェクトの細分化レベルではなく問合せの細分化レベルで登録するようにリクエストするには、属性OCI_ATTR_SUBSCR_CQ_QOSFLAGSOCI_SUBSCR_CQ_QOS_QUERYフラグ・ビットを設定します。

オプションで擬似列CQ_NOTIFICATION_QUERY_IDを指定して、登録済問合せの問合せIDを取得できます。この場合、細分化レベルが自動的には問合せレベルに変換されないことに注意してください。戻り時の擬似列の値は、問合せに割り当てられた一意の問合せIDに設定されます。OCIベースの登録の場合は問合せIDの擬似列を省略できますが、その場合は問合せIDが文ハンドルのREAD属性として送信されます。(この属性はOCI_ATTR_CQ_QUERYIDです)。

通知中に、クライアントが指定したコールバックが起動され、トップレベルの通知記述子が引数として渡されます。

変更された問合せの問合せID情報は、OCI_DTYPE_CQDESという特殊な記述子型を介して送られます。問合せのコレクション(OCIColl)が、トップレベルの通知記述子に埋め込まれます。各記述子はOCI_DTYPE_CQDES型です。問合せ記述子の属性は、次のとおりです。

  • OCI_ATTR_CQDES_OPERATION: OCI_EVENT_QUERYCHANGEまたはOCI_EVENT_DEREGです。

  • OCI_ATTR_CQDES_QUERYID: 変更された問合せの問合せIDです。

  • OCI_ATTR_CQDES_TABLE_CHANGES: 問合せ結果セットが変更される原因となった表に対するDML操作を記述する表記述子の配列です。各表記述子はOCI_DTYPE_TABLE_CHDES型です。


関連項目:


「OCI_DTYPE_CQDES」

連続問合せ通知の登録

コール側セッションには、登録対象のすべてのオブジェクトに対するCHANGE NOTIFICATIONシステム権限およびSELECT権限が必要です。登録は、データベースに記録される永続エンティティで、RACのすべてのインスタンスから参照可能です。登録が問合せの細分化レベルにあった場合、RACの任意のインスタンスで問合せ結果セットを変更およびコミットする原因となるトランザクションにより、通知が生成されます。登録がオブジェクトの細分化レベルにあった場合、RACの任意のインスタンスで登録済オブジェクトを変更するトランザクションにより、通知が生成されます。

マテリアライズド・ビューまたは非マテリアライズド・ビューが関係する問合せは、サポートされません。

登録インタフェースは、コールバック、およびAQのネームスペース拡張であるDBCHANGEを使用して、問合せ対象オブジェクトの変更を通知します。

登録を作成する手順は、次のとおりです。

  • 登録は、OCI_EVENTSおよびOCI_OBJECTモードで作成する必要があります。

  • サブスクリプション・ハンドル属性OCI_ATTR_SUBSCR_NAMESPACEをネームスペースOCI_SUBSCR_NAMESPACE_DBCHANGEに設定する必要があります。

  • サブスクリプション・ハンドル属性OCI_ATTR_SUBSCR_CALLBACKを使用して、問合せハンドルに関連したOCIコールバックを格納します。このコールバックには、次のプロトタイプがあります。

    void notification_callback (void *ctx, OCISubscription *subscrhp,
                                void *payload, ub4 paylen, void *desc, ub4 mode);
    

    パラメータの詳細は、「OCIでの通知コールバック」を参照してください。

  • 必要に応じて、OCI_ATTR_SUBSCR_CTXを使用してクライアント固有のコンテキストを関連付けることができます。

  • OCI_ATTR_SUBSCR_TIMEOUTを設定して、ub4タイムアウト間隔を秒単位で指定できます。設定しない場合、タイムアウトはありません。

  • OCI_SUBSCR_QOS_PURGE_ON_NTFNを設定すると、最初の通知で登録が削除されます。

  • OCI_SUBSCR_QOS_RELIABLEを設定すると、通知は永続的になります。ノードに障害が発生した後でも、残存しているRACのインスタンスを使用して、連続問合せ通知メッセージを送受信できます。これは、この登録に関連付けられた、無効化されたメッセージが、データベースに永続的にキューとして残っているためです。FALSEである場合、無効化されたメッセージは高速メモリー内キューにエンキューされます。このオプションは、登録の永続性ではなく通知の永続性を指定するものです。デフォルトでは、登録は自動的に永続的になります。

  • OCISubscriptionRegister()をコールし、DBCHANGEネームスペースに新しい登録を作成します。

  • 複数の問合せ文をサブスクリプション・ハンドルに関連付けるには、文ハンドルOCI_HTYPE_STMTOCI_ATTR_CHNF_REGHANDLE属性を設定します。問合せが実行されると、登録が完了します。

  • サブスクリプションの登録を解除する必要がある場合、クライアントは、サブスクリプション・ハンドルをパラメータとしてOCISubscriptionUnRegister()関数をコールできます。

サブスクリプション・ハンドルへの文ハンドルのバインドが有効なのは、問合せの初回の実行時のみです。アプリケーションが後続の実行時に同じOCI文ハンドルを使用する必要がある場合、アプリケーションは文ハンドルの登録ハンドル属性に再移入する必要があります。文ハンドルをサブスクリプション・ハンドルにバインドできるのは、文が問合せである場合のみです(実行時に判別されます)。実行の一部としてDML文が実行されると、例外が発行されます。

連続問合せ通知のサブスクリプション・ハンドル属性

連続問合せ通知のサブスクリプション・ハンドル属性を次に説明します。属性は、汎用属性(すべてのサブスクリプションに対して共通)と、連続問合せ通知に固有のネームスペース特有属性に分けられます。文ハンドルのWRITE属性を変更できるのは、登録の作成前のみです。

OCI_ATTR_SUBSCR_NAMESPACEWRITE): サブスクリプション・ハンドルの場合、OCI_SUBSCR_NAMESPACE_DBCHANGEに設定する必要があります。

OCI_ATTR_SUBSCR_CALLBACKWRITE): サブスクリプション・ハンドルに関連するコールバックを格納するために使用します。通知を受信すると、コールバックが実行されます。

新しい連続問合せ通知メッセージが作成されると、無効化に関する詳細情報が含まれるOCI_DTYPE_CHDES型の記述子がdescに設定されてコールバックがリスナー・スレッド内で呼び出されます。

汎用フラグOCI_ATTR_SUBSCR_QOSFLAGSを設定する場合は、次の値を使用します。

#define OCI_SUBSCR_QOS_RELIABLE             0x01                 /* reliable */
#define OCI_SUBSCR_QOS_PURGE_ON_NTFN        0x10      /* purge on first ntfn */

OCI_SUBSCR_QOS_RELIABLEを設定すると、通知は永続的になります。したがって、ノードがクラッシュした後でも、残存しているRACクラスタのインスタンスを使用して、無効化されたメッセージを送受信できます。これは、この登録IDに関連付けられた、無効化されたメッセージが、データベースに永続的にキューとして残っているためです。FALSEである場合、無効化されたメッセージは高速メモリー内キューにエンキューされます。このオプションは、登録の永続性ではなく通知の永続性を指定するものです。デフォルトでは、登録は自動的に永続的になります。

OCI_SUBSCR_QOS_PURGE_ON_NTFNビットが設定されている場合は、最初の通知で登録が削除されることを意味します。

パラレルの例を次に示します。

OCI_ATTR_SUBSCR_CQ_QOSFLAGS。この属性では、連続問合せ通知固有の次のQOSフラグを記述します(モードはWRITE、データ型はub4)。

  • 0x1 OCI_SUBSCR_CQ_QOS_QUERY: 設定されている場合、問合せレベルの細分性が必須であることを示します。通知は、問合せ結果セットが変更される場合にのみ生成されます。デフォルトでは、このQOSレベルにFalseの正数はありません。

  • 0x2 OCI_SUBSCR_CQ_QOS_BEST_EFFORT: 設定されている場合、ベスト・エフォート・フィルタリングが許容されることを示します。キャッシュ・アプリケーションで使用できます。データベースでは、評価のコストに基づく経験則を使用し、完全プルーニングを回避できる場合があります。

OCI_ATTR_SUBSCR_TIMEOUT: この属性を使用すると、秒単位で定義したub4タイムアウト値を指定できます。 タイムアウト値が0(ゼロ)または未指定の場合、登録は明示的に解除されるまで有効です。 残りの属性は、連続問合せ通知機能固有のネームスペースまたは機能です。

OCI_ATTR_CHNF_TABLENAMES(データ型は(OCIColl *))− 登録された表名のリストを取り出すための属性です。これらの属性は、問合せの実行後にサブスクリプション・ハンドルから使用できます。

OCI_ATTR_CHNF_ROWIDS− ブール型属性(デフォルトはFALSE)です。TRUEに設定すると、連続問合せ通知メッセージには、操作タイプやROWIDなどの行レベルの詳細が含まれます。

OCI_ATTR_CHNF_OPERATIONS− 操作タイプに基づいて通知をフィルタで選択するために使用するub4フラグです。登録が問合せレベルの細分性を持つ場合、このオプションは無視されます。用意されているフラグは、次のとおりです。

  • OCI_OPCODE_ALL− すべての操作

  • OCI_OPCODE_INSERT− 表に対する挿入操作

  • OCI_OPCODE_UPDATE− 表に対する更新操作

  • OCI_OPCODE_DELETE− 表に対する削除操作

OCI_ATTR_CHNF_CHANGELAG - クライアントが遅延させるトランザクション数を指定するためのub4値です。クライアントは、このオプションを連続問合せ通知メッセージのスロットル・メカニズムとして使用できます。このオプションを選択すると、OCI_ATTR_CHNF_ROWIDSTRUEに設定されていても、通知にROWIDレベルの細分性を持つ情報が含まれなくなります。登録が問合せレベルの細分性を持つ場合、このオプションは無視されます。

OCISubscriptionRegister()コールが呼び出されると、すでに作成されている登録では、前述のいずれの属性も変更できなくなります。これらの属性への変更は、すでに作成されている登録には反映されませんが、新しく作成された、同じ登録ハンドルを使用する登録には反映されます。

NTFNグループ化オプションを使用して、通知の間隔を置くことができます。関連する汎用通知属性は次のとおりです。

OCI_ATTR_SUBSCR_NTFN_GROUPING_VALUE
OCI_ATTR_SUBSCR_NTFN_GROUPING_TYPE
OCI_ATTR_SUBSCR_NTFN_GROUPING_START_TIME
OCI_ATTR_SUBSCR_NTFN_GROUPING_REPEAT_COUNT

関連項目:


これらの属性の詳細は、「データベースへのパブリッシュ・サブスクライブの直接登録」を参照してください。

OCI_ATTR_CQ_QUERYID属性の使用

OCIStmtExecute()のコールによる登録後、文ハンドルOCI_HTYPE_STMTOCI_ATTR_CQ_QUERYID属性が登録済問合せの問合せIDを取得します。

連続問合せ通知の記述子

連続問合せ通知の記述子は、アプリケーションによって指定された通知コールバックのdescパラメータに渡されます。次の属性は、連続問合せ通知に固有のものです。連続問合せ通知の記述子のOCI型定数は、OCI_DTYPE_CHDESです。

通知コールバックは、トップレベルの通知記述子OCI_DTYPE_CHDESを引数として受け取ります。この記述子には、イベント・タイプがOCI_EVENT_QUERYCHANGEであるかOCI_EVENT_OBJCHANGEであるかに基づいて、OCI_DTYPE_CQDESまたはOCI_DTYPE_TABLE_CHDES記述子のコレクションが含まれます。OCI_EVENT_QUERYCHANGE型の通知の場合、連続問合せ記述子には表連続問合せ記述子の配列が埋め込まれます。ROWIDレベルの細分性を持つ情報がリクエストされた場合、各OCI_DTYPE_TABLE_CHDESには変更された各ROWIDに対応する行レベルの連続問合せ記述子(OCI_DTYPE_ROW_CHDES)の配列が含まれます。

OCI_DTYPE_CHDES

これはトップレベルの連続問合せ通知記述子型です。

OCI_ATTR_CHDES_DBNAME (oratext *): データベースの名前(連続問合せ通知のソース)

OCI_ATTR_CHDES_XID (RAW(8)): メッセージのメッセージID

OCI_ATTR_CHDES_NFYTYPE− 通知タイプを示すフラグ。

  • 0x0 OCI_EVENT_NONE: 連続問合せ通知に関する追加情報なし

  • 0x1 OCI_EVENT_STARTUP: インスタンスの起動

  • 0x2 OCI_EVENT_SHUTDOWN: インスタンスの停止

  • 0x3 OCI_EVENT_SHUTDOWN_ANY: 任意のインスタンスの停止: Real Application Clusters(RAC)

  • ox5 OCI_EVENT_DEREG: 登録解除またはタイムアウト

  • 0x6 OCI_EVENT_OBJCHANGE: オブジェクト変更通知

  • 0x7 OCI_EVENT_QUERYCHANGE: 問合せ変更通知

OCI_ATTR_CHDES_TABLE_CHANGES− コレクション型。データ型(OCIColl *)の表への操作を示します。この属性が存在するのはOCI_ATTR_CHDES_NFTYPE属性がOCI_EVENT_OBJCHANGE型だった場合のみで、それ以外の場合はNULLになります。コレクションの各要素は、OCI_DTYPE_TABLE_CHDES型の連続問合せ記述子の表です。

OCI_ATTR_CHDES_QUERIES: 無効化された問合せを記述するコレクション型。コレクションの各メンバーはOCI_DTYPE_CQDES型です。この属性が存在するのはOCI_ATTR_CHDES_NFTYPE属性がOCI_EVENT_QUERYCHANGEだった場合のみで、それ以外の場合はNULLになります。

OCI_DTYPE_CQDES

この通知記述子は、通常はDMLトランザクションまたはDDLトランザクションのコミットに応じて、無効化された問合せを記述します。属性は次のとおりです。

OCI_ATTR_CQDES_OPERATION (ub4, READ): 問合せで発生した操作。次の2つの値のいずれかです。

  • OCI_EVENT_QUERYCHANGE: 問合せ結果セットの変更

  • OCI_EVENT_DEREG: 問合せの登録解除

OCI_ATTR_CQDES_TABLE_CHANGES (OCIColl *, READ): 問合せ結果セットの変更原因となった表に対するDMLまたはDDL操作を記述する、表連続問合せ記述子のコレクション。コレクションの各要素はOCI_DTYPE_TABLE_CHDES型です。

OCI_ATTR_CQDES_QUERYID (ub8, READ): 無効化された問合せの問合せID。

OCI_DTYPE_TABLE_CHDES

この通知記述子は、登録済問合せに関係する表の変更内容に関する情報を送信します。

  • OCI_ATTR_CHDES_TABLE_NAME (oratext *): スキーマ注釈付き表名。

  • OCI_ATTR_CHDES_TABLE_OPFLAGS (ub4)− 表への操作を示すフラグのフィールド。次の各フラグ・フィールドは、属性内の個別のビット位置にあります。

    • 0x1 OCI_OPCODE_ALLROWS: 表は完全に無効化されています。

    • 0x2 OCI_OPCODE_INSERT: 表に対する挿入操作。

    • 0x4 OCI_OPCODE_UPDATE: 表に対する更新操作。

    • 0x8 OCI_OPCODE_DELETE: 表に対する削除操作。

    • 0x10 OCI_OPCODE_ALTER: 表は変更されました(スキーマ変更)。これには、行の移行を引き起こしたDDL文と内部操作が含まれます。

    • 0x20 OCI_OPCODE_DROP: 表は削除されました。

  • OCI_ATTR_CHDES_TABLE_ROW_CHANGES− これは、表内の行の変更を示す埋込みコレクションです。コレクションの各要素は、次の属性を持つOCI_DTYPE_ROW_CHDES型の行連続問合せ記述子です。

    • OCI_ATTR_CHDES_ROW_ROWID (OraText *)− ROWIDの文字列表現。

    • OCI_ATTR_CHDES_ROW_OPFLAGS− 操作タイプ(INSERTUPDATEDELETEまたはOTHER)を反映します。

連続問合せ通知の例

簡単なOCIプログラムdemoquery.cを次に示します。リストにあるコメントを参照してください。コール側セッションには、登録対象のすべてのオブジェクトに対するCHANGE NOTIFICATIONシステム権限およびSELECT権限が必要です。

/* Copyright (c) 2006, Oracle. All rights reserved.  */

#ifndef S_ORACLE
# include <oratypes.h>
#endif

/**************************************************************************
 *This is a DEMO program. To test, compile the file to generate the executable
 *demoquery. Then demoquery can be invoked from a command prompt.
 *It will have the following output:

Initializing OCI Process
Registering query : select last_name, employees.department_id, department_name
                     from employees, departments
                     where employee_id = 200
                     and employees.department_id = departments.department_id
Query Id 23
Waiting for Notifications

*Then from another session, log in as HR/HR and perform the following
* DML transactions. It will cause two notifications to be generated.

update departments set department_name ='Global Admin' where department_id=10;
commit;
update departments set department_name ='Adminstration' where department_id=10;
commit;

*The demoquery program will now show the following output corresponding
*to the notifications received.


Query 23 is changed
Table changed is HR.DEPARTMENTS table_op 4
Row changed is AAAMBoAABAAAKX2AAA row_op 4
Query 23 is changed
Table changed is HR.DEPARTMENTS table_op 4
Row changed is AAAMBoAABAAAKX2AAA row_op 4


*The demo program waits for exactly 10 notifications to be received before
*logging off and unregistering the subscription.

***************************************************************************/

/*---------------------------------------------------------------------------
                     PRIVATE TYPES AND CONSTANTS
  ---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
                     STATIC FUNCTION DECLARATIONS
  ---------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oci.h>

#define MAXSTRLENGTH 1024

static int notifications_processed = 0;
static OCISubscription *subhandle1 = (OCISubscription *)0;
static OCISubscription *subhandle2 = (OCISubscription *)0;
static void checker(/*_ OCIError *errhp, sword status _*/);
static void registerQuery(/*_ OCISvcCtx *svchp, OCIError *errhp, OCIStmt *stmthp,
                           OCIEnv *envhp _*/);
static void myCallback (/*_  dvoid *ctx, OCISubscription *subscrhp,
                        dvoid *payload, ub4 *payl, dvoid *descriptor,
                        ub4 mode _*/);
static int NotificationDriver(/*_ int argc, char *argv[]  _*/);
static sword status;
static boolean logged_on = FALSE;
static void processRowChanges(OCIEnv *envhp, OCIError *errhp, OCIStmt *stmthp,
                               OCIColl *row_changes);
static void processTableChanges(OCIEnv *envhp, OCIError *errhp,
                 OCIStmt *stmthp, OCIColl *table_changes);
static void processQueryChanges(OCIEnv *envhp, OCIError *errhp, OCIStmt *stmthp,
                 OCIColl *query_changes);
static int nonractests2(/*_ int argc, char *argv[] _*/);


int main(int argc, char **argv)
{

  NotificationDriver(argc, argv);
  return 0;
}


int NotificationDriver(argc, argv)
int argc;
char *argv[];
{
  OCIEnv *envhp;
  OCISvcCtx *svchp, *svchp2;
  OCIError *errhp, *errhp2;
  OCISession *authp, *authp2;
  OCIStmt *stmthp, *stmthp2;
  OCIDuration dur, dur2;
  int i;
  dvoid *tmp;
  OCISession *usrhp;
  OCIServer *srvhp;

  printf("Initializing OCI Process\n");
/* Initialize the environment. The environment has to be initialized
     with OCI_EVENTS and OCI_OBJECTS to create a continuous query notification
     registration and receive notifications.
  */
  OCIEnvCreate( (OCIEnv **) &envhp, OCI_EVENTS|OCI_OBJECT, (dvoid *)0,
                    (dvoid * (*)(dvoid *, size_t)) 0,
                    (dvoid * (*)(dvoid *, dvoid *, size_t))0,
                    (void (*)(dvoid *, dvoid *)) 0,
                    (size_t) 0, (dvoid **) 0 );

  OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR,
                         (size_t) 0, (dvoid **) 0);
   /* server contexts */
  OCIHandleAlloc((dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER,
                 (size_t) 0, (dvoid **) 0);
  OCIHandleAlloc((dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX,
                 (size_t) 0, (dvoid **) 0);
   checker(errhp,OCIServerAttach(srvhp, errhp, (text *) 0, (sb4) 0,
                                 (ub4) OCI_DEFAULT));
  /* set attribute server context in the service context */
  OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp,
              (ub4) 0, (ub4) OCI_ATTR_SERVER, (OCIError *) errhp);

   /* allocate a user context handle */
  OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION,
                               (size_t) 0, (dvoid **) 0);

  OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION,
             (dvoid *)((text *)"HR"), (ub4)strlen((char *)"HR"),
              OCI_ATTR_USERNAME, errhp);

 OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION,
            (dvoid *)((text *)"HR"), (ub4)strlen((char *)"HR"),
             OCI_ATTR_PASSWORD, errhp);
   checker(errhp,OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS,
           OCI_DEFAULT));
   /* Allocate a statement handle */
  OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp,
                                (ub4) OCI_HTYPE_STMT, 52, (dvoid **) &tmp);

  OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, (dvoid *)usrhp, (ub4)0,
                       OCI_ATTR_SESSION, errhp);

  registerQuery(svchp, errhp, stmthp, envhp);
  printf("Waiting for Notifications\n");
  while (notifications_processed !=10)
  {
    sleep(1);
  }
  printf ("Going to unregister HR\n");
  fflush(stdout);
  /* Unregister HR */
  checker(errhp,
           OCISubscriptionUnRegister(svchp, subhandle1, errhp, OCI_DEFAULT));
  checker(errhp, OCISessionEnd(svchp, errhp, usrhp, (ub4) 0));
   printf("HR Logged off.\n");

  if (subhandle1)
     OCIHandleFree((dvoid *)subhandle1, OCI_HTYPE_SUBSCRIPTION);
  if (stmthp)
     OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT);
  if (srvhp)
     OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER);
  if (svchp)
     OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX);
  if (authp)
     OCIHandleFree((dvoid *) usrhp, (ub4) OCI_HTYPE_SESSION);
  if (errhp)
     OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR);
  if (envhp)
     OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV);


  return 0;

}

void checker(errhp, status)
OCIError *errhp;
sword status;
{
  text errbuf[512];
  sb4 errcode = 0;
  int retval = 1;

  switch (status)
  {
  case OCI_SUCCESS:
    retval = 0;
    break;
  case OCI_SUCCESS_WITH_INFO:
    (void) printf("Error - OCI_SUCCESS_WITH_INFO\n");
    break;
 case OCI_NEED_DATA:
    (void) printf("Error - OCI_NEED_DATA\n");
    break;
  case OCI_NO_DATA:
    (void) printf("Error - OCI_NODATA\n");
    break;
  case OCI_ERROR:
    (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode,
                        errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
    (void) printf("Error - %.*s\n", 512, errbuf);
    break;
  case OCI_INVALID_HANDLE:
    (void) printf("Error - OCI_INVALID_HANDLE\n");
    break;
  case OCI_STILL_EXECUTING:
    (void) printf("Error - OCI_STILL_EXECUTE\n");
    break;
  case OCI_CONTINUE:
    (void) printf("Error - OCI_CONTINUE\n");
    break;
  default:
    break;
 }
  if (retval)
  {
    exit(1);
  }
}


void processRowChanges(OCIEnv *envhp, OCIError *errhp, OCIStmt *stmthp,
                         OCIColl *row_changes)
{
  dvoid **row_descp;
  dvoid *row_desc;
  boolean exist;
  ub2 i, j;
  dvoid *elemind = (dvoid *)0;
  oratext *row_id;
  ub4 row_op;


   sb4 num_rows;
   if (!row_changes) return;
    checker(errhp, OCICollSize(envhp, errhp,
                    (CONST OCIColl *) row_changes, &num_rows));
    for (i=0; i<num_rows; i++)
    {
      checker(errhp, OCICollGetElem(envhp,
                     errhp, (OCIColl *) row_changes,
                     i, &exist, &row_descp, &elemind));

      row_desc = *row_descp;
      checker(errhp, OCIAttrGet (row_desc,
                  OCI_DTYPE_ROW_CHDES, (dvoid *)&row_id,
                  NULL, OCI_ATTR_CHDES_ROW_ROWID, errhp));
      checker(errhp, OCIAttrGet (row_desc,
                  OCI_DTYPE_ROW_CHDES, (dvoid *)&row_op,
                  NULL, OCI_ATTR_CHDES_ROW_OPFLAGS, errhp));

      printf ("Row changed is %s row_op %d\n", row_id, row_op);
      fflush(stdout);
    }
}

void processTableChanges(OCIEnv *envhp, OCIError *errhp, OCIStmt *stmthp,
                         OCIColl *table_changes)
{
  dvoid **table_descp;
  dvoid *table_desc;
  dvoid **row_descp;
  dvoid *row_desc;
  OCIColl *row_changes = (OCIColl *)0;
  boolean exist;
  ub2 i, j;
  dvoid *elemind = (dvoid *)0;
  oratext *table_name;
  ub4 table_op;


   sb4 num_tables;
   if (!table_changes) return;
    checker(errhp, OCICollSize(envhp, errhp,
                    (CONST OCIColl *) table_changes, &num_tables));
    for (i=0; i<num_tables; i++)
    {
      checker(errhp, OCICollGetElem(envhp,
                     errhp, (OCIColl *) table_changes,
                     i, &exist, &table_descp, &elemind));

      table_desc = *table_descp;
      checker(errhp, OCIAttrGet (table_desc,
                  OCI_DTYPE_TABLE_CHDES, (dvoid *)&table_name,
                  NULL, OCI_ATTR_CHDES_TABLE_NAME, errhp));
      checker(errhp, OCIAttrGet (table_desc,
                  OCI_DTYPE_TABLE_CHDES, (dvoid *)&table_op,
                  NULL, OCI_ATTR_CHDES_TABLE_OPFLAGS, errhp));
      checker(errhp, OCIAttrGet (table_desc,
                  OCI_DTYPE_TABLE_CHDES, (dvoid *)&row_changes,
                  NULL, OCI_ATTR_CHDES_TABLE_ROW_CHANGES, errhp));

      printf ("Table changed is %s table_op %d\n", table_name,table_op);
      fflush(stdout);
     if (!bit(table_op, OCI_OPCODE_ALLROWS))
       processRowChanges(envhp, errhp, stmthp, row_changes);
    }
}

void processQueryChanges(OCIEnv *envhp, OCIError *errhp, OCIStmt *stmthp,
                         OCIColl *query_changes)
{
  sb4 num_queries;
  ub8 queryid;
  OCINumber qidnum;
  ub4 queryop;
  dvoid *elemind = (dvoid *)0;
  dvoid *query_desc;
  dvoid **query_descp;
  ub2 i;
  boolean exist;
  OCIColl *table_changes = (OCIColl *)0;

  if (!query_changes) return;
  checker(errhp, OCICollSize(envhp, errhp,
                     (CONST OCIColl *) query_changes, &num_queries));
  for (i=0; i < num_queries; i++)
  {
    checker(errhp, OCICollGetElem(envhp,
                     errhp, (OCIColl *) query_changes,
                     i, &exist, &query_descp, &elemind));

    query_desc = *query_descp;
    checker(errhp, OCIAttrGet (query_desc,
                  OCI_DTYPE_CQDES, (dvoid *)&queryid,
                  NULL, OCI_ATTR_CQDES_QUERYID, errhp));
    checker(errhp, OCIAttrGet (query_desc,
                  OCI_DTYPE_CQDES, (dvoid *)&queryop,
                  NULL, OCI_ATTR_CQDES_OPERATION, errhp));
    printf(" Query %d is changed\n", queryid);
    if (queryop == OCI_EVENT_DEREG)
      printf("Query Deregistered\n");
      checker(errhp, OCIAttrGet (query_desc,
                  OCI_DTYPE_CQDES, (dvoid *)&table_changes,
                  NULL, OCI_ATTR_CQDES_TABLE_CHANGES, errhp));
      processTableChanges(envhp, errhp, stmthp, table_changes);


   }
}


void myCallback (ctx, subscrhp, payload, payl, descriptor, mode)
dvoid *ctx;
OCISubscription *subscrhp;
dvoid *payload;
ub4 *payl;
dvoid *descriptor;
ub4 mode;
{
  OCIColl *table_changes = (OCIColl *)0;
  OCIColl *row_changes = (OCIColl *)0;
  dvoid *change_descriptor = descriptor;
  ub4 notify_type;
  ub2 i, j;
  OCIEnv *envhp;
  OCIError *errhp;
  OCIColl *query_changes = (OCIColl *)0;
  OCIServer *srvhp;
  OCISvcCtx *svchp;
  OCISession *usrhp;
  dvoid     *tmp;
  OCIStmt *stmthp;

 (void)OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t)0, (dvoid **)0 );

  (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR,
                   (size_t) 0, (dvoid **) 0);
   /* server contexts */
  (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER,
                   (size_t) 0, (dvoid **) 0);

  (void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX,
                   (size_t) 0, (dvoid **) 0);

  OCIAttrGet (change_descriptor, OCI_DTYPE_CHDES, (dvoid *) &notify_type,
              NULL, OCI_ATTR_CHDES_NFYTYPE, errhp);
  fflush(stdout);
  if (notify_type == OCI_EVENT_SHUTDOWN ||
      notify_type == OCI_EVENT_SHUTDOWN_ANY)
  {
     printf("SHUTDOWN NOTIFICATION RECEIVED\n");
     fflush(stdout);
     notifications_processed++;
     return;
  }
 if (notify_type == OCI_EVENT_STARTUP)
  {
     printf("STARTUP NOTIFICATION RECEIVED\n");
     fflush(stdout);
     notifications_processed++;
     return;
  }

  notifications_processed++;
  checker(errhp, OCIServerAttach( srvhp, errhp, (text *) 0, (sb4) 0,
                                  (ub4) OCI_DEFAULT));

  OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, (ub4) OCI_HTYPE_SVCCTX,
                  52, (dvoid **) &tmp);
  /* set attribute server context in the service context */
  OCIAttrSet( (dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)srvhp,
              (ub4) 0, (ub4) OCI_ATTR_SERVER, (OCIError *) errhp);

  /* allocate a user context handle */
  OCIHandleAlloc((dvoid *)envhp, (dvoid **)&usrhp, (ub4) OCI_HTYPE_SESSION,
           (size_t) 0, (dvoid **) 0);

  OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION,
           (dvoid *)"HR", (ub4)strlen("HR"), OCI_ATTR_USERNAME, errhp);

  OCIAttrSet((dvoid *)usrhp, (ub4)OCI_HTYPE_SESSION,
           (dvoid *)"HR", (ub4)strlen("HR"),
           OCI_ATTR_PASSWORD, errhp);

  checker(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS,
                                   OCI_DEFAULT));

  OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX,
           (dvoid *)usrhp, (ub4)0, OCI_ATTR_SESSION, errhp);

  /* Allocate a statement handle */
  OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp,
                  (ub4) OCI_HTYPE_STMT, 52, (dvoid **) &tmp);

  if (notify_type == OCI_EVENT_OBJCHANGE)
  {
    checker(errhp, OCIAttrGet (change_descriptor,
                OCI_DTYPE_CHDES, &table_changes, NULL,
                OCI_ATTR_CHDES_TABLE_CHANGES, errhp));
    processTableChanges(envhp, errhp, stmthp, table_changes);
  }
  else if (notify_type == OCI_EVENT_QUERYCHANGE)
  {
     checker(errhp, OCIAttrGet (change_descriptor,
                OCI_DTYPE_CHDES, &query_changes, NULL,
                OCI_ATTR_CHDES_QUERIES, errhp));
      processQueryChanges(envhp, errhp, stmthp, query_changes);
  }
   checker(errhp, OCISessionEnd(svchp, errhp, usrhp, OCI_DEFAULT));
  checker(errhp, OCIServerDetach(srvhp, errhp, OCI_DEFAULT));
 if (stmthp)
    OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT);
  if (errhp)
    OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR);
  if (srvhp)
    OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER);
  if (svchp)
    OCIHandleFree((dvoid *)svchp, OCI_HTYPE_SVCCTX);
  if (usrhp)
    OCIHandleFree((dvoid *)usrhp, OCI_HTYPE_SESSION);
  if (envhp)
    OCIHandleFree((dvoid *)envhp, OCI_HTYPE_ENV);

}

void registerQuery(svchp, errhp, stmthp, envhp)
OCISvcCtx *svchp;
OCIError *errhp;
OCIStmt *stmthp;
OCIEnv *envhp;
{
  OCISubscription *subscrhp;
  ub4 namespace = OCI_SUBSCR_NAMESPACE_DBCHANGE;
  ub4 timeout = 60;
  OCIDefine *defnp1 = (OCIDefine *)0;
  OCIDefine *defnp2 = (OCIDefine *)0;
  OCIDefine *defnp3 = (OCIDefine *)0;
  OCIDefine *defnp4 = (OCIDefine *)0;
  OCIDefine *defnp5 = (OCIDefine *)0;
  int mgr_id =0;
text query_text1[] = "select last_name, employees.department_id, department_name \
 from employees,departments where employee_id = 200 and employees.department_id =\
  departments.department_id";

  ub4 num_prefetch_rows = 0;
  ub4 num_reg_tables;
  OCIColl *table_names;
  ub2 i;
  boolean rowids = TRUE;
  ub4 qosflags = OCI_SUBSCR_CQ_QOS_QUERY  ;
  int empno=0;
  OCINumber qidnum;
  ub8 qid;
  char outstr[MAXSTRLENGTH], dname[MAXSTRLENGTH];
  int q3out;

    fflush(stdout);
  /* allocate subscription handle */
  OCIHandleAlloc ((dvoid *) envhp, (dvoid **) &subscrhp,
                  OCI_HTYPE_SUBSCRIPTION, (size_t) 0, (dvoid **) 0);

  /* set the namespace to DBCHANGE */
  checker(errhp, OCIAttrSet (subscrhp, OCI_HTYPE_SUBSCRIPTION,
                  (dvoid *) &namespace, sizeof(ub4),
                  OCI_ATTR_SUBSCR_NAMESPACE, errhp));

  /* Associate a notification callback with the subscription */
  checker(errhp, OCIAttrSet (subscrhp, OCI_HTYPE_SUBSCRIPTION,
                  (void *)myCallback, 0, OCI_ATTR_SUBSCR_CALLBACK, errhp));
 /* Allow extraction of rowid information */
  checker(errhp, OCIAttrSet (subscrhp, OCI_HTYPE_SUBSCRIPTION,
                  (dvoid *)&rowids, sizeof(ub4),
                  OCI_ATTR_CHNF_ROWIDS, errhp));

     checker(errhp, OCIAttrSet (subscrhp, OCI_HTYPE_SUBSCRIPTION,
                  (dvoid *)&qosflags, sizeof(ub4),
                  OCI_ATTR_SUBSCR_CQ_QOSFLAGS, errhp));

  /* Create a new registration in the DBCHANGE namespace */
  checker(errhp,
           OCISubscriptionRegister(svchp, &subscrhp, 1, errhp, OCI_DEFAULT));

  /* Multiple queries can now be associated with the subscription */

    subhandle1 = subscrhp;


    printf("Registering query : %s\n", (const signed char *)query_text1);
    /* Prepare the statement */
    checker(errhp, OCIStmtPrepare (stmthp, errhp, query_text1,
            (ub4)strlen((const signed char *)query_text1), OCI_V7_SYNTAX,
            OCI_DEFAULT));

    checker(errhp,
           OCIDefineByPos(stmthp, &defnp1,
                  errhp, 1, (dvoid *)outstr, MAXSTRLENGTH * sizeof(char),
                  SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
    checker(errhp,
           OCIDefineByPos(stmthp, &defnp2,
                     errhp, 2, (dvoid *)&empno, sizeof(empno),
                     SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
    checker(errhp,
           OCIDefineByPos(stmthp, &defnp3,
                      errhp, 3, (dvoid *)&dname, sizeof(dname),
                     SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT));

    /* Associate the statement with the subscription handle */
    OCIAttrSet (stmthp, OCI_HTYPE_STMT, subscrhp, 0,
              OCI_ATTR_CHNF_REGHANDLE, errhp);

    /* Execute the statement, the execution performs object registration */
    checker(errhp, OCIStmtExecute (svchp, stmthp, errhp, (ub4) 1, (ub4) 0,
                 (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL ,
                 OCI_DEFAULT));
    fflush(stdout);

    OCIAttrGet(stmthp, OCI_HTYPE_STMT, &qid, (ub4 *)0,
                OCI_ATTR_CQ_QUERYID, errhp);
    printf("Query Id %d\n", qid);

  /* commit */
  checker(errhp, OCITransCommit(svchp, errhp, (ub4) 0));

}

static void cleanup(envhp, svchp, srvhp, errhp, usrhp)
OCIEnv *envhp;
OCISvcCtx *svchp;
OCIServer *srvhp;
OCIError *errhp;
OCISession *usrhp;
{
  /* detach from the server */
  checker(errhp, OCISessionEnd(svchp, errhp, usrhp, OCI_DEFAULT));
  checker(errhp, OCIServerDetach(srvhp, errhp, (ub4)OCI_DEFAULT));

  if (usrhp)
    (void) OCIHandleFree((dvoid *) usrhp, (ub4) OCI_HTYPE_SESSION);
  if (svchp)
    (void) OCIHandleFree((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX);
  if (srvhp)
    (void) OCIHandleFree((dvoid *) srvhp, (ub4) OCI_HTYPE_SERVER);
  if (errhp)
    (void) OCIHandleFree((dvoid *) errhp, (ub4) OCI_HTYPE_ERROR);
  if (envhp)
    (void) OCIHandleFree((dvoid *) envhp, (ub4) OCI_HTYPE_ENV);

}

データベースの起動と停止

OCI関数OCIDBStartup()およびOCIDBShutdown()には、Oracleデータベースを起動および停止するために最小限必要なインタフェースが用意されています。C言語のプログラムから、OCIDBStartup()をコールする前に、サーバーに接続し、事前認証モードでSYSDBAまたはSYSOPERセッションを開始する必要があります。インスタンスが起動していない場合はこのモードのみを使用できます。このモードはインスタンスを起動するためにのみ使用されます。OCIDBStartup()をコールすると、データベースをマウントまたはオープンせずに1つのサーバー・インスタンスが起動します。データベースをマウントまたはオープンするには、事前認証セッションを終了し、通常のSYSDBAまたはSYSOPERセッションを開始し、適切なALTER DATABASE文を実行します。

データベースを停止するには、アクティブなSYSDBAまたはSYSOPERセッションが必要です。OCI_DBSHUTDOWN_ABORT以外のすべてのモードでは、OCIDBShutdown()を2通りでコールします。1つは、データベースに対するこれ以上の接続を禁止することにより停止操作を開始するコールで、この後に適切なALTER DATABASEコマンドが続き、データベースをディスマウントしてクローズします。もう1つのコールは、インスタンスを停止して停止操作を終了するためのコードです。特別な状況では、データベースをできるだけ速く停止するために、OCIDBShutdown()OCI_DBSHUTDOWN_ABORTモードでコールします。このモードは、SQL*PlusのSHUTDOWN ABORTと等価です。

これらの関数は両方とも、サーバーに対する専用接続を必要とします。ディスパッチャを介して共有サーバーに接続されている場合、データベースを起動または停止しようとすると、ORA-106が発生します。

OCIAdmin管理ハンドル・データ型を使用して、インタフェースを拡張可能にします。OCIAdminは、ハンドル・タイプOCI_HTYPE_ADMINに関連付けられています。OCIAdminパラメータadmhpに値を渡すかどうかは、OCIDBStartup()ではオプションで選択できますが、OCIDBShutdown()では不要です。


関連項目:


OCIでの起動と停止の例

起動するには、SYSOPERまたはSYSDBAとしてOCI_PRELIM_AUTHモードでデータベースに接続する必要があります。ディスパッチャを介して共有サーバーには接続できません。クライアント側のパラメータ・ファイル(pfile)を使用するには、OCIAttrSet()を使用して属性OCI_ATTR_ADMIN_PFILEを管理ハンドルに設定する必要があります。このように設定しない場合、サーバー側のパラメータ・ファイル(spfile)が使用されます。サーバー側のパラメータ・ファイルの場合、(OCIAdmin *)0を渡します。OCIDBStartup()をコールすると、サーバー上の1つのインスタンスが起動します。

次のコード例では、管理ハンドルに設定されているクライアント側のパラメータ・ファイル(pfile)を使用しています。

...

/*  Example 0 - Startup:  */
OCIAdmin *admhp;
text *mount_stmt = (text *)"ALTER DATABASE MOUNT";
text *open_stmt = (text *)"ALTER DATABASE OPEN";
text *pfile = (text *)"/ade/viewname/oracle/work/t_init1.ora";

/* Start the authentication session */
checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp,
         OCI_CRED_RDBMS, OCI_SYSDBA|OCI_PRELIM_AUTH));

/* Allocate admin handle for OCIDBStartup */
checkerr(errhp, OCIHandleAlloc((void *) envhp, (void **) &admhp,
         (ub4) OCI_HTYPE_ADMIN, (size_t) 0, (void **) 0));

/* Set attribute pfile in the admin handle
(do not do this if you want to use the spfile) */
checkerr (errhp, OCIAttrSet( (void *) admhp, (ub4) OCI_HTYPE_ADMIN,
          (void *) pfile, (ub4) strlen(pfile),
          (ub4) OCI_ATTR_ADMIN_PFILE, (OCIError *) errhp));

/* Startup in NOMOUNT mode */
  checkerr(errhp, OCIDBStartup(svchp, errhp, admhp, OCI_DEFAULT, 0));
   checkerr(errhp, OCIHandleFree((void *) admhp, (ub4) OCI_HTYPE_ADMIN));

/* End the authentication session */
OCISessionEnd(svchp, errhp, usrhp, (ub4)OCI_DEFAULT);

/* Start the sysdba session */
checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS,
         OCI_SYSDBA));

/* Mount the database */
checkerr(errhp, OCIStmtPrepare2(svchp, &stmthp, errhp, mount_stmt, (ub4)
         strlen((char*) mount_stmt),
         (CONST OraText *) 0, (ub4) 0, (ub4) OCI_NTV_SYNTAX, (ub4)
         OCI_DEFAULT));
checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4)0,
         (OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT));
checkerr(errhp, OCIStmtRelease(stmthp, errhp, (OraText *)0, 0, OCI_DEFAULT));

/* Open the database */
checkerr(errhp, OCIStmtPrepare2(svchp, &stmthp, errhp, open_stmt, (ub4)
         strlen((char*) open_stmt),
         (CONST OraText *)0, (ub4)0, (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4)0,
         (OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT));
checkerr(errhp, OCIStmtRelease(stmthp, errhp, (OraText *)0, 0, OCI_DEFAULT));

/* End the sysdba session */
OCISessionEnd(svchp, errhp, usrhp, (ub4)OCI_DEFAULT);
...

停止するには、SYSOPERまたはSYSDBAとしてデータベースに接続する必要があります。ディスパッチャを介して共有サーバーには接続できません。OCI_DBSHUTDOWN_ABORT以外のモードで停止する場合、次の手順を続けて実行する必要があります。

  1. OCIDBShutdown()OCI_DEFAULTOCI_DBSHUTDOWN_TRANSACTIONALOCI_DBSHUTDOWN_TRANSACTIONAL_LOCALまたはOCI_DBSHUTDOWN_IMMEDIATEモードでコールし、これ以上の接続を禁止します。

  2. 必要なALTER DATABASEコマンドを使用し、データベースをクローズしてディスマウントします。

  3. OCIDBShutdown()OCI_DBSHUTDOWN_FINALモードでコールし、インスタンスを停止します。

/*  Example 1 - Orderly shutdown:  */
...
text *close_stmt = (text *)"ALTER DATABASE CLOSE NORMAL";
text *dismount_stmt = (text *)"ALTER DATABASE DISMOUNT";

/* Start the sysdba session */
checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS,
         OCI_SYSDBA));

/* Shutdown in the default mode (transactional, transactional-local,
  immediate would be fine too) */
checkerr(errhp, OCIDBShutdown(svchp, errhp, (OCIAdmin *)0, OCI_DEFAULT));

/* Close the database */
checkerr(errhp, OCIStmtPrepare2(svchp, &stmthp, errhp, close_stmt, (ub4)
         strlen((char*) close_stmt),
         (CONST OraText *)0, (ub4)0, (ub4) OCI_NTV_SYNTAX,
         (ub4) OCI_DEFAULT));
checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4)0,
        (OCISnapshot *) NULL,
        (OCISnapshot *) NULL, OCI_DEFAULT));
checkerr(errhp, OCIStmtRelease(stmthp, errhp, (OraText *)0, 0, OCI_DEFAULT));

/* Dismount the database */
checkerr(errhp, OCIStmtPrepare2(svchp, &stmthp, errhp, dismount_stmt,
         (ub4) strlen((char*) dismount_stmt), (CONST OraText *)0, (ub4)0,
         (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4)0,
         (OCISnapshot *) NULL,
         (OCISnapshot *) NULL, OCI_DEFAULT));
checkerr(errhp, OCIStmtRelease(stmthp, errhp, (OraText *)0, 0, OCI_DEFAULT));

/* Final shutdown */
checkerr(errhp, OCIDBShutdown(svchp, errhp, (OCIAdmin *)0,
         OCI_DBSHUTDOWN_FINAL));

/* End the sysdba session */
checkerr(errhp, OCISessionEnd(svchp, errhp, usrhp, (ub4)OCI_DEFAULT));
...

次の停止例では、OCI_DBSHUTDOWN_ABORTモードを使用しています。

/*  Example 2 - Shutdown using abort:  */
...
/* Start the sysdba session */
...
checkerr(errhp, OCISessionBegin (svchp, errhp, usrhp, OCI_CRED_RDBMS,
         OCI_SYSDBA));

/* Shutdown in the abort mode */
checkerr(errhp, OCIDBShutdown(svchp, errhp, (OCIAdmin *)0,
         OCI_SHUTDOWN_ABORT));

/* End the sysdba session */
checkerr(errhp, OCISessionEnd(svchp, errhp, usrhp, (ub4)OCI_DEFAULT));
...

ROWIDの暗黙的フェッチ

ROWIDは、データベース内の行のグローバル一意識別子です。ROWIDは行が表に挿入されるときに作成され、行が削除されると破棄されます。ROWID値には、重要な用途がいくつかあります。これは、表の各行の一意識別子です。また、1行にアクセスする場合に最も高速な手段であり、表の行の格納方法を示すことができます。

SELECT ...FOR UPDATE文でのROWIDの暗黙的フェッチは、SELECT文で指定された列のROWIDでなくても、クライアント側でROWIDが取得されることを意味します。OCIDefineByPos()positionパラメータは0(ゼロ)に設定されます。ROWID疑似列値を取得する場合、次のホスト変数を指定できます。

SELECT ...FOR UPDATE文では更新対象の行を識別し、結果セットの各行をロックします。これは、1行の既存の値に基づいて更新する必要がある場合に役立ちます。その場合は、別のユーザーにより行が変更されないことを確認する必要があります。

ROWIDの値を格納する文字バッファの指定時(SQLT_STR形式で取得する場合など)には、ROWIDを格納するのに十分なメモリーを割り当てるようにしてください。ROWIDデータ型とUROWIDデータ型は区別する必要があります。ROWIDデータ型に格納できるのは物理ROWIDのみですが、UROWID型には論理ROWID(索引構成表の行の識別子)も格納できます。ROWID型の最長内部長は10バイトですが、UROWIDデータ型の場合は3950バイトです。

動的定義は、OCI_DYNAMIC_FETCHとして設定されたmodeによるOCIDefineByPos()のコールと等価です。動的定義を使用すると、特定の定義ハンドルの属性を追加設定できます。実行時にコールされ、検索されるフェッチ済データまたはそのピースを格納するバッファへのポインタを取得する、コールバック関数を指定します。

ROWIDの暗黙的フェッチを使用する前に、文ハンドルで属性OCI_ATTR_FETCH_ROWIDを次のように設定する必要があります。

OCIAttrSet(stmthp, OCI_HTYPE_STMT, 0, 0 , OCI_ATTR_FETCH_ROWID, errhp);

動的定義は、ROWIDの暗黙的フェッチと互換性がありません。 通常のシナリオの場合、このモードのアプリケーションでは1つの列の各行にバッファを提供できます。つまり、1つの列値がフェッチされるたびにコールバックが起動されます。

位置0(ゼロ)についてOCIDefineByPos()を使用するこの機能は、データ配列を一度にユーザー・バッファにフェッチし、その各ROWIDを同時に取得することが目的です。この機能では、ROWIDがSELECTを使用した問合せの列のROWIDでなくても、SELECT....FOR UPDATE文である場合にROWIDのフェッチが可能です。データを1つずつユーザー・バッファにフェッチする場合は、既存のOCI_ATTR_ROWID属性を使用できます。

この機能を使用してROWIDをフェッチする場合、文ハンドルのOCI_ATTR_ROWID属性を同時に使用してROWIDを取得することはできません。特定の文ハンドルに対して1度に使用できるのは、どちらか一方のみです。

ROWIDの暗黙的フェッチの例

Cプログラムのこのフラグメントを使用してビルドします。

#include <oci.h>

int main()
{
 ...
 text *mySql = (text *) "SELECT emp_name FROM emp FOR UPDATE";
 text rowid[100][15] = {0};
 text empName[100][15] = {0};
 ...

 /* Set up the environment, error handle etc */
 ...

 /* Prepare the statement -  select ... for update */


  if (OCIStmtPrepare (select_p, errhp,
                      mySql, strlen(mySql), OCI_NTV_SYNTAX, OCI_DEFAULT))
  {
    printf ("Prepare failed \n");
    return (OCI_ERROR);
  }

 /* Set attribute for implicit fetching of ROWIDs on the statement handle. */
 if (OCIAttrSet(select_p, OCI_HTYPE_STMT, 0, 0, OCI_ATTR_FETCH_ROWID, errhp))
 {
   printf ("Unable to set the attribute - OCI_ATTR_FETCH_ROWID \n");
   return OCI_ERROR;
 }
  /*
   * Define the positions 0 - for getting ROWIDs and other positions
   * to fetch other columns.
   * Also, getting the define conversion done implicitly by fetching
   * the ROWIDs in the string format.
   */

  if (OCIDefineByPos ( select_p,
                       &defnp0,
                       errhp,
                       0,
                       rowid[0],
                       15,
                       SQLT_STR,
                       (void *) ind,
                       (void *) 0,
                       (void *) 0,
                       OCI_DEFAULT) ||
       OCIDefineByPos(select_p,
                       &defnp1,
                       errhp,
                       1,
                       empName[0],
                       15,
                       SQLT_STR,
                       (void *) 0,
                       (void *) 0,
                       (void *) 0,
                       OCI_DEFAULT)
                       )
  {
    printf ("Failed to define\n");
    return (OCI_ERROR);
  }


  /* Execute the statement */

 if (errr = OCIStmtExecute(svchp,
                            select_p,
                            errhp,
                            (ub4) 5,
                            (ub4) 0,
                            (OCISnapshot *) NULL,
                            (OCISnapshot *) NULL,
                            (ub4) OCI_DEFAULT))
  {
    if (errr != OCI_NO_DATA)
       return errr;
  }

  printf ("Column 0  \t Column 1\n");
  printf ("_________ \t ________\n");

  for (i =0 ;i<5 i++)
   {
     printf("%s \t %s \n", rowid[i], empName[i]);
   }

 return OCI_SUCCESS;
}

クライアント結果キャッシュ

OCIアプリケーションでは、OCI結果キャッシュを活用するためのクライアント・メモリーを使用して、繰返しの多い問合せの応答時間を短縮できます。

この機能により、クライアント・メモリーにおけるSQL問合せ結果セットのクライアント側のキャッシュが可能になります。OCI結果キャッシュはOCIアプリケーションに対して完全に透過的であり、結果セット・データのキャッシュは、結果セットに影響するセッションまたはデータベースのすべての変更内容と整合性が保たれます。

この機能を使用するアプリケーションでは、キャッシュ・ヒットがある問合せのパフォーマンスが向上します。OCIでは、これらの問合せを将来実行する際に、キャッシュ内の結果を透過的に使用できます。OCIクライアント・プロセスからローカルに結果を取り出す処理は、データベース・コールの実行および問合せの再実行よりも高速で行われるため、頻繁な問合せの実行では、結果がキャッシュされている場合パフォーマンスが大幅に向上します。

OCIキャッシュを使用すると、問合せの処理で消費されていたサーバーのCPUも節減されるため、サーバーの拡張性が向上します。複数のセッションのOCI文で、スキーマ、SQLテキスト、バインド値およびセッションの設定が類似している場合、OCIプロセス・メモリー内のキャッシュされた同一の結果セットと一致することがあります。類似していない場合、サーバーに対して問合せが実行されます。

クライアント結果キャッシュを使用する場合、アプリケーション・レベルでOCI文キャッシュまたはキャッシュ文を有効化する必要があります。

クライアント結果キャッシュの利点

OCIクライアント問合せ結果キャッシュの利点は次のとおりです。

  • 結果キャッシュはクライアント側にあるため、キャッシュ・ヒットが存在すると、OCIStmtExecute()およびOCIStmtFetch()のコールがサーバー・ラウンドトリップではなくローカルで処理されます。これにより、サーバーCPUおよびサーバーI/Oなどのサーバー・リソースにおいて、パフォーマンスが大幅に節減されます。

  • OCIのクライアント側の問合せ結果セット・キャッシュは、透過的かつ一貫性のあるキャッシュです。

  • OCIクライアントの結果キャッシュはプロセス単位であるため、複数のクライアント・セッションで一致するキャッシュ内の結果セットを同時に使用できます。

  • 各OCIアプリケーションで独自のカスタム結果セット・キャッシュを保持する必要性が最小限になります。

  • キャッシュ内の結果セットのキャッシュに関する各局面(つまり、複数のスレッド、文、セッションによる同時アクセス、キャッシュ内の結果セットの無効化またはリフレッシュ、およびキャッシュ・メモリー管理)が透過的に管理されます。

  • OCIプロセスでサーバーに対してラウンドトリップが発生した場合、結果セットに影響するデータベースの変更内容について、キャッシュ内の結果セットが透過的に無効化されます。

  • この一貫性のあるキャッシュは、OCIを使用して構築されたすべてのOCIアプリケーションおよびドライバ(JDBC-OCI、ODP.Net、OCCI、Pro*C/C++、Pro*COBOL、ODBCなど)に対して自動的に使用可能になります。

  • キャッシュには、サーバー・メモリーより安価なOCIクライアント・メモリーが使用されます。

  • クライアントのローカル・キャッシュでは、そのクライアントにより実行される問合せについて参照の局所性が向上します。

使用に関するガイドライン

結果を問合せ結果キャッシュに格納する必要があることを示すには、問合せに/*+ result_cache */ヒントの注釈を付ける必要があります。読取り専用またはほぼ読取りのみのデータベース・オブジェクトの場合、アプリケーションで問合せに結果キャッシュ・ヒントの注釈を付けることをお薦めします。結果キャッシュ・ヒントが、結果のサイズが大きい問合せに関するものである場合、これらの結果では大量のクライアント結果キャッシュ・メモリーが使用されることがあります。

アプリケーションで指定されたバインド値の各セットにより、(同じSQLテキストに対して)異なるキャッシュ結果セットが作成されるため、これらのすべての結果セットで大量のクライアント結果キャッシュ・メモリーが使用される場合があります。

初期化パラメータRESULT_CACHE_MODEを設定し、SQL問合せのクライアント結果キャッシュをすべての問合せ(可能な場合)について使用するか、または結果キャッシュ・ヒントの注釈が付いた問合せについてのみ使用するかを制御できます。

クライアント結果キャッシュが有効である場合、問合せ結果セットをクライアントまたはサーバー(あるいはその両方)にキャッシュできます。クライアント結果キャッシュは、サーバー結果キャッシュ(デフォルトで有効)が無効化されている場合でも有効化できます。

すべてのOCI文ハンドル・コールにおける最初のOCIStmtExecute()のコールは、キャッシュ内に有効な結果セットがある場合でも、必ずサーバーに対して行われます。各文ハンドルをキャッシュ内の結果セットと照合できるようにするには、OCIStmtExecute()をコールする必要があります。アプリケーションがOCI文ハンドルについて独自の文キャッシュを持つようにするか、またはOCI文キャッシュを使用し、OCIStmtPrepare2()が一度実行されたOCI文ハンドルを戻せるようにすることをお薦めします。同一または異なるセッションからの複数のOCI文ハンドルは、キャッシュ内の同一の結果セットからデータを同時にフェッチできます。

結果セットをキャッシュするには、このキャッシュ結果セットを透過的に作成するOCIStmtExecute()OCIStmtFetch()またはOCIStmtFetch2()のコールで、ORA-1403「データが見つかりません」エラーを取得するまで行をフェッチする必要があります。ローカルにキャッシュされた結果セットと一致する後続のOCIStmtExecute()またはOCIStmtFetch()のコールでは、最後までフェッチする必要はありません。

SQLヒント

RESULT_CACHE_MODEサーバー初期化パラメータがFORCEに設定されている場合を除き、SQLヒントによりキャッシュする問合せを明示的に指定する必要があります。OCIStmtPrepare()およびOCIStmtPrepare2()コールに渡されるSQLテキストで、SQLの/*+ result_cache */または/*+ no_result_cache */ヒントを設定する必要があります。


関連項目:

  • これらのSQLヒントの詳細は、『Oracle Database SQLリファレンス』を参照してください。

  • RESULT_CACHE_MODEの詳細は、『Oracle Databaseリファレンス』を参照してください。


以前のリリースとの互換性

この機能を使用するには、アプリケーションをリリース11.1以降のクライアント・ライブラリと再リンクし、リリース11.1以降のデータベース・サーバーに接続する必要があります。 この機能は、JDBC Type IIドライバ、OCCI、Pro*C/C++およびODP.NETを含むすべてのOCIアプリケーションで使用できます。 OCIドライバは、OCIStmtPrepare()およびOCIStmtPrepare2()コールに結果キャッシュ・ヒントを自動的に渡すため、キャッシュの恩恵を受けることができます。

キャッシュされない問合せ

結果キャッシュ・ヒントが指定されている場合でも、OCIクライアントにキャッシュされない問合せがあります。 サーバーの結果キャッシュ機能が有効である場合、こうした問合せはデータベースにキャッシュできます(詳細は、『Oracle Database概要』のSQL問合せの結果キャッシュに関する項を参照してください)。SQL問合せに次のいずれかが含まれる場合、その問合せの結果セットはOCIクライアント結果キャッシュにキャッシュされません。

  • ビュー

  • リモート・オブジェクト

  • 選択リストの複合型

  • スナップショットベースの問合せまたはフラッシュバック問合せ

  • シリアライズ可能の読取り専用トランザクション内またはフラッシュバック・セッション内で実行される問合せ

  • PL/SQLファンクションが含まれる問合せ

  • 表でVPDポリシーが有効となっている問合せ

クライアント・キャッシュの一貫性

クライアント・キャッシュでは、キャッシュ内の結果セットに影響する可能性のあるセッションの状態またはデータベースの変更内容と結果セットの一貫性が透過的に保たれます。

トランザクションにより、そのキャッシュ結果の作成に使用されたデータベース・オブジェクトのデータまたはメタデータが変更された場合、後続のサーバーへのラウンドトリップ時にOCIクライアントに無効化されたデータが送信されます。OCIアプリケーションで一定時間にわたりデータベース・コールが行われない場合、こうした無効化の有無を確認するため、クライアント・キャッシュの遅延設定により次のOCIStmtExecute()コールによるデータベース・コールが強制的に実行されます。

データベースの無効化に関連するキャッシュ内の結果セットはただちに無効化され、後続のOCIStmtExecute()コールはこうした結果セットと照合されません。現在これらのキャッシュ内の結果セットからフェッチしているOCI文ハンドルは、こうした無効化データを受信した際に、この(無効化された)キャッシュ内の結果セットから引き続きフェッチできます。

キャッシュ内に使用可能な領域がある場合、プロセスによる次回のOCIStmtExecute()コールにより、新規結果セットをキャッシュできます。OCIクライアント結果キャッシュでは、未使用のメモリーが定期的に再生されます。

セッションにオープン・トランザクションがある場合、OCIでは、このトランザクションで変更されたデータベース・オブジェクトを参照する問合せが、クライアント・キャッシュではなくサーバーに対して行われます。

一貫性を保つこのメカニズムにより、OCIキャッシュはコミットされたデータベースの変更に常に近い状態になります。キャッシュできない問合せ(DML、OCILobコールなど)のため、データベース・ラウンドトリップに伴う比較的頻繁なコールをOCIアプリケーションが実行する場合、これらのコールによりクライアント・キャッシュがデータベースの変更を反映して透過的に最新の状態に保たれます。

OCIクライアント結果キャッシュでは、クライアントにおけるスレッドのサポートは必要ありません。

クライアント結果キャッシュに関するデプロイメント時設定

クライアント結果キャッシュには、デプロイメント時設定に関するサーバー初期化パラメータおよびクライアント構成パラメータがあります。

サーバー初期化パラメータは次の2つです。

  • CLIENT_RESULT_CACHE_SIZE

    デフォルト値は0(ゼロ)であり、クライアント・キャッシュ機能が無効であることを示します。 クライアント結果キャッシュ機能を有効にするには、サイズを32768バイト(32KB)以上に設定してください。これは、クライアントのプロセス単位の結果セット・キャッシュの最大サイズです。すべてのOCIクライアント・プロセスは、この最大サイズを取得します。 CLIENT_RESULT_CACHE_SIZE初期化パラメータを使用してこの機能をサーバーで有効化している場合にかぎり、sqlnet.ora構成パラメータOCI_RESULT_CACHE_MAX_SIZEでこの値を上書きできます。

    現在のデフォルトの最大サイズを表示するには、CLIENT_RESULT_CACHE_SIZEパラメータの値を表示します。この最大サイズを増やすには、CLIENT_RESULT_CACHE_SIZEを設定します。ただし、CLIENT_RESULT_CACHE_SIZEは静的パラメータであるため、ALTER SYSTEM文を使用する場合はSCOPE = SPFILE句を含める必要があります。また、このパラメータへの変更を有効にするには、データベースを再起動する必要があります。

    クライアント結果キャッシュ機能がサーバーで無効化されている場合、クライアント構成パラメータOCI_RESULT_CACHE_MAX_SIZEは無視され、クライアントではクライアント結果キャッシュを有効化できないことに注意してください。

    設定可能なキャッシュ・サイズの最小値は次のようになります。

    (使用可能なクライアント・メモリー)+

    ((キャッシュされる見込み結果セット数)

    *(結果セット内の1行の平均サイズ)

    *(結果セット内の平均行数))


    注意:


    クライアント結果キャッシュの最大値は2GBです。この値よりも大きな値を設定すると、2GBに切り捨てられます。

  • CLIENT_RESULT_CACHE_LAG

    初期化パラメータCLIENT_RESULT_CACHE_LAGを使用すると、結果セットに影響するデータベース内の変更からクライアント結果キャッシュが遅延できる最大時間をミリ秒で指定できます。デフォルトは3000ミリ秒です。

    現在の遅延を表示するには、CLIENT_RESULT_CACHE_LAGパラメータの値を表示します。この値を変更するには、CLIENT_RESULT_CACHE_LAGを設定します。ただし、CLIENT_RESULT_CACHE_LAGは静的パラメータであるため、ALTER SYSTEM文を使用する場合はSCOPE = SPFILE句を含める必要があります。また、このパラメータへの変更を有効にするには、データベースを再起動する必要があります。

クライアント構成ファイル

クライアント構成ファイルはオプションであり、サーバーのinit.ora初期化ファイル内で設定されているキャッシュ・パラメータを上書きします。これらのパラメータは、sqlnet.oraファイルに含まれます。クライアント構成には、次のオプション・パラメータを使用できます。

  • OCI_RESULT_CACHE_MAX_SIZE(オプション): プロセス単位の問合せキャッシュの最大サイズ(バイト数)。 クライアントのsqlnet.oraファイルで32768未満のサイズを指定すると、このsqlnet.oraファイルを読み取るクライアント・プロセスのクライアント結果キャッシュ機能が無効になります。

  • OCI_RESULT_CACHE_MAX_RSET_SIZE(オプション): プロセス単位の問合せキャッシュ内の結果セットの最大サイズ(バイト数)。

  • OCI_RESULT_CACHE_MAX_RSET_ROWS(オプション): プロセス単位の問合せキャッシュ内の結果セットの最大サイズ(行数)。

クライアントではキャッシュの遅延を設定できないので注意してください。

クライアント・キャッシュの統計

OCIは、OCIクライアントからの既存のラウンドトリップで、クライアント・キャッシュに関連する統計を定期的にサーバーに送信し、これらの統計はCLIENT_RESULT_CACHE_STATS$に格納されます。正常にキャッシュされた結果セット数、キャッシュ・ヒット数および無効化されたキャッシュ内の結果セット数などの情報がここに格納されます。問合せのキャッシュ・ミスの数は、クライアント結果キャッシュ統計内の作成数の数以上になります。より正確なキャッシュ・ミス数については、サーバーの自動ワークロード・リポジトリ(AWR)レポートに示されるサーバー実行数と等しくなります。


関連項目:


CLIENT_RESULT_CACHE_STAT$ビューの詳細は、『Oracle Databaseリファレンス』を参照してください。

OCIクライアント結果キャッシュおよびサーバー結果キャッシュ

クライアント側の結果キャッシュは、サーバー結果キャッシュとは別の機能です。クライアント結果キャッシュでは、トップレベルのSQL問合せの結果がOCIクライアント・メモリーにキャッシュされますが、サーバー結果キャッシュでは、結果セットがサーバーSGAメモリーにキャッシュされます。

また、サーバー結果キャッシュでは問合せの一部をキャッシュできます。クライアント結果キャッシュはサーバー結果キャッシュとは関係なく有効化できますが、どちらもSQL結果キャッシュ・ヒントおよびパラメータ設定の一部を共有します。(詳細は、『Oracle Database概要』のSQL問合せの結果キャッシュに関する項を参照してください)。

表10-1 クライアントおよびサーバー結果キャッシュの設定

パラメータ、PL/SQLパッケージおよびデータベース・ビュー 結果キャッシュの関連付け

client_result_cache_*パラメータ

client_result_cache_size、

client_result_cache_lag

クライアント結果キャッシュ

SQLヒント/*+ result_cache */、

/*+ no_result_cache */

クライアント結果キャッシュ、サーバー結果キャッシュ

sqlnet.ora OCI_RESULT_CACHE* パラメータ:

OCI_RESULT_CACHE_MAX_SIZE

OCI_RESULT_CACHE_MAX_RSET_SIZE

OCI_RESULT_CACHE_MAX_RSET_ROWS

クライアント結果キャッシュ

統計ビュー: client_result_cache_stats$

クライアント結果キャッシュ

result_cache_modeパラメータ

クライアント結果キャッシュ、サーバー結果キャッシュ

他のすべてのresult_cache*パラメータ(result_cache_max_sizeなど)

サーバー結果キャッシュ

パッケージDBMS_RESULT_CACHE

サーバー結果キャッシュ

統計ビューv$result_cache_*、gv$result_cache_*

v$result_cache_statistics、gv$result_cache_memoryなど

サーバー結果キャッシュ


クライアント結果キャッシュの例

このアプリケーションのデモ・ファイルについては、rdbms/demo/cdemoqc.sqlファイルおよびrdbms/demo/cdemoqc.cファイル(Oracleホームの下)を参照してください。

OCIでの障害診断

OCIの11gリリース1(11.1)では、障害診断が導入されました。OCIクライアント上のインシデント(問題の発生)は、ユーザーの介入なしで診断データの形式(ダンプ・ファイルまたはコア・ダンプ・ファイル)で取得されます。診断データは、インシデントについて作成された自動診断リポジトリ(ADR)サブディレクトリに格納されます。たとえば、LinuxまたはUNIXアプリケーションがNULLポインタ参照で失敗した場合、コア・ファイルはオペレーティング・システム・ディレクトリではなくADRホーム・ディレクトリ(存在する場合)に書き込まれます。ADRサブディレクトリ構造および出力を処理するためのユーティリティであるADRコマンド・インタプリタ(ADRCI)について、次の各項で説明します。

ADRホームは、OCIなどの特定の製品のインスタンスおよび特定のオペレーティング・システム・ユーザーに関するすべての診断データのルート・ディレクトリです。ADRホームは、ADRベースという同一のルート・ディレクトリの下でグループ化されます。

Oracle Databaseの障害診断およびADR構造については、次のマニュアルで詳細に説明しています。


関連項目:


『Oracle Database管理者ガイド』の診断データの管理に関する項

ADRベースの場所

ADRベースの場所は、OCIにより次の順序で決定されます。

  1. OCIは、最初にsqlnet.oraファイル(存在する場合)で次のような文を検索します(LinuxまたはUNIX)。

    ADR_BASE=/foo/adr
    

    adr(ディレクトリ名)はすでに存在している必要があり、OCIアプリケーションを実行し同一のADRベースを共有する、すべてのオペレーティング・システム・ユーザーが書込み可能である必要があります。 fooはパス名を表します。sqlnet.oraの場所は、$TNS_ADMINディレクトリ(Windowsでは%TNS_ADMIN%)で指定されています。$TNS_ADMINがない場合、現行ディレクトリが使用されます。ADR_BASEが設定されており、すべてのユーザーが1つのsqlnet.oraを共有する場合、adrディレクトリが存在しない、またはユーザーが書き込むことができないときにはOCIは検索を停止します。ADR_BASEが設定されていない場合、OCIは検索を続行し、特定のディレクトリの有無をテストします。

    たとえば、sqlnet.oraにエントリADR_BASE=/home/chuck/testが含まれる場合、ADRベースは/home/chuck/test/oradiag_chuckであり、ADRホームは/home/chuck/test/oradiag_chuck/diag/clients/user_chuck/host_4144260688_11のようになります。

  2. $ORACLE_BASE(Windowsでは%ORACLE_BASE%)が存在します。この場合、Oracle Universal Installerを使用したデータベースのインストール時にクライアント・サブディレクトリが作成されているため、これが存在します。

    たとえば、$ORACLE_BASE/home/chuck/obaseである場合、ADRベースは/home/chuck/obaseであり、ADRホームは/home/chuck/obase/diag/clients/user_chuck/host_4144260688_11のようになります。

  3. $ORACLE_HOME(Windowsでは%ORACLE_BASE%)が存在します。この場合、Oracle Universal Installerを使用したデータベースのインストール時にクライアント・サブディレクトリが作成されているため、これが存在します。

    たとえば、$ORACLE_HOME/ade/chuck_l1/oracleである場合、ADRベースは/ade/chuck_l1/oracle/logであり、ADRホームは/ade/chuck_l1/oracle/log/diag/clients/user_chuck/host_4144260688_11のようになります。

  4. オペレーティング・システムのホーム・ディレクトリは、LinuxまたはUNIXでは$HOME、Windowsでは%USERPROFILE%です。LinuxまたはUNIXでは、ユーザーchuckの場所は/home/chuck/oradiag_chuckのようになります。Windowsでは、C:\Documents and Settings\chuckの下にOracleというフォルダが作成されます。

    たとえば、Instant Clientでは、$HOME/home/chuckである場合、ADRベースは/home/chuck/oradiag_chuckであり、ADRホームは/home/chuck/oradiag_chuck/diag/clients/user_chuck/host_4144260688_11です。

  5. Windowsでは、アプリケーションがサービスとして動作している場合、ホーム・ディレクトリ・オプションはスキップされます。

  6. LinuxまたはUNIXオペレーティング・システムの一時ディレクトリは/var/tmpです。

    たとえば、Instant Clientでは、$HOMEが書込み不可である場合、ADRベースは/var/tmp/oradiag_chuckであり、ADRホームは/var/tmp/oradiag_chuck/diag/clients/user_chuck/host_4144260688_11です。

    Windowsオペレーティング・システムの一時ディレクトリは、次の順序で検索されます。

    1. %TMP%

    2. %TEMP%

    3. %USERPROFILE%

    4. Windowsシステム・ディレクトリ

これらのディレクトリの選択肢がいずれも使用不可および書込み不可である場合、ADRは作成されず、診断は実行されません。


関連項目:


『Oracle Database Net Servicesリファレンス・ガイド』

ADRCIの使用

ADRCIは、ADR内の診断データを表示し、インシデントおよび問題に関する情報をOracleサポートが使用できるようzipファイルに圧縮できるコマンドライン・ツールです。ADRCIは対話式に、またスクリプトから使用できます。問題が発生すると、OCIまたはクライアントで重大なエラーとなります。各問題には問題キーがあります。 インシデントは問題の発生を意味し、数字を使用した一意のインシデントIDで識別されます。 各インシデントには、属性のセット(ORAエラー番号、エラー・パラメータ値およびその他の情報)である問題キーが割り当てられています。2つのインシデントの問題キーが一致する場合、根本的な原因は同じです。


関連項目:


ADRCIの概要については、『Oracle Databaseユーティリティ』を参照してください。

次に、LinuxシステムでADRCIを起動し、SHOW BASEコマンドについてHELPコマンドを使用し、SHOW BASEコマンドを-PRODUCT CLIENTオプション(OCIアプリケーションに必要)とともに使用しています。ADRCIコマンドは大/小文字の区別はありません。ユーザー入力は太字で表示されます。

% adrci

ADRCI: Release 11.1.0.5.0 - Beta on Wed May 2 15:53:06 2007

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

adrci> help show base

  Usage: SHOW BASE [-product <product_name>]

  Purpose: Show the current ADR base setting.

  Options:
    [-product <product_name>]: This option allows users to show the
    given product's ADR Base location. The current registered products are
    "CLIENT" and "ADRCI".

  Examples:
    show base -product client
    show base

adrci> show base -product client
ADR base is "/ade/chuck_l3/oracle/log/oradiag_chuck"

次に、SET BASEコマンドを記述しています。

adrci> help set base

  Usage:  SET BASE <base_str>

  Purpose: Set the ADR base to use in the current ADRCI session.
           If there are valid ADR homes under the base, all homes will
           will be added to the current ADRCI session.

  Arguments:
    <base_str>: It is the ADR base directory, which is a system-dependent
    directory path string.

  Notes:
    On platforms that use "." to signify current working directory,
    it can be used as base_str.

  Example:
    set base /net/sttttd1/scratch/someone/view_storage/someone_v1/log
    set base .

adrci> quit

ADRCIを起動すると、デフォルトのADRベースはrdbmsサーバーに対するものとなります。$ORACLE_HOME/ade/chuck_l3/oracleに設定されます。

% adrci

ADRCI: Release 11.1.0.5.0 - Beta on Wed May 2 16:16:55 2007

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

ADR base = "/ade/chuck_l3/oracle/log"

OCIアプリケーションのインシデントの場合、ベースを次のようにチェックおよび設定する必要があります。

adrci> show base -product client
ADR base is "/ade/chuck_l3/oracle/log"
adrci> set base /ade/chuck_l3/oracle/log

Instant Clientの場合、$ORACLE_HOMEがないため、デフォルトのベースはユーザーのホーム・ディレクトリです。

adrci> show base -product client
ADR base is "/home/chuck/oradiag_chuck"
adrci> set base /home/chuck/oradiag_chuck
adrci> show incidents

ADR Home = /home/chuck/oradiag_chuck/diag/clients/user_chuck/host_4144260688_11:
*************************************************************************
INCIDENT_ID    PROBLEM_KEY           CREATE_TIME
-------------------------------------------------------------------------
1                     oci 24550 [6]              2007-05-01 17:20:02.803697 -07:00
1 rows fetched

adrci>

sqlnet.oraを使用したADRの作成の管理および障害診断の無効化

診断性を削除するには、sqlnet.oraで次のパラメータを設定し(デフォルトはTRUE)、診断をオフにします。

DIAG_ADR_ENABLED=FALSE
DIAG_DDE_ENABLED=FALSE

OCIシグナル・ハンドラをオフにし、標準オペレーティング・システムの障害処理を再度有効化するには、sqlnet.oraで次のパラメータを設定します。

DIAG_SIGHANDLER_ENABLED=FALSE

前述のように、sqlnet.oraADR_BASEを使用し、ADRベースの場所を設定します。


関連項目:

  • 『Oracle Database Net Servicesリファレンス・ガイド』

  • 自動診断リポジトリの構造に関する詳細は、『Oracle Database Net Services管理者ガイド』を参照してください。