Case Study 1: Customer Account Hierarchy in IMS

Background

First National Federal Bank has served the mid-Atlantic region for over sixty years, processing millions of transactions daily across checking, savings, mortgage, and investment accounts. The bank's core customer data resides in an IMS (Information Management System) hierarchical database that was designed in 1978 and has been continuously refined. The database models the natural hierarchy of banking relationships: a customer owns one or more accounts, and each account contains a history of transactions.

In early 2025, senior systems programmer Raymond Okafor was tasked with building a new customer inquiry program. Branch tellers needed a consolidated view of a customer's entire relationship with the bank -- every account and the most recent transactions on each account -- displayed on a single CICS screen. The back-end COBOL program would navigate the IMS hierarchy using DL/I (Data Language/I) calls, retrieve the necessary segments, and format the data for presentation.

This case study examines how Raymond designed the IMS database structure, defined the Program Communication Block (PCB) masks in COBOL, and coded the DL/I calls to navigate the customer-account-transaction hierarchy.

The IMS Database Structure

The IMS database, named CUSTDB, uses a simple three-level hierarchy:

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

Each segment type has a fixed layout:

  • CUSTOMER (root): Contains customer ID, name, address, phone, and relationship date. The customer ID is the sequence field.
  • ACCOUNT: Contains account number, account type (CHK, SAV, MTG, INV), status (ACTIVE, CLOSED, FROZEN), current balance, and date opened. The account number is the sequence field within each customer occurrence.
  • TRANSACTION: Contains transaction ID, date, type (DEP, WDR, TFR, PMT, INT), amount, running balance, and description. The transaction ID is the sequence field within each account occurrence.

The Database Description (DBD) defines these segments and their relationships. In production, the DBD is generated by the DBA team and assembled into the IMS catalog. The COBOL programmer does not code the DBD but must understand its structure to write correct DL/I calls.

The Program Specification Block (PSB)

Before a COBOL program can access an IMS database, a PSB must be defined. The PSB specifies which segments the program is authorized to access and what operations (Get, Insert, Replace, Delete) are permitted. Raymond's inquiry program needed read-only access to all three segment types:

    PCB  TYPE=DB,DBDNAME=CUSTDB,PROCOPT=G,KEYLEN=25
    SENSEG NAME=CUSTOMER,PARENT=0
    SENSEG NAME=ACCOUNT,PARENT=CUSTOMER
    SENSEG NAME=TRANSACT,PARENT=ACCOUNT

The PROCOPT=G restricts the program to Get operations only -- no updates, inserts, or deletes. This is appropriate for an inquiry program and provides a safety net against accidental data modification.

COBOL Program: PCB Mask and Segment Layouts

