Anda di halaman 1dari 56

Introducing your COBOL

programs to DB2 version 8

David Churn
DST Systems, Inc.

16 October 2008 • 09:00 – 10:00


Platform: DB2 for z/OS

It is supposed to be easy to change your existing programs from single row to


multiple row fetch. There are some difficulties involved in this process
especially when it is a COBOL program. This presentation will take you
through the issues that have been encountered and how DST solved them.
Coding examples and some suggested standards will be included.

1
The Five Points
• SQL in COBOL
• Array handling
• Using GET DIAGNOSTICS
• Unit of work
• Mixing in other SQL features

Greetings!

There are other good feature in v8 that will speed performance but do not impact
how COBOL programs are written. Features like scalar full-SELECT and common
table expressions have an impact on the program’s SQL only. They will not be
covered in this presentation.

2
Disclaimer
• The information is presented “as is” without any
warranty either expressed or implied. The use of
this information is the client’s responsibility.
• All information in this presentation relates to DB2
Version 8 and COBOL version v3r4.
• COBOL programs were developed on z/OS
mainframe using TSO and ISPF.

3
About DST Systems
http://www.dstsystems.com
• Leading provider of computer software solutions
and services, NYSE listed – “DST”
• Revenue $2.24 billion
• 110 million+ shareowner accounts

• 24,000 MIPS
• 150 TB DASD
• 145,000 workstations
• 462,000 DB2 objects
• Non-mainframe: 600 servers (DB2, Oracle,
Sybase) with 2.3 million objects
.
4

If you have ever invested in a mutual fund, have had a prescription filled, or are a
cable or satellite television subscriber, you may have already had dealings with our
company.

DST Systems, Inc. is a publicly traded company (NYSE: DST) with headquarters in
Kansas City, MO. Founded in 1969, it employs about 12,000 associates
domestically and internationally.

The three operating segments - Financial Services, Output Solutions and Customer
Management - are further enhanced by DST’s advanced technology and e-
commerce solutions.

4
DST associate mix
• Applications Development
• Database Administrators
• Database Consultants

Developers
Project Leaders
Analysts
Programmers
DBA DB Consulting
hundreds tens ones

Our development staff is heavily slanted toward application development. Most


enhancements are coded by the applications area to provide new functionality. Application
Developers code their own SQL and are responsible for checking the EXPLAIN
information.

DBAs assist with the enhancements and handle implementing changes to each production
system’s database. They review new SQL and assist with designing indexes as needed.

Database Consulting assists with SQL development on a project basis and assisting our
trainers. One of our goals as Database Consultants is to pass along best coding practices to
the developers. Database Consultants evaluate new features of DB2 and write the standards
for DB2 and COBOL.

5
SQL in COBOL

This section gives an overview of the new features added to SQL in version 8 that
impact how a COBOL program is written. The largest coding change comes from
the new multiple row functions for SELECT and INSERT.

6
DB2 v8 gives COBOL programs the ability to define larger fields and data inside the program. COBOL has a
full size CURSOR name takes 3 lines using the ISPF editor on TSO. A full size character constant takes 546 l

7
SQL continuation
• Word/literal occupies column 72
• Next line has
• Hyphen in column 7
• Spaces in 8 through 11
• Followed by remainder of word/literal
• Character literal requires a quote
7 12 72
| |
EXEC SQL INSERT INTO tbl(column1,colum
- n2, column3, column4)
VALUES ( 0123
- 45, ‘chara
- ‘cter literal’)
END-EXEC.
8

Even with only 60 characters on a line, it was a rare need to know these rules. With most DB2 object having m

8
Binary Numbers – TRUNC(STD)
• COMP, COMP-4 and USAGE BINARY are synonyms
for truncating binary.
• Truncation happens when field
• Receives data from a MOVE
• Arithmetic result
• COMP-5 indicates no truncation.

S9(4) COMP = -9999 to +9999 2 bytes


S9(9) COMP = -999,999,999 to +999,999,999 4 bytes

S9(4) COMP-5 = -32768 to +32767 2 bytes


S9(9) COMP-5 = -2147483648 to +2147483647 4 bytes

The COBOL standard states that numeric fields must be truncated to their picture
clause. This is sometimes referred to as the ‘odometer effect’. A two byte binary
field can contain a minimum value of -32768 and a maximum of +32767. Because
the field is defined as PIC S9(4) COMP, COBOL will limit them to 4 digits.

DST standard; use COMP-5 for


SMALLINT
INTEGER
VARCHAR lengths
Null indicators

Note: This applies when the COBOL compiler option TRUNC(STD) is set. It may
apply for TRUNC(OPT). It does not apply with TRUNC(BIN). Consult the
COBOL for zOS Programming Guide for more details.

9
Largest numbers
• Largest COBOL numeric picture
• S9(31) COMP-3
• S9(1)V9(30) COMP-3
• z(30)9
• z,zzz,zzz,zzz,zzz,zzz,zzz,zzz,zzz,zzz,zz9
• Largest DB2 numeric
• DECIMAL(31,0)
• COBOL and DB2 math use 31 digits of precision
• Precompiler parm DEC(31)
• Compiler parm ARITH(EXTEND)

10

