COBOL is the default story on z/OS, but DB2 speaks SQL through every IBM host language the precompiler supports. This page is a map of those other neighbourhoods: C and C++ embedded SQL, PL/I, assembler with DSNHLI and attachment stubs, and REXX with DSNREXX. The SQLCA, SQLDA, static versus dynamic SQL, cursors, LOBs, and XML do not change meaning — only how you spell them in each language.
Sample programs shipped with Db2 illustrate the split: DSN8BC3 (COBOL static), DSN8BD3 (C static), DSN8BP3 (PL/I static), DSNTEP2 (PL/I dynamic). REXX does not appear in that precompile list because IBM documents no program preparation for REXX SQL.
| Language | SQL form | Preparation |
|---|---|---|
| C / C++ | EXEC SQL ... ; | Precompile or coprocessor, compile, link, BIND |
| PL/I | EXEC SQL ... ; | Precompile or coprocessor, compile, link, BIND |
| Assembler | EXEC SQL ... | Precompile, assemble, link, BIND |
| REXX | ADDRESS DSNREXX EXECSQL ... | No exec prepare; DSNREXX plan must exist |
| C ODBC / CLI | SQLExecDirect / SQLExecute (not EXEC SQL) | Compile, link ODBC; no DBRM for CLI calls |
Place SQL wherever an executable C statement is legal. Each statement begins with EXEC SQL — those two keywords on one line — and ends with a semicolon. You can continue the SQL across following lines. C block comments /* ... */ may appear inside SQL where a blank is allowed, but not between EXEC and SQL. C++ // comments are for C statements, not for embedded SQL; use SQL comments inside the SQL text.
1234567891011EXEC SQL INCLUDE SQLCA; EXEC SQL BEGIN DECLARE SECTION; char hv_empno[7]; char hv_lastname[16]; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT LASTNAME INTO :hv_lastname FROM DSN8C10.EMP WHERE EMPNO = :hv_empno;
C/C++ go through the Db2 precompiler or a coprocessor, producing a DBRM and modified source. Host variables are ordinary C objects, referenced with a colon in SQL. The coprocessor is more flexible about where they are declared; the classic precompiler wants a DECLARE SECTION for standard host variables. Names must be valid C identifiers. Match Db2 types: CHAR to null-terminated or VARCHAR structs as your shop standardizes; DECIMAL often to a packed struct; DATE/TIME/TIMESTAMP to character buffers of the documented length.
INCLUDE SQLCA generates a C struct sqlca with lowercase members: sqlcode, sqlstate, sqlerrmc, sqlerrd[6] (zero-based!). INCLUDE SQLDA generates the descriptor used with DESCRIBE, FETCH USING DESCRIPTOR, and EXECUTE USING DESCRIPTOR. Check sqlcode after every executable statement, same discipline as COBOL.
Static SQL is written in the source and bound in the package. Dynamic SQL uses PREPARE from a char buffer, then EXECUTE or a cursor. DECLARE CURSOR / OPEN / FETCH / CLOSE work as in COBOL; rowset FETCH needs WITH ROWSET POSITIONING and C arrays. CICS and IMS still forbid SQL COMMIT — call the transaction manager from C the same as from COBOL.
LOB and XML columns use locator host variables or file-reference variables; you FETCH a locator then use HOLD LOCATOR / LOB routines or XMLSERIALIZE depending on the design. Besides EXEC SQL, C on z/OS can use ODBC/CLI (no DBRM for those calls) and can call stored procedures. Do not mix “I linked ODBC” with “I forgot to BIND the embedded package” — they are different stacks.
PL/I embedded SQL also uses EXEC SQL ... ;. Host variables are PL/I variables with a colon in SQL. INCLUDE SQLCA produces a DECLARE with SQLCODE FIXED(31) BINARY, SQLERRM CHAR(70) VAR, SQLERRD(6), SQLWARN0–A, and SQLSTATE CHAR(5). INCLUDE SQLDA is available for dynamic SQL.
123456EXEC SQL INCLUDE SQLCA; EXEC SQL SELECT LASTNAME INTO :LASTNAME FROM DSN8C10.EMP WHERE EMPNO = :EMPNO;
Static and dynamic SQL, cursors, LOBs, and XML follow the same SQL Reference rules as COBOL. DSNTEP2 is the famous dynamic PL/I sample: it PREPARE/DESCRIBE/FETCHes whatever you put in SYSIN. Preparation is precompile (or coprocessor), PL/I compile, link with the right attachment, BIND PACKAGE. PL/I shops still hit -818 when the DBRM and load module drift.
High-volume exits, glue CSECTs, and old tools still embed SQL in assembler. The precompiler recognizes EXEC SQL in assembler source, writes a DBRM, and replaces SQL with a parameter list plus a call to DSNHLI.
DSNHLI is the Host Language Interface. Your program does not pick a Db2 address space by coding DSNHLI itself; the attachment facility stub you include at link-edit is DSNHLI (or an alias of it).
| Stub | When you link it |
|---|---|
| DSNELI | TSO (DSN command processor) |
| DSNCLI | CICS |
| DFSLI000 | IMS |
| DSNALI | Call attachment facility (CAF) |
| DSNRLI | RRS attachment facility (RRSAF) |
SQL communication is still the SQLCA: SQLCAID, SQLCODE, SQLERRM as H,CL70, SQLERRD 6F, SQLWARN flags, SQLSTATE CL5. After each executable SQL, branch on SQLCODE. Dynamic SQL uses an SQLDA you map with DSECTs from INCLUDE SQLDA. Assembler does not get you out of BIND or out of CICS SYNCPOINT rules.
DSNREXX is how TSO/E REXX issues SQL. You do not precompile the exec. You add the host command environment, connect to a subsystem, and run SQL dynamically.
123456789101112/* REXX */ call RXSUBCOM 'ADD', 'DSNREXX', 'DSNREXX' ssid = 'DB2P' address DSNREXX 'CONNECT' ssid if SQLCODE <> 0 then do say 'CONNECT failed' SQLCODE SQLSTATE exit 8 end /* SQL here */ address DSNREXX 'EXECSQL COMMIT' address DSNREXX 'DISCONNECT' call RXSUBCOM 'DELETE', 'DSNREXX', 'DSNREXX'
Batch invocation is typically IKJEFT01 with SYSTSIN calling the exec, STEPLIB to SDSNLOAD, and the DSNREXX plan available. If you exit without COMMIT/ROLLBACK/DISCONNECT, behaviour depends on how the thread ends — IBM’s guidance is to COMMIT or ROLLBACK explicitly so you are not surprised by termination processing.
All REXX SQL is dynamic. A usual SELECT pattern:
After each EXECSQL, REXX variables SQLCODE and SQLSTATE are set. FETCH deposits column values into the SQLDA / stem variables DSNREXX defines for that describe. You write the loop; there is no automatic result-set object. Parameter markers work on PREPARE/EXECUTE the same as in COBOL dynamic SQL — prefer them over concatenating unchecked text.
LOB locators, XML, isolation, and lock duration are SQL and bind options, not language features. If a cursor trick works in COBOL, the SQL works in C; only the host-variable declaration changes.
Db2 is one kitchen. COBOL, C, PL/I, and assembler are different waiters who all fill out the same order pad (SQL) and wear the same name tag on their jacket (DSNHLI) so the kitchen knows which door they came through (TSO, CICS, IMS). REXX is a walk-up window: you shout the order in plain words every time (dynamic SQL) and you do not get a filed recipe card (no DBRM of your exec). Everyone still checks the sticky note that comes back with the plate (SQLCODE) before they tell the customer the food is ready.
1. How does a C program delimit embedded SQL on Db2 for z/OS?
2. What is DSNHLI?
3. REXX programs that use DSNREXX require which preparation?
4. Which languages can use INCLUDE SQLCA the same way conceptually?
5. Assembler Db2 programs communicate SQL status how?