The heart of any IMS COBOL program is the linkage between the program and IMS, established through the PCB mask and the ENTRY statement. Raymond defined the following structures:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CUSTINQ1.
      *================================================================*
      * CUSTINQ1 - Customer Account Inquiry Program                    *
      * Navigates the CUSTDB IMS hierarchy to retrieve a customer's    *
      * complete relationship: all accounts and recent transactions.   *
      *================================================================*

       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.

       DATA DIVISION.
       WORKING-STORAGE SECTION.

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

      *================================================================*
      * Status code evaluation fields                                  *
      *================================================================*
       01  WS-GOOD-STATUS       PIC XX VALUE SPACES.
       01  WS-NOT-FOUND         PIC XX VALUE 'GE'.
       01  WS-END-OF-PARENT     PIC XX VALUE 'GE'.
       01  WS-END-OF-DB         PIC XX VALUE 'GB'.

      *================================================================*
      * Customer segment I/O area                                      *
      *================================================================*
       01  WS-CUSTOMER-SEG.
           05 WS-CUST-ID            PIC X(10).
           05 WS-CUST-LAST-NAME     PIC X(25).
           05 WS-CUST-FIRST-NAME    PIC X(20).
           05 WS-CUST-MIDDLE-INIT   PIC X(1).
           05 WS-CUST-ADDR-LINE1    PIC X(30).
           05 WS-CUST-ADDR-LINE2    PIC X(30).
           05 WS-CUST-CITY          PIC X(20).
           05 WS-CUST-STATE         PIC X(2).
           05 WS-CUST-ZIP           PIC X(10).
           05 WS-CUST-PHONE         PIC X(15).
           05 WS-CUST-REL-DATE      PIC X(10).
           05 WS-CUST-TIER          PIC X(2).
           05 FILLER                PIC X(25).

      *================================================================*
      * Account segment I/O area                                       *
      *================================================================*
       01  WS-ACCOUNT-SEG.
           05 WS-ACCT-NUMBER        PIC X(12).
           05 WS-ACCT-TYPE          PIC X(3).
           05 WS-ACCT-STATUS        PIC X(8).
           05 WS-ACCT-BALANCE       PIC S9(11)V99 COMP-3.
           05 WS-ACCT-OPEN-DATE     PIC X(10).
           05 WS-ACCT-LAST-ACTIVITY PIC X(10).
           05 WS-ACCT-BRANCH        PIC X(4).
           05 FILLER                PIC X(20).

      *================================================================*
      * Transaction segment I/O area                                   *
      *================================================================*
       01  WS-TRANSACT-SEG.
           05 WS-TXN-ID             PIC X(15).
           05 WS-TXN-DATE           PIC X(10).
           05 WS-TXN-TYPE           PIC X(3).
           05 WS-TXN-AMOUNT         PIC S9(9)V99 COMP-3.
           05 WS-TXN-RUN-BALANCE    PIC S9(11)V99 COMP-3.
           05 WS-TXN-DESC           PIC X(30).
           05 FILLER                PIC X(10).

      *================================================================*
      * Segment Search Arguments (SSAs)                                *
      *================================================================*
       01  WS-CUST-QUAL-SSA.
           05 FILLER                PIC X(9)  VALUE 'CUSTOMER('.
           05 FILLER                PIC X(10) VALUE 'CUST_ID  ='.
           05 WS-SSA-CUST-ID       PIC X(10).
           05 FILLER                PIC X(1)  VALUE ')'.

       01  WS-ACCT-UNQUAL-SSA.
           05 FILLER                PIC X(9)  VALUE 'ACCOUNT  '.

       01  WS-TXN-UNQUAL-SSA.
           05 FILLER                PIC X(9)  VALUE 'TRANSACT '.

      *================================================================*
      * Program control fields                                         *
      *================================================================*
       01  WS-INPUT-CUST-ID         PIC X(10).
       01  WS-ACCT-COUNT            PIC 9(3)  VALUE ZEROS.
       01  WS-TXN-COUNT             PIC 9(5)  VALUE ZEROS.
       01  WS-TOTAL-BALANCE         PIC S9(13)V99 VALUE ZEROS.
       01  WS-MAX-TXN-PER-ACCT      PIC 9(3)  VALUE 10.
       01  WS-TXN-DISPLAY-COUNT     PIC 9(3)  VALUE ZEROS.
       01  WS-MORE-ACCOUNTS         PIC X     VALUE 'Y'.
           88 NO-MORE-ACCOUNTS                VALUE 'N'.
       01  WS-MORE-TRANSACTIONS     PIC X     VALUE 'Y'.
           88 NO-MORE-TRANSACTIONS            VALUE 'N'.
       01  WS-ERROR-FLAG            PIC X     VALUE 'N'.
           88 PROCESSING-ERROR                VALUE 'Y'.
       01  WS-ERROR-MSG             PIC X(80) VALUE SPACES.
       01  WS-BALANCE-EDITED        PIC $$$,$$$,$$$,$$9.99-.
       01  WS-AMOUNT-EDITED         PIC $$$$,$$$,$$9.99-.

      *================================================================*
      * PCB Mask - defined in LINKAGE SECTION                          *
      *================================================================*
       LINKAGE SECTION.

       01  LS-PCB-MASK.
           05 LS-DBD-NAME           PIC X(8).
           05 LS-SEG-LEVEL          PIC XX.
           05 LS-STATUS-CODE        PIC XX.
           05 LS-PROC-OPTIONS       PIC X(4).
           05 LS-RESERVED           PIC S9(5) COMP.
           05 LS-SEG-NAME           PIC X(8).
           05 LS-KEY-LENGTH         PIC S9(5) COMP.
           05 LS-NUM-SENS-SEGS      PIC S9(5) COMP.
           05 LS-KEY-FEEDBACK       PIC X(25).

      *================================================================*
      * PROCEDURE DIVISION with IMS entry point                        *
      *================================================================*
       PROCEDURE DIVISION USING LS-PCB-MASK.

       0000-MAIN-CONTROL.
           PERFORM 1000-INITIALIZE
           PERFORM 2000-RETRIEVE-CUSTOMER
           IF NOT PROCESSING-ERROR
               PERFORM 3000-RETRIEVE-ACCOUNTS
           END-IF
           PERFORM 9000-WRAP-UP
           GOBACK.

      *================================================================*
      * 1000-INITIALIZE: Set up program variables and accept input.    *
      *================================================================*
       1000-INITIALIZE.
           MOVE ZEROS TO WS-ACCT-COUNT
           MOVE ZEROS TO WS-TXN-COUNT
           MOVE ZEROS TO WS-TOTAL-BALANCE
           MOVE 'N' TO WS-ERROR-FLAG
           MOVE 'Y' TO WS-MORE-ACCOUNTS

      *    In a CICS environment, the customer ID would come from
      *    the terminal input. Here we accept it for batch testing.
           ACCEPT WS-INPUT-CUST-ID FROM SYSIN

           DISPLAY '============================================='
           DISPLAY ' CUSTOMER RELATIONSHIP INQUIRY'
           DISPLAY ' Searching for Customer: ' WS-INPUT-CUST-ID
           DISPLAY '============================================='
           .

      *================================================================*
      * 2000-RETRIEVE-CUSTOMER: Issue GU call with qualified SSA to    *
      * position directly on the target customer segment.              *
      *================================================================*
       2000-RETRIEVE-CUSTOMER.
           MOVE WS-INPUT-CUST-ID TO WS-SSA-CUST-ID

           CALL 'CBLTDLI' USING WS-DLI-GU
                                 LS-PCB-MASK
                                 WS-CUSTOMER-SEG
                                 WS-CUST-QUAL-SSA

           EVALUATE LS-STATUS-CODE
               WHEN WS-GOOD-STATUS
                   PERFORM 2100-DISPLAY-CUSTOMER
               WHEN WS-NOT-FOUND
                   MOVE 'Y' TO WS-ERROR-FLAG
                   STRING 'Customer ' WS-INPUT-CUST-ID
                       ' not found in database.'
                       DELIMITED SIZE INTO WS-ERROR-MSG
                   DISPLAY WS-ERROR-MSG
               WHEN OTHER
                   MOVE 'Y' TO WS-ERROR-FLAG
                   STRING 'Unexpected DL/I status: '
                       LS-STATUS-CODE
                       ' on GU CUSTOMER call.'
                       DELIMITED SIZE INTO WS-ERROR-MSG
                   DISPLAY WS-ERROR-MSG
                   PERFORM 8000-DLI-ERROR-HANDLER
           END-EVALUATE
           .

      *================================================================*
      * 2100-DISPLAY-CUSTOMER: Format and display customer details.    *
      *================================================================*
       2100-DISPLAY-CUSTOMER.
           DISPLAY ' '
           DISPLAY ' CUSTOMER INFORMATION'
           DISPLAY ' --------------------'
           DISPLAY '   Customer ID:   ' WS-CUST-ID
           DISPLAY '   Name:          '
               WS-CUST-FIRST-NAME ' '
               WS-CUST-MIDDLE-INIT '. '
               WS-CUST-LAST-NAME
           DISPLAY '   Address:       ' WS-CUST-ADDR-LINE1
           IF WS-CUST-ADDR-LINE2 NOT = SPACES
               DISPLAY '                  ' WS-CUST-ADDR-LINE2
           END-IF
           DISPLAY '                  '
               WS-CUST-CITY ', ' WS-CUST-STATE ' '
               WS-CUST-ZIP
           DISPLAY '   Phone:         ' WS-CUST-PHONE
           DISPLAY '   Member Since:  ' WS-CUST-REL-DATE
           DISPLAY '   Tier:          ' WS-CUST-TIER
           .

      *================================================================*
      * 3000-RETRIEVE-ACCOUNTS: Use GNP to retrieve all account        *
      * segments under the current customer. For each account, also    *
      * retrieve recent transactions.                                  *
      *================================================================*
       3000-RETRIEVE-ACCOUNTS.
           DISPLAY ' '
           DISPLAY ' ACCOUNTS ON FILE'
           DISPLAY ' ================'

           MOVE 'Y' TO WS-MORE-ACCOUNTS

           PERFORM 3100-GET-NEXT-ACCOUNT

           PERFORM UNTIL NO-MORE-ACCOUNTS
               ADD 1 TO WS-ACCT-COUNT
               PERFORM 3200-DISPLAY-ACCOUNT
               ADD WS-ACCT-BALANCE TO WS-TOTAL-BALANCE
               PERFORM 4000-RETRIEVE-TRANSACTIONS
               PERFORM 3100-GET-NEXT-ACCOUNT
           END-PERFORM

           PERFORM 3300-DISPLAY-ACCOUNT-SUMMARY
           .

      *================================================================*
      * 3100-GET-NEXT-ACCOUNT: Issue GNP call to get the next          *
      * account segment under the established customer parent.         *
      * GNP (Get Next within Parent) ensures we stay within the        *
      * current customer's subtree.                                    *
      *================================================================*
       3100-GET-NEXT-ACCOUNT.
           CALL 'CBLTDLI' USING WS-DLI-GNP
                                 LS-PCB-MASK
                                 WS-ACCOUNT-SEG
                                 WS-ACCT-UNQUAL-SSA

           EVALUATE LS-STATUS-CODE
               WHEN WS-GOOD-STATUS
                   CONTINUE
               WHEN 'GE'
                   MOVE 'N' TO WS-MORE-ACCOUNTS
               WHEN OTHER
                   MOVE 'N' TO WS-MORE-ACCOUNTS
                   MOVE 'Y' TO WS-ERROR-FLAG
                   STRING 'DL/I error ' LS-STATUS-CODE
                       ' on GNP ACCOUNT call.'
                       DELIMITED SIZE INTO WS-ERROR-MSG
                   DISPLAY WS-ERROR-MSG
                   PERFORM 8000-DLI-ERROR-HANDLER
           END-EVALUATE
           .

      *================================================================*
      * 3200-DISPLAY-ACCOUNT: Format and display account information.  *
      *================================================================*
       3200-DISPLAY-ACCOUNT.
           MOVE WS-ACCT-BALANCE TO WS-BALANCE-EDITED
           DISPLAY ' '
           DISPLAY '   Account #' WS-ACCT-COUNT ': '
               WS-ACCT-NUMBER
           DISPLAY '     Type:            '
               WS-ACCT-TYPE
           DISPLAY '     Status:          '
               WS-ACCT-STATUS
           DISPLAY '     Current Balance: '
               WS-BALANCE-EDITED
           DISPLAY '     Opened:          '
               WS-ACCT-OPEN-DATE
           DISPLAY '     Last Activity:   '
               WS-ACCT-LAST-ACTIVITY
           DISPLAY '     Branch:          '
               WS-ACCT-BRANCH
           .

      *================================================================*
      * 3300-DISPLAY-ACCOUNT-SUMMARY: Show total accounts and          *
      * combined balance across all accounts.                          *
      *================================================================*
       3300-DISPLAY-ACCOUNT-SUMMARY.
           MOVE WS-TOTAL-BALANCE TO WS-BALANCE-EDITED
           DISPLAY ' '
           DISPLAY ' ================'
           DISPLAY ' RELATIONSHIP SUMMARY'
           DISPLAY '   Total Accounts:      ' WS-ACCT-COUNT
           DISPLAY '   Combined Balance:    ' WS-BALANCE-EDITED
           DISPLAY '   Total Transactions:  ' WS-TXN-COUNT
           DISPLAY ' ================'
           .

      *================================================================*
      * 4000-RETRIEVE-TRANSACTIONS: Use GNP to retrieve transaction   *
      * segments under the current account. Limits display to the     *
      * most recent N transactions (WS-MAX-TXN-PER-ACCT).            *
      *================================================================*
       4000-RETRIEVE-TRANSACTIONS.
           DISPLAY '     Recent Transactions:'
           DISPLAY '     DATE       TYPE   AMOUNT'
               '         BALANCE        DESCRIPTION'
           DISPLAY '     ---------- ---- ------------'
               ' -------------- ---------------------'

           MOVE 'Y' TO WS-MORE-TRANSACTIONS
           MOVE ZEROS TO WS-TXN-DISPLAY-COUNT

           PERFORM 4100-GET-NEXT-TRANSACTION

           PERFORM UNTIL NO-MORE-TRANSACTIONS
               OR WS-TXN-DISPLAY-COUNT >= WS-MAX-TXN-PER-ACCT
               ADD 1 TO WS-TXN-COUNT
               ADD 1 TO WS-TXN-DISPLAY-COUNT
               PERFORM 4200-DISPLAY-TRANSACTION
               PERFORM 4100-GET-NEXT-TRANSACTION
           END-PERFORM

           IF WS-TXN-DISPLAY-COUNT = ZEROS
               DISPLAY '     (No transactions on file)'
           END-IF
           .

      *================================================================*
      * 4100-GET-NEXT-TRANSACTION: Issue GNP to get the next           *
      * transaction under the current account parent.                  *
      *================================================================*
       4100-GET-NEXT-TRANSACTION.
           CALL 'CBLTDLI' USING WS-DLI-GNP
                                 LS-PCB-MASK
                                 WS-TRANSACT-SEG
                                 WS-TXN-UNQUAL-SSA

           EVALUATE LS-STATUS-CODE
               WHEN WS-GOOD-STATUS
                   CONTINUE
               WHEN 'GE'
                   MOVE 'N' TO WS-MORE-TRANSACTIONS
               WHEN OTHER
                   MOVE 'N' TO WS-MORE-TRANSACTIONS
                   MOVE 'Y' TO WS-ERROR-FLAG
                   STRING 'DL/I error ' LS-STATUS-CODE
                       ' on GNP TRANSACT call.'
                       DELIMITED SIZE INTO WS-ERROR-MSG
                   DISPLAY WS-ERROR-MSG
                   PERFORM 8000-DLI-ERROR-HANDLER
           END-EVALUATE
           .

      *================================================================*
      * 4200-DISPLAY-TRANSACTION: Format and display one transaction.  *
      *================================================================*
       4200-DISPLAY-TRANSACTION.
           MOVE WS-TXN-AMOUNT TO WS-AMOUNT-EDITED
           MOVE WS-TXN-RUN-BALANCE TO WS-BALANCE-EDITED
           DISPLAY '     '
               WS-TXN-DATE ' '
               WS-TXN-TYPE '  '
               WS-AMOUNT-EDITED ' '
               WS-BALANCE-EDITED ' '
               WS-TXN-DESC
           .

      *================================================================*
      * 8000-DLI-ERROR-HANDLER: Centralized error handling for         *
      * unexpected DL/I status codes. Logs diagnostic information.     *
      *================================================================*
       8000-DLI-ERROR-HANDLER.
           DISPLAY '*** DL/I ERROR DIAGNOSTIC ***'
           DISPLAY '  DBD Name:        ' LS-DBD-NAME
           DISPLAY '  Segment Level:   ' LS-SEG-LEVEL
           DISPLAY '  Status Code:     ' LS-STATUS-CODE
           DISPLAY '  Segment Name:    ' LS-SEG-NAME
           DISPLAY '  Key Feedback:    ' LS-KEY-FEEDBACK
           DISPLAY '*** END DIAGNOSTIC ***'
           .

      *================================================================*
      * 9000-WRAP-UP: Final processing.                                *
      *================================================================*
       9000-WRAP-UP.
           IF PROCESSING-ERROR
               DISPLAY ' '
               DISPLAY '*** INQUIRY COMPLETED WITH ERRORS ***'
               DISPLAY '  ' WS-ERROR-MSG
           ELSE
               DISPLAY ' '
               DISPLAY '*** INQUIRY COMPLETED SUCCESSFULLY ***'
           END-IF
           .

Solution Walkthrough

Step 1: Understanding the DL/I Call Structure

Every DL/I call in COBOL follows the same pattern:

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

The four components are:

  1. Function code: A 4-byte field specifying the operation (GU, GN, GNP, ISRT, REPL, DLET).
  2. PCB mask: The Program Communication Block defined in the LINKAGE SECTION, through which IMS returns status information.
  3. I/O area: A WORKING-STORAGE record where IMS places the retrieved segment data (on Get calls) or from which IMS reads the data to store (on Insert/Replace calls).
  4. SSA (Segment Search Argument): Specifies which segment type to operate on, and optionally a qualification (key value match).

Step 2: The GU Call for Direct Access

The program begins by issuing a GU (Get Unique) call to position directly on the target customer:

       CALL 'CBLTDLI' USING WS-DLI-GU
                             LS-PCB-MASK
                             WS-CUSTOMER-SEG
                             WS-CUST-QUAL-SSA

The qualified SSA CUSTOMER(CUST_ID =0000012345) tells IMS to search the database for the customer segment whose CUST_ID field matches the specified value. This is a direct, random access operation -- IMS uses its internal index to locate the segment without scanning sequentially.

After the call, the program checks LS-STATUS-CODE: - Spaces (blank): The segment was found and placed in WS-CUSTOMER-SEG. - GE: No segment matching the qualification was found. - Any other value: An unexpected error occurred and must be logged.

