【実務・中級編】ON CONVERSION条件によるデータ型不一致の動的捕捉 – PL/Iの基本構文とデータ制御実践ガイド

「数値のはずがゴミデータ」でジョブが落ちる前に:PL/I `ON CONVERSION` で防衛的プログラミングを極める

メインフレームの現場で、バッチ処理中に突然 `IBM0231S ONCODE=301` というメッセージと共にジョブが異常終了(ABEND)し、冷や汗をかいた経験はないだろうか?

いわゆる「CONVERSION条件」。外部ファイル(VSAMやQSAM)から読み込んだ数値項目に、本来入っているはずのない空白や、誤った文字データが混入している際、PL/Iが「これ、数値として扱えないよ!」と悲鳴を上げる現象だ。

今日は、システムアーキテクトとして、この「データ不一致」をスマートにさばき、ジョブを無理やり落とすのではなく、安全にログを吐いて処理を継続させるための、PL/Iの実践的な流儀を伝授しよう。

1. なぜ CONVERSION 条件が発生するのか

PL/Iは厳格な言語だ。例えば、文字属性のフィールドから数値属性のフィールドへ値を代入(代入文や`READ`など)する際、コンパイラは内部的に「データ変換」を行う。この時、数値項目に数値以外の文字が混入していると、PL/Iの実行時環境は即座に例外を発生させ、デフォルトではジョブを終了させる。

特に、レガシーシステムのマイグレーションにおいて、データソースが他システムからの連携ファイルである場合、この「ゴミデータ問題」は避けて通れない。

2. ONユニットによる「動的捕捉」の基本

`ON CONVERSION` ユニットを使えば、変換エラーが発生した瞬間に制御を奪い取り、エラーログを出力して処理を続行(あるいはスキップ)させることが可能だ。

実践的なサンプルコード

以下に、レコード読み込み時にデータ不一致が発生しても、ジョブを止めずにエラー箇所を特定するコーディング例を示す。

/i
/ プログラムの基本構造 /
MAIN_PROC: PROCEDURE OPTIONS(MAIN);

/ 宣言部 /
DCL IN_RECORD CHAR(80); / 入力レコード /
DCL NUM_VAL FIXED DEC(5); / 数値項目として扱いたいフィールド /
DCL FILE_IN FILE RECORD INPUT;

/ ONユニットの定義:CONVERSIONが発生した時の挙動を定義する /
ON CONVERSION
BEGIN;
/ エラー箇所の特定とログ出力 /
PUT SKIP LIST(‘!!! データ変換エラー発生 !!!’);
PUT SKIP LIST(‘発生箇所: 数値項目に不正なデータが含まれています’);
PUT SKIP LIST(‘入力データの内容: ‘ || IN_RECORD);

/

  • ここで重要なのは「処理をどう継続するか」。
  • 本来はエラーレコードを別ファイルへ退避させる設計にすべきだ。

/
PUT SKIP LIST(‘当該レコードをスキップし、処理を継続します。’);
END;

OPEN FILE(FILE_IN);

DO WHILE(^EOF);
READ FILE(FILE_IN) INTO(IN_RECORD);

/

  • ここで代入が発生する瞬間にONユニットが発動する可能性がある。
  • SUBSTRで該当箇所を切り出して代入する設計が一般的。

/
NUM_VAL = SUBSTR(IN_RECORD, 1, 5);

/ 正常処理のロジックをここに記述 /
END;

CLOSE FILE(FILE_IN);
END MAIN_PROC;

3. 実務で「唸る」ための3つのポイント

単に `ON CONVERSION` を書くだけでは、プロフェッショナルとは言えない。以下の点を意識してほしい。

① ONユニット内での「再試行」は要注意

`ON CONVERSION` が発生した後、デフォルトのままでは同じ場所で無限ループに陥る可能性がある。エラーが発生したフィールドには「何らかのデフォルト値(0など)」を強引に代入して制御を戻すか、フラグを立てて処理をスキップする設計が鉄則だ。

② `DATAFIELD` ビルトイン関数の活用

`ON` ユニット内では `DATAFIELD` 関数を使うことで、実際に変換に失敗した「原因となったデータ」を即座に取得できる。
/i
PUT SKIP LIST(‘エラーの原因となった文字列: ‘ || DATAFIELD);

これを使うだけで、障害調査の工数は劇的に削減される。

③ そもそも「変換」させない設計(事前チェック)

ONユニットは強力だが、多用すると実行時のオーバーヘッドになる。頻繁に不正データが混入することが分かっている場合は、`VERIFY` 関数を使って、代入前に「数値のみで構成されているか」を事前にチェックする方が、アーキテクチャとしては遥かに健全だ。

/i
/ 事前チェックの例:5桁の数値か確認 /
IF VERIFY(SUBSTR(IN_RECORD, 1, 5), ‘0123456789’) ^= 0 THEN DO;
/ 数値以外が含まれている場合の独自エラーハンドリング /
END;

まとめ:現場のエンジニアへ

PL/Iの `ON` ユニットは、まさに「縁の下の力持ち」だ。大規模なバッチ処理において、たった1レコードのゴミデータで数時間のジョブを無駄にするのは、システムエンジニアとして避けたい事態である。

「プログラムは、データが汚れていることを前提に書け」。これが、数々の障害現場を乗り越えてきた私の哲学だ。ぜひ、次回の改修から `ON CONVERSION` を組み込み、堅牢なバッチプログラムを作成してほしい。

何か不明な点や、特定のレガシー環境での挙動について知りたいことがあれば、遠慮なく聞いてくれ。メインフレームの深淵は、まだまだ奥が深いぞ。

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