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

戻る
戻る
 
次へ
次へ
 

11 OCIオブジェクト・リレーショナル・プログラミング

この章では、オブジェクトをOracleデータベース・サーバーで操作するためのOCIの機能を紹介します。また、OCIのオブジェクト・ナビゲーショナル関数コールについても説明します。

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

OCIオブジェクトの概要

OCIによって、アプリケーションは、スカラー値、コレクション、任意のオブジェクト型のインスタンスなど、Oracleデータベース・サーバー内のすべてのデータ型にアクセスできます。次のデータ型があります。

Oracleサーバーのオブジェクト機能を十分に活用するには、ほとんどのアプリケーションでは単にオブジェクトにアクセスするのみでは十分ではありません。アプリケーションでは、オブジェクトを取り出した後、そのオブジェクトから他のオブジェクトへ参照を通してナビゲートする必要があります。OCIはそのための機能を提供します。OCIのオブジェクト・ナビゲーショナル・コールを使用すると、アプリケーションはオブジェクトに対して次の関数を実行できます。

OCIナビゲーショナル・コールについては、この章の後半で詳しく説明します。

また、OCIは、Oracleのデータベースに格納されている型情報にアクセスする機能も備えています。アプリケーションでは、OCIDescribeAny()関数を使用して、データベースに格納されている型に関するほとんどの情報(メソッド、属性、型メタデータなど)にアクセスできます。


関連項目:


OCIDescribeAny()については、第6章「スキーマ・メタデータの記述」で説明します。

Oracleオブジェクトを操作するアプリケーションでは、オブジェクトをホスト言語形式で表現する手段が必要です。Oracleには、Object Type Translator(OTT)というユーティリティがあります。このユーティリティを使用すると、データベース内の型定義をCの構造体宣言に変換できます。宣言はヘッダー・ファイルに格納され、それをOCIアプリケーションに組み込むことができます。

型定義がCで表現されている場合、属性の型は特別なC変数型にマップされます。OCIには、アプリケーションによるこれらのデータ型の操作とそれによるオブジェクトの属性の操作を可能にする、一連のデータ型マッピング関数および操作関数が含まれています。


関連項目:


これらの関数については、第12章「OCIのオブジェクト・リレーショナル・データ型」で詳しく説明します。

オブジェクトに関する用語は混同することがあります。この章では、以降「オブジェクト」と「インスタンス」という用語は両方とも、データベースに格納されているオブジェクトか、オブジェクト・キャッシュにあるオブジェクトのいずれかを指します。

OCIでのオブジェクトの操作

リレーショナルOCIアプリケーションを制御するプログラミング原理の多くは、オブジェクト・リレーショナル・アプリケーションにも適用されます。オブジェクト・リレーショナル・アプリケーションでは、標準OCIコールを使用してデータベース接続を確立し、SQL文を処理します。その違いは、発行したSQL文でオブジェクト参照を取り出し、その参照をOCIのオブジェクト関数で操作できる点にあります。オブジェクトは、値インスタンスとして(オブジェクト参照を使用せずに)直接操作することもできます。

基本的なオブジェクト・プログラム構造体

オブジェクトを使用するOCIアプリケーションの基本的な構造体は、本質的にはリレーショナルOCIアプリケーションと同じです。これについては、「OCIプログラム構造」で説明しています。ここでは、基本的なオブジェクト機能についての追加情報とともに、そのモデルをもう一度示します。

  1. OCIプログラミング環境を初期化します。環境は、オブジェクト・モードで初期化してください。

    また、アプリケーションでは通常、ヘッダー・ファイルからデータベース・オブジェクトのC構造体の表現を組み込む必要があります。


    関連項目:


    これらの構造体はプログラマであれば作成できますが、より簡単な方法として、第15章「OCIでのObject Type Translatorの使用」で説明するように、Object Type Translator(OTT)でも生成できます。

  2. 必要なハンドルを割り当て、サーバーとの接続を確立します。

  3. SQL文を準備して実行します。これは、ローカル・(クライアント側)ステップで、プレースホルダのバインドと出力変数の定義を行います。オブジェクト・リレーショナル・アプリケーションの場合、このSQL文はオブジェクトへの参照(REF)を戻します。


    注意:


    オブジェクトは参照(REF)のみでなく、オブジェクト全体をフェッチすることもできます。参照可能なオブジェクトを選択(SELECT)する場合は、それを確保するのではなく、そのオブジェクトを値によって取得します。参照不可能なオブジェクトを選択することもできます。この方法によるオブジェクト全体のフェッチについては、「埋込みオブジェクトのフェッチ」で説明しています。

  4. プリコンパイルされたSQL文をデータベース・サーバーに関連付けて実行します。

  5. 戻された結果をフェッチします。

    オブジェクト・リレーショナル・アプリケーションでは、このステップでREFを取り出し、参照対象のオブジェクトを確保します。オブジェクトを確保した後、次の一部またはすべてを実行します。

    • オブジェクトの属性を操作し、それに使用済のマークを設定します。

    • 別の1個のオブジェクトまたは一連のオブジェクトへのREFをたどります。

    • 型および属性の情報にアクセスします。

    • 複合オブジェクト検索グラフをナビゲートします。

    • 変更したオブジェクトをサーバーにフラッシュします。

  6. トランザクションをコミットします。このステップでは暗黙的に、変更されたすべてのオブジェクトをサーバーにフラッシュし、変更をコミットします。

  7. 再利用しない文とハンドルを解放するか、プリコンパイルされたSQL文を再実行します。

この章の後の項で、すべてのステップを詳しく説明します。


関連項目:


永続オブジェクト、一時オブジェクトおよび値

Oracleの型のインスタンスは、その存続期間によって、永続オブジェクトと一時オブジェクトに分類されます。永続オブジェクトのインスタンスは、オブジェクト識別子による参照が可能かどうかによって、スタンドアロン・オブジェクトと埋込みオブジェクトに分割されます。


注意:


このマニュアルでは、オブジェクトとインスタンスは同じ意味の用語です。


関連項目:


オブジェクトの詳細は、『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください。

永続オブジェクト

永続オブジェクトはOracleデータベースに格納されているオブジェクトです。永続オブジェクトは、OCIアプリケーションによってオブジェクト・キャッシュにフェッチされ、変更されます。永続オブジェクトは、それにアクセスしているアプリケーションの存続期間が過ぎても存続できます。作成された永続オブジェクトは、明示的に削除されるまでデータベースに残留します。永続オブジェクトには次の2種類があります。

  • スタンドアロン・インスタンス。オブジェクト表の行に格納され、それぞれが他と重複しないオブジェクト識別子を持っています。OCIアプリケーションでは、スタンドアロン・インスタンスへのREFを取り出してオブジェクトを確保し、確保したオブジェクトからその他の関連オブジェクトにナビゲートできます。スタンドアロン・オブジェクトは、参照可能オブジェクトとも呼ばれます。

    参照可能オブジェクトの選択(SELECT)も可能で、その場合はREFをフェッチするかわりに、オブジェクトを値によってフェッチします。

  • 埋込みインスタンスは、オブジェクト表の行として格納されません。埋込みインスタンスは、他の構造体の中に埋め込まれます。埋込みオブジェクトの例は、別のオブジェクトの属性であるオブジェクトや、データベースの表のオブジェクト列に存在するインスタンスなどです。埋込みインスタンスにはオブジェクト識別子がないため、OCIアプリケーションでは、埋込みインスタンスへのREFを取得できません。

    埋込みオブジェクトは、参照不可能なオブジェクトまたは値インスタンスとも呼ばれます。埋込みオブジェクトは値と呼ばれることもありますが、それがスカラー・データ値と混同して使用されることはありません。どちらの意味であるかは文脈で判断できます。

次のSQLの例では、この2種類の永続オブジェクトの違いを説明します。

例1 スタンドアロン・オブジェクト

CREATE TYPE person_t AS OBJECT
   (name      varchar2(30),
    age       number(3));
CREATE TABLE person_tab OF person_t;

オブジェクト表person_tabに格納されるオブジェクトは、スタンドアロン・インスタンスです。このオブジェクトはオブジェクト識別子を持ち、参照可能です。したがって、OCIアプリケーションで確保できます。

例2 埋込みオブジェクト

CREATE TABLE department
   (deptno     number,
    deptname   varchar2(30),
    manager    person_t);

department表のmanager列に格納されるオブジェクトは、埋込みオブジェクトです。このオブジェクトはオブジェクト識別子を持たず、参照不可能です。つまり、OCIアプリケーションで確保することはできないため、確保を解除する必要もありません。このオブジェクトは常に、オブジェクト・キャッシュ内に値によって取り込まれます。

一時オブジェクト

一時オブジェクトは一時インスタンスであり、アプリケーションの存続期間を超えて存続せず、サーバーに格納またはフラッシュできません。一時オブジェクトはいつでもアプリケーションで削除できます。

アプリケーションでは、OCIObjectNew()関数を使用して一時オブジェクトを作成し、計算のための一時的な値を格納することがよくあります。一時オブジェクトを永続オブジェクトに変換することはできません。オブジェクトのロールは、インスタンス化されたときに決定されます。


関連項目:


OCIObjectNew()の使用方法は、「オブジェクトの作成」を参照してください。

このマニュアルでは、値は次のいずれかを意味します。

  • データベースの表の非オブジェクト列に格納されるスカラー値。OCIアプリケーションでは、SQL文を発行してデータベースから値をフェッチできます。

  • 埋込みまたは参照不可能オブジェクト。

どちらを指しているのかは文脈で判断できます。


注意:


参照可能オブジェクトは、確保するかわりにオブジェクト・キャッシュ内で選択(SELECT)することが可能です。その場合は、REFをフェッチせずに、オブジェクトを値によってフェッチします。

OCIオブジェクト・アプリケーションの開発

この項では、基本的なOCIオブジェクト・アプリケーションの開発に伴うステップを説明します。「基本的なオブジェクト・プログラム構造体」で説明している各ステップについて、さらに詳しく説明します。

次の図は、アプリケーションがオブジェクトを操作する方法について、そのプログラム・ロジックを簡単に示しています。図を簡略にするために、必要なステップの一部が省略されています。この図にある各ステップについては、後の項で説明します。

図11-1 基本的なオブジェクト操作のフロー

図11-1の説明は次にあります
「図11-1 基本的なオブジェクト操作のフロー」の説明

Cアプリケーションでのオブジェクトの表現

OCIアプリケーションでオブジェクト型を操作するには、データベースにそのオブジェクト型が存在している必要があります。通常は、CREATE TYPEなど、SQLのDDL文で型を作成します。

型定義DDLコマンドがOracleサーバーで処理されると、型定義は型記述子オブジェクト(TDO)としてデータ・ディクショナリに格納されます。

アプリケーションでデータベースからオブジェクトのインスタンスを取り出す場合は、クライアント側のオブジェクト表現を使用する必要があります。C言語のプログラムでは、オブジェクト型の表現はstructです。OCIオブジェクト・アプリケーションには、各オブジェクト型構造体に対応するNULLインジケータ構造体があります。


関連項目:


アプリケーション・プログラマが、オブジェクトのキャッシュによって生成されるデフォルトの構造体以外のオブジェクト表現を利用する場合は、「オブジェクト・キャッシュおよびメモリー管理」を参照してください。

Oracleには、データベースのオブジェクト型のC構造体表現を生成するObject Type Translator(OTT)というユーティリティがあります。たとえば、次のように宣言した型がデータベースにあるとします。

CREATE TYPE emp_t AS OBJECT
( name       VARCHAR2(30),
  empno      NUMBER,
  deptno     NUMBER,
  hiredate   DATE,
  salary     NUMBER);

OTTでは、次のC構造体と、対応するNULLインジケータ構造体が生成されます。

struct emp_t
{
  OCIString    * name;
  OCINumber    empno;
  OCINumber    deptno;
  OCIDate      hiredate;
  OCINumber    salary;
};
typedef struct emp_t emp_t

struct emp_t_ind
{
  OCIInd     _atomic;
  OCIInd     name;
  OCIInd     empno;
  OCIInd     deptno;
  OCIInd     hiredate;
  OCIInd     salary;
};
typedef struct emp_t_ind emp_t_ind;

この構造体宣言で使用している変数型は、OCIオブジェクト・コールで採用されている特殊な型です。OCI関数のサブセットでは、このデータ型のデータを操作します。

これらの構造体の宣言は自動的にヘッダー・ファイルに書き込まれます。このファイルの名前はOTT入力パラメータで判断されます。このヘッダー・ファイルをアプリケーションのコード・ファイルに組み込んで、オブジェクトにアクセスできます。


関連項目:


これらの関数については、この章の後半に説明がありますが、第12章「OCIのオブジェクト・リレーショナル・データ型」でも詳しく説明します。

環境およびオブジェクト・キャッシュの初期化

OCIアプリケーションでオブジェクトにアクセスして操作する場合は、OCIアプリケーションの最初のOCIコールであるOCIEnvCreate()コールのmodeパラメータに、OCI_OBJECTの値を指定する必要があります。modeにこの値を指定して、アプリケーションでオブジェクトを操作することをOCIライブラリに通知します。この通知には次の重要な効果があります。

  • オブジェクト・ランタイム環境の確立

  • オブジェクト・キャッシュの設定

オブジェクト・キャッシュ用のメモリーは、オブジェクトがキャッシュ内にロードされたときに、必要に応じて割り当てられます。

OCIInitialize()modeパラメータにOCI_OBJECTを設定しないと、オブジェクト関連関数を使用しても結果はエラーになります。

クライアント側のオブジェクト・キャッシュは、プログラムのプロセス領域に割り当てられます。このキャッシュは、サーバーから取り出してアプリケーションで使用できるオブジェクトのメモリーです。


注意:


OCI環境をオブジェクト・モードで初期化すると、実際にオブジェクト・コールを使用するかどうかに関係なく、オブジェクト・キャッシュ用のメモリーを割り当てることになります。


関連項目:


オブジェクト・キャッシュについては、この章の全体で説明されています。オブジェクト・キャッシュの詳しい説明は、第14章「OCIのオブジェクトに関する高度なトピック」を参照してください。

データベース接続の実行

アプリケーションでは、OCI環境を正しく初期化した後、サーバーに接続できます。これは標準OCI接続コールを介して行われます。詳細は、「OCIプログラミング・ステップ」を参照してください。標準OCI接続コールを使用すると、アプリケーションでオブジェクトにアクセスするための特別な配慮は必要ありません。

OCI環境ごとに、1つのオブジェクト・キャッシュのみ割り当てられます。1つの環境内で異なる接続を通じて取出しまたは作成されたオブジェクトは、すべて同じ物理的なオブジェクト・キャッシュを使用します。各接続には、それぞれ専用の論理的なオブジェクト・キャッシュがあります。

サーバーからのオブジェクト参照の取出し

アプリケーションでオブジェクトを操作するには、最初にサーバーから1つ以上のオブジェクトを取り出す必要があります。取出しは、1つ以上のオブジェクトへのREFを戻すSQL文を発行して行います。


注意:


SQL文によって、データベースからREFではなく、埋込みオブジェクトをフェッチすることもできます。詳細は、「埋込みオブジェクトのフェッチ」を参照してください。

次の例では、テキスト・ブロックがアプリケーションで宣言されています。このテキスト・ブロックには、データベース内の従業員のオブジェクト表(emp_tab)から1つの従業員オブジェクトへのREFを取り出すように設計されたSQL文が格納されています。また、実行時に入力変数(:emp_num)として渡される特定の従業員番号が指定されています。

text *selemp = (text *) "SELECT REF(e)
                          FROM emp_tab e
                          WHERE empno = :emp_num";

アプリケーションでは、第2章「OCIプログラミングの基本」で説明したリレーショナルSQL文の操作と同じ方法でこの文を作成し、処理します。

  • OCIStmtPrepare()を使用してアプリケーション要求を準備します。

  • 適切なバインド・コールを使用してホスト入力変数をバインドします。

  • 従業員オブジェクト参照を受け取る出力変数を宣言し、準備します。ここでは、「Cアプリケーションでのオブジェクトの表現」で宣言した参照に類似した従業員オブジェクト参照を使用します。

OCIRef  *emp1_ref = (OCIRef *) 0; /* reference to an employee object */

出力変数の定義時に、定義コールのdtyデータ型パラメータをSQLT_REF(REFのデータ型定数)に設定します。

  • OCIStmtExecute()で文を実行します。

  • OCIStmtFetch()を使用して、結果のREFemp1_refにフェッチします。

これで、オブジェクト参照を使用して、オブジェクトまたはデータベースからのオブジェクトにアクセスして操作できます。


関連項目:


オブジェクトの確保

フェッチを行うステップが完了すると、アプリケーションでは、オブジェクトへのREF、つまりポインタを取得します。この時点ではまだ実際のオブジェクトは操作できません。オブジェクトを操作するには、そのオブジェクトの確保が必要です。オブジェクトの確保では、オブジェクト・インスタンスをオブジェクト・キャッシュにロードすることにより、必要に応じて、インスタンスの属性へのアクセスおよび変更や、1オブジェクトからその他のオブジェクトへの参照追跡を可能にします。さらにアプリケーションでは、変更したオブジェクトをいつサーバーに書き込むか制御することもできます。


注意:


この項では、一度に1つのオブジェクトを確保する単純な操作の例を示します。複合オブジェクト検索を介した複数オブジェクトの取出しの詳細は、「複合オブジェクト検索」を参照してください。

アプリケーションでオブジェクトを確保するには、関数OCIObjectPin()をコールします。この関数のパラメータによって、オブジェクトのPINオプション、確保継続時間およびロック・オプションを指定できます。

次のコード例は、前の項で取り出した従業員参照のPINオペレーションを示しています。

if (OCIObjectPin(env, err, emp1_ref, (OCIComplexObject *) 0,
     OCI_PIN_ANY,
     OCI_DURATION_TRANS,
     OCI_LOCK_X,  &emp1) != OCI_SUCCESS)
     process_error(err);

この例のprocess_error()はエラー処理関数を表しています。OCIObjectPin()関数で、OCI_SUCCESS以外の値が戻された場合、このエラー処理関数がコールされます。OCIObjectPin()関数のパラメータは次のとおりです。

  • envはOCI環境ハンドルです。

  • errはOCIエラー・ハンドルです。

  • emp1_refは、SQLによって取り出された参照です。

  • (OCIComplexObject *)0は、このPINオペレーションで複合オブジェクト検索を行わないことを示します。

  • OCI_PIN_ANYはPINオプションです。詳細は、「オブジェクト・コピーの確保」を参照してください。

  • OCI_DURATION_TRANSは確保継続時間です。詳細は、「オブジェクト継続時間」を参照してください。

  • OCI_LOCK_Xはロック・オプションです。詳細は、「更新するためのオブジェクトのロック」を参照してください。

  • emp1は出力パラメータで、確保したオブジェクトへのポインタを戻します。

