How to use copybooks for COBOL programm using CICS and DB2?

Summary

A developer building a CICS/DB2 application in COBOL encountered program length issues and compilation failures when attempting to modularize code using copybooks. The core issue stems from a misunderstanding of the precompilation order of operations. Because DB2 SQL (via EXEC SQL) must be preprocessed into standard COBOL before the COBOL compiler can process it, and because EXEC CICS also requires preprocessing, attempting to include complex logic containing these statements via standard COPY statements during the COBOL compilation phase results in syntax errors or unprocessed code. The solution is not to copy code containing EXEC statements directly into PROCEDURE DIVISION paragraphs, but rather to structure the code as separate subprograms (CICS pseudo-conversational programs or COBOL subroutines) or to use COPY only for non-procedural definitions (constants, data structures) while including specific include statements for CICS/DB2 processing within the program body.

Root Cause

The root cause is the linear dependency chain of IBM z/OS precompilers. The user’s JCL flows through a strict pipeline:

  1. DB2 Preprocessor (DSNHPC): Scans for EXEC SQL and translates it into API calls.
  2. CICS Translator (DFHECP1$): Scans for EXEC CICS and translates it into API calls.
  3. COBOL Compiler (IGYCRCTL): Compiles the resulting standard COBOL.

When the user attempted to COPY a paragraph containing EXEC CICS or EXEC SQL statements:

  • If COPY is used during COBOL compilation: The DB2 and CICS statements arrive at the COBOL compiler unprocessed. The COBOL compiler does not understand EXEC SQL or EXEC CICS and throws syntax errors.
  • If COPY is used within the JCL SYSIN: The precompilers generally process the input stream linearly. If the copybook contains complex logic without the proper context (linkage section, working storage, specific compiler directives), it creates fragmentation.

Why This Happens in Real Systems

In large mainframe environments, monolithic programs are a common technical debt scenario. Developers naturally try to refactor long programs by moving paragraphs to copybooks. This fails in CICS/DB2 programs because:

  • Procedural Coupling: CICS and DB2 interactions are tightly coupled to the specific transaction context (Commarea, Storage, Cursors).
  • Precompiler Limitations: Precompilers are text substitution engines. They do not handle “Object-Oriented” or modular encapsulation of procedural logic via simple copybooks.
  • The “Glue” Logic: A paragraph containing EXEC CICS RECEIVE and EXEC SQL SELECT requires the LINKAGE SECTION and WORKING-STORAGE SECTION to be aware of the data definitions. Copying raw logic without the surrounding data definitions causes compilation failure.

Real-World Impact

  • Technical Debt: Programs bloat into thousands of lines, becoming “black boxes” that are difficult to maintain.
  • Compilation Errors: Developers waste hours debugging IGY-PSxxxx syntax errors because the compiler sees EXEC CICS instead of the translated code.
  • Deployment Complexity: Improper modularization leads to “Copybook Hell,” where changing a single copybook requires a full recompile of all dependent programs, even if the logic change was minor.
  • Maintenance Risk: Long programs increase the risk of introducing bugs during updates due to the difficulty of understanding flow control.

Example or Code

The user’s JCL is correct for a single module. To achieve modularity (the user’s goal), they must use COBOL Call Statements or CICS Link Commands.

Scenario: Moving EXEC SQL SELECT logic to a subprogram.

Instead of trying to COPY a paragraph like this:

* DANGEROUS: Do not put this in a copybook called directly
       SELECT-EMPLOYEE.
           EXEC SQL
               SELECT EMP_NAME, EMP_SALARY
               INTO :WS-NAME, :WS-SALARY
               FROM EMPLOYEE
               WHERE EMP_ID = :WS-ID
           END-EXEC.

You create a separate COBOL program (e.g., GETEMPL), and call it.

The Subprogram (GETEMPL):

IDENTIFICATION DIVISION.
       PROGRAM-ID. GETEMPL.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
           EXEC SQL INCLUDE SQLCA END-EXEC.
           EXEC SQL INCLUDE EMPREC END-EXEC.
       LINKAGE SECTION.
       01  LS-EMP-ID             PIC 9(9).
       01  LS-EMP-NAME           PIC X(50).
       PROCEDURE DIVISION USING LS-EMP-ID LS-EMP-NAME.
           MOVE LS-EMP-ID TO WS-EMP-ID.
           EXEC SQL
               SELECT EMP_NAME INTO :WS-EMP-NAME
               FROM EMPLOYEE
               WHERE EMP_ID = :WS-EMP-ID
           END-EXEC.
           MOVE WS-EMP-NAME TO LS-EMP-NAME.
           GOBACK.

The Main Program (Calling it):

PROCEDURE DIVISION.
           MOVE '12345' TO WS-EMP-ID.
           CALL 'GETEMPL' USING WS-EMP-ID WS-EMP-NAME.

How Senior Engineers Fix It

Senior engineers enforce separation of concerns through architectural patterns:

  1. Service Programs (COBOL Subprograms):

    • Move DB2-heavy logic (CRUD operations) into stateless COBOL subprograms.
    • These subprograms handle the EXEC SQL and return standard COBOL data structures.
    • The main CICS program calls these subprograms using the CALL statement.
  2. CICS Pseudo-Conversational Design:

    • If the logic is CICS-specific (e.g., BMS mapping, queueing), create a separate CICS transaction program.
    • Use LINK or XCTL to transfer control between screens/logic flows.
  3. Proper Use of Copybooks (The “Right” Way):

    • Use COPY exclusively for:
      • Data Structures: COPY EMPREC. (SQLCA, DCLGENS).
      • Constants: COPY DFHBMSCA. (CICS BMS constants).
      • Paragraph Headers: If you must use copybooks for code, the included code must be standard COBOL only, meaning it must not contain unprocessed EXEC blocks. However, this is rarely the correct approach for logic.
  4. JCL Optimization:

    • Ensure the COPY libraries are added to the SYSLIB concatenation in the COBOL Compiler step (as you have done), but the source inside those copybooks must be compilable COBOL (i.e., the EXEC statements should have been preprocessed before the compiler sees them, or they shouldn’t be there).

Why Juniors Miss It

  • Lack of Precompiler Knowledge: Juniors often treat COBOL like a modern language where include works universally. They fail to realize that EXEC CICS and EXEC SQL are not keywords of the COBOL compiler; they are directives for external tools that run before the compiler.
  • “Copy and Paste” Mentality: It seems logical: “This code is long, I’ll put it in a file and include it.” They do not realize that in the mainframe toolchain, COPY is a text-inclusion command that happens at a specific stage in the build pipeline.
  • Fear of Changing Program Structure: It is often easier to try to hack a copybook than to refactor a monolith into a calling structure, which requires understanding Linkage Sections and program interfaces.
  • Misunderstanding “Reusability”: They confuse “code reuse” (copying text) with “logical reuse” (calling a subroutine). In mainframe engineering, calling a subprogram is the standard path for reusable logic.