Step 3: GNP Calls for Dependent Segments

After establishing position on the customer segment, the program uses GNP (Get Next within Parent) to retrieve dependent segments. The critical distinction between GN and GNP is:

  • GN (Get Next): Moves forward through the entire database. If you reach the last child of a parent, GN will move to the next root segment -- crossing parent boundaries.
  • GNP (Get Next within Parent): Moves forward only within the children of the established parent. When there are no more children, IMS returns status code GE instead of crossing to another parent.

For the account retrieval, the parent is the customer established by the GU call:

       CALL 'CBLTDLI' USING WS-DLI-GNP
                             LS-PCB-MASK
                             WS-ACCOUNT-SEG
                             WS-ACCT-UNQUAL-SSA

The unqualified SSA ACCOUNT (padded with spaces to 9 bytes) tells IMS to retrieve the next ACCOUNT segment under the current parent, regardless of its key value. Each successive GNP call retrieves the next account until GE is returned.

For transactions, the parent context shifts to the current account. IMS maintains a position at each level of the hierarchy. When a GNP retrieves an ACCOUNT segment, that account becomes the established parent for TRANSACT segments. Subsequent GNP calls with the TRANSACT SSA retrieve only transactions belonging to that specific account.

Step 4: Status Code Handling

Raymond implemented an EVALUATE structure for status code checking, which is the recommended pattern in production IMS programs:

       EVALUATE LS-STATUS-CODE
           WHEN WS-GOOD-STATUS
               CONTINUE
           WHEN 'GE'
               MOVE 'N' TO WS-MORE-ACCOUNTS
           WHEN OTHER
               PERFORM 8000-DLI-ERROR-HANDLER
       END-EVALUATE

