ヘッダーをスキップ
Pro*C/C++プログラマーズ・ガイド
11gリリース2(11.2)
B61343-01
  ドキュメント・ライブラリへ
ライブラリ
製品リストへ
製品
目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

4 データ型とホスト変数

この章では、Pro*C/C++プログラムの作成に必要な基本的な情報について説明します。この章の項目は、次のとおりです。

この章には、学習用の完全なデモンストレーション・プログラムもいくつか記載されています。これらのプログラムには、この章で説明する技法の使用例が示されています。これらはdemoディレクトリにあり、オンラインで使用できるため、コンパイル、実行および必要に応じた変更もできます。

Oracleのデータ型

Oracleでは、内部データ型および外部データ型という2種類のデータ型が認識されます。内部データ型は、Oracleでデータベース表に列値を格納する方法と、NULL、SYSDATE、USERなどの疑似列値の表現に使用する形式を指定します。外部データ型は、入力ホスト変数と出力ホスト変数に値を格納するための形式を指定します。

Oracleの内部データ型(ビルトインとも呼ばれます)の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

内部データ型

表4-1は、Oracleでデータベースの列に格納される値に使用される内部データ型を示しています。

表4-1 Oracle内部データ型

名前 説明

VARCHAR2

可変長文字列(4000バイト以下)。

NVARCHAR2またはNCHAR VARYING

可変長シングルバイト文字列または各国語キャラクタ文字列(4000バイト以下)。

NUMBER

100をベースとして表された、精度と位取りのある数値。

LONG

可変長文字列(2**31-1バイト以下)。

BINARY_FLOAT

32ビット浮動小数点数(4バイト)。

BINARY_DOUBLE

64ビット浮動小数点数(8バイト)。

TIMESTAMP

日付の年、月、日の値、および、時刻の時、分、および秒の値(7または11バイト)。

DATE

固定長の日付+時刻値(7バイト)。

INTERVAL YEAR

年および月単位の期間を格納します(5バイト)。

INTERVAL DAY

日、時、分および秒単位で期間を格納します(11バイト)。

RAW

可変長バイナリ・データ(2000バイト以下)。

LONG RAW

可変長バイナリ・データ(2**31-1バイト以下)。

ROWID

バイナリ値。

UROWID

バイナリ値(4000バイト以下)。

CHAR

固定長文字列(2000バイト以下)。

NCHAR

固定長シングルバイト文字列または各国語キャラクタ文字列(2000バイト以下)。

CLOB

文字データ(4GB以下)。

NCLOB

各国語キャラクタ・セット・データ(4GB以下)。

BLOB

バイナリ・データ(4GB以下)。

BFILE

外部ファイル・バイナリ・データ(4GB以下)。


これらの内部データ型は、C言語のデータ型とは大きく異なる場合があります。たとえば、C言語にはOracleのNUMBERデータ型と同等のデータ型はありません。ただし、NUMBERは、floatdoubleなどのC言語のデータ型との間で変換できますが、ある程度の制限があります。たとえば、OracleのNUMBERデータ型は小数点以下最大38桁の精度で指定できますが、現行のC言語の実装ではdoubleをそこまでの精度で表せるデータ型はありません。

OracleのNUMBERデータ型は値を正確に(精度の制限内で)表しますが、浮動小数点形式では10.0などの値を正確に表すことができません。

構造化されていないデータ(テキスト、グラフィック・イメージ、ビデオ・クリップまたはサウンド波形)を格納するには、LOBデータ型を使用します。BFILEデータは、データベース外部のオペレーティング・システム・ファイルに格納されます。LOB型には、データの位置を指定するロケータが格納されます。


関連項目

第16章「LOB」

NCHARとNVARCHAR2は、マルチバイト・キャラクタ・データの格納に使用されます。


関連項目

これらのデータ型については、「グローバリゼーション・サポート」を参照してください。

外部データ型

表4-2のように、外部データ型にはすべての内部データ型と、C言語の構文とほぼ一致するいくつかのデータ型が含まれています。たとえば、STRING外部データ型は、C言語ではNULL終了記号文字列を指します。

表4-2 Oracle外部データ型

名前 説明

VARCHAR2

可変長文字列(65535バイト以下)。

NUMBER

100をベースとして表された10進数。

INTEGER

符号付き整数。

FLOAT

実数。

STRING

NULLで終了する可変長文字列。

VARNUM

10進数(NUMBERと同様だが表現の長さのコンポーネントが含まれる)。

LONG

固定長文字列(2**31-1バイトまで)。

VARCHAR

可変長文字列(65533バイト以下)。

ROWID

バイナリ値(外部の長さはシステムに依存)。

DATE

固定長の日付/時刻値(7バイト)。

VARRAW

可変長バイナリ・データ(65533バイト以下)。

RAW

固定長バイナリ・データ(65535バイト以下)。

LONG RAW

固定長バイナリ・データ(2**31-1バイト以下)。

UNSIGNED

符号なし整数。

LONG VARCHAR

可変長文字列(2**31-5バイト以下)。

LONG VARRAW

可変長バイナリ・データ(2**31-5バイト以下)。

CHAR

固定長文字列(65535バイト以下)。

CHARZ

固定長のNULL終了文字列(65534バイト以下)。

CHARF

CHARのデフォルトをVARCHAR2またはCHARZではなくCHARにするために、TYPE文またはVAR文で使用する。


次にOracleデータ型について簡単に説明します。

VARCHAR2

VARCHAR2データ型を使用して、可変長文字列を格納します。VARCHAR2値の最大長は64KBです。

VARCHAR2(n)値の最大長は、文字数ではなくバイト数で指定します。したがって、VARCHAR2(n)変数にマルチバイト文字を格納すると、最大長はn文字より少なくなります。

Oracleでは、CHAR_MAP=VARCHAR2オプションを使用してプリコンパイルすると、char[n]またはcharとして宣言しているすべてのホスト変数に、VARCHAR2データ型が割り当てられます。

入力時

Oracleは入力ホスト変数に指定されたバイト数を読み込み、後続の空白文字を取り除き、入力値をターゲット・データベース列に格納します。ここでは注意が必要です。未初期化ホスト変数には、一連のヌル文字が含まれている場合があります。したがって、常に文字入力ホスト変数の宣言長まで空白文字で埋め、ヌル文字で終了しないでください。

入力値がデータベース列の定義より長い場合は、エラーが生成されます。入力値がすべて空白の場合は、1つのNULLと同様に扱われます。

文字値が有効な数を表す場合は、NUMBER列値に変換できます。そうではない場合はエラーになります。

出力時

Oracleは出力ホスト変数に指定されたバイト数を戻し、必要に応じて空白文字で埋めてから、出力値をターゲット・ホスト変数に割り当てます。NULLが戻されると、Oracleはホスト変数に空白文字を埋めます。

出力値がホスト変数の宣言長より長い場合は、Oracleはその値の長すぎる分を切り捨ててから、ホスト変数に割り当てます。そのホスト変数に標識変数が対応付けられている場合、Oracleは標識変数を出力値の元の長さに設定します。

NUMBER列値は文字値に変換できます。文字ホスト変数の長さにより精度が決定されます。ホスト変数の長さが数に対して短すぎる場合は、科学表記法が使用されます。たとえば、列値123456789を長さ6の文字ホスト変数にSELECTすると、値1.2E08が戻されます。明示的にNULLが選択された場合、ホスト変数の値は予測不能です。標識変数の値がNULLかどうかをチェックする必要があります。

NUMBER

NUMBERデータ型を使用して、固定小数点数または浮動小数点数を格納します。精度および位取りを指定できます。NUMBER値の最大精度は38です。強度範囲は1.0E-130〜9.99...9E125(9が38個に続けて0が88個)です。位取りの範囲は-84〜127です。

NUMBER値は、可変長形式で格納されます。つまり、1バイトの指数部に19バイトの仮数部が続きます。指数バイトの上位1ビットは符号ビットであり、正数のときに設定します。下位7ビットは強度を表します。

仮数は38桁の数値を形成し、各バイトは100をベースとする2桁を表します。仮数の符号は、最初(左端)のバイトの値で指定されます。101より大きければ仮数は負であり、その1桁目は左端のバイトから101を差し引いた値と等しくなります。

出力時に、ホスト変数にはOracleで内部表現された数が入ります。予想される最大の数に対応するには、出力ホスト変数を22バイトの長さにする必要があります。数の表現に使用されるバイトのみが戻されます。Oracleでは、出力値に空白文字が埋められず、ヌル文字で終了しません。戻された値の長さを知る必要がある場合は、かわりにVARNUMデータ型を使用します。

この外部データ型を使用する必要はほとんどありません。

INTEGER

INTEGERデータ型を使用して、小数部のない数を格納します。整数は符号付きの2バイト、4バイトまたは8バイトの2進数です。ワード内のバイトの順序付けはシステムによって異なります。入力ホスト変数と出力ホスト変数に長さを指定する必要があります。出力時には、列値が実数であれば、小数部が切り捨てられます。

FLOAT

FLOATデータ型を使用して、小数部を持つ数、あるいはINTEGERデータ型の容量を超える数を格納します。数は、使用しているコンピュータの浮動小数点形式を使用して表示されます。通常、記憶域には4バイトまたは8バイトを必要とします。入力ホスト変数と出力ホスト変数に長さを指定する必要があります。

Oracleでは、数の内部形式が10進数であるため、ほとんどの浮動小数点処理よりも高い精度で数を表現できます。したがって、FLOAT変数へのフェッチを行うと、精度が低下する可能性があります。

STRING

STRINGデータ型は、VARCHAR2データ型に似ていますが、STRING値は常にヌル文字で終了するという違いがあります。Oracleでは、CHAR_MAP=STRINGオプションを使用してプリコンパイルすると、char[n]またはcharとして宣言しているすべてのホスト変数に、STRINGデータ型が割り当てられます。

入力時

Oracleは指定された長さを使用して、ヌル終端文字のスキャンを制限します。ヌル終端文字が見つからなければ、エラーが生成されます。長さを指定しなければ、最大長は2000バイトと想定されます。STRINGの値の最小長は2バイトです。最初の文字がヌル終端文字で、指定した長さが2の場合、列がNOT NULLと定義されていなければOracleはNULLを挿入します。列がNOT NULLと定義されている場合はエラーが発生します。空白のみの値はそのまま格納されます。

出力時

Oracleは戻された最後の文字に1バイトのヌル文字を追加します。文字列長が指定された長さを超える場合は、Oracleは出力値を切り捨て、1バイトのヌル文字を追加します。NULLがSELECTされた場合は、Oracleは最初の文字位置に1バイトのヌル文字を入れて戻します。明示的にNULLが選択された場合、ホスト変数の値は予測不能です。標識変数の値がNULLかどうかをチェックする必要があります。

VARNUM

VARNUMデータ型はNUMBERデータ型に似ていますが、VARNUM変数の1バイト目にその表現の長さが格納されるという違いがあります。

入力時には、ホスト変数の1バイト目を値の長さに設定する必要があります。出力時には、ホスト変数には長さに続いてOracleで内部表現された数が設定されています。この数が最大になっても支障がないように、ホスト変数の長さは22バイト必要です。列値をVARNUMホスト変数にSELECTした後で、1バイト目をチェックして値の長さを取得できます。

通常、このデータ型はほとんど使用されません。

LONG

LONGデータ型を使用して、固定長文字列を格納します。

