17 オブジェクト

この章では、Pro*C/C++のユーザー定義オブジェクトのサポートについて説明します。この章のトピックは、次のとおりです:

17.1 オブジェクトの概要

Pro*C/C++では、Oracle8以降これまでサポートされていたOracleのリレーショナル・データ型に加えて、次のユーザー定義データ型がサポートされます。

  • オブジェクト型

  • オブジェクト型のREF

  • コレクション・オブジェクト・タイプ

  • 型の継承

関連項目

17.1.1 オブジェクト型

オブジェクト型は、ユーザー定義によるデータ型です。これには、CREATE TYPE SQL文で変数として定義されるデータ型の属性と、オブジェクト型に適用できる動作としての関数およびプロシージャからなるメソッドが含まれます。このマニュアルでは、属性のみを持つオブジェクト型を考えます。

次に例を示します。

--Defining an object type...
CREATE TYPE employee_type AS OBJECT(
    name    VARCHAR2(20),
    id      NUMBER,
    MEMBER FUNCTION get_id(name VARCHAR2) RETURN NUMBER);
/
--
--Creating an object table...
CREATE TABLE employees OF employee_type;
--Instantiating an object, using a constructor...
INSERT INTO employees VALUES (
        employee_type('JONES', 10042));

LONG、LONG RAW、NCLOB、NCHARおよびNCHAR可変幅データ型は、オブジェクト属性では使用できません

17.1.2 オブジェクト型のREF

REF(「reference」の短縮形)はオブジェクト自体の参照ではなく、データベース表に格納されているオブジェクトを参照します。REF型は、リレーショナル列に指定できるのみでなく、オブジェクト型のデータ型としても指定できます。たとえば、次のように、表employee_tabにオブジェクト型employee_t自体のREFを表す列を組み込むことができます。

CREATE TYPE employee_t AS OBJECT(
   empname         CHAR(20),
   empno           INTEGER,
   manager         REF employee_t);
/
CREATE TABLE employee_tab OF employee_t;

17.1.3 型の継承

Oracleでは、オブジェクトの型の継承がサポートされます。これにより、類似するオブジェクト型の間で属性とメソッドを共有したり、オブジェクト型の特性を拡張したりできます。

Pro*C/C++では、次のSQL演算子によるオブジェクト型の継承がサポートされます。

  • IS OF type

  • TREAT

IS OF type演算子は、特定のtype情報についてオブジェクト・インスタンスをテストするために使用します。

次のコード例では、pEmployee_tおよびStudent_t型のすべてのpオブジェクトの参照が戻されます。

SELECT REF(p)
   FROM person_tab p
   WHERE VALUE(p) IS OF (Employee_t, Student_t);

次のコード例では、Student_t型のpのみを含むすべての行が戻されます。

SELECT VALUE(p)
   FROM person_tab p
   WHERE VALUE(p) IS OF (ONLY Student_t);

TREAT演算子は、式の宣言された型を変更するために使用します。

次のコード例では、Student_t型のpを含むすべての行が戻されます。pのうち、Student_t型でないすべてのインスタンスについては、NULLが戻されます。

SELECT TREAT(VALUE(p) AS Student_t)
   FROM person_tab p;

次のコード例では、Student_t型のすべてのpオブジェクトとサブタイプPartTimeStudent_tのオブジェクトの参照が戻されます。

SELECT TREAT(REP(p) AS REF Student_t) 
   FROM person_tab p
   WHERE VALUE(p) IS OF (Student_t);

17.2 Pro*C/C++でのオブジェクト型の使用について

OTT(Object Type Translator)で生成されたC言語の構造体へのポインタを、Pro*C/C++アプリケーションでホスト変数と標識変数として宣言します。オブジェクト型の場合、標識変数はオプションですが、使用することをお薦めします。

Pro*C/C++プログラムでは、オブジェクト型を、OTTを使用してデータベース・オブジェクトから生成されたC言語の構造体として表現します。次の操作を必ず実行してください。

  • OTTによって生成されるヘッダー・ファイルに、構造体定義およびそれに対応付けられたNULLインジケータ構造体、オブジェクト型のREFを表すC言語のデータ型を指定して、Pro*C/C++プログラムにインクルードします。

  • OTT生成の型ファイルをPro*C/C++のINTYPEコマンドライン・オプションとして入力します。この型ファイルにより、OTTによって生成されるC言語の構造体とそれに対応するデータベース内のオブジェクト型の間およびスキーマと型のバージョン情報との間の対応関係がコード化されます。

関連項目

17.2.1 NULLインジケータ

Object Type Translator(OTT)によって、オブジェクト型のNULLステータスを表すC言語の構造体が生成されます。生成されたこれらの構造体型を、オブジェクト型の標識変数の宣言で使用する必要があります。

その他のOracle型では、NULLインジケータに対して特別な処置は必要ありません。

オブジェクト型には内部構造があるため、オブジェクト型を表すNULLインジケータにも内部構造があります。コレクション・オブジェクト・タイプ以外のオブジェクト型を表すNULLインジケータ構造体は、オブジェクト型全体を表すアトミック(シングル)NULLステータスのみでなく、すべての属性のNULLステータスも提供します。OTTにより、オブジェクト型を表すNULLインジケータ構造体を示すC言語の構造体が生成されます。NULLインジケータ構造体の名前は、Object_typename_indです。Object_typenameは、データベース内のユーザー定義型を表すC言語の構造体の名前です。

17.3 オブジェクト・キャッシュ

オブジェクト・キャッシュは、プログラムがデータベース・オブジェクトとのインタフェースに使用するために割り当てられたクライアントのメモリー領域です。オブジェクトには、2つのインタフェースが機能します。連想アクセス用インタフェースはオブジェクトの一時コピーを操作し、ナビゲーショナル・アクセス用インタフェースは永続オブジェクトを操作します。

17.3.1 永続オブジェクト対一時コピー

Pro*C/C++でEXEC SQL ALLOCATE文を使用してキャッシュに割り当てたオブジェクトは、Oracleデータベース内では永続オブジェクトの一時コピーになります。したがって、これらのコピーはフェッチした後にキャッシュ内で更新できますが、その変更をデータベース内で永続的なものにするには、明示的なSQLコマンドを使用する必要があります。この一時コピーまたは値ベースのオブジェクト・キャッシング・モデルはリレーショナル・モデルの拡張で、ここではリレーショナル表のスカラー列をホスト変数にフェッチすること、その場で更新することおよび更新結果をサーバーに通信することが可能です。

17.4 連想アクセス用インタフェース

連想アクセス用インタフェースは、オブジェクトの一時コピーを操作します。メモリーは、EXEC SQL ALLOCATE文を使用してオブジェクト・キャッシュ内で割り当てます。

SQLLIBランタイム・コンテキストごとに、オブジェクト・キャッシュが1つずつ作成されます。

各オブジェクトは、EXEC SQL SELECT文またはEXEC SQL FETCH文によって取り出されます。この2つの文では、ホスト変数の属性値が設定されます。NULLインジケータが与えられている場合は、それも設定されます。

オブジェクトの挿入、更新または削除には、EXEC SQL INSERT文、EXEC SQL UPDATE文およびEXEC SQL DELETE文を使用します。文が実行される前に、オブジェクトのホスト変数の属性を設定する必要があります。

トランザクション文EXEC SQL COMMITおよびEXEC SQL ROLLBACKは、変更をサーバーに永続的に書き込むときや、変更を取り消すときに使用します。

EXEC SQL FREE文を使用すると、オブジェクト・キャッシュ内のメモリーを明示的に解放できます。接続の終了時には、その割当て済メモリーが暗黙的に解放されます。

17.4.1 連想アクセス用インタフェースを使用する場合

次のような場合に使用します。

  • 表の明示的な結合による処理上の負荷が大きくはないような、オブジェクトの大規模なコレクションにアクセスする場合。

  • 参照できないオブジェクトにアクセスする場合。このようなオブジェクトには、識別性がありません。たとえば、リレーショナル列内のオブジェクト型などです。

  • 一連のオブジェクトにUPDATEやINSERTなどの操作を適用する場合。たとえば、特定部門のすべての従業員に$1000のボーナスを追加する場合などです。

17.4.2 ALLOCATE

オブジェクト・キャッシュに領域を割り当てるには、次の文を使用します。次に構文を示します。

EXEC SQL [AT [:]database] ALLOCATE :host_ptr [[INDICATOR]:ind_ptr] ;

入力する変数は、次のとおりです。

database (IN)

データベース接続の名前を含むヌル文字で終了する文字列。データベース接続は次の文で事前に行われています。

EXEC SQL CONNECT :user [AT [:]database];

AT句のATを省略するか、databaseが空の文字列であれば、デフォルトのデータベース接続とみなされます。

host_ptr (IN)

オブジェクト型、コレクション・オブジェクト・タイプまたはREFに対してOTTにより生成されたホスト構造体へのポインタ、またはC言語のデータ型であるOCIDate、OCINumber、OCIRawまたはOCIStringのいずれかへのポインタ。

ind_ptr (IN)

標識変数ind_ptrとキーワードINDICATORはともにオプションです。構造体の型を持つインジケータへのポインタにかぎり、ALLOCATE文およびFREE文に指定できます。

host_ptrおよびind_ptrには、ホスト配列を構成できます。

割当てはセッションが終了するまで有効です。どのインスタンスも、FREE文で明示的に解放されなくても、セッション(接続)が終了すると解放されます。

17.4.3 FREE

EXEC SQL [AT[:]database] [OBJECT] FREE :host_ptr [[INDICATOR]:ind_ptr];

オブジェクト・キャッシュに格納されるオブジェクトの領域の割当てを解除するには、FREE文を使用します。この文に使用する変数は、ALLOCATE文の場合と同じです。

注意:

ホスト変数や標識変数へのポインタは、NULLには設定されません

17.4.4 CACHE FREE ALL

EXEC SQL [AT [:]database] [OBJECT] CACHE FREE ALL;

前述の文を使用すると、指定したデータベース接続用のオブジェクト・キャッシュ・メモリーがすべて解放されます。

17.4.5 連想アクセス用インタフェースを使用したオブジェクトへのアクセス

SQLを使用してオブジェクトにアクセスする場合、Pro*C/C++アプリケーションは永続オブジェクトの一時コピーを操作します。これは、SELECT、UPDATEおよびDELETEの各文を使用するリレーショナル・アクセス・インタフェースの直接の拡張です。

図17-1では、永続オブジェクトの一時コピーにALLOCATE文でキャッシュを割り当てます。割り当てられるオブジェクトにデータは含まれていませんが、OTTによって生成される構造体の形式をとります。

person *per_p;
...
EXEC SQL ALLOCATE :per_p;

SELECT文を実行してキャッシュに移入できます。また、FETCH文やC言語の代入を使用してキャッシュにデータを入れることもできます。

EXEC SQL SELECT ... INTO :per_p FROM person_tab WHERE ...

図のように、INSERT、UPDATEまたはDELETE文を使用して、サーバー・オブジェクトを変更します。データは、次のINSERT文を使用して表に挿入できます。

EXEC SQL INSERT INTO person_tab VALUES(:per_p);

最後に、FREE文を使用して、オブジェクトのコピーに対応するメモリーを解放します。

EXEC SQL FREE :per_p;

図17-1 SQLを使用したオブジェクトへのアクセス

図17-1の説明が続きます
「図17-1 SQLを使用したオブジェクトへのアクセス」の説明

17.5 ナビゲーショナル・アクセス用インタフェース

ナビゲーショナル・アクセス用インタフェースを使用すると、連想アクセス用インタフェースと同じスキーマにアクセスできます。ナビゲーショナル・アクセス用インタフェースはオブジェクトに対するREFを間接参照して、あるオブジェクトから他のオブジェクトへとたどる(ナビゲート)ことで(永続および一時)オブジェクトにアクセスします。次に、一部の定義を示します。

オブジェクトの確保とは、オブジェクトを間接参照し、プログラムがオブジェクトにアクセスできるようにするという意味の用語です。

オブジェクトの確保解除とは、オブジェクトが不要になったことをキャッシュに対して示すことです。

間接参照とは、サーバーがREFを使用してクライアント内にそのオブジェクトのある版を作成することであると定義できます。キャッシュ内では、各オブジェクトとそれに対応するサーバー・オブジェクトとの間の対応付けが保たれますが、自動的な一貫性は得られません。キャッシュ内の各オブジェクトの内容の正確さと一貫性を確認するのは、ユーザーの責任です。

オブジェクト・コピーのリリースとは、キャッシュに対してオブジェクトが現在使用されていないことを示すことです。メモリーを解放するために、不要になったオブジェクトをリリースして暗黙的にメモリーの解放ができるようにします。

オブジェクト・コピーを解放すると、オブジェクト・コピーはキャッシュから削除され、使用されていたメモリーが解放されます。

オブジェクトをマークすることで、キャッシュ内のオブジェクト・コピーが更新されており、オブジェクト・コピーをフラッシュするときに対応するサーバー・オブジェクトを更新する必要があることが、キャッシュに通知されます。

オブジェクトをマーク解除すると、オブジェクトが更新されたという指示が削除されます。

オブジェクトをフラッシュすると、キャッシュ内のマークされたコピーに対して行ったローカルな変更が、サーバー内の対応するオブジェクトに書き込まれます。この時点で、キャッシュ内のオブジェクト・コピーもマーク解除されます。

キャッシュ内のオブジェクト・コピーをリフレッシュすると、そのコピーは、サーバー内の対応するオブジェクトの最新値に置き換わります。

ナビゲーショナル・アクセス用インタフェースと連想アクセス用インタフェースは併用できます。

キャッシュ・コピーを更新、削除およびフラッシュする(キャッシュ内の変更をサーバーに書き込む)には、EXEC SQL OBJECT文、ナビゲーショナル・アクセス用インタフェースを使用します。

関連項目:

ナビゲーショナル・アクセス用インタフェースと連想アクセス用インタフェースの併用方法は、ナビゲーショナル・アクセスのサンプル・コードを参照してください。

17.5.1 ナビゲーショナル・アクセス用インタフェースを使用する場合

次の場合にナビゲーショナル・アクセス用インタフェースを使用します。

  • 表の明示的な結合による処理上の負荷が大きい単一のオブジェクト、もしくは少数のオブジェクトへアクセスする場合。間接参照(DEREF)を使用してオブジェクト間でナビゲートする場合は、表全体の明示的な結合よりも処理負荷の少ない暗黙的な結合を行います。

  • 多数の異なるオブジェクトに多数の少しの変更を加える場合。すべてのオブジェクトをクライアントにフェッチし、変更し、更新済としてマーク設定してから、変更後のすべてのオブジェクトをフラッシュしてサーバーに戻すほうが手軽です。

17.5.2 ナビゲーション文に使用されるルール

埋込みSQL OBJECT文は、次の仮定のもとに後述します。

  • AT句がない場合、デフォルト(名前なし)接続とみなされます。

  • 特に指定する場合を除き、ホスト変数は配列になります。

  • 配列サイズを明示的に指定するには、FOR句を使用します。FOR句がない場合、永続ホスト変数の最小サイズが使用されます。

  • 文の実行後に、SQLCAを状態変数として使用すると、処理された要素数はsqlca.sqlerrd[2]に戻されます。

  • パラメータには、入力または出力を示すINまたはOUT(あるいはその両方)が指定されています。

17.5.3 OBJECT CREATE

EXEC SQL [AT [:]database] [FOR [:]count] OBJECT CREATE :obj [INDICATOR]:
obj_ind [TABLE tab] [RETURNING REF INTO :ref] ;

tabは次のとおりです。

{:hv | [schema.]table}

この文を使用して、オブジェクト・キャッシュ内で参照可能オブジェクトを作成します。オブジェクトの型は、ホスト変数objに対応します。オプションの型ホスト変数(:obj_ind,:ref,:ref_ind)を指定する場合は、すべてが同じ型に対応している必要があります。

参照可能オブジェクトは、永続オブジェクト(TABLE句あり)でも一時オブジェクト(TABLE句なし)でもかまいません。永続オブジェクトは、暗黙的に保持され、更新済としてマークされます。一時オブジェクトは、暗黙的に保持されます。

ホスト変数は、次のとおりです。

obj (OUT)

オブジェクト・インスタンス・ホスト変数objは、OTTが生成した構造体へのポインタである必要があります。この変数は、オブジェクト・キャッシュ内で作成される参照可能オブジェクトを判別するために使用されます。正常に実行されると、objは新規作成されたオブジェクトを指します。

obj_ind (OUT)

この変数はOTTが生成したインジケータ構造体を指します。その型は、オブジェクト・インスタンスのホスト変数の型と対である必要があります。正常に実行されると、obj_indは参照可能なオブジェクトに対する対になるインジケータ構造体へのポインタとなります。

tab (IN)

TABLE句を使用して永続オブジェクトを作成します。表名は、ホスト変数hv、または未宣言のSQL識別子として指定できます。スキーマ名で修飾することもできます。表名を含むホスト変数には、後続ブランクを使用しないでください。

hv (IN)

表を指定するホスト変数。ホスト変数を使用する場合、配列を使用しないでください 。また、空白文字で埋めないでください。大/小文字が区別されます。永続オブジェクトの配列を作成すると、すべてが同じ表に対応付けられます。

table (IN)

大/小文字が区別される未宣言のSQL識別子。

ref (OUT)

参照ホスト変数は、OTTによって生成される参照の型へのポインタである必要があります。refの型は、オブジェクト・インスタンスのホスト変数の型と同じである必要があります。実行後のrefには、新規作成されたオブジェクトのrefへのポインタが含まれます。

属性は、NULLに初期設定されます。オブジェクト・ビューに対する新しいオブジェクトの作成は現在サポートされていません。

オブジェクト・ビューに対する新しいオブジェクトの作成は現在サポートされていません

17.5.4 OBJECT DEREF

EXEC SQL [AT [:]database] [FOR [:]count] OBJECT DEREF :ref INTO :obj [[INDICATOR]:obj_ind
] [FOR UPDATE [NOWAIT]] ;

オブジェクト参照refを指定すると、OBJECT DEREF文は指定されたrefに対応するオブジェクトまたはオブジェクトの配列を、オブジェクト・キャッシュ内で保持します。これらのオブジェクトへのポインタは、変数objおよびobj_ind内で戻されます。

ホスト変数は、次のとおりです。

ref (IN)

これはオブジェクト参照変数であり、OTTによって生成される参照の型へのポインタである必要があります。この変数(または変数の配列)は間接参照され、キャッシュ内のそれに対応するオブジェクトへのポインタを戻します。

obj (OUT)

オブジェクト・インスタンスのホスト変数objはOTTが生成した構造体へのポインタである必要があります。その型は、オブジェクト参照のホスト変数の型と同じである必要があります。正常に実行されると、objにはオブジェクト・キャッシュ内で保持されたオブジェクトへのポインタが含まれます。

obj_ind (OUT)

オブジェクト・インスタンス標識変数obj_indはOTTが生成したインジケータ構造体へのポインタである必要があります。その型は、オブジェクト参照の標識変数の型と対である必要があります。正常に実行されると、obj_indには参照可能オブジェクトと対になるインジケータ構造体へのポインタが含まれます。

FOR UPDATE

この句を指定すると、サーバー内でそれに対応するオブジェクト用に排他ロックが取得されます。

NOWAIT

このオプション設定のキーワードを指定すると、別のユーザーがすでにオブジェクトをロックしていた場合、ただちにエラーが戻されます。

17.5.5 OBJECT RELEASE

EXEC SQL [AT [:]database] [FOR [:]count] OBJECT RELEASE :obj ;

この文では、オブジェクト・キャッシュ内のオブジェクトが確保解除されます。オブジェクトが確保されず、更新もされなければ、暗黙的な解放の対象になります。

オブジェクトがn回間接参照された場合は、オブジェクト・キャッシュから暗黙的に解放されるように、n回リリースする必要があります。不要になったオブジェクトは、すべてリリースすることをお薦めします。

17.5.6 OBJECT DELETE

EXEC SQL [AT [:]database] [FOR [:]count] OBJECT DELETE :obj ;

