Skip to Content

Handling Variable-Length Records in COBOL on Z/OS

__________________________________________________________

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 file with Fixed length Records

 
Fixed length records in a sequential dataset on ZOS

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.

A sequential file with Variable length Records

 
In this example the maximum length of the record is defined as 16 and the minimum as 3 bytes.

 

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’.

 

 

 

ZEDINFOTECH, prasad.uday60@gmail.com 26 May 2025
Tags
Archive
Mainframe vs Mobile Wallets – The battle of Transaction First