■概略
オープンソースエンジニア歴30年超の筆者が2023年からIBMiを学びだした学習記録です
(CGI1)IBMiのAPIサーバをFFRPGのCGIで作成する(1)」 で作成したサービスプログラム内の
関数を呼び出します
■CGIの要件
・以下のテーブルから指定した物件CDに該当する戸数を取得しJSONで返す
・物件CD未指定ときは 0001 を返す
・POST & GETの読み込み最大長は1024バイト(prototype.ffrpgで指定)
・CGIの出力最大長は2048000バイト=2MB(prototype.ffrpgで指定)
・CGIで引き渡すパラメータは最大10まで(prototype.ffrpgで指定)
◯対象テーブルとフィールド
BKNLIBF.GMBKAF(物件マスター)
COLUMN_NAME | COLUMN_TEXT | DATA_TYPE | LENGTH |
---|---|---|---|
BKA001 | 物件CD | CHAR | 4 |
BKA002 | 物件枝番 | NUMERIC | 2 |
BKA003 | 戸数 | NUMERIC | 4 |
◯SQL
select * from BKNLIBF.GMBKAF
where BKA001='{物件CD}'
◯URL(入力条件)
http://{サーバ}:8080/cgi-bin/BKNKOSU.PGM?bukken_cd={物件CD}
◯JSON(出力条件)
[{"bukken_cd":"物件CD","KOSU":"戸数"}]
■CGIのソースコード
◯POSTとGETから物件CD取得
getCGIVars()関数を呼び、パラメータをCGIkeysとCGIvaluesにいれる
メイン
exsr srGetCGIVars; // POSTとGETからパラメータを取得
サブルーチン
begsr srGetCGIVars;
getCGIVars(CGIkeys : CGIvalues);
for i = 1 to CGIVarsNum;
if CGIkeys(i) = 'bukken_cd';
bukken_cd = %trim(CGIvalues(i));
endif;
endfor;
endsr;
◯SQL生成
実行するSQLを文字列として生成する
注意) '(シングルクォーテーション)の扱い
文字列フィールドを条件に指定する場合は、値を ' で囲む必要がある
例 : where 文字列フィールド='値'
RPGの文字列変数の値は'(シングルクォーテーション)で囲む必要がある
"(ダブルクォーテーション)は使えない
よって文字列に '(シングルクォーテーション)を含めるには、
'' とシングルクォーテーションを2回繰り返すことでエスケープになる
文字列変数 = '''' → 文字列変数の値は '(シングルクォーテーション)1個
メイン
exsr srCreateSQL; // SQL生成
サブルーチン
begsr srCreateSQL;
sql_str = 'select * from BKNLIBF.GMBKAF';
where_str = ' where BKA001=''' + bukken_cd + '''';
if bukken_cd <> '';
sql_str += where_str;
endif;
endsr;
◯SQL実行と結果変数resultの取得
SQL組込み関数のカーソル機能で複数行を取得し、結果配列変数resultに代入する
なおresultはOS7.4から利用可能な動的配列を利用している
結果数は不明なので、初期配列数は0、最大20000まで動的に拡張する
メイン
exsr srExecSQL; // SQLを実行しresultを取得する
サブルーチン
begsr srExecSQL;
exec sql prepare sql1 from :sql_str;
exec sql declare csr1 cursor for sql1;
exec sql open csr1;
dou SQLSTATE = END_OF_FILE;
exec sql fetch csr1 into :dsGMBKAF;
if SQLSTATE <> END_OF_FILE;
i = %elem(result) + 1;
result(i).key1 = 'bukken_cd';
result(i).val1 = %char(dsGMBKAF.BKA001);
result(i).key2 = 'KOSU';
result(i).val2 = %char(dsGMBKAF.BKA003);
endif;
enddo;
exec sql close csr1;
endsr;
◯結果変数resultをJSONに変換し出力
メイン
exsr srConvertJSON; // resultをJSON変換しBufOutに入れる
responseHTTP(BufOut); // 出力する
サブルーチン
begsr srConvertJSON;
BufOut = '[';
for i=1 to %elem(result);
BufOut = %trim(BufOut) + '{';
BufOut = %trim(BufOut) +
'"' + result(i).key1 +'":' +
'"' + result(i).val1 +'",' +
'"' + result(i).key2 +'":' +
'"' + result(i).val2 +'"';
// JSON末尾の , はトル
if i = %elem(result);
BufOut = %trim(BufOut) + '}';
else;
BufOut = %trim(BufOut) + '},';
endif;
endfor;
BufOut = %trim(BufOut) + ']';
endsr;
◯CGIの全ソースコード
prototype.ffrpgは(CGI1)IBMiのAPIサーバをFFRPGのCGIで作成する(1)と同じ
**free
// 2024/06/26 えむぼま高見禎成 作成
//
//【注意】
// POST & GETの読み込み最大長は1024バイト(prototype.ffrpgで指定)
// CGIの出力最大長は2048000バイト=2MB(prototype.ffrpgで指定)
// CGIで引き渡すパラメータは最大10まで(prototype.ffrpgで指定)
// Qtmh*呼出し時はvarchar不可。charでないとCGI実行エラーになる!
//
ctl-opt main(main);
ctl-opt text('物件別戸数取得CGI');
// プロトタイプ
/include ./prototype.ffrpg
// メイン関数
dcl-proc main;
// CGI用変数(大文字始まりは外部連携利用)
dcl-s CGIkeys char(BufInLen) dim(CGIVarsNum);
dcl-s CGIvalues char(BufInLen) dim(CGIVarsNum);
dcl-s BufOut char(BufOutLen);
// 変数
dcl-s i packed(4:0);
dcl-s bukken_cd char(4) inz('0001');
dcl-s sql_str varchar(255) inz('');
dcl-s where_str varchar(255) inz('');
// レコード様式 [JSON形式に応じて要変更]
dcl-ds dsGMBKAF extname('GMBKAF') qualified;
end-ds;
// JSON展開前の結果変数 [JSON形式に応じて要変更]
// 動的配列の最大サイズの16MBを超えないように定義すること
// 物件数は7000強なので最大20000にした
dcl-ds result dim(*auto : 20000) qualified;
key1 varchar(20) inz('');
val1 varchar(20) inz('');
key2 varchar(20) inz('');
val2 varchar(20) inz('');
end-ds;
exsr srGetCGIVars; // POSTとGETからパラメータを取得
exsr srCreateSQL; // SQL生成
exsr srExecSQL; // SQLを実行しresultを取得する
exsr srConvertJSON; // resultをJSON変換しBufOutに入れる
responseHTTP(BufOut); // 出力する
return;
// -----------------サブルーチン---------------------
// POSTとGETからパラメータを取得
begsr srGetCGIVars;
getCGIVars(CGIkeys : CGIvalues);
for i = 1 to CGIVarsNum;
if CGIkeys(i) = 'bukken_cd';
bukken_cd = %trim(CGIvalues(i));
elseif CGIkeys(i) = 'token';
token = %trim(CGIvalues(i));
endif;
endfor;
endsr;
// SQL生成 --ここにSQLを組込む
// bukken_cdがなければ全件(whereなし)
begsr srCreateSQL;
sql_str = 'select * from PMLIBF.GMBKAF';
where_str = ' where BKA001=''' + bukken_cd + '''';
if bukken_cd <> '';
sql_str += where_str;
endif;
endsr;
// SQLカーソルでresult取得
begsr srExecSQL;
exec sql prepare sql1 from :sql_str;
if SQLSTATE = SYNTAX_ERROR;
leavesr;
endif;
exec sql declare csr1 cursor for sql1;
exec sql open csr1;
dou SQLSTATE = END_OF_FILE;
exec sql fetch csr1 into :dsGMBKAF;
if SQLSTATE <> END_OF_FILE;
i = %elem(result) + 1;
result(i).key1 = 'bukken_cd';
result(i).val1 = %char(dsGMBKAF.BKA001);
result(i).key2 = 'KOSU';
result(i).val2 = %char(dsGMBKAF.BKA003);
endif;
enddo;
exec sql close csr1;
endsr;
// JSONに変換
begsr srConvertJSON;
BufOut = '[';
for i=1 to %elem(result);
BufOut = %trim(BufOut) + '{';
BufOut = %trim(BufOut) +
'"' + result(i).key1 +'":' +
'"' + result(i).val1 +'",' +
'"' + result(i).key2 +'":' +
'"' + result(i).val2 +'"';
// JSON末尾の , はトル
if i = %elem(result);
BufOut = %trim(BufOut) + '}';
else;
BufOut = %trim(BufOut) + '},';
endif;
endfor;
BufOut = %trim(BufOut) + ']';
endsr;
end-proc;
■CGIのコンパイルbash
◯個人ライブラリにコンパイル
#!/bin/bash
USER=`whoami`
#---
TARGET_LIB=${USER}"LIB"
PGM="BKNKOSU"
SRVPGM="CGILIB"
DIR="/home/${USER}/CGIs/QFFRPGSRC"
#---
# メインモジュール
file=$DIR"/"$PGM".SQLFFRPG"
target=$TARGET_LIB"/"$PGM
target_srv=$TARGET_LIB"/"$SRVPGM
system "DLTMOD MODULE($target)"
system "CRTSQLRPGI OBJ($target) SRCSTMF('$file') OBJTYPE(*MODULE) COMPILEOPT('TGTCCSID(5035)') RPGPPOPT(*LVL2)"
# プログラム
system "DLTPGM PGM($target)"
system "CRTPGM PGM($target) MODULE($PGM) BNDSRVPGM($SRVPGM)" 2>&1
◯developブランチをCGILIBへ出力
#!/bin/bash
USER=`whoami`
#---
TARGET_LIB='CGILIB'
PGM="CGITemplate"
SRVPGM="CGILIB"
DIR="/home/${USER}/CGIs/QFFRPGSRC"
#---
# gitでdevelopに変更し最新に更新する
git checkout develop && git pull origin --ff-only
# メインモジュール
file=$DIR"/"$PGM".SQLFFRPG"
target=$TARGET_LIB"/"$PGM
target_srv=$TARGET_LIB"/"$SRVPGM
system "DLTMOD MODULE($target)"
system "CRTSQLRPGI OBJ($target) SRCSTMF('$file') OBJTYPE(*MODULE) COMPILEOPT('TGTCCSID(5035)') RPGPPOPT(*LVL2)"
# プログラム
system "DLTPGM PGM($target)"
system "CRTPGM PGM($target) MODULE($PGM) BNDSRVPGM($SRVPGM)" 2>&1
# 元のbranchに戻る
git checkout -```