永続オブジェクトの場合、この文はオブジェクト・キャッシュ内のオブジェクトまたはオブジェクトの配列を削除済としてマークします。オブジェクトがサーバー内で削除されるのは、そのオブジェクトのフラッシュ時またはキャッシュのフラッシュ時です。オブジェクト・キャッシュ内で確保されているメモリーは解放されません。

一時オブジェクトの場合は、そのオブジェクトが削除済としてマーク設定されます。オブジェクト用のメモリーは解放されません。

17.5.7 OBJECT UPDATE

EXEC SQL [AT [:]database] [FOR [:]count] OBJECT UPDATE :obj ;

永続オブジェクトの場合、この文はオブジェクト・キャッシュ内でオブジェクトを更新済としてマークします。変更結果は、オブジェクトのフラッシュ時またはキャッシュのフラッシュ時に、サーバーに書き込まれます。

一時オブジェクトの場合、この文は何も操作しません。

17.5.8 OBJECT FLUSH

EXEC SQL [AT [:]database] [FOR [:]count] OBJECT FLUSH :obj ;

この文は、更新済、削除済または作成済としてマークされた永続オブジェクトをサーバーにフラッシュします。

注意:

オブジェクトがフラッシュされると、排他ロックが暗黙的に取得されます。この文が正常終了すると、オブジェクトのマークが削除されます。オブジェクトのバージョンがLATEST(後続の項を参照)であれば、暗黙的にリフレッシュされます。

17.5.9 オブジェクトへのナビゲーショナル・アクセス

ナビゲーショナル・アクセス用インタフェースの実例は、図17-2を参照してください。

ALLOCATE文を使用して、personオブジェクトを指すREFのコピー用に、オブジェクト・キャッシュ内のメモリーを割り当てます。割り当てられたREFには、データは含まれません。

person *per_p;
person_ref *per_ref_p;
...
EXEC SQL ALLOCATE :per_p;

SELECT文を使用してpersonオブジェクトのREFを取り出すことで、割り当てたメモリーに移入します(正確な書式はアプリケーションによって異なります)。

EXEC SQL SELECT ... INTO :per_ref_p;

次に、オブジェクト内で変更できるように、DEREF文を使用してキャッシュ内でオブジェクトを確保します。DEREF文は、ポインタper_ref_pを使用して、クライアント側キャッシュ内でpersonオブジェクトのインスタンスを作成します。personオブジェクトへのポインタper_pが戻されます。

EXEC SQL OBJECT DEREF :per_ref_p INTO :per_p;

図17-2 ナビゲーショナル・アクセス

図17-2の説明が続きます
「図17-2 ナビゲーショナル・アクセス」の説明

C言語の代入文を使用するか、またはOBJECT SET文によるデータ変換を使用して、キャッシュ内でオブジェクトを変更します。

次に、オブジェクトを更新済としてマーク設定する必要があります。図17-3を参照してください。キャッシュ内のオブジェクトを更新済としてマーク設定し、サーバーにフラッシュできるようにするには、次の文を使用します。

EXEC SQL OBJECT UPDATE :per_p;

FLUSH文によって変更結果をサーバーに送ります。

EXEC SQL OBJECT FLUSH :per_p;

オブジェクトをリリースします。

EXEC SQL OBJECT RELEASE :per_p;

図17-3 ナビゲーショナル・アクセス(続き)

図17-3の説明が続きます
「図17-3 ナビゲーショナル・アクセス(続き)」の説明

オブジェクト属性とC言語のデータ型の間で変換するには、次の項で説明する文を使用します。

17.6 オブジェクト属性とC言語のデータ型の変換

この項では、属性と型の変換に関する問題を説明します。

17.6.1 OBJECT SET

EXEC SQL [AT [:]database] 
  OBJECT SET  [ {'*' | {attr[, attr]} } OF] 
    :obj [[INDICATOR]:obj_ind] 
       TO {:hv [[INDICATOR]:hv_ind] 
          [, :hv [INDICATOR]:hv_ind]]} ;

この文は、連想アクセス用インタフェースとナビゲーショナル・アクセス用インタフェースのどちらで作成したオブジェクトにも使用します。この文によって、オブジェクトの属性が更新されます。永続オブジェクトの場合は、オブジェクトが更新され、フラッシュされたときに、変更がサーバーに書き込まれます。キャッシュのフラッシュは、更新済オブジェクトになされたすべての変更をサーバーに書き込みます。

OF句はオプション設定です。OF句を指定しなければ、objの属性がすべて設定されます。次のように記述しても同じ結果が得られます。

... OBJECT SET * OF ...

ホスト変数リストには、属性の値を提供するように展開された構造体を組み込むことができます。ただし、obj内の属性の数は、展開する変数リスト内の要素数と同じである必要があります。

ホスト変数と属性は、次のとおりです。

attr

各属性はホスト変数ではなく、オブジェクトのどの属性が更新されるかを指定する識別子にすぎません。リスト内の最初の属性は、リスト内の最初の式と対になります。属性は、OCIString、OCINumber、OCIDateまたはOCIRefのいずれかにする必要があります。

obj (IN/OUT)

objには、更新対象となるオブジェクトを指定します。バインド変数objに配列を使用することはできません。これはOTTが生成した構造体へのポインタである必要があります。

obj_ind (IN/OUT)

更新対象となる対になるインジケータ構造体です。これはOTTが生成したインジケータ構造体へのポインタである必要があります。

hv (IN)

これは、OBJECT SET文への入力に使用されるバインド変数です。hvはint、float、OCIRef *、1次元文字配列またはこれらの型の構造体である必要があります。

hv_ind (IN)

これは、OBJECT SET文への入力に使用される対になるインジケータです。hv_indは2バイト整数スカラーまたは2バイト整数スカラーの構造体である必要があります。

標識変数の使用方法:

ホスト変数のインジケータがある場合は、オブジェクト・インジケータも必要です。

hv_indを-1に設定すると、それに対応付けられたフィールドがobj_ind内で-1に設定されます。

次の暗黙的な変換が許されます。

  • [OCIString | STRING | VARCHAR | CHARZ]からOCIStringへ

  • OCIRefからOCIRefへ

  • [OCINumber | int | float | double]からOCINumberへ

  • [OCIDate | STRING | VARCHAR | CHARZ ]からOCIDateへ

    注意:

    • ネストされた構造体は使用できません。

    • この文を使用して、参照可能オブジェクトをアトミックNULLに設定することはできません。かわりに、NULLインジケータの適切なフィールドを設定してください。

    • OCIDateTimeまたはOCIIntervalデータ型とOCIStringとの間での変換はサポートされていません。

17.6.2 OBJECT GET

EXEC SQL [AT [:]database] 
   OBJECT GET [ { '*' | {attr[, attr]} } FROM]
     :obj [[INDICATOR]:obj_ind] 
        INTO {:hv [[INDICATOR]:hv_ind]
          [, :hv [[INDICATOR]:hv_ind]]} ;

この文では、オブジェクトの属性がネイティブなC言語のデータ型に変換されます。

FROM句はオプションです。FROM句を指定しなければ、objの属性がすべて変換されます。次のように記述しても同じ結果が得られます。

... OBJECT GET * FROM ...

ホスト変数リストには、属性の値を受け取るように展開された構造体を組み込んでもかまいません。ただし、obj内の属性の数は、展開されるホスト変数リスト内の要素の数と同じである必要があります。

ホスト変数と属性は、次のとおりです。

attr

各属性はホスト変数ではなく、オブジェクトのどの属性が取り出されるかを指定する識別子にすぎません。リスト内の最初の属性は、リスト内の最初のホスト変数と対になります。属性はベース型を表す必要があります。OCIString、OCINumber、OCIRefまたはOCIDateのいずれかにする必要があります。

obj (IN)

この変数では、属性を取り出すときのソースとして機能するオブジェクトを指定します。バインド変数objに配列を使用することはできません。

hv (OUT)

これは、OBJECT GET文からの出力を保持するためのバインド変数です。int、float、double、1次元文字配列またはこれらの型の構造体にできます。この文では、このホスト変数に変換済の属性値が戻されます。

hv_ind (OUT)

これは、属性値に対応付けられた標識変数です。また、2バイト整数スカラーまたは2バイト整数スカラーの構造体です。

標識変数の使用方法:

オブジェクト・インジケータを指定しなかった場合、属性は有効とみなされます。オブジェクトがアトミックNULLの場合または、要求した属性がNULLで、オブジェクト標識変数を指定しなかった場合は、オブジェクト属性がC言語のデータ型に変換されるプログラム・エラーになりますこの状況では、Oracleエラーを呼び出せないことがあります。

オブジェクト変数がアトミックNULLの場合、または要求した属性がNULLで、ホスト変数インジケータ(hv_ind)が与えられている場合は、-1に設定されます。

オブジェクトがアトミックNULLの場合、または要求した属性がNULLで、ホスト変数インジケータが与えられていない場合は、エラーが発生します。

次の暗黙的な変換が許されます。

  • OCIStringから[STRING | VARCHAR | CHARZ | OCIString]へ

  • OCINumberから[int | float | double | OCINumber]へ

  • OCIRefからOCIRefへ

  • OCIDateから[STRING | VARCHAR | CHARZ | OCIDate]へ

    注意:

    • ネストされた構造体は使用できません。

    • OCIDateTimeまたはOCIIntervalデータ型とOCIStringとの間での変換はサポートされていません。

17.7 オブジェクト・オプションの設定/取得

ランタイム・コンテキストには、ランタイム・コンテキストが生成されて割り当てられたときにデフォルトの値が設定されるオプションがあります。これらのオプションは次の埋込みSQLディレクティブで設定します。

17.7.1 CONTEXT OBJECT OPTION SET

EXEC SQL CONTEXT OBJECT OPTION SET {option[, option]} TO {:hv[, :hv]} ;

変数は、次のとおりです。

:hv(IN) ...

入力バインド変数hv ...はSTRING型、VARCHAR型またはCHARZ型です。

option...

ランタイム・コンテキストのどのオプションを更新するかを指定する単純な識別子です。最初のオプションは、最初の入力バインド変数と対になります。現在サポートされている値を次に示します。

表17-1 CONTEXT OBJECT OPTION値の有効な選択肢

オプション値 指定内容

DATEFORMAT

Date属性とコレクション要素の書式。

DATELANG

Date型とDatetime型すべてのグローバリゼーション・サポート言語。

次に例を示します。

char *new_format = "DD-MM-YYYY";
char *new_lang = "French";
char *new_date = "14-07-1789";
/* One of the attributes of the license type is dateofbirth */
license *aLicense; 
...
/* Declaration and allocation of context ... */
EXEC SQL CONTEXT OBJECT OPTION SET DATEFORMAT, DATELANG TO :new_format,   :new_lang;
/* Navigational object obtained  */
...
EXEC SQL OBJECT SET dateofbirth OF :aLicense TO :new_date;
...

17.7.2 CONTEXT OBJECT OPTION GET

影響されるコンテキストは、その時点で使用されているコンテキストと解釈されます。これらのオプションの値を決定するには、次のディレクティブを使用します。

EXEC SQL CONTEXT OBJECT OPTION GET {option[, option]} INTO {:hv[, :hv]} ;

表17-1オプションの値は次のとおりです。

出力に使用されるバインド変数hv ...はSTRING型、VARCHAR型またはCHARZ型です。影響されるコンテキストは、その時点で使用されているコンテキストと解釈されます。

17.8 オブジェクトに対する新しいプリコンパイラ・オプション

オブジェクトをサポートするには、次のプリコンパイラ・オプションを使用します。

17.8.1 VERSION

このオプションでは、EXEC SQL OBJECT DEREF文によってどのバージョンのオブジェクトが戻されるかが決まります。これにより、キャッシュ・オブジェクトとサーバー・オブジェクトの間で、一貫性レベルを変更できます。

EXEC ORACLE OPTION文を使用してインラインで設定します。設定できる値は、次のとおりです。

RECENT (デフォルト)

現行のトランザクション内でオブジェクトがオブジェクト・キャッシュに選択されている場合は、そのオブジェクトが戻されます。オブジェクトが選択されていない場合は、サーバーから取り出されます。シリアライズされた状態で実行中のトランザクションの場合、このオプションの動作はVERSION=LATESTと同じですが、ネットワークのラウンドトリップはそれほど多くありません。この値は、ほとんどのPro*C/C++アプリケーションで問題なく使用できます。

LATEST

オブジェクトがオブジェクト・キャッシュに存在しない場合は、データベースから取り出されます。オブジェクト・キャッシュに存在している場合は、サーバーからリフレッシュされます。この値を指定すると、ネットワークのラウンドトリップが増大するため、慎重に使用してください。この値を使用するのは、オブジェクト・キャッシュでサーバー側バッファとできるかぎり一貫性のある状態を保つ必要がある場合です。

ANY

オブジェクトがすでにオブジェクト・キャッシュに存在している場合は、そのオブジェクトが戻されます。オブジェクトがオブジェクト・キャッシュに存在しなければ、サーバーから取り出されます。この値を指定すると、ネットワークのラウンドトリップは最小になります。この値を使用するのは、アプリケーションが読取り専用オブジェクトにアクセスする場合や、ユーザーがオブジェクトに排他的にアクセスする場合です。

17.8.2 DURATION

このプリコンパイラ・オプションは、後続のEXEC SQL OBJECT CREATE文とEXEC SQL OBJECT DEREF文に使用される確保継続時間を設定するときに使用します。キャッシュ内のオブジェクトは、保持期間の終わりに暗黙的に解放されます。

ナビゲーショナル・アクセス用インタフェースでのみ使用します。

このオプションは、EXEC ORACLE OPTION文で設定できます。設定できる値は、次のとおりです。

TRANSACTION (デフォルト)

オブジェクトは、トランザクションの完了時に暗黙的に解放されます。

SESSION

オブジェクトは、接続の終了時に暗黙的に解放されます。

17.8.3 OBJECT

このプリコンパイラ・オプションを指定すると、オブジェクト・キャッシュを使用できます。

DBMS=NATIVE | V8に対するOBJECTSのデフォルト値はYESです。オブジェクト・キャッシュのデフォルト・サイズは、OCIデフォルト・キャッシュ・サイズと同じく8MBです。

関連項目

17.8.4 INTYPE

プログラムでオブジェクト型、コレクション・オブジェクト・タイプまたはREF型を使用する場合は、このコマンドライン・オプションでINTYPEファイルを指定する必要があります。

次の構文で、INTYPEオプションを指定します。

   INTYPE=filename1 INTYPE=filename2 ...

この場合、filename1、filename2...は、OTTで生成された型ファイルの名前です。これらのファイルはPro*C/C++への読取り専用入力ファイルになります。それに含まれる情報は単純なテキスト形式ですが、エンコードされている場合もあり、ユーザーが読める形式になっているとはかぎりません。

Pro*C/C++の1つのプリコンパイル単位に対する入力ファイルとして、複数のINTYPEファイルを指定できます。

このオプションは、EXEC ORACLE文内でインラインで使用することはできません。

OTTは、データベース内で作成されたオブジェクト型を表すC言語の構造体の宣言を生成し、型ファイルと呼ばれるファイルに型の名前とバージョン情報を書き込みます。

オブジェクト型の名前は、それを表すC言語の構造体の型やC++クラスの型と同じであるとはかぎりません。これには、次の理由が考えられます。

  • サーバーに指定されたオブジェクト型の名前に、CまたはC++識別子で無効な文字が含まれている場合

  • ユーザーがOTTに対して、構造体またはクラスに異なる名前を使用するように要求した場合

  • ユーザーがOTTに対して、名前の大文字を小文字に、小文字を大文字に変更するように要求した場合

前述の状況では、構造体やクラスの宣言からは、その構造体やクラスがどのオブジェクト型と一致するかを推論できません。この情報はPro*C/C++に必要であり、OTTによって型ファイル内で生成されます。

17.8.5 ERRTYPE

   ERRTYPE=filename

エラーは、画面のみでなく、指定したファイルにも書き込まれます。このオプションを省略すると、エラーは画面にのみ出力されます。ただし、ERRTYPEは1つしか指定できません。値が1つしかない他のコマンドライン・オプションと同様に、コマンドラインでERRTYPEに複数の値を入力すると、最後の値がすべてに優先します。

このオプションは、EXEC ORACLE文内でインラインで使用することはできません。

17.8.6 オブジェクトに対するSQLCHECKのサポート

各オブジェクト型とその属性は、Oracle型のCバインドに従ってCプログラムに表されます。プリコンパイラ・コマンドライン・オプションSQLCHECKをSEMANTICSまたはFULLに設定すると、Pro*C/C++はプリコンパイル中に、ホスト変数型がデータベース・スキーマ内でその型に必須のCバインドに準拠しているかどうかを検証します。さらに、Oracle型がプログラム実行中に正しくマップされているかどうかを検証するために、常に実行時チェックが行われます。

リレーショナル・データ型は通常の方法でチェックされます。

リレーショナルSQLデータ型とホスト変数型は、両方の型が同一の場合または両方の型の間で変換が可能な場合に、互換性を持ちます。一方、オブジェクト型が互換性を持つのは、両方の型が同一の場合のみです。それらの型を次のように指定する必要があります。

  • 同じ名前にします。

  • 同じスキーマに含めます(スキーマが明示的に指定されている場合)。

オプションSQLCHECK=SEMANTICSまたはFULLを指定すると、Pro*C/C++はプリコンパイル中に、指定されたユーザーIDとパスワードを使用してデータベースにログインし、構造体の宣言が生成されたオブジェクト型と、埋込みSQL文に使用されたオブジェクト型が同じかどうかを検証します。

17.8.7 実行時のタイプ・チェック

Pro*C/C++は、ある型について、入力INTYPEファイルからオブジェクト、コレクション・オブジェクトおよびREFホスト変数の型の名前とバージョン、可能な場合にはスキーマ情報を収集し、これらの情報を生成したコードに格納します。これにより、実行時にオブジェクトおよびREFバインド変数の型情報にアクセスできます。型が同じでない場合は、固有のエラー・メッセージが戻されます。

17.9 Pro*C/C++のオブジェクト例

簡単なオブジェクトの例を検証します。型personと表person_tabを作成します。この表には同じくオブジェクト型の列addressが含まれています。

create type person as object (
        lastname        varchar2(20),
        firstname       char(20),
        age             int,
        addr            address
)
/
create table person_tab of person;

表にデータを挿入し、処理します。

17.9.1 連想アクセス

Pro*C/C++を使用して、lastnameの値を「Smith」から「Smythe」に変更する方法を考えてみます。

OTTを実行して、personにマップするC言語の構造体を生成します。Pro*C/C++プログラムに、OTTによって生成されるヘッダー・ファイルをインクルードする必要があります。

アプリケーション内で、クライアント側キャッシュ内の永続メモリーへのポインタ、person_pを宣言します。それからメモリーを割り当てて、戻されたポインタを使用します。

char *new_name = "Smythe";
person *person_p;
...
EXEC SQL ALLOCATE :person_p;

これで、永続オブジェクトのコピーにメモリーが割り当てられます。割当て済オブジェクトには、まだデータは含まれていません。

C言語の代入文か、SELECT文またはFETCH文を使用して既存のオブジェクトを取り出し、キャッシュにデータを入れます。

EXEC SQL SELECT VALUE(p) INTO :person_p FROM person_tab p WHERE lastname = 'Smith';

キャッシュ内のコピーに対する変更結果は、INSERT文、UPDATE文およびDELETE文を使用してサーバー・データベースに送信します。

EXEC SQL OBJECT SET lastname OF :person_p TO :new_name;
EXEC SQL INSERT INTO person_tab VALUES(:person_p);

次の文を使用してキャッシュ・メモリーを解放します。

EXEC SQL FREE :person_p;

17.9.2 ナビゲーショナル・アクセス

オブジェクト・キャッシュ内に、REFをオブジェクトpersonにコピーするためのメモリーを割り当てます。ALLOCATE文はREFへのポインタを戻します。

person *person_p;
person_ref *per_ref_p;
...
EXEC SQL ALLOCATE :per_ref_p;

割当て済のREFには、データが含まれていません。データを入れるには、オブジェクトのREFを取り出します。

EXEC SQL SELECT ... INTO :per_ref_p;

それからREFを間接参照して、オブジェクトのインスタンスをクライアント側のキャッシュに入れます。間接参照コマンドでは、per_ref_pを使用して、キャッシュ内で対応するオブジェクトのインスタンスを作成します。

EXEC SQL OBJECT DEREF :per_ref_p INTO :person_p;

C言語の代入を使用するか、またはOBJECT GET文を使用して、キャッシュ内のデータを変更します。

/* lname is a C variable to hold the result */
EXEC SQL OBJECT GET lastname FROM :person_p INTO :lname;
...
EXEC SQL OBJECT SET lastname OF :person_p TO :new_name;
/* Mark the changed object as changed with OBJECT UPDATE command */;
EXEC SQL OBJECT UPDATE :person_p;
EXEC SQL FREE :per_ref_p;

変更をデータベース内で永続的なものにするために、FLUSHを使用します。

EXEC SQL OBJECT FLUSH :person_p;

サーバーが変更されたため、オブジェクトをリリースできます。リリースされるオブジェクトが、オブジェクト・キャッシュ・メモリーからただちに解放されるとはかぎりません。最近の使用頻度が最も低いスタックに置かれます。キャッシュがいっぱいになると、オブジェクトはメモリーからスワップされます。

リリースされるのはオブジェクトのみで、そのオブジェクトを指すREFはキャッシュ内に残留します。REFをリリースするには、REF用のRELEASE文を使用します。person_pが指すオブジェクトをリリースするには次のようにします。

EXEC SQL OBJECT RELEASE :person_p;

または、確保継続時間が適切に設定されていれば、トランザクション・コミットを発行すると、キャッシュ内のオブジェクトがすべてリリースされます。

17.10 型の継承のサンプル・コード

次のコード例では、4つのオブジェクト型が作成されます。

  • Person_t

  • Person_tのサブタイプとしてEmployee_t

  • Person_tのサブタイプとしてStudent_t

  • Student_tのサブタイプとしてPartTimeStudent_t

また、次の表も作成されます。

  • Person_tとそのサブタイプのオブジェクトを保持するためのperson_tab

次のSQLファイルinhdemo1.sqlでは、オブジェクト型と表が生成されてから、表に値が挿入されます。

connect scott/tiger;

rem ** Always drop your objects in reverse dependency order
drop table person_tab;
drop type PartTimeStudent_t;
drop type Student_t;
drop type Employee_t;
drop type Person_t;

rem ** Create the TYPES, TYPED TABLES and TABLES we need

rem ** Create a Person_t ADT
CREATE TYPE Person_t AS OBJECT
( ssn NUMBER,
  name VARCHAR2(30),
  address VARCHAR2(100)) NOT FINAL;
/

rem ** Create a Person_t subtype Employee_t
CREATE TYPE Employee_t UNDER Person_t
( empid NUMBER, 
  mgr VARCHAR2(30));
/

rem ** Create a Person_t subtype Student_t
CREATE TYPE Student_t UNDER Person_t 
( deptid NUMBER,
   major VARCHAR2(30)) NOT FINAL;
/

rem ** Create a Student_t subtype PartTimeStudent_t
CREATE TYPE PartTimeStudent_t UNDER Student_t
( numhours NUMBER);
/

rem ** Create a typed table for person_t objects
CREATE table person_tab of person_t;

rem ** Insert 2 Employee_t objects into the person_t typed table
insert into person_tab values
  (Employee_t(123456, 'Alison Laurence', '100 Geary Street, San Francisco, CA 94013',
1001, 'CEO'));
insert into person_tab values
  (Employee_t(234567, 'William Bates', '123 Main Street, Anytown, WA 97818',
1002,'CFO'));

rem ** Insert 2 Student_t objects into the person_t typed table
insert into person_tab values
  (Student_t(20001, 'Van Gates', '1825 Aikido Way, Los Angeles, CA, 45300', 20,
'English'));
insert into person_tab values
  (Student_t(20002, 'Bill Wallace', '12 Shugyo Blvd, Los Angeles, CA, 95100', 30,
'Computer Science'));

rem ** Insert 1 PartTimeStudent_t object into the person_t typed table
insert into person_tab values
  (PartTimeStudent_t(20003, 'Jean Claude', '874 Richmond Street, New York, NY 45100',
40, 'Music',20));

commit;

例で使用したintypeファイルinhdemo1.typのリストを次に示します。

case=same
type person_t
type employee_t
type student_t
type parttimestudent_t

プリコンパイラ・ファイルinhdemo1.pcのリストを次に示します。

/*****************************************************************************
 *
 * This is a simple Pro*C/C++ program designed to illustrate how to
 * access type inheritance objects.
 *
 * To build the executable:
 *
 *   1. Execute the SQL script, inhdemo1.sql in SQL*Plus to create:
 *   - 4 object types person_t, employee_t as a subtype of person_t,
 *              student_t as a subtype of person_t and parttimestudent_t as
 *              a subtype of student_t.
 *   - 1 typed table person_tab to hold "person_t" and its subtype objects
 *
 *   2. Run OTT: (The following command should appear on one line)
 *        ott intype=inhdemo1.typ hfile=inhdemo1.h outtype=out.typ
 *            code=c userid=scott/tiger
 *
 *   3. Precompile using Pro*C/C++:
 *        proc inhdemo1 intype=out.typ
 *   4. Compile/Link (This step is platform specific)
 *
 ****************************************************************************/

/* Include files */

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

#include <sqlca.h>                                /* SQL Communications Area */
#include <sql2oci.h>         /* SQLLIB interoperability routines for OCI8 */
#include "inhdemo1.h"        /* OTT-generated header with C typedefs for the */
                                    /* database types "person" and "address" */
/* Macros */
#define ARRAY_SIZE 10
#define NAME_LENGTH 31
#define ADDR_LENGTH 101

/* Global variables */

  char *uid="scott/tiger";
  int i;
  int count;
  VARCHAR  dynstmt[100];