Without using the parms above, the largest COBOL numeric field can be 18 digits
and the largest DB2 numeric field can be 15 digits. These smaller parms are faster
than the 31 digits parms.

The smaller compiler parms are


Precompiler DEC(15)
Compiler ARITH(COMPAT)

If the program has a multi-operation math statement, then the compiler parms also
specify the number of digits used for the intermediate results.

10
Definitions
• Array: A group of things arranged in a structured way.
In COBOL, a WORKING-STORAGE field with OCCURS.
• Copybook: predefined COBOL instructions that can be
added to a program with either the COPY or EXEC SQL
INCLUDE instructions.
• Host Variable: COBOL field, in either
WORKING-STORAGE or LOCAL-STORAGE
• Host Variable Array: An array that is used in SQL as a
host variable.
• Restartable: Functionality in a program that lets it start
over after an error situation.
• Unit of Work: point where one piece of work is
considered done.

11

These define the terms used in this presentation which can have different meaning
in another context. For this presentation, table means a DB2 table.

11
Multi-row Fetch/Insert
• Fetch or Insert up to 32,767 rows in one statement
• Fewer calls to DB2
• Use arrays instead of fields
• Requires more memory
• Limit the number returned for CICS
• Request the same or fewer rows than defined in the
OCCURS, but not more.
• Increases program complexity
• Additional perform loop level
• More error handling code

12

Our current production COBOL compiler v3r4 expanded the maximum size of an
01 level item to 128Mb while leaving the total size of all working-storage at
128Mb.

CICS programs need to manage the amount of memory they are going to use. For
batch programs DST defines all columns in a table with the same number of
occurrences for each column and null indicator. If a CICS program is only going to
use a few columns from a table with hundreds of columns, then we examine how to
reduce the extra unused memory.

12
If the program requests 100 rows but DB2 returns only 10 rows, the program performs like
it requested 10 rows. Some knowledge of the data is needed to evaluate whether to use
multi-row FETCH.

recommendation = Use Multi-row fetch when a cursor typically returns 4 or more rows.

13
Multi-row Fetch SQL syntax
Cursor Definition Example
DECLARE MEANINGFUL_NAME CURSOR
WITH ROWSET POSITIONING FOR
SELECT …
Fetch Example
FETCH NEXT ROWSET FROM MEANINGFUL_NAME
FOR numeric literal ROWS
INTO :hv-array1, :hv-array2 …
OR
FETCH NEXT ROWSET FROM MEANINGFUL_NAME
FOR :hv ROWS
INTO :hv-array1, :hv-array2 …

14

When the number of rows is not given multi-row FETCH defaults to 1 row.

A program cannot tell DB2 which occurrences to populate in a FETCH. If the program fetches 20 rows in

14
Recommend Multi-row Fetch
• More than 4 rows per fetch
• Program is designed for multi-row FETCH
• Driving cursor defined WITH HOLD
• Fetch 100 rows
• Process all rows
• End unit of work (COMMIT)
• Entire cursor process is within a single unit of work.
• Open cursor
• All rows processed completely
• Close cursor
• Start-up array loading cursors

15

Since coding for a multi-row fetch CURSOR is more complex than using a single row CURSOR, we evalu

15
Avoid Multi-row Fetch
• Added complexity without clear savings
• Program does not have a clear unit of work
• Burying multi-row functionality inside fetch routine
OPEN *=same routine
FETCH*
UPDATE
program PROCESS Check
(1) (x) COMMIT Get more rows?
FETCH* MR-FETCH
Give row
CLOSE
16

Fetch time is typically only a small part of the total program time. Even an 55% improvement of 10 seconds i

Programs that have no clear Logical Unit of Work are more difficult to change. It may even be impossible to

Multi-row SELECT works better when it is designed into the program from the beginning. Burying multi

16
If the program requests 100 rows but DB2 returns only 10 rows, the program performs like
it requested 10 rows. Some knowledge of the data is needed to evaluate whether to use
multi-row INSERT.

recommendation = Use Multi-row insert when a unit-of-work typically inserts 15 or more


rows to a table.

17
Multi-row Insert Syntax
• Atomic (default)
• Severe error (negative SQLCODE) rolls back
entire INSERT
• Stops on first error
• Easier logic to reposition for restart

EXEC SQL INSERT INTO table (column list)


VALUES (value list, host variable arrays)
FOR :hv ROWS
ATOMIC
END-EXEC
18

When a program performs a multi-row INSERT using the ATOMIC option, DB2 behaves according to the
•An error rolls back the entire INSERT but only the INSERT.
•DB2 stops checking for errors after it finds the first failed row. There will be only 1 error returned.
•A COBOL program is easier to code restart and reposition logic using the ATOMIC option.

18
Multi-row Insert Syntax
• Not Atomic
• No rollback
• Does not stop
• Restarting can be difficult
• New SQLCODEs and SQLSTATEs

EXEC SQL INSERT INTO table (column list)


VALUES (value list, host variable arrays)
FOR :hv ROWS
NOT ATOMIC CONTINUE ON SQLEXCEPTION
END-EXEC
19

