30 min read

Mainframe utilities are the indispensable workhorses of the z/OS environment. Every COBOL developer, from the first day on the job, interacts with these programs to manage datasets, sort files, copy records, and perform the dozens of routine...

Chapter 29: Mainframe Utilities for COBOL Developers

Mainframe utilities are the indispensable workhorses of the z/OS environment. Every COBOL developer, from the first day on the job, interacts with these programs to manage datasets, sort files, copy records, and perform the dozens of routine operations that keep batch processing systems running. While COBOL handles the business logic, utilities handle the data plumbing -- moving, transforming, cataloging, and verifying the datasets that flow through production job streams.

This chapter provides a comprehensive, hands-on guide to the utilities you will use most frequently. We build directly on the JCL foundations established in Chapter 27 and the batch processing patterns covered in Chapter 28. Where those chapters focused on the language and architecture of batch jobs, this chapter focuses on the specific utility programs you invoke within those jobs and the control statements that drive them.

By the end of this chapter, you will be able to write JCL to define VSAM clusters, sort and merge transaction files, copy and reformat datasets, compare program versions, and integrate these utilities into production-quality COBOL batch streams.


29.1 Understanding Mainframe Utilities

Mainframe utilities are pre-written system programs provided by IBM (or third-party vendors) that perform common data management tasks. They are invoked through JCL just like any other program, but instead of containing your business logic, they contain generalized logic for operations such as copying, sorting, printing, and cataloging datasets.

29.1.1 Why Utilities Matter

Consider a typical nightly batch cycle at a bank. Before the COBOL account-update program can run, the previous day's transaction file must be sorted by account number. After the update runs, the old master file must be backed up, the new master must be cataloged, and an audit report must be printed. Without utilities, a developer would need to write COBOL programs for each of these operations. Utilities eliminate that burden.

29.1.2 Categories of Utilities

Mainframe utilities fall into several broad categories:

Category Utilities Purpose
VSAM Management IDCAMS Define, delete, copy, print, and catalog VSAM datasets
Sequential Copy IEBGENER, ICEGENER Copy and reformat sequential datasets
Partitioned Dataset IEBCOPY Copy, compress, and merge PDS/PDSE members
Sort/Merge DFSORT, SyncSort Sort, merge, filter, and reformat records
Dummy Utility IEFBR14 Allocate or delete datasets without processing
Comparison SuperC (ISRSUPC) Compare datasets or PDS members
Development ISPF Interactive editor, browser, and development tool

29.1.3 How Utilities Are Invoked

Every utility is invoked through the EXEC statement in JCL. The utility reads its input from DD statements and receives control parameters through a designated control DD -- typically SYSIN, SYSPRINT, or a utility-specific name.

