Showing posts with label GET DIAGNOSTICS. Show all posts
Showing posts with label GET DIAGNOSTICS. Show all posts

Saturday, 14 September 2013

Db2 Rowset Data Modification: Positioned UPDATE, DELETE, and Multi-Row INSERT

Db2 rowset data modification flow showing fetch rowset update delete insert and SQLCA checks
Validate row counts after rowset changes.

A rowset positioning cursor can fetch several rows into COBOL host-variable arrays with one FETCH. After that fetch, Db2 can modify the current rowset with positioned UPDATE or DELETE statements, or target one row inside the rowset. That power is useful, but it also makes row-count validation non-negotiable.

This guide explains how to modify data with rowset positioning in Db2 for z/OS, including positioned update, positioned delete, single-row targeting inside a rowset, multi-row insert, ATOMIC versus NOT ATOMIC, and SQLCA checks for COBOL programs.

What rowset modification means

A rowset cursor fetches a block of rows instead of one row at a time. The program can then process arrays in working storage. For updateable rowset cursors, Db2 can apply positioned updates or deletes to the current rowset, or to a single row within that rowset.

The important distinction is scope. WHERE CURRENT OF cursor-name can affect the current rowset. FOR ROW n OF ROWSET targets one row in that rowset. A production program should make that choice explicit and then verify the affected-row count.

Rowset modification options

OperationScopeWhat to check
Positioned UPDATE ... WHERE CURRENT OFCan update all rows in the current rowset.Expected rowset size, row count, and whether every fetched row should change.
Positioned DELETE ... WHERE CURRENT OFCan delete all rows in the current rowset.Business rule, audit requirement, and commit/rollback scope.
FOR ROW n OF ROWSETTargets one row in the current rowset.Host variable row number is within the fetched row count.
INSERT ... FOR n ROWSInserts multiple rows from host-variable arrays.ATOMIC or NOT ATOMIC, diagnostics, and failed-row handling.

Positioned update for the current rowset

Use this form only when every row in the current rowset should receive the change. If the cursor fetched 50 rows, design and test the program as a 50-row update path, not as a single-row path.

EXEC SQL
   UPDATE EMP
      SET SALARY = :WS-NEW-SALARY
    WHERE CURRENT OF C1
END-EXEC

IF SQLCODE = 0
   PERFORM CHECK-ROWSET-UPDATE-COUNT
ELSE
   PERFORM WRITE-DB2-ERROR
END-IF

Do not assume that SQLCODE = 0 is enough. Check the row count available for your statement and Db2 level, and compare it with the number of rows the program intended to update.

Update one row inside a rowset

When only one row in the fetched rowset should change, use rowset row targeting. The row number can be a host variable, which lets the program select the matching array element after validation.

EXEC SQL
   UPDATE EMP
      SET SALARY = :WS-NEW-SALARY
    FOR ROW :WS-ROW-NO OF ROWSET
    FOR CURSOR C1
END-EXEC

Validate WS-ROW-NO before the SQL statement. It should be greater than zero and less than or equal to the number of rows fetched into the current rowset.

Delete with rowset positioning

A positioned delete can remove every row in the current rowset or one selected row, depending on the syntax used. Treat this as a high-risk path in batch programs because the wrong rowset size can delete more rows than expected.

EXEC SQL
   DELETE FROM EMP
    WHERE CURRENT OF C1
END-EXEC

EXEC SQL
   DELETE FROM EMP
    FOR ROW 3 OF ROWSET
    FOR CURSOR C1
END-EXEC

For production deletes, write audit data before commit. Include the key values from the host-variable arrays, not just the rowset number.

Multi-row insert with host-variable arrays

Db2 can insert multiple rows from host-variable arrays with FOR n ROWS. This is useful for bulk insert paths where the COBOL program has already filled arrays with validated data.

EXEC SQL
   INSERT INTO EMP_TBL
          (EMP_NO, EMP_NAME, SALARY)
   FOR :WS-INSERT-COUNT ROWS
   VALUES (:HV-EMP-NO,
           :HV-EMP-NAME,
           :HV-SALARY)
   ATOMIC
END-EXEC

With ATOMIC, Db2 treats the insert set as one unit for success or failure. With NOT ATOMIC, individual rows can succeed or fail, so the program must inspect diagnostics and handle partial success.

ATOMIC versus NOT ATOMIC

ChoiceBehaviorWhen it fits
ATOMICThe multi-row statement succeeds or fails as a unit.Use when partial inserts would break the business rule.
NOT ATOMICRows can succeed or fail independently.Use only when the program has diagnostics handling for failed rows.

SQLCA and diagnostics checks

Rowset processing needs stronger checks than a one-row cursor loop. At minimum, validate SQLCODE, SQLSTATE, affected-row count, fetched-row count, and diagnostics for partial success cases.

  • Check SQLCODE after every rowset update, delete, or insert.
  • Compare affected rows with the intended number of rows.
  • Use diagnostics when NOT ATOMIC can produce per-row results.
  • Log key values from arrays when a row fails, not only the array index.
  • Commit only after the full rowset operation passes business validation.

