4 データ型とホスト変数

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

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

4.1 Oracleのデータ型

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

4.1.1 内部データ型

表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以下)。

BOOLEAN

BOOLEAN データ型は、明確な真理値TrueとFalseで構成されます。

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

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

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

ノート:

LONGデータ型(LONGLONG RAWLONG VARCHARLONG VARRAW)のすべての形式は、Oracle8iリリース8.1.6で非推奨になりました。以降のリリースでは、LONGデータ型は既存のアプリケーションとの下位互換性のために提供されていました。以降のリリースで開発された新しいアプリケーションでは、大量の文字データにCLOBおよびNCLOBデータ型を使用することをお薦めします。

詳細については、以下を参照:

LONGからLOBへの表列の移行

NCHARとNVARCHAR2は、マルチバイト文字データの格納に使用されます。

BOOLEANデータ型を使用して、論理値(TRUEまたはFALSE)をデータベース列に格納できます。

関連項目

4.1.2 外部データ型

表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文で使用する。

BOOLEAN

ブール値(True、FalseまたはUnknown)

ノート:

LONGデータ型(LONGLONG RAWLONG VARCHARLONG VARRAW)のすべての形式は、Oracle8iリリース8.1.6で非推奨になりました。以降のリリースでは、LONGデータ型は既存のアプリケーションとの下位互換性のために提供されていました。以降のリリースで開発された新しいアプリケーションでは、大量の文字データにCLOBおよびNCLOBデータ型を使用することをお薦めします。

詳細については、以下を参照:

LONGからLOBへの表列の移行

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

4.1.2.1 VARCHAR2

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

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

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

4.1.2.1.1 入力時

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

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

文字値が有効な数値を表している場合は、Oracleはその文字値をNUMBER列値に変換できます。文字値が有効な数値を表していない場合は、エラーが発生します。

4.1.2.1.2 出力時

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

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

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

4.1.2.2 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では出力値の空白を埋め込んだり、NULLで終了させたりしません。戻された値の長さを知る必要がある場合は、かわりにVARNUMデータ型を使用します。

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

4.1.2.3 INTEGER

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

4.1.2.4 FLOAT

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

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

4.1.2.5 STRING

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

4.1.2.5.1 入力時

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

4.1.2.5.2 出力時

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

4.1.2.6 VARNUM

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

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

通常、このデータ型を使用する理由はほとんどありません。

4.1.2.7 LONG

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

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

4.1.2.8 VARCHAR

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

4.1.2.9 ROWID

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

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

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

BBBBBBBB.RRRR.FFFF 

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

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

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

ノート:

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

4.1.2.10 DATE

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

表4-3 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.(西暦紀元前)の日付は99以下です。エポックは、紀元前4712年1月1日です。この日付の場合、世紀のバイトは53で、年のバイトは88です。時間のバイト範囲は1から24です。分と秒の範囲は、1から60です。時刻のデフォルトは、午前零時(1, 1, 1)です。

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

4.1.2.11 RAW

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

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

4.1.2.12 VARRAW

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

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

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

4.1.2.13 LONG RAW

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

LONG RAWデータはLONGデータと似ていますが、OracleではLONG RAWデータの意味は解釈されず、LONG RAWデータをあるシステムから別のシステムへ送信しても文字セットは変換されません。

4.1.2.14 UNSIGNED

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

4.1.2.15 LONG VARCHAR

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

4.1.2.16 LONG VARRAW

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

4.1.2.17 CHAR

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

4.1.2.17.1 入力時

Oracleでは、入力ホスト変数に指定されたバイト数を読み取り、後続の空白を切り捨てずに、ターゲット・データベース列に入力値を格納します。

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

4.1.2.17.2 出力時

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

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

4.1.2.18 CHARZ

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

4.1.2.18.1 入力時

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

4.1.2.18.2 出力時

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

4.1.2.19 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かどうかをチェックする必要があります。

4.1.2.20 BOOLEAN

アプリケーションは、データベースにデータを挿入するときに、BOOLEAN型の列にTRUEまたはFALSE値を挿入できます。値は次のとおりです。

  • "TRUE"または"true"

  • "FALSE"または"false"

ゼロ以外の整数はTRUEを表し、整数ゼロ(0)はFALSEを表します。

NOT NULL制約によって禁止されていないかぎり、ブール・データ型では真理値UNKNOWNもNULL値としてサポートされます。

4.1.3 その他の外部データ型

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

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

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

4.1.3.2 ANSI DATE

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

このデータ型ではなく、日付および時刻が含まれているTIMESTAMPデータ型の使用をお薦めします。

4.1.3.3 TIMESTAMP

TIMESTAMPデータ型は、DATEデータ型の拡張です。DATEデータ型の年、月、日の他、時、分、秒の値が格納されます。タイム・ゾーンはありません。TIMESTAMPデータ型の書式は次のようになります。

