ここで紹介するTESTREAD というRPGプログラムは

①任意のデータ・ベースを読取る
②任意のレコード長を読取り警告エラーは出ない。
③超高速でデータ・ベースを読取る
という長所を兼ね備えたプログラムである。
大量のデータ・ペースも一瞬に読み取って処理することができる
スグレモノである。
1万レコードの読取りなどはホンの一瞬で終わるので
その速さに驚くかも知れない。
汎用的にどのデータ・ベースでも読取ることができる技術として米国で紹介されていたのを
少し改良したものである。
[TESTREADの実行画面]
C 関数による読取り (TESTREAD)
選択項目を入力して,実行キーを押してください。
ファイル . . . . . . . . . . . SHOHIN 名前
ライブラリー . . . . . . . . QTRFIL 名前 , *LIBL, *CURLIB
メンバー . . . . . . . . . . . *FIRST 名前 , *FIRST, *LAST, *ALL
[コマンド: TESTREAD ]
ソースはこちらから
0001.00 CMD PROMPT('C 関数による読取り ')
0002.00 PARM KWD(FILE) TYPE(FILE) MAX(1) +
0003.00 PROMPT(' ファイル ')
0004.00 FILE: QUAL TYPE(*NAME) LEN(10) MIN(1)
0005.00 QUAL TYPE(*NAME) LEN(10) DFT(*LIBL) +
0006.00 SPCVAL((*LIBL) (*CURLIB '*CURLIB ')) +
0007.00 EXPR(*YES) PROMPT(' ライブラリー ')
0008.00 PARM KWD(MEMBER) TYPE(*NAME) LEN(10) DFT(*FIRST) +
0009.00 SPCVAL((*FIRST) (*LAST) (*ALL)) +
0010.00 PROMPT(' メンバー ')
[コンパイル]
CRTCMD CMD(OBJLIB/TESTREAD) PGM(OJLIB/TESTREADCL) SRCFILE(R610SRC/QCMDSRC) AUT(*ALL)
[ CLP: TESTREADCL ]
ソースはこちらから
0001.00 PGM PARM(&FILFILLIB &MBR)
0002.00 /*----------------------------------------------------------------------*/
0003.00 /* TESTREADCL : C 関数による読取り */
0004.00 /* */
0005.00 /* 2021/11/25 作成 */
0006.00 /*----------------------------------------------------------------------*/
0007.00 DCL VAR(&FILFILLIB) TYPE(*CHAR) LEN(20)
0008.00 DCL VAR(&FILE) TYPE(*CHAR) LEN(10)
0009.00 DCL VAR(&FILLIB) TYPE(*CHAR) LEN(10)
0010.00 DCL VAR(&MBR) TYPE(*CHAR) LEN(10)
0011.00 DCL VAR(&MSG) TYPE(*CHAR) LEN(132)
0012.00 DCL VAR(&STMMSG) TYPE(*CHAR) LEN(132)
0013.00 DCL VAR(&MSGID) TYPE(*CHAR) LEN(7)
0014.00 DCL VAR(&MSGF) TYPE(*CHAR) LEN(10)
0015.00 DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)
0016.00 DCL VAR(&MSGKEY) TYPE(*CHAR) LEN(4)
0017.00 DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(132)
0018.00 DCL VAR(&ERRDTA) TYPE(*CHAR) LEN(132)
0019.00 DCL VAR(&TYPE) TYPE(*CHAR) LEN(1)
0020.00 DCL VAR(&TOPGMQ) TYPE(*CHAR) LEN(10)
0021.00 DCL VAR(&MSGTYPE) TYPE(*CHAR) LEN(10) +
0022.00 VALUE('*ESCAPE ')
0023.00 DCL VAR(&ERR) TYPE(*CHAR) LEN(1)
0024.00 DCL VAR(&NULL4) TYPE(*CHAR) LEN(4) +
0025.00 VALUE(X'00000000')
0026.00 DCL VAR(&APIERR) TYPE(*CHAR) LEN(116) +
0027.00 VALUE(X'000074') /* 2 進数 */
0028.00 MONMSG MSGID(CPF9999) EXEC(GOTO CMDLBL(ERROR))
0029.00
0030.00 /*( 環境の取得 )*/
0031.00 RTVJOBA TYPE(&TYPE)
0032.00 IF COND(&TYPE *EQ '0') THEN(DO) /* バッチ */
0033.00 CHGVAR VAR(&TOPGMQ) VALUE('*SYSOPR ')
0034.00 ENDDO /* バッチ */
0035.00 ELSE CMD(DO) /* 対話式 */
0036.00 CHGVAR VAR(&TOPGMQ) VALUE('*TOPGMQ ')
0037.00 ENDDO /* 対話式 */
0038.00
0039.00 /*( 入力パラメータの取得 )*/
0040.00 CHGVAR VAR(&FILE) VALUE(%SST(&FILFILLIB 01 10))
0041.00 CHGVAR VAR(&FILLIB) VALUE(%SST(&FILFILLIB 11 10))
0042.00
0043.00 /*( プログラムの実行 )*/
0044.00 CALL PGM(TEST.COM/TESTREAD) PARM(&FILE &FILLIB +
0045.00 &MBR &ERR &MSG)
0046.00 IF COND(&ERR *EQ ' ') THEN(DO)
0047.00 CHGVAR VAR(&MSGTYPE) VALUE('*DIAG ')
0048.00 ENDDO
0049.00 IF COND(&MSG *NE ' ') THEN(DO)
0050.00 GOTO SNDMSG
0051.00 ENDDO
0052.00 RETURN
0053.00
0054.00 ERROR: RCVMSG MSGTYPE(*LAST) RMV(*NO) KEYVAR(&MSGKEY) +
0055.00 MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) +
0056.00 MSGFLIB(&MSGFLIB)
0057.00 IF COND(&MSGID *EQ 'CPF9999') THEN(DO)
0058.00 CHGVAR VAR(&ERRDTA) VALUE(&MSGDTA)
0059.00 RCVMSG MSGTYPE(*PRV) MSGKEY(&MSGKEY) RMV(*NO) +
0060.00 MSG(&MSG) MSGDTA(&MSGDTA) MSGID(&MSGID) +
0061.00 MSGF(&MSGF) MSGFLIB(&MSGFLIB)
0062.00 CHGVAR VAR(&STMMSG) VALUE(' プログラム ' *CAT +
0063.00 %SST(&ERRDTA 8 10) *TCAT +
0064.00 ' のステートメント ' *CAT %SST(&ERRDTA +
0065.00 24 4) *CAT ' で次のエラーが発生しました。 ')
0066.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&STMMSG) +
0067.00 TOMSGQ(&TOPGMQ) MSGTYPE(*DIAG)
0068.00 ENDDO
0069.00 SNDMSG: IF COND(&MSGID *EQ ' ') THEN(DO)
0070.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) +
0071.00 TOMSGQ(&TOPGMQ) MSGTYPE(&MSGTYPE)
0072.00 MONMSG MSGID(CPF2400) EXEC(RETURN)
0073.00 ENDDO
0074.00 ELSE CMD(DO)
0075.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +
0076.00 MSGDTA(&MSGDTA) TOMSGQ(&TOPGMQ) +
0077.00 MSGTYPE(&MSGTYPE)
0078.00 MONMSG MSGID(CPF2400) EXEC(RETURN)
0079.00 ENDDO
0080.00 ENDPGM
[コンパイル]
CRTCLPGM PGM(OBJLIB/TESTREADCL) SRCFILE(MYSRCLIB/QCLSRC) OPTION(*SRCDG) AUT(*ALL)
[解説]
コマンド入力されたファイル名、ライブラリー名とメンバー名をプログラム: TESTREAD に渡して
実行している。
[ RPG : TESTREAD ]
ソースはこちらから
0001.00 H DFTNAME(TESTREAD) DATEDIT(*YMD/)
0002.00 F********** C 関数による読取り ****************************************
0003.00 F*
0004.00 F**********************************************************************
0005.00
0006.00 * CRTBNDRPG OBJ(OBJLIB/TESTREAD) SRCFILE(MYSRCLIB/QRPGLESRC)
0007.00 * DFTACTRP(*NO) ACTGRP(*NEW) DBGVIEW(*SOURCE) AUT(*ALL)
0008.00
0009.00 *-------------------------------------------------------------------*
0010.00 * 2021/11/25 : 作成
0011.00 *-------------------------------------------------------------------*
0012.00 *( 作業変数 )
0013.00 D TRUE# S 4B 0 INZ(0)
0014.00 D FALSE# S 4B 0 INZ(-1)
0015.00 D EOF# S 4B 0 INZ(-1)
0016.00 D DFT C CONST(X'0B000100')
0017.00 D OE# C CONST(X'0E')
0018.00 D OF# C CONST(X'0F')
0019.00
0020.00 D*( _Ropen のプロトタイプ宣言 )
0021.00 *[ 例 ]
0022.00 * RFILE = _Ropen("ASNET.USR/USRLIBL", "rr")
0023.00 D Ropen PR * ExtProc('_Ropen')
0024.00 D RFILE * VALUE OPTIONS(*STRING:*TRIM)
0025.00 D OPTION * Value OPTIONS(*STRING:*TRIM)
0026.00
0027.00 D*( _Rreadn のプロトタイプ宣言 )
0028.00 * _RIOFB_T*_Rreadn(_RFILE *, void *, size_t, int);
0029.00 *[ 例 ]
0030.00 D Rreadn PR * ExtProc('_Rreadn')
0031.00 D RFILE * Value
0032.00 D RECORD * Value
0033.00 D RCD_LEN 10I 0 Value
0034.00 D OPT 10I 0 Value
0035.00
0036.00 D*( _Rclose のプロトタイプ宣言 )
0037.00 D Rclose PR 10I 0 ExtProc('_Rclose')
0038.00 D RFILE * Value
0039.00
0040.00 D IOFB_P S *
0041.00 D RIOFB DS 64 QUALIFIED
0042.00 D BASED(IOFB_P)
0043.00 D KEY *
0044.00 D SYSPRM *
0045.00 D RRN 10I 0
0046.00 D NUM_BYTE 10I 0
0047.00
0048.00 D RFILE DS 336 QUALIFIED
0049.00 D BASED(RFILE_P)
0050.00 D BUF_LENGTH 193 196I 0
0051.00
0052.00 D RCD_LEN S 10I 0
0053.00 D DATA S 5000A
0054.00 D RFILE_P S *
0055.00 D BYTES S 10I 0
0056.00 D HIVAL S 1N INZ(*ON)
0057.00
0058.00 C*-------------------------------------------------------------------------+
0059.00 C *ENTRY PLIST |
0060.00 C PARM FILE 10 |
0061.00 C PARM FILLIB 10 |
0062.00 C PARM MBR 10 |
0063.00 C*-------------------------------------------------------------------------+
0064.00 /FREE
0065.00 RFILE_P = Ropen(%TRIMR(FILLIB) + '/' + %TRIMR(FILE): 'rr');
0066.00 RCD_LEN = RFILE.BUF_LENGTH;
0067.00 DOW HIVAL;
0068.00 IOFB_P = Rreadn(RFILE_P: %ADDR(DATA): RCD_LEN: DFT);
0069.00 IF (RIOFB.NUM_BYTE = EOF#);
0070.00 LEAVE;
0071.00 ENDIF;
0072.00 EXSR CHECK;
0073.00 /END-FREE
0074.00 C********************************
0075.00 C* レコードの処理はここから *
0076.00 C********************************
0077.00 C EXSR PRINT
0078.00 C********************************
0079.00 C* レコードの処理はここまで *
0080.00 C********************************
0081.00 /FREE
0082.00 ENDDO;
0083.00 Rclose(RFILE_P);
0084.00 /END-FREE
0085.00 C SETON LR
0086.00 C RETURN
0087.00 C******************************************************
0088.00 C CHECK BEGSR
0089.00 C******************************************************
0090.00 C ENDSR
0091.00 C******************************************************
0092.00 C PRINT BEGSR
0093.00 C******************************************************
0094.00 C ENDSR
[コンパイル]
CRTBNDRPG PGM(TEST.COM/TESTREAD) SRCFILE(R610SRC/QRPGLESRC) DFTACTGRP(*NO)
ACTGRP(*NEW) DBGVIEW(*SOURCE) AUT(*ALL)
[解説]
RPG : TESTREAD はC言語のデータ・ベース読取り関数: _Ropen, _Rreadn, _Rclose を
使って処理している。
このうち _Rreadn は読取りバイト数を指定して読み取るので
読取りのときに警告エラーが出ることはない。
_Ropen で読み取るとレコード長: BUF_LENGTH を取得することができるので
その長さを指定して読み取ればよい。
0064.00 /FREE 0065.00 RFILE_P = Ropen(%TRIMR(FILLIB) + '/' + %TRIMR(FILE): 'rr'); 0066.00 RCD_LEN = RFILE.BUF_LENGTH; 0067.00 DOW HIVAL; 0068.00 IOFB_P = Rreadn(RFILE_P: %ADDR(DATA): RCD_LEN: DFT); 0069.00 IF (RIOFB.NUM_BYTE = EOF#); 0070.00 LEAVE; 0071.00 ENDIF; 0072.00 EXSR CHECK; 0073.00 /END-FREE : 0081.00 /FREE 0082.00 ENDDO; 0083.00 Rclose(RFILE_P); 0084.00 /END-FREE
が読取り処理である。1万件くらいのファイルを読んでも瞬時に終わるので
驚かれる。
この技術は弊社の次の追加機能にも使われている。
製品とするのであれば高速処理が当然必要なのでこの技術を採用している。
