31 min read

Before relational databases existed, before SQL was invented, before DB2 processed its first query, there was IMS. IBM's Information Management System debuted in 1966 as the database system for the Apollo space program, tracking the millions of...

Chapter 26: IMS Database and Transaction Management

IBM Enterprise COBOL

Introduction: The Original Enterprise Database

Before relational databases existed, before SQL was invented, before DB2 processed its first query, there was IMS. IBM's Information Management System debuted in 1966 as the database system for the Apollo space program, tracking the millions of parts needed to build the Saturn V rocket. Each rocket contained roughly 3.5 million parts, organized in a natural hierarchy: rocket to stage, stage to assembly, assembly to subassembly, subassembly to component. A hierarchical database was the natural fit.

That same hierarchical model proved equally natural for business data. A bank has customers. Each customer has accounts. Each account has transactions. A hospital has patients. Each patient has visits. Each visit has diagnoses and procedures. An insurance company has policies. Each policy has claims. Each claim has payments. These are parent-child relationships -- trees -- and IMS stores them exactly that way.

Nearly sixty years later, IMS remains in production at the world's largest financial institutions. An estimated 95% of Fortune 1000 companies have IMS databases in their enterprise stack. IMS processes over 50 billion transactions per day globally. Major banks run their core deposit and loan systems on IMS. Airlines manage reservations through IMS. Government agencies store citizen records in IMS hierarchies that were designed decades ago and continue to function with extraordinary reliability.

IMS is really two subsystems in one. IMS DB (Database Manager) is the hierarchical database engine that stores and retrieves data through the DL/I (Data Language/I) call interface. IMS TM (Transaction Manager), also known as IMS DC (Data Communications), is the online transaction processing system that manages terminals, queues messages, and dispatches application programs -- much like CICS does for its environment. A COBOL program running under IMS uses DL/I calls both to access the database and to communicate with terminals.

This chapter teaches you to write COBOL programs that interact with IMS databases and process IMS transactions. You will learn the hierarchical data model, the DL/I call interface, Program Communication Blocks (PCBs) and Program Specification Blocks (PSBs), Segment Search Arguments (SSAs), all major database calls, the IMS Transaction Manager message processing model, checkpoint/restart for batch recovery, and the JCL required to execute IMS batch programs. Every concept is illustrated with complete COBOL code using a banking customer-account-transaction hierarchy.

[IBM Enterprise COBOL] IMS is an IBM mainframe product that runs exclusively on z/OS. It cannot be installed on Linux, Windows, or macOS, and there is no GnuCOBOL equivalent. If you want hands-on practice, IBM Z Xplore (formerly IBM Z Open Education) provides free access to a real z/OS system with IMS capabilities. Instructions for accessing Z Xplore appear at the end of this chapter.


26.1 The Hierarchical Data Model

Trees, Not Tables

Relational databases store data in two-dimensional tables (rows and columns) connected by foreign keys. IMS stores data in tree structures -- hierarchies -- where each record (called a segment) has at most one parent and can have multiple children. The root segment sits at the top with no parent. Every other segment hangs below its parent in a strictly defined tree.

Consider a banking database. The natural hierarchy looks like this:

CUSTOMER (root segment)
    |
    +-- ACCOUNT (child of CUSTOMER)
    |     |
    |     +-- TRANSACTION (child of ACCOUNT)
    |
    +-- ADDRESS (child of CUSTOMER)
    |
    +-- CONTACT (child of CUSTOMER)

Customer CUST000100 might have three accounts (checking, savings, loan). The checking account might have fifty transactions. The customer also has a mailing address and a billing address, plus phone and email contacts. All of this hangs under the single CUSTOMER root in a tree.

Key Terminology

Term Definition
Segment The basic unit of data in IMS, equivalent to a record or row. Each segment has a defined layout of fields.
Segment Type The template definition for a class of segments (e.g., CUSTOMER, ACCOUNT). Defined in the DBD.
Root Segment The topmost segment in a hierarchy. Every hierarchy has exactly one root segment type.
Parent Segment A segment that has one or more child segment types defined beneath it.
Child Segment A segment that exists under a parent. A child cannot exist without its parent.
Twin Segments Multiple occurrences of the same segment type under the same parent. Customer CUST000100 might have three ACCOUNT twins.
Hierarchical Path The chain of segments from the root down to a specific segment.
Sequence Field The key field within a segment type, used for ordering and direct access.
Database Record One complete root segment together with all its dependent (child) segments at all levels.
DBD Database Description -- a control block that defines the physical structure of the database (segment types, fields, hierarchical relationships, access methods).
PSB Program Specification Block -- a control block that defines a program's view of one or more databases (which segments are visible, what operations are allowed).
PCB Program Communication Block -- one component of a PSB, representing a single database view. A PSB can contain multiple PCBs.

Hierarchical Sequence

IMS traverses a database in hierarchical sequence -- a depth-first, left-to-right traversal of the tree. For the banking hierarchy above, the hierarchical sequence visits:

  1. CUSTOMER (root)
  2. First ACCOUNT under this customer
  3. First TRANSACTION under that account
  4. Second TRANSACTION under that account
  5. (all remaining TRANSACTIONs)
  6. Second ACCOUNT under this customer
  7. First TRANSACTION under the second account
  8. (and so on through all accounts and transactions)
  9. First ADDRESS under this customer
  10. Second ADDRESS
  11. First CONTACT
  12. (and so on)
  13. Next CUSTOMER root (next database record)

This traversal order matters because the Get Next (GN) call returns segments in exactly this sequence.

Physical Database Organizations

[IBM Enterprise COBOL] IMS supports several physical storage organizations for databases:

Organization Abbreviation Description
Hierarchical Sequential Access Method HSAM Sequential, read-only access. Used for archival data.
Hierarchical Indexed Sequential HISAM Indexed sequential access using VSAM KSDS. Good for moderate-size databases with key access.
Hierarchical Direct Access Method HDAM Direct (hashed) access to root segments. Fastest for random access by key.
Hierarchical Indexed Direct HIDAM Indexed access to root segments with direct access to dependents. Best for both random and sequential access.
Fast Path DEDB DEDB Data Entry Database. High-performance option for very high-volume online transaction processing.

The database organization is transparent to the COBOL application programmer. Your DL/I calls work the same way regardless of whether the database is HDAM or HIDAM. The choice of organization is made by the database administrator when creating the DBD, based on access patterns and performance requirements.


26.2 The DL/I Call Interface (CBLTDLI)

How COBOL Talks to IMS

Every interaction between a COBOL program and IMS goes through DL/I (Data Language/I), IMS's call-level interface. In COBOL, you invoke DL/I using the CALL 'CBLTDLI' statement. CBLTDLI is the COBOL-specific entry point to the DL/I interface (the "CBL" prefix stands for COBOL; assembler programs use ASMTDLI, PL/I programs use PLITDLI).

The general format of every DL/I call from COBOL is:

           CALL 'CBLTDLI' USING function-code
                                 pcb-mask
                                 io-area
                                 ssa-1
                                 ssa-2
                                 ...

The parameters are:

  1. Function code: A 4-byte field specifying the operation (GU, GN, GNP, GHU, GHN, GHNP, ISRT, REPL, DLET, CHKP, XRST, and others).
  2. PCB mask: The Program Communication Block address, defined in the LINKAGE SECTION and received through the PROCEDURE DIVISION USING clause.
  3. I/O area: A WORKING-STORAGE area where segment data is placed (on retrieval) or taken from (on insert/replace).
  4. SSAs (optional): Zero or more Segment Search Arguments that qualify the call -- specifying which segment to access and how to reach it.

Defining Function Codes

Function codes are simple 4-byte alphanumeric values. Define them in WORKING-STORAGE:

       WORKING-STORAGE SECTION.
      *
      * DL/I function codes
       01  DLI-GU              PIC X(4) VALUE 'GU  '.
       01  DLI-GN              PIC X(4) VALUE 'GN  '.
       01  DLI-GNP             PIC X(4) VALUE 'GNP '.
       01  DLI-GHU             PIC X(4) VALUE 'GHU '.
       01  DLI-GHN             PIC X(4) VALUE 'GHN '.
       01  DLI-GHNP            PIC X(4) VALUE 'GHNP'.
       01  DLI-ISRT            PIC X(4) VALUE 'ISRT'.
       01  DLI-REPL            PIC X(4) VALUE 'REPL'.
       01  DLI-DLET            PIC X(4) VALUE 'DLET'.
       01  DLI-CHKP            PIC X(4) VALUE 'CHKP'.
       01  DLI-XRST            PIC X(4) VALUE 'XRST'.

Note that each value is exactly 4 bytes, padded with spaces. IMS is strict about this format.

Defining I/O Areas

The I/O area is where IMS places segment data on a retrieval call, and where your program places data before an insert or replace. Define one I/O area for each segment type you work with:

      * I/O area for CUSTOMER segment
       01  CUSTOMER-SEGMENT.
           05  CUST-ID             PIC X(10).
           05  CUST-NAME           PIC X(30).
           05  CUST-ADDRESS        PIC X(50).
           05  CUST-CITY           PIC X(20).
           05  CUST-STATE          PIC X(2).
           05  CUST-ZIP            PIC X(10).
           05  CUST-PHONE          PIC X(15).
           05  CUST-TYPE           PIC X(1).
               88  CUST-INDIVIDUAL     VALUE 'I'.
               88  CUST-COMMERCIAL     VALUE 'C'.
           05  CUST-OPEN-DATE      PIC X(10).
           05  CUST-STATUS         PIC X(1).
               88  CUST-ACTIVE         VALUE 'A'.
               88  CUST-INACTIVE       VALUE 'I'.
               88  CUST-CLOSED         VALUE 'C'.

      * I/O area for ACCOUNT segment
       01  ACCOUNT-SEGMENT.
           05  ACCT-NUMBER         PIC X(12).
           05  ACCT-TYPE           PIC X(2).
               88  ACCT-CHECKING       VALUE 'CK'.
               88  ACCT-SAVINGS        VALUE 'SV'.
               88  ACCT-LOAN           VALUE 'LN'.
           05  ACCT-BALANCE        PIC S9(11)V99 COMP-3.
           05  ACCT-OPEN-DATE      PIC X(10).
           05  ACCT-STATUS         PIC X(1).
           05  ACCT-INTEREST-RATE  PIC S9(3)V9(4) COMP-3.

      * I/O area for TRANSACTION segment
       01  TRANSACTION-SEGMENT.
           05  TRAN-ID             PIC X(15).
           05  TRAN-DATE           PIC X(10).
           05  TRAN-TIME           PIC X(8).
           05  TRAN-TYPE           PIC X(2).
               88  TRAN-DEPOSIT        VALUE 'DP'.
               88  TRAN-WITHDRAWAL     VALUE 'WD'.
               88  TRAN-TRANSFER       VALUE 'XF'.
           05  TRAN-AMOUNT         PIC S9(11)V99 COMP-3.
           05  TRAN-DESC           PIC X(30).

