18 min read

Every chapter up to this point has focused on batch processing -- programs that run in the background, processing files from beginning to end without human interaction. But the mainframe is not just a batch engine. When a bank teller looks up your...

Chapter 24: CICS Transaction Processing Fundamentals

IBM Enterprise COBOL

Introduction: Online Transaction Processing on the Mainframe

Every chapter up to this point has focused on batch processing -- programs that run in the background, processing files from beginning to end without human interaction. But the mainframe is not just a batch engine. When a bank teller looks up your account balance, when an airline agent books your flight, when a government clerk processes your benefit claim on a terminal, the mainframe is processing those requests in real time through an online transaction processing system.

On IBM mainframes, that system is CICS -- the Customer Information Control System. CICS has been the dominant online transaction processing (OLTP) monitor on mainframes since its introduction in 1969. Today it processes an estimated 1.2 million transactions per second worldwide, supporting over 30 billion transactions per day. Banks, airlines, insurance companies, retailers, and government agencies all depend on CICS for their interactive mainframe applications.

CICS provides services that batch programs handle for themselves: terminal management (reading input from and writing output to user screens), task management (running thousands of concurrent transactions), program management (loading and dispatching application programs), file management (providing shared access to files and databases), and recovery management (ensuring data integrity when failures occur).

COBOL programs that run under CICS look different from batch programs. They do not have ENVIRONMENT DIVISION file definitions. They do not use READ, WRITE, OPEN, or CLOSE. They do not use DISPLAY or ACCEPT. Instead, they use EXEC CICS commands -- a parallel command-level API that requests CICS services. A CICS COBOL program is, at its core, a COBOL program with EXEC CICS...END-EXEC statements in place of native file I/O and terminal I/O.

This chapter covers the fundamentals of CICS programming with COBOL: the EXEC CICS interface, terminal I/O with SEND and RECEIVE, screen design with BMS (Basic Mapping Support), file operations, the critical pseudo-conversational programming model, EIB fields, error handling, program control, and temporary storage.


24.1 CICS Overview: Architecture and Concepts

How CICS Works

CICS runs as an address space (region) on z/OS. Within that region, multiple transactions execute concurrently, sharing the same memory space. A transaction is initiated when a user types a transaction identifier (a 1-4 character code) on a 3270 terminal and presses Enter. CICS loads the associated program, creates a task, and dispatches the program to process the request.

Key CICS Concepts

Concept Description
Transaction A unit of work initiated by a user, identified by a 4-character TRANSID (e.g., INQC for customer inquiry)
Task A running instance of a transaction. Multiple tasks can run the same transaction concurrently.
Program The COBOL program associated with a transaction, defined in the Program Processing Table (PPT)
Terminal A 3270 screen device where the user interacts with CICS
EIB Execute Interface Block, a control block containing information about the current task
COMMAREA Communication Area, a block of data passed between transaction instances (pseudo-conversational) or between programs
BMS Basic Mapping Support, the facility for formatting 3270 screens
PCT Program Control Table, maps transaction IDs to programs
PPT Processing Program Table, defines programs known to CICS
FCT File Control Table, defines files accessible through CICS file control

CICS vs. Batch: What Changes

Batch COBOL CICS COBOL
OPEN, READ, WRITE, CLOSE EXEC CICS READ, WRITE, REWRITE, DELETE
DISPLAY, ACCEPT EXEC CICS SEND, RECEIVE
SELECT...ASSIGN Files defined in FCT
STOP RUN EXEC CICS RETURN
SORT, MERGE Not available (use batch)
FILE STATUS EXEC CICS RESP/RESP2
Report Writer Not applicable (use BMS maps)

24.2 The EXEC CICS...END-EXEC Interface

All CICS services are accessed through the EXEC CICS command interface:

           EXEC CICS command
               option(value)
               option(value)
               ...
           END-EXEC

General Syntax Rules

  1. EXEC CICS begins every CICS command.
  2. END-EXEC terminates the command. Like EXEC SQL, do not place a period after END-EXEC unless you intend to end a COBOL sentence.
  3. Options are keyword-value pairs specific to each command.
  4. Data items referenced in CICS commands do not use a colon prefix (unlike DB2 host variables).
  5. Literal values in CICS are enclosed in quotes or apostrophes depending on compiler settings.

Common CICS Commands

      * Send data to the terminal
           EXEC CICS SEND TEXT
               FROM(WS-MESSAGE)
               LENGTH(WS-MSG-LENGTH)
           END-EXEC

      * Read a VSAM record
           EXEC CICS READ
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(WS-CUSTOMER-KEY)
               LENGTH(WS-REC-LENGTH)
           END-EXEC

      * Return control to CICS
           EXEC CICS RETURN
           END-EXEC

24.3 SEND TEXT and SEND MAP

SEND TEXT: Simple Terminal Output

The simplest way to send output to a 3270 terminal is SEND TEXT:

       WORKING-STORAGE SECTION.
       01  WS-MESSAGE         PIC X(80).
       01  WS-MSG-LENGTH      PIC S9(4) COMP VALUE 80.

       PROCEDURE DIVISION.
       0000-MAIN.
           MOVE 'WELCOME TO CUSTOMER INQUIRY SYSTEM'
               TO WS-MESSAGE

           EXEC CICS SEND TEXT
               FROM(WS-MESSAGE)
               LENGTH(WS-MSG-LENGTH)
               ERASE
               FREEKB
           END-EXEC

           EXEC CICS RETURN
           END-EXEC
           .

Key options for SEND TEXT:

Option Description
FROM(data-area) The data to send to the terminal
LENGTH(data-value) Length of the data
ERASE Clear the screen before writing
FREEKB Unlock the keyboard so the user can type
CURSOR(position) Position the cursor at a specific screen location

SEND MAP: Formatted Screen Output

For formatted screens (which is what most CICS applications use), the SEND MAP command sends data to the terminal using a predefined screen layout called a BMS map:

           EXEC CICS SEND MAP('CUSTMAP')
               MAPSET('CUSTSET')
               FROM(CUSTMAPO)
               ERASE
               FREEKB
               CURSOR
           END-EXEC

Key options for SEND MAP:

Option Description
MAP(name) The map name (defined in the BMS mapset)
MAPSET(name) The mapset name (the BMS load module)
FROM(data-area) The symbolic map output structure
ERASE Clear the screen before sending
FREEKB Unlock the keyboard
CURSOR Position the cursor at the field with the cursor attribute set, or at position (0,0)
ERASEAUP Erase all unprotected fields
DATAONLY Send only data fields, not constant text or attributes
MAPONLY Send only the map layout, not data from the program

24.4 RECEIVE MAP: Reading User Input

The RECEIVE MAP command reads data entered by the user on a BMS-formatted screen:

           EXEC CICS RECEIVE MAP('CUSTMAP')
               MAPSET('CUSTSET')
               INTO(CUSTMAPI)
           END-EXEC

After RECEIVE MAP, the symbolic map input structure (CUSTMAPI) contains the data typed by the user in each input field, along with the length of each field and the attention key pressed (AID key).

Processing Received Data

       2000-RECEIVE-AND-PROCESS.
           EXEC CICS RECEIVE MAP('CUSTMAP')
               MAPSET('CUSTSET')
               INTO(CUSTMAPI)
               RESP(WS-CICS-RESP)
               RESP2(WS-CICS-RESP2)
           END-EXEC

           IF WS-CICS-RESP = DFHRESP(NORMAL)
      *        Process the data entered by the user
               MOVE CUSTIDI TO WS-SEARCH-KEY
               IF WS-SEARCH-KEY = SPACES
                   MOVE 'PLEASE ENTER A CUSTOMER ID'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP
               ELSE
                   PERFORM 2100-LOOKUP-CUSTOMER
               END-IF
           ELSE IF WS-CICS-RESP = DFHRESP(MAPFAIL)
      *        User pressed Enter without typing anything
               MOVE 'NO DATA ENTERED'
                   TO MSGEXTO
               PERFORM 3000-SEND-MAP
           END-IF
           .

24.5 BMS: Basic Mapping Support

BMS is the CICS facility for defining 3270 screen layouts. A BMS map definition is written in assembler macro language (not COBOL) and is assembled into two outputs: a physical map (a load module that CICS uses to format the screen) and a symbolic map (a COBOL copybook that your program uses to populate and read screen fields).

BMS Map Definition

A BMS mapset consists of three macros:

  • DFHMSD: Defines the mapset (a collection of maps)
  • DFHMDI: Defines an individual map (screen layout)
  • DFHMDF: Defines a field on the map
CUSTSET  DFHMSD TYPE=&SYSPARM,                                X
               MODE=INOUT,                                     X
               LANG=COBOL,                                     X
               STORAGE=AUTO,                                   X
               CTRL=(FREEKB,FRSET),                            X
               TIOAPFX=YES
*
CUSTMAP  DFHMDI SIZE=(24,80),                                  X
               LINE=1,                                         X
               COLUMN=1
*
* Row 1: Title
         DFHMDF POS=(1,25),                                    X
               LENGTH=30,                                      X
               ATTRB=(ASKIP,BRT),                              X
               INITIAL='CUSTOMER INQUIRY SCREEN'
*
* Row 3: Customer ID label and input field
         DFHMDF POS=(3,2),                                     X
               LENGTH=12,                                      X
               ATTRB=(ASKIP,NORM),                             X
               INITIAL='CUSTOMER ID:'
*
CUSTID   DFHMDF POS=(3,15),                                    X
               LENGTH=10,                                      X
               ATTRB=(UNPROT,NORM,IC),                         X
               INITIAL=' '
         DFHMDF POS=(3,26),                                    X
               LENGTH=1,                                       X
               ATTRB=ASKIP
*
* Row 5: Customer Name (output)
         DFHMDF POS=(5,2),                                     X
               LENGTH=5,                                       X
               ATTRB=(ASKIP,NORM),                             X
               INITIAL='NAME:'
*
CUSTNM   DFHMDF POS=(5,8),                                    X
               LENGTH=30,                                      X
               ATTRB=(ASKIP,NORM)
*
* Row 7: Balance (output)
         DFHMDF POS=(7,2),                                     X
               LENGTH=8,                                       X
               ATTRB=(ASKIP,NORM),                             X
               INITIAL='BALANCE:'
*
CUSTBAL  DFHMDF POS=(7,11),                                   X
               LENGTH=14,                                      X
               ATTRB=(ASKIP,NORM)
*
* Row 22: Message line
MSGEXT   DFHMDF POS=(22,2),                                   X
               LENGTH=70,                                      X
               ATTRB=(ASKIP,BRT)
*
* Row 24: PF Key instructions
         DFHMDF POS=(24,2),                                    X
               LENGTH=40,                                      X
               ATTRB=(ASKIP,NORM),                             X
               INITIAL='PF3=EXIT  PF12=CANCEL  ENTER=SEARCH'
*
CUSTSET  DFHMSD TYPE=FINAL
         END

Understanding Attribute Bytes

Every field on a 3270 screen is preceded by an attribute byte that controls its behavior:

Attribute Description
ASKIP Auto-skip: cursor skips over this field (used for labels and output)
UNPROT Unprotected: user can type in this field (input field)
PROT Protected: field is visible but user cannot type in it
NORM Normal intensity display
BRT Bright (highlighted) intensity
DRK Dark (invisible) -- used for password fields
NUM Numeric-only input
IC Initial cursor position
FSET Modified data tag set -- field appears changed even if user did not modify it

The Symbolic Map (COBOL Copybook)

When you assemble the BMS map with TYPE=DSECT, the assembler generates a COBOL copybook containing the symbolic map. This copybook defines two structures: one for input (suffixed with I) and one for output (suffixed with O):

      * Generated by BMS assembly (simplified)
       01  CUSTMAPI.
           05  FILLER              PIC X(12).
           05  CUSTIDL             PIC S9(4) COMP.
           05  CUSTIDF             PIC X.
           05  FILLER REDEFINES CUSTIDF.
               10  CUSTIDA         PIC X.
           05  CUSTIDI             PIC X(10).
           05  CUSTNML             PIC S9(4) COMP.
           05  CUSTNMF             PIC X.
           05  FILLER REDEFINES CUSTNMF.
               10  CUSTNMA         PIC X.
           05  CUSTNMI             PIC X(30).
           05  CUSTBALL            PIC S9(4) COMP.
           05  CUSTBALF            PIC X.
           05  FILLER REDEFINES CUSTBALF.
               10  CUSTBALA        PIC X.
           05  CUSTBALI            PIC X(14).
           05  MSGEXTL             PIC S9(4) COMP.
           05  MSGEXTF             PIC X.
           05  FILLER REDEFINES MSGEXTF.
               10  MSGEXTA         PIC X.
           05  MSGEXTI             PIC X(70).

       01  CUSTMAPO REDEFINES CUSTMAPI.
           05  FILLER              PIC X(12).
           05  FILLER              PIC X(3).
           05  CUSTIDO             PIC X(10).
           05  FILLER              PIC X(3).
           05  CUSTNMO             PIC X(30).
           05  FILLER              PIC X(3).
           05  CUSTBALO            PIC X(14).
           05  FILLER              PIC X(3).
           05  MSGEXTO             PIC X(70).

For each named field, the symbolic map includes:

Suffix Type Description
L PIC S9(4) COMP Length of data entered by user (input)
F PIC X Flag/attribute byte
A PIC X (REDEFINES F) Attribute byte for output modification
I PIC X(n) Input data (what the user typed)
O PIC X(n) Output data (what the program sends)

Populating and Sending a Map

       3000-SEND-CUSTOMER-MAP.
      *    Clear the output map
           MOVE LOW-VALUES TO CUSTMAPO

      *    Populate output fields
           MOVE WS-CUST-ID      TO CUSTIDO
           MOVE WS-CUST-NAME    TO CUSTNMO
           MOVE WS-CUST-BAL-FMT TO CUSTBALO

      *    Set a message
           MOVE 'CUSTOMER RECORD FOUND'
               TO MSGEXTO

      *    Send the map
           EXEC CICS SEND MAP('CUSTMAP')
               MAPSET('CUSTSET')
               FROM(CUSTMAPO)
               ERASE
               FREEKB
               CURSOR
           END-EXEC
           .

24.6 File Control: CICS File Operations

CICS provides its own file control commands for reading and writing VSAM files (and DB2 tables through the DB2 attachment facility). These commands replace the native COBOL READ, WRITE, REWRITE, and DELETE verbs.

READ: Random Read

       01  WS-CUSTOMER-RECORD.
           05  WS-CUST-KEY     PIC X(10).
           05  WS-CUST-NAME    PIC X(30).
           05  WS-CUST-BALANCE PIC S9(7)V99 COMP-3.
           05  WS-CUST-STATUS  PIC X.

       01  WS-REC-LENGTH      PIC S9(4) COMP.
       01  WS-CICS-RESP       PIC S9(8) COMP.
       01  WS-CICS-RESP2      PIC S9(8) COMP.

       2100-READ-CUSTOMER.
           MOVE LENGTH OF WS-CUSTOMER-RECORD
               TO WS-REC-LENGTH

           EXEC CICS READ
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(WS-SEARCH-KEY)
               LENGTH(WS-REC-LENGTH)
               RESP(WS-CICS-RESP)
               RESP2(WS-CICS-RESP2)
           END-EXEC

           EVALUATE WS-CICS-RESP
               WHEN DFHRESP(NORMAL)
                   SET WS-CUSTOMER-FOUND TO TRUE
               WHEN DFHRESP(NOTFND)
                   SET WS-CUSTOMER-NOT-FOUND TO TRUE
               WHEN DFHRESP(DISABLED)
                   MOVE 'FILE IS DISABLED' TO MSGEXTO
               WHEN DFHRESP(NOTOPEN)
                   MOVE 'FILE IS NOT OPEN' TO MSGEXTO
               WHEN OTHER
                   PERFORM 9100-CICS-ERROR
           END-EVALUATE
           .

WRITE: Add a New Record

       2200-ADD-CUSTOMER.
           MOVE WS-NEW-CUST-KEY TO WS-CUST-KEY
           MOVE WS-NEW-CUST-NAME TO WS-CUST-NAME
           MOVE 0 TO WS-CUST-BALANCE
           MOVE 'A' TO WS-CUST-STATUS

           MOVE LENGTH OF WS-CUSTOMER-RECORD
               TO WS-REC-LENGTH

           EXEC CICS WRITE
               FILE('CUSTFILE')
               FROM(WS-CUSTOMER-RECORD)
               RIDFLD(WS-CUST-KEY)
               LENGTH(WS-REC-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

           EVALUATE WS-CICS-RESP
               WHEN DFHRESP(NORMAL)
                   MOVE 'CUSTOMER ADDED SUCCESSFULLY'
                       TO MSGEXTO
               WHEN DFHRESP(DUPREC)
                   MOVE 'CUSTOMER ALREADY EXISTS'
                       TO MSGEXTO
               WHEN OTHER
                   PERFORM 9100-CICS-ERROR
           END-EVALUATE
           .

REWRITE: Update an Existing Record

To update a record, you must first READ it with the UPDATE option, then REWRITE it:

       2300-UPDATE-CUSTOMER.
      *    Read with UPDATE to lock the record
           EXEC CICS READ
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(WS-SEARCH-KEY)
               LENGTH(WS-REC-LENGTH)
               UPDATE
               RESP(WS-CICS-RESP)
           END-EXEC

           IF WS-CICS-RESP = DFHRESP(NORMAL)
      *        Modify the record
               ADD WS-TRANS-AMOUNT TO WS-CUST-BALANCE

      *        Write the updated record back
               EXEC CICS REWRITE
                   FILE('CUSTFILE')
                   FROM(WS-CUSTOMER-RECORD)
                   LENGTH(WS-REC-LENGTH)
                   RESP(WS-CICS-RESP)
               END-EXEC

               IF WS-CICS-RESP = DFHRESP(NORMAL)
                   MOVE 'UPDATE SUCCESSFUL' TO MSGEXTO
               ELSE
                   PERFORM 9100-CICS-ERROR
               END-IF
           ELSE
               EVALUATE WS-CICS-RESP
                   WHEN DFHRESP(NOTFND)
                       MOVE 'CUSTOMER NOT FOUND' TO MSGEXTO
                   WHEN OTHER
                       PERFORM 9100-CICS-ERROR
               END-EVALUATE
           END-IF
           .

DELETE: Remove a Record

       2400-DELETE-CUSTOMER.
           EXEC CICS DELETE
               FILE('CUSTFILE')
               RIDFLD(WS-DELETE-KEY)
               RESP(WS-CICS-RESP)
           END-EXEC

           EVALUATE WS-CICS-RESP
               WHEN DFHRESP(NORMAL)
                   MOVE 'CUSTOMER DELETED' TO MSGEXTO
               WHEN DFHRESP(NOTFND)
                   MOVE 'CUSTOMER NOT FOUND' TO MSGEXTO
               WHEN OTHER
                   PERFORM 9100-CICS-ERROR
           END-EVALUATE
           .

Browse: Sequential Reading (STARTBR/READNEXT/READPREV/ENDBR)

To read records sequentially in CICS (equivalent to a sequential READ loop in batch), you use the browse commands:

       2500-BROWSE-CUSTOMERS.
      *    Start the browse at a specific key
           EXEC CICS STARTBR
               FILE('CUSTFILE')
               RIDFLD(WS-START-KEY)
               GTEQ
               RESP(WS-CICS-RESP)
           END-EXEC

           IF WS-CICS-RESP NOT = DFHRESP(NORMAL)
               MOVE 'BROWSE START FAILED' TO MSGEXTO
               PERFORM 3000-SEND-MAP
               EXEC CICS RETURN END-EXEC
           END-IF

      *    Read records sequentially
           PERFORM 2510-READ-NEXT
               UNTIL WS-BROWSE-DONE
                  OR WS-BROWSE-COUNT >= 20

      *    End the browse
           EXEC CICS ENDBR
               FILE('CUSTFILE')
               RESP(WS-CICS-RESP)
           END-EXEC
           .

       2510-READ-NEXT.
           EXEC CICS READNEXT
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(WS-BROWSE-KEY)
               LENGTH(WS-REC-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

           EVALUATE WS-CICS-RESP
               WHEN DFHRESP(NORMAL)
                   ADD 1 TO WS-BROWSE-COUNT
                   PERFORM 2520-DISPLAY-RECORD
               WHEN DFHRESP(ENDFILE)
                   SET WS-BROWSE-DONE TO TRUE
               WHEN DFHRESP(NOTFND)
                   SET WS-BROWSE-DONE TO TRUE
               WHEN OTHER
                   SET WS-BROWSE-DONE TO TRUE
                   PERFORM 9100-CICS-ERROR
           END-EVALUATE
           .

24.7 Pseudo-Conversational Programming

Pseudo-conversational programming is the most important concept in CICS application design. Understanding it is essential because virtually all CICS applications use this model.

The Problem: Conversational Programming

In a conversational model, a CICS task starts when the user enters a transaction, and the task remains active while the user reads the screen, thinks, and types a response. This means the task holds memory, locks, and other resources for the entire think-time -- which could be seconds, minutes, or hours if the user goes to lunch.

With thousands of concurrent users, conversational programming would require enormous amounts of memory and system resources.

The Solution: Pseudo-Conversational Programming

In the pseudo-conversational model, the task ends after sending the screen to the user. When the user presses Enter or a PF key, CICS starts a new task to process the response. Between the two tasks, no CICS resources are held.

The key mechanism is the RETURN TRANSID command with a COMMAREA (Communication Area):

      * End the current task, specifying:
      * - TRANSID: which transaction to start when user responds
      * - COMMAREA: data to pass to the next task instance
           EXEC CICS RETURN
               TRANSID('INQC')
               COMMAREA(WS-COMMAREA)
               LENGTH(WS-COMMAREA-LENGTH)
           END-EXEC

The Pseudo-Conversational Lifecycle

User types "INQC" and presses Enter
    |
    v
CICS starts Task 1 for TRANSID INQC
    |
    v
Program sends the inquiry screen (SEND MAP)
    |
    v
Program executes RETURN TRANSID('INQC') COMMAREA(data)
    |
    v
Task 1 ENDS -- no resources held
    |
    (User thinks, types customer ID, presses Enter)
    |
    v
CICS starts Task 2 for TRANSID INQC
    |
    v
Program checks EIBCALEN (COMMAREA length)
    - EIBCALEN = 0: This is the first invocation (Task 1 path)
    - EIBCALEN > 0: This is a subsequent invocation (Task 2+ path)
    |
    v
Program receives the map (RECEIVE MAP)
    |
    v
Program processes the request (reads file, etc.)
    |
    v
Program sends results (SEND MAP)
    |
    v
Program executes RETURN TRANSID('INQC') COMMAREA(data)
    |
    v
Task 2 ENDS
    |
    (cycle repeats)

COMMAREA: Passing Data Between Task Instances

The COMMAREA is a block of data that survives between task instances. It is the only way to pass data from one pseudo-conversational instance to the next. When the program receives control, CICS places the COMMAREA from the previous RETURN in the LINKAGE SECTION:

       WORKING-STORAGE SECTION.
       01  WS-COMMAREA.
           05  CA-TRANS-STATE     PIC X.
               88  CA-FIRST-TIME  VALUE '1'.
               88  CA-MAP-SENT    VALUE '2'.
               88  CA-PROCESSING  VALUE '3'.
           05  CA-CUSTOMER-KEY    PIC X(10).
           05  CA-LAST-MAP        PIC X(8).
           05  CA-ERROR-FLAG      PIC 9.

       01  WS-COMMAREA-LENGTH  PIC S9(4) COMP
                               VALUE LENGTH OF WS-COMMAREA.

       LINKAGE SECTION.
       01  DFHCOMMAREA         PIC X(100).

The EIBCALEN Check

The program determines whether this is its first invocation or a subsequent invocation by checking EIBCALEN -- the length of the incoming COMMAREA:

       PROCEDURE DIVISION.
       0000-MAIN.
           IF EIBCALEN = 0
      *        First time -- no COMMAREA, send initial screen
               PERFORM 1000-FIRST-TIME
           ELSE
      *        Subsequent invocation -- process user input
               MOVE DFHCOMMAREA TO WS-COMMAREA
               PERFORM 2000-PROCESS-INPUT
           END-IF
           .

       1000-FIRST-TIME.
           INITIALIZE WS-COMMAREA
           SET CA-MAP-SENT TO TRUE
           MOVE SPACES TO MSGEXTO
           MOVE 'ENTER CUSTOMER ID AND PRESS ENTER'
               TO MSGEXTO

           EXEC CICS SEND MAP('CUSTMAP')
               MAPSET('CUSTSET')
               FROM(CUSTMAPO)
               ERASE
               FREEKB
               CURSOR
           END-EXEC

           EXEC CICS RETURN
               TRANSID('INQC')
               COMMAREA(WS-COMMAREA)
               LENGTH(WS-COMMAREA-LENGTH)
           END-EXEC
           .

       2000-PROCESS-INPUT.
      *    Check which key the user pressed
           EVALUATE EIBAID
               WHEN DFHPF3
                   EXEC CICS SEND TEXT
                       FROM(WS-GOODBYE-MSG)
                       LENGTH(WS-GOODBYE-LEN)
                       ERASE
                   END-EXEC
                   EXEC CICS RETURN END-EXEC

               WHEN DFHPF12
                   PERFORM 1000-FIRST-TIME

               WHEN DFHENTER
                   PERFORM 2100-HANDLE-ENTER

               WHEN OTHER
                   MOVE 'INVALID KEY PRESSED'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP-DATAONLY
           END-EVALUATE
           .

24.8 The EIB: Execute Interface Block

The EIB is a CICS-managed control block that is automatically available to every CICS program. It contains information about the current task, terminal, and transaction.

Key EIB Fields

Field Type Description
EIBTIME PIC S9(7) COMP-3 Current time (0HHMMSS format)
EIBDATE PIC S9(7) COMP-3 Current date (0CYYDDD format, C=century)
EIBTRNID PIC X(4) Transaction ID of the current task
EIBTASKN PIC S9(7) COMP-3 Task number
EIBTRMID PIC X(4) Terminal ID
EIBCPOSN PIC S9(4) COMP Cursor position on the screen
EIBCALEN PIC S9(4) COMP Length of the COMMAREA (0 if none)
EIBAID PIC X Attention identifier (which key was pressed)
EIBFN PIC X(2) Function code of the last CICS command
EIBRCODE PIC X(6) Response code of the last CICS command
EIBDS PIC X(8) Last dataset (file) name referenced
EIBREQID PIC X(8) Request identifier

EIBAID: Attention Identifier Constants

The EIBAID field tells you which key the user pressed. CICS provides copybook DFHAID with predefined constants:

       WORKING-STORAGE SECTION.
       COPY DFHAID.
      * DFHAID defines:
      * 01  DFHENTER   PIC X VALUE X'7D'.    Enter key
      * 01  DFHPF1     PIC X VALUE X'F1'.    PF1
      * 01  DFHPF2     PIC X VALUE X'F2'.    PF2
      * 01  DFHPF3     PIC X VALUE X'F3'.    PF3
      * 01  DFHPF12    PIC X VALUE X'7C'.    PF12
      * 01  DFHPA1     PIC X VALUE X'6C'.    PA1
      * 01  DFHCLEAR   PIC X VALUE X'6D'.    Clear key

       PROCEDURE DIVISION.
       2000-PROCESS-INPUT.
           EVALUATE EIBAID
               WHEN DFHENTER
                   PERFORM 2100-PROCESS-ENTER
               WHEN DFHPF3
                   PERFORM 9000-EXIT-PROGRAM
               WHEN DFHPF5
                   PERFORM 2200-REFRESH-DATA
               WHEN DFHPF7
                   PERFORM 2300-PAGE-BACKWARD
               WHEN DFHPF8
                   PERFORM 2400-PAGE-FORWARD
               WHEN DFHPF12
                   PERFORM 2500-CANCEL
               WHEN DFHCLEAR
                   PERFORM 9000-EXIT-PROGRAM
               WHEN OTHER
                   MOVE 'INVALID KEY - USE PF3 TO EXIT'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP-DATAONLY
           END-EVALUATE
           .

24.9 Error Handling: RESP and RESP2

CICS error handling uses the RESP and RESP2 options on every CICS command. This is the modern recommended approach, replacing the older HANDLE CONDITION mechanism.

Using RESP and RESP2

       01  WS-CICS-RESP       PIC S9(8) COMP.
       01  WS-CICS-RESP2      PIC S9(8) COMP.

       2100-READ-CUSTOMER.
           EXEC CICS READ
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(WS-SEARCH-KEY)
               LENGTH(WS-REC-LENGTH)
               RESP(WS-CICS-RESP)
               RESP2(WS-CICS-RESP2)
           END-EXEC

           EVALUATE WS-CICS-RESP
               WHEN DFHRESP(NORMAL)
                   PERFORM 2110-DISPLAY-CUSTOMER
               WHEN DFHRESP(NOTFND)
                   MOVE 'CUSTOMER NOT FOUND'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP-DATAONLY
               WHEN DFHRESP(DISABLED)
                   MOVE 'FILE IS CURRENTLY DISABLED'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP-DATAONLY
               WHEN DFHRESP(NOTOPEN)
                   MOVE 'FILE IS NOT OPEN - CONTACT SUPPORT'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP-DATAONLY
               WHEN OTHER
                   PERFORM 9100-UNEXPECTED-ERROR
           END-EVALUATE
           .

Common DFHRESP Values

DFHRESP Value Description
NORMAL Operation completed successfully
NOTFND Record not found
DUPREC Duplicate record on WRITE
DISABLED File is disabled
NOTOPEN File is not open
ENDFILE End of file during browse
INVREQ Invalid request (logic error)
IOERR I/O error
LENGERR Length error
NOSPACE No space on file for WRITE
MAPFAIL No data received on RECEIVE MAP
PGMIDERR Program not found (LINK/XCTL)
ERROR General error

The Older HANDLE CONDITION (For Reference)

The HANDLE CONDITION command was the original CICS error handling mechanism. While still supported, it is not recommended for new programs because it creates non-linear control flow similar to GO TO:

      * NOT RECOMMENDED for new programs
           EXEC CICS HANDLE CONDITION
               NOTFND(2200-NOT-FOUND)
               DUPREC(2300-DUPLICATE)
               ERROR(9100-ERROR)
           END-EXEC

      * RECOMMENDED: Use RESP/RESP2 instead

Centralized CICS Error Handler

       9100-UNEXPECTED-ERROR.
           MOVE SPACES TO WS-ERROR-MESSAGE

           STRING 'CICS ERROR - RESP: '
               WS-CICS-RESP
               ' RESP2: '
               WS-CICS-RESP2
               ' EIBTRNID: '
               EIBTRNID
               ' EIBFN: '
               EIBFN
               DELIMITED BY SIZE
               INTO WS-ERROR-MESSAGE
           END-STRING

      *    Log the error
           EXEC CICS WRITEQ TD
               QUEUE('CSMT')
               FROM(WS-ERROR-MESSAGE)
               LENGTH(LENGTH OF WS-ERROR-MESSAGE)
           END-EXEC

      *    Display error to user
           MOVE WS-ERROR-MESSAGE TO MSGEXTO
           PERFORM 3000-SEND-MAP-DATAONLY

           EXEC CICS RETURN
               TRANSID('INQC')
               COMMAREA(WS-COMMAREA)
               LENGTH(WS-COMMAREA-LENGTH)
           END-EXEC
           .

CICS provides two commands for transferring control between programs.

LINK is the CICS equivalent of the COBOL CALL statement. It transfers control to another program and expects that program to return:

      * Call a validation subprogram
           EXEC CICS LINK
               PROGRAM('CUSTVAL')
               COMMAREA(WS-VALIDATION-DATA)
               LENGTH(WS-VAL-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

           IF WS-CICS-RESP = DFHRESP(NORMAL)
               IF WS-VAL-RETURN-CODE = 0
                   PERFORM 2200-PROCESS-VALID
               ELSE
                   PERFORM 2300-HANDLE-ERRORS
               END-IF
           ELSE IF WS-CICS-RESP = DFHRESP(PGMIDERR)
               MOVE 'VALIDATION PROGRAM NOT FOUND'
                   TO MSGEXTO
           END-IF

XCTL: Transfer Control (No Return)

XCTL transfers control to another program and does not return to the calling program. It is used for navigating between screens in a menu-driven application:

      * Transfer to customer update screen
           EXEC CICS XCTL
               PROGRAM('CUSTUPD')
               COMMAREA(WS-NAVIGATION-DATA)
               LENGTH(WS-NAV-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

      * If we get here, XCTL failed
           IF WS-CICS-RESP = DFHRESP(PGMIDERR)
               MOVE 'UPDATE PROGRAM NOT AVAILABLE'
                   TO MSGEXTO
               PERFORM 3000-SEND-MAP-DATAONLY
           END-IF
Feature LINK XCTL
Returns to caller Yes No
Caller's storage Preserved Released
Analogy CALL/RETURN GO TO (program level)
Use case Call a subroutine Navigate to next screen

24.11 Temporary Storage Queues (TSQ) and Transient Data Queues (TDQ)

Temporary Storage Queues (TSQ)

TSQs provide a scratch pad for storing data temporarily. They are commonly used for multi-page browse lists, storing data between pseudo-conversational instances (as an alternative to COMMAREA for large data), and passing data between programs.

      * Write data to a TSQ
           EXEC CICS WRITEQ TS
               QUEUE(WS-TSQ-NAME)
               FROM(WS-BROWSE-LINE)
               LENGTH(WS-LINE-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

      * Read a specific item from a TSQ
           EXEC CICS READQ TS
               QUEUE(WS-TSQ-NAME)
               INTO(WS-BROWSE-LINE)
               LENGTH(WS-LINE-LENGTH)
               ITEM(WS-ITEM-NUMBER)
               RESP(WS-CICS-RESP)
           END-EXEC

      * Read the number of items in a TSQ
           EXEC CICS READQ TS
               QUEUE(WS-TSQ-NAME)
               INTO(WS-BROWSE-LINE)
               LENGTH(WS-LINE-LENGTH)
               ITEM(WS-ITEM-NUMBER)
               NUMITEMS(WS-TOTAL-ITEMS)
               RESP(WS-CICS-RESP)
           END-EXEC

      * Delete the entire TSQ when done
           EXEC CICS DELETEQ TS
               QUEUE(WS-TSQ-NAME)
               RESP(WS-CICS-RESP)
           END-EXEC

TSQ Naming Convention

TSQ names should be unique per terminal session. A common convention includes the terminal ID:

       01  WS-TSQ-NAME        PIC X(8).

           STRING 'BRW' EIBTRMID
               DELIMITED BY SIZE
               INTO WS-TSQ-NAME
           END-STRING
      *    Result: 'BRWTxx1' where Txx1 is the terminal ID

Transient Data Queues (TDQ)

TDQs are used for logging, audit trails, and trigger-level processing. Unlike TSQs, TDQ records can only be read once (destructive read):

      * Write an audit record to a TDQ
           EXEC CICS WRITEQ TD
               QUEUE('AUDT')
               FROM(WS-AUDIT-RECORD)
               LENGTH(WS-AUDIT-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

      * Write to CICS system log
           EXEC CICS WRITEQ TD
               QUEUE('CSMT')
               FROM(WS-LOG-MESSAGE)
               LENGTH(WS-LOG-LENGTH)
           END-EXEC

24.12 CICS and DB2: Combining Transaction Processing with Database Access

Many CICS applications access DB2 databases in addition to (or instead of) VSAM files. A CICS-DB2 program uses both EXEC CICS and EXEC SQL commands within the same COBOL source.

CICS-DB2 Program Structure

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CUSTDB2.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       COPY DFHAID.
       COPY CUSTSET.

           EXEC SQL INCLUDE SQLCA END-EXEC.

           EXEC SQL BEGIN DECLARE SECTION END-EXEC.
       01  HV-CUST-ID         PIC S9(9) COMP.
       01  HV-CUST-NAME       PIC X(30).
       01  HV-CUST-BALANCE    PIC S9(7)V99 COMP-3.
           EXEC SQL END DECLARE SECTION END-EXEC.

       01  WS-COMMAREA.
           05  CA-STATE        PIC X.
           05  CA-CUST-ID      PIC S9(9) COMP.

       01  WS-CICS-RESP       PIC S9(8) COMP.
       01  WS-BAL-DISPLAY     PIC Z,ZZZ,ZZ9.99-.

       LINKAGE SECTION.
       01  DFHCOMMAREA         PIC X(20).

       PROCEDURE DIVISION.
       0000-MAIN.
           IF EIBCALEN = 0
               PERFORM 1000-SEND-INITIAL-MAP
           ELSE
               MOVE DFHCOMMAREA TO WS-COMMAREA
               PERFORM 2000-PROCESS-INPUT
           END-IF
           .

       2100-LOOKUP-DB2.
           MOVE CUSTIDI TO HV-CUST-ID

           EXEC SQL
               SELECT CUST_NAME, CUST_BALANCE
               INTO :HV-CUST-NAME, :HV-CUST-BALANCE
               FROM CUSTOMER
               WHERE CUST_ID = :HV-CUST-ID
           END-EXEC

           EVALUATE SQLCODE
               WHEN 0
                   MOVE HV-CUST-NAME TO CUSTNMO
                   MOVE HV-CUST-BALANCE TO WS-BAL-DISPLAY
                   MOVE WS-BAL-DISPLAY TO CUSTBALO
                   MOVE 'CUSTOMER FOUND' TO MSGEXTO
               WHEN +100
                   MOVE 'CUSTOMER NOT FOUND IN DB2'
                       TO MSGEXTO
               WHEN OTHER
                   STRING 'DB2 ERROR: SQLCODE=' SQLCODE
                       DELIMITED BY SIZE
                       INTO MSGEXTO
                   END-STRING
           END-EVALUATE
           .

Compilation for CICS-DB2 Programs

Programs that use both CICS and DB2 require three preprocessing steps: DB2 precompile, CICS translation, and COBOL compilation. The order matters -- DB2 precompile typically runs first, followed by CICS translation. With the integrated translator in IBM Enterprise COBOL V5+, the compiler can process both EXEC SQL and EXEC CICS commands in a single compilation step using the compiler options CICS and SQL:

//COBOL  EXEC PGM=IGYCRCTL,
//       PARM='LIB,RENT,CICS,SQL,LIST,MAP'

SYNCPOINT in CICS

In CICS, EXEC SQL COMMIT is not used directly. Instead, CICS provides its own SYNCPOINT command that coordinates commits across multiple resource managers (DB2, VSAM, MQ):

      * In CICS, use SYNCPOINT instead of SQL COMMIT
           EXEC CICS SYNCPOINT
               RESP(WS-CICS-RESP)
           END-EXEC

      * For rollback in CICS:
           EXEC CICS SYNCPOINT ROLLBACK
               RESP(WS-CICS-RESP)
           END-EXEC

The SYNCPOINT command ensures that both DB2 and VSAM changes are committed atomically -- either both commit or both roll back.


24.13 CICS Application Design Patterns

Multi-Screen Navigation

Most CICS applications consist of multiple screens (maps) that the user navigates between. A common pattern uses a central dispatch program:

      * Menu screen dispatches to function screens
       2000-PROCESS-MENU.
           EXEC CICS RECEIVE MAP('MENUMAP')
               MAPSET('MENUSET')
               INTO(MENUMAPI)
               RESP(WS-CICS-RESP)
           END-EXEC

           EVALUATE MENUSELI
               WHEN '1'
      *            Customer Inquiry
                   EXEC CICS XCTL
                       PROGRAM('CUSTINQ')
                       COMMAREA(WS-NAV-DATA)
                       LENGTH(WS-NAV-LENGTH)
                   END-EXEC
               WHEN '2'
      *            Customer Update
                   EXEC CICS XCTL
                       PROGRAM('CUSTUPD')
                       COMMAREA(WS-NAV-DATA)
                       LENGTH(WS-NAV-LENGTH)
                   END-EXEC
               WHEN '3'
      *            Account Inquiry
                   EXEC CICS XCTL
                       PROGRAM('ACCTINQ')
                       COMMAREA(WS-NAV-DATA)
                       LENGTH(WS-NAV-LENGTH)
                   END-EXEC
               WHEN OTHER
                   MOVE 'INVALID SELECTION' TO MSGEXTO
                   PERFORM 3000-SEND-MENU
           END-EVALUATE
           .

Data Validation in CICS

CICS programs must validate user input before performing any file or database operations. The validation pattern typically checks each input field and accumulates error messages:

       2200-VALIDATE-INPUT.
           SET WS-INPUT-VALID TO TRUE

      *    Check customer ID is entered
           IF CUSTIDL = 0 OR CUSTIDI = SPACES
               MOVE -1 TO CUSTIDL
               MOVE 'CUSTOMER ID IS REQUIRED'
                   TO MSGEXTO
               SET WS-INPUT-INVALID TO TRUE
           END-IF

      *    Check customer ID is numeric
           IF WS-INPUT-VALID
               IF CUSTIDI NOT NUMERIC
                   MOVE -1 TO CUSTIDL
                   MOVE 'CUSTOMER ID MUST BE NUMERIC'
                       TO MSGEXTO
                   SET WS-INPUT-INVALID TO TRUE
               END-IF
           END-IF

      *    If input is invalid, resend the map with cursor
      *    positioned at the first error field
           IF WS-INPUT-INVALID
               EXEC CICS SEND MAP('CUSTMAP')
                   MAPSET('CUSTSET')
                   FROM(CUSTMAPO)
                   DATAONLY
                   FREEKB
                   CURSOR
               END-EXEC
               EXEC CICS RETURN
                   TRANSID('INQC')
                   COMMAREA(WS-COMMAREA)
                   LENGTH(WS-COMMAREA-LENGTH)
               END-EXEC
           END-IF
           .

The technique of setting the field's length (L suffix) to -1 before SEND MAP positions the cursor at that field, directing the user's attention to the error.

Handling Concurrent Updates (Optimistic Locking)

In pseudo-conversational applications, the time between displaying a record and updating it can be long (the user's think time). Another user might update the same record during that time. Optimistic locking detects this conflict:

       01  WS-COMMAREA.
           05  CA-STATE        PIC X.
           05  CA-CUST-KEY     PIC X(10).
           05  CA-ORIG-BALANCE PIC S9(7)V99 COMP-3.
           05  CA-TIMESTAMP    PIC X(26).

      * When displaying the record, save the current values
       2100-DISPLAY-FOR-UPDATE.
           EXEC CICS READ
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(WS-CUST-KEY)
               LENGTH(WS-REC-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

           IF WS-CICS-RESP = DFHRESP(NORMAL)
      *        Save original values in COMMAREA
               MOVE WS-CUST-BALANCE TO CA-ORIG-BALANCE
               MOVE WS-CUST-TIMESTAMP TO CA-TIMESTAMP
               PERFORM 3000-SEND-UPDATE-MAP
           END-IF
           .

      * When updating, verify the record has not changed
       2200-APPLY-UPDATE.
           EXEC CICS READ
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(CA-CUST-KEY)
               LENGTH(WS-REC-LENGTH)
               UPDATE
               RESP(WS-CICS-RESP)
           END-EXEC

           IF WS-CICS-RESP = DFHRESP(NORMAL)
      *        Check if record was modified since we displayed it
               IF WS-CUST-TIMESTAMP NOT = CA-TIMESTAMP
                   MOVE 'RECORD CHANGED BY ANOTHER USER'
                       TO MSGEXTO
                   EXEC CICS UNLOCK
                       FILE('CUSTFILE')
                   END-EXEC
                   PERFORM 3000-SEND-MAP-DATAONLY
               ELSE
      *            Safe to update
                   PERFORM 2210-APPLY-CHANGES
                   EXEC CICS REWRITE
                       FILE('CUSTFILE')
                       FROM(WS-CUSTOMER-RECORD)
                       LENGTH(WS-REC-LENGTH)
                       RESP(WS-CICS-RESP)
                   END-EXEC
                   MOVE 'UPDATE SUCCESSFUL' TO MSGEXTO
               END-IF
           END-IF
           .

24.14 CICS Abend Handling

CICS provides its own abend mechanism with four-character abend codes. Some abends are issued by CICS itself (system abends), and others can be issued by the application program.

Common CICS Abend Codes

Abend Code Description
ASRA Program check (equivalent to S0Cx system abends)
AICA Program is in a runaway loop
AEI0 Program raised an exception
AKCP The program issued an EXEC CICS command that is not valid for the context
APCT Program not found (PCT entry missing)
AFCR File not found (FCT entry missing)

HANDLE ABEND

The HANDLE ABEND command establishes an abend exit routine. If the program abends, CICS transfers control to the specified paragraph or program instead of terminating:

       0000-MAIN.
           EXEC CICS HANDLE ABEND
               LABEL(9500-ABEND-EXIT)
           END-EXEC

      *    Normal processing
           PERFORM 1000-PROCESS
           EXEC CICS RETURN END-EXEC
           .

       9500-ABEND-EXIT.
           MOVE 'PROGRAM ABENDED - PLEASE RETRY'
               TO MSGEXTO
           EXEC CICS SEND MAP('CUSTMAP')
               MAPSET('CUSTSET')
               FROM(CUSTMAPO)
               ERASE
               FREEKB
           END-EXEC
           EXEC CICS RETURN END-EXEC
           .

ABEND Command

A CICS program can deliberately abend with a user-specified code:

           IF WS-CRITICAL-ERROR
               EXEC CICS ABEND
                   ABCODE('UERR')
                   CANCEL
               END-EXEC
           END-IF

The CANCEL option terminates the transaction and releases all resources. Without CANCEL, the abend can be intercepted by a HANDLE ABEND routine.


24.15 Compiling CICS Programs

CICS COBOL programs require a translation step before compilation, similar to the DB2 precompile. The CICS translator processes EXEC CICS commands and replaces them with CALL statements to the CICS runtime.

The Build Process

COBOL Source with EXEC CICS
        |
        v
  CICS TRANSLATOR (DFHECP1$)
  - Converts EXEC CICS commands to CALL statements
  - Adds DFHEIBLK and DFHCOMMAREA to LINKAGE
        |
        v
  Modified COBOL Source
        |
        v
  COBOL COMPILE (IGYCRCTL)
        |
        v
  LINK-EDIT (IEWL) with CICS stubs
        |
        v
  Load Module (deployed to CICS region)
//*------------------------------------------------------------
//*  STEP 1: CICS TRANSLATION
//*------------------------------------------------------------
//TRN     EXEC PGM=DFHECP1$,
//        PARM='COBOL3,SP'
//STEPLIB  DD DSN=CICSTS.V5R6M0.SDFHLOAD,DISP=SHR
//SYSIN    DD DSN=USER.SRCLIB(CUSTINQ),DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSPUNCH DD DSN=&&CICSOUT,DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(800,(500,500))
//*
//*------------------------------------------------------------
//*  STEP 2: COBOL COMPILE
//*------------------------------------------------------------
//COB     EXEC PGM=IGYCRCTL,
//        PARM='LIB,RENT,LIST,MAP,XREF'
//STEPLIB  DD DSN=IGY.V6R4M0.SIGYCOMP,DISP=SHR
//SYSIN    DD DSN=&&CICSOUT,DISP=(OLD,DELETE)
//SYSLIB   DD DSN=USER.COPYLIB,DISP=SHR
//         DD DSN=CICSTS.V5R6M0.SDFHCOB,DISP=SHR
//         DD DSN=CICSTS.V5R6M0.SDFHMAC,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSLIN   DD DSN=&&LOADSET,DISP=(NEW,PASS),
//            UNIT=SYSDA,SPACE=(800,(500,500))
//SYSUT1   DD UNIT=SYSDA,SPACE=(800,(500,500))
//SYSUT2   DD UNIT=SYSDA,SPACE=(800,(500,500))
//SYSUT3   DD UNIT=SYSDA,SPACE=(800,(500,500))
//SYSUT4   DD UNIT=SYSDA,SPACE=(800,(500,500))
//*
//*------------------------------------------------------------
//*  STEP 3: LINK-EDIT
//*------------------------------------------------------------
//LKED    EXEC PGM=IEWL,
//        PARM='LIST,MAP,RENT,AMODE=31,RMODE=ANY'
//SYSLIB   DD DSN=CEE.SCEELKED,DISP=SHR
//         DD DSN=CICSTS.V5R6M0.SDFHLOAD,DISP=SHR
//SYSLMOD  DD DSN=USER.CICS.LOADLIB(CUSTINQ),DISP=SHR
//SYSLIN   DD DSN=&&LOADSET,DISP=(OLD,DELETE)
//         DD *
  INCLUDE SYSLIB(DFHELII)
  NAME CUSTINQ(R)
/*
//SYSPRINT DD SYSOUT=*

Integrated CICS Translator

Modern versions of IBM Enterprise COBOL (V5+) support the integrated CICS translator, which eliminates the separate translation step. The compiler option CICS tells the compiler to process EXEC CICS commands directly:

//COBOL  EXEC PGM=IGYCRCTL,
//       PARM='LIB,RENT,CICS,LIST,MAP'
//STEPLIB  DD DSN=IGY.V6R4M0.SIGYCOMP,DISP=SHR
//         DD DSN=CICSTS.V5R6M0.SDFHLOAD,DISP=SHR

24.13 Complete CICS Customer Inquiry Program

The following program demonstrates a complete pseudo-conversational CICS customer inquiry application:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CUSTINQ.
      *========================================================*
      * CICS CUSTOMER INQUIRY PROGRAM                           *
      * TRANSID: INQC                                           *
      * MAPSET:  CUSTSET / MAP: CUSTMAP                         *
      *========================================================*

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  WS-PROGRAM-ID      PIC X(8) VALUE 'CUSTINQ'.

       COPY DFHAID.
       COPY CUSTSET.

       01  WS-COMMAREA.
           05  CA-STATE        PIC X.
               88  CA-INITIAL  VALUE SPACES.
               88  CA-MAP-SENT VALUE 'M'.
           05  CA-CUST-KEY     PIC X(10).

       01  WS-COMMAREA-LENGTH PIC S9(4) COMP
                              VALUE LENGTH OF WS-COMMAREA.

       01  WS-CUSTOMER-RECORD.
           05  WS-CUST-KEY     PIC X(10).
           05  WS-CUST-NAME    PIC X(30).
           05  WS-CUST-BALANCE PIC S9(7)V99 COMP-3.
           05  WS-CUST-STATUS  PIC X.

       01  WS-REC-LENGTH      PIC S9(4) COMP.
       01  WS-CICS-RESP       PIC S9(8) COMP.
       01  WS-CICS-RESP2      PIC S9(8) COMP.
       01  WS-BAL-DISPLAY     PIC Z,ZZZ,ZZ9.99-.

       01  WS-GOODBYE-MSG     PIC X(30)
           VALUE 'INQUIRY SESSION ENDED'.
       01  WS-GOODBYE-LEN     PIC S9(4) COMP VALUE 30.

       LINKAGE SECTION.
       01  DFHCOMMAREA         PIC X(100).

       PROCEDURE DIVISION.
       0000-MAIN.
           IF EIBCALEN = 0
               PERFORM 1000-FIRST-TIME
           ELSE
               MOVE DFHCOMMAREA TO WS-COMMAREA
               PERFORM 2000-PROCESS-INPUT
           END-IF
           .

       1000-FIRST-TIME.
           INITIALIZE WS-COMMAREA
           SET CA-MAP-SENT TO TRUE

           MOVE LOW-VALUES TO CUSTMAPO
           MOVE 'ENTER CUSTOMER ID AND PRESS ENTER'
               TO MSGEXTO

           EXEC CICS SEND MAP('CUSTMAP')
               MAPSET('CUSTSET')
               FROM(CUSTMAPO)
               ERASE
               FREEKB
               CURSOR
           END-EXEC

           EXEC CICS RETURN
               TRANSID('INQC')
               COMMAREA(WS-COMMAREA)
               LENGTH(WS-COMMAREA-LENGTH)
           END-EXEC
           .

       2000-PROCESS-INPUT.
           EVALUATE EIBAID
               WHEN DFHPF3
                   EXEC CICS SEND TEXT
                       FROM(WS-GOODBYE-MSG)
                       LENGTH(WS-GOODBYE-LEN)
                       ERASE
                       FREEKB
                   END-EXEC
                   EXEC CICS RETURN END-EXEC

               WHEN DFHPF12
                   PERFORM 1000-FIRST-TIME

               WHEN DFHENTER
                   PERFORM 2100-HANDLE-ENTER

               WHEN DFHCLEAR
                   EXEC CICS SEND TEXT
                       FROM(WS-GOODBYE-MSG)
                       LENGTH(WS-GOODBYE-LEN)
                       ERASE
                       FREEKB
                   END-EXEC
                   EXEC CICS RETURN END-EXEC

               WHEN OTHER
                   MOVE LOW-VALUES TO CUSTMAPO
                   MOVE 'INVALID KEY - PF3=EXIT'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP-DATAONLY
           END-EVALUATE
           .

       2100-HANDLE-ENTER.
           EXEC CICS RECEIVE MAP('CUSTMAP')
               MAPSET('CUSTSET')
               INTO(CUSTMAPI)
               RESP(WS-CICS-RESP)
           END-EXEC

           IF WS-CICS-RESP = DFHRESP(MAPFAIL)
               MOVE LOW-VALUES TO CUSTMAPO
               MOVE 'PLEASE ENTER A CUSTOMER ID'
                   TO MSGEXTO
               PERFORM 3000-SEND-MAP-DATAONLY
           ELSE IF WS-CICS-RESP NOT = DFHRESP(NORMAL)
               PERFORM 9100-UNEXPECTED-ERROR
           ELSE
               IF CUSTIDL = 0 OR CUSTIDI = SPACES
                   MOVE LOW-VALUES TO CUSTMAPO
                   MOVE 'CUSTOMER ID REQUIRED'
                       TO MSGEXTO
                   PERFORM 3000-SEND-MAP-DATAONLY
               ELSE
                   MOVE CUSTIDI TO WS-CUST-KEY
                   PERFORM 2200-READ-CUSTOMER
               END-IF
           END-IF
           .

       2200-READ-CUSTOMER.
           MOVE LENGTH OF WS-CUSTOMER-RECORD
               TO WS-REC-LENGTH

           EXEC CICS READ
               FILE('CUSTFILE')
               INTO(WS-CUSTOMER-RECORD)
               RIDFLD(WS-CUST-KEY)
               LENGTH(WS-REC-LENGTH)
               RESP(WS-CICS-RESP)
               RESP2(WS-CICS-RESP2)
           END-EXEC

           MOVE LOW-VALUES TO CUSTMAPO

           EVALUATE WS-CICS-RESP
               WHEN DFHRESP(NORMAL)
                   MOVE WS-CUST-KEY TO CUSTIDO
                   MOVE WS-CUST-NAME TO CUSTNMO
                   MOVE WS-CUST-BALANCE TO WS-BAL-DISPLAY
                   MOVE WS-BAL-DISPLAY TO CUSTBALO
                   MOVE 'CUSTOMER FOUND' TO MSGEXTO
                   MOVE WS-CUST-KEY TO CA-CUST-KEY

               WHEN DFHRESP(NOTFND)
                   MOVE WS-CUST-KEY TO CUSTIDO
                   MOVE 'CUSTOMER NOT FOUND' TO MSGEXTO

               WHEN DFHRESP(DISABLED)
                   MOVE 'CUSTOMER FILE IS DISABLED'
                       TO MSGEXTO

               WHEN DFHRESP(NOTOPEN)
                   MOVE 'CUSTOMER FILE NOT OPEN'
                       TO MSGEXTO

               WHEN OTHER
                   PERFORM 9100-UNEXPECTED-ERROR
           END-EVALUATE

           PERFORM 3000-SEND-MAP-DATAONLY
           .

       3000-SEND-MAP-DATAONLY.
           EXEC CICS SEND MAP('CUSTMAP')
               MAPSET('CUSTSET')
               FROM(CUSTMAPO)
               DATAONLY
               FREEKB
               CURSOR
           END-EXEC

           EXEC CICS RETURN
               TRANSID('INQC')
               COMMAREA(WS-COMMAREA)
               LENGTH(WS-COMMAREA-LENGTH)
           END-EXEC
           .

       9100-UNEXPECTED-ERROR.
           EXEC CICS SEND TEXT
               FROM(WS-ERROR-MSG)
               LENGTH(80)
               ERASE
               FREEKB
           END-EXEC

           EXEC CICS RETURN END-EXEC
           .

Summary

This chapter covered the fundamentals of CICS transaction processing with COBOL:

  • CICS is IBM's online transaction processing monitor, handling billions of transactions daily on mainframes worldwide. It provides terminal management, task management, program management, file management, and recovery services.
  • EXEC CICS...END-EXEC is the command-level interface for all CICS services, replacing native COBOL I/O statements.
  • SEND TEXT and SEND MAP write output to the 3270 terminal. SEND MAP uses predefined BMS screen layouts for formatted displays.
  • RECEIVE MAP reads user input from BMS-formatted screens, populating the symbolic map input structure.
  • BMS (Basic Mapping Support) defines 3270 screen layouts using DFHMSD (mapset), DFHMDI (map), and DFHMDF (field) macros, with attribute bytes controlling field behavior (ASKIP, UNPROT, BRT, DRK, NUM, IC).
  • File control commands (READ, WRITE, REWRITE, DELETE) provide random access to VSAM files, while browse commands (STARTBR, READNEXT, READPREV, ENDBR) provide sequential access.
  • Pseudo-conversational programming is the fundamental CICS application design pattern. The task ends after sending the screen (RETURN TRANSID with COMMAREA) and a new task starts when the user responds. EIBCALEN distinguishes first invocations from subsequent ones.
  • The EIB (Execute Interface Block) provides task information including EIBAID (which key was pressed), EIBCALEN (COMMAREA length), EIBTRNID (transaction ID), and EIBTRMID (terminal ID).
  • Error handling uses RESP and RESP2 options on every CICS command, with DFHRESP symbolic constants (NORMAL, NOTFND, DUPREC, etc.) for readable error checking.
  • Program control uses LINK (call and return) and XCTL (transfer without return) for navigation between CICS programs.
  • TSQ and TDQ provide temporary storage and transient data capabilities for scratch pads, browse lists, logging, and inter-program communication.
  • Compilation requires CICS translation (or integrated translation with COBOL V5+), COBOL compilation with CICS copylib, and link-editing with CICS stubs.

CICS programming represents a fundamentally different paradigm from batch COBOL. The pseudo-conversational model, the EXEC CICS command interface, and the BMS screen definition facility require new skills and new ways of thinking about program design. But the core language is still COBOL, and the principles of structured programming, defensive error handling, and clear naming conventions apply equally in the CICS environment.


CICS Programming: Key Restrictions and Differences from Batch

CICS imposes several restrictions on COBOL programs that batch programmers must understand before writing their first CICS application.

Prohibited Statements

The following COBOL statements are not allowed in CICS programs:

Prohibited Statement CICS Replacement
OPEN, CLOSE File operations managed by CICS
READ, WRITE, REWRITE, DELETE (native) EXEC CICS READ/WRITE/REWRITE/DELETE
ACCEPT EXEC CICS RECEIVE
DISPLAY EXEC CICS SEND TEXT (or write to TSQ/TDQ)
STOP RUN EXEC CICS RETURN
SORT, MERGE Not available in CICS (use batch)

WORKING-STORAGE vs. LOCAL-STORAGE in CICS

In CICS, if multiple tasks execute the same program concurrently, they share the same copy of the program's code but (with IBM Enterprise COBOL V5+ and threadsafe programs) each task gets its own copy of WORKING-STORAGE. In older configurations, WORKING-STORAGE was shared, creating reentrancy problems. Modern CICS COBOL programs should always be compiled with the RENT (re-entrant) compiler option.

For maximum safety, use LOCAL-STORAGE instead of WORKING-STORAGE in CICS programs. LOCAL-STORAGE is allocated fresh for each task invocation and is automatically freed when the task ends:

       LOCAL-STORAGE SECTION.
       01  WS-CUSTOMER-RECORD.
           05  WS-CUST-KEY     PIC X(10).
           05  WS-CUST-NAME    PIC X(30).
           05  WS-CUST-BALANCE PIC S9(7)V99 COMP-3.

Channel/Container Model (Modern CICS)

In CICS TS 3.1 and later, the channel/container model provides a modern alternative to the COMMAREA for passing data between programs. Containers are named data areas of virtually unlimited size, grouped into channels:

      * Put data into a container
           EXEC CICS PUT CONTAINER('CUSTDATA')
               CHANNEL('CUSTCHAN')
               FROM(WS-CUSTOMER-RECORD)
               FLENGTH(LENGTH OF WS-CUSTOMER-RECORD)
           END-EXEC

      * Link to another program passing the channel
           EXEC CICS LINK
               PROGRAM('CUSTPROC')
               CHANNEL('CUSTCHAN')
               RESP(WS-CICS-RESP)
           END-EXEC

      * In the called program, retrieve the container
           EXEC CICS GET CONTAINER('CUSTDATA')
               CHANNEL('CUSTCHAN')
               INTO(WS-CUSTOMER-RECORD)
               FLENGTH(WS-DATA-LENGTH)
               RESP(WS-CICS-RESP)
           END-EXEC

The channel/container model overcomes the COMMAREA's 32KB size limitation and provides a more structured way to pass complex data between programs.

CICS Web Services

Modern CICS can expose COBOL programs as web services (SOAP or RESTful JSON). A COBOL program that follows good modular design practices (clear LINKAGE SECTION interface, no terminal I/O embedded in business logic) can be exposed as a web service with minimal or no code changes. CICS TS provides the PIPELINE facility for SOAP services and the URIMAP/PROGRAM mapping for RESTful services.

This capability means that COBOL business logic written decades ago can serve modern web and mobile front ends without rewriting the business rules. The COBOL program processes the business logic, and the CICS infrastructure handles the HTTP protocol, JSON/XML transformation, and security.


Exercises

  1. SEND TEXT: Write a CICS program that sends a three-line welcome message to the terminal using SEND TEXT, then returns to CICS.

  2. BMS Map Design: Design a BMS map for a simple employee inquiry screen with the following fields: employee ID (input), employee name (output), department (output), hire date (output), salary (output), and a message line. Write the DFHMSD/DFHMDI/DFHMDF macro definitions.

  3. Pseudo-Conversational Inquiry: Write a complete pseudo-conversational CICS program that accepts an employee ID on the first screen, reads the employee record from a VSAM file, and displays the employee information. Handle PF3 (exit), PF12 (clear and restart), and Enter (search).

  4. Error Handling: Add comprehensive error handling to the program from Exercise 3. Handle NOTFND, DISABLED, NOTOPEN, MAPFAIL, and unexpected errors. Log all unexpected errors to CSMT using WRITEQ TD.

  5. Browse with TSQ: Write a CICS program that browses a VSAM file, stores the browse results in a TSQ (20 records per page), and allows the user to page forward (PF8) and backward (PF7) through the results. Use the TSQ item number to track the current page position.