JavaやCOBOLの経験はあるけれど、IBMの汎用機(メインフレーム)やPL/Iの世界に足を踏み入れたばかりの皆さん、こんにちは!
「レガシーシステム」「メインフレーム」と聞くと、なんだか冷たくて近寄りがたい、間違えたらシステム全体が吹っ飛んでしまうような恐怖心を感じていませんか? 大丈夫です、安心してください。歴史ある言語であっても、一つひとつのルールを紐解いていけば、JavaやCOBOLと共通する思想がたくさん見えてきますよ。
さて、今回はPL/Iの数ある特徴的な機能の中から、「ON OVERFLOW条件と算術例外のハンドリング」をテーマにお届けします。
基幹システムのバッチ処理で、ある日突然、夜間バッチが異常終了(ABEND)し、膨大なダンプリストを前に途方に暮れる……そんなシチュエーションを回避するための知恵を、一緒に優しく学んでいきましょう!
—
1. PL/Iには「予約語」がない?(ちょっとした脱線話)
本題に入る前に、PL/Iのユニークな仕様を一つご紹介させてください。
JavaやCOBOLでは、`IF`や`MOVE`、あるいは`int`などの言語仕様で定められた単語(予約語)を、変数名として使うことはできませんよね。コンパイラに怒られてしまいます。
しかし、PL/Iには原則として予約語が存在しません。
例えば、以下のような宣言も、PL/Iのコンパイラは平然と受け入れます。
1
DCL IF FIXED BIN (31); / 変数名に 「IF」 を使っちゃう暴挙 /
「えっ、じゃあコンパイラはどうやって `IF` が条件分岐なのか、変数なのかを判断しているの?」と思いますよね。
PL/Iは、その「文脈(コンテキスト)」で判断しています。人間が会話の中で「財布の『財布』は名詞だな」と文脈で理解しているのと同じです。
……とはいえ、後からコードを読む開発者が発狂しかねないので、実際の現場では予約語っぽい名前を変数に使うのはタブーとされています。でも、「PL/Iは懐が深い言語なんだな」とちょっと親近感が湧きませんか?
—
2. 算術例外「OVERFLOW」とは何か?
さて、ここからが本題です。
金融や流通の基幹システムを扱っていると、売上金額や金利計算などで「数字の桁あふれ」に直面することがあります。
Javaの `int` 型がオーバーフローしたとき、あるいはCOBOLで `COMP-3` の定義桁数を超えたとき、言語や設定によってはそのまま処理が続行されて予期せぬゴミデータが生まれたり、即座に例外が発生したりしますよね。
PL/Iにおいても、定義された変数の精度(サイズ)の限界を超える値が算術演算の結果として生じた場合、`OVERFLOW`条件(例外)が発生します。
イメージしてみましょう
小さなコップ(精度の小さい変数)に、消防車のホースから放水されるような大量の水(大きすぎる計算結果)をドボドボと注ぎ込もうとしている状態です。コップから水があふれ出しますよね。これがオーバーフローです。
—
3. `ON OVERFLOW` で例外を「優しく」捕まえる
PL/Iの素晴らしいところは、この例外が発生したときに、プログラムが即座にクラッシュ(ABEND)するのを防ぎ、「もしあふれ出たら、こうしてね」というセーフティネット(割り込み処理)を自分で張れる点です。
実際のコードを見てみましょう。
1
DCL A FIXED DECIMAL(5,0) VALUE(99999);
DCL B FIXED DECIMAL(5,0) VALUE(1);
DCL RESULT FIXED DECIMAL(5,0);
/ OVERFLOWが発生したときの動きをあらかじめ定義する /
ON OVERFLOW BEGIN;
PUT SKIP EDIT (‘【警告】計算結果が桁あふれを起こしました!処理を継続します。’) (A);
/ 必要であればここで代替値をセットするなどのリカバリを行う /
RESULT = 0;
END;
/ 5桁の限界(99999)にさらに1を足そうとする危険な計算 /
RESULT = A + B;
PUT SKIP EDIT (‘計算結果: ‘, RESULT) (A, F(10));
このコードでは、`99999` に `1` を足すことで明らかに桁あふれ(OVERFLOW)が発生します。
しかし、あらかじめ `ON OVERFLOW BEGIN … END;` という「監視網」を張っておいたおかげで、プログラムは突然死することなく、私たちが意図したリカバリ処理(警告メッセージを出して `RESULT` に 0 を入れるなど)を実行して安全に生き延びることができるのです。
—
4. ダンプ解析における注意点:レガシーの現場からのアドバイス
さて、ここからが実務で最も大切な、シニアアーキテクトからの生きたアドバイスです。
もし `ON OVERFLOW` のようなトラップを仕掛け忘れた状態で、本番バッチ中にオーバーフローが発生するとどうなるでしょうか?
メインフレームは容赦なく処理を中断し、システム異常終了(例えばIBM汎用機でお馴染みの S0C7 などのデータ例外、あるいは言語固有のABENDコード)を引き起こし、いわゆる「ストレージダンプ(Core Dump)」を出力します。
ダンプ解析を行う際、初心者のうちは以下の点にハマりがちです。
1. 「どこで」起きたか特定できない焦り
PL/Iの最適化コンパイラ(OPT(2)やOPT(3)など)をかけていると、機械語レベルで命令の順序が前後に入れ替わることがあります。ダンプリストのオフセットアドレスと、元のPL/Iソースコードの行番号が「あれ?微妙にズレてない?」とパニックになることがあります。コンパイル時には `LIST` や `OFFSET` オプションを活用し、生成されたアセンブラリストと見比べる習慣をつけましょう。
2. 「ゾンビデータ」の伝播
もし意図的に `ON OVERFLOW` でトラップせず、かつコンパイラオプションで例外が無効化されていると、あふれた上位の桁が単に「切り捨てられた」状態で次の処理にデータが渡ります。これが後続の計算を静かに破壊し、数日後に大問題として発覚する「サイレント・データコラプション」を引き起こします。エラーで即座に落ちてくれる方が、システムとしてはマシ、というレガシー特有の哲学がここにはあります。
—
まとめ
いかがでしたでしょうか?
- PL/Iには予約語がない自由な世界だが、文脈を読んで優しく動いている。
- 計算の桁あふれは `OVERFLOW` 条件として検知できる。
- `ON OVERFLOW` を使えば、予期せぬクラッシュを防いで優しくハンドリングできる。
- ただし、本番のダンプ解析を見据えて、最適化と例外処理の設計には気を配ろう。
レガシーシステムやメインフレームの世界は、ルールさえ分かってしまえば、非常に堅牢でロジカルな美しい世界です。「古いから怖い」と身構えず、一つひとつコードを紐解いていけば、必ずあなたの強力なスキルになりますよ。
今日の解説が、皆さんのメインフレーム生活の第一歩を優しく照らす灯りとなれば幸いです。それでは、また次回のレガシー・ラボでお会いしましょう!
