3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ILERPGAdvent Calendar 2024

Day 17

RPGLE %PROC のアップデート

Last updated at Posted at 2024-12-16

IBM i 7.5 - Enhancements timed with Technology Refresh 5 (TR5)
前に書いた記事 新命令ON-EXIT の中で %PROC関数(プロシージャの取得) が使えるようになったとのことなので試してみました。

関連リンク

TR導入

通常の手順で V7R5-TR5 を導入したのですが、今回のサンプルコードはコンパイルエラーとなってしまいました。該当のPTF番号を DSPPTF で確認してもやはり導入されておりませんでした。
今回TRの対象個別PTF SJ02921 ~ SJ02923 を個別オーダーし導入したら、動作するようになりましたので、TR5の導入でうまく行かない場合は個別を試してみて下さい。

スクリーンショット 2024-12-05 184927.png

【注意事項】SJ02921 を入れた際の

今回の %PROC とは直接関係ありませんが、TR5で案内されている SJ02921 - RPGLE-CMPL NEW DATEYY PARAMETER FOR CRTRPGMOD AND CRTBNDRPG の個別PTFを導入した場合は、コマンド CRTBNDRPGCRTRPGMOD の省略値を CHGCMDDFT で独自変更している場合はリセットされますので注意して下さい。私の環境も DBGVIEW(*ALL) としていたのですが、リセットされておりました。

%PROCのサンプルコード

以下が実際に ON-EXIT 内で %PROC で使用したサンプルコード例です。

RPGLE.Q242101R.RPGLE
**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)

プログラムを実行すると次の結果が得られます。

2024-12-17-01.png

実行結果を考察

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つ分の違いがあらわれます。

2024-12-17-02.png

2024-12-17-03.png

モジュールのプロシージャの建付けは以下の様な感じでしょうか?本来フラットな筈のサブプロシージャに ON-EXIT だけは階層があるように見えます。

.自動生成されたON-EXITルーチンの階層イメージ
 メインプロシージャ(Q242101R)
    └ サブプロシージャ(SUBPROC1)*OWNER
        └ ON-EXIT プロシージャ(_QRNI_ON_EXIT_SUBPROC1)*ONEXIT

複数のプロシージャで ON-EXIT を実装したり何パターンか試してみましたが、ちゃんと ON-EXIT プロシージャ が孫階層的になっており、変数スコープも維持されておりました。面白いですね (^^)
ILE 内部では変数スコープ維持を頑張っているのか?それとも3段目の特別なプロシージャとなっているのか?新しい機能のそれ自体にも興味がありますが、それがどう実装されているのか?想像するのもまた技術者としては楽しいです。RPG は日々進化しています!

3
0
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?