【テクニカル・上級編】EXEC CICS LINK/XCTLにおけるCOMMAREAの受け渡しとデータ構造の同期 – PL/Iの基本構文とデータ制御実践ガイド

はじめに:CICSオンラインにおける「見えない壁」とCOMMAREAの罠

メインフレームの現場で長く生きていると、ある日突然、見慣れないトランザクション・ダンプに遭遇する。
`ASRA`、あるいは`AEID`。画面はフリーズし、オンラインログには冷酷なメッセージが吐き出される。
原因を辿っていくと、大抵の犯人は決まってこれだ。「送信側と受信側でのCOMMAREA(通信領域)のレイアウト不一致」。

JavaやC#といったモダンな言語の世界では、オブジェクトのシリアライズやJSONスキーマのバリデーションが自動で行われるため、構造体のわずかなズレなんてものはコンパイラやフレームワークが優しく教えてくれる。
しかし、私たちが愛してやまない(そして時には呪う)IBMメインフレームの世界、特にPL/IとCICSが交差する領域では、そんな甘えは一切通用しない。

CICSの `EXEC CICS LINK` や `XCTL` で渡される `COMMAREA` は、単なるバイトの塊(バイナリ・ストリーム)に過ぎない。
CICS自身は、その中身が何であるかなど一切関知しない。ただ「アドレスが指す領域を指定された長さに切って渡した」それだけだ。
受け取る側のPL/Iプログラムが、自らの都合の良いように(あるいは不注意によって)異なる構造体(Structure)をマッピングした瞬間、メモリ上のデータは一瞬でグリッチと化し、アベンドへのカウントダウンが始まる。

