【実務・中級編】CHARACTER VARYING型の内部構造と長さ制御 – PL/Iの基本構文とデータ制御実践ガイド

【PL/I深掘り】VARYING文字列の「2バイトの罠」を制する者は、基幹システムを制す

若手エンジニア諸君、今日もメインフレームの迷宮でバグの山と格闘していることだろう。

PL/Iという言語は、C言語やJavaのような「予約語による厳格な制限」を嫌う、ある種の自由奔放な設計思想を持っている。だが、その自由さが裏目に出て、メモリレイアウトの深淵を理解していないと、後の世代に「負の遺産」として引き継がれる致命的なバグを生むことになる。

今日は、特にトラブルの温床となりやすい `CHARACTER VARYING` 型の内部構造と、現場で死ぬほど見てきた「SUBSTR関数による破壊」について、実務の現場感覚を交えて解説しよう。

VARYING型の「知られざる素顔」:先頭2バイトの重み

PL/Iの `CHARACTER(N) VARYING` を宣言したとき、メモリ上では何が起きているか。多くの開発者は「最大Nバイトの領域」としか認識していないが、それは大きな間違いだ。

実際には、「現在の文字列長を格納するための2バイトの接頭辞(Prefix)」+「データ本体」という構造で格納されている。

例えば `DCL MSG CHAR(80) VARYING;` と宣言した場合、メモリ上には合計82バイトが確保される。先頭の2バイトには、現在の有効な文字列長を示すバイナリ値(ハーフワード)が格納され、それに続く領域にデータが並ぶ。

この「先頭2バイト」を意識せずに、バイナリ転送やレコード入出力を行うとどうなるか? 想像するだけで冷や汗が出るだろう。VSAMデータセットへ直接書き出す際、この構造を無視してダンプを取ると、先頭の2バイトが文字化けしたような意味不明な値になり、後続の読み取り処理で `INVALID DATA` や長さ不正の例外を食らうことになる。

実践:SUBSTR操作と「うっかり」を防ぐコード

`SUBSTR` 関数は便利だが、`VARYING` 型に対して不用意に使うと、その動的な長さ管理が崩壊する可能性がある。特に注意すべきは、`SUBSTR` の結果を別の変数に代入する際、ターゲット側が `VARYING` か `FIXED` かによって挙動が微妙に異なる点だ。

現場でよく見る「動くが危ういコード」を修正した、標準的な書き方を示そう。

1
/ —————————————————————— /
/ 文字列操作の安全な実装例 /
/ —————————————————————— /
PROCEDURE_NAME: PROCEDURE;

/ VARYING変数の宣言:最大長は256 /
DCL WORK_STR CHAR(256) VARYING;
DCL EXTRACTED CHAR(20) VARYING;
DCL LEN FIXED BIN(15);

WORK_STR = ‘IBM-MAINFRAME-DEVELOPMENT’;

/ 安全策1:長さを明示的に確認してから操作する /
LEN = LENGTH(WORK_STR);
IF LEN >= 10 THEN DO;
/ SUBSTRで切り出した結果をVARYING変数へ代入 /
/ 自動的に先頭の2バイトに長さ情報が再計算される /
EXTRACTED = SUBSTR(WORK_STR, 5, 6);
END;

/ 現場の知見:出力時はLENGTH関数を通すことで、 /
/ 不要な空白やゴミデータによる誤作動を防ぐのが鉄則 /
PUT SKIP LIST(‘LENGTH: ‘ || LENGTH(EXTRACTED));
PUT SKIP LIST(‘DATA: ‘ || EXTRACTED);

END PROCEDURE_NAME;

VSAMアクセスとONユニットによる守護

バッチ処理において、VSAMファイルから読み込んだデータを `VARYING` 型に代入する際は、特に注意が必要だ。ファイル定義(FIB)とメモリ上の定義が微妙に食い違っていると、`ONCODE 8091`(文字列の長さ不正)などが容赦なく飛んでくる。

もし `VARYING` を扱う処理で例外が頻発するなら、必ず `ON` ユニットを適切に配置し、異常を検知した際のログを残すようにせよ。

1
/ 文字列操作の例外を捕捉するためのONユニット /
ON STRINGRANGE BEGIN;
PUT SKIP LIST(‘エラー発生:文字列の範囲外参照を検知しました’);
/ ここでダンプを取得するか、異常終了させる設計にするのが堅牢 /
STOP;
END;

先輩からのアドバイス:保守の現場で生き残るために

1. 「とりあえずVARYING」は禁物:固定長で済む項目(キー項目やコード体系)に `VARYING` を使うな。パフォーマンス低下とデバッグの難易度上昇を招くだけだ。
2. バイナリ操作は慎重に:`SUBSTR` で無理やりバイナリを切り出して別形式へマッピングするようなコードは、将来のマイグレーション時に地雷となる。
3. BUILTINを信じろ:`LENGTH`, `INDEX`, `VERIFY` といった組み込み関数は、内部の「2バイト構造」を正しくハンドリングするように設計されている。自前でポインタ演算のようなことをしようとせず、標準関数を使いこなせ。

PL/Iの歴史は長い。しかし、その根底にあるメモリレイアウトの理屈は、時代が変わっても変わらない。この「2バイトの内部構造」を頭の中に視覚化できるようになったとき、君たちはまた一段階、ベテランの領域へ近づくことになるだろう。

さあ、次のバッチ改修も、この知識を武器にスマートに切り抜けてくれ。健闘を祈る。

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