LONGデータ型はVARCHAR2データ型に似ていますが、LONG値の最大長は2147483647バイト、つまり2GBであるという違いがあります。

VARCHAR

VARCHARデータ型を使用して、可変長文字列を格納します。VARCHAR変数では、2バイト長のフィールドの後に65533バイト以下の文字列フィールドが続きます。ただし、VARCHAR配列要素では、文字列フィールドの最大長は65530バイトです。VARCHAR変数の長さを指定するときには、長さフィールド用の2バイトが含まれているか確認してください。これより長い文字列には、LONG VARCHARデータ型を使用してください。明示的にNULLが選択された場合、ホスト変数の値は予測不能です。標識変数の値がNULLかどうかをチェックする必要があります。

ROWID

索引構成表の行には、永続物理アドレスは設定されていません。論理ROWIDには、物理ROWIDの場合と同じ構文を使用してアクセスします。このため、物理ROWIDは、データ・オブジェクト番号(同じセグメント内のスキーマ・オブジェクト)を格納します。

論理ROWIDと物理ROWIDの両方(およびOracle以外の表のROWID)をサポートするために、ユニバーサルROWIDが定義されました。

文字ホスト変数を使用すると、ROWIDを読取り可能な書式で格納できます。ROWIDを文字ホスト変数にSELECTまたはFETCHすると、その2進値は18バイトの文字列に変換され、次の形式で戻されます。

BBBBBBBB.RRRR.FFFF 

BBBBBBBBはデータベース・ファイル内のブロック、RRRRはブロック内の行(最初の行は0)、FFFFはデータベース・ファイルです。これらの値は16進数です。たとえば、次のROWIDがあるとします。

0000000E.000A.0007 
points to the 11th row in the 15th block in the 7th database file. 

関連項目

アプリケーションでユニバーサルROWIDを使用する方法の詳細は、「ユニバーサルROWID」を参照してください。

通常、ROWIDを文字ホスト変数にFETCHし、ホスト変数をUPDATE文またはDELETE文のWHERE句のROWID疑似列と比較します。これにより、カーソルによりフェッチされた最終行を識別できます。


注意:

完全な移植性が必要な場合、あるいはアプリケーションでOracle Open Gatewayテクノロジを使用してOracle以外のデータベースと通信する場合は、ホスト変数を宣言するときに最大長を(18ではなく)256に指定してください。ホスト変数の内容については予測できませんが、ホスト変数はSQL文中で通常どおりに動作します。

DATE

DATEデータ型を使用して、日付と時刻を7バイトの固定長フィールドに格納します。表4-3のように、世紀、年、月、日、時刻(24時間形式)、分、秒が、この順番で左から右に格納されています。

表4-3 DATE書式

DATEデータ型 世紀

バイト

1

2

3

4

5

6

7

意味

世紀

1994年10月17日午後1時23分12秒

119

194

10

17

14

24

13


世紀バイトと年号バイトは100を加えた表記です。時刻、分および秒のバイトは1を加えた表記です。紀元前(B.C.E.)は100未満です。原点は紀元前4712年1月1日です。この日付では、世紀バイトは53、年号バイトは88です。時間バイトの範囲は1〜24、分および秒バイトの範囲は1〜60です。時間のデフォルトは真夜中(1、1、1)です。

通常、DATEデータ型はほとんど使用されません。

RAW

RAWデータ型を使用して、バイナリ・データまたはバイト文字列を格納します。RAW値の最大長は65535バイトです。

RAWデータはCHARACTERデータに似ていますが、OracleではRAWデータは意味がないものと解釈され、システム間でRAWデータを転送するときにはキャラクタ・セットは変換されないという違いがあります。

VARRAW

VARRAWデータ型を使用して、可変長のバイナリ・データまたはバイト文字列を格納します。VARRAWデータ型はRAWデータ型に似ていますが、VARRAW変数は2バイトの長さフィールドの後に長さ65533バイト以下のデータ・フィールドが付いているという違いがあります。これより長い文字列には、LONG VARRAWデータ型を使用してください。

VARRAW変数の長さを指定するときは、長さフィールド用の2バイトが含まれているかを確認してください。変数の最初の2バイトは、整数として解釈できる必要があります。

VARRAW変数の長さを取得するには、長さフィールドを参照してください。

LONG RAW

LONG RAWデータ型を使用して、バイナリ・データまたはバイト文字列を格納します。LONG RAW値の最大長は2147483647バイト、つまり2GBです。

LONG RAWデータはLONGデータに似ていますが、OracleではLONG RAWデータは意味がないものと解釈され、システム間でLONG RAWデータを転送するときにはキャラクタ・セットは変換されないという違いがあります。

UNSIGNED

UNSIGNEDデータ型を使用して、符号なし整数を格納します。符号なし整数は、2バイトまたは4バイトの2進数です。ワード内のバイトの順序付けはシステムによって異なります。入力ホスト変数と出力ホスト変数に長さを指定する必要があります。出力時には、列値が浮動小数点数であれば、小数部が切り捨てられます。

LONG VARCHAR

LONG VARCHARデータ型を使用して、可変長文字列を格納します。LONG VARCHAR変数では、4バイトの長さフィールドの後に文字列フィールドが続きます。文字列フィールドの最大長は2147483643(2**31 - 5)バイトです。VAR文またはTYPE文に使用するLONG VARCHARの長さを指定する場合は、4バイトの長さフィールドを含めないでください。

LONG VARRAW

LONG VARRAWデータ型を使用して、可変長のバイナリ・データまたはバイト文字列を格納します。LONG VARRAW変数では、4バイトの長さフィールドの後にデータ・フィールドが続きます。データ・フィールドの最大長は2147483643バイトです。VAR文またはTYPE文に使用するLONG VARRAWの長さを指定する場合は、4バイトの長さフィールドを含めないでください。

CHAR

CHARデータ型を使用して、固定長文字列を格納します。CHAR値の最大長は65535バイトです。

入力時

Oracleは入力ホスト変数に指定されたバイト数を読み込み、後続の空白文字を削除せずに、入力値をターゲット・データベース列に格納します。

入力値がデータベース列の定義より長い場合は、エラーが生成されます。入力値がすべて空白文字の場合は、Oracleは1つの文字値と同様に扱います。

出力時

Oracleは出力ホスト変数に指定されたバイト数を戻し、必要に応じて空白埋込みを行ってから、出力値をターゲット・ホスト変数に割り当てます。NULLが戻されると、Oracleはホスト変数に空白文字を埋めます。

出力値がホスト変数の宣言長より長い場合は、Oracleはその値の長すぎる分を切り捨ててから、ホスト変数に割り当てます。標識変数が使用可能な場合は、そこに出力値の本来の長さを設定します。明示的にNULLが選択された場合、ホスト変数の値は予測不能です。標識変数の値がNULLかどうかをチェックする必要があります。

CHARZ

DBMS=V7またはV8の場合、デフォルトでは、OracleはPro*C/C++プログラム内のすべての文字ホスト変数にCHARZデータ型を割り当てます。CHARZデータ型は、ヌル文字で終了する固定長文字列を示します。CHARZ値の最大長は65534バイトです。

入力時

CHARZデータ型とSTRINGデータ型の機能は同じです。入力値はヌル文字で終了する必要があります。ヌル終端文字は、文字列の区切り記号としての役割のみを果し、格納データの一部にはなりません。

出力時

CHARZホスト変数を必要に応じて空白文字で埋めて、ヌル文字で終了します。この出力値は、データが長すぎるために切捨てが必要な場合にも、常にヌル文字で終了します。明示的にNULLが選択された場合、ホスト変数の値は予測不能です。標識変数の値がNULLかどうかをチェックする必要があります。

CHARF

CHARFデータ型は、EXEC SQL TYPE文およびEXEC SQL VAR文で使用します。DBMSオプションをV7またはV8に設定してプリコンパイルするときに、TYPE文またはVAR文で外部データ型CHARを指定すると、C言語のデータ型、もしくは固定長でヌル文字で終了するデータ型であるCHARZに同値化されます。

ただし、これらの型に同値化するのではなく、固定長の外部型CHARに同値化することが必要な場合もあります。外部型CHARFを使用すると、C言語のデータ型または変数は、DBMS値に関係なく常に固定長のANSIデータ型CHARと同値化されます。CHARFによりC言語のデータ型がVARCHAR2またはCHARZと同値化されることはありません。そのかわり、CHAR_MAP=CHARFオプションを設定すると、char[n]またはcharとして宣言されたホスト変数はすべてCHAR文字列と同値化されます。明示的にNULLが選択された場合、ホスト変数の値は予測不能です。標識変数の値がNULLかどうかをチェックする必要があります。

その他の外部データ型

この項では、その他の外部データ型について説明します。

日時および時間隔のデータ型

ここでは、日時および時間隔のデータ型の概要を説明します。


関連項目

詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ANSI DATE

ANSI DATEDATEに基づいていますが、時刻部分が含まれていません。(したがって、タイムゾーンもありません。)ANSI DATEは、DATEデータ型に関するANSI仕様に準拠しています。DATEまたはタイムスタンプ・データ型にANSI DATEを割り当てると、OracleのDATEとタイムスタンプの時刻部分が0に設定されます。DATEまたはタイムスタンプをANSI DATEに割り当てると、時刻部分は無視されます。

ANSI DATEではなく、日付と時刻の両方を含むTIMESTAMPデータ型を使用することをお薦めします。

TIMESTAMP

TIMESTAMPデータ型は、DATEデータ型が拡張されたものです。DATEデータ型の年、月、日に加えて時、分および秒の値が格納されます。タイムゾーンはありません。TIMESTAMPデータ型の書式は、次のとおりです。

TIMESTAMP(fractional_seconds_precision) 

fractional_seconds_precision(オプション)では、SECOND日時フィールドの小数部の桁数を指定します。桁数の範囲は0〜9で、デフォルトは6です。

TIMESTAMP WITH TIME ZONE

TIMESTAMP WITH TIME ZONETSTZ)は、値に明示的なタイムゾーンによる時差を含むTIMESTAMPの変形です。タイムゾーンによる時差は、地方時とUTC(協定世界時、旧称はグリニッジ標準時)との時差(時および分単位)です。TIMESTAMP WITH TIME ZONEデータ型の書式は、次のとおりです。

TIMESTAMP(fractional_seconds_precision) WITH TIME ZONE

fractional_seconds_precision(オプション)では、SECOND日時フィールドの小数部の桁数を指定します。桁数の範囲は0〜9で、デフォルトは6です。

2つのTIMESTAMP WITH TIME ZONE値がUTCで同じ瞬間を表す場合は、データに格納されているTIME ZONEオフセットに関係なく同一とみなされます。

TIMESTAMP WITH LOCAL TIME ZONE

TIMESTAMP WITH LOCAL TIME ZONETSLTZ)は、値にタイムゾーンによる時差を含むTIMESTAMPのもう1つの変形です。格納形式は、TIMESTAMPと同じです。この型は、TIMESTAMP WITH TIME ZONEとは異なり、データベースに格納されるデータはデータベースのタイムゾーンに定められ、タイムゾーンによる時差は列データの一部としては格納されません。ユーザーがデータを取り出すときには、そのユーザーのローカル・セッションのタイムゾーンで戻されます。

タイムゾーンによる時差は、地方時とUTC(協定世界時、旧称はグリニッジ標準時)との時差(時および分単位)です。TIMESTAMP WITH LOCAL TIME ZONEデータ型の書式は、次のとおりです。