これでオブジェクトが確保され、OCIアプリケーションでは、そのオブジェクトを変更できます。この単純な例では、オブジェクトは他のオブジェクトへの参照を含んでいません。


関連項目:


あるインスタンスから別のインスタンスへのナビゲーション例は、「単純なオブジェクト・ナビゲーション」を参照してください。

配列確保

OCIアプリケーションでは、OCIObjectArrayPin()をコールすることによって、参照の配列に対してオブジェクトの配列を確保できます。参照は、異なる種類のオブジェクトを指し示すことができます。この関数によって、異なる表から異なる型のオブジェクトを1回のネットワーク・ラウンドトリップでフェッチできます。

オブジェクト属性の操作

これでオブジェクトが確保され、OCIアプリケーションでは、その属性を変更できます。OCIには、オブジェクト型構造体のデータ型を操作する一連の関数である、OCIデータ型マッピング関数および操作関数があります。


注意:


オブジェクト・キャッシュで確保したオブジェクトに対する変更内容は、オブジェクトのコピー(インスタンス)にのみ反映され、データベースにある元のオブジェクトには影響を与えません。アプリケーションで行った変更をデータベースに反映するには、変更内容をサーバーにフラッシュまたはコミットする必要があります。詳細は、「オブジェクトのマークおよび変更のフラッシュ」を参照してください。

たとえば、従業員給与を増額できるよう前項で従業員オブジェクトを確保したとします。また、この会社では、入社して180日間未満の従業員には、年間昇給率が案分比例されるとします。

この例の場合、従業員の入社日にアクセスし、現行の日付の180日前より前か後をチェックする必要があります。その計算を基盤として、従業員の給与を$5000(180日より前)または$3000(180日より後)分増額します。次のページのコード例では、このプロセスを示しています。

データ型マッピング関数および操作関数で操作できるのは特定のいくつかのデータ型であり、int型などのその他の型は、適切なOCI型に変換しなければ計算で使用できないことに注意してください。

/* assume that sysdate has been fetched into sys_date, a string. */
/* emp1 and emp1_ref are the same as in previous sections. */
/* err is the OCI error handle. */
/* NOTE: error handling code is not included in this example. */

sb4 num_days;        /* the number of days between today and hiredate */
OCIDate curr_date;          /* holds the current date for calculations */
int raise;   /* holds the employee's raise amount before calculations */
OCINumber raise_num;       /* holds employee's raise for calculations */
OCINumber new_sal;                 /* holds the employee's new salary */

/* convert date string to an OCIDate */
OCIDateFromText(err, (text *) sys_date, (ub4) strlen(sys_date), (text *)
          NULL, (ub1) 0, (text *) NULL, (ub4) 0, &curr_date);

  /* get number of days between hire date and today */
OCIDateDaysBetween(err, &curr_date, &emp1->hiredate, &num_days);

/* calculate raise based on number of days since hiredate */
if (num_days > 180)
    raise = 5000;
else
    raise = 3000;

/* convert raise value to an OCINumber */
OCINumberFromInt(err, (void  *)&raise, (uword)sizeof(raise),
                 OCI_NUMBER_SIGNED, &raise_num);

/* add raise amount to salary */
OCINumberAdd(err, &raise_num, &emp1->salary, &new_sal);
OCINumberAssign(err, &new_sal, &emp1->salary);

この例は、値をパラメータとしてOCIデータ型マッピング関数および操作関数に渡す前に、どのようにOCIデータ型(OCIDateOCINumberなど)に変換するかを示しています。


関連項目:


OCIデータ型、データ型マッピング関数および操作関数の詳細は、第12章「OCIのオブジェクト・リレーショナル・データ型」を参照してください。

オブジェクトのマークおよび変更のフラッシュ

前の項の例では、オブジェクト・インスタンスの属性を変更しました。ただし、この時点では変更はクライアント側のオブジェクト・キャッシュにのみ存在しています。変更をデータベースに確実に書き込むために、アプリケーションで特定のステップを実行する必要があります。

最初のステップでは、オブジェクトが変更されたことを示します。これは、OCIObjectMarkUpdate()関数を使用して行います。この関数は、オブジェクトに使用済(変更あり)のマークを設定します。

使用済フラグが設定されているオブジェクトは、変更をデータベースに記録するために、サーバーにフラッシュする必要があります。次の3つの方法でこれを実行します。

  • 単一の使用済オブジェクトは、OCIObjectFlush()をコールしてフラッシュします。

  • OCICacheFlush()を使用して、キャッシュ全体をフラッシュします。この場合、OCIはキャッシュで管理されている使用済リストを横断して、使用済オブジェクトをサーバーにフラッシュします。

  • OCITransCommit()をコールして、トランザクションをコミットします。この方法でも、使用済リストを横断してオブジェクトをサーバーにフラッシュします。

フラッシュ操作は、キャッシュの永続オブジェクトのみに作用します。一時オブジェクトはサーバーにフラッシュされません。

オブジェクトをサーバーにフラッシュすることで、データベースのトリガーをアクティブにすることができます。実際、アプリケーションでオブジェクトを明示的にフラッシュし、サーバー側のトリガーを起動することが必要な場合があります。


関連項目:


埋込みオブジェクトのフェッチ

使用しているアプリケーションで、埋込みオブジェクト・インスタンス(オブジェクト表でなく、通常の表の列に格納されているオブジェクト)をフェッチする必要がある場合、「サーバーからのオブジェクト参照の取出し」で説明するREF検索機能は使用できません。埋込みインスタンスにはオブジェクト識別子がないため、埋込みインスタンスへのREFは取得できません。これは埋込みインスタンスがオブジェクト・ナビゲーションの基礎として機能しないことを意味します。しかし、アプリケーションで埋込みインスタンスをフェッチすることが必要な状況は数多くあります。

たとえば、address型が作成されたとします。

CREATE TYPE address AS OBJECT
( street1             varchar2(50),
  street2             varchar2(50),
  city                varchar2(30),
  state               char(2),
  zip                 number(5));

その型を、他の表で列のデータ型として使用することができます。

CREATE TABLE clients
( name          varchar2(40),
  addr          address);

OCIアプリケーションで次のSQL文を発行します。

SELECT addr FROM clients
WHERE name='BEAR BYTE DATA MANAGEMENT'

この文は、clients表の埋込みオブジェクトaddressを戻します。アプリケーションでは、このオブジェクトの属性値を別の処理で使用できます。

アプリケーションでは、第2章「OCIプログラミングの基本」で説明したリレーショナルSQL文の操作と同じ方法でこの文を作成し、処理します。

  • OCIStmtPrepare()を使用してアプリケーション要求を準備します。

  • 適切なバインド・コールを使用して入力変数をバインドします。

  • addressインスタンスを受け取る出力変数を定義します。「Cアプリケーションでのオブジェクトの表現」で説明するとおり、OTTで生成されたオブジェクト型のC構造体表現を使用します。

    addr1      *address; /* variable of the address struct type */
    

    出力変数を定義するときは、定義コールのデータ型パラメータdtyをSQLT_NTY(名前付きデータ型のデータ型定数)に設定する必要があります。

  • OCIStmtExecute()で文を実行します。

  • OCIStmtFetch()を使用して結果のインスタンスをaddr1にフェッチします。

次に、「オブジェクト属性の操作」で説明しているように、インスタンスの属性にアクセスするか、あるいはインスタンスを別のSQL文の入力パラメータとして渡すことができます。


注意:


埋込みインスタンスに対する変更内容は、SQLのUPDATE文の実行によってのみ永続的にできます。


関連項目:


SQL文の準備と実行の詳細は、「OCIプログラミング・ステップ」を参照してください。

オブジェクトのメタ属性

オブジェクトのメタ属性には、オブジェクトの状態に関する情報を、アプリケーションまたはオブジェクト・キャッシュに提供できるフラグの役割があります。たとえば、オブジェクトのメタ属性の1つとして、オブジェクトがサーバーにフラッシュ済かどうかを示す属性があります。これは、アプリケーションでインスタンスの動作を制御するのに役立ちます。

永続オブジェクトのインスタンスと一時オブジェクトのインスタンスには、それぞれ異なるメタ属性があります。永続オブジェクトのメタ属性は、さらに永続メタ属性と一時メタ属性に分かれます。一時メタ属性は、インスタンスがメモリー内にあるときにのみ存在します。永続メタ属性は、サーバーに格納されているオブジェクトにも適用されます。

永続オブジェクトのメタ属性

表11-1は、スタンドアロン永続オブジェクトのメタ属性を示しています。

表11-1 永続オブジェクトのメタ属性

メタ属性 意味

既存

オブジェクトが存在しているか

NULL

インスタンスのNULL情報

ロック

オブジェクトはロックされているか

使用済

オブジェクトに使用済のマークが設定されているか

確保済

オブジェクトは確保済か

割当て時間

「オブジェクト継続時間」を参照してください。

確保継続時間

「オブジェクト継続時間」を参照してください。



注意:


埋込み永続オブジェクトの属性は、一時属性である「NULLかどうか」と「割当て時間」のみです。

OCIは、アプリケーションでオブジェクトのあらゆる属性のステータスをチェックできるOCIObjectGetProperty()関数を提供します。この関数の構文は次のとおりです。

sword OCIObjectGetProperty ( OCIEnv              *envh,
                             OCIError            *errh,
                             CONST void          *obj,
                             OCIObjectPropId     propertyId,
                             void                *property,
                             ub4                 *size );

propertyIdおよびpropertyパラメータは、あらゆるプロパティまたは属性に関する情報の取出しに使用されます。

