【テクニカル・上級編】ON ZERODIVIDEによるゼロ除算のトラップ – PL/Iの基本構文とデータ制御実践ガイド

ゼロ除算の罠:PL/IのONユニットが守る基幹システムの「生存戦略」

メインフレームの現場で何十年と稼働し続けるPL/Iプログラム。そのコードを読み解いていると、たまに若手エンジニアが「なぜこんな冗長なエラー処理を?」と首を傾げる箇所に出くわす。その筆頭が `ON ZERODIVIDE` だ。

最近のJavaやC#の感覚でいれば、例外はキャッチしてログを吐けば終わりかもしれない。だが、我々が扱う汎用機のバッチ処理において、単純なアベンド(ABEND)は「システムの死」を意味する。数千万件のトランザクションが飛び交うバッチプロセスにおいて、たった一度のゼロ除算で全ジョブがロールバックされる事態は、何としても避けねばならない。

今回は、PL/Iにおける `ON ZERODIVIDE` の実務的な活用と、そこから派生するメモリ操作や移行設計の深淵について語ろう。

1. 「ON ZERODIVIDE」による動的なリカバリ設計

まず、典型的な構造を確認しよう。`OPTIONS(MAIN)` で定義されたメインプロシージャの中に、例外ハンドラのスコープを適切に定義することが肝要だ。

/i
MAIN_PROC: PROCEDURE OPTIONS(MAIN);

/ ゼロ除算発生時のリカバリ処理 /
ON ZERODIVIDE BEGIN;
PUT SKIP LIST (‘警告: ゼロ除算を検知。計算値をゼロに補正して継続します。’);
/ ここで変数を安全な値にリセットし、フローを継続させる /
RESULT_VAL = 0;
GOTO RESUME_POINT;
END;

/ 処理ロジック /
CALC_LOOP: DO I = 1 TO MAX_COUNT;
RESULT_VAL = TOTAL_AMOUNT / DIVISOR_ARRAY(I);

RESUME_POINT: ; / ここに復帰する /
/ 続きのロジック /
END CALC_LOOP;

END MAIN_PROC;

ここで重要なのは、`GOTO` を使った復帰だ。PL/Iの `ON` ユニットは、正常終了後に呼び出し元へ戻ることも可能だが、演算例外の場合は計算結果が未定義(または不定)になるため、このように復帰ポイントを明示的に制御する設計が、基幹システムでは「正義」となる。

2. ポインタと動的メモリ操作の闇

もし君がマイグレーションを控えたアーキテクトなら、この `ON` ユニット内で「動的メモリ」を操作する際の危険性に気づかなければならない。`BASED` 変数を使用して `ALLOCATE` されたメモリ領域に対し、計算エラー時に不完全なポインタ参照を行えば、演算例外以上に厄介な `S0C4`(保護例外)を誘発する。

CICS環境下でこの現象が起きると、タスクがハングアップし、DSA(Dynamic Storage Area)が汚染される。ダンプを解析した際、`ZERODIVIDE` の `PSW`(プログラムステータスワード)が指し示す先と、現在のポインタ値が乖離している場合、それは往々にして「メモリの食い合い」が発生している証拠だ。

3. パックデシマル(FIXED DECIMAL)の罠

PL/Iの `FIXED DECIMAL` は、COBOLの `COMP-3` と同様、内部的にはパックデシマルとして保持される。ここで厄介なのが、符号の不整合だ。

DB2からフェッチした値が、稀に無効な符号(X’0C’以外など)を持っていて、それが除算時に `SOC7`(データ例外)を吐くことがある。`ON ZERODIVIDE` だけでは捕まえられない。我々ベテランは、必ず `ON FIXEDOVERFLOW` や `ON CONVERSION` もセットで記述する。特に、DB2の埋め込みSQLで `NULL` 値を直接算術演算に回すような「うっかりミス」は、マイグレーション時にJavaの `BigDecimal` への変換で最もバグを産む箇所だ。

4. コンパイラ最適化と「予期せぬ挙動」

`OPTIMIZE(3)` などの高い最適化オプションを付与すると、コンパイラは「ゼロ除算は絶対に起きない」という前提でコードを再構成することがある。例えば、条件分岐の評価順序を入れ替えてしまい、防御的なチェックがスキップされるケースだ。

移行の際、古いコンパイラ(OS/PL/Iなど)から現行の `Enterprise PL/I` に移行すると、この最適化挙動の差異で、「昔はエラーにならなかったのに、今はアベンドする」という現象が多発する。これこそが、ブラックボックス化されたコードを解読する際に、アーキテクトが最も恐れる瞬間だ。

結論:レガシーは「生き物」である

PL/Iのプログラムを単なる文字列としてJavaへ書き換えることは、誰にでもできる。しかし、PL/Iが持つ「演算例外をハンドリングし、システムを止めずに最後までやり抜く」という生存本能のような設計思想を、いかにターゲット言語で再現するか。

`ON ZERODIVIDE` は、単なるコードの一行ではなく、システムが異常事態に直面した際の「最後の砦」だ。君たちがこれから挑むマイグレーションにおいても、この「異常時にどう振る舞うか」という哲学だけは、決して見失わないでほしい。

コードは嘘をつかない。しかし、コンパイラとハードウェアの背後にある「意図」を読み解ける者だけが、真のシステムアーキテクトと呼べるのだ。

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