The WHEN OTHER clause is essential. Status codes such as AI (segment I/O area problem), AK (invalid SSA), or AD (function code error) indicate programming errors and must be caught immediately. In production, the error handler would write to a log dataset, issue a WTO (Write to Operator) message, and potentially call the IMS ROLB (Rollback) function to undo any partial updates.

Step 5: The PCB Mask as Diagnostic Tool

The PCB mask is not merely a parameter to DL/I calls -- it is a rich diagnostic resource. After every call, IMS updates the PCB mask with:

  • LS-DBD-NAME: Confirms which database was accessed.
  • LS-SEG-LEVEL: The hierarchical level of the last segment accessed (01 for root, 02 for first child level, etc.).
  • LS-STATUS-CODE: The result of the operation.
  • LS-SEG-NAME: The name of the last segment type accessed.
  • LS-KEY-FEEDBACK: The concatenated key of the current position in the database. For the CUSTDB hierarchy, this would contain the customer ID followed by the account number followed by the transaction ID, showing exactly where IMS is positioned.

Raymond's error handler displays all of these fields, giving support staff the information they need to diagnose problems without requiring a dump analysis.

Key Design Decisions

Why GNP Instead of Qualified GN

Raymond chose unqualified GNP calls for accounts and transactions rather than qualified GN calls. The alternative would have been to retrieve all account numbers first, then issue qualified GU calls for each. The GNP approach is superior because:

  1. Fewer calls: GNP sequentially retrieves each child with one call per segment. The GU approach would require an extra retrieval step to get the account list.
  2. Natural hierarchy: GNP follows the IMS hierarchy naturally, making the code self-documenting.
  3. Performance: Sequential access within a parent is the fastest path in IMS. Each GNP typically requires zero or one physical I/O because dependent segments are stored physically near their parent.

Why a Transaction Limit

The program limits transaction display to ten per account (WS-MAX-TXN-PER-ACCT). Some accounts have thousands of historical transactions. Retrieving all of them for a screen inquiry would be wasteful and slow. The limit is a configurable field that could be driven by user preference or screen capacity.

Why GOBACK Instead of STOP RUN

In an IMS environment, the program must return control to IMS rather than terminating the region. GOBACK returns control to the calling program or to IMS. STOP RUN would abnormally terminate the IMS region, which is a serious operational problem. Raymond emphasized this distinction in his team's coding standards.

Common Pitfalls in IMS COBOL Programming

  1. Forgetting to check status codes: Every DL/I call must be followed by a status code check. A missing check can cause the program to process garbage data from a failed retrieval.

  2. Confusing GN with GNP: Using GN when GNP is intended causes the program to cross parent boundaries, retrieving segments belonging to other customers.

  3. SSA formatting errors: SSAs must be exactly 9 bytes for the segment name (padded with spaces), and qualified SSAs must follow precise formatting rules. A misplaced parenthesis or incorrect field name produces status code AK.

  4. I/O area size mismatches: The COBOL I/O area must be at least as large as the largest segment that will be retrieved into it. An undersized I/O area causes storage overlays.

  5. Using STOP RUN in IMS programs: As noted above, STOP RUN terminates the IMS region. Always use GOBACK.

Discussion Questions

  1. The GU call with a qualified SSA provides direct access to a specific customer. What happens to database positioning if the GU call returns status code GE (not found)? Can the program issue GNP calls after a failed GU? Why or why not?

  2. In the current design, the program retrieves all accounts sequentially using GNP. How would you modify the program to retrieve only active accounts (those with WS-ACCT-STATUS = 'ACTIVE')? What type of SSA would you use, and what would it look like?

  3. The PCB mask uses PROCOPT=G (read only). If the program needed to update a customer's phone number during the inquiry, what changes would be needed to the PSB, the PCB mask, and the COBOL code?

  4. Compare the IMS hierarchical model used in this case study with a relational database approach. What are the advantages of the hierarchical model for this specific use case (customer-account-transaction)? What are the disadvantages?

  5. The error handler displays diagnostic information to the console. In a production CICS environment, console output is not appropriate. How would you redesign the error handling for a production transaction processing environment? Consider logging, operator notification, and user-facing error messages.

  6. If the bank added a new segment type, BENEFICIARY, as a child of ACCOUNT (sibling to TRANSACTION), what changes would be required in the PSB, the PCB mask, the SSAs, and the program logic? Would existing GNP calls for transactions still work correctly without modification?