//STEP01   EXEC PGM=utilityname
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  control statements go here
/*
//input-dd DD DSN=input.dataset,DISP=SHR
//output-dd DD DSN=output.dataset,DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=27920)

The specific DD names vary by utility, and learning which DD names each utility expects is a core part of mastering these tools.


29.2 IDCAMS -- Access Method Services

IDCAMS (the ICF Catalog Access Method Services utility) is the primary tool for managing VSAM datasets and ICF catalogs. [IBM Enterprise COBOL] VSAM is the dominant file organization for online and batch data on z/OS, and IDCAMS is the gateway to creating and maintaining those files.

29.2.1 DEFINE CLUSTER -- Creating VSAM Datasets

The DEFINE CLUSTER command creates a VSAM dataset. VSAM datasets consist of a data component and, for KSDS (Key-Sequenced Data Sets), an index component.

Here is a complete example that defines a KSDS cluster for a bank account master file:

//DEFCLUST EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DEFINE CLUSTER (                                    -
           NAME(PROD.ACCT.MASTER.KSDS)                -
           INDEXED                                    -
           RECORDS(500000 100000)                     -
           RECORDSIZE(400 400)                        -
           KEYS(10 0)                                 -
           FREESPACE(20 10)                           -
           SHAREOPTIONS(2 3)                          -
           SPEED                                      -
           ERASE                                      -
           )                                          -
         DATA (                                       -
           NAME(PROD.ACCT.MASTER.KSDS.DATA)           -
           CONTROLINTERVALSIZE(4096)                  -
           VOLUMES(VOL001)                            -
           )                                          -
         INDEX (                                      -
           NAME(PROD.ACCT.MASTER.KSDS.INDEX)          -
           CONTROLINTERVALSIZE(2048)                  -
           VOLUMES(VOL001)                            -
           )
  IF LASTCC = 0 THEN                                 -
    SET MAXCC = 0
/*

Key parameters explained:

  • INDEXED: Creates a KSDS. Use NUMBERED for RRDS or NONINDEXED for ESDS.
  • RECORDS(primary secondary): Space allocation in number of records. The primary extent holds 500,000 records; each secondary extent adds 100,000.
  • RECORDSIZE(avg max): Average and maximum record lengths. For fixed-length records, both values are the same.
  • KEYS(length offset): The key is 10 bytes long starting at position 0 (the first byte of the record).
  • FREESPACE(ci-percent ca-percent): Reserves 20% of each control interval and 10% of each control area for future inserts.
  • SHAREOPTIONS(crossregion crosssystem): Level 2 allows multiple readers or a single writer within a region; level 3 allows full sharing across systems.
  • SPEED: Loads data without preformatting (faster than RECOVERY option).
  • ERASE: Overwrites data with binary zeros when the cluster is deleted, an important security feature for financial data.
  • CONTROLINTERVALSIZE: The physical I/O block size for data and index components.

Defining an ESDS for Transaction Logging

An Entry-Sequenced Data Set is ideal for transaction logs where records are always appended in arrival order:

//DEFESDS  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DEFINE CLUSTER (                                    -
           NAME(PROD.DAILY.TRANLOG.ESDS)              -
           NONINDEXED                                 -
           RECORDS(1000000 200000)                    -
           RECORDSIZE(250 500)                        -
           SHAREOPTIONS(2 3)                          -
           SPEED                                      -
           )                                          -
         DATA (                                       -
           NAME(PROD.DAILY.TRANLOG.ESDS.DATA)         -
           CONTROLINTERVALSIZE(8192)                  -
           VOLUMES(VOL002)                            -
           )
/*

Defining an RRDS for Lookup Tables

A Relative Record Data Set provides direct access by record number, useful for small lookup tables:

//DEFRRDS  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DEFINE CLUSTER (                                    -
           NAME(PROD.BRANCH.LOOKUP.RRDS)              -
           NUMBERED                                   -
           RECORDS(5000 1000)                         -
           RECORDSIZE(150 150)                        -
           SHAREOPTIONS(2 3)                          -
           )                                          -
         DATA (                                       -
           NAME(PROD.BRANCH.LOOKUP.RRDS.DATA)         -
           CONTROLINTERVALSIZE(4096)                  -
           VOLUMES(VOL001)                            -
           )
/*

29.2.2 REPRO -- Copying and Loading Data

REPRO copies records from one dataset to another. It is used to load data into VSAM clusters, to unload VSAM data to sequential files for backup, and to copy between VSAM datasets.

Loading a Sequential File into a KSDS

After defining a KSDS, you typically load it from a sorted sequential file:

//LOADKSDS EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=PROD.ACCT.MASTER.SEQLOAD,DISP=SHR
//OUTFILE  DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//SYSIN    DD *
  REPRO INFILE(INFILE)                                -
        OUTFILE(OUTFILE)                              -
        REPLACE
  IF LASTCC <= 4 THEN                                -
    SET MAXCC = 0
/*

The REPLACE option allows existing records with the same key to be overwritten. Without REPLACE, duplicate keys cause an error.

Unloading a VSAM Dataset to Sequential File

For backup or migration, unload VSAM data to a sequential flat file:

//UNLOAD   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//OUTFILE  DD DSN=BACKUP.ACCT.MASTER.SEQ,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(50,10),RLSE),
//            DCB=(RECFM=FB,LRECL=400,BLKSIZE=32000)
//SYSIN    DD *
  REPRO INFILE(INFILE)                                -
        OUTFILE(OUTFILE)                              -
        COUNT(999999999)
/*

Selective Copy with FROMKEY/TOKEY

Copy only a range of accounts (for example, accounts 1000000000 through 1999999999):

//SELCOPY  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//OUTFILE  DD DSN=WORK.ACCT.SUBSET.SEQ,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=400,BLKSIZE=32000)
//SYSIN    DD *
  REPRO INFILE(INFILE)                                -
        OUTFILE(OUTFILE)                              -
        FROMKEY(1000000000)                           -
        TOKEY(1999999999)
/*

29.2.3 DELETE -- Removing Datasets

DELETE removes a dataset entry from the catalog and optionally scratches the physical data from the volume:

//DELCLUST EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE PROD.ACCT.MASTER.KSDS                        -
         CLUSTER                                      -
         PURGE                                        -
         ERASE
  IF LASTCC = 8 THEN                                 -
    SET MAXCC = 0
/*
  • CLUSTER: Specifies the entry type (use NONVSAM for non-VSAM datasets).
  • PURGE: Overrides any retention period set on the dataset.
  • ERASE: Overwrites data with zeros before deletion.
  • The conditional IF LASTCC = 8 handles the common case where the dataset does not exist (return code 8), setting MAXCC to 0 so the job continues.

Delete and Redefine Pattern

A common production pattern is to delete an existing cluster and then immediately redefine it. This ensures a clean dataset for each batch cycle:

//RECREATE EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE PROD.DAILY.TRANLOG.ESDS                      -
         CLUSTER                                      -
         PURGE
  IF LASTCC <= 8 THEN                                -
    SET MAXCC = 0
  DEFINE CLUSTER (                                    -
           NAME(PROD.DAILY.TRANLOG.ESDS)              -
           NONINDEXED                                 -
           RECORDS(1000000 200000)                    -
           RECORDSIZE(250 500)                        -
           SHAREOPTIONS(2 3)                          -
           SPEED                                      -
           )                                          -
         DATA (                                       -
           NAME(PROD.DAILY.TRANLOG.ESDS.DATA)         -
           CONTROLINTERVALSIZE(8192)                  -
           VOLUMES(VOL002)                            -
           )
/*

29.2.4 PRINT -- Displaying Dataset Contents

PRINT displays the contents of a dataset in character, hexadecimal, or dump format. This is invaluable for debugging:

//PRINTDS  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//SYSIN    DD *
  PRINT INFILE(INFILE)                                -
        CHARACTER                                     -
        COUNT(50)
/*
  • CHARACTER: Displays data in readable character format.
  • HEX: Displays in hexadecimal (useful for packed-decimal fields).
  • DUMP: Displays in combined hex/character dump format.
  • COUNT(50): Limits output to the first 50 records.

To print a specific key range:

//PRINTRNG EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//SYSIN    DD *
  PRINT INFILE(INFILE)                                -
        DUMP                                          -
        FROMKEY(5550010000)                           -
        TOKEY(5550019999)
/*

29.2.5 LISTCAT -- Catalog Information

LISTCAT displays catalog entries for datasets, providing details about allocation, space usage, and attributes:

//LISTCAT  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  LISTCAT ENTRIES(PROD.ACCT.MASTER.KSDS)              -
          ALL
/*

The ALL option produces complete information including:

  • Dataset organization and attributes
  • Space allocation and usage statistics
  • Volume serial numbers
  • Creation and expiration dates
  • Record counts and key information
  • CI/CA split counts (critical for performance monitoring)

To list all datasets matching a pattern:

//LISTALL  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  LISTCAT LEVEL(PROD.ACCT)                            -
          VOLUME                                      -
          ALLOCATION
/*

29.2.6 ALTER -- Modifying Dataset Attributes

ALTER changes the attributes of an existing catalog entry without deleting and redefining:

//ALTERDS  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  ALTER PROD.ACCT.MASTER.KSDS                         -
        FREESPACE(15 7)                               -
        SHAREOPTIONS(3 3)                             -
        BUFFERSPACE(1048576)
/*

Common ALTER uses include changing FREESPACE after a reorganization, adjusting SHAREOPTIONS, and modifying BUFFERSPACE for performance tuning.

29.2.7 IDCAMS Conditional Processing

IDCAMS supports conditional logic through IF/THEN/ELSE/END constructs that test return codes:

//CONDPROC EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE PROD.WORK.TEMPFILE NONVSAM PURGE
  IF LASTCC = 8 THEN                                 -
    DO                                                -
      SET MAXCC = 0                                   -
    END                                               -
  ELSE                                                -
    IF LASTCC > 0 THEN                               -
      DO                                              -
        SET MAXCC = 16                                -
      END
  DEFINE CLUSTER (                                    -
           NAME(PROD.ACCT.NEWINDEX.KSDS)              -
           INDEXED                                    -
           RECORDS(100000 50000)                      -
           RECORDSIZE(200 200)                        -
           KEYS(10 0)                                 -
           FREESPACE(20 10)                           -
           )                                          -
         DATA (                                       -
           NAME(PROD.ACCT.NEWINDEX.KSDS.DATA)         -
           CONTROLINTERVALSIZE(4096)                  -
           )                                          -
         INDEX (                                      -
           NAME(PROD.ACCT.NEWINDEX.KSDS.INDEX)        -
           CONTROLINTERVALSIZE(2048)                  -
           )
  IF LASTCC > 0 THEN                                 -
    SET MAXCC = 16
/*

Return code conventions for IDCAMS:

Return Code Meaning
0 Successful completion
4 Warning -- operation completed with minor issues
8 Dataset not found (for DELETE) or logical error
12 Severe error -- operation could not complete
16 Critical error -- immediate termination

29.3 IEBGENER -- Sequential Dataset Copy and Reformat

IEBGENER is one of the simplest and most frequently used utilities. It copies sequential datasets, optionally reformatting records during the copy operation.

29.3.1 Basic Sequential Copy

The simplest IEBGENER job copies one sequential dataset to another with no transformation:

//GENCOPY  EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SYSUT2   DD DSN=BACKUP.ACCT.TRANS.D260210,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SYSIN    DD DUMMY

Key points:

  • SYSUT1: Input dataset.
  • SYSUT2: Output dataset.
  • SYSPRINT: Message output.
  • SYSIN DD DUMMY: No control statements needed for a straight copy. You must specify DUMMY; omitting SYSIN causes an error.

29.3.2 Copying to Print (SYSOUT)

To print the contents of a dataset to the JES spool:

//GENPRINT EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=PROD.REPORTS.DAILY.SUMMARY,DISP=SHR
//SYSUT2   DD SYSOUT=A
//SYSIN    DD DUMMY

29.3.3 Record Reformatting with IEBGENER

IEBGENER can reformat records using GENERATE and RECORD statements in SYSIN. This example extracts account number (positions 1-10), account name (positions 11-40), and balance (positions 85-96) from a 200-byte record into a new 56-byte record:

//REFORMAT EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=PROD.ACCT.MASTER.SEQ,DISP=SHR
//SYSUT2   DD DSN=WORK.ACCT.EXTRACT,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=56,BLKSIZE=27944)
//SYSIN    DD *
  GENERATE MAXFLDS=3,MAXLITS=0
  RECORD FIELD=(10,1,,1),                             X
         FIELD=(30,11,,11),                           X
         FIELD=(12,85,,41)
/*

The FIELD parameter syntax is FIELD=(length,input-position,conversion,output-position). The conversion field is blank here, meaning no conversion is applied.

29.3.4 Adding Literals During Copy

You can insert literal strings into the output record. This example adds a header identifier and a date to each output record:

//ADDLIT   EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SYSUT2   DD DSN=WORK.ACCT.TRANS.TAGGED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=220,BLKSIZE=27720)
//SYSIN    DD *
  GENERATE MAXFLDS=3,MAXLITS=18
  RECORD FIELD=(8,'20260210',,1),                     X
         FIELD=(200,1,,9),                            X
         FIELD=(10,'DAILY-TRAN',,209)
/*

29.3.5 IEBGENER Limitations

IEBGENER is limited in its reformatting capabilities. It cannot filter records, perform arithmetic, or handle complex transformations. For those operations, DFSORT (discussed in Section 29.5) or a COBOL program is more appropriate. Additionally, IEBGENER does not directly support VSAM input or output -- use IDCAMS REPRO for VSAM operations.


29.4 IEBCOPY -- PDS Member Management

IEBCOPY is the standard utility for copying, compressing, and merging Partitioned Data Sets (PDS) and Partitioned Data Sets Extended (PDSE). It operates on the library (PDS/PDSE) level, copying individual members or entire libraries.

29.4.1 Full PDS Copy

Copy all members from one PDS to another:

//PDSCOPY  EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=*
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//SYSUT4   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//INDD     DD DSN=DEV.COBOL.SRCLIB,DISP=SHR
//OUTDD    DD DSN=PROD.COBOL.SRCLIB,DISP=SHR
//SYSIN    DD *
  COPY OUTDD=OUTDD,INDD=INDD
/*
  • SYSUT3/SYSUT4: Work datasets used by IEBCOPY for spill and directory processing.
  • INDD/OUTDD: The DD names referenced in the COPY statement. These names are arbitrary but must match the DD statements.

29.4.2 Selective Member Copy

Copy specific members from one PDS to another:

//SELCOPY  EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=*
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//SYSUT4   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//INLIB    DD DSN=DEV.COBOL.SRCLIB,DISP=SHR
//OUTLIB   DD DSN=TEST.COBOL.SRCLIB,DISP=SHR
//SYSIN    DD *
  COPY OUTDD=OUTLIB,INDD=INLIB
  SELECT MEMBER=(ACCTUPD,TRANVAL,RPTGEN)
/*

29.4.3 Copy with Renaming

Copy members while renaming them in the target library:

//COPYRNAM EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=*
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//SYSUT4   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//INLIB    DD DSN=DEV.COBOL.SRCLIB,DISP=SHR
//OUTLIB   DD DSN=PROD.COBOL.SRCLIB,DISP=SHR
//SYSIN    DD *
  COPY OUTDD=OUTLIB,INDD=INLIB
  SELECT MEMBER=((ACCTUPD,ACCTUP01,R))
  SELECT MEMBER=((TRANVAL,TRANVL01,R))
/*

The syntax (oldname,newname,R) copies the member with a new name. The R flag means replace if the target member already exists.

29.4.4 PDS Compression (In-Place Copy)

Over time, as members in a PDS are deleted and replaced, space is wasted. Compression reclaims this space:

//COMPRESS EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=*
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//SYSUT4   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//PDSLIB   DD DSN=PROD.COBOL.LOADLIB,DISP=OLD
//SYSIN    DD *
  COPY OUTDD=PDSLIB,INDD=PDSLIB
/*

When INDD and OUTDD reference the same DD, IEBCOPY performs an in-place compress. The dataset must be allocated with DISP=OLD to ensure exclusive access.

29.4.5 Merging Multiple PDS Libraries

Merge members from several source libraries into one target:

//MERGELIB EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=*
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//SYSUT4   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//INDD1    DD DSN=DEV.COBOL.SRCLIB,DISP=SHR
//INDD2    DD DSN=FIX.COBOL.SRCLIB,DISP=SHR
//INDD3    DD DSN=PROD.COBOL.SRCLIB,DISP=SHR
//OUTDD    DD DSN=MERGED.COBOL.SRCLIB,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(50,10,100)),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=27920)
//SYSIN    DD *
  COPY OUTDD=OUTDD,INDD=(INDD1,INDD2,INDD3)
/*

When multiple INDD libraries are specified, IEBCOPY processes them left to right. If the same member name exists in multiple input libraries, the first occurrence is copied and subsequent duplicates are skipped unless the R (replace) option is used.

29.4.6 Excluding Members

Copy all members except specific ones:

//EXCLUDE  EXEC PGM=IEBCOPY
//SYSPRINT DD SYSOUT=*
//SYSUT3   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//SYSUT4   DD UNIT=SYSDA,SPACE=(CYL,(5,1))
//INLIB    DD DSN=DEV.COBOL.SRCLIB,DISP=SHR
//OUTLIB   DD DSN=PROD.COBOL.SRCLIB,DISP=SHR
//SYSIN    DD *
  COPY OUTDD=OUTLIB,INDD=INLIB
  EXCLUDE MEMBER=(TESTPGM,DEBUGMOD,TEMPWORK)
/*

29.5 DFSORT -- The Sort/Merge Powerhouse

DFSORT (Data Facility Sort) is arguably the most powerful and versatile utility on the mainframe. While its name suggests only sorting, DFSORT can sort, merge, copy, filter, reformat, summarize, join, and generate reports -- all without writing a single line of COBOL. [IBM Enterprise COBOL] SyncSort is a compatible third-party alternative with nearly identical syntax; most examples in this section work with either product.

29.5.1 Basic SORT Operation

The fundamental operation sorts records by one or more key fields. This example sorts a daily transaction file by account number (positions 1-10) in ascending order:

//SORTJOB  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=PROD.ACCT.TRANS.SORTED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A)
/*

Key components:

  • SORTIN: Input dataset.
  • SORTOUT: Output dataset.
  • SORTWK01-03: Work datasets for the sort algorithm. Provide at least three for optimal performance. The system calculates the required size, but allocate generously.
  • SORT FIELDS: Specifies (position,length,format,order). CH = character, A = ascending, D = descending.

29.5.2 Multi-Key Sort

Sort by multiple keys. This sorts transactions first by branch code (positions 180-183) ascending, then by transaction date (positions 41-48) ascending, then by transaction amount (positions 85-96, packed decimal) descending:

//MULTISRT EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=PROD.ACCT.TRANS.MULTI.SORTED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SYSIN    DD *
  SORT FIELDS=(180,4,CH,A,41,8,CH,A,85,12,PD,D)
/*

Common data format codes:

Code Format Description
CH Character EBCDIC character data
ZD Zoned Decimal Zoned decimal numeric
PD Packed Decimal Packed decimal (COMP-3)
BI Binary Binary integer (COMP)
FI Fixed-point Integer Signed binary
FL Floating-point Floating-point numeric

29.5.3 INCLUDE and OMIT -- Record Filtering

INCLUDE selects records that match criteria; OMIT excludes records that match. Only one can be used per sort operation.

Select Only Deposit Transactions

Select records where the transaction type (position 49, 1 byte) is 'D' for deposit:

//FILTDEP  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.DEPOSITS.SORTED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A)
  INCLUDE COND=(49,1,CH,EQ,C'D')
/*

Complex Filter with AND/OR

Select transactions over $10,000 (packed decimal in positions 85-96) for branch codes 0100 through 0199:

//CMPLXFLT EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.HIGHVAL.TRANS,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A,41,8,CH,A)
  INCLUDE COND=(85,12,PD,GT,+1000000,AND,
                180,4,CH,GE,C'0100',AND,
                180,4,CH,LE,C'0199')
/*

The packed decimal value +1000000 represents $10,000.00 (assuming two implied decimal places).

Omit Zero-Balance Accounts

//OMITZERO EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.MASTER.SEQ,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.ACTIVE,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=400,BLKSIZE=32000)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A)
  OMIT COND=(85,12,PD,EQ,+0)
/*

29.5.4 COPY -- Pass-Through Without Sorting

When you need DFSORT's filtering or reformatting capabilities but do not need to change the record order, use COPY instead of SORT:

//COPYONLY EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.DEPOSITS.ONLY,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SYSIN    DD *
  OPTION COPY
  INCLUDE COND=(49,1,CH,EQ,C'D')
/*

No SORTWK datasets are needed for COPY operations since no sorting takes place.

29.5.5 INREC -- Reformat Input Records

INREC reformats records before sorting. This is useful for building a sort key from scattered fields or for reducing record length before sorting to improve performance.

Extract and restructure fields from a 400-byte master file record into a 60-byte work record:

//INRECEX  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.MASTER.SEQ,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.SUMMARY,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=60,BLKSIZE=27960)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SYSIN    DD *
  INREC FIELDS=(1,10,            account number
                11,30,           account name
                85,12,           current balance
                150,8)           last activity date
  SORT FIELDS=(1,10,CH,A)
/*

After INREC, the sort key positions reference the reformatted record, not the original.

29.5.6 OUTREC -- Reformat Output Records

OUTREC reformats records after sorting but before writing to SORTOUT. This example builds a report-ready output with inserted literals and edited numeric fields:

//OUTRECEX EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.SORTED,DISP=SHR
//SORTOUT  DD DSN=WORK.TRANS.REPORT.DATA,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=133,BLKSIZE=27930)
//SYSIN    DD *
  OPTION COPY
  OUTREC FIELDS=(C'ACCT: ',
                 1,10,
                 C'  DATE: ',
                 41,8,
                 C'  TYPE: ',
                 49,1,
                 C'  AMOUNT: ',
                 85,12,PD,EDIT=(STTTTTTTTTTT.TT),
                 C' ',
                 180,4)
/*

The EDIT mask (STTTTTTTTTTT.TT) formats a packed decimal field with sign, leading zeros suppressed (T), decimal point, and two decimal places. S represents the sign position; T positions display a digit or a space for leading zeros.

29.5.7 SUM -- Summarizing Records

SUM adds numeric fields for records with identical sort keys. This is powerful for generating totals without writing any COBOL code.

Sum transaction amounts by account number:

//SUMTRANS EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.TRANS.TOTALS,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A)
  SUM FIELDS=(85,12,PD)
/*

For each unique account number, DFSORT produces one output record where the transaction amount field contains the sum of all transactions for that account. All other fields come from the last record with that key.

To remove duplicates without summing (keeping only the first record for each key), use:

  SUM FIELDS=NONE

29.5.8 MERGE Operation

MERGE combines two or more pre-sorted input files into a single sorted output. The inputs must already be sorted in the same order as the merge keys.

//MERGETX  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN01 DD DSN=PROD.ACCT.TRANS.REGION1.SORTED,DISP=SHR
//SORTIN02 DD DSN=PROD.ACCT.TRANS.REGION2.SORTED,DISP=SHR
//SORTIN03 DD DSN=PROD.ACCT.TRANS.REGION3.SORTED,DISP=SHR
//SORTOUT  DD DSN=PROD.ACCT.TRANS.NATIONAL.SORTED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(50,10),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SYSIN    DD *
  MERGE FIELDS=(1,10,CH,A,41,8,CH,A)
/*

MERGE is significantly faster than concatenating the files and re-sorting because it takes advantage of the pre-existing order in each input.

29.5.9 OUTFIL -- Multiple Output Files

OUTFIL directs output to multiple files with different selection criteria, reformatting, and header/trailer records. This eliminates the need to read a file multiple times.

Split transactions by type into separate files with headers:

//SPLITTYP EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.SORTED,DISP=SHR
//DEPOSIT  DD DSN=WORK.TRANS.DEPOSITS,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//WITHDRAW DD DSN=WORK.TRANS.WITHDRAWALS,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//TRANSFER DD DSN=WORK.TRANS.TRANSFERS,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SYSIN    DD *
  OPTION COPY
  OUTFIL FNAMES=DEPOSIT,
    INCLUDE=(49,1,CH,EQ,C'D'),
    HEADER1=(C'DEPOSIT TRANSACTIONS - ',
             DATE=(4MD/),
             C' ',TIME=(12:),2/)
  OUTFIL FNAMES=WITHDRAW,
    INCLUDE=(49,1,CH,EQ,C'W'),
    HEADER1=(C'WITHDRAWAL TRANSACTIONS - ',
             DATE=(4MD/),
             C' ',TIME=(12:),2/)
  OUTFIL FNAMES=TRANSFER,
    INCLUDE=(49,1,CH,EQ,C'T'),
    HEADER1=(C'TRANSFER TRANSACTIONS - ',
             DATE=(4MD/),
             C' ',TIME=(12:),2/)
/*

29.5.10 DFSORT Performance Tips

  • Allocate sufficient SORTWK space: The general rule is that total SORTWK space should be at least twice the input file size. Spread it across three or more work datasets on separate volumes for parallel I/O.
  • Use INREC to reduce record length: Sorting shorter records requires less memory and fewer I/Os.
  • Use FILSZ or DYNALLOC: The FILSZ option tells DFSORT the expected number of records, allowing optimal resource allocation. DYNALLOC lets DFSORT allocate its own work datasets.
  • Use EQUALS for stable sorts: If records with equal keys must retain their original order, specify OPTION EQUALS. Without it, DFSORT may rearrange records with equal keys for performance.
//OPTSORT  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=PROD.ACCT.TRANS.SORTED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(50,10)),VOL=SER=WRK001
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(50,10)),VOL=SER=WRK002
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(50,10)),VOL=SER=WRK003
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A)
  OPTION EQUALS,DYNALLOC=(SYSDA,3)
/*

29.6 IEFBR14 -- The Do-Nothing Utility

IEFBR14 is the simplest program on the mainframe -- it does literally nothing except set a return code of zero. Its purpose is to let JCL DD statement processing handle dataset allocation and deletion.

29.6.1 Creating an Empty Dataset

The system allocates datasets based on DD statements before the program runs. IEFBR14 exploits this to create datasets:

//CREATEDS EXEC PGM=IEFBR14
//NEWFILE  DD DSN=PROD.ACCT.TRANS.DAILY.NEW,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//NEWPDS   DD DSN=PROD.COBOL.WORK.SRCLIB,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5,50)),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=27920,DSORG=PO)

29.6.2 Deleting Datasets

By specifying DISP=(OLD,DELETE,DELETE), the system deletes the dataset after IEFBR14 completes:

//CLEANUP  EXEC PGM=IEFBR14
//DELFILE1 DD DSN=WORK.ACCT.TRANS.TEMP1,
//            DISP=(OLD,DELETE,DELETE)
//DELFILE2 DD DSN=WORK.ACCT.TRANS.TEMP2,
//            DISP=(OLD,DELETE,DELETE)
//DELFILE3 DD DSN=WORK.ACCT.EXTRACT.TEMP,
//            DISP=(OLD,DELETE,DELETE)

29.6.3 Catalog and Uncatalog Operations

To catalog an existing dataset that is not in the catalog:

//CATALOG  EXEC PGM=IEFBR14
//CATDS    DD DSN=MIGR.ACCT.ARCHIVE.DATA,
//            DISP=(OLD,CATLG),
//            UNIT=TAPE,VOL=SER=TAP001

To uncatalog a dataset (remove the catalog entry without deleting the physical data):

//UNCAT    EXEC PGM=IEFBR14
//UNCATDS  DD DSN=OLD.ACCT.ARCHIVE.DATA,
//            DISP=(OLD,UNCATLG)

29.6.4 Creating Multiple Datasets in a Cleanup Step

A common production pattern is a pre-processing cleanup step that deletes and recreates work files:

//PRECLEAN EXEC PGM=IEFBR14
//WORK01   DD DSN=WORK.BATCH.SORT.TEMP,
//            DISP=(MOD,DELETE,DELETE),
//            UNIT=SYSDA,SPACE=(TRK,0)
//WORK02   DD DSN=WORK.BATCH.MERGE.TEMP,
//            DISP=(MOD,DELETE,DELETE),
//            UNIT=SYSDA,SPACE=(TRK,0)
//NEW01    DD DSN=WORK.BATCH.SORT.TEMP,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//NEW02    DD DSN=WORK.BATCH.MERGE.TEMP,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)

Using DISP=(MOD,DELETE,DELETE) instead of (OLD,DELETE,DELETE) prevents the step from failing if the dataset does not yet exist. The MOD disposition will tolerate a missing dataset in certain configurations, though the behavior can depend on the system settings. An alternative is to use IDCAMS DELETE with the IF LASTCC = 8 pattern shown earlier, which is more reliable.


29.7 ICEGENER -- Enhanced Copy Utility

ICEGENER is an IBM-provided replacement for IEBGENER that leverages DFSORT technology. [IBM Enterprise COBOL] On many z/OS installations, IEBGENER is aliased to ICEGENER, meaning that jobs invoking IEBGENER actually run ICEGENER automatically.

29.7.1 Basic Copy with ICEGENER

The JCL is identical to IEBGENER:

//ICECOPY  EXEC PGM=ICEGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SYSUT2   DD DSN=BACKUP.ACCT.TRANS.D260210,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SYSIN    DD DUMMY

29.7.2 ICEGENER with DFSORT Control Statements

The major advantage of ICEGENER is that it accepts DFSORT control statements through SYSIN, giving you access to INCLUDE, OMIT, INREC, OUTREC, and OUTFIL. This means you can filter and reformat records using ICEGENER without changing the DD name conventions:

//ICEFILT  EXEC PGM=ICEGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SYSUT2   DD DSN=WORK.ACCT.DEPOSITS.EXTRACT,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=56,BLKSIZE=27944)
//SYSIN    DD *
  INCLUDE COND=(49,1,CH,EQ,C'D')
  OUTREC FIELDS=(1,10,11,30,85,12,41,4)
/*

29.7.3 When to Use ICEGENER vs. DFSORT

Use ICEGENER when you are performing copy-like operations (no sorting) and want to maintain compatibility with existing IEBGENER JCL. Use DFSORT directly when you need sorting, merging, or advanced features like OUTFIL with multiple outputs.


29.8 File Comparison Utilities -- SuperC (ISRSUPC)

SuperC (also known as ISRSUPC, the ISPF/PDF Search-Compare utility) compares two datasets or PDS members and produces a detailed report of differences. This is essential for code reviews, change tracking, and debugging.

29.8.1 Comparing Two Sequential Datasets

//COMPARE  EXEC PGM=ISRSUPC,PARM=DELTAL
//NEWDD    DD DSN=DEV.COBOL.SRCLIB(ACCTUPD),DISP=SHR
//OLDDD    DD DSN=PROD.COBOL.SRCLIB(ACCTUPD),DISP=SHR
//OUTDD    DD SYSOUT=*
//SYSIN    DD *
  CMPCOLM 7:72
/*
  • PARM=DELTAL: Produces a delta listing showing only lines that differ. Other options include LINECMP (line-by-line comparison) and WORDCMP (word-level comparison).
  • NEWDD/OLDDD: The "new" and "old" versions being compared. The naming convention reflects the expected use case of comparing a new version against an old baseline.
  • OUTDD: The comparison report output.
  • CMPCOLM 7:72: Compares only columns 7 through 72, which is the standard COBOL source area (Area A + Area B), ignoring sequence numbers in columns 1-6 and identification in columns 73-80.

29.8.2 Comparing Entire PDS Libraries

To compare all matching members between two PDS libraries:

//CMPLIBS  EXEC PGM=ISRSUPC,PARM=DELTAL
//NEWDD    DD DSN=DEV.COBOL.SRCLIB,DISP=SHR
//OLDDD    DD DSN=PROD.COBOL.SRCLIB,DISP=SHR
//OUTDD    DD SYSOUT=*
//SYSIN    DD *
  CMPCOLM 7:72
/*

SuperC will compare each member that exists in both libraries and report differences. Members that exist in only one library are flagged as inserted or deleted.

29.8.3 Search Mode

SuperC can also search for strings within a dataset, functioning as a batch-mode grep:

//SEARCH   EXEC PGM=ISRSUPC,PARM=SRCHCMP
//NEWDD    DD DSN=PROD.COBOL.SRCLIB,DISP=SHR
//OUTDD    DD SYSOUT=*
//SYSIN    DD *
  SRCHFOR 'PERFORM VARYING'
  SRCHFOR 'COMPUTE'
  CMPCOLM 7:72
/*

This searches the entire PDS for any lines containing either "PERFORM VARYING" or "COMPUTE" within the COBOL source columns.

29.8.4 Understanding SuperC Output

The comparison report uses change markers in column 1:

Marker Meaning
I Inserted line (exists in NEW, not in OLD)
D Deleted line (exists in OLD, not in NEW)
= Reformatted line (content moved within the record)

A typical delta report excerpt:

LISTING OUTPUT OF SUPERC    COMPARE     ISRSUPC   -   5655-147
NEW: DEV.COBOL.SRCLIB(ACCTUPD)
OLD: PROD.COBOL.SRCLIB(ACCTUPD)
- - - - - - - - - - - - - - - - - - - - - - - - - - -
I  000145      05  WS-NEW-FEE-AMOUNT     PIC 9(7)V99.
D  000200      PERFORM 2100-CALC-INTEREST
I  000200      PERFORM 2100-CALC-INTEREST
I  000201      PERFORM 2150-CALC-FEE

29.9 ISPF as a Development Environment

ISPF (Interactive System Productivity Facility) is the primary interactive interface for z/OS developers. [IBM Enterprise COBOL] While it is technically a full-screen application rather than a batch utility, every COBOL developer must master it for daily development work.

29.9.1 ISPF Panel Navigation

ISPF is organized into numbered options from the Primary Option Menu:

Option Name Purpose
0 Settings Configure ISPF preferences
1 View Browse datasets (read-only)
2 Edit Edit datasets and PDS members
3 Utilities Dataset utilities (allocate, rename, delete, etc.)
4 Foreground Compile and link-edit in foreground
5 Batch Submit JCL for batch execution
6 Command Enter TSO commands
7 Dialog Test Test ISPF dialogs
8 LM Utilities Library management utilities
11 Workplace Tabbed multi-session workspace
13 z/OS UNIX Access z/OS UNIX file system
SD SDSF System Display and Search Facility (view job output)

29.9.2 ISPF Editor Essential Commands

The ISPF editor is a powerful line-oriented and command-oriented editor. The primary commands (entered on the command line) and line commands (entered in the line number area) are essential for productivity.

Primary Commands

Command Purpose
FIND string Search for a string
CHANGE old new ALL Replace all occurrences
SORT A col1 col2 Sort lines ascending on columns
SUBMIT Submit the current member as JCL
CREATE membername Create a new PDS member from marked lines
REPLACE membername Replace a PDS member with marked lines
COPY membername Copy a member into the current edit session
RESET Reset all pending line commands
SAVE Save without exiting
CANCEL Exit without saving
UNDO Undo the last change
HILITE COBOL Enable COBOL syntax highlighting
COLS Display a column ruler
NUMBER ON STD Turn on standard COBOL numbering
PROFILE CAPS OFF Disable auto-capitalization
BOUNDS 7 72 Set edit boundaries to COBOL Area A/B

Line Commands

Command Purpose
I Insert a line after this line
In Insert n blank lines
D Delete this line
Dn Delete n lines
DD/DD Delete a block of lines
C Copy this line
CC/CC Copy a block of lines
M Move this line
MM/MM Move a block of lines
A Place copied/moved lines after this line
B Place copied/moved lines before this line
R Repeat this line
Rn Repeat this line n times
TS Text split at cursor position
TF Text flow (rejoin split lines)
X Exclude this line from display
XX/XX Exclude a block of lines
S Show excluded lines
F Show first excluded line
L Show last excluded line

29.9.3 SDSF -- Viewing Job Output

SDSF (System Display and Search Facility) is accessed through ISPF and is the primary tool for viewing batch job output. After submitting JCL, you use SDSF to check results.

Key SDSF commands:

Command Purpose
ST Display job status
DA Display active jobs
H Display held output
LOG Display system log
PREFIX jobname Filter by job name prefix
OWNER userid Filter by submitting user
? Select a job to view its output
S View a job's spool files
SE Edit JCL from spool
SJ View submitted JCL
XD Delete output from spool

When viewing job output, use the FIND command to search for return codes, error messages, or specific output strings. Check the JESMSGLG, JESJCL, and JESYSMSG DD output for JCL errors and system messages.


29.10 Utility Integration with COBOL Batch Jobs

The real power of mainframe utilities emerges when they are integrated into multi-step batch jobs alongside COBOL programs. This section presents complete job streams that combine utilities with COBOL processing, building on the batch processing patterns from Chapter 28.

29.10.1 Complete Account Update Job Stream

This production-quality job stream demonstrates a typical nightly account update cycle. It includes pre-processing with utilities, COBOL processing, and post-processing with utilities:

//ACCTUPD  JOB (PROD,ACCT),'NIGHTLY ACCT UPDATE',
//            CLASS=A,MSGCLASS=X,MSGLEVEL=(1,1),
//            NOTIFY=&SYSUID,RESTART=*
//*
//*============================================================
//* STEP 1: DELETE AND RECREATE WORK FILES
//*============================================================
//CLEANUP  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE WORK.ACCT.TRANS.SORTED NONVSAM PURGE
  IF LASTCC <= 8 THEN SET MAXCC = 0
  DELETE WORK.ACCT.UPDATE.REPORT NONVSAM PURGE
  IF LASTCC <= 8 THEN SET MAXCC = 0
  DELETE WORK.ACCT.ERROR.FILE NONVSAM PURGE
  IF LASTCC <= 8 THEN SET MAXCC = 0
/*
//*
//*============================================================
//* STEP 2: SORT DAILY TRANSACTIONS BY ACCOUNT NUMBER
//*============================================================
//SORTTRAN EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.TRANS.SORTED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A)
  INCLUDE COND=(49,1,CH,NE,C'X')
  OPTION EQUALS
/*
//*
//*============================================================
//* STEP 3: BACKUP CURRENT MASTER FILE
//*============================================================
//BACKUP   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//OUTFILE  DD DSN=BACKUP.ACCT.MASTER.D260210,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(50,10),RLSE),
//            DCB=(RECFM=FB,LRECL=400,BLKSIZE=32000)
//SYSIN    DD *
  REPRO INFILE(INFILE) OUTFILE(OUTFILE)
/*
//*
//*============================================================
//* STEP 4: RUN COBOL ACCOUNT UPDATE PROGRAM
//*============================================================
//UPDTACCT EXEC PGM=ACCTUPD
//STEPLIB  DD DSN=PROD.COBOL.LOADLIB,DISP=SHR
//SYSOUT   DD SYSOUT=*
//TRANSIN  DD DSN=WORK.ACCT.TRANS.SORTED,DISP=SHR
//ACCTMSTR DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//UPDTLOG  DD DSN=WORK.ACCT.UPDATE.REPORT,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FBA,LRECL=133,BLKSIZE=27930)
//ERRFILE  DD DSN=WORK.ACCT.ERROR.FILE,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(1,1),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//*
//*============================================================
//* STEP 5: CHECK FOR ERRORS - PRINT ERROR FILE
//*============================================================
//PRINTERR EXEC PGM=ICEGENER,
//            COND=(0,NE,UPDTACCT)
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=WORK.ACCT.ERROR.FILE,DISP=SHR
//SYSUT2   DD SYSOUT=A
//SYSIN    DD DUMMY
//*
//*============================================================
//* STEP 6: PRINT UPDATE REPORT
//*============================================================
//PRTRPT   EXEC PGM=ICEGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=WORK.ACCT.UPDATE.REPORT,DISP=SHR
//SYSUT2   DD SYSOUT=A
//SYSIN    DD DUMMY
//*
//*============================================================
//* STEP 7: CLEANUP WORK FILES
//*============================================================
//WRKCLEAN EXEC PGM=IEFBR14
//WORK01   DD DSN=WORK.ACCT.TRANS.SORTED,
//            DISP=(OLD,DELETE,DELETE)

29.10.2 COBOL Program Using SORT as a Subroutine

COBOL can invoke DFSORT directly through the SORT verb, but an alternative approach is to use JCL to sort data before and after COBOL processing. The COBOL SORT verb is covered in Chapter 28. Here is the JCL approach where DFSORT runs as separate steps:

//*============================================================
//* SORT TRANSACTIONS BEFORE COBOL PROCESSING
//*============================================================
//PRESORT  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.RAW,DISP=SHR
//SORTOUT  DD DSN=&&SORTTEMP,
//            DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A,41,8,CH,A)
  INCLUDE COND=(49,1,CH,NE,C'X')
/*
//*============================================================
//* RUN COBOL TRANSACTION PROCESSOR
//*============================================================
//PROCESS  EXEC PGM=TRANPROC
//STEPLIB  DD DSN=PROD.COBOL.LOADLIB,DISP=SHR
//SYSOUT   DD SYSOUT=*
//TRANSIN  DD DSN=&&SORTTEMP,DISP=(OLD,DELETE)
//ACCTMSTR DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//RPTOUT   DD DSN=&&RPTTEMP,
//            DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FBA,LRECL=133,BLKSIZE=27930)
//*============================================================
//* SORT REPORT OUTPUT BY BRANCH FOR DISTRIBUTION
//*============================================================
//RPTPOST  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=&&RPTTEMP,DISP=(OLD,DELETE)
//SORTOUT  DD DSN=PROD.REPORTS.TRANS.BYBRANCH,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FBA,LRECL=133,BLKSIZE=27930)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(10,5))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(10,5))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(10,5))
//SYSIN    DD *
  SORT FIELDS=(10,4,CH,A,1,10,CH,A)
/*

This pattern uses temporary datasets (&&SORTTEMP, &&RPTTEMP) that are automatically deleted at job end, eliminating the need for explicit cleanup steps.

29.10.3 VSAM File Maintenance Job

A complete VSAM maintenance job that reorganizes a KSDS by unloading, deleting, redefining, and reloading:

//VSAMREOR JOB (PROD,DBA),'VSAM REORG',
//            CLASS=A,MSGCLASS=X,MSGLEVEL=(1,1),
//            NOTIFY=&SYSUID
//*
//*============================================================
//* STEP 1: UNLOAD VSAM TO SEQUENTIAL FILE
//*============================================================
//UNLOAD   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//OUTFILE  DD DSN=&&UNLOAD,
//            DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(CYL,(100,20),RLSE),
//            DCB=(RECFM=FB,LRECL=400,BLKSIZE=32000)
//SYSIN    DD *
  REPRO INFILE(INFILE) OUTFILE(OUTFILE)
/*
//*
//*============================================================
//* STEP 2: DELETE AND REDEFINE THE CLUSTER
//*============================================================
//REDEFINE EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE PROD.ACCT.MASTER.KSDS                        -
         CLUSTER PURGE ERASE
  IF LASTCC <= 8 THEN SET MAXCC = 0
  DEFINE CLUSTER (                                    -
           NAME(PROD.ACCT.MASTER.KSDS)                -
           INDEXED                                    -
           RECORDS(500000 100000)                     -
           RECORDSIZE(400 400)                        -
           KEYS(10 0)                                 -
           FREESPACE(20 10)                           -
           SHAREOPTIONS(2 3)                          -
           SPEED                                      -
           ERASE                                      -
           )                                          -
         DATA (                                       -
           NAME(PROD.ACCT.MASTER.KSDS.DATA)           -
           CONTROLINTERVALSIZE(4096)                  -
           VOLUMES(VOL001)                            -
           )                                          -
         INDEX (                                      -
           NAME(PROD.ACCT.MASTER.KSDS.INDEX)          -
           CONTROLINTERVALSIZE(2048)                  -
           VOLUMES(VOL001)                            -
           )
/*
//*
//*============================================================
//* STEP 3: RELOAD THE DATA
//*============================================================
//RELOAD   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//INFILE   DD DSN=&&UNLOAD,DISP=(OLD,DELETE)
//OUTFILE  DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//SYSIN    DD *
  REPRO INFILE(INFILE) OUTFILE(OUTFILE)
/*
//*
//*============================================================
//* STEP 4: VERIFY THE REORGANIZED CLUSTER
//*============================================================
//VERIFY   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  LISTCAT ENTRIES(PROD.ACCT.MASTER.KSDS) ALL
/*

29.10.4 End-of-Month Reporting Job Stream

This job stream demonstrates how utilities and COBOL programs work together for month-end processing:

//EOMRPT   JOB (PROD,FIN),'END OF MONTH REPORTS',
//            CLASS=A,MSGCLASS=X,MSGLEVEL=(1,1),
//            NOTIFY=&SYSUID
//*
//*============================================================
//* STEP 1: EXTRACT MONTH'S TRANSACTIONS FROM ARCHIVE
//*============================================================
//EXTRACT  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.ARCHIVE,DISP=SHR
//SORTOUT  DD DSN=&&MONTHTX,
//            DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(CYL,(50,10),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(100,20))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(100,20))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(100,20))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A,41,8,CH,A)
  INCLUDE COND=(41,6,CH,EQ,C'202601')
/*
//*
//*============================================================
//* STEP 2: GENERATE ACCOUNT SUMMARY TOTALS
//*============================================================
//SUMMARY  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=&&MONTHTX,DISP=(OLD,PASS)
//SORTOUT  DD DSN=&&ACCTSUM,
//            DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A)
  SUM FIELDS=(85,12,PD,100,12,PD)
/*
//*
//*============================================================
//* STEP 3: SPLIT TRANSACTIONS BY TYPE FOR REPORTS
//*============================================================
//SPLIT    EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=&&MONTHTX,DISP=(OLD,PASS)
//DEPOSITS DD DSN=&&DEPOS,
//            DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//WITHDRAW DD DSN=&&WITHDR,
//            DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SYSIN    DD *
  OPTION COPY
  OUTFIL FNAMES=DEPOSITS,INCLUDE=(49,1,CH,EQ,C'D')
  OUTFIL FNAMES=WITHDRAW,INCLUDE=(49,1,CH,EQ,C'W')
/*
//*
//*============================================================
//* STEP 4: RUN COBOL MONTH-END REPORT PROGRAM
//*============================================================
//EOMCOBOL EXEC PGM=EOMRPTPG
//STEPLIB  DD DSN=PROD.COBOL.LOADLIB,DISP=SHR
//SYSOUT   DD SYSOUT=*
//ACCTSUM  DD DSN=&&ACCTSUM,DISP=(OLD,DELETE)
//DEPOSITS DD DSN=&&DEPOS,DISP=(OLD,DELETE)
//WITHDRAW DD DSN=&&WITHDR,DISP=(OLD,DELETE)
//ACCTMSTR DD DSN=PROD.ACCT.MASTER.KSDS,DISP=SHR
//RPTOUT   DD SYSOUT=A
//RPTCSV   DD DSN=PROD.REPORTS.EOM.CSV.M202601,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(5,2),RLSE),
//            DCB=(RECFM=FB,LRECL=500,BLKSIZE=27500)
//*
//*============================================================
//* STEP 5: ARCHIVE MONTH'S TRANSACTIONS TO TAPE
//*============================================================
//ARCHIVE  EXEC PGM=ICEGENER
//SYSPRINT DD SYSOUT=*
//SYSUT1   DD DSN=&&MONTHTX,DISP=(OLD,DELETE)
//SYSUT2   DD DSN=ARCHIVE.ACCT.TRANS.M202601,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=TAPE,VOL=SER=ARC026,
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=32000)
//SYSIN    DD DUMMY

29.11 Common Utility Recipes

This section provides ready-to-use patterns for tasks that COBOL developers perform frequently. These are the recipes you will reach for repeatedly in your daily work.

29.11.1 Recipe: Remove Duplicate Records

Remove duplicate records from a sorted file, keeping only the first occurrence of each key:

//DEDUP    EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.TRANS.DEDUPED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(50,10))
//SYSIN    DD *
  SORT FIELDS=(1,10,CH,A,41,8,CH,A,49,1,CH,A)
  SUM FIELDS=NONE
/*

29.11.2 Recipe: Count Records in a Dataset

Use DFSORT to count total records and produce a count report:

//RECCOUNT EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.RECORD.COUNT,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(TRK,(1,1),RLSE),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=27920)
//SYSIN    DD *
  OPTION COPY
  OUTFIL REMOVECC,NODETAIL,
    TRAILER1=(C'TOTAL RECORDS: ',COUNT=(M10,LENGTH=10))
/*

29.11.3 Recipe: Convert Fixed-Length to Variable-Length

//FIX2VAR  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.DATA.FB,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.DATA.VB,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=VB,LRECL=404,BLKSIZE=32760)
//SYSIN    DD *
  OPTION COPY,VLSCMP
/*

The VLSCMP option strips trailing spaces from each record, producing variable-length records that save space when records have significant trailing padding.

29.11.4 Recipe: Add Sequence Numbers to a File

//ADDSEQ   EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.DATA.INPUT,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.DATA.NUMBERED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=210,BLKSIZE=27720)
//SYSIN    DD *
  OPTION COPY
  OUTREC FIELDS=(SEQNUM,10,ZD,1,200)
/*

This prepends a 10-digit zero-filled sequence number to each record.

29.11.5 Recipe: Extract and Reformat for CSV Output

Create a CSV file from a fixed-format COBOL data file for import into a spreadsheet or downstream system:

//MAKECSV  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.MASTER.SEQ,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.MASTER.CSV,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=VB,LRECL=500,BLKSIZE=32760)
//SYSIN    DD *
  OPTION COPY
  OUTFIL REMOVECC,
    BUILD=(1,10,C',',
           11,30,C',',
           41,8,C',',
           49,2,C',',
           85,12,PD,EDIT=(STTTTTTTTTTT.TT),C',',
           100,12,PD,EDIT=(STTTTTTTTTTT.TT),C',',
           150,8),
    HEADER1=(C'ACCT_NUM,ACCT_NAME,OPEN_DATE,',
             C'ACCT_TYPE,BALANCE,AVAIL_BAL,',
             C'LAST_ACTIVITY')
/*

29.11.6 Recipe: Conditional Dataset Deletion

Delete multiple datasets, ignoring errors for datasets that do not exist:

//CONDEL   EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE WORK.BATCH.TEMP.FILE1 NONVSAM PURGE
  IF LASTCC NE 0 THEN SET MAXCC = 0
  DELETE WORK.BATCH.TEMP.FILE2 NONVSAM PURGE
  IF LASTCC NE 0 THEN SET MAXCC = 0
  DELETE WORK.BATCH.TEMP.FILE3 NONVSAM PURGE
  IF LASTCC NE 0 THEN SET MAXCC = 0
  DELETE WORK.BATCH.TEMP.KSDS CLUSTER PURGE
  IF LASTCC NE 0 THEN SET MAXCC = 0
/*

29.11.7 Recipe: Create a Test Subset from Production Data

Extract a sample of records for testing purposes. This takes every 100th record:

//SAMPLE   EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.MASTER.SEQ,DISP=SHR
//SORTOUT  DD DSN=TEST.ACCT.MASTER.SAMPLE,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(1,1),RLSE),
//            DCB=(RECFM=FB,LRECL=400,BLKSIZE=32000)
//SYSIN    DD *
  OPTION COPY
  SAMPLE 100
/*

Alternatively, to extract the first 1000 records:

//FIRST1K  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.MASTER.SEQ,DISP=SHR
//SORTOUT  DD DSN=TEST.ACCT.MASTER.FIRST1K,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(1,1),RLSE),
//            DCB=(RECFM=FB,LRECL=400,BLKSIZE=32000)
//SYSIN    DD *
  OPTION COPY,STOPAFT=1000
/*

29.12 Troubleshooting Utility Errors

Utility jobs fail regularly in production environments. Knowing how to diagnose and resolve common errors quickly is a critical skill.

29.12.1 IDCAMS Common Errors

Error: IDC3003I FUNCTION IS TERMINATED. CONDITION CODE IS 12

This typically means a DEFINE CLUSTER failed because of invalid parameters or insufficient space. Check the SYSPRINT output for a preceding IDC message that identifies the specific problem.

Common causes: - The volume specified does not exist or has insufficient space - The dataset name already exists (use DELETE first, or check for naming conflicts) - The RECORDSIZE maximum is less than the average - The KEYS length plus offset exceeds the record size

Error: IDC0551I ENTRY NOT FOUND (DELETE operation, return code 8)

The dataset you are trying to delete does not exist. This is usually expected in cleanup steps. Handle it with:

  DELETE dataset.name ...
  IF LASTCC = 8 THEN SET MAXCC = 0

Error: IDC3009I VSAM OPEN RETURN CODE IS 118 (REPRO operation)

Return code 118 means the dataset was not properly closed after a previous failure. Use VERIFY to fix it:

//FIXVSAM  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  VERIFY DATASET(PROD.ACCT.MASTER.KSDS)
/*

After VERIFY, retry the REPRO operation.

Error: IDC3301I ERROR DURING OPEN - DUPLICATE RECORD

During a REPRO REPLACE operation, this error occurs when the target KSDS already has a record with the same key and REPLACE was not specified. Add the REPLACE keyword:

  REPRO INFILE(INFILE) OUTFILE(OUTFILE) REPLACE

29.12.2 IEBGENER Common Errors

Error: IEB311I SYSIN DD STATEMENT MISSING

IEBGENER requires a SYSIN DD statement. If no control statements are needed, code:

//SYSIN    DD DUMMY

Error: IEB352I SYSUT2 LRECL IS TOO SMALL

The output record length is shorter than the input record length, and no reformatting is specified. Either increase the SYSUT2 LRECL or provide RECORD statements to reformat.

Error: IEB303A INCONSISTENT DCB

The DCB parameters on SYSUT2 conflict with each other or with SYSUT1. Verify that RECFM, LRECL, and BLKSIZE are consistent (for example, BLKSIZE must be a multiple of LRECL for RECFM=FB).

29.12.3 IEBCOPY Common Errors

Error: IEB154I MEMBER NOT FOUND IN INPUT DATA SET

A SELECT statement references a member that does not exist in the input PDS. Verify the member name spelling. Member names are at most 8 characters and are case-insensitive.

Error: IEB1071E INSUFFICIENT SPACE ON OUTPUT DATA SET

The output PDS does not have enough space for the copied members. Either allocate more space or compress the output PDS first.

Error: IEB165I DATASET NOT PARTITIONED

IEBCOPY works only with PDS and PDSE datasets. You are attempting to use it with a sequential dataset. Use IEBGENER or ICEGENER for sequential copies.

29.12.4 DFSORT Common Errors

Error: ICE046A SORT CAPACITY EXCEEDED

The sort work datasets (SORTWKnn) do not have enough space for the volume of data being sorted. Solutions:

  1. Increase SPACE on SORTWK DD statements
  2. Add more SORTWK datasets (up to 32 are supported)
  3. Use OPTION DYNALLOC=(SYSDA,5) to let DFSORT allocate its own work space
  4. Use INREC to reduce the record length before sorting

Error: ICE052A INSUFFICIENT STORAGE

The region size (REGION parameter on JOB or EXEC) is too small. Increase REGION to at least 4M for large sorts, or specify REGION=0M for maximum available memory:

//SORTSTEP EXEC PGM=SORT,REGION=0M

Error: ICE054A SORT/MERGE FIELD EXTENDS BEYOND RECORD

A SORT FIELDS parameter specifies a position and length that exceed the record length. For example, SORT FIELDS=(190,20,CH,A) on a 200-byte record attempts to read from position 190 for 20 bytes (positions 190-209), which exceeds the record boundary. Verify record length and field positions.

Error: ICE105A INVALID INCLUDE/OMIT CONDITION

The INCLUDE or OMIT condition has a syntax error. Common mistakes: - Using = instead of EQ - Missing commas between conditions - Incorrect parentheses - Comparing different data types without conversion

29.12.5 General Troubleshooting Strategy

When any utility job fails, follow this diagnostic approach:

  1. Check the JES job log (JESMSGLG): Look for system-level messages about allocation failures, security violations, or abend codes.

  2. Check the utility SYSPRINT output: This contains the utility's own diagnostic messages, which are usually more specific than JCL messages.

  3. Verify the condition code: Each step's condition code appears in the job log. Cross-reference it with the utility's return code documentation.

  4. Check DD statement parameters: Many errors stem from inconsistent DCB parameters, incorrect dataset names, or wrong DISP values.

  5. Verify dataset existence and status: Use ISPF 3.4 (DSLIST) or IDCAMS LISTCAT to confirm that input datasets exist and are not held by another job.

  6. Check for enqueue conflicts: If a job hangs rather than fails, another job or TSO session may hold the dataset exclusively. Use the system display command D GRS,RES=(*,datasetname) to check enqueue holders.

  7. Review previous step output: A utility step may fail because a previous step produced unexpected output. Check the SYSPRINT and return codes of all preceding steps.


29.13 Advanced DFSORT Techniques

Beyond basic sorting and filtering, DFSORT provides advanced capabilities that can replace simple COBOL programs entirely.

29.13.1 Joining Two Files with JOINKEYS

DFSORT can join two files on a common key, similar to a SQL JOIN. [IBM Enterprise COBOL] This example joins an account master file with a transaction summary file:

//JOINFILE EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTJNF1 DD DSN=PROD.ACCT.MASTER.SEQ,DISP=SHR
//SORTJNF2 DD DSN=WORK.ACCT.TRANS.TOTALS,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.COMBINED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=600,BLKSIZE=27600)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SYSIN    DD *
  JOINKEYS FILE=F1,FIELDS=(1,10,A)
  JOINKEYS FILE=F2,FIELDS=(1,10,A)
  JOIN UNPAIRED,F1,F2
  REFORMAT FIELDS=(F1:1,400,F2:1,200)
  SORT FIELDS=(1,10,CH,A)
/*
  • JOINKEYS: Specifies the join key for each input file.
  • JOIN UNPAIRED,F1,F2: Performs a full outer join, including unmatched records from both files.
  • REFORMAT: Defines the combined record layout. F1 fields come first (400 bytes), followed by F2 fields (200 bytes), yielding a 600-byte output record.

Join types: - JOIN UNPAIRED: Full outer join - JOIN UNPAIRED,F1,ONLY: Left outer join - JOIN UNPAIRED,F2,ONLY: Right outer join - No JOIN statement: Inner join (only matched records)

29.13.2 IFTHEN -- Conditional Record Processing

IFTHEN allows different processing rules for different records within the same pass. This example processes deposit and withdrawal transactions differently:

//CONDPROC EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.TRANS.FLAGGED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=210,BLKSIZE=27720)
//SYSIN    DD *
  OPTION COPY
  OUTREC IFTHEN=(WHEN=(49,1,CH,EQ,C'D'),
                 BUILD=(1,200,C'CREDIT    ')),
         IFTHEN=(WHEN=(49,1,CH,EQ,C'W'),
                 BUILD=(1,200,C'DEBIT     ')),
         IFTHEN=(WHEN=NONE,
                 BUILD=(1,200,C'OTHER     '))
/*

The WHEN=NONE clause acts as a default case, processing any records that did not match earlier conditions.

29.13.3 Date Processing with DFSORT

DFSORT has built-in date manipulation functions. [IBM Enterprise COBOL] Convert a date field from YYYYMMDD to MM/DD/YYYY format:

//DATEFMT  EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.TRANS.FMTDATE,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(20,5),RLSE),
//            DCB=(RECFM=FB,LRECL=210,BLKSIZE=27720)
//SYSIN    DD *
  OPTION COPY
  OUTREC FIELDS=(1,40,
                 41,8,Y4T=(MDY/),
                 49,152)
/*

The Y4T=(MDY/) function converts a 4-digit year date to MM/DD/YYYY format with slash separators.

29.13.4 Generating Reports Entirely with DFSORT

DFSORT can produce complete formatted reports with headers, detail lines, and trailers without any COBOL code:

//RPTGEN   EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.SORTED,DISP=SHR
//SORTOUT  DD SYSOUT=A,
//            DCB=(RECFM=FBA,LRECL=133,BLKSIZE=27930)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(20,10))
//SYSIN    DD *
  SORT FIELDS=(180,4,CH,A,1,10,CH,A)
  OUTFIL REMOVECC,
    HEADER1=(/,
      C' ',58C'=',/,
      C' DAILY TRANSACTION REPORT',/,
      C' DATE: ',DATE=(4MD/),
      C'    TIME: ',TIME=(12:),/,
      C' ',58C'=',/,
      C' BRANCH  ACCOUNT     DATE       TYPE ',
      C' AMOUNT',/,
      C' ',58C'-'),
    OUTREC=(C' ',
            180,4,
            C'    ',
            1,10,
            C'  ',
            41,8,
            C'   ',
            49,1,
            C'    ',
            85,12,PD,EDIT=(STTTTTTTTTTT.TT)),
    TRAILER1=(/,
      C' ',58C'-',/,
      C' TOTAL RECORDS: ',COUNT=(M10,LENGTH=10),/,
      C' ',58C'=',/,
      C' END OF REPORT')
/*

29.13.5 Using DFSORT Symbols

DFSORT supports symbolic parameters that make control statements more readable and maintainable:

//SYMEXAMP EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=PROD.ACCT.TRANS.DAILY,DISP=SHR
//SORTOUT  DD DSN=WORK.ACCT.TRANS.SELECTED,
//            DISP=(NEW,CATLG,DELETE),
//            UNIT=SYSDA,SPACE=(CYL,(10,5),RLSE),
//            DCB=(RECFM=FB,LRECL=200,BLKSIZE=27800)
//SORTWK01 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK02 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SORTWK03 DD UNIT=SYSDA,SPACE=(CYL,(30,10))
//SYMNAMES DD *
  ACCT-NUM,1,10,CH
  TRAN-DATE,41,8,CH
  TRAN-TYPE,49,1,CH
  TRAN-AMT,85,12,PD
  BRANCH-CD,180,4,CH
//SYSIN    DD *
  SORT FIELDS=(ACCT-NUM,A,TRAN-DATE,A)
  INCLUDE COND=(TRAN-TYPE,EQ,C'D',AND,
                TRAN-AMT,GT,+100000)
/*

The SYMNAMES DD defines symbolic names for field positions, lengths, and formats. This makes DFSORT control statements self-documenting and reduces errors from hard-coded positions.


29.14 Security Considerations

When working with mainframe utilities, security is paramount, especially in financial environments.

29.14.1 RACF and Dataset Access

[IBM Enterprise COBOL] Every dataset access through a utility is subject to RACF (Resource Access Control Facility) security checks. The user ID that submits the job must have appropriate authority:

Operation Required Access Level
Read a dataset READ
Write to an existing dataset UPDATE
Create a new dataset ALTER on the high-level qualifier
Delete a dataset ALTER on the dataset profile
Define a VSAM cluster ALTER on the high-level qualifier

If a utility step receives an S913 abend (RACF authorization failure), contact your security administrator to request appropriate access.

29.14.2 Sensitive Data Handling

When using utilities to copy or print financial data:

  • Always specify the ERASE option on VSAM DEFINE CLUSTER and DELETE commands to prevent data remnants on disk.
  • Avoid printing sensitive data (account numbers, SSNs, balances) to SYSOUT without masking. Use DFSORT OUTREC to mask fields if needed.
  • Use RACF DATASET profiles to restrict access to production master files.
  • Ensure work datasets are allocated on secured volumes and are deleted in cleanup steps.

29.15 Best Practices Summary

Effective utility usage follows several guiding principles that experienced COBOL developers internalize over time.

29.15.1 JCL and Utility Best Practices

  1. Always include cleanup steps: Delete temporary datasets at the beginning and end of job streams. Use IDCAMS with IF LASTCC logic rather than IEFBR14 for more reliable cleanup.

  2. Use temporary datasets for intermediate work: Temporary datasets (&&name) are automatically cleaned up when the job ends, reducing the risk of orphaned work files.

  3. Specify DCB parameters explicitly: Do not rely on defaults or catalog inheritance for output datasets. Explicit RECFM, LRECL, and BLKSIZE prevent surprises.

  4. Use RLSE (Release unused space): Always include RLSE in the SPACE parameter for output datasets to return unused space to the system.

  5. Provide adequate SORTWK space: Under-allocating sort work space is the most common cause of sort failures. Allocate at least twice the input file size across three or more work datasets.

  6. Use OPTION EQUALS for stable sorts: When record order matters for records with equal keys, always specify EQUALS.

  7. Test with subsets first: When developing new utility jobs, use STOPAFT or SAMPLE to process a small number of records before running against full production volumes.

  8. Document utility control statements: Add comments to explain why specific field positions, filter conditions, and sort keys are used. Future maintainers will thank you.

29.15.2 Performance Best Practices

  1. Use ICEGENER instead of IEBGENER: ICEGENER is faster due to DFSORT optimization and supports filtering and reformatting without an additional sort step.

  2. Use INREC to shrink records before sorting: If only a few fields participate in the sort, use INREC to extract them. Sorting shorter records is dramatically faster.

  3. Spread SORTWK across volumes: Place each SORTWKnn dataset on a separate DASD volume for parallel I/O.

  4. Use OUTFIL for multi-file output: Processing a file once with OUTFIL is far faster than reading it multiple times with separate sort steps.

  5. Use MERGE instead of SORT for pre-sorted inputs: When combining already-sorted files, MERGE avoids the overhead of a full sort pass.

  6. Optimize VSAM BUFFERSPACE: For large IDCAMS REPRO operations, increasing BUFFERSPACE on the cluster reduces I/O operations.


29.16 Quick Reference Card

IDCAMS Commands

Command Purpose Key Parameters
DEFINE CLUSTER Create VSAM dataset NAME, INDEXED/NONINDEXED/NUMBERED, RECORDS, RECORDSIZE, KEYS, FREESPACE
REPRO Copy data INFILE, OUTFILE, REPLACE, FROMKEY, TOKEY, COUNT
DELETE Remove dataset CLUSTER/NONVSAM, PURGE, ERASE
PRINT Display records CHARACTER/HEX/DUMP, COUNT, FROMKEY, TOKEY
LISTCAT Show catalog info ENTRIES, LEVEL, ALL, VOLUME, ALLOCATION
ALTER Change attributes FREESPACE, SHAREOPTIONS, BUFFERSPACE
VERIFY Fix improperly closed dataset DATASET

DFSORT Control Statements

Statement Purpose Example
SORT FIELDS Define sort keys SORT FIELDS=(1,10,CH,A)
MERGE FIELDS Define merge keys MERGE FIELDS=(1,10,CH,A)
OPTION COPY Copy without sorting OPTION COPY
INCLUDE COND Select records INCLUDE COND=(5,2,CH,EQ,C'NY')
OMIT COND Exclude records OMIT COND=(5,2,CH,EQ,C'XX')
INREC FIELDS Reformat before sort INREC FIELDS=(1,10,20,5)
OUTREC FIELDS Reformat after sort OUTREC FIELDS=(1,10,C' ',20,5)
SUM FIELDS Summarize numeric fields SUM FIELDS=(15,8,PD)
SUM FIELDS=NONE Remove duplicates SUM FIELDS=NONE
OUTFIL Multi-output with filters OUTFIL FNAMES=OUT1,INCLUDE=(...)
JOINKEYS Join two files JOINKEYS FILE=F1,FIELDS=(1,10,A)

Utility DD Name Conventions

Utility Input DD Output DD Control DD Messages DD
IDCAMS User-defined User-defined SYSIN SYSPRINT
IEBGENER SYSUT1 SYSUT2 SYSIN SYSPRINT
ICEGENER SYSUT1 SYSUT2 SYSIN SYSPRINT
IEBCOPY User-defined User-defined SYSIN SYSPRINT
DFSORT SORTIN SORTOUT SYSIN SYSOUT
ISRSUPC NEWDD OUTDD SYSIN (via OUTDD)

29.17 Summary

Mainframe utilities form the operational backbone of COBOL batch processing environments. In this chapter, we covered:

  • IDCAMS for comprehensive VSAM dataset management, including DEFINE CLUSTER, REPRO, DELETE, PRINT, LISTCAT, and ALTER, along with conditional processing for robust error handling.

  • IEBGENER for straightforward sequential dataset copying and basic record reformatting using GENERATE and RECORD control statements.

  • IEBCOPY for PDS and PDSE management, including full library copies, selective member operations, compression, merging, and member renaming.

  • DFSORT as a versatile data processing engine supporting SORT, MERGE, COPY, INCLUDE/OMIT filtering, INREC/OUTREC reformatting, SUM summarization, OUTFIL multi-output, JOINKEYS file joining, and IFTHEN conditional processing.

  • IEFBR14 as a mechanism for dataset allocation and deletion through JCL disposition processing.

  • ICEGENER as an enhanced, DFSORT-powered replacement for IEBGENER that supports filtering and reformatting.

  • SuperC (ISRSUPC) for comparing datasets and PDS members, essential for code reviews and change tracking.

  • ISPF as the interactive development environment, including editor commands, SDSF for job monitoring, and panel navigation.

  • Integration patterns showing how utilities and COBOL programs work together in production job streams for account updates, VSAM reorganization, and end-of-month reporting.

The ability to combine these utilities effectively -- to sort before processing, filter during extraction, reformat for output, and verify after completion -- is what separates a productive COBOL developer from one who struggles with the batch environment. In the next chapter, we explore z/OS datasets in greater depth, examining the physical and logical organization of data that these utilities manage.


Key Terms: IDCAMS, VSAM, KSDS, ESDS, RRDS, IEBGENER, IEBCOPY, DFSORT, SyncSort, IEFBR14, ICEGENER, SuperC, ISRSUPC, ISPF, SDSF, REPRO, DEFINE CLUSTER, LISTCAT, SORTWK, INCLUDE, OMIT, INREC, OUTREC, OUTFIL, JOINKEYS, PDS, PDSE

Cross-References: - Chapter 27: JCL Essentials -- JCL syntax, DD statements, and job submission - Chapter 28: Batch Processing -- Batch design patterns, COBOL SORT verb, and job scheduling - Chapter 30: z/OS Datasets -- Dataset organization, access methods, and catalog management