TIMESTAMP(fractional_seconds_precision) WITH LOCAL TIME ZONE

fractional_seconds_precision(オプション)では、SECOND日時フィールドの小数部の桁数を指定します。桁数の範囲は0〜9で、デフォルトは6です。

INTERVAL YEAR TO MONTH

INTERVAL YEAR TO MONTHには、YEARおよびMONTH日時フィールドを使用して期間が格納されます。INTERVAL YEAR TO MONTHデータ型の書式は、次のとおりです。

INTERVAL YEAR(year_precision) TO MONTH

オプションのyear_precisionは、YEAR日時フィールドの桁数です。year_precisionのデフォルト値は2です。

INTERVAL DAY TO SECOND

INTERVAL DAY TO SECONDには、日、時、分および秒単位で期間が格納されます。INTERVAL DAY TO SECONDデータ型の書式は、次のとおりです。

INTERVAL DAY (day_precision) TO SECOND(fractional_seconds_precision)

パラメータは、次のとおりです。

  • day_precisionは、DAY日時フィールドの桁数です。これはオプションです。有効な値は0〜9で、デフォルトは2です。

fractional_seconds_precisionは、SECOND日時フィールドの小数部の桁数です。これはオプションです。有効な値は0〜9で、デフォルトは6です。

日時を使用した予期しない結果の回避


注意:

日時データのDML操作で予期しない結果を回避するために、組込みSQL関数DBTIMEZONEおよびSESSIONTIMEZONEを問い合せて、データベースとセッションのタイムゾーンを確認できます。タイムゾーンを手動で設定しない場合、Oracleではデフォルトでオペレーティング・システムのタイムゾーンが使用されます。オペレーティング・システムのタイムゾーンが有効なOracleタイムゾーンでない場合、Oracleではデフォルト値としてUTCが使用されます。

ホスト変数

ホスト変数は、ホスト・プログラムとOracle間の通信に重要な役割を果します。通常、プリコンパイラ・プログラムがホスト変数からOracleにデータを入力し、Oracleがプログラム内のホスト変数にデータを出力します。Oracleは入力データをデータベース列に格納し、出力データをプログラムのホスト変数に格納します。

ホスト変数には、スカラー型として解決される任意のC言語の式を指定してもかまいません。ただし、ホスト変数も「左辺値」であることが必要です。ほとんどのホスト変数のホスト配列もサポートされています。

ホスト変数の宣言

ホスト変数は、Oracleプログラム・インタフェースでサポートされているC言語のデータ型を指定して、Cプログラム言語の規則に従って宣言します。このC言語のデータ型には、ソースまたはターゲットのデータベース列のデータ型との互換性が必要です。

MODE=ORACLEの場合、特別な宣言部でホスト変数を宣言する必要はありません。ただし、宣言部がANSI SQL標準の一部である場合に宣言部を使用しないと、FIPSフラガーで警告が発行されます。CODE=CPP(C++コードのコンパイル中)、PARSE=NONEまたはPARSE=PARTIALの場合は、宣言部を使用する必要があります。

表4-4は、C言語のデータ型と、ホスト変数の宣言時に使用できる疑似型を示しています。ホスト変数に使用できるのは、これらのデータ型のみです。

表4-4 ホスト変数のC言語のデータ型

C言語のデータ型または疑似型 説明

char

単一文字

char[n]

n文字配列(文字列)

int

整数

short

小さい整数

long

大きい整数

long long

極めて大きい整数(8バイト)

float

浮動小数点数(通常は単精度)

double

浮動小数点数(通常は倍精度)

VARCHAR[n]

可変長文字列


表4-5は、互換性のあるOracleの内部データ型を示しています。

表4-5 C言語とOracleのデータ型の互換性

内部型 C言語のデータ型 説明

VARCHAR2(Y)

(注意1)

char

単一文字

CHAR(X)

(注意1)

char[n]

VARCHAR[n]

int

short

long

long long

float

double

nバイトの文字配列

nバイトの可変長文字配列

整数

小さい整数

大きい整数

極めて大きい整数(8バイト)

浮動小数点数

倍精度浮動小数点数

number

NUMBER

int

整数

NUMBER(P,S)

(注意2)

short

int

long

float

double

char

char[n]

VARCHAR[n]

小さい整数

整数

大きい整数

浮動小数点数

倍精度浮動小数点数

number

単一文字

nバイトの文字配列

nバイトの可変長文字配列

DATE

char[n]

VARCHAR[n]

nバイトの文字配列

nバイトの可変長文字配列

LONG

char[n]

VARCHAR[n]

nバイトの文字配列

nバイトの可変長文字配列

RAW(X)

(注意1)

unsigned char[n]

VARCHAR[n]

nバイトの文字配列

nバイトの可変長文字配列

LONG RAW

unsigned char[n]

VARCHAR[n]

nバイトの文字配列

nバイトの可変長文字配列

ROWID

unsigned char[n]

VARCHAR[n]

nバイトの文字配列

nバイトの可変長文字配列

注意:

1. Xの範囲は1〜2000で、デフォルト値は1です。Yの範囲は1〜4000です。

2. Pの範囲は1〜38で、Sの範囲は-84〜127です。




単純なC言語のデータ型の1次元配列は、ホスト変数としての役割も果します。char[n]およびVARCHAR[n]の場合、nには配列内にある文字列の数ではなく、文字列の最大長を指定します。2次元配列を指定できるのは、char[m][n]およびVARCHAR[m][n]の場合のみです。mには配列内の文字列の数を指定し、nには文字列の最大長を指定します。

単純なC言語のデータ型へのポインタがサポートされています。char[n]およびVARCHAR[n]変数へのポインタは、charまたはVARCHAR(長さの指定なし)へのポインタとして宣言する必要があります。ただし、ポインタの配列はサポートされていません。

記憶域クラス指定子

Pro*C/C++では、ホスト変数の宣言時にautoexternおよびstatic記憶域クラス指定子を使用できます。ただし、プリコンパイラはホスト変数の前にアンパサンド(&)を挿入することでアドレスを取得するため、register記憶域クラス指定子を使用してホスト変数を格納することはできません。C言語の規則に従うと、auto記憶域クラス指定子を使用できるのはブロック内のみです。

ANSI C規格に準拠するために、Pro*C/C++プリコンパイラでは次のように、最大長の指定の有無にかかわらず、extern char[n]ホスト変数を宣言できます。

extern char  protocol[15]; 
extern char  msg[]; 

ただし、最大長は常に指定する必要があります。前述の例で、あるプリコンパイル・ユニットで宣言された出力ホスト変数msgが、他のプリコンパイル・ユニットで定義された場合、プリコンパイラではその最大長を認識する方法がありません。2番目のプリコンパイル・ユニットのmsgに十分な記憶域を割り当てないと、メモリーが破損することがあります。(十分な記憶域とは通常、ホスト変数にSELECTまたはFETCHされる可能性のある最長の列値のバイト数に、ヌル終端文字が付く場合に備えた1バイトを加えた値です。)

extern char[ ]ホスト変数の最大長を指定しない場合、プリコンパイラから警告メッセージが発行されます。また、ホスト変数にはCHARACTER列値が格納されるとみなされますが、この値の長さは255文字以内にする必要があります。したがって、長さ256文字以上のVARCHAR2またはLONG列値をホスト変数にSELECTまたはFETCHする場合は、最大長を指定する必要があります。

型修飾子

ホスト変数の宣言時には、constおよびvolatile型修飾子も使用できます。

constホスト変数は定数を持つ必要があります。つまり、プログラムではその初期値を変更できません。volatileホスト変数の値は、プログラムでは認識されない方法で(システムに接続されたデバイスなどにより)変更されることがあります。

ホスト変数の参照

ホスト変数は、SQL DML文で使用します。SQL文中ではホスト変数の先頭にコロン(:)を付ける必要がありますが、C言語の文中では先頭にコロンを付けないでください。次に例を示します。

char    buf[15];
int     emp_number; 
float   salary; 
... 
gets(buf); 
emp_number = atoi(buf); 

EXEC SQL SELECT sal INTO :salary FROM emp 
    WHERE empno = :emp_number; 

わかりにくくなる可能性もありますが、次のように、ホスト変数にOracleの表または列と同じ名前を付けることもできます。

int     empno; 
char    ename[10]; 
float   sal; 
... 
EXEC SQL SELECT ename, sal INTO :ename, :sal FROM emp 
    WHERE empno = :empno; 

制限

ホスト変数名はC識別子であるため、宣言および参照時には大/小文字区別を一致させる必要があります。ホスト変数は、列、表またはSQL文中の他のOracleオブジェクトでは置換できません。また、Oracle予約語も使用できません。

ホスト変数は、プログラムのアドレスに設定する必要があります。このため、関数コールおよび数値式はホスト変数に指定できません。次のコードは無効です。

#define MAX_EMP_NUM    9000 
... 
int get_dept(); 
... 
EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES 
    (:MAX_EMP_NUM + 10, 'CHEN', :get_dept()); 

標識変数

個々のホスト変数をオプションの標識変数に対応付けることができます。標識変数は、2バイトの整数として定義する必要があります。また、SQL文中では、先頭にコロンを付け、(INDICATORキーワードを使用しない場合にかぎり)ホスト変数の直後に指定する必要があります。宣言部を使用する場合は、宣言部中でも標識変数を宣言する必要があります。

これはリレーショナル列に適用されるもので、オブジェクト型には適用されません。

INDICATORキーワード

標識変数の前にオプションのキーワードINDICATORを挿入することで読みやすくできます。その場合も、標識変数の前にはコロンを付ける必要があります。正しい構文は、次のとおりです。

:host_variable INDICATOR :indicator_variable 

これと同じ意味を、次のように表すこともできます。

:host_variable:indicator_variable 

ホスト・プログラムでは、両方の形式を使用できます。

可能なインジケータの値とその意味は、次のとおりです。

インジケータの値 意味
0 操作は成功しました。
-1 NULLが戻されたか、挿入または更新されました。
-2 LONG型の文字ホスト変数の出力は、長すぎる部分が切り捨てられましたが、元の列の長さは判別できません。
>0 SELECTまたはFETCHの結果として文字ホスト変数に入ったデータは、長すぎる文が切り捨てられました。この場合、そのホスト変数がマルチバイト・キャラクタ変数であれば、インジケータの値は元の列の長さを文字数で表したものになります。そのホスト変数がマルチバイト・キャラクタ変数でなければ、インジケータの長さは元の列の長さをバイト数で表したものになります。

標識変数の使用例

通常、標識変数は、入力ホスト変数へのNULLの割当てと、出力ホスト変数に含まれるNULLまたは切捨て値の検出に使用されます。次の例では、3つのホスト変数と1つの標識変数を宣言してから、SELECT文を使用して、ホスト変数emp_numberの値と一致する従業員番号をデータベース内で検索します。一致する行が見つかると、出力ホスト変数salaryおよびcommissionが、その行の列SALおよびCOMMの値に設定され、リターン・コードが標識変数ind_commに格納されます。後継の文では、ind_commを使用してその後の処理を選択しています。

EXEC SQL BEGIN DECLARE SECTION; 
    int    emp_number; 
    float  salary, commission; 
    short comm_ind;  /* indicator variable  */
EXEC SQL END DECLARE SECTION;
    char temp[16];
    float  pay;      /* not used in a SQL statement */
