IBM i 7.5 - Enhancements timed with Technology Refresh 5 (TR5) で
前に書いた記事 新命令ON-EXIT の中で %PROC関数(プロシージャの取得)
が使えるようになったとのことなので試してみました。
関連リンク
- IBM i 7.5 - Enhancements timed with Technology Refresh 5 (TR5)
- RPG Cafe: Fall 2024: Use %PROC() in ON-EXIT
- %PROC (現行プロシージャーの戻り値の名前)
TR導入
通常の手順で V7R5-TR5 を導入したのですが、今回のサンプルコードはコンパイルエラーとなってしまいました。該当のPTF番号を DSPPTF
で確認してもやはり導入されておりませんでした。
今回TRの対象個別PTF SJ02921 ~ SJ02923
を個別オーダーし導入したら、動作するようになりましたので、TR5の導入でうまく行かない場合は個別を試してみて下さい。
【注意事項】SJ02921 を入れた際の
今回の %PROC
とは直接関係ありませんが、TR5で案内されている SJ02921 - RPGLE-CMPL NEW DATEYY PARAMETER FOR CRTRPGMOD AND CRTBNDRPG の個別PTFを導入した場合は、コマンド CRTBNDRPG
と CRTRPGMOD
の省略値を CHGCMDDFT
で独自変更している場合はリセットされますので注意して下さい。私の環境も DBGVIEW(*ALL)
としていたのですが、リセットされておりました。
%PROCのサンプルコード
以下が実際に ON-EXIT 内で %PROC
で使用したサンプルコード例です。
**FREE
// H**********************************************************************
// H* *
// H* システム名 :RPG教育 *
// H* サブシステム名 :教育プログラム *
// H* プログラム名 :%PROCのON−EXIT内での使用 *
// H* プログラムID : Q242101R *
// H* 会 社 名 :株式会社中部システム *
// H* *
// H* 作 成 者 :㈱中部システム Y.USHIDA *
// H* 作 成 日 : 2024/12/02 *
// H* 管 理 番 号: ____________ *
// H* *
// H* 変 更 者 : *
// H* 変 更 日 : ____/__/__ *
// H* 管 理 番 号: *
// H* *
// H* プログラム特記事項 *
// H* _ *
// H* _ *
// H* *
// H*-*******************************************************************
// H*-*H仕様書 **
// H*-*******************************************************************
CTL-OPT
DFTACTGRP(*NO) ACTGRP(*NEW)
DATEDIT(*YMD)
DECEDIT('0.')
EXPROPTS(*RESDECPOS)
CURSYM('¥')
COPYRIGHT('...')
;
// D*-********************************************************************
// D*-* SDS宣言 **
// D*-********************************************************************
// https://www.ibm.com/docs/ja/i/7.5?topic=exceptionerrors-program-status-data-structure
DCL-DS *N PSDS;
S#PGM *PROC ; //プログラム名
S#STS *STATUS ; //状況コード
S#ROUTINE *ROUTINE ; //ルーチン名
S#JOB CHAR(10) POS(244) ; //ジョブ名
S#USER CHAR(10) POS(254) ; //ユーザー名
S#JNBR ZONED(6:0) POS(264) ; //ジョブ№
END-DS;
// D*-********************************************************************
// D*-* 変数等宣言 **
// D*-********************************************************************
DCL-S W#RTN CHAR(040 ) ; //結果
// C*-********************************************************************
// C*-* メインルーチン **
// C*-********************************************************************
W#RTN = SUBPROC1(99999 ) ;
DSPLY W#RTN ;
W#RTN = SUBPROC1(90000 ) ;
DSPLY W#RTN ;
*INLR = *ON ;
RETURN ;
// P*-********************************************************************
// P*-* サブプロシージャ(1) **
// P*-********************************************************************
DCL-PROC SUBPROC1 ;
//インターフェース
DCL-PI *N CHAR(001 ) ; //S=成功、E=失敗
IN_CODE PACKED(005 :000) VALUE ; //コード
END-PI;
// F*-*******************************************************************
// F*-*ファイル宣言 **
// F*-*******************************************************************
DCL-F ITEM KEYED USAGE(*UPDATE : *OUTPUT ) ;
DCL-DS R#ITEMR LIKEREC(ITEMR :*ALL ) ;
DCL-DS K#ITEM LIKEREC(ITEMR :*KEY ) ;
// D*-********************************************************************
// D*-* 変数等宣言 **
// D*-********************************************************************
DCL-S W#MSG CHAR(040 ) ; //メッセージ
DCL-S W#ZERO PACKED(003 :000 ) ;
DCL-S W#NOMON IND ; //*ON=監視なしの終了
DCL-S W#PGM1 CHAR(010 ) ; //プログラム名
DCL-S W#PROC1 CHAR(040 ) ; //プロシージャ名
DCL-S W#PROC2 CHAR(040 ) ; //プロシージャ名
DCL-S W#PROC3 CHAR(040 ) ; //プロシージャ名
//プログラム名取得
W#PGM1 = S#PGM ;
//サブプロシージャ名取得
W#PROC1 = %PROC() ;
//サブロジック
K#ITEM.CODE = IN_CODE ;
MONITOR ;
CHAIN %KDS(K#ITEM :01 ) ITEMR R#ITEMR ;
IF %FOUND ;
WRITE ITEMR R#ITEMR ;
ENDIF ;
ON-ERROR *ALL ;
W#MSG = '[ERROR:*ALL]'
+ %CHAR(%STATUS )
+ '*ALL監視エラー' ;
DSPLY W#MSG ;
RETURN 'E' ;
ENDMON ;
W#ZERO = *ZERO ;
W#ZERO = 100 / W#ZERO ;
RETURN 'S' ;
//必ずサブプロシージャで通過する終了処理
ON-EXIT W#NOMON ;
//ON−EXITを実装実行しているサブプロシージャ名
W#PROC2 = %PROC(*ONEXIT ) ;
//ON−EXITの実装呼び出し元サブプロシージャ名(※このソース)
W#PROC3 = %PROC(*OWNER ) ;
W#MSG = '[S#PGM][S#ROUTINE]'
+ %TRIM(S#PGM )
+ ' ' + S#ROUTINE ;
DSPLY W#MSG ;
W#MSG = '[W#PROC1]'
+ %TRIM(W#PGM1 )
+ ' ' + W#PROC1 ;
DSPLY W#MSG ;
W#MSG = '[W#PROC2]'
+ %TRIM(W#PGM1 )
+ ' ' + W#PROC2 ;
DSPLY W#MSG ;
W#MSG = '[W#PROC3]'
+ %TRIM(W#PGM1 )
+ ' ' + W#PROC3 ;
DSPLY W#MSG ;
IF %FOUND(ITEM ) ;
UNLOCK ITEM ;
W#MSG = '[UNLOCK]'
+ 'レコードロック解放' ;
DSPLY W#MSG ;
ENDIF ;
W#MSG = '[EXIT]'
+ '全ての処理が通過する'
+ %CHAR(W#NOMON ) ;
DSPLY W#MSG ;
//監視外の例外が発生している場合
IF W#NOMON ;
//ログなど...
RETURN 'E' ;
ENDIF ;
END-PROC;
以下変数は、それぞれサンプルプログラムにおいて別のタイミングやパラメータで %PROC関数
を用いてプロシージャ名を取得しています。
変数名 | 取得タイミングやパラメータ |
---|---|
W#PROC1 | サブプロシージャの本体ルーチンで %PROC()
|
W#PROC2 | サブプロシージャのON-EXITルーチンで %PROC(*ONEXIT)
|
W#PROC3 | サブプロシージャのON-EXITルーチンで %PROC(*OWNER)
|
プログラムを実行すると次の結果が得られます。
実行結果を考察
W#PROC1 は、サブプロシージャの本体ルーチンで %PROC()
を実行しているのでプロシージャ名である SUBPROC1 が返されます。これは従来より可能でした、次からは新しく実装された機能になります。
W#PROC2 は、サブプロシージャの ON-EXIT
で %PROC(*ONEXIT)
を実行しているので、実際に ON-EXIT
を処理しているプロシージャ名である _QRNI_ON_EXIT_SUBPROC1 が返されます。通常このプロシージャ名を我々開発者は特に意識していません。
W#PROC3 は、サブプロシージャの ON-EXIT
で %PROC(*OWNER)
を実行しているので、ON-EXIT
の呼び出し元プロシージャ名である SUBPROC1 が返されます。これは我々開発者が意識しているプロシージャ名です。
ON-EXIT
内の一般的なログの収集等に使われるプロシージャ名は %PROC(*OWNER)
になるでしょう。
ここからは想像ですが、ソースコード内に ON-EXIT
を実装したプロシージャが存在すると、ILE コンパイラーは ON-EXIT
以下を部分的に抜き出し、つづいてその内容を必須処理ルーチンとした別プロシージャ _QRNI_ON_EXIT_プロシージャ名 を自動生成しているのでは?と考えてます。
実際に DSPPGM PGM(Q242101R)
コマンドで確認すると、ON-EXIT
なしとありではプロシージャ数に1つ分の違いがあらわれます。
モジュールのプロシージャの建付けは以下の様な感じでしょうか?本来フラットな筈のサブプロシージャに ON-EXIT
だけは階層があるように見えます。
メインプロシージャ(Q242101R)
└ サブプロシージャ(SUBPROC1)*OWNER
└ ON-EXIT プロシージャ(_QRNI_ON_EXIT_SUBPROC1)*ONEXIT
複数のプロシージャで ON-EXIT
を実装したり何パターンか試してみましたが、ちゃんと ON-EXIT プロシージャ が孫階層的になっており、変数スコープも維持されておりました。面白いですね (^^)
ILE 内部では変数スコープ維持を頑張っているのか?それとも3段目の特別なプロシージャとなっているのか?新しい機能のそれ自体にも興味がありますが、それがどう実装されているのか?想像するのもまた技術者としては楽しいです。RPG は日々進化しています!