The layout of each I/O area must match the segment definition in the DBD exactly -- same field order, same lengths, same data types. If they do not match, your program will read garbage or corrupt the database.


26.3 PCBs and PSBs: The Program's View of the Database

What Is a PSB?

A Program Specification Block (PSB) defines a COBOL program's authorized view of IMS databases. It specifies which databases the program can access, which segments within each database are visible (this is called segment sensitivity), and what operations are permitted (read, insert, replace, delete). The PSB is created by the DBA using IMS utility statements and stored in the IMS PSBLIB.

A PSB contains one or more Program Communication Blocks (PCBs). Each PCB represents either a database view or the I/O PCB for terminal/message processing.

The IO PCB

Every IMS program receives an IO PCB as its first PCB. The IO PCB provides status information for system-level calls (checkpoint, restart) and, in online programs, handles message I/O with terminals. Even batch programs that never communicate with a terminal receive the IO PCB.

Define the IO PCB mask in the LINKAGE SECTION:

       LINKAGE SECTION.
      *
      * IO PCB Mask (always the first PCB in the PSB)
       01  IO-PCB-MASK.
           05  IO-LTERM-NAME       PIC X(8).
           05  FILLER              PIC X(2).
           05  IO-STATUS-CODE      PIC X(2).
           05  IO-DATE             PIC S9(7) COMP-3.
           05  IO-TIME             PIC S9(7) COMP-3.
           05  IO-MSG-SEQ-NUM      PIC S9(7) COMP-3.
           05  IO-MOD-NAME         PIC X(8).

The IO-STATUS-CODE field tells you the result of system calls. For message processing, a status code of QC means no more messages are available.

DB PCB Masks

Each database the program accesses has its own DB PCB. The DB PCB mask tells you, after every DL/I call, what happened:

      * DB PCB Mask for CUSTOMER database
       01  CUST-DB-PCB-MASK.
           05  CUST-DBD-NAME       PIC X(8).
           05  CUST-SEG-LEVEL      PIC X(2).
           05  CUST-STATUS-CODE    PIC X(2).
           05  CUST-PROC-OPTIONS   PIC X(4).
           05  FILLER              PIC S9(5) COMP.
           05  CUST-SEG-NAME       PIC X(8).
           05  CUST-KEY-LENGTH     PIC S9(5) COMP.
           05  CUST-NUM-SENS-SEGS  PIC S9(5) COMP.
           05  CUST-KEY-FEEDBACK   PIC X(30).

The key fields in the DB PCB mask are:

Field Description
DBD-NAME The name of the Database Description. Matches the DBD in the IMS catalog.
SEG-LEVEL The hierarchical level number of the last segment accessed (01 = root, 02 = first child level, etc.).
STATUS-CODE The result of the last DL/I call. Spaces means success. Non-blank codes indicate conditions or errors.
PROC-OPTIONS The processing options allowed for this PCB (G=Get, I=Insert, R=Replace, D=Delete).
SEG-NAME The name of the last segment type accessed.
KEY-LENGTH The length of the concatenated key.
NUM-SENS-SEGS The number of segment types this PCB is sensitive to.
KEY-FEEDBACK The concatenated key of the current position in the database. Contains keys from the root down to the current segment.

Receiving PCBs in the PROCEDURE DIVISION

IMS passes PCB addresses to your program through the PROCEDURE DIVISION USING clause. The PCBs must appear in the same order they are defined in the PSB:

       PROCEDURE DIVISION USING IO-PCB-MASK
                                CUST-DB-PCB-MASK.

For programs that access multiple databases:

       PROCEDURE DIVISION USING IO-PCB-MASK
                                CUST-DB-PCB
                                PROD-DB-PCB.

The order is critical. The first parameter is always the IO PCB. Subsequent parameters are DB PCBs in the order they appear in the PSB definition. If you get the order wrong, your program will use the wrong PCB for calls and produce unpredictable results.

Multiple PCBs in Practice

A program that needs to access both a CUSTOMER database (for reading and updating) and a PRODUCT database (for read-only reference lookups) would have a PSB with three PCBs:

  1. IO PCB (always first)
  2. CUSTOMER DB PCB (processing options: GIRD -- Get, Insert, Replace, Delete)
  3. PRODUCT DB PCB (processing options: G -- Get only)

Each DL/I call specifies which PCB to use, directing the call to the correct database:

      * Access the CUSTOMER database
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB
                                 CUSTOMER-IO-AREA
                                 CUST-QUAL-SSA

      * Access the PRODUCT database
           CALL 'CBLTDLI' USING DLI-GU
                                 PROD-DB-PCB
                                 PRODUCT-IO-AREA
                                 PROD-QUAL-SSA

Each PCB maintains its own independent position within its database. Calls against the CUSTOMER PCB do not affect the position in the PRODUCT database, and vice versa.


26.4 Segment Search Arguments (SSAs)

Directing the DL/I Call

Segment Search Arguments tell IMS which segment to access. Without SSAs, DL/I calls operate on whatever the next segment happens to be in hierarchical sequence. With SSAs, you can specify exactly which segment type, which key value, and which path through the hierarchy you want.

Unqualified SSAs

An unqualified SSA specifies only the segment type name. It is exactly 9 bytes: 8 bytes for the segment name (padded with spaces) plus 1 trailing space:

      * Unqualified SSAs - segment name only (9 bytes)
       01  CUST-UNQUAL-SSA        PIC X(9) VALUE 'CUSTOMER '.
       01  ACCT-UNQUAL-SSA        PIC X(9) VALUE 'ACCOUNT  '.
       01  TRAN-UNQUAL-SSA        PIC X(9) VALUE 'TRANSACT '.

An unqualified SSA on a GN call says "give me the next segment of this type" without specifying which one. An unqualified SSA on a GNP call says "give me the next child of this type under the current parent."

Qualified SSAs

A qualified SSA adds a search condition -- a field name, a comparison operator, and a value. The format is:

segment-name(field-name  OP value)

Where OP is one of: =, >=, <=, >, <, != (not equal).

In COBOL, define qualified SSAs as group items so you can set the key value dynamically:

      * Qualified SSA for CUSTOMER by key
       01  CUST-QUAL-SSA.
           05  FILLER              PIC X(9) VALUE 'CUSTOMER('.
           05  FILLER              PIC X(10) VALUE 'CUSTID   ='.
           05  CUST-SSA-KEY        PIC X(10) VALUE SPACES.
           05  FILLER              PIC X(1) VALUE ')'.

      * Qualified SSA for ACCOUNT by key
       01  ACCT-QUAL-SSA.
           05  FILLER              PIC X(9) VALUE 'ACCOUNT ('.
           05  FILLER              PIC X(10) VALUE 'ACCTNO   ='.
           05  ACCT-SSA-KEY        PIC X(12) VALUE SPACES.
           05  FILLER              PIC X(1) VALUE ')'.

Before issuing the DL/I call, move the desired key value into the SSA:

           MOVE 'CUST000100' TO CUST-SSA-KEY

           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA

This GU call says: "Go directly to the CUSTOMER segment whose CUSTID field equals CUST000100."

Boolean SSAs (Multiple Qualifications)

You can combine multiple conditions in a single SSA using * (AND) or + (OR) between qualifications:

      * Boolean SSA: Active AND Individual customers
       01  CUST-BOOLEAN-SSA.
           05  FILLER              PIC X(9) VALUE 'CUSTOMER('.
           05  FILLER              PIC X(10) VALUE 'CUSTSTAT ='.
           05  BOOL-STATUS         PIC X(1) VALUE 'A'.
           05  FILLER              PIC X(1) VALUE '*'.
           05  FILLER              PIC X(10) VALUE 'CUSTTYPE ='.
           05  BOOL-TYPE           PIC X(1) VALUE 'I'.
           05  FILLER              PIC X(1) VALUE ')'.

The * between the two qualifications acts as a logical AND. A GN call with this SSA returns only customer segments that are both active (status = 'A') and individual (type = 'I').

SSA Command Codes

Command codes modify how DL/I processes a call. They are placed in position 9 of the SSA, preceded by an asterisk:

segment-name*C(qualification)

Where C is the command code letter.

Code Name Description
D Path Retrieves the segment along the path (used with path calls to return multiple segments).
F First Go to the first occurrence of this segment type under the parent.
L Last Go to the last occurrence of this segment type under the parent.
N No position change Do not update current position at this level.
P Set parentage Establish parentage at this level so subsequent GNP calls return children of this segment.
U Maintain position Maintain current position at this level after the call.

Example: SSA with the F (First) command code to get the first account:

      * SSA with F (first) command code
       01  ACCT-FIRST-SSA.
           05  FILLER              PIC X(9) VALUE 'ACCOUNT *'.
           05  FILLER              PIC X(1) VALUE 'F'.

Example: SSA with the D (path) command code:

      * SSA with D (path) command code
       01  CUST-PATH-SSA.
           05  FILLER              PIC X(9) VALUE 'CUSTOMER*'.
           05  FILLER              PIC X(1) VALUE 'D'.
           05  FILLER              PIC X(1) VALUE '('.
           05  FILLER              PIC X(10) VALUE 'CUSTID   ='.
           05  CUST-PATH-KEY       PIC X(10) VALUE SPACES.
           05  FILLER              PIC X(1) VALUE ')'.

The D command code in a path call tells IMS to retrieve the customer segment along with a lower-level segment in a single call, making the navigation more efficient.

Path SSAs: Multi-Level Qualification

You can provide SSAs for multiple levels of the hierarchy to navigate a complete path in a single call:

      * Navigate CUSTOMER -> ACCOUNT -> TRANSACTION in one call
           MOVE 'CUST000100' TO CUST-SSA-KEY
           MOVE '999000000001' TO ACCT-SSA-KEY

           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB-MASK
                                 TRANSACTION-SEGMENT
                                 CUST-QUAL-SSA
                                 ACCT-QUAL-SSA
                                 TRAN-UNQUAL-SSA

This single GU call navigates three levels deep: position to customer CUST000100, then to account 999000000001 under that customer, then to the first transaction under that account. The TRANSACTION-SEGMENT I/O area receives the transaction data.


26.5 Database Retrieval Calls: GU, GN, GNP, GHU, GHN, GHNP

IMS provides six retrieval calls, organized into two categories: standard retrieval and hold retrieval.

GU -- Get Unique (Direct Access)

GU navigates directly to a specific segment based on qualified SSAs. It repositions the database regardless of where you were before. Think of GU as a "random access" call -- it goes straight to the target.

      * Get Unique: Direct access to customer CUST000100
           MOVE 'CUST000100' TO CUST-SSA-KEY

           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA

           EVALUATE CUST-STATUS-CODE
               WHEN SPACES
                   DISPLAY 'Customer found: ' CUST-NAME
               WHEN 'GE'
                   DISPLAY 'Customer not found'
               WHEN OTHER
                   DISPLAY 'DL/I error: ' CUST-STATUS-CODE
                   PERFORM 9999-DLI-ERROR
           END-EVALUATE

Status code spaces means the segment was found and placed in the I/O area. Status code GE means no segment matched the SSA criteria.

GN -- Get Next (Sequential Access)

GN retrieves the next segment in hierarchical sequence. It moves forward from the current position. Use GN with an unqualified SSA to read all segments of a particular type sequentially:

      * Get Next: Read all customers sequentially
           MOVE 0 TO WS-CUSTOMER-COUNT
           SET NOT-END-OF-DATABASE TO TRUE

           PERFORM UNTIL END-OF-DATABASE
               CALL 'CBLTDLI' USING DLI-GN
                                     CUST-DB-PCB-MASK
                                     CUSTOMER-SEGMENT
                                     CUST-UNQUAL-SSA

               EVALUATE CUST-STATUS-CODE
                   WHEN SPACES
                       ADD 1 TO WS-CUSTOMER-COUNT
                       DISPLAY 'Customer: ' CUST-ID
                               ' - ' CUST-NAME
                   WHEN 'GB'
                       SET END-OF-DATABASE TO TRUE
                   WHEN 'GE'
                       SET END-OF-DATABASE TO TRUE
                   WHEN OTHER
                       DISPLAY 'GN error: ' CUST-STATUS-CODE
                       PERFORM 9999-DLI-ERROR
               END-EVALUATE
           END-PERFORM

Status code GB means the end of the database has been reached. Status code GE means no more segments of the requested type were found.

GNP -- Get Next within Parent

GNP retrieves the next segment within the scope of the currently established parent. It only returns child segments under the current parent -- it never crosses a parent boundary.

The pattern is: first use GU to position to a parent, then use GNP in a loop to read all children:

      * Position to the parent customer
           MOVE 'CUST000100' TO CUST-SSA-KEY
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA

      * Then read all ACCOUNT children using GNP
           PERFORM UNTIL END-OF-DATABASE
               CALL 'CBLTDLI' USING DLI-GNP
                                     CUST-DB-PCB-MASK
                                     ACCOUNT-SEGMENT
                                     ACCT-UNQUAL-SSA

               EVALUATE CUST-STATUS-CODE
                   WHEN SPACES
                       ADD 1 TO WS-ACCOUNT-COUNT
                       ADD ACCT-BALANCE TO WS-TOTAL-BALANCE
                       MOVE ACCT-BALANCE TO WS-DISPLAY-BALANCE
                       DISPLAY '  Account: ' ACCT-NUMBER
                               ' Type: ' ACCT-TYPE
                               ' Balance: ' WS-DISPLAY-BALANCE
                   WHEN 'GE'
                       SET END-OF-DATABASE TO TRUE
                   WHEN 'GP'
                       SET END-OF-DATABASE TO TRUE
                   WHEN OTHER
                       DISPLAY 'GNP error: ' CUST-STATUS-CODE
                       PERFORM 9999-DLI-ERROR
               END-EVALUATE
           END-PERFORM

The GE status from GNP means there are no more segments of the requested type under the parent. The GP status (rare) indicates a parentage problem.

GHU, GHN, GHNP -- Hold Variants

The "hold" variants (GHU, GHN, GHNP) work identically to their non-hold counterparts except that they place a hold on the retrieved segment. The hold is required before you can issue a REPL (Replace) or DLET (Delete) call. This is IMS's way of ensuring that you do not update or delete a segment you have not actually retrieved.

      * Get Hold Unique: Retrieve with hold for update
           MOVE 'CUST000100' TO CUST-SSA-KEY

           CALL 'CBLTDLI' USING DLI-GHU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA

           IF CUST-STATUS-CODE = SPACES
               DISPLAY 'Customer retrieved with hold: '
                       CUST-NAME
               DISPLAY '(Segment can now be updated or deleted)'
           END-IF

The hold is released after a REPL call, a DLET call, or any subsequent non-hold Get call. If you issue another GU (without H), the hold from the previous GHU is released.


26.6 Database Update Calls: ISRT, REPL, DLET

ISRT -- Insert

ISRT adds a new segment to the database. For a root segment, provide an unqualified SSA. For a child segment, provide qualified SSAs for the parent path plus an unqualified SSA for the segment being inserted.

Inserting a root segment:

      * Build the new customer segment
           INITIALIZE CUSTOMER-SEGMENT
           MOVE 'CUST000999' TO CUST-ID
           MOVE 'JOHNSON, ROBERT A'  TO CUST-NAME
           MOVE '1234 OAK AVENUE'    TO CUST-ADDRESS
           MOVE 'CHICAGO'            TO CUST-CITY
           MOVE 'IL'                 TO CUST-STATE
           MOVE '60601'              TO CUST-ZIP
           MOVE '312-555-0199'       TO CUST-PHONE
           MOVE 'I'                  TO CUST-TYPE
           MOVE WS-FORMATTED-DATE    TO CUST-OPEN-DATE
           MOVE 'A'                  TO CUST-STATUS

      * Insert the root segment
           CALL 'CBLTDLI' USING DLI-ISRT
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-UNQUAL-SSA

           EVALUATE CUST-STATUS-CODE
               WHEN SPACES
                   DISPLAY 'Customer inserted: ' CUST-ID
               WHEN 'II'
                   DISPLAY 'Duplicate key: ' CUST-ID
               WHEN OTHER
                   DISPLAY 'ISRT error: ' CUST-STATUS-CODE
           END-EVALUATE

Status code II means a segment with the same key already exists.

Inserting a child segment under a parent:

      * Set the parent's key in the qualified SSA
           MOVE 'CUST000999' TO CUST-SSA-KEY

      * Build the new account segment
           INITIALIZE ACCOUNT-SEGMENT
           MOVE '999000000001' TO ACCT-NUMBER
           MOVE 'CK'            TO ACCT-TYPE
           MOVE 1500.00         TO ACCT-BALANCE
           MOVE WS-FORMATTED-DATE TO ACCT-OPEN-DATE
           MOVE 'A'             TO ACCT-STATUS
           MOVE 0.0025          TO ACCT-INTEREST-RATE

      * Insert account under the parent customer
           CALL 'CBLTDLI' USING DLI-ISRT
                                 CUST-DB-PCB-MASK
                                 ACCOUNT-SEGMENT
                                 CUST-QUAL-SSA
                                 ACCT-UNQUAL-SSA

The CUST-QUAL-SSA identifies the parent customer. The ACCT-UNQUAL-SSA identifies the segment type being inserted. IMS locates the parent first, then inserts the child in key sequence under it.

Inserting a grandchild segment (three levels deep):

      * Set SSA keys for the full path
           MOVE 'CUST000999'   TO CUST-SSA-KEY
           MOVE '999000000001' TO ACCT-SSA-KEY

      * Insert transaction under customer/account path
           CALL 'CBLTDLI' USING DLI-ISRT
                                 CUST-DB-PCB-MASK
                                 TRANSACTION-SEGMENT
                                 CUST-QUAL-SSA
                                 ACCT-QUAL-SSA
                                 TRAN-UNQUAL-SSA

REPL -- Replace (Update)

REPL updates a segment that was previously retrieved with a hold call (GHU, GHN, or GHNP). You modify the I/O area fields (except the key field) and then issue REPL:

      * Step 1: Retrieve the segment with hold
           MOVE 'CUST000999' TO CUST-SSA-KEY

           CALL 'CBLTDLI' USING DLI-GHU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA

           IF CUST-STATUS-CODE NOT = SPACES
               DISPLAY 'GHU failed: ' CUST-STATUS-CODE
               GO TO 5000-EXIT
           END-IF

      * Step 2: Modify non-key fields ONLY
      * WARNING: Never change the key field (CUST-ID)!
           MOVE '5678 MAPLE BOULEVARD' TO CUST-ADDRESS
           MOVE 'EVANSTON'             TO CUST-CITY
           MOVE '60201'                TO CUST-ZIP

      * Step 3: Issue REPL -- no SSA needed
           CALL 'CBLTDLI' USING DLI-REPL
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT

           EVALUATE CUST-STATUS-CODE
               WHEN SPACES
                   DISPLAY 'Customer updated successfully'
               WHEN 'DJ'
                   DISPLAY 'Error: no prior hold call'
               WHEN 'DA'
                   DISPLAY 'Error: key field was changed'
               WHEN OTHER
                   DISPLAY 'REPL error: ' CUST-STATUS-CODE
           END-EVALUATE

Critical rules for REPL: - You must issue a hold call (GHU, GHN, GHNP) before REPL. - You must not change the key field of the segment. - REPL does not use SSAs -- it updates the segment that was held. - Status code DJ means you did not issue a prior hold call. - Status code DA means you modified the key field.

DLET -- Delete