When a program performs a multi-row INSERT using the NOT ATOMIC option, DB2 behaves according to
•DB2 can get multiple errors on the INSERT. The program needs to use GET DIAGNOSTICS to report the e
•The code is more complex to restart a program using the NOT ATOMIC option.
•This type of INSERT is ideal for a program where the only response to an error is to save the row, skip over i

DB2 will return one of the four SQLCODEs when a program does a multiple row fetch. To determine the ind
•All successful – SQLCODE = +0, SQLSTATE = 00000
•All successful but warnings – SQLCODE = +252, SQLSTATE = 01659
•At least one (but not all) failed –SQLCODE = -253, SQLSTATE = 22529
•All failed – SQLCODE = -254, SQLSTATE = 22530

19
Recommend Multi-row Insert
• More than 15 rows per insert
• Many Inserts on single table
• Inserting is the only process in the program
• Like load utility without the outage
• Many inserts within a unit of work

20

recommendation = Use multi-row insert when the primary purpose of the program is to insert--especially w

Using ATOMIC or NOT ATOMIC options are based on the application logic. To date most have been ATOM

20
Avoid Multi-row Insert
• Multiple tables are changed
• If some/all rows fail (ATOMIC), how does the
program back out the other changes related to
those rows?
• If some rows fail (NOT ATOMIC), how does the
program back out only the changes related to the
failed rows?
• Do not delay commits for the purpose of building up a
host variable array.

21

The program should change other tables after the multi-row insert. So when the program is doing ATOMIC in
changes only to successful rows. All this logic will add time to the coding and testing of the program.

Artificially delaying commits defeats the purpose of commit checks—reducing rollback time and contention w

21
Array Handling
Multi-row FETCH and INSERT
It is not about the SQL.
It is about the COBOL!

22
Host Variable Arrays
• SQL references arrays of elements
01 DCL-EMPLOYEE-20.
05 EMPLOYEE-ID PIC S9(5)COMP-3
OCCURS 20 TIMES.
05 COMMENT-TXT OCCURS 20 TIMES.
49 COMMENT-TXT-LEN PIC S9(4) COMP-5.
49 COMMENT-TXT-TEXT PIC X(255).

• SQL cannot reference a group item array.


01 EMPLOYEE-TABLE.
03 DCL-EMPLOYEE-20 OCCURS 20 TIMES.
05 EMPLOYEE-ID PIC S9(5) COMP-3.
05 COMMENT-TXT.
49 COMMENT-TXT-LEN PIC S9(4) COMP-5.
49 COMMENT-TXT-TEXT PIC X(255).
23

DB2 requires that an array is created for each column used in a SELECT. COBOL has been optimized to proc
instructions than the second example. If many fields are defined in the group item (01) then the performance

DST uses standardized host variable arrays that are created for multi-row functions. If the copybook is used in
Other OCCURS sizes can be used but need justification.

23
New Multi-row copybooks
• DCLGEN does not build multi-row copybooks.
• May require two copy books
• WHERE clause references single column definitions
• FETCH INTO references host variable arrays
• Remember group item lists

24

The standard DCLGEN process included with SPUFI will not generate a table definition
where the COBOL fields have the OCCURS clause. Either someone will have to change
the generated copybook or someone will need to write something produce the fields to be
used in a multi-row function.

There may be a need to have both a single row and a multi-row versions of the copybook.
SQL WHERE clauses can only reference one type of array. SQL cannot reference one
occurrence of an array item.

The only COBOL can pass an array is for an IN list. The array has to be defined as follows.
Each elementary item is required to have a name even if the value is constant.

01 HV-CUST-INITIALS.
05 HV-INIT1-TX PIC X(3) VALUE SPACE.
05 HV-INIT2-TX PIC X(3) VALUE SPACE.
05 HV-INIT3-TX PIC X(3) VALUE SPACE.
05 HV-INIT4-TX PIC X(3) VALUE SPACE.
05 HV-INIT5-TX PIC X(3) VALUE SPACE.
05 HV-INIT6-TX PIC X(3) VALUE SPACE.

PROCEDURE DIVISION.
24

Array Handling Restrictions
• Use subscripts to access one row from multiple tables
• COMP vs. COMP-5 (COMP is faster)
• Updating many indexes is slower than one subscript
• Cannot use variable length arrays
• OCCURS DEPENDING ON rejected by precompiler
and coprocessor
• SEARCH and SEARCH ALL will search entire array
• Must be visible to the SQL precompiler.
• Cannot use COPY … REPLACING
• Initializing groups of arrays is slower than initializing one
array with many fields.

25

There are many different ways to process COBOL arrays. We found that
using subscripts was the best way to handle the occurrences with many host
variable arrays. We also found that all host variable arrays need to be fixed
length even though it makes the SEARCH or SEARCH ALL statements
process the entire array.

It is faster for COBOL to access an array with an index instead of a subscript.


If there are multiple columns inside host variable arrays, then the faster speed
is lost to updating multiple indexes instead of one subscript. A program will
compile using the same name for multiple indexes as long as it does not
reference the name. A program will not compile using an INDEXED BY
clause reference another index.

Host variable arrays must be visible to the SQL processor. For programs using the
precomiler, host variable arrays must be defined in the program or included in the
program with EXEC SQL INCLUDE. Programs using the coprocessor can use the
COPY and could change the number of rows using the following statement.
COPY DATYP REPLACING ==OCCURS 20== BY ==OCCURS 40==.

There are fewer Assembler instructions created for initializing one array with
multiple fields instead of initializing many host variable arrays.

25
COBOL Array Handling
• SEARCH WHEN clause is limited to one element
SEARCH EMPLOYEE-ID [will vary its index]
AT END
(at end code)
WHEN EMPLOYEE-ID (EMPLOYEE-IDX) = ws-employee-id
AND WORK-DTE (WORK-DTE-IDX) = ws-work-dte
(when found code)
END-SEARCH

• WORK-DTE-IDX will not be incremented by the


SEARCH verb.
• The program compiles successfully, but will produce
incorrect results if it requires automatic incrementing.

26

When a program has fetched data into host variable arrays and there is a multiple column key, the program ca

A custom routine must be coded to find the right row.

26
Multi-row Fetch data
• When fetched, null columns do not update the
column host variable – only the null indicator.
ID Name Account Null 1st 8 row FETCH
1
9 David
Jim Churn
Smith 100
135 0 SQLCODE=0
SQLSTATE=00000
2 John
10 DavidSmith
Churn 200 0
-1
SQLERRD(3) = 8
3 Harry
11 Henry Thompson
Jones 46
357 0
2nd 8 row FETCH
12
4 Kathy
Henry Winters
Jones 579
24680 0 SQLCODE=+100
5 Henry Jones 25000 0 SQLSTATE=02000
6 Jean Smith 76 0 SQLERRD(3)=4
7 Jean Smith 234 0 Last 4 rows are
carry over from the
8 Jim Smith 1000 0 last FETCH
27

When working with nullable columns it is still important to define and check the
null indicator. It would not be good to mix up John Smith’s money with David
Churn’s account.

27
Moving VARCHAR
• For VARCHAR columns, move only the bytes that
DB2 populated.
• Move source (start,length) to destination
MOVE text-field OF DCL-xxx-Mnnn (1:
text-len OF DCL-XXX-Mnnn)
TO

• Becomes move source (sub) (start:length) to …


MOVE text-field OF DCL-xxx-Mnnn (sub) (1:
text-len OF DCL-XXX-Mnnn (sub) )
TO

28

Like null indicators, a program should move variable length fields for the length that DB2 returned. Subscript

28
Process loops
Old New
2000-PROCESS. 2000-PROCESS.

PERFORM 2100-OPEN-CURSOR PERFORM 2100-OPEN-CURSOR


PERFORM 2200-FETCH PERFORM UNTIL END-OF-CUR
PERFORM UNTIL END-OF-CUR PERFORM 2200-FETCH
ADD +1 TO FETCH-COUNT PERFORM 6000-WRITE VARYING
PERFORM 6000-WRITE EMPLOYEE-SUB FROM +1 by +1
PERFORM 2200-FETCH UNTIL EMPLOYEE-SUB >
END-PERFORM SQLERRD(3)
PERFORM 2300-CLOSE-CURSOR ADD SQLERRD(3) TO FETCH-COUNT
END-PERFORM
PERFORM 9600-CHECK-UOW PERFORM 2300-CLOSE-CURSOR
PERFORM 9000-READ
PERFORM 9600-CHECK-UOW
PERFORM 9000-READ

29

There are two changes to the potential program’s logic. 1) The priming FETCH is eliminated. 2) The 6000

This New example is not the best way to actually code it but is a good way to illustrate the change. In actual c

29
Multi-row Fetch Caution
• Non-rowset fetch puts ID Name
data in first occurrence
1 David Fetch 3 rows
• Mixing rowset and non-
rowset fetchs gives 2 Gordon Fetch next
unobvious results
• Fetch more rows than 3 Jim Fetch 3 rows
array occurrences 4 Mike Fetch 3 rows
gives SQLCODE=+354
SQLSTATE=01668 5 Suresh
6 Thomas

30

When a program only uses multi-row fetch, rows are returned in a predictable fashion.
The first Fetch 3 rows returns David, Gordon, and Jim.
The second Fetch 3 rows returns Mike, Suresh, and Thomas.

When a program adds a FETCH NEXT in between the Fetch 3 rows it give the following results.
The first Fetch 3 rows returns David, Gordon, and Jim.
The Fetch next returns Gordon.
The second Fetch 3 rows returns Jim, Mike, and Suresh.
This could cause the program to process the rows for Gordon and Jim twice.

30
Using Where Current
• UPDATE/DELETE… WHERE CURRENT...
• Changes behavior based on last FETCH
• UPDATE/DELETE WHERE CURRENT OF..FOR ROW
x OF ROWSET
• Update/Deletes a specific row of the rowset
• Restartable cursors must have an ORDER BY
• Cursors with ORDER BY cannot use WHERE
CURRENT

31

If positioned on a single row (previous fetch was regular), then DB2 updates/deletes
single row

If positioned on a rowset (previous fetch was ROWSET … FOR n ROWS), then


DB2 updates/deletes entire set of rows

If you mix and match row and rowset fetches in your program, the program could
have DB2 accidentally update or delete a rowset instead of a single row!

