Showing posts with label SQLCA. Show all posts
Showing posts with label SQLCA. 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 Application Environment: COBOL, DBRM, Package, Plan, and Runtime Flow



Last updated: July 2026

A COBOL program with embedded SQL does not run against Db2 just because the source compiled. The program must pass through precompile, compile, link-edit, bind, execution JCL, runtime libraries, and SQL return-code checks. A missing package, a wrong collection, or a stale plan can stop the job before the first business record is processed.

The Db2 application environment is the set of source members, DBRMs, packages, plans, load modules, subsystem settings, libraries, and runtime checks that let an application program use Db2 safely on z/OS.

Db2 application environment flow from COBOL source to precompile, compile link, bind, and runtime
Build and bind before the program runs.

What belongs in a Db2 application environment

For a Db2 for z/OS application, the environment usually includes developer source libraries, precompile output, DBRM libraries, load libraries, bind jobs, package collections, plans, runtime JCL, and operational logging. The exact names vary by shop, but the responsibilities are similar.

PartPurposeWhat to verify
COBOL sourceContains embedded SQL inside EXEC SQL and END-EXEC.Host variables, copybooks, SQLCA include, and indicator variables are correct.
Precompile stepSeparates SQL from COBOL and creates a DBRM.DBRM member name, SQL syntax, and precompiler options match the application standard.
Compile and link-editBuilds the executable load module.Correct compiler options, copybook libraries, and Db2 interface modules are available.
Bind package or planCreates the executable SQL control structure used by Db2.Collection, owner, qualifier, isolation, validation timing, and package/plan name are right.
Runtime JCL or online regionRuns the program under batch, CICS, IMS, or another execution path.Subsystem, libraries, plan or package reference, and error logging are correct.
SQLCA handlingReports SQL execution results back to the program.Program checks SQLCODE, SQLSTATE, warning flags, and row counts where needed.

Batch COBOL Db2 flow

A common batch flow starts with a COBOL source member, runs a Db2 precompile, compiles the modified COBOL, link-edits the load module, binds the DBRM into a package or plan, and executes the program through JCL. If one of those artifacts is out of sync, production can fail with package-not-found, authorization, or access-path problems.

//BINDPKG  EXEC PGM=IKJEFT01
//SYSTSPRT DD SYSOUT=*
//SYSTSIN  DD *
  DSN SYSTEM(DB2P)
  BIND PACKAGE(APP1COLL) -
       MEMBER(ACCTUPD) -
       ACTION(REPLACE) -
       ISOLATION(CS) -
       VALIDATE(BIND)
  END
/*

The bind job is not just a build step. It decides where Db2 will look for objects, which collection holds the package, when object checks happen, and what access path Db2 records for static SQL.

Online application paths

Batch is not the only application path. CICS and IMS programs can also call Db2, but the runtime setup is different. CICS needs the correct Db2 connection setup, transaction definition, program definition, and plan or package access. IMS regions need the correct dependent-region and Db2 attachment configuration.

For support work, the practical question is simple: which subsystem did the program connect to, which plan or package did it use, and what SQL return code came back?

Development, test, and production separation

Most shops keep separate Db2 subsystems or schemas for development, test, and production. The program name can stay the same while the collection, qualifier, or subsystem changes by environment. That is useful, but it also creates easy mistakes.

  • A test package might be rebound while production still uses an old access path.
  • A job might point to the wrong subsystem after a JCL copy.
  • A package collection might contain the right member name but the wrong version.
  • A static SQL change might be compiled but not bound.

Runtime checks inside the program

The application environment is incomplete without runtime validation. A program should include SQLCA handling and should check the SQL result close to the statement that produced it.

EXEC SQL
   INCLUDE SQLCA
END-EXEC.

EXEC SQL
   SELECT ACCT_STATUS
     INTO :WS-ACCT-STATUS
     FROM ACCOUNT
    WHERE ACCT_NO = :WS-ACCT-NO
END-EXEC.

EVALUATE SQLCODE
   WHEN 0
      PERFORM PROCESS-ACCOUNT
   WHEN +100
      PERFORM HANDLE-NOT-FOUND
   WHEN OTHER
      PERFORM WRITE-DB2-ERROR
      PERFORM ROLLBACK-WORK
END-EVALUATE.

That small check prevents a program from treating a missing row as a valid business result. For data-change SQL, add row-count checks when the program expects exactly one row or a known number of rows.

Common failure points

DBRM and load module are not from the same source level

This often happens when a compile runs but the bind step is missed. The load module contains the latest logic, while Db2 still executes SQL based on an older package.

Wrong collection or plan

A job can run the correct program and still use the wrong package collection. Check the bind cards, run JCL, and runtime messages together.

Authorization missing at bind or run time

Bind authorization and execution authorization are separate concerns. A developer may be able to compile a program but not bind or run against a protected table.

SQL warnings ignored

Warnings can indicate truncation or null-handling problems. Treat warning flags as part of the application contract, not as decoration.

Checklist before moving to production

  • Confirm the source, DBRM, load module, package, and plan names match the release package.
  • Confirm the bind ran in the correct Db2 subsystem with the intended collection and qualifier.
  • Confirm runtime JCL or online definitions point to the expected subsystem and libraries.
  • Confirm SQLCA handling logs SQLCODE, SQLSTATE, message tokens, program name, and business keys.
  • Confirm restart or rollback behavior for failed updates in batch jobs.

Related Db2 topics

Use this guide with Db2 Binding Application, Db2 Binding and Rebinding, Db2 Packages, Db2 SQL Execution Validation, and Db2 SQLCODE and SQLSTATE.

FAQ

What is a Db2 application environment?

It is the set of build, bind, runtime, and support components that allow an application program to execute SQL against Db2, including source, DBRM, package or plan, load module, subsystem, JCL, and SQLCA handling.

Why does a COBOL Db2 program need precompile and bind?

The precompile step extracts embedded SQL and creates a DBRM. The bind step turns that DBRM into executable SQL control information that Db2 can use at runtime.

What should be checked when a Db2 program fails in production?

Check the subsystem, package collection, plan, load library, bind timestamp, SQLCODE, SQLSTATE, message tokens, and the business key being processed when the failure occurred.

Db2 SQL Execution Validation: SQLCA, SQLCODE, Row Counts, and COMMIT Checks


Db2 SQL execution validation flow using SQL statement, SQLCA, SQLCODE, row count, and program action

Validate the SQL result before the next step.

A COBOL program can compile, bind, and start correctly, then still make a bad production decision if it ignores the result of the SQL statement it just ran. A singleton SELECT might return +100, a searched UPDATE might affect zero rows, or a warning flag might show that data was truncated into a host variable.

Db2 SQL execution validation is the application logic that checks those results before the next business step runs. For batch and online programs, that usually means checking SQLCODE, SQLSTATE, selected SQLCA fields, indicator variables, affected-row counts, and commit or rollback decisions.

What SQL execution validation means

Execution validation is not the same as syntax checking. The Db2 precompiler validates embedded SQL structure, and bind processing validates access paths and object references for static SQL. Runtime validation happens after each SQL statement runs inside the program.

At runtime, the program should decide whether the SQL result is expected, unexpected but recoverable, or a hard error. That decision must be close to the statement that caused it. When error handling is pushed to the end of a paragraph, the program often loses the table name, key value, and business context needed for useful diagnosis.

Fields most programs should check

Field or valueWhat to checkTypical program action
SQLCODE0, +100, warnings, and negative values.Continue, branch to no-data logic, log warning, or stop with an error path.
SQLSTATEFive-character class and subclass, useful for grouped error handling.Use with SQLCODE when you need portable or class-based handling.
SQLERRMCMessage tokens returned by Db2.Write it to an error log with the program name, table, and key fields.
SQLERRD(3)Commonly checked for affected-row count after searched UPDATE, DELETE, or INSERT processing. Confirm behavior for your statement and Db2 level.Reject a zero-row update when one row was required, or flag too many rows when a key should be unique.
SQLWARN fieldsWarning flags such as truncation or null assignment cases.Log and decide whether the warning is acceptable for that transaction.
Indicator variablesNull and truncation status for nullable columns.Prevent spaces, zeros, or old working-storage values from being treated as real data.

Validation pattern for singleton SELECT

A singleton SELECT INTO expects either one row or no row. Treating +100 as a normal zero-value result can create bad output files, missing customer records, or incorrect audit rows.

EXEC SQL
   SELECT ACCT_STATUS,
          CURRENT_BAL
     INTO :WS-ACCT-STATUS,
          :WS-CURRENT-BAL
     FROM ACCOUNT
    WHERE ACCT_NO = :WS-ACCT-NO
END-EXEC

EVALUATE SQLCODE
   WHEN 0
      PERFORM VALIDATE-ACCOUNT-DATA
   WHEN +100
      MOVE 'ACCOUNT NOT FOUND' TO WS-ERROR-TEXT
      PERFORM WRITE-APPLICATION-ERROR
   WHEN OTHER
      PERFORM WRITE-DB2-ERROR
      PERFORM ABEND-PROGRAM
END-EVALUATE

If nullable columns are selected, add indicator variables. Without them, the program may accept stale working-storage values after a null column is returned.

Validation pattern for UPDATE, INSERT, and DELETE

For data-change statements, SQLCODE = 0 only says Db2 accepted the statement. The program still needs to check whether the number of affected rows matches the business rule.

EXEC SQL
   UPDATE ACCOUNT
      SET ACCT_STATUS = :WS-NEW-STATUS
    WHERE ACCT_NO     = :WS-ACCT-NO
END-EXEC

EVALUATE SQLCODE
   WHEN 0
      IF SQLERRD(3) = 1
         PERFORM WRITE-AUDIT-ROW
      ELSE
         MOVE 'UNEXPECTED UPDATE COUNT' TO WS-ERROR-TEXT
         PERFORM WRITE-APPLICATION-ERROR
         PERFORM ROLLBACK-WORK
      END-IF
   WHEN +100
      MOVE 'NO ACCOUNT UPDATED' TO WS-ERROR-TEXT
      PERFORM WRITE-APPLICATION-ERROR
   WHEN OTHER
      PERFORM WRITE-DB2-ERROR
      PERFORM ROLLBACK-WORK
END-EVALUATE

For a key-based update, one affected row may be the only acceptable result. For a batch correction statement, thousands of rows may be expected. Code the expected count instead of assuming any successful SQLCODE is enough.

Cursor FETCH validation

A cursor loop usually has three valid paths: row found, end of cursor, and error. The program should not treat every non-zero SQLCODE as an abend, because +100 is the normal end-of-data signal for a FETCH.

PERFORM UNTIL WS-END-OF-CURSOR = 'Y'
   EXEC SQL
      FETCH C1
       INTO :WS-ACCT-NO,
            :WS-ACCT-STATUS
   END-EXEC

   EVALUATE SQLCODE
      WHEN 0
         PERFORM PROCESS-ACCOUNT
      WHEN +100
         MOVE 'Y' TO WS-END-OF-CURSOR
      WHEN OTHER
         PERFORM WRITE-DB2-ERROR
         PERFORM ROLLBACK-WORK
         MOVE 'Y' TO WS-END-OF-CURSOR
   END-EVALUATE
END-PERFORM

Commit and rollback checks

Transaction control belongs in the validation design. A batch job that updates 50,000 rows should know when to commit, what to do after a failed commit, and how much restart information has been written. An online program should avoid sending a success message before the unit of work is safely committed.

  • Check every SQL statement that changes data before issuing COMMIT.
  • Use ROLLBACK when a related update, insert, or delete fails inside the same unit of work.
  • Log the business key, program name, paragraph, SQLCODE, SQLSTATE, and SQLERRMC.
  • For restartable batch jobs, record the last committed key or checkpoint data.

Common mistakes

Checking only negative SQLCODEs

+100 can be correct for a cursor end, but wrong for a required singleton lookup. Warnings can also matter when host variables receive truncated values.

Ignoring affected-row count

An update that affects zero rows can still return a successful SQL execution path. The business rule decides whether zero rows is acceptable.

Logging only the SQLCODE

A production support team needs more than -803 or -911. Include table name, key values, module name, and message tokens where available.

Related Db2 topics

Use this article with Db2 SQLCODE and SQLSTATE, Db2 Application Environment, Db2 Data Types, Db2 Binding Application, and Db2 Utilities.

FAQ

Should a COBOL Db2 program check SQLCODE after every statement?

Yes. Every embedded SQL statement should have a nearby validation path so the program can handle success, no-data, warning, and error results with the correct business context.

Is SQLCODE +100 always an error?

No. For a cursor fetch, +100 usually means end of cursor. For a required singleton lookup, it may mean the application cannot continue safely.

When should SQLERRD(3) be checked?

Check it when the program must confirm how many rows were affected by a data-change statement. Confirm the exact meaning for your SQL statement and Db2 version.

Db2 SQLCODE and SQLSTATE: SQLCA Return Codes for COBOL Programs


Db2 SQLCODE SQLSTATE and SQLCA return code checks for COBOL programs
Check SQLCODE after each Db2 statement.

SQLCODE +100 is not the same as a failed SELECT. It means no row was found, and a COBOL program often has to handle that path cleanly. A negative SQLCODE is different: it means the SQL statement failed and the program should not continue as if the data is valid.

Db2 returns SQL status information through the SQLCA, including SQLCODE, SQLSTATE, warning flags, row counts, and diagnostic text. Good programs check those fields immediately after each SQL statement that matters.

SQLCODE quick meaning

SQLCODE valueMeaningProgram action
0Statement completed successfullyContinue normal processing.
> 0Statement completed with a warning or special conditionHandle the specific code. +100 is common for no row found.
< 0Statement failedLog SQLCA details and take the error path.

SQLSTATE quick meaning

SQLSTATE is a five-character return code. The first two characters identify a class, and the last three identify a subclass. It is useful when code needs a standard status check across database products, while SQLCODE often gives Db2-specific detail.

SQLSTATE classGeneral meaning
00Successful completion
01Warning
02No data
Other classesError or condition that must be checked against Db2 message documentation

Important SQLCA fields

FieldUse
SQLCODEPrimary numeric return code checked by many COBOL programs.
SQLSTATEFive-character status code useful for standard classes.
SQLERRMCMessage tokens that can identify object names or values related to an error.
SQLERRDDiagnostic integers; one common use is row count after some SQL operations.
SQLWARNWarning indicators, such as truncation or null-related conditions.

COBOL SQLCODE handling pattern

EXEC SQL
    SELECT CUSTOMER_NAME
      INTO :WS-CUSTOMER-NAME
      FROM CUSTOMER
     WHERE CUSTOMER_ID = :WS-CUSTOMER-ID
END-EXEC.

EVALUATE SQLCODE
    WHEN 0
        CONTINUE
    WHEN +100
        MOVE 'N' TO WS-CUSTOMER-FOUND
    WHEN OTHER
        DISPLAY 'DB2 ERROR SQLCODE=' SQLCODE
        DISPLAY 'SQLSTATE=' SQLSTATE
        DISPLAY 'SQLERRMC=' SQLERRMC
        PERFORM ABEND-ROUTINE
END-EVALUATE.

Do not bury this check far away from the SQL statement. When a production issue happens, the fastest clue is often the exact statement, SQLCODE, SQLSTATE, and message tokens written together.

Common mistakes

  • Treating +100 as a fatal error when it is a normal no-row path for the program.
  • Ignoring positive warning codes because only negative codes stop the job.
  • Checking SQLCODE after several statements instead of immediately after the statement that set it.
  • Logging only SQLCODE and losing SQLSTATE or SQLERRMC details.
  • Continuing after a negative SQLCODE and writing output records from invalid host variable values.

Related DB2 topics

SQLCODE handling connects to Db2 SQL Execution Validation, Db2 Application Environment, Db2 Data Types, Db2 Triggers, and Db2 DSN Command Reference.

FAQ

Is SQLCODE +100 an error?

No. +100 means no row was found or no more rows are available. It is often a normal branch in SELECT and cursor logic.

Should COBOL check SQLCODE or SQLSTATE?

Many Db2 COBOL programs check SQLCODE first because it gives Db2-specific detail. SQLSTATE is useful for standard status classes and cross-product logic.

Where is SQLCODE stored?

When the SQLCA is included, Db2 places the return code in the SQLCA field SQLCODE. Some precompiler options can also use standalone SQLCODE and SQLSTATE host variables.

The rule is simple enough to save a batch night: check the SQL return status before trusting the host variables.

New In-feed ads