プライマリ・コンテンツに移動
Oracle® Call Interfaceプログラマーズ・ガイド
12c リリース1 (12.1)
B72465-07
目次へ移動
目次
索引へ移動
索引

前
次

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

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

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

OCIオブジェクトの概要

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

  • オブジェクト

  • 可変長配列(varray)

  • ネストした表(多重集合)

  • 参照(REF)

  • LOB

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

  • オブジェクトの作成、アクセス、ロック、削除、コピーおよびフラッシュ

  • オブジェクトとそのメタオブジェクトへの参照の取得

  • オブジェクト属性の値の動的な取得および設定

OCIナビゲーショナル・コールについては、「OCIオブジェクト・アプリケーションの開発について」でより詳しく説明しています。

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

関連項目:

OCIDescribeAny()の詳細は、「スキーマ・メタデータの記述」を参照してください

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

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

関連項目:

関数の詳細は、「OCIのオブジェクト・リレーショナル・データ型」を参照してください

オブジェクトに関する用語は混同することがあります。この章の残りの部分では、オブジェクトおよびインスタンスという用語の両方が、データベースに格納されているか、またはオブジェクト・キャッシュ内にあるオブジェクトのことを示しています。

OCIでのオブジェクトの操作について

リレーショナルOCIアプリケーションを制御するプログラミング原理の多くは、オブジェクト・リレーショナル・アプリケーションにも適用されます。

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

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

オブジェクトを使用するOCIアプリケーションの基本的な構造体は、本質的にはリレーショナルOCIアプリケーションと同じです。

ここでは、基本的なオブジェクト機能についての追加情報とともに、そのモデルをもう一度示します。

  1. OCIプログラミング環境を初期化します。オブジェクト・モードで環境を初期化する必要があります。

    アプリケーションでは、ヘッダー・ファイルにデータベース・オブジェクトのC構造体表現が含まれている必要があります。これらの構造体はプログラマであれば作成できますが、より簡単な方法として、Object Type Translator (OTT)でも生成できます。

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

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

    注意:

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

  4. プリペアド文をデータベース・サーバーに関連付けて実行します。

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

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

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

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

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

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

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

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

  7. 再利用しない文とハンドルを解放するか、プリペアド文を再実行します。

この章の残りの項で、こららの手順について詳しく説明します。

関連項目:

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

Oracle型のインスタンスは、その存続期間に応じて永続オブジェクト一時オブジェクトに分類されます。

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

注意:

このマニュアルでは、オブジェクトインスタンスという用語は代替可能に使用されます。

この項には次のトピックが含まれます:

関連項目:

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

永続オブジェクト

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

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

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

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

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

例11-1例11-2では、これら2種類の永続オブジェクトの違いを説明するSQLの例を示しています。

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

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

例11-1 スタンドアロン・オブジェクトのSQL定義

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

例11-2 埋込みオブジェクトのSQL定義

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

一時オブジェクト

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

一時オブジェクトはいつでもアプリケーションで削除できます。

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

関連項目:

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

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

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

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

注意:

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

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

この項では、基本的なOCIオブジェクト・アプリケーションの開発に伴うステップを説明します。

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

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

図11-1の説明が続きます
「図11-1 基本的なオブジェクト操作のフロー」の説明

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

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

通常は、CREATE TYPEなど、SQLのDDL文で型を作成します。

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

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

Oracle Databaseには、データベースのオブジェクト型の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入力パラメータによって決定されます。このヘッダー・ファイルをアプリケーションのコード・ファイルにインクルードすると、オブジェクトにアクセスできます。

関連項目:

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

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

この通知には次の重要な効果があります。

  • オブジェクト・ランタイム環境を確立します。

  • オブジェクト・キャッシュを設定します。

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

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

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

注意:

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

関連項目:

データベース接続の実行について

OCI環境が適切に初期化されると、アプリケーションはサーバーに接続できるようになります。この接続は、「OCIプログラミング・ステップ」で説明されている標準のOCI接続コールによって確立されます。これらのコールを使用する場合、このアプリケーションはオブジェクトにアクセスしているため、追加の考慮事項は必要ありません。

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

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