...
printf("Employee number? "); 
gets(temp);
emp_number = atof(temp);
EXEC SQL SELECT SAL, COMM 
    INTO :salary, :commission:ind_comm 
    FROM EMP 
    WHERE EMPNO = :emp_number; 
if(ind_comm == -1)    /* commission is null */
    pay = salary; 
else
    pay = salary + commission; 

関連項目

「標識変数」

標識変数のガイドライン

標識変数の宣言および参照については、次のガイドラインに従ってください。標識変数は、次のようにする必要があります。

  • 2バイトの整数として(宣言部がある場合はそこに)明示的に宣言します。

  • SQL文中では前にコロン(:)を付けます。

  • SQL文中とPL/SQLブロック内では、そのホスト変数の直後に指定します(INDICATORキーワードを前に付ける場合は除きます)。

また、次の点にも注意してください。

  • ホスト言語文中で、前にコロン(:)を付けないでください。

  • ホスト言語文中で、そのホスト変数の直後に指定しないでください。

  • Oracleの予約語にしないでください。

Oracle制限事項

DBMS=V7またはV8の場合は、標識変数に対応付けられていないホスト変数にNULLをSELECTまたはFETCHすると、次のエラー・メッセージが発行されます。

ORA-01405: fetched column value is NULL

MODE=ORACLEおよびDBMS=V7またはV8を指定してプリコンパイルする場合は、UNSAFE_NULL=YESを指定してORA-01405メッセージを使用禁止にできます。


関連項目

「UNSAFE_NULL」

VARCHAR変数

VARCHAR疑似型を使用すると、可変長文字列を宣言できます。プログラムで扱う文字列がVARCHAR2列またはLONG列からの出力、あるいはその列への入力である場合、標準のC言語文字列のかわりにVARCHARホスト変数を使用する方が便利なこともあります。データ型名VARCHARは、すべて大文字でも、すべて小文字でもかまいませんが、大文字と小文字を混在させることはできません。このマニュアルでは、VARCHARがC言語固有のデータ型とは異なることを強調するために、大文字を使用しています。

VARCHAR変数の宣言

VARCHARは、C言語の拡張型または宣言済の構造体と考えてください。たとえば、次のVARCHAR宣言があると仮定します。

VARCHAR   username[20];
 

プリコンパイラは上の宣言を、配列メンバーおよび長さメンバーを持つ次の構造体に展開します。

struct 
{ 
    unsigned short  len; 
    unsigned char   arr[20]; 
} username; 

VARCHAR変数の利点は、SELECTまたはFETCHの後にVARCHAR構造体の長さメンバーを明示的に参照できることです。Oracleでは、選択された文字列の長さが長さメンバーに置かれます。このメンバーを、ヌル終端文字('\0')の追加などに使用できます。

username.arr[username.len] = '\0'; 

また、次のように、長さはstrncpy文またはprintf文でも指定できます。

printf("Username is %.*s\n", username.len, username.arr);

VARCHAR変数の最大長は、その宣言内で指定します。長さの範囲は、1〜65533にする必要があります。たとえば、次の宣言は、長さが指定されていないため無効です。

VARCHAR   null_string[];    /* invalid */

長さの指定では、配列メンバーに格納される値の現行の長さが保持されます。

次のように、1行に複数のVARCHARを宣言できます。

VARCHAR emp_name[ENAME_LEN], dept_loc[DEPT_NAME_LEN];

VARCHARの長さ指定子には、#defineによる定義済マクロか、プリコンパイル時に整数で解決できる任意の複合式を使用できます。

また、VARCHARデータ型へのポインタも宣言できます。


注意:

次のようなtypedef文は使用しないでください。
typedef VARCHAR buf[64]; 

このような文を使用すると、Cコンパイル・エラーが発生します。


VARCHAR変数の参照

SQL文では、次のように、接頭辞としてコロンを付けた構造体名を使用してVARCHAR変数を参照します。

... 
int       part_number; 
VARCHAR   part_desc[40]; 
... 
main() 
{ 
    ... 
    EXEC SQL SELECT pdesc INTO :part_desc 
        FROM parts 
        WHERE pnum = :part_number; 
    ... 

問合せが実行された後、データベースから取り出され、part_desc.arrに格納された文字列の実際の長さがpart_desc.lenに保持されます。

C言語の文では、次のように、コンポーネント名を使用してVARCHAR変数を参照します。

printf("\n\nEnter part description: "); 
gets(part_desc.arr); 
/* You must set the length of the string
   before using the VARCHAR in an INSERT or UPDATE */
part_desc.len = strlen(part_desc.arr); 

VARCHAR変数にNULLを戻す

Oracleでは、VARCHAR出力ホスト変数の長さコンポーネントが自動的に設定されます。SELECTまたはFETCHでVARCHAR変数にNULLを入れた場合、サーバーでは長さメンバーも配列メンバーも変更されません。


注意:

NULLをVARCHARホスト変数に選択した場合に、対応する標識変数がないと、実行時にORA-01405エラーが発生します。これを回避するには、すべてのホスト変数に対応して標識変数を記述します。(一時修正としては、UNSAFE_NULL=YESプリコンパイラ・オプションを使用します。「DBMS」も参照してください。)

VARCHAR変数を使用したNULLの挿入

VARCHAR変数の長さを0に設定してからUPDATE文またはINSERT文を実行すると、列値はNULLに設定されます。列にNOT NULL制約がある場合は、エラーが戻されます。

関数へのVARCHAR変数の受渡し

VARCHARは構造体であり、ほとんどのCコンパイラでは、構造体を値で関数に渡すこと、および関数からコピーで構造体を戻すことが可能です。ただし、Pro*C/C++では、VARCHARを参照により関数に渡す必要があります。次の例は、VARCHAR変数を関数に渡す正しい方法を示しています。

VARCHAR emp_name[20]; 
... 
emp_name.len = 20; 
SELECT ename INTO :emp_name FROM emp 
WHERE empno = 7499; 
... 
print_employee_name(&emp_name); /* pass by pointer */ 
... 
 
print_employee_name(name) 
VARCHAR *name; 
{ 
    ... 
    printf("name is %.*s\n", name->len, name->arr); 
    ... 
}

VARCHAR配列コンポーネントの長さを調べる方法

プリコンパイラでVARCHAR宣言が処理されると、生成される構造体内の配列要素の実際の長さが、宣言された長さよりも長くなることがあります。たとえば、Sun Solarisシステムで次のようなPro*C/C++宣言があるとします。

VARCHAR my_varchar[12];
 

この宣言は、プリコンパイラにより次のように展開されます。

struct my_varchar
{
    unsigned short len;
    unsigned char  arr[12];
};

しかし、このシステムのプリコンパイラまたはCコンパイラは、配列コンポーネントの長さをパディングして14バイトにします。このアラインメント要件は、構造体全体の長さをパディングして16バイトにします。パディングされた配列が14バイト、長さが2バイトです。

SQLVarcharGetLength()(非スレッドsqlvcp()と置換)関数(SQLLIBランタイム・ライブラリの一部)により、配列メンバーの実際の(パディングされている場合もあります)長さが戻されます。

SQLVarcharGetLength()関数には、VARCHARホスト変数またはVARCHARポインタ・ホスト変数のデータの長さを渡します。SQLVarcharGetLength()からは、VARCHARの配列コンポーネント合計の長さが戻されます。合計の長さには、使用しているCコンパイラにより追加された可能性のあるパディングが含まれます。

SQLVarcharGetLength()の構文は、次のとおりです。

SQLVarcharGetLength (dvoid *context, unsigned long *datlen, unsigned long *totlen); 

シングル・スレッド・アプリケーションの場合は、sqlvcp()を使用してください。VARCHARの長さをdatlenパラメータに指定してから、sqlvcp()をコールします。関数の戻り時には、totlenパラメータに配列要素の合計の長さが設定されています。どちらのパラメータもunsigned long整数へのポインタであるため、参照で渡す必要があります。


関連項目

この関数および他のすべてのSQLLIBパブリック関数の詳細は、「SQLLIBパブリック関数の新しい名前」を参照してください。

サンプル・プログラム: sqlvcp()の使用

次のサンプル・プログラムは、Pro*C/C++アプリケーションでの関数の使用方法を示しています。また、このサンプル・プログラムではsqlgls()関数も使用しています。このサンプルでは、まずVARCHARポインタを宣言してから、sqlvcp()関数を使用してVARCHARバッファに必要なサイズを決定します。プログラムでは、EMP表から従業員名がFETCHされて出力されます。最後に、sqlgls()関数を使用してSQL文とその関数コード、長さの属性が出力されます。このプログラムは、demoディレクトリのsqlvcp.pcとしてオンラインで使用できます。

/*
 *  The sqlvcp.pc program demonstrates how you can use the
 *  sqlvcp() function to determine the actual size of a
 *  VARCHAR struct. The size is then used as an offset to
 *  increment a pointer that steps through an array of
 *  VARCHARs.
 *
 *  This program also demonstrates the use of the sqlgls()
 *  function, to get the text of the last SQL statement executed.
 *  sqlgls() is described in the "Error Handling" chapter of
 *  The Programmer's Guide to the Oracle Pro*C/C++ Precompiler.
 */

#include <stdio.h> 
#include <sqlca.h>
#include <sqlcpr.h>

/*  Fake a VARCHAR pointer type. */ 

struct my_vc_ptr 
{ 
    unsigned short len; 
    unsigned char arr[32767]; 
}; 

/* Define a type for the VARCHAR pointer */
typedef struct my_vc_ptr my_vc_ptr; 
my_vc_ptr *vc_ptr; 


EXEC SQL BEGIN DECLARE SECTION; 
VARCHAR *names;  
int      limit;    /* for use in FETCH FOR clause  */ 
char    *username = "scott/tiger"; 
EXEC SQL END DECLARE SECTION; 
void sql_error(); 
extern void sqlvcp(), sqlgls(); 

main() 
{ 
    unsigned int vcplen, function_code, padlen, buflen; 
    int i; 
    char stmt_buf[120]; 

    EXEC SQL WHENEVER SQLERROR DO sql_error(); 

    EXEC SQL CONNECT :username; 
    printf("\nConnected.\n"); 
     
/*  Find number of rows in table. */ 
    EXEC SQL SELECT COUNT(*) INTO :limit FROM emp; 
     
     
/*  Declare a cursor for the FETCH statement. */ 
    EXEC SQL DECLARE emp_name_cursor CURSOR FOR 
    SELECT ename FROM emp; 
    EXEC SQL FOR :limit OPEN emp_name_cursor; 
     
/*  Set the desired DATA length for the VARCHAR. */ 
    vcplen = 10; 
     
/*  Use SQLVCP to help find the length to malloc. */ 
    sqlvcp(&vcplen, &padlen); 
    printf("Actual array length of VARCHAR is %ld\n", padlen); 
     
/*  Allocate the names buffer for names. 
    Set the limit variable for the FOR clause. */ 
    names = (VARCHAR *) malloc((sizeof (short) + 
    (int) padlen) * limit); 
    if (names == 0) 
    { 
        printf("Memory allocation error.\n"); 
        exit(1); 
    }
/*  Set the maximum lengths before the FETCH. 
 *  Note the "trick" to get an effective VARCHAR *.
 */ 
    for (vc_ptr = (my_vc_ptr *) names, i = 0; i < limit; i++) 
    { 
        vc_ptr->len = (short) padlen; 
        vc_ptr = (my_vc_ptr *)((char *) vc_ptr + 
        padlen + sizeof (short)); 
    } 
/*  Execute the FETCH. */ 
    EXEC SQL FOR :limit FETCH emp_name_cursor INTO :names; 
     
/*  Print the results. */ 
    printf("Employee names--\n"); 
    
    for (vc_ptr = (my_vc_ptr *) names, i = 0; i < limit; i++) 
    { 
        printf
         ("%.*s\t(%d)\n", vc_ptr->len, vc_ptr->arr, vc_ptr->len); 
        vc_ptr = (my_vc_ptr *)((char *) vc_ptr + 
                  padlen + sizeof (short)); 
    } 
     
/*  Get statistics about the most recent 
 *  SQL statement using SQLGLS. Note that 
 *  the most recent statement in this example 
 *  is not a FETCH, but rather "SELECT ENAME FROM EMP" 
 *  (the cursor).
 */ 
    buflen = (long) sizeof (stmt_buf); 
    
/*  The returned value should be 1, indicating no error. */ 
    sqlgls(stmt_buf, &buflen, &function_code);
    if (buflen != 0)
    { 
        /* Print out the SQL statement. */ 
        printf("The SQL statement was--\n%.*s\n", buflen, stmt_buf); 
     
        /* Print the returned length. */ 
        printf("The statement length is %ld\n", buflen); 
     
        /* Print the attributes. */ 
        printf("The function code is %ld\n", function_code); 
    
        EXEC SQL COMMIT RELEASE; 
        exit(0); 
    }
    else 
    { 
        printf("The SQLGLS function returned an error.\n"); 
        EXEC SQL ROLLBACK RELEASE; 
        exit(1); 
    } 
} 

void
sql_error() 
{ 
    char err_msg[512]; 
    int buf_len, msg_len;

     
    EXEC SQL WHENEVER SQLERROR CONTINUE; 
 
    buf_len = sizeof (err_msg); 
    sqlglm(err_msg, &buf_len, &msg_len); 
    printf("%.*s\n", msg_len, err_msg); 
 
    EXEC SQL ROLLBACK RELEASE; 
    exit(1); 
} 

カーソル変数

Pro*C/C++プログラムでは、問合せにカーソル変数を使用できます。カーソル変数は、OracleサーバーでPL/SQLを使用して定義し、オープンする必要のあるカーソルのハンドルです。カーソル変数の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

カーソル変数の利点は、次のとおりです。

カーソル変数の宣言

Pro*C/C++のSQL_CURSOR疑似型を使用して、Pro*C/C++プログラム内でカーソル変数を宣言します。次に例を示します。

EXEC SQL BEGIN DECLARE SECTION;
    sql_cursor     emp_cursor;             /* a cursor variable */
    SQL_CURSOR     dept_cursor;      /* another cursor variable */
    sql_cursor     *ecp;      /* a pointer to a cursor variable */
    ...
EXEC SQL END DECLARE SECTION;
ecp = &emp_cursor;             /* assign a value to the pointer */

カーソル変数を宣言するときに、型指定にはすべて大文字のSQL_CURSOR、あるいはすべて小文字のsql_cursorを使用できます。大文字と小文字の組合せは使用できません。

カーソル変数は、Pro*C/C++プログラム内の他のホスト変数と同様です。カーソル変数にはスコープがあり、C言語のスコープ規則に従っています。カーソル変数は、他の関数にパラメータとして渡すことができ、カーソル変数を宣言しているソース・ファイルの外部にある関数にも渡すことができます。また、カーソル変数を戻す関数のみでなく、カーソル変数へのポインタを戻す関数も定義できます。


注意:

SQL_CURSORは、C言語の構造体としてPro*C/C++で生成されるコードに実装されます。したがって、常にポインタを使用して他の関数に渡したり、関数からカーソル変数へのポインタを戻したりすることができます。ただし、SQL_CURSORを値で渡す、あるいは戻すことができるのは、Cコンパイラでその操作がサポートされている場合のみです。

カーソル変数の割当て

カーソル変数をオープンするか、カーソル変数を使用してFETCHする前に、カーソルを割り当てる必要があります。そのためには、新しいプリコンパイラ・コマンドALLOCATEを使用します。たとえば、前述の例で宣言したSQL_CURSOR emp_cursorを割り当てるには、次の文を記述します。

EXEC SQL ALLOCATE :emp_cursor;

カーソルの割当てには、プリコンパイル時も実行時もサーバーのコールは必要ありません。ALLOCATE文に誤り(未宣言のホスト変数など)があると、Pro*C/C++ではプリコンパイル時エラーが発行されます。カーソル変数を割り当てると、ヒープ・メモリーが使用されます。このため、プログラム・ループ内でカーソルを解放できます。カーソル変数に割り当てられるメモリーは、カーソルがクローズされるときには解放されず、明示的なCLOSEが実行されるか、接続がクローズされるときにのみ解放されます。

EXEC SQL CLOSE :emp_cursor;

カーソル変数のオープン

カーソル変数はOracleデータベース・サーバー上でオープンする必要があります。埋込みSQL OPENコマンドを使用しても、カーソル変数はオープンできません。カーソル変数をオープンするには、カーソルをオープン(および同じ文中で定義)するPL/SQLストアド・プロシージャをコールする方法と、Pro*C/C++プログラム内で無名PL/SQLブロックを使用してカーソル変数をオープンし、定義する方法があります。

たとえば、次のPL/SQLパッケージがデータベースに格納されているとします。

CREATE PACKAGE demo_cur_pkg AS
    TYPE EmpName IS RECORD (name VARCHAR2(10));
    TYPE cur_type IS REF CURSOR RETURN EmpName;
    PROCEDURE open_emp_cur (
               curs     IN OUT cur_type,
               dept_num IN     NUMBER);
END;

CREATE PACKAGE BODY demo_cur_pkg AS
    CREATE PROCEDURE open_emp_cur (
               curs     IN OUT cur_type,
               dept_num IN     NUMBER) IS
    BEGIN
        OPEN curs FOR
            SELECT ename FROM emp
                WHERE deptno = dept_num
                ORDER BY ename ASC;
    END;
END;

このパッケージが格納された後で、Pro*C/C++プログラムからopen_emp_curストアド・プロシージャをコールしてカーソルcursをオープンし、プログラム内のカーソルからFETCHできます。次に例を示します。

...
sql_cursor    emp_cursor;
char          emp_name[11];
...
EXEC SQL ALLOCATE :emp_cursor;  /* allocate the cursor variable */
...
/* Open the cursor on the server side. */
EXEC SQL EXECUTE
    begin
        demo_cur_pkg.open_emp_cur(:emp_cursor, :dept_num);
    end;
;
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
    EXEC SQL FETCH :emp_cursor INTO :emp_name;
    printf("%s\n", emp_name);
}
...

Pro*C/C++プログラム内で無名PL/SQLブロックを使用してカーソルをオープンするには、無名ブロック内でカーソルを定義します。次に例を示します。

sql_cursor emp_cursor;
int dept_num = 10;
...
EXEC SQL EXECUTE
    BEGIN
        OPEN :emp_cursor FOR SELECT ename FROM emp
             WHERE deptno = :dept_num;
    END;
END-EXEC;
...

前述の各例は、PL/SQLを使用してカーソル変数をオープンする方法を示しています。次のように、埋込みSQL文でCURSOR句を使用してカーソル変数をオープンすることもできます。

...
sql_cursor emp_cursor;
...
EXEC ORACLE OPTION(select_error=no);
EXEC SQL
    SELECT CURSOR(SELECT ename FROM emp WHERE deptno = :dept_num)
    INTO :emp_cursor FROM DUAL;
EXEC ORACLE OPTION(select_error=yes);

前述の文では、emp_cursorカーソル変数が最も外側のSELECTの最初の列にバインドされています。最初の列は、それ自体が問合せですが、CURSOR(...)変換句が指定されているため、sql_cursorホスト変数と互換性のある形式で表されています。

CURSOR句を含む問合せを使用する場合は、SELECT_ERRORオプションをNOに設定する必要があります。これにより、親カーソルの取消しが禁止され、プログラムをエラーなしで実行できます。

スタンドアロン・ストアド・プロシージャでのオープン

前述の例では、参照カーソルがパッケージ内で定義され、カーソルはそのパッケージ内のプロシージャ内でオープンされました。しかし、参照カーソルは、カーソルをオープンするプロシージャと同じパッケージ内で定義しなくてもかまいません。

スタンドアロン・ストアド・プロシージャ内でカーソルをオープンする必要がある場合は、別のパッケージ内にカーソルを定義し、カーソルをオープンするスタンドアロン・ストアド・プロシージャ内で、そのパッケージを参照できます。次に例を示します。

PACKAGE dummy IS
    TYPE EmpName IS RECORD (name VARCHAR2(10));
    TYPE emp_cursor_type IS REF CURSOR RETURN EmpName;
END;
-- and then define a standalone procedure:
PROCEDURE open_emp_curs (
      emp_cursor IN OUT dummy.emp_cursor_type;
      dept_num   IN     NUMBER) IS
    BEGIN
        OPEN emp_cursor FOR
            SELECT ename FROM emp WHERE deptno = dept_num;
    END;
END;

戻り型

PL/SQLストアド・プロシージャ内に参照カーソルを定義する場合は、カーソルが戻す値の型を宣言する必要があります。参照カーソルの型とその戻り型の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。

カーソル変数のクローズと解放

カーソル変数をクローズするには、CLOSEコマンドを使用します。たとえば、前述の例でOPENしたemp_cursorカーソル変数をクローズするには、埋込みSQL文を使用します。

EXEC SQL CLOSE :emp_cursor;

カーソル変数はホスト変数であるため、前にコロンを付ける必要があります。

ALLOCATEで割り当てたカーソル変数を再利用できます。アプリケーションで必要な回数だけオープン、FETCHおよびCLOSEできます。ただし、サーバーから切断してから再接続する場合は、カーソル変数をALLOCATEで再度割り当てる必要があります。

カーソルは、FREE埋込みSQL文で割当て解除されます。次に例を示します。

EXEC SQL FREE :emp_cursor;

オープンしているカーソルはクローズされ、割り当てられたメモリーは解放されます。

OCIでのカーソル変数の使用(リリース7のみ)

Pro*C/C++のカーソル変数をOCI関数と共有できます。そのためには、SQLLIB変換関数SQLCDAFromResultSetCursor()(以前のsqlcdat())およびSQLCDAToResultSetCursor(以前のsqlcurt())を使用する必要があります。これらの関数を使用して、OCIのカーソル・データ領域をPro*C/C++のカーソル変数に変換します。

SQLCDAFromResultSetCursor()関数では、割当て済のカーソル変数がOCIカーソル・データ領域に変換されます。次に構文を示します。

void SQLCDAFromResultSetCursor(dvoid *context, Cda_Def *cda, void *cur, 
   sword *retval);

各パラメータは次のとおりです。

パラメータ 説明
context SQLLIBランタイム・コンテキストへのポインタ
cda 変換先のOCIカーソル・データ領域へのポインタ
cur 変換元のPro*C/C++カーソル変数へのポインタ
retval エラーがなければ0、それ以外の場合はSQLLIB(SQL)のエラー番号


注意:

エラーの場合には、CDAのV2およびrcリターン・コード・フィールドもエラー・コードを受け取ります。CDAの処理済行数フィールドは設定されません。

非スレッドまたはデフォルト・コンテキスト・アプリケーションでは、定義した定数SQL_SINGLE_RCTXをコンテキストとして渡してください。


SQLCDAToResultSetCursor()関数では、OCIのカーソル・データ領域がPro*C/C++のカーソル変数に変換されます。次に構文を示します。

void SQLCDAToResultSetCursor(dvoid *context, void *cur, Cda_Def *cda, 
   int *retval);

各パラメータは次のとおりです。

パラメータ 説明
context SQLLIBランタイム・コンテキストへのポインタ
cur 変換先のPro*C/C++カーソル変数へのポインタ
cda 変換元のOCIカーソル・データ領域へのポインタ
retval エラーがなければ0、それ以外の場合はエラー・コード


注意:

SQLCA構造体は、このルーチンでは更新されません。SQLCAコンポーネントが設定されるのは、変換されたカーソルを使用してデータベース操作が実行された後のみです。

非スレッド・アプリケーションでは、定義した定数SQL_SINGLE_RCTXをコンテキストとして渡してください。


これらの関数に対するANSIとK&Rのプロトタイプは、sql2oci.hヘッダー・ファイルに用意されています。これらの関数をコールする前に、cdaおよびcurのメモリーを割り当てる必要があります。


関連項目

SQLLIBパブリック関数の詳細は、「SQLLIBパブリック関数の新しい名前」の表を参照してください。

制限

カーソル変数の使用には、次の制限が適用されます。

  • Pro*C/C++とOCI V7で同じカーソル変数を使用する場合は、接続直後にSQLLDAGetCurrent()またはSQLLDAGetName()を使用する必要があります。

  • カーソル変数をOCIリリース8で対応するものには変換できません。

  • カーソル変数は動的SQLでは使用できません。

  • カーソル変数を使用できるコマンドは、ALLOCATE、FETCH、FREEおよびCLOSEのみです。

  • DECLARE CURSORコマンドは、カーソル変数には適用されません。

  • CLOSEでクローズしたカーソル変数からのFETCHはできません。

  • ALLOCATEで割り当てられていないカーソル変数からのFETCHはできません。

  • MODE=ANSIを指定してプリコンパイルする場合、すでにクローズ済のカーソル変数をクローズするとエラーになります。

  • AT句は、ALLOCATEコマンド、カーソル変数を参照するFETCHコマンドおよびCLOSEコマンドには使用できません。

  • カーソル変数はデータベースの列に格納できません。

  • カーソル変数自体は、パッケージ指定内で宣言できません。パッケージ指定内で宣言できるのは、カーソル変数の型のみです。

  • カーソル変数は、PL/SQLレコードのコンポーネントにはできません。

例: cv_demo.sqlおよびsample11.pc

次のサンプル・プログラム(PL/SQLスクリプトとPro*C/C++プログラム)は、カーソル変数の使用方法を示しています。これらのソースはdemoディレクトリにあり、オンラインで使用できます。demoディレクトリにある同じアプリケーションの別バージョンcv_demo.pcも参照してください。

cv_demo.sql

-- PL/SQL source for a package that declares and
-- opens a ref cursor
CONNECT SCOTT/TIGER;
CREATE OR REPLACE PACKAGE emp_demo_pkg as
   TYPE emp_cur_type IS REF CURSOR RETURN emp%ROWTYPE;
     PROCEDURE open_cur(curs IN OUT emp_cur_type, dno IN NUMBER);
END emp_demo_pkg;
 
 
CREATE OR REPLACE PACKAGE BODY emp_demo_pkg AS
    PROCEDURE open_cur(curs IN OUT emp_cur_type, dno IN NUMBER) IS
    BEGIN 
        OPEN curs FOR SELECT *
            FROM emp WHERE deptno = dno
            ORDER BY ename ASC;
    END;
END emp_demo_pkg;

sample11.pc

/*
 *  Fetch from the EMP table, using a cursor variable.
 *  The cursor is opened in the stored PL/SQL procedure
 *  open_cur, in the EMP_DEMO_PKG package.
 *
 *  This package is available on-line in the file
 *  sample11.sql, in the demo directory.
 *
 */
 
#include <stdio.h>
#include <sqlca.h>
#include <stdlib.h>
#include <sqlda.h>
#include <sqlcpr.h>
 
/* Error handling function. */
void sql_error(msg)
    char *msg;
{
    size_t clen, fc;
    char cbuf[128];
 
    clen = sizeof (cbuf);
    sqlgls((char *)cbuf, (size_t *)&clen, (size_t *)&fc);
 
    printf("\n%s\n", msg);
    printf("Statement is--\n%s\n", cbuf);
    printf("Function code is %ld\n\n", fc);
 
    sqlglm((char *)cbuf, (size_t *) &clen, (size_t *) &clen);
    printf ("\n%.*s\n", clen, cbuf);
  
    EXEC SQL WHENEVER SQLERROR CONTINUE;
    EXEC SQL ROLLBACK WORK RELEASE;
    exit(EXIT_FAILURE);
}

void main()
{
    char temp[32];
 
    EXEC SQL BEGIN DECLARE SECTION;
        char *uid = "scott/tiger";
        SQL_CURSOR emp_cursor;
        int dept_num;
        struct
        {
            int   emp_num;
            char  emp_name[11];
            char  job[10];
            int   manager;
            char  hire_date[10];
            float salary;
            float commission;
            int   dept_num;
        } emp_info;
    
        struct
        {
            short emp_num_ind;
            short emp_name_ind;
            short job_ind;
            short manager_ind;
            short hire_date_ind;
            short salary_ind;
            short commission_ind;
            short dept_num_ind;
        } emp_info_ind;
    EXEC SQL END DECLARE SECTION;
    
    EXEC SQL WHENEVER SQLERROR do sql_error("Oracle error");
    
/* Connect to Oracle. */
    EXEC SQL CONNECT :uid;
 
/* Allocate the cursor variable. */
    EXEC SQL ALLOCATE :emp_cursor;
 
/* Exit the inner for (;;) loop when NO DATA FOUND. */
    EXEC SQL WHENEVER NOT FOUND DO break;
 
    for (;;)
    {
        printf("\nEnter department number  (0 to exit): ");
        gets(temp);
        dept_num = atoi(temp);
        if (dept_num <= 0)
            break;
 
        EXEC SQL EXECUTE
            begin
                emp_demo_pkg.open_cur(:emp_cursor, :dept_num);
            end;
        END-EXEC;
 
        printf("\nFor department %d--\n", dept_num);
        printf("ENAME           SAL     COMM\n");
        printf("-----           ---     ----\n");
 
/* Fetch each row in the EMP table into the data struct.
   Note the use of a parallel indicator struct. */
        for (;;)
        {
             EXEC SQL FETCH :emp_cursor 
                 INTO :emp_info INDICATOR :emp_info_ind;
 
             printf("%s ", emp_info.emp_name);
             printf("%8.2f ", emp_info.salary);
             if (emp_info_ind.commission_ind != 0)
                 printf("    NULL\n");
             else
                 printf("%8.2f\n", emp_info.commission);
        }
 
    }
 
/* Close the cursor. */
    EXEC SQL WHENEVER SQLERROR CONTINUE;
    EXEC SQL CLOSE :emp_cursor;

/* Disconnect from Oracle. */
    EXEC SQL ROLLBACK WORK RELEASE;
    exit(EXIT_SUCCESS);

}

コンテキスト変数

ランタイム・コンテキストは、通常は単にコンテキストと呼ばれ、クライアント・メモリーの領域へのハンドルです。このクライアント・メモリーには、0個以上の接続、0個以上のカーソル、そのインライン・オプション(MODE、HOLD_CURSOR、RELEASE_CURSOR、SELECT_ERRORなど)および他の状態情報が含まれます。

コンテキスト・ホスト変数を定義するには、sql_context疑似型を使用します。次に例を示します。

sql_context my_context ;

CONTEXT ALLOCATEプリコンパイラ・ディレクティブを使用し、コンテキスト用のメモリーを割り当てて初期化します。

EXEC SQL CONTEXT ALLOCATE :context ;

contextは、コンテキストへのハンドルであるホスト変数です。次に例を示します。

EXEC SQL CONTEXT ALLOCATE :my_context ;

CONTEXT USEプリコンパイラ・ディレクティブを使用して、プログラム・ロジックの流れではなく、ソース・ファイルのその点から埋込みSQL文(CONNECT、INSERT、DECLARE CURSORなど)で使用するコンテキストを定義します。このコンテキストは、別のCONTEXT USE文の検出時まで使用されます。次に構文を示します。

EXEC SQL CONTEXT USE {:context | DEFAULT} ;

DEFAULTキーワードでは、以降に実行されるすべての埋込みSQL文で使用されるデフォルト(またはグローバル)・コンテキストが指定されます。このコンテキストは、別のCONTEXT USEディレクティブが検出されるまで使用されます。次に簡単な例を示します。

EXEC SQL CONTEXT USE :my_context ;

コンテキスト変数my_contextが定義および割り当てられていない場合、エラーが戻されます。

CONTEXT FREE文を使用すると、コンテキストに使用されたメモリーが不要になった場合に、メモリーを解放できます。

EXEC SQL CONTEXT FREE :context ;

次に例を示します。

EXEC SQL CONTEXT FREE :my_context ;

次の例は、ユーザー定義コンテキストと同じアプリケーションにおけるデフォルト・コンテキストの使用方法を示しています。

CONTEXT USEの例

#include <sqlca.h>
#include <ociextp.h>
main()
{
   sql_context ctx1;
   char *usr1 = "scott/tiger";
   char *usr2 = "system/manager";

   /* Establish connection to SCOTT in global runtime context */
   EXEC SQL CONNECT :usr1;

   /* Establish connection to SYSTEM in runtime context ctx1 */
   EXEC SQL CONTEXT ALLOCATE :ctx1;
   EXEC SQL CONTEXT USE :ctx1;
   EXEC SQL CONNECT :usr2; 

   /* Insert into the emp table from schema SCOTT */
   EXEC SQL CONTEXT USE DEFAULT;
   EXEC SQL INSERT INTO emp (empno, ename) VALUES (1234, 'WALKER');
   ...
}

ユニバーサルROWID

データベース・サーバーでは、ヒープ表および索引構成表という2種類の表編成が使用されています。

デフォルトでは、ヒープ表が使用されます。物理行アドレス(ROWID)は、ヒープ表の行の識別に使用される永続的なプロパティです。物理ROWIDの外部文字書式は、64をベースとする18バイト文字列です。

索引構成表には、永続識別子としての物理行アドレスはありません。これらの表には、論理ROWIDが定義されています。索引構成表からSELECT ROWID ...文を使用すると、ROWIDは表の主キー、制御情報およびオプションの物理的な不確定要素を含む不透明な構造になります。このROWIDをWHERE ROWID = ...などの句を含むSQL文で使用して、表から値を取得できます。

ユニバーサルROWIDは、物理ROWIDと論理ROWIDの両方で使用できます。表編成の変更はアプリケーションに影響しないため、ユニバーサルROWIDを使用すると、ヒープ表または索引構成表のデータにアクセスできます。ROWIDに使用される列データ型はUROWID(length)で、lengthはオプションです。

すべての新規アプリケーションで、ユニバーサルROWIDを使用します。

ユニバーサルROWIDの詳細は、『Oracle Database概要』を参照してください。

ユニバーサルROWID変数の使用方法は、次のとおりです。

次に例を示します。

OCIRowid *my_urowid ;
...
EXEC SQL ALLOCATE :my_urowid ;
/* Bind my_urowid as type SQLT_RDD -- no implicit conversion */
EXEC SQL SELECT rowid INTO :my_urowid FROM my_table WHERE ... ;
...
EXEC SQL UPDATE my_table SET ... WHERE rowid = :my_urowid ;
EXEC SQL FREE my_urpwid ;
...

また、19(18バイトとヌル終端文字)〜4001の幅を持つ文字ホスト変数を、ユニバーサルROWIDのホスト・バインド変数として使用することもできます。文字ベースのユニバーサルROWIDはヒープ表でもサポートされていますが、下位互換性しかありません。ユニバーサルROWIDは可変長であるため、切り捨てられる場合があります。

文字変数の使用方法は、次のとおりです。

/* n is based on table characteristics  */
int n=4001 ;
char my_urowid_char[n] ;
...
EXEC SQL ALLOCATE :my_urowid_char ;
/* Bind my_urowid_char as SQLT_STR  */
EXEC SQL SELECT rowid INTO :my_urowid_char FROM my_table WHERE ... ;
EXEC ORACLE OPTION(CHAR_MAP=STRING);
EXEC SQL UPDATE my_table SET ... WHERE rowid = :my_urowid_char ;
EXEC SQL FREE :my_urowid_char ;
...

関連項目

ユニバーサルROWIDを使用した位置付け更新の例は、「位置付け更新」を参照してください。

SQLRowidGet()

SQLLIB関数SQLRowidGet()を使用すると、最後に挿入、更新または選択された行のユニバーサルROWIDへのポインタを取得できます。関数プロトタイプとその引数は、次のとおりです。

void SQLRowidGet (dvoid *rctx, OCIRowid **urid) ;

rctx (IN)

これは、ランタイム・コンテキストへのポインタです。デフォルト・コンテキストまたは非スレッドの場合は、SQL_SINGLE_RCTXを渡します。

urid (OUT)

これは、ユニバーサルROWIDポインタへのポインタです。通常の実行が終了すると、有効なROWIDをポイントします。エラーが発生した場合は、NULLが戻されます。


注意:

SQLRowidGet()をコールするには、ユニバーサルROWIDポインタを事前に割り当てる必要があります。その後、ユニバーサルROWIDにFREEを使用してください。

ホスト構造体

C言語の構造体を使用すると、ホスト変数を組み込むことができます。SELECT文またはFETCH文のINTO句と、INSERT文のVALUESリストに、ホスト変数を含んでいる構造体を参照します。ホスト構造体のすべてのコンポーネントは、表4-4の定義のように正当なPro*C/C++ホスト変数である必要があります。

構造体がホスト変数として使用されると、構造体の名前のみがSQL文で使用されます。ただし、構造体の各メンバーは、Oracleにデータを送信したり、問合せでOracleからデータを受信したりします。次の例は、EMP表に従業員を1人追加するときに使用されるホスト構造体を示しています。

typedef struct 
{ 
    char  emp_name[11]; /* one greater than column length */ 
    int   emp_number; 
    int   dept_number; 
    float salary; 
} emp_record; 
... 
/* define a new structure of type "emp_record" */ 
emp_record new_employee; 
 
strcpy(new_employee.emp_name, "CHEN"); 
new_employee.emp_number = 9876; 
new_employee.dept_number = 20; 
new_employee.salary = 4250.00; 
 
EXEC SQL INSERT INTO emp (ename, empno, deptno, sal) 
    VALUES (:new_employee); 

メンバーが構造体で宣言される順序は、SQL文中の対応する列の順序と一致する必要があります。また、INSERT文で列のリストが省略されている場合は、データベース表の列の順序と一致する必要があります。

たとえば、ホスト構造体を次のように使用すると無効になり、ランタイム・エラーが発生します。

struct 
{ 
    int empno; 
    float salary;          /* struct components in wrong order */
    char emp_name[10]; 
} emp_record; 
 
... 
SELECT empno, ename, sal 
   INTO :emp_record FROM emp; 

前述の例が無効となるのは、構造体のコンポーネントが選択リスト内の対応する列とは異なる順序で宣言されているためです。SELECT文の正しい書式は、次のとおりです。

SELECT empno, sal, ename   /* reverse order of sal and ename */
    INTO :emp_record FROM emp;

ホスト構造体と配列

配列とは、要素と呼ばれる関連データ項目のコレクションで、単一の変数名に対応付けられています。ホスト変数として宣言された配列は、ホスト配列と呼ばれます。同様に、配列として宣言された標識変数は、インジケータ配列と呼ばれます。インジケータ配列は、任意のホスト配列に対応付けることができます。

ホスト配列により、データ項目のコレクション全体を単一のSQL文で操作できるため、パフォーマンスを向上させることができます。いくつかの例外を除けば、スカラーのホスト変数が許可される場所であれば、任意の位置でホスト配列を使用できます。また、インジケータ配列は任意のホスト配列に対応付けることができます。

ホスト配列の詳細は、第8章「ホスト配列」も参照してください。

ホスト配列は、ホスト構造体のコンポーネントとして使用できます。次の例では、配列を含む構造体を使用して、EMP表に3つの新規項目をINSERTします。

struct 
{ 
    char emp_name[3][10]; 
    int emp_number[3]; 
    int dept_number[3]; 
} emp_rec; 
... 
strcpy(emp_rec.emp_name[0], "ANQUETIL"); 
strcpy(emp_rec.emp_name[1], "MERCKX"); 
strcpy(emp_rec.emp_name[2], "HINAULT"); 
emp_rec.emp_number[0] = 1964; emp_rec.dept_number[0] = 5; 
emp_rec.emp_number[1] = 1974; emp_rec.dept_number[1] = 5; 
emp_rec.emp_number[2] = 1985; emp_rec.dept_number[2] = 5; 
 
EXEC SQL INSERT INTO emp (ename, empno, deptno) 
    VALUES (:emp_rec); 
...

PL/SQLレコード

C言語の構造体は、PL/SQLレコードにバインドできません。

ネストした構造体と共用体

ホスト構造体はネストできません。次の例は無効です。

struct 
{ 
    int emp_number; 
    struct 
    { 
        float salary; 
        float commission; 
    } sal_info;            /* INVALID */ 
    int dept_number; 
} emp_record; 
... 
EXEC SQL SELECT empno, sal, comm, deptno 
    INTO :emp_record 
    FROM emp; 

また、C言語の共用体をホスト構造体として使用することも、ホスト構造体として使用される構造体に共用体をネストすることもできません。

ホスト・インジケータ構造体

標識変数を使用する必要があっても、ホスト変数がホスト構造体に含まれている場合は、ホスト構造体内のホスト変数ごとに標識変数が含まれるように、2番目の構造体を設定します。

たとえば、ホスト構造体student_recordを次のように宣言するとします。

struct 
{ 
    char s_name[32]; 
    int s_id; 
    char grad_date[9]; 
} student_record; 

このホスト構造体を次のような問合せで使用するとします。

EXEC SQL SELECT student_name, student_idno, graduation_date 
    INTO :student_record 
    FROM college_enrollment 
    WHERE student_idno = 7200; 

また、卒業日がNULLでもよいかどうかを知る必要があります。さらに、個別のホスト・インジケータ構造体を宣言する必要があります。これは、次のように宣言します。

struct 
{ 
    short s_name_ind;  /* indicator variables must be shorts */ 
    short s_id_ind; 
    short grad_date_ind; 
} student_record_ind; 

SQL文中のインジケータ構造体は、ホスト・標識変数を参照する場合と同じ方法で参照してください。

EXEC SQL SELECT student_name, student_idno, graduation_date 
    INTO :student_record INDICATOR :student_record_ind 
    FROM college_enrollment 
    WHERE student_idno = 7200;
 

問合せが完了すると、選択された各コンポーネントのNULL/NOT NULLステータスはホスト・インジケータ構造体で使用可能になります。


注意:

このマニュアルでは、従来どおりホスト変数または構造体の名前に_indを追加して、標識変数とインジケータ構造体の名前にしています。ただし、標識変数の名前は任意です。異なる規則を使用しても、規則をまったく使用しなくてもかまいません。

サンプル・プログラム: カーソルとホスト構造体

この項のデモ・プログラムは、明示カーソルを使用し、データをホスト構造体に格納する問合せを示しています。このプログラムは、demoディレクトリのファイルsample2.pc内で使用できます。

/*
 *  sample2.pc
 *
 *  This program connects to ORACLE, declares and opens a cursor, 
 *  fetches the names, salaries, and commissions of all
 *  salespeople, displays the results, then closes the cursor. 
 */ 

#include <stdio.h>
#include <sqlca.h>

#define UNAME_LEN      20 
#define PWD_LEN        40 
 
/*
 * Use the precompiler typedef'ing capability to create
 * null-terminated strings for the authentication host
 * variables. (This isn't really necessary--plain char *'s
 * does work as well. This is just for illustration.)
 */
typedef char asciiz[PWD_LEN]; 

EXEC SQL TYPE asciiz IS STRING(PWD_LEN) REFERENCE; 
asciiz     username; 
asciiz     password; 

struct emp_info 
{ 
    asciiz     emp_name; 
    float      salary; 
    float      commission; 
}; 


/* Declare function to handle unrecoverable errors. */ 
void sql_error(); 


main() 
{ 
    struct emp_info *emp_rec_ptr; 

/* Allocate memory for emp_info struct. */ 
    if ((emp_rec_ptr = 
        (struct emp_info *) malloc(sizeof(struct emp_info))) == 0)
    { 
        fprintf(stderr, "Memory allocation error.\n"); 
        exit(1); 
    } 
 
/* Connect to ORACLE. */ 
    strcpy(username, "SCOTT"); 
    strcpy(password, "TIGER"); 
 
    EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--");
 
    EXEC SQL CONNECT :username IDENTIFIED BY :password; 
    printf("\nConnected to ORACLE as user: %s\n", username); 
 
/* Declare the cursor. All static SQL explicit cursors
 * contain SELECT commands. 'salespeople' is a SQL identifier,
 * not a (C) host variable.
 */
    EXEC SQL DECLARE salespeople CURSOR FOR 
        SELECT ENAME, SAL, COMM 
            FROM EMP 
            WHERE JOB LIKE 'SALES%'; 
 
/* Open the cursor. */
    EXEC SQL OPEN salespeople; 
 
/* Get ready to print results. */
    printf("\n\nThe company's salespeople are--\n\n");
    printf("Salesperson   Salary   Commission\n"); 
    printf("-----------   ------   ----------\n"); 
 
/* Loop, fetching all salesperson's statistics.
 * Cause the program to break the loop when no more
 * data can be retrieved on the cursor.
 */
    EXEC SQL WHENEVER NOT FOUND DO break; 

    for (;;) 
    { 
        EXEC SQL FETCH salespeople INTO :emp_rec_ptr; 
        printf("%-11s%9.2f%13.2f\n", emp_rec_ptr->emp_name, 
                emp_rec_ptr->salary, emp_rec_ptr->commission); 
    } 
 
/* Close the cursor. */
    EXEC SQL CLOSE salespeople; 
 
    printf("\nArrivederci.\n\n");

    EXEC SQL COMMIT WORK RELEASE; 
    exit(0); 
} 



void 
sql_error(msg) 
char *msg;
{ 
    char err_msg[512];
    int buf_len, msg_len;

    EXEC SQL WHENEVER SQLERROR CONTINUE;

    printf("\n%s\n", msg);

/* Call sqlglm() to get the complete text of the
 * error message.
 */
    buf_len = sizeof (err_msg);
    sqlglm(err_msg, &buf_len, &msg_len);
    printf("%.*s\n", msg_len, err_msg);

    EXEC SQL ROLLBACK RELEASE;
    exit(1);
} 