TIMESTAMP(fractional_seconds_precision) 

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

4.1.3.4 TIMESTAMPWITHTIMEZONE

TIMESTAMP WITH TIME ZONE (TSTZ)データ型は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オフセットにかかわらず、同一であるとみなされます。

4.1.3.5 TIMESTAMPWITHLOCALTIMEZONE

TIMESTAMP WITH LOCAL TIME ZONE (TSLTZ)データ型はTIMESTAMPの別の改良型で、その値にタイム・ゾーン置換が含まれています。格納される値の形式は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です。

4.1.3.6 INTERVALYEARTOMONTH

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

INTERVAL YEAR(year_precision) TO MONTH

year_precision(オプション)には、YEAR日時フィールドの桁数を指定します。year_precisionのデフォルト値は2です。

4.1.3.7 INTERVALDAYTOSECOND

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です。

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

ノート:

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

4.2 ホスト変数

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

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

4.2.1 ホスト変数の宣言

ホスト変数は、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]

可変長文字列

bool

ブール型のデータ

表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バイトの可変長文字配列

BOOLEAN

bool

short

int

long

float

double

char

char[n]

ブール型のデータ

小さい整数

整数

大きい整数

浮動小数点数

倍精度浮動小数点

NUMBER

単一文字

ノート:

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(長さの指定なし)へのポインタとして宣言する必要があります。ただし、ポインタの配列はサポートされていません。

4.2.1.1 記憶域クラス指定子

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する場合は、最大長を指定する必要があります

4.2.1.2 型修飾子

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

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

4.2.2 ホスト変数の参照

ホスト変数は、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; 
4.2.2.1 制限事項

ホスト変数名は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()); 

4.3 標識変数

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

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

関連項目

4.3.1 INDICATORキーワード

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

:host_variable INDICATOR :indicator_variable 

これは次の構文と同じ意味です。

:host_variable:indicator_variable 

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

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

インジケータの値 意味

0

操作は成功しました。

-1

NULLが戻されたか、挿入または更新されました。

-2

LONG型の文字ホスト変数の出力は、長すぎる部分が切り捨てられましたが、元の列の長さは判別できません。

>0

SELECTまたはFETCHの結果として文字ホスト変数に入ったデータは、長すぎる文が切り捨てられました。この場合、そのホスト変数がマルチバイト文字変数であれば、インジケータの値は元の列の長さを文字数で表したものになります。そのホスト変数がマルチバイト文字変数でなければ、インジケータの長さは元の列の長さをバイト数で表したものになります。

4.3.2 標識変数の使用例

通常、標識変数は、入力ホスト変数への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; 

関連項目

4.3.3 標識変数のガイドライン

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

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

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

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

標識変数では、次のことをしないでください

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

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

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

4.3.4 Oracle制限事項

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

ORA-01405: fetched column value is NULL

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

関連項目

4.4 VARCHAR変数

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

4.4.1 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コンパイル・エラーが発生します。

4.4.2 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); 

4.4.3 VARCHAR変数にNULLを戻す

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

ノート:

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

関連項目

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

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

4.4.5 関数への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); 
    ... 
}

4.4.6 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整数へのポインタであるため、参照で渡す必要があります。

4.4.7 サンプル・プログラム: 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 Developer'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); 
} 

4.5 カーソル変数

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

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

  • メンテナンスのしやすさ

    問合せは、カーソル変数をオープンするストアド・プロシージャに集中されます。カーソルを変更する必要がある場合は、ストアド・プロシージャの変更のみで済みます。各アプリケーションを変更する必要はありません。

  • 便利なセキュリティ機能

    アプリケーションのユーザーは、Pro*C/C++アプリケーションからサーバーへの接続時に使用されるユーザー名です。ユーザーには、カーソルをオープンするストアド・プロシージャに対する実行権限が必要ですが、問合せに使用する表に対する読取り権限は不要です。このセキュリティ機能を使用して、表内の列や、他のストアド・プロシージャへのアクセスを制限できます。

4.5.1 カーソル変数の宣言

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コンパイラでその操作がサポートされている場合のみです。

4.5.2 カーソル変数の割当て

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

EXEC SQL ALLOCATE :emp_cursor;

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

EXEC SQL CLOSE :emp_cursor;

4.5.3 カーソル変数のオープン

カーソル変数は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に設定する必要があります。これにより、親カーソルの取消しが禁止され、プログラムをエラーなしで実行できます。

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

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

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

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;
4.5.3.2 戻り型

PL/SQLストアド・プロシージャ内に参照カーソルを定義する場合は、カーソルが戻す値の型を宣言する必要があります。

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

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

EXEC SQL CLOSE :emp_cursor;

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

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

カーソルは、FREE埋込みSQL文で割当て解除されます。たとえば:

EXEC SQL FREE :emp_cursor;

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

4.5.5 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のメモリーを割り当てる必要があります。

