おい、最近夜間バッチの終了時間がじわじわと延びていないか?
そして、突如としてシスログ(SYSLOG)やジョブログに `IBM0221S ONCODE=321 FIXEDOVERFLOW` なんていうエラーメッセージが吐き出され、夜中に運用担当者からたたき起こされた経験はないか?
メインフレームの基幹システムを支えるPL/Iの世界では、数値演算の桁あふれは避けて通れない「いぶし銀のトラブル」だ。C言語やJavaに慣れた若い連中からすると、「おいおい、なんで変数のサイズを超えたくらいでプログラムがいちいち異常終了するんだよ」と文句が出るかもしれない。だが、金融や流通の巨大な勘定系データを扱う我々にとって、この「桁あふれを黙殺しない」という鉄の意志こそが、データの信頼性を担保する最後の砦なのだ。
今日は、この `FIXED BINARY`(固定小数点二進数)のオーバーフローと、それを優しく、かつ厳格に手なずけるための `ON FIXEDOVERFLOW` 制御について、現場のノウハウを余すところなく伝授しよう。
—
1. なぜ FIXED BINARY はオーバーフローに厳しいのか?
PL/Iのデータ型の中で、主算術演算の主役を張るのは何と言っても `FIXED BINARY` だ。COBOLで言うところの `COMP` や `COMP-4` に相当するが、コンパイラの最適化やハードウェア(IBM Zのアーキテクチャ)の命令セットとの密接な連携において、PL/Iのそれは非常にシビアな挙動を示す。
例えば、`FIXED BINARY(15)` で定義された変数は、符号付きの16ビット、すなわち `-32,768` から `32,767` までの値しか保持できない。もし、日々の売上集計や利息計算の途中でこの範囲を超える演算結果が生じたとき、ハードウェアはプログラム割り込み(中断)を発生させようとする。
ここでPL/Iの真骨頂が現れる。PL/Iには、こうした例外条件を検知して独自のリカバリ処理を行わせる 「ON条件(条件処理機構)」 が標準装備されているのだ。これを使いこなせないようでは、ベテランのPL/Iエンジニアとは呼べない。
—
2. ON FIXEDOVERFLOW による条件捕捉と制御フロー
もしプログラム内で `FIXEDOVERFLOW` 条件に対する `ON` ユニット(例外処理ルーチン)を定義しておかないと、条件が発生した瞬間にデフォルトの動作(通常はメッセージを出力してABEND:異常終了)が実行される。
しかし、`ON FIXEDOVERFLOW` を記述しておけば、プログラムを強制終了させずに処理を継続させたり、適切なログを残して安全にバイパスさせることが可能になる。
ここで重要なのは、「ONユニット内で何をするか」 と 「制御の戻り先(GOTOの可否)」 だ。
ONユニットの実行が完了すると、原則として処理は「例外が発生した文の次の文」、あるいは「例外が発生した演算そのものの再試行(可能な場合)」へと戻る。しかし、桁あふれを起こした不完全な値のまま後続計算を進めると、データベース(VSAMやDB2)へゴミデータを書き込む大惨事になりかねない。そのため、実務ではONユニット内でフラグを立てて処理をアボート(または安全なルートへ分岐)させることが多い。
—
3. 実践!VSAMファイル処理を伴う堅牢なPL/Iプログラム例
百聞は一見にしかずだ。実際のバッチ処理を想定したソースコードを見てみよう。
このサンプルでは、日次売上トランザクションをVSAM(KSDS)から読み込み、単価と数量を掛け合わせた結果を `FIXED BINARY(15)` の変数に格納しようとしてオーバーフローの危機に直面した際、それを `ON FIXEDOVERFLOW` で捕捉して安全にエラー処理を行う構造を示している。
1
/ /
/ プログラム名: SLSMAIN /
/ 概要: VSAMマスタから売上データを読み込み、演算とオーバーフロー /
/ のハンドリングを行うバッチプログラム /
/ /
SLSMAIN: PROC OPTIONS(MAIN);
/ — 宣言部 — /
DCL SALES_FILE FILE RECORD INPUT
ENVIRONMENT(KEYED ORGANIZATION(INDEXED));
DCL 1 SALES_REC,
5 CUST_ID CHAR(5), / 顧客ID /
5 UNIT_PRICE FIXED BIN(15), / 単価 (小規模想定) /
5 QUANTITY FIXED BIN(15); / 数量 /
DCL WK_TOTAL FIXED BIN(15); / 計算用ワーク (危険域) /
DCL SAFE_TOTAL FIXED DEC(9,2); / 安全な十進演算用 /
DCL EOF_FLAG CHAR(1) VALUE(‘0’);
DCL OVERFLOW_OCCUR CHAR(1) VALUE(‘0’);
/ — 条件処理(ONユニット)の定義 — /
ON FIXEDOVERFLOW
BEGIN;
/ 現場の鉄則: ログに詳細を出力し、フラグを立てて暴走を防ぐ /
PUT SKIP LIST(‘【警告】FIXED BINARY オーバーフローを検知しました。’);
PUT SKIP EDIT (‘顧客ID: ‘, CUST_ID) (A, A);
OVERFLOW_OCCUR = ‘1’;
/ 強制的に安全な処理ルートへジャンプ(またはエラー処理へ) /
GOTO ERROR_ROUTINE;
END;
/ — ファイルオープン — /
OPEN FILE(SALES_FILE);
/ — メインループ — /
DO WHILE (EOF_FLAG = ‘0’);
READ FILE(SALES_FILE) INTO(SALES_REC);
IF ENDFILE(SALES_FILE) THEN
EOF_FLAG = ‘1’;
ELSE DO;
/ 初期化 /
OVERFLOW_OCCUR = ‘0’;
/ 【危険な演算】
もし UNIT_PRICE と QUANTITY の積が 32,767 を超えると、
ここで即座に上の ON FIXEDOVERFLOW が発動する。 /
WK_TOTAL = UNIT_PRICE QUANTITY;
IF OVERFLOW_OCCUR = ‘0’ THEN DO;
/ 正常系の処理 /
PUT SKIP EDIT(‘正常計算: 顧客=’, Cust_id, ‘ 合計=’, WK_TOTAL)
(A, A, A, F(10));
END;
ERROR_ROUTINE:
IF OVERFLOW_OCCUR = ‘1’ THEN DO;
/ 異常系の処理:安全なDECIMAL型で再計算するか、エラーリストへ退避 /
SAFE_TOTAL = DECIMAL(UNIT_PRICE, 5, 0) DECIMAL(QUANTITY, 5, 0);
PUT SKIP EDIT(‘【リカバリ】DECIMAL演算で救済: ‘, SAFE_TOTAL)
(A, F(15,2));
/ ここでエラーファイルへの出力やカウンター加算を行う /
END;
END;
END;
/ — 終了処理 — /
CLOSE FILE(SALES_FILE);
PUT SKIP LIST(‘— 正常終了 (バッチ処理完了) —‘);
RETURN;
END SLSMAIN;
—
4. アーキテクトからの実践アドバイス:オーバーフローを防ぐコーディング標準
上記のコードを見て、「おっ、ONユニットでGOTOを使ってうまく逃げているな」と思っただろう。しかし、実務の現場では、「そもそも FIXEDOVERFLOW を起こさない設計・コーディング」 が最上位の正義であることを忘れてはならない。
ONユニットによる例外処理は、どうしてもオーバーヘッド(実行性能の低下)を伴う。基幹システムの超高負荷な日次・月次バッチにおいて、エラーでもないのに頻繁にONユニットを通過するような設計は言語道断だ。
以下のプラクティスをチームのコーディング標準として徹底してほしい。
1. データ型の選定を見直す
小規模なカウンタやフラグなら `FIXED BIN(15)` でも良いが、金額や数量、累積値など、少しでも上限を超えるリスクがある項目には、ケチらずに `FIXED BIN(31)`(32ビット、約21億まで許容)を使用すること。ハードウェアの32ビットレジスタ処理の効率も良く、パフォーマンス上のデメリットはほぼない。
2. ビルトイン関数(BUILTIN)の活用
精度の拡張や型変換を行う際は、明示的に `DECIMAL` や `FLOAT`、あるいは拡張精度のビルトイン関数をかませることで、意図しない暗黙の型変換や精度落ちを防ぐことができる。
3. ONユニットは「最後の安全弁」と心得る
日常的な入力データの異常値チェックは、演算の前段階(バリデーションフェーズ)で弾くのが鉄則だ。`FIXEDOVERFLOW` は、予期せぬ巨大データの流入や、将来的な桁あふれによるサイレントエラー(気づかないうちにデータが化ける現象)を防ぐための「保険」として使え。
レガシーシステムの保守・改修は、先人が遺したコードの意図を読み解き、現代の安定稼働の要求水準に合わせてリファインしていく地道な作業の連続だ。この `FIXEDOVERFLOW` の制御一つをとっても、メインフレームの深いアーキテクチャを理解しているかどうかがエンジニアの腕の見せ所となる。
次のバッチ改修では、ぜひこの知見を思い出して、堅牢で美しいPL/Iコードを組み上げてくれ。期待しているぞ。
