この章では、OCIDescribeAny()関数を使用して、スキーマ要素に関する情報を取得する方法を説明します。
この章は、次の項目で構成されています。
OCIDescribeAny()関数を使用すると、次のスキーマ・オブジェクトおよびそのサブスキーマ・オブジェクトを明示的に記述できます。
他のスキーマ要素(ファンクションの引数、列、型属性および型メソッド)の情報は、前述のスキーマ・オブジェクトのいずれかの記述、あるいはサブスキーマ・オブジェクトの明示的な記述によって取得できます。
アプリケーションで表を記述する場合は、その表の列の情報も取り出すことができます。さらに、OCIDescribeAny()では、表の列、関数のパッケージ、型のフィールドなどのサブスキーマ・オブジェクトの名前が指定されている場合、それらのサブスキーマ・オブジェクトを直接記述できます。
OCIDescribeAny()コールには、引数の1つとして記述ハンドルが必要です。記述ハンドルは、OCIHandleAlloc()へのコールを使用して、事前に割り当ててください。
次の図6-1に示すように、OCIDescribeAny()で戻された情報は、ツリーのように階層的に編成されています。
OCIDescribeAny()によって戻される記述ハンドルには、このような記述ツリーを指し示す属性OCI_ATTR_PARAMがあります。ツリーの各ノードには、そのノードに関連する属性、および再帰的な記述ハンドルのように詳細情報を含むサブツリーを指し示す属性があります。列リストなどのリスト要素のように、すべての属性が同じ構造である場合、それらの属性をパラメータと呼びます。ノードに関連付けられた属性はOCIAttrGet()によって、パラメータはOCIParamGet()によって戻されます。
表の記述ハンドルについてのOCIAttrGet()に対するコールは、列リストの情報のハンドルを戻します。アプリケーションでは、OCIParamGet()を使用して、列リスト内の特定の列の列記述へのハンドルを取り出します。列記述子へのハンドルをOCIAttrGet()へ受け渡すことによって、名前やデータ型などの列に関する詳細を得ることができます。
SQL文を実行した後、文ハンドルの属性として選択リストに関する情報を取得できます。明示的な記述コールは必要ありません。アプリケーションで文ハンドルから選択リストに関する情報を取り出すには、選択リストの各位置に対してOCIParamGet()を1回ずつコールし、その位置のパラメータ記述子を割り当てる必要があります。
|
注意: 後続の OCIAttrGet()コールまたはOCIParamGet()コールでは、すべての記述がOCIDescribeAny()によってクライアント側のキャッシュに保存されているので、追加のネットワーク・ラウンドトリップは発生しません。 |
OCIDescribeAny()コールは基本情報に戻される情報を制限し、それが別の記述になる場合、ノードの拡張を停止します。たとえば、表の列がオブジェクト型である場合、OCIは型を記述しているサブツリーを戻しません。その情報は別の記述によって取得できるからです。
OCIDescribeAny()によって、またはOCIStmtExecute()を暗黙的に使用することでは、表名は戻されません。列が表に関連付けられていないこともあります。ほとんどの場合、この表はすでに認識されています。
記述操作を行う際には、次の注意があります。
OCI_ATTR_TYPECODEは、CREATE TYPE文を使用して新しい型が作成されたときに、ユーザーが指定した型を表す型コードを戻します。これらの型コードは、数え上げ可能な型のOCITypeCodeで、OCI_TYPECODE定数で表されます。内部PL/SQL型(ブール、索引付き表)はサポートされません。
OCI_ATTR_DATA_TYPEは、データベースの列に格納されるデータ型を表す型コードを戻します。これらは、Oracleの以前のバージョンで戻される記述値に似ています。これらの値は、SQLT定数(ub2値)で表されます。BOOLEAN型はSQLT_BOLを戻します。
|
関連項目: 型コードの詳細( OCI_ATTR_TYPECODE属性に戻されるOCI_TYPCODE値、OCI_ATTR_DATA_TYPE属性に戻されるSQLT型コードなど)は、「型コード」を参照してください。 |
型オブジェクトを記述するには、OCIプロセスをオブジェクト・モードで初期化する必要があります。
/* Initialize the OCI Process */
if (OCIEnvCreate((OCIEnv **) &envhp, (ub4) OCI_OBJECT, (voivoid *) 0,
(void * (*)(void *,size_t)) 0,
(void * (*)(void *, void *, size_t)) 0,
(void (*)(void *, void *)) 0, (size_t) 0, (void **) 0))
{
printf("FAILED: OCIEnvCreate()\n");
return OCI_ERROR;
}
OCIStmtExecute()による暗黙的記述およびOCIDescribeAny()による明示的記述を使用して、列属性OCI_ATTR_PRECISIONを戻すことができます。暗黙的記述を使用する場合は、精度をsb2に設定する必要があります。明示的記述を使用する場合は、精度をプレースホルダに対してub1に設定する必要があります。この設定は、ディクショナリ内の精度のデータ型と一致させるために必要です。
型メソッド用のOCI_ATTR_LIST_ARGUMENTS属性は、そのメソッドの2番目のレベルの引数を表します。
たとえば、次のように、レコードmy_typeと、型my_typeの引数が指定されたプロシージャmy_procを指定します。
my_type record(a number, b char) my_proc (my_input my_type)
OCI_ATTR_LIST_ARGUMENTS属性は、my_typeレコードの引数aとbに適用されます。
パラメータは、OCIParamGet()によって戻されます。パラメータは、異なる種類のオブジェクトや情報を記述できます。また、パラメータの属性は、そのパラメータに含まれる記述の型や型固有の属性によって異なります。この項では、様々なパラメータに所属する属性およびハンドルについて説明します。
OCIDescribeAny()では、3つ以上の名前コンポーネント(たとえば、schema.type.attr1.attr2.method1)はサポートされないことに注意してください。コンポーネントが複数である場合、最初のコンポーネントはスキーマ名として解釈されます(他のフラグが設定されていない場合)。フラグの中には、オブジェクトがPUBLIC下で参照されるように指定する、つまり「a」を記述するものがあります(ここで、「a」はカレント・スキーマ内のオブジェクトまたはパブリック・シノニムのいずれか)。
オブジェクト型が何であるかわからない場合は、OCI_PTYPE_UNKを指定してください。これを指定しない場合、実際のオブジェクト型が指定した型と一致しない場合にはエラーが戻されます。
次の表6-1は、すべてのパラメータの属性のリストです。
表6-1 すべてのパラメータの属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
パラメータの数。 |
ub2 |
|
|
オブジェクトIDまたはスキーマID。 |
ub4 |
|
|
スキーマ内のデータベース名またはオブジェクト名。 |
OraText * |
|
|
そのオブジェクトが存在しているスキーマの名前。 |
OraText * |
|
|
パラメータによって記述される情報の種類。可能な値は次のとおりです。
|
ub1 |
|
|
Oracle日付書式がその記述の基礎となるオブジェクトのタイムスタンプ。 |
ub1 * |
次の項では、様々なパラメータの型に特有の属性およびハンドルのリストを示します。
表またはビューのパラメータ(OCI_PTYPE_TABLE型またはOCI_PTYPE_VIEW型)には、次の型特有の属性があります。
表6-2 表またはビューの属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
オブジェクトID。 |
ub4 |
|
|
列の数。 |
ub2 |
|
|
列リスト( |
void * |
|
|
エクステント表の場合の、基礎型のTDOへのREF。 |
OCIRef* |
|
|
表が一時表であることを示します。 |
ub1 |
|
|
|
表に型が指定されていることを示します。 |
ub1 |
|
一時表の継続時間。可能な値は次のとおりです。
|
OCIDuration |
その他に、表に所属する次の属性があります。
プロシージャまたはファンクションのパラメータ(OCI_PTYPE_PROC型またはOCI_PTYPE_FUNC型)の場合、型特有の属性は次のとおりです。
表6-4 プロシージャまたはファンクションの属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
引数リスト。「リスト属性」を参照してください。 |
void * |
|
|
プロシージャまたはファンクションに実行者権限があることを示します。 |
ub1 |
次の属性は、パッケージ・サブプログラムでのみ定義されます。
パッケージのパラメータ(OCI_PTYPE_PKG型)の場合、型特有の属性は次のとおりです。
型のパラメータの場合(OCI_PTYPE_TYPE型)、その属性は表6-7にリストされているとおりです。これらの属性は、OCIInitialize()のコールの際に、アプリケーションによってOCI_OBJECTモードでOCIプロセスが初期化される場合にのみ有効です。
表6-7 型の属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
列の型がオブジェクト型の場合は、その型の型記述子オブジェクトのメモリー内REFを戻します。OCIRef用の領域が確保されていない場合は、領域がキャッシュ内に暗黙的に割り当てられます。次に、コール元は |
OCIRef * |
|
|
型コード。「データ型コード」を参照してください。現在は、 |
OCITypeCode |
|
|
型がコレクションの場合はコレクションの型コードで、それ以外の場合は無効です。「データ型コード」を参照してください。現在は、 |
OCITypeCode |
|
|
不完全な型であることを示します。 |
ub1 |
|
|
システム型であることを示します。 |
ub1 |
|
|
事前定義済の型であることを示します。 |
ub1 |
|
|
一時的な型であることを示します。 |
ub1 |
|
|
システム生成型であることを示します。 |
ub1 |
|
|
NESTED TABLE属性を含む型です。 |
ub1 |
|
|
LOB属性を含む型です。 |
ub1 |
|
|
|
ub1 |
|
|
コレクション要素へのハンドル。「コレクション属性」を参照してください。 |
void * |
|
|
型属性の数。 |
ub2 |
|
|
型属性のリスト。「リスト属性」を参照してください。 |
void * |
|
|
型メソッドの数。 |
ub2 |
|
|
型メソッドのリスト。「リスト属性」を参照してください。 |
void * |
|
|
型のマップ・メソッド。「型メソッド属性」を参照してください。 |
void * |
|
|
型のオーダー・メソッド。「型メソッド属性」を参照してください。 |
void * |
|
|
型に実行者権限があることを示します。 |
ub1 |
|
|
型属性名である文字列へのポインタ。 |
OraText * |
|
|
型作成時のスキーマ名が付いた文字列。 |
OraText * |
|
|
最後の型であることを示します。 |
ub1 |
|
|
インスタンス化可能な型であることを示します。 |
ub1 |
|
|
サブタイプであることを示します。 |
ub1 |
|
|
スーパータイプを含むスキーマの名前。 |
OraText * |
|
|
スーパータイプの名前。 |
OraText * |
型の属性のパラメータの場合(OCI_PTYPE_TYPE_ATTR型)、その属性は表6-8にリストされているとおりです。
表6-8 型属性の属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
型属性の最大サイズ。この長さは、文字列と行について、文字ではなくバイト単位で戻されます。 |
ub2 |
|
|
型コード。「データ型コード」を参照してください。 |
OCITypeCode |
|
|
型属性のデータ型。「データ型コード」を参照してください。 |
ub2 |
|
|
型属性名である文字列へのポインタ。 |
OraText * |
|
|
数値型属性の精度。精度が0(ゼロ)以外でスケールが-127の場合は |
ub1 for explicit describe sb2 for implicit describe |
|
|
数値型属性のスケール。精度が0(ゼロ)以外でスケールが-127の場合は |
sb1 |
|
|
型名である文字列。データ型が |
OraText * |
|
|
型作成時のスキーマ名が付いた文字列。 |
OraText * |
|
|
列の型がオブジェクト型の場合は、その型のTDOのメモリー内 |
OCIRef * |
|
|
型属性が文字列/キャラクタ・タイプの場合は、キャラクタ・セットID。 |
ub2 |
|
|
型属性が文字列/キャラクタ・タイプの場合は、キャラクタ・セット・フォーム。 |
ub1 |
|
|
日時または時間隔の小数秒の精度。 |
ub1 |
|
|
時間隔の先行フィールドの精度。 |
ub1 |
型のメソッドのパラメータの場合(OCI_PTYPE_TYPE_METHOD型)、その属性は表6-9にリストされているとおりです。
表6-9 型メソッドの属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
メソッド名(プロシージャまたはファンクション)。 |
OraText * |
|
|
メソッドのカプセル化レベル( |
OCITypeEncap |
|
|
引数リスト。「OCI_ATTR_LIST_ARGUMENTSについての注意」および「リスト属性」を参照してください。 |
void * |
|
|
メソッドがコンストラクタであることを示します。 |
ub1 |
|
|
メソッドがデストラクタであることを示します。 |
ub1 |
|
|
メソッドが演算子であることを示します。 |
ub1 |
|
|
メソッドが自己参照的であることを示します。 |
ub1 |
|
|
メソッドがマップ・メソッドであることを示します。 |
ub1 |
|
|
メソッドがオーダー・メソッドであることを示します。 |
ub1 |
|
|
「Read No Data State」がメソッドに設定されていることを示します。 |
ub1 |
|
|
「Read No Process State」がメソッドに設定されていることを示します。 |
ub1 |
|
|
「Write No Data State」がメソッドに設定されていることを示します。 |
ub1 |
|
|
「Write No Process State」がメソッドに設定されていることを示します。 |
ub1 |
|
|
最後のメソッドであることを示します。 |
ub1 |
|
|
インスタンス化可能なメソッドであることを示します。 |
ub1 |
|
|
オーバーライドするメソッドであることを示します。 |
ub1 |
コレクション型のパラメータの場合(OCI_PTYPE_COLL型)、その属性は表6-10にリストされているとおりです。
表6-10 コレクション型の属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
型属性の最大サイズ。この長さは、文字列と行について、文字ではなくバイト単位で戻されます。 |
ub2 |
|
|
型コード。「データ型コード」を参照してください。 |
OCITypeCode |
|
|
型属性のデータ型。「データ型コード」を参照してください。 |
ub2 |
|
|
配列の要素の数。コレクションが配列である場合にのみ有効です。 |
ub4 |
|
|
型属性名である文字列へのポインタ。 |
OraText * |
|
|
数値型属性の精度。精度が0(ゼロ)以外でスケールが-127の場合はFLOATで、それ以外の場合は |
ub1 for explicit describe sb2 for implicit describe |
|
|
数値型属性のスケール。精度が0(ゼロ)以外でスケールが-127の場合は |
sb1 |
|
|
型名である文字列。データ型が |
OraText * |
|
|
型作成時のスキーマ名が付いた文字列。 |
OraText * |
|
|
列の型がオブジェクト型の場合は、その型のTDOのメモリー内REFを戻します。OCIRef用の領域が確保されていない場合は、領域がキャッシュ内に暗黙的に割り当てられます。次に、コール元は |
OCIRef * |
|
|
型属性が文字列/キャラクタ・タイプの場合は、キャラクタ・セットID。 |
ub2 |
|
|
型属性が文字列/キャラクタ・タイプの場合は、キャラクタ・セット・フォーム。 |
ub1 |
順序のパラメータの場合(OCI_PTYPE_SEQ型)、その属性は表6-12にリストされているとおりです。
表6-12 順序の属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
オブジェクトID。 |
ub4 |
|
|
最小値(Oracle |
ub1 * |
|
|
最大値(Oracle |
ub1 * |
|
|
増分(Oracle |
ub1 * |
|
|
キャッシュされた順序番号の数。順序がキャッシュされた順序でない場合は、0(ゼロ)です(Oracle |
ub1 * |
|
|
順序が順序指定されているかどうか。 |
ub1 |
|
|
最高水位標( |
ub1 * |
表またはビューの列のパラメータの場合(OCI_PTYPE_COL型)、その属性は表6-13にリストされているとおりです。
表6-13 表またはビューの列の属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
列の長さセマンティクスの型を戻します。0(ゼロ)はバイト長セマンティクスを示し、1は文字長セマンティクスを示します。「記述での文字長セマンティクスのサポート」を参照してください。 |
ub1 |
|
|
列の文字長を戻します。この文字長は列で許容できる文字数です。これに対して、バイト長を取得するのは |
ub2 |
|
|
列の最大サイズ。この長さは、文字列と行について、文字ではなくバイト単位で戻されます。 |
ub2 |
|
|
列のデータ型。「データ型コード」を参照してください。 |
ub2 |
|
|
列名である文字列へのポインタ。 |
OraText * |
|
|
数値列の精度。精度が0(ゼロ)以外でスケールが-127の場合は |
ub1 for explicit describe sb2 for implicit describe |
|
|
数値列のスケール。精度が0(ゼロ)以外でスケールが-127の場合はFLOATで、それ以外の場合は |
sb1 |
|
|
列にNULL値が許可されていない場合に、0(ゼロ)を戻します。CUBEまたはROLLUP操作に対する正しい値を戻しません。 |
ub1 |
|
|
型名である文字列を戻します。データ型が |
OraText * |
|
|
型の作成時に使用したスキーマ名を持つ文字列を戻します。 |
OraText * |
|
|
列の型がオブジェクト型の場合は、その型のTDOの |
OCIRef * |
|
|
列が文字列/キャラクタ・タイプの場合は、キャラクタ・セットID。 |
ub2 |
|
|
列が文字列/キャラクタ・タイプの場合は、キャラクタ・セット・フォーム。 |
ub1 |
プロシージャやファンクションの引数のパラメータ(OCI_PTYPE_ARG型)、型メソッドの引数のパラメータ(OCI_PTYPE_TYPE_ARG型)またはメソッド結果のパラメータ(OCI_PTYPE_TYPE_RESULT型)の場合、属性は表6-14にリストされているとおりです。
表6-14 引数および結果の属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
引数名である文字列へのポインタを戻します。 |
OraText * |
|
|
引数リストの引数の位置。常に0(ゼロ)を戻します。 |
ub2 |
|
|
型コード。「データ型コード」を参照してください。 |
OCITypeCode |
|
|
引数のデータ型。「データ型コード」を参照してください。 |
ub2 |
|
|
引数のデータ型のサイズ。この長さは、文字列と行について、文字ではなくバイト単位で戻されます。 |
ub2 |
|
|
数値引数の精度。精度が0(ゼロ)以外でスケールが-127の場合は |
明示的記述の場合は 暗黙的記述の場合は |
|
|
数値引数のスケール。精度が0(ゼロ)以外でスケールが-127の場合は |
|
|
|
データ型のレベル。この属性は常に0(ゼロ)を戻します。 |
ub2 |
|
|
引数にデフォルト値があるかどうかを示します。 |
ub1 |
|
|
|
次のレベルの引数のリスト(引数がレコード型または表型のとき)。 |
void * |
|
次の引数モードを示します。 0はIN( 1はOUT( 2はIN/OUT( |
OCITypeParamMode |
|
|
基数を戻します(数値型の場合)。 |
ub1 |
|
|
列にNULL値が許可されていない場合に、0(ゼロ)を戻します。 |
ub1 |
|
|
型名である文字列、またはパッケージのローカル型の場合は、パッケージ名の文字列を戻します。データ型がSQLT_NTYまたはSQLT_REFの場合は、戻される値には型名が含まれます。データ型がSQLT_NTYの場合は、名前付きデータ型の型名が戻されます。データ型がSQLT_REFの場合は、REFによって示されている名前付きデータ型の型名が戻されます。 |
OraText * |
|
|
SQLT_NTYまたはSQLT_REFについては、型の作成時に使用したスキーマ名を持つ文字列を戻すか、パッケージのローカル型の場合には、そのパッケージの作成時に使用したスキーマ名を持つ文字列を戻します。 |
OraText * |
|
|
SQLT_NTYまたはSQLT_REFについては、パッケージのローカル型の場合に、型名を持つ文字列を戻します。 |
OraText * |
|
|
SQLT_NTYまたはSQLT_REFについては、型が存在しているデータベースのデータベース・リンク名を持つ文字列を戻します。この動作は、パッケージがリモートで、そのパッケージがローカル型の場合にのみ発生します。 |
OraText * |
|
|
引数の型がオブジェクトの場合に、その型のTDOのREFを戻します。 |
OCIRef * |
|
|
引数が文字列/キャラクタ・タイプの場合に、キャラクタ・セットIDを戻します。 |
ub2 |
|
|
引数が文字列/キャラクタ・タイプの場合に、キャラクタ・セット・フォームを戻します。 |
ub1 |
列、引数またはサブプログラムのリストのパラメータ(OCI_PTYPE_LIST型)の場合、型特有の属性およびハンドル(パラメータ)は次のとおりです。
リストには、リスト型を指定するOCI_ATTR_LIST_TYPE属性があります。リストの横断時に可能な値とその下限は次のとおりです。
表6-15 リスト属性
| リスト属性 | 説明 | 下限 |
|---|---|---|
|
|
列リスト。 |
1 |
|
プロシージャ引数リスト。 |
1 |
|
|
ファンクション引数リスト。 |
0 |
|
|
サブプログラム・リスト。 |
0 |
|
|
型属性リスト。 |
1 |
|
|
型メソッド・リスト。 |
1 |
|
|
結果引数なしの型メソッド・リスト。 |
0 |
|
|
結果引数なしの型メソッド・リスト。 |
1 |
|
|
スキーマ内のオブジェクト・リスト。 |
0 |
|
|
データベース内のスキーマ・リスト。 |
0 |
各リストには、LowerBound ..OCI_ATTR_NUM_PARAMSパラメータがあります。LowerBoundは、表6-15「リスト属性」の「下限」列の値です。ファンクション引数リストの場合、位置0には、戻り値(OCI_PTYPE_ARG型)のパラメータがあります。
データベース型のパラメータの場合(OCI_PTYPE_DATABASE型)、その属性は表6-17にリストされているとおりです。
表6-17 データベース固有の属性
| 属性 | 説明 | 属性データ型 |
|---|---|---|
|
データベースのバージョン。 |
OraText * |
|
|
サーバー・ハンドルからのデータベース・キャラクタ・セットID。 |
ub2 |
|
|
サーバー・ハンドルからのデータベース・キャラクタ・セットID。 |
ub2 |
|
|
データベース内のスキーマのリスト( |
ub1 |
|
|
プロシージャ名の最大長。 |
ub4 |
|
|
列名の最大長。 |
ub4 |
|
|
カーソルおよびデータベース内のプリコンパイルされたSQL文に、コミット操作を反映させる方法。値は次のとおりです。
|
ub1 |
|
|
カタログ(データベース)名の最大長。 |
ub1 |
|
|
修飾表内のカタログの位置。値は |
ub1 |
|
|
データベースがセーブポイントをサポートするかどうか。値は |
ub1 |
|
|
データベースがNOWAIT句をサポートするかどうか。値は |
ub1 |
|
|
DDL文で自動コミット・モードが必要かどうか。値は |
ub1 |
|
|
データベースのロック・モード。値は |
ub1 |
ルールのパラメータの場合(OCI_PTYPE_RULE型)、その属性は表6-18にリストされているとおりです。
Oracle9i以上での問合せ情報と列情報は文字長セマンティクスでサポートされます。
記述ハンドルの次の属性は、文字長セマンティクスをサポートします。
OCI_ATTR_CHAR_SIZEでは、列の文字長を取得します。この文字長は列で許容できる文字数です。これに対して、バイト長を取得するのはOCI_ATTR_DATA_SIZEです。
ストアド・プロシージャ・パラメータがバインドされていないため、属性OCI_ATTR_CHAR_SIZEまたはOCI_ATTR_DATA_SIZEを使用してOCIAttrGet()をコールすると、ストアド・プロシージャ・パラメータのデータは戻されません。
OCI_ATTR_CHAR_USEDでは、列の長さセマンティクスの型を取得します。0(ゼロ)はバイト長セマンティクスを示し、1は文字長セマンティクスを示します。
アプリケーションでは、OCIStmtExecute()を使用して選択リスト問合せを暗黙的にも明示的にも記述できます。その他のスキーマ要素は、OCIDescribeAny()を使用して明示的に記述する必要があります。
データベース列が文字長セマンティクスを使用して作成されている場合、暗黙的な記述情報には、文字長、バイト長、およびデータベース列の作成方法を示すフラグが含まれます。OCI_ATTR_CHAR_SIZEは、列または式の文字長です。この場合、OCI_ATTR_CHAR_USEDフラグは、列または式が文字長セマンティクスを使用して作成されたことを示す1になります。
OCI_ATTR_DATA_SIZEは、すべてのデータ、すなわちOCI_ATTR_CHAR_SIZEの文字数と同じだけのデータを保持するのに十分な大きさの値になります。OCI_ATTR_DATA_SIZEは通常、(OCI_ATTR_CHAR_SIZE)×(クライアントの各文字の最大バイト)の値に設定されます。
データベース列がバイト長セマンティクスを使用して作成されている場合、暗黙的な記述による動作は、リリース1(9.0.1)より前と同じになります。戻されるOCI_ATTR_DATA_SIZEは、(列のバイト長)×(クライアントとサーバーのキャラクタ・セット間での最大変換率)の値になります。つまり、(列のバイト長)÷(サーバーの各文字の最大バイト数)×(クライアントの各文字の最大バイト数)になります。OCI_ATTR_CHAR_USEDは0で、OCI_ATTR_CHAR_SIZEはOCI_ATTR_DATA_SIZEと同じ値に設定されます。
次の例では、異なる種類のスキーマ・オブジェクトを記述するためのOCIDescribeAny()の使用方法を示します。より詳細なコード例は、Oracleのインストールに含まれているデモ・プログラムcdemodsa.cを参照してください。
この例では、表の列データ型を取り出す明示的な記述の使用方法を示しています。
...
int i=0;
text objptr[] = "EMPLOYEES"; /* the name of a table to be described */
ub2 numcols, col_width;
ub1 char_semantics;
ub2 coltyp;
ub4 objp_len = (ub4) strlen((char *)objptr);
OCIParam *parmh = (OCIParam *) 0; /* parameter handle */
OCIParam *collsthd = (OCIParam *) 0; /* handle to list of columns */
OCIParam *colhd = (OCIParam *) 0; /* column handle */
OCIDescribe *dschp = (OCIDescribe *)0; /* describe handle */
OCIHandleAlloc((void *)envhp, (void **)&dschp,
(ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (void **)0);
/* get the describe handle for the table */
if (OCIDescribeAny(svch, errh, (void *)objptr, objp_len, OCI_OTYPE_NAME, 0,
OCI_PTYPE_TABLE, dschp))
return OCI_ERROR;
/* get the parameter handle */
if (OCIAttrGet((void *)dschp, OCI_HTYPE_DESCRIBE, (void *)&parmh, (ub4 *)0,
OCI_ATTR_PARAM, errh))
return OCI_ERROR;
/* The type information of the object, in this case, OCI_PTYPE_TABLE,
is obtained from the parameter descriptor returned by the OCIAttrGet(). */
/* get the number of columns in the table */
numcols = 0;
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM, (void *)&numcols, (ub4 *)0,
OCI_ATTR_NUM_COLS, errh))
return OCI_ERROR;
/* get the handle to the column list of the table */
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM, (void *)&collsthd, (ub4 *)0,
OCI_ATTR_LIST_COLUMNS, errh)==OCI_NO_DATA)
return OCI_ERROR;
/* go through the column list and retrieve the data-type of each column,
and then recursively describe column types. */
for (i = 1; i <= numcols; i++)
{
/* get parameter for column i */
if (OCIParamGet((void *)collsthd, OCI_DTYPE_PARAM, errh, (void **)&colhd, (ub4)i))
return OCI_ERROR;
/* for example, get datatype for ith column */
coltyp = 0;
if (OCIAttrGet((void *)colhd, OCI_DTYPE_PARAM, (void *)&coltyp, (ub4 *)0,
OCI_ATTR_DATA_TYPE, errh))
return OCI_ERROR;
/* Retrieve the length semantics for the column */
char_semantics = 0;
OCIAttrGet((void*) colhd, (ub4) OCI_DTYPE_PARAM,
(void*) &char_semantics,(ub4 *) 0, (ub4) OCI_ATTR_CHAR_USED,
(OCIError *) errh);
col_width = 0;
if (char_semantics)
/* Retrieve the column width in characters */
OCIAttrGet((void*) colhd, (ub4) OCI_DTYPE_PARAM,
(void*) &col_width, (ub4 *) 0, (ub4) OCI_ATTR_CHAR_SIZE,
(OCIError *) errh);
else
/* Retrieve the column width in bytes */
OCIAttrGet((void*) colhd, (ub4) OCI_DTYPE_PARAM,
(void*) &col_width,(ub4 *) 0, (ub4) OCI_ATTR_DATA_SIZE,
(OCIError *) errh);
}
if (dschp)
OCIHandleFree((void *) dschp, OCI_HTYPE_DESCRIBE);
...
プロシージャとファンクションの違いは、ファンクションには引数リストに位置0(ゼロ)の戻り型がありますが、プロシージャには、引数リストの位置0(ゼロ)に対応する引数がないことです。型メソッドの記述に必要なステップ(ファンクションとプロシージャへの分割も行います)は、通常のPL/SQLファンクションおよびプロシージャのステップとまったく同じです。プロシージャおよびファンクションは、オブジェクトのデフォルト型を引数として使用できることに注意してください。次のプロシージャで考えてみます。
P1 (arg1 emp.sal%type, arg2 emp%rowtype)
emp表の各行には、name(VARCHAR2(20))およびsal(NUMBER)の2列があるとします。P1の引数リストには、arg1とarg2の2つの引数がそれぞれレベル0(ゼロ)の位置1と位置2にあり、引数のnameとsalがそれぞれレベル1の位置1と位置2にあります。P1の記述では、引数の数として2を戻し、レベル0(ゼロ)を超える(> 0)引数を、レベル0(ゼロ)の引数の属性として戻します。
...
int i = 0, j = 0;
text objptr[] = "add_job_history"; /* the name of a procedure to be described */
ub4 objp_len = (ub4)strlen((char *)objptr);
ub2 numargs = 0, numargs1, pos, level;
text *name, *name1;
ub4 namelen, namelen1;
OCIParam *parmh = (OCIParam *) 0; /* parameter handle */
OCIParam *arglst = (OCIParam *) 0; /* list of args */
OCIParam *arg = (OCIParam *) 0; /* argument handle */
OCIParam *arglst1 = (OCIParam *) 0; /* list of args */
OCIParam *arg1 = (OCIParam *) 0; /* argument handle */
OCIDescribe *dschp = (OCIDescribe *)0; /* describe handle */
OCIHandleAlloc((void *)envhp, (void **)&dschp,
(ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (void **)0);
/* get the describe handle for the procedure */
if (OCIDescribeAny(svch, errh, (void *)objptr, objp_len, OCI_OTYPE_NAME, 0,
OCI_PTYPE_PROC, dschp))
return OCI_ERROR;
/* get the parameter handle */
if (OCIAttrGet((void *)dschp, OCI_HTYPE_DESCRIBE, (void *)&parmh, (ub4 *)0,
OCI_ATTR_PARAM, errh))
return OCI_ERROR;
/* Get the number of arguments and the arg list */
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM, (void *)&arglst,
(ub4 *)0, OCI_ATTR_LIST_ARGUMENTS, errh))
return OCI_ERROR;
if (OCIAttrGet((void *)arglst, OCI_DTYPE_PARAM, (void *)&numargs, (ub4 *)0,
OCI_ATTR_NUM_PARAMS, errh))
return OCI_ERROR;
/* For a procedure, we begin with i = 1; for a
function, we begin with i = 0. */
for (i = 1; i <= numargs; i++) {
OCIParamGet ((void *)arglst, OCI_DTYPE_PARAM, errh, (void **)&arg, (ub4)i);
namelen = 0;
OCIAttrGet((void *)arg, OCI_DTYPE_PARAM, (void *)&name, (ub4 *)&namelen,
OCI_ATTR_NAME, errh);
/* to print the attributes of the argument of type record
(arguments at the next level), traverse the argument list */
OCIAttrGet((void *)arg, OCI_DTYPE_PARAM, (void *)&arglst1, (ub4 *)0,
OCI_ATTR_LIST_ARGUMENTS, errh);
/* check if the current argument is a record. For arg1 in the procedure
arglst1 is NULL. */
if (arglst1) {
numargs1 = 0;
OCIAttrGet((void *)arglst1, OCI_DTYPE_PARAM, (void *)&numargs1, (ub4 *)0,
OCI_ATTR_NUM_PARAMS, errh);
/* Note that for both functions and procedures,the next higher level
arguments start from index 1. For arg2 in the procedure, the number of
arguments at the level 1 would be 2 */
for (j = 1; j <= numargs1; j++) {
OCIParamGet((void *)arglst1, OCI_DTYPE_PARAM, errh, (void **)&arg1,
(ub4)j);
namelen1 = 0;
OCIAttrGet((void *)arg1, OCI_DTYPE_PARAM, (void *)&name1, (ub4 *)&namelen1,
OCI_ATTR_NAME, errh);
}
}
}
if (dschp)
OCIHandleFree((void *) dschp, OCI_HTYPE_DESCRIBE);
...
この例では、名前付きオブジェクト型についての明示的な記述の使用方法を示します。オブジェクトを名前またはオブジェクト参照(OCIRef)によって記述する方法を説明します。次のコード・フラグメントによって、オブジェクト型の属性について各データ型値の取出しが試みられます。
...
int i = 0;
text type_name[] = "inventory_typ";
ub4 type_name_len = (ub4)strlen((char *)type_name);
OCIRef *type_ref = (OCIRef *) 0;
ub2 numattrs = 0, describe_by_name = 1;
ub2 datatype = 0;
OCITypeCode typecode = 0;
OCIDescribe *dschp = (OCIDescribe *) 0; /* describe handle */
OCIParam *parmh = (OCIParam *) 0; /* parameter handle */
OCIParam *attrlsthd = (OCIParam *) 0; /* handle to list of attrs */
OCIParam *attrhd = (OCIParam *) 0; /* attribute handle */
/* allocate describe handle */
if (OCIHandleAlloc((void *)envh, (void **)&dschp,
(ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (void **)0))
return OCI_ERROR;
/* get the describe handle for the type */
if (describe_by_name) {
if (OCIDescribeAny(svch, errh, (void *)type_name, type_name_len,
OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE, dschp))
return OCI_ERROR;
}
else {
/* get ref to type using OCIAttrGet */
/* get the describe handle for the type */
if (OCIDescribeAny(svch, errh, (void*)type_ref, 0, OCI_OTYPE_REF,
0, OCI_PTYPE_TYPE, dschp))
return OCI_ERROR;
}
/* get the parameter handle */
if (OCIAttrGet((void *)dschp, OCI_HTYPE_DESCRIBE, (void *)&parmh, (ub4 *)0,
OCI_ATTR_PARAM, errh))
return OCI_ERROR;
/* The type information of the object, in this case, OCI_PTYPE_TYPE, is
obtained from the parameter descriptor returned by the OCIAttrGet */
/* get the number of attributes in the type */
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM, (void *)&numattrs, (ub4 *)0,
OCI_ATTR_NUM_TYPE_ATTRS, errh))
return OCI_ERROR;
/* get the handle to the attribute list of the type */
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM, (void *)&attrlsthd, (ub4 *)0,
OCI_ATTR_LIST_TYPE_ATTRS, errh))
return OCI_ERROR;
/* go through the attribute list and retrieve the data-type of each attribute,
and then recursively describe attribute types. */
for (i = 1; i <= numattrs; i++)
{
/* get parameter for attribute i */
if (OCIParamGet((void *)attrlsthd, OCI_DTYPE_PARAM, errh, (void **)&attrhd, i))
return OCI_ERROR;
/* for example, get datatype and typecode for attribute; note that
OCI_ATTR_DATA_TYPE returns the SQLT code, while OCI_ATTR_TYPECODE returns the
Oracle Type System typecode. */
datatype = 0;
if (OCIAttrGet((void *)attrhd, OCI_DTYPE_PARAM, (void *)&datatype, (ub4 *)0,
OCI_ATTR_DATA_TYPE,errh))
return OCI_ERROR;
typecode = 0;
if (OCIAttrGet((void *)attrhd, OCI_DTYPE_PARAM,(void *)&typecode, (ub4 *)0,
OCI_ATTR_TYPECODE, errh))
return OCI_ERROR;
/* if attribute is an object type, recursively describe it */
if (typecode == OCI_TYPECODE_OBJECT)
{
OCIRef *attr_type_ref;
OCIDescribe *nested_dschp;
/* allocate describe handle */
if (OCIHandleAlloc((void *)envh,(void**)&nested_dschp,
(ub4)OCI_HTYPE_DESCRIBE,(size_t)0, (void **)0))
return OCI_ERROR;
if (OCIAttrGet((void *)attrhd, OCI_DTYPE_PARAM,
(void *)&attr_type_ref, (ub4 *)0, OCI_ATTR_REF_TDO,errh))
return OCI_ERROR;
OCIDescribeAny(svch, errh,(void*)attr_type_ref, 0,
OCI_OTYPE_REF, 0, OCI_PTYPE_TYPE, nested_dschp);
/* go on describing the attribute type... */
}
}
if (dschp)
OCIHandleFree((void *) dschp, OCI_HTYPE_DESCRIBE);
...
この例では、名前付きコレクション型についての明示的な記述の使用方法を示しています。
text type_name[] = "phone_list_typ";
ub4 type_name_len = (ub4) strlen((char *)type_name);
OCIRef *type_ref = (OCIRef *) 0;
ub2 describe_by_name = 1;
ub4 num_elements = 0;
OCITypeCode typecode = 0, collection_typecode = 0, element_typecode = 0;
void *collection_element_parmh = (void *) 0;
OCIDescribe *dschp = (OCIDescribe *) 0; /* describe handle */
OCIParam *parmh = (OCIParam *) 0; /* parameter handle */
/* allocate describe handle */
if (OCIHandleAlloc((void *)envh, (void **)&dschp,
(ub4)OCI_HTYPE_DESCRIBE, (size_t)0, (void **)0))
return OCI_ERROR;
/* get the describe handle for the type */
if (describe_by_name) {
if (OCIDescribeAny(svch, errh, (void *)type_name, type_name_len,
OCI_OTYPE_NAME, 0, OCI_PTYPE_TYPE, dschp))
return OCI_ERROR;
}
else {
/* get ref to type using OCIAttrGet */
/* get the describe handle for the type */
if (OCIDescribeAny(svch, errh, (void*)type_ref, 0, OCI_OTYPE_REF,
0, OCI_PTYPE_TYPE, dschp))
return OCI_ERROR;
}
/* get the parameter handle */
if (OCIAttrGet((void *)dschp, OCI_HTYPE_DESCRIBE, (void *)&parmh, (ub4 *)0,
OCI_ATTR_PARAM, errh))
return OCI_ERROR;
/* get the Oracle Type System type code of the type to determine that this is a
collection type */
typecode = 0;
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM,(void *)&typecode, (ub4 *)0,
OCI_ATTR_TYPECODE, errh))
return OCI_ERROR;
/* if typecode is OCI_TYPECODE_NAMEDCOLLECTION,
proceed to describe collection element */
if (typecode == OCI_TYPECODE_NAMEDCOLLECTION)
{
/* get the collection's type: ie, OCI_TYPECODE_VARRAY or OCI_TYPECODE_TABLE */
collection_typecode = 0;
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM, (void *)&collection_typecode,
(ub4 *)0,
OCI_ATTR_COLLECTION_TYPECODE, errh))
return OCI_ERROR;
/* get the collection element; you MUST use this to further retrieve information
about the collection's element */
if (OCIAttrGet((void *)parmh, OCI_DTYPE_PARAM, &collection_element_parmh,
(ub4 *)0,
OCI_ATTR_COLLECTION_ELEMENT, errh))
return OCI_ERROR;
/* get the number of elements if collection is a VARRAY; not valid for nested
tables */
if (collection_typecode == OCI_TYPECODE_VARRAY) {
if (OCIAttrGet((void *)collection_element_parmh, OCI_DTYPE_PARAM,
(void *)&num_elements, (ub4 *)0, OCI_ATTR_NUM_ELEMS, errh))
return OCI_ERROR;
}
/* now use the collection_element parameter handle to retrieve information about
the collection element */
element_typecode = 0;
if (OCIAttrGet((void *)collection_element_parmh, OCI_DTYPE_PARAM,
(void *)&element_typecode, (ub4 *)0, OCI_ATTR_TYPECODE, errh))
return OCI_ERROR;
/* do the same to describe additional collection element information; this is
very similar to describing type attributes */
}
if (dschp)
OCIHandleFree((void *) dschp, OCI_HTYPE_DESCRIBE);
...
次のコード例では、問合せ実行に続く問合せに対応した列名やデータ型を取り出すループを示しています。この問合せは、事前にOCIStmtPrepare()のコールによって文ハンドルと関連付けられています。
...
OCIParam *mypard = (OCIParam *) 0;
ub2 dtype;
text *col_name;
ub4 counter, col_name_len, char_semantics;
ub2 col_width;
sb4 parm_status;
text *sqlstmt = (text *)"SELECT * FROM employees WHERE employee_id = 100";
checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (OraText *)sqlstmt,
(ub4)strlen((char *)sqlstmt),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, 0, 0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT));
/* Request a parameter descriptor for position 1 in the select-list */
counter = 1;
parm_status = OCIParamGet((void *)stmthp, OCI_HTYPE_STMT, errhp,
(void **)&mypard, (ub4) counter);
/* Loop only if a descriptor was successfully retrieved for
current position, starting at 1 */
while (parm_status == OCI_SUCCESS) {
/* Retrieve the datatype attribute */
checkerr(errhp, OCIAttrGet((void*) mypard, (ub4) OCI_DTYPE_PARAM,
(void*) &dtype,(ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE,
(OCIError *) errhp ));
/* Retrieve the column name attribute */
col_name_len = 0;
checkerr(errhp, OCIAttrGet((void*) mypard, (ub4) OCI_DTYPE_PARAM,
(void**) &col_name, (ub4 *) &col_name_len, (ub4) OCI_ATTR_NAME,
(OCIError *) errhp ));
/* Retrieve the length semantics for the column */
char_semantics = 0;
checkerr(errhp, OCIAttrGet((void*) mypard, (ub4) OCI_DTYPE_PARAM,
(void*) &char_semantics,(ub4 *) 0, (ub4) OCI_ATTR_CHAR_USED,
(OCIError *) errhp ));
col_width = 0;
if (char_semantics)
/* Retrieve the column width in characters */
checkerr(errhp, OCIAttrGet((void*) mypard, (ub4) OCI_DTYPE_PARAM,
(void*) &col_width, (ub4 *) 0, (ub4) OCI_ATTR_CHAR_SIZE,
(OCIError *) errhp ));
else
/* Retrieve the column width in bytes */
checkerr(errhp, OCIAttrGet((void*) mypard, (ub4) OCI_DTYPE_PARAM,
(void*) &col_width,(ub4 *) 0, (ub4) OCI_ATTR_DATA_SIZE,
(OCIError *) errhp ));
/* increment counter and get next descriptor, if there is one */
counter++;
parm_status = OCIParamGet((void *)stmthp, OCI_HTYPE_STMT, errhp,
(void **)&mypard, (ub4) counter);
} /* while */
...