データを変数ファイルに書き込む
Question
レコードを変数ファイル (任意のファイル) に書き込もうとしているのですが、何度やっても「Buffer length longer than record for member FILEX.(バッファー長がメンバー FILEX のレコードより長いです)」というエラーが表示されます。私のプログラムはどのレコード長でも動作するはずで、(読み取りだけではなく) 書き込みが必要です。私のショップには SQL プリコンパイラーはありません。どうしたらよいでしょうか。
Answer
こうしたファイルを扱う場合の私のお気に入りの方法は、C レコード入出力 API を使用する方法です。これらは ILE C 向けに設計されてはいますが、ILE RPG (さらに言えば、ILE CL) 用に呼び出して使用できます。C プログラマーがデータベース・ファイルにアクセスする最も一般的な方法は、SQL を通してアクセスする方法です。しかし、IBM i の ILE C も、ファイルに対する RPG のネイティブ・アクセスに似て、レコード・レベルで入出力する API セットを持っています。
しかし RPG 命令コードと異なり、C ルーチンはすべてサブプロシージャーとして実装されており、コンパイル時にファイルの名前やそのレイアウトを知っている必要はありません。そのメリットの 1 つとして、コード変更をせずにあらゆるファイルと連携させることができるということです。デメリットは、RPG の命令コードよりもわずかに速度が遅いということです。
さらに状況を明確にするため、質問された読者は以下のコードを送信してくれました (これは動作せず、記載のエラーを生成している点に注意してください)
:DDS コード:
A R OUTFILE1 TEXT('TEMP FILE')
A FIELDA 5000A
RPG コードを図5 に示します。
前述のコードは、入力パラメーターに指定された名前によって異なるファイルを開き、最初のレコードを読み込んで、そのレコードが存在する場合は (ファイルが空になるように) 削除し、第 3 パラメーターにあるデータを使用して新しいレコードを書き込みます。
同じことをする場合 (ただ、エラーがないように)、3 種類の API を使用する必要があります。
_Ropen: レコード単位ファイルを開きます
_Rwrite: レコードをレコード単位ファイルに書き込みます
_Rclose: レコード単位ファイルを閉じます
これらの API (とさらに相当数の API の) のプロトタイプを既に作成し、RECIO_H というコピーブックにそれらを置きました。RECIO_H メンバー全体をここで掲載しませんが、本記事の最後にあるコード・ダウンロード・リンクに含まれています。API 名を RPG から呼び出す場合、その名前から先行する下線を削除しなければならないことを指摘しておきたいと思います。RPG では、プロトタイプは下線文字で開始することができないためです。例えば、私の _Rclose プロトタイプは次のようになります。
D Rclose PR 10I 0 ExtProc('_Rclose')
D fp likeds(RFILE_T)
これを RPG から呼び出す場合、(プロトタイプの左手側で示しているように) Rclose という名前を使用しますが、ExtProc() キーワードのおかげで、実際は ILE C で _Rclose ルーチンを呼び出します。 難しい話はこれくらいにして、図6 は API を使用してレコードを作成する RPG プログラムを示します。
Ropen() コールで指定した wr+ は、ファイルが既に存在する場合はファイルをクリアし、読み取りと書き込みの両方でファイルを開くようシステムに指示します。ファイルがクリアされるため、最初の RRN に繋いで、ファイルを削除する必要はありません。
いったんファイルを開いたら、ファイルのレコード長 (myFile データ構造体の buf_length サブフィールドに入ります) を確認します。コマンド・ラインからのデータの長さがレコード長と同じ (あるいはそれより短い) ことを確認し、Rwrite() を呼び出してレコードを書き込みます。Rclose() を素早く呼び出すとファイルが閉じます。(RPG のネイティブ・レコード入出力を使用しなかったため、私のファイルは RPG では自動的に閉じません)。最後に、プログラムが終了します。