オブジェクトを操作するには、アプリケーションでまずサーバーから1つ以上のオブジェクトを取り出す必要があります。

これは、1つ以上のオブジェクトへのREFを戻すSQL文を発行して行います。

注意:

SQL文によって、データベースからREFではなく、埋込みオブジェクトをフェッチすることもできます。

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

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

アプリケーションでは、次のようにリレーショナルSQL文の操作と同じ方法で、この文を準備し処理します。

  1. OCIStmtPrepare2()を使用してアプリケーション要求を準備します。
  2. 1つ以上の適切なバインド・コールを使用して、ホスト入力変数をバインドします。
  3. 従業員オブジェクト参照を受け取る出力変数を宣言し、準備します。ここで、従業員オブジェクト参照を使用します。
    OCIRef  *emp1_ref = (OCIRef *) 0; /* reference to an employee object */
    

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

  4. OCUStmtExecute()で文を実行します。
  5. OCIStmtFetch2()を使用して、結果のREFemp1_refにフェッチします。

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

関連項目:

オブジェクトの確保

オブジェクトの確保では、オブジェクト・インスタンスをオブジェクト・キャッシュにロードすることにより、必要に応じて、インスタンスの属性へのアクセスおよび変更や、1オブジェクトからその他のオブジェクトへの参照追跡を可能にします。

フェッチを行うステップが完了すると、アプリケーションでは、オブジェクトへのREF、つまりポインタを取得します。この時点ではまだ実際のオブジェクトは操作できません。オブジェクトを操作する前にオブジェクトを確保する必要があります。さらにアプリケーションでは、変更したオブジェクトをいつサーバーに書き込むか制御することもできます。

注意:

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

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

例11-3は、前の「サーバーからのオブジェクト参照の取出し」の項でアプリケーションにより取り出された従業員参照に対する確保操作を説明するサンプル・コードです。

この例の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アプリケーションでは、そのオブジェクトを変更できます。この単純な例では、オブジェクトは他のオブジェクトへの参照を含んでいません。

この項には次のトピックが含まれます。「配列確保」

例11-3 オブジェクトの確保

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

関連項目:

配列確保

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

オブジェクト属性の操作

これでオブジェクトが確保され、OCIアプリケーションでは、その属性を変更できます。

OCIには、オブジェクト型構造体のデータ型を操作する一連の関数である、OCIデータ型マッピング関数および操作関数があります。

注意:

オブジェクト・キャッシュ内に確保されているオブジェクトに対して変更を加えた場合、影響を受けるのはそのオブジェクトのコピー(インスタンス)のみで、データベース内の元のオブジェクトは影響を受けません。アプリケーションで行った変更をデータベースに反映するには、変更内容をサーバーにフラッシュまたはコミットする必要があります。

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

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

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

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

例11-4 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);

関連項目:

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

オブジェクトへの変更をデータベースに確実に書き込むために、アプリケーションではオブジェクトにマークを設定してフラッシュする特定のステップを実行する必要があります。

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

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

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

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

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

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

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

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

関連項目:

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

アプリケーションは、埋込みオブジェクト・インスタンスをフェッチする必要があります。

使用しているアプリケーションで、埋込みオブジェクト・インスタンス(オブジェクト表でなく、通常の表の列に格納されているオブジェクト)をフェッチする必要がある場合、「サーバーからのオブジェクト参照の取出し」で説明されている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を戻します。アプリケーションでは、このオブジェクトの属性値を別の処理で使用できます。

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

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

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

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

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

    出力変数の定義時に、定義コールのdtyデータ型パラメータを、名前付きデータ型のデータ型定数、SQLT_NTYに設定します。

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

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

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

注意:

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

関連項目:

オブジェクトのメタ属性

オブジェクトのメタ属性には、オブジェクトの状態に関する情報を、アプリケーションまたはオブジェクト・キャッシュに提供できるフラグの役割があります。

