【実務・中級編】RECORD I/OにおけるDECLARE FILEの属性指定 – PL/Iの基本構文とデータ制御実践ガイド

PL/I RECORD I/OのDECLaRE FILE属性:排他制御の落とし穴と回避策

おい、諸君。今日はPL/Iで基幹バッチ処理を組む上で、避けては通れない「RECORD I/O」における `DECLARE FILE` の属性指定について、ちょっと深掘りして話しておこう。特に、`SEQUENTIAL`、`DIRECT`、`INPUT`、`OUTPUT`、`UPDATE` といった属性の組み合わせが、どういう排他制御に繋がるのか、そしてそこにはどんな落とし穴があるのか、俺たちが現場で実際にぶつかるであろうケースを想定して、実践的に解説していく。

「なんだ、FILE属性の話か。そんなの、マニュアル読めばわかるだろ?」と思った諸君。甘い。マニュアルは確かに正確だが、現場の「生きた」データと「動く」プログラムの挙動、そして「なぜそうなったのか」という背景までは教えてくれない。俺たちが求めているのは、そういう「血の通った」知識のはずだ。

PL/Iプログラムの基本構造とFILE定義の重要性

まず、PL/Iプログラムの基本構造について、軽くおさらいしておこう。

MYPROG: PROCEDURE OPTIONS(MAIN);
/ ここに宣言部 /

DCL
/ ファイル宣言 /
INPUT_FILE FILE RECORD SEQUENTIAL INPUT ENV(‘SYSUT1’) KEYED,
OUTPUT_FILE FILE RECORD SEQUENTIAL OUTPUT ENV(‘SYSUT2’),
UPDATE_FILE FILE RECORD SEQUENTIAL UPDATE ENV(‘SYSUT3’) KEYED,
DIRECT_FILE FILE RECORD DIRECT UPDATE ENV(‘SYSUT4’) KEYED;

/ ここに実行部 /

END MYPROG;

このように、PL/Iプログラムは `PROCEDURE OPTIONS(MAIN)` で始まり、`END` で終わる。その中で、`DCL` (DECLARE) ステートメントを使って、変数やファイルなどのデータ構造を宣言する。特に、ファイル定義 (`DECLARE FILE`) は、バッチ処理の肝となるレコード入出力の基本であり、ここで指定する属性が、後々のデータアクセスや排他制御に大きく影響してくるんだ。

RECORD I/OにおけるFILE属性の組み合わせと排他制御

さて、本題の `DECLARE FILE` の属性指定だ。RECORD I/Oでは、以下の属性の組み合わせが重要になる。

  • アクセスモード:
  • `SEQUENTIAL`: ファイルを先頭から順に読み書きする。
  • `DIRECT`: キーを指定して、ファイル内の任意のレコードに直接アクセスする。
  • 入出力モード:
  • `INPUT`: ファイルから読み込むだけ。
  • `OUTPUT`: ファイルに書き込むだけ。
  • `UPDATE`: ファイルを読み込み、かつ書き換える(更新する)。

これらの属性をどう組み合わせるかで、ファイルへのアクセス方法、そして最も重要な「排他制御」の挙動が変わってくる。

1. `SEQUENTIAL INPUT`

DCL SEQ_IN_FILE FILE RECORD SEQUENTIAL INPUT ENV(‘SYSUT1’);

これは最も基本的なファイル定義だ。ファイルを先頭から順番に読み込んでいくだけ。他のプログラムがこのファイルを同時に `UPDATE` や `OUTPUT` モードで開いている場合、競合が発生する可能性がある。ただし、`INPUT` モードで開いている限り、通常は他の `INPUT` モードでのオープンをブロックすることはない。

排他制御への影響:
このファイル定義自体は、積極的に排他制御を行うものではない。あくまで「読み取り専用」であることを示す。しかし、OSやJES(Job Entry Subsystem)のレベルでのファイルロック機構によっては、他のプロセスが書き込もうとした際にエラーになる可能性はある。

2. `SEQUENTIAL OUTPUT`

DCL SEQ_OUT_FILE FILE RECORD SEQUENTIAL OUTPUT ENV(‘SYSUT2’);

このファイル定義は、新しいデータをファイルに追記していく、あるいは既存のファイルを上書きしていく場合に使われる。

排他制御への影響:
`OUTPUT` モードでファイルを開いた場合、通常、そのファイルは他のプロセスによる書き込み(`OUTPUT` や `UPDATE`)から保護される。つまり、競合する他の `OUTPUT` や `UPDATE` モードのオープンはブロックされる可能性が高い。これは、データの一貫性を保つために重要だ。

