【実務・中級編】ZERODIVIDE条件の発生原因とONユニット制御 – PL/Iの基本構文とデータ制御実践ガイド

メインフレームの墓場から救い出す:PL/Iにおける「ZERODIVIDE」との正しい付き合い方

やあ、今日も深夜のバッチジョブと格闘している諸君。IBMメインフレームの世界へようこそ。
コードの海を漂っていると、時折出会うのが「ABEND S0CB」という名の悪魔だ。そう、ゼロ除算だ。PL/Iで開発をしていると、コンパイラの親切心(あるいは冷酷さ)によって `ZERODIVIDE` 条件として検知される。

今日は、若手エンジニアがよくやりがちな「とりあえずONユニットで隠蔽する」という悪癖を直し、本物のシステムアーキテクトが現場でどう例外を制御しているのか、その勘所を伝授しよう。

1. なぜ「ゼロ除算」はシステムを止めるのか

PL/Iの `OPTIONS(MAIN)` プロシージャにおいて、除算演算子 `/` を使った際、右オペランドが「0」である場合、システムは `ZERODIVIDE` 条件を発生させる。

ここで重要なのは、「なぜそのデータが来たのか」というビジネスロジックの欠落を、プログラムが身を挺して訴えているという事実だ。単に「止まればいい」わけではない。VSAMファイルから読み込んだ売上データがゼロだったのか、あるいは集計計算のループ変数が初期化漏れを起こしていたのか。

現場で一番やってはいけないのは、何も考えずに `ON ZERODIVIDE BEGIN; … END;` を記述して、プログラムを無理やり続行させることだ。それは「熱が出たから解熱剤を飲んで無理やり出社する」のと同じで、のちに「集計結果が合わない」という、もっと恐ろしい障害を引き起こす。

2. 実践的なONユニット制御の流儀

例外処理は、「回復可能か、さもなくば潔く止まるか」の二択であるべきだ。以下に、現場で使える堅牢なコーディング例を示す。

/i
MAIN_PROC: PROCEDURE OPTIONS(MAIN);

/ 宣言部 /
DCL DIVIDEND FIXED DEC(15,2);
DCL DIVISOR FIXED DEC(15,2);
DCL RESULT FIXED DEC(15,2);

/ ZERODIVIDE発生時のハンドリング定義 /
ON ZERODIVIDE
BEGIN;
PUT SKIP LIST(‘ ERROR: ゼロ除算が発生しました。計算をスキップします ‘);
/ ここでログを出力し、カウンターをインクリメントし、処理を継続する /
RESULT = 0;
GOTO CALC_CONTINUE;
END;

/ 計算ロジック /
DIVIDEND = 1000.00;
DIVISOR = 0.00; / ここでゼロ除算が発生 /

RESULT = DIVIDEND / DIVISOR;

CALC_CONTINUE:
PUT SKIP LIST(‘RESULT IS: ‘ || RESULT);

/ プログラム終了 /
RETURN;

END MAIN_PROC;

ポイント解説

  • GOTOの活用: ONユニット内からの脱出には `GOTO` が最も確実だ。スタックを巻き戻すよりも、制御フローを明確にする。
  • ONユニットの有効範囲: プログラムの冒頭で宣言すればモジュール全体をカバーできるが、特定の計算ブロックだけで有効にしたい場合は、`BEGIN; … END;` ブロック内で `ON ZERODIVIDE` を定義し、終了後に `REVERT ZERODIVIDE;` を呼ぶのが通のやり方だ。

3. デバッグの現場から:VSAMアクセスとの絡み

実務で一番厄介なのは、VSAMから読み取った値が「空白」であったり「予期せぬ値」であったりして、それが計算時にゼロとして扱われてしまうケースだ。

`FIXED DEC`(パック十進数)を扱う際、空白が含まれていると `CONVERSION` 条件も併発する。もし君が保守担当なら、除算の前に必ず `IF` 文でガードを入れることを忘れるな。

/i
/ 安全な計算のためのガードロジック /
IF DIVISOR ^= 0 THEN
RESULT = DIVIDEND / DIVISOR;
ELSE
DO;
/ ビジネス上の異常検知としてログ出力 /
CALL LOG_ERROR(‘INVALID DIVISOR DETECTED: ‘ || DIVISOR);
RESULT = 0;
END;

4. ベテランからのアドバイス

いいかい、メインフレームのバッチ処理において、最も避けるべきは「原因不明のまま落ちる」ことだ。

1. システムログ(SYSOUT)を信じるな: ユーザーはログを見ない。`ON ZERODIVIDE` の中には、必ず「どのキーのデータで」「どの計算式で」失敗したかを特定できる情報を書き出せ。
2. BUILTIN関数を活用せよ: `ABS` や `TRUNC` など、PL/Iには強力な組み込み関数がある。特に数値の精度(Precision)が意図通りか、コンパイルリストの属性を常に確認する癖をつけろ。
3. レガシーを恐れるな: 30年前のソースコードであっても、PL/Iの論理は変わらない。ルールを守って書けば、それはどんな最新言語よりも安定して動く最強のコードになる。

PL/Iは、書き手を選り好みする「気難しい言語」かもしれない。だが、その厳格さこそが、金融や流通の基幹システムを支え続けてきた理由だ。恐れず、しかし慎重に。今日も素晴らしいバッチ処理を。

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