たとえば、オブジェクトのメタ属性の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_DURATION_SESSION

  • OCI_DURATION_TRANS

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の場合、そのオブジェクトはビューであり、そうでない場合はビューではありません。指定されたオブジェクトが一時インスタンスまたは値インスタンスを指し示している場合は、エラーが戻されます。property引数はboolean型にしてください。

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

関連項目:

その他の属性関数

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

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

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

NULL

<なし>

OCIObjectGetInd()

存在

<なし>

OCIObjectExists()

ロック

OCIObjectLock()

OCIObjectIsLocked()

使用済

OCIObjectMarkUpdate()

OCIObjectIsDirty()

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

一時オブジェクトには、永続的属性はありません。表11-3では、一時属性を示しています。

表11-3 一時メタ属性

一時メタ属性 意味

既存

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

確保済

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

使用済

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

NULL

インスタンスのNULL情報。

割当て時間

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

確保継続時間

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

複合オブジェクト検索

複合オブジェクトには、そのルート・オブジェクトと、指定したネスト・レベルに基づいてそれぞれプリフェッチされた論理的に関連する一連のオブジェクトが含まれます。

例11-3例11-4では、一度に1つのインスタンスのみがフェッチまたは確保されました。これらの場合、オブジェクトを取り出すためのサーバー・ラウンドとリップが、確保操作ごとに必要でした。

オブジェクト指向のアプリケーションでは、その問題点を、オブジェクト・グラフを形成する相互関連オブジェクトの集合としてモデル化する場合があります。アプリケーションは、いくつかのイニシャル・オブジェクトの集合から始めて、これらのイニシャル・オブジェクトの参照を使用して残りのオブジェクトを横断することにより、オブジェクトを処理します。クライアント/サーバー設定では、各トラバースがオブジェクトをフェッチするために、ネットワーク・ラウンドトリップを引き起こします。

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

注意:

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

複合オブジェクトは、論理的に関連した複数のオブジェクトの集合で、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型への参照であり、この型がリンク済リストとして実装されることを示しています。

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

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

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

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

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

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

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

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

  • REF(PO object)

  • {(customer, 1)}

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

  • REF(PO object)

  • {(customer, UB4MAXVAL), (purchase_order, UB4MAXVAL)}

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

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

  • REF(PO object)

  • {(line_item, 1)}

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

オブジェクトのプリフェッチについて

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

注意:

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

プリフェッチ・オブジェクトすべてに、READまたはSELECT権限が必要です。複合オブジェクト内のオブジェクトに対するREADまたは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_TYPE_LEVEL- 前述の型の参照に使用するネスト・レベル

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

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

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

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の使用時には、次の点について留意してください。

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

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

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

    注意:

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

CORの例

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

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

例11-5 OCIでの複合オブジェクト検索の使用

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インスタンスは参照不可能です。SQLインタフェースを使用できるのは、manager列インスタンスをフェッチする場合にかぎります。ただし、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インジケータ構造体が含まれます。例11-6では、対応するNULLインジケータ構造体とともに型のC表現を示しています。

注意:

person_inddependentsAgeフィールドは、VARRAY (persondependentsAgeフィールド)全体がアトミック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;

例11-6 型のC表現とそれらに対応するNULLインジケータ構造体

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;

関連項目:

オブジェクトの作成について

OCIアプリケーションでは、OCIObjectNew()を使用してあらゆるオブジェクトを作成できます。

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

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

この項には次のトピックが含まれます。「新規オブジェクトの属性値」

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

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

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

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

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

属性の型 デフォルト値
REF

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

DATE

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

ANSI DATE

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

TIMESTAMP

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

TIMESTAMP WITH TIME ZONE

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

TIMESTAMP WITH LOCAL TIME ZONE

Oracle Databaseで扱える最古の日時で、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。デフォルト値は、NULL文字列属性のデフォルト値と同じです。

CHAR, NCHAR

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

