BPAM (Basic Partitioned Access Method)
BPAM is used with partitioned data sets. To understand anything about BPAM, one must know something of PDS structure.
A partitioned data set (PDS) as designed to contain a number of (relatively) small data sets called members, one after another, within its designated space. It has a directory listing these.
Partitioned data sets are used to store various kinds of data
(load modules, JCL procedures and macros, among other things) and a common task for the operating system (or the assembler, or a compiler) is to search through the directories of one or more PDSes listed in JOBLIB, STEPLIB, SYSLIB or JCLLIB to find a member with a specific name, so that member can be read.
While BPAM can be used for various purposes, its most important use is the kind of search just described. The search can be done using the FIND macro. Once the member has been located using the directory information, it can be read using the READ macro (much the same as with BSAM).
If we want to locate and read not just one member of a PDS but several members, or if we want to read a specific member more than once, it may be better to use the BLDL macro, which reads information from the PDS directory about the members we request and stores it in a data structure in memory. This includes information about the location of each member, and the POINT macro can then be used to prepare for reading the member.
BPAM can also be used for other tasks related to partitioned data sets. The STOW macro (not included in these notes) can be used to modify a PDS directory by adding, changing, replacing or deleting an entry.
This is a rather abbreviated description of BPAM. For more
information, please consult the manuals Using Data Sets and Macro Instructions for Data Sets.
------
PDS Directory Structure
The PDS directory is at the beginning of the PDS’s space and is organized in blocks of 256 bytes each. The blocks are not organized into records in the usual fashion.
Each block contains information about members:
---- the number of bytes used in this block (2 bytes)
---- data about one or more members
For each member, we have:
---- name of the member (8 characters)
---- TTR value (3 bytes) where:
TT = a relative track number, i.e., on which track belonging to
this PDS does this member begin, and
R = a relative block number, i.e., in which block of the track
does this member begin
---- C (1 byte) where:
bit 0 = 1 indicates the member name is an alias
bits 1-2 = number of pointers to locations with the member (not
of concern to us at present)
bits 3-7 = length of the user data field as a number of halfwords
---- user data field (also not of concern to us at present)
A PDS member may have alternate names known as aliases. The alias will be listed in the directory and the TTR value will be the same as for the original name.
If we have several PDSes of similar characteristics (such as LRECL), we can concatenate them in the JCL under one DD name, and they can be processed as if they were one large PDS.
------
DCB macro
The DCB macro for BPAM is much the same as that for BSAM, with a few differences:
The mandatory parameters are DDNAME, DSORG, MACRF and EODAD.
The value of DSORG should be “PO”, indicating a partitioned data set, rather than “PS”.
The possible values for MACRF are ‘R’ for READ and ‘W’ for WRITE.
We do not have a locate mode with BPAM. As with BSAM, data is copied
from the PDS into our buffer.
It will be the CHECK macro that transfers control to the EODAD in the event of encountering end-of-file.
BLKSIZE and LRECL can be obtained from the label record. In any case, if we do want to read a member, we will need to know the LRECL and BLKSIZE.
OPEN macro
This is the same as with BSAM. Our choices are to open for
INPUT, OUTPUT or UPDAT. (UPDAT is used for rewriting one record in
place.)
CLOSE macro
This is the same as with BSAM.
READ macro
This is the same as with BSAM.
WRITE macro
This is the same as with BSAM.
CHECK macro
This is the same as with BSAM.
FIND macro
The FIND macro is used to search the directory of a PDS (or several PDSes concatenated together) for information about a member with a specific name. The next READ of the data set will occur at the beginning of that member. As this is an input operation, the data set must already be open for input. As the data set is partitioned, the DCB for it should have TYPORG=PO rather than PS.
The FIND macro is used as follows:
FIND dcbname,nameaddress,D
where:
nameaddress = address of an 8-byte field containing the member’s
name, left-justified, padded with blanks as needed
D indicates that only the name of the member is
provided
There are other possibilities for FIND; the above is a simple case.
FIND gives us a return code in register 15: 0 if the member was
located and nonzero if anything went wrong. (In the latter case, a
reason code is also provided, in register 1.)
BLDL macro
The BLDL macro is used to obtain information from the directory of a PDS (or several PDSes concatenated together) and store the data in a user-provided storage area which we will call the “BLDL list”. This is an input operation, so the data set should first be opened for input.
The BLDL list has the following structure (in this order):
---- FF = a halfword field containing the number of entries in the
list
---- LL = a halfword field containing the length of each entry in the
list (a number of bytes = at least 12)
---- one or more entries each having the following structure:
--- an 8-byte field containing the name of a member of the PDS
(left justified, padded if necessary with blanks)
--- TT = a 2-byte binary field containing the relative track
number where the member begins (relative to the beginning of
the PDS)
--- R = a 1-byte binary number containing the relative block
number on the track indicated by TT
--- K = a 1 byte binary number indicating which of the PDSes
concatenated together contains the member; for the first or
only PDS, this is 0
--- Z = a 1-byte binary number indicating where the member was
found (a private library, link library, etc.)
--- C = a 1-byte binary number providing information about
whether the name sought is a member name or an alias, about
“note list fields” and about the size of the user data field
--- 0 to 62 bytes of “user data”
The user supplies the FF, LL and the names. When BLDL is executed, the TTR and K fields are filled in, and more as well (Z, C and user data), provided LL is large enough.
The BLDL macro is used as follows:
BLDL dcbname,BLDL list address
The names should be in ascending alphanumeric order. Of course, we could obtain the names of the members at run time (from a parameter passed to our program or by reading some other input file) and then move them into the BLDL list.
BLDL gives us a return code in register 15: 0 if all members were located, 4 if at least one member was not found, and 8 if anything went wrong. (In the latter case, a reason code is also provided, in register 1.)
There are more details to be known about BLDL, such as “note list fields”, which are not covered here.
POINT macro
The POINT macro prepares for the next READ or WRITE operation to begin at a specific block address. The data set must be open for input or output as needed.
The block address is supplied as a 4-byte field TTRZ as follows:
*** TTR = 3 bytes as described above in the BLDL list
*** Z = a byte containing the value 0
A common way to obtain the TTR value is to take it from a BLDL list after using BLDL.
The POINT macro is used as follows:
POINT dcbname,TTRZ
Normally POINT is followed immediately by a READ or WRITE.
------
Reading the PDS directory
It is possible to read the directory of a PDS directly.
---- The DD statement should name the PDS but without a member name.
---- We can use QSAM with the GET macro or BSAM with the READ macro.
---- We need BLKSIZE=256 and RECFM=F (or RECFM=U).
---- The last directory entry has a member name = 8X'FF'. Anything
in the last directory block after that is unpredictable.
Notice that for each block, we know how many bytes of that block are in use.
After we read the last directory block, we will encounter end-of-file and the CHECK macro will use the EODAD.
------
It is useful to realize that if all we want to work with is one specific member of one specific PDS, we may not need BPAM at all. We can, on a DD statement, specify DSN=pdsname(membername), and then we can work with the data set using BSAM or QSAM as if it is an ordinary sequential file. We can read it or write to it; we can even create a new member of the PDS in this fashion. (The OPEN and CLOSE macros do the work of PDS directory maintenance for us.)