OVRDBF を F4キーでいつもプロンプト表示していると
「ファイルの開始桁」キー・ワードがあるので、これを指定すれば
キーでレコードを CHAIN して検索することができるのだろうと
思ってみても実際に試してみた人は少ないのではないだろうか ?
また実際に CLP でファイルをキー指定で検索しても
エラーに悩まされて諦めた人もいるかも知れない。
ここでは実際に CLP で DCLF で指定されたキーつきのファイルを
キー・フィールドを指定して検索する方法とそのテクニックを紹介する。
さらに IBM が推薦している方法との比較も考察してみよう。
RPGプログラムではなく CLP でもファイルに CHAIN できるのなら
不要な RPG を書かなくて済むし何よりスマートである。
是非、このテクニックは覚えて欲しい。
【 サンプルCLP: TESTKEYR 】
0001.00 PGM 0002.00 /*-------------------------------------------------------------------*/ 0003.00 /* TESTKEYR : KEY レコードの検索 */ 0004.00 /* */ 0005.00 /* 2017/05/02 作成 */ 0006.00 /*-------------------------------------------------------------------*/ 0007.00 DCL VAR(&MSG) TYPE(*CHAR) LEN(132) 0008.00 DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) 0009.00 DCL VAR(&MSGF) TYPE(*CHAR) LEN(10) 0010.00 DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10) 0011.00 DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(132) 0012.00 DCL VAR(&TYPE) TYPE(*CHAR) LEN(1) 0013.00 DCL VAR(&TOPGMQ) TYPE(*CHAR) LEN(10) 0014.00 DCL VAR(&MSGTYPE) TYPE(*CHAR) LEN(10) + 0015.00 VALUE('*ESCAPE ') 0016.00 DCL VAR(&APIERR) TYPE(*CHAR) LEN(116) + 0017.00 VALUE(X'000074') /* 2 進数 */ 0018.00 DCL VAR(&NULL4) TYPE(*CHAR) LEN(4) + 0019.00 VALUE(X'00000000') 0020.00 DCLF FILE(QTRFIL/SHOHIN) RCDFMT(*ALL) 0021.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) 0022.00 0023.00 /*( 環境の取得 )*/ 0024.00 RTVJOBA TYPE(&TYPE) 0025.00 IF COND(&TYPE *EQ '0') THEN(DO) /* バッチ */ 0026.00 CHGVAR VAR(&TOPGMQ) VALUE('*SYSOPR ') 0027.00 ENDDO /* バッチ */ 0028.00 ELSE CMD(DO) /* 対話式 */ 0029.00 CHGVAR VAR(&TOPGMQ) VALUE('*TOPGMQ ') 0030.00 ENDDO /* 対話式 */ 0031.00 0032.00 /*( キーのセット )*/ 0033.00 CHGVAR VAR(&SHCODE) VALUE('NV-CF1 ') 0034.00 OVRDBF FILE(SHOHIN) TOFILE(QTRFIL/SHOHIN) + 0035.00 POSITION(*KEYAE 1 SHOHINR &SHCODE) + 0036.00 SECURE(*YES) OVRSCOPE(*JOB) 0037.00 RCVF RCDFMT(SHOHINR) 0038.00 MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(REDEND)) 0039.00 SNDPGMMSG MSG(' 見つかったキーは SHCODE=' *CAT + 0040.00 &SHCODE *CAT ' です。 ') MSGTYPE(*DIAG) 0041.00 DLTOVR FILE(SHOHIN) LVL(*JOB) 0042.00 RETURN 0043.00 0044.00 REDEND: 0045.00 DLTOVR FILE(SHOHIN) LVL(*JOB) 0046.00 RETURN 0047.00 0048.00 ERROR: RCVMSG MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) + 0049.00 MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) + 0050.00 MSGFLIB(&MSGFLIB) 0051.00 DLTOVR FILE(SHOHIN) LVL(*JOB) 0052.00 SNDMSG: IF COND(&MSGID *EQ ' ') THEN(DO) 0053.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) + 0054.00 TOMSGQ(&TOPGMQ) MSGTYPE(&MSGTYPE) 0055.00 ENDDO 0056.00 ELSE CMD(DO) 0057.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 0058.00 MSGDTA(&MSGDTA) TOMSGQ(&TOPGMQ) + 0059.00 MSGTYPE(&MSGTYPE) 0060.00 ENDDO 0061.00 ENDPGM
【解説】
この CLP はあらゆる環境や条件下でも適切な動作をするように考慮されている
基本パターンから構成されているので多少、冗長に見えるかも知れないが
中身はシンプルである。
まず
DCLF FILE(QTRFIL/SHOHIN) RCDFMT(*ALL)
によってファイルを定義しているが、ここではキーつきでオープンするとか
ファイル識別子を指定する必要はない。
次にキーのセットとして
CHGVAR VAR(&SHCODE) VALUE('NV-CF1 ') OVRDBF FILE(SHOHIN) TOFILE(QTRFIL/SHOHIN) + POSITION(*KEYAE 1 SHOHINR &SHCODE) + SECURE(*YES) OVRSCOPE(*JOB)
を行っている。
DCLF でファイル定義して暗黙的にファイルをオープンしているはずなので
このファイル SHOHIN に対する OVRDBF が効くのか? と心配する人もいるかも知れないが
ファイルがオープンされるのは実は
RCVF RCDFMT(SHOHINR)
の時点なので OVRDBFは有効に効果を発揮する。
ところで
OVRDBF FILE(SHOHIN) TOFILE(QTRFIL/SHOHIN) + POSITION(*KEYAE 1 SHOHINR &SHCODE) + SECURE(*YES) OVRSCOPE(*JOB)
では POSITION に *KEY ではなく *KEYAE を指定していることに注意して欲しい。
これはファイルの開始桁(POSITION) パラメータに問題があるからである。
実は POSITION パラメータのキー値の部分は
可変の長さ (VARY(*YES)) として定義されているので
CHGVAR VAR(&SHCODE) VALUE('NV-CF1 ')
のようにブランクを後続に含む値を渡すと後続のブランク文字列は切り捨てられて
この場合だと 「NV-CF1」 の 6桁の値として POSITION キー・ワードは解釈する。
さらにこの場合、キー: SHCODE は 10桁/span>であるので
6桁の 「NV-CF1」 の指定は無条件にエラーになる。
しかも追いかけるように IBM が示すエラー・メッセージは
CPF4137: メンバー SHOHIN の位置指定オプションが正しくない。
とのエラー・メッセージが出力される。
このメッセージから推測されるのは
POSITION(*KEYAE 1 SHOHINR &SHCODE)
の
1 が正しくないのかと思ってしまう。
POSITION(*KEYAE 1 SHOHINR &SHCODE)
ではなく
POSITION(*KEYAE 1 SHOHINR 'NV-CF1 ')
と指定すれば正しく動作するのだが後続ブランクのあるキーを正しく指定することができない。
IBM は恐らく多くのユーザーからこの問題について質問と苦情を受けたのだろう。
IBM が行った回答は文字列を作って QCMDEXC で実行する、というものである。
【 IBM Knowledge Center : コマンド・パラメーターの末尾ブランク 】
https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/rbam6/tralb.htm
これは誠に不細工な方法であり他人に見られたくない方法である。
弊社の提案はキーが必ず存在するのであれば *KEYAE を使う方法である。
キーが存在しない場合も含めるなら RCVF の後で読んだレコードのキーを比較すれば良い。
どちらが見やすくスマートな方法に見えるだろうか?