今回は、PL/Iの極めてユニークな言語仕様である「予約語を持たない柔軟性」と「ベース変数(Based Variable)による動的メモリ制御」を武器に、このCOMMAREAの同期問題をねじ伏せ、さらに将来のオープン系マイグレーション(Java/C#化)も見据えた堅牢なアーキテクチャ設計について、現場の知見を総動員して解説しよう。

—

1. PL/Iの「予約語レス」な恐怖と、COMMAREA定義の基本

PL/Iの最も尖った特徴の一つに、「言語仕様上の予約語(Reserved Words)がほぼ存在しない」という点がある。
例えば、COBOLであれば `VALUE` や `PIC` は厳格な予約語であり、変数名に使うことはできない。しかしPL/Iでは、コンテキスト(文脈)によってキーワードが変数名としても解釈される。この自由度の高さが、時として凄まじい可読性の低下や、意図しないコンパイルエラー、あるいは「動くけれど壊れているコード」を生み出す温床になる。

CICSの `COMMAREA` を定義する際、私たちは通常、構造体(Structure)を用いる。
ここで最も重要なのは、送信側(Caller)と受信側(Callee)で、メモリ上のオフセットとデータ長(Length)が1バイトたりともズレてはならないという厳格な物理的制約である。

以下のコードは、送信側と受信側で共通して利用されるべき、正しいCOMMAREAの定義例(COPYBOOK相当)だ。

/ ========================================================== /
/ COMMAREA 共通定義コピーブック (CUSTCOMM) > /
/ ========================================================== /
DCL 1 CUST-COMMAREA SHARED,
3 CA-RET-CODE CHAR(2), / 応答コード(00:正常, 99:異常) /
3 CA-FUNC-ID CHAR(1), / 処理機能ID /
3 CA-CUST-INFO, / 顧客情報サブ構造体 DEEP /
5 CA-CUST-ID FIXED BIN(31), / 顧客番号(フルワード) /
5 CA-CUST-NAME CHAR(40), / 顧客氏名 /
5 CA-CUST-BAL DECIMAL FIXED(11,2); / 顧客残高(パックデシマル) /

この定義を両方のプログラムが確実に共有していれば問題は起きない。
だが、実際の現場では「受信側だけ勝手にフィールドを追加した」「送信側が `FIXED BIN(15)` で送ってきたのに、受信側で `FIXED BIN(31)` として受けてしまった」といったヒューマンエラーが後を絶たない。

—

2. ベース変数とポインタによる動的マッピングの実装

CICSの `EXEC CICS ADDRESS COMMAREA(P_PTR)` を実行すると、システムはCOMMAREAの先拠アドレスを私たちのプログラムに渡してくれる。
これをPL/Iで安全にハンドリングするためには、ベース変数(Based Variable)とポインタ(Pointer)を組み合わせたコーディングが不可欠だ。

以下のコードは、受け取ったCOMMAREAの領域に、先ほど定義した構造体をベース変数としてスマートに重ね合わせる実装例である。

/ ========================================================== /
/ 受信側プログラム:COMMAREA動的マッピングの例 /
/ ========================================================== /
RCV-PROGRAM: PROC OPTIONS(MAIN);

/ ポインタ変数の宣言 /
DCL WS-COMMAREA-PTR POINTER;

/ ベース付き構造体の宣言(メモリ実体は持たず、ポインタの先を指す) /
DCL 1 CUST-COMMAREA BASED(WS-COMMAREA-PTR),
3 CA-RET-CODE CHAR(2),
3 CA-FUNC-ID CHAR(1),
3 CA-CUST-INFO,
5 CA-CUST-ID FIXED BIN(31),
5 CA-CUST-NAME CHAR(40),
5 CA-CUST-BAL DECIMAL FIXED(11,2);

/ CICS埋め込みコマンドによるCOMMAREAアドレスの取得 /
EXEC CICS ADDRESS COMMAREA(WS-COMMAREA-PTR);

/ ポインタがNULL(COMMAREAなし)かどうかの厳格なチェック /
IF WS-COMMAREA-PTR = NULL() THEN DO;
/ コマンドエラーまたは初期起動時の処理 /
GOTO EXIT-RTN;
END;

/ データの読み込みとビジネスロジックの実行 /
SELECT(CA-FUNC-ID);
WHEN(‘1’) DO;
/ 参照処理 /
CALL PROCESS-INQUIRY;
END;
WHEN(‘2’) DO;
/ 更新処理 /
CALL PROCESS-UPDATE;
END;
OTHERWISE
CA-RET-CODE = ‘E1’; / 未定義機能IDエラー /
END;

EXIT-RTN:
EXEC CICS RETURN;

END RCV-PROGRAM;

ここで注目してほしいのは、`WS-COMMAREA-PTR` が指すアドレスに対して、構造体レイアウトをダイナミックにオーバーレイ(重ね合わせ)している点だ。
しかし、この手法には大きなリスクが潜んでいる。送信側が想定している領域の長さ(LENGTH)と、受信側が期待している構造体の長さが一致している保証は、CICSは一切してくれないという点だ。

—

3. アベンド回避のための防衛的プログラミングと「長さ」の検証

もし送信側が 50 バイトのCOMMAREAを送り、受信側の構造体が 60 バイトを要求していた場合、何が起きるか?
受信側が 50 バイト目以降(メモリ上のゴミ、あるいは他のプログラムの管理領域)にアクセスした瞬間、S0C4(Protection Exception)やデータ例外(ASRA)が発生し、オンラインシステム全体を巻き込む大惨事になりかねない。

これを防ぐためには、CICSが提供する `EIBCALEN`(Execution Interface Block の Communications Area Length)を、処理の最初に必ず検証する「防衛的プログラミング」が必須となる。

/ 領域長の安全確認(防御的アーキテクチャ) /
IF EIBCALEN < STG(CUST-COMMAREA) THEN DO; / 送信されたデータ長が、必要最小限の構造体長に満たない場合 / / ※ STG組み込み関数で構造体のバイト数を正確に取得する / CALL HANDLE-LENGTH-ERROR; EXEC CICS RETURN; END; PL/Iの `STG`(または `STORAGE`)組み込み関数は、構造体や変数が消費する実際のバイト数をコンパイル時に(あるいは動的に)計算してくれる非常に強力な武器だ。この `STG(CUST-COMMAREA)` と `EIBCALEN` を比較することで、構造体のレイアウト変更に伴うバージョン違い(新旧混在による不整合)を検出し、安全に異常終了(またはエラーコード返却)させることが可能になる。 ---

4. 潜む魔物:パックデシマル(COMP-3)の内部符号反転バグとデータアライメント

メインフレーム特有のデータ型である `DECIMAL FIXED`(COBOLの `COMP-3` に相当するパックデシマル)や `FIXED BINARY` の取り扱いには、アーキテクチャ特有の落とし穴がある。

パックデシマルの符号ズレ

CICSを介して他言語(例えばオープン系のAPIや、Java製のバッチ)とCOMMAREAのデータをJSON等に変換せず、そのままバイナリでやり取りするような過渡期のアーキテクチャにおいて、最も頻発するのがパックデシマルの内部符号(Zone/Sign半バイト)の化けだ。
PL/Iコンパイラは、算術演算が行われた際に自動的に符号の正当性をチェックするが、不正なメモリ領域からベース変数を介して無理やりパックデシマルを読み込んだ場合、符号ニブル(最下位4ビット)が `C`, `D`, `F` 以外の不正な値(例: `A` やタブ文字等)になっていると、算術演算を実行した瞬間に `S0C7`(Data Exception)アベンドを引き起こす。

アライメント(ALIGN / UNALIGNED)の罠

もう一つの見落としがちな仕様が、アライメントだ。
PL/Iコンパイラはデフォルトで、フルワード(4バイト境界)やダブルワード(8バイト境界)に数値を綺麗に並べようとする(`ALIGN` 属性)。これにより CPU のアクセス効率が上がる反面、構造体の途中にパディング(埋め草の空白バイト)が勝手に挿入される。

もし、送信側のプログラムが `UNALIGNED`(パディングなし)でデータを詰め込み、受信側がデフォルトの `ALIGN` で構造体を定義していたらどうなるか?
パディングの有無によってフィールドのオフセットが完全にズレ、読み込んだ値が全く別の意味不明な数値に化ける。

/ 厳格なレイアウト同期のための必須属性:UNALIGNED /
DCL 1 CUST-COMMAREA BASED(WS-COMMAREA-PTR) UNALIGNED,
3 CA-RET-CODE CHAR(2),
…

CICSのCOMMAREAのように、外部(あるいは他のプログラム)とバイナリレイアウトを完全一致させる必要がある構造体には、必ず `UNALIGNED` 属性を明示すること。これがレガシーシステムのアーキテククトとしての最低限の処世術である。

—

5. マイグレーション時代における設計視点:PL/IからJava/C#への継承

現在、多くの企業がメインフレームからの脱却(レガシーマイグレーション)を検討、あるいは実行している。
PL/Iで書かれたオンラインプログラムをJava(Spring Bootなど)やC#(.NET Core)にリライトする際、最も頭を悩ませるのが、この「COMMAREAに依存した密結合な画面・プログラム間通信」の剥ぎ取りだ。

オープン系へ移行する際、バイナリのCOMMAREAをそのまま維持するアプローチ(例えば、Java側で `ByteBuffer` や構造体マッピングライブラリを使ってバイト配列をパースする方法)をとる現場があるが、これは悪夢の始まりであることが多い。
前述したパックデシマルの符号問題、ビッグエンディアン(IBM)とリトルエンディアン(x86)のバイトオーダー(エンディアン)の違いが、移行後のテスト工程で地雷のように爆発する。

アーキテククトとしての推奨アプローチ

1. コンバージョン層の隔離:
移行期においては、CICSのCOMMAREAレイアウトをそのままJSONスキーマ(またはDTOクラス)に厳密にマッピングし、API境界(Gateway)でバイナリとオブジェクトの相互変換を行う共通コンポーネントを必ず設けること。
2. 言語仕様への依存からの脱却:
PL/Iの `BASED` 変数による強引なメモリ共有は、オープン系では「アンセーフコード(C#の `unsafe` など)」に該当し、保守性を著しく下げる。マイグレーションを機に、データ構造は純粋な属性値の集合として定義し直し、JSON/XMLベースの疎結合なメッセージングへリファクタリングすべきである。

—

おわりに:コードの背後にある「物理メモリ」を想像せよ

PL/Iという言語は、ハードウェアの構造(メモリ、レジスタ、アドレッシング)をプログラマの直ぐ足元まで引きずり出してくれる、極めてアグレッシブで美しい言語だ。
しかし、その自由度の高さゆえに、記述者の意図とは裏腹に、メモリのわずかな解釈のズレがシステム全体の崩壊を招く。

`EXEC CICS LINK` におけるCOMMAREAのやり取りは、単なるデータの受け渡しではない。それは、送信側と受信側のプログラムが「メモリの景色を完全に共有している」という、極めて危うい信頼関係の上に成り立っている。

次にあなたがCOMMAREAのバグに直面したとき、あるいはPL/Iからオープン系へのマイグレーション設計図を描くときは、思い出してほしい。
画面の向こう側で動いているのは、綺麗に整列した抽象概念ではなく、冷徹なまでの「バイトの連続体」なのだということを。そのバイトの並びを完璧に支配できたとき、あなた真のメインフレーム・アーキテククトとしての誇りを手にすることができるだろう。

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