この章では、Object Type Translator(OTT)について説明します。OTTを使用すると、データベース・オブジェクト・タイプや名前付きコレクション型をC構造体にマップして、OCIアプリケーションで使用できます。
この章は、次の項目で構成されています。
Object Type Translator(OTT)は、Oracleサーバーでユーザー定義型を使用するC言語アプリケーションを開発するのに役立ちます。
SQLのCREATE TYPE文を使用すると、オブジェクト型を作成できます。これらの型の定義をデータベースに格納しておき、データベースの表を作成するときに使用できます。これらの表を作成すると、OCIのプログラマは、表に格納されたオブジェクトにアクセスできます。
オブジェクト・データにアクセスするアプリケーションでは、データをホスト言語形式で表現する必要があります。これは、オブジェクト型をC構造体として表現することによって実現できます。プログラマがデータベース・オブジェクト・タイプを表す構造体宣言を、手入力でコーディングすることは可能です。しかし、多くの型がある場合、この作業は時間がかかり、エラーを生む原因になることも少なくありません。OTTを使用して適切な構造体宣言を自動的に生成することにより、このステップを単純化できます。OCIのアプリケーションでは、OTTで生成された初期化関数をコールします。
OTTは、格納済のデータ型を表す構造体を作成するのみでなく、オブジェクト型またはそのフィールドがNULLかどうかを示すパラレル・インジケータ構造体も生成します。
Object Type Translator(OTT)は、オブジェクト型と名前付きコレクション型のデータベース定義を、OCIアプリケーションに組み込むことができるC構造体宣言に変換します。
OTTを明示的に起動し、データベース型をC表現に変換する必要があります。
ほとんどのオペレーティング・システムでは、コマンドラインからOTTを起動します。intypeファイルを入力として取得し、outtypeファイル、1つ以上のCのヘッダー・ファイルおよびオプションの実装ファイルを生成します。OTTを起動するコマンドの例を次に示します。
ott userid=scott intype=demoin.typ outtype=demoout.typ code=c hfile=demo.h\
initfile=demov.c
このコマンドで、OTTをユーザー名'scott'でデータベースに接続します。 パスワードの入力を求められます。
実装ファイル(demov.c)には、変換済のユーザー定義型の情報を含む型バージョン表を初期化する関数を格納します。
各パラメータについては、この章の後の項で詳しく説明します。
demoin.typファイルの例
CASE=LOWER TYPE emptype
demoout.typファイルの例
CASE = LOWER TYPE SCOTT.EMPTYPE AS emptype VERSION = "$8.0" HFILE = demo.h
この例のdemoin.typファイルには、TYPEが前に付く変換対象の型(TYPE emptypeなど)があります。outtypeファイルの構造体は、intypeファイルに似ており、OTTで取得した情報が追加されます。
OTTによる変換が終了すると、ヘッダー・ファイルには、intypeファイルで指定した各型のC構造体表現と、各型に対応したNULLインジケータ構造体が入っています。たとえば、intypeファイルにリストされたemployee型が次のように定義されたとします。
CREATE TYPE emptype AS OBJECT
(
name VARCHAR2(30),
empno NUMBER,
deptno NUMBER,
hiredate DATE,
salary NUMBER
);
OTTで生成されたヘッダー・ファイル(demo.h)には、その他の項目の中に、次の宣言が含まれます。
struct emptype
{
OCIString * name;
OCINumber empno;
OCINumber deptno;
OCIDate hiredate;
OCINumber salary;
};
typedef struct emptype emptype;
struct emptype_ind
{
OCIInd _atomic;
OCIInd name;
OCIInd empno;
OCIInd deptno;
OCIInd hiredate;
OCIInd salary;
};
typedef struct employee_ind employee_ind;
このコマンドで生成されたサンプルの実装ファイルdemov.cには、次の宣言が含まれます。
#ifndef OCI_ORACLE
#include <oci.h>
#endif
sword demov(OCIEnv *env, OCIError *err)
{
sword status = OCITypeVTInit(env, err);
if (status == OCI_SUCCESS)
status = OCITypeVTInsert(env, err,
"HR", 2,
"EMPTYPE", 7,
"$8.0", 4);
return status;
}
intypeファイルのパラメータで、生成済構造体の命名方法を制御します。この例では、構造体名のemptypeがデータベース型名のemptypeと一致しています。構造体名は小文字です。これは、intypeファイル内にCASE=lowerの行があるためです。
構造体宣言(OCIStringやOCIIndなど)のデータ型は、特殊なデータ型です。
次の各項では、OTTの使用方法をそれぞれの局面から説明します。
この章の残りの各項では、OCIでのOTTの使用方法を説明します。その後に続く参照の項では、コマンドライン構文、パラメータ、intypeファイルの構造、ネストした#includeファイルの生成、スキーマ名の使用方法、デフォルトの名前マッピングおよび制限事項を説明します。
OTTを使用するときの最初のステップは、オブジェクト型または名前付きコレクション型を作成してデータベースに格納することです。そのためには、SQLのCREATE TYPE文を使用します。
OTTを起動するステップは、次のとおりです。OTTパラメータは、コマンドラインで、または構成ファイルをコールしたファイルで指定できます。一部のパラメータは、intypeファイルでも指定できます。
1つのパラメータが複数箇所に指定されている場合は、コマンドラインのパラメータ値がintypeファイルの値より優先され、intypeファイルの値はユーザー定義の構成ファイルの値より優先され、ユーザー定義の構成ファイルの値は、デフォルトの構成ファイルの値より優先されます。
グローバル・オプション、つまり、コマンドライン上のオプションまたはすべてのTYPE文の前にあるintypeファイルの先頭にあるオプションの場合は、コマンドラインの値がintypeファイルの値より優先されます。(intypeファイルでグローバルに指定できるオプションは、CASE、CODE、INITFILEおよびINITFUNCです。HFILEは指定できません)。intypeファイルにTYPE指定で記述されているオプションは、特定の型のみに適用され、型に通常適用されるコマンドラインのオプションより優先されます。したがって、TYPE person HFILE=p.hと入力すると、この値はpersonのみに適用され、コマンドラインのHFILEより優先されます。この文はコマンドライン・パラメータとはみなされません。
構成ファイルは、OTTパラメータが入っているテキスト・ファイルです。ファイル内の非空白行には、1つのオプションと、それに対応付けられた1つ以上の値が入っています。1行に2つ以上のパラメータを指定した場合は、最初のパラメータのみが使用されます。 構成ファイルの非空白行では、空白は使用できません。
構成ファイルは、コマンドラインで名前を付けることができます。さらに、デフォルトの構成ファイルは常に読み取られます。このデフォルトの構成ファイルは常に存在している必要がありますが、空でもかまいません。デフォルトの構成ファイルの名前はottcfg.cfgであり、構成ファイルの位置はシステム固有の設定です。たとえば、Solarisでのファイル指定は、$ORACLE_HOME/precomp/admin/ottcfg.cfgです。詳細は、使用しているオペレーティング・システムのマニュアルを参照してください。
ほとんどのオペレーティング・システムでは、コマンドラインからOTTを起動します。入出力ファイルやデータベース接続情報などを指定できます。OTTの起動方法は、使用しているオペレーティング・システム固有のマニュアルを参照してください。
コマンドラインからOTTを起動する例を次に示します。
ott userid=bren intype=demoin.typ outtype=demoout.typ code=c \
hfile=demo.h initfile=demov.c
|
注意: 等号(=)の両側には空白を挿入しないでください。 |
次の各項では、この例で使用しているコマンドラインの要素を説明します。
outtypeファイルの名前を指定します。OTTでCヘッダー・ファイルを生成すると、変換された型の情報がouttypeファイルに書き込まれます。このファイルには、変換された各型のエントリが、バージョン文字列およびC表現を書き込んだヘッダー・ファイルとともに含まれています。
「OTTコマンドライン起動の例」では、outtypeファイルの名前がdemoout.typに指定されています。
|
注意: outtypeのキーワードで指定されたファイルがすでに存在している場合、そのファイルは、OTTが実行されると上書きされます。outtypeファイル名とintypeファイル名が同じ場合は、outtypeファイル内の情報でintypeファイルが上書きされます。 |
変換の目標言語を指定します。次のオプションがあります。
C(ANSI_Cと等価)
ANSI_C(ANSI C対応)
KR_C(Kernighan & Ritchie C対応)
現在はデフォルト・オプションがないため、このパラメータは必須です。
構造体の宣言は、両方のC言語において同一です。INITFILEファイルに定義されている初期化関数のスタイルは、KR_Cが使用されているかどうかによって異なります。INITFILE オプションが使用されていない場合、3つのオプションはすべて等価です。
生成された構造体を書き込むCヘッダー・ファイルの名前を指定します。
「OTTコマンドライン起動の例」では、生成される構造体はdemo.hと呼ばれるファイルに格納されます。
|
注意: hfileキーワードで指定されたファイルがすでに存在している場合、そのファイルは、次の例外を除いて、OTTが実行されると上書きされます。OTTによって生成されたファイルの内容が、そのファイルの前の内容と同一の場合、OTTはファイルへの実際の書込みは行いません。これにより、ファイルの変更時間を節約でき、LinuxおよびUNIXのmakeおよび他のオペレーティング・システムの類似した機能で、不必要な再コンパイルが実行されません。 |
intypeファイルは、OTTの実行時に変換するデータベース型をOTTに指示し、生成された構造体のネーミングも制御します。 intypeファイルは、ユーザー作成ファイルでも、前回OTTを起動したときのouttypeファイルでもかまいません。intypeパラメータが使用されていない場合は、OTTの接続先のスキーマにあるすべての型が変換されます。
簡単なユーザー作成intypeファイルの例を次に示します。
CASE=LOWER
TYPE employee
TRANSLATE SALARY$ AS salary
DEPTNO AS department
TYPE ADDRESS
TYPE item
TYPE "Person"
TYPE PURCHASE_ORDER AS p_o
第1行のCASEキーワードは、生成されたC識別子を小文字にすることを指示しています。ただし、このCASEオプションは、intypeファイルに明示的に記述されていない識別子にのみ適用されます。そのため、常にemployeeはemployee、ADDRESSはADDRESSというC構造体になります。これらの構造体のメンバーは、小文字で名前が付けられます。
TYPEキーワードで始まる行は、データベース内の変換する型を指定しています。この例では、EMPLOYEE、ADDRESS、ITEM、PERSONおよびPURCHASE_ORDERの各型が相当します。
TRANSLATE...ASキーワードは、オブジェクト型のC構造体への変換時に、オブジェクト属性の名前変更が必要なことを指定しています。この例では、employee型のSALARY$属性がsalaryに変換されます。
最終行のASキーワードは、オブジェクト型を構造体に変換するとき、名前を変更することを指定しています。この例では、purchase_orderというデータベース型をp_oという構造体に変換します。
ASキーワードが、型または属性の名前の変換に使用されていない場合は、その型または属性のデータベース名がC識別子名として使用されます。ただし、CASEオプションは有効のため、有効なC識別子文字にマップできない文字は、アンダースコアで置換されます。型または属性名を変換する理由は、次のとおりです。
名前に、アルファベット、数字またはアンダースコア以外の文字が含まれている
名前がCキーワードと競合する
型名が、同じ有効範囲内の別の識別子と競合する。 たとえば、プログラムで、異なるスキーマにある同じ名前の2つの型を使用する場合に発生します。
プログラマが別の名前に変更する
OTTでは、intypeファイルにリストされていない他の型の変換が必要になる場合があります。これは、OTTでは変換前にintypeファイル内の型の依存性が分析され、必要に応じてその他の型が変換されるためです。たとえば、ADDRESS型がintypeファイルにリストされていなくても、Person型がADDRESS型の属性を所有している場合、Person型の定義は必須のため、OTTは、ADDRESSを変換します。
TRANSITIVEパラメータの値としてFALSEを指定すると、OTTは、intypeファイルに指定されていない型は生成しません。
通常の大/小文字の区別がないSQL識別子は、intypeファイルでは、大/小文字のどのような組合せのつづりでもかまいません。引用符は付けません。
CREATE TYPE "Person"などの大/小文字を区別して作成したSQL識別子を参照するには、TYPE "Person"などの引用符を使用します。SQL識別子は、宣言の際に引用した場合は、大/小文字が区別されます。引用符は、TYPE "CASE"などのOTT予約語であるSQL識別子の参照にも使用できます。このために名前に引用符を付けるときは、そのSQL識別子がCREATE TYPE Caseのように大/小文字を区別せずに作成されている場合、その名前は大文字にする必要があります。OTT予約語がSQL識別子の名前参照用に使用されているが、引用符が付けられていない場合、OTTはintypeファイルに構文エラーをレポートします。
OTTでデータベース型から生成したC構造体には、オブジェクト型の属性ごとに1つずつ対応する要素が含まれています。属性のデータ型は、Oracleのオブジェクト・データ型で使用される型にマップされます。Oracleのデータ型には、事前定義済の基本型の集合が組み込まれており、オブジェクト型やコレクションなどのユーザー定義型の作成をサポートします。
また、Oracleには、オブジェクト型属性をC構造体で表現するための事前定義済の型の集合も含まれています。たとえば、次のようなオブジェクト型定義と、OTTで生成した対応する構造体宣言があるとします。
CREATE TYPE employee AS OBJECT
( name VARCHAR2(30),
empno NUMBER,
deptno NUMBER,
hiredate DATE,
salary$ NUMBER);
CASE=LOWERで、型または属性名の明示的なマッピングがないと仮定すると、OTT出力は次のようになります。
struct employee
{ OCIString * name;
OCINumber empno;
OCINumber department;
OCIDate hiredate;
OCINumber salary_;
};
typedef struct emp_type emp_type;
struct employee_ind
{
OCIInd _atomic;
OCIInd name;
OCIInd empno;
OCIInd department;
OCIInd hiredate;
OCIInd salary_;
}
typedef struct employee_ind employee_ind;
ここでは、構造体宣言のデータ型、OCIString、OCINumber、OCIDateおよびOCIIndを使用してオブジェクト型の属性のデータ型をマップしています。たとえば、empno属性のNUMBERデータ型は、OCINumberデータ型にマップされます。また、これらのデータ型は、バインド変数および定義変数の型としても使用できます。
この項では、Oracleのオブジェクト属性型とOTTで生成されるCの型とのマッピングを説明します。次の「OTT型マッピングの例」では、様々なマッピングの例を示します。次の表には、属性として使用できる型から、OTTで生成されるオブジェクト・データ型へのマッピングをリストします。
表15-1 オブジェクト型属性のオブジェクト・データ型マッピング
| オブジェクト属性の型 | Cマッピング |
|---|---|
|
|
OCIBFileLocator* |
|
BLOB |
OCILobLocator *またはOCIBlobLocator * |
|
CHAR(N)、CHARACTER(N)、NCHAR(N) |
OCIString * |
|
CLOB、NCLOB |
OCILobLocator *またはOCIClobLocator * |
|
DATE |
OCIDate |
|
ANSI DATE |
OCIDateTime * |
|
TIMESTAMP、TIMESTAMP WITH TIME ZONE、TIMESTAMP WITH LOCAL TIME ZONE |
OCIDateTime * |
|
INTERVAL YEAR TO MONTH、INTERVAL DAY TO SECOND |
OCIInterval * |
|
DEC、DEC(N)、DEC(N,N) |
OCINumber |
|
DECIMAL、DECIMAL(N)、DECIMAL(N,N) |
OCINumber |
|
FLOAT、FLOAT(N)、DOUBLE PRECISION |
OCINumber |
|
BINARY_FLOAT |
float |
|
BINARY_DOUBLE |
double |
|
INT、INTEGER、SMALLINT |
OCINumber |
|
ネストしたオブジェクト型 |
ネストしたオブジェクト型のCの名前 |
|
NESTED TABLE |
OCITable * |
|
NUMBER、NUMBER(N)、NUMBER(N,N) |
OCINumber |
|
NUMERIC、NUMERIC(N)、NUMERIC(N,N) |
OCINumber |
|
RAW(N) |
OCIRaw * |
|
REAL |
OCINumber |
|
REF |
OCIRef * |
|
VARCHAR(N) |
OCIString * |
|
VARCHAR2(N)、NVARCHAR2(N) |
OCIString * |
|
OCIArray * |
|
注意: REF、VARRAYおよびNESTED TABLE型の場合、OTTでは、typedefが生成されます。このtypedefで宣言された型は、構造体宣言でデータ・メンバーの型として使用されます。次の項「OTT型マッピングの例」を参照してください。 |
オブジェクト型にREFまたはコレクション型の属性が含まれている場合は、最初にREFまたはコレクション型のtypedefが生成されます。次に、オブジェクト型に対応する構造体宣言が生成されます。構造体には、REFまたはコレクション型へのポインタを型に持つ要素が含まれます。
あるオブジェクト型に、別のオブジェクト型を持つ属性が含まれている場合、OTTではネストした型が最初に生成されます(TRANSITIVE=TRUEの場合)。次に、オブジェクト型属性が、ネストしたオブジェクト型である型のネストした構造体にマッピングされます。
OTTがオブジェクト以外のデータベース属性の型をマップするOracleのCデータ型は構造体で、OCIDate以外は不透明です。
次の例では、OTTで作成される各種の型のマッピングを示します。
次のようなデータベース型があるとします。
CREATE TYPE my_varray AS VARRAY(5) of integer; CREATE TYPE object_type AS OBJECT (object_name VARCHAR2(20)); CREATE TYPE my_table AS TABLE OF object_type; CREATE TYPE other_type AS OBJECT (object_number NUMBER); CREATE TYPE many_types AS OBJECT ( the_varchar VARCHAR2(30), the_char CHAR(3), the_blob BLOB, the_clob CLOB, the_object object_type, another_ref REF other_type, the_ref REF many_types, the_varray my_varray, the_table my_table, the_date DATE, the_num NUMBER, the_raw RAW(255));
次のような内容のintypeファイルがあるとします。
CASE = LOWER TYPE many_types
OTTによって次のC構造体が生成されます。
|
注意: ここでは構造体についての補足説明として、コメントを付けています。これらのコメントは、実際のOTT出力の一部ではありません。 |
#ifndef MYFILENAME_ORACLE
#define MYFILENAME_ORACLE
#ifndef OCI_ORACLE
#include <oci.h>
#endif
typedef OCIRef many_types_ref;
typedef OCIRef object_type_ref;
typedef OCIArray my_varray; /* used in many_types */
typedef OCITable my_table; /* used in many_types*/
typedef OCIRef other_type_ref;
struct object_type /* used in many_types */
{
OCIString * object_name;
};
typedef struct object_type object_type;
struct object_type_ind /*indicator struct for*/
{ /*object_types*/
OCIInd _atomic;
OCIInd object_name;
};
typedef struct object_type_ind object_type_ind;
struct many_types
{
OCIString * the_varchar;
OCIString * the_char;
OCIBlobLocator * the_blob;
OCIClobLocator * the_clob;
struct object_type the_object;
other_type_ref * another_ref;
many_types_ref * the_ref;
my_varray * the_varray;
my_table * the_table;
OCIDate the_date;
OCINumber the_num;
OCIRaw * the_raw;
};
typedef struct many_types many_types;
struct many_types_ind /*indicator struct for*/
{ /*many_types*/
OCIInd _atomic;
OCIInd the_varchar;
OCIInd the_char;
OCIInd the_blob;
OCIInd the_clob;
struct object_type_ind the_object; /*nested*/
OCIInd another_ref;
OCIInd the_ref;
OCIInd the_varray;
OCIInd the_table;
OCIInd the_date;
OCIInd the_num;
OCIInd the_raw;
};
typedef struct many_types_ind many_types_ind;
#endif
intypeファイルでは変換対象として1つの項目しか指定していませんが、2つのオブジェクト型と2つの名前付きコレクション型が変換されていることに注意してください。これは、OTTパラメータTRANSITIVEのデフォルト値がTRUEのためです。前述の項で説明しているとおり、TRANSITIVE=TRUEの場合、OTTは、リストされている型の変換を完了するために、変換対象の型の属性に使用されている型をすべて自動的に変換します。
この自動変換は、オブジェクト型属性のポインタまたは参照によってのみアクセスされる型には適用されません。たとえば、many_types型には属性としてanother_ref REF other_typeがありますが、struct other_typeは生成されません。
この例では、VARRAY、NESTED TABLEおよびREFの各型を宣言するために、typedefがどのように使用されているかも示しています。
typedefは、始めに使用されます。
typedef OCIRef many_types_ref; typedef OCIRef object_type_ref; typedef OCIArray my_varray; typedef OCITable my_table; typedef OCIRef other_type_ref;
構造体many_typesでは、次のようにVARRAY、NESTED TABLEおよびREFの各属性が宣言されています。
struct many_types
{ ...
other_type_ref * another_ref;
many_types_ref * the_ref;
my_varray * the_varray;
my_table * the_table;
...
}
OTTでデータベース・オブジェクト・タイプを表現するC構造体が生成されるたびに、対応するNULLインジケータ構造体も生成されます。C構造体にオブジェクト型を選択するとき、パラレル構造体の中にNULLインジケータ情報を選択できます。
たとえば、前の項目の例では次のNULLインジケータ構造体が生成されます。
struct many_types_ind
{
OCIInd _atomic;
OCIInd the_varchar;
OCIInd the_char;
OCIInd the_blob;
OCIInd the_clob;
struct object_type_ind the_object;
OCIInd another_ref;
OCIInd the_ref;
OCIInd the_varray;
OCIInd the_table;
OCIInd the_date;
OCIInd the_num;
OCIInd the_raw;
};
typedef struct many_types_ind many_types_ind;
NULLインジケータ構造体のレイアウトは重要です。構造体の第1要素(_atomic)は、アトミックNULLインジケータです。この値は、オブジェクト型全体のNULL状態を示します。このアトミックNULLインジケータの後に、OTTで生成した、オブジェクト型を表現する構造体の各要素に対応するインジケータ要素が続きます。
あるオブジェクト型の定義の一部として別のオブジェクト型が含まれている場合(この例ではobject_type属性)、その属性のインジケータ・エントリは、ネストしたオブジェクト型(TRANSITIVE=TRUEの場合)に対応しているNULLインジケータ構造体(object_type_ind)です。
VARRAYとNESTED TABLEには、各要素のNULL情報が含まれています。
NULLインジケータ構造体のその他の要素のデータ型は、すべてOCIIndです。
オブジェクトの型の継承をサポートするために、OTTは、新しい属性を宣言する前に、継承される属性を、特別な名前_superを持つカプセル化された構造体内で宣言することで、オブジェクトのサブタイプを表すC構造体を生成します。これによって、スーパータイプを継承するオブジェクトのサブタイプについては、その構造体の第1要素が_superと命名され、サブタイプの各属性に対応する要素がその後に続きます。この_superと命名された要素の型がスーパータイプの名前です。
たとえば、サブタイプStudent_tとEmployee_tを持つPerson_t型は、次のように作成されます。
CREATE TYPE Person_t AS OBJECT ( ssn NUMBER, name VARCHAR2(30), address VARCHAR2(100)) NOT FINAL; CREATE TYPE Student_t UNDER Person_t ( deptid NUMBER, major VARCHAR2(30)) NOT FINAL; CREATE TYPE Employee_t UNDER Person_t ( empid NUMBER, mgr VARCHAR2(30));
次のような内容のintypeファイルがあるとします。
CASE=SAME TYPE EMPLOYEE_T TYPE STUDENT_T TYPE PERSON_T
OTTでは、Person_t、Student_tおよびEmployee_tに対するC構造体とそれぞれのNULLインジケータ構造体が次のように生成されます。
#ifndef MYFILENAME_ORACLE
#define MYFILENAME_ORACLE
#ifndef OCI_ORACLE
#include <oci.h>
#endif
typedef OCIRef EMPLOYEE_T_ref;
typedef OCIRef STUDENT_T_ref;
typedef OCIRef PERSON_T_ref;
struct PERSON_T
{
OCINumber SSN;
OCIString * NAME;
OCIString * ADDRESS;
};
typedef struct PERSON_T PERSON_T;
struct PERSON_T_ind
{
OCIInd _atomic;
OCIInd SSN;
OCIInd NAME;
OCIInd ADDRESS;
};
typedef struct PERSON_T_ind PERSON_T_ind;
struct EMPLOYEE_T
{
PERSON_T_ind;
OCINumber EMPID;
OCIString * MGR;
};
typedef struct EMPLOYEE_T EMPLOYEE_T;
struct EMPLOYEE_T_ind
{
PERSON_T _super;
OCIInd EMPID;
OCIInd MGR;
};
typedef struct EMPLOYEE_T_ind EMPLOYEE_T_ind;
struct STUDENT_T
{
PERSON_T _super;
OCINumber DEPTID;
OCIString * MAJOR;
};
typedef struct STUDENT_T STUDENT_T;
struct STUDENT_T_ind
{
PERSON_T _super;
OCIInd DEPTID;
OCIInd MAJOR;
};
typedef struct STUDENT_T_ind STUDENT_T_ind;
#endif
前述のCマッピング変換によって、サブタイプのインスタンスからCのスーパータイプのインスタンスへのアップキャストが簡単かつ適切に行われます。たとえば、次のようにします。
STUDENT_T *stu_ptr = some_ptr; /* some STUDENT_T instance */ PERSON_T *pers_ptr = (PERSON_T *)stu_ptr; /* up-casting */
NULLインジケータ構造体も同じように生成されます。スーパータイプPerson_tのNULLインジケータ構造体の第1要素は、_atomicです。サブタイプEmployee_tとStudent_tのNULLインジケータ構造体の第1要素は、_superです(サブタイプに対するアトミック要素は生成されません)。
NOT FINAL型の属性(つまり置換可能な属性)の場合、埋込み属性は、ポインタとして表現されます。
次のBook_t型を想定します。
CREATE TYPE Book_t AS OBJECT ( title VARCHAR2(30), author Person_t /* substitutable */);
OTTで生成された対応するC構造体には、Person_tへのポインタが含まれています。
struct Book_t
{
OCIString *title;
Person_t *author; /* pointer to Person_t struct */
}
この型に対応するNULLインジケータ構造体は、次のとおりです。
struct Book_t_ind
{
OCIInd _atomic;
OCIInd title;
OCIInd author;
}
author属性に対応するNULLインジケータ構造体は、authorオブジェクト自体から取得できます。「OCIObjectGetInd()」を参照してください。
FINALとして定義されている型は、サブタイプを持つことができません。したがって、FINAL型の属性は、置換可能ではありません。この場合、マッピングは前の状態のままです。つまり、属性の構造体はインラインです。ここで、型を変更し、NOT FINALとして定義すると、マッピングの変更が必要になります。OTTを再実行することで、新しいマッピングが生成されます。
outtypeファイルは、OTTコマンドラインで名前が付けられます。OTTでCヘッダー・ファイルが生成されると、変換の結果がouttypeファイルに書き込まれます。このファイルには、変換された各型のエントリが、バージョン文字列およびC表現を書き込んだヘッダー・ファイルとともに含まれています。
OTTの1回の実行で生成されたouttypeファイルは、それ以降のOTTの起動ではintypeファイルとして使用できます。
たとえば、この章の前半の例で使用した単純なintypeファイルを想定します。
CASE=LOWER
TYPE employee
TRANSLATE SALARY$ AS salary
DEPTNO AS department
TYPE ADDRESS
TYPE item
TYPE "Person"
TYPE PURCHASE_ORDER AS p_o
この例では、OTTで生成するC識別子の大/小文字の区別を指定し、変換する型をリストして指定しています。そのうち2つの型については、ネーミング規則が指定されています。
OTT実行後のouttypeファイルは、次のようになります。
CASE = LOWER
TYPE EMPLOYEE AS employee
VERSION = "$8.0"
HFILE = demo.h
TRANSLATE SALARY$ AS salary
DEPTNO AS department
TYPE ADDRESS AS ADDRESS
VERSION = "$8.0"
HFILE = demo.h
TYPE ITEM AS item
VERSION = "$8.0"
HFILE = demo.h
TYPE "Person" AS Person
VERSION = "$8.0"
HFILE = demo.h
TYPE PURCHASE_ORDER AS p_o
VERSION = "$8.0"
HFILE = demo.h
outtypeファイルの内容を調べると、intype指定に含まれていなかった型がリストされていることに気づきます。たとえば、intypeファイルでは、次の内容によるperson型の変換のみを指定したとします。
CASE = LOWER TYPE PERSON
このperson型の定義にaddress型の属性が含まれている場合、outtypeファイルには、PERSONとADDRESSの両方のエントリが含まれます。person型を完全に変換するには、最初にaddressを変換する必要があります。
パラメータTRANSITIVEがTRUEに設定されている(デフォルトの)場合、OTTは、変換を実行する前にintypeファイル内の型の依存性を分析してから、必要に応じて他の型を変換します。
OTTで生成したCヘッダー・ファイルと実装ファイルは、Oracleサーバー内のオブジェクトにアクセスするOCIアプリケーションで使用できます。ヘッダー・ファイルは、#include文でOCIコードに取り込みます。
OCIアプリケーションでは、ヘッダー・ファイルを組み込んだ後、ホスト言語形式のオブジェクト・データにアクセスし、操作できます。
図15-1「OCIアプリケーションでのOTTの使用方法」は、最も単純なアプリケーションのOCIでOTTを使用する場合のステップを示しています。
SQLを使用してデータベースに型定義を作成します。
OTTで、オブジェクト型と名前付きコレクション型のC表現を含むヘッダー・ファイルを生成します。INITFILEオプションで命名された実装ファイルも生成します。
アプリケーションを記述します。OCIアプリケーションでユーザーが記述したコードで、INITFUNC関数を宣言してコールします。
ヘッダー・ファイルをOCIソース・コード・ファイルにインクルードします。
OTTで生成された実装ファイルを含めて、OCIアプリケーションがコンパイルされ、OCIライブラリにリンクされます。
OCI実行可能ファイルをOracleサーバーに対して実行します。
アプリケーション内部では、OCIプログラムでバインド操作と定義操作を実行できます。そのためには、OTTで生成したヘッダー・ファイルに示されている型で宣言したプログラム変数を使用します。
たとえば、アプリケーションでSQLのSELECT文を使用して、オブジェクトへのREFをフェッチし、適切なOCI関数を使用してそのオブジェクトを確保します。オブジェクトを確保した後、その他のOCI関数を使用してそのオブジェクトの属性データにアクセスし、操作できます。
OCIには、オブジェクト型の属性と名前付きコレクション型で操作するために特別に設計された、一連のデータ型マッピング関数および操作関数が組み込まれています。
使用可能な関数の例を次に示します。
OCIStringSize()は、OCIString文字列のサイズを取得します。
OCINumberAdd()は、2つのOCINumberの数値を加算します。
OCILobIsEqual()は、2つのLOBロケータが等しいかどうかを比較します。
OCIRawPtr()は、ロー・データ型OCIRawへのポインタを取得します。
OCICollAppend()は、コレクション型(OCIArrayまたはOCITable)に要素を追加します。
OCITableFirst()は、ネストした表(OCITable)の最初の既存要素の索引を戻します。
OCIRefIsNull()は、REF(OCIRef)がNULLかどうかをテストします。
これらの関数の詳細は、このマニュアルの他の章を参照してください。
OTTは、必要に応じてC初期化関数を生成します。初期化関数では、プログラムで使用されている各オブジェクト型について、どのバージョンの型が使用されているかを環境に通知します。 INITFUNCオプションでOTTを起動する場合は、初期化関数の名前を指定するか、初期化関数が含まれている実装ファイル(INITFILE)の名前に基づいてデフォルト名を選択できます。
初期化関数には、環境ハンドル・ポインタとエラー・ハンドル・ポインタの2つの引数があります。一般的に、使用する初期化関数は1つですが、必ずしもそうである必要はありません。プログラムにコンパイル済の個別のピースがあり、異なる型を要求する場合は、各ピースに対して初期化関数が含まれた1つの初期化ファイルをそれぞれ要求して、OTTを個別に実行できます。
たとえば、OCIEnvCreate()をコールして、明示的なOCIオブジェクト・コールによって環境ハンドルを作成した後は、初期化関数も明示的にコールする必要があります。明示的に作成した環境ハンドルそれぞれに対して、必ずすべての初期化関数をコールする必要があります。これによって、各ハンドルは、プログラム全体で使用しているすべてのOracleデータ型にアクセスできます。
EXEC SQL CONTEXT USEやEXEC SQL CONNECTなどの埋込みSQL文を使用して環境ハンドルを暗黙的に作成する場合、ハンドルは暗黙的に初期化されるため、初期化関数をコールする必要はありません。これは、Pro*C/C++をOCIアプリケーションと結合している場合にのみ適用します。
次に、初期化関数の例を示します。
intypeファイルのex2c.typに次の内容が含まれているとします。
TYPE BREN.PERSON TYPE BREN.ADDRESS
さらに、次のコマンドラインが含まれているとします。
ott userid=bren intype=ex2c outtype=ex2co hfile=ex2ch.h initfile=ex2cv.c
OTTでは、次のファイルex2cv.cが生成されます。
#ifndef OCI_ORACLE
#include <oci.h>
#endif
sword ex2cv(OCIEnv *env, OCIError *err)
{
sword status = OCITypeVTInit(env, err);
if (status == OCI_SUCCESS)
status = OCITypeVTInsert(env, err,
"BREN", 5,
"PERSON", 6,
"$8.0", 4);
if (status == OCI_SUCCESS)
status = OCITypeVTInsert(env, err,
"BREN", 5,
"ADDRESS", 7,
"$8.0", 4);
return status;
}
関数ex2cvによって、型バージョン表が作成され、BREN.PERSON型とBREN.ADDRESS型が挿入されます。
プログラムで明示的に環境ハンドルを作成する場合、明示的に作成するハンドルごとに初期化関数をコールする必要があるので、すべての初期化関数を生成し、コンパイルし、リンクしてください。プログラムが明示的に環境ハンドルを作成しない場合、初期化関数は必要ありません。
OTTで生成したヘッダー・ファイルを使用するプログラムでは、同時に生成された初期化関数も使用する必要があります。OTTでヘッダー・ファイルを生成し、プログラムで環境ハンドルを明示的に作成した場合は、実装ファイルもコンパイルして、実行可能ファイルにリンクする必要があります。
C初期化関数は、OTTで処理する型のバージョン情報を提供します。C初期化関数は、OTTで処理する各オブジェクト・データ型の名前とバージョン識別子を型バージョン表に追加します。
型バージョン表は、Oracleの型マネージャが、特定のプログラムで使用する型のバージョンを特定するときに使用します。 異なる時期にOTTで生成した異なる複数の初期化関数によって、型バージョン表に同じ型が複数回追加される可能性があります。型が複数回追加される場合、毎回同じバージョンの型が確実に登録されるようにします。
初期化関数に対して関数プロトタイプを宣言し、その関数をコールするのは、OCIプログラマの役割です。
|
注意: Oracleのカレント・リリースでは、型ごとにバージョンは1つのみです。型バージョン表の初期化は、Oracleの今後のリリースとの互換性を保つためにのみ必要です。 |
OTTの動作は、OTTコマンドラインまたはCONFIGファイルに指定するパラメータによって制御します。 また、一部のパラメータは、intypeファイルにも指定できます。
この項では、次の項目について詳しく説明します。
この章では、次の規則を使用してOTTの構文を説明します。
イタリックの文字列は、ユーザーが指定する変数またはパラメータです。
大文字の文字列は、そのとおりに入力する文字列です。ただし、大/小文字は区別されないため、小文字で入力しても有効です。
OTTキーワードは、例やヘッダーでは小文字の固定幅フォントでリストされていますが、本文では、目立つように大文字で印刷されています。
大カッコ[...]で囲んだ項目は、オプション項目です。
1つの項目(あるいはカッコで囲まれた複数の項目)の直後の省略記号(...)は、その項目を何度も繰り返し指定できることを示します。
これ以外の句読点記号は、示されているとおりに入力します。「.」や「@」などが含まれます。
OTTコマンドライン・インタフェースは、OTTを明示的に起動してデータベース型をC構造体に変換するときに使用します。オブジェクトを使用するOCIアプリケーションを開発する場合は、必ずこのインタフェースが必要です。
OTTコマンドライン文は、キーワードOTTと、その後に続くOTTパラメータのリストによって構成されます。
OTTコマンドライン文に指定できるパラメータは、次のとおりです。
[userid=username/password[@db_name]] [intype=in_filename] outtype=out_filename code=C|ANSI_C|KR_C [hfile=filename] [errtype=filename] [config=filename] [initfile=filename] [initfunc=filename] [case=SAME|LOWER|UPPER|OPPOSITE] [schema_name=ALWAYS|IF_NEEDED|FROM_INTYPE] [transitive=TRUE|FALSE] [URL=url]
|
注意: 一般に、 OTTコマンドの後に続くパラメータの順序は重要ではありません。ただし、OUTTYPEおよびCODEの各パラメータは常に必須です。 |
HFILEパラメータは、ほとんどの場合に使用されます。省略すると、HFILEをintypeファイルの型ごとに個別に指定する必要があります。OTTでは、intypeファイルにリストされていない型を変換する必要があると判断すると、エラーをレポートします。したがって、HFILEパラメータを省略できるのは、INTYPEファイルが以前にOTT OUTTYPEファイルとして生成された場合にかぎります。
intypeファイルを省略すると、スキーマ全体が変換されます。詳細は、この次の項でパラメータの説明を参照してください。
OTTコマンドライン文の例を次に示します(パスワードの入力を求められます)。
OTT userid=marc intype=in.typ outtype=out.typ code=c hfile=demo.h\ errtype=demo.tls case=lower
OTTコマンドラインの各パラメータについては、この後の各項で説明します。
OTTコマンドラインにパラメータを入力するときの書式は、次のとおりです。
parameter=value
parameterはリテラル・パラメータ文字列であり、valueは有効なパラメータ設定値です。リテラル・パラメータ文字列は大/小文字を区別しません。
コマンドラインのパラメータは、空白またはタブのいずれかを使用して区切ります。
パラメータは構成ファイル内にも指定できます。ただし、この場合は、行内の空白は許可されないため、各パラメータは独立した行に指定する必要があります。さらに、パラメータCASE、HFILE、INITFUNCおよびINITFILEをintypeファイルに指定できます。
USERIDパラメータでは、Oracleユーザー名、パスワードおよびオプションのデータベース名(Oracle Net Servicesのデータベース指定文字列)を指定します。データベース名を省略すると、デフォルトのデータベースが使用されます。このパラメータの構文は、次のとおりです。
userid=username/password[@db_name]
USERIDパラメータはオプションです。これが省略されると、OTTは、ユーザーOPS$usernameで自動的にデフォルトのデータベースへの接続を試行します。usernameは、オペレーティング・システムのユーザー名です。 これが第1パラメータである場合は、「USERID=」、パスワードおよびデータベース名を省略して、次のように指定できます。
OTT username ...
セキュリティ上の問題から、ユーザー名を入力するときのみ残りの項目を入力するよう求められます。
INTYPEパラメータでは、オブジェクト型指定のリストの読取り元ファイルの名前を指定します。読み取ったリストにある型が、OTTによって変換されます。
このパラメータの構文は、次のとおりです。
intype=filename
"USERIDが第1パラメータ、INTYPEが第2パラメータで、USERID=を省略した場合は、INTYPE=も省略できます。INTYPEが指定されていない場合は、ユーザーのスキーマの型すべてが変換されます。
OTT username filename...
intypeファイルは、型宣言のMakefileと考えることができます。C構造体宣言の必要な型をintypeファイルにリストします。
コマンドラインまたはintypeファイルのファイル名に拡張子がない場合は、「TYP」や「.typ」などのオペレーティング・システム固有の拡張子が追加されます。
OTTで処理されるすべてのオブジェクト・データ型の型情報を書き込むファイルの名前です。 outtypeファイルには、intypeファイルで明示的に指定したすべての型が含まれます。それに加えて、変換の対象である他の型の宣言で使用しているために変換された型も含まれます(TRANSITIVE=TRUEの場合)。 outtypeファイルは、以後OTTを起動するときにintypeファイルとして使用する必要があります。
outtype=filename
INTYPEパラメータとOUTTYPEパラメータが同一のファイルを参照している場合、intypeファイルの古い情報は、新しいINTYPEの情報に置き換えられます。これは、型の変更から開始し、型宣言の生成、ソースコードの編集、プリコンパイル、コンパイル、デバッグに至るサイクルで、同一のintypeファイルを繰り返し使用するときに便利です。
OUTTYPEは必ず指定してください。
コマンドラインまたはintypeファイルのファイル名に拡張子がない場合は、「TYP」や「.typ」などのオペレーティング・システム固有の拡張子が追加されます。
CODE=C、CODE=KR_CまたはCODE=ANSI_Cとして指定されるOTT出力の目的ホスト言語です。「CODE=C」は、「CODE=ANSI_C」と等価です。
CODE=C|KR_C|ANSI_C
このパラメータは、デフォルト値がないので必ず指定する必要があります。
INITFILEパラメータでは、OTTで生成した初期化ファイルを書き込むファイルの名前を指定します。このパラメータを省略すると、初期化関数は生成されません。
Pro*C/C++プログラムの場合、必要な初期化はSQLLIBランタイム・ライブラリによって実行されるため、INITFILEは不要です。OCIプログラムのユーザーは、INITFILEファイルをコンパイルおよびリンクし、環境ハンドルの作成時に初期化関数をコールする必要があります。
コマンドラインまたはintypeファイルで指定したINITFILEファイル名に拡張子がない場合は、「C」や「.c」などのオペレーティング・システム固有の拡張子が追加されます。
initfile=filename
INITFUNCパラメータは、OCIプログラムのみで使用します。OTTで生成する初期化関数の名前を指定します。このパラメータを省略すると、INITFILEの名前から初期化関数の名前が付けられます。
initfunc=filename
インクルード(.h)ファイルの名前を指定します。これは、intypeファイルで、型を記述して型のインクルード・ファイルを指定していない場合に、その型を宣言するためにOTTによって生成されるインクルード・ファイルです。intypeファイルで各型のインクルード・ファイルを個々に指定していない場合、このパラメータは必須です。このパラメータは、intypeファイルに記述されていない型が他の型で必要なために生成する場合、これらの他の型が2つ以上の異なるファイルで宣言されている場合およびTRANSITIVE=TRUEの場合も必須です。
コマンドラインまたはintypeファイルで指定したHFILEファイル名に拡張子がない場合は、「H」や「.h」などのオペレーティング・システム固有の拡張子が追加されます。
hfile=filename
CONFIGパラメータでは、共通で使用するパラメータ指定をリストしたOTT構成ファイルの名前を指定します。また、パラメータ指定は、オペレーティング・システムによって異なる位置にあるシステム構成ファイルから読み取られます。残りのすべてのパラメータ指定は、コマンドラインまたはintypeファイルで指定する必要があります。
config=filename
|
注意: CONFIGパラメータは、CONFIGファイルでは使用できません。 |
このパラメータを指定すると、intypeファイルのリストが、すべての情報メッセージおよびエラー・メッセージとともにERRTYPEファイルに書き込まれます。情報メッセージおよびエラー・メッセージは、ERRTYPEを指定したかどうかに関係なく、標準出力に送信されます。
実質的に、ERRTYPEファイルはエラー・メッセージが追加されたintypeファイルのコピーです。ほとんどの場合、エラー・メッセージにはエラーの原因となったテキストへのポインタが示されます。
コマンドラインまたはINTYPEファイルで指定したERRTYPEファイル名に拡張子がない場合は、「TLS」や「.tls」などのオペレーティング・システム固有の拡張子が追加されます。
errtype=filename
このパラメータは、OTTで生成する一部のC識別子の大/小文字の区別に影響を与えます。CASEの可能な値は、SAME、LOWER、UPPERおよびOPPOSITEです。CASE = SAMEの場合は、データベース型と属性名をC識別子に変換するときに、大/小文字は変更されません。CASE=LOWERの場合、大文字はすべて小文字に変換されます。CASE=UPPERの場合、小文字はすべて大文字に変換されます。CASE=OPPOSITEの場合、大文字はすべて小文字に変換され、小文字はすべて大文字に変換されます。
CASE=[SAME|LOWER|UPPER|OPPOSITE]
このオプションは、intypeファイルに記述されていない識別子(明示的にリストされていない属性または型)のみに影響を与えます。大/小文字の変換は、正当な識別子が生成された後で行われます。
INTYPEオプションで指定した型のC構造体識別子の大/小文字は、intypeファイルの大/小文字と同じです。たとえば、intypeファイルに次の行が含まれるとします。
TYPE Worker
OTTでは次のように生成されます。
struct Worker {...};
一方で、intypeファイルに次のように記述したとします。
TYPE wOrKeR
OTTでは次のように生成されます。
struct wOrKeR {...};
これはintypeファイルの大/小文字区別どおりです。
intypeファイルに記述されていない、大/小文字の区別のないSQL識別子は、CASE=SAMEの場合は大文字で、CASE=OPPOSITEの場合は小文字で指定されます。宣言されるとき引用符が付けられていないSQL識別子の場合、大/小文字の区別はありません。
デフォルト・スキーマに基づいた型のデータベース名を、outtypeファイル内のスキーマ名で修飾する場合は、このオプションで制御できます。OTTで生成したouttypeファイルには、型名も含めて、OTTで処理された型の情報が含まれています。
TRUE(デフォルト)またはFALSEの値を取得します。intypeファイルで明示的にリストされていない型の依存性が変換対象かどうかを示します。
TRANSITIVE=TRUEが指定されている場合は、他の型で必要でintypeファイルで記述されていない型が生成されます。
TRANSITIVE=FALSEが指定されている場合は、intypeファイルに指定されていない型は生成されません。生成した他の型の属性型として使用されている場合でも生成されません。
OTTでは、JavaインタフェースであるJDBC(Java Database Connectivity)を使用してデータベースに接続します。URLパラメータのデフォルト値は次のとおりです。
URL=jdbc:oracle:oci8:@
OCI8ドライバは、Oracleのインストールでクライアント側で使用します。シン・ドライバ(Oracleをインストールしない場合にクライアント側で使用するJavaドライバ)は、次のように指定します。
URL=jdbc:oracle:thin:@host:port:sid
hostはデータベースが実行されているホストの名前、portはポート番号、sidはOracle SIDです。
OTTパラメータは、コマンドラインまたはコマンドラインで名前が付けられたCONFIGファイル、あるいはその両方で指定できます。パラメータの一部は、intypeファイルでも指定できます。
OTTは、次のように起動します。
OTT username/password parameters
コマンドラインのパラメータの1つが次のパラメータであるとします。
config=filename
構成ファイルfilenameからその他のパラメータが読み取られます。
さらに、パラメータは、オペレーティング・システムによって異なる位置にあるデフォルトの構成ファイルから読み取られます。このファイルの存在は必要ですが、空でもかまいません。構成ファイルのパラメータは、スペースなしで、1行につき1つ表示してください。
引数を指定せずにOTTを実行すると、オンライン・パラメータ・リファレンスが表示されます。
変換されるOTTの型は、INTYPEパラメータで指定したファイルで命名されます。 パラメータCASE、INITFILE、INITFUNCおよびHFILEは、intypeファイルにも指定できます。OTTで生成したouttypeファイルにはCASEパラメータを含めることができ、初期化ファイルが生成されている場合は、INITFILEとINITFUNCの各パラメータを含めることができます。outtype ファイルでは、型ごとにそれぞれHFILEを指定します。
OTTコマンドの大/小文字区別は、オペレーティング・システムによって異なります。
intypeおよびouttypeファイルは、OTTで変換する型をリストし、型名や属性名を有効なC識別子に変換する方法を判断するのに必要な情報すべてを提供します。これらのファイルには、1つ以上の型指定を記述します。 また、次のオプションを指定する場合もあります。
CASE
HFILE
INITFILE
INITFUNC
CASE、INITFILEまたはINITFUNCの各オプションを指定する場合は、すべての型指定よりも前に指定する必要があります。これらのオプションをコマンドラインとintypeファイルの両方に指定した場合は、コマンドラインの値が使用されます。
INTYPEでの型指定によって、変換対象のオブジェクト・データ型の名前が指定されます。また、outtypeでの型指定によって、変換済のオブジェクト・データ型の名前が指定されます。
TYPE employee
TRANSLATE SALARY$ AS salary
DEPTNO AS department
TYPE ADDRESS
TYPE PURCHASE_ORDER AS p_o
型指定の構造体は次のとおりです。[]内の値は、オプションの入力を示します。
TYPE type_name [AS type_identifier] [VERSION [=] version_string] [HFILE [=] hfile_name] [TRANSLATE{member_name [AS identifier]}...]
type_nameの構文は次のとおりです。
[schema_name.]type_name
schema_nameは、指定のオブジェクト・データ型を所有するスキーマの名前です。type_nameは、その型の名前です。デフォルト・スキーマは、OTTを実行するユーザーのデフォルト・スキーマです。デフォルト・データベースは、ローカル・データベースです。
型指定の構成要素を次に説明します。
type_name− オブジェクト・データ型の名前です。
type_identifier− 型を表すのに使用するC識別子です。省略すると、デフォルトの名前マッピング・アルゴリズムが使用されます。
version_string−OTTの前の起動によるコード生成時に使用した型のバージョン文字列です。 バージョン文字列は、OTTによって生成され、outtypeファイルに書き込まれます。このファイルは、後でOTTを実行するときにintypeファイルとして使用できます。バージョンの文字列はOTTの操作に影響を与えませんが、最終的には実行中のプログラムで使用されるオブジェクト・データ型のバージョンを選択するのに使用されます。
type_identifier− 型を表すのに使用するC識別子です。省略すると、デフォルトの型マッピング・アルゴリズムが使用されます。
hfile_name− 該当する構造体の宣言またはクラスが現れるヘッダー・ファイルの名前です。hfile_nameを省略すると、宣言の生成時には、コマンドラインのHFILEパラメータで指定したファイルが使用されます。
member_name− 次のidentifierに変換される属性(データ番号)の名前です。
identifier− ユーザーのプログラムで属性を表現するC識別子です。 識別子は、任意の数の属性に対してこの方法で指定できます。指定していない属性については、デフォルトの名前マッピング・アルゴリズムが使用されます。
オブジェクト・データ型は、次のいずれかの場合に変換する必要があります。
intypeファイルに指定されています。
変換が必要な別の型を宣言する場合、およびTRANSITIVE=TRUEの場合は必須です。
明示的に記述していない型があり、その型が、正確に1つのファイルのみに宣言した型で必要だとします。この場合、明示的に記述していない型の変換結果は、それを必要とする明示的に宣言した型と同じファイルに書き込まれます。
明示的に記述していない型が、複数の異なるファイルの型の宣言に必要な場合、この必須の型の変換結果は、グローバルなHFILEファイルに書き込まれます。
OTTで生成した各HFILEファイルに、他の必要なファイルを#includesで組み込み、ファイル名から構成された記号を#definesで定義します。この記号は、HFILEがすでに組み込まれているかどうかを判断するために使用できます。たとえば、データベースに次の型があるとします。
create type px1 AS OBJECT (col1 number, col2 integer); create type px2 AS OBJECT (col1 px1); create type px3 AS OBJECT (col1 px1);
intypeファイルに含まれる情報は次のとおりです。
CASE=lower type pxl hfile tott95a.h type px3 hfile tott95b.h
次のようにしてOTTを起動します。
ott scott tott95i.typ outtype=tott95o.typ code=c
この場合、次の2つのヘッダー・ファイルが生成されます。
ファイルtott95b.hは次のとおりです。
#ifndef TOTT95B_ORACLE
#define TOTT95B_ORACLE
#ifndef OCI_ORACLE
#include <oci.h>
#endif
#ifndef TOTT95A_ORACLE
#include "tott95a.h"
#endif
typedef OCIRef px3_ref;
struct px3
{
struct px1 col1;
};
typedef struct px3 px3;
struct px3_ind
{
OCIInd _atomic;
struct px1_ind col1
};
typedef struct px3_ind px3_ind;
#endif
ファイルtott95a.hは次のとおりです。
#ifndef TOTT95A_ORACLE
#define TOTT95A_ORACLE
#ifndef OCI_ORACLE
#include <oci.h>
#endif
typedef OCIRef px1_ref;
struct px1
{
OCINumber col1;
OCINumber col2;
}
typedef struct px1 px1;
struct px1_ind
{
OCIInd _atomic;
OCIInd col1;
OCIInd col2;
}
typedef struct px1_ind px1_ind;
#endif
このファイルでは、TOTT95B_ORACLEという記号を最初に定義しています。そのため、プログラマは、次の構造体を使用してtott95b.hを条件付きで組み込むことができます。その場合、tott95b.hがインクルード・ファイルに依存しているかどうかを考慮する必要はありません。
#ifndef TOTT95B_ORACLE #include "tott95b.h" #endif
この方法によって、プログラマは、適当なファイル(たとえばfoo.h)からtott95b.hを組み込むことができます。その際、tott95b.hが、foo.hに組み込まれるその他のファイルにも組み込まれるかどうかは、わかっていなくてもかまいません。
記号TOTT95B_ORACLEの定義の後に、ファイルoci.hが#includedによって組み込まれています。oci.hは、OTTで生成したすべてのHFILEに組み込まれます。oci.hには、Pro*C/C++またはOCIのプログラマにとって便利な型と関数の宣言が格納されています。OTTの#includeで山カッコが使用されるのは、この場合のみです。
次に、ファイルtott95a.hを組み込みます。このファイルを組み込む理由は、tott95b.hに必要な「struct px1」の宣言が入っているからです。ユーザーのintypeファイルで、1つ以上のファイルに型宣言を書き込むように要求すると、OTTでは、他のファイルのうちどれを各HFILEに組み込むかを判断し、必要な#includesを生成します。
このOTTの#includeで、引用符が使用されていることに注意してください。tott95b.hを組み込むプログラムをコンパイルするとき、tott95a.hの検索は、ソース・プログラムが検出された場所から始まり、それ以降は実装定義の検索規則に従います。この方法でtott95a.hを検索できない場合、intypeファイルでtott95a.hの位置を指定するには、完全なファイル名(/で始まるLinuxまたはUNIXの絶対パス名など)を使用する必要があります。
このパラメータは、OTTが接続されたデフォルト・スキーマに基づいて付けた型の名前を、outtypeファイル内のスキーマ名で修飾するかどうかを決定します。
デフォルト・スキーマ以外のスキーマに基づいて付けた型の名前は、常にouttypeファイル内のスキーマ名で修飾されます。
スキーマ名で修飾するかしないかで、プログラム実行中に型がどのスキーマで検索されるかが決定します。
次の3通りの設定があります。
schema_names=ALWAYS (デフォルト)
outtypeファイル内のすべての型名をスキーマ名で修飾します。
schema_names=IF_NEEDED
デフォルト・スキーマに所属しているOUTTYPEファイル内の型名はスキーマ名で修飾しません。デフォルト・スキーマ以外のスキーマに属する型名は、スキーマ名で修飾します。
schema_names=FROM_INTYPE
intypeファイルに記述されている型は、intypeファイル内のスキーマ名で修飾されている場合のみ、OUTTYPEファイル内のスキーマ名で修飾します。デフォルト・スキーマに所属している型のうち、intypeファイルで記述されていない型を、型の依存性のために生成する必要がある場合があります。このような型は、その型に依存している、OTTで最初に検出された型がスキーマ名で記述されている場合にのみ、スキーマ名で記述されます。ただし、OTTが接続されたデフォルト・スキーマにない型は、常に明示的に指定したスキーマ名で記述されます。
OTTで生成するouttypeファイルは、Pro*C/C++への入力パラメータです。Pro*C/C++の観点からいえば、これはPro*C/C++のintypeファイルです。このファイルは、データベース型名をC構造体名と対応付けます。この情報は、構造体内で正しいデータベース型が確実に選択されるようにするために、実行時に使用されます。outtypeファイル(Pro*C/C++のintypeファイル)内のスキーマ名で型が指定されている場合、その型は、プログラム実行中に名前付きスキーマ内で検索されます。 型がスキーマ名なしで指定される場合、プログラムが接続されているデフォルト・スキーマ内で検索されます。デフォルト・スキーマは、OTTが使用するデフォルト・スキーマと異なる場合があります。
SCHEMA_NAMESにFROM_INTYPEを設定し、intypeファイルで読み取ります。
TYPE Person TYPE david.Dept TYPE sam.Company
OTTで生成した構造体を使用して、Pro*C/C++アプリケーションでsam.Company、david.DeptおよびPersonの各型を使用します。スキーマ名のないPersonを使用して、アプリケーションを接続するスキーマのPerson型を表します。
OTTとアプリケーションの両方がスキーマdavidに接続する場合、アプリケーションは、OTTが使用した型と同じ型(david.Person)を使用します。OTTがスキーマdavidに接続し、アプリケーションがスキーマjanaに接続している場合、アプリケーションでは、jana.Person型を使用します。この動作が有効なのは、スキーマdavidとスキーマjanaで同じCREATE TYPE Person文が実行された場合のみです。
一方、アプリケーションでは、どのスキーマに接続するかに関係なくdavid.Dept型を使用します。この場合、intypeファイルに型名とともにスキーマ名を記述する必要があります。
明示的に指定していない型が、OTTによって変換される場合があります。たとえば、次のSQL宣言があるとします。
CREATE TYPE Address AS OBJECT ( street VARCHAR2(40), city VARCHAR(30), state CHAR(2), zip_code CHAR(10) ); CREATE TYPE Person AS OBJECT ( name CHAR(20), age NUMBER, addr ADDRESS );
OTTがスキーマdavidに接続され、SCHEMA_NAMES=FROM_INTYPEが指定されて、ユーザーのintypeファイルに次のいずれかが組み込まれているとします。
TYPE Person or TYPE david.Person
ただし、david.Address型は記述されていません。この型は、david.Person型でネストしたオブジェクトの型として使用されます。intypeファイルにTYPE david.Personを記述してある場合は、TYPE david.PersonおよびTYPE david.Addressがouttypeファイルに記述されます。intypeファイルにType Personを記述してある場合は、TYPE PersonおよびTYPE Addressがouttypeファイルに記述されます。
OTTで変換された複数の型にdavid.Address型が埋め込まれていても、intypeファイルに明示的に記述されていない場合、スキーマ名を使用するかどうかは、埋め込まれているdavid.Address型がOTTで最初に検出された時点で決まります。なんらかの理由で、david.Addressにはスキーマ名を付け、一方のPerson型には付けない場合、ユーザーは明示的に次の内容を要求する必要があります。
TYPE david.Address
これは、intypeファイルで指定します。
各型を単一のスキーマ内に宣言する通常の場合は、すべての型名をintypeファイル内のスキーマ名で修飾するのが最も安全です。
OTTでオブジェクト型または属性のC識別子名を作成する場合、OTTは、その名前をデータベース・キャラクタ・セットから有効なC識別子に変換します。最初に、名前はデータベース・キャラクタ・セットからOTTで使用するキャラクタ・セットに変換されます。次に、その変換された名前の変換内容がintypeファイルに指定されている場合は、intypeファイルで指定された変換内容が使用されます。それ以外の場合、OTTではCASEオプションを適用して、その名前を文字ごとにコンパイラのキャラクタ・セットに変換します。次にこのプロセスの詳細を示します。
OTTがデータベース・エンティティの名前を読み取る場合、その名前は、データベース・キャラクタ・セットからOTTで使用するキャラクタ・セットに自動的に変換されます。 OTTがデータベース・エンティティの名前を正常に読み取れるように、名前のすべての文字はOTTのキャラクタ・セットに含まれている必要があります。ただし、文字のコードが2つのキャラクタ・セットで異なっている場合があります。
必要なすべての文字が、OTTで使用するキャラクタ・セットに確実に含まれるようにする最も簡単な方法は、データベース・キャラクタ・セットの内容と同一にすることです。ただし、OTTのキャラクタ・セットは、コンパイラのキャラクタ・セットのスーパーセットである必要があります。つまり、コンパイラのキャラクタ・セットが7ビットASCIIの場合は、OTTのキャラクタ・セットにはサブセットとして7ビットASCIIを含む必要があります。コンパイラのキャラクタ・セットが7ビットEBCDICの場合は、OTTのキャラクタ・セットにはサブセットとして7ビットEBCDICを含む必要があります。ユーザーは、OTTで使用するキャラクタ・セットを、環境変数NLS_LANGを設定して指定するか、他のオペレーティング・システム固有のメカニズムによって指定します。
OTTがデータベース・エンティティの名前を読み取ると、その名前は、OTTで使用するキャラクタ・セットからコンパイラのキャラクタ・セットに変換されます。その名前の変換内容がINTYPEファイルで指定されている場合、OTTはその変換内容を使用します。
それ以外の場合、OTTでは、次のように名前の変換を行います。
最初に、OTTのキャラクタ・セットがマルチバイト・キャラクタ・セットの場合で、名前の中のマルチバイト文字に等価のシングルバイト文字がある場合、そのマルチバイト文字をシングルバイト文字に変換します。
次に、その名前を、OTTのキャラクタ・セットからコンパイラのキャラクタ・セットに変換します。コンパイラのキャラクタ・セットは、US7ASCIIなどのシングルバイト・キャラクタ・セットです。
最後に、有効なCASEオプションに従って、文字の大/小文字を設定します。C識別子内で無効な文字やコンパイラのキャラクタ・セットに変換されない文字は、アンダースコアに置き換えられます。1文字でもアンダースコアに置き換えられた場合、OTTは警告メッセージを出します。名前の中のすべての文字がアンダースコアに置き換えられた場合、OTTはエラー・メッセージを出します。
文字単位の名前の変換では、コンパイラのキャラクタ・セットにあるアンダースコア、数字またはシングルバイト文字は変更されません。したがって、有効なC識別子は変更されません。
名前の変換ではたとえば、ウムラウトの付いた「o」、アクセント符号の付いた「a」などのシングルバイト文字をそれぞれ「o」や「a」に変換したり、またマルチバイト文字をシングルバイトと等価に変換できます。名前に等価のシングルバイトがないマルチバイト文字がある場合、通常、その名前の変換はエラーとなります。この場合、ユーザーは、intypeファイルで名前の変換を指定する必要があります。
C言語の同一の名前に複数のデータベース識別子がマッピングされている場合に生じるネーミングの競合は、OTTでは検出されません。また、データベース識別子がCキーワードにマッピングされるときのネーミング問題も検出されません。
現在、OTTは、コマンドラインまたはintypeファイルに指定したファイル名を比較することで、2つのファイルが同一かどうかを判断しています。OTTで2つのファイル名が同一のファイルを参照しているかどうかを判別する必要がある場合は、1つの潜在的な問題が生じます。たとえば、OTTで生成されたファイルfoo.hで、foo1.hに記述されている型宣言と、/private/elias/foo1.hに記述されている別の型宣言が必要な場合、OTTは、2つのファイルが同一の場合は1つの#includeを、異なる場合は2つの#includeを生成します。しかし、実際には2つのファイルは異なるという結論が出され、次のように2つの#includesが生成されます。
#ifndef FOO1_ORACLE #include "foo1.h" #endif #ifndef FOO1_ORACLE #include "/private/elias/foo1.h" #endif
foo1.hと/private/elias/foo1.hが別々のファイルである場合は、最初のファイルのみが組み込まれます。foo1.hと/private/elias/foo1.hが同一ファイルである場合は、#includeが重複して記述されます。
そのため、コマンドラインまたはintypeファイルでファイルを複数回記述するときは、各記述で正確に同じファイル名を使用する必要があります。