DLET removes a segment and all its dependent children. Like REPL, it requires a prior hold call:

      * Retrieve and hold the segment to delete
           CALL 'CBLTDLI' USING DLI-GHU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA

           IF CUST-STATUS-CODE = SPACES
      * Delete the segment (and all its children!)
               CALL 'CBLTDLI' USING DLI-DLET
                                     CUST-DB-PCB-MASK
                                     CUSTOMER-SEGMENT

               IF CUST-STATUS-CODE = SPACES
                   DISPLAY 'Segment deleted'
               END-IF
           END-IF

Important: Deleting a parent segment deletes all its children and grandchildren. If you DLET a CUSTOMER segment, all ACCOUNT, TRANSACTION, ADDRESS, and CONTACT segments under it are also deleted. This is called a cascade delete and it is automatic.


26.7 Status Code Handling

After every DL/I call, check the status code in the PCB mask. The status code is the single most important field for program logic. Here is a comprehensive reference:

Common Status Codes

Code Meaning Typical Action
(spaces) Successful call Continue processing
GE Segment not found Handle not-found condition
GB End of database reached Stop sequential processing
GK Segment type changed (GN returned a different type) Check segment name in PCB
GP Parentage changed (GNP went outside parent scope) Stop child processing
II Duplicate key on insert Handle duplicate
DA Key field changed before REPL Programming error -- fix code
DJ No prior hold call for REPL/DLET Programming error -- fix code
AI Program not authorized for database PSB configuration error
AK Invalid SSA for PCB sensitivity SSA references segment not in PCB
QC No more messages (IO PCB, online) End message processing loop

A Robust Error Handler

       9999-DLI-ERROR.
           DISPLAY '*** CRITICAL DL/I ERROR ***'
           DISPLAY 'Status code : ' CUST-STATUS-CODE
           DISPLAY 'Segment name: ' CUST-SEG-NAME
           DISPLAY 'DBD name    : ' CUST-DBD-NAME
           DISPLAY 'Segment lvl : ' CUST-SEG-LEVEL
           GOBACK.

For production programs, you should log the error to a file, issue an abend with a meaningful code, or (in online programs) send an error message to the terminal and continue processing the next message.


26.8 Complete Example: Reading an IMS Database

The following program demonstrates all the major read operations against the banking hierarchy. It performs a GU (direct access), a GN loop (sequential scan), a GNP loop (children within a parent), and a GHU (hold for potential update). This corresponds to example-01-ims-db-read.cob in the code examples.

      *================================================================*
      * IMS DB READ OPERATIONS - COMPLETE EXAMPLE                      *
      * Demonstrates: GU, GN, GNP, GHU calls                          *
      * Database: CUSTOMER -> ACCOUNT -> TRANSACTION                   *
      * [IBM Enterprise COBOL] - IMS DL/I interface                    *
      *================================================================*
       IDENTIFICATION DIVISION.
       PROGRAM-ID.  IMSREAD1.

       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SOURCE-COMPUTER. IBM-ZOS.
       OBJECT-COMPUTER. IBM-ZOS.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

      * DL/I function codes
       01  DLI-GU              PIC X(4) VALUE 'GU  '.
       01  DLI-GN              PIC X(4) VALUE 'GN  '.
       01  DLI-GNP             PIC X(4) VALUE 'GNP '.
       01  DLI-GHU             PIC X(4) VALUE 'GHU '.

      * I/O areas
       01  CUSTOMER-SEGMENT.
           05  CUST-ID             PIC X(10).
           05  CUST-NAME           PIC X(30).
           05  CUST-ADDRESS        PIC X(50).
           05  CUST-CITY           PIC X(20).
           05  CUST-STATE          PIC X(2).
           05  CUST-ZIP            PIC X(10).
           05  CUST-PHONE          PIC X(15).
           05  CUST-TYPE           PIC X(1).
           05  CUST-OPEN-DATE      PIC X(10).
           05  CUST-STATUS         PIC X(1).

       01  ACCOUNT-SEGMENT.
           05  ACCT-NUMBER         PIC X(12).
           05  ACCT-TYPE           PIC X(2).
           05  ACCT-BALANCE        PIC S9(11)V99 COMP-3.
           05  ACCT-OPEN-DATE      PIC X(10).
           05  ACCT-STATUS         PIC X(1).
           05  ACCT-INTEREST-RATE  PIC S9(3)V9(4) COMP-3.

      * SSAs
       01  CUST-UNQUAL-SSA        PIC X(9) VALUE 'CUSTOMER '.
       01  ACCT-UNQUAL-SSA        PIC X(9) VALUE 'ACCOUNT  '.

       01  CUST-QUAL-SSA.
           05  FILLER              PIC X(9) VALUE 'CUSTOMER('.
           05  FILLER              PIC X(10) VALUE 'CUSTID   ='.
           05  CUST-SSA-KEY        PIC X(10) VALUE SPACES.
           05  FILLER              PIC X(1) VALUE ')'.

      * Work fields
       01  WS-CUSTOMER-COUNT       PIC S9(7) COMP-3 VALUE 0.
       01  WS-ACCOUNT-COUNT        PIC S9(7) COMP-3 VALUE 0.
       01  WS-TOTAL-BALANCE        PIC S9(13)V99 COMP-3 VALUE 0.
       01  WS-END-OF-DB            PIC X(1) VALUE 'N'.
           88  END-OF-DATABASE         VALUE 'Y'.
           88  NOT-END-OF-DATABASE     VALUE 'N'.
       01  WS-DISPLAY-BALANCE      PIC -(12)9.99.
       01  WS-DISPLAY-COUNT        PIC ZZZ,ZZ9.

      * PCB masks in LINKAGE
       LINKAGE SECTION.
       01  IO-PCB-MASK.
           05  IO-LTERM-NAME       PIC X(8).
           05  FILLER              PIC X(2).
           05  IO-STATUS-CODE      PIC X(2).
           05  IO-DATE             PIC S9(7) COMP-3.
           05  IO-TIME             PIC S9(7) COMP-3.
           05  IO-MSG-SEQ-NUM      PIC S9(7) COMP-3.
           05  IO-MOD-NAME         PIC X(8).

       01  CUST-DB-PCB-MASK.
           05  CUST-DBD-NAME       PIC X(8).
           05  CUST-SEG-LEVEL      PIC X(2).
           05  CUST-STATUS-CODE    PIC X(2).
           05  CUST-PROC-OPTIONS   PIC X(4).
           05  FILLER              PIC S9(5) COMP.
           05  CUST-SEG-NAME       PIC X(8).
           05  CUST-KEY-LENGTH     PIC S9(5) COMP.
           05  CUST-NUM-SENS-SEGS  PIC S9(5) COMP.
           05  CUST-KEY-FEEDBACK   PIC X(30).

       PROCEDURE DIVISION USING IO-PCB-MASK
                                CUST-DB-PCB-MASK.

       0000-MAIN-CONTROL.
           PERFORM 1000-GU-SINGLE-CUSTOMER
           PERFORM 2000-GN-ALL-CUSTOMERS
           PERFORM 3000-GNP-ACCOUNTS
           GOBACK.

       1000-GU-SINGLE-CUSTOMER.
           MOVE 'CUST000100' TO CUST-SSA-KEY
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA
           IF CUST-STATUS-CODE = SPACES
               DISPLAY 'Found: ' CUST-NAME
           ELSE
               DISPLAY 'Not found: ' CUST-STATUS-CODE
           END-IF
           .

       2000-GN-ALL-CUSTOMERS.
           MOVE 0 TO WS-CUSTOMER-COUNT
           SET NOT-END-OF-DATABASE TO TRUE
           PERFORM UNTIL END-OF-DATABASE
               CALL 'CBLTDLI' USING DLI-GN
                                     CUST-DB-PCB-MASK
                                     CUSTOMER-SEGMENT
                                     CUST-UNQUAL-SSA
               IF CUST-STATUS-CODE = SPACES
                   ADD 1 TO WS-CUSTOMER-COUNT
               ELSE
                   SET END-OF-DATABASE TO TRUE
               END-IF
           END-PERFORM
           MOVE WS-CUSTOMER-COUNT TO WS-DISPLAY-COUNT
           DISPLAY 'Total customers: ' WS-DISPLAY-COUNT
           .

       3000-GNP-ACCOUNTS.
           MOVE 'CUST000100' TO CUST-SSA-KEY
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA
           IF CUST-STATUS-CODE NOT = SPACES
               DISPLAY 'Parent not found'
               GO TO 3000-EXIT
           END-IF
           MOVE 0 TO WS-ACCOUNT-COUNT
           MOVE 0 TO WS-TOTAL-BALANCE
           SET NOT-END-OF-DATABASE TO TRUE
           PERFORM UNTIL END-OF-DATABASE
               CALL 'CBLTDLI' USING DLI-GNP
                                     CUST-DB-PCB-MASK
                                     ACCOUNT-SEGMENT
                                     ACCT-UNQUAL-SSA
               IF CUST-STATUS-CODE = SPACES
                   ADD 1 TO WS-ACCOUNT-COUNT
                   ADD ACCT-BALANCE TO WS-TOTAL-BALANCE
                   MOVE ACCT-BALANCE TO WS-DISPLAY-BALANCE
                   DISPLAY '  Acct: ' ACCT-NUMBER
                           ' Bal: ' WS-DISPLAY-BALANCE
               ELSE
                   SET END-OF-DATABASE TO TRUE
               END-IF
           END-PERFORM
           MOVE WS-TOTAL-BALANCE TO WS-DISPLAY-BALANCE
           DISPLAY 'Total balance: ' WS-DISPLAY-BALANCE
           .
       3000-EXIT.
           EXIT.

26.9 Complete Example: Updating an IMS Database

This program demonstrates ISRT, REPL, and DLET calls. It inserts a new customer with an account and a transaction, updates the customer address, applies a deposit to the account balance, and deletes a transaction. This corresponds to example-02-ims-db-update.cob.

      *================================================================*
      * IMS DB UPDATE OPERATIONS - COMPLETE EXAMPLE                    *
      * Demonstrates: ISRT, REPL, DLET calls                          *
      * [IBM Enterprise COBOL] - IMS DL/I interface                    *
      *================================================================*
       IDENTIFICATION DIVISION.
       PROGRAM-ID.  IMSUPD1.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  DLI-GHU             PIC X(4) VALUE 'GHU '.
       01  DLI-GU              PIC X(4) VALUE 'GU  '.
       01  DLI-GHNP            PIC X(4) VALUE 'GHNP'.
       01  DLI-ISRT            PIC X(4) VALUE 'ISRT'.
       01  DLI-REPL            PIC X(4) VALUE 'REPL'.
       01  DLI-DLET            PIC X(4) VALUE 'DLET'.

       01  CUSTOMER-SEGMENT.
           05  CUST-ID             PIC X(10).
           05  CUST-NAME           PIC X(30).
           05  CUST-ADDRESS        PIC X(50).
           05  CUST-CITY           PIC X(20).
           05  CUST-STATE          PIC X(2).
           05  CUST-ZIP            PIC X(10).
           05  CUST-PHONE          PIC X(15).
           05  CUST-TYPE           PIC X(1).
           05  CUST-OPEN-DATE      PIC X(10).
           05  CUST-STATUS         PIC X(1).

       01  ACCOUNT-SEGMENT.
           05  ACCT-NUMBER         PIC X(12).
           05  ACCT-TYPE           PIC X(2).
           05  ACCT-BALANCE        PIC S9(11)V99 COMP-3.
           05  ACCT-OPEN-DATE      PIC X(10).
           05  ACCT-STATUS         PIC X(1).
           05  ACCT-INTEREST-RATE  PIC S9(3)V9(4) COMP-3.

       01  CUST-UNQUAL-SSA        PIC X(9) VALUE 'CUSTOMER '.
       01  ACCT-UNQUAL-SSA        PIC X(9) VALUE 'ACCOUNT  '.
       01  TRAN-UNQUAL-SSA        PIC X(9) VALUE 'TRANSACT '.

       01  CUST-QUAL-SSA.
           05  FILLER              PIC X(9)  VALUE 'CUSTOMER('.
           05  FILLER              PIC X(10) VALUE 'CUSTID   ='.
           05  CUST-SSA-KEY        PIC X(10) VALUE SPACES.
           05  FILLER              PIC X(1)  VALUE ')'.

       01  ACCT-QUAL-SSA.
           05  FILLER              PIC X(9)  VALUE 'ACCOUNT ('.
           05  FILLER              PIC X(10) VALUE 'ACCTNO   ='.
           05  ACCT-SSA-KEY        PIC X(12) VALUE SPACES.
           05  FILLER              PIC X(1)  VALUE ')'.

       01  WS-DISPLAY-BALANCE      PIC -(12)9.99.

       LINKAGE SECTION.
       01  IO-PCB-MASK.
           05  FILLER              PIC X(10).
           05  IO-STATUS-CODE      PIC X(2).
           05  FILLER              PIC X(20).
       01  CUST-DB-PCB-MASK.
           05  CUST-DBD-NAME       PIC X(8).
           05  CUST-SEG-LEVEL      PIC X(2).
           05  CUST-STATUS-CODE    PIC X(2).
           05  CUST-PROC-OPTIONS   PIC X(4).
           05  FILLER              PIC S9(5) COMP.
           05  CUST-SEG-NAME       PIC X(8).
           05  CUST-KEY-LENGTH     PIC S9(5) COMP.
           05  CUST-NUM-SENS-SEGS  PIC S9(5) COMP.
           05  CUST-KEY-FEEDBACK   PIC X(30).

       PROCEDURE DIVISION USING IO-PCB-MASK
                                CUST-DB-PCB-MASK.
       0000-MAIN-CONTROL.
           PERFORM 1000-INSERT-CUSTOMER
           PERFORM 2000-INSERT-ACCOUNT
           PERFORM 3000-UPDATE-ADDRESS
           PERFORM 4000-UPDATE-BALANCE
           GOBACK.

       1000-INSERT-CUSTOMER.
           INITIALIZE CUSTOMER-SEGMENT
           MOVE 'CUST000999' TO CUST-ID
           MOVE 'JOHNSON, ROBERT A'  TO CUST-NAME
           MOVE '1234 OAK AVENUE'    TO CUST-ADDRESS
           MOVE 'CHICAGO'            TO CUST-CITY
           MOVE 'IL'                 TO CUST-STATE
           MOVE '60601'              TO CUST-ZIP
           MOVE 'I'                  TO CUST-TYPE
           MOVE 'A'                  TO CUST-STATUS
           CALL 'CBLTDLI' USING DLI-ISRT
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-UNQUAL-SSA
           IF CUST-STATUS-CODE = SPACES
               DISPLAY 'Customer inserted: ' CUST-ID
           ELSE
               DISPLAY 'ISRT error: ' CUST-STATUS-CODE
           END-IF
           .

       2000-INSERT-ACCOUNT.
           MOVE 'CUST000999' TO CUST-SSA-KEY
           INITIALIZE ACCOUNT-SEGMENT
           MOVE '999000000001' TO ACCT-NUMBER
           MOVE 'CK'            TO ACCT-TYPE
           MOVE 1500.00         TO ACCT-BALANCE
           MOVE 'A'             TO ACCT-STATUS
           MOVE 0.0025          TO ACCT-INTEREST-RATE
           CALL 'CBLTDLI' USING DLI-ISRT
                                 CUST-DB-PCB-MASK
                                 ACCOUNT-SEGMENT
                                 CUST-QUAL-SSA
                                 ACCT-UNQUAL-SSA
           IF CUST-STATUS-CODE = SPACES
               DISPLAY 'Account inserted: ' ACCT-NUMBER
           END-IF
           .

       3000-UPDATE-ADDRESS.
           MOVE 'CUST000999' TO CUST-SSA-KEY
           CALL 'CBLTDLI' USING DLI-GHU
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA
           IF CUST-STATUS-CODE NOT = SPACES
               GO TO 3000-EXIT
           END-IF
      * Modify non-key fields only
           MOVE '5678 MAPLE BOULEVARD' TO CUST-ADDRESS
           MOVE 'EVANSTON'             TO CUST-CITY
           MOVE '60201'                TO CUST-ZIP
           CALL 'CBLTDLI' USING DLI-REPL
                                 CUST-DB-PCB-MASK
                                 CUSTOMER-SEGMENT
           IF CUST-STATUS-CODE = SPACES
               DISPLAY 'Address updated for ' CUST-ID
           END-IF
           .
       3000-EXIT.
           EXIT.

       4000-UPDATE-BALANCE.
           MOVE 'CUST000999'   TO CUST-SSA-KEY
           MOVE '999000000001' TO ACCT-SSA-KEY
           CALL 'CBLTDLI' USING DLI-GHU
                                 CUST-DB-PCB-MASK
                                 ACCOUNT-SEGMENT
                                 CUST-QUAL-SSA
                                 ACCT-QUAL-SSA
           IF CUST-STATUS-CODE NOT = SPACES
               GO TO 4000-EXIT
           END-IF
           ADD 250.00 TO ACCT-BALANCE
           CALL 'CBLTDLI' USING DLI-REPL
                                 CUST-DB-PCB-MASK
                                 ACCOUNT-SEGMENT
           IF CUST-STATUS-CODE = SPACES
               MOVE ACCT-BALANCE TO WS-DISPLAY-BALANCE
               DISPLAY 'New balance: ' WS-DISPLAY-BALANCE
           END-IF
           .
       4000-EXIT.
           EXIT.

26.10 IMS Transaction Manager (IMS TM/DC)

Online Transaction Processing with IMS

IMS is not just a database -- it is also a full online transaction processing system. IMS TM (Transaction Manager), also called IMS DC (Data Communications), performs the same role for IMS applications that CICS performs for CICS applications: it manages terminals, queues messages, schedules programs, and provides recovery services.

How IMS TM Works

The flow of an IMS online transaction follows this sequence:

  1. A terminal user types a transaction code and data on a 3270 terminal (e.g., ACCTINQ INQ CUST000100) and presses Enter.
  2. IMS TM receives the message and places it in the message queue.
  3. IMS TM schedules an MPP (Message Processing Program) associated with that transaction code.
  4. The MPP reads the input message from the queue using a GU call with the IO PCB.
  5. The MPP accesses one or more IMS databases using DL/I calls with DB PCBs.
  6. The MPP sends the response back to the terminal using an ISRT call with the IO PCB.
  7. IMS TM delivers the output message to the terminal.

MPP -- Message Processing Program

An MPP is the IMS equivalent of a CICS transaction program. It processes messages from the IMS message queue. The key differences from a batch IMS program are:

  • The MPP reads input messages with GU IO-PCB-MASK INPUT-MESSAGE.
  • The MPP sends output messages with ISRT IO-PCB-MASK OUTPUT-MESSAGE.
  • The MPP loops, processing messages until the queue is empty (status code QC).
  • The MPP does not open files or define the ENVIRONMENT DIVISION for I/O.

Message Format

IMS messages have a specific format. Each message segment begins with a 4-byte prefix:

       01  INPUT-MESSAGE.
           05  IN-LL               PIC S9(4) COMP.
           05  IN-ZZ               PIC S9(4) COMP.
           05  IN-TRAN-CODE        PIC X(8).
           05  IN-DATA             PIC X(100).
  • LL: The total length of this message segment (including LL and ZZ).
  • ZZ: Reserved, always zero.
  • TRAN-CODE: The transaction code typed by the user (e.g., ACCTINQ).
  • DATA: The rest of the user's input.

Output messages use the same LL/ZZ prefix:

       01  OUTPUT-MSG-HEADER.
           05  OUT-HDR-LL          PIC S9(4) COMP VALUE +80.
           05  OUT-HDR-ZZ          PIC S9(4) COMP VALUE +0.
           05  OUT-HDR-LINE        PIC X(76).

Complete MPP Example

The following program implements an account inquiry transaction. When a bank teller types ACCTINQ INQ CUST000100, the program looks up the customer, retrieves all accounts, and sends a formatted response back to the terminal. This corresponds to example-04-ims-tm.cob.

      *================================================================*
      * IMS MPP - ACCOUNT INQUIRY TRANSACTION                          *
      * Transaction code: ACCTINQ                                      *
      * Functions: INQ (full inquiry), BAL (balance only)              *
      * [IBM Enterprise COBOL] - IMS TM/DC interface                   *
      *================================================================*
       IDENTIFICATION DIVISION.
       PROGRAM-ID.  IMSTM01.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

       01  DLI-GU              PIC X(4) VALUE 'GU  '.
       01  DLI-GNP             PIC X(4) VALUE 'GNP '.
       01  DLI-ISRT            PIC X(4) VALUE 'ISRT'.

      * Input message area
       01  INPUT-MESSAGE.
           05  IN-LL               PIC S9(4) COMP.
           05  IN-ZZ               PIC S9(4) COMP.
           05  IN-TRAN-CODE        PIC X(8).
           05  IN-DATA             PIC X(100).

       01  INPUT-FIELDS.
           05  IN-FUNCTION         PIC X(3).
               88  FUNC-INQUIRY        VALUE 'INQ'.
               88  FUNC-BALANCE        VALUE 'BAL'.
           05  IN-CUSTOMER-ID      PIC X(10).

      * Output message area
       01  OUTPUT-MSG.
           05  OUT-LL              PIC S9(4) COMP VALUE +80.
           05  OUT-ZZ              PIC S9(4) COMP VALUE +0.
           05  OUT-LINE            PIC X(76).

      * Database segments and SSAs
       01  CUSTOMER-SEGMENT.
           05  CUST-ID             PIC X(10).
           05  CUST-NAME           PIC X(30).
           05  CUST-ADDRESS        PIC X(50).
           05  CUST-CITY           PIC X(20).
           05  CUST-STATE          PIC X(2).
           05  CUST-ZIP            PIC X(10).
           05  CUST-PHONE          PIC X(15).
           05  CUST-TYPE           PIC X(1).
           05  CUST-OPEN-DATE      PIC X(10).
           05  CUST-STATUS         PIC X(1).

       01  ACCOUNT-SEGMENT.
           05  ACCT-NUMBER         PIC X(12).
           05  ACCT-TYPE           PIC X(2).
           05  ACCT-BALANCE        PIC S9(11)V99 COMP-3.
           05  ACCT-OPEN-DATE      PIC X(10).
           05  ACCT-STATUS         PIC X(1).
           05  ACCT-INTEREST-RATE  PIC S9(3)V9(4) COMP-3.

       01  CUST-QUAL-SSA.
           05  FILLER              PIC X(9)  VALUE 'CUSTOMER('.
           05  FILLER              PIC X(10) VALUE 'CUSTID   ='.
           05  CUST-SSA-KEY        PIC X(10) VALUE SPACES.
           05  FILLER              PIC X(1)  VALUE ')'.
       01  ACCT-UNQUAL-SSA        PIC X(9)  VALUE 'ACCOUNT  '.

       01  WS-DISPLAY-BALANCE     PIC $$$,$$$,$$9.99-.
       01  WS-TOTAL-BALANCE       PIC S9(13)V99 COMP-3 VALUE 0.
       01  WS-MORE-MESSAGES       PIC X(1) VALUE 'Y'.
           88  MESSAGES-AVAILABLE      VALUE 'Y'.
           88  NO-MORE-MESSAGES        VALUE 'N'.
       01  WS-END-ACCT            PIC X(1) VALUE 'N'.
           88  END-OF-ACCOUNTS         VALUE 'Y'.
           88  MORE-ACCOUNTS           VALUE 'N'.

       LINKAGE SECTION.
       01  IO-PCB-MASK.
           05  IO-LTERM-NAME       PIC X(8).
           05  FILLER              PIC X(2).
           05  IO-STATUS-CODE      PIC X(2).
           05  FILLER              PIC X(20).

       01  CUST-DB-PCB.
           05  CUST-DBD-NAME       PIC X(8).
           05  CUST-SEG-LEVEL      PIC X(2).
           05  CUST-STATUS-CODE    PIC X(2).
           05  CUST-PROC-OPTIONS   PIC X(4).
           05  FILLER              PIC S9(5) COMP.
           05  CUST-SEG-NAME       PIC X(8).
           05  CUST-KEY-LENGTH     PIC S9(5) COMP.
           05  CUST-NUM-SENS-SEGS  PIC S9(5) COMP.
           05  CUST-KEY-FEEDBACK   PIC X(30).

       PROCEDURE DIVISION USING IO-PCB-MASK
                                CUST-DB-PCB.
       0000-MAIN-CONTROL.
      *    MPP message processing loop
           PERFORM 1000-GET-MESSAGE
           PERFORM UNTIL NO-MORE-MESSAGES
               PERFORM 2000-PROCESS-INQUIRY
               PERFORM 1000-GET-MESSAGE
           END-PERFORM
           GOBACK.

       1000-GET-MESSAGE.
           INITIALIZE INPUT-MESSAGE
      *    GU with IO PCB reads next message from queue
           CALL 'CBLTDLI' USING DLI-GU
                                 IO-PCB-MASK
                                 INPUT-MESSAGE
           IF IO-STATUS-CODE = SPACES
               SET MESSAGES-AVAILABLE TO TRUE
           ELSE
               SET NO-MORE-MESSAGES TO TRUE
           END-IF
           .

       2000-PROCESS-INQUIRY.
           UNSTRING IN-DATA DELIMITED BY SPACES
               INTO IN-FUNCTION IN-CUSTOMER-ID
           END-UNSTRING
           MOVE IN-CUSTOMER-ID TO CUST-SSA-KEY
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-DB-PCB
                                 CUSTOMER-SEGMENT
                                 CUST-QUAL-SSA
           IF CUST-STATUS-CODE NOT = SPACES
               MOVE SPACES TO OUT-LINE
               STRING 'CUSTOMER NOT FOUND: ' IN-CUSTOMER-ID
                   DELIMITED BY SIZE INTO OUT-LINE
               CALL 'CBLTDLI' USING DLI-ISRT
                                     IO-PCB-MASK
                                     OUTPUT-MSG
               GO TO 2000-EXIT
           END-IF
      *    Send customer info to terminal
           MOVE SPACES TO OUT-LINE
           STRING 'NAME: ' CUST-NAME
               DELIMITED BY SIZE INTO OUT-LINE
           CALL 'CBLTDLI' USING DLI-ISRT
                                 IO-PCB-MASK OUTPUT-MSG
      *    Read and display accounts
           MOVE 0 TO WS-TOTAL-BALANCE
           SET MORE-ACCOUNTS TO TRUE
           PERFORM UNTIL END-OF-ACCOUNTS
               CALL 'CBLTDLI' USING DLI-GNP
                                     CUST-DB-PCB
                                     ACCOUNT-SEGMENT
                                     ACCT-UNQUAL-SSA
               IF CUST-STATUS-CODE = SPACES
                   ADD ACCT-BALANCE TO WS-TOTAL-BALANCE
                   MOVE ACCT-BALANCE TO WS-DISPLAY-BALANCE
                   MOVE SPACES TO OUT-LINE
                   STRING 'ACCT: ' ACCT-NUMBER
                          ' TYPE: ' ACCT-TYPE
                          ' BAL: ' WS-DISPLAY-BALANCE
                       DELIMITED BY SIZE INTO OUT-LINE
                   CALL 'CBLTDLI' USING DLI-ISRT
                                         IO-PCB-MASK
                                         OUTPUT-MSG
               ELSE
                   SET END-OF-ACCOUNTS TO TRUE
               END-IF
           END-PERFORM
           MOVE WS-TOTAL-BALANCE TO WS-DISPLAY-BALANCE
           MOVE SPACES TO OUT-LINE
           STRING 'TOTAL: ' WS-DISPLAY-BALANCE
               DELIMITED BY SIZE INTO OUT-LINE
           CALL 'CBLTDLI' USING DLI-ISRT
                                 IO-PCB-MASK OUTPUT-MSG
           .
       2000-EXIT.
           EXIT.

Notice the two distinct uses of DL/I calls: GU IO-PCB-MASK reads from the message queue (terminal input), while GU CUST-DB-PCB reads from the database. ISRT IO-PCB-MASK sends output to the terminal. The PCB parameter determines whether the call goes to the message queue or the database.


26.11 MPP vs. BMP Regions

IMS runs application programs in different types of regions:

Region Type Full Name Description
MPP Message Processing Program Online region that processes messages from the IMS message queue. Handles interactive terminal transactions. Short-running.
BMP Batch Message Processing Batch region that has access to IMS databases while the online system is running. Long-running batch jobs that share databases with MPP regions.
IFP IMS Fast Path High-performance online region for very high-volume, short transactions using Fast Path DEDBs.
Batch DL/I Batch Data Language/I Batch region that runs when the IMS online system is shut down. Exclusive access to databases for utilities, reorganization, and bulk processing.

MPP Characteristics

  • Processes messages from the message queue.
  • Short-running: processes one message (or a set of messages), then returns.
  • Scheduled by IMS when messages arrive.
  • Uses the IO PCB for terminal communication.
  • Commits work after each message (automatic sync point).

BMP Characteristics

  • Runs as a batch job (submitted through JCL) but accesses IMS databases.
  • Can run concurrently with the online system, sharing databases with MPP regions.
  • Long-running: processes all records in a sequential pass.
  • Should issue periodic checkpoints (CHKP) to commit work and enable restart.
  • Uses the IO PCB for checkpoints and status, but typically not for terminal I/O.
  • The JCL invokes DFSRRC00, the IMS region controller, rather than calling the application program directly.

26.12 Checkpoint and Restart

Why Checkpoint/Restart Matters

Long-running batch IMS programs (BMPs) may process millions of database records. If the program fails after processing 800,000 records, you do not want to start over from the beginning. IMS provides checkpoint/restart to solve this problem.

A checkpoint (CHKP call) does three things: 1. Commits all database changes since the last checkpoint. 2. Saves a snapshot of application data (your counters, positions, and flags) so they can be restored on restart. 3. Writes a log record that marks the recovery point.

An extended restart (XRST call) at the beginning of the program checks whether a prior checkpoint exists from a failed run. If so, it restores the saved application data and repositions the database so processing can resume from the last checkpoint.