異なるプロパティIDとそれに対応するproperty引数の型を次に示します。

OCI_OBJECTPROP_LIFETIME

このプロパティによって、指定されたオブジェクトが永続オブジェクト、一時オブジェクト、または値のインスタンスかのいずれであるかが識別されます。property引数はOCIObjectLifetime型の変数へのポインタにしてください。可能な値は、次のとおりです。

  • OCI_OBJECT_PERSISTENT

  • OCI_OBJECT_TRANSIENT

  • OCI_OBJECT_VALUE

OCI_OBJECTPROP_SCHEMA

このプロパティによって、オブジェクトが存在する表のスキーマ名が戻されます。指定されたオブジェクトが一時インスタンスまたは値を指し示している場合は、エラーが戻されます。スキーマ名の保持に入力バッファのサイズが足りない場合は、エラーが戻され、エラー・メッセージで必要なサイズが表示されます。成功した場合は、sizeによって、戻されたスキーマ名のサイズがバイト単位で戻されます。property引数は、text型の配列にしてください。コール元は、sizeをバイト単位で配列のサイズに設定する必要があります。

OCI_OBJECTPROP_TABLE

このプロパティによってそのオブジェクトが存在する表名が戻されます。指定されたオブジェクトが一時インスタンスまたは値を指し示している場合は、エラーが戻されます。表名の保持に入力バッファが足りない場合は、エラーが戻され、エラー・メッセージで必要なサイズが表示されます。成功した場合は、sizeによって、戻された表名のサイズがバイト単位で戻されます。property引数は、text型の配列にしてください。コール元では、sizeを配列のサイズにバイト単位で設定する必要があります。

OCI_OBJECTPROP_PIN_DURATION

このプロパティによってオブジェクトの確保継続時間が戻されます。指定されたオブジェクトが値のインスタンスを指し示している場合は、エラーが戻されます。property引数はOCIDuration型の変数へのポインタにしてください。次の値が有効です。

  • OCI_DURATION_SESSION

  • OCI_DURATION_TRANS

OCI_OBJECTPROP_ALLOC_DURATION

このプロパティによって、オブジェクトの割当て時間が戻されます。property引数はOCIDuration型の変数へのポインタにしてください。次の値が有効です。

OCI_OBJECTPROP_LOCK

このプロパティによってオブジェクトのロック状況が戻されます。可能なロック状況は、OCILockOptで計数値です。指定されたオブジェクトが一時インスタンスまたは値インスタンスを指し示している場合は、エラーが戻されます。property引数はOCILockOpt型の変数へのポインタにしてください。オブジェクトのロック状況は、OCIObjectIsLocked()関数をコールしても取り出せます。

OCI_OBJECTPROP_MARKSTATUS

このプロパティによって使用済ステータスが戻され、オブジェクトが新規のオブジェクトであるか、更新されたオブジェクトであるか、削除されたオブジェクトであるかが示されます。指定されたオブジェクトが一時インスタンスまたは値インスタンスを指し示している場合は、エラーが戻されます。property引数はOCIObjectMarkStatus型にしてください。次の値が有効です。

  • OCI_OBJECT_NEW

  • OCI_OBJECT_DELETED

  • OCI_OBJECT_UPDATED

次のマクロを使用してマーク状態をテストすることが可能です。

  • OCI_OBJECT_IS_UPDATED (flag)

  • OCI_OBJECT_IS_DELETED (flag)

  • OCI_OBJECT_IS_NEW (flag)

  • OCI_OBJECT_IS_DIRTY (flag)

OCI_OBJECTPROP_VIEW

このプロパティによって指定されたオブジェクトがオブジェクト・ビューであるかどうかが識別されます。戻されたプロパティ値がTRUEであれば、オブジェクトはビューであり、TRUEでない場合はオブジェクトはビューではありません。指定されたオブジェクトが一時インスタンスまたは値インスタンスを指し示している場合は、エラーが戻されます。このproperty引数はブール型にする必要があります。

ビューが仮想表であるのと同様に、オブジェクト・ビューは仮想オブジェクト表です。ビューの各行はオブジェクトであるため、メソッドのコール、ドット表記法を使用したオブジェクト属性へのアクセスおよびオブジェクトを指すREFの作成が可能です。

その他の属性関数

次の表に示すように、OCIには、アプリケーションでこれらの属性を直接的または間接的に設定あるいはチェックできる関数が提供されています。

表11-2 設定およびチェック関数

メタ属性 設定に使用する関数 チェックに使用する関数

NULL

<なし>

OCIObjectGetInd()

存在

<なし>

OCIObjectExists()

ロック

OCIObjectLock()

OCIObjectIsLocked()

使用済

OCIObjectMark()

OCIObjectIsDirty()


一時オブジェクトのメタ属性

一時オブジェクトには次の一時属性があります。一時オブジェクトに永続属性はありません。

表11-3 一時メタ属性

一時メタ属性 意味

既存

オブジェクトが存在しているか

確保済

オブジェクトはアプリケーションによってアクセスされるか

使用済

オブジェクトに使用済のマークが設定されているか

NULL

インスタンスのNULL情報

割当て時間

「オブジェクト継続時間」を参照してください。

確保継続時間

「オブジェクト継続時間」を参照してください。


複合オブジェクト検索

ここまでの例は、一度に1つのインスタンスのみのフェッチまたは確保を行う例でした。その場合、オブジェクトを取り出すためのサーバー・ラウンドトリップが、PINオペレーションごとに別個に発生します。

オブジェクト指向アプリケーションでは、相互に関連したオブジェクトの集合として問題をモデル化することがよくあります。これらのオブジェクトは、オブジェクトのグラフを形成します。アプリケーションでは、初期オブジェクト集合の一部からオブジェクトの処理を開始し、その一部のオブジェクトの参照を使用して残りのオブジェクトを横断します。クライアント/サーバー設定では、横断のたびにオブジェクトをフェッチするためのネットワーク・ラウンドトリップが発生し、非効率的です。

オブジェクトの処理時に、複合オブジェクト検索(COR)を使用すると、アプリケーションのパフォーマンスが向上する場合があります。これはプリフェッチ・メカニズムであり、アプリケーションでは、このメカニズムを使用して、リンクされた一連のオブジェクトを1回の操作で取り出すための基準を指定します。


注意:


後述するように、プリフェッチ・オブジェクトがすべて確保されているとはかぎりません。それらはオブジェクト・キャッシュ内にフェッチされるため、後続の確保コールはローカル操作で行われます。

複合オブジェクトは、論理的に関連した複数のオブジェクトの集合です。この集合は、ルート・オブジェクトと、指定したネスト・レベルに基づいてそれぞれプリフェッチされた一連のオブジェクトで構成されています。ルート・オブジェクトは、明示的にフェッチまたは確保されます。ネスト・レベルは、複合オブジェクトのルート・オブジェクトから指定のプリフェッチ・オブジェクトまで最短で横断した場合の参照の数です。

アプリケーションで複合オブジェクトを指定するときは、複合オブジェクトの内容と境界を記述します。複合オブジェクトのフェッチは、環境のプリフェッチ制限、つまり、複数オブジェクトのプリフェッチに使用可能なオブジェクト・キャッシュ内のメモリー容量によって制約されます。


注意:


CORによって機能性が追加されるわけではなく、パフォーマンスが改善されるのみです。オプションとして使用してください。

この説明の例として、次の型宣言があるとします。

CREATE TYPE customer(...);
CREATE TYPE line_item(...);
CREATE TYPE line_item_varray as VARRAY(100) of REF line_item;
CREATE TYPE purchase_order AS OBJECT
( po_number         NUMBER,
  cust              REF customer,
  related_orders    REF purchase_order,
  line_items        line_item_varray);

purchase_order型には、スカラー値po_numberVARRAYのline_itemsおよび2つの参照が含まれています。1つはcustomer型への参照、もう1つはpurchase_order型への参照であり、この型がリンク済リストとして実装されることを示しています。

複合オブジェクトをフェッチする場合は、アプリケーションで次の指定をする必要があります。

  1. 目的のルート・オブジェクトへのREF

  2. 複合オブジェクトの境界を指定するための1組以上の型およびネストの情報。型情報は、CORでたどるREF属性を示し、ネスト・レベルはリンクをたどるレベル数を示します。

前述の発注情報オブジェクトの場合は、アプリケーションで次の指定をする必要があります。

  1. ルート発注情報オブジェクトへのREF

  2. custrelated_ordersまたはline_itemsについての1組以上の型およびネストの情報。

発注情報をプリフェッチするアプリケーションでは、発注書を発行した顧客の情報にアクセスすることも十分考えられます。単純なナビゲーションでは、2つのオブジェクトをフェッチするためにサーバーに2回アクセスすることが必要です。複合オブジェクト検索によって、発注情報を確保するときに顧客をプリフェッチできます。この場合、複合オブジェクトは、発注情報オブジェクトと参照する顧客のオブジェクトで構成されます。

前の例では、アプリケーションはREFpurchase_orderを指定し、cust REF属性をネスト・レベル1までたどるように指示します。

  1. REF(PO object)

  2. {(customer, 1)}

アプリケーションで、purchase_orderオブジェクトと、オブジェクト・グラフに含まれるすべてのオブジェクトをプリフェッチする必要がある場合、custおよびrelated_ordersは両方とも、最大のネスト・レベルまでたどるようにアプリケーションで指示します。

  1. REF(PO object)

  2. {(customer, UB4MAXVAL), (purchase_order, UB4MAXVAL)}

UB4MAXVALは、ルート・オブジェクトから参照を通して到達できる指定の型のオブジェクトすべてのプリフェッチを指定します。

アプリケーションで、POおよび関連する明細項目すべてをフェッチする場合は、次の指定をします。

  1. REF(PO object)

  2. {(line_item, 1)}

アプリケーションでは、REFを通して特定の深さまで到達できる(推移閉包)オブジェクトすべてをフェッチすることも選択できます。そのためには、目的の深さをレベル・パラメータとして設定する必要があります。前述の2つの例では、それぞれアプリケーションで(PO object REF, UB4MAXVAL)(PO object REF, 1)を指定して、必要なオブジェクトをプリフェッチすることもできます。この場合は多数のフェッチが余計に発生しますが、指定が非常に簡単であり、サーバー・ラウンドトリップが1回のみですみます。

オブジェクトのプリフェッチ

複合オブジェクトを指定してフェッチした後に行う、複合オブジェクトに含まれるオブジェクトのフェッチでは、ネットワーク・ラウンドトリップは発生しません。これは、オブジェクトがすでにプリフェッチ済であり、オブジェクト・キャッシュ内にあるためです。プリフェッチするオブジェクトが多すぎると、オブジェクト・キャッシュがあふれることがあるので注意が必要です。オブジェクト・キャッシュがあふれると、アプリケーションですでに確保している他のオブジェクトがキャッシュから押し出され、パフォーマンスの向上ではなく逆にパフォーマンスの低下につながることがあります。


注意:


プリフェッチ・オブジェクトすべてを保持するためのメモリーがキャッシュにない場合は、オブジェクトの一部がプリフェッチされない場合があります。アプリケーションでは、後でそれらのオブジェクトにアクセスするとき、ネットワーク・ラウンドトリップが発生します。

プリフェッチ・オブジェクトすべてに、SELECT権限が必要です。複合オブジェクト内のオブジェクトに対するSELECT権限がアプリケーションにない場合、そのオブジェクトはプリフェッチできません。

OCIでの複合オブジェクト検索の実装

複合オブジェクト検索(COR)によって、アプリケーションは、ルート・オブジェクトをフェッチするときに複合オブジェクトのプリフェッチができます。単純オブジェクトに対して使用するのと同じOCIObjectPin()関数に、複合オブジェクト指定を渡します。

アプリケーションでは、複合オブジェクト検索ハンドルを使用して、複合オブジェクト検索のパラメータを指定します。このハンドルは、OCIComplexObject型であり、その他のOCIハンドルと同じ方法で割り当てます。

複合オブジェクト検索ハンドルの内容は、複合オブジェクト検索記述子のリストです。複合オブジェクト検索記述子は、OCIComplexObjectComp型であり、その他のOCI記述子と同じ方法で割り当てます。

各COR記述子には、REF型とネスト・レベルが含まれています。REF型では、複合オブジェクトを組み立てるときにたどる参照の型を指定します。ネスト・レベルで、特定の型の参照をどこまでたどるかを指定します。ネスト・レベルの最大値には、整数値または定数UB4MAXVALを指定します。

アプリケーションでは、タイプ・パラメータとネスト・レベル・パラメータのCOR記述子を作成しないで、CORハンドルにネスト・レベルを指定することもできます。この場合、すべてのREFについて、CORハンドルに指定されたネスト・レベルまでたどります。また、要求があったときに個別にコレクション属性がフェッチされる(アウト・ライン)かどうかも、CORハンドルで指定できます。デフォルトでは、コレクション属性は、それを含むオブジェクトとともにフェッチされます(インライン)。

アプリケーションでCORハンドルの属性を設定するには、OCIAttrSet()を使用します。次の属性があります。

OCI_ATTR_COMPLEXOBJECT_LEVEL− ネスト・レベル

OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE− オブジェクト型のコレクション属性をアウト・ラインでフェッチ

アプリケーションで、OCIDescriptorAlloc()を使用してCOR記述子を割り当て、次の属性を設定できます。

OCI_ATTR_COMPLEXOBJECTCOMP_TYPEREF

OCI_ATTR_COMPLEXOBJECTCOMP_LEVEL− 前述の型の参照に使用するネスト・レベル

これらの属性を設定すると、アプリケーションではOCIParamSet()をコールして記述子を複合オブジェクト検索ハンドルに設定します。ハンドルにはハンドルの記述子の数を指定するOCI_ATTR_PARAM_COUNT属性があります。この属性はOCIAttrGet()で読み取ることができます。

ハンドルに記述子を挿入した後、ハンドルをOCIObjectPin()コールに渡してルート・オブジェクトを確保し、複合オブジェクトの残りのオブジェクトのプリフェッチを行います。

複合オブジェクト検索ハンドルと記述子は、必要がなくなったとき、明示的に解放する必要があります。


関連項目:


ハンドルと記述子の詳細は、「ハンドル」および「OCI記述子」を参照してください。

CORプリフェッチ

アプリケーションでは、ルート・オブジェクトのフェッチ時に複合オブジェクトを指定します。プリフェッチ・オブジェクトは、指定のルート・オブジェクトを基点とするオブジェクトのグラフに対して、幅優先横断を実行することによって取得されます。横断は、必要なオブジェクトがすべてプリフェッチされたとき、またはプリフェッチ・オブジェクトの合計サイズがプリフェッチ制限を超えたときに停止します。

CORインタフェース

複合オブジェクトをフェッチするためのインタフェースは、OCI確保インタフェースです。アプリケーションは、初期化済のCORハンドルをOCIObjectPin()に(またはハンドルの配列をOCIObjectArrayPin()に)渡して、ルート・オブジェクト、およびCORハンドルで指定したプリフェッチ・オブジェクトをフェッチすることができます。

sword OCIObjectPin ( OCIEnv              *env,
                     OCIError            *err,
                     OCIRef              *object_ref,
                     OCIComplexObject    *corhdl,
                     OCIPinOpt           pin_option,
                     OCIDuration         pin_duration,
                     OCILockOpt          lock_option,
                     void                **object );

sword OCIObjectArrayPin ( OCIEnv            *env,
                          OCIError          *err,
                          OCIRef            **ref_array,
                          ub4               array_size,
                          OCIComplexObject  **cor_array,
                          ub4               cor_array_size,
                          OCIPinOpt         pin_option,
                          OCIDuration       pin_duration,
                          OCILockOpt        lock,
                          void              **obj_array,
                          ub4               *pos );

CORの使用時には、次の点について留意してください。

  1. NULLのCORハンドル引数は、デフォルトでルート・オブジェクトのみを確保します。

  2. ルート・オブジェクト型でネスト・レベル0のCORハンドルは、ルート・オブジェクトのみをフェッチします。つまり、NULLのCORハンドルに相当します。

  3. ロック・オプションは、ルート・オブジェクトのみに適用されます。


    注意:


    プリフェッチ・オブジェクトにロック・オプションを指定するために、アプリケーションでは配列インタフェース(OCIObjectArrayPin())を使用して、複合オブジェクト内のオブジェクトすべてにアクセスし、REFの配列を作成し、別のラウンドトリップで複合オブジェクト全体をロックできます。

CORの例

次の例では、複合オブジェクト検索を行うためにアプリケーション・プログラムを修正する方法を詳しく説明します。

発注情報とそれに関連した明細項目を表示するアプリケーションを考えてみます。太字のコードでこの処理を実行します。残りのコードでは、プリフェッチの複合オブジェクト検索を使用するため、アプリケーションのパフォーマンスが向上します。

OCIEnv *envhp;
OCIError *errhp;
OCIRef **liref;
OCIRef *poref;
OCIIter *itr;
boolean  eoc;
purchase_order *po = (purchase_order *)0;
line_item *li = (line_item *)0;
OCISvcCtx *svchp;
OCIComplexObject *corhp;
OCIComplexObjectComp *cordp;
OCIType *litdo;
ub4 level = 0;

/* get COR Handle */
OCIHandleAlloc((void  *) envhp, (void  **) &corhp, (ub4)
                OCI_HTYPE_COMPLEXOBJECT, 0, (void  **)0);

/* get COR descriptor for type line_item */
OCIDescriptorAlloc((void  *) envhp, (void  **) &cordp, (ub4)
                OCI_DTYPE_COMPLEXOBJECTCOMP, 0, (void  **) 0);

/* get type of line_item to set in COR descriptor */
OCITypeByName(envhp, errhp, svchp, (const text *) 0, (ub4) 0,
              (const text *) "LINE_ITEM",
              (ub4) strlen((const char *) "LINE_ITEM"), (text *) 0,
              (ub4) 0, OCI_DURATION_SESSION,
              OCI_TYPEGET_HEADER, &litdo);

/* set line_item type in COR descriptor */
OCIAttrSet( (void  *) cordp, (ub4) OCI_DTYPE_COMPLEXOBJECTCOMP,
            (void  *) litdo, (ub4) sizeof(void  *), (ub4)
            OCI_ATTR_COMPLEXOBJECTCOMP_TYPE, (OCIError *) errhp);
level = 1;

/* set depth level for line_item_varray in COR descriptor */
OCIAttrSet( (void  *) cordp, (ub4) OCI_DTYPE_COMPLEXOBJECTCOMP,
            (void  *) &level, (ub4) sizeof(ub4), (ub4)
            OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL, (OCIError *) errhp);

/* put COR descriptor in COR handle */
OCIParamSet(corhp, OCI_HTYPE_COMPLEXOBJECT, errhp, cordp,
            OCI_DTYPE_COMPLEXOBJECTCOMP, 1);

/* pin the purchase order */
OCIObjectPin(envhp, errhp, poref, corhp, OCI_PIN_LATEST,
   OCI_DURATION_SESSION, OCI_LOCK_NONE, (void  **)&po);

/* free COR descriptor and COR handle */
OCIDescriptorFree((void  *) cordp, (ub4) OCI_DTYPE_COMPLEXOBJECTCOMP);
OCIHandleFree((void  *) corhp, (ub4) OCI_HTYPE_COMPLEXOBJECT);

/* iterate and print line items for this purchase order */
OCIIterCreate(envhp, errhp, po->line_items, &itr);

/* get first line item */
OCIIterNext(envhp, errhp, itr, (void  **)&liref, (void  **)0, &eoc);
while (!eoc)        /* not end of collection */
{
/* pin line item */
   OCIObjectPin(envhp, errhp, *liref, (void  *)0, OCI_PIN_RECENT,
       OCI_DURATION_SESSION,
       OCI_LOCK_NONE, (void  **)&li));
  display_line_item(li);

/* get next line item */
OCIIterNext(envhp, errhp, itr, (void  **)&liref, (void  **)0, &eoc);
}

OCIとSQLのオブジェクトへのアクセス

アプリケーションで複数オブジェクト(オブジェクト参照によって相互に関連)のグラフを操作する必要がある場合は、オブジェクトへのアクセスに、SQLインタフェースよりもOCIインタフェースを使用する方が効率的です。SQLインタフェースを使用してオブジェクトのグラフを取り出すには、複数のSELECT文の実行、つまり、複数のネットワーク・ラウンドトリップが必要になる場合があります。OCIによって提供される複合オブジェクト検索機能を使用すると、アプリケーションは1つのOCIObjectPin()コール内で複数のオブジェクトのグラフを取り出せます。

アプリケーションでオブジェクトのグラフを取り出し、それをユーザーとの対話を基に変更して、その変更をデータベース内に持続させる場合の更新について考えてみます。SQLインタフェースを使用する場合、アプリケーションではオブジェクトのグラフの更新に複数のUPDATE文を実行する必要があります。新しいオブジェクトの作成と既存のオブジェクトの削除が変更に含まれている場合は、対応するINSERT文およびDELETE文も実行する必要があります。さらに、アプリケーションでは、表名の変更状況など、INSERT文、UPDATE文またはDELETE文の実行に必要な、さらに多くの情報を記録する必要があります。

OCIのOCICacheFlush()関数を使用すると、アプリケーションですべての変更(オブジェクトの挿入、削除および更新)を単一の操作でフラッシュできます。OCIではすべてが記録されるので、アプリケーション側のコーディングが少なくてすみます。このように、オブジェクトのグラフの操作にOCIを使用すると、効率的なだけでなく使用しやすいインタフェースが提供されます。

たとえば、アプリケーションでREFを使用してオブジェクトをフェッチする必要がある場合を考えてみます。OCIの場合、このフェッチは、OCIObjectPin()コールを使用してそのオブジェクトを確保することで、実行されます。SQLインタフェースの場合、このフェッチは、SELECT文(たとえば、SELECT DEREF(ref) from tbl;)のREFを参照解除することで実行されます。同じREF(同じオブジェクトへの参照)が1つのトランザクション内で複数回参照解除されるような状況について考えてみます。OCI_PIN_RECENTオプションとともにOCIObjectPin()をコールすると、トランザクションに対してオブジェクトがサーバーから1度のみフェッチされ、同じREFで確保が繰り返し行われる結果、すでにキャッシュ内に確保されているオブジェクトへのポインタが戻されます。 SQLインタフェースの場合は、SELECT DEREF...文の実行のたびに、サーバーからオブジェクトがフェッチされるため、サーバーへのラウンドトリップが何度も行われ、同じオブジェクトが複数コピーされる結果となります。

最後に、アプリケーションで、参照不可能なオブジェクトをフェッチする必要がある場合について考えてみます。たとえば、次のとおりです。

CREATE TABLE department
(
deptno number,
deptname varchar2(30),
manager employee_t
);

manager列に格納されたemployee_tインスタンスは、参照不可能です。manager列インスタンスをフェッチするには、SQLインタフェースのみが使用できます。ただし、employee_tREF属性がある場合は、OCIコールを使用してREFをナビゲートできます。

確保カウントおよび確保解除

オブジェクト・キャッシュ内の各オブジェクトには、確保カウントが関連付けられています。本来、確保カウントはオブジェクトに並行アクセスするコード・モジュールの数を表します。オブジェクトを初めてキャッシュに確保したときに、確保カウントが1に設定されます。複合オブジェクト検索でプリフェッチ・オブジェクトをオブジェクト・キャッシュに入れた時点では、オブジェクトの確保カウントは0(ゼロ)です。

すでに確保されているオブジェクトを確保することができます。そうすると、確保カウントが1増えます。プロセスでオブジェクトの使用が終了したときは、OCIObjectUnpin()を使用して確保解除を行う必要があります。このコールによって確保カウントが1減ります。

オブジェクトの確保カウントが0(ゼロ)になった場合、必要があればオブジェクトをキャッシュから出し、オブジェクトが占めているメモリー領域を解放できます。

オブジェクトの確保カウントは、OCIObjectPinCountReset()をコールして、明示的に0(ゼロ)に設定できます。

アプリケーションではOCICacheUnpin()をコールして、キャッシュ内にある特定の接続に関連した全オブジェクトを確保解除できます。


関連項目:


NULLインジケータ構造体

データベース表で、行の中に値のない列がある場合、その列はNULLまたはNULLを含むと呼ばれます。オブジェクトには、次の2種類のNULLを適用できます。

  • オブジェクトの属性はすべて、NULL値を持つことができます。これはオブジェクトの属性の値が不明であることを意味します。

  • オブジェクトのインスタンスは、アトミックNULLにできます。これはオブジェクト全体の値が不明なことを意味します。

アトミックNULLとは、オブジェクトが存在しないということではありません。アトミックNULLのインスタンスは、値が不明なだけで、存在しています。つまり、データを持たないオブジェクトとみなすことができます。

OCIでオブジェクトを操作する場合は、アプリケーションで使用する各オブジェクト型のNULLインジケータ構造体を定義できます。そのために必要な作業は、通常、OTTで生成したNULLインジケータ構造体を構造体宣言とともに組み込むことのみです。OTTの出力ヘッダー・ファイルを組み込むと、アプリケーションでNULLインジケータ構造体を使用できるようになります。

各型に対するNULLインジケータ構造体の内容は、アトミックNULLインジケータ(OCIInd型)とインスタンスの各属性のNULLインジケータです。型にオブジェクト属性がある場合、NULLインジケータ構造体には、その属性のNULLインジケータ構造体が含まれます。次の例は、それぞれ対応するNULLインジケータ構造体を持つ型のC言語での表現方法を示しています。

struct address
{
   OCINumber    no;
   OCIString    *street;
   OCIString    *state;
   OCIString    *zip;
};
typedef struct address address;

struct address_ind
{
  OCIInd    _atomic;
  OCIInd    no;
  OCIInd    street;
  OCIInd    state;
  OCIInd    zip;
};
typedef struct address_ind address_ind;


struct person
{
   OCIString      *fname;
   OCIString      *lname;
   OCINumber      age;
   OCIDate        birthday;
   OCIArray       *dependentsAge;
   OCITable       *prevAddr;
   OCIRaw         *comment1;
   OCILobLocator  *comment2;
   address        addr;
   OCIRef         *spouse;
};
typedef struct person person;

struct person_ind
{
  OCIInd        _atomic;
  OCIInd        fname;
  OCIInd        lname;
  OCIInd        age;
  OCIInd        birthday;
  OCIInd        dependentsAge;
  OCIInd        prevAddr;
  OCIInd        comment1;
  OCIInd        comment2;
  address_ind   addr;
  OCIInd        spouse;
};
typedef struct person_ind person_ind;

注意:


person_inddependentsAgeフィールドは、VARRAY(personの配列dependentsAgeフィールド)全体がアトミックNULLかどうかを示します。dependentsAgeフィールドの個々の要素のNULL情報は、OCICollGetElem()のコールのelemindパラメータを通して取り出せます。同様に、person_indprevAddrフィールドは、NESTED TABLE(personprevAddrフィールド)全体がアトミックNULLかどうかを示します。prevAddrフィールドの個々の要素のNULL情報は、OCICollGetElem()のコールのelemindパラメータを通して取り出せます。

オブジェクト型インスタンスの場合は、NULLインジケータ構造体の最初のフィールドがアトミックNULLインジケータで、残りのフィールドはレイアウトがオブジェクト型インスタンスの属性に似ている属性NULLインジケータです。

アプリケーションでは、アトミックNULLインジケータの値をチェックすることで、インスタンスがアトミックNULLかどうかをテストできます。また、他のインスタンスをチェックすることで、次のコード例で示すように、アプリケーションでその属性のNULL状態をテストできます。

person_ind *my_person_ind
if( my_person_ind -> _atomic == OCI_IND_NULL)
   printf ("instance is atomically NULL\n");
else
if( my_person_ind -> fname == OCI_IND_NULL)
   printf ("fname attribute is NULL\n");

前述の例では、アトミックNULLインジケータまたは属性NULLインジケータの値が事前定義の値OCI_IND_NULLと比較され、NULLかどうかがテストされます。この比較では、事前定義済の次の値が使用可能です。

  • OCI_IND_NOTNULL− 値がNULLでないことを示します。

  • OCI_IND_NULL− 値がNULLであることを示します。

  • OCI_IND_BADNULL− 囲みオブジェクト(親オブジェクト)がNULLであることを示します。この値はPL/SQLで使用され、INVALID_NULLとしても参照されます。たとえば、型インスタンスがNULLの場合、その属性はINVALID_NULLです。

OCIObjectGetInd()関数を使用して、オブジェクトのNULLインジケータ構造体を取り出します。

C構造体内の属性を更新する場合、その属性のNULLインジケータも設定する必要があります。

obj->attr1 = string1;
OCIObjectGetInd(envhp, errhp, obj, &ind);
ind->attr1 = OCI_IND_NOTNULL;

関連項目:


OTTで生成するNULLインジケータ構造体の詳細は、第15章「OCIでのObject Type Translatorの使用」を参照してください。

オブジェクトの作成

OCIアプリケーションでは、OCIObjectNew()を使用してあらゆるオブジェクトを作成できます。アプリケーションで永続オブジェクトを作成するには、新規オブジェクトを挿入するオブジェクト表を指定してください。この値は、OCIObjectPinTable()をコールして取り出し、tableパラメータで渡します。一時オブジェクトを作成するには、作成するオブジェクトの型に対する型記述子オブジェクト(OCIDescribeAny()をコールして取出し)のみを渡す必要があります。

また、 typecodeパラメータに適切な値を渡し、OCIObjectNew()を使用して、スカラーのインスタンス(REF、LOB、文字列、ロー、数値、日付など)およびコレクション(VARRAYやNESTED TABLEなど)を作成できます。

新規オブジェクトの属性値

デフォルトでは、新規作成されたオブジェクトのすべての属性に NULL値があります。属性データを初期化した後で、対応する各属性のNULLステータスをNULL以外に変更する必要があります。

オブジェクトの作成時に、属性をNULL以外の値に設定できます。これは、OCIAttrSet()を使用して環境ハンドルのOCI_OBJECT_NEWNOTNULL属性をTRUEに設定することによって実行できます。その後、この属性をFALSEに設定することにより、このモードを無効にできます。

OCI_OBJECT_NEWNOTNULLTRUEに設定されている場合は、OCIObjectNew()によってNULL以外のオブジェクトが作成されます。オブジェクトの属性には、次の表に示したデフォルト値があり、対応するNULLインジケータは、NOT NULLに設定されています。

表11-4 新しいオブジェクトの属性値

属性の型 デフォルト値
REF

オブジェクトにREF属性がある場合は、オブジェクトをフラッシュする前にこの属性を有効なREFに設定する必要があります。そうしないとエラーが戻されます。

DATE

Oracleで扱える最古の日付。01-JAN-4712 BCE(ユリウス日の第1日)の午前0時。

ANSI DATE

Oracleで扱える最古の日付。01-JAN-4712 BCE(ユリウス日の第1日)。

TIMESTAMP

Oracleで扱える最古の日時。01-JAN-4712 BCE(ユリウス日の第1日)の午前0時。

TIMESTAMP WITH TIME ZONE

Oracleで扱える最古の日時。UTC(0:0)タイム・ゾーンで、01-JAN-4712 BCE(ユリウス日の第1日)の午前0時。

TIMESTAMP WITH LOCAL TIME ZONE

Oracleで扱える最古の日時。UTC(0:0)タイム・ゾーンで、01-JAN-4712 BCE(ユリウス日の第1日)の午前0時。

INTERVAL YEAR TO MONTH

INTERVAL '0-0' YEAR TO MONTH

INTERVAL DAY TO SECOND

INTERVAL '0 0:0:0' DAY TO SECOND

FLOAT

0.

NUMBER

0

DECIMAL

0.

RAW

長さが0に設定されたロー・データ。注意: RAW属性のデフォルト値は、NULL RAW属性のデフォルト値と同じです。

VARCHAR2, NVARCHAR2

長さが0で最初の文字がNULLに設定されたOCIString。デフォルト値は、ヌル文字列属性のデフォルト値と同じです。

CHAR, NCHAR

長さが0で最初の文字がNULLに設定されたOCIString。デフォルト値は、ヌル文字列属性のデフォルト値と同じです。

VARCHAR

長さが0で最初の文字がNULLに設定されたOCIString。デフォルト値は、ヌル文字列属性のデフォルト値と同じです。

VARRAY

要素が0のコレクション。

NESTED TABLE

要素が0の表。

CLOB, NCLOB

空のCLOB

BLOB

空のBLOB

BFILE

ディレクトリ・オブジェクトおよびファイル名を設定することによって、BFILEを有効な値に初期化する必要があります。


オブジェクトの解放およびコピー

OCIObjectFree()を使用して、OCIObjectNew()で割り当てたメモリーを解放できます。オブジェクト・インスタンスには、追加メモリー(2次メモリー・チャンク)へのポインタである属性を設定できます。

オブジェクトの解放とは、関連するNULLインジケータ構造体や2次メモリー・チャンクなど、オブジェクトに割り当てたすべてのメモリーの割当てを解除することです。2次メモリー・チャンクを明示的に解放したり、ポインタの再割当てをすることはできません。これは、メモリー・リークやメモリーの破損が発生する可能性があるためです。このプロシージャによって、一時オブジェクトが、存続期間内に削除されます(永続オブジェクトは削除されません)。アプリケーションでは、永続オブジェクトを削除するには、OCIObjectMarkDelete() を使用します。

アプリケーションでは、OCIObjectCopy()を使用して、1つのインスタンスを同じ型の別のインスタンスにコピーできます。

オブジェクト参照と型参照

アプリケーションでは、OCIのオブジェクト拡張機能を利用して、オブジェクトの内容に対してポインタや参照による柔軟なアクセスができます。OCIでは、ポインタが示すオブジェクトに参照を戻すOCIObjectGetObjectRef()関数を提供しています。

また、アプリケーションで、オブジェクトの型情報へのアクセスを行う場合は、OCIではOCIObjectGetProperty()関数で、ポインタが示すオブジェクトの型記述子オブジェクト(TDO)に参照を戻します。

システム生成オブジェクト識別子(OID)を備えたオブジェクト表に基づいて永続オブジェクトが生成されると、OCIObjectGetObjectRef()を使用してただちにこのオブジェクトへの参照を取得できます。 ただし、永続オブジェクトがオブジェクト・ビューまたは主キー・ベースのOIDを備えたオブジェクト表に基づいている場合、主キーに属するすべての属性を設定してからでなければ参照は取得できません。

オブジェクト・ビューおよび主キー・ベースのOIDを備えたオブジェクト表に基づくオブジェクトの作成

アプリケーションで、OCIObjectNew()コールを使用して、オブジェクト・ビュー、または主キー・ベースのオブジェクト識別子(OID)を備えたオブジェクト表に基づいたオブジェクトを作成できます。 このようなビューおよびテーブルのオブジェクト識別子は属性値に基づいているため、その後、アプリケーションでOCIObjectSetAttr()を使用して、主キーに属するすべての属性を設定する必要があります。 属性値を設定すると、アプリケーションで、OCIObjectGetObjectRef()をコールすることによって属性値に基づいたオブジェクト参照を取得できます。

この処理には、次のステップが必要です。

  1. 新しいオブジェクトの基になるオブジェクト・ビューまたはオブジェクト表を確保します。

  2. ステップ1のPINオペレーションで取得した表またはビューへのハンドルを渡して、OCIObjectNew()を使用して新しいオブジェクトを作成します。

  3. OCIObjectSetAttr()を使用して、オブジェクト属性の必要な値を入力します。 指定する値には、オブジェクト表またはオブジェクト・ビューのユーザー定義オブジェクト識別子を構成する属性も含む必要があります。

  4. 必要に応じて、OCIObjectGetObjectRef()を使用して主キーを基にしたオブジェクトへの参照を取得します。さらにオブジェクトを作成する場合は、ステップ2に戻ります。

  5. 新しく作成されたオブジェクトをサーバーにフラッシュします。

次のコード例では、このプロセスを実装して、HRスキーマ内のemp_viewオブジェクト・ビューに対して新しいオブジェクトを作成する方法を示します。

void object_view_new ()
{
void     *table;
OCIRef   *pkref;
void     *object;
OCIType  *emptdo;
...
/* Set up the service context, error handle and so on.. */
...
/* Pin the object view */
OCIObjectPinTable(envp,errorp,svctx, "HR", strlen("HR"), "EMP_VIEW",
    strlen("EMP_VIEW"),(void  *) 0, OCI_DURATION_SESSION, (void  **) &table);

/* Create a new object instance  */
OCIObjectNew(envp, errorp, svctx, OCI_TYPECODE_OBJECT,(OCIType *)emptdo, table,
OCI_DURATION_SESSION,FALSE,&object);

/* Populate the attributes of "object" */
OCIObjectSetAttr(...);
...
/* Allocate an object reference */
OCIObjectNew(envp, errorp, svctx, OCI_TYPECODE_REF, (OCIType *)0, (void  *)0,
    OCI_DURATION_SESSION,TRUE,&pkref);

/* Get the reference using OCIObjectGetObjectRef */
OCIObjectGetObjectRef(envp,errorp,object,pkref);
...
/* Flush new object(s) to server */
...
} /* end function */

オブジェクト・アプリケーションでのエラー処理

アプリケーションでオブジェクトを使用するかどうかにかかわらず、OCIアプリケーションでのエラー処理は同じです。


関連項目:


関数のリターン・コードとエラー・メッセージの詳細は、「OCIでのエラー処理」を参照してください。

型の継承

オブジェクトの型の継承は、C++やJavaでの継承に類似している点が数多くあります。オブジェクト型は、既存のオブジェクト型のサブタイプとして作成できます。サブタイプは、元の型であるスーパータイプの属性とメソッド(メンバー関数とプロシージャ)をすべて継承します。単一の継承のみがサポートされます。つまり、1つのオブジェクトが複数のスーパータイプを所有することはできません。サブタイプが継承した属性やメソッドには、新しい属性やメソッドを追加できます。サブタイプが継承した任意のメソッドをオーバーライド(実装を再定義)することもできます。サブタイプは、そのスーパータイプの拡張(つまり、スーパータイプの継承)といえます。


関連項目:


『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』

たとえば、Person_t型は、サブタイプStudent_tとサブタイプEmployee_tを所有できます。さらに、Student_tも独自のサブタイプPartTimeStudent_tを所有できます。サブタイプを所有するには、型宣言にフラグNOT FINALが必要です。デフォルトのフラグはFINALで、この型はサブタイプを所有できないことを意味します。

この章でこれまで説明した型は、すべてFINALです。リリース1(9.0.1)より前に開発されたアプリケーションの型は、すべてFINALです。FINALの型は、NOT FINALに変更できます。サブタイプを所有しないNOT FINAL型は、FINALに変更できます。次の例では、Person_tNOT FINALとして宣言されています。

CREATE TYPE Person_t AS OBJECT
( ssn NUMBER,
  name VARCHAR2(30),
  address VARCHAR2(100)) NOT FINAL;

サブタイプは、スーパータイプで宣言された属性とメソッドをすべて継承します。また、新しい属性やメソッドを宣言することもできます。その場合は、スーパータイプとは異なる名前を指定する必要があります。次のように、キーワードUNDERによって、スーパータイプが識別されます。

CREATE TYPE Student_t UNDER Person_t
( deptid NUMBER,
  major  VARCHAR2(30)) NOT FINAL;

新しく宣言した属性deptidおよびmajorは、サブタイプStudent_tに所属しています。たとえば、サブタイプEmployee_tを次のように宣言します。

CREATE TYPE Employee_t UNDER Person_t
( empid NUMBER,
  mgr   VARCHAR2(30));

この結果OTTによって生成される構造体については、次の項目を参照してください。

このサブタイプStudent_tは、PartTimeStudent_tなどの独自のサブタイプを所有できます。

CREATE TYPE PartTimeStudent_t UNDER Student_t
( numhours NUMBER) ;

代入性

ポリモフィズムの利点の一部は、プロパティの持つ代入性によるものです。代入性によって、サブタイプの値をスーパータイプ用に記述された元のコードで使用できます。この場合、サブタイプに関する事前の知識は特に必要ありません。サブタイプの値は、メソッドの特化範囲内で異なるメカニズムが使用されている場合でも、周辺のコードに対応してスーパータイプの値と同じように動作します。

インスタンスの代入性とは、サブタイプのオブジェクト値を、スーパータイプで宣言されたコンテキスト内で使用できるようにする機能を指します。REFの代入性とは、サブタイプへのREFを、スーパータイプへのREFで宣言されたコンテキスト内で使用できるようにする機能を指します。

REF型の属性は置換可能です。つまり、REF Tとして定義された属性は、Tのインスタンスまたはそのサブタイプの任意のインスタンスへのREFを保持できます。

オブジェクト型の属性は置換可能です。つまり、(オブジェクト)型Tとして定義された属性は、Tのインスタンスまたはそのサブタイプの任意のインスタンスを保持できます。

コレクションの要素の型は置換可能です。つまり、T型の要素を持つコレクションを定義した場合、そのコレクションは、T型のインスタンスとそのサブタイプの任意のインスタンスを保持できます。オブジェクト属性の代入性の例を次に示します。

CREATE TYPE Book_t AS OBJECT
( title VARCHAR2(30),
  author Person_t     /* substitutable */);

したがって、Book_tインスタンスは、次のように、タイトル文字列とPerson_t(または、Person_tの任意のサブタイプ)インスタンスを指定することによって作成できます。

Book_t('My Oracle Experience',
        Employee_t(12345, 'Joe', 'SF', 1111, NULL))

NOT INSTANTIABLEの型とメソッド

型はNOT INSTANTIABLEとして宣言できます。これは、その型に(デフォルトまたはユーザー定義の)コンストラクタがないことを意味します。したがって、この型のインスタンスは構成できません。通常、このような型は、インスタンス化可能なサブタイプの定義に使用されます。このプロパティの使用方法を次に示します。

CREATE TYPE Address_t AS OBJECT(...) NOT INSTANTIABLE NOT FINAL;
CREATE TYPE USAddress_t UNDER Address_t(...);
CREATE TYPE IntlAddress_t UNDER Address_t(...);

型のメソッドは、NOT INSTANTIABLEとして宣言できます。メソッドをNOT INSTANTIABLEとして宣言することは、型がそのメソッドを実装しないことを意味します。また、NOT INSTANTIABLEメソッドが含まれている型は、必ずNOT INSTANTIABLEとして宣言する必要があります。たとえば、次のようにします。

CREATE TYPE T AS OBJECT
(
  x NUMBER,
  NOT INSTANTIABLE MEMBER FUNCTION func1() RETURN NUMBER
) NOT INSTANTIABLE NOT FINAL;

NOT INSTANTIABLE型のサブタイプは、スーパータイプの任意のNOT INSTANTIABLEメソッドをオーバーライドして、具体的な実装を行うことができます。NOT INSTANTIABLEメソッドが残っている場合、サブタイプも必ずNOT INSTANTIABLEとして宣言する必要があります。

NOT INSTANTIABLEサブタイプは、インスタンス化可能なスーパータイプの下に定義できます。NOT INSTANTIABLE型をFINALとして宣言することは無効なため、使用できません。

OCIでの型の継承のサポート

次のコールは、型の継承をサポートしています。

OCIDescribeAny()

継承された型に固有の情報を提供する関数が拡張されました。継承された型のプロパティにはその他の属性が追加されています。たとえば、型のスーパータイプを取得できます。


関連項目:


OCIDescribeAny()を使用して読み取れる属性については、表6-7「型の属性」および表6-9「型メソッドの属性」を参照してください。

バインド関数および定義関数

OCIのバインド関数は、REF、インスタンスおよびコレクション要素の代入性をサポートしています(スーパータイプがある場合は、サブタイプのインスタンスを渡すことができます)。すべての型のチェックと変換は、サーバー側で実行されるため、OCIのバインド・インタフェースに対する変更はありません。

OCIの定義関数も、代入性をサポートしています(サブタイプのインスタンスをスーパータイプの保持を宣言した定義変数にフェッチできます)。ただし、この場合、サブタイプのインスタンスを保持するために、システムによるメモリーのサイズ変更が必要になることがあります。


注意:


この場合、クライアント・プログラムでは、オブジェクト・キャッシュから割り当てられた(したがって、サイズ変更が可能な)オブジェクトを使用する必要があります。

値が多相になる可能性がある場合、クライアントでは、(スタック上に割り当てられた)構造体を定義変数として使用しないでください。


関連項目:


バインド処理と定義処理の詳細は、第12章「OCIのオブジェクト・リレーショナル・データ型」を参照してください。

OCIObjectGetTypeRef()

この関数は、入力オブジェクトの最も特定な型のTDOのREFを戻します。この操作では、ユーザーに最も特定な型に対する権限がない場合、エラーが戻されます。

OCIObjectCopy()

この関数は、ソース・インスタンスの内容をターゲット・インスタンスにコピーします。ソース・インスタンスとターゲット・インスタンスは、同じ型にしてください。スーパータイプとサブタイプ間でコピーすることはできません。

同様に、tdo引数は、ソースおよびターゲット・オブジェクトと同じオブジェクト・タイプを記述する必要があり、ソースおよびターゲット・オブジェクトのスーパータイプまたはサブタイプを参照しないようにする必要があります。


関連項目:


「OCIObjectCopy()」

OCICollAssignElem()

入力要素は、宣言された型のサブタイプのインスタンスにできます。コレクションの型がPerson_tの場合は、この関数を使用して、Employee_tインスタンスをコレクションの要素として割り当てることができます。

OCICollAppend()

入力要素は、宣言された型のサブタイプのインスタンスにできます。コレクションの型が、Person_tの場合は、この関数を使用して、コレクションにEmployee_tインスタンスを追加できます。

OCICollGetElem()

戻されたコレクション要素は、宣言された型のサブタイプのインスタンスにできます。

OTTでの型の継承のサポート

Object Type Translator(OTT)は、オブジェクトの型の継承をサポートします。このサポートは、継承される属性を'_super'というカプセル化された構造体内で最初に宣言し、その後に新しい属性を宣言することで実行されます。これを実行する理由は、Cでは型の継承がサポートされていないためです。


関連項目:


例および説明は、「OTTによる型の継承のサポート」を参照してください。

型の変更

型属性の追加、削除および変更がサポートされています。この概念は、型の変更と呼ばれています。型の変更は、次のマニュアルで説明しています。


関連項目:


『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』

OCIDescribeAny()は、要求された型の最新バージョンの情報を戻します。ただし、これは、入力オブジェクトの型がOCI_OTYPE_NAMEで、記述済のオブジェクトの型がOCI_PTYPE_TYPEの場合、つまり、OCIDescribeAny()に入力する名前が型名である場合です。


関連項目:


「OCITypeArrayByName()」および「OCITypeByName()」。型情報にアクセスするには、これらの関数以外に、OCIDescribeAny()を使用します。


関連項目:


型の変更のオブジェクト・キャッシュへの影響は、「型の変更とオブジェクト・キャッシュ」を参照してください。