main()
{

  printf("\n*** STARTING OBJECT TYPE INHERITANCE DEMO ***\n");

  EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--\n");

  EXEC SQL connect :uid;
  printf("Connected successfully.\n");
  
  exec sql select count(*) into :count from person_tab;
  printf("\nThere are %d entries in table person_tab.\n", count);

  do_fetch_all();                                  /* Fetch person_t objects */
  do_fetch_employee();                           /* Fetch employee_t objects */
  do_fetch_student();                        /* Fetch only student_t objects */
  do_fetch_parttimestudent();              /* Fetch parttimestuden_t objects */
  do_fetch_student_employee();     /* Fetch student_t and employee_t objects */

  printf("\nFetching only student_t objects with dynamic sql:\n");
  strcpy((char *)dynstmt.arr,
   "SELECT value(p) from person_tab p where value(p) is of (only student_t)");
  do_dynamic_fetch();             /* Fetch student_t object with dynamic sql */

  printf("\nFetching student_t and its subtype objects with dynamic sql:\n");
  strcpy((char *)dynstmt.arr,
   "SELECT treat(value(p) as student_t) from person_tab p where value(p) is
of(student_t)");
  do_dynamic_fetch();             /* Fetch student_t object with dynamic sql */

  printf("\n*** END OF OBJECT TYPE INHERITANCE DEMO ***\n");
  exit(EXIT_SUCCESS);

}

void printPerson(person)
  person_t *person;
{
  int writtenSSN=-1;
  text writtenName[NAME_LENGTH];
  text writtenAddr[ADDR_LENGTH];

  EXEC SQL OBJECT GET SSN, NAME, ADDRESS FROM :person INTO
     :writtenSSN, :writtenName, :writtenAddr;
  printf("\nSSN=%10d\nNAME=%s\nAddr=%s\n", writtenSSN, writtenName,
          writtenAddr);
}

void printEmployee(employee)
  employee_t *employee;
{
  int writtenID=-1;
  text writtenMgr[NAME_LENGTH];

  printPerson(employee);
  EXEC SQL OBJECT GET EMPID, MGR FROM :employee INTO :writtenID, :writtenMgr;
  printf("EMPID=%10d\nMGR=%s\n", writtenID, writtenMgr);
}

void printStudent(student)
  student_t *student;
{
  int writtendeptid=-1;
  text writtenMajor[NAME_LENGTH];

  printPerson(student);
  EXEC SQL OBJECT GET DEPTID, MAJOR FROM :student INTO :writtendeptid, :writtenMajor;
  printf("DEPTID=%10d\nMAJOR=%s\n", writtendeptid, writtenMajor);
}

void printPartTimeStudent(parttimes)
  parttimestudent_t *parttimes;
{
  int written_numhours=-1;

  printStudent(parttimes);
  EXEC SQL OBJECT GET NUMHOURS FROM :parttimes INTO :written_numhours;
  printf("NUMHOURS=%10d\n", written_numhours);
}

/* Declare error handling function. */
sql_error(msg)
    char *msg;
{
    char err_msg[128];
    size_t buf_len, msg_len;

    EXEC SQL WHENEVER SQLERROR CONTINUE;

    printf("\n%s\n", msg);
    buf_len = sizeof (err_msg);
    sqlglm(err_msg, &buf_len, &msg_len);
    printf("%.*s\n", msg_len, err_msg);

    EXEC SQL ROLLBACK RELEASE;
    exit(EXIT_FAILURE);
}

/*****************************************************************************
 * The following function shows how to select person_t objects
 ****************************************************************************/

do_fetch_all()
{
person_t *personArray[ARRAY_SIZE];
person_t_ind *personArray_ind[ARRAY_SIZE];

  printf("\nFetching person_t objects:\n");

  exec sql declare c1 cursor for
    select value(p) from person_tab p;

  exec sql allocate :personArray:personArray_ind;

  exec sql open c1;

  exec sql whenever not found goto :done;
  while(sqlca.sqlcode==0)
    {
      exec sql fetch c1 into :personArray:personArray_ind;
      if (sqlca.sqlcode == 1403) goto done;
      for (i=0; i < ARRAY_SIZE; i++ )
        printPerson(personArray[i]);
    }

 done:
  for (i=0; i < sqlca.sqlerrd[2] % ARRAY_SIZE; i++)
    printPerson(personArray[i]);

  printf("Total number of person_t objects fetched: %d.\n",
          sqlca.sqlerrd[2]);

  exec sql close c1;
  exec sql free :personArray:personArray_ind;
}

/*****************************************************************************
 * The following function shows how to select person_t subtype employee_t
 * objects
 ****************************************************************************/

do_fetch_employee()
{
employee_t *empArray[ARRAY_SIZE];
employee_t_ind *empArray_ind[ARRAY_SIZE];

  printf("\nFetching employee_t objects:\n");

  exec sql allocate :empArray:empArray_ind;

  exec sql declare c2 cursor for
    select value(p) from person_tab p
      where value(p) is of (employee_t);

  exec sql open c2;

  exec sql whenever not found goto :done_emp;
  while(sqlca.sqlcode==0)
    {
      exec sql fetch c2 into :empArray:empArray_ind;
      for (i=0; i < ARRAY_SIZE; i++ )
        printEmployee(empArray[i]);
    }

 done_emp:
   for (i=0; i < sqlca.sqlerrd[2] % ARRAY_SIZE; i++)
     printEmployee(empArray[i]);

   printf("Total number of employee_t objects fetched: %d.\n",
          sqlca.sqlerrd[2]);

  exec sql close c2;
  exec sql free :empArray:empArray_ind;
}

/*****************************************************************************
 * The following function shows how to select person_t subtype student_t 
 * objects
 ****************************************************************************/

do_fetch_student()
{
student_t *studentArray[ARRAY_SIZE];
student_t_ind *studentArray_ind[ARRAY_SIZE];

  printf("\nFetching student_t objects:\n");

  exec sql declare c3 cursor for
    select value(p) from person_tab p
      where value(p) is of (student_t);

  exec sql allocate :studentArray:studentArray_ind;

  exec sql open c3;

  exec sql whenever not found goto :done_student;
  for (;;)
    {
      exec sql fetch c3 into :studentArray:studentArray_ind;
      for (i=0; i < ARRAY_SIZE; i++ )
        printStudent(studentArray[i]);
    }

 done_student:
  for (i=0; i < sqlca.sqlerrd[2] % ARRAY_SIZE; i++)
    printStudent(studentArray[i]);

  printf("Total number of student_t objects fetched: %d.\n",
          sqlca.sqlerrd[2]);

  exec sql close c3;
  exec sql free :studentArray:studentArray_ind;
}

/*****************************************************************************
 * The following function shows how to select student_t subtype
 * parttimestudent objects
 ****************************************************************************/

do_fetch_parttimestudent()
{
parttimestudent_t *parttimestudentArrayArray[ARRAY_SIZE];
parttimestudent_t_ind *parttimestudentArrayArray_ind[ARRAY_SIZE];

  printf("\nFetching parttimestudent_t objects:\n");

  exec sql declare c4 cursor for
    select value(p) from person_tab p
      where value(p) is of (parttimestudent_t);

  exec sql allocate :parttimestudentArrayArray:parttimestudentArrayArray_ind;

  exec sql open c4;

  exec sql whenever not found goto :done_parttimestudent;
  while(sqlca.sqlcode==0)
    {
      exec sql fetch c4 into :parttimestudentArrayArray:parttimestudentArrayArray_ind;
      for (i=0; i < ARRAY_SIZE; i++ )
        printPartTimeStudent(parttimestudentArrayArray[i]);
    }

 done_parttimestudent:
  for (i=0; i < sqlca.sqlerrd[2] % ARRAY_SIZE; i++)
    printPartTimeStudent(parttimestudentArrayArray[i]);

  printf("Total number of parttimestudent_t objects fetched: %d.\n",
          sqlca.sqlerrd[2]);

  exec sql close c4;
  exec sql free :parttimestudentArrayArray:parttimestudentArrayArray_ind;
}

/*****************************************************************************
 * The following function shows how to select person_t subtypes student_t 
 * and employee_t objects
 ****************************************************************************/

do_fetch_student_employee()
{
person_t *personArray[ARRAY_SIZE];
person_t_ind *personArray_ind[ARRAY_SIZE];

  printf("\nFetching only student_t and employee_t objects:\n");

  exec sql declare c5 cursor for
    select value(p) from person_tab p
      where value(p) is of (only student_t, employee_t);

  exec sql allocate :personArray:personArray_ind;

  exec sql open c5;

  exec sql whenever not found goto :done_student_employee;
  while(sqlca.sqlcode==0)
    {
      exec sql fetch c5 into :personArray:personArray_ind;
      for (i=0; i < ARRAY_SIZE; i++ )
        printPerson(personArray[i]);
    }

 done_student_employee:
  for (i=0; i < sqlca.sqlerrd[2] % ARRAY_SIZE; i++)
        printPerson(personArray[i]);

  printf("Total number of stuent_t and employee_t objects fetched: %d.\n",
sqlca.sqlerrd[2]);

  exec sql close c5;
  exec sql free :personArray:personArray_ind;
}

/*****************************************************************************
 * The following function shows how to select person_t subtype student_t 
 * objects using dynamic sql.
 ****************************************************************************/

do_dynamic_fetch()
{
student_t *student;
student_t_ind  *student_ind;

  exec sql allocate :student:student_ind;

  dynstmt.len = (unsigned short)strlen((char *)dynstmt.arr);
  EXEC SQL PREPARE S FROM :dynstmt;
  EXEC SQL DECLARE C CURSOR FOR S;
  EXEC SQL OPEN C;

  exec sql whenever not found do break;
  for (;;)
  {
     EXEC SQL FETCH C INTO :student:student_ind;
     printStudent(student);
  }

  printf("\nQuery returned %d row%s.\n", sqlca.sqlerrd[2],
         (sqlca.sqlerrd[2] == 1) ? "" : "s");

  EXEC SQL CLOSE C;
  exec sql free :student:student_ind;
}

17.11 ナビゲーショナル・アクセスのサンプル・コード

サンプル・コードでは3つのオブジェクト型が生成されます。budokaは武道家です。

  • customer

  • budoka

  • location

さらに、次の2つの表が作成されます。

  • person_tab

  • customer_tab

次のSQLファイルnavdemo1.sqlでは、型と表が生成されてから、表に値が挿入されます。

connect scott/tiger

drop table customer_tab;
drop type customer;
drop table person_tab;
drop type budoka;
drop type location;

create type location as object (
        num     number,
        street  varchar2(60),
        city    varchar2(30),
        state   char(2),
        zip     char(10)
);
/

create type budoka as object (
        lastname        varchar2(20),
        firstname       varchar(20),
        birthdate       date,
        age             int,
        addr            location
);
/

create table person_tab of budoka;

create type customer as object (
        account_number varchar(20),
        aperson ref budoka
);
/

create table customer_tab of customer;

insert into person_tab values (
        budoka('Seagal', 'Steven', '14-FEB-1963', 34,
                location(1825, 'Aikido Way', 'Los Angeles', 'CA', 45300)));
insert into person_tab values (
        budoka('Norris', 'Chuck', '25-DEC-1952', 45,
                location(291, 'Grant Avenue', 'Hollywood', 'CA', 21003)));
insert into person_tab values (
        budoka('Wallace', 'Bill', '29-FEB-1944', 53,
                location(874, 'Richmond Street', 'New York', 'NY', 45100)));
insert into person_tab values (
        budoka('Van Damme', 'Jean Claude', '12-DEC-1964', 32,
                location(12, 'Shugyo Blvd', 'Los Angeles', 'CA', 95100)));

insert into customer_tab
        select 'AB123', ref(p)
          from person_tab p where p.lastname = 'Seagal';
insert into customer_tab
        select 'DD492', ref(p)
          from person_tab p where p.lastname = 'Norris';
insert into customer_tab 
        select 'SM493', ref(p)
          from person_tab p where p.lastname = 'Wallace';
insert into customer_tab
        select 'AC493', ref(p)
          from person_tab p where p.lastname = 'Van Damme';
        
commit work;

例に使用したintypeファイルnavdemo1.typのリストを次に示します。

case=lower
type location
type budoka
type customer

OTTが生成するヘッダー・ファイルnavdemo1.hは、#includeプリプロセッサ・ディレクティブの付いたプリコンパイラのコードにインクルードされます。

プリコンパイラ・コード内のコメントを読み込みます。プログラムは新しいbudokaオブジェクト(Jackie Chanのもの)を追加してから、customer_tab表のすべての顧客を表示します。

プリコンパイラ・ファイルnavdemo1.pcのリストを次に示します。

/*************************************************************************
 *
 * This is a simple Pro*C/C++ program designed to illustrate the
 * Navigational access to objects in the object cache.
 *
 * To build the executable:
 *
 *   1. Execute the SQL script, navdemo1.sql in SQL*Plus
 *   2. Run OTT: (The following command should appear on one line)
 *        ott intype=navdemo1.typ hfile=navdemo1.h outtype=navdemo1_o.typ
 *            code=c user=scott/tiger
 *   3. Precompile using Pro*C/C++:
 *        proc navdemo1 intype=navdemo1_o.typ
 *   4. Compile/Link (This step is platform specific)
 *
 *************************************************************************/

#include "navdemo1.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlca.h>

void whoops(errcode, errtext, errtextlen)
  int   errcode;
  char *errtext;
  int   errtextlen;
{
  printf("ERROR! sqlcode=%d: text = %.*s", errcode, errtextlen, errtext);
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  EXEC SQL ROLLBACK WORK RELEASE;
  exit(EXIT_FAILURE);
}

void main()
{
  char *uid = "scott/tiger";

       /* The following types are generated by OTT and defined in navdemo1.h */
  customer *cust_p;                            /* Pointer to customer object */
  customer_ind *cust_ind;        /* Pointer to indicator struct for customer */
  customer_ref *cust_ref;            /* Pointer to customer object reference */
  budoka *budo_p;                                /* Pointer to budoka object */
  budoka_ref *budo_ref;                /* Pointer to budoka object reference */
  budoka_ind *budo_ind;            /* Pointer to indicator struct for budoka */

    /* These are data declarations to be used to insert/retrieve object data */
  VARCHAR acct[21];
  struct { char lname[21], fname[21]; int age; } pers;
  struct { int num; char street[61], city[31], state[3], zip[11]; } addr;

  EXEC SQL WHENEVER SQLERROR DO whoops(
    sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, sqlca.sqlerrm.sqlerrml);

  EXEC SQL CONNECT :uid;

  EXEC SQL ALLOCATE :budo_ref;

  /* Create a new budoka object with an associated indicator
   * variable returning a REF to that budoka as well.
   */
  EXEC SQL OBJECT CREATE :budo_p:budo_ind TABLE PERSON_TAB
	          RETURNING REF INTO :budo_ref;

  /* Create a new customer object with an associated indicator */
  EXEC SQL OBJECT CREATE :cust_p:cust_ind TABLE CUSTOMER_TAB;

  /* Set all budoka indicators to NOT NULL.  We
   * will be setting all attributes of the budoka.
   */
  budo_ind->_atomic = budo_ind->lastname = budo_ind->firstname = 
    budo_ind->age = OCI_IND_NOTNULL;

  /* We will also set all address attributes of the budoka */
  budo_ind->addr._atomic = budo_ind->addr.num = budo_ind->addr.street = 
    budo_ind->addr.city = budo_ind->addr.state = budo_ind->addr.zip = 
      OCI_IND_NOTNULL;

  /* All customer attributes will likewise be set */
  cust_ind->_atomic = cust_ind->account_number = cust_ind->aperson =
    OCI_IND_NOTNULL;

  /* Set the default CHAR semantics to type 5 (STRING) */
  EXEC ORACLE OPTION (char_map=string);

  strcpy((char *)pers.lname, (char *)"Chan");
  strcpy((char *)pers.fname, (char *)"Jackie");
  pers.age = 38;

  /* Convert native C types to OTS types */
  EXEC SQL OBJECT SET lastname, firstname, age OF :budo_p TO :pers;

  addr.num = 1893;
  strcpy((char *)addr.street, (char *)"Rumble Street");
  strcpy((char *)addr.city, (char *)"Bronx");
  strcpy((char *)addr.state, (char *)"NY");
  strcpy((char *)addr.zip, (char *)"92510");
  
  /* Convert native C types to OTS types */
  EXEC SQL OBJECT SET :budo_p->addr TO :addr;

  acct.len = strlen(strcpy((char *)acct.arr, (char *)"FS926"));

  /* Convert native C types to OTS types - Note also the REF type */
  EXEC SQL OBJECT SET account_number, aperson OF :cust_p TO :acct, :budo_ref;

  /* Mark as updated both the new customer and the budoka */
  EXEC SQL OBJECT UPDATE :cust_p;
  EXEC SQL OBJECT UPDATE :budo_p;

  /* Now flush the changes to the server, effectively
   * inserting the data into the respective tables.
   */
  EXEC SQL OBJECT FLUSH :budo_p;
  EXEC SQL OBJECT FLUSH :cust_p;

  /* Associative access to the REFs from CUSTOMER_TAB */
  EXEC SQL DECLARE ref_cur CURSOR FOR 
    SELECT REF(c) FROM customer_tab c;

  EXEC SQL OPEN ref_cur;

  printf("\n");

  /* Allocate a REF to a customer for use in the following */
  EXEC SQL ALLOCATE :cust_ref;

  EXEC SQL WHENEVER NOT FOUND DO break;
  while (1)
  {
    EXEC SQL FETCH ref_cur INTO :cust_ref;
    
    /* Pin the customer REF, returning a pointer to a customer object */
    EXEC SQL OBJECT DEREF :cust_ref INTO :cust_p:cust_ind;

    /* Convert the OTS types to native C types */
    EXEC SQL OBJECT GET account_number FROM :cust_p INTO :acct;
    printf("Customer Account is %.*s\n", acct.len, (char *)acct.arr);
    
    /* Pin the budoka REF, returning a pointer to a budoka object */
    EXEC SQL OBJECT DEREF :cust_p->aperson INTO :budo_p:budo_ind;

    /* Convert the OTS types to native C types */
    EXEC SQL OBJECT GET lastname, firstname, age FROM :budo_p INTO :pers;
    printf("Last Name: %s\nFirst Name: %s\nAge: %d\n",
	   pers.lname, pers.fname, pers.age);

    /* Do the same for the address attributes as well */
    EXEC SQL OBJECT GET :budo_p->addr INTO :addr;
    printf("Address:\n");
    printf("  Street: %d %s\n  City: %s\n  State: %s\n  Zip: %s\n\n",
	   addr.num, addr.street, addr.city, addr.state, addr.zip);

    /* Unpin the customer object and budoka objects */
    EXEC SQL OBJECT RELEASE :cust_p;
    EXEC SQL OBJECT RELEASE :budo_p;
  }

  EXEC SQL CLOSE ref_cur;
  
  EXEC SQL WHENEVER NOT FOUND DO whoops(
    sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, sqlca.sqlerrm.sqlerrml);

  /* Associatively select the newly created customer object */
  EXEC SQL SELECT VALUE(c) INTO :cust_p FROM customer_tab c
            WHERE c.account_number = 'FS926';

  /* Mark as deleted the new customer object */
  EXEC SQL OBJECT DELETE :cust_p;

  /* Flush the changes, effectively deleting the customer object */
  EXEC SQL OBJECT FLUSH :cust_p;

  /* Associatively select a REF to the newly created budoka object */
  EXEC SQL SELECT REF(p) INTO :budo_ref FROM person_tab p
            WHERE p.lastname = 'Chan';

  /* Pin the budoka REF, returning a pointer to the budoka object */
  EXEC SQL OBJECT DEREF :budo_ref INTO :budo_p;

  /* Mark the new budoka object as deleted in the object cache */
  EXEC SQL OBJECT DELETE :budo_p;

  /* Flush the changes, effectively deleting the budoka object */
  EXEC SQL OBJECT FLUSH :budo_p;

  /* Finally, free all object cache memory and log off */
  EXEC SQL OBJECT CACHE FREE ALL;

  EXEC SQL COMMIT WORK RELEASE;

  exit(EXIT_SUCCESS);
}

プログラムの実行結果は次のとおりです。

Customer Account is AB123
Last Name: Seagal
First Name: Steven
Birthdate: 02-14-1963
Age: 34
Address:
  Street: 1825 Aikido Way
  City: Los Angeles
  State: CA
  Zip: 45300     

Customer Account is DD492
Last Name: Norris
First Name: Chuck
Birthdate: 12-25-1952
Age: 45
Address:
  Street: 291 Grant Avenue
  City: Hollywood
  State: CA
  Zip: 21003     

Customer Account is SM493
Last Name: Wallace
First Name: Bill
Birthdate: 02-29-1944
Age: 53
Address:
  Street: 874 Richmond Street
  City: New York
  State: NY
  Zip: 45100     

Customer Account is AC493
Last Name: Van Damme
First Name: Jean Claude
Birthdate: 12-12-1965
Age: 32
Address:
  Street: 12 Shugyo Blvd
  City: Los Angeles
  State: CA
  Zip: 95100     

Customer Account is FS926
Last Name: Chan
First Name: Jackie
Birthdate: 10-10-1959
Age: 38
Address:
  Street: 1893 Rumble Street
  City: Bronx
  State: NY
  Zip: 92510

関連項目:

intypeファイルの書式の詳細は、OTTコマンドラインを参照してください。

17.12 C言語の構造体の使用について

Oracle8以前は、Pro*C/C++のSQL SELECT文では、C言語の構造体を1つのホスト変数として指定できました。その場合、構造体の各メンバーは、リレーショナル表の1つのデータベース列に対応付けられます。つまり、各メンバーは問合せによって戻される選択リスト内の1つの項目を表します。

Oracle8i以上のバージョンでは、データベース内のオブジェクト型は、1つのエンティティであり、1つの項目として選択できます。Oracle7の表記法では、構造体はスカラー変数のグループなのか、それともオブジェクトなのかがあいまいです。

Pro*C/C++では、次の規則を利用してこのあいまいさを解消しています。

OTTを使用してC宣言が生成された場合にかぎり、C言語の構造体のホスト変数がオブジェクト型を表すとみなされます。そのため、型記述はPro*C/C++へのINTYPEオプションで指定される型ファイルに表示されます。他のすべてのホスト構造体は、データベースに同じ名前のデータ型が存在する場合でも、Oracle7構文が使用されているものとみなされます。

したがって、既存の構造体ホスト変数の型と同じ名前を持つ新しいオブジェクト型を使用する場合は、Pro*C/C++ではINTYPEファイル内のオブジェクト型定義が使用されることに注意してください。これは、コンパイル・エラーの原因となる場合があります。この修正には、既存のホスト変数の型を名前変更するか、またはOTTを使用してオブジェクト型に新しい名前を付けます。

前述の規則は、OTT生成のデータ型に対して別名指定されるユーザー定義のデータ型にまで広く適用されます。例として、emptypeがヘッダー・ファイルdbtypes.h内でOTTによって生成された構造体であり、Pro*C/C++プログラムに次の文を組み込んだ場合を考えます。

#include <dbtypes.h>
typedef emptype myemp;
myemp *employee;

変数employeeを表す型の名前myempは、データベース内で定義されたあるオブジェクト型を表すOTT生成の型の名前emptypeに対して別名指定されます。これによって、Pro*C/C++では、変数employeeはオブジェクト型を表すものとみなされます。

前述の規則は、OTT生成の型を持つC言語の構造体や、OTT生成の型に対して別名指定されているC言語の構造体を、オブジェクト型以外の型のデータのフェッチに使用できないという意味ではありません。単に、Pro*C/C++は自動的にそうした構造体を拡張しないということです。ユーザーは自由に一般的な構文を使用して、構造体の個々のフィールドを単一データベースの列の選択や更新に使用できます。

17.13 REFの使用について

REF型はオブジェクト自体ではなく、オブジェクトの参照を示します。REF型はリレーショナル列のみでなく、オブジェクト型の属性としても指定できます。

17.13.1 REFのC言語の構造体の生成

オブジェクト型のREFのC言語での表現は、OTTにより型の変換中に生成されます。たとえば、データベース内のユーザー定義型PERSONの参照は、C言語では「Person_ref」型で示されます。正確な型名は型変換時に有効なOTTオプションで決定されます。OTTにより生成された型ファイルは、Pro*C/C++のINTYPEプリコンパイラ・オプションで指定する必要があります。また、OTTにより生成されたヘッダーは、#includeを使用してPro*C/C++プログラムに組み込む必要があります。このスキームにより、REF型に対する適切なタイプ・チェックがPro*C/C++のプリコンパイル中に間違いなく実行されます。

REF型では、OTTで特殊なインジケータ構造体を生成する必要がありません。かわりに、2バイトの符号付きスカラー・インジケータが使用されます。

17.13.2 REFの宣言

Pro*C/C++でREF型を表すホスト変数は、該当するOTT生成の型へのポインタとして宣言する必要があります。

オブジェクト型とは異なり、REF型を表す標識変数は、2バイトの符号付きスカラー型OCIIndとして宣言されます。標識変数は本来オプションですが、Pro*C/C++で宣言された各ホスト変数に対してそれぞれ1つずつ指定するようにプログラミングしてください。

17.13.3 埋込みSQLでのREFの使用

REF型は、オブジェクト・キャッシュに格納されています。ただし、REF型を表すインジケータはスカラーであるため、キャッシュには割り当てられていません。このインジケータは通常ユーザー・スタックに格納されています。

REF型を表すホスト構造体を埋込みSQL文で指定する前に、EXEC SQL ALLOCATEコマンドを使用してオブジェクト・キャッシュ内の領域を割り当ててください。使用後は、EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLコマンドを自由に使用できます。

スカラー標識変数用のメモリーはオブジェクト・キャッシュに割り当てられていないため、REF型を表すインジケータはALLOCATEコマンドおよびFREEコマンドには使用できません。OCIIndとして宣言されたスカラー・インジケータはプログラム・スタックに格納されています。ALLOCATE文を指定すれば、実行時に、指定されたホスト変数のための領域がオブジェクト・キャッシュに割り当てられます。ナビゲーショナル・アクセス用インタフェースでは、C割当てではなく、EXEC SQL GETとEXEC SQL SETを使用してください。

Pro*C/C++では、関連するSQL文および埋込みPL/SQLブロックでのREFホスト変数の指定がサポートされています。

17.14 OCIDate、OCIString、OCINumberおよびOCIRawの使用について

これらのOCI型はそれぞれ、日付、可変長のヌルで終了する文字列、Oracleでの数、および可変長のバイナリ・データを表す新しいC言語の表現です。これらの型は、いくつかの面でこれまでのC言語の数量表現よりも機能的になっています。たとえば、OCIDate型はクライアント側のルーチンが日付演算を実行する準備をします。これは以前のリリースではサーバーでのSQL文を必要としていました。

17.14.1 OCIDate、OCIString、OCINumber、OCIRawの宣言

OCI*型は、OTT生成の構造体でオブジェクト型の属性として表示され、Pro*C/C++プログラムではオブジェクト型の一部として使用します。オブジェクト型として使用しない場合に、初心者レベルのC言語およびPro*C/C++ユーザーは、これらの型のホスト変数を単独で宣言しないでください。経験豊富なPro*C/C++ユーザーは、これらの型の高い機能性を活かすように、それぞれのCホスト変数を宣言してもかまいません。ホスト変数はこれらの型へのポインタOCIString *sなどとして宣言される必要があります。対応付けられた(オプションの)インジケータは、2バイトの符号付きスカラー、つまりOCIInd s_indなどとして宣言されます。

17.14.2 埋込みSQLでのOCI型の使用

これらの型のホスト変数のための領域は、EXEC SQL ALLOCATEを使用してオブジェクト・キャッシュに割り当てられます。これらの型を表すスカラー標識変数は、ALLOCATEおよびFREEコマンドには使用できません。このようなインジケータは、スタック上で静的に割り当てるか、またはヒープ上で動的に割り当てます。領域の割当ては、EXEC SQL FREE文またはEXEC SQL CACHE FREE ALL文を使用して解除できます。また、セッションの終わりには自動的に解除されます。

17.14.3 OCI型の操作

年、月、日、時など、様々な日付コンポーネントごとに個別フィールドを持つ構造型OCIDateを除き、他のOCI型はカプセル化されているため外部ユーザーには見えません。現在、VARCHARのような既存のC言語のデータ型はPro*C/C++で処理されますが、この方法とは対照的にOCIヘッダー・ファイルoci.hをインクルードし、その関数を使用してDATE算術を実行したり、これらの型とint charなどのC言語固有の型の間で変換したりできます。

17.15 Pro*C/C++の新しいデータベース型の概要

表17-2に、オブジェクト・サポートのための新たなデータベース型を示します。

表17-2 Pro*C/C++での新しいデータベース型の使用

操作データベース型 DECLARE ALLOCATE FREE MANIPULATE

オブジェクト型

ホスト: OTTで生成されたC言語の構造体へのポインタ

インジケータ: OTTで生成されたインジケータ構造体へのポインタ

連想アクセス用インタフェース:

EXEC SQL ALLOCATE

ナビゲーショナル・アクセス用インタフェース:

EXEC SQL OBJECT CREATE ...

EXEC SQL OBJECT DEREF

ホスト変数およびインジケータのためのメモリーをオブジェクト・キャッシュに割り当てます。

EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLを使用して解放するか、セッションの終わりに自動的に解放します。

C言語のポインタを間接参照(DEREF)して各属性を取得します。操作方法は属性の型によって異なります(次を参照)。

コレクション・オブジェクト・タイプ

(NESTED TABLEおよび可変長配列)

ホスト: OTTで生成されたC言語の構造体へのポインタ

インジケータ: OCIInd

EXEC SQL ALLOCATE

ホスト変数のためのメモリーをオブジェクト・キャッシュに割り当てます。

EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLを使用して解放するか、セッションの終わりに自動的に解放します。

OCIColl*関数(oci.hに定義)を使用して、各要素を取得または設定します。コレクションも参照してください。

REF

ホスト: OTTで生成されたC言語の構造体へのポインタ

インジケータ: OCIInd

EXEC SQL ALLOCATE

ホスト変数のためのメモリーをオブジェクト・キャッシュに割り当てます。

EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLを使用して解放するか、セッションの終わりに自動的に解放します。

EXEC SQL OBJECT DEREFを使用します。

ナビゲーショナル・アクセス用インタフェースでEXEC SQL OBJECT SET/GETを使用します。

LOB

ホスト:

OCIBlobLocator *、OCIClobLocator *またはOCIBfileLocator *

インジケータ: OCIInd

EXEC SQL ALLOCATE

を使用してホスト変数用のメモリーをユーザー・ヒープ内で割り当てます。

malloc()

EXEC SQL FREEを使用して解放するか、すべてのPro*C/C++接続のクローズ時に自動的に解放します。EXEC SQL CACHE FREE ALLでは、オブジェクトのLOB属性のみ解放されます。

または、dbms_lobパッケージの埋込みPL/SQLストアド・プロシージャを使用するか、あるいは

oci.hに定義されているOCILob*関数を使用します。

LOBも参照してください。

注意:

Pro*C/C++では、これらの型のホスト配列は、SQLのバルク・フェッチまたはバルク挿入操作で宣言および使用できます。

-

-

-

-

表17-3に、Pro*C/C++での新たなC言語のデータ型の利用方法を示します。

表17-3 Pro*C/C++での新たなC言語のデータ型の使用

操作C言語のデータ型 DECLARE ALLOCATE FREE MANIPULATE

OCIDate

ホスト: OCIDate *

インジケータ: OCIInd

EXEC SQL ALLOCATE

ホスト変数のためのメモリーをオブジェクト・キャッシュに割り当てます。

EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLを使用して解放するか、セッションの終わりに自動的に解放します。

(1)oci.hに定義されたOCIDate*関数を使用します。

(2)EXEC SQL OBJECT GET/SETを使用します。または

(3)oci.hに定義されているOCINumber*関数を使用します。

OCINumber

ホスト: OCINumber *

インジケータ: OCIInd

EXEC SQL ALLOCATE

ホスト変数のためのメモリーをオブジェクト・キャッシュに割り当てます。

EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLを使用して解放するか、セッションの終わりに自動的に解放します。

(1)EXEC SQL OBJECT GET/SETを使用します。または

(2)oci.hに定義されているOCINumber*関数を使用します。

OCIRaw

ホスト: OCIRaw *

インジケータ: OCIInd

EXEC SQL ALLOCATE

ホスト変数のためのメモリーをオブジェクト・キャッシュに割り当てます。

EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLを使用して解放するか、セッションの終わりに自動的に解放します。

oci.hに定義されているOCIRaw*関数を使用します。

OCIString

ホスト: OCIString *

インジケータ: OCIInd

EXEC SQL ALLOCATE

ホスト変数のためのメモリーをオブジェクト・キャッシュに割り当てます。

EXEC SQL FREEまたはEXEC SQL CACHE FREE ALLを使用して解放するか、セッションの終わりに自動的に解放します。

(1)EXEC SQL OBJECT GET/SETを使用します。または

(2)oci.hに定義されているOCIString*関数を使用します。

注意:

Pro*C/C++では、これらの型のホスト配列は、SQLのバルク・フェッチまたはバルク挿入操作で使用できない場合があります。

-

-

-

-

Oracle8での新しいデータ型は、REF、BLOB、NCLOB、CLOBおよびBFILEです。これらの型は、オブジェクト内またはリレーショナル列に使用することができます。どちらの場合も、Cバインドに従ってホスト変数にマップされます。

関連項目:

Cバインドについては、Pro*C/C++の新しいデータベース型の概要を参照してください。

17.16 動的SQLでのOracleデータ型使用の制限

現在Pro*C/C++では、動的SQL方法: 1、2、3および4(ANSIおよびOracle)の異なる型をサポートしています。

動的SQL方法1、2および3を使用すると、前述のPro*C/C++拡張機能、つまり新しいオブジェクト型、REF、NESTED TABLE、可変長配列、NCHAR、NCHARの可変長配列およびLOB型などをすべて処理できます。

従来のの動的SQL方法4は、基本的にリリース8.0より前のPro*C/C++でサポートされるOracle型に制限されています。NCHAR、NCHAR可変幅およびLOBデータ型のホスト変数はサポートされています。動的SQL方法4は、オブジェクト型、NESTED TABLE、可変長配列およびREF型の処理には使用できません。

そのかわり新しいアプリケーションにはすべて、Oracle8iで導入されたすべてのデータ型をサポートするANSI動的SQL方法4を使用してください。