【実務・中級編】JCL PARM引数と固定小数点数 – PL/Iの基本構文とデータ制御実践ガイド

こんにちは。メインフレームの現場で、日々COBOLやPL/Iの巨大なソースコードと格闘している同志の皆さん。
今日は、JCLの`PARM`引数として渡された「文字データ」を、PL/Iプログラム内で`FIXED`(固定小数点数)型に安全に受け渡し、バリデーションとエラーハンドリングを行う方法について、実務のノウハウを交えて徹底的に解説しよう。

夜間バッチの真っ最中に、オペレータから「コンソールにS0C7(あるいはPL/I特有のIBM製異常終了コード)が出てジョブが落ちました!」と叩き起こされた経験はないだろうか? その原因の多くは、JCLの変更漏れや誤ったパラメータ指定、そしてプログラム側での甘い型変換とバリデーション不足にある。

今回は、この古典的かつ極めて重要なテーマについて、ベテランの視点から「二度と夜中に呼ばれないための鉄壁のコード」を伝授する。

—

1. JCL PARM引数とFIXED型の落とし穴

JCLの`EXEC`ステートメントで指定する`PARM`は、純粋な文字ストリング(CHARACTER)としてプログラムに渡される。例えば、`PARM=’12345’`と書かれていれば、それは数値ではなく「文字の ‘1’, ‘2’, ‘3’, ‘4’, ‘5’」の集まりだ。

これをPL/Iのプログラム側で計算や条件判定に使うために `FIXED BINARY` や `FIXED DECIMAL` に暗黙的、あるいは安易に明示的変換しようとすると、次のような罠にハマる。

  • 半角スペースや数値以外の混入: `PARM=’1234 ‘` や `PARM=’123A5’` のようなゴミデータが混ざったとき、そのまま代入するとコンバージョンエラー(IBMメインフレームでは `IBM0221S` や `IBM0223S` などのシグナル)が発生する。
  • 桁あふれ(Overflow): パラメータが想定以上の長さを持ち、受け側の`FIXED`の精度を超えた場合、上位桁が切り捨てられて予期せぬデータ破損を招く。

ここで、PL/Iの強力なメカニズムである `ON-unit`(例外処理機構) と ビルトイン関数(`VERIFY`, `CFIXED`など) を組み合わせた、実務標準の防御的プログラミングを見ていこう。

—

2. 実践PL/Iソースコード解説

以下に、JCLからのパラメータを受け取り、厳密なバリデーションを行った上で `FIXED BINARY(31)` として安全に処理するサンプルプログラムを示す。すべて大文字のIBMメインフレーム標準スタイルで記述している。

1
PARMPRC: PROC OPTIONS(MAIN);

/————————————————————–/
/ 宣言部 /
/————————————————————–/
/ JCLからのPARMを受け取るための外部記述変数 /
DCL 1 PARM_AREA,
5 PARM_LEN ALARM FIXED BIN(15), / パラメータ長 /
5 PARM_TEXT CHAR(100); / パラメータ本体 /

/ 内部処理用の固定小数点数(31ビット符号付き) /
DCL WK_LIMIT_VAL FIXED BIN(31) INIT(0);

/ ワーク用文字変数 /
DCL WK_STR CHAR(10);
DCL WK_POS FIXED BIN(15);

/ フラグ変数 /
DCL FLG_ERROR BIT(1) INIT(‘0’B);

/————————————————————–/
/ ON-unit宣言: データ変換エラーの捕捉 /
/————————————————————–/
ON CONVERSION BEGIN;
DISPLAY(‘ SEVERE ERROR: CONVERSION EXCEPTION OCCURRED ‘);
DISPLAY(‘INVALID CHARACTER IN JCL PARM. CHECK EXEC STATEMENT.’);
FLG_ERROR = ‘1’B;
GOTO PARM_ERR_EXIT;
END;

/————————————————————–/
/ メイン処理ロジック /
/————————————————————–/
/ 1. パラメータの取得(FETCH/GETではなく特殊変数PARMを使用) /
GET FILE(SYSIBN) PARM(PARM_TEXT); / ※処理系により取得方法は異なりますが /
/ 一般的にはPROCの引数として受け取ります: /
/ PARMPRC: PROC(DUMMY_PARM) OPTIONS(MAIN); のスタイルも主流です /

/ 今回は分かりやすく標準的なメインプロシージャ引数スタイルで説明 /

/ ※実務では PROC(P_PARM) OPTIONS(MAIN); DCL P_PARM CHAR(100) VARYING; が一般的 /

DISPLAY(‘RECEIVED PARM LENGTH: ‘ || TRIM(CHAR(PARM_LEN)));
DISPLAY(‘RECEIVED PARM TEXT: [‘ || PARM_TEXT || ‘]’);

/ 2. 基本長チェック(空パラメータや長すぎないかの確認) /
IF PARM_LEN = 0 | PARM_LEN > 8 THEN DO;
DISPLAY(‘ ERROR: PARM LENGTH IS INVALID. (1 TO 8 BYTES REQUIRED) ‘);
GOTO PARM_ERR_EXIT;
END;

/ 有効な長さに切り出し /
WK_STR = SUBSTR(PARM_TEXT, 1, PARM_LEN);

/ 3. バリデーション: 数字以外の文字が含まれていないか VERIFY で検証 /
/ VERIFY(string, match) は、matchに含まれない文字の位置を返す。 /
/ 0が返れば、すべてmatch(この場合は数字)で構成されている証拠。 /
WK_POS = VERIFY(WK_STR, ‘0123456789’);

IF WK_POS ^= 0 THEN DO;
DISPLAY(‘ ERROR: NON-NUMERIC CHARACTER FOUND AT POSITION: ‘
|| TRIM(CHAR(WK_POS)) || ‘ ‘);
GOTO PARM_ERR_EXIT;
END;

/ 4. 安全に FIXED BINARY へ変換 /
/ ここまでのチェックを通過しているため、CONVERSION例外は起きないはず /
WK_LIMIT_VAL = WK_STR;

DISPLAY(‘SUCCESS: CONVERTED FIXED BINARY VALUE = ‘ || TRIM(CHAR(WK_LIMIT_VAL)));

/ 通常の業務処理へ続く… /
GOTO NORMAL_EXIT;

PARM_ERR_EXIT:
/ 異常終了処理 /
DISPLAY(‘ JOB TERMINated ABNORMALLY DUE TO PARM ERROR ‘);
CALL PLIRETC(16); / リターンコード16を返して異常終了 /
STOP;

NORMAL_EXIT:
RETURN;

END PARMPRC;

—

3. アーキテクトが教えるコードの急所とテクニック

上記のコードには、何十年ものメインフレーム運用の歴史から導き出された「現場の知恵」が詰まっている。特に注目してほしいポイントを解説しよう。

① `VERIFY` ビルトイン関数の圧倒的優位性

文字データを `FIXED` 型へ代入する前に、`VERIFY(WK_STR, ‘0123456789’)` を通している点に注目してほしい。
PL/Iの `VERIFY` は、第1引数の文字列の中で、第2引数に含まれていない文字が最初に出現する位置(インデックス)を返す。すべて数字であれば `0` を返すため、これだけで「純粋な数字文字列であるか」の判定が1発で終わる。IF文で1文字ずつループを回して `IF CH < '0' | CH > ‘9’` なんてコードを書いている古臭いプログラムを見かけたら、今すぐこのビルトイン関数に書き換えさせよう。

② `ON CONVERSION` による二重の防御

どんなに事前チェックを厳重にしても、JCLの記述ミスやコンパイラの仕様変更、思わぬメモリエラーなどにより予期せぬデータが流れ込むリスクはゼロにはならない。
PL/Iには `ON CONVERSION` という強力な例外処理(ONユニット)がある。万が一、型変換時にハードウェアレベルでのデータ例外が発生しても、プログラムが即座に強制終了(S0C7など)するのを防ぎ、自前のエラーハンドリング(今回はエラーメッセージを出して `PLIRETC(16)` で安全にジョブを落とす)に制御を回収できる。
「異常な入力でプログラムを急死させず、ログを残して綺麗に終わらせる」 これが基幹系バッチの鉄則だ。

③ `FIXED BINARY(31)` の選択

メインフレーム(z/OS)のアーキテクチャ上、演算器の効率やCOBOLの `COMP`(S9(9) COMPUTATIONAL)との親和性を考慮すると、数値項目は `FIXED BINARY(31)`(フルワード)または `FIXED DECIMAL` を選択するのが最も安全かつ高速だ。
文字型から数値型へ代入する際、PL/Iコンパイラは適切な内部変換ルーチンを生成するが、その前提として「データが正しい形式であること」をプログラマが担保する責務がある。

—

おわりに

レガシーシステムのマイグレーションや保守において、JCLやパラメータ周りの仕様変更は最もデグリー(不具合)を生みやすいブラックボックスの一つだ。

「動けばいいや」と型変換をコンパイラ任せにするコードは、いつか必ず深夜のトラブルを引き起こす。
今回紹介した `VERIFY` による事前バリデーションと、`ON CONVERSION` による例外キャッチの二段構えをマスターすれば、JCLのPARM起因のトラブルは完全に根絶できる。

明日からのコーディング、そしてコードレビューの際に、ぜひこの知見を役立ててほしい。質問や「うちの現場ではこうしている」といった意見があれば、いつでも声をかけてくれ。

タイトルとURLをコピーしました