この章では、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
インジケータ構造体が入っています。たとえば、例15-1に示すように、intypeファイルにリストされたemployee型が定義されたとします。
例15-1 intypeファイルにリストされたemployeeオブジェクト型の定義
CREATE TYPE emptype AS OBJECT ( name VARCHAR2(30), empno NUMBER, deptno NUMBER, hiredate DATE, salary NUMBER );
OTTで生成されたヘッダー・ファイル(demo.h
)には、その他の項目の中に、例15-2に示すような宣言が含まれます。
例15-2 生成されたヘッダー・ファイル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;
例15-3は、このコマンドで生成されたサンプルの実装ファイル(demov.c
)に含まれている内容を示しています。
例15-3 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
など)のデータ型は、特殊なデータ型です。
この章の残りの各項では、OCIでのOTTの使用方法を説明します。その後に続く参照の項では、コマンドライン構文、パラメータ、intypeファイルの構造、ネストした#include
ファイルの生成、スキーマ名の使用方法、デフォルトの名前マッピングおよび制限事項を説明します。
OTTを使用するときの最初のステップは、オブジェクト型または名前付きコレクション型を作成してデータベースに格納することです。そのためには、SQLのCREATE TYPE
文を使用します。
関連項目: CREATE TYPE 文の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
OTTを起動するステップは、次のとおりです。OTTパラメータは、コマンドラインで、または構成ファイルをコールしたファイルで指定できます。一部のパラメータは、intypeファイルでも指定できます。
1つのパラメータが複数箇所に指定されている場合は、コマンドラインのパラメータ値がintypeファイルの値より優先され、intypeファイルの値はユーザー定義の構成ファイルの値より優先され、ユーザー定義の構成ファイルの値は、デフォルトの構成ファイルの値より優先されます。
グローバル・オプション、つまり、コマンドラインのオプションまたはintypeファイルのTYPE
文の前のオプションについては、intypeファイルの値がコマンドラインの値で上書きされます。(intypeファイルでグローバルとして指定できるオプションには、CASE
、CODE
、INITFILE
およびINITFUNC
があります。HFILE
は含まれません。)TYPE
を指定するintypeファイルのオプションは、特定の型にのみ適用されます。その型に適用される、コマンドラインで指定したそれ以外のオプションは上書きされます。TYPE person HFILE=p.h
と入力した場合、オプションはperson
にのみ適用され、コマンドラインのHFILE
は上書きされます。文はコマンドライン・パラメータとはみなされません。
構成ファイルは、OTTパラメータが入っているテキスト・ファイルです。ファイル内の非空白行には、1つのパラメータと、それに対応付けられた1つ以上の値が入っています。1行に2つ以上のパラメータを指定した場合は、最初のパラメータのみが使用されます。構成ファイルの非空白行では、空白は使用できません。
構成ファイルは、コマンドラインで名前を付けることができます。さらに、デフォルトの構成ファイルは常に読み取られます。このデフォルトの構成ファイルは常に存在している必要がありますが、空でもかまいません。デフォルトの構成ファイルの名前はottcfg.cfg
であり、構成ファイルの位置はシステム固有の設定です。たとえば、Solarisでのファイル指定は、$ORACLE_HOME/precomp/admin/ottcfg.cfg
です。詳細は、使用しているオペレーティング・システムのマニュアルを参照してください。
ほとんどのオペレーティング・システムでは、コマンドラインからOTTを起動します。入出力ファイルやデータベース接続情報などを指定できます。OTTの起動方法は、使用しているオペレーティング・システム固有のマニュアルを参照してください。
例15-4は、コマンドラインからのOTTの起動方法を示しています。
例15-4 コマンドラインからのOTTの起動
ott userid=bren intype=demoin.typ outtype=demoout.typ code=c \ hfile=demo.h initfile=demov.c
注意: 等号(=)の両側には空白を挿入しないでください。 |
次の各項では、この例で使用しているコマンドラインの要素を説明します。
outtypeファイルの名前を指定します。OTTでCヘッダー・ファイルを生成すると、変換された型の情報がouttypeファイルに書き込まれます。このファイルには、変換された各型のエントリが、バージョン文字列およびC表現を書き込んだヘッダー・ファイルとともに含まれています。
例15-4では、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ヘッダー・ファイルの名前を指定します。
例15-4では、生成される構造体はdemo.h
と呼ばれるファイルに格納されます。
注意: キーワードhfile で既存のファイルを指定した場合は、OTTの実行時に上書きされますが、次のように例外が1つあります。OTTで生成されたファイルの内容がそのファイルの前の内容と同一の場合、OTTはそのファイルに実際には書き込みません。これにより、ファイルの変更時間を節約でき、LinuxおよびUNIXのmake および他のオペレーティング・システムでの類似機能で、不必要な再コンパイルが実行されません。 |
OTTの実行時に、intypeファイルはどのデータベース型の変換が必要であるかをOTTに指示します。また、このファイルを使用して、生成される構造体の命名方法も指定できます。intypeファイルは、ユーザー作成ファイルでも、前回OTTを起動したときのouttypeファイルでもかまいません。intype
パラメータが使用されていない場合は、OTTの接続先のスキーマにあるすべての型が変換されます。
例15-5は、簡単なユーザー作成intypeファイルを示しています。
例15-5 ユーザー作成intypeファイルの内容
CASE=LOWER TYPE employee TRANSLATE SALARY$ AS salary DEPTNO AS department TYPE ADDRESS TYPE item TYPE "Person" TYPE PURCHASE_ORDER AS p_o
例15-5の詳細な説明は次のようになります。
第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 Databaseのデータ型には、事前定義済の基本型の集合が組み込まれています。これらのデータ型は、オブジェクト型やコレクションなどのユーザー定義型の作成をサポートします。
また、Oracle Databaseには、オブジェクト型属性をC構造体で表現するための事前定義済の型の集合も含まれています。たとえば、例15-6のようなオブジェクト型定義と、例15-7のようなOTTで生成した対応する構造体宣言があるとします。
例15-6 従業員用のオブジェクト型定義
CREATE TYPE employee AS OBJECT ( name VARCHAR2(30), empno NUMBER, deptno NUMBER, hiredate DATE, salary$ NUMBER);
CASE=LOWER
で、型または属性名の明示的なマッピングがないと仮定すると、OTT出力は例15-7のようになります。
例15-7 OTTで生成した構造体宣言
struct employee { OCIString * name; OCINumber empno; OCINumber deptno; OCIDate hiredate; OCINumber salary_; }; typedef struct emp_type emp_type; struct employee_ind { OCIInd _atomic; OCIInd name; OCIInd empno; OCIInd deptno; OCIInd hiredate; OCIInd salary_; } typedef struct employee_ind employee_ind;
ここでは、構造体宣言のデータ型、OCIString
、OCINumber
、OCIDate
およびOCIInd
を使用してオブジェクト型の属性のデータ型をマップしています。たとえば、empno
属性のNUMBER
データ型は、OCINumber
データ型にマップされます。また、これらのデータ型は、バインド変数および定義変数の型としても使用できます。
この項では、Oracleのオブジェクト属性型とOTTで生成されるCの型とのマッピングを説明します。「OTT型マッピングの例」では、様々なマッピングの例を示します。表15-1は、属性として使用できる型から、OTTで生成されるオブジェクト・データ型へのマッピングをリストしています。
表15-1 オブジェクト型属性のオブジェクト・データ型マッピング
オブジェクト属性の型 | Cマッピング |
---|---|
BFILE |
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
以外は不透明です。
例15-9は、例15-8に示すデータベース型の指定時に、OTTで作成される各種の型のマッピングを示しています。
例15-8 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では、例15-9に示すようなC構造体が生成されます。
例15-9 オブジェクト型定義から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は、リストされている型の変換を完了するために、変換対象の型の属性に使用されている型をすべて自動的に変換します。
この自動変換は、オブジェクト型属性のポインタまたはREF
によってのみアクセスされる型には適用されません。たとえば、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
インジケータ情報を選択できます。
たとえば、例15-9では、次の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
と命名された要素の型がスーパータイプの名前です。
たとえば、例15-10に示すように、サブタイプStudent_t
とEmployee_t
を持つPerson_t
型があるとします。
例15-10 オブジェクト型とサブタイプの定義
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));
また、例15-11に示す内容のintypeファイルもあるとします。
例15-12に示すように、OTTでは、Person_t
、Student_t
およびEmployee_t
に対するC構造体とそれぞれのNULL
インジケータ構造体が生成されます。
例15-12 OTTによる型に対する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; /* upcasting */
同様に、NULL
インジケータ構造体が生成されます。スーパータイプPerson_t
のNULL
インジケータ構造体の最初の要素は_atomic
で、サブタイプEmployee_t
およびStudent_t
のNULL
インジケータ構造体の最初の要素は_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ファイルとして使用できます。
たとえば、例15-13に示すように、例15-5で使用した簡単なintypeファイルがあるとします。
例15-13 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つの型については、ネーミング規則が指定されています。
例15-14は、OTT実行後のouttypeファイルを示しています。
例15-14 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指定に含まれていなかった型がリストされていることに気づきます。たとえば、person
型が次のように変換されることのみ指定されたintypeファイルがあるとします。
CASE = LOWER TYPE PERSON
ただし、このperson
型の定義にaddress
型の属性が含まれているため、outtypeファイルには、PERSON
とADDRESS
の両方のエントリが含まれます。person
型を完全に変換するには、最初にaddress
を変換する必要があります。
パラメータTRANSITIVE
がTRUE
に設定されている(デフォルトの)場合、OTTは、変換を実行する前にintypeファイル内の型の依存性を分析してから、必要に応じて他の型を変換します。
Oracleサーバー内のオブジェクトにアクセスするOCIアプリケーションでは、OTTで生成したCヘッダー・ファイルと実装ファイルを使用できます。ヘッダー・ファイルは、#include
文でOCIコードに取り込みます。
OCIアプリケーションでは、ヘッダー・ファイルを組み込んだ後、ホスト言語形式のオブジェクト・データにアクセスし、操作できます。
図15-1は、最も単純なアプリケーションのOCIでOTTを使用する場合のステップを示しています。
SQLを使用してデータベースに型定義を作成します。
OTTで、オブジェクト型と名前付きコレクション型のC表現を含むヘッダー・ファイルを生成します。INITFILE
オプションで命名された実装ファイルも生成します。
アプリケーションを記述します。OCIアプリケーションでユーザーが記述したコードで、INITFUNC
関数を宣言してコールします。
ヘッダー・ファイルをOCIソース・コード・ファイルにインクルードします。
OTTで生成された実装ファイルを含めて、OCIアプリケーションがコンパイルされ、OCIライブラリにリンクされます。
OCI実行可能ファイルをOracle Databaseに対して実行します。
アプリケーション内部では、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アプリケーションと結合している場合にのみ適用します。
次に、初期化関数の例を示します。
例15-15に示すような内容を含むintypeファイル、ex2c.typ
があるとします。
例15-16に示すように、コマンドラインからOTTを起動し、初期化関数を指定します。
OTTでは、例15-17に示すような内容のex2cv.c
ファイルが生成されます。
例15-17 ex2cv.cという名前のOTTで生成したファイルの内容
#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 Databaseの型マネージャが、特定のプログラムで使用する型のバージョンを特定するときに使用します。異なる時期にOTTで生成した異なる複数の初期化関数によって、型バージョン表に同じ型が複数回追加される可能性があります。型が複数回追加される場合、Oracle Databaseでは、毎回同じバージョンの型が確実に登録されるようにします。
初期化関数に対して関数プロトタイプを宣言し、その関数をコールするのは、OCIプログラマの役割です。
注意: Oracle Databaseのカレント・リリースでは、型ごとにバージョンは1つのみです。型バージョン表の初期化は、Oracle Databaseの今後のリリースとの互換性を保つためにのみ必要です。 |
OTTコマンドラインまたはCONFIG
ファイルで指定できるパラメータは、OTTの動作を制御します。また、一部のパラメータは、intypeファイルにも指定できます。
この項では、次の項目について詳しく説明します。
この項では、次の規則を使用してOTTの構文を説明します。
イタリックの文字列は、ユーザーが指定する変数またはパラメータです。
大文字の文字列は、そのとおりに入力する文字列です。ただし、大/小文字は区別されないため、小文字で入力しても有効です。
OTTキーワードは、例やヘッダーでは小文字の固定幅フォントでリストされていますが、本文では、目立つように大文字で印刷されています。
大カッコ[...]で囲んだ項目は、オプション項目です。
1つの項目(あるいはカッコで囲まれた複数の項目)の直後の省略記号(...)は、その項目を何度も繰り返し指定できることを示します。
これ以外の句読点記号は、示されているとおりに入力します。「.」や「@」などが含まれます。
OTTコマンドライン・インタフェースは、OTTを明示的に起動してデータベース型をC構造体に変換するときに使用します。オブジェクトを使用するOCIアプリケーションを開発する場合は、必ずこのインタフェースが必要です。
OTT
コマンドライン文は、キーワードOTTと、その後に続くOTTパラメータのリストによって構成されます。
OTTコマンドライン文に指定できるパラメータは、次のとおりです。
[userid=username/password[@db_name]] [intype=filename] outtype=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コマンドライン文の例を次に示します(パスワードの入力を求められます)。
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 Net Servicesのデータベース指定文字列)を指定します。データベース名を省略すると、デフォルトのデータベースが使用されます。このパラメータの構文は、次のとおりです。
userid=username/password[@db_name]
USERID
パラメータはオプションです。省略した場合、OTTは自動的にユーザーOPS$username
でデフォルトのデータベースへの接続を試みます。ここで、username
は、ユーザーのオペレーティング・システムのユーザー名です。これが最初のパラメータである場合、次に示すように、USERID=
、パスワードおよびデータベース名を省略できます。
OTT username ...
セキュリティ上の問題から、ユーザー名を入力するときのみ残りの項目を入力するよう求められます。
INTYPE
パラメータでは、オブジェクト型指定のリストの読取り元ファイルの名前を指定します。読み取ったリストにある型が、OTTによって変換されます。
このパラメータの構文は、次のとおりです。
intype=filename
"USERID
が第1パラメータ、INTYPE
が第2パラメータで、USERID=
を省略した場合は、INTYPE=
も省略できます。INTYPE
パラメータが指定されていない場合は、ユーザーのスキーマの型すべてが変換されます。
OTT username filename...
intypeファイルは、型宣言のmakefileと考えることができます。C構造体宣言の必要な型をリストします。
コマンドラインまたはintypeファイルのファイル名に拡張子がない場合は、「TYP
」や「.typ
」などのオペレーティング・システム固有の拡張子が追加されます。
OUTTYPE
パラメータは、OTTが処理するすべてのオブジェクト・データ型の型情報を書き込むファイルの名前を指定します。これには、intypeファイルで明示的に指定したすべての型が含まれます。さらに、変換対象である他の型の宣言で使用しているために変換された型が含まれる場合もあります(TRANSITIVE=TRUE
の場合)。このファイルは、それ以後にOTTを起動するときにintypeファイルとして使用できます。
outtype=filename
INTYPE
パラメータとOUTTYPE
パラメータが同一のファイルを参照している場合、intypeファイルの古い情報は、新しいINTYPE
パラメータの情報に置き換えられます。これは、型の変更から開始し、型宣言の生成、ソースコードの編集、プリコンパイル、コンパイル、デバッグに至るサイクルで、同一のintypeファイルを繰り返し使用するときに便利です。
パラメータOUTTYPE
は必ず指定してください。
コマンドラインまたはouttypeファイルのファイル名に拡張子がない場合は、「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
HFILE
パラメータは、intypeファイルに記述した型の宣言でインクルード(.h
)ファイルを指定しなかった場合に、OTTによって生成されるインクルード・ファイルの名前を指定します。intypeファイルで各型のインクルード・ファイルを個々に指定していない場合は、このパラメータが必要です。また、intypeファイルに記述していない型を、2つ以上の異なるファイルで宣言されている他の型で使用し、TRANSITIVE=TRUE
の場合は、intypeファイルに記述していない型も生成する必要があります。そのような場合もこのパラメータが必要です。
コマンドラインまたはintypeファイルで指定したHFILE
ファイル名に拡張子がない場合は、「H
」や「.h
」などのオペレーティング・システム固有の拡張子が追加されます。
hfile=filename
CONFIG
パラメータでは、共通で使用するパラメータ指定をリストしたOTT構成ファイルの名前を指定します。また、パラメータ指定は、オペレーティング・システムによって異なる位置にあるシステム構成ファイルから読み取られます。残りのすべてのパラメータ指定は、コマンドラインまたはintypeファイルで指定する必要があります。
config=filename
注意: CONFIG パラメータは、CONFIG ファイルでは使用できません。 |
ERRTYPE
パラメータを指定すると、OTTでは、intypeファイルのリストが、すべての情報メッセージおよびエラー・メッセージとともにERRTYPE
ファイルに書き込まれます。情報メッセージおよびエラー・メッセージは、ERRTYPE
パラメータを指定したかどうかに関係なく、標準出力に送信されます。
実質的に、ERRTYPE
ファイルはエラー・メッセージが追加されたintypeファイルのコピーです。ほとんどの場合、エラー・メッセージにはエラーの原因となったテキストへのポインタが示されます。
コマンドラインまたはintypeファイルで指定したERRTYPE
ファイル名に拡張子がない場合は、「TLS
」や「.tls
」などのオペレーティング・システム固有の拡張子が追加されます。
errtype=filename
CASE
パラメータは、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
その場合、intypeファイルで指定された大/小文字に続いて、OTTでは次の行が生成されます。
struct wOrKeR {...};
intypeファイルに記述されていない、大/小文字の区別のないSQL識別子は、CASE=SAME
,の場合は大文字で、CASE=OPPOSITE
の場合は小文字で指定されます。宣言されるとき引用符で囲まれていないSQL識別子の場合、大/小文字の区別はありません。
SCHEMA_NAMES
パラメータは、デフォルト・スキーマに基づいた型のデータベース名を、outtypeファイル内のスキーマ名で修飾する場合に、制御を行います。OTTで生成したouttypeファイルには、型名も含めて、OTTで処理された型の情報が含まれています。
TRANSITIVE
パラメータの値は、TRUE
(デフォルト)またはFALSE
のいずれかです。intypeファイルで明示的にリストされていない型の依存性が変換対象かどうかを示します。
TRANSITIVE=TRUE
が指定されている場合は、他の型で必要でintypeファイルで記述されていない型が生成されます。
TRANSITIVE=FALSE
が指定されている場合は、intypeファイルに指定されていない型は生成されません。生成した他の型の属性型として使用されている場合でも生成されません。
URL
パラメータの場合、OTTでは、JavaインタフェースであるJDBC (Java Database Connectivity)を使用してデータベースに接続します。URL
パラメータのデフォルト値は次のとおりです。
URL
=jdbc:oracle:oci8:@
OCI8ドライバは、Oracle Databaseのインストールでクライアント側で使用します。
JDBCシン・ドライバ(Oracle Databaseをインストールしない場合にクライアント側で使用するJavaドライバ)を指定するには、次のURL
パラメータの構文を使用します。
URL=jdbc:oracle:thin:@host:port:sid
host
はデータベースが実行されているホストの名前、port
はポート番号、sid
はOracle SIDです。
OTTパラメータは、コマンドラインまたはコマンドラインで名前が付けられたCONFIG
ファイル、あるいはその両方で指定できます。パラメータの一部は、intypeファイルでも指定できます。
OTTは、次のように起動します。
OTT username/password parameters
コマンドラインのパラメータの1つが次のパラメータである場合、構成ファイルfilename
からその他のパラメータが読み取られます。
config=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
- Oracle Databaseオブジェクト・データ型の名前です。
type_identifier
- 型を表すのに使用するC識別子です。type_identifier
を省略すると、デフォルトの名前マッピング・アルゴリズムが使用されます。
version_string
は、OTTの以前の起動によってコードが生成されたときに使用された型のバージョン文字列です。バージョン文字列はOTTによって生成され、outtypeファイルに書き込まれます。このファイルは、後でOTTを実行するときにintypeファイルとして使用できます。バージョン文字列はOTTの操作には影響しませんが、最終的にこれを使用して、起動中のプログラムで使用されるオブジェクト・データ型のバージョンが選択されます。
hfile_name
- 該当する構造体の宣言またはクラスが現れるヘッダー・ファイルの名前です。hfile_name
を省略すると、宣言の生成時には、コマンドラインのHFILE
パラメータで指定したファイルが使用されます。
member_name
- identifier
に変換される属性(データ番号)の名前です。
identifier
- ユーザーのプログラムで属性を表現するC識別子です。識別子は、任意の数の属性に対してこの方法で指定できます。指定していない属性については、デフォルトの名前マッピング・アルゴリズムが使用されます。
オブジェクト・データ型は、次のいずれかの場合に変換する必要があります。
intypeファイルに指定されています。
変換が必要な別の型を宣言する場合、およびTRANSITIVE=TRUE
の場合は必須です。
明示的に記述していない型があり、その型が、正確に1つのファイルのみに宣言した型で必要だとします。この場合、OTTでは、明示的に記述していない型の変換結果は、それを必要とする明示的に宣言した型と同じファイルに書き込まれます。
明示的に記述していない型が、複数の異なるファイルの型の宣言に必要な場合、OTTでは、この必須の型の変換結果は、グローバルなHFILE
ファイルに書き込まれます。
OTTで生成した各HFILE
では、#include
ディレクティブを使用して、他の必要なファイルをインクルードし、#define
ディレクティブを使用して、ファイル名から構成された記号を定義します。これは、HFILE
がインクルードされているかどうかを判断するために使用できます。たとえば、データベースに例15-18に示すような型があるとします。
例15-18 OTTによるインクルード・ファイルの生成方法を示すオブジェクト型定義
create type px1 AS OBJECT (col1 number, col2 integer); create type px2 AS OBJECT (col1 px1); create type px3 AS OBJECT (col1 px1);
intypeファイルの内容を例15-19に示します。
例15-20に示すコマンドを含むOTTを起動する場合、例15-21および例15-22に示すヘッダー・ファイルが生成されます。
ヘッダー・ファイルtott95b.h
の内容を例15-21に示します。
例15-21 ヘッダー・ファイル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の内容を例15-22に示します。
例15-22 ヘッダー・ファイル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
例15-21では、TOTT95B_ORACLE
という記号を最初に定義しています。そのため、プログラマは、例15-23に示すように、構造体を使用してtott95b.h
を条件付きで組み込むことができます。その場合、tott95b.h
がインクルード・ファイルに依存しているかどうかを考慮する必要はありません。
この方法によって、プログラマは、適当なファイル (
たとえばfoo.h)
からtott95b.h
を組み込むことができます。その際、tott95b.h
が、foo.hに組み込まれるその他のファイルにも組み込まれるかどうかは、わかっていなくてもかまいません。
記号TOTT95B_ORACLE
の定義の後に、ファイルoci.h
がインクルードされます。OTT生成のすべてのHFILE
には、Pro*C/C++やOCIのプログラマに役立つ型と関数の宣言が含まれたoci.h
がインクルードされます。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
またはTYPE david.Person
のいずれかが組み込まれているとします。
ただし、intypeファイルには、david.Person
型でネストしたオブジェクト型として使用されているdavid.Address
型は記述されていません。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
型には付けない場合、ユーザーはintypeファイルで明示的に次を指定する必要があります。
TYPE david.Address
各型を単一のスキーマ内に宣言する通常の場合は、すべての型名を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ファイルでファイルを複数回記述するときは、各記述で正確に同じファイル名を使用する必要があります。