3. `SEQUENTIAL UPDATE`

DCL SEQ_UP_FILE FILE RECORD SEQUENTIAL UPDATE ENV(‘SYSUT3’) KEYED;

この属性の組み合わせは、ファイルを読み込み、その内容を更新(書き換え)する場合に使う。`KEYED` 属性が付いている場合は、キーを使ってレコードを特定して更新する。

排他制御への影響:
`SEQUENTIAL UPDATE` は、最も強力な排他制御を伴う可能性がある。ファイルを `UPDATE` モードで開いたということは、「このファイルを読み込んで、書き換えるぞ」という意思表示だ。そのため、他のプロセスがこのファイルを `INPUT`、`OUTPUT`、あるいは `UPDATE` モードで開こうとすると、ブロックされる可能性が非常に高い。これは、更新中のデータが他のプロセスによって読み取られたり、さらに書き換えられたりするのを防ぐためだ。

現場の知恵:
ここで注意が必要なのは、`SEQUENTIAL UPDATE` でファイルを開いた場合、`READ` ステートメントでレコードを読み取った後、そのレコードは「ロックされた」状態になることだ。そのロックを解除するには、`REWRITE` ステートメントで書き換えるか、`DELETE` ステートメントで削除するか、あるいは `END` ステートメントでファイルをクローズするか、`FILE` ステートメントで別のレコードを読み込む必要がある。もし、読み込んだレコードを処理した後に、何もせずに次の `READ` を発行しようとすると、意図しないエラー(例えば `804-X` エラーのようなもの)に遭遇する可能性がある。

/ 例:SEQUENTIAL UPDATE でのレコード処理 /
READ FILE(SEQ_UP_FILE) INTO(RECORD_AREA);
IF STATUS_CODE = 0 THEN DO;
/ レコード処理 /
IF UPDATE_NEEDED THEN DO;
/ レコードを書き換える /
REWRITE FILE(SEQ_UP_FILE) FROM(UPDATED_RECORD_AREA);
/ ここでレコードのロックが解除される /
END;
ELSE DO;
/ 更新しない場合でも、次のREADのためにロックを解除する必要がある /
/ 通常は、次のREADで自動的に解除されるが、明示的に意識しておく /
/ READ FILE(SEQ_UP_FILE) INTO(ANOTHER_RECORD_AREA); /
END;
END;

4. `DIRECT UPDATE` (VSAM KSDSなどを想定)

DCL DIRECT_UP_FILE FILE RECORD DIRECT UPDATE ENV(‘SYSUT4’) KEYED;

VSAMのKSDS(Key Sequenced Data Set)など、キーを使ってランダムアクセス可能なファイルを `UPDATE` モードで開く場合だ。これは、特定のキーに対応するレコードを直接読み込み、更新するシナリオで使われる。

排他制御への影響:
`DIRECT UPDATE` も `SEQUENTIAL UPDATE` と同様に、強力な排他制御を伴う。特定のレコードをキーで指定して読み込んだ場合、そのレコード(またはレコードのキー範囲)がロックされる。他のプロセスが同じレコード(またはロック範囲内のレコード)を `UPDATE` モードでアクセスしようとすると、ブロックされる。

現場の知恵:
VSAMなどのKSAM(Keyed Sequential Access Method)ファイルでは、レコードロックの粒度が重要になる。

  • レコードレベルロック: 指定したキーのレコードのみがロックされる。他のプロセスは、ロックされていない別のレコードにアクセスできる。
  • キー範囲ロック (String Positioning): `READ` ステートメントでキーを指定した場合、そのキーから次のキーまでの範囲がロックされることがある。これは、シーケンシャルリードと組み合わせた場合に特に注意が必要だ。

VSAMの `ENQ`/`DEQ` などのリソース管理との兼ね合いも複雑なので、共有リソースを扱う場合は、シスプロ(システムプログラマー)と連携して、適切なロック戦略を検討する必要がある。

5. `DIRECT INPUT`

DCL DIRECT_IN_FILE FILE RECORD DIRECT INPUT ENV(‘SYSUT5’) KEYED;

キーを使ってレコードを直接読み込む場合。

排他制御への影響:
`DIRECT INPUT` モードの場合、通常、他のプロセスによる書き込みをブロックすることはない。ただし、読み取り対象のレコードが他のプロセスによって `UPDATE` モードでロックされている場合は、そのロックが解除されるまで待たされる可能性がある。

