【PL/I深掘り】SUBSTR関数の「第3引数省略」が引き起こすメモリ境界の罠
現場のメインフレームエンジニア諸君、今日もJCLのジョブカードと格闘しているか?
PL/Iのコードを読んでいると、たまに「なぜこの書き方をしているんだ?」と首を傾げたくなるようなロジックに出くわすことがある。特に、文字列操作の基本中の基本である `SUBSTR` 関数だ。
「第3引数を省略すれば、文字列の最後まで切り出してくれる」……教科書的にはその通りだ。だが、我々が扱うのは数十万件のVSAMレコードや、数GBに及ぶフラットファイルだ。この「省略」という甘美な仕様が、固定長(CHAR(n))と可変長(VARYING)でどうメモリ上の挙動を変えるのか、そこまで意識してコーディングしているだろうか?
今日は、現場でハマりやすい `SUBSTR` の深層心理について解説する。
—
1. SUBSTR関数の基本と「省略時」の暗黙的なルール
まずは仕様を再確認しよう。`SUBSTR(string, start, length)` だ。第3引数 `length` を省略すると、PL/Iコンパイラは「指定した `start` 位置から、元の文字列の末尾まで」を切り出すよう命令を生成する。
ここまではいい。問題は、対象が「固定長」か「可変長」かだ。
固定長文字列(CHAR(n))の場合
固定長の場合、メモリ上には常に最大長分の領域が確保されている。`SUBSTR` で切り出した結果は、「一時的なテンポラリ変数(中間作業領域)」に展開される。この際、切り出し先の長さが元の変数の定義長と一致しなければ、コンパイラは動的にメモリを確保し、値を転送する。
可変長文字列(CHAR(n) VARYING)の場合
`VARYING` 属性が付いている場合、文字列の先頭2バイトには「現在の実効長」が格納されている。`SUBSTR` を用いてこの値を別の変数に代入する場合、PL/Iは内部的にこの「現在の実効長」を参照してメモリ操作を行う。
—
2. 実践コード:保守の現場で見かける「危うい」実装
バッチ処理でよくある、VSAMレコードから特定フィールドを切り出す例を見てみよう。
1
/ VSAMレコード定義を想定 /
DCL RECORD_AREA CHAR(100);
DCL WORK_KEY CHAR(20);
DCL VARYING_KEY CHAR(20) VARYING;
/
- ケース1: 固定長からの切り出し
- 第3引数を省略すると、結果は一時領域にコピーされ、そこからWORK_KEYに転送される
/
WORK_KEY = SUBSTR(RECORD_AREA, 10, 5);
/
- ケース2: 現場でたまに見かける「不必要なSUBSTR」
- 第3引数を省略することで、意図しない末尾のスペースまで転送されることがある
/
VARYING_KEY = SUBSTR(RECORD_AREA, 1, 10);
このコード、何が問題になり得るか分かるか?
固定長文字列に対して `SUBSTR` を使い、第3引数を省略すると、ソースの定義長(上記の例なら100バイト)に基づいた残り全てが評価対象となる。もし代入先の変数(`WORK_KEY`)のサイズが小さければ、切り詰め(Truncation)が発生し、エラーにはならずともデータ欠損が起きるんだ。
—
3. デバッグのコツ:ONユニットで「切り詰め」を検知せよ
PL/Iの恐ろしいところであり、同時に強力なところは、`CONVERSION` や `STRINGSIZE` 条件が `ONユニット` で捕捉できることだ。
もし大規模改修中にデータの切り詰めが疑われるなら、以下のコードをテストプログラムに仕込んでおくことを強く推奨する。
1
/ 意図しないデータ切り詰めを検知するデバッグ用ONユニット /
ON STRINGSIZE BEGIN;
PUT SKIP LIST(‘警告: データ切り詰めが発生しました!’);
PUT SKIP LIST(‘ソースの定義長がターゲットの定義長を超えています’);
END;
/
- 実際、バッチ処理の中でSUBSTRを多用する際は、
- 第3引数を必ず明示するのがプロの矜持だ。
/
WORK_KEY = SUBSTR(RECORD_AREA, 10, 5); / 長さを明示すれば、STRINGSIZEは発火しない /
—
結論:プロのエンジニアは「省略」を許さない
PL/Iは柔軟だ。だが、その柔軟さは大規模システムにおける「予期せぬメモリ操作」のリスクと表裏一体である。
- 固定長文字列を扱うなら: 常に第3引数で長さを明示せよ。VSAMのフィールド定義が変わった際、`SUBSTR` の結果が勝手に広がって後続の代入先を壊す事故を防げる。
- VARYINGを扱うなら: 長さ計算に `LENGTH` 組み込み関数を組み合わせ、現在の有効長を確実に把握せよ。
「動いているからいい」ではなく、「なぜその記述が最適なのか」を言語化できること。それが、この枯れた技術を使いこなす我々メインフレーム技術者の価値だ。
次は、`ON FIXEDOVERFLOW` と `DECIMAL` 演算の精度管理について話そうか。また現場で会おう。
