Cursor SQLCODEs are almost always application-flow bugs: you FETCH after COMMIT closed the cursor, OPEN twice, UPDATE a column you never listed in FOR UPDATE, or reference a name that was never DECLARED. This DB2 for z/OS page covers IBM’s -501, -502, -503, and -504.
Class 24 SQLSTATE values talk about cursor state. Class 34 is “invalid cursor name.” 42912 is a syntax/semantics restriction on which columns a positioned UPDATE may touch. None of these mean “table missing” or “deadlock”—though a prior -911 / -913 can leave you with a closed cursor so thenext FETCH shows -501.
| SQLCODE | SQLSTATE | Meaning |
|---|---|---|
| -501 | 24501 | FETCH/CLOSE: cursor not open |
| -502 | 24502 | OPEN: cursor already open |
| -503 | 42912 | Positioned UPDATE column not in FOR UPDATE |
| -504 | 34000 | Cursor not declared / allocated / still valid |
IBM: THE CURSOR IDENTIFIED IN A FETCH OR CLOSE STATEMENT IS NOT OPEN. The program fetched or closed when the cursor was not open. After a cursor is closed, any later FETCH or CLOSE for that cursor gets -501.
IBM lists typical ways the cursor became closed:
System action: cannot process. Programmer response: ensure the cursor is open when FETCH/CLOSE runs. SQLSTATE 24501.
12345EXEC SQL OPEN C1 END-EXEC. EXEC SQL FETCH C1 INTO :HV-EMPNO END-EXEC. EXEC SQL COMMIT END-EXEC. * Without WITH HOLD, C1 is closed — next FETCH → -501 EXEC SQL FETCH C1 INTO :HV-EMPNO END-EXEC.
Fix: OPEN again after COMMIT, or declare DECLARE C1 CURSOR WITH HOLD FOR … when your design needs hold across commits. Also check for silent CLOSE in error handlers that always CLOSE “just in case.”
IBM: THE CURSOR IDENTIFIED IN AN OPEN STATEMENT IS ALREADY OPEN. System action: statement fails; the cursor is unchanged (not reopened, not reset to first row). Programmer response: do not OPEN an open cursor. SQLSTATE 24502.
Loops that OPEN every iteration without CLOSE are the usual offender. Another pattern: two paths both OPEN “to be safe.” Db2 will not treat the second OPEN as rewind—you must CLOSE then OPEN, or use a design that opens once.
123EXEC SQL OPEN C1 END-EXEC. EXEC SQL OPEN C1 END-EXEC. * Second OPEN → SQLCODE -502; cursor still as after first OPEN
IBM: A COLUMN CANNOT BE UPDATED BECAUSE IT IS NOT IDENTIFIED IN THE UPDATE CLAUSE OF THE SELECT STATEMENT OF THE CURSOR. Positioned UPDATE tried to change a column that was not listed in FOR UPDATE of the cursor declaration. Every updatable column must appear there.
System action: cannot process; no data updated. Programmer response: add the column name to FOR UPDATE. SQLSTATE 42912.
1234567891011121314EXEC SQL DECLARE C1 CURSOR FOR SELECT EMPNO, SALARY FROM EMP WHERE WORKDEPT = :HV-DEPT FOR UPDATE OF SALARY END-EXEC. * EXEC SQL UPDATE EMP SET BONUS = :HV-BONUS WHERE CURRENT OF C1 END-EXEC. * BONUS not in FOR UPDATE OF → -503
Either add BONUS to FOR UPDATE OF SALARY, BONUS, or stop updating BONUS through this cursor. Ambiguous or read-only cursors need FOR FETCH ONLY or isolation fixes—that is a different family of codes than -503.
IBM: CURSOR NAME cursor-name IS NOT DECLARED. One of several situations:
System action: cannot process. Programmer response: check completeness and spelling; DECLARE/ALLOCATE before use. If precompile used SQL(Db2) and warned on DECLARE, fix those warnings. For allocated cursors after COMMIT/ROLLBACK/CLOSE: call the procedure again and reissue ASSOCIATE LOCATORS / ALLOCATE CURSOR, or declare WITH HOLD in the procedure so COMMIT keeps the result set. SQLSTATE 34000.
123456* Typo: declared C_EMP but FETCHed C1 → -504 EXEC SQL DECLARE C_EMP CURSOR FOR SELECT EMPNO FROM EMP END-EXEC. EXEC SQL OPEN C_EMP END-EXEC. EXEC SQL FETCH C1 INTO :HV-EMPNO END-EXEC.
Positioned UPDATE/DELETE when the cursor is not open (−507) or not positioned on a row (−508). Same lifecycle discipline as -501. If your error handler only checks for -501 after FETCH, add the positioned-update cousins so batch updaters fail clearly.
Dynamic cursors need a successful PREPARE before OPEN. Wrong order surfaces different codes—always read the Codes book for the number you actually received. A -518-style “SQL statement not yet prepared” problem is not fixed by CLOSE/OPEN alone; fix the prepare name and then OPEN.
Keep one clear state machine per cursor: closed → open → positioned → closed. After COMMIT, either treat the cursor as closed (re-OPEN) or document WITH HOLD and still handle -501 if an earlier error closed it. Never OPEN “just in case” inside a loop. For updatable cursors, list every column you might SET in FOR UPDATE OF at declare time—adding columns later without changing the DECLARE is how -503 appears in production months after the first version shipped.
When you allocate result-set cursors from stored procedures, treat ASSOCIATE LOCATORS + ALLOCATE CURSOR as part of the open path. After COMMIT without WITH HOLD on the procedure cursor, or after calling the procedure again, re-associate and re-allocate before FETCH—otherwise -504 looks like a mysterious “name vanished” bug.
A cursor is a bookmark in a book. -501 is “you tried to read with the book closed.” -502 is “you tried to open a book that is already open.” -503 is “you tried to erase a word that was not on the erasable list.” -504 is “you asked for bookmark Blue but you never made a bookmark named Blue” (or someone threw it away after COMMIT).
1. SQLCODE -501 means:
2. SQLCODE -502 is returned when:
3. SQLCODE -503 means:
4. SQLCODE -504 covers:
5. After COMMIT without WITH HOLD, a FETCH typically gets: