この章では、Pro*C/C++プログラムの作成に必要な基本的な情報について説明します。この章の項目は、次のとおりです。
この章には、学習用の完全なデモンストレーション・プログラムもいくつか記載されています。これらのプログラムには、この章で説明する技法の使用例が示されています。これらはdemo
ディレクトリにあり、オンラインで使用できるため、コンパイル、実行および必要に応じた変更もできます。
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バイト以下)。 |
ROWID |
バイナリ値。 |
DATE |
固定長の日付+時刻値(7バイト)。 |
RAW |
可変長バイナリ・データ(2000バイト以下)。 |
LONG RAW |
可変長バイナリ・データ(2**31-1バイト以下)。 |
CHAR |
固定長文字列(2000バイト以下)。 |
NCHAR |
固定長シングルバイト文字列または各国語キャラクタ文字列(2000バイト以下)。 |
BFILE |
外部ファイル・バイナリ・データ(4GB以下)。 |
BLOB |
バイナリ・データ(4GB以下)。 |
CLOB |
文字データ(4GB以下)。 |
NCLOB |
各国語キャラクタ・セット・データ(4GB以下)。 |
これらの内部データ型は、C言語のデータ型とは大きく異なる場合があります。たとえば、C言語にはOracleのNUMBERデータ型と同等のデータ型はありません。ただし、NUMBERは、floatやdoubleなどのC言語のデータ型との間で変換できますが、ある程度の制限があります。たとえば、OracleのNUMBERデータ型は小数点以下最大38桁の精度で指定できますが、現行のC言語の実装ではdoubleをそこまでの精度で表せるデータ型はありません。
OracleのNUMBERデータ型は値を正確に(精度の制限内で)表しますが、浮動小数点形式では10.0などの値を正確に表すことができません。
構造化されていないデータ(テキスト、グラフィック・イメージ、ビデオ・クリップまたはサウンド波形)を格納するには、LOBデータ型を使用します。BFILEデータは、データベース外部のオペレーティング・システム・ファイルに格納されます。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値の最大長は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値の最大精度は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データ型を使用して、小数部のない数を格納します。整数は符号付きの2バイトまたは4バイトの2進数です。ワード内のバイトの順序付けはシステムによって異なります。入力ホスト変数と出力ホスト変数に長さを指定する必要があります。出力時には、列値が実数であれば、小数部が切り捨てられます。
FLOATデータ型を使用して、小数部を持つ数、あるいはINTEGERデータ型の容量を超える数を格納します。数は、使用しているコンピュータの浮動小数点形式を使用して表示されます。通常、記憶域には4バイトまたは8バイトを必要とします。入力ホスト変数と出力ホスト変数に長さを指定する必要があります。
Oracleでは、数の内部形式が10進数であるため、ほとんどの浮動小数点処理よりも高い精度で数を表現できます。したがって、FLOAT変数へのフェッチを行うと、精度が低下する可能性があります。
STRINGデータ型は、VARCHAR2データ型に似ていますが、STRING値は常にヌル文字で終了するという違いがあります。Oracleでは、CHAR_MAP=STRINGオプションを使用してプリコンパイルすると、char[n]またはcharとして宣言しているすべてのホスト変数に、STRINGデータ型が割り当てられます。
VARNUMデータ型はNUMBERデータ型に似ていますが、VARNUM変数の1バイト目にその表現の長さが格納されるという違いがあります。
入力時には、ホスト変数の1バイト目を値の長さに設定する必要があります。出力時には、ホスト変数には長さに続いてOracleで内部表現された数が設定されています。この数が最大になっても支障がないように、ホスト変数の長さは22バイト必要です。列値をVARNUMホスト変数にSELECTした後で、1バイト目をチェックして値の長さを取得できます。
通常、このデータ型はほとんど使用されません。
LONGデータ型を使用して、固定長文字列を格納します。
LONGデータ型はVARCHAR2データ型に似ていますが、LONG値の最大長は2147483647バイト、つまり2GBであるという違いがあります。
VARCHARデータ型を使用して、可変長文字列を格納します。VARCHAR変数では、2バイト長のフィールドの後に65533バイト以下の文字列フィールドが続きます。ただし、VARCHAR配列要素では、文字列フィールドの最大長は65530バイトです。VARCHAR変数の長さを指定するときには、長さフィールド用の2バイトが含まれているか確認してください。これより長い文字列には、LONG VARCHARデータ型を使用してください。明示的にNULLが選択された場合、ホスト変数の値は予測不能です。標識変数の値がNULLかどうかをチェックする必要があります。
Oracle8より前のリリースでは、ROWIDデータ型は各表の行の物理アドレスを16進数として格納するために使用されていました。ROWIDには行の物理アドレスが含まれており、これにより一度のブロック・アクセスで行を効率的に取得できました。
Oracle8からは、論理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を文字ホスト変数にFETCHし、ホスト変数をUPDATE文またはDELETE文のWHERE句のROWID疑似列と比較します。これにより、カーソルによりフェッチされた最終行を識別できます。
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値の最大長は65535バイトです。
RAWデータはCHARACTERデータに似ていますが、OracleではRAWデータは意味がないものと解釈され、システム間でRAWデータを転送するときにはキャラクタ・セットは変換されないという違いがあります。
VARRAWデータ型を使用して、可変長のバイナリ・データまたはバイト文字列を格納します。VARRAWデータ型はRAWデータ型に似ていますが、VARRAW変数は2バイトの長さフィールドの後に長さ65533バイト以下のデータ・フィールドが付いているという違いがあります。これより長い文字列には、LONG VARRAWデータ型を使用してください。
VARRAW変数の長さを指定するときは、長さフィールド用の2バイトが含まれているかを確認してください。変数の最初の2バイトは、整数として解釈できる必要があります。
VARRAW変数の長さを取得するには、長さフィールドを参照してください。
LONG RAWデータ型を使用して、バイナリ・データまたはバイト文字列を格納します。LONG RAW値の最大長は2147483647バイト、つまり2GBです。
LONG RAWデータはLONGデータに似ていますが、OracleではLONG RAWデータは意味がないものと解釈され、システム間でLONG RAWデータを転送するときにはキャラクタ・セットは変換されないという違いがあります。
UNSIGNEDデータ型を使用して、符号なし整数を格納します。符号なし整数は、2バイトまたは4バイトの2進数です。ワード内のバイトの順序付けはシステムによって異なります。入力ホスト変数と出力ホスト変数に長さを指定する必要があります。出力時には、列値が浮動小数点数であれば、小数部が切り捨てられます。
LONG VARCHARデータ型を使用して、可変長文字列を格納します。LONG VARCHAR変数では、4バイトの長さフィールドの後に文字列フィールドが続きます。文字列フィールドの最大長は2147483643(2**31 - 5)バイトです。VAR文またはTYPE文に使用するLONG VARCHARの長さを指定する場合は、4バイトの長さフィールドを含めないでください。
LONG VARRAWデータ型を使用して、可変長のバイナリ・データまたはバイト文字列を格納します。LONG VARRAW変数では、4バイトの長さフィールドの後にデータ・フィールドが続きます。データ・フィールドの最大長は2147483643バイトです。VAR文またはTYPE文に使用するLONG VARRAWの長さを指定する場合は、4バイトの長さフィールドを含めないでください。
CHARデータ型を使用して、固定長文字列を格納します。CHAR値の最大長は65535バイトです。
DBMS=V7またはV8の場合、デフォルトでは、OracleはPro*C/C++プログラム内のすべての文字ホスト変数にCHARZデータ型を割り当てます。CHARZデータ型は、ヌル文字で終了する固定長文字列を示します。CHARZ値の最大長は65534バイトです。
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
はDATE
に基づいていますが、時刻部分が含まれていません。(したがって、タイムゾーンもありません。)ANSI
DATE
は、DATE
データ型に関するANSI
仕様に準拠しています。DATE
またはタイムスタンプ・データ型にANSI
DATE
を割り当てると、OracleのDATE
とタイムスタンプの時刻部分が0に設定されます。DATE
またはタイムスタンプをANSI
DATE
に割り当てると、時刻部分は無視されます。
ANSI
DATE
ではなく、日付と時刻の両方を含むTIMESTAMP
データ型を使用することをお薦めします。
TIMESTAMP
データ型は、DATE
データ型が拡張されたものです。DATE
データ型の年、月、日に加えて時、分および秒の値が格納されます。タイムゾーンはありません。TIMESTAMP
データ型の書式は、次のとおりです。
TIMESTAMP(fractional_seconds_precision)
fractional_seconds_precision
(オプション)では、SECOND
日時フィールドの小数部の桁数を指定します。桁数の範囲は0〜9で、デフォルトは6です。
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
オフセットに関係なく同一とみなされます。
TIMESTAMP
WITH
LOCAL
TIME
ZONE
(TSLTZ
)は、値にタイムゾーンによる時差を含む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
には、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 (day_precision) TO SECOND(fractional_seconds_precision)
パラメータは、次のとおりです。
day_precision
は、DAY
日時フィールドの桁数です。これはオプションです。有効な値は0〜9で、デフォルトは2です。
fractional_seconds_precision
は、SECOND
日時フィールドの小数部の桁数です。これはオプションです。有効な値は0〜9で、デフォルトは6です。
ホスト変数は、ホスト・プログラムと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 |
大きい整数 |
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 float double |
nバイトの文字配列 nバイトの可変長文字配列 整数 小さい整数 大きい整数 浮動小数点数 倍精度浮動小数点数 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++では、ホスト変数の宣言時にauto、externおよび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する場合は、最大長を指定する必要があります。
ホスト変数は、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を挿入することで読みやすくできます。その場合も、標識変数の前にはコロンを付ける必要があります。正しい構文は、次のとおりです。
: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の予約語にしないでください。
VARCHAR疑似型を使用すると、可変長文字列を宣言できます。プログラムで扱う文字列がVARCHAR2列またはLONG列からの出力、あるいはその列への入力である場合、標準のC言語文字列のかわりにVARCHARホスト変数を使用する方が便利なこともあります。データ型名VARCHARは、すべて大文字でも、すべて小文字でもかまいませんが、大文字と小文字を混在させることはできません。このマニュアルでは、VARCHARがC言語固有のデータ型とは異なることを強調するために、大文字を使用しています。
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コンパイル・エラーが発生します。 |
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);
Oracleでは、VARCHAR出力ホスト変数の長さコンポーネントが自動的に設定されます。SELECTまたはFETCHでVARCHAR変数にNULLを入れた場合、サーバーでは長さメンバーも配列メンバーも変更されません。
注意: NULLをVARCHARホスト変数に選択した場合に、対応する標識変数がないと、実行時にORA-01405エラーが発生します。これを回避するには、すべてのホスト変数に対応して標識変数を記述します。(一時修正としては、UNSAFE_NULL=YESプリコンパイラ・オプションを使用します。「DBMS」も参照してください。) |
VARCHAR変数の長さを0に設定してからUPDATE文またはINSERT文を実行すると、列値はNULLに設定されます。列にNOT NULL制約がある場合は、エラーが戻されます。
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宣言が処理されると、生成される構造体内の配列要素の実際の長さが、宣言された長さよりも長くなることがあります。たとえば、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整数へのポインタであるため、参照で渡す必要があります。
次のサンプル・プログラムは、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サーバー(リリース7.2以上)でPL/SQLを使用して定義し、オープンする必要のあるカーソルのハンドルです。カーソル変数の詳細は、『Oracle Database PL/SQL言語リファレンス』を参照してください。
カーソル変数の利点は、次のとおりです。
メンテナンスのしやすさ
問合せは、カーソル変数をオープンするストアド・プロシージャに集中されます。カーソルを変更する必要がある場合は、ストアド・プロシージャの変更のみで済みます。各アプリケーションを変更する必要はありません。
便利なセキュリティ機能
アプリケーションのユーザーは、Pro*C/C++アプリケーションからサーバーへの接続時に使用されるユーザー名です。ユーザーには、カーソルをオープンするストアド・プロシージャに対する実行権限が必要ですが、問合せに使用する表に対する読込み権限は不要です。このセキュリティ機能を使用して、表内の列や、他のストアド・プロシージャへのアクセスを制限できます。
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言語のスコープ規則に従っています。カーソル変数は、他の関数にパラメータとして渡すことができ、カーソル変数を宣言しているソース・ファイルの外部にある関数にも渡すことができます。また、カーソル変数を戻す関数のみでなく、カーソル変数へのポインタを戻す関数も定義できます。
カーソル変数をオープンするか、カーソル変数を使用して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;
カーソル変数をクローズするには、CLOSEコマンドを使用します。たとえば、前述の例でOPENしたemp_cursorカーソル変数をクローズするには、埋込みSQL文を使用します。
EXEC SQL CLOSE :emp_cursor;
カーソル変数はホスト変数であるため、前にコロンを付ける必要があります。
ALLOCATEで割り当てたカーソル変数を再利用できます。アプリケーションで必要な回数だけオープン、FETCHおよびCLOSEできます。ただし、サーバーから切断してから再接続する場合は、カーソル変数をALLOCATEで再度割り当てる必要があります。
カーソルは、FREE埋込みSQL文で割当て解除されます。次に例を示します。
EXEC SQL FREE :emp_cursor;
オープンしているカーソルはクローズされ、割り当てられたメモリーは解放されます。
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のメモリーを割り当てる必要があります。
カーソル変数の使用には、次の制限が適用されます。
Pro*C/C++とOCI V7で同じカーソル変数を使用する場合は、接続直後にSQLLDAGetCurrent()またはSQLLDAGetName()を使用する必要があります。
カーソル変数をOCIリリース8で対応するものには変換できません。
カーソル変数を使用できるコマンドは、ALLOCATE、FETCH、FREEおよびCLOSEのみです。
DECLARE CURSORコマンドは、カーソル変数には適用されません。
CLOSEでクローズしたカーソル変数からのFETCHはできません。
ALLOCATEで割り当てられていないカーソル変数からのFETCHはできません。
MODE=ANSIを指定してプリコンパイルする場合、すでにクローズ済のカーソル変数をクローズするとエラーになります。
AT句は、ALLOCATEコマンド、カーソル変数を参照するFETCHコマンドおよびCLOSEコマンドには使用できません。
カーソル変数はデータベースの列に格納できません。
カーソル変数自体は、パッケージ指定内で宣言できません。パッケージ指定内で宣言できるのは、カーソル変数の型のみです。
カーソル変数は、PL/SQLレコードのコンポーネントにはできません。
次のサンプル・プログラム(PL/SQLスクリプトとPro*C/C++プログラム)は、カーソル変数の使用方法を示しています。これらのソースはdemo
ディレクトリにあり、オンラインで使用できます。demoディレクトリにある同じアプリケーションの別バージョンcv_demo.pc
も参照してください。
-- 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;
/* * 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'); ... }
データベース・サーバーでは、ヒープ表および索引構成表という2種類の表編成が使用されています。
デフォルトでは、ヒープ表が使用されます。これは、Oracle8以前のすべての表で使用されていた表編成です。物理行アドレス(ROWID)は、ヒープ表の行の識別に使用される永続的なプロパティです。物理ROWIDの外部文字書式は、64をベースとする18バイト文字列です。
索引構成表には、永続識別子としての物理行アドレスはありません。これらの表には、論理ROWIDが定義されています。索引構成表からSELECT ROWID ...文を使用すると、ROWIDは表の主キー、制御情報およびオプションの物理的な不確定要素を含む不透明な構造になります。このROWIDをWHERE ROWID = ...などの句を含むSQL文で使用して、表から値を取得できます。
Oracle 8.1以降のリリースでは、ユニバーサルROWIDが導入されています。ユニバーサルROWIDは、物理ROWIDと論理ROWIDの両方で使用できます。表編成の変更はアプリケーションに影響しないため、ユニバーサルROWIDを使用すると、ヒープ表または索引構成表のデータにアクセスできます。ROWIDに使用される列データ型はUROWID(length)で、length
はオプションです。
すべての新規アプリケーションで、ユニバーサルROWIDを使用します。
ユニバーサルROWIDの詳細は、『Oracle Database概要』を参照してください。
ユニバーサル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 ; ...
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); ...
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ステータスはホスト・インジケータ構造体で使用可能になります。
この項のデモ・プログラムは、明示カーソルを使用し、データをホスト構造体に格納する問合せを示しています。このプログラムは、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言語では、他の変数を指すポインタがサポートされています。ポインタには、変数の値ではなくアドレス(格納場所)が保持されます。
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は、それぞれのグローバリゼーション・サポート・パラメータの指定内容を示しています。
グローバリゼーション・サポート・パラメータ | 指定 |
---|---|
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では、地域によって異なる次の機能のデフォルト値を指定します。
日付書式
小数点文字
グループ・セパレータ
各国通貨記号
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関数に渡すこともできます。グローバリゼーション・サポートの詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。
3つの内部データベース・データ型に、各国語キャラクタ・セット・データを格納できます。この種のデータ型は、NCHAR、NCLOBおよびNVARCHAR2です(NCHAR VARYINGとも呼ばれます)。これらのデータ型を使用できるのは、リレーショナル列のみです。旧リリースのPro*C/C++でもマルチバイトのNCHARホスト変数がサポートされていましたが、意味が多少違います。
NLS_LOCALコマンドライン・オプションをYESに設定すると、Oracle7におけるような、以前の意味でのマルチバイト・サポートがSQLLIBにより提供されます(引用符で囲まれた文字列から文字Nが削除されます)。SQLLIBは、空白埋めと削除、標識変数の設定などを行います。
NLS_LOCALをNO(デフォルト)に設定すると、Oracle7より後のリリースでは、新しい方法でマルチバイト文字列がサポートされます(引用符で囲まれた文字列の前に文字Nが付きます)。空白埋めと削除および標識変数の設定は、SQLLIBではなくデータベースで行われます。
すべての新規アプリケーションには、NLS_LOCAL=NOを使用してください。
各国語キャラクタ・セット・データを保持するホスト変数を指定するには、文字変数宣言に句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;
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からエラー・コードが戻されます。
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 } ) ]
埋込みSQL文中のマルチバイト文字列は、その文字列をマルチバイトとして識別する文字リテラルと、後続の文字列で構成されます。文字列は、通常の一重引用符(')で囲みます。
たとえば、次のような埋込みSQL文があるとします。
EXEC SQL SELECT empno INTO :emp_num FROM emp WHERE ename = N'<Japanese_string>';
このSQL文には、マルチバイト文字列が含まれています(<Japanese_string>は、実際には漢字の可能性があります)。つまり、文字列の直前に文字リテラルNが付いているため、これはマルチバイト文字列として識別されます。Oracleでは大/小文字が区別されないため、この例ではnとNのどちらを使用してもかまいません。