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:
- DB2 Preprocessor (DSNHPC): Scans for
EXEC SQLand translates it into API calls. - CICS Translator (DFHECP1$): Scans for
EXEC CICSand translates it into API calls. - COBOL Compiler (IGYCRCTL): Compiles the resulting standard COBOL.
When the user attempted to COPY a paragraph containing EXEC CICS or EXEC SQL statements:
- If
COPYis used during COBOL compilation: The DB2 and CICS statements arrive at the COBOL compiler unprocessed. The COBOL compiler does not understandEXEC SQLorEXEC CICSand throws syntax errors. - If
COPYis used within the JCLSYSIN: 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 RECEIVEandEXEC SQL SELECTrequires theLINKAGE SECTIONandWORKING-STORAGE SECTIONto 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-PSxxxxsyntax errors because the compiler seesEXEC CICSinstead 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:
-
Service Programs (COBOL Subprograms):
- Move DB2-heavy logic (CRUD operations) into stateless COBOL subprograms.
- These subprograms handle the
EXEC SQLand return standard COBOL data structures. - The main CICS program calls these subprograms using the
CALLstatement.
-
CICS Pseudo-Conversational Design:
- If the logic is CICS-specific (e.g., BMS mapping, queueing), create a separate CICS transaction program.
- Use
LINKorXCTLto transfer control between screens/logic flows.
-
Proper Use of Copybooks (The “Right” Way):
- Use
COPYexclusively 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
EXECblocks. However, this is rarely the correct approach for logic.
- Data Structures:
- Use
-
JCL Optimization:
- Ensure the
COPYlibraries are added to theSYSLIBconcatenation in the COBOL Compiler step (as you have done), but the source inside those copybooks must be compilable COBOL (i.e., theEXECstatements should have been preprocessed before the compiler sees them, or they shouldn’t be there).
- Ensure the
Why Juniors Miss It
- Lack of Precompiler Knowledge: Juniors often treat COBOL like a modern language where
includeworks universally. They fail to realize thatEXEC CICSandEXEC SQLare 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,
COPYis 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.