ポインタ変数

C言語では、他の変数を指すポインタがサポートされています。ポインタには、変数の値ではなくアドレス(格納場所)が保持されます。

ポインタ変数の宣言

ポインタは、次のように、通常のC言語の形式に従ってホスト変数として定義します。

int   *int_ptr; 
char  *char_ptr;

ポインタ変数の参照

SQL文では、次のようにポインタに接頭辞としてコロンを付けてください。

EXEC SQL SELECT intcol INTO :int_ptr FROM ... 

文字列へのポインタを除き、参照される値のサイズは宣言で指定したベース型のサイズにより決定されます。文字列へのポインタの場合、参照される値はNULL終了文字列とみなされます。そのサイズは、strlen()関数のコールにより実行時に決定されます。詳細は、「グローバリゼーション・サポート」も参照してください。

ポインタを使用すると、構造体のメンバーを参照できます。まずポインタ・ホスト変数を宣言してから、次の例に示すように、必要なメンバーのアドレスにポインタを設定します。構造体メンバーとポインタ変数のデータ型は同一にする必要があります。両者が一致しない場合、ほとんどのコンパイラでは警告が発行されます。

struct 
{ 
    int  i; 
    char c; 
} structvar; 
int   *i_ptr; 
char  *c_ptr; 
... 
main() 
{ 
    i_ptr = &structvar.i; 
    c_ptr = &structvar.c; 
/* Use i_ptr and c_ptr in SQL statements. */ 
... 

構造体ポインタ

構造体へのポインタをホスト変数として使用できます。次の例を考えてみます。

  • 構造体を宣言します。

  • 構造体へのポインタを宣言します。

  • 構造体にメモリーを割り当てます。

  • 構造体へのポインタを問合せでホスト変数として使用します。

  • 構造体のコンポーネントの参照を解除して、結果を出力します。

struct EMP_REC 
{ 
    int emp_number; 
    float salary; 
}; 
char *name = "HINAULT"; 
... 
struct EMP_REC *sal_rec; 
sal_rec = (struct EMP_REC *) malloc(sizeof (struct EMP_REC)); 
... 
EXEC SQL SELECT empno, sal INTO :sal_rec 
    FROM emp 
    WHERE ename = :name; 

printf("Employee number and salary for %s: ", name); 
printf("%d, %g\n", sal_rec->emp_number, sal_rec->salary);

SQL文では、ホスト構造体へのポインタは、ホスト構造体とまったく同じ方法で参照されます。「〜のアドレス」を示す表記(&)は不要で、実際には使用するとエラーになります。

グローバリゼーション・サポート

広く使用されている7ビットまたは8ビットのASCIIおよびEBCDICのキャラクタ・セットは、英数字を表すには十分ですが、日本語のようなアジアの言語には数千もの文字が含まれる場合があります。これらの言語では、1文字を表すために16ビット(2バイト)以上が必要です。Oracleによる様々な言語の処理方法について説明します。

Oracleには、シングルバイトおよびマルチバイトの文字データを処理し、キャラクタ・セット間で変換できるように、グローバリゼーション・サポートが用意されています。これにより、異なる言語環境間でアプリケーションを実行できます。グローバリゼーション・サポートでは、数値書式と日付書式は、ユーザー・セッション用に指定された言語規則が自動的に適応されます。したがって、グローバリゼーション・サポートにより、世界中のユーザーがそれぞれの母国語でOracleとやりとりできます。

様々なグローバリゼーション・サポートまたはNLSパラメータを指定して、言語によって異なる機能の操作を制御できます。これらのパラメータのデフォルト値は、Oracle初期ファイルで設定できます。表4-6は、それぞれのグローバリゼーション・サポート・パラメータの指定内容を示しています。

表4-6 グローバリゼーション・サポート・パラメータ

グローバリゼーション・サポート・パラメータ 指定

NLS_LANGUAGE

言語によって異なる表記規則

NLS_TERRITORY

地域によって異なる表記規則

NLS_DATE_FORMAT

日付書式

NLS_DATE_LANGUAGE

曜日と月の名前に使用する言語

NLS_NUMERIC_CHARACTERS

小数点文字とグループ・セパレータ

NLS_CURRENCY

各国通貨記号

NLS_ISO_CURRENCY

ISO通貨記号

NLS_SORT

ソート基準


主なパラメータは、NLS_LANGUAGEおよびNLS_TERRITORYです。NLS_LANGUAGEでは、言語によって異なる次の機能のデフォルト値を指定します。

NLS_TERRITORYでは、地域によって異なる次の機能のデフォルト値を指定します。

パラメータNLS_LANGを次のように指定して、ユーザー・セッション用に言語ごとに異なるグローバリゼーション・サポート機能の操作を制御できます。

NLS_LANG = <language>_<territory>.<character set> 

languageではユーザー・セッション用のNLS_LANGUAGEの値、territoryではNLS_TERRITORYの値、character setでは端末に使用されるコード体系を指定します。コード体系(通常はキャラクタ・セットまたはコード・ページと呼ばれます)は、端末で表示可能なキャラクタ・セットに対応する数値コードの範囲です。これには、端末との通信を制御するコードも含まれています。

NLS_LANGは、環境変数(またはシステムでそれに相当するもの)として定義します。たとえば、Cシェルを使用するUNIXでは、NLS_LANGを次のように定義できます。

setenv NLS_LANG French_France.WE8ISO8859P1 

Oracleデータベース・セッション中に、グローバリゼーション・サポート・パラメータの値を変更できます。ALTER SESSION文を次のように使用してください。

ALTER SESSION SET <globalization support_parameter> = <value>

Pro*C/C++では、グローバリゼーション・サポート機能がすべてサポートされているため、アプリケーションではOracleデータベースに格納されている外国語データを処理できます。たとえば、外国語の文字変数を宣言し、それをINSTRB、LENGTHBおよびSUBSTRBなどの文字列関数に渡すことができます。これらの関数の構文は、それぞれINSTR、LENGTHおよびSUBSTR関数と同じですが、文字単位ではなくバイト単位で機能します。

NLS_INITCAP、NLS_LOWERおよびNLS_UPPER関数を使用して、大/小文字変換の特別なインスタンスを処理できます。また、NLSSORT関数を使用して、バイナリ順序ではなく言語上の順序に基づいてWHERE句の比較を指定できます。グローバリゼーション・サポート・パラメータをTO_CHAR、TO_DATEおよびTO_NUMBER関数に渡すこともできます。グローバリゼーション・サポートの詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。

NCHAR変数

3つの内部データベース・データ型に、各国語キャラクタ・セット・データを格納できます。この種のデータ型は、NCHAR、NCLOBおよびNVARCHAR2です(NCHAR VARYINGとも呼ばれます)。これらのデータ型を使用できるのは、リレーショナル列のみです。

CHARACTER SET [IS] NCHAR_CS

各国語キャラクタ・セット・データを保持するホスト変数を指定するには、文字変数宣言に句CHARACTER SET [IS] NCHAR_CSを挿入します。これで、その変数に各国語キャラクタ・セット・データを格納できます。トークンISは省略してもかまいません。NCHAR_CSは、各国語キャラクタ・セットの名前です。

次に例を示します。

char character set is nchar_cs *str = "<Japanese_string>";

この例で、<Japanese_string>は、変数NLS_NCHARで定義されたように、各国語キャラクタ・セットAL16UTF16にあるUnicode文字で構成されています。

また、コマンドラインにNLS_CHAR=strと入力し、アプリケーションのコードを変更しても、同じ操作を実行できます。

char *str = "<Japanese_string>"

Pro*C/C++では、このように宣言された変数は、環境変数NLS_NCHARで指定されたキャラクタ・セットとして処理されます。NCHAR変数のサイズは、通常のCの変数と同様にバイト数で指定されます。

データをstrに入れるには、次の簡単な問合せを使用します。

EXEC SQL
   SELECT ENAME INTO :str FROM EMP WHERE DEPT = n'<Japanese_string1>';

また、strを次のSELECT文で使用することもできます。

EXEC SQL 
   SELECT DEPT INTO :dept FROM DEPT_TAB WHERE ENAME = :str;

環境変数NLS_NCHAR

Pro*C/C++では、NLS_LOCAL=NOの場合に、データベース・サポートとともに各国語キャラクタ・セットがサポートされます。NLS_LOCAL=NOで、新規の環境変数NLS_NCHARが有効な各国語キャラクタ・セットに設定されていれば、データベース・サーバーでNCHARがサポートされます。『Oracle Databaseリファレンス』のNLS_NCHARに関する項を参照してください。

NLS_NCHARでは、各国語キャラクタ・セット・データ(NCHAR、NVARCHAR2、NCLOB)に使用するキャラクタ・セットを指定します。キャラクタ・セットを指定しない場合は、定義済、あるいはNLS_LANGで間接的に定義済のキャラクタ・セットが使用されます。

NLS_NCHARには、プリコンパイル時と実行時に、有効な各国語キャラクタ・セット(言語名ではなく、NLS_LANGで設定)を指定する必要があります。SQLLIBでは、最初のSQL文の実行時にランタイム・チェックが実行されます。プリコンパイル時と実行時のキャラクタ・セットが異なっていると、SQLLIBからエラー・コードが戻されます。

VAR文でのCONVBUFSZ句

EXEC SQL VAR文を使用すると、ホスト変数をOracleの外部データ型に同値化して、デフォルトの割当てを上書きできます。これはホスト変数の同値化と呼ばれます。

EXEC SQL VAR文には、オプション句CONVBUFSZ (<size>)を使用できます。Oracleランタイム・ライブラリ内で、指定したホスト変数をキャラクタ・セット間で変換するためのバッファのサイズ<size>をバイト単位で指定します。

新しい構文は、次のいずれかです。

EXEC SQL VAR host_variable IS datatype [CONVBUFSZ [IS] (size)] ;

または

EXEC SQL VAR host_variable [CONVBUFSZ [IS] (size)];

datatypeは、次のとおりです。

type_name [ ( { length | precision, scale } ) ]

関連項目

すべてのキーワード、例および変数の詳細は、「VAR(Oracle埋込みSQLディレクティブ)」を参照してください。

埋込みSQL内の文字列

埋込みSQL文中のマルチバイト文字列は、その文字列をマルチバイトとして識別する文字リテラルと、後続の文字列で構成されます。文字列は、通常の一重引用符(')で囲みます。

たとえば、次のような埋込みSQL文があるとします。

EXEC SQL SELECT empno INTO :emp_num FROM emp
    WHERE ename = N'<Japanese_string>';

このSQL文には、マルチバイト文字列が含まれています(<Japanese_string>は、実際には漢字の可能性があります)。つまり、文字列の直前に文字リテラルNが付いているため、これはマルチバイト文字列として識別されます。Oracleでは大/小文字が区別されないため、この例ではnとNのどちらを使用してもかまいません。

文字列の制限事項

マルチバイト文字列では、データ型の同値化(TYPEまたはVARコマンド)は使用できません。

動的SQL方法4は、Pro*C/C++のマルチバイト文字列ホスト変数には使用できません。

標識変数

標識変数は、マルチバイト・キャラクタ(NLS_CHARオプションで指定)であるホスト文字変数とともに使用できます。