【実務・中級編】 DL/I ステータスコード – 階層型DBMS

DL/I ステータスコードの完全支配:生き残りのための階層型DBMSエラーハンドリング

こんにちは。チーフアーキテクトの私だ。
今回のコードレビューで、また「ステータスコードの文字列直接比較」による脆弱なエラーハンドリングを見かけた。現代のWeb系から流れてきたエンジニアには、メインフレームの遺物に見えるかもしれない。だが、IMS DB(DL/I)を基幹に据えるシステムにおいて、DL/Iステータスコード(2文字の半角英数字)の扱いは、システムの生死を分ける極めて重要な境界防衛線だ。

今回は、単なるリファレンスの引き写しではない。極限の負荷とデータ整合性が求められる現場で、私がどのようにDL/Iステータスコードを飼い慣らし、堅牢なアーキテクチャを構築してきたか、そのノウハウのすべてを伝授しよう。

—

1. DL/Iステータスコードの本質と「空白(SP)」の罠

DL/I(Data Language/I)コールを発行すると、PCB(Program Communication Block)の特定領域に2バイトのステータスコードが返却される。

リレーショナルデータベース(RDBMS)の例外機構(`try-catch` や SQLSTATE)に慣れた頭脳にとって、この「戻り値がステータスコードという文字列表現であること」と「基本的に異常終了せず、コードで状態を返してくること」は、最初のパラダイムシフトになる。

ステータスコードの分類学

実務上、意識すべきコードは以下の3カテゴリに大別される。

1. 正常系(Success)

  • ` `(スペース2文字、または `OK` が返る一部例外を除き基本はSpaces):処理成功。

2. 想定内の分岐・制御系(Expected Condition)

  • `GE` (Data Not Found): 該当セグメントなし。論理削除チェックやマスタ未登録判定で頻出。
  • `GB` (End of Chain): セグメントタイプのオカレンス終端。ループ脱出のトリガー。

3. 異常・致命的エラー系(Fatal Error)

  • `AJ`, `AK`, `U` など: セグメント競合、構造違反、ポインタチェインの破壊など。

> 【アーキテクトの警告】
> 「` `(スペース)以外はすべてエラー」という雑なハンドリングをしてはならない。`GE` は「エラー」ではなく「ビジネスロジック上の分岐点」だ。ここを混同すると、データが存在しないだけでバッチが異常終了する脆弱なシステムが完成する。

—

2. 実務で遭遇するアンチパターンと堅牢な設計パターン

では、実際のCOBOL/PL/Iプログラムにおける設計を見ていこう。まずは「やってはいけないコード」からだ。

❌ アンチパターン:散在するマジックストリングと場当たり的な分岐

  • 悪い例:ステータスコードをあちこちで直接評価している

CALL ‘CBLTDLI’ USING
GU-FUNC,
CUSTOMER-PCB,
CUSTOMER-SEGMENT,
CUST-SSA.

IF CUST-STATUS = ‘GE’
MOVE ‘Y’ TO NOT-FOUND-SW
ELSE
IF CUST-STATUS NOT = SPACES
DISPLAY ‘FATAL ERROR: ‘ CUST-STATUS
MOVE 8 TO RETURN-CODE
PERFORM ABEND-ROUTINE
END-IF
END-IF

何が問題か?

  • ステータスコードの意味(`GE` など)がコード中にハードコーディングされており、仕様変更やメンテナンス性に劣る。
  • 異常系のハンドリングが散乱し、トランザクションのロールバック(`ROLL` コール)やログ出力の粒度がバラバラになる。

—

⭕ 堅牢な設計パターン:ステータスハンドラ・カプセル化レイヤー

プロ級の設計では、DL/Iコールのラッパー層(または評価関数)を一枚噛ませる。これにより、通信プロトコルとビジネスロジックを完全に分離する。

以下に、概念的な構造を示す。

> 良い例:ステータスコード判定を専用の評価モジュールに委譲する
CALL ‘CBLTDLI’ USING
GU-FUNC,
CUSTOMER-PCB,
CUSTOMER-SEGMENT,
CUST-SSA.

MOVE CUST-STATUS TO DLIC-STATUS-IN.
CALL ‘DLIEVAL’ USING DLIC-PARAM.

EVALUATE TRUE
WHEN DLIC-IS-SUCCESS
— 正常処理の継続 —
CONTINUE
WHEN DLIC-IS-NOT-FOUND
— 業務上の「データなし」処理(GE) —
PERFORM HANDLE-CUST-NOT-FOUND
WHEN OTHER
— 致命的エラー:ログ出力・ロールバック・異常終了 —
PERFORM HANDLE-FATAL-ERROR
END-EVALUATE.

堅牢な判定ロジックのポイント

  • 一元管理: ステータスコードの定義と判定基準(何が致命的で、何がリトライ可能か)を1つのモジュールに閉じ込める。
  • ログの完全性: 致命的エラー時は、PCB内のキー値、機能コード(GU, IS, DLET等)、セグメント名を必ずログに吐き出させる構造にする。これがないと、深夜の障害時に原因特定が不可能になる。

—

3. パフォーマンス上の注意点:ステータスコードと「無駄な探索」の呪縛

階層型DBMS、特にIMS DBでは、ステータスコードの扱いがパフォーマンスに直結する。

`GE`(Data Not Found)を多発させる設計の罪

RDBMSの感覚で、存在確認のために毎回 `GU`(Get Unique)や `GN`(Get Next)を叩き、返ってきた `GE` を見て「あ、なかったからインサートしよう」というフロー(Read-after-Writeの逆、あるいはその場しのぎの存在チェック)を組む開発者がいる。

階層型データベースにおいて、物理的なポインタチェインを辿るコストは決して安くない。

  • 不必要なDL/Iコールは、OSのI/OおよびCPUサイクルの無駄遣いである。
  • 階層パスが深い(Root -> Segment A -> Segment B -> Segment C)場合、途中のセグメントで `GE` になると、DBMSはそこまでのパス構築コストを無駄に支払うことになる。

対策:
パス全体の存在が確実な場合を除き、親セグメントの修飾子付きSSA(Segment Search Argument)を適切に構築し、無駄な試行錯誤的コールを排除せよ。ステータスコード `GE` が返ってくる頻度をプロファイリングし、高頻度で発生しているパスがあれば、それはアクセスパスの設計不良のシグナルだ。

—

4. チーフアーキテクトからの提言

階層型DBMSは古い? いや、基幹系においてその圧倒的なスループットとデータ整合性の担保能力はいまだに色褪せない。しかし、それを扱うエンジニアの技量が低下すれば、システムはたちまち硬直する。

DL/Iステータスコードは、単なる「エラー番号」ではない。データベースの深部からのメッセージだ。
コードレビューの際は、以下の3点を厳しくチェックしてほしい。

1. すべてのDL/Iコールの直後にステータスチェックが行われているか?(チェック漏れは論外)
2. `GE` や `GB` などの制御系コードが、適切に業務ロジックへハンドリングされているか?
3. 致命的エラー(`AJ`, `AK` 等)が発生した際に、トランザクションの整合性(ロールバックと監査ログ)が担保される設計になっているか?

この2文字を制する者が、階層型DBMSを制す。次のコードレビューを楽しみにしている。

コメント

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