Common mistakes

Using WHERE CURRENT OF when only one row should change

In rowset processing, that can affect the whole current rowset. Use row targeting when the business rule is one row.

Not validating the row number

A host variable used in FOR ROW n OF ROWSET must be checked against the number of rows actually fetched.

Using NOT ATOMIC without diagnostics handling

Partial success is only useful when the program can identify failed rows and decide whether to continue, retry, or roll back.

Related Db2 topics

Use this guide with Db2 Rowset Positioning Cursor, Db2 SQL Execution Validation, Db2 SQLCODE and SQLSTATE, Db2 GET DIAGNOSTICS, and Db2 Application Environment.

FAQ

Can WHERE CURRENT OF affect more than one row with a rowset cursor?

Yes. With rowset positioning, a positioned update or delete can affect all rows in the current rowset. Use row targeting when only one row should be changed.

How do I update one row in a Db2 rowset?

Use FOR ROW n OF ROWSET with the cursor name and validate that n is within the number of rows fetched into the current rowset.

When should I use NOT ATOMIC for multi-row insert?

Use NOT ATOMIC only when partial success is acceptable and the program checks diagnostics for each failed row.

Saturday, 24 August 2013

Db2 GET DIAGNOSTICS Statement Information Items



Db2 GET DIAGNOSTICS Statement Information Items

Db2 GET DIAGNOSTICS statement information items including ROW_COUNT, NUMBER, MORE, cursor attributes, and data types
Db2 statement diagnostics after SQL execution.

GET DIAGNOSTICS is useful when a COBOL + Db2 program needs more detail than a single SQLCODE. After an UPDATE, a multi-row FETCH, an OPEN, a PREPARE, or a stored procedure CALL, statement-information items can tell the program how many rows were affected, how many conditions exist, whether warning detail was discarded, or which cursor attributes Db2 used.

This page focuses only on statement-information items. For the base syntax, read DB2 GET DIAGNOSTICS Statement. For diagnostic details tied to a specific warning or error, use the related condition information page. For connection diagnostics, use the connection information page.

What Statement Information Means

Statement information describes the last SQL statement that ran before GET DIAGNOSTICS. It is not the same as condition information. A statement item answers questions such as:

  • How many rows did the last UPDATE, INSERT, DELETE, MERGE, or FETCH affect?
  • How many warnings or errors are available in the diagnostics area?
  • Did Db2 discard any condition records because the diagnostic area was too small?
  • After an OPEN or ALLOCATE, is the cursor scrollable, held, rowset-positioned, static, dynamic, sensitive, or insensitive?

IBM documents these items in the Db2 for z/OS GET DIAGNOSTICS statement reference. The target host variable must be compatible with the diagnostic item data type.

Statement Information Items and Data Types

Item Data type When to use it
DB2_GET_DIAGNOSTICS_DIAGNOSTICS VARCHAR(32672) Returns text about errors or warnings from the GET DIAGNOSTICS statement itself, such as truncation while assigning a diagnostic value.
DB2_LAST_ROW INTEGER After a multiple-row FETCH, returns +100 when the last row is in the returned rowset; otherwise it returns zero.
DB2_NUMBER_PARAMETER_MARKERS INTEGER After PREPARE, returns the number of parameter markers in the prepared SQL statement.
DB2_NUMBER_RESULT_SETS INTEGER After CALL, returns the number of result sets returned by the stored procedure.
DB2_NUMBER_ROWS DECIMAL(31,0) After OPEN or FETCH, returns the result-table row count when known. After PREPARE, it can return the estimated result count. For sensitive dynamic cursors, treat it as approximate.
DB2_RETURN_STATUS INTEGER After a stored procedure CALL, returns the procedure status when the procedure uses a RETURN statement.
DB2_SQL_ATTR_CURSOR_HOLD CHAR(1) After ALLOCATE or OPEN, returns Y when the cursor can remain open across units of work, or N when it cannot.
DB2_SQL_ATTR_CURSOR_ROWSET CHAR(1) After ALLOCATE or OPEN, returns Y when the cursor supports rowset positioning, or N for row-positioned operation only.
DB2_SQL_ATTR_CURSOR_SCROLLABLE CHAR(1) After ALLOCATE or OPEN, returns Y for a scrollable cursor or N for a forward-only cursor.
DB2_SQL_ATTR_CURSOR_SENSITIVITY CHAR(1) After ALLOCATE or OPEN, returns I for insensitive cursor behavior or S for sensitive cursor behavior.
DB2_SQL_ATTR_CURSOR_TYPE CHAR(1) After ALLOCATE or OPEN, returns F for forward cursor, S for static cursor, or D for dynamic cursor.
MORE CHAR(1) Returns Y when Db2 discarded some warning or error records because the diagnostic area needed too much storage; otherwise returns N.
NUMBER INTEGER Returns the number of condition records stored for the previous SQL statement. Use this before looping through CONDITION 1, CONDITION 2, and so on.
ROW_COUNT DECIMAL(31,0) Returns rows affected by the previous data-change statement or rows fetched by a multiple-row FETCH. After TRUNCATE or some mass-delete cases, Db2 can return -1.
DB2_SQL_NESTING_LEVEL INTEGER Returns the current nesting level for a compiled SQL function, native SQL procedure, or trigger. Outside that nesting context, the value is zero.

