順次データセットは、QSAMを利用すれば論理レコード単位で簡単にアクセスできます。区分データセット用にはBPAMが提供されています。しかしながら、BPAMの場合はブロック(物理レコード)単位でないとアクセスできず、ブロックを論理レコードにバラしたり(あるいは論理レコードをまとめてブロックにまとめたり)バッファリングの制御なども自分でやらねばなりません。バッファリング制御は、オプション処理的なものなのでやらなくてもアクセス自体はできます。しかし、ブロッキングとデブロッキングの処理は避けることができません。決して難しい処理ではありませんが、面倒であることは確かでやらずに済むならそれに越したことはありません。
JCLでDSN=dsname(member)のようにデータセット名の後ろに()でメンバー名まで指定すれば、区分データセットのメンバーをQSAMでアクセスすることができます。これは、区分データセットのメンバー自体が順次データセットと同じ構造を持っているからです。予めアクセスするメンバーが決まっているならJCL側の定義と組み合わせてQSAMでアクセスすることもできます。例えば、パラメーター・メンバーなどはその代表的なものの1つです。ところが、1つや2つのメンバーではなく数十あるいは全部のメンバーに順番にアクセスしたい、となった場合はどうでしょうか?JCL側ではメンバー名まで定義できないことになります。そのような場合は、アクセスするメンバーをJCLで定義する代わりに、動的割り振り(DYNALLOC)でアロケーションしてQSAMでアクセス方法もあります。しかし、DYNALLOCは比較的オーバーヘッドが大きい処理なのでアクセスするメンバー数が多くなるとパフォーマンスの問題が出てきます(ISPFの起動プロシージャー内で沢山のデータセットをALLOCコマンドで割り振っているとISPFが起動されるまでに時間が掛かることと同じ)。ここでは、メンバーをQSAMでアクセスでき、かつアロケーションのオーバーヘッドも掛からない方法として、JFCBを使用した区分データセットのオープン方法を紹介します。
1 2 3 4 |
//STEP1 EXEC PGM=PDSPRINT //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=USR1.JCLLIB // |
このような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情報を使ったデータセットのオープン処理を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
USING INFMJFCB,JFCBAREA ADDRESS TO JFCB READ AREA RDJFCB UT1DCB READ SYSUT1 DD STMT JFCB OI JFCBIND1,JFCPDS INDICATES DATASET IS PDS MEMBER MVC JFCBELNM,MEMBER1 SET NEXT MEMBER NAME BAS RA,MEMPROC MEMBER PROCESSING FOR MEMBER1 MVC JFCBELNM,MEMBER2 SET NEXT MEMBER NAME BAS RA,MEMPROC MEMBER PROCESSING FOR MEMBER2 : : MEMPROC DS 0H OPEN (UT1DCB,INPUT),TYPE=J OPEN DATASET WITH MODIFIED JFCB+ (OPEN THE SPECIFIED PDS MEMBER) : : UT1DCB DCB DDNAME=SYSUT1, QSAM DCB + DSORG=PS,MACRF=GL, + EXLST=UT1EXLST,EODAD=UT1EOD UT1EXLST DS 0F DC XL1'87',AL3(JFCBAREA) JFCBAREA DS 0F DC (JFCBLGTH)X'00' JFCB READ AREA : : DJFCB DSECT , IEFJFCBN LIST=YES JFCB DSECT : |
ポイントになる箇所は強調表示で示してあります。メンバー名は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ディレクトリーの読み込み方は、「アセンブラーで区分データセットのディレクトリー部を読み込む」で解説しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- MAINENTR CSECT DEFINE CONTROL SECTION USING *,12 DEFINE BASE REGISTER SAVE (14,12),, SAVE CALLER REGISTERS + 'MAINENTR &SYSDATE &SYSTIME' LR 12,15 GR12 --> OUR 1ST BASE ADDRESS LR 15,13 SAVE CALLER SAVEAREA CNOP 0,4 INSURE FULL WORD BOUNDARY BAS 13,*+4+72 AROUND OUR SAVEAREA DC 18F'-1' OUR GPR SAVEAREA ST 15,4(,13) SAVE CALLER SAVEAREA POINTER ST 13,8(,15) FORWARD CHAIN FOR LINK TRACE B MAINPROC DO MAINLINE PROCESSING * *----------------------------------* * * EXIT PROCESSING * * *----------------------------------* EXIT8 DS 0H LA 15,8 SET CC=8 B EXITPROC EXIT0 DS 0H SLR 15,15 SET CC=0 EXITPROC DS 0H L 13,4(,13) RESTORE CALLER SAVEAREA ST 15,16(,13) PASS RETURN CODE TO CALLER RETURN (14,12),T RESTORE CALLER REGISTERS + AND RETURN TO CALLER EJECT , *********************************************************************** * SAMPLE CODE FOR PRINTING PDS/PDSE ALL MEMBERS * * ===================================================== * * READ PDS/PDSE MEMBER BY QSAM. * *********************************************************************** MAINPROC DS 0H * *----------------------------------* * * OPEN OUTPUT DATASET * * *----------------------------------* OPEN (PRTDCB,OUTPUT) OPEN THE PRINT DATASET LTR R15,R15 SUCCESSFUL ? BNZ EXIT8 NO, MAY BE DD STMT NOT DEFINED * *----------------------------------* * * SETUP FOR PDS QSAM ACCESSING * * *----------------------------------* USING INFMJFCB,JFCBAREA ADDRESS TO JFCB READ AREA RDJFCB UT1DCB READ SYSUT1 DD STMT JFCB LTR R15,R15 SUCCESSFUL ? BNZ EXIT8 NO, MAY BE DD STMT NOT DEFINED OI JFCBIND1,JFCPDS INDICATES DATASET IS PDS MEMBER * *----------------------------------* * * OPEN PDS DIRECTORY BY QSAM * * *----------------------------------* OPEN (DIRDCB,INPUT) OPEN THE PDS DIRECTORY READDIR DS 0H GET DIRDCB READ NEXT DIR BLOCK RECORD LH R7,0(,R1) GR7 <--- REMAINING LENGTH AHI R7,-2 ADJUST IT(SUBTRACT COUNT FLD LN LA R6,2(,R1) GR6 <--- DIR BLOCK RECORD USING PDS2,R6 ADDRESS IT * *----------------------------------* * * PRINT NEXT PDS MEMBER * * *----------------------------------* MEMLOOP DS 0H CLC PDS2NAME,=8X'FF' END OF DIRECTORY ? BE CLOSDIR YES, END OF PROCESSING MVC JFCBELNM,PDS2NAME SET NEXT MEMBER NAME BAS R10,PRTMEMBR PRINT MEMBER RECORD * *----------------------------------* * * LOCATE TO NEXT MEMBER ENTRY * * *----------------------------------* NI PDS2INDC,PDS2LUSR DROP OTHER BITS SLR R15,R15 CLEAR WORKREG IC R15,PDS2INDC LOAD USER DATA LENGTH INDICATOR SLL R15,1 GET USER DATA LENGTH LA R6,PDS2USRD(R15) LOCATE TO NEXT MEMBER SLR R7,R15 UPDATE REMAINING LENGTH AHI R7,-(PDS2USRD-PDS2) ADJUST IT BP MEMLOOP LOOP FOR NEXT MEMBER B READDIR LOOP FOR NEXT DIR BLOCK DROP R6 FORGET PDS DIRECTORY BLOCK CLOSDIR DS 0H CLOSE (DIRDCB) CLOSE THE PDS DIRECTORY * *----------------------------------* * * CLOSE OUTPUT DATASET * * *----------------------------------* DOCLOSE DS 0H CLOSE (PRTDCB) CLOSE USED DATASET B EXIT0 ALL PROCESSING DONE EJECT , *********************************************************************** EJECT , *********************************************************************** * INTERNAL SUB ROUTINES * *********************************************************************** PRTMEMBR DS 0H MVC MEMNAME,JFCBELNM SET NEXT MEMBER NAME PUT PRTDCB,TITLE1 PRINT TITLE-1 LINE PUT PRTDCB,TITLE2 PRINT TITLE-2 LINE OPEN (UT1DCB,INPUT),TYPE=J OPEN DATASET WITH MODIFIED JFCB+ (OPEN THE SPECIFIED PDS MEMBER) PRTLOOP DS 0H GET UT1DCB READ NEXT RECORD LR R0,R1 LOAD RECORD ADDRESS PUT PRTDCB,(0) PRINT IT TO SYSPRINT B PRTLOOP LOOP UNTIL EOD UT1EOD DS 0H CLOSE (UT1DCB) CLOSE INPUT DATASET B 0(,10) RETURN TO MAINLINE EJECT , *********************************************************************** * DATA AREA * *********************************************************************** PRTDCB DCB DDNAME=SYSPRINT, QSAM DCB FOR PRINT OUT + DSORG=PS,MACRF=PM, + RECFM=FB,LRECL=80 DIRDCB DCB DDNAME=SYSUT1, QSAM DCB FOR PDS DIRECTORY + DSORG=PS,MACRF=GL, + RECFM=F,LRECL=256,BLKSIZE=256 UT1DCB DCB DDNAME=SYSUT1, QSAM DCB FOR PDS MEMBER + DSORG=PS,MACRF=GL, + EXLST=UT1EXLST,EODAD=UT1EOD UT1EXLST DS 0F DC XL1'87',AL3(JFCBAREA) JFCBAREA DS 0F DC (JFCBLGTH)X'00' JFCB READ AREA TITLE1 DC CL80'MEMBER=XXXXXXXX' MEMNAME EQU TITLE1+7,8 TITLE2 DC CL80'----+----1----+----2----+----3----+----4----+----5-X ---+----6----+----7----+----8' *=====================================================================* LTORG , EJECT , *********************************************************************** * DSECT * *********************************************************************** DJFCB DSECT , IEFJFCBN LIST=YES JFCB DSECT IHAPDS PDSBLDL=NO PDS DIRECTORY ENTRY DSECT YREGS , S/370 REGISTER EQUATES END |