【実務・中級編】SELECT-WHEN-OTHERWISE構造の内部実装とジャンプテーブル – PL/Iの基本構文とデータ制御実践ガイド

PL/Iの「SELECT」はただのIF文の羅列ではない――コンパイラが見せる「ジャンプテーブル」の魔法

若手のエンジニアから、「PL/IのSELECT文って、結局IF-THEN-ELSEを綺麗に書いただけのものですよね?」という質問を受けることがある。

結論から言おう。それは大きな誤解だ。PL/Iの設計思想は、単なる可読性の向上に留まらない。コンパイラは、コードの書き方次第で、生成される機械語の効率を劇的に変える賢い最適化エンジンを内包している。今回は、このSELECT-WHEN-OTHERWISE構造が裏側でどう処理されているのか、その「心臓部」に深く切り込んでいこう。

1. 予約語を持たない言語の「自由」と「罠」

PL/Iの仕様で最もユニークなのは、言語自体に「予約語(Reserved Words)」が存在しない点だ。`SELECT`という変数名を使っても、コンパイラは文脈から「ああ、これはキーワードとしてのSELECTだな」と判断してくれる。

しかし、この自由度は、メンテナンスの現場では諸刃の剣になる。後輩たちが書いた「変数名に予約語をふんだんに使ったコード」をデバッグする苦労は、ベテランなら誰もが一度は経験するはずだ。だからこそ、可読性を確保する意味でも、制御構造である`SELECT`は「論理を整理する」ための強力な武器として正しく使うべきだ。

2. SELECT-WHENの内部実装:ジャンプテーブルという最適化

コンパイラは、`SELECT`の条件式が定数や連続した値である場合、内部的に「ジャンプテーブル(分岐テーブル)」を生成する。

もし`WHEN`の条件式がバラバラであれば、コンパイラは`IF-ELSE`の連鎖(逐次比較)を生成する。しかし、条件が密に詰まっている場合、コンパイラはインデックス計算一発で直接ターゲットアドレスへジャンプする機械語を生成するのだ。

  • WHENが少ない場合: `IF-ELSE`連鎖による順次検索。比較回数が増えるほどCPUサイクルを消費する。
  • WHENが多い場合: コンパイラがジャンプテーブルを構築。条件の数に関わらず、ほぼ一定の計算コストで処理が完了する。

この「定数時間での分岐」こそが、数百万件のVSAMレコードを処理するバッチプログラムにおいて、数ミリ秒の差を生み出し、やがて深夜のジョブ終了時刻を数分早める要因になる。

3. 実践:保守現場で使えるSELECT構造の最適化

では、実際のコーディング例を見てみよう。VSAMから読み込んだトランザクション種別を判定する処理を想定する。

1
//
/ トランザクション処理の例:種別コードに応じた分岐 /
//
PROC_TRANS: PROC(TRANS_CODE) OPTIONS(MAIN);

DCL TRANS_CODE CHAR(2) INIT(’01’);
DCL STATUS_MSG CHAR(20);

/

  • コンパイラに分岐テーブルを生成させるヒントを与える書き方。
  • WHENの条件値が順序立てられていると、最適化が効きやすい。

/
SELECT (TRANS_CODE);
WHEN (’01’) STATUS_MSG = ‘新規登録処理’;
WHEN (’02’) STATUS_MSG = ‘更新処理’;
WHEN (’03’) STATUS_MSG = ‘削除処理’;
WHEN (’04’, ’05’) STATUS_MSG = ‘エラー修正’;

OTHERWISE DO;
/ 予期せぬコードへの対応。必ずOTHERWISEは置くこと /
STATUS_MSG = ‘不明なコード’;
CALL LOG_ERROR(TRANS_CODE);
END;
END;

PUT SKIP LIST(‘RESULT: ‘ || STATUS_MSG);

END PROC_TRANS;

4. ベテランからのアドバイス:ONユニットとの付き合い方

バッチ処理の中で忘れがちなのが、`SELECT`文の中でVSAMアクセスや数値演算を行う際の`ON`ユニット制御だ。

もし`WHEN`条件の中で複雑な演算や入出力を伴うなら、必ずその前後に`ON CONDITION`や`ON ENDFILE`を意識したエラーハンドリングを構築してほしい。せっかく綺麗に整理した`SELECT`構造も、エラー発生時に制御フローが崩壊しては元も子もない。

特に、`SELECT`ブロック内で`GOTO`を使って脱出するような邪道なコーディングは厳禁だ。コンパイラが最適化のために準備したジャンプテーブルの整合性を破壊し、予期せぬセグメンテーションフォールト(S0C4など)を誘発する温床になる。

最後に:コードは「機械」のために書く

PL/Iの優雅さは、その構文の柔軟性にある。しかし、我々エンジニアが目指すべきは「誰が見ても分かるコード」であると同時に、「メインフレームのCPUが最も効率的に走れるコード」であるはずだ。

`SELECT-WHEN`を単なる条件分岐として使わず、コンパイラがどう機械語に翻訳するかを想像しながら書いてみてほしい。その視点を持つだけで、君たちが書くコードの品質は、一段上のレベルへと引き上げられるはずだ。

次は、`DECLARE`文でのアライメント(ALIGN/UNALIGNED)が、なぜレコード処理の速度に致命的な差を生むのかについて語ろう。メインフレームの深淵はまだまだ奥が深い。

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