__________________________________________________________
Handling Variable-Length Records in COBOL on Z/OS
Captain Uday Prasad
(Based on IBM’s DFSMS Using Data Sets Manual, SC26-7410-08 / VSAM demystified. – IBM REDBOOK)
In a world where data never fits neatly into boxes, COBOL on z/OS bends the rules—without breaking them!"
Have you ever tried to fit an elephant in a shoebox? In today's changing data world, that's how fixed-length records feel. Luckily, COBOL on z/OS knows how to deal with records of different lengths. It is flexible, quick, and designed to handle chaos in the real world. COBOL doesn't just handle changing transaction sizes or unpredictable data streams; it lives on them. One byte at a time, let's look at how this old engine keeps up with today's needs.
Introduction
On IBM z/OS, where every byte and cycle counts, COBOL’s support for variable-length records (VLRs) is a study in efficiency. By leveraging RECFM=V, RDW, and strategic file definitions, COBOL dynamically handles data streams of unpredictable size—without wasting disk or memory. Let’s dissect the mechanisms that make this possible.
A Data set or a file is a collection of logically related data and can be a source program, a library of macros, or a file of data records used by a processing program. Data records are the basic unit of information used by a processing program. You can store data on secondary storage devices, such as a direct access storage device (DASD) or magnetic tape volume. The term DASD applies to disks or to a mass storage medium on which a computer stores data. You can store all types of data sets on DASD but only sequential data sets on magnetic tape.
|
A sequential dataset—often known as a PS or Physical Sequential dataset—is a basic data structure in z/OS used to store and control data in a linear succession.
Records stored in a file may be in a FIXED length
format or a VARIABLE length format. Files with fixed-length records possess a
predetermined record length. An employee file with a fixed-length record of 16
bytes will appear as follows upon creation.
In the above example the Logical record length of the employee file is 16 bytes for all the records. It is fixed and once defined it doesn’t change.
A variable-length record on the other hand lacks a predetermined length. Each record in the file varies in its length based on the fields contained inside each record. For instance, the same file as above will appear as follows if the records are of variable lengths. The length of the name field may differ for each record.
|
Here is how the FD entry for the two files are defined in a COBOL program.
What Does Using a Variable Record Length Do?
In a fixed-length file, each record occupies a predefined, constant amount of space. If a record's actual data is shorter than this fixed length, the remaining space is often padded with blanks or other filler characters and may be considered as a waste of space.
Reduced storage space needs is one of the most important advantages of variable record length. Should your data records have different quantities of information, the usage of fixed-length records would cause loss of space in records not fully using the overall length allocated. Variable record lengths only consume the storage space needed for the data included inside each record.
The RDW (Record Descriptor Word) Concept
Non VSAM files
In a variable length record in a sequential file each record consists of an RDW followed by the actual data. The length of the data portion can vary for each record. The RDW's length (typically 4 bytes on z/OS) is constant, and its first two bytes usually indicate the total length of the record (RDW + Data).
In order for the system to effectively manage records of varying lengths, it is customary to prefix each record with a Record Descriptor Word, also known as an RDW. The whole length of the record, including the RDW record itself, is referred to as the record length.
The RDW is not typically directly manipulated by the COBOL programmer in everyday situations. The construction of the RDW and its interpretation are both handled by the operating system and access methods. In most cases, the COBOL programmer doesn't directly change the RDW. The operating system and access methods take care of both building the RDW and figuring out what it means. The operating system and access methods handle both the construction and interpretation of the RDW. However, the file when created should have 4 extra bytes defined to accommodate the RDW in the allocation panel of ISPF. See the example below.
How It Works in Practice:
COBOL automatically:
When writing,
· Calculates record length
· Prepends the RDW
When reading:
· z/OS first reads the RDW to determine record length
· COBOL fetches exactly that many bytes
Key Advantages:
- No wasted space (unlike fixed-length records)
- Handles records from 5 bytes to 32KB+ in same file
- Backward compatible with most z/OS utilities
Cobol program to convert a sequential file with fixed length record to a variable length sequential file.
IDENTIFICATION DIVISION.
*
PROGRAM-ID. TEST2.
* AUTHOR. ZEDINFOTECH.
DATE-WRITTEN. 2025-05-20.
*
*REMARKS. Reads fixed-length records from one sequential file
*and writes them as variable-length records to another.
*
ENVIRONMENT DIVISION.
*
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT FIXED-IFILE
ASSIGN TO 'FIXIN'
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL.
*
SELECT VAR-OUT-FILE
ASSIGN TO 'VAROUT'
ORGANIZATION IS SEQUENTIAL
ACCESS MODE IS SEQUENTIAL.
*
DATA DIVISION.
*
FILE SECTION.
*
FD FIXED-IFILE
RECORD CONTAINS 80 CHARACTERS
RECORDING MODE IS F.
01 FIXED-INPUT-RECORD.
05 IN-EMP-ID PIC X(10).
05 IN-EMP-NAME PIC X(20).
05 PIC X(50).
*
FD VAR-OUT-FILE
RECORD VARYING FROM 1 TO 80 CHARACTERS
DEPENDING ON WS-OUTPUT-RECORD-LENGTH
RECORDING MODE IS V.
01 VAR-OUTPUT-RECORD PIC X(80).
*
WORKING-STORAGE SECTION.
*
01 ARE-THERE-MORE-RECORDS PIC X(01) VALUE 'Y'.
88 NO-MORE-RECORDS VALUE 'N'.
*
01 WS-OUTPUT-RECORD-LENGTH PIC 9(04) COMP.
* This will hold the length of the data for the output rec
* COBOL adds the 4-byte RDW automatically.
01 WS-TEMP-OUTPUT-DATA.
05 WS-OUT-EMP-ID PIC X(10).
05 WS-OUT-EMP-NAME PIC X(20).
*
PROCEDURE DIVISION.
*
000-MAIN-LOGIC.
OPEN INPUT FIXED-IFILE
OUTPUT VAR-OUT-FILE
PERFORM UNTIL NO-MORE-RECORDS
READ FIXED-IFILE
AT END
SET NO-MORE-RECORDS TO TRUE
NOT AT END
PERFORM 100-PROCESS-RECORD
END-READ
END-PERFORM
CLOSE FIXED-IFILE
VAR-OUT-FILE
DISPLAY 'File conversion complete.'
STOP RUN.
*
100-PROCESS-RECORD.
*
* Move data from fixed input record to working storage
MOVE 1 TO WS-OUTPUT-RECORD-LENGTH
MOVE IN-EMP-ID TO WS-OUT-EMP-ID
MOVE IN-EMP-NAME TO WS-OUT-EMP-NAME
STRING WS-OUT-EMP-ID DELIMITED BY SIZE
WS-OUT-EMP-NAME DELIMITED BY SPACE
INTO VAR-OUTPUT-RECORD
POINTER WS-OUTPUT-RECORD-LENGTH
END-STRING
* The POINTER from STRING will be 1 + actual length used
* So, subtract 1 to get the true length of the data.
SUBTRACT 1 FROM WS-OUTPUT-RECORD-LENGTH
IF WS-OUTPUT-RECORD-LENGTH < 0
MOVE 0 TO WS-OUTPUT-RECORD-LENGTH
END-IF.
* write the variable-length record
WRITE VAR-OUTPUT-RECORD
INVALID KEY
DISPLAY 'Error writing record for Employee'
NOT INVALID KEY
CONTINUE
END-WRITE.
_______________________________________________________________________
Jcl to run the program
//SHRDV03R JOB NOTIFY=&SYSUID
//STEP01 EXEC PGM=TEST2
//* This JCL will run your cobol program
//STEPLIB DD DSN=SHRDV03.ZEDINFO.COBOL.LOAD,DISP=SHR
//SYSPRINT DD SYSOUT=*
//FIXIN DD DSN=SHRDV03.ZEDINFO.IFILE,DISP=SHR
//VAROUT DD DSN=SHRDV03.ZEDINFO.VFILE,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,VOL=SER=ZAPRD4,
// SPACE=(TRK,(2,1),RLSE),
// DCB=(RECFM=V,LRECL=84,BLKSIZE=840)
VSAM files
The organization of data in all VSAM data sets, except linear data sets, is arranged in records, also called logical records. A logical record is the user record requested from, or given to, the VSAM record management function.
Remember: The terms logical record and record are used interchangeably
Control interval
Logical records of VSAM data sets are stored differently from logical records in non-VSAM data sets. VSAM stores records in control intervals. A control interval is a continuous area of direct access storage that VSAM uses to store data records and control information that describes the records. Whenever a record is retrieved from direct access storage, the entire control interval containing the record is read into a VSAM I/O buffer in virtual storage. The desired record is transferred from the VSAM buffer to a user-defined buffer or work area.
Control interval (CI) is a unique VSAM concept. It is the fundamental building block of every VSAM data set. A CI is a contiguous area of DASD volume track that VSAM uses to store data logical records and control information that describes the records in the CI.
A CI is also the unit of information that VSAM transfers between the DASD device and the central storage during one I/O operation. If the CI is formed by several physical blocks, these blocks are read or written in a single I/O operation (with several Read or Write CCWs). Whenever a logical record is retrieved from a DASD device, the entire CI containing the record is read into a VSAM I/O buffer in virtual storage. The logical record is then transferred from the VSAM buffer to a user-defined logical record buffer or work area. The CI size can be from 512 byes to 32 KB.
A control interval consists of:
· Logical records
· Free space
· Control information fields - CIDF and RDF
In a linear data set, all of the control interval bytes are data bytes. There is no imbedded control information.
CIDFs are 4 bytes long, and contain the amount and location of free space. RDFs are 3 bytes long, and describe the length of records and how many adjacent records are of the same length. The four bytes at the end of a control interval contains the displacement from the beginning of the control interval to the start of the free space and the length of the free space.
If two or more adjacent records have the same length, only two RDFs are used for this group. One RDF gives the length of each record, and the other gives the number of consecutive records of the same length. Figure 5 shows RDFs for records of the same and different lengths:
If a record exceeds the maximum record length, an error message is generated. If a record in an entry-sequenced or key-sequenced data set, or variable-length RRDS is smaller than the maximum record length, VSAM saves disk space by storing the actual record length in the RDF. However, in a fixed-length RRDS, records do not vary in length. The RDF reflects the length of the record slot, and cannot be adjusted.
Since the RDF keeps an account of Length and numbers of the variable records in each CIDF in VSAM files. There is no need of any RDW to be defined as in the case of a non VSAM file.
Free Space
When a key-sequenced data set is defined, unused space can be scattered throughout the data set to permit records to be inserted or lengthened. The unused space is called free space. When a new record is added to a control interval (CI) or an existing record is lengthened, subsequent records are moved into the following free space to make room for the new or lengthened record.
Conversely, when a record is deleted or shortened, the space given up is reclaimed as free space for later use. When you define your data set, use the FREESPACE parameter to specify what percentage of each CI is to be set aside as free space when the data set is initially loaded.
Within each CA, reserve free space by using free CIs. If you have free space in your CA, it is easier to avoid splitting your control area when you want to insert additional records or lengthen existing records. When you define your data set, specify what percentage of the control area is to be set aside as free space, using the FREESPACE parameter.
ESDS Entry-Sequenced Data Sets with variable length records
An entry-sequenced data set is comparable to a sequential (non-VSAM) data set. It contains records that can be either spanned or non-spanned. As below shows, records are sequenced by the order of their entry in the data set, rather than by a key field in the logical record.
![]() |
R1 |
R2 |
R3 |
|
Records are added only at the end of the data set. Existing records cannot be deleted. If you want to delete a record, you must flag that record as inactive. As far as VSAM is concerned, the record is not deleted. Records can be updated, but they cannot be lengthened. To change the length of a record in an entry-sequenced data set, you must store it either at the end of the data set (as a new record) or in the place of a record of the same length that you have flagged as inactive or that is no longer required. When a record is loaded or added, VSAM indicates its relative byte address (RBA). The RBA is the offset of this logical record from the beginning of the data set. The first record in a data set has an RBA of 0. The value of the RBA for the second and subsequent records depends on whether the file is spanned and on the control interval size chosen for the file, either manually or automatically. In general, it is not possible to predict the RBA of each record, except for the case of fixed-length records and a known control interval size.
COBOL Definition for an ESDS FILE Example:
FD VAR-OFILE
RECORD VARYING FROM 1 TO 80 CHARACTERS
DEPENDING ON WS-OUTPUT-RECORD-LENGTH.
01 VAR-OUTPUT-RECORD.
05 OUT-EMP-ID PIC 9(10).
05 OUT-EMP-NAME PIC X (70).
![]() |
JCL FOR CREATION OF ESDS FILE FOR A MAX RECORD SIZE OF 16 BYTES
//SYSIN DD *
DEFINE CLUSTER (NAME (SHRDV03.ESDS. EMPV.CLUSTER)-
TRACKS (2,1) -
VOLUMES(ZAPRD4) -
RECSZ (1,80)-
CISZ (4096)-
NONINDEXED)-
KSDS Key-Sequenced Data Sets and Variable length records
In a key-sequenced data set, logical records are placed in the data set in ascending collating sequence by a field, called the key.
The key must be: Unique and in the same position in each record.
After it is specified, the value of the key cannot be altered, but the entire record can be erased or deleted. For compressed data sets, the key itself and any data before the key will not be compressed. When a new record is added to the data set, it is inserted in its collating sequence by key.
Program to create a KSDS file with variable length records
Cobol
Definition Language for a KSDS file
FD VAR-OFILE
RECORD VARYING FROM 1 TO 80 CHARACTERS
DEPENDING ON WS-OUTPUT-RECORD-LENGTH.
01 VAR-OUTPUT-RECORD.
05 OUT-EMP-ID PIC X (10).
05 OUT-EMP-NAME PIC X (70).
JCL FOR CREATION OF KSDS FILE FOR A MAX RECORD SIZE OF 16 BYTES
//SYSIN DD *
DEFINE CLUSTER (NAME (SHRDV03.KSDS. EMPVAR1.CLUSTER) -
TRACKS (2,1) -
VOLUMES(ZAPRD4) -
KEYS (10,0) -
FREESPACE (10,20)-
RECSZ (01,80)-
CISZ (4096)-
INDEXED-
REUSE)-
DATA (NAME (SHRDV03.KSDS. EMPVAR1.DATA)) -
INDEX(NAME (SHRDV03.KSDS. EMPVAR1.INDEXED)
RRDS and Variable length records
A variable-length RRDS (VRRDS) is similar to a fixed-length RRDS, except that it contains variable-length records. Each record has a unique relative record number, and is placed in ascending relative record number order. Each record is stored and retrieved using its relative record number. Unlike a fixed-length RRDS, a variable-length RRDS does not have slots. The relative record number of a record cannot change. When that record is erased, the relative record number can be reused for a new record.
You must load the variable-length RRDS sequentially in ascending relative record number order. To define a variable-length RRDS, specify NUMBERED and RECORDSIZE. The average record length and maximum record length in RECORDSIZE must be different.
Free space is used for inserting and lengthening variable-length RRDS records. When a record is deleted or shortened, the space given up is reclaimed as free space for later use. When you define your data set, use the FREESPACE parameter to specify what percentage of each control interval and control area is to be set aside as a free space when the data set is initially loaded. A variable-length RRDS cannot have spanned records and alternate indexes. VRRDS is a KSDS processed as an RRDS so a prime index is created Program to create an VVRDDS with variable length records.
COBOL Definition for RRDS File
![]() |
|||
![]() |
FD VAR-OFILE
RECORD VARYING FROM 1 TO 80 CHARACTERS
DEPENDING ON WS-OUTPUT-RECORD-LENGTH.
01 VAR-OUTPUT-RECORD.
05 OUT-EMP-ID PIC X (10).
05 OUT-EMP-NAME PIC X (70).
JCL FOR CREATION OF RRDS FILE FOR A MAX RECORD SIZE OF 16 BYTES
//SYSIN DD *
DEFINE CLUSTER (NAME (SHRDV03.RRDS. EMPVAR.CLUSTER)-
CYLINDERS (10,5)-
VOLUMES(ZAPRD4)-
CISZ (4096)-
RECORDSIZE (1,16)-
NUMBERED)-
DATA (NAME (SHRDV03.RRDS. EMPVAR.DATA)
/*
SUMMARY OF VSAM DATASETS
ESDS |
KSDS |
Fixed-Length RRDS |
Variable-Length RRDS |
Linear Data Sets |
Records are in order as they are entered |
Records are in collating sequence by key field |
Records are in relative record number order |
Records are in relative record number order |
No processing at record level |
Direct access by RBA |
Direct access by key or by RBA |
Direct access by relative record number |
Direct access by relative record number |
Access with data-in-virtual (DIV) |
Alternate indexes permitted1 |
Alternate indexes permitted |
No alternate indexes permitted |
No alternate indexes permitted |
No alternate indexes permitted |
A record’s RBA cannot change |
A record’s RBA can change |
A record’s relative record number cannot change |
A record’s relative record number cannot change |
No processing at record level |
Space at the end of the data set is used for adding records |
Free space is used for inserting and lengthening records |
Empty slots in the data set are used for adding records |
Free space is used for inserting and lengthening records |
No processing at record level |
A record cannot be deleted, but you can reuse its space for a record of the same length1 |
Space given up by a deleted or shortened record becomes free space |
A slot given up by a deleted record can be reused |
Space given up by a deleted or shortened record becomes free space |
No processing at record level |
Spanned records permitted |
Spanned records permitted |
No spanned records |
No spanned records |
No spanned records |
Extended format permitted1 |
Extended format or compression permitted |
Extended format permitted |
Extended format permitted |
Extended format permitted
|
Key Differences: VSAM vs. Non-VSAM RDW Handling
Feature |
VSAM |
Non-VSAM (QSAM, etc.) |
RDW Handling |
Automatic (VSAM adds/removes it) |
Manual (program must include it) |
RDW in COBOL FD |
Not visible (handled by VSAM) |
Must be defined in record layout |
Fixed-Length |
No RDW needed |
No RDW needed |
Variable-Length |
VSAM manages RDW |
Program must manage RDW |
Final Thoughts:
"In an era where data is anything but uniform, COBOL’s variable-length record support proves why this 'legacy' language remains indispensable. Whether dealing with unpredictable transaction sizes or evolving business needs, mastering these techniques ensures your z/OS applications stay flexible, efficient, and ready for whatever data comes next."
Next time someone calls COBOL ‘rigid’, point them to variable-length records—where a 60-year-old language flexes like a gymnast. Want to see how this plays out in DevOps? Stay tuned for Part 2: ‘COBOL meets JSON’.