30.6. ホスト変数の使用

項30.4では、埋め込みSQLプログラムでどのようにSQL文を実行するのかについて説明しました。 この文の中には固定値しか使用しないものや、ユーザが指定する値を文の中に挿入する手段を提供しないもの、問い合わせが返す値をプログラムで処理する手段を提供しないものがありました。 この種の文は実際のアプリケーションでは役に立ちません。 本節では、ホスト変数という単純な機構を使用した、Cプログラムと埋め込みSQL文との間でデータをやりとりする方法を詳細に説明します。

30.6.1. 概要

埋め込みSQLにおけるCプログラムとSQL文との間でのデータのやりとりは特に単純です。 値に適切な引用符を付与するといった、様々な複雑な処理を伴う、プログラムにデータを文中に張り付けさせるという方法はなく、単にSQL文の中に、先頭にコロンを付けたC変数名を書くだけです。 以下に例を示します。

EXEC SQL INSERT INTO sometable VALUES (:v1, 'foo', :v2);

この文は、v1v2という2つのC変数を参照し、また、通常のSQL文字列リテラルも使用しています。 これは、使用できるデータの種類は1つだけという制限がないことを表しています。

SQL文内にCの変数を挿入するこの様式は、SQL文で値式が想定されている所であればどこでも動作します。 SQL環境では、このC変数への参照をホスト変数と呼びます。

30.6.2. 宣言セクション

例えば問い合わせ内のパラメータとして、プログラムからデータベースへデータを渡す、もしくは、データベースからプログラムへデータを渡すためには、このようなデータを格納させる予定のC変数を、埋め込みSQLプリプロセッサが管理できるように、特殊な印のついたセクションで宣言する必要があります。

このセクションは以下で始まります。

EXEC SQL BEGIN DECLARE SECTION;

そして、以下で終ります。

EXEC SQL END DECLARE SECTION;

この行の間は、以下のような通常のC変数宣言でなければなりません。

int   x;
char  foo[16], bar[16];

プログラム内に複数の宣言セクションを持たせることができます。

また、宣言は普通のC変数としてそのまま出力ファイルに出力されます。 ですので、これらを再度宣言する必要はありません。 通常、SQLコマンドで使用する予定がない変数はこの特別なセクションの外側で宣言されます。

構造体やunionの定義もまた、DECLAREセクションの内側で表す必要があります。 さもないと、プリプロセッサはその定義が不明であるために、これらの型を扱うことができません。

VARCHAR という特別な型は、各変数ごとに名前が付けられたstructに変換されます。

VARCHAR var[180];

という宣言は、以下のように変換されます。

struct varchar_var { int len; char arr[180]; } var;

この構造体は、varchar型のSQLデータとのインタフェースに適しています。

30.6.3. SELECT INTOFETCH INTO

ここまでで、プログラムで生成したデータをSQLコマンドに渡すことができるようになりました。 しかし、どのように問い合わせの結果を取り出すのでしょうか? この目的のために、埋め込みSQLでは、通常のSELECTFETCHを派生した、特殊なコマンドを提供しています。 これらのコマンドは特別なINTO句を持ち、ここで返された値をどのホスト変数に格納すればいいかを指定します。

以下にサンプルを示します。

/*
 * 以下のテーブルを前提としています。
 * CREATE TABLE test1 (a int, b varchar(50));
 */

EXEC SQL BEGIN DECLARE SECTION;
int v1;
VARCHAR v2;
EXEC SQL END DECLARE SECTION;

 ...

EXEC SQL SELECT a, b INTO :v1, :v2 FROM test;

INTO句がSELECTリストとFROM句の間に現れます。 SELECTリスト内の要素数とINTO直後のリスト(目的リストとも呼ばれます)の要素数は等しくなければなりません。

以下にFETCHコマンドの使用例を示します。

EXEC SQL BEGIN DECLARE SECTION;
int v1;
VARCHAR v2;
EXEC SQL END DECLARE SECTION;

 ...

EXEC SQL DECLARE foo CURSOR FOR SELECT a, b FROM test;

 ...

do {
    ...
    EXEC SQL FETCH NEXT FROM foo INTO :v1, :v2;
    ...
} while (...);

ここでは、INTO句が通常のすべての句の後ろに現れています。

これらの手法は両方とも、一度に1行のみを取り出すことができます。 複数の行を含む可能性がある結果集合を処理する必要がある場合は、2番目の例で示したようにカーソルを使用する必要があります。

30.6.4. 指示子

上の例ではNULL値を扱っていません。 実際は、データベースからNULL値を取り出した場合、データ取得のサンプルはエラーになります。 NULL値をデータベースに渡す、あるいは、データベースからNULL値を取り出すためには、データを持つホスト変数毎に二次的ホスト変数指定をつけなければなりません。 この二次的ホスト変数は指示子と呼ばれ、データがNULLかどうかを通知するフラグを持ちます。 この場合、実際のホスト変数の値は無視されます。 以下に、NULL値の取り出しを正しく扱う例を示します。

EXEC SQL BEGIN DECLARE SECTION;
VARCHAR val;
int val_ind;
EXEC SQL END DECLARE SECTION:

 ...

EXEC SQL SELECT b INTO :val :val_ind FROM test1;

val_ind指示子変数は、値がNULLでなければ0になります。 値がNULLならば、負の値になります。

指示子は他にも機能があります。 指示子の値が正ならば、その値は非NULLですが、ホスト変数に格納する時に切り詰められたことを示します。