After every executable SQL statement, DB2 for z/OS writes a status report. COBOL programs traditionally read that report from the SQLCA. Native SQL procedures and modern multi-row statements also use GET DIAGNOSTICS, which can return more than one condition, a full message, and the stacked diagnostics area inside a handler. This page is the map: SQLCA fields, SQLCODE versus SQLSTATE, tokens, WHENEVER, DSNTIAR, DSN messages, and CURRENT versus STACKED diagnostics.
Think of two views of the same event. The diagnostics area is what Db2 keeps after a statement. The SQLCA is a 136-byte copy of the most important pieces, laid out for host languages. INCLUDE SQLCA in WORKING-STORAGE (or LOCAL-STORAGE). With precompiler option STDSQL(YES) you declare stand-alone SQLCODE and SQLSTATE instead and skip the SQLCA—then GET DIAGNOSTICS is how you still see ROW_COUNT and MESSAGE_TEXT.
| Field | Meaning |
|---|---|
| SQLCODE | Signed integer: 0 success, +100 no data, other + warning, − error |
| SQLSTATE | Five characters; class 00/01/02 versus exception classes |
| SQLERRMC / SQLERRML | Up to 70 bytes of tokens; length in SQLERRML; tokens separated by X'FF' |
| SQLERRD(3) | Rows affected / fetched; reason code for -911/-913; line number in some cases |
| SQLWARN0–A | Warning flags; SQLWARN0 is W if any other warning flag is set |
| SQLERRP | Implementation-dependent module name (useful with some connection codes) |
123EXEC SQL INCLUDE SQLCA END-EXEC.
Check SQLCODE after every executable statement. Zero is success—then look at SQLWARN0. +100 is not found (not a crash). Negative means the statement did not complete successfully. Warning conditions (other positives, or SQLCODE 0 with SQLWARN0 = W) mean “it worked, but read the flags.” Error conditions are negatives and SQLSTATE classes other than 00, 01, and 02.
SQLCODE is product-oriented and what most COBOL shops still test. SQLSTATE is five characters designed so classes of problems match across IBM SQL products: 00 success, 01 warning, 02 no data. Look codes up in the IBM Codes book (SQL codes chapter) at ibm.com/docs for Db2 for z/OS. Search with the sign: -911 not 911.
Message tokens fill the blanks in IBM text (“table PAY.EMP”). They land in SQLERRMC. If the 70-byte field truncates them, GET DIAGNOSTICS DB2_ORDINAL_TOKEN_n still has each token. A reason code (hex, for example 00C90088 deadlock versus 00C9008E timeout) often appears as a token and in SQLERRD(3) for -911/-913. GET DIAGNOSTICS DB2_REASON_CODE returns that number when the message has one.
SQL messages in SYSOUT often look like DSNT408I SQLCODE = -803. That is a DSN (usually DSNT) wrapper around the same SQLCODE. Utility messages are DSNU; this diagnostics page is about SQLCODE/SQLSTATE, not DSNU010I. Abend reason codes (04E) are a different Codes-book part—do not mix them with SQL reason tokens.
WHENEVER is a precompiler directive, not a run-time Db2 feature. It tells the precompiler to insert a test after later SQL statements:
Action is CONTINUE or GOTO paragraph. WHENEVER stays in effect until another WHENEVER for that class. GOTO error paragraphs are easy to write and hard to maintain (every statement shares one handler). Many shops prefer explicit IF SQLCODE after each statement, or a PERFORM that inspects SQLCODE and calls DSNTIAR.
1234567891011EXEC SQL WHENEVER NOT FOUND CONTINUE END-EXEC. EXEC SQL WHENEVER SQLERROR GOTO SQL-ERR END-EXEC. EXEC SQL SELECT LASTNAME INTO :HV-LNAME FROM EMP WHERE EMPNO = :HV-EMPNO END-EXEC. IF SQLCODE = +100 DISPLAY 'EMPLOYEE NOT FOUND' END-IF.
DSNTIAR is the IBM sample assembler routine that formats the SQLCA into 72-byte (or longer) print lines. COBOL calls it with the SQLCA, a message structure, and a halfword line length. Output resembles DSNT408I for errors and DSNT400I for successful SQL with extra text. Use it in batch SYSOUT and in CICS error screens. GET DIAGNOSTICS MESSAGE_TEXT is the SQL-language equivalent of that short text (without the message number; use DB2_MESSAGE_ID for the id).
1234567801 ERROR-MESSAGE. 05 ERROR-LEN PIC S9(4) COMP VALUE +720. 05 ERROR-TEXT PIC X(72) OCCURS 10 TIMES. 01 ERROR-TEXT-LEN PIC S9(9) COMP VALUE +72. * CALL 'DSNTIAR' USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN.
GET DIAGNOSTICS is embeddable SQL only (not dynamic PREPARE). No extra privilege. It reports on the last SQL statement that was not GET DIAGNOSTICS (and not a compound BEGIN). Three shapes:
| Item | Meaning |
|---|---|
| NUMBER / MORE | How many conditions stored; Y if some were discarded (over 65535 bytes) |
| ROW_COUNT | Rows that qualified for INSERT/UPDATE/DELETE/MERGE or rows fetched |
| DB2_RETURNED_SQLCODE | SQLCODE for CONDITION n |
| RETURNED_SQLSTATE | SQLSTATE for CONDITION n |
| MESSAGE_TEXT | Short message with tokens substituted; empty when SQLCODE is 0 |
| DB2_REASON_CODE | Numeric reason code when the message has one (for example deadlock 00C90088) |
| DB2_ORDINAL_TOKEN_n | Nth token (1–100) without the 70-byte SQLERRMC limit |
| DB2_ROW_NUMBER | Which row of a multi-row statement hit the condition |
1234567891011EXEC SQL GET DIAGNOSTICS :HV-ROWS = ROW_COUNT END-EXEC. EXEC SQL GET DIAGNOSTICS CONDITION 1 :HV-SQLCODE = DB2_RETURNED_SQLCODE, :HV-SQLSTATE = RETURNED_SQLSTATE, :HV-MSG = MESSAGE_TEXT, :HV-REASON = DB2_REASON_CODE END-EXEC.
NUMBER is how many errors and warnings were stored. If the previous SQLSTATE was 00000, NUMBER is still 1 (a success condition). MORE = Y means some conditions were discarded because storage exceeded 65535 bytes—you did not see every warning. Loop CONDITION from 1 to NUMBER for multi-row INSERT with several failing rows. CONDITION 1 matches the SQLSTATE that was actually returned on the statement.
CURRENT (the default) is the diagnostics area for the previous SQL statement. STACKED is a second area that exists only inside a condition handler in a native SQL procedure, compiled SQL function, or trigger. When the handler runs its own INSERT to a log table, CURRENT becomes that INSERT. STACKED still holds the SELECT or UPDATE that fired the handler. If GET DIAGNOSTICS is the first statement in the handler, CURRENT and STACKED are the same.
123456789DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN GET CURRENT DIAGNOSTICS CONDITION 1 V_HANDLER_MSG = MESSAGE_TEXT; GET STACKED DIAGNOSTICS CONDITION 1 V_ORIG_MSG = MESSAGE_TEXT, V_ORIG_CODE = DB2_RETURNED_SQLCODE; INSERT INTO ERRLOG (MSG, ORIG) VALUES (V_HANDLER_MSG, V_ORIG_MSG); END;
Using STACKED outside a handler fails with SQLCODE -20228 (SQLSTATE 0Z002). That is why COBOL programs almost always use CURRENT (or omit the keyword) and SQL PL handlers use STACKED for the original exception.
COBOL: INCLUDE SQLCA; after each statement test SQLCODE; on negatives CALL DSNTIAR and ROLLBACK (or CICS SYNCPOINT ROLLBACK); on +100 take the not-found path; on 0 inspect SQLWARN0. SQL PL: DECLARE handlers for NOT FOUND, SQLWARNING, SQLEXCEPTION; GET STACKED DIAGNOSTICS in the handler; do not assume SQLCODE still holds the original value after the handler’s first statement. Multi-row: GET DIAGNOSTICS ROW_COUNT and CONDITION loop with DB2_ROW_NUMBER.
After you ask the library a question, the librarian stamps a tiny card (SQLCA) with a number (SQLCODE) and a five-letter stamp (SQLSTATE). Sometimes the full story does not fit on the card, so you ask “tell me everything” (GET DIAGNOSTICS) and get a longer note, including which book in a stack of books had the problem (DB2_ROW_NUMBER). If a helper runs in to write in the accident log, their new stamp would cover the original card—unless you look at the carbon copy the helper is not allowed to overwrite (STACKED). DSNTIAR is the photocopier that turns the tiny card into a sentence you can pin on the wall. WHENEVER is a sticky note on your desk that says “if the number is bad, jump to the red paragraph.”
1. GET DIAGNOSTICS reads diagnostics from:
2. SQLERRMC versus GET DIAGNOSTICS MESSAGE_TEXT:
3. WHENEVER SQLERROR GOTO ERR-PARA means:
4. DSNTIAR is used to:
5. STACKED diagnostics exist because: