この章では、オブジェクト型トランスレータ(OTT)ユーティリティについて説明します。このユーティリティを使用して、データベース・オブジェクト型、LOB型および名前付きコレクション型をC++クラスの宣言にマッピングし、OCCIアプリケーションで使用できるようにします。
ここでは、次の項目について説明します。
|
関連項目: この章で使用するデモ・プログラムの完全なコード・リストおよびOTTユーティリティによって生成されるクラスおよびメソッド実装は、 $ORACLE_HOME/rdbms/demoを参照してください。 |
オブジェクト型トランスレータ(OTT)ユーティリティは、Oracleデータベース・サーバーのユーザー定義型を利用するアプリケーションの開発に役立ちます。
オブジェクト型は、SQLのCREATE TYPE文を使用して作成できます。これらの型の定義はデータベースに格納されており、データベース表の作成時に使用できます。表が作成されると、OCCIプログラマは表に格納されているオブジェクトにアクセスできます。
オブジェクト・データにアクセスするアプリケーションには、データをホスト言語形式で表現する機能が必要です。この機能は、オブジェクト型クラスをC++で表現することで実現します。
構造体またはクラスを手動でコーディングしてデータベース・オブジェクト型を表現することもできますが、時間がかかり、エラーが発生しやすくなります。OTTユーティリティは、C++に対する適切なクラスを自動的に生成することで、このステップを簡略化します。
OCCIの場合、アプリケーションでは、次のファイルを組み込んでリンクする必要があります。
生成されたクラス宣言が含まれたヘッダー・ファイルを組み込みます。
マッピングを登録する関数のプロトタイプが含まれたヘッダー・ファイルを組み込みます。
オブジェクトをインスタンス化している間にOCCIがコールする静的メソッドが含まれたC++ソース・ファイルとのリンクを設定します。
マッピングを環境に登録する関数が含まれているファイルとのリンクを設定して、この関数をコールします。
データベース型をC++の表現に変換するには、OTTユーティリティを明示的に起動する必要があります。OCCIプログラマでは、マッピングを環境に登録する必要があります。この関数はOTTユーティリティによって生成されます。
ほとんどのオペレーティング・システムでは、コマンドラインからOTTユーティリティを起動します。OTTユーティリティでは、INTYPEファイルを入力として受け取り、OUTTYPEファイル、プロトタイプ情報が含まれる1つ以上のC++ヘッダー・ファイルおよび生成されたマッピングを登録する追加C++メソッド・ファイルを生成します。
例8-1 OTTユーティリティの使用方法
次のコマンドは、OTTユーティリティを起動してC++クラスを生成します。 OTTはユーザー名demousrを使用して接続を試行します。システムではパスワードが要求されます。
ott userid=demousr intype=demoin.typ outtype=demoout.typ code=cpp hfile=demo.h cppfile=demo.cpp mapfile=RegisterMappings.cpp
OTTユーティリティでは、demoin.typファイルをINTYPEファイルとして使用し、demoout.typファイルをOUTTYPEファイルとして使用します。生成された宣言はCODE=cppパラメータで指定されたC++でdemo.hファイルに出力され、メソッド実装はdemo.cppファイルに出力され、マッピングを登録する関数は、RegisterMappings.hに出力されたプロトタイプとともに、RegisterMappings.cppに出力されます。
OTTユーティリティを使用する最初のステップは、オブジェクト型または名前付きコレクション型を作成してデータベースに格納することです。そのためには、SQLのCREATE TYPE文を使用します。
例8-2 OTTユーティリティのオブジェクト作成文
CREATE TYPE FULL_NAME AS OBJECT (first_name CHAR(20), last_name CHAR(20)); CREATE TYPE ADDRESS AS OBJECT (state CHAR(20), zip CHAR(20)); CREATE TYPE ADDRESS_TAB AS VARRAY(3) OF REF ADDRESS; CREATE TYPE PERSON AS OBJECT (id NUMBER, name FULL_NAME, curr_addr REF ADDRESS, prev_addr_1 ADDRESS_TAB) NOT FINAL; CREATE TYPE STUDENT UNDER PERSON (school_name CHAR(20));
データベースに型を作成した後の次のステップでは、OTTユーティリティを起動します。
OTTパラメータは、コマンドラインまたは構成ファイルのいずれかで指定できます。一部のパラメータはINTYPEファイルでも指定できます。
1つのパラメータを複数箇所に指定する場合は、コマンドラインのパラメータ値がINTYPEファイルのパラメータ値よりも優先されます。INTYPEファイルの値は、ユーザー定義の構成ファイルの値よりも優先されます。また、このユーザー定義の構成ファイルの値は、デフォルトの構成ファイルの値よりも優先されます。
したがって、パラメータの優先順位は、次のとおりです。
OTTコマンドライン
INTYPEファイルの値
ユーザー定義の構成ファイル
デフォルトの構成ファイル
グローバル・オプション(つまり、コマンドラインのオプションまたはTYPE文の前にあるINTYPEファイルの最初のオプション)の場合は、コマンドラインの値がINTYPEファイルの値よりも優先されます。(INTYPEファイルでグローバル指定できるオプションは、CASE、INITFILE、INITFUNC、MAPFILEおよびMAPFUNCです。HFILEまたはCPPFILEは、グローバル指定できません。)INTYPEファイルにTYPE指定で記述されている内容は、特定の型に対してのみ適用され、この特定の型に対して通常適用されるコマンドラインの内容よりも優先されます。したがって、TYPE person HFILE=p.hを入力すると、その内容はpersonのみに適用され、コマンドラインのHFILEが上書きされます。この文は、コマンドライン・パラメータとみなされません。
INTYPEファイルは、OTTユーティリティで変換する型のリストです。
CASE、CPPFILE、HFILE、INITFILE、INITFUNC、MAPFILEおよびMAPFUNCの各パラメータは、INTYPEファイルに指定できます。
構成ファイルは、OTTパラメータが記述されているテキスト・ファイルです。ファイル内の各非空白行には、1つのパラメータと、それに関連付けられた1つ以上の値が含まれています。1行に2つ以上のパラメータを指定した場合は、最初のパラメータのみが使用されます。構成ファイルの非空白行では、空白を使用できません。
構成ファイルは、コマンドラインで名前を指定できます。また、デフォルトの構成ファイルは常に読み込まれます。このデフォルトの構成ファイルは、常に存在している必要がありますが、空でも構いません。デフォルトの構成ファイルの名前はottcfg.cfgであり、ファイルの位置はオペレーティング・システム固有の設定です。
|
関連項目: デフォルトの構成ファイルの位置は、使用しているオペレーティング・システムのマニュアルを参照してください。 |
ほとんどのプラットフォームでは、コマンドラインからOTTユーティリティを起動します。コマンドラインでは特に、入出力ファイルおよびデータベース接続情報を指定できます。
|
関連項目: オペレーティング・システムでOTTユーティリティを起動する方法は、使用しているオペレーティング・システムのマニュアルを参照してください。 |
例8-3 OTTユーティリティを起動してC++クラスを生成する方法
OTTはユーザー名demousrを使用して接続を試行します。システムではパスワードが要求されます。
ott userid=demousr intype=demoin.typ outtype=demoout.typ code=cpp hfile=demo.h cppfile=demo.cpp mapfile=RegisterMappings.cpp
|
注意: OTTコマンドラインの等号( =)の前後には空白を使用できません。 |
OTTコマンドライン文は、コマンドOTTと、その後に続くOTTユーティリティ・パラメータのリストで構成されています。
HFILEパラメータは、ほとんどの場合に使用されます。省略した場合は、INTYPEファイル内の各型に対して、HFILEを個別に指定する必要があります。OTTユーティリティは、INTYPEファイルにリストされていない型の変換が必要であると判断した場合は、エラーをレポートします。したがって、INTYPEファイルが以前にOTT OUTTYPEファイルとして生成されている場合のみ、HFILEパラメータを省略できます。
INTYPEファイルを省略すると、スキーマ全体が変換されます。詳細は、次の項のパラメータの説明を参照してください。
OTTユーティリティを使用してC++を生成するには、CODEパラメータをCODE=CPPに設定する必要があります。CODE=CPPを指定した場合は、メソッド実装ファイルとマッピング登録関数ファイルのファイル名を定義するために、CPPFILEパラメータとMAPFILEパラメータを指定する必要があります。マッピング関数の名前は、OTTユーティリティによってMAPFILEから作成するか、MAPFUNCパラメータを使用して指定できます。また、ATTRACCESSは、生成したコードの変更を指定できるオプションのパラメータです。これらのパラメータは、C++クラスの生成を制御します。
OTTコマンドラインにパラメータを入力します。この場合、parameterはリテラル・パラメータ文字列であり、valueは有効なパラメータ設定値です。リテラル・パラメータ文字列は大/小文字を区別しません。
parameter=value
コマンドラインのパラメータは、空白またはタブのいずれかを使用して区切ります。
パラメータは構成ファイル内にも指定できます。ただし、この場合は、行内の空白は許可されないため、各パラメータは独立した行に指定する必要があります。また、CASE、CPPFILE、HFILE、INITFILE、INTFUNC、MAPFILEおよびMAPFUNCの各パラメータは、INTYPEファイルに指定できます。
表8-1は、OTTユーティリティのすべてのパラメータを示しています。
表8-1 OTTユーティリティのパラメータの概要
| パラメータ | 説明 |
|---|---|
|
|
型属性へのアクセスが |
|
|
生成されるC++識別子の大/小文字の区別に影響します。 |
|
|
変換のターゲット言語を指定します。 |
|
|
共通に使用されるパラメータ指定がリストされるOTT構成ファイルの名前を指定します。 |
|
|
メソッド実装が書き込まれるC++ソース・ファイルの名前を指定します。 |
|
|
エラー・メッセージ出力ファイルの名前を指定します。 |
|
|
生成されたC++クラスが書き込まれるC++のヘッダー・ファイル名を指定します。 |
|
|
|
|
|
OTTユーティリティで生成するマッピング・ファイルとそれに対応するヘッダー・ファイルの名前を指定します。 |
|
|
生成するマッピングの登録に使用する関数の名前を指定します。 |
|
|
|
|
|
デフォルト・スキーマに基づいて命名した型のデータベース名の修飾を制御します。 |
|
|
INTYPEに明示的にリストされていない型の依存性を変換するかどうかを指定します。 |
|
|
アプリケーションがUTF16をサポートし、 |
|
|
ユーザーが追加したコードを引き継ぐために、OTTマーカーをサポートする必要があるかどうかを指定します。 |
|
|
OTTユーティリティが使用するデータベース接続情報を指定します。 |
このパラメータは、型属性へのアクセスを指定します。
PROTECTEDは、デフォルトです。
PRIVATEの場合、OTTユーティリティにより、getXXX()およびsetXXX()のそれぞれの型属性に対して、アクセッサ・メソッドおよびミューテータ・メソッドが生成されます。
このパラメータは、生成されるC++識別子の大/小文字の区別に影響します。CASEの有効な値は、次のとおりです。
SAMEの場合、データベース型と属性名をC++識別子に変換するときに、文字の大/小文字は変更されません。
LOWERの場合、大文字はすべて小文字に変換されます。
UPPER の場合、小文字はすべて大文字に変換されます。
OPPOSITEの場合、大文字はすべて小文字に変換され、小文字はすべて大文字に変換されます。
このパラメータは、INTYPEファイルに記述されていない識別子(明示的にリストされていない属性または型)のみに作用します。大/小文字の変換は、正当な識別子が生成された後で行われます。
|
注意: INTYPEファイルに記述されていない、大/小文字の区別のないSQL識別子は、CASE=SAMEの場合は大文字で、CASE=OPPOSITEの場合は小文字で表現されます。SQL識別子は、宣言時に引用符が付けられていない場合、大/小文字が区別されません。 |
このパラメータは、OTTユーティリティで出力するホスト言語を指定します。OCCIアプリケーション用にC++コードを生成するには、CODE=CPPをOTTユーティリティに指定する必要があります。
このパラメータは、共通に使用されるパラメータ指定がリストされるOTT構成ファイルの名前を指定します。パラメータ指定は、オペレーティング・システム固有の位置にあるシステム構成ファイルからも読み込まれます。残りのすべてのパラメータ指定は、コマンドラインまたはINTYPEファイルに指定する必要があります。
|
注意: OTTコマンドラインに指定できるのは、 CONFIGパラメータのみです。このパラメータはCONFIGファイルに指定できません。 |
このパラメータは、OTTユーティリティで生成するメソッド実装が格納されるC++ソース・ファイルの名前を指定します。このファイルに生成されるメソッドは、オブジェクトをインスタンス化するときにOCCIによってコールされます。アプリケーション内で直接コールされることはありません。
次の場合、このパラメータは必須です。
INTYPEファイルに指定されていない型の生成が必要で、2つ以上のCPPFILEが生成されている場合。この場合、未指定の型は、コマンドラインに指定したCPPFILEに格納されます。
INTYPEパラメータが未指定で、スキーマ内のすべての型をOTTユーティリティで変換する場合。
CPPFILEパラメータがINTYPEファイルの個々の型に対して指定されている場合、このパラメータはオプションです。
このパラメータは、エラー・メッセージ出力ファイルの名前を指定します。情報メッセージおよびエラー・メッセージは、ERRTYPEを指定したかどうかに関係なく、標準出力されます。基本的に、ERRTYPEファイルは、エラー・メッセージが追加されたINTYPEファイルのコピーです。ほとんどの場合、エラー・メッセージにはエラーの原因となったテキストへのポインタが含まれます。
コマンドラインで、拡張子を付けずにファイル名をERRTYPEパラメータに指定すると、.TLSや.tlsなどのプラットフォーム固有の拡張子が自動的に追加されます。
このパラメータは、OTTユーティリティで生成するヘッダー・ファイル(.h)の名前を指定します。コマンドラインに指定されたHFILEには、型の宣言が含まれています。この宣言は、INTYPEファイルに指定されていますが、そのヘッダー・ファイルはこのファイルには指定されていません。
このパラメータは、各型のヘッダー・ファイルがINTYPEファイルに個別に指定されていない場合に必要です。このパラメータは、INTYPEファイルに記述されていない型を、他の型が必要とする理由から生成する場合にも必要です。この他の型は、2つ以上の異なるファイルで宣言されます。
コマンドラインまたはINTYPEファイルで、拡張子を付けずにファイル名をHFILEパラメータに指定すると、.Hや.hなどのプラットフォーム固有の拡張子が自動的に追加されます。
このパラメータは、オブジェクト型指定のリストを読み込む元のファイル名を指定します。OTTユーティリティによって、リストにある各型が変換されます。INTYPEパラメータが指定されていない場合は、ユーザーのスキーマにある型すべてが変換されます。
コマンドラインで、拡張子を付けずにファイル名をINTYPEパラメータに指定すると、.TYPや.typなどのプラットフォーム固有の拡張子が自動的に追加されます。
USERIDが第1パラメータ、INTYPEが第2パラメータの場合で、USERID=が省略されている場合は、INTYPE=を省略できます。
INTYPEファイルは、型宣言に対するMakeファイルとみなすことができます。このファイルには、C++クラスを必要とする型がリストされます。
このパラメータは、OTTユーティリティで生成するマッピング・ファイル(XXX.cpp)とそれに対応するヘッダー・ファイル(XXX.h)の名前を指定します。XXX.cppファイルにはマッピングを登録する関数の実装が格納され、XXX.hファイルにはその関数のプロトタイプが格納されます。
このパラメータは、コマンドラインまたはINTYPEファイルに指定できます。
このパラメータは、OTTユーティリティで生成する、マッピングの登録に使用する関数の名前を指定します。
このパラメータを省略すると、マッピングを登録する関数の名前は、MAPFILEパラメータに指定されているファイル名に基づいて作成されます。
このパラメータは、コマンドラインまたはINTYPEファイルに指定できます。
このパラメータは、OTTユーティリティが処理するオブジェクト・データ型すべての型情報を出力するファイルの名前を指定します。このファイルには、INTYPEファイルに明示的に指定されたすべての型が格納されます。また、変換が必要な他の型の宣言で使用されているために変換される、追加の型が格納される場合があります。このファイルは、OTTユーティリティの今後の起動で、INTYPEファイルとして使用できます。
INTYPEパラメータとOUTTYPEパラメータが同一のファイルを参照している場合、INTYPEファイルの古い情報は、新しいINTYPEの情報によって置換されます。これは、型の変更から始まり、型宣言の生成、ソースコードの編集、プリコンパイル、コンパイル、デバッグに至るサイクル内で、同一のINTYPEファイルを繰返し使用するときに便利です。
コマンドラインまたはINTYPEファイルに、拡張子を付けずにファイル名をOUTTYPEパラメータに指定すると、.TYPや.typなどのプラットフォーム固有の拡張子が自動的に追加されます。
OUTTYPEファイルで命名されたデフォルト・スキーマに基づく型のデータベース名を修飾する場合、このパラメータで制御します。OTTユーティリティによって生成されたOUTTYPEファイルには、型名を含めて、OTTユーティリティで処理された型の情報が記述されます。次の値が有効です。
ALWAYS(デフォルト)の場合、OUTTYPEファイル内のすべての型名はスキーマ名で修飾されます。
IF_NEEDEDの場合、デフォルト・スキーマに所属するOUTTYPEファイル内の型名は、スキーマ名で修飾されません。その他のスキーマに所属する型名は、スキーマ名で修飾されます。
FROM_INTYPEの場合、INTYPEファイルに記述されている型は、INTYPEファイル内のスキーマ名で修飾されている場合に限って、OUTTYPEファイル内のスキーマ名で修飾されます。INTYPEファイルには記述されていないが、型の依存性のために生成されたデフォルト・スキーマ内の型は、その型に依存しているOTTユーティリティで最初に検出された型がスキーマ名付きで記述されている場合にのみ、スキーマ名付きで記述されます。ただし、OTTユーティリティが接続しているデフォルト・スキーマにない型は、常に、明示的に指定したスキーマ名付きで記述されます。
デフォルト・スキーマ以外のスキーマに基づく型の名前は、OUTTYPEファイル内のスキーマ名で常に修飾されます。
スキーマ名の有無によって、プログラム実行中に型を検索するスキーマが決定されます。
例8-4 OTTユーティリティでのSCHEMA_NAMESパラメータの使用方法
SCHEMA_NAMESパラメータがFROM_INTYPEに設定され、INTYPEファイルに次の指定がある例を想定します。
TYPE Person TYPE joe.Dept TYPE sam.Company
OTTユーティリティとアプリケーションの両方がスキーマjoeに接続する場合、アプリケーションはOTTユーティリティが使用する型と同じ型(joe.Person)を使用します。OTTユーティリティはスキーマjoeに接続しているが、アプリケーションはスキーマmaryに接続している場合、アプリケーションはmary.Person型を使用します。この動作は、スキーマjoeとスキーマmaryで同一のCREATE TYPE Person文が実行されている場合にのみ適切です。
一方、アプリケーションは、接続しているスキーマに関係なく、joe.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ユーティリティはスキーマjoeに接続し、SCHEMA_NAMES=FROM_INTYPEが指定され、ユーザーのINTYPEファイルには、TYPE PersonまたはTYPE joe.Personのいずれかが含まれていると仮定します。INTYPEファイルには、joe.Person型でネストしたオブジェクト型として使用されているjoe.Address型は指定されていません。
INTYPEファイルにType Personが指定されている場合は、TYPE PersonとTYPE AddressがOUTTYPEファイルに指定されます。
INTYPEファイルにTYPE joe.Personが指定されている場合は、TYPE joe.PersonとTYPE joe.AddressがOUTTYPEファイルに指定されます。
OTTユーティリティが変換する複数の型には、joe.Address型が埋め込まれているが、そのことがINTYPEファイルには明示的に記述されていない場合、スキーマ名を使用するかどうかの判断は、埋め込まれたjoe.Address型をOTTユーティリティが最初に検出したときに行われます。なんらかの理由で、ユーザーがスキーマ名をjoe.Address型には付け、Person型には付けないようにするには、TYPE joe.Addressのように、この内容をINTYPEファイルで明示的に指定する必要があります。
各型を単一のスキーマ内で宣言する通常の場合は、すべての型名をINTYPEファイル内のスキーマ名で修飾することが最も安全です。
このパラメータは、INTYPEファイルに明示的にリストされていない型の依存性を変換するかどうかを指定します。次の値が有効です。
TRUE(デフォルト): 他の型に必要な型で、INTYPEファイルに指定されていない型が生成されます。
FALSE: INTYPEファイルに指定されていない型は生成されません。これは、ファイルに指定されていない型が、生成された他の型に対する属性の型として使用されている場合にも適用されます。
このパラメータは、アプリケーションでUnicode(UTF16)をサポートするかどうかを指定します。
NONE(デフォルト)
ALL: すべてのCHAR(CHAR/VARCHAR)およびNCHAR(NCHAR/NVARCHAR2)型属性が、OTT生成のC++クラス・ファイルでUString型として宣言されます。対応するgetXXX()/setXXX()の戻り値または戻りパラメータは、UString型です。また、生成される永続演算子newは、UString引数のみ受け入れます。
|
注意: この設定は、クライアント・キャラクタセットおよび各国語キャラクタセットの両方がUTF16である場合に使用してください。 |
ONLYNCHAR: ALLオプションに類似していますが、NCHAR型属性のみがUStringとして宣言されます。
|
注意: この設定は、アプリケーションにおいて環境の各国語キャラクタセットのみをUTF16に設定する場合に使用してください。 |
例8-5 OTTでUnicodeをサポートするためのスキーマの定義方法
create type CitiesList as varray(100) of varchar2(100); create type Country as object ( CNo Number(10), CName Varchar2(100), CNationalName NVarchar2(100), MainCities CitiesList);
例8-6 OTTでのUNICODE=ALLパラメータの使用方法
class Country : public oracle::occi::PObject
{
private:
oracle::occi::Number CNO;
oracle::occi::UString CNAME;
oracle::occi::UString CNATIONALNAME;
OCCI_STD_NAMESPACE:::vector< oracle::occi::UString > MAINCITIES;
public:
oracle::occi::Number getCno() const;
void setCno(const oracle::occi::Number &value);
oracle::occi::UString getCname() const;
void setCname(const oracle::occi::UString &value);
oracle::occi::UString getCnationalname() const;
void setCnationalname(const oracle::occi::UString &value);
OCCI_STD_NAMESPACE::vector< oracle::occi::UString >& getMaincities();
const OCCI_STD_NAMESPACE::vector< oracle::occi::UString >&
getMaincities() const;
void setMaincities(const OCCI_STD_NAMESPACE::vector< oracle::occi::UString
> &value);
...
}
例8-7 OTTでのUNICODE=ONLYCHARパラメータの使用方法
class Country : public oracle::occi::PObject
{
private:
oracle::occi::Number CNO;
oracle::occi::string CNAME;
oracle::occi::UString CNATIONALNAME;
OCCI_STD_NAMESPACE::vector< std::string > MAINCITIES;
public:
oracle::occi::Number getCno() const;
void setCno(const oracle::occi::Number &value);
oracle::occi::string getCname() const;
void setCname(const OCCI_STD_NAMESPACE::string &value);
oracle::occi::UString getCnationalname() const;
void setCnationalname(const oracle::occi::UString &value);
OCCI_STD_NAMESPACE::vector< OCCI_STD_NAMESPACE::string>&
getMaincities();
const OCCI_STD_NAMESPACE::vector< OCCI_STD_NAMESPACE::string >&
getMaincities() const;
void setMaincities(const OCCI_STD_NAMESPACE::vector
< OCCI_STD_NAMESPACE::string > &value);
...
}
このパラメータは、ユーザーが追加したコードを引き継ぐために、OTTマーカーをサポートするかどうかを指定します。次の値が有効です。
FALSE(デフォルト): OTT_USERCODE_STARTとOTT_USERCODE_ENDの2つのマーカーの間にユーザーがコードを追加しても、追加したコードは引き継がれません。
TRUE: OTT_USER_CODESTARTとOTT_USERCODE_ENDの2つのマーカーの間に追加されたコードは、同じファイルが再生成されたときに引き継がれます。
このパラメータは、Oracleユーザー名およびオプションのデータベース名(Oracle Netのデータベース指定文字列)を指定します。データベース名を省略すると、デフォルトのデータベースが使用されます。
USERID=username[@db_name]
これが第1パラメータである場合は、USERID=を省略して、次のように指定できます。
OTT username ...
ユーザーIDに対応するパスワードが要求されるので注意してください。
このパラメータはオプションです。このパラメータを省略すると、OTTユーティリティは、ユーザーOPS$usernameでデフォルトのデータベースに自動的に接続します。usernameは、オペレーティング・システムのユーザー名です。
OTTパラメータは、コマンドラインまたはコマンドラインで名前が指定されたCONFIGファイル、あるいはその両方に指定できます。パラメータの一部は、INTYPEファイルにも指定できます。
OTTユーティリティは、次のように起動します。
OTT parameters
CONFIGパラメータを使用して、構成ファイルの名前をコマンドラインで次のように指定できます。
CONFIG=filename
コマンドラインでこのパラメータの名前を指定すると、他のパラメータは、ファイル名filenameの構成ファイルから読み込まれます。
パラメータは、オペレーティング・システム固有の位置にあるデフォルトの構成ファイルからも読み込まれます。このファイルの存在は必要ですが、空でも構いません。構成ファイルにデータを入力する場合、空白は使用できないこと、パラメータは1行ごとに入力する必要があることに注意してください。
引数を指定しないでOTTユーティリティを実行すると、オンライン・パラメータ・リファレンスが表示されます。
OTTユーティリティによって変換される型は、INTYPEパラメータで指定されたファイルに従って名前が付けられます。CASE、CPPFILE、HFILE、INITFILE、INITFUNC、MAPFILEおよびMAPFUNCの各パラメータは、INTYPEファイルにも指定できます。OTTユーティリティによって生成されたOUTTYPEファイルにはCASEパラメータが含まれ、初期化ファイルが生成された場合はINITFILEパラメータとINITFUNCパラメータが、C++コードが生成された場合はMAPFILEパラメータとMAPFUNCパラメータが含まれます。OUTTYPEファイルは、C++用のCPPFILEと同様に、各型に対するHFILEを個別に指定します。
OTTコマンドの大/小文字区別は、オペレーティング・システムによって異なります。
現在、OTTユーティリティでは、コマンドラインまたはINTYPEファイルにユーザーが指定したファイル名を比較することによって、2つのファイルが同一かどうかを判断しています。しかし、OTTユーティリティで2つのファイル名が同一のファイルを参照しているかどうかを判別する必要がある場合、1つの潜在的な問題が生じます。たとえば、OTTで生成されたファイルfoo1.hで、foo1.hに記述されている型宣言と、/private/smith/foo1.hに記述されている別の型宣言が必要な場合、OTTユーティリティは、2つのファイルが同一の場合は1つの#includeを、異なる場合は2つの#includeを生成する必要があります。しかし、実際にはOTTは2つのファイルが異なるとみなし、次のように2つの#includeを生成します。
#ifndef FOO1_ORACLE #include "foo1.h" #endif #ifndef FOO1_ORACLE #include "/private/smith/foo1.h" #endif
foo1.hと/private/smith/foo1.hが異なるファイルである場合は、最初のファイルのみがインクルードされることになります。foo1.hと/private/smith/foo1.hが同一ファイルである場合は、冗長な#includeが記述されることになります。
そのため、1つのファイルをコマンドラインまたはINTYPEファイルに複数回指定する場合は、ファイルの各指定では同じファイル名を正確に使用する必要があります。
OTTユーティリティの実行時に、INTYPEファイルは、変換するデータベース型をOTTユーティリティに指定します。INTYPEファイルは、生成する構造体やクラスの名前付けも制御します。INTYPEファイルは、直接作成できますが、以前にOTTユーティリティを起動したときに生成されたOUTTYPEファイルを利用することもできます。INTYPEファイルを使用しないと、OTTユーティリティが接続しているスキーマのすべての型が変換されます。
例8-8 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とADDRESSは、それぞれemployeeとADDRESSというC構造体になります。これらの構造体のメンバーには、小文字で名前が指定されます。
TYPEキーワードで始まる行は、変換するデータベース内の型を指定します。この例では、EMPLOYEE型、ADDRESS型、ITEM型、PERSON型およびPURCHASE_ORDER型を変換するように設定しています。
TRANSLATE ...ASキーワードは、オブジェクト型をC構造体に変換するときに、オブジェクト属性の名前を変更することを指定しています。この例では、employee型のSALARY$属性がsalaryに変換されます。
最終行のASキーワードは、オブジェクト型を構造体に変換するときに、名前を変更することを指定しています。この例では、purchase_orderデータベース型をp_oと呼ばれる構造体に変換します。
OTTユーティリティでは、INTYPEファイルにリストされていない他の型の変換が必要になる場合があります。これは、OTTユーティリティは、変換前にINTYPEファイルにある型の依存性を分析し、必要に応じて他の型を変換するためです。たとえば、ADDRESS型はINTYPEファイルにリストされていなくても、Person型にADDRESS型の属性がある場合、OTTユーティリティでは、Person型の定義が必須のため、ADDRESSを変換します。
|
注意: INTYPEファイルで指定されていない必要なオブジェクト型をOTTユーティリティで生成しないように指定するには、TRANSITIVE=FALSEを設定してください。デフォルトは、TRANSITIVE=TRUEです。 |
INTYPEファイルでは、通常の大/小文字の区別がないSQL識別子は、大/小文字のどのような組合せのつづりでも可能です。引用符は付けません。
CREATE TYPE "Person"などの大/小文字を区別して作成されているSQL識別子を参照するには、TYPE "Person"のように引用符を使用してください。SQL識別子は、宣言時に引用符が付けられた場合、大/小文字が区別されます。引用符は、TYPE "CASE"などのOTT予約語であるSQL識別子を参照するためにも使用できます。この場合、そのSQL識別子が、CREATE TYPE Caseのように大/小文字の区別なしに作成されていた場合、引用符付きの名前は大文字であることが必要です。SQL識別子の名前を参照するためのOTT予約語に引用符が付けられていない場合、OTTユーティリティは、INTYPEファイルに構文エラーをレポートします。
INTYPEファイルとOUTTYPEファイルには、OTTユーティリティによって変換された型がリストされ、型名または属性名を有効なCまたはC識別子に変換する方法の決定に必要なすべての情報が含まれています。これらのファイルには、1つ以上の型指定が記述されています。また、CASE、CPPFILE、HFILE、INITFILE、INITFUNC、MAPFILEまたはMAPFUNCが指定されている場合もあります。
CASE、INITFILE、INITFUNC、MAPFILEまたはMAPFUNCオプションを指定する場合は、すべての型指定に先行して指定する必要があります。これらのオプションがコマンドラインとINTYPEファイルの両方に指定されている場合は、コマンドラインの値が使用されます。
|
関連項目: 簡単なユーザー定義の INTYPEファイルの例およびこのファイルからOTTユーティリティによって生成される完全なOUTTYPEファイルの例は、「OUTTYPEファイルの概要」を参照してください。 |
INTYPEファイル内の型指定によって、変換するオブジェクト・データ型の名前が指定されます。次の記述は、ユーザー作成INTYPEファイルの例です。
TYPE employee
TRANSLATE SALARY$ AS salary
DEPTNO AS department
TYPE ADDRESS
TYPE PURCHASE_ORDER AS p_o
型指定の構造は、次のとおりです。
TYPE type_name
[GENERATE type_identifier]
[AS type_identifier]
[VERSION [=] version_string]
[HFILE [=] hfile_name]
[CPPFILE [=] cppfile_name]
[TRANSLATE{member_name [AS identifier]}...]
type_nameの構文は、次のフォーマットに従います。
[schema_name.]type_name
この構文のschema_nameは、指定されたオブジェクト・データ型を所有するスキーマの名前です。type_nameは、その型の名前です。未指定の場合、デフォルト・スキーマはOTTユーティリティを起動しているユーザーIDのスキーマになります。特定のスキーマを使用するには、schema_nameを使用する必要があります。
型指定の構成要素は、次のとおりです。
type_name: オブジェクト・データ型の名前です。
type_identifier: クラスの表現に使用するCまたはC++の識別子です。GENERATE句は、OTTユーティリティが生成するクラスの名前を指定するために使用されます。記述するクラスの名前は、AS句によって指定されます。GENERATE句は、通常、クラスを拡張するために使用されます。ユーザー定義型を示すC構造体またはC++クラスの名前は、必要に応じて、GENERATE句を伴わずに、AS句によって指定されます。
version_string: 型のバージョン文字列です。OTTユーティリティが前の起動でコードを生成したときに使用した内容です。バージョン文字列は、OTTユーティリティによって生成され、OUTTYPEファイルに出力されます。このファイルは、後でOTTユーティリティを起動するときにINTYPEファイルとして使用できます。バージョンの文字列は、OTTユーティリティ操作には影響を与えませんが、実行中のプログラムで使用するオブジェクト・データ型のバージョンを選択するために使用できます。
hfile_name: 対応するクラスの宣言が書き込まれるヘッダー・ファイルの名前です。HFILE句を省略すると、コマンドラインのHFILEパラメータで指定したファイルが使用されます。
cppfile_name: 対応するクラスのメソッド実装が書き込まれるC++ソース・ファイルの名前です。CPPFILE句を省略すると、コマンドラインのCPPFILEパラメータで指定したファイルが使用されます。
member_name: 識別子に変換される属性(データ・メンバー)の名前です。
identifier: プログラムで属性を表現するために使用するCまたはC++の識別子です。この方法によって、任意の数の属性に対して識別子を指定できます。属性が指定されていない場合には、デフォルトの名前マッピング・アルゴリズムが使用されます。
オブジェクト・データ型は、次のいずれかの場合に変換する必要があります。
そのオブジェクト・データ型がINTYPEファイルに指定されている場合。
そのオブジェクト・データ型には変換が必要な別の型の宣言が必要で、TRANSITIVEパラメータがTRUEに設定されている場合。
明示的に記述されていない型が、あるファイル内で正確に宣言された型に必要とされる場合、必要とされる型の変換結果は、その結果を必要とする明示的に宣言された型と同じファイルに書き込まれます。
明示的に記述されていない型が、複数の異なるファイル内で宣言された型に必要とされる場合、必要とされる型の変換結果は、グローバルなHFILEファイルに書き込まれます。
|
注意: INTYPEファイルに指定されていない必要なオブジェクト型を、OTTユーティリティで生成するかどうかを指定できます。必要なオブジェクト型をOTTユーティリティで生成しない場合は、TRANSITIVE=FALSEを設定してください。デフォルトは、TRANSITIVE=TRUEです。 |
OTTユーティリティで生成したHFILEファイルには、他の必要なファイルをインクルード(#include)し、ファイル名から作成した記号を定義(#define)します。この定義(#define)された記号は、関連するHFILEファイルがすでにインクルード(#include)されているかどうかを判断するために使用できます。たとえば、データベースに次の型があると仮定します。
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 hr intype=tott95i.typ outtype=tott95o.typ code=cpp
...
Enter password: password
OTTユーティリティは、tott95a.hとtott95b.hというファイル名を持つ2つのヘッダー・ファイルを作成します。これらのファイルを次に示します。
例8-9 ott95a.hのリスト
#ifndef TOTT95A_ORACLE
# define TOTT95A_ORACLE
#ifndef OCCI_ORACLE
# include <occi.h>
#endif
/************************************************************/
// generated declarations for the PX1 object type.
/************************************************************/
class px1 : public oracle::occi::PObject {
protected:
oracle::occi::Number col1;
oracle::occi::Number col2;
public:
void *operator new(size_t size);
void *operator new(size_t size, const oracle::occi::Connection * sess,
const OCCI_STD_NAMESPACE::string& table);
void *operator new(size_t, void *ctxOCCI_);
void *operator new(size_t size, const oracle::occi::Connection *sess,
const OCCI_STD_NAMESPACE::string &tableName,
const OCCI_STD_NAMESPACE::string &typeName,
const OCCI_STD_NAMESPACE::string &tableSchema,
const OCCI_STD_NAMESPACE::string &typeSchema);
void getSQLTypeName(oracle::occi::Environment *env, void **schemaName,
unsigned int &schemaNameLen, void **typeName,
unsigned int &typeNameLen) const;
px1();
px1(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
static void *readSQL(void *ctxOCCI_);
virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
static void writeSQL(void *objOCCI_, void *ctxOCCI_);
virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
~px1();
};
#endif
例8-10 ott95b.hのリスト
#ifndef TOTT95B_ORACLE
# define TOTT95B_ORACLE
#ifndef OCCI_ORACLE
# include <occi.h>
#endif
#ifndef TOTT95A_ORACLE
# include "tott95a.h"
#endif
/************************************************************/
// generated declarations for the PX3 object type.
/************************************************************/
class px3 : public oracle::occi::PObject {
protected:
px1 * col1;
public:
void *operator new(size_t size);
void *operator new(size_t size, const oracle::occi::Connection * sess,
const OCCI_STD_NAMESPACE::string& table);
void *operator new(size_t, void *ctxOCCI_);
void *operator new(size_t size, const oracle::occi::Connection *sess,
const OCCI_STD_NAMESPACE::string &tableName,
const OCCI_STD_NAMESPACE::string &typeName,
const OCCI_STD_NAMESPACE::string &tableSchema,
const OCCI_STD_NAMESPACE::string &typeSchema);
void getSQLTypeName(oracle::occi::Environment *env, void **schemaName,
unsigned int &schemaNameLen, void **typeName,
unsigned int &typeNameLen) const;
px3();
px3(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
static void *readSQL(void *ctxOCCI_);
virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
static void writeSQL(void *objOCCI_, void *ctxOCCI_);
virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
~px3();
};
#endif
tott95b.hファイルでは、記号TOTT95B_ORACLEがファイルの先頭に定義(#define)されています。これによって、このヘッダー・ファイルを別のファイルに条件付きでインクルード(#include)できます。インクルードするには、次の構造体を使用します。
#ifndef TOTT95B_ORACLE #include "tott95b.h" #endif
この方法を使用すると、たとえば、foo.hにtott95b.hをインクルード(#include)できます。この場合、foo.hに他のファイルのインクルード(#include)があるかどうか、また、tott95b.hのインクルード(#include)があるかどうかを事前に知る必要はありません。
次に、ファイルtott95a.hがインクルードされます。これは、このファイルにはtott95b.hに必要なstruct px1の宣言が指定されているためです。INTYPEファイルの要求で、複数のファイルに型宣言を書き込む場合、OTTユーティリティは、各HFILEにインクルード(#include)する必要のある他のファイルを判断し、必要な#includeファイルをそれぞれ生成します。
OTTユーティリティでは、この#includeに" "が使用されます。tott95b.hがインクルードされているプログラムをコンパイルするとき、tott95a.hの検索は、ソース・プログラムが検出された場所から開始され、以降は実装定義の検索規則に従います。この方法でtott95a.hを検索できない場合は、完全なファイル名(スラッシュ文字(/)で始まるUNIXの絶対パス名など)をINTYPEファイルで使用して、tott95a.hの位置を指定する必要があります。
OTTユーティリティによって、データベース型からC++クラスが生成されると、構造体またはクラスには、オブジェクト型の各属性に対応する1つの要素が含まれます。属性のデータ型は、Oracleオブジェクト・データ型で使用される型にマッピングされます。Oracleのデータ型には、事前定義の基本的な一連の型が組み込まれており、オブジェクト型やコレクションなどのユーザー定義の型の作成をサポートします。
一連の事前定義の型には、数値型や文字型を含む、プログラマによく知られている標準の型があります。ラージ・オブジェクト・データ型(BLOBやCLOBなど)も含まれています。
例8-11 OTTユーティリティを使用したオブジェクト属性の表現方法
Oracleには、オブジェクト型属性をC++クラスで表現するための一連の事前定義の型も含まれています。次のようなオブジェクト型定義とそれに対応するOTT生成の構造体宣言を想定します。
CREATE TYPE employee AS OBJECT ( name VARCHAR2(30), empno NUMBER, deptno NUMBER, hiredate DATE, salary NUMBER );
CASEパラメータがLOWERに設定され、型名または属性名の明示的なマッピングがないと仮定すると、OTTユーティリティの出力は、次のようになります。
#ifndef DATATYPES_ORACLE
# define DATATYPES_ORACLE
#ifndef OCCI_ORACLE
# include <occi.h>
#endif
/************************************************************/
// generated declarations for the EMPLOYEE object type.
/************************************************************/
class employee : public oracle::occi::PObject {
protected:
OCCI_STD_NAMESPACE::string NAME;
oracle::occi::Number EMPNO;
oracle::occi::Number DEPTNO; oracle::occi::Date HIREDATE;
oracle::occi::Number SALARY;
public:
void *operator new(size_t size);
void *operator new(size_t size, const oracle::occi::Connection * sess,
const OCCI_STD_NAMESPACE::string& table);
void *operator new(size_t, void *ctxOCCI_);
void *operator new(size_t size, const oracle::occi::Connection *sess,
const OCCI_STD_NAMESPACE::string &tableName,
const OCCI_STD_NAMESPACE::string &typeName,
const OCCI_STD_NAMESPACE::string &tableSchema,
const OCCI_STD_NAMESPACE::string &typeSchema);
void getSQLTypeName(oracle::occi::Environment *env, void **schemaName,
unsigned int &schemaNameLen, void **typeName,
unsigned int &typeNameLen) const;
employee();
employee(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
static void *readSQL(void *ctxOCCI_);
virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
static void writeSQL(void *objOCCI_, void *ctxOCCI_);
virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
~employee();
};
#endif
表8-2は、属性として使用できる型から、OTTユーティリティで生成されるオブジェクト・データ型へのマッピングのリストです。
表8-2 オブジェクト型属性のC++オブジェクト・データ型マッピング
| オブジェクト属性の型 | C++マッピング |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ネストされたオブジェクト型のC++の名前 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例8-12 OTTユーティリティを使用したオブジェクト・データ型のマップ方法
この例では、次のデータベース型が作成されていることを想定しています。
CREATE TYPE my_varray AS VARRAY(5) of integer;
CREATE TYPE object_type AS OBJECT
(object_name VARCHAR2(20));
CREATE TYPE other_type AS OBJECT
(object_number NUMBER);
CREATE TYPE my_table AS TABLE OF object_type;
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
次の記述は、C++に関するOTTの型マッピングの例です。前項の例で作成された型と次のオプションを含むINTYPEファイルを前提にしています。
CASE = LOWER TYPE many_types
#ifndef MYFILENAME_ORACLE
#define MYFILENAME_ORACLE
#ifndef OCCI_ORACLE
#include <occi.h>
#endif
/************************************************************/
// generated declarations for the OBJECT_TYPE object type.
/************************************************************/
class object_type : public oracle::occi::PObject
{
protected:
OCCI_STD_NAMESPACE::string object_name;
public:
void *operator new(size_t size);
void *operator new(size_t size, const oracle::occi::Connection * sess,
const OCCI_STD_NAMESPACE::string& table);
void getSQLTypeName(oracle::occi::Environment *env, void **schemaName,
unsigned int &schemaNameLen, void **typeName,
unsigned int &typeNameLen) const;
object_type();
object_type(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
static void *readSQL(void *ctxOCCI_);
virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
static void writeSQL(void *objOCCI_, void *ctxOCCI_);
virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};
/************************************************************/
// generated declarations for the OTHER_TYPE object type.
/************************************************************/
class other_type : public oracle::occi::PObject
{
protected:
oracle::occi::Number object_number;
public:
void *operator new(size_t size);
void *operator new(size_t size, const oracle::occi::Connection * sess,
const OCCI_STD_NAMESPACE::string& table);
void getSQLTypeName(oracle::occi::Environment *env, void **schemaName,
unsigned int &schemaNameLen, void **typeName,
unsigned int &typeNameLen) const;
other_type();
other_type(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
static void *readSQL(void *ctxOCCI_);
virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
static void writeSQL(void *objOCCI_, void *ctxOCCI_);
virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};
/************************************************************/
// generated declarations for the MANY_TYPES object type.
/************************************************************/
class many_types : public oracle::occi::PObject
{
protected:
OCCI_STD_NAMESPACE::string the_varchar;
OCCI_STD_NAMESPACE::string the_char;
oracle::occi::Blob the_blob;
oracle::occi::Clob the_clob;
object_type * the_object;
oracle::occi::Ref< other_type > another_ref;
oracle::occi::Ref< many_types > the_ref;
OCCI_STD_NAMESPACE::vector< oracle::occi::Number > the_varray;
OCCI_STD_NAMESPACE::vector< object_type * > the_table;
oracle::occi::Date the_date;
oracle::occi::Number the_num;
oracle::occi::Bytes the_raw;
public:
void *operator new(size_t size);
void *operator new(size_t size, const oracle::occi::Connection * sess,
const OCCI_STD_NAMESPACE::string& table);
void getSQLTypeName(oracle::occi::Environment *env, void **schemaName,
unsigned int &schemaNameLen, void **typeName,
unsigned int &typeNameLen) const;
many_types();
many_types(void *ctxOCCI_) : oracle::occi::PObject (ctxOCCI_) { };
static void *readSQL(void *ctxOCCI_);
virtual void readSQL(oracle::occi::AnyData& streamOCCI_);
static void writeSQL(void *objOCCI_, void *ctxOCCI_);
virtual void writeSQL(oracle::occi::AnyData& streamOCCI_);
};
#endif
OTTユーティリティでは、次のC++クラス宣言が生成されます(コメントはOTT出力の一部ではなく、例を明解にする目的でのみ追加したものです)。
C++では、TRANSITIVE=TRUEの場合、OTTユーティリティは、変換する型の属性として使用されている型をすべて自動的に変換します。これには、オブジェクト型属性のポインタまたはREFによってのみアクセスされる型も含まれます。C++の例では、many_typesオブジェクトのみがINTYPEファイルに指定されていますが、クラス宣言はすべてのオブジェクト型に対して生成されています。これには、many_typesオブジェクトのREFによってのみアクセスされるother_typeオブジェクトも含まれています。
オブジェクト型または属性に対するCまたはC++の識別子名を作成する場合、OTTユーティリティは、その名前をデータベース・キャラクタ・セットから有効なCまたはC++の識別子に変換します。最初に、データベース・キャラクタ・セットからOTTユーティリティで使用するキャラクタ・セットに、名前が変換されます。次に、変換した結果の名前が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またはC++識別子で無効な文字またはコンパイラのキャラクタ・セットに変換内容がない文字は、アンダースコア(_)に置換されます。1文字でもアンダースコアに置換された場合、OTTユーティリティは警告メッセージを表示します。名前の中のすべての文字がアンダースコアに置換された場合、OTTユーティリティはエラー・メッセージを表示します。
文字単位の名前の変換では、コンパイラのキャラクタ・セットにあるアンダースコア、数字またはシングルバイト文字は変更されません。したがって、有効なCまたはC++の識別子は変更されません。
名前の変換では、ウムラウト付きのoやアクサングラーブ付きのaなどのアクセント付きシングルバイト文字を、それぞれo、aまたはアクセントなしに変換したり、マルチバイト文字をそれと等価のシングルバイトに変換する場合があります。名前に等価のシングルバイトがないマルチバイト文字がある場合、通常、その名前の変換はエラーとなります。この場合、ユーザーは、INTYPEファイルで名前の変換を指定する必要があります。
C言語の同一の名前に複数のデータベース識別子がマッピングされている場合に生じる名前の競合は、OTTユーティリティでは検出されません。また、データベース識別子がCキーワードにマッピングされるときの名前の問題も検出されません。
OUTTYPEファイルは、OTTコマンドラインで名前が指定されます。OTTユーティリティによって、C++ヘッダー・ファイルが生成されると、変換の結果がOUTTYPEファイルに出力されます。このファイルには、変換された各型のエントリが、そのバージョン文字列も含めて格納され、さらに、C++表現で記述されたヘッダー・ファイルが格納されます。
あるOTTユーティリティの実行によるOUTTYPEファイルは、そのOTTユーティリティのその後の起動でINTYPEファイルとして使用できます。
例8-13 OTTユーティリティによって生成されるOUTTYPEファイル
このINTYPEファイルでは、プログラマによって、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
INTYPEファイルで指定しなかった型がOUTTYPEファイルに含まれている場合があります。たとえば、INTYPEファイルにperson型のみの変換を指定した場合を想定します。
CASE = LOWER TYPE PERSON
person型の定義にaddress型の属性が含まれている場合、OUTTYPEファイルには、PERSONとADDRESSの両方のエントリが含まれます。person型を完全に変換するには、最初にaddressを変換する必要があります。
OTTユーティリティは、変換前にINTYPEファイルにある型の依存性を分析し、必要に応じて他の型を変換します。
|
注意: INTYPEファイルで指定されていない必要なオブジェクト型をOTTユーティリティで生成しないように指定するには、TRANSITIVE=FALSEを設定してください。デフォルトは、TRANSITIVE=TRUEです。 |
OTTユーティリティは、オブジェクトを生成し、SQLデータ型をC++クラスにマッピングします。OTTユーティリティは、オブジェクトをインスタンス化するときにOCCIがコールするいくつかのメソッドと、マッピングを環境に登録するためにOCCIアプリケーションでコールされる関数も実装しています。これらの宣言は、使用しているOCCIアプリケーションにインクルード(#include)するヘッダー・ファイルに格納されます。マッピングを登録する関数のプロトタイプは、OCCIアプリケーションにもインクルードされる独立したヘッダー・ファイルに記述されます。メソッド実装は、OCCIアプリケーションにリンクされているC++ソース・コード・ファイル(拡張子.cpp)に格納されます。マッピングを登録する関数は、アプリケーションにもリンクされている独立したC++(xxx.cpp)ファイルに格納されます。
図8-1は、OTTユーティリティをOCCIで使用する場合のステップを示しています。これらのステップは、次の図の後に説明します。
SQL DLLを使用してデータベースに型定義を作成します。
OTTユーティリティで変換するデータベース型が含まれたINTYPEファイルを作成します。
C++が生成されるように指定し、OTTユーティリティを起動します。
OTTユーティリティは、次のファイルを生成します。
オブジェクト型のC++クラス表現が含まれたヘッダー・ファイル(拡張子.h)。ファイル名は、HFILEパラメータによって、OTTコマンドラインに指定されます。
マッピングを登録する関数(MAPFUNC)のプロトタイプが含まれたヘッダー・ファイル。
オブジェクトをインスタンス化している間にOCCIがコールする静的メソッドが含まれたC++ソース・ファイル(拡張子.cpp)。これらのメソッドは、使用しているOCCIアプリケーションから直接コールしないでください。ファイル名は、CPPFILEパラメータによって、OTTコマンドラインに指定されます。
マッピングを環境に登録するために使用する関数が含まれたファイル(拡張子.cpp)。ファイル名は、MAPFILEパラメータによって、OTTコマンドラインに指定されます。
変換された各型のエントリ、バージョン文字列および変換結果を書き込むヘッダー・ファイルが含まれたファイル(OUTTYPEファイル)。ファイル名は、OUTTYPEパラメータによって、OTTコマンドラインに指定されます。
OCCIアプリケーションを記述し、OTTユーティリティで作成されたヘッダー・ファイルをOCCIソース・コード・ファイルにインクルードします。
アプリケーションで環境を宣言し、関数MAPFUNCをコールしてマッピングを登録します。
OCCIアプリケーションをコンパイルしてOCCIオブジェクト・コードを作成し、そのオブジェクト・コードをOCCIライブラリにリンクしてプログラム実行可能ファイルを作成します。
OTTユーティリティによって、データベース・オブジェクト型からC++クラスが生成されると、そのクラスの宣言には、オブジェクト型の各属性に対応する1つの要素が含まれます。属性のデータ型は、表8-2に定義されているように、Oracleオブジェクト・データ型で使用される型にマッピングされます。
各クラスごとに、2つのnew演算子、readSQL()メソッドおよびwriteSQL()メソッドが生成されます。これらは、オブジェクトのマーシャリングおよびアンマーシャリングの際にOCCIによって使用されます。
デフォルトでは、オブジェクト型に対してOTTユーティリティが生成したC++クラスはPObjectクラスから導出されるため、生成されたそのクラス内のコンストラクタもPObjectクラスから導出されます。継承されたデータベース型の場合、クラスは、生成されたコンストラクタのように親の型のクラスから導出され、親のクラスにはない属性に対応する要素のみが含まれます。
データベース型の属性に対応する要素を含むクラス宣言およびメソッド宣言は、OTTユーティリティによって生成されたヘッダー・ファイルに含まれます。メソッド実装は、OTTユーティリティによって生成されたCPPFILEファイルに含まれます。
例8-14 OTTユーティリティを使用してC++クラスを生成する方法
この例は、OTTユーティリティを使用してC++クラスを生成する方法を示しています。
型を定義します。
CREATE TYPE FULL_NAME AS OBJECT (first_name CHAR(20), last_name CHAR(20)); CREATE TYPE ADDRESS AS OBJECT (state CHAR(20), zip CHAR(20)); CREATE TYPE ADDRESS_TAB AS VARRAY(3) of REF ADDRESS; CREATE TYPE PERSON AS OBJECT (id NUMBER, name FULL_NAME, curr_addr REF ADDRESS, prev_addr_l ADDRESS_TAB) NOT FINAL; CREATE TYPE STUDENT UNDER PERSON (school_name CHAR(20));
INTYPEファイルを準備します。
CASE = SAME
MAPFILE = RegisterMappings_3.cpp
TYPE FULL_NAME AS FullName
TRANSLATE first_name as FirstName
last_name as LastName
TYPE ADDRESS
TYPE PERSON
TYPE STUDENT
OTTユーティリティを起動します。
ott userid=demousr intype=demoin_3.typ outype=demoout_3.typ code=cpp hfile=demo_3.h cppfile=demo_3.cpp
マッピングを環境に登録するために、1つの関数がOTTユーティリティによって生成されます。この関数には、OTTユーティリティの起動によって変換されるすべての型に対するマッピングが含まれています。関数名は、MAPFUNCパラメータに指定した名前になります。指定されていない場合は、MAPFILE パラメータから導出されます。この関数に対する引数は、Environmentへのポインタのみです。
この関数は、指定されたEnvironmentを使用してMapを取得し、変換した各タイプのマッピングを登録します。
OTTユーティリティによって生成されたクラスの機能を拡張するために、新しいクラスを導出できます。メソッドをクラスに追加することもできますが、内在するリスクがあるため、お薦めしません。
ADDRESS SQLオブジェクト型からCAddressクラスおよびMyAddressクラスの両方を生成することを想定します。MyAddressクラスは、CAddressクラスから導出できます。これを行うには、OTTユーティリティで生成するコードを次のように変更する必要があります。
CAddressクラスのかわりにMyAddressクラスを使用して、データ型がADDRESSの属性を表現します。
CAddressクラスのかわりにMyAddressクラスを使用して、データ型がADDRESSのベクターおよびREFの要素を表現します。
ADDRESSから継承されるデータベース・オブジェクト型のベース・クラスとして、CAddressクラスのかわりにMyAddressクラスを使用します。導出クラスがMyAddressのサブタイプである場合でも、コールされたreadSQL()メソッドとwriteSQL()メソッドは、CAddressクラスのメソッドです。
|
注意: あるクラスを、生成した別のクラスのベース・クラスとして拡張および使用する場合は、継承する型のクラスと継承される型のクラスを独立したファイルに生成する必要があります。 |
例8-15 OTTユーティリティを使用してC++クラスを拡張する方法
OTTユーティリティを使用してCAddressクラス(MyAddressクラスから導出)を生成するには、TYPE文に次の句を指定する必要があります。
TYPE ADDRESS GENERATE CAdress AS MyAddress
以前に作成したFULL_NAME、ADDRESS、PERSONおよびPFGRFDENTのデータベース型を指定し、INTYPEファイルを変更してGENERATE ... AS句を挿入します。
CASE = SAME
MAPFILE = RegisterMappings_5.cpp
TYPE FULL_NAME GENERATE CFullName AS MyFullName
TRANSLATE first_name as FirstName
last_name as LastName
TYPE ADDRESS GENERATE CAddress AS MyAddress
TYPE PERSON GENERATE CPerson AS MyPerson
TYPE STUDENT GENERATE CStudent AS MyStudent
OTT生成コードの機能を拡張するために、プログラマはOTT生成ファイルにコードを追加する場合があります。OTTは、事前定義されたマーカー(タグ)を検索することによって、OTT生成コードとユーザーが追加したコードを区別します。OTTでは、OTT_USERCODE_STARTを「ユーザー・コード・マーカーの開始」、OTT_USERCODE_ENDを「ユーザー・コード・マーカーの終了」と認識します。
OTTマーカーをサポートするため、ユーザー・ブロックは次のように定義されます。
OTT_USERCODE_START + user added code + OTT_USERCODE_END
OTTマーカーのサポートによって、*.hファイルおよび*.cppファイルのユーザーが追加したブロックを引き継ぐことができます。
次の各項では、OTTマーカーのサポートのプロパティについて説明します。
ユーザーは、ファイルを生成するために最初にOTTを起動するときから、コマンドライン・オプションUSE_MARKER=TRUEを使用する必要があります。
ユーザーは、マーカーを他のC++文と同様に処理する必要があります。コマンドライン・オプションUSE_MARKER=TRUEの使用時に、マーカーはOTTによって生成済ファイル内に次のように定義されます。
#ifndef OTT_USERCODE_START
#define OTT_USERCODE_START
#endif
#ifndef OTT_USERCODE_END
#define OTT_USERCODE_END
#endif
マーカーのOTT_USERCODE_STARTおよびOTT_USERCODE_ENDの前後には空白が必要です。
OTTは、次回のコード生成時に、マーカーに囲まれた指定のテキスト/コードをコピーします。
ユーザーが変更したコード:
1 // --- modified generated code
2 OTT_USERCODE_START
3 // --- including "myfullname.h"
4 #ifndef MYFULLNAME_ORACLE
5 #include "myfullname.h"
6 #endif
7 OTT_USERCODE_END
8 // --- end of code addition
引き継がれるコード:
1 OTT_USERCODE_START
2 // --- including "myfullname.h"
3 #ifndef MYFULLNAME_ORACLE
4 #include "myfullname.h"
5 #endif
6 OTT_USERCODE_END
次の例に示すように、データベースのTYPEファイルまたはINTYPEファイルが変更されると、OTTでは、ユーザーが追加したコードを正しく引き継ぐことができません。
ユーザーがタイプ名の大/小文字を変更すると、OTTでは、ユーザーがINTYPEファイル内のクラス名の大/小文字を変更する前にコードが関連付けられていたクラス名の検出に失敗します。
CASE=UPPER CASE=LOWER
TYPE employee TYPE employee
TRANSLATE SALARY$ AS salary TRANSLATE SALARY$ AS salary
DEPTNO AS department DEPTNO AS department
TYPE ADDRESS TYPE ADDRESS
TYPE item TYPE item
TYPE "Person" TYPE "Person"
TYPE PURCHASE_ORDER AS p_o TYPE PURCHASE_ORDER AS p_o
ユーザーが別の名前でクラスを生成するように要求した場合(INTYPEファイルのGENERATE AS 句)、OTTでは、ユーザーがINTYPEファイル内のクラス名を変更する前にコードが関連付けられていたクラス名の検出に失敗します。
CASE=LOWER CASE=LOWER TYPE employee TYPE employee TRANSLATE SALARY$ AS salary TRANSLATE SALARY$ AS salary DEPTNO AS department DEPTNO AS department TYPE ADDRESS TYPE ADDRESS TYPE item TYPE item TYPE "Person" TYPE "Person" TYPE PURCHASE_ORDER AS p_o TYPE PURCHASE_ORDER AS purchase_order
OTTで.hファイルまたは.cppファイルの解析中にエラーが発生した場合、そのエラーはレポートされ、ファイルはエラーが発生した状態のままになります。これによって、ユーザーは、レポートされたエラーを修正し、OTTを再実行できます。
OTTでは、次の場合にエラーが発生します。
OTT_USERCODE_STARTに対応するOTT_USERCODE_ENDが検出されない場合
マーカーがネストされている場合(OTTで、前のOTT_USERCODE_STARTに対応するOTT_USERCODE_ENDが検出される前に、次のOTT_USERCODE_STARTが検出された場合)
OTT_USERCODE_STARTの前にOTT_USERCODE_ENDが検出された場合
ユーザーは、マーカーのサポートを有効にするために、コマンドライン・オプションUSE_MARKER=TRUEを使用する必要があります。ユーザーが追加したコードをOTTマーカーが引き継ぐには、一般的には2つの方法があります。
.hファイルにユーザー・コードを追加する場合。
グローバル・スコープにユーザー・コードを追加する場合。通常は、ユーザーが別のヘッダー・ファイルを組み込んだり宣言を転送する必要がある場合です。後のコード例を参照してください。
クラス宣言にユーザー・コードを追加する場合。OTT生成のクラス宣言に、データ・メンバー用のプライベート・スコープとメソッド用のパブリック・スコープがある場合、またはデータ・メンバー用の保護付きスコープとメソッド用のパブリック・スコープがある場合です。ユーザー・ブロックは、OTT生成のすべての宣言の後、いずれかのアクセス指定子内に追加できます。
例8-16 OTTユーティリティを使用してユーザー・コードをヘッダー・ファイルに追加する方法
...
#ifndef OTT_USERCODE_START
#define OTT_USERCODE_START
#endif
#ifndef OTT_USERCODE_END
#define OTT_USERCODE_END
#endif
#ifndef OCCI_ORACLE
#include <occi.h>
#endif
OTT_USERCODE_START // user added code
...
OTT_USERCODE_END
#ifndef ... // OTT generated include
#include " ... "
#endif
OTT_USERCODE_START // user added code
...
OTT_USERCODE_END
class <class_name_1> : public oracle::occi::PObject
{ protected:
... // OTT generated data members
OTT_USERCODE_START // user added code for data member / method
... // declaration / inline method
OTT_USERCODE_END
public:
void *operator new(size_t size);
...
OTT_USERCODE_START // user added code for data member / method
... // declaration / inline method definition
OTT_USERCODE_END
};
OTT_USERCODE_START // user added code
...
OTT_USERCODE_END
class <class_name_2> : public oracle::occi::PObject
{
...
};
OTT_USERCODE_START // user added code
...
OTT_USERCODE_END
...
#endif // end of .h file
.cppファイルにユーザー・コードを追加する場合。 OTTでは、新規のユーザー定義メソッドをOTTマーカー内に追加できます。ユーザー・ブロックは、ファイルの先頭部分で、インクルード(include)の直後、かつOTT生成メソッドの定義の前に追加する必要があります。OTT生成のインクルード(include)が複数ある場合、ユーザー・コードは、それらのOTT生成のインクルード(include)の間にも追加できます。xxx.cppファイル内のこれ以外の位置に追加されたユーザー・コードは引き継がれません。
例8-17 OTTユーティリティを使用してユーザー・コードをソース・ファイルに追加する方法
#ifndef OTT_USERCODE_START
#define OTT_USERCODE_START
#endif
#ifndef OTT_USERCODE_END
#define OTT_USERCODE_END
#endif
...
OTT_USERCODE_START // user added code
...
OTT_USERCODE_END
...
OTT_USERCODE_START // user added code
...
OTT_USERCODE_END
/*************************************************************
/ generated method implementations for the ... object type.
/*************************************************************/
void *<class_name_1>::operator new(size_t size)
{
return oracle::occi::PObject::operator new(size);
}
...
// end of .cpp file