DB2intermediate

Cursors: Static and Dynamic

Understand why COBOL needs cursors to process multi-row SQL result sets and the difference between static and dynamic cursor definitions.

COBOL cannot receive a result set. SELECT INTO handles exactly one row; anything that might return several needs a cursor, which hands rows over one at a time.

A cursor is a librarian's bookmark moving through a shelf of matching books one at a time on request — a static cursor knows exactly which shelf to search before the day even starts, while a dynamic cursor gets handed a search request written on the fly and has to figure out where to look right then.

Key Concepts

1
The four steps.
    EXEC SQL DECLARE C1 CURSOR FOR
         SELECT CUST_ID, NAME FROM CUSTOMER
          WHERE REGION = :WS-REGION
    END-EXEC.
2
    EXEC SQL OPEN C1 END-EXEC.
3
    PERFORM UNTIL SQLCODE = 100
        EXEC SQL FETCH C1 INTO :WS-ID, :WS-NAME END-EXEC
        IF SQLCODE = 0
            PERFORM PROCESS-ROW
        END-IF
    END-PERFORM.
4
    EXEC SQL CLOSE C1 END-EXEC.
5
DECLARE is not executable — it is a declaration the precompiler reads. OPEN is where the query runs.
DECLAREOPEN
6
WITH HOLD is the one that matters in batch. A commit normally closes every open cursor, which is a problem for a program that must commit periodically while working through a million rows.
WITH HOLD
7
    EXEC SQL DECLARE C1 CURSOR WITH HOLD FOR ... END-EXEC.
8
The cursor survives the commit and keeps its position. Without it, a program that commits every thousand rows loses its place and either starts again or fails.
9
FOR UPDATE OF enables positioned updates.
    DECLARE C1 CURSOR FOR
        SELECT ... FROM CUSTOMER FOR UPDATE OF STATUS
FOR UPDATE OF
10
    EXEC SQL UPDATE CUSTOMER SET STATUS = 'C'
             WHERE CURRENT OF C1 END-EXEC.
11
WHERE CURRENT OF updates the row the cursor is on, with no need to repeat its key. The columns to be changed must be named in the declaration.
WHERE CURRENT OF
12
Static and dynamic. Everything above is static: the SQL is fixed at precompile time and its access path is chosen at bind.
13
A dynamic cursor builds the statement at runtime:
14
    MOVE 'SELECT CUST_ID FROM CUSTOMER WHERE ' TO WS-SQL
    STRING WS-SQL DELIMITED SIZE WS-CONDITION DELIMITED SIZE
        INTO WS-STMT
15
    EXEC SQL PREPARE S1 FROM :WS-STMT END-EXEC.
    EXEC SQL DECLARE C1 CURSOR FOR S1 END-EXEC.
16
Necessary when the filters genuinely are not known until the program runs — a search screen where the user picks which criteria to use.
17
The costs of dynamic. The access path is chosen at execution rather than at bind, so you pay for that each time and cannot review it in advance with EXPLAIN.
EXPLAIN
18
And building SQL by concatenation is SQL injection if any part of it comes from user input. Parameter markers — WHERE REGION = ? with values supplied on OPEN — avoid that, and should be used whenever the shape is fixed and only the values vary.
WHERE REGION = ?OPEN
19
What the interviewer is probing.1. "What is the difference between static and dynamic SQL?" Probing: the central point. Stalls: "Nothing." Moves up: static is precompiled with the access path fixed at bind; dynamic is built and optimised at run time, which costs more but allows flexibility.
20
2. "When is dynamic SQL justified?" Probing: judgement. Stalls: "Never." Moves up: when the predicates genuinely vary at run time — a query builder or an ad-hoc reporting screen.
21
3. "What is the danger with dynamic SQL?" Probing: the security angle. Stalls: "Performance." Moves up: concatenating user input creates an injection risk, so parameter markers are mandatory, not optional.
22
4. "What does FOR UPDATE OF do on a cursor?" Probing: the detail. Stalls: "Nothing." *Moves up:* declares intent to update, taking stronger locks and enabling positioned UPDATE and DELETE on the current row.