31
Multi-row Insert Feature
• A non-array column has the same value for ALL
rows
• In the following example, ID and name are simple
host variables, not host variable arrays.
05 HV-ID PIC S9(7) COMP-3 VALUE ZERO.
05 HVA-ACCOUNT PIC S9(15) COMP-3
OCCURS 100 TIMES VALUE ZERO.
05 HV-NAME PIC X(100) VALUE SPACES.
05 HVA-AMOUNT PIC S9(11)V99 COMP-3
OCCURS 100 TIMES VALUE ZERO.

INSERT INTO TABLE (id, account, name, amount)


VALUES (:hv-id, :hva-account, :hv-name, :hva-amount)
FOR :hv-num-rows ROWS ATOMIC

32

Multi-row INSERTs do not have to use host variable arrays for every column. If the value
for all rows will be the same, then the program could use a non-array COBOL field to save
the one value.

Like the multi-row FETCH, DB2 always starts with the first occurrence of a host variable
array. There is no way to tell DB2 to start with any other occurrence. The program should
always set the number of rows inserted. If it tells DB2 insert 4 rows from an array of 8
rows, the first 4 occurrences will be used, the remaining 4 occurrences will be ignored.

32
Multi-row Insert Caution
• Formatting everything
• Null indicators
• VARCHAR lengths
• Number of rows in INSERT
• Error handling in loops
• Group moves to or from the host variable arrays

33

Like a single INSERT, verify that all the indicators and lengths are set right in the host variable arrays. The p

There will be more logic to process errors from inserting multiple rows. Displaying information from the SQL

If programs usually move a row’s information in one group move, they will have to change to individual mov

33
Using GET DIAGNOSTICS

What happened?!?

34
GET DIAGNOSTICS
• EXEC SQL GET DIAGNOSTICS identifies
• number of messages
• each message’s SQLCODE and SQLSTATE
• row number in the host variable array
• Calling GET DIAGNOSTICS returns an SQLCODE
and refreshes the SQLCA

35

It is possible to get multiple warnings as well as an error on one row. Whenever a


program uses a multi-row fetch or multi-row insert, it should also use GET
DIAGNOSTICS.

35
Multi-row Fetch Results
• Success, SQLCODE=0, SQLSTATE=00000
• 1 serious error
• “regular” message, SQLCODE=negative
• GET DIAGNOSTICS will repeat error
• One to many warnings
• Overall warning - SQLCODE=+354,
SQLSTATE=01668
• Multiple warning conditions
• GET DIAGNOSTICS needed to expose messages
• Check SQLERRD(3) for rows returned

36

If the program just reports on information in the SQLCA, then it may be hard to determine what happened.

SQLCODE=+354, SQLSTATE=01668
A ROWSET FETCH STATEMENT RETURNED ONE OR MORE ROWS OF DATA, WITH ONE OR MORE BIND CON
Explanation: A rowset FETCH statement returned one or more rows of data, however, one or more bind out processing error condit