COBOL Example: Capture ROW_COUNT After UPDATE

Use ROW_COUNT when the program must log how many rows the last SQL statement changed. In COBOL, define a packed decimal or numeric host variable that can hold DECIMAL(31,0).

01  WS-ROW-COUNT        PIC S9(9) COMP-5.

EXEC SQL
    UPDATE CUSTOMER
       SET STATUS = 'I'
     WHERE LAST_ORDER_DATE < :WS-CUTOFF-DATE
END-EXEC.

IF SQLCODE = 0
   EXEC SQL
       GET DIAGNOSTICS :WS-ROW-COUNT = ROW_COUNT
   END-EXEC
END-IF.

If the update qualifies 250 customer rows, WS-ROW-COUNT receives 250. Do not use this as a substitute for checking SQLCODE; use it after the SQL statement has completed successfully or when your error path expects this item to be available.

COBOL Example: Count Diagnostic Conditions

NUMBER is useful when one SQL statement can return more than one warning or error condition. After reading NUMBER, the program can loop through condition items such as RETURNED_SQLSTATE, DB2_RETURNED_SQLCODE, and MESSAGE_TEXT.

01  WS-DIAG-COUNT       PIC S9(9) COMP-5.
01  WS-DIAG-ID          PIC S9(9) COMP-5.
01  WS-RETURNED-SQLCODE PIC S9(9) COMP-5.
01  WS-MESSAGE-TEXT     PIC X(240).

EXEC SQL
    GET DIAGNOSTICS :WS-DIAG-COUNT = NUMBER
END-EXEC.

PERFORM VARYING WS-DIAG-ID FROM 1 BY 1
        UNTIL WS-DIAG-ID > WS-DIAG-COUNT
   EXEC SQL
       GET DIAGNOSTICS CONDITION :WS-DIAG-ID
           :WS-RETURNED-SQLCODE = DB2_RETURNED_SQLCODE,
           :WS-MESSAGE-TEXT     = MESSAGE_TEXT
   END-EXEC
END-PERFORM.

For basic SQLCODE and SQLSTATE handling, see the SQLCA guide. GET DIAGNOSTICS adds detail, but the program still needs a clear SQL error-handling rule.

Cursor Attribute Items

The cursor attribute items are useful after OPEN when a program needs to confirm cursor behavior. For example, a Db2 browse program might record whether a cursor is scrollable, static or dynamic, rowset-positioned, and sensitive or insensitive.

01  WS-CURSOR-SCROLLABLE PIC X.
01  WS-CURSOR-TYPE       PIC X.
01  WS-CURSOR-SENSITIVE  PIC X.

EXEC SQL
    OPEN C1
END-EXEC.

IF SQLCODE = 0
   EXEC SQL
       GET DIAGNOSTICS
           :WS-CURSOR-SCROLLABLE = DB2_SQL_ATTR_CURSOR_SCROLLABLE,
           :WS-CURSOR-TYPE       = DB2_SQL_ATTR_CURSOR_TYPE,
           :WS-CURSOR-SENSITIVE  = DB2_SQL_ATTR_CURSOR_SENSITIVITY
   END-EXEC
END-IF.

For scrollable cursor design rules, see Db2 Scrollable Cursor Guidelines for COBOL Programs.

Common Mistakes

  • Reading ROW_COUNT after another SQL statement has already run. The diagnostics area belongs to the previous eligible SQL statement.
  • Moving straight to CONDITION 2 without checking NUMBER.
  • Using a short character host variable for DB2_GET_DIAGNOSTICS_DIAGNOSTICS and then ignoring truncation.
  • Assuming DB2_NUMBER_ROWS is exact for every cursor. Sensitive dynamic cursors can make this value approximate.
  • Defining all targets as PIC X. Numeric items such as ROW_COUNT, NUMBER, and DB2_NUMBER_ROWS need compatible numeric host variables.

FAQ

Is ROW_COUNT the same as SQLERRD(3)?

They can overlap for common row-count cases, but GET DIAGNOSTICS ROW_COUNT is the direct statement-information item. Use your shop standard consistently and test the specific SQL statement type.

When should I use NUMBER?

Use NUMBER before reading condition information. It tells the program how many diagnostic condition records are available for the previous SQL statement.

Can GET DIAGNOSTICS be dynamically prepared?

No. In Db2 for z/OS, GET DIAGNOSTICS is an executable statement for embedded applications, and it cannot be dynamically prepared.

Keep the call close to the SQL statement you are diagnosing. If another SQL statement runs first, the diagnostic area may no longer describe the statement you meant to inspect.

New In-feed ads