PL/Iの「SIZE」条件が暴く、基幹システムの静かなる崩壊
メインフレームの現場で長く生きていると、「計算結果が合わない」という相談を何度受けたか分からない。多くの場合、犯人は演算エラーではなく、PL/Iのコンパイラが「見なかったことにしてくれた」数値の切り捨てだ。
特に、`FIXED DECIMAL`の桁あふれを無視して突き進むレガシーコードは、マイグレーションにおける最大の爆弾となる。今回は、PL/Iが持つこの「見て見ぬふり」の仕様をどう封じ込め、現代的なシステムへと安全に橋渡しするか、アーキテクトの視点で深掘りする。
—
SIZE条件はなぜデフォルトで「無効」なのか
PL/Iには`SIZE`という条件がある。演算の結果が格納先の変数の精度(桁数)を超えた場合、この条件を有効(`ON`)にしていれば割り込みが発生し、制御をハンドラに移せる。
しかし、多くの現場のソースコードでは、`PROCEDURE`の先頭に`DEFAULT(NOSIZE)`が明示的、あるいは暗黙的に置かれている。なぜか? 理由は単純だ。メインフレームの貴重なCPUサイクルを、桁あふれのチェックに浪費したくないからだ。
しかし、これが命取りになる。特に、外部インターフェースからのデータや、DB2から取得した値を演算する際、想定外の桁あふれが起きると、上位桁が問答無用で切り捨てられ、システムは「正しい顔をして」誤った計算結果を後続処理へ流し続ける。
SIZE条件を有効にするための実践的アプローチ
単に`ON SIZE`を記述するだけでは不十分だ。コンパイラオプションと、エラー処理の設計が肝になる。
/ メインプログラムの構造とSIZE条件の監視 /
MY_PROGRAM: PROCEDURE OPTIONS(MAIN);
/ SIZE条件を有効にするための宣言 /
ON SIZE BEGIN;
PUT SKIP LIST(‘!!! 重大な数値オーバーフローを検知しました !!!’);
/ ここでダンプを取得するか、後続のDB2処理をロールバックする /
CALL DUMP_ERROR_STATE;
STOP;
END;
DCL A FIXED DEC(5,0) INIT(99999);
DCL B FIXED DEC(5,0) INIT(2);
DCL C FIXED DEC(5,0);
/ 本来なら199998となり、5桁のAには収まらない /
/ NOSIZEであれば、上位桁が捨てられ 99996 になる等の悲劇が起きる /
C = A B;
/ 正常終了 /
PUT SKIP LIST(‘計算結果:’, C);
END MY_PROGRAM;
マイグレーションの現場で直面する「負の遺産」
JavaやC#への移行を検討する際、このPL/Iの「適当さ」をどう扱うかがアーキテクトの腕の見せ所だ。
1. パックデシマル(COMP-3)の内部符号問題:
PL/Iの`FIXED DEC`は、メモリ上でパックデシマル形式をとる。稀に、データ転送の不備で符号部分(最下位ニブル)が`0x0F`(正)ではなく`0x0C`や`0x0D`、あるいは不正な値になっている場合がある。これに演算を加えると、PL/Iは稀に奇妙な挙動を示す。移行先では`BigDecimal`などの厳格なクラスを使うことになるが、PL/I側の「曖昧な符号」をどう正規化するかのマッピング定義を怠ると、マイグレーション後に「なぜか合計金額が合わない」という地獄を見る。
2. ポインタとベース変数によるメモリ破壊:
`BASED`変数を使用して動的にメモリを確保するコードでは、`SIZE`条件以前に、配列外参照が境界を越えて他の変数を汚染することがある。ダンプ解析を行う際、`SIZE`によるアベンドなのか、`S0C4`(保護違反)なのか、あるいは計算結果の不整合なのかを切り分けるために、コンパイラオプション `TEST` や `LIST` を駆使し、メモリマップと突き合わせる泥臭い作業が不可欠だ。
アーキテクトへの提言:現代的な解への変換
もしあなたが今、PL/Iコードを別の言語へ書き換えているなら、以下の戦略を強く推奨する。
- 「隠れた切り捨て」を「明示的な例外」へ:
移行先では、数値演算時に「桁あふれ(Overflow)」が発生した際、必ず例外を投げるように設計せよ。PL/Iの古い習慣を移植してはいけない。
- 境界値テストの自動化:
PL/Iの`FIXED DEC(P, Q)`の定義を一つずつ洗い出し、最大値・最小値の境界テストを自動生成するツールを噛ませるべきだ。特にDB2の`DECIMAL`型との互換性チェックは必須である。
最後に:技術の継承について
PL/Iを扱うことは、コンピュータの計算の根源と向き合うことだ。コンパイラが裏でどのような命令(`AP`命令や`SP`命令など)を生成しているのかを知ることで、初めて「なぜそこで落ちるのか」が理解できる。
「動いているから触らない」というレガシーの掟は、マイグレーションという機会においてのみ破棄できる。SIZE条件をあえて有効にし、コードの深淵を覗くこと。それが、次の世代のシステムを堅牢にするための第一歩となる。
技術的な悩みや、特定のモジュールでのダンプ解析に行き詰まっているなら、いつでも議論しよう。メインフレームの深淵は、まだもう少しだけ、我々の知識を必要としているようだ。
