【実務・中級編】ON ZERODIVIDE条件による算術例外のトラップ – PL/Iの基本構文とデータ制御実践ガイド

現場の知恵:PL/Iにおけるゼロ除算(ZERODIVIDE)の「お作法」とABEND回避術

メインフレームの現場で長年PL/Iを扱っていると、必ず一度は遭遇するのが「S0CB」の恐怖だ。特に、何万件というレコードを処理するバッチプログラムの最中、計算ロジックの一箇所でゼロ除算が発生し、ジョブが異常終了(ABEND)して深夜の呼び出しを食らう……。そんな苦い経験を持つエンジニアも少なくないだろう。

今回は、PL/Iにおいて「なぜ予約語が存在しないのか」という言語の懐の深さに触れつつ、`ON ZERODIVIDE`条件を用いた、現場で使える堅牢な例外処理の実装テクニックを伝授する。

1. PL/Iの識別子と「予約語がない」という思想

PL/Iの面白いところは、言語仕様として「予約語」という概念が存在しないことだ。例えば、`IF`や`THEN`、`GOTO`といったキーワードを、そのまま変数名として使うことが文法上は許されている。

しかし、これは「やっても良い」ことと「やるべき」ことの境界線を見極めなければならないという、シニアレベルの判断を要求する仕様でもある。可読性を損なうような変なコードを書けば、後任の担当者が悲鳴を上げることになる。コンパイラはコンテキストを高度に解析して「これはキーワードか、それとも変数か」を判断している。この柔軟性こそ、PL/Iが長年メインフレームの世界で生き残ってきた理由の一つだ。

2. ZERODIVIDEを「事故」で終わらせないために

算術例外、特にゼロ除算はデータ品質に依存する。入力データがクレンジングされておらず、単価が0のまま計算ロジックに流れてくると、容赦なくS0CBが発生する。

ここで重要になるのが `ON ZERODIVIDE` ユニットだ。これを使うことで、システムデフォルトの「即死(ABEND)」を回避し、プログラム側でリカバリ処理を行うことが可能になる。

実践的実装サンプル

以下のコードは、VSAMファイルを読み込み、計算処理を行うバッチ処理のひな形だ。重要なのは、`ON`ユニットでトラップを張り、エラー発生時のフラグを立てて処理を継続させる点にある。

/i
/——————————————————————-/
/ PL/I ZERODIVIDE トラップ実装サンプル /
/——————————————————————-/
CALC_PROC: PROC OPTIONS(MAIN);

DCL WS_DIVIDEND FIXED DEC(15,2);
DCL WS_DIVISOR FIXED DEC(15,2);
DCL WS_RESULT FIXED DEC(15,2);
DCL ERR_FLG BIT(1) INIT(‘0’B);

/ ZERODIVIDE発生時の挙動を定義 /
ON ZERODIVIDE BEGIN;
PUT SKIP LIST(‘ WARNING: ZERODIVIDE DETECTED. SKIPPING RECORD ‘);
ERR_FLG = ‘1’B; / エラーフラグを立てて復帰 /
END;

/ メイン処理ループ(VSAM読み込みを想定) /
DO UNTIL(EOF_FLG);
ERR_FLG = ‘0’B;

/ ここで計算を実行 /
WS_RESULT = WS_DIVIDEND / WS_DIVISOR;

/ エラーがなければ後続処理 /
IF ^ERR_FLG THEN DO;
/ 正常時の処理(DB更新やVSAM出力など) /
CALL WRITE_DATA(WS_RESULT);
END;
ELSE DO;
/ エラー時はレコードを飛ばすかログを残す /
CALL LOG_ERROR(‘CALCULATION FAILED’);
END;
END;

END CALC_PROC;

3. 実務で知っておくべき「ONユニット」の注意点

コードを見て「これで完璧だ」と思ったかもしれないが、現場のシニアエンジニアとしていくつか釘を刺しておきたい。

  • ONユニットのスコープ: `ON`ユニットは、実行中のブロックおよび呼び出し先(サブプロシージャ)に対しても有効だ。どこでエラーが起きても良いように、メインの初期化部分で定義しておくのが一般的だが、局所的に挙動を変えたい場合は`REVERT`ステートメントを活用して、適切に制御を戻すことを忘れてはいけない。
  • 非力なデバッグを避ける: `ON`ユニット内で`DISPLAY`や`PUT`を使うと、大量の例外が発生した際にログが爆発してジョブが遅延する。運用保守の観点からは、エラー発生回数をカウンタで保持し、閾値を超えたら「異常終了」するように組むのがプロの矜持だ。
  • BUILTIN関数の活用: 今回は単純な除算だったが、浮動小数点や複雑な計算を行う際は、`DIVIDE`組み込み関数を使うことで、より厳密な精度制御と桁あふれ(FIXEDOVERFLOW)のハンドリングが可能になる。

まとめ:防御的プログラミングのすすめ

メインフレームのバッチ処理において、最も避けるべきは「何が起きたかわからないままの異常終了」だ。`ON ZERODIVIDE`は、単なるエラー回避の手段ではなく、「例外をシステムの状態としてどう扱うか」という設計思想そのものである。

今回紹介した手法をベースに、皆さんの現場のコーディング標準に合わせて「エラーログの詳細度」や「リトライ制御」を肉付けしていってほしい。それができれば、どんな難解なレガシーシステムの改修も、怖れるに足りないはずだ。

困ったときはいつでも相談してくれ。PL/Iは古いが、その仕様にはまだまだ深遠な知恵が詰まっているのだから。

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