この章では、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
ファイルでファイルを複数回記述するときは、各記述で正確に同じファイル名を使用する必要があります。