QSAMでPDSメンバーにアクセスする

順次データセットは、QSAMを利用すれば論理レコード単位で簡単にアクセスできます。区分データセット用にはBPAMが提供されています。しかしながら、BPAMの場合はブロック(物理レコード)単位でないとアクセスできず、ブロックを論理レコードにバラしたり(あるいは論理レコードをまとめてブロックにまとめたり)バッファリングの制御なども自分でやらねばなりません。バッファリング制御は、オプション処理的なものなのでやらなくてもアクセス自体はできます。しかし、ブロッキングとデブロッキングの処理は避けることができません。決して難しい処理ではありませんが、面倒であることは確かでやらずに済むならそれに越したことはありません。
JCLでDSN=dsname(member)のようにデータセット名の後ろに()でメンバー名まで指定すれば、区分データセットのメンバーをQSAMでアクセスすることができます。これは、区分データセットのメンバー自体が順次データセットと同じ構造を持っているからです。予めアクセスするメンバーが決まっているならJCL側の定義と組み合わせてQSAMでアクセスすることもできます。例えば、パラメーター・メンバーなどはその代表的なものの1つです。ところが、1つや2つのメンバーではなく数十あるいは全部のメンバーに順番にアクセスしたい、となった場合はどうでしょうか?JCL側ではメンバー名まで定義できないことになります。そのような場合は、アクセスするメンバーをJCLで定義する代わりに、動的割り振り(DYNALLOC)でアロケーションしてQSAMでアクセス方法もあります。しかし、DYNALLOCは比較的オーバーヘッドが大きい処理なのでアクセスするメンバー数が多くなるとパフォーマンスの問題が出てきます(ISPFの起動プロシージャー内で沢山のデータセットをALLOCコマンドで割り振っているとISPFが起動されるまでに時間が掛かることと同じ)。ここでは、メンバーをQSAMでアクセスでき、かつアロケーションのオーバーヘッドも掛からない方法として、JFCBを使用した区分データセットのオープン方法を紹介します。

このようなJCLで、SYSUT1 DDステートメントに定義された区分データセットの全メンバーをSYSPRINT DDステートメントに定義されたデータセットへプリントするプログラムの例です。

DDステートメント定義情報の変更を行ってからデータセットをオープンする

JFCBを使用したデータセットのオープン処理を行うため、最初にJFCBを読み込みます。JFCBは、JCLのDDステートメントの定義情報だと考えればいいです。読み込んだJFCBにはJCLのDSNパラメーターで指定されたデータセット名は格納されていますが、メンバー名は当然ながら入っていません。メンバー名指定なしの区分データセットをQSAMでオープンするとディレクトリー部の先頭に位置付いてしまい、レコード形式などが不一致となるのでS013でABENDします。しかし、DSNパラメーターにメンバー名が入っていればオープンした時にそのメンバーの先頭に位置付けられてQSAMでアクセスができます。

従って、読み込んだJFCBのメンバー名フィールドにアクセスしたいメンバー名をセットすれば、JCL DDステートメントのDSNパラメーターに括弧で括ってメンバー名まで指定したことと同じ状況を作り出せます。その為には、データセットのオープン前にJFCBを読み込み、その内容(JCL DDステートメント情報)を変更してから、プログラムで変更したJFCB情報を使ったデータセットのオープン処理を行います。

ポイントになる箇所は強調表示で示してあります。メンバー名はJFCBELEMフィールドに設定します。DDステートメントにDSN=dsname(member)と定義されると、JFCBのJFCBDSNMにdsnameが、JFCBELEMにmemberが格納されます。従って、オープン前にJFCBELEMにメンバー名を設定すれば、DDステートメントでメンバー名まで指定したことと同じになります。なお、オープン時に区分データセットのメンバー部に位置付けさせるためには、メンバー名の設定に加えて、JFCBIND1フィールドのJFCPDSフラグをオンにする必要があります。JFCPDSフラグは1度オンにすれば、MVS(DFSMSdfp)側で変更されることはありません。
JFCBの準備ができたら、データセットをQSAMでオープンします。RDJFCBマクロで使用したDCBを指定してOPENマクロを発行します。この時、OPENマクロにTYPE=Jパラメーターを追加します。TYPE=Jは、JFCBがユーザー側で提供されたことを示します。TYPE=Jパラメーターを忘れると変更後のJFCBは反映されません。メンバーの読み込みならGETマクロ、メンバーの書き込みならPUTマクロを使用します。QSAMなので論理レコード単位でのアクセスです。1つのメンバーの処理を終えたら、データセットをクローズします。別のメンバーへの処理を行うのであれば、JFCBELEMに次のメンバー名を設定してオープンから繰り返します。
なお、メンバー内容を書き込みする場合、クローズ時にメンバー・ディレクトリーのユーザー・データ部分は消えてしまいます。ISPFエディターで保管したメンバーをアプリケーション・プログラムのQSAMアクセスで書き直すような場合、メンバーのISPF統計データは消えてしまうことは知っておく必要があります。必要であれば、BLDLマクロなどでメンバー・ディレクトリーの情報を読み取っておき、後でBPAMでオープンし直してSTOWマクロで必要なユーザー・データを書き込む、などの処理を追加します。※JFCBの読み込み方とRDJFCBマクロの使い方は、「DD文定義情報を得る(DEVTYPEとRDJFCB)」で解説しています。

サンプル・プログラム(PDSPRINT)ソース・コード

PDS内メンバーのQSAMアクセスをセットアップした後、PDSデータセットのディレクトリー部をやはりQSAMでオープンします。
GETマクロでPDSディレクトリー・ブロックを1ブロック読み込み、その中に登録されているメンバー・エントリーを取り出します。メンバー名をJFCBにセットしたら、PDSメンバーをオープンしてGETマクロで1レコード読み込み出力側のデータセットに書き出します。メンバーがEODになるまで処理を繰り返し、PDSメンバーをクローズします。
読み込み済みディレクトリー・ブロック内の次のメンバー・エントリーに位置付けて、メンバー名をJFCBにセットする処理から繰り返します。ディレクトリー・ブロック内の全てのメンバーを処理し終えたら、次のディレクトリー・ブロックの読み込みから繰り返します。次に処理すべきメンバー・エントリーのメンバー名がxFFFFFFFFFFFFFFFFであれば(これ以上メンバーがないことを示す)、PDSデータセットのディレクトリー部と出力側のデータセットをクローズしてプログラム処理を終了します。※PDSディレクトリーの読み込み方は、「アセンブラーで区分データセットのディレクトリー部を読み込む」で解説しています。