4.5.6 制限(カーソル変数)

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

  • 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レコードのコンポーネントにはできません。

4.5.7 例: cv_demo.sqlおよびsample11.pc

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

4.5.7.1 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;
4.5.7.2 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);

}

4.6 コンテキスト変数

ランタイム・コンテキストは、通常は単にコンテキストと呼ばれ、クライアント・メモリーの領域へのハンドルです。このクライアント・メモリーには、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');
   ...
}

4.7 ユニバーサルROWID

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

デフォルトでは、ヒープ表が使用されます。物理的な行アドレス(ROWID)は、ヒープ表の行を識別するためのパーマネント・プロパティです。物理ROWIDの外部文字書式は、ベース64でエンコーディングした18バイトの文字列です。

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

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

新しいアプリケーションでは、ユニバーサルROWIDを使用してください。

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

  • OCIROWIDへのタイプ・ポインタとして宣言します。

  • ユニバーサルROWID変数用のメモリーを割り当てます。

  • ユニバーサル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 ;
...

4.7.1 SQLRowidGet()

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

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

rctx (IN)

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

urid (OUT)

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

ノート:

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

4.8 ホスト構造体

C言語の構造体を使用すると、ホスト変数を組み込むことができます。SELECT文またはFETCH文のINTO句と、INSERT文のVALUESリストに、ホスト変数を含んでいる構造体を参照します。ホスト構造体のすべてのコンポーネントは、**INTERNAL XREF ERROR**の定義のように正当な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;

4.8.1 ホスト構造体と配列

配列とは、1つの変数名に関連付けられた要素と呼ばれる関連データ項目の集合です。ホスト変数として宣言されたとき、配列はホスト配列と呼ばれます。同様に、配列として宣言されたインジケータ変数はインジケータ配列と呼ばれます。インジケータ配列は、任意のホスト配列に対応付けることができます。

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

ホスト配列は、ホスト構造体のコンポーネントとして使用できます。次の例では、配列を含む構造体を使用して、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); 
...

関連項目

4.8.2 PL/SQLレコード

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

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

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

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言語の共用体をホスト構造体として使用することも、ホスト構造体として使用される構造体に共用体をネストすることもできません。

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

標識変数を使用する必要があっても、ホスト変数がホスト構造体に含まれている場合は、ホスト構造体内のホスト変数ごとに標識変数が含まれるように、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を追加して、標識変数とインジケータ構造体の名前にしています。ただし、標識変数の名前は任意です。異なる規則を使用しても、規則をまったく使用しなくてもかまいません。

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

この項のデモ・プログラムは、明示カーソルを使用し、データをホスト構造体に格納する問合せを示しています。このプログラムは、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);
} 

4.9 ポインタ変数

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

4.9.1 ポインタ変数の宣言

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

int   *int_ptr; 
char  *char_ptr;

4.9.2 ポインタ変数の参照

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. */ 
... 

4.9.3 構造体ポインタ

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

  • 構造体を宣言します。

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

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

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

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

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

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

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

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

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

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

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

NLS_LANGUAGE

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

NLS_TERRITORY

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

NLS_DATE_FORMAT

日付書式

NLS_DATE_LANGUAGE

日および月の名前に使用する言語

NLS_NUMERIC_CHARACTERS

10進数文字およびグループ・セパレータ

NLS_CURRENCY

各国通貨記号

NLS_ISO_CURRENCY

ISO通貨記号

NLS_SORT

ソート基準

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

  • サーバー・メッセージの言語

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

  • ソート基準

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

  • 日付書式

  • 小数点文字

  • グループ・セパレータ

  • 各国通貨記号

  • ISO通貨記号

パラメータ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関数に渡すこともできます。

4.11 NCHAR変数

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

4.11.1 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;

4.11.2 環境変数NLS_NCHAR

Pro*C/C++では、NLS_LOCAL=NOの場合に、データベース・サポートとともに各国語文字セットがサポートされます。NLS_LOCAL=NOで、新規の環境変数NLS_NCHARが有効な各国語文字セットに設定されていれば、データベース・サーバーでNCHARがサポートされます。

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

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

4.11.3 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 } ) ]

4.11.4 埋込みSQL内の文字列

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

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

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

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

4.11.5 文字列の制限事項

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

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

4.11.6 標識変数

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

4.12 ブール・データの処理

ブール・データ型のサポートにより、アプリケーションは次のことができます。

  • BOOLEAN列のブール型、整数型および文字型データをバインドします。

  • BOOLEAN列データをブール型、整数型および文字データ型変数にフェッチします。

  • BOOLEAN列に関するメタデータをフェッチします。

BOOLEAN型の列からデータをフェッチすると、データが'boolean'型の変数でフェッチされる場合にtrueまたはfalseが返されます。出力変数の型がINTEGERの場合、1または0の整数値が返されます。列値がNULLの場合、宣言された変数は変更されません。