COBOL & Databases: Embedded SQL and DB2/IMS Integration

COBOL Intermediate/Advanced

Chapter 4 · COBOL & Databases: Embedded SQL and DB2/IMS Integration

Every real file in this course so far — sequential, indexed, relative — has been COBOL's own native I/O. Real mainframe COBOL just as often talks to a genuinely separate system entirely: a real database, most commonly IBM's own DB2, sometimes the older IMS.

DB2: A Real, Traceable History

DB2's own roots trace to Edgar F. Codd's real 1970 relational-database model, developed further inside IBM's own System R research project starting in 1974 — the very project that produced SQL itself. IBM's real DB2 product launched on the MVS mainframe platform in 1983.

Embedded SQL: EXEC SQL / END-EXEC

Real SQL statements sit directly inside COBOL source, marked off by EXEC SQL and END-EXEC:

EXEC SQL SELECT CUST_NAME, CUST_BALANCE INTO :WS-CUST-NAME, :WS-CUST-BALANCE FROM CUSTOMER WHERE CUST_ID = :WS-CUST-ID END-EXEC.
A Real Precompiler, Not a New Language Feature COBOL Understands Directly A genuine precompiler runs before the real COBOL compiler ever sees the source — it parses every EXEC SQL block and replaces it with real, ordinary host-language statements calling into a database code library. Underneath, embedded SQL genuinely resolves down to Chapter 9's own real CALL mechanism — the COBOL compiler itself never has any built-in understanding of SQL at all.

Host Variables: The Real Colon Prefix

:WS-CUST-ID, :WS-CUST-NAME, and :WS-CUST-BALANCE above are real host variables — ordinary COBOL WORKING-STORAGE fields, declared exactly like any other field, referenced inside SQL with a real leading colon so the precompiler can tell a COBOL field apart from a genuine database column name.

SQLCODE: Did the Statement Genuinely Succeed?

After every real embedded SQL statement executes, a genuine result code — SQLCODE — reports what happened:

SQLCODEReal Meaning
0Statement genuinely succeeded
100No real row matched the query
negativeA genuine SQL error occurred
IF SQLCODE = 0 DISPLAY "FOUND: " WS-CUST-NAME ELSE IF SQLCODE = 100 DISPLAY "NO CUSTOMER WITH THAT ID" ELSE DISPLAY "SQL ERROR: " SQLCODE END-IF END-IF.

Cursors: When One Row Genuinely Isn't Enough

A plain SELECT ... INTO can only ever return one real row. Retrieving many rows needs a real cursor — a mechanism that genuinely traverses a whole result set, one row at a time, via a real four-step sequence:

EXEC SQL DECLARE CUST-CURSOR CURSOR FOR SELECT CUST_ID, CUST_NAME FROM CUSTOMER WHERE CUST_BALANCE < 0 END-EXEC. EXEC SQL OPEN CUST-CURSOR END-EXEC. PERFORM UNTIL SQLCODE = 100 EXEC SQL FETCH CUST-CURSOR INTO :WS-CUST-ID, :WS-CUST-NAME END-EXEC IF SQLCODE = 0 DISPLAY "OVERDRAWN: " WS-CUST-NAME END-IF END-PERFORM. EXEC SQL CLOSE CUST-CURSOR END-EXEC.

DECLARE names the real query; OPEN genuinely executes it and establishes the result set; FETCH pulls one real row at a time into host variables; CLOSE releases it. This loop's own real shape — checking a result code after every fetch — deliberately echoes Fundamentals' own priming-read pattern for sequential files, applied here to a database result set instead.

IMS: A Genuinely Different, Older Real Model

IMS predates DB2 substantially — real development began in 1966, to track the bill of materials for the Saturn V rocket, with the system formally installed in 1968. Unlike DB2's real relational model, IMS uses a genuinely hierarchical structure, accessed via real DL/I calls rather than SQL. Its own real staying power is striking: 2003 — 35 years after release — was IMS's best sales year yet, with over 95% of the Fortune 1000 still using it.

Hands-On Exercises

Exercise 1

Using this chapter's own real finding-box, explain in your own words why the real COBOL compiler itself has no built-in understanding of SQL at all, and what actually happens to an EXEC SQL block before the COBOL compiler ever sees the source.

📄 View solution
Exercise 2

Using this chapter's own real cursor example, explain in your own words why a plain SELECT ... INTO couldn't have been used to find every overdrawn customer, and why the PERFORM UNTIL SQLCODE = 100 loop condition is genuinely the correct one to end the FETCH loop.

📄 View solution
Exercise 3

Using this chapter's own real material, explain in your own words the genuine structural difference between DB2 and IMS as database systems, and why a program written to use DL/I calls against IMS couldn't simply be pointed at a DB2 database with no other changes.

📄 View solution

Chapter 4 Quick Reference

  • EXEC SQL ... END-EXEC — real embedded SQL, processed by a genuine precompiler before real COBOL compilation
  • :host-variable — a colon-prefixed real WORKING-STORAGE field, distinguishing it from a genuine database column
  • SQLCODE — real per-statement result: 0 success, 100 no row found, negative a genuine error
  • DECLARE / OPEN / FETCH / CLOSE — the real four-step cursor sequence for a multi-row result set
  • DB2 — real relational model, SQL-based, launched 1983; IMS — real hierarchical model, DL/I calls, dating to 1966