6. `DIRECT OUTPUT`

DCL DIRECT_OUT_FILE FILE RECORD DIRECT OUTPUT ENV(‘SYSUT6’) KEYED;

キーを使って新しいレコードを直接挿入する場合。

排他制御への影響:
`DIRECT OUTPUT` でファイルを開いた場合、通常は他のプロセスによる書き込みをブロックする。ただし、競合するキーが存在しないことを前提とする。もし、既存のキーと同じキーを挿入しようとすると、エラーになる。

ONユニットによるエラーハンドリング

これらのファイル操作では、様々なエラーが発生しうる。特に、排他制御に関するエラー(例えば、他のプロセスにロックされているファイルにアクセスしようとした場合など)は、バッチ処理の異常終了に繋がる。これらのエラーを適切にハンドリングするために、`ON` ユニットを効果的に使うことが重要だ。

MYPROG: PROCEDURE OPTIONS(MAIN);
DCL
INPUT_FILE FILE RECORD SEQUENTIAL INPUT ENV(‘SYSUT1’);

/ ON ENDFILE ユニット /
ON ENDFILE(INPUT_FILE) BEGIN;
PUT SKIP LIST(‘END OF FILE REACHED FOR INPUT_FILE.’);
/ ファイル処理の終了処理 /
RETURN; / または GOTO END_PROC; /
END;

/ ON ERROR ユニット /
ON ERROR BEGIN;
PUT SKIP LIST(‘UNEXPECTED ERROR OCCURRED.’);
/ エラーコードや状況を表示 /
PUT SKIP LIST(‘STATUS: ‘, STATUS);
/ 異常終了処理 /
ABEND; / または SIGNAL … /
END;

/ ON CONVERSION ユニット /
ON CONVERSION BEGIN;
PUT SKIP LIST(‘DATA CONVERSION ERROR.’);
PUT SKIP LIST(‘TARGET: ‘, TARGET);
PUT SKIP LIST(‘SOURCE: ‘, SOURCE);
/ 異常終了処理 /
ABEND;
END;

/ ファイルオープン /
OPEN FILE(INPUT_FILE);

/ レコード読み込みループ /
DO WHILE (TRUE);
READ FILE(INPUT_FILE) INTO(RECORD_AREA);
/ レコード処理 /

END;

END MYPROG;

  • `ON ENDFILE(file_name)`: ファイルの終わりに達したときに実行される。
  • `ON ERROR`: 予期しないエラーが発生した場合に実行される。`STATUS` ブックにはエラーコードが格納される。
  • `ON CONVERSION`: データ変換エラーが発生した場合に実行される。

これらの `ON` ユニットを適切に設定しておくことで、異常終了を防ぎ、エラー発生時の原因究明を容易にすることができる。特に、`ON ERROR` では、`STATUS` ブックの内容を確認し、どのようなエラーで異常終了したのかを把握することが極めて重要だ。

まとめ:現場で気をつけるべきポイント

PL/IのRECORD I/Oにおける `DECLARE FILE` の属性指定は、単なるデータ定義ではない。それは、プログラムがどのようにデータにアクセスし、他のプロセスとどのように協調(あるいは競合)するのか、その「振る舞い」を定義するものだ。

  • `UPDATE` モードは強力な排他制御を伴う: ファイルを更新する可能性がある場合は、他のプロセスとの競合に十分注意すること。
  • `SEQUENTIAL UPDATE` と `DIRECT UPDATE` のロック挙動を理解する: レコードを読み込んだ後、そのレコードがロックされていることを意識し、適切なタイミングでロックを解除すること。
  • VSAMなどのKSAMファイルでは、ロック粒度やレンジロックも考慮する: 複雑な共有リソースアクセスでは、シスプロとの連携が不可欠。
  • `ON` ユニットを効果的に使う: エラーハンドリングは、バッチ処理の堅牢性を高めるために必須。特に `ON ERROR` で `STATUS` を確認する癖をつけること。
  • ドキュメント(JCL、COBOL/PL/Iソース、VSAM定義など)をしっかり読む: 競合する可能性のあるプログラムや、ファイル定義そのものを理解することが、問題解決の第一歩。

これらの知識を頭に入れ、日々の保守や改修に臨んでほしい。マニュアルの「文字」ではなく、現場の「空気」を読みながらコーディングし、デバッグすることが、俺たちベテランエンジニアの仕事だからな。

不明な点があれば、いつでも聞きに来い。

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