Symfoware Server SQLビギナーズガイド - FUJITSU - |
目次 索引 |
第7章 アプリケーションの実行時に動的SQL文を実行する方法 | > 7.3 SQL文の条件を動的に変更して実行する | > 7.3.1 SQLDA構造体の操作方法 |
データの取り出しを連続的に行う場合には、動的SELECT文を準備して実行します。SQLDA構造体を使用して、動的パラメタ指定のある動的SELECT文を実行するアプリケーションの例を以下に示します。
例
端末から入力した動的SELECT文の例です。端末から入力した動的パラメタ指定の値を探索条件としてデータを検索し、その値を表示します。
#include <stdio.h> #include <string.h> #include "qdbnosis.h" EXEC SQL BEGIN DECLARE SECTION; char SQLSTATE[6]; char SQLMSG[256]; VARCHAR str[1024]; /* SQL文変数 */ …(1) SQLDA *sqlda_in ; /* SQLDA構造体 */ SQLDA *sqlda_out; /* SQLDA構造体 */ EXEC SQL END DECLARE SECTION; void main() { short vartype; /* データ型 */ short varleng; /* 文字数 */ short varolen; /* バイト数 */ short varprec; /* 精度 */ short varscal; /* 位取り SQL記述子域 */ char varname[129]; /* 列の名前 */ short vardcod; /* 日時,時間隔 */ short vardpre; /* 時間隔精度 */ short varicount; /* 動的パラメタ指定の数 */ short varocount; /* 選択リストの数 */ short i; /* SQL記述子域のカウンタ */ char icdata[100][15]; /* CHARACTER型 */ char incdata[100][21]; /* NCHAR型 */ long iidata[100]; /* 真数型 相手指定 */ double ifdata[100]; /* 概数型 */ char iddata[100][22]; /* 日時,時間隔 */ char ocdata[100][15]; /* CHARACTER型 */ char oncdata[100][21]; /* NCHAR型 */ long oidata[100]; /* 真数型 相手指定 */ double ofdata[100]; /* 概数型 */ char oddata[100][22]; /* 日時,時間隔 */ short inddata[100]; /* 標識変数 */ size_t size; /* SQLDAのサイズ */ memset(SQLSTATE, 0x00, 6); …(2) memset(SQLMSG, 0x00, 256); …(2) memset(&str, 0x00, sizeof(str)); …(2) memset(varname, 0x00, sizeof(varname)); …(2) memset(icdata, 0x00, sizeof(icdata)); …(2) memset(incdata, 0x00, sizeof(incdata)); …(2) memset(iddata, 0x00, sizeof(iddata)); …(2) memset(ocdata, 0x00, sizeof(ocdata)); …(2) memset(oncdata, 0x00, sizeof(oncdata)); …(2) memset(oddata, 0x00, sizeof(oddata)); …(2) size = sizeof(SQLDA) + sizeof(sqlvar) * (100 - 1); …(3) sqlda_in = (SQLDA *)malloc(size); sqlda_out = (SQLDA *)malloc(size); memset( sqlda_in, 0x00, size ); memset( sqlda_out, 0x00, size ); sqlda_in->SQLN = 100; …(4) sqlda_out->SQLN = 100; EXEC SQL CONNECT TO DEFAULT; …(5) EXEC SQL WHENEVER SQLERROR GOTO :ERR; …(6) printf( "実行する動的SELECT文を指定してください \n" ); gets( str.sqlvar ); …(7) str.sqllen = strlen( str.sqlvar ); EXEC SQL DECLARE CUR1 CURSOR FOR STMID; …(8) EXEC SQL PREPARE STMID FROM :str; …(9) EXEC SQL DESCRIBE INPUT STMID USING SQL DESCRIPTOR :sqlda_in; …(10) EXEC SQL DESCRIBE OUTPUT STMID USING SQL DESCRIPTOR :sqlda_out; …(11) /********************/ /* 動的パラメタ指定 */ /********************/ varicount = sqlda_in->SQLD; …(12) for( i = 0; i < varicount; i++ ) { vartype = sqlda_in->SQLVAR[i].SQLTYPE; …(13) varleng = sqlda_in->SQLVAR[i].SQLLEN; …(13) varprec = sqlda_in->SQLVAR[i].SQLPRECISION.PRECISION; …(13) varscal = sqlda_in->SQLVAR[i].SQLSCALE; …(13) vardcod = sqlda_in->SQLVAR[i].SQLSCALE; …(13) vardpre = sqlda_in->SQLVAR[i].SQLPRECISION.INTERVAL. …(13) DATETIME_INTERVAL_PRECISION; …(13) memcpy( varname, sqlda_out->SQLVAR[i].SQLNAME.SQLNAMEC, …(13) sqlda_out->SQLVAR[i].SQLNAME.SQLNAMEL ); …(13) varname[sqlda_out->SQLVAR[i].SQLNAME.SQLNAMEL] = 0x00; …(13) /* CHAR型 */ …(14) if( vartype == 1 || vartype == 12 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%s", &icdata[i][0] ); …(14) sqlda_in->SQLVAR[i].SQLTYPE = 12; …(14) sqlda_in->SQLVAR[i].SQLLEN = strlen( &icdata[i][0] ); …(14) sqlda_in->SQLVAR[i].SQLDATA = (char *)&icdata[i][0]; …(14) } …(14) else if( vartype == 11 || vartype == 13 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%s", &incdata[i][0] ); …(14) sqlda_in->SQLVAR[i].SQLTYPE = 13; …(14) sqlda_in->SQLVAR[i].SQLLEN = strlen( &incdata[i][0] ); …(14) sqlda_in->SQLVAR[i].SQLDATA = (char *)&incdata[i][0]; …(14) } …(14) /* INTEGER型かSMALLINT型 */ …(14) else if( vartype == 4 || vartype == 5 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%ld", &iidata[i] ); …(14) sqlda_in->SQLVAR[i].SQLTYPE = 4; …(14) sqlda_in->SQLVAR[i].SQLLEN = 4; …(14) sqlda_in->SQLVAR[i].SQLPRECISION.PRECISION = 31; …(14) sqlda_in->SQLVAR[i].SQLSCALE = 0; …(14) sqlda_in->SQLVAR[i].SQLDATA = (char *)&iidata[i]; …(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[i] ); …(14) sqlda_in->SQLVAR[i].SQLTYPE = 8; …(14) sqlda_in->SQLVAR[i].SQLLEN = 8; …(14) sqlda_in->SQLVAR[i].SQLPRECISION.PRECISION = 52; …(14) sqlda_in->SQLVAR[i].SQLSCALE = 0; …(14) sqlda_in->SQLVAR[i].SQLDATA = (char *)&ifdata[i]; …(14) } …(14) /* 日時型かINTERVAL型 */ …(14) else if( vartype == 9 || vartype == 10 ) { …(14) printf( "%sの値を指定してください \n", varname ); …(14) scanf( "%s", &iddata[i][0] ); …(14) sqlda_in->SQLVAR[i].SQLTYPE = 12; …(14) sqlda_in->SQLVAR[i].SQLLEN = strlen( &iddata[i][0] ); …(14) sqlda_in->SQLVAR[i].SQLDATA = (char *)&iddata[i][0]; …(14) } …(14) } /**************/ /* 選択リスト */ /**************/ varocount = sqlda_out->SQLD; …(15) for( i = 0; i < varocount; i++ ) { …(16) vartype = sqlda_out->SQLVAR[i].SQLTYPE; …(16) varleng = sqlda_out->SQLVAR[i].SQLLEN; …(16) varprec = sqlda_out->SQLVAR[i].SQLPRECISION.PRECISION; …(16) varscal = sqlda_out->SQLVAR[i].SQLSCALE; …(16) vardcod = sqlda_out->SQLVAR[i].SQLSCALE; …(16) vardpre = sqlda_out->SQLVAR[i].SQLPRECISION.INTERVAL. …(16) DATETIME_INTERVAL_PRECISION; /* CHAR型かVCHAR型 */ …(17) if( vartype == 1 || vartype == 12 ) { …(17) sqlda_out->SQLVAR[i].SQLTYPE = 1; …(17) sqlda_out->SQLVAR[i].SQLLEN = 14; …(17) sqlda_out->SQLVAR[i].SQLDATA = (char *)&ocdata[i][0]; …(17) } …(17) /* NCHAR型かNVCHAR型 */ …(17) else if( vartype == 11 || vartype == 13 ) { …(17) sqlda_out->SQLVAR[i].SQLTYPE = 11; …(17) sqlda_out->SQLVAR[i].SQLLEN = 20; …(17) sqlda_out->SQLVAR[i].SQLDATA = (char *)&oncdata[i][0]; …(17) } …(17) /* INTEGER型かSMALLINT型 */ …(17) else if( vartype == 4 || vartype == 5 ) { …(17) sqlda_out->SQLVAR[i].SQLTYPE = 4; …(17) sqlda_out->SQLVAR[i].SQLLEN = 4; …(17) sqlda_out->SQLVAR[i].SQLPRECISION.PRECISION = 31; …(17) sqlda_out->SQLVAR[i].SQLSCALE = 0; …(17) sqlda_out->SQLVAR[i].SQLDATA = (char *)&oidata[i]; …(17) } …(17) /* NUMERIC型かDECIMAL型かREAL型かDOUBLE PRECISION型 */ …(17) else if( vartype == 2 || vartype == 3 || …(17) vartype == 7 || vartype == 8 ) { …(17) sqlda_out->SQLVAR[i].SQLTYPE = 8; …(17) sqlda_out->SQLVAR[i].SQLLEN = 8; …(17) sqlda_out->SQLVAR[i].SQLPRECISION.PRECISION = 52; …(17) sqlda_out->SQLVAR[i].SQLSCALE = 0; …(17) sqlda_out->SQLVAR[i].SQLDATA = (char *)&ofdata[i]; …(17) } …(17) /* 日時型かINTERVAL型 */ …(17) else if( vartype == 9 || vartype == 10 ) { …(17) sqlda_out->SQLVAR[i].SQLTYPE = 12; …(17) sqlda_out->SQLVAR[i].SQLLEN = 21; …(17) sqlda_out->SQLVAR[i].SQLDATA = (char *)&oddata[i][0]; …(17) } …(17) } EXEC SQL OPEN CUR1 USING SQL DESCRIPTOR :sqlda_in; …(18) EXEC SQL WHENEVER NOT FOUND GOTO :NOTFND; …(19) for(;;) { EXEC SQL FETCH CUR1 INTO SQL DESCRIPTOR :sqlda_out; …(20) /************/ /* 実行結果 */ /************/ for( i = 0; i < varocount; i++ ) { vartype = sqlda_out->SQLVAR[i].SQLTYPE; memcpy( varname, sqlda_out->SQLVAR[i].SQLNAME.SQLNAMEC, sqlda_out->SQLVAR[i].SQLNAME.SQLNAMEL ); varname[sqlda_out->SQLVAR[i].SQLNAME.SQLNAMEL] = 0x00; /* CHAR型 */ if( vartype == 1 ) { printf( "%s -> %s ", varname, &ocdata[i][0] ); } /* NCHAR型 */ else if( vartype == 11 ) { printf( "%s -> %s ", varname, &oncdata[i][0] ); } /* 真数型 */ else if( vartype == 4 ) { printf( "%s -> %d ", varname, oidata[i] ); } /* 概数型 */ else if( vartype == 8 ) { printf( "%s -> %lf ", varname, ofdata[i] ); } /* 日時型かINTERVAL型 */ else if( vartype == 12 ) { printf( "%s -> %s ", varname, &oddata[i][2] ); } } printf( "\n" ); } NOTFND: EXEC SQL CLOSE CUR1; …(21) EXEC SQL DEALLOCATE PREPARE STMID; …(22) EXEC SQL COMMIT WORK; …(23) EXEC SQL DISCONNECT DEFAULT; …(24) free( sqlda_in ); free( sqlda_out ); return; ERR: EXEC SQL WHENEVER SQLERROR CONTINUE; printf( "SQLERROR SQLSTATE = %s SQLMSG = %s\n", SQLSTATE, SQLMSG ); EXEC SQL ROLLBACK WORK; EXEC SQL DISCONNECT DEFAULT; free( sqlda_in ); free( sqlda_out ); return; } |
(1) SQL文変数はSQL文を格納する領域です。可変長文字列は、コンパイル時に以下の構造体に展開されます。
struct { short sqllen; /* 長さ領域の変数 */ char sqlvar[100]; /* 文字列領域の変数 */ }str;
(2) ホスト変数を初期化します。
(3) SQLDA構造体の領域を獲得します。
(4) 配列SQLVARの配列数(SQLNの値)を指定します。
(5) コネクションを接続します。
(6) SQL文の実行でデータなし以外のエラーが生じた場合にERRへ進み、エラー情報を出力してプログラムは終了します。
(7) 端末から入力された動的SELECT文を読み込み、strに格納します。
(8) カーソルCUR1を宣言します。カーソル指定としてSQL文識別子STMIDを指定します。
(9) strのSQL文を実行できるようにするための準備処理を行います。
(10) 入力した動的SELECT文の動的パラメタ指定の情報をSQLDA構造体(sqlda_in)に取り込みます。
(11) 入力した動的SELECT文の選択リストの情報をSQLDA構造体(sqlda_out)に取り込みます。
(12) SQLDA構造体(sqlda_in)に設定されている選択リストの個数(SQLDの値)を取得します。
(13) SQLDA構造体(sqlda_in)に設定されているおのおのの動的パラメタ指定の情報(SQLTYPE、SQLLEN、SQLPRECISION、SQLSCALE、DATETIME_INTERVAL_CODE、DATETIME_INTERVAL_PRECISIONの値)を取得します。
(14) SQLDA構造体(sqlda_in)に設定されている動的パラメタ指定のデータ型を変更し、端末から読み込んだ動的パラメタ指定の値を設定します。
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) SQLDA構造体に設定されている選択リストの個数(SQLDの値)を取得します。
(16) SQLDA構造体に設定されているそれぞれの選択リストの情報(SQLTYPE、SQLLEN、SQLPRECISION、SQLSCALEの値)を取得します。
(17) SQLDA構造体に実行結果を取り出す相手指定のデータ型や変数アドレスを設定します。
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の位置づけおよびデータの読み込みを行います。このとき、SQLDA構造体(sqlda_out)のSQLDATAに設定したアドレスに実行結果の値が設定されます。
(21) カーソルCUR1をクローズします。
(22) SQL文識別子STMIDに対応する被準備文を解放します。
(23) 現行のトランザクションを終了します。
(24) コネクションを切断します。
目次 索引 |