The CHKP Call

      * Checkpoint data area - saved and restored
       01  WS-CHKP-DATA.
           05  CHKP-LAST-CUST-ID  PIC X(10) VALUE SPACES.
           05  CHKP-CUST-COUNT    PIC S9(7) COMP-3 VALUE 0.
           05  CHKP-ACCT-COUNT    PIC S9(7) COMP-3 VALUE 0.
           05  CHKP-UPD-COUNT     PIC S9(7) COMP-3 VALUE 0.
           05  CHKP-RECORDS-SINCE PIC S9(7) COMP-3 VALUE 0.
           05  FILLER             PIC X(154) VALUE SPACES.

       01  WS-CHKP-AREA-LENGTH    PIC S9(8) COMP VALUE +200.
       01  WS-CHKP-ID             PIC X(8) VALUE SPACES.
       01  WS-CHKP-SEQ            PIC 9(6) VALUE 0.

Issue the CHKP call periodically (e.g., every 500 records):

       7000-TAKE-CHECKPOINT.
      *    Generate a unique checkpoint ID
           ADD 1 TO WS-CHKP-SEQ
           STRING 'INTCL' WS-CHKP-SEQ
               DELIMITED BY SIZE INTO WS-CHKP-ID
           END-STRING

      *    Issue the symbolic checkpoint
           CALL 'CBLTDLI' USING DLI-CHKP
                                 IO-PCB-MASK
                                 WS-CHKP-DATA
                                 WS-CHKP-AREA-LENGTH
                                 WS-CHKP-ID

           IF IO-STATUS-CODE = SPACES
               DISPLAY 'CHECKPOINT ' WS-CHKP-ID ' TAKEN'
               MOVE 0 TO CHKP-RECORDS-SINCE
           ELSE
               DISPLAY 'CHECKPOINT ERROR: ' IO-STATUS-CODE
           END-IF
           .

The CHKP call parameters are: 1. DLI-CHKP: The function code for checkpoint. 2. IO-PCB-MASK: Always the IO PCB for system calls. 3. WS-CHKP-DATA: The application data area to be saved. 4. WS-CHKP-AREA-LENGTH: The length of the data area. 5. WS-CHKP-ID: An 8-byte identifier for this checkpoint.

The XRST Call

Issue the XRST call at the very beginning of the program, before any database processing:

       1500-CHECK-RESTART.
           CALL 'CBLTDLI' USING DLI-XRST
                                 IO-PCB-MASK
                                 WS-CHKP-DATA
                                 WS-CHKP-AREA-LENGTH
                                 WS-CHKP-ID

           IF IO-STATUS-CODE = SPACES
               IF WS-CHKP-ID NOT = SPACES
      *            Restart: data area has been restored
                   DISPLAY 'RESTARTING FROM: ' WS-CHKP-ID
                   DISPLAY 'LAST CUSTOMER: '
                           CHKP-LAST-CUST-ID
               ELSE
      *            Fresh start: no prior checkpoint
                   DISPLAY 'FRESH START'
                   INITIALIZE WS-CHKP-DATA
               END-IF
           ELSE
               DISPLAY 'XRST ERROR: ' IO-STATUS-CODE
               GOBACK
           END-IF
           .

If XRST finds a prior checkpoint, it restores WS-CHKP-DATA to the values it held at the last successful CHKP call. The database position is also restored automatically. Your program can then resume from where it left off -- the counters, flags, and last-processed key are all intact.

Checkpoint Interval

Choose a checkpoint interval that balances recovery time against overhead. Common intervals are every 500 to 5,000 records. More frequent checkpoints mean less work is lost on failure but add I/O overhead. Less frequent checkpoints are more efficient but risk more rework on restart. For critical financial batch jobs, 500 records is typical.


26.13 JCL for IMS Batch Programs

The IMS Region Controller: DFSRRC00

IMS batch programs (BMPs and Batch DL/I) are not invoked directly. Instead, JCL executes DFSRRC00, the IMS region controller. DFSRRC00 initializes the IMS environment, loads the PSB, invokes your application program, and manages checkpoint/restart.

Complete JCL Example

The following JCL runs the interest calculation BMP program (example-05-ims-batch.jcl):

//INTCALC  JOB (ACCT),'INTEREST CALC',
//         CLASS=A,MSGCLASS=X,MSGLEVEL=(1,1),
//         NOTIFY=&SYSUID,REGION=0M
//*================================================================*
//* JCL FOR IMS BMP EXECUTION                                      *
//*================================================================*
//*
//STEP01   EXEC PGM=DFSRRC00,
//  PARM=(BMP,IMSBMP01,IMSBMP01,,,,,,,,,,,Y,N,,,,,,,,,,,'')
//*
//* PARM explanation:
//*   BMP      - Region type
//*   IMSBMP01 - Application program name (load module)
//*   IMSBMP01 - PSB name
//*   Y        - Checkpoint/restart indicator
//*   N        - Not conversational
//*
//*----------------------------------------------------------------*
//* LOAD LIBRARIES                                                 *
//*----------------------------------------------------------------*
//STEPLIB  DD DSN=IMS.SDFSRESL,DISP=SHR
//         DD DSN=APPL.LOADLIB,DISP=SHR
//*
//*----------------------------------------------------------------*
//* IMS SYSTEM LIBRARIES                                           *
//*----------------------------------------------------------------*
//DFSRESLB DD DSN=IMS.SDFSRESL,DISP=SHR
//IMS      DD DSN=IMS.DBDLIB,DISP=SHR
//         DD DSN=IMS.PSBLIB,DISP=SHR
//*
//*----------------------------------------------------------------*
//* IMS LOG DATASET (critical for recovery)                        *
//*----------------------------------------------------------------*
//IEFRDER  DD DSN=IMS.LOG.INTCALC.PRIMARY,
//         DISP=(NEW,CATLG,CATLG),
//         UNIT=SYSDA,
//         SPACE=(CYL,(50,10),RLSE),
//         DCB=(RECFM=VB,LRECL=6136,BLKSIZE=6144)
//*
//IEFRDER2 DD DSN=IMS.LOG.INTCALC.SECOND,
//         DISP=(NEW,CATLG,CATLG),
//         UNIT=SYSDA,
//         SPACE=(CYL,(50,10),RLSE),
//         DCB=(RECFM=VB,LRECL=6136,BLKSIZE=6144)
//*
//*----------------------------------------------------------------*
//* VSAM BUFFER POOL DEFINITIONS                                   *
//*----------------------------------------------------------------*
//DFSVSAMP DD *
  4096,10
  IOBF=(4096,10)
  IOBF=(2048,5)
  LOCKMAX=500
