この章では、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 Databaseの以前のバージョンで戻される記述値に似ています。これらの値は、SQLT定数(ub2
値)で表されます。ブール型はSQLT_BOL
を戻します。
型オブジェクトを記述するには、例6-1のように、OCIプロセスをオブジェクト・モードで初期化する必要があります。
例6-1 オブジェクト・モードでの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
に設定します。この設定は、ディクショナリ内の精度のデータ型と一致させるために必要です。
パラメータは、OCIParamGet()によって戻されます。パラメータは、複数の型のオブジェクトまたは情報を記述して、そこに含まれる記述の型に応じた属性または型固有の属性を持つことができます。この項では、複数のパラメータに属している属性およびハンドルについて説明します。
OCIDescribeAny()では、3つ以上の名前コンポーネント(たとえば、schema.type.attr1.attr2.method1
)はサポートされません。コンポーネントが複数である場合、最初のコンポーネントはスキーマ名として解釈されます(他のフラグが設定されていない場合)。フラグの中には、オブジェクトがPUBLIC下で参照されるように指定する、つまり「a」を記述するものがあります(ここで、「a」はカレント・スキーマ内のオブジェクトまたはパブリック・シノニムのいずれか)。
オブジェクト型が何であるかわからない場合は、OCI_PTYPE_UNK
を指定してください。そうでない場合、実際のオブジェクト型が指定した型と一致しない場合にはエラーが戻されます。
次の表6-1は、すべてのパラメータの属性のリストです。
表6-1 すべてのパラメータの属性
次の項では、様々なパラメータの型に特有の属性およびハンドルのリストを示します。
表6-2では、表またはビュー(OCI_PTYPE_TABLE
型またはOCI_PTYPE_VIEW
型)のパラメータの型に特有の属性を示しています。
表6-2 表またはビューの属性
属性 | 説明 | 属性のデータ型 |
---|---|---|
オブジェクトID |
ub4 |
|
列の数。 |
ub2 |
|
列リスト( |
OCIParam * |
|
エクステント表の基本型の型記述オブジェクト(TDO)に対する |
OCIRef * |
|
表が一時表であることを示します。 |
ub1 |
|
表に型が指定されていることを示します。 |
ub1 |
|
一時表の継続時間。可能な値は次のとおりです。 |
OCIDuration |
表6-3では、表に属する追加属性を示しています。
表6-4では、プロシージャまたはファンクションのパラメータ(OCI_PTYPE_PROC
型またはOCI_PTYPE_FUNC
型)の場合の型に特有の属性を示しています。
表6-4 プロシージャまたはファンクションの属性
属性 | 説明 | 属性のデータ型 |
---|---|---|
引数リスト。「リスト属性」を参照してください。 |
void * |
|
プロシージャまたはファンクションに実行者権限があることを示します。 |
ub1 |
表6-5では、パッケージ・サブプログラム用にのみ定義されている属性を示しています。
表6-6では、パッケージのパラメータ(OCI_PTYPE_PKG
型)の場合の属性を示しています。
表6-7では、型のパラメータ(OCI_PTYPE_TYPE
型)の場合の属性を示しています。これらの属性は、OCIEnvCreate()のコールの際に、アプリケーションによってOCI_OBJECT
モードでOCIプロセスが初期化された場合にのみ有効です。
表6-7 型の属性
属性 | 説明 | 属性のデータ型 |
---|---|---|
列の型がオブジェクト型の場合は、その型の型記述子オブジェクト(TDO)のインメモリー |
OCIRef * |
|
型コード。「データ型コード」を参照してください。現在は、 |
OCITypeCode |
|
型がコレクションの場合はコレクションの型コードで、それ以外の場合は無効です。「データ型コード」を参照してください。現在は、 |
OCITypeCode |
|
不完全な型であることを示します。 |
ub1 |
|
システム型であることを示します。 |
ub1 |
|
事前定義済の型であることを示します。 |
ub1 |
|
一時的な型であることを示します。 |
ub1 |
|
システム生成型であることを示します。 |
ub1 |
|
ネストした表属性を含む型です。 |
ub1 |
|
LOB属性を含む型です。 |
ub1 |
|
|
ub1 |
|
コレクション要素へのハンドル。「コレクション属性」を参照してください。 |
void * |
|
型属性の数。 |
ub2 |
|
型属性のリスト。「リスト属性」を参照してください。 |
void * |
|
型メソッドの数。 |
ub2 |
|
型メソッドのリスト。「リスト属性」を参照してください。 |
void * |
|
型のマップ・メソッド。「型メソッド属性」を参照してください。 |
void * |
|
型のオーダー・メソッド。「型メソッド属性」を参照してください。 |
void * |
|
型に実行者権限があることを示します。 |
ub1 |
|
型属性名である文字列へのポインタ。 |
OraText * |
|
型作成時のスキーマ名が付いた文字列。 |
OraText * |
|
最後の型であることを示します。 |
ub1 |
|
インスタンス化可能な型であることを示します。 |
ub1 |
|
サブタイプであることを示します。 |
ub1 |
|
スーパータイプを含むスキーマの名前。 |
OraText * |
|
スーパータイプの名前。 |
OraText * |
表6-8では、型の属性のパラメータ(OCI_PTYPE_TYPE_ATTR
型)の場合の属性を示しています。
表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 |
表6-9では、型のメソッドのパラメータ(OCI_PTYPE_TYPE_METHOD
型)の場合の属性を示しています。
表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 |
表6-10では、コレクション型のパラメータ(OCI_PTYPE_COLL
型)の場合の属性を示しています。
表6-10 コレクション型の属性
属性 | 説明 | 属性のデータ型 |
---|---|---|
型属性の最大サイズ。この長さは、文字列と行について、文字ではなくバイト単位で戻されます。 |
ub2 |
|
型コード。「データ型コード」を参照してください。 |
OCITypeCode |
|
型属性のデータ型。「データ型コード」を参照してください。 |
ub2 |
|
配列の要素の数。コレクションが配列である場合にのみ有効です。 |
ub4 |
|
型属性名である文字列へのポインタ。 |
OraText * |
|
数値型属性の精度。精度が0 (ゼロ)以外でスケールが-127の場合は |
ub1 for explicit describe sb2 for implicit describe |
|
数値型属性のスケール。精度が0 (ゼロ)以外でスケールが-127の場合は |
sb1 |
|
型名である文字列。データ型が |
OraText * |
|
型作成時のスキーマ名が付いた文字列。 |
OraText * |
|
列の型がオブジェクト型の場合は、その型の型記述子オブジェクト(TDO)のインメモリー |
OCIRef * |
|
型属性が文字列また文字型の場合は、キャラクタ・セットID。 |
ub2 |
|
型属性が文字列または文字型の場合は、キャラクタ・セット・フォーム。 |
ub1 |
表6-12では、順序のパラメータ(OCI_PTYPE_SEQ
型)の場合の属性を示しています。
表6-12 順序の属性
属性 | 説明 | 属性のデータ型 |
---|---|---|
オブジェクトID |
ub4 |
|
最小値(Oracle |
ub1 * |
|
最大値(Oracle |
ub1 * |
|
増分(Oracle |
ub1 * |
|
キャッシュされた順序番号の数。順序がキャッシュされた順序でない場合は、0 (ゼロ)です(Oracle |
ub1 * |
|
順序が順序指定されているかどうか。 |
ub1 |
|
最高水位標( |
ub1 * |
注意: BINARY_FLOAT およびBINARY_DOUBLE の場合:
OCIDescribeAny()を使用して、表の
|
表6-13では、表またはビューの列のパラメータ(OCI_PTYPE_COL
型)の場合の属性を示しています。
表6-13 表またはビューの列の属性
属性 | 説明 | 属性のデータ型 |
---|---|---|
列の長さセマンティクスの型を戻します。0 (ゼロ)はバイト長セマンティクスを示し、1は文字長セマンティクスを示します。「記述操作での文字長セマンティクスのサポート」を参照してください。 |
ub1 |
|
列の文字長、つまり列内で使用可能な文字数を戻します。これは |
ub2 |
|
列の最大サイズ。この長さは、文字列と行について、文字ではなくバイト単位で戻されます。 |
ub2 |
|
列のデータ型。「データ型コード」を参照してください。 |
ub2 |
|
列名である文字列へのポインタ。 |
OraText * |
|
数値列の精度。精度が0 (ゼロ)以外でスケールが-127の場合は |
ub1 for explicit describe sb2 for implicit describe |
|
数値列のスケール。精度が0 (ゼロ)以外でスケールが-127の場合は |
sb1 |
|
列にNULL値が許可されていない場合に、0 (ゼロ)を戻します。 |
ub1 |
|
型名である文字列を戻します。データ型が |
OraText * |
|
型の作成時に使用したスキーマ名を持つ文字列を戻します。 |
OraText * |
|
列の型がオブジェクト型の場合は、その型のTDOの |
OCIRef * |
|
列が文字列または文字型の場合は、キャラクタ・セットID。 |
ub2 |
|
列が文字列または文字型の場合は、キャラクタ・セット・フォーム。 |
ub1 |
表6-14では、プロシージャやファンクションの引数のパラメータ(OCI_PTYPE_ARG
型)、型メソッド引数のパラメータ(OCI_PTYPE_TYPE_ARG
型)またはメソッド結果のパラメータ(OCI_PTYPE_TYPE_RESULT
型)の場合の属性を示しています。
表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 |
|
パッケージのローカル型の場合は、型名またはパッケージ名の文字列を戻します。データ型が |
OraText * |
|
|
OraText * |
|
|
OraText * |
|
|
OraText * |
|
引数型がオブジェクトの場合は、その型の型記述子オブジェクト(TDO)の |
OCIRef * |
|
引数が文字列または文字型の場合は、キャラクタ・セットIDを戻します。 |
ub2 |
|
引数が文字列または文字型の場合は、キャラクタ・セット・フォームを戻します。 |
ub1 |
列、引数またはサブプログラムのリストのパラメータ(OCI_PTYPE_LIST
型)の場合、 表6-15に示すような型に特有の属性およびハンドル(パラメータ)があります。
リストには、リスト型を指定するOCI_ATTR_LTYPE
属性があります。表6-15では、リストの横断時に予想される値とその下限を示しています。
表6-15 リスト属性
リスト属性 | 説明 | 下限 |
---|---|---|
列リスト。 |
1 |
|
プロシージャ引数リスト。 |
1 |
|
ファンクション引数リスト。 |
0 |
|
サブプログラム・リスト。 |
0 |
|
型属性リスト。 |
1 |
|
型メソッド・リスト。 |
1 |
|
結果引数なしの型メソッド・リスト。 |
0 |
|
結果引数なしの型メソッド・リスト。 |
1 |
|
スキーマ内のオブジェクト・リスト。 |
0 |
|
データベース内のスキーマ・リスト。 |
0 |
リストには、リスト内の要素数を調べるOCI_ATTR_NUM_PARAMS
属性があります。
各リストには、LowerBound
... OCI_ATTR_NUM_PARAMS
パラメータがあります。LowerBound
は、表6-15の「下限」列の値です。ファンクション引数リストの場合、位置0には、戻り値(OCI_PTYPE_ARG
型)のパラメータがあります。
表6-17では、データ型のパラメータ(OCI_PTYPE_DATABASE
型)の場合の属性を示しています。
表6-17 データベース固有の属性
属性 | 説明 | 属性のデータ型 |
---|---|---|
データベースのバージョン。 |
OraText * |
|
サーバー・ハンドルからのデータベース・キャラクタ・セットID。 |
ub2 |
|
サーバー・ハンドルからのデータベース各国語キャラクタ・セットID。 |
ub2 |
|
データベース内のスキーマのリスト( |
ub1 |
|
プロシージャ名の最大長。 |
ub4 |
|
列名の最大長。 |
ub4 |
|
|
ub1 |
|
カタログ(データベース)名の最大長。 |
ub1 |
|
修飾表内のカタログの位置。値は |
ub1 |
|
データベースがセーブポイントをサポートするかどうか。値は |
ub1 |
|
データベースがNOWAIT句をサポートするかどうか。値は |
ub1 |
|
DDL文で自動コミット・モードが必要かどうか。値は |
ub1 |
|
データベースのロック・モード。値は |
ub1 |
表6-18では、ルールのパラメータ(OCI_PTYPE_RULE
型)の場合の属性を示しています。
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
)×(クライアントの各文字の最大バイト数)に設定されます。
データベース列がバイト長セマンティクスを使用して作成されている場合、暗黙的な記述では(その動作はリリース9.0より前と同じ)、戻されるOCI_ATTR_DATA_SIZE
は、(列のバイト長)×(クライアントとサーバーのキャラクタ・セット間での最大変換率)の値になります。つまり、(列のバイト長)÷(サーバーの各文字の最大バイト数)×(クライアントの各文字の最大バイト数)になります。OCI_ATTR_CHAR_USED
値は0で、OCI_ATTR_CHAR_SIZE
値はOCI_ATTR_DATA_SIZE
と同じ値に設定されます。
次の例では、異なる種類のスキーマ・オブジェクトを記述するためのOCIDescribeAny()の使用方法を示します。より詳細なコード例は、Oracle Databaseのインストールに含まれているデモ・プログラムcdemodsa.c
を参照してください。
例6-2では、表の列データ型を取り出す明示的な記述の使用方法を示しています。
... 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 data type 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)
例6-3では、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, you begin with i = 1; for a function, you 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); ...
例6-4では、名前付きオブジェクト型についての明示的な記述の使用方法を示しています。オブジェクトを名前またはオブジェクト参照(OCIRef
)によって記述する方法を説明します。次のコード・フラグメントによって、オブジェクト型の属性について各データ型値の取出しが試みられます。
例6-4 名前付きオブジェクト型についての明示的な記述の使用方法
... 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 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 data type and typecode for attribute; note that OCI_ATTR_DATA_TYPE returns the SQLT code, whereas 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); ...
例6-5では、名前付きコレクション型についての明示的な記述の使用方法を示しています。
例6-5 名前付きコレクション型についての明示的な記述の使用
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: 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); ...
例6-6では、問合せの実行後に、問合せに対応する列名およびデータ型を取り出すループを示しています。この問合せは、事前にOCIStmtPrepare()のコールによって文ハンドルと関連付けられています。
例6-6 データ型、列名および文字長セマンティクスを取り出すためのパラメータ記述子の使用
... 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 data type 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 */ ...