After DECLARE/OPEN/FETCH/CLOSE, production programs add WITH HOLD so a batch can commit without losing its place, WITH RETURN so a stored procedure hands back a result set, SENSITIVE STATIC or SENSITIVE DYNAMIC for how live the result is, and positioned UPDATE/DELETE (including rowset and FOR ROW n). This DB2 for z/OS page is that second layer.
SENSITIVE STATIC SCROLL (scroll is typical) builds a result whose membership is fixed at OPEN. If another transaction commits an update to a row that is in your result, a SENSITIVE FETCH can show the new values. If that row is deleted, FETCH can return a hole (no data, a warning/SQLCODE that the row is gone). Inserts that would have qualified are not added to a STATIC result.
12345DECLARE C_STAT SENSITIVE STATIC SCROLL CURSOR FOR SELECT EMPNO, LASTNAME, SALARY FROM DSN8C10.EMP WHERE WORKDEPT = :DEPT FOR UPDATE OF SALARY;
FETCH SENSITIVE vs FETCH INSENSITIVE on this cursor chooses whether this FETCH sees the latest base-table values or the original result-table copy. Default follows the cursor’s sensitivity.
SENSITIVE DYNAMIC does not freeze membership. The cursor behaves like a moving window on the base tables. Committed inserts can appear on a later FETCH; deleted rows disappear. This is closer to “live query” and closer to ordinary isolation-level visibility. It cannot be INSENSITIVE. Updatable dynamic scrollable cursors have extra restrictions—read the SQL Reference before mixing DYNAMIC with positioned UPDATE in a complicated join.
| Declaration | Sees after OPEN |
|---|---|
| SENSITIVE STATIC | Updates/deletes to rows that were in the result at OPEN; not new inserts |
| SENSITIVE DYNAMIC | Live table: committed inserts/updates/deletes per isolation |
WITH HOLD means COMMIT does not close the cursor. After commit, the cursor sits after the last row you fetched. You FETCH next to continue. You cannot positioned-UPDATE until you FETCH again.
12345678EXEC SQL DECLARE EMPLUPDT CURSOR WITH HOLD FOR SELECT EMPNO, LASTNAME, PHONENO, JOB, SALARY, WORKDEPT FROM DSN8C10.EMP WHERE WORKDEPT < 'D11' ORDER BY EMPNO FOR UPDATE OF PHONENO END-EXEC.
| Event | WITH HOLD | Not held |
|---|---|---|
| COMMIT / syncpoint commit | Stays open; positioned after last fetched row | Closed |
| ROLLBACK / SYNCPOINT ROLLBACK | Closed (SQL ROLLBACK) | Closed |
| CLOSE cursor | Closed | Closed |
| CICS EOT / IMS new message | Effectively ended; reopen | Ended |
Restrictions: do not leave held cursors on a thread that might go inactive—locks can stick. IMS MPP and message-driven BMP: each message is a new user; WITH HOLD does not carry across messages. CICS: WITH HOLD survives SYNCPOINT COMMIT inside a task, but EOT (pseudo-conversational RETURN) closes the story—you reopen after the next task. SQL COMMIT in CICS/IMS is the wrong lever; use the transaction manager’s syncpoint (next page).
In a stored procedure, DECLARE CURSOR ... WITH RETURN TO CALLER (or TO CLIENT) marks a result-set cursor. OPEN it, do not CLOSE it before RETURN; the caller FETCHes. TO CALLER is the nested caller; TO CLIENT is the outermost client. You can return multiple result sets from one procedure (multiple WITH RETURN cursors left open).
12345DECLARE C_OUT CURSOR WITH RETURN TO CALLER FOR SELECT EMPNO, LASTNAME FROM DSN8C10.EMP WHERE WORKDEPT = P_DEPT ORDER BY EMPNO;
After FETCH positions the cursor on a row:
123UPDATE DSN8C10.EMP SET PHONENO = :NEW-PHONE WHERE CURRENT OF EMPLUPDT;
Rules of thumb:
12DELETE FROM DSN8C10.EMP WHERE CURRENT OF C_EMP;
Deletes the current row. The cursor is left in a position from which the next FETCH NEXT gets the following row (you do not skip one). Same updatability rules as positioned UPDATE. Prefer searched DELETE (WHERE key = ...) when you already have the primary key and do not need cursor position.
WITH ROWSET POSITIONING plus FETCH NEXT ROWSET FOR n ROWS positions on a current rowset, not a single row. Positioned statements then use:
12345678FETCH NEXT ROWSET FROM C1 FOR 20 ROWS INTO :HVA-EMPNO, :HVA-SALARY; -- Update only the 5th row of that rowset UPDATE DSN8C10.EMP SET SALARY = SALARY * 1.03 WHERE CURRENT OF C1 FOR ROW 5 OF ROWSET;
Host arrays used on FETCH must stay aligned with n. If SQLERRD(3) returned 7 rows, FOR ROW 8 is invalid. Dimension arrays to the maximum FOR n ROWS you will request.
FOR n ROWS appears on FETCH (how many to retrieve) and on INSERT (how many array rows to insert):
1234INSERT INTO DSN8C10.EMP (EMPNO, LASTNAME) FOR :N ROWS VALUES (:HVA-EMPNO, :HVA-LASTNAME) ATOMIC;
n is at most 32767. ATOMIC means one row failure fails the statement; NOT ATOMIC CONTINUE ON SQLEXCEPTION can keep inserting remaining rows (diagnostics in GET DIAGNOSTICS). This is the bulk-insert twin of rowset FETCH—not a cursor option, but the same host-array skill.
FETCH FIRST n ROWS ONLY on the SELECT limits the result table size. FOR n ROWS on FETCH limits this call. If both appear, FETCH FIRST n ROWS ONLY dominates the result cardinality.
FOR ROW n OF ROWSET qualifies positioned UPDATE/DELETE (and some FETCH forms) to a single row inside the current rowset. n must be between 1 and the number of rows in that rowset. Use it when you FETCHed 50 rows, the program decided only row 12 should change, and you do not want to UPDATE all 50.
12345678910EXEC SQL DECLARE C_BAT CURSOR WITH HOLD WITH ROWSET POSITIONING FOR SELECT EMPNO, SALARY FROM DSN8C10.EMP WHERE WORKDEPT = :WS-DEPT FOR UPDATE OF SALARY END-EXEC. EXEC SQL OPEN C_BAT END-EXEC. * Fetch, update selected rows with FOR ROW n, COMMIT every 500 rows. * WITH HOLD keeps C_BAT open across COMMIT.
That is the industrial pattern: rowset FETCH for speed, positioned UPDATE for the rows that need change, WITH HOLD so COMMIT frequency does not restart the scan, FOR READ ONLY instead when the job is extract-only.
A normal bookmark falls out of the book when you take a snack break (COMMIT). WITH HOLD is tape on the bookmark so it stays. ROLLBACK throws the book on the floor—tape or not, you lost the place. SENSITIVE STATIC is a photocopy of the pages; scribbles on the real book might show through on those pages, but new pages added to the library do not appear in your photocopy. SENSITIVE DYNAMIC is reading the real bookshelf. WHERE CURRENT OF is “erase the sentence my finger is on.” FOR ROW 5 OF ROWSET is “I picked up five cards; change only the fifth.” WITH RETURN is handing the rest of the stack to mom when you are done picking.
1. What does WITH HOLD do?
2. WHERE CURRENT OF cursor-name performs:
3. WITH RETURN is used to:
4. SENSITIVE STATIC vs SENSITIVE DYNAMIC:
5. FOR ROW n OF ROWSET on UPDATE means: