Symfoware Server SQLビギナーズガイド - FUJITSU - |
目次 索引 |
第7章 アプリケーションの実行時に動的SQL文を実行する方法 | > 7.3 SQL文の条件を動的に変更して実行する | > 7.3.2 SQL記述子域の操作方法 |
データの取り出しを連続的に行う場合には、動的SELECT文を準備して実行します。
SQL記述子域を使用して、動的パラメタ指定のある動的SELECT文を実行するアプリケーションの例を以下に示します。
例
端末から入力した動的SELECT文の例です。端末から入力した動的パラメタ指定の値を探索条件としてデータを検索し、その値を表示します。
#include <stdio.h> #include <string.h> EXEC SQL BEGIN DECLARE SECTION; EXEC SQL INCLUDE varfile.h; …(1) EXEC SQL END DECLARE SECTION; void main() { memset(SQLSTATE, 0x00, 6); …(2) memset(SQLMSG, 0x00, 256); …(2) memset(&str, 0x00, sizeof(str)); …(2) memset(varname, 0x00, 39); …(2) memset(varchar, 0x00, 39); …(2) memset(&icdata, 0x00, sizeof(icdata)); …(2) memset(&incdata, 0x00, sizeof(incdata)); …(2) memset(&iddata, 0x00, sizeof(iddata)); …(2) memset(ocdata, 0x00, 15); …(2) memset(oncdata, 0x00, sizeof(oncdata)); …(2) memset(&oddata, 0x00, sizeof(oddata)); …(2) EXEC SQL CONNECT TO DEFAULT; …(3) EXEC SQL WHENEVER SQLERROR GOTO :ERR; …(4) printf( "実行する動的SELECT文を指定してください \n" ); gets( str.sqlvar ); …(5) str.sqllen = strlen( str.sqlvar ); EXEC SQL DECLARE CUR1 CURSOR FOR STMID; …(6) EXEC SQL PREPARE STMID FROM :str; …(7) EXEC SQL ALLOCATE DESCRIPTOR 'INDESC' WITH MAX 100; …(8) EXEC SQL ALLOCATE DESCRIPTOR 'OUTDESC' WITH MAX 100; …(9) EXEC SQL DESCRIBE INPUT STMID USING SQL DESCRIPTOR 'INDESC'; …(10) EXEC SQL DESCRIBE OUTPUT STMID USING SQL DESCRIPTOR 'OUTDESC'; …(11) /********************/ /* 動的パラメタ指定 */ /********************/ EXEC SQL GET DESCRIPTOR 'INDESC' :varicount = COUNT; …(12) for( i = 1; i <= varicount; i++ ) { EXEC SQL GET DESCRIPTOR 'INDESC' VALUE :i …(13) :vartype = TYPE, …(13) :varleng = LENGTH, …(13) :varolen = OCTET_LENGTH, …(13) :varprec = PRECISION, …(13) :varscal = SCALE, …(13) :varname = NAME, …(13) :varchar = CHARACTER_SET_NAME, …(13) :vardcod = DATETIME_INTERVAL_CODE, …(13) :vardpre = DATETIME_INTERVAL_PRECISION; …(13) /* CHAR型かNCHAR型 */ …(14) if( vartype == 1 || vartype == 12 ) { …(14) /* 文字列型 */ …(14) if( strncmp( varchar, "BASIC", 5 ) == 0 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%s", icdata.sqlvar ); …(14) icdata.sqllen = strlen( icdata.sqlvar ); …(14) EXEC SQL SET DESCRIPTOR 'INDESC' VALUE :i …(14) TYPE = 1, …(14) LENGTH = 14, …(14) OCTET_LENGTH = 14, …(14) CHARACTER_SET_NAME = 'BASIC', …(14) DATA = :icdata; …(14) } …(14) /* 各国語文字列型 */ …(14) else { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%s", incdata.sqlvar ); …(14) incdata.sqllen = strlen( incdata.sqlvar ); …(14) EXEC SQL SET DESCRIPTOR 'INDESC' VALUE :i …(14) TYPE = 1, …(14) LENGTH = 10, …(14) OCTET_LENGTH = 20, …(14) CHARACTER_SET_NAME = 'NCHAR', …(14) DATA = :incdata; …(14) } …(14) } …(14) /* INTEGER型かSMALLINT型 */ …(14) else if( vartype == 4 || vartype == 5 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%ld", &iidata ); …(14) EXEC SQL SET DESCRIPTOR 'INDESC' VALUE :i …(14) TYPE = 4, …(14) PRECISION = 31, …(14) SCALE = 0, …(14) INDICATOR = 0, …(14) DATA = :iidata; …(14) } …(14) /* NUMERIC型かDECIMAL型かREAL型かDOUBLE PRECISION型 */ …(14) else if( vartype == 2 || vartype == 3 || …(14) vartype == 7 || vartype == 8 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%lf", &ifdata ); …(14) EXEC SQL SET DESCRIPTOR 'INDESC' VALUE :i …(14) TYPE = 8, …(14) PRECISION = 52, …(14) SCALE = 0, …(14) DATA = :ifdata; …(14) } …(14) /* 日時型かINTERVAL型 */ …(14) else if( vartype == 9 || vartype == 10 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%s", iddata.sqlvar ); …(14) iddata.sqllen = strlen( iddata.sqlvar ); …(14) EXEC SQL SET DESCRIPTOR 'INDESC' VALUE :i …(14) TYPE = 12, …(14) LENGTH = 19, …(14) OCTET_LENGTH = 19, …(14) CHARACTER_SET_NAME = 'BASIC', …(14) DATA = :iddata; …(14) } …(14) } /**************/ /* 選択リスト */ /**************/ EXEC SQL GET DESCRIPTOR 'OUTDESC' :varocount = COUNT; …(15) for( i = 1; i <= varocount; i++ ) { EXEC SQL GET DESCRIPTOR 'OUTDESC' VALUE :i :vartype = TYPE, …(16) :varleng = LENGTH, …(16) :varolen = OCTET_LENGTH, …(16) :varprec = PRECISION, …(16) :varscal = SCALE, …(16) :varchar = CHARACTER_SET_NAME, …(16) :vardcod = DATETIME_INTERVAL_CODE, …(16) :vardpre = DATETIME_INTERVAL_PRECISION; …(16) /* CHAR型かNCHAR型 */ …(17) if( vartype == 1 || vartype == 12 ) { …(17) /* 文字列型 */ …(17) if( strncmp( varchar, "BASIC", 5 ) == 0 ) { …(17) EXEC SQL SET DESCRIPTOR 'OUTDESC' VALUE :i …(17) TYPE = 1, …(17) LENGTH = 14, …(17) OCTET_LENGTH = 14, …(17) CHARACTER_SET_NAME = 'BASIC'; …(17) } …(17) /* 各国語文字列型 */ …(17) else { …(17) EXEC SQL SET DESCRIPTOR 'OUTDESC' VALUE :i …(17) TYPE = 1, …(17) LENGTH = 10, …(17) OCTET_LENGTH = 20, …(17) CHARACTER_SET_NAME = 'NCHAR'; …(17) } …(17) } …(17) /* INTEGER型かSMALLINT型 */ …(17) else if( vartype == 4 || vartype == 5 ) { …(17) EXEC SQL SET DESCRIPTOR 'OUTDESC' VALUE :i …(17) TYPE = 4, …(17) PRECISION = 31, …(17) SCALE = 0; …(17) } …(17) /* NUMERIC型かDECIMAL型かREAL型かDOUBLE PRECISION型 */ …(17) else if( vartype == 2 || vartype == 3 || …(17) vartype == 7 || vartype == 8 ) { …(17) EXEC SQL SET DESCRIPTOR 'OUTDESC' VALUE :i …(17) TYPE = 8, …(17) PRECISION = 52, …(17) SCALE = 0; …(17) } …(17) /* 日時型かINTERVAL型 */ …(17) else if( vartype == 9 || vartype == 10 ) { …(17) EXEC SQL SET DESCRIPTOR 'OUTDESC' VALUE :i …(17) TYPE = 12, …(17) LENGTH = 19, …(17) OCTET_LENGTH = 19, …(17) CHARACTER_SET_NAME = 'BASIC'; …(17) } …(17) } EXEC SQL OPEN CUR1 USING SQL DESCRIPTOR 'INDESC'; …(18) EXEC SQL WHENEVER NOT FOUND GOTO :NOTFND; …(19) for(;;) { EXEC SQL FETCH CUR1 INTO SQL DESCRIPTOR 'OUTDESC'; …(20) /************/ /* 実行結果 */ /************/ for( i = 1; i <= varocount; i++ ) { EXEC SQL GET DESCRIPTOR 'OUTDESC' VALUE :i …(21) :vartype = TYPE, …(21) :varchar = CHARACTER_SET_NAME; …(21) /* CHAR型かNCHAR型 */ …(21) if( vartype == 1 ) { …(21) /* 文字列型 */ …(21) if( strncmp( varchar, "BASIC", 5 ) == 0 ) { …(21) EXEC SQL GET DESCRIPTOR 'OUTDESC' VALUE :i …(21) :varname = NAME, …(21) :ocdata = DATA; …(21) printf( "%s -> %s ", varname, ocdata ); …(21) } …(21) /* 各国語文字列型 */ …(21) else { …(21) EXEC SQL GET DESCRIPTOR 'OUTDESC' VALUE :i …(21) :varname = NAME, …(21) :oncdata = DATA; …(21) printf( "%s -> %s ", varname, oncdata ); …(21) } …(21) } …(21) /* 真数型 */ …(21) else if( vartype == 4 ) { …(21) EXEC SQL GET DESCRIPTOR 'OUTDESC' VALUE :i …(21) :varname = NAME, …(21) :oidata = DATA; …(21) printf( "%s -> %d ", varname, oidata ); …(21) } …(21) /* 概数型 */ …(21) else if( vartype == 8 ) { …(21) EXEC SQL GET DESCRIPTOR 'OUTDESC' VALUE :i …(21) :varname = NAME, …(21) :ofdata = DATA; …(21) printf( "%s -> %lf ", varname, ofdata ); …(21) } …(21) /* 日時型かINTERVAL型 */ …(21) else if( vartype == 12 ) { …(21) EXEC SQL GET DESCRIPTOR 'OUTDESC' VALUE :i …(21) :varname = NAME, …(21) :oddata = DATA; …(21) oddata.sqlvar[oddata.sqllen] = \0; …(21) printf( "%s -> %s \n", varname, oddata.sqlvar ); …(21) } …(21) } printf( "\n" ); } NOTFND: EXEC SQL CLOSE CUR1; …(22) EXEC SQL DEALLOCATE DESCRIPTOR 'INDESC'; …(23) EXEC SQL DEALLOCATE DESCRIPTOR 'OUTDESC'; …(24) EXEC SQL DEALLOCATE PREPARE STMID; …(25) EXEC SQL COMMIT WORK; …(26) EXEC SQL DISCONNECT DEFAULT; …(27) return; ERR: EXEC SQL WHENEVER SQLERROR CONTINUE; printf( "SQLERROR SQLSTATE = %s SQLMSG = %s\n", SQLSTATE, SQLMSG ); EXEC SQL ROLLBACK WORK; EXEC SQL DISCONNECT DEFAULT; return; } |
(1) インクルードファイルvarfile.hのホスト変数を展開します。SQL文変数はSQL文を格納する領域です。可変長文字列は、コンパイル時に以下の構造体に展開されます。
struct { short sqllen; /* 長さ領域の変数 */ char sqlvar[100]; /* 文字列領域の変数 */ }str;
(2) ホスト変数を初期化します。
(3) コネクションを接続します。
(4) SQL文の実行でデータなし以外のエラーが生じた場合にERRへ進み、エラー情報を出力してプログラムは終了します。
(5) 端末から入力された動的SELECT文を読み込み、strに格納します。
(6) カーソルCUR1を宣言します。カーソル指定としてSQL文識別子STMIDを指定します。
(7) strのSQL文を実行できるようにするための準備処理を行います。
(8) 動的パラメタ指定のためのSQL記述子域INDESCを割り当てます。
(9) 相手指定のためのSQL記述子域OUTDESCを割り当てます。
(10) 入力した動的SELECT文の動的パラメタ指定の情報をSQL記述子域INDESCに取り込みます。
(11) 入力した動的SELECT文の選択リストの情報をSQL記述子域OUTDESCに取り込みます。
(12) INDESCに設定されている動的パラメタ指定の個数(COUNTの値)を取得します。
(13) INDESCに設定されているおのおのの動的パラメタ指定の情報(TYPE、LENGTH、OCTET_LENGTH、RECISION、SCALE、CHARACTER_SET_NAME、DATETIME_INTERVAL_CODE、DATETIME_INTERVAL_PRECISIONの値)を取得します。
(14) INDESCに設定されている動的パラメタ指定のデータ型を変更し、端末から読み込んだ動的パラメタ指定の値を設定します。
CHARACTER(n)、CHARACTER VARYING(n)をCHARACTER(14)に変更します。(nは文字列の長さ)
NATIONAL CHARACTER(n)、NATIONAL CHARACTER VARYING(n)をNATIONAL CHARACTER(10)に変更します。(nは文字列の長さ)
INTEGER、SMALLINTをINTEGERに変更します。
NUMERIC(p,q)、DECIMAL(p,q)、REAL、DOUBLE PRECISIONをDOUBLE PRECISIONに変更します。(pは精度、qは位取り)
DATE、TIME、TIMESTAMPおよびINTERVALをCHARACTER VARYING(19)に変更します。(nは文字列の長さ)
(15) OUTDESCに設定されている選択リストの個数(COUNTの値)を取得します。
(16) OUTDESCに設定されているおのおのの選択リストの情報(TYPE、LENGTH、OCTET_LENGTH、PRECISION、SCALE、CHARACTER_SET_NAME、DATETIME_INTERVAL_CODE、DATETIME_INTERVAL_PRECISIONの値)を取得します。
(17) OUTDESCに実行結果を取り出す相手指定のデータ型を設定します。
CHARACTER(n)、CHARACTER VARYING(n)をCHARACTER(14)に変更します。(nは文字列の長さ)
NATIONAL CHARACTER(n)、NATIONAL CHARACTER VARYING(n)をNATIONAL CHARACTER(10)に変更します。(nは文字列の長さ)
INTEGER、SMALLINTをINTEGERに変更します。
NUMERIC(p,q)、DECIMAL(p,q)、REAL、DOUBLE PRECISIONをDOUBLE PRECISIONに変更します。(pは精度、qは位取り)
DATE、TIME、TIMESTAMPおよびINTERVALをCHARACTER VARYING(19)に変更します。(nは文字列の長さ)
(18) (14)の値を使用して、カーソルCUR1をオープンします。
(19) 検索の結果データが見つからない場合にNOTFNDに進み、プログラムは終了します。
(20) カーソルCUR1の位置づけおよびデータの読み込みを行います。このとき、OUTDESCのDATAに実行結果の値が設定されます。
(21) SQL記述子域OUTDESCからNAMEとDATAの値を取得し、それぞれ相手指定のデータ型に一致したホスト変数に格納します。実行結果を端末に出力します。
(22) カーソルCUR1をクローズします。
(23) SQL記述子域INDESCを解放します。
(24) SQL記述子域OUTDESCを解放します。
(25) SQL文識別子STMIDに対応する被準備文を解放します。
(26) 現行のトランザクションを終了します。
(27) コネクションを切断します。
インクルードファイル“varfile.h”
/************************/ /* ホスト変数の定義開始 */ /************************/ char SQLSTATE[6]; char SQLMSG[256]; VARCHAR str[100]; /* SQL文変数 */ short vartype; /* データ型 */ …(1) short varleng; /* 文字数 */ …(1) short varolen; /* バイト数 */ …(1) short varprec; /* 精度 */ …(1) short varscal; /* 位取り */ …(1) char varname[39]; /* 列の名前 */ …(1) char varchar[39]; /* 文字セット名 */ …(1) short vardcod; /* 日時,時間隔 */ …(1) short vardpre; /* 時間隔精度 */ …(1) short varicount; /* 動的パラメタ指定の数 */ short varocount; /* 選択リストの数 */ short i; /* SQL記述子域のカウンタ */ VARCHAR icdata[15]; /* CHARACTER型 */ …(2) VARCHAR CHARACTER SET IS NCHAR incdata[21];/* NCHAR型 */ …(2) long iidata; /* 真数型 */ …(2) double ifdata; /* 概数型 */ …(2) VARCHAR iddata[20]; /* 日時,時間隔 */ …(2) char ocdata[15]; /* CHARACTER型 */ …(3) char CHARACTER SET IS NCHAR oncdata[21]; /* NCHAR型 */ …(3) long oidata; /* 真数型 */ …(3) double ofdata; /* 概数型 */ …(3) VARCHAR oddata[20]; /* 日時,時間隔 */ …(3) /************************/ /* ホスト変数の定義終了 */ /************************/ |
(1) SQL記述子域
(2) 動的パラメタ指定
(3) 相手指定
備考.このアプリケーションの実行が正常に終了したときの出力例のイメージを以下に示します。ゴシック体の文字列が入力されたものとします。
実行する動的SELECT文を指定してください SELECT * FROM 在庫管理.在庫表 WHERE 在庫数量 < ? 在庫数量の値を指定してください 10 製品番号 -> 212 製品名 -> テレビ 在庫数量 -> 0 倉庫番号 -> 2 製品番号 -> 215 製品名 -> ビデオ 在庫数量 -> 5 倉庫番号 -> 2 製品番号 -> 226 製品名 -> 冷蔵庫 在庫数量 -> 8 倉庫番号 -> 1 |
目次 索引 |