VARCHAR

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

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には、オブジェクトに対するポインタを指定すると、オブジェクトの型記述子オブジェクト(TDO)に対する参照を戻すOCIObjectGetProperty()関数があります。

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

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

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

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

  1. 新しいオブジェクトの基になるオブジェクト・ビューまたはオブジェクト表を確保します。
  2. ステップ1の確保操作で取得した表またはビューに対するハンドルを渡し、OCIObjectNew()を使用して新しいオブジェクトを作成します。
  3. OCIObjectSetAttr()を使用して、オブジェクト属性の必要な値を入力します。これらには、オブジェクト表またはオブジェクト・ビューのユーザー定義オブジェクト識別子を構成する属性を含める必要があります。
  4. ステップ1の確保操作で取得した表またはビューに対するハンドルを渡し、OCIObjectNew()を使用してオブジェク参照を割り当てます。
  5. 必要に応じて、OCIObjectGetObjectRef()を使用して主キーを基にしたオブジェクトへの参照を取得します。必要ならば、ステップ2に戻ってさらにオブジェクトを作成します。
  6. 新しく作成されたオブジェクトをサーバーにフラッシュします。

例11-7 オブジェクト・ビューに対する新規オブジェクトの作成

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 objects to server */
...
} /* end function */

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

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

他のOCIアプリケーションと同じです。

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

関連項目:

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

型の継承について

オブジェクトの型継承には、C++およびJavaでの継承と類似した点が多くあります。

オブジェクト型は、既存のオブジェクト型のサブタイプとして作成できます。サブタイプは、元の型であるスーパータイプのすべての属性とメソッド(メンバー関数とプロシージャ)を継承します。サポートされているのは1回の継承のみで、オブジェクトは複数のスーパータイプを持つことはできません。スーパータイプは、新規属性とメソッドを継承する属性とメソッドに追加します。また、継承されたメソッドのいずれかをオーバーライド(実装の再定義)することもできます。サブタイプは、そのスーパータイプを拡張(つまり、元から継承)します。

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

この章でこれまで説明した型は、すべてFINALです。Oracle Databaseリリース9.0より前に開発されたアプリケーションの型は、すべて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により生成される構造体については、「OTTでの型の継承のサポート」を参照してください。

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

CREATE TYPE PartTimeStudent_t UNDER Student_t
( numhours NUMBER) ;

関連項目:

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

代入性

ポリモフィズムのメリットは、一部代入性プロパティから引き出されます。代入性により、必要になるサブタイプに関する特別な知識がなくても、元々スーパータイプに対して記述されたコードにサブタイプの値を使用させることができます。サブタイプの値は、スーパータイプの値と同様に、メソッドの特殊化の範囲内で別のメカニズムを使用する可能性がある場合でも、前後のコードに対して作用します。

インスタンスの代入性とは、サブタイプのオブジェクト値を、スーパータイプで宣言されたコンテキスト内で使用できるようにする機能を指します。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()関数は、継承された型固有の情報を提供します。継承された型のプロパティにはその他の属性が追加されています。たとえば、型のスーパータイプを取得できます。

関連項目:

既存のスキーマおよびサブスキーマ・オブジェクトの記述にOCIDescribeAny()を使用できる属性については、表6-7および表6-9を参照してください。

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

OCIのバインド関数は、REF、インスタンスおよびコレクション要素の代入性をサポートしています(スーパータイプがある場合は、サブタイプのインスタンスを渡すことができます)。

すべての型のチェックと変換は、サーバー側で実行されるため、OCIのバインド・インタフェースに対する変更はありません。

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

注意:

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

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

関連項目:

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

OCIObjectGetTypeRef()

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

OCIObjectCopy()

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

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

OCICollAssignElem()

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

OCICollAppend()

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

OCICollGetElem()

戻されるコレクション要素は、宣言された型のサブタイプのインスタンスの場合があります。コレクションの型がPerson_tの場合は、OCICollGetElem()関数を使用して、コレクションにEmployee_tインスタンスなどの要素へのポインタを取得します。

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

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

これを実行する理由は、Cでは型の継承がサポートされていないためです。

関連項目:

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

型進化について

型属性の追加、削除および変更がサポートされています。この概念は、型進化と呼ばれます。

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

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

関連項目: