QSAM Basics | Record Formats |
Programming for QSAM | Allocating Data Sets |
Opening and Closing Data Sets | Reading, Writing, and Updating Records |
QSAM Return Codes | Service Descriptions |
QSAM Basics
Using QSAM you can access three types of data sets. These are
described in the sections that follow.
A physical sequential data set's records can be updated in place, and can be extended (records added to the end), if the data set is allocated DISP=MOD.
Physical sequential data sets may reside on direct access devices or on tape.
When a member is added to a PDS, an entry for the member is inserted into the directory. Entries in the directory are ordered by member name in ascending sequence. Only one user at a time can add a member to a PDS.
A member's records can be updated in place. However, the only way to extend a member is to completely rewrite it (i.e., DISP=MOD will not cause records to be added to the end of a member as it does with sequential files).
When a member is deleted from a partitioned data set, its entry is removed from the directory. However, the space previously occupied by the member's records cannot be reused until the data set is "compressed" by a utility such as IEBCOPY.
PDSE data sets, from a usage standpoint, are identical to partitioned data sets but with additional capabilities. Most importantly, PDSEs permit multiple users to write to a data set simultaneously (though each user must be writing a different member). PDSEs also reuse storage that is freed by member deletions, and thus, do not require periodic compression.
When using QSAM to read a partitioned data set member, you must allocate the data set including the name of the member. If you allocate a PDS without specifying a member name, you will read the data set's directory. Thus, to read all of the members in a data set using QSAM, you must allocate, open, read, close, and free each member individually (a computationally expensive proposition). Because this is a common operation, REXXTOOLS provides another method for processing PDSes, the BPAM interface (see "BPAM Functions" ).
Partitioned and partitioned extended data sets can reside only on DASD. In addition, PDSEs must be managed by DFSMS.
//DDIN DD * This is a sysin record This is too This is the last one /*SYSIN data sets have a logical record length of 80 bytes. The data set is terminated with a "/*" or another JCL statement. SYSIN data sets cannot be written. They can be read only.
SYSOUT data sets are created by specification of the SYSOUT keyword on either a DD or ALLOCATE statement. For example:
//DDOUT DD SYSOUT=*,RECFM=VB,LRECL=133SYSOUT data sets can be written only.
Note: It may be necessary to specify DCB characteristics
for SYSIN, SYSOUT, and temporary data sets in order to open them
using the REXXTOOLS QSAM interface.
Record Formats
The records in sequential, partitioned, and SYSIN/SYSOUT data
sets can take several forms:
The REXXTOOLS QSAM functions support the following formats (RECFMs):
F | FA | FB | FBA |
FBM | FBS | FBSA | FBSM |
FM | FS | FSA | FSM |
V | VA | VB | VBA |
VBM | VM | U | UA |
UM |
The individual letters of RECFM indicate the following:
For information regarding the selection of an appropriate data
set organization and record format refer to the IBM publication
Using Data Sets
for your system's level of DFP or DFSMS.
Programming For QSAM
The basic flow of a program that processes a data set using QSAM
is as follows:
Note: To process a PDS/PDSE member, you must specify the
member name on the allocation. If you allocate just the PDS data
set name, your program will read the directory.
Opening and Closing Data Sets
To associate your program with the data set you want to process,
you use the
OPEN
function. The
CLOSE
function performs the opposite action by disassociating your
program with the data set.
Shadow REXXTOOLS maintains information about open QSAM files in a data structure associated with the task under which the OPEN function was executed. The information is maintained by ddname. Files remain registered with REXXTOOLS and open until they are explicitly closed, or until the task that opened them terminates.
All REXX programs under a MVS task share the same REXXTOOLS QSAM data structures. Thus if program A calls program B (REXX CALL or function call), any ddname that is opened by either program A or program B is known to the other. File sharing also extends to directly subtasked REXX programs. As a consequence, if Program A attaches program B, the files opened by program A are known by program B. However, files opened by program B will not be known to A when control is returned. This is because task termination will close all files opened by program B.
Notes:
VERY IMPORTANT: It is possible to open a newly allocated data set for input. The operation of QSAM in this case is undefined. You may successfully read what appears to be valid data, or (and this is more likely) your program may encounter errors and possibly abnormally terminate.
If the data set is allocated with a status of NEW, records will be added to the data set starting at the beginning of the data set's space (or the first available space in the case of a PDS or PDSE member). If the data set is allocated with a status of OLD, the records will replace existing records, if any. If a sequential data set is allocated with a status of MOD, records will be appended to the end of the data set. A status of MOD will not cause additional records to be appended to the end of a PDS or PDSE member.
/* REXX */ address rexxtool "alloc fi(indd) da(user.data(timecard)) shr" if open('qsam','indd','input') <> 0 then do say 'OPEN failed with RC='rc 'REASON='reason exit 8 end timerec = get('indd') do while rc = 0 parse var timerec lname +10 fname +10 timein +8 timeout +8 timerec = get('indd') end call close 'indd' "free fi(indd)"
/* REXX */ address rexxtool "alloc fi(outdd) da(data.out) new sp(1 1) track", "dsorg(ps) recfm(f b) lrecl(80) unit(sysda)" call open 'qsam', 'outdd', 'output' parse pull record do while record <> '' call put 'outdd', record parse pull record end call close 'outdd' "free fi(outdd)"
In the following example, a sequential data set's records are updated. A 2-byte packed decimal date field in YY format is converted to a 2-byte binary date that contains the century.
/* REXX */ if open('qsam','iodd','update') <> 0 then do say 'OPEN failed with RC='rc 'REASON='reason exit 8 end record = get('iodd') do while rc = 0 parse var record firstpart +25 date +2 lastpart date = d2c(p2d(date)+1900,2) if put('iodd',firstpart||date||lastpart) <> 0 then do say 'PUT failed with RC='rc 'REASON='reason exit rc end record = get('iodd') end if close('iodd') <> 0 then say 'CLOSE failed with RC='rc 'REASON='reason exitNote: For this example, the IODD ddname is assumed to be allocated in the JCL prior to execution. P2D is a REXXTOOLS function for converting packed decimal data to REXX decimal.
In addition, except for the GET function which returns a record, all QSAM functions return the return code as their value. For example, the following code will display the return code 2 times, once as OPEN's returned value, and once as the value of the RC variable
say "RC="open('qsam','indd','input') "RC="rc "REASON="reasonUnless otherwise noted, the values for RC and REASON are taken directly from the underlying QSAM macro return and reason codes. In all cases, a return code of zero indicates success.
In the case of GET and PUT, the underlying QSAM macros do not produce return codes. The REXXTOOLS GET function returns RC=8 when end-of-file is reached. All other non-zero GET and PUT return codes are ABEND codes and are accompanied by an "IEC" message.
Very Important: The complete list of QSAM return and reason codes can be found in the IBM publication Macro Instructions for Data Sets for your system's level of DFP or DFSMS. ABEND codes and "IEC" messages are documented in one or more MVS messages and code publications.
Note: The return and reason codes (including ABEND codes)
produced by the QSAM functions are all decimal (not hexadecimal)
values.
Service Descriptions
The sections that follow describe the syntax and operation of the
QSAM-related functions.