/*
//*
//*----------------------------------------------------------------*
//* DATABASE DD STATEMENTS                                         *
//*----------------------------------------------------------------*
//CUSTDB   DD DSN=IMS.DB.CUSTOMER.DATA,DISP=SHR
//CUSTDBI  DD DSN=IMS.DB.CUSTOMER.INDEX,DISP=SHR
//CUSTDBO  DD DSN=IMS.DB.CUSTOMER.OVFL,DISP=SHR
//*
//*----------------------------------------------------------------*
//* APPLICATION OUTPUT FILES                                       *
//*----------------------------------------------------------------*
//RPTFILE  DD DSN=APPL.INTCALC.REPORT,
//         DISP=(NEW,CATLG,DELETE),
//         UNIT=SYSDA,
//         SPACE=(TRK,(50,10),RLSE),
//         DCB=(RECFM=FB,LRECL=132,BLKSIZE=0)
//*
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSOUT   DD SYSOUT=*

Key DD Statements Explained

DD Name Purpose
STEPLIB Contains the IMS RESLIB (IMS runtime modules) and the application load library (your compiled program).
DFSRESLB IMS resident library, used by the region controller.
IMS Concatenation of DBDLIB (database definitions) and PSBLIB (program specifications).
IEFRDER / IEFRDER2 IMS log datasets. Primary and secondary. Critical for recovery and restart.
DFSVSAMP VSAM buffer pool definitions. Controls I/O buffer sizes and counts for database access performance.
CUSTDB, CUSTDBI, CUSTDBO Database DD statements. Each physical database referenced by the PSB needs DD statements for its VSAM clusters (data, index, overflow).
RPTFILE Application-specific output file (not IMS-specific).

DFSRRC00 Return Codes

RC Meaning
0 Successful completion
4 Warning (check IMS log for details)
8 Application error
12 Severe error
16 IMS system error

Restart After Failure

To restart a failed BMP after a checkpoint:

  1. Resubmit the same JCL (the IMS log from the failed run must still exist).
  2. DFSRRC00 detects the prior checkpoint from the log.
  3. The XRST call in your program restores the saved data area.
  4. Your program resumes processing from the last checkpoint.

This is one of IMS's most powerful features for production batch processing. A job that fails at 3 AM after processing 2 million records out of 5 million does not need to reprocess those 2 million records. It restarts from the last checkpoint and processes only the remaining records.


26.14 Hierarchical Database Navigation Patterns

Full Hierarchy Traversal

A common requirement is to traverse an entire database record -- the root and all its descendants at every level. The pattern uses GU to position to the root, then nested GNP loops for each level:

      * Position to the root customer
           MOVE 'CUST000100' TO CUST-SSA-KEY
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-PCB
                                 CUSTOMER-IO-AREA
                                 CUST-QUAL-SSA
           IF CUST-STATUS-CODE NOT = SPACES
               GO TO 2000-EXIT
           END-IF

           DISPLAY 'CUSTOMER: ' CUST-ID ' - ' CUST-NAME

      *    Read all ACCOUNT children
           SET MORE-CHILDREN TO TRUE
           PERFORM UNTIL END-OF-CHILDREN
               CALL 'CBLTDLI' USING DLI-GNP
                                     CUST-PCB
                                     ACCOUNT-IO-AREA
                                     ACCT-UNQUAL-SSA
               IF CUST-STATUS-CODE = SPACES
                   DISPLAY '  ACCOUNT: ' ACCT-NUMBER
      *            For each account, read its transactions
                   PERFORM 2100-READ-TRANSACTIONS
               ELSE
                   SET END-OF-CHILDREN TO TRUE
               END-IF
           END-PERFORM

The challenge in multi-level traversal is that reading child segments at one level can affect the position at higher levels. After reading transactions under the first account, you may need to re-establish position to continue reading the next account. The code examples demonstrate this pattern in detail.

Cross-Database Operations

When your program accesses multiple databases (through multiple PCBs), each PCB maintains its own independent database position. This allows you to look up a customer in the CUSTOMER database and then find that customer's orders in a separate ORDER database without losing position in either:

      * Look up customer in CUSTOMER database
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-PCB
                                 CUSTOMER-IO-AREA
                                 CUST-QUAL-SSA

      * Look up orders in ORDER database (separate PCB)
           MOVE CUST-ID TO ORDR-SSA-CUST
           CALL 'CBLTDLI' USING DLI-GN
                                 ORDER-PCB
                                 ORDER-IO-AREA
                                 ORDR-CUST-SSA

The CUST-PCB and ORDER-PCB maintain separate positions. Calls against ORDER-PCB do not disturb the position in the CUSTOMER database.

Efficient Navigation with Path Calls

Instead of issuing multiple GU and GNP calls to navigate to a deeply nested segment, use a single GU with SSAs at each level:

      * INEFFICIENT: Three separate calls
      *   Call 1: GU CUSTOMER (root)
      *   Call 2: GNP ACCOUNT (child)
      *   Call 3: GNP TRANSACTION (grandchild)

      * EFFICIENT: Single path call
           MOVE 'CUST000100' TO CUST-D-KEY
           CALL 'CBLTDLI' USING DLI-GU
                                 CUST-PCB
                                 TRANSACTION-IO-AREA
                                 CUST-PATH-D-SSA
                                 ACCT-UNQUAL-SSA
                                 TRAN-UNQUAL-SSA

The D command code on the customer SSA tells IMS to include the customer segment in the path traversal. A single GU call navigates the entire hierarchy from root to the transaction level, reducing the number of DL/I calls and improving performance.


26.15 IMS-COBOL Integration Patterns

Pattern 1: Batch Sequential Processing

Process all records sequentially with checkpoints:

XRST (check for restart)
GN loop reading root segments
    GNP loop reading children
        Process / Update
    End GNP loop
    Checkpoint every N records
End GN loop
Final CHKP

Pattern 2: Online Inquiry (MPP)

Non-conversational inquiry transaction:

GU IO-PCB (read input message)
Parse input
GU DB-PCB (look up root segment)
GNP DB-PCB loop (read children)
ISRT IO-PCB (send each output line)
End loop
ISRT IO-PCB (send summary)
GOBACK

Pattern 3: Online Update (MPP)

Non-conversational update transaction:

GU IO-PCB (read input message)
Parse input
GHU DB-PCB (retrieve segment with hold)
Validate data
Modify non-key fields
REPL DB-PCB (update the segment)
ISRT IO-PCB (send confirmation)
GOBACK

Pattern 4: Lookup Across Databases

Cross-reference between related databases:

GU CUST-PCB (find customer)
Save CUST-ID
GN ORDER-PCB with SSA on CUST-ID (find orders)
Loop:
    GNP ORDER-PCB (read order lines)
End loop

Common Mistakes to Avoid

  1. Forgetting the hold call before REPL/DLET. Status code DJ is the telltale sign. Always use GHU/GHN/GHNP before REPL or DLET.

  2. Changing the key field before REPL. Status code DA. The key field identifies the segment's position in the hierarchy. Changing it would corrupt the database structure.

  3. Using the wrong PCB for a call. If you pass the IO PCB instead of the DB PCB, IMS interprets the call as a message operation, not a database operation. This can produce unexpected results or abends.

  4. Not checking status codes after every call. A single unchecked error can cascade through the rest of the program. Always check the status code in the PCB after every CALL 'CBLTDLI'.

  5. SSA field name mismatch. The field name in the SSA must match the field name defined in the DBD, not the COBOL field name in your program. These are frequently different (e.g., DBD field CUSTID vs. COBOL field CUST-ID).

  6. I/O area size mismatch. If your COBOL I/O area is shorter than the actual segment, data can be truncated. If it is longer, you may read garbage beyond the segment end. Match the segment definition exactly.

  7. Losing database position. After a GU call to re-position, the current position at all lower levels is reset. Be aware of how each call affects position.


26.16 Hands-On Practice with IBM Z Xplore

[IBM Enterprise COBOL] Since IMS runs exclusively on IBM z/OS, you cannot install it on a personal computer or run IMS programs under GnuCOBOL. However, IBM provides free access to a real mainframe through the IBM Z Xplore program (formerly known as IBM Z Open Education and Master the Mainframe).

Getting Started with Z Xplore

  1. Visit the IBM Z Xplore website at https://www.ibm.com/z/resources/zxplore.
  2. Create a free IBM ID if you do not already have one.
  3. Register for the Z Xplore learning paths.
  4. You will receive credentials for a real z/OS system accessible via a 3270 terminal emulator or SSH.

What You Can Practice

The Z Xplore environment includes: - TSO/ISPF for editing datasets and submitting JCL. - COBOL compiler (IBM Enterprise COBOL) for compiling programs. - IMS resources (depending on the learning path) for running DL/I programs. - JCL submission for executing batch jobs. - SDSF for viewing job output and logs.

Alternative Learning Resources

If direct IMS access is not available through Z Xplore at the time you are reading this, consider these alternatives:

  • IBM IMS documentation: The IBM Knowledge Center provides comprehensive IMS documentation including the Application Programming Guide, which covers all DL/I calls with examples.
  • IBM Redbooks: Several IBM Redbooks cover IMS programming in detail, including "IMS Primer" (SG24-5352) and "IMS Application Programming" (SC18-9698).
  • Desk-checking: You can write IMS COBOL programs on any system and desk-check them against the status code tables and call formats in this chapter. Understanding the call interface conceptually is valuable even without a running IMS system.

26.17 IMS in Modern Architectures

IMS databases do not exist in isolation. Modern enterprises connect IMS to contemporary systems through several integration technologies:

IMS Connect

IMS Connect provides TCP/IP access to IMS transactions. Java applications, web services, and REST APIs can send messages to IMS transactions through IMS Connect, allowing IMS data and business logic to participate in modern architectures without modifying the COBOL programs.

IMS Open Database

IMS Open Database allows non-COBOL applications to access IMS databases directly using standard SQL or a JDBC/ODBC interface. Java programs can issue SQL queries against IMS hierarchical databases through the IMS Universal Drivers.

IMS and MQ

IBM MQ (formerly WebSphere MQ) can queue messages for IMS transactions, enabling asynchronous integration with other systems. A web application can place a message on an MQ queue, and IMS picks it up for processing -- decoupling the front-end from the back-end.

IMS and DB2

Many enterprises maintain both IMS and DB2 databases. A single COBOL program can access both -- using DL/I calls for IMS and EXEC SQL for DB2 -- within the same transaction. This is common in banks where the core deposit system is on IMS but regulatory reporting goes through DB2.


What You Have Learned

This chapter covered IMS database and transaction management from the COBOL programmer's perspective. Here is a summary of the key concepts:

The Hierarchical Data Model: - IMS stores data in tree structures (hierarchies) where each segment has one parent and may have multiple children. - The root segment sits at the top. Child segments depend on their parents and cannot exist independently. - A database record is one root segment together with all its descendants. - IMS traverses hierarchies in depth-first, left-to-right order (hierarchical sequence).

The DL/I Call Interface: - COBOL programs communicate with IMS through CALL 'CBLTDLI' -- the DL/I call interface. - Every call takes a function code, a PCB mask, an I/O area, and optional Segment Search Arguments (SSAs). - Function codes are 4-byte values: GU, GN, GNP, GHU, GHN, GHNP, ISRT, REPL, DLET, CHKP, XRST.

PCBs and PSBs: - The PSB defines a program's authorized view of IMS databases. - Each PCB represents one database view or the IO PCB for message/system calls. - PCBs are received through the PROCEDURE DIVISION USING clause, with the IO PCB always first. - The status code in the PCB tells you the result of every DL/I call.

Segment Search Arguments (SSAs): - Unqualified SSAs specify a segment type name only (9 bytes). - Qualified SSAs add search conditions with field names, operators, and values. - Boolean SSAs combine conditions with AND (*) or OR (+). - Command codes (D, F, L, N, P, U) modify call behavior for path calls, first/last access, and position management.

Database Calls: - GU (Get Unique): Direct access by key -- random access to any segment. - GN (Get Next): Sequential forward retrieval in hierarchical sequence. - GNP (Get Next within Parent): Retrieves children within a parent scope. - GHU/GHN/GHNP: Hold variants that lock the segment for subsequent update or delete. - ISRT: Inserts a new segment. Root segments need an unqualified SSA. Child segments need parent path SSAs. - REPL: Updates a held segment. Must not change the key field. - DLET: Deletes a held segment and all its descendants (cascade delete).

Status Codes: - Spaces = success. GE = not found. GB = end of database. II = duplicate on insert. - DA = key field changed. DJ = no prior hold call. QC = no more messages. - Always check the status code after every DL/I call.

IMS Transaction Manager (IMS TM): - IMS TM manages online transaction processing with terminals, message queues, and program scheduling. - MPP (Message Processing Program) processes messages from the queue. - GU IO-PCB reads input messages. ISRT IO-PCB sends output messages. - MPPs loop until status code QC indicates no more messages.

MPP vs. BMP Regions: - MPP: Online, short-running, processes messages from the queue. - BMP: Batch, long-running, accesses IMS databases while the online system runs. - Batch DL/I: Batch with exclusive database access (online system not running).

Checkpoint/Restart: - CHKP commits database changes and saves application state for recovery. - XRST at program start checks for a prior checkpoint and restores state on restart. - Checkpoint intervals of 500-5,000 records balance recovery time and overhead. - Restart resubmits the same JCL; IMS and XRST handle repositioning automatically.

JCL for IMS Batch: - DFSRRC00 is the IMS region controller invoked by JCL. - The PARM field specifies region type, program name, PSB name, and processing options. - DD statements include STEPLIB, DFSRESLB, IMS (DBDLIB/PSBLIB), IEFRDER (log), DFSVSAMP (buffers), and database datasets.

IMS-COBOL Integration Patterns: - Sequential batch processing: XRST, GN loop, periodic CHKP, final CHKP. - Online inquiry: GU IO-PCB, GU DB-PCB, GNP loop, ISRT IO-PCB. - Online update: GU IO-PCB, GHU DB-PCB, modify, REPL, ISRT IO-PCB. - Cross-database operations use separate PCBs with independent positions.

In the next chapter, we will explore additional enterprise data access technologies that complement the IMS, DB2, and CICS skills you have built throughout Part V of this book.