第3章 アプリケーションの作成
3.1 SQL 埋込み C プログラムの作成方法
3.1.3 ホスト変数および標識変数の指定方法
-
メッセージの長さがメッセージ変数の長さ(n)を超える場合、メッセージの先頭からn文字分設定されます。カーソル宣言の指定位置
カーソル宣言は、Cプログラムソース上のどの位置にも記述できます。ただし、宣言したカーソル名を参照するカーソル系の SQL文より、ソースファイル上で先行して記述します。なお、カーソル名は、Cプログラムソース上で一意にすることが必要 です。
埋込み例外宣言の指定位置
埋込み例外宣言は、Cプログラムの関数内であればどの位置にも記述できます。埋込み例外宣言の意味と有効範囲に ついては、“3.1.4 SQL文の処理結果の確認”で説明します。
実行文の指定位置
データ操作文やトランザクション制御文などの実行文は、C言語の実行文が記述可能な位置ならどの位置にも記述でき ます。
INCLUDE文の指定位置
アプリケーション中にINCLUDE文を指定することができます。インクルードファイルには、SQL文およびC言語の言語テ キストを記述できます。インクルードファイルに、ホスト変数および状態変数の宣言を格納しておくことにより、複数のアプ リケーションで共通に使用する変数をまとめて宣言することができます。
表宣言
表宣言は、スキーマ名の修飾をしない表名を定義する宣言文です。表宣言で定義した表名を、それ以降のSQL文で記 述する場合、スキーマ名を省略することができます。INCLUDE文と表宣言の例を以下に示します。
[インクルードファイル“HOSTVAR”]
char SQLSTATE[6];
long STOCK;
[SQL埋込みCプログラム]
EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL INCLUDE HOSTVAR;
EXEC SQL END DECLARE SECTION;
main(){
EXEC SQL DECLARE 在庫表 TABLE ON SCH1;
EXEC SQL SELECT 在庫数量 INTO :STOCK FROM 在庫表 WHERE 製品番号 = 240;
↑ スキーマ名修飾省略 printf("%d¥n",STOCK);
}
ホスト変数および標識変数をSQL文中に指定する場合には、変数の前にコロン“:”を付けて指定します。以下にその指 定例を示します(ゴシック部がホスト変数または標識変数です)。ただし、SQL文以外の、C言語のステートメント中では、一般の C言語の変数と同じで、コロン“:”は付けません。
標識変数には、SQL文の処理結果が以下のように格納されます。
・
取り出すデータがNULL値の場合、標識変数には、-1が格納されます。・
取り出すデータのデータ型が文字列または各国語文字列で、かつNULL値ではなく、取り出すデータの長さが相手 指定の文字列または各国語文字列の長さよりも長い場合は、取り出すデータの有効な長さが標識変数に格納され ます。・
取り出すデータの有効な長さが32,000バイトを超える場合は、標識変数に0または32,000が格納されます。・
上記以外の場合は、標識変数に0が格納されます。なお、標識変数を指定していない場合、取り出すデータがNULL値になると、SQL文の処理はエラーになります。
例1
ホスト変数の指定例
STOCKおよびHOUSEをホスト変数、QFLAGをSTOCKの標識変数、そして、WFLAGをHOUSEの標識変数として指 定します。SQL文中にホスト変数および標識変数を指定する場合は、コロン“:”を付けます。
EXEC SQL SELECT 在庫数量,倉庫番号 INTO :STOCK INDICATOR :QFLAG, :HOUSE INDICATOR :WFLAG FROM 在庫表 WHERE 製品番号 = 110;
例2
SQL文以外のC言語のステートメント上のホスト変数の指定例
STOCKをホスト変数、QFLAGをSTOCKの標識変数として使用しています。C言語のステートメントでは、これらの変 数にコロン“:”は付けません。
EXEC SQL FETCH CU1 INTO :STOCK INDICATOR :QFLAG;
if( QFLAG == -1) goto p_null ; if( STOCK == 0) goto p_loop ;
ホスト変数を使用する場合の注意事項
文字列型または各国語文字列型の場合、NULL文字(¥0)はデータ受渡しの対象にはなりません。そのため、アプリケー ションで文字列の終わりを認識するような処理を行う場合、NULL文字を設定しなければなりません。以下に例を示しま す。
SQLSTATE[5]='¥0';
printf( "SQLSTATE:%s¥n" , SQLSTATE );
ホスト変数へ入出力するデータの文字コード系の考慮
ホスト変数へ入出力するデータの文字コード系がSymfoware/RDBの文字コード系と異なる場合は、そのホスト変数に格 納するデータの文字コード系を、クライアント用の動作環境ファイルまたは環境変数に設定します。
以下に、ホスト変数へ入出力するデータの文字コード系がSymfoware/RDBの文字コード系と異なる場合の例、および、
ホスト変数へ入出力するデータの文字コード系とSymfoware/RDBの文字コード系が同じ場合の例を示します。
例1
ホスト変数へ入出力するデータの文字コードとSymfoware/RDBの文字コード系が異なる場合
以下の例では、Symfoware/RDBの文字コード系がシフトJISコード、また、SELECT文(1)でホスト変数に格納された データの文字コード系がUNICODEであるとします。そして、このデータを格納するデータベースの文字コード系は UNICODEであるとします。
この場合、クライアント用の動作環境ファイルまたは環境変数には、ホスト変数に格納されているデータがUNICODE であることを示すパラメタを設定します。設定するパラメタについての詳細は、“6.4.3 クライアント用の動作環境ファイ ルの作成”を参照してください。
こうすることによって、サーバでのコード変換の必要がなくなります。
EXEC SQL BEGIN DECLARE SECTION;
char SQLSTATE[6];
char SQLMSG[256];
:
char CHARACTER SET NCHAR H1[10];
EXEC SQL END DECLARE SECTION;
:
memset(H1,'¥0',sizeof(H1));
EXEC SQL SELECT COL1 INTO :H1 FROM S1.T0 WHERE COL0=3; …… (1) EXEC SQL INSERT INTO S1.T1 VALUES(3,:H1); …… (2)
(1) データベースよりUNICODEなどのSymfoware/RDBの文字コード系と異なるコードのデータが取得できます。
(2) 上記のSELECT文で取得したデータのコードのまま、INSERT文が実行できます。このように、アプリケーションに
おいて、Symfoware/RDBの文字コード系と異なるコード系のデータが操作可能です。
例2
ホスト変数へ入出力するデータの文字コードがSymfoware/RDBの文字コード系と同じ場合
以下の例では、Symfoware/RDBの文字コード系がシフトJISコードであるとします。この場合、ホスト変数に入出力す るデータの文字コード系はシフトJISコードになります。
EXEC SQL BEGIN DECLARE SECTION;
char SQLSTATE[6];
char SQLMSG[256];
:
char CHARACTER SET NCHAR H1[10];
EXEC SQL END DECLARE SECTION;
:
memset(H1,'¥0',sizeof(H1));
memcpy(H1,"日本語",6); …… (1) EXEC SQL INSERT INTO S1.T1 VALUES(:H1); …… (2) (1) Symfoware/RDBの文字コード系の“日本語”がホスト変数H1に格納されます。
(2) Symfoware/RDBの文字コード系の“日本語”でINSERT文を実行します。このように、Symfoware/RDBの文字コー
ド系を使用してデータ操作を行う場合に適しています。
マルチスレッド環境でのホスト変数の宣言
マルチスレッド環境で実行するアプリケーションでは、ホスト変数にはauto変数を使用することを推奨します。extern変数および
static変数などを使用した場合は、スレッド間でホスト変数が共有されるため、複数のスレッドから同時にデータベースを
アクセスすると、参照および更新が正しくできない場合があります。extern変数およびstatic変数などを使用する場合は、
セマフォを利用するなどして、並列に動作するスレッド間の排他制御を考慮したアプリケーションを作成してください。
参照
セマフォの詳細については、OSのシステム関数について説明されているマニュアルを参照してください。
long long型および、8バイトで実装されるlong型のホスト変数の利用について
long型は、コンパイラにより、4バイトになる場合と8バイトになる場合があります。8バイトで実装されるlong型および、long long型のホスト変数を利用した場合、ホスト変数には最大20桁のデータを代入 できます。
一方、データベースで扱えるデータの最大桁数は18桁です。
このため、19桁以上の値を代入したホスト変数をSQL文中の検索条件などで利用した場合、データベースアクセス時に エラーとなります。検索条件などに19桁以上の値を指定することで、データベースアクセス時のエラーが発生することを 防ぎたい場合は、アプリケーション中で事前にホスト変数の値が18桁以下であるかをチェックしてください。
条件値以下のすべての値を取り出すための条件値が18桁を超えている場合に、アプリケーションにて条件値を18桁の 最大数に変更するプログラム例を以下に示します。
例
下記の表にアクセスし、列VALUE1の値が検索条件の値以下の行の列CODE1をすべて取り出す例を示します。
スキーマ:SCH1 表:TBL1
列:CODE1:SMALLINT UNIQUE NOT NULL VALUE1:DECIMAL(18,0)
18桁以下の場合に、真を返却するマクロ(sample1.h)
#define CheckGetPrecision18(data) ((long long)(data) <= 999999999999999999LL ) 検索条件の組立て(C言語)
short gyoumu1() { long long condition;
short code[65536];
int count;
condition = 123456789012345678LL; /*実際は、画面入力などを元にデータを組み立てます。*/
count = dba_KINGAKU_SETTEI( code , condition );
return 0;
}
データベースアクセスアプリケーション(SQL埋込みCプログラム)
#include "sample1.h"
short dba_KINGAKU_SETTEI( short *para1 , long long para2 ) { EXEC SQL BEGIN DECLARE SECTION;
char SQLSTATE[6];
char SQLMSG[256];
short code1;
long long condition;
EXEC SQL END DECLARE SECTION;
int count;
EXEC SQL WHENEVER SQLERROR GOTO :ERROR;
EXEC SQL WHENEVER NOT FOUND GOTO :NOTFOUND;
condition = para2;
/* データベースの対応カラムの精度と比較 */
if ( !CheckGetPrecision18( condition ) ) {
condition = 999999999999999999LL; /* 条件値を18桁の最大値に変更 */
}
/* カーソル宣言 */
EXEC SQL DECLARE CUR1 CURSOR FOR SELECT CODE1 FROM SCH1.TBL1 WHERE VALUE1 <= :condition;
EXEC SQL OPEN CUR1;
for ( count = 0 ;; count++ ) {
EXEC SQL FETCH CUR1 INTO :code1;
para1[count] = code1;
} NOTFOUND:
EXEC SQL CLOSE CUR1;
return(count);
ERROR:
EXEC SQL CLOSE CUR1;
return(-1);
}