All of the following conditions will cause a multi-row FETCH to return an SQLCODE=+354
•Nulls were bypassed for an aggregate function for row 3, 1 message results
•Date was adjusted occurs for row 9, 1 message results
•rows 3, 9, and 45 have nulls in a column but the program does not have a null indicator. 1 message fo
•6 errors result! 3 missing null-indicator, 1 nulls bypassed, 1 date adjusted and (1) 01668 (the program

36
For Multi-row Insert
• ATOMIC
• Error handling does not change
• NOT ATOMIC CONTINUE ON SQLEXCEPTION
• SQLCODE=+252, SQLSTATE=01659, success
with warnings
• SQLCODE=-253, SQLSTATE=22529, one or
more rows in error
• SQLCODE=-254, SQLSTATE=22530, all rows
failed
• EXEC SQL GET DIAGNOSTICS to see the
results for each failed row

37

Whether the program gets multiple errors depends on the atomicity of the INSERT.
A program can get one error with an ATOMIC multi-row INSERT. A program can
get multiple errors with a NOT ATOMIC multi-row INSERT. The SQLCODE
passed back in the SQLCA is as useful as the one for multi-row FETCH.

37
GET DIAGNOSTICS
• How many errors?
EXEC SQL GET DIAGNOSTICS
:hv1 = NUMBER
,:hv2 = DB2_LAST_ROW
,:hv3 = MORE
END-EXEC.

• Specific condition information


EXEC SQL GET DIAGNOSTICS CONDITION 1 (or :hv)
:GD-RETURNED-SQLSTATE = RETURNED_SQLSTATE
, :GD-DB2-RETURNED-SQLCODE = DB2_RETURNED_SQLCODE
, :GD-DB2-REASON-CODE = DB2_REASON_CODE
, :GD-DB2-ROW-NUMBER = DB2_ROW_NUMBER
END-EXEC.

38

GET DIAGNOSTICS can return general information about errors, or information about a specific error. This
specifics on each error. Unlike DSNTIAR this is another call to DB2 and should use SQLCODE checks after

These are the options that are useful when determining how many errors are present.
•NUMBER returns an integer – the number of conditions identified.
•DB2_LAST_ROW returns an integer – it will contain +100 if the last operation was a multi-row fetch that re
•MORE returns a Y/N indicator where Y means there was more error information available than could be retu

Specifics
•The program should use a perform loop to acquire all of the error information.
•This statement acquires the sqlstate, sqlcode, reason code (sub reason) and row number associated with a spe
•The program can hard code a condition number or can use a host variable.

38
DST Usage
• Copybooks
• WORKING-STORAGE or LOCAL-STORAGE
(copy in the notes)
• PROCEDURE DIVISION
• PERFORM 9970-MR-DIAGNOSTICS

39
01 WS00730 SYNC.
05 GET-DIAGNOSTICS-SQLSTATE PIC X(5) VALUE ZEROS.
05 GD-TOO-MANY-ERRORS PIC X VALUE 'N'.
88 DB2-TOO-MANY-ERRORS VALUE 'Y'.
05 LAST-ROW-SQLCODE PIC S9(9) COMP-5 VALUE ZERO.
88 LAST-ROW-FETCHED VALUE +100.
05 NUM-ERROR-INFO PIC S9(4) COMP VALUE ZERO.
05 ROW-ERROR-INFO OCCURS 500 TIMES.
*500 should be sufficient for 100 fetch/insert (subject
* To change)
10 ROW-SQLCODE PIC S9(9) COMP-5 VALUE ZERO.
10 ROW-REASON-CDE PIC S9(9) COMP-5 VALUE ZERO.
10 ROW-SQLSTATE PIC X(5) VALUE ZEROS.
10 ROW-NUMBER PIC S9(5) COMP-3 VALUE ZERO.
* TEMP WORKING VARIABLES
05 DB2-NUMBER-OF-ERRORS PIC S9(9) COMP-5 VALUE ZERO.
05 DB2-RETURNED-SQLCODE PIC S9(9) COMP-5 VALUE ZERO.
05 DB2-REASON-CODE PIC S9(9) COMP-5 VALUE ZERO.
05 DB2-RETURNED-SQLSTATE PIC X(5) VALUE SPACES.
05 DB2-ROW-NUMBER PIC S9(31) COMP-3 VALUE ZERO.
05 DB2-CONDITION-NUMBER PIC S9(4) COMP-5 VALUE ZERO.

39
* THIS MACRO IS USED FOR EXEC SQL GET DIAGNOSTICS ERROR
* PROCESSING.
*
* PROGRAM SHOULD PERFORM 9970-MR-DIAGNOSTICS AFTER ANY
ZC0068 logic
* MULTI-ROW EXEC SQL STATEMENT RETURNS AN ERROR.
*
• Issues GET DIAGNOSTICS to obtain
9970-MR-DIAGNOSTICS.
• The number of conditions
MOVE ZERO TO NUM-ERROR-INFO OF WS00730.
• The previous statement’s sqlstate
EXEC SQL • Whether more errors occurred than could be
GET DIAGNOSTICS
reported (copybook limit Is 500 errors)
• Performs a loop to obtain each=error’s
:WS00730.DB2-NUMBER-OF-ERRORS NUMBER
• SQLCODE
, :WS00730.LAST-ROW-INDICATOR = DB2_LAST_ROW
• SQLSTATE
, :WS00730.GD-TOO-MANY-ERRORS = MORE
• Return code
END-EXEC.
• Row number
• Populates the array of error information within the
MOVE SQLSTATE
WS00730CTO GET-DIAGNOSTICS-SQLSTATE
copybook OF WS00730
IF GET-DIAGNOSTICS-SQLSTATE OF WS00730 = ZEROS
40

* LIMIT RETURNED ERRORS TO 500.


IF DB2-NUMBER-OF-ERRORS > +500
SET DB2-TOO-MANY-ERRORS OF WS00730 TO TRUE
MOVE +500 TO DB2-NUMBER-OF-ERRORS OF WS00730
END-IF

* DB2 BUILDS THE ERROR/CONDITION INFORMATION IN REVERSE ORDER


* SO WE WILL BUILD OUR LIST OF INFORMATION BACKWARDS
* SO THE ERRORS APPEAR IN THE ORDER THEY OCCURRED.
PERFORM VARYING DB2-CONDITION-NUMBER OF WS00730
FROM DB2-NUMBER-OF-ERRORS OF WS00730 BY -1
UNTIL DB2-CONDITION-NUMBER < 1
OR SQLSTATE NOT = ZEROS

EXEC SQL GET DIAGNOSTICS CONDITION


:WS00730.DB2-CONDITION-NUMBER
:WS00730.DB2-RETURNED-SQLSTATE = RETURNED_SQLSTATE
,:WS00730.DB2-RETURNED-SQLCODE = DB2_RETURNED_SQLCODE
,:WS00730.DB2-REASON-CODE = DB2_REASON_CODE
,:WS00730.DB2-ROW-NUMBER = DB2_ROW_NUMBER
END-EXEC
MOVE SQLSTATE TO GET-DIAGNOSTICS-SQLSTATE OF WS00730 40
Sample Program Logic
• Design a process to handle the messages.
• Consider
• Can the program continue?
• What has been rolled back?
• Multi-row FETCH
• Multi-row INSERT
• Atomic vs. Not Atomic
• Are other processes dependent on this data?
• Sample code to display gathered messages

41

This logic will display the errors gathered from the include book code.

Sample DISPLAY loop


PERFORM VARYING DB2-CONDITION-NUMBER OF WS00730
FROM +1 BY +1
UNTIL DB2-CONDITION-NUMBER OF WS00730
> NUM-ERROR-INFO OF WS00730
DISPLAY 'ROW NUMBER : ' ROW-NUMBER OF WS00730
(DB2-CONDITION-NUMBER OF WS00730)
DISPLAY 'SQLSTATE : ' ROW-SQLSTATE OF WS00730
(DB2-CONDITION-NUMBER OF WS00730)
DISPLAY 'SQLCODE : ' ROW-SQLCODE OF WS00730
(DB2-CONDITION-NUMBER OF WS00730)
DISPLAY 'REASON-CDE : ' ROW-REASON-CDE OF WS00730
(DB2-CONDITION-NUMBER OF WS00730)
DISPLAY 'ROW CONTENTS : ' UPON CONSOLE
(put DISPLAY OF HOST VARIABLE ARRAY CONTENT here)
END-PERFORM

41
Unit of work

42
Restartability
• Why restart? DB2 rollback costs twice as much as the
actual change (insert, update, or delete)
• Restart concept
• Where does the unit of work begin and end
• Determine what triggers an end to a unit of work.
• Next row from driving cursor
• Change in control break field value
• End of file condition
• Must be designed into the program
• Do other changes COMMIT before multi-row INSERT?
• How does the program reposition during restart?
43

Maintainable units of work do not just happen. The associate writing the program has to figure out where they

When the program does not have an apparent unit of work, it is difficult to enhance the program. It may be im

If you cannot identify the beginning and ending of the Unit Of Work, you cannot “sneak” in a multi-row opera
If a Unit of Work ends before the program completes a multi-row insert, the insert will become part of
If a Unit of Work ends before the program completely processes all the rows fetched from a multi-

43
Mass Inserts
Instead of Try
{Priming Read} {Priming READ}
PERFORM UNTIL EOF PERFORM UNTIL EOF
MOVE fields MOVE ZERO TO WS-NUMBER-TO-INSERT
INSERT PERFORM VARYING x FROM +1 BY +1
CHECK COMMIT UNTIL x > +100 OR EOF
READ MOVE fields TO hv array (x)
END-PERFORM. ADD +1 TO WS-NUMBER-TO-INSERT
READ
END-PERFORM
IF WS-NUMBER-TO-INSERT > ZERO
MR-INSERT
CHECK COMMIT
END-IF
END-PERFORM.

44

If the program’s process is to insert rows into a table, then the program can COMMIT after filling a multiple r

44
Multi-row FETCH within a
UOW
Instead of Try
PERFORM UNTIL EOC PERFORM UNTIL EOC
FETCH MR-FETCH
Perform Process- MOVE SQLERRD(3)
row TO rows-fetched
PERFORM process-row
END-PERFORM.
VARYING x FROM +1 BY +1
CHECK COMMIT UNTIL x > rows-fetched
END-PERFORM
CHECK COMMIT

45

The program should not process more data than DB2 returned. Refer to new example.

45
Mixing SQL features

•INSERT within SELECT


•SELECT INTO … ORDER BY … FETCH FIRST
•SEQUENCE objects
•XML

46
Select from Insert
• Fewer DB2 calls
• INSERT and SELECT errors are possible
• Can be used with multi-row FETCH and INSERT
• Does not work when an AFTER TRIGGER modifies
the changed table. (SQLCODE=-989,
SQLSTATE=560C3) Proceed with caution.
SELECT col_id, insert_tsp, i_amt
FROM FINAL TABLE (
INSERT INTO TRIGGER_TBL
(insert_tsp, i_amt)
VALUES(current timestamp,
:i-amt)
47

Programs have the ability to get the assigned values of columns in the same
statement where they are created. Some of the DB2 assigned columns that can be
brought back to the program are identity column values, assigned sequence object
values, and special register values (like CURRENT TIMESTAMP).

When using this type of statement both INSERT errors and SELECT errors are
possible, like the following examples.
•Duplicate key from INSERT (SQLSTATE=23505)
•Null without a null indicator from the SELECT (SQLSTATE=22002)

Unfortunately, this statement is incompatible with some AFTER triggers. When an


AFTER trigger, triggered Stored Procedure, or triggered UDF modifies the table
that called it, the program gets an SQLCODE +100. Calling GET DIAGNOSTICS
reveals the following error.

The following text is from DB2 V8 Messages and Codes, pages 132-133
-989 AFTER TRIGGER trigger-name ATTEMPTED TO MODIFY A ROW IN
TABLE table-name THAT WAS INSERTED BY AN INSERT STATEMENT
WITHIN A SELECT STATEMENT
Explanation: An INSERT statement was specified in the FROM clause of a
SELECT statement of a subselect or a SELECT INTO statement, but the underlying
target base table of the INSERT has an AFTER trigger defined which modifies the
table being inserted. This is disallowed.
System Action: The statement cannot be processed. 47
Multi-row Select from Insert

Build details
(x)
Open cursor
Add rows Insert rows Fetch x rows
(y) (1)
Close cursor

Audit rows
(x)
The number of rows and iterations should all
be the same!
48

Whenever a program is going to do many inserts and it needs some of


the assigned values, it can be written to execute a multi-row INSERT
within a multi-row SELECT. To keep the logic simpler, keep the
number of rows in the FETCH the same as the number of rows in the
INSERT. An ORDER BY INPUT SEQUENCE clause should be used
on the CURSOR definition to ensure the host variable array rows
match. GET DIAGNOSTICS should also be used to look for INSERT
errors with OPEN statement and SELECT errors on the FETCH.

48
COBOL arrays example
• Build all detail columns into host variable arrays
• 3 calls to DB2
occ ID lmdt lmid col1 col2 col3 seq col4
1 100 ...01 AB U 11 77 2 MN Build
2 200 ...01 CD V 22 88 4 OP OPEN
3 300 ...02 EF W 33 99 6 QR
FETCH
4 400 ...02 GH X 44 111 8 ST
5 500 ...03 IJ Y 55 222 10 UV
CLOSE
6 600 ...03 KL Z 66 333 12 WX Audit

ID lmdt lmid col1 col2 col3 seq col4


becomes 100 …01 AB U 11 77 2 MN
49

When to program needs to create a single image of a row it cannot use a group
move from the host variable arrays. Instead individual moves from the host
variable arrays need to move each column into a one row image. The color show
when the individual host variable arrays are populated.

Note; ID is an identity column, lmdt is populated with a CURRENT TIMESTAMP,


and seq is given a value from a sequence object.

49
CURSOR definition
DECLARE NEW_EMPLOYEES CURSOR
WITH ROWSET POSITIONING FOR
SELECT EMPLOYEE_ID
, WORK_DTE
FROM FINAL TABLE
( INSERT INTO HOURS
( WORK_DTE, WORK_HOURS
, APPROVAL_DTE )
VALUES ( CURRENT DATE
, :DCLHOURS.WORK-HOURS, NULL )
FOR :WS-INSERT-QTY ROWS ATOMIC )
ORDER BY INPUT SEQUENCE

50

The slide show the actual SQL for populating an example row.
Below is an example of the FETCH

EXEC SQL
FETCH NEXT ROWSET
FROM NEW_EMPLOYEES
FOR :WS-INSERT-QTY ROWS
INTO :DCLHOURS.EMPLOYEE-ID
, :DCLHOURS.WORK-DTE
END-EXEC
.
EVALUATE SQLCODE
WHEN ...
WHEN OTHER
GET DIAGNOSTICS needed
END-EVALUATE

50
SELECT INTO with ORDER BY
• Replace CURSOR with single SELECT
• Get first or last row from results
• Continuing after “more than one” error gives
unpredictable results (SQLCODE -811,
SQLSTATE=21000)
Use this Instead of this
SELECT A.COL1 OPEN
, A.COL2
FETCH one row
INTO :WS-COL1
, :WS-COL2 CLOSE
FROM TABLEA AS A
WHERE …
ORDER BY A.COL1
FETCH FIRST 1 ROW ONLY
51

Another handy feature introduced in version 8 is allowing an ORDER BY clause on


a non-CURSOR SELECT. When used with the FETCH FIRST 1 ROW ONLY, a
program does not need a CURSOR process to SELECT a specific row.

Using “more-than-one-row” logic to return first row has always been unpredictable.
In test results, we found that DB2 v7 would return the first row found—usually in
the clustering sequence. In DB2 v8, the second row is returned.

51
Sequence Objects work just like Identity columns but are not part of a single table. They can be used like an i
those numbers. The syntax above shows how to get values from a sequence object without a SELECT, INSER

A program can also return the just assigned value of an identity column by using the IDENTITY_VAL_LOCA

52
XML
• COBOL verbs
• XML PARSE to read a document
• XML GENERATE to write a document
• DB2 processes and functions
• XML extender
• Save document in one column
• Use document access definition file (DAD)
• Parse into a relational table
• Build XML document
• Functions to build elements from columns
• Better functionality in DB2 9

53

There are several choices for building and reading an XML document that relates to
DB2 data. COBOL has its own built in function to parse an XML document and
build an XML document from an array. DB2 has an automatic way to parse and
build XML documents from table items. Programs can also call XML scalar
functions on DB2 columns to return the data in XML format.

It would take another presentation to cover these options adequately. There is also
better functionality in DB2 9 to handle XML data.

53
Conclusions
• Longer names yield better descriptions
• More COBOL complexity
• Multi-row INSERT
• Multi-row FETCH
• Less COBOL complexity
• SELECT from INSERT
• SELECT INTO … ORDER BY … FETCH FIRST
• New features
• Sequence Objects
• XML

54

Our COBOL programs have access to new features that improve performance. The
multi-row functions improve performance while adding some complexity to our
programs. The other features improve performance and make the program less
complex. Most of the improvements make fewer trips between the program and
DB2.

DB2 version 8 provides new functionality that makes handling XML data easier and
DB2 9 will make it even easier.

54
Acknowledgements
• Special thanks to Mike Todd

55

Special thanks to Mike Todd for providing access to his notes and permission to use
the information.

55
Session F14
Introducing your COBOL
programs to DB2 version 8

David Churn
DST Systems, Inc.
dcchurn@dstsystems.com

56

56

Anda mungkin juga menyukai