KEMBAR78
DB2 Application programming and sql guide | PDF
DB2 Version 9.1 for z/OS

Application Programming and SQL Guide

SC18-9841-01
DB2 Version 9.1 for z/OS

Application Programming and SQL Guide

SC18-9841-01
Note
Before using this information and the product it supports, be sure to read the general information under “Notices” at the
end of this information.

Second edition (October 2007)
This edition applies to DB2 Version 9.1 for z/OS (DB2 V9.1 for z/OS), product number 5635-DB2, and to any
subsequent releases until otherwise indicated in new editions. Make sure you are using the correct edition for the
level of the product.
Specific changes are indicated by a vertical bar to the left of a change. A vertical bar to the left of a figure caption
indicates that the figure has changed. Editorial changes that have no technical significance are not noted.
© Copyright International Business Machines Corporation 1983, 2007. All rights reserved.
US Government Users Restricted Rights – Use, duplication or disclosure restricted by GSA ADP Schedule Contract
with IBM Corp.
Contents
About this information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
DB2 Utilities Suite . . . . . . . . .
Who should read this information . . . .
Terminology and citations . . . . . . .
How to read syntax diagrams . . . . .
Accessibility features for DB2 Version 9.1 for
How to send your comments . . . . .

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

.
.
.

. xi
. xi
. xi
. . . . . . . . . . . . . . . . . . . . . . . . xii
z/OS . . . . . . . . . . . . . . . . . . . . . . xiii
. . . . . . . . . . . . . . . . . . . . . . . . xiv

Chapter 1. Planning for and designing DB2 applications . . . . . . . . . . . . . . . 1
|

|

Application and SQL release incompatibilities . . . . . . . . . . . . .
Determining the value of any SQL processing options that affect the design of your
Determining the binding method . . . . . . . . . . . . . . . . .
Changes that invalidate plans or packages . . . . . . . . . . . . .
Determining the value of any bind options that affect the design of your program
Designing your application to promote concurrency . . . . . . . . . . .
Designing your application for recovery . . . . . . . . . . . . . . .
Unit of work in TSO . . . . . . . . . . . . . . . . . . . .
Unit of work in CICS . . . . . . . . . . . . . . . . . . . .
Planning for program recovery in IMS programs . . . . . . . . . . .
Undoing selected changes within a unit of work by using savepoints . . . .
Planning for recovery of table spaces that are not logged . . . . . . . .
Designing your application to access distributed data . . . . . . . . . .
Remote servers and distributed data . . . . . . . . . . . . . . .
Advantages of DRDA access . . . . . . . . . . . . . . . . . .
Preparing for coordinated updates to two or more data sources . . . . . .
Forcing restricted system rules in your program . . . . . . . . . . .
Maximizing the performance of an application that accesses distributed data .

. . .
program
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .

.

.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

. 1
11
12
14
16
16
17
18
18
19
26
28
29
30
30
31
32
32

Chapter 2. Connecting to DB2 from your application program . . . . . . . . . . . . 43
Invoking the call attachment facility . . . . . . . . .
Call attachment facility . . . . . . . . . . . .
Making the CAF language interface (DSNALI) available .
Requirements for programs that use CAF . . . . . .
How CAF modifies the content of registers . . . . . .
Implicit connections to CAF . . . . . . . . . . .
CALL DSNALI statement parameter list . . . . . . .
Summary of CAF behavior . . . . . . . . . . .
CAF connection functions . . . . . . . . . . .
Turning on a CAF trace . . . . . . . . . . . .
CAF return codes and reason codes . . . . . . . .
Sample CAF scenarios . . . . . . . . . . . . .
Examples of invoking CAF . . . . . . . . . . .
Invoking the Resource Recovery Services attachment facility .
Resource Recovery Services attachment facility . . . .
Making the RRSAF language interface (DSNRLI) available
Requirements for programs that use RRSAF . . . . .
How RRSAF modifies the content of registers . . . . .
Implicit connections to RRSAF . . . . . . . . . .
CALL DSNRLI statement parameter list . . . . . . .
Summary of RRSAF behavior . . . . . . . . . .
RRSAF connection functions . . . . . . . . . . .
RRSAF return codes and reason codes . . . . . . .
Sample RRSAF scenarios . . . . . . . . . . .
Program examples for RRSAF . . . . . . . . . .
Controlling the CICS attachment facility from an application
© Copyright IBM Corp. 1983, 2007

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

44
47
50
51
52
52
53
55
56
67
67
68
69
75
77
81
82
83
83
84
85
86
116
116
118
121

iii
Detecting whether the CICS attachment facility is operational .
Improving thread reuse in CICS applications . . . . . . .

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

. 121
. 122

Chapter 3. Including DB2 queries in an application program . . . . . . . . . . . . 123
Declaring table and view definitions. . . . . . . . . . . . . . . . . . .
DCLGEN (declarations generator) . . . . . . . . . . . . . . . . . .
Generating declarations for your table by using DCLGEN . . . . . . . . . .
Including data declarations from DCLGEN in your program . . . . . . . . .
Defining the SQL communications area . . . . . . . . . . . . . . . . . .
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . . . .
Putting parameter information in an SQLDA by using DESCRIBE INPUT . . . . . .
Declaring host variables, host variable arrays, and host structures . . . . . . . . .
Host variables, host variable arrays, and host structures . . . . . . . . . . .
Host variables in an SQL statement . . . . . . . . . . . . . . . . . .
Host variable arrays in an SQL statement . . . . . . . . . . . . . . . .
Retrieving multiple rows of data into host variable arrays . . . . . . . . . .
Inserting multiple rows of data from host variable arrays. . . . . . . . . . .
C and C++ syntax for host variable array declarations . . . . . . . . . . . .
COBOL syntax for host variable array declarations . . . . . . . . . . . . .
PL/I syntax for host variable array declarations . . . . . . . . . . . . . .
Host structures in an SQL statement . . . . . . . . . . . . . . . . . .
Indicator variables and indicator variable arrays . . . . . . . . . . . . . .
Compatibility of SQL and language data types . . . . . . . . . . . . . . .
Equivalent SQL and assembler data types . . . . . . . . . . . . . . . .
Equivalent SQL and C data types. . . . . . . . . . . . . . . . . . .
Equivalent SQL and COBOL data types . . . . . . . . . . . . . . . .
Equivalent SQL and Fortran data types . . . . . . . . . . . . . . . . .
Equivalent SQL and PL/I data types . . . . . . . . . . . . . . . . .
Determining equivalent SQL and REXX data types . . . . . . . . . . . . .
Data types that DB2 assigns to REXX input . . . . . . . . . . . . . . .
Embedding SQL statements in your application . . . . . . . . . . . . . . .
Embedding SQL statements in assembler applications . . . . . . . . . . . .
Embedding SQL statements in C or C++ applications . . . . . . . . . . . .
Embedding SQL statements in COBOL applications . . . . . . . . . . . .
Embedding SQL statements in Fortran applications . . . . . . . . . . . . .
Embedding SQL statements in PL/I applications . . . . . . . . . . . . .
Embedding SQL statements in REXX procedures . . . . . . . . . . . . .
Delimiting an SQL statement . . . . . . . . . . . . . . . . . . . .
Including dynamic SQL in your program . . . . . . . . . . . . . . . .
Conventions used in examples of coding SQL statements . . . . . . . . . . .
Macros for assembler applications . . . . . . . . . . . . . . . . . .
Accessing the DB2 REXX language support application programming interfaces . . .
Setting the isolation level of SQL statements in a REXX procedure . . . . . . . .
Checking the execution of SQL statements . . . . . . . . . . . . . . . . .
Checking the execution of SQL statements by using the SQLCA . . . . . . . .
Checking the execution of SQL statements by using SQLCODE and SQLSTATE . . .
Checking the execution of SQL statements by using the WHENEVER statement . . .
Checking the execution of SQL statements by using the GET DIAGNOSTICS statement
Handling SQL error codes . . . . . . . . . . . . . . . . . . . . . .
Arithmetic and conversion errors . . . . . . . . . . . . . . . . . . .
Writing applications that enable users to create and modify tables . . . . . . . . .
Saving SQL statements that are translated from end user requests . . . . . . . . .
Retrieving data from DB2 tables in REXX programs . . . . . . . . . . . . .
XML data in embedded SQL applications . . . . . . . . . . . . . . . . .
Host variable data types for XML data in embedded SQL applications . . . . . .
XML column updates in embedded SQL applications . . . . . . . . . . . .
XML data retrieval in embedded SQL applications . . . . . . . . . . . . .
Object-oriented extensions in COBOL . . . . . . . . . . . . . . . . . .
Cursors and statement names in REXX . . . . . . . . . . . . . . . . . .
Programming examples . . . . . . . . . . . . . . . . . . . . . . .
Sample dynamic and static SQL in a C program . . . . . . . . . . . . . .

iv

Application Programming and SQL Guide

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

124
125
130
135
135
137
139
140
142
143
182
182
182
183
189
195
199
207
219
221
226
231
235
237
241
241
243
243
246
248
252
253
256
258
258
296
296
296
298
298
299
303
303
304
310
317
317
318
318
319
320
324
327
329
330
331
331
Sample COBOL dynamic SQL program . . . . . . . . . . . .
Sample COBOL program using DRDA access with CONNECT statements
Sample COBOL program using private protocol access . . . . . .
Sample DB2 REXX application. . . . . . . . . . . . . . .
Example programs that call stored procedures . . . . . . . . .

Chapter 4. Creating and modifying DB2 objects

|

|

|

|

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

334
345
351
357
367

. . . . . . . . . . . . . . . . . 385

Creating tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Storing LOB data in a table . . . . . . . . . . . . . . . . . . . . . . . .
Identity columns . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creating tables for data integrity . . . . . . . . . . . . . . . . . . . . . .
Creating work tables for the EMP and DEPT sample tables . . . . . . . . . . . . .
Creating created temporary tables . . . . . . . . . . . . . . . . . . . . .
Creating declared temporary tables . . . . . . . . . . . . . . . . . . . . .
Providing a unique key for a table . . . . . . . . . . . . . . . . . . . . . .
Fixing tables with incomplete definitions . . . . . . . . . . . . . . . . . . . .
Dropping tables . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Defining a view . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Dropping a view . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creating a common table expression . . . . . . . . . . . . . . . . . . . . . .
Common table expressions . . . . . . . . . . . . . . . . . . . . . . . .
Examples of recursive common table expressions . . . . . . . . . . . . . . . .
Creating triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Invoking stored procedures and user-defined functions from triggers . . . . . . . . . .
Inserting, updating, and deleting data in views by using INSTEAD OF triggers . . . . . .
Trigger packages . . . . . . . . . . . . . . . . . . . . . . . . . . .
Trigger cascading . . . . . . . . . . . . . . . . . . . . . . . . . . .
Order of multiple triggers . . . . . . . . . . . . . . . . . . . . . . . .
Interactions between triggers and referential constraints . . . . . . . . . . . . . .
Interactions between triggers and tables that have multilevel security with row-level granularity
Triggers that return inconsistent results . . . . . . . . . . . . . . . . . . . .
Sequence objects . . . . . . . . . . . . . . . . . . . . . . . . . . . .
DB2 object relational extensions . . . . . . . . . . . . . . . . . . . . . . .
Creating a distinct type . . . . . . . . . . . . . . . . . . . . . . . . . .
Distinct types . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Example of distinct types, user-defined functions, and LOBs . . . . . . . . . . . .
Defining a user-defined function . . . . . . . . . . . . . . . . . . . . . . .
User-defined functions . . . . . . . . . . . . . . . . . . . . . . . . .
Components of a user-defined function definition . . . . . . . . . . . . . . . .
Writing an external user-defined function . . . . . . . . . . . . . . . . . . .
Making a user-defined function reentrant . . . . . . . . . . . . . . . . . . .
Using special registers in a user-defined function or a stored procedure . . . . . . . . .
Accessing transition tables in a user-defined function or stored procedure . . . . . . . .
Preparing an external user-defined function for execution . . . . . . . . . . . . .
Abnormal termination of an external user-defined function . . . . . . . . . . . . .
Saving information between invocations of a user-defined function by using a scratchpad . . .
Example of creating and using a user-defined scalar function . . . . . . . . . . . .
User-defined function samples that ship with DB2 . . . . . . . . . . . . . . . .
Determining the authorization cache size for stored procedures and user-defined functions . .
Creating a stored procedure . . . . . . . . . . . . . . . . . . . . . . . .
Stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . . .
Setting up the stored procedures environment . . . . . . . . . . . . . . . . .
Creating a native SQL procedure . . . . . . . . . . . . . . . . . . . . . .
Changing an existing version of a native SQL procedure . . . . . . . . . . . . . .
Regenerating an existing version of a native SQL procedure . . . . . . . . . . . . .
Removing an existing version of a native SQL procedure . . . . . . . . . . . . . .
Deploying a native SQL procedure to other DB2 for z/OS servers . . . . . . . . . . .
Creating an external SQL procedure . . . . . . . . . . . . . . . . . . . . .
Creating an external stored procedure . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

385
386
388
391
393
402
403
405
407
408
409
409
410
411
411
412
413
417
425
426
427
428
429
429
431
431
434
435
436
436
438
440
443
445
447
470
471
473
477
477
477
479
479
480
481
481
494
500
526
526
527
527
528
541

Contents

v
Creating multiple versions of external procedures and external SQL procedures . . .
COMMIT and ROLLBACK statements in a stored procedure . . . . . . . . .
Special registers in a stored procedure . . . . . . . . . . . . . . . . .
Restrictions for stored procedures . . . . . . . . . . . . . . . . . .
Writing a program or stored procedure to receive the result sets from a stored procedure

Chapter 5. Adding and modifying data
|

|
|

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

553
553
554
554
554

. . . . . . . . . . . . . . . . . . . . . 561

Inserting data into tables . . . . . . . . . . .
Inserting rows by using the INSERT statement . . .
Inserting data and updating data in a single operation
Selecting values while inserting data . . . . . .
Adding data to the end of a table . . . . . . . .
Storing data that does not have a tabular format . . .
Updating table data . . . . . . . . . . . . .
Selecting values while updating data . . . . . .
Updating thousands of rows . . . . . . . . .
Deleting data from tables . . . . . . . . . . .
Selecting values while deleting data . . . . . . .

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.

561
561
567
569
575
576
576
577
578
578
580

Chapter 6. Accessing data . . . . . . . . . . . . . . . . . . . . . . . . . . . 583

|
|
|

|

|

Determining which tables you have access to . . . . . . . . . . . . . .
Displaying information about the columns for a given table . . . . . . . . .
Retrieving data by using the SELECT statement . . . . . . . . . . . . .
Selecting derived columns . . . . . . . . . . . . . . . . . . .
Selecting XML data . . . . . . . . . . . . . . . . . . . . .
Formatting the result table . . . . . . . . . . . . . . . . . . .
Combining result tables from multiple SELECT statements . . . . . . . .
Summarizing group values . . . . . . . . . . . . . . . . . . .
Finding rows that were changed within a specified period of time . . . . .
Joining data from more than one table . . . . . . . . . . . . . . .
Optimizing retrieval for a small set of rows . . . . . . . . . . . . .
Creating recursive SQL by using common table expressions . . . . . . . .
Updating data as it is retrieved from the database . . . . . . . . . . .
Avoiding decimal arithmetic errors . . . . . . . . . . . . . . . .
Implications of using SELECT * . . . . . . . . . . . . . . . . .
Subqueries . . . . . . . . . . . . . . . . . . . . . . . .
Restrictions when using distinct types with UNION, EXCEPT, and INTERSECT .
Comparison of distinct types . . . . . . . . . . . . . . . . . .
Nested SQL statements . . . . . . . . . . . . . . . . . . . .
Retrieving a set of rows by using a cursor . . . . . . . . . . . . . . .
Cursors . . . . . . . . . . . . . . . . . . . . . . . . .
Accessing data by using a row-positioned cursor . . . . . . . . . . .
Accessing data by using a rowset-positioned cursor . . . . . . . . . .
Retrieving rows by using a scrollable cursor . . . . . . . . . . . . .
Accessing XML or LOB data quickly by using FETCH WITH CONTINUE . . .
Determining the attributes of a cursor by using the SQLCA . . . . . . . .
Determining the attributes of a cursor by using the GET DIAGNOSTICS statement
Scrolling through previously retrieved data . . . . . . . . . . . . .
Updating previously retrieved data . . . . . . . . . . . . . . . .
FETCH statement interaction between row and rowset positioning . . . . .
Examples of fetching rows by using cursors . . . . . . . . . . . . .
Specifying direct row access by using row IDs . . . . . . . . . . . . .
ROWID columns . . . . . . . . . . . . . . . . . . . . . .
Ways to manipulate LOB data . . . . . . . . . . . . . . . . . . .
LOB host variable, LOB locator, and LOB file reference variable declarations . .
LOB materialization . . . . . . . . . . . . . . . . . . . . .
Saving storage when manipulating LOBs by using LOB locators . . . . . .
Deferring evaluation of a LOB expression to improve performance . . . . .
LOB file reference variables . . . . . . . . . . . . . . . . . .
Referencing a sequence object . . . . . . . . . . . . . . . . . . .

vi

Application Programming and SQL Guide

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

583
583
584
587
587
588
593
598
600
600
611
612
613
613
614
615
623
624
625
626
627
631
636
641
646
649
650
650
652
652
653
658
660
660
661
667
667
669
671
673
|
|

Retrieving thousands of rows . . . . .
Determining when a row was changed . .
Checking whether an XML column contains
Accessing DB2 data that is not in a table .
Ensuring that queries perform sufficiently .
Items to include in a batch DL/I program .

. . . . . .
. . . . . .
a certain value .
. . . . . .
. . . . . .
. . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

674
674
675
675
675
676

Chapter 7. Invoking a user-defined function . . . . . . . . . . . . . . . . . . . 679
Determining the authorization ID for invoking user-defined functions . . . .
Ensuring that DB2 executes the intended user-defined function. . . . . . .
Function resolution . . . . . . . . . . . . . . . . . . . .
Checking how DB2 resolves functions by using DSN_FUNCTION_TABLE . .
Restrictions when passing arguments with distinct types to functions . . . .
Cases when DB2 casts arguments for a user-defined function . . . . . . .
Maximizing the number of user-defined functions and stored procedures that can

.
.
.
.
.
.
run

. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
concurrently

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

680
681
682
685
687
689
690

Chapter 8. Calling a stored procedure from your application . . . . . . . . . . . . 693

|

Parameter list for stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . .
Linkage conventions for stored procedures . . . . . . . . . . . . . . . . . . . . . . .
Improving stored procedure performance by using indicator variables . . . . . . . . . . . . . .
Compatible data types for parameters that are passed to stored procedures . . . . . . . . . . . .
Preparing a client program for a stored procedure . . . . . . . . . . . . . . . . . . . . .
How DB2 determines which stored procedure to run . . . . . . . . . . . . . . . . . . . .
Calling different versions of a stored procedure from a single application . . . . . . . . . . . . .
Invoking multiple instances of a stored procedure . . . . . . . . . . . . . . . . . . . . .
Stored procedures that access non-DB2 resources . . . . . . . . . . . . . . . . . . . . .
Designating the active version of a native SQL procedure . . . . . . . . . . . . . . . . . .
Temporarily overriding the active version of a native SQL procedure . . . . . . . . . . . . . . .
Specifying the number of stored procedures that can run concurrently . . . . . . . . . . . . . .
DB2-supplied stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . . .
WLM environment refresh stored procedure (WLM_REFRESH) . . . . . . . . . . . . . . .
The DSNACICS stored procedure . . . . . . . . . . . . . . . . . . . . . . . . .
The DSNAIMS stored procedure . . . . . . . . . . . . . . . . . . . . . . . . . .
The DB2 EXPLAIN stored procedure . . . . . . . . . . . . . . . . . . . . . . . .
Deprecated: Store an XML document from an MQ message queue in DB2 tables (DXXMQINSERT) . . .
Deprecated: Store an XML document from an MQ message queue in DB2 tables (DXXMQSHRED) . . . .
Deprecated: Store a large XML document from an MQ message queue in DB2 tables (DXXMQINSERTCLOB)
Deprecated: Store a large XML document from an MQ message queue in DB2 tables (DXXMQSHREDCLOB)
Deprecated: Store XML documents from an MQ message queue in DB2 tables (DXXMQINSERTALL) . . .
Deprecated: Store XML documents from an MQ message queue in DB2 tables (DXXMQSHREDALL) . . .
Deprecated: Store large XML documents from an MQ message queue in DB2 tables
(DXXMQSHREDALLCLOB) . . . . . . . . . . . . . . . . . . . . . . . . . . .
Deprecated: Store large XML documents from an MQ message queue in DB2 tables
(DXXMQINSERTALLCLOB) . . . . . . . . . . . . . . . . . . . . . . . . . . .
Deprecated: Send XML documents to an MQ message queue (DXXMQGEN) . . . . . . . . . . .
Deprecated: Send XML documents to an MQ message queue (DXXMQRETRIEVE) . . . . . . . . .
Deprecated: Send large XML documents to an MQ message queue (DXXMQGENCLOB) . . . . . . .
Deprecated: Send XML documents to an MQ message queue (DXXMQRETRIEVECLOB) . . . . . . .
The XML schema registration stored procedure (XSR_REGISTER) . . . . . . . . . . . . . . .
The add XML schema document stored procedure (XSR_ADDSCHEMADOC) . . . . . . . . . . .
The XML schema registration completion stored procedure (XSR_COMPLETE) . . . . . . . . . .
The XML schema removal stored procedure (XSR_REMOVE) . . . . . . . . . . . . . . . .
The XML decomposition stored procedure (XDBDECOMPXML) . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

696
697
712
713
721
722
722
723
724
725
726
726
727
729
731
739
744
746
749
751
754
. 756
. 758

. 761
.
.
.
.
.
.
.
.
.
.

763
766
769
773
777
780
781
783
784
785

Chapter 9. Coding methods for distributed data . . . . . . . . . . . . . . . . . 787
Accessing distributed data by using three-part table names . . . . . . . .
Accessing remote declared temporary tables by using three-part table names .
Accessing distributed data by using explicit CONNECT statements . . . . .
Specifying a location alias name for multiple sites . . . . . . . . . .
Releasing connections . . . . . . . . . . . . . . . . . . .

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

Contents

.
.
.
.
.

787
789
789
790
791

vii
|
|
|
|

Transmitting mixed data. . . . . . . . . . . . . . . . . . . . . . . . .
Identifying the server at run time . . . . . . . . . . . . . . . . . . . . .
SQL limitations at dissimilar servers . . . . . . . . . . . . . . . . . . . . .
Support for executing long SQL statements in a distributed environment . . . . . . . .
Distributed queries against ASCII or Unicode tables . . . . . . . . . . . . . . .
Restrictions when using scrollable cursors to access distributed data . . . . . . . . . .
Restrictions when using rowset-positioned cursors to access distributed data . . . . . . .
WebSphere MQ with DB2 . . . . . . . . . . . . . . . . . . . . . . . .
WebSphere MQ messages . . . . . . . . . . . . . . . . . . . . . . .
DB2 MQ functions and DB2 MQ XML stored procedures . . . . . . . . . . . . .
Generating XML documents from existing tables and sending them to an MQ message queue
Shredding XML documents from an MQ message queue . . . . . . . . . . . . .
DB2 MQ tables . . . . . . . . . . . . . . . . . . . . . . . . . . .
Converting applications to use the MQI functions . . . . . . . . . . . . . . .
Basic messaging with WebSphere MQ . . . . . . . . . . . . . . . . . . .
Sending messages with WebSphere MQ . . . . . . . . . . . . . . . . . .
Retrieving messages with WebSphere MQ . . . . . . . . . . . . . . . . . .
Application to application connectivity with WebSphere MQ . . . . . . . . . . .
Asynchronous messaging in DB2 for z/OS . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

791
791
792
792
793
793
794
794
794
798
804
804
804
813
814
815
815
817
820

Chapter 10. DB2 as a Web services consumer and provider . . . . . . . . . . . . 833
The SOAPHTTPV and SOAPHTTPC user-defined functions .
SQLSTATEs for DB2 as a Web services consumer . . . .

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

. 833
. 835

Chapter 11. Preparing an application to run on DB2 for z/OS . . . . . . . . . . . . 837

|

Setting the DB2I defaults . . . . . . . . . . . . . . . . . . . . . . .
Processing SQL statements . . . . . . . . . . . . . . . . . . . . . . .
Processing SQL statements by using the DB2 precompiler . . . . . . . . . . .
Processing SQL statements by using the DB2 coprocessor. . . . . . . . . . . .
Translating command-level statements in a CICS program . . . . . . . . . . .
Differences between the DB2 precompiler and the DB2 coprocessor . . . . . . . .
CCSID conversion of source programs . . . . . . . . . . . . . . . . . .
Options for SQL statement processing . . . . . . . . . . . . . . . . . .
Program preparation options for remote packages . . . . . . . . . . . . . .
Compiling and link-editing an application . . . . . . . . . . . . . . . . . .
Binding an application . . . . . . . . . . . . . . . . . . . . . . . .
Binding a DBRM to a package . . . . . . . . . . . . . . . . . . . . .
Binding an application plan . . . . . . . . . . . . . . . . . . . . .
Bind process for remote access . . . . . . . . . . . . . . . . . . . .
Binding a batch program . . . . . . . . . . . . . . . . . . . . . .
Converting an existing plan into packages to run remotely . . . . . . . . . . .
Setting the program level . . . . . . . . . . . . . . . . . . . . . .
DYNAMICRULES bind option . . . . . . . . . . . . . . . . . . . .
Determining the authorization cache size for plans . . . . . . . . . . . . . .
Determining the authorization cache size for packages . . . . . . . . . . . .
Dynamic plan selection . . . . . . . . . . . . . . . . . . . . . . .
Rebinding an application . . . . . . . . . . . . . . . . . . . . . . .
Rebinding a package . . . . . . . . . . . . . . . . . . . . . . . .
Rebinding a plan . . . . . . . . . . . . . . . . . . . . . . . . .
Rebinding lists of plans and packages . . . . . . . . . . . . . . . . . .
Generating lists of REBIND commands . . . . . . . . . . . . . . . . . .
Automatic rebinding . . . . . . . . . . . . . . . . . . . . . . . .
Specifying the rules that apply to SQL behavior at run time . . . . . . . . . . . .
DB2 program preparation overview . . . . . . . . . . . . . . . . . . . .
Input and output data sets for DL/I batch jobs . . . . . . . . . . . . . . . .
DB2-supplied JCL procedures for preparing an application . . . . . . . . . . . .
JCL to include the appropriate interface code when using the DB2-supplied JCL procedures
Tailoring DB2-supplied JCL procedures for preparing CICS programs . . . . . . .
DB2I primary option menu . . . . . . . . . . . . . . . . . . . . . . .
DB2I panels that are used for program preparation . . . . . . . . . . . . . . .

viii

Application Programming and SQL Guide

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

839
840
842
848
850
851
853
853
862
864
865
866
871
875
879
879
880
881
882
883
883
885
885
886
887
887
893
894
895
897
900
900
901
902
903
DB2 Program Preparation panel . . . . . . . . . . . .
DB2I Defaults Panel 1 . . . . . . . . . . . . . . .
DB2I Defaults Panel 2 . . . . . . . . . . . . . . .
Precompile panel . . . . . . . . . . . . . . . . .
Bind Package panel . . . . . . . . . . . . . . . .
Bind Plan panel . . . . . . . . . . . . . . . . .
Defaults for Bind Package panel and Defaults for Bind Plan panel.
System Connection Types panel . . . . . . . . . . . .
Panels for entering lists of values . . . . . . . . . . . .
Program Preparation: Compile, Link, and Run panel . . . . .
DB2I panels that are used to rebind and free plans and packages . .
Bind/Rebind/Free Selection panel . . . . . . . . . . .
Rebind Package panel . . . . . . . . . . . . . . .
Rebind Trigger Package panel . . . . . . . . . . . . .
Rebind Plan panel . . . . . . . . . . . . . . . . .
Free Package panel . . . . . . . . . . . . . . . .
Free Plan panel . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

905
909
911
912
915
918
921
926
927
928
930
930
932
933
935
937
938

Chapter 12. Running an application on DB2 for z/OS . . . . . . . . . . . . . . . 939

|
|

DSN command processor . . . . . . . . . . . . . . . .
DB2I Run panel . . . . . . . . . . . . . . . . . . .
Running a program in TSO foreground . . . . . . . . . . . .
Running a DB2 REXX application . . . . . . . . . . . . .
Invoking programs through the Interactive System Productivity Facility .
ISPF . . . . . . . . . . . . . . . . . . . . . .
Invoking a single SQL program through ISPF and DSN . . . . .
Invoking multiple SQL programs through ISPF and DSN . . . . .
Loading and running a batch program . . . . . . . . . . . .
Authorization for running a batch DL/I program . . . . . . .
Restarting a batch program . . . . . . . . . . . . . . .
Running stored procedures from the command line processor . . . .
Command line processor CALL statement . . . . . . . . . .
Example of running a batch DB2 application in TSO . . . . . . .
Example of calling applications in a command procedure . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

939
940
941
942
942
943
944
945
946
947
947
950
950
951
952

Chapter 13. Testing and debugging an application program on DB2 for z/OS . . . . . 955
Designing a test data structure . . . . . . . . . . . . . . . . . . . . . . . . . .
Analyzing application data needs . . . . . . . . . . . . . . . . . . . . . . . .
Authorization for test tables and applications. . . . . . . . . . . . . . . . . . . . .
Example SQL statements to create a comprehensive test structure . . . . . . . . . . . . . .
Populating the test tables with data . . . . . . . . . . . . . . . . . . . . . . . . .
Methods for testing SQL statements . . . . . . . . . . . . . . . . . . . . . . . . .
Executing SQL by using SPUFI . . . . . . . . . . . . . . . . . . . . . . . . . .
SPUFI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Content of a SPUFI input data set . . . . . . . . . . . . . . . . . . . . . . . .
The SPUFI panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Changing SPUFI defaults . . . . . . . . . . . . . . . . . . . . . . . . . . .
Setting the SQL terminator character in a SPUFI input data set . . . . . . . . . . . . . . .
Controlling toleration of warnings in SPUFI . . . . . . . . . . . . . . . . . . . . .
Output from SPUFI . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Testing an external user-defined function . . . . . . . . . . . . . . . . . . . . . . .
Testing a user-defined function by using the Debug Tool for z/OS . . . . . . . . . . . . .
Testing a user-defined function by routing the debugging messages to SYSPRINT . . . . . . . .
Testing a user-defined function by using driver applications . . . . . . . . . . . . . . . .
Testing a user-defined function by using SQL INSERT statements . . . . . . . . . . . . . .
Debugging a stored procedure. . . . . . . . . . . . . . . . . . . . . . . . . . .
Debugging stored procedures with the Debug Tool and IBM VisualAge COBOL . . . . . . . . .
Debugging a C language stored procedure with the Debug Tool and C/C++ Productivity Tools for z/OS
Debugging with the Unified Debugger . . . . . . . . . . . . . . . . . . . . . . .
Debugging stored procedures with the Debug Tool for z/OS . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

Contents

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

955
955
956
957
958
958
959
962
963
963
965
970
971
971
973
973
975
975
976
976
977
978
978
979

ix
Recording stored procedure debugging messages
Driver applications for debugging procedures .
DB2 tables that contain debugging information .
Debugging an application program . . . . . .
Locating the problem in an application . . . .
Techniques for debugging programs in TSO . .
Techniques for debugging programs in IMS . .
Techniques for debugging programs in CICS . .
Finding a violated referential or check constraint .

in a file
. . .
. . .
. . .
. . .
. . .
. . .
. . .
. . .

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.

981
981
981
982
982
987
987
988
992

Chapter 14. DB2 sample applications and data . . . . . . . . . . . . . . . . . . 993
DB2 sample tables . . . . . . . . . . . . . . . . . . . .
Activity table (DSN8910.ACT) . . . . . . . . . . . . . . .
Department table (DSN8910.DEPT) . . . . . . . . . . . . .
Employee table (DSN8910.EMP) . . . . . . . . . . . . . .
Employee photo and resume table (DSN8910.EMP_PHOTO_RESUME) .
Project table (DSN8910.PROJ) . . . . . . . . . . . . . .
Project activity table (DSN8910.PROJACT) . . . . . . . . . .
Employee to project activity table (DSN8910.EMPPROJACT) . . . .
Unicode sample table (DSN8910.DEMO_UNICODE) . . . . . . .
Relationships among the sample tables . . . . . . . . . . .
Views on the sample tables . . . . . . . . . . . . . . .
Storage of sample application tables . . . . . . . . . . . .
DB2 sample applications . . . . . . . . . . . . . . . . .
Types of sample applications . . . . . . . . . . . . . . .
Application languages and environments for the sample applications .
Sample applications in TSO . . . . . . . . . . . . . . .
Sample applications in IMS . . . . . . . . . . . . . . .
Sample applications in CICS . . . . . . . . . . . . . . .
DSNTIAUL. . . . . . . . . . . . . . . . . . . . .
DSNTIAD . . . . . . . . . . . . . . . . . . . . .
DSNTEP2 and DSNTEP4 . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

. 993
. 993
. 994
. 995
. 999
. 1000
. 1001
. 1002
. 1003
. 1004
. 1005
. 1009
. 1013
. 1015
. 1017
. 1018
. 1020
. 1021
. 1021
. 1026
. 1028

Information resources for DB2 for z/OS and related products . . . . . . . . . . . 1035
How to obtain DB2 information . . . . . . . . . . . . . . . . . . . . . . . . 1041
How to use the DB2 library . . . . . . . . . . . . . . . . . . . . . . . . . . 1045
Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049
Programming Interface Information . . . . . . . . . . . . . . . .
General-use Programming Interface and Associated Guidance Information . .
Product-sensitive Programming Interface and Associated Guidance Information .
Trademarks . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

1050
1050
1051
1051

Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1053
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1097

x

Application Programming and SQL Guide
About this information
This information discusses how to design and write application programs that
access DB2 for z/OS (DB2®), a highly flexible relational database management
system (DBMS).
Visit the following Web site for information about ordering DB2 books and
obtaining other valuable information about DB2 for z/OS: http://
publib.boulder.ibm.com/infocenter/imzic

DB2 Utilities Suite
Important: In this version of DB2 for z/OS®, the DB2 Utilities Suite is available as
an optional product. You must separately order and purchase a license to such
utilities, and discussion of those utility functions in this publication is not intended
to otherwise imply that you have a license to them.
The DB2 Utilities Suite is designed to work with the DFSORT™ program, which
you are licensed to use in support of the DB2 utilities even if you do not otherwise
license DFSORT for general use. If your primary sort product is not DFSORT,
consider the following informational APARs mandatory reading:
v II14047/II14213: USE OF DFSORT BY DB2 UTILITIES
v II13495: HOW DFSORT TAKES ADVANTAGE OF 64-BIT REAL
ARCHITECTURE
These informational APARs are periodically updated.
Related information
DB2 utilities packaging

Who should read this information
This information is for DB2 application developers who are familiar with
Structured Query Language (SQL) and who know one or more programming
languages that DB2 supports.

Terminology and citations
In this information, DB2 Version 9.1 for z/OS is referred to as ″DB2 for z/OS.″ In
cases where the context makes the meaning clear, DB2 for z/OS is referred to as
″DB2.″ When this information refers to titles of DB2 for z/OS books, a short title is
used. (For example, ″See DB2 SQL Reference″ is a citation to IBM® DB2 Version 9.1
for z/OS SQL Reference.)
When referring to a DB2 product other than DB2 for z/OS, this information uses
the product’s full name to avoid ambiguity.
The following terms are used as indicated:
DB2

Represents either the DB2 licensed program or a particular DB2 subsystem.

OMEGAMON
Refers to any of the following products:
© Copyright IBM Corp. 1983, 2007

xi
v
v
v
v

IBM
IBM
IBM
IBM

Tivoli® OMEGAMON® XE for DB2 Performance Expert on z/OS
Tivoli OMEGAMON XE for DB2 Performance Monitor on z/OS
DB2 Performance Expert for Multiplatforms and Workgroups
DB2 Buffer Pool Analyzer for z/OS

C, C++, and C language
Represent the C or C++ programming language.
CICS

Represents CICS® Transaction Server for z/OS.

IMS

Represents the IMS™ Database Manager or IMS Transaction Manager.

MVS

|

Represents the MVS™ element of the z/OS operating system, which is
equivalent to the Base Control Program (BCP) component of the z/OS
operating system.

RACF Represents the functions that are provided by the RACF® component of the
z/OS Security Server.

How to read syntax diagrams
Certain conventions apply to the syntax diagrams that are used in IBM
documentation.
Apply the following rules when reading the syntax diagrams that are used in DB2
for z/OS documentation:
v Read the syntax diagrams from left to right, from top to bottom, following the
path of the line.
The ─── symbol indicates the beginning of a statement.
The ─── symbol indicates that the statement syntax is continued on the next
line.
The ─── symbol indicates that a statement is continued from the previous line.
The ─── symbol indicates the end of a statement.
v Required items appear on the horizontal line (the main path).
required_item

v Optional items appear below the main path.
required_item
optional_item

If an optional item appears above the main path, that item has no effect on the
execution of the statement and is used only for readability.
optional_item
required_item

v If you can choose from two or more items, they appear vertically, in a stack.
If you must choose one of the items, one item of the stack appears on the main
path.
required_item

xii

Application Programming and SQL Guide

required_choice1
required_choice2
If choosing one of the items is optional, the entire stack appears below the main
path.
required_item
optional_choice1
optional_choice2

If one of the items is the default, it appears above the main path and the
remaining choices are shown below.
default_choice
required_item
optional_choice
optional_choice

v An arrow returning to the left, above the main line, indicates an item that can be
repeated.

required_item

repeatable_item

If the repeat arrow contains a comma, you must separate repeated items with a
comma.
,
required_item

|
|
|

repeatable_item

A repeat arrow above a stack indicates that you can repeat the items in the
stack.
v Sometimes a diagram must be split into fragments. The syntax fragment is
shown separately from the main syntax diagram, but the contents of the
fragment should be read as if they are on the main path of the diagram.

|
|

required_item

|

fragment-name:

|

fragment-name

required_item
optional_name

|
|
|
|

v With the exception of XPath keywords, keywords appear in uppercase (for
example, FROM). Keywords must be spelled exactly as shown. XPath keywords
are defined as lowercase names, and must be spelled exactly as shown. Variables
appear in all lowercase letters (for example, column-name). They represent
user-supplied names or values.
v If punctuation marks, parentheses, arithmetic operators, or other such symbols
are shown, you must enter them as part of the syntax.

Accessibility features for DB2 Version 9.1 for z/OS
Accessibility features help a user who has a physical disability, such as restricted
mobility or limited vision, to use information technology products successfully.
About this information

xiii
Accessibility features
The following list includes the major accessibility features in z/OS products,
including DB2 Version 9.1 for z/OS. These features support:
v Keyboard-only operation.
v Interfaces that are commonly used by screen readers and screen magnifiers.
v Customization of display attributes such as color, contrast, and font size
Tip: The Information Management Software for z/OS Solutions Information
Center (which includes information for DB2 Version 9.1 for z/OS) and its related
publications are accessibility-enabled for the IBM Home Page Reader. You can
operate all features using the keyboard instead of the mouse.

Keyboard navigation
You can access DB2 Version 9.1 for z/OS ISPF panel functions by using a keyboard
or keyboard shortcut keys.
For information about navigating the DB2 Version 9.1 for z/OS ISPF panels using
TSO/E or ISPF, refer to the z/OS TSO/E Primer, the z/OS TSO/E User’s Guide, and
the z/OS ISPF User’s Guide. These guides describe how to navigate each interface,
including the use of keyboard shortcuts or function keys (PF keys). Each guide
includes the default settings for the PF keys and explains how to modify their
functions.

Related accessibility information
Online documentation for DB2 Version 9.1 for z/OS is available in the Information
Management Software for z/OS Solutions Information Center, which is available at
the following Web site: http://publib.boulder.ibm.com/infocenter/dzichelp

IBM and accessibility
See the IBM Accessibility Center at http://www.ibm.com/able for more information
about the commitment that IBM has to accessibility.

How to send your comments
Your feedback helps IBM to provide quality information. Please send any
comments that you have about this book or other DB2 for z/OS documentation.
You can use the following methods to provide comments:
v Send your comments by e-mail to db2zinfo@us.ibm.com and include the name
of the product, the version number of the product, and the number of the book.
If you are commenting on specific text, please list the location of the text (for
example, a chapter and section title or a help topic title).
v You can send comments from the Web. Visit the library Web site at:
www.ibm.com/software/db2zos/library.html
This Web site has an online reader comment form that you can use to send
comments.
v You can also send comments by using the feedback link at the footer of each
page in the Information Management Software for z/OS Solutions Information
Center at http://publib.boulder.ibm.com/infocenter/db2zhelp.

xiv

Application Programming and SQL Guide
Chapter 1. Planning for and designing DB2 applications
Whether you are writing a new DB2 application or migrating an existing
application from a previous release of DB2, you need to make some planning and
design decisions before you write or run the program.
If you are migrating an existing application from a previous release of DB2, read
the application and SQL release incompatibilities and make any necessary changes
in the application.
If
v
v
v

you are writing a new DB2 application, first determine the following items:
the value of some of the SQL processing options
the binding method
the value of some of the bind options

Then make sure that your program implements the appropriate recommendations
so that it promotes concurrency, can handle recovery and restart situations, and can
efficiently access distributed data.
|

Application and SQL release incompatibilities

|
|

When you migrate to Version 9.1, be aware of the following application and SQL
release incompatibilities.

|
|
|

Adjust applications that depend on error information that is
returned from DB2-supplied stored procedures and user-defined
functions

|
|
|
|
|
|
|

Adjust applications that depend on error information that is returned from
DB2-supplied stored procedures and user-defined functions. In Version 9.1, a
number of the DB2-supplied stored procedures and user-defined functions return
different error information from the information that they returned in previous
releases of DB2. The DB2-supplied stored procedures and user-defined functions
have been enhanced to return the more meaningful SQLCODEs from the SQL
statements in the bodies of the routines.

|

Qualify user-defined function names

|
|
|
|
|
|

If you use a user-defined function that has the same name as a built in function
that has been added to Version 9.1, ensure that you fully qualify the function
name. If the function name is unqualified and SYSIBM precedes the schema that
you used for this function in the SQL path, DB2 invokes one of the built-in
functions. For a list of built-in functions, including those that have been added in
Version 9.1, see the topic “Functions”.

|

Fully define objects

|
|
|
|
|

Ensure that you do not have any incomplete object definitions in your DB2 Version
8 catalog. For example, if a table has a primary or unique key defined but the
enforcing primary or unique key index does not exist, the table definition is
considered incomplete. You need to complete or drop all such objects before you
begin migration because their behavior will be different in Version 9.1. For
© Copyright IBM Corp. 1983, 2007

1
|
|
|

example, if you attempt to create an enforcing primary key index to complete a
table definition in Version 9.1 and the residing table space is implicitly created, the
index will be treated as a regular index instead of an enforcing index.

|

SQL reserved words

|
|

Version 9.1 has several new SQL reserved words. Refer to DB2 SQL Reference for
the list, and adjust your applications accordingly.

|
|

Changes to PL/I applications with no DECLARE VARIABLE
statements

|
|
|
|
|

For PL/I applications with no DECLARE VARIABLE statements, the rules for host
variables and string constants in the FROM clause of a PREPARE or EXECUTE
IMMEDIATE statement have changed. A host variable must be a varying-length
string variable that is preceded by a colon. A PL/I string cannot be preceded by a
colon.

|

Changes in BIND PACKAGE and BIND PLAN defaults

|
|
|
|
|

The default value for bind option CURRENTDATA is changed from YES to NO.
This applies to the BIND PLAN and the BIND PACKAGE subcommands, as well
as the CREATE TRIGGER for trigger packages, and the CREATE PROCEDURE and
the ALTER PROCEDURE ADD VERSION SQL statements for SQL PL procedure
packages. Specifying NO for CURRENTDATA is the best option for performance.

|
|
|
|

The default value for bind option ISOLATION is changed from RR to CS. This
applies to the BIND PLAN and the remote BIND PACKAGE subcommands. For
the BIND PACKAGE subcommand, the current default (plan value) stays. The
default change does not apply to implicitly-built CTs (for example, DISTSERV CTs).

|
|

Although you can specify DBPROTOCOL(PRIVATE) for the DBPROTOCOL
parameter of the BIND option, DB2 issues a new warning message, DSNT226I.

|
|
|
|

All BIND statements for plans and packages that are bound during the installation
or migration process specify the ISOLATION parameter explicitly, except for
routines that do not fetch data. The current settings are maintained for
compatibility.

|
|

Automatic rebind of plans and packages created before DB2
Version 4

|
|
|
|
|

If you have plans and packages that were bound on DB2 Version 4 and before and
you specified YES or COEXIST in the AUTO BIND field of panel DSNTIPO, DB2
Version 9.1 autobinds these packages. Thus, you might experience an execution
delay the first time that such a plan is loaded. Also, DB2 might change the access
path due to the autobind, potentially resulting in a more efficient access path.

|
|
|

If you specified NO in the AUTO BIND field of panel DSNTIPO, DB2 Version 9.1
returns SQLCODE -908, SQLSTATE 23510 for each attempt to use such a package
or plan until it is rebound.

2

Application Programming and SQL Guide
|
|

Changed behavior of the INSERT statement with the
OVERRIDING USER VALUES clause

|
|
|

When the INSERT statement is specified with the OVERRIDING USER VALUES
clause, the value for the insert operation is ignored for columns that are defined
with the GENERATED BY DEFAULT attribute.

|

DESCRIBE no longer returns LONG type values

|
|
|
|

Because DB2 no longer stores LONG type values in the catalog, when you execute
a DESCRIBE statement against a column with a LONG VARCHAR or LONG
VARGRAPHIC data type, the DESCRIBE statement returns the values as
VARCHAR or VARGRAPHIC data type.

|
|
|
|

The DSNTIAUL sample program was updated through APAR PK46518 to account
for this change. You need to apply APAR PK46518 and precompile, bind compile,
and link-edit DSNTIAUL to make it compatible with the changed DESCRIBE
behavior.

|
|

DB2 enforces the restrictions about where a host variable array
can be specified

|
|
|
|
|
|
|
|

host-variable-array is the meta-variable for host variable arrays in syntax diagrams.
host-variable-array is included only in the syntax for multi-row FETCH, multi-row
INSERT, multi-row MERGE, and EXECUTE in support of a dynamic multi-row
INSERT or MERGE statement. host-variable-array is not included in the syntax
diagram for expression , so a host variable array cannot be used in other contexts.
In previous releases, if you specified host-variable-array in an unsupported context,
you received no errors. In Version 9.1, if a host variable array is referenced in an
unsupported context, DB2 issues an error.

|
|

For more information about where you can specify the host-variable-array variable,
see DB2 SQL Reference.

|
|

DEBUGSESSION system privilege required for continued
debugging of SQL procedures

|
|
|
|
|

After you migrate to new-function mode, users that debug external SQL
procedures need the DEBUGSESSION system privilege. Only users of the new
Unified Debugger enabled client platforms need this system privilege. Users of the
Version 8 SQL Debugger-enabled client platforms do not need this system
privilege.

|

Changes to the result length of the DECRYPT function

|
|
|
|

The result length of the DECRYPT function is shortened to 8 bytes less than the
length of the input value. If the result expands because of a difference between
input and result CCSIDs, you must cast the encrypted data to a larger VARCHAR
value before the DECRYPT function is run.

|
|

COLTYPE column in SYSIBM.SYSCOLUMNS and
SYSIBM.SYSCOLUMNS_HIST for LONG column types

|
|
|

When new tables are created with LONG VARCHAR or LONG VARGRAPHIC
columns, the COLTYPE values in SYSIBM.SYSCOLUMNS and
SYSIBM.SYSCOLUMNS_HIST contain VARCHAR or VARG.
Chapter 1. Planning for and designing DB2 applications

3
|
|
|

CREATEDBY column in SYSIBM.SYSDATATYPES,
SYSIBM.SYSROUTINES, SYSIBM.SYSSEQUENCES, and
SYSIBM.SYSTRIGGERS

|
|
|
|

The CREATEDBY column might contain a different value than in previous releases
of DB2. The column might contain a different value in static CREATE statements
for distinct types, functions, and procedures or when a dynamic SQL statement
sets the CURRENT SQLID value to a value other than USER.

|

Drop and recreate SYSPROC.DSNWZP

|
|
|

Drop and recreate SYSPROC.DSNWZP as part of running job DSNTIJSG or alter it
to specify READS SQL DATA, as shown in the following SQL statement:

|
|
|
|

On data sharing systems, SYSPROC.DSNWZP needs to be dropped and recreated
as part of migrating the first member, but not for subsequent members. DSNTIJSG
grants execute access on DSNWZP to PUBLIC. If necessary, change PUBLIC to a
specific authorization ID.

|
|

DB2 returns all DSNWZP output in the same format as DB2
parameters

|
|
|
|
|
|

In previous releases, DSNWZP returned the current setting of several system
parameters in a format other than the one used by the system parameter macros.
For example, DSN6SPRM expected the setting for EDMPOOL in kilobytes, and
DSNWZP returned it in bytes. In Version 9.1, DB2 returns all DSNWZP output in
the same format as DB2 parameters. Modify programs that call DSNWZP if they
compensate for the format differences.

|
|

DB2 enforces the restriction that row IDs are not compatible with
character strings when they are used with a set operator

|
|
|
|

In previous releases, DB2 did not always enforce the restriction that row IDs are
not compatible with character strings. In Version 9.1, DB2 enforces the restriction
that row IDs are not compatible with string types when they are used with a set
operator (UNION, INTERSECT, or EXCEPT).

|
|

You can no longer explicitly create a database name as
DSNxxxxx

|
|
|

After you migrate to compatibility mode, if you explicitly create a database name
with eight characters that begins with DSN and is followed by exactly five digits,
DB2 issues an SQLCODE -20074 (SQLSTATE 42939).

|
|

Database privileges on the DSNDB04 database now give you
those privileges on all implicitly-created databases

|
|
|
|
|

Because database privileges on the DSNDB04 database now give you those
privileges on all implicitly created databases, careful consideration is needed before
you grant database privileges on DSNDB04. For example, in Version 9.1, if you
have the STOPDB privilege on DSNDB04, you also have the STOPDB privilege on
all implicitly-created databases.

ALTER PROCEDURE SYSPROC.DSNWZP READS SQL DATA;

4

Application Programming and SQL Guide
|
|

Implicitly-created objects that are associated with LOB columns
require additional privileges

|
|
|
|

In previous releases, implicitly-created objects that are associated with LOB
columns did not require CREATETAB and CREATETS privileges on the database
of the base table or USE privilege on the buffer pool and storage group that is
used by the LOB objects. In Version 9.1, these privileges are required.

|

Adjust applications to use LRHCLR instead of LGDISCLR

|
|
|
|

The LGDISCLR field in the DSNDQJ00 macro has been removed. Update
applications that used the LGDISCLR value in the DSNDQJ00 mapping macro to
determine whether a log record is a compensation log record to use the LRHCLR
value instead.

|

Changed behavior for the CREATE statement

|
|
|

You can no longer create databases with the AS TEMP clause or table spaces that
specify TEMP as the target database. The TEMP database is no longer used by
DB2. The WORKFILE database is the only temporary database.

|

The DECLARE statement and the work file database

|
|
|
|

If you have applications in Version 8 that issue DECLARE SENSITIVE STATIC
SCROLL CURSOR or DECLARE GLOBAL TEMPORARY TABLE statements,
ensure that the work file database exists and that it has at least one table space
with a 32-KB page size to avoid errors.

|

Plan for the XML data type

|
|
|

Drop any user-defined data types with the name XML to prevent problems with
the new Version 9 built-in XML data type. You can recreate the existing
user-defined data types with new names.

|

Changes to XMLNAMESPACES

|
|
|
|

In Version 8, in the XMLNAMESPACES function, if the XML-namespace-uri
argument had a value of http://www.w3.org/XML/1998/namespace or
http://www.w3.org/2000/xmlns/, DB2 did not issue an error. In Version 9.1,
starting in compatibility mode, DB2 issues an error.

|

Changes to serialization of empty elements

|
|
|
|

In Version 8, DB2 serialized empty XML elements in a different way than it
serializes them in Version 9.1. In Version 8, empty element ″a″ was serialized as
<a></a>. In Version 9.1, starting in compatibility mode, empty element ″a″ is
serialized as <a/>.

|

Adjust monitor programs that access OP buffers

|
|
|
|
|

Adjust assignment strategies of monitor programs that access OP buffers. In
Version 8, traces were left in a disabled state, which consumed CPU for trace data
that could not be retrieved. In Version 9.1, traces that are started with a destination
of OPX choose the next available buffer that is not in use and traces are no longer
left in a disabled state.

Chapter 1. Planning for and designing DB2 applications

5
|
|
|
|
|
|
|

In addition, in Version 8, when the thread that owned an OP buffer terminated, OP
traces were left in a disabled state and could be reactivated by starting another
trace to that buffer. In Version 9.1, if an OP buffer terminates and the only
destinations for the trace records are OP buffers, the traces that are started to that
buffer are stopped. If an OP buffer terminates and the trace is started to both OP
and non-OP destinations, the traces that are started to that buffer are modified to
use non-OP destinations only.

|
|

The message format of DSNW128I and DSNW129I has changed, so modify
automation that is based on those message formats.

|

Changed behavior for system-required objects

|
|
|
|
|

After you migrate to Version 9.1 new-function mode, if the containing table space
is implicitly-created, you cannot drop any system-required objects, except for the
LOB table space, even if you explicitly created these objects in a previous release.
The following statements will not work properly if the system-required objects
were implicitly created by DB2:

|
|
|
|
|

CREATE AUXILIARY TABLE
If you issue a CREATE AUXILIARY TABLE statement and an auxiliary
table that was implicitly created by DB2 already exists for the same base
table, the CREATE AUXILIARY TABLE statement fails and DB2 issues
SQLCODE -646, SQLSTATE 55017, and reason code 3.

|
|
|
|
|

CREATE LOB TABLESPACE
If you issue a CREATE LOB TABLESPACE statement to create a LOB table
space in an implicitly created database, the CREATE LOB TABLESPACE
statement fails and DB2 issues SQLCODE -2035, SQLSTATE 429BW, and
reason code 1.

|
|
|
|
|

CREATE DATABASE
If you specify a database name with eight characters that begins with DSN
and is followed by exactly five digits in a CREATE DATABASE statement,
the CREATE DATABASE statement fails and DB2 issues SQLCODE -20074,
SQLSTATE 42939.

|
|
|
|

CREATE INDEX
If you create an index on a primary key, unique key, or ROWID column
that is defined as GENERATED BY DEFAULT, the index will be treated as
a regular index instead of an enforcing index.

|
|
|
|
|

CREATE AUXILIARY INDEX
If you issue a CREATE AUXILIARY INDEX statement and an auxiliary
index that was implicitly created by DB2 already exists for the same base
table, the CREATE AUXILIARY INDEX statement fails and DB2 issues
SQLCODE -748, SQLCODE 54048, and reason code 3.

|
|
|
|
|
|
|
|
|

CREATE
If you issue a CREATE statement and do not specify an IN clause or table
space name, and the default buffer pool is not large enough, DB2 chooses a
4-KB, 8-KB, 16-KB, or 32-KB buffer pool, depending on the record size. If
you issue a CREATE statement and do not specify an IN clause or table
space name, DB2 implicitly creates a segmented or partitioned-by-growth
table space, depending on the value of TABLE SPACE TYPE on installation
panel DSNTIP7. If you drop the table, DB2 also drops the containing table
space.

6

Application Programming and SQL Guide
|
|
|
|
|

DROP TABLE
If you issue a DROP TABLE statement to drop an auxiliary table from a
table space that was implicitly created by DB2, the DROP TABLE statement
fails and DB2 issues SQLCODE -2035, SQLSTATE 429BW, and reason code
2.

|
|
|
|

DROP TABLESPACE
If you issue a DROP TABLESPACE statement to drop an implicitly-created
LOB table space, the DROP TABLESPACE statement fails and DB2 issues
SQLCODE -2035, SQLSTATE 429BW, and reason code 2.

|
|
|
|
|
|
|
|

DROP INDEX
If you issue a DROP INDEX statement to drop an enforcing primary key,
unique key, or ROWID index from a table space that was implicitly
created, the DROP INDEX statement fails and DB2 issues SQLCODE -669,
SQLSTATE 42917, and reason code 2. If you issue a DROP INDEX
statement to drop an auxiliary index from a table space that was implicitly
created, the DROP INDEX statement fails and DB2 issues SQLCODE -2035,
SQLSTATE 429BW, and reason code 2.

|
|

Changes to INSERT, UPDATE, or DELETE statements on some
indexes

|
|
|

In Version 9.1, you cannot execute INSERT, UPDATE, or DELETE statements that
affect an index in the same commit scope as ALTER INDEX statements on that
index.

|
|

Availability of LOB or XML values in JDBC or SQLJ applications
with progressive streaming

|
|
|
|
|
|
|

In previous releases, if a JDBC or SQLJ application retrieved LOB data into an
application variable, the contents of the application variable were still available
after the cursor was moved or closed. DB2 Version 9.1 for z/OS supports
streaming. The IBM DB2 Driver for JDBC and SQLJ uses progressive streaming as
the default for retrieval of LOB or XML values. When progressive streaming is in
effect, the contents of LOB or XML variables are no longer available after the
cursor is moved or closed.

|
|

LOBs with a maximum length greater than 1 GB can now be
logged

|
|
|

In previous releases, only LOBs with a maximum length of 1 GB or less could be
logged. In Version 9.1, LOBs with a maximum length that is greater than 1 GB can
be logged.

|
|
|
|

DB2 returns an error when a LOB value is specified for an
argument to a stored procedure and the argument value is
longer than the target parameter and the excess is not trailing
blanks

|
|
|
|

In previous releases, DB2 did not return an error when a LOB value was specified
for an argument to a stored procedure and the argument value was longer than the
target parameter and the excess was not trailing blanks. DB2 truncated the data
and the procedure executed. In Version 9.1, DB2 returns an error.

Chapter 1. Planning for and designing DB2 applications

7
|

Changes to VARCHAR function formatting of decimal data

|
|
|
|

In Version 9.1, the formatting of decimal data has changed for the VARCHAR
function and CAST specification with a VARCHAR result type. When the input
data is decimal, any leading zeroes in the input value are removed, and leading
zeroes are not added to an input value that did not already contain leading zeroes.

|

Changes to VARCHAR_FORMAT function length attribute

|
|

In Version 9.1, the length attribute of the result is the length attribute of the format
string, up to a maximum of 100.

|
|

’W’ is no longer recognized as a valid format element of the
VARCHAR_FORMAT function format string

|
|
|
|
|

’W’ is no longer recognized as a valid format element. Use WW instead. Drop and
recreate existing views and materialized queries that are defined with Version 9.1
and that use the ’W’ format element with the VARCHAR_FORMAT function.
Rebind existing bound statements that are bound with Version 9.1 and that use the
’W’ format element with the VARCHAR_FORMAT function.

|
|

Leading or trailing blanks from the VARCHAR_FORMAT function
format string are no longer removed

|
|
|
|
|
|
|

Leading or trailing blanks from the format string for the VARCHAR_FORMAT
function are no longer removed. Existing view definitions are recalculated as part
of Version 9.1, so the new rules take effect. You can continue to use existing
materialized query statements, but they use the old rules and remove leading and
trailing blanks. Existing references to the VARCHAR_FORMAT function in bound
statements only get the new behavior when they have been bound or rebound in
Version 9.1.

|
|

DB2 issues warnings when some BEFORE or AFTER triggers are
created

|
|
|

DB2 Version 9.1 for z/OS issues a warning when a BEFORE or AFTER trigger is
created and a trigger transition variable is passed as an argument for a parameter
on a CALL statement that is within the trigger body.

|

DB2 drops certain indexes when a unique constraint is dropped

|
|
|
|

In previous releases, if a unique constraint was dropped, DB2 did not drop the
index that enforced uniqueness. In Version 9.1, if a table is in an implicitly-created
table space, and a unique constraint on that table is dropped, DB2 drops the index
that enforces uniqueness.

|
|

Changes to the upper limit to the size of the row that is used by
sort to evaluate column functions

|
|
|

The maximum limit of a row (data and key columns) that is used by sort to
evaluate MULTIPLE DISTINCT and GROUP BY column functions is decreased to
32600. If you exceed the limit, DB2 issues an error.

8

Application Programming and SQL Guide
|
|

DB2 enforces restriction on specifying a CAST FROM clause for
some forms of CREATE FUNCTION statements

|
|
|
|
|
|
|
|

The CAST FROM clause is included only in the syntax diagram for the CREATE
FUNCTION statement for an external scalar function. The CAST FROM clause is
not included in the syntax diagrams for the other variations of CREATE
FUNCTION (external table function, sourced function, or SQL function); the clause
cannot be used for these other variations. In previous releases, if you specified a
CAST FROM clause in an unsupported context, you received no errors. In Version
9.1 if a CAST FROM clause is specified in an unsupported context, DB2 issues an
error.

|
|

DB2 enforces restrictions on specifying the AS LOCATOR clause
and TABLE LIKE clause

|
|
|
|
|
|
|

The AS LOCATOR clause for LOBs is included in the syntax diagram for the
CREATE FUNCTION statement for an SQL function. This clause is not supported
in other contexts when identifying an existing SQL function such as in an ALTER,
COMMENT, DROP, GRANT, or REVOKE statement. In previous releases, if you
specified an AS LOCATOR clause for LOBs in an unsupported context, you might
not have received an error. In Version 9.1 if an AS LOCATOR clause for LOBs is
specified in an unsupported context, DB2 issues an error.

|
|
|
|
|
|
|
|
|

The TABLE LIKE clause for a trigger transition table is included only in the syntax
diagram for the CREATE FUNCTION statement for an external scalar function,
external table function, or sourced function. This clause is not supported for SQL
functions or in other contexts when identifying an existing function such as in an
ALTER, COMMENT, DROP, GRANT, or REVOKE statement, or in the SOURCE
clause of a CREATE FUNCTION statement. In previous releases, if you specified a
TABLE LIKE clause for a trigger transition table in an unsupported context, you
might not have received an error. In Version 9.1 if a TABLE LIKE clause for a
trigger transition table is specified in an unsupported context, DB2 issues an error.

|
|

DB2 enforces restriction on the CCSID parameter for the
DECRYPT_BIT and DECRYPT_BINARY functions

|
|
|
|
|

The CCSID parameter is not supported by the DECRYPT_BIT and
DECRYPT_BINARY built-in functions. In previous releases, if you specified an
argument for the CCSID parameter for these functions, you received no errors. In
Version 9.1 if an argument is specified for the CCSID parameter in an unsupported
context, DB2 issues an error.

|
|

Changed behavior of CREATE PROCEDURE for an SQL
procedure

|
|
|
|
|
|

With the introduction of native SQL procedures in Version 9.1, the semantics of the
CREATE PROCEDURE statement for an SQL procedure has changed. Starting in
Version 9.1, all SQL procedures that are created without the FENCED option or the
EXTERNAL option in the CREATE PROCEDURE statement are native SQL
procedures. In previous releases of DB2, if you did not specify either of these
options, the procedures were created as external SQL procedures.

|
|
|

If you do specify FENCED or EXTERNAL, the meanings are the same as in
previous releases of DB2. Both of these keywords mean that an external SQL
procedure is to be created.

Chapter 1. Planning for and designing DB2 applications

9
|
|

Resolution of parameter names, variable names and column
names in SQL procedures

|
|
|
|
|
|
|
|

In Version 9.1, the rules used for name resolution within a native SQL procedure
differ from the rules that were used for SQL procedures in prior releases. Because
an SQL parameter or SQL variable can have the same name as a column name,
you should explicitly qualify the names of any SQL parameters, SQL variables or
columns that have non-unique names. For more information about how the names
of these items are resolved, see the topic “References to SQL parameters and SQL
variables”. The rules used for name resolution within external SQL procedures
remains unchanged.

|

Clearing of the diagnostics area

|
|
|
|
|
|
|
|
|
|

In Version 9.1, when an SQL statement other than GET DIAGNOSTICS or
compound-statement is processed, the current diagnostics area is cleared before
DB2 processes the SQL statement. Clearing of the diagnostics area can result in
different values being returned for RETURNED_SQLSTATE and
DB2_RETURNED_SQLCODE for a GET DIAGNOSTICS statement than what
would be returned if the GET DIAGNOSTICS statement were issued from within
an external SQL procedure, or an SQL procedure with Version 8. Additionally,
there might be some differences in the values returned for the SQLSTATE and
SQLCODE SQL variables than would have been returned from an external SQL
procedure, or an SQL procedure with Version 8.

|
|

SQLSTATE and SQLCODE SQL variables after a GET
DIAGNOSTICS statement

|
|

In Version 9.1, the SQLSTATE and SQLCODE SQL variables are not cleared
following a GET DIAGNOSTICS statement.

|

Coding multiple SQL statements in a handler body

|
|
|
|
|
|

Previous releases of DB2 did not allow for a compound statement within a handler.
A workaround to include multiple statements within a handler (without support
for a compound statement in a handler) was to use another control statement, such
as an IF statement, which in turn contained multiple statements. Version 9.1 now
supports a compound statement within a handler body. The compound statement
is recommended for including multiple statements within a handler body.

|

Unhandled warnings

|
|

In Version 9.1, when a procedure completes processing with an unhandled
warning, DB2 returns the unhandled warning to the calling application.

|

Changed messages from SQL procedures

|
|
|
|
|

In Version 9.1, DB2 issues different messages for the new native SQL procedures
than it does for external SQL procedures. For external SQL procedures, DB2
continues to issue DSNHxxxx messages. For native SQL procedures, DB2 issues
SQL return codes. The relationship between these messages is shown in the
following table:

10

Application Programming and SQL Guide
|
|

Table 1. Relationship between DSNHxxxx messages that are issued for external SQL
procedures and SQLCODEs that are issued for native SQL procedures

|

DSNHxxxx message1

SQLCODE2

|

DSNH051I

-051

|

DSNH385I

+385

|

DSNH590I

-590

|

DSNH4408I

-408

|

DSNH4777I

-777

|

DSNH4778I

-778

|

DSNH4779I

-779

|

DSNH4780I

-780

|

DSNH4781I

-781

|

DSNH4782I

-782

|

DSNH4785I

-785

|
|

DSNH4787I

-787

|
|
|
|

Note:
1. These messages are used for external SQL procedures, which can be defined by
specifying EXTERNAL or FENCED in Version 9.1.
2. These messages are used for native SQL procedures in Version 9.1.

|

Enhanced data type checking for zero-length characters

|
|

In Version 9.1, when you specify Char(0), DB2 issues SQLCODE -804 regardless of
the null indicator value.

|
|
|

Determining the value of any SQL processing options that affect the
design of your program

|
|
|
|

When you process SQL statements in an application program, you can specify
options that describe the basic characteristics of the program or indicate how you
want the output listings to look. Although most of these options do not affect how
you design or code the program, a few options do.

|
|
|
|

SQL processing options specify program characteristics such as the following items:
v The host language in which the program is written
v The maximum precision of decimal numbers in the program
v How many lines are on a page of the precompiler listing

|

In many cases, you may want to accept the default value provided.

|
|

To determine the value of any SQL processing options that affect the design of
your program:

|
|
|
|
|

Review the list of SQL processing options and decide the values for any options
that affect the way that you write your program. For example, you need to know if
you are using NOFOR or STDSQL(YES) before you begin coding.
Related concepts
“DB2 program preparation overview” on page 895
Chapter 1. Planning for and designing DB2 applications

11
Related reference
“Descriptions of SQL processing options” on page 854

|
|
|
|

Determining the binding method

|
|
|
|

Before you can run an application, you must bind a plan. You can bind all of your
database request modules (DBRMs) into a single application plan or you can first
bind packages and then bind those packages into a plan. The bind method that
you choose can affect your application design.

|
|
|
|
|
|

You can choose one of the following binding methods:
v Bind all of your DBRMs into a single application plan.
v Bind all of your DBRMs into separate packages. Then bind all those packages
into a single application plan.

|
|
|

The use of packages affects your application design. For example, you might
decide to put certain SQL statements together in the same program, precompile
them into the same DBRM, and then bind them into a single package.

|

To determine the binding method:

|
|

Consider the advantages and disadvantages of each binding method, which are
described in the following table.

v Bind some of your DBRMs into separate packages. Then bind those packages
and any other DBRMs for that program into an application plan.

| Table 2. Advantages and disadvantages of each binding method
| Binding method

Advantages

Disadvantages

| Bind all of your DBRMs
| into a single application
| plan.
|
|
|

This method has fewer steps and is appropriate in
some cases. This method is suitable for small
applications that are unlikely to change or that require
all resources to be acquired when the plan is allocated,
rather than when your program first uses them.

Maintenance is difficult. This
method has the disadvantage
that a change to one DBRM
requires rebinding the entire
plan, even though most DBRMs
are unchanged.

12

Application Programming and SQL Guide
|

Table 2. Advantages and disadvantages of each binding method (continued)

|

Binding method

Advantages

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Bind all of your DBRMs
into separate packages.
Then bind all those
packages into a single
application plan

Maintenance is easier. When you use packages, you do
not need to bind the entire plan again when you
change one SQL statement. You need to bind only the
package that is associated with the changed SQL
statement.

Disadvantages

Too many packages might be
difficult to track. Input to
binding a package is a single
DBRM only. A one-to-one
correspondence between
programs and packages might
You can incrementally develop your program without easily enable you to keep track
rebinding the plan. A collection is a group of associated of each. However, your
packages. Binding packages into package collections
application might consist of too
enables you to add packages to an existing application many packages to track easily.
plan without having to bind the plan again. If you
include a collection name in the package list when you
bind a plan, any package in the collection becomes
available to the plan. The collection can be empty when
you first bind the plan. Later, you can add packages to
the collection and drop or replace existing packages
without binding the plan again.

|
|
|
|
|
|
|
|
|
|
|
|
|
|

You can maintain several versions of a package within
the same plan. Maintaining several versions of a plan
without using packages requires a separate plan for
each version, and therefore, separate plan names and
RUN commands. Isolating separate versions of a
program into packages requires only one plan and
helps to simplify program migration and fallback. For
example, you can maintain separate development, test,
and production levels of a program by binding each
level of the program as a separate version of a package,
all within a single plan. You cannot bind or rebind a
package or a plan while it is running. However, you
can bind a different version of a package that is
running.

|
|
|
|
|
|
|
|
|

You can use different bind options for different
DBRMs. The options of the BIND PLAN command
apply to all DBRMs that are bound directly to the plan.
The options of the BIND PACKAGE command apply to
only the single DBRM that is bound to that package.
The package options need not all be the same as the
plan options, and they need not be the same as the
options for other packages that are used by the same
plan.

|
|
|
|
|
|
|
|

You can use different name qualifiers for different
groups of SQL statements. You can use a bind option
to name a qualifier for the unqualified object names in
SQL statements in a plan or package. By using
packages, you can use different qualifiers for SQL
statements in different parts of your application. By
rebinding, you can redirect your SQL statements, for
example, from a test table to a production table.

|
|
|
|
|
|

Unused packages are not locked. Packages and plans
are locked when you bind or run them. Packages that
run under a plan are not locked until the plan uses
them. If you run a plan and some packages in the
package list never run, those packages are never
locked.

Chapter 1. Planning for and designing DB2 applications

13
| Table 2. Advantages and disadvantages of each binding method (continued)
| Binding method

Advantages

Disadvantages

|
|
|
|
|
|
|
|
|
|
|
|

This method helps you migrate to using packages.
Binding DBRMs directly to the plan and specifying a
package list is a suitable method for maintaining
existing applications. You can add a package list when
you rebind an existing plan. To migrate gradually to
the use of packages, bind DBRMs as packages when
you need to make changes.

Depending on your application
design, you might not gain some
of the advantages of using
packages.

Bind some of your
DBRMs into separate
packages. Then bind
those packages and any
other DBRMs for that
program into an
application plan.

Related concepts
“DB2 program preparation overview” on page 895
Related tasks
“Binding an application” on page 865

Changes that invalidate plans or packages

|
|
|
|

Changes to your program or database objects can invalidate plans and packages.
Consider the effect of these changes when you determine the binding method for
your program.

|
|
|

A change to your program probably invalidates one or more of your packages and
perhaps your entire plan. For some changes, you must bind a new object; for
others, rebinding is sufficient.

|
|
|
|
|

A plan or package can also become invalid for reasons that do not depend on
operations in your program. For example, when an index is dropped that is used
in an access path by one of your queries, a plan or package can become invalid. In
those cases, DB2 might rebind the plan or package automatically the next time that
the plan or package is used.

|
|

The following table lists the actions that you must take when changes are made to
your program or database objects.

|

Table 3. Changes that require plans or packages to be rebound.

|

Change made

Required action

|
|
|

Run RUNSTATS to update catalog statistics

Rebind the package or plan by using the
REBIND command. Rebinding might
improve the access path that DB2 uses.

|
|
|
|

Add an index to a table

Rebind the package or plan by using the
REBIND command. Rebinding causes DB2 to
consider using the index when accessing this
table.

|
|
|
|
|
|

Change the bind options

|
|
|

Change both statements in the host language Precompile, compile, and link the application
and SQL statements
program. Issue the BIND command with
ACTION(REPLACE) for the package or plan.

14

Application Programming and SQL Guide

1

Rebind the package or plan by using the
REBIND command and specifying the new
value for the bind option. If the option that
you want to change is not available for the
REBIND command, issue the BIND
command with ACTION(REPLACE) instead.
|

Table 3. Changes that require plans or packages to be rebound. (continued)

|

Change made

Required action

|
|
|
|
|

Drop a table, index, or other object, and
recreate the object

If a table with a trigger is dropped, recreate
the trigger if you recreate the table.
Otherwise, no change is required. DB2
attempts to automatically rebind the plan or
package the next time it is run.

|
|
|
|

Drop an object that a package depends on

No action is required. If the package or plan
becomes invalid, DB2 automatically rebinds
the plan or package the next time that it is
allocated.

|
|
|
|
|
|
|
|
|
|
|
|

The package might become invalid according
to the following criteria:

|
|
|

In all cases, the plan does not become invalid
until it has a DBRM that references the
dropped object.

v If the package is not appended to any
running plan, the package becomes
invalid.
v If the package is appended to a running
plan, and the drop occurs within that plan,
the package becomes invalid. However, if
the package is appended to a running
plan, and the drop occurs outside of that
plan, the object is not dropped, and the
package does not become invalid.

|
|
|
|
|
|

Revoke an authorization to use an object

No action is required. DB2 attempts to
automatically rebind the plan or package the
next time it is run. Automatic rebind fails if
authorization is still not available. In this
case, you must rebind the package or plan by
using the REBIND command.

|
|
|
|
|
|

Rename a column in a table on which a plan
or package is dependent

No action is required. DB2 automatically
rebinds invalidated plans and packages. If
automatic rebind is unsuccessful, modify,
recompile, and rebind the affected
applications.

|

Note:
1. In the case of changing the bind options, the change is not actually made until
you perform the required action.
Related concepts
“Automatic rebinding” on page 893
“Trigger packages” on page 427
Related tasks
“Rebinding an application” on page 885

|
|
|
|
|
|
|

Chapter 1. Planning for and designing DB2 applications

15
|
|
|

Determining the value of any bind options that affect the design of
your program

|
|
|
|

Several options of the BIND PACKAGE and BIND PLAN commands can affect
your program design. For example, you can use a bind option to ensure that a
package or plan can run only from a particular CICS connection or IMS region;
your code does not need to enforce this situation.

|

To determine the value of any bind options that affect the design of your program:

|
|
|
|
|
|
|

Review the list of bind options and decide the values for any options that affect
the way that you write your program. For example, you should decide the values
of the ACQUIRE and RELEASE options before you write your program. These
options determine when your application acquires and releases locks on the objects
it uses.
Related reference
″BIND and REBIND options″ (DB2 Command Reference)

|
|

Designing your application to promote concurrency

|
|
|

You should design your program so that it protects the integrity of the data, but
does not prevent other processes from accessing the same data for long periods of
time.

|
|
|
|

Concurrency is the ability of more than one application process to access the same
data at essentially the same time. Concurrency must be controlled to prevent lost
updates and such possibly undesirable effects as unrepeatable reads and access to
uncommitted data.

|
|
|
|
|
|
|
|
|
|
|
|

To design your application to promote concurrency:
1. Understand the techniques that DB2 uses to control concurrency.
One basic way that DB2 controls concurrency is by using locks for units of
work. When a unit of work completes, all locks that were implicitly acquired
by that unit of work are released, which enables a new unit of work to begin.
The amount of processing time that is used by a unit of work in your program
affects the length of time that DB2 prevents other users from accessing that
locked data. When several programs try to use the same data concurrently, each
program’s unit of work should be as short as possible to minimize the
interference between the programs.
Other techniques are discussed in the performance information about
improving concurrency.
2. Follow the recommendations for application design for concurrency.
Related tasks
″Programming for concurrency″ (DB2 Performance Monitoring and Tuning
Guide)
″Programming your applications for concurrency″ (DB2 Performance
Monitoring and Tuning Guide)

|
|
|
|
|
|

16

Application Programming and SQL Guide
|
|

Designing your application for recovery

|
|
|

If your application fails or DB2 terminates abnormally, you need to ensure the
integrity of any data that was manipulated in your application. You should
consider possible recovery situations when you design your application.

|

To design your application for recovery:
1. Put any changes that logically need to be made at the same time in the same
unit of work. This action ensures that in case DB2 terminates abnormally or
your application fails, the data is left in a consistent state.
A unit of work is a logically distinct procedure that contains steps that change
the data. If all the steps complete successfully, you want the data changes to
become permanent. But, if any of the steps fail, you want all modified data to
return to the original value before the procedure began. For example, suppose
two employees in the sample table DSN8910.EMP exchange offices. You need to
exchange their office phone numbers in the PHONENO column. You need to
use two UPDATE statements to make each phone number current. Both
statements, taken together, are a unit of work. You want both statements to
complete successfully. For example, if only one statement is successful, you
want both phone numbers rolled back to their original values before attempting
another update.

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

2. Consider how often you should commit any changes to the data.
If your program abends or the system fails, DB2 backs out all uncommitted
data changes. Changed data returns to its original condition without interfering
with other system activities.
For IMS and CICS applications, if the system fails, DB2 data does not always
return to a consistent state immediately. DB2 does not process indoubt data
(data that is neither uncommitted nor committed) until you restart IMS or the
CICS attachment facility. To ensure that DB2 and IMS are synchronized, restart
both DB2 and IMS. To ensure that DB2 and CICS are synchronized, restart both
DB2 and the CICS attachment facility.
3. Consider whether your application should intercept abends.
If your application intercepts abends, DB2 commits work, because it is unaware
that an abend has occurred. If you want DB2 to roll back work automatically
when an abend occurs in your program, do not let the program or run-time
environment intercept the abend. If your program uses Language
Environment®, and you want DB2 to roll back work automatically when an
abend occurs in the program, specify the run-time options
ABTERMENC(ABEND) and TRAP(ON).
4. For TSO applications only: Issue COMMIT statements before you connect to
another DBMS.
If the system fails at this point, DB2 cannot know whether your transaction is
complete. In this case, as in the case of a failure during a one-phase commit
operation for a single subsystem, you must make your own provision for
maintaining data integrity.
5. For TSO applications only: Determine if you want to provide an abend exit
routine in your program.
If you provide this routine, it must use tracking indicators to determine if an
abend occurs during DB2 processing. If an abend does occur when DB2 has
control, you must allow task termination to complete. DB2 detects task
termination and terminates the thread with the ABRT parameter. Do not re-run
the program.

Chapter 1. Planning for and designing DB2 applications

17
Allowing task termination to complete is the only action that you can take for
abends that are caused by the CANCEL command or by DETACH. You cannot
use additional SQL statements at this point. If you attempt to execute another
SQL statement from the application program or its recovery routine,
unexpected errors can occur.
Related concepts
″Unit of work″ (DB2 SQL Reference)

|
|
|
|
|
|
|

Unit of work in TSO

|
|
|

Applications that use the TSO attachment facility can explicitly define units of
work by using the SQL COMMIT and ROLLBACK statements.

|
|
|
|
|

In TSO applications, a unit of work starts when the first updates of a DB2 object
occur. A unit of work ends when one of the following conditions occurs:
v The program issues a subsequent COMMIT statement. At this point in the
processing, your program has determined that the data is consistent; all data
changes that were made since the previous commit point were made correctly.
v The program issues a subsequent ROLLBACK statement. At this point in the
processing, your program has determined that the data changes were not made
correctly and, therefore, should not be permanent. A ROLLBACK statement
causes any data changes that were made since the last commit point to be
backed out.
v The program terminates and returns to the DSN command processor, which
returns to the TSO Terminal Monitor Program (TMP).

|
|
|
|
|
|
|

The first and third conditions in the preceding list are called a commit point. A
commit point occurs when you issue a COMMIT statement or your program
terminates normally.
Related reference
″COMMIT″ (DB2 SQL Reference)
″ROLLBACK″ (DB2 SQL Reference)

|
|
|
|
|
|

Unit of work in CICS

|
|
|
|

CICS applications can explicitly define units of work by using the CICS
SYNCPOINT command. Alternatively, units of work are defined implicitly by
several logic breaking points.

|
|
|
|
|
|
|
|
|

All the processing that occurs in your program between two commit points is
known as a logical unit of work (LUW) or unit of work. In CICS applications, a
unit of work is marked as complete by a commit or synchronization (sync) point,
which is defined in one of following ways:
v Implicitly at the end of a transaction, which is signaled by a CICS RETURN
command at the highest logical level.

|
|
|

v Explicitly by CICS SYNCPOINT commands that the program issues at logically
appropriate points in the transaction.
v Implicitly through a DL/I PSB termination (TERM) call or command.
v Implicitly when a batch DL/I program issues a DL/I checkpoint call. This call
can occur when the batch DL/I program shares a database with CICS
applications through the database sharing facility.

|
|

For example, consider a program that subtracts the quantity of items sold from an
inventory file and then adds that quantity to a reorder file. When both transactions

18

Application Programming and SQL Guide
|
|
|
|
|

complete (and not before) and the data in the two files is consistent, the program
can then issue a DL/I TERM call or a SYNCPOINT command. If one of the steps
fails, you want the data to return to the value it had before the unit of work began.
That is, you want it rolled back to a previous point of consistency. You can achieve
this state by using the SYNCPOINT command with the ROLLBACK option.

|
|
|
|
|

By using a SYNCPOINT command with the ROLLBACK option, you can back out
uncommitted data changes. For example, a program that updates a set of related
rows sometimes encounters an error after updating several of them. The program
can use the SYNCPOINT command with the ROLLBACK option to undo all of the
updates without giving up control.

|
|
|

The SQL COMMIT and ROLLBACK statements are not valid in a CICS
environment. You can coordinate DB2 with CICS functions that are used in
programs, so that DB2 and non-DB2 data are consistent.

|

Planning for program recovery in IMS programs

|
|
|
|

To be prepared for recovery situations for IMS programs that access DB2 data, you
need to make several design decisions that are specific to IMS programs. These
decisions are in addition to the general recommendations that you should follow
when designing your application for recovery.

|
|

Both IMS and DB2 handle recovery in an IMS application program that accesses
DB2 data. IMS coordinates the process, and DB2 handles recovery for DB2 data.

|

To plan for program recovery in IMS programs:
1. For a program that processes messages as its input, decide whether to specify
single-mode or multiple-mode transactions on the TRANSACT statement of the
APPLCTN macro for the program.

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Single-mode
Indicates that a commit point in DB2 occurs each time the program
issues a call to retrieve a new message. Specifying single-mode can
simplify recovery; if the program abends, you can restart the program
from the most recent call for a new message. When IMS restarts the
program, the program starts by processing the next message.
Multiple-mode
Indicates that a commit point occurs when the program issues a
checkpoint call or when it terminates normally. Those two events are
the only times during the program that IMS sends the program’s
output messages to their destinations. Because fewer commit points are
processed in multiple-mode programs than in single-mode programs,
multiple-mode programs could perform slightly better than
single-mode programs. When a multiple-mode program abends, IMS
can restart it only from a checkpoint call. Instead of having only the
most recent message to reprocess, a program might have several
messages to reprocess. The number of messages to process depends on
when the program issued the last checkpoint call.
DB2 does some processing with single- and multiple-mode programs. When a
multiple-mode program issues a call to retrieve a new message, DB2 performs
an authorization check and closes all open cursors in the program.
2. Decide whether to issue checkpoint calls (CHKP) and if so, how often to issue
them. Each call indicates to IMS that the program has reached a sync point and
establishes a place in the program from which you can restart the program.
Chapter 1. Planning for and designing DB2 applications

19
|
|
|
|
|
|
|
|
|

Consider the following factors when deciding when to use checkpoint calls:
v How long it takes to back out and recover that unit of work. The program
must issue checkpoints frequently enough to make the program easy to back
out and recover.
v How long database resources are locked in DB2 and IMS.
v For multiple-mode programs: How you want the output messages grouped.
Checkpoint calls establish how a multiple-mode program groups its output
messages. Programs must issue checkpoints frequently enough to avoid
building up too many output messages.

|
|
|
|
|
|
|
|
|

Restriction: You cannot use SQL COMMIT and ROLLBACK statements in the
DB2 DL/I batch support environment, because IMS coordinates the unit of
work.
3. Issue CLOSE CURSOR statements before any checkpoint calls or GU calls to
the message queue, not after.
4. After any checkpoint calls, set the value of any special registers that were reset
if their values are needed after the checkpoint:
A CHKP call causes IMS to sign on to DB2 again, which resets the special
registers that are shown in the following table.

|

Table 4. Special registers that are reset by a checkpoint call.

|
|

Special register

Value to which it is reset after a checkpoint
call

|

CURRENT PACKAGESET

blanks

|

CURRENT SERVER

blanks

|

CURRENT SQLID

blanks

|
|
|
|
|
|
|
|

CURRENT DEGREE

1

5. After any commit points, reopen the cursors that you want and re-establish
positioning

|
|
|
|
|
|

6. Decide whether to specify the WITH HOLD option for any cursors. This option
determines whether the program retains the position of the cursor in the DB2
database after you issue IMS CHKP calls. You always lose the program
database positioning in DL/I after an IMS CHKP call.
The program database positioning in DB2 is affected according to the following
criteria:
v If you do not specify the WITH HOLD option for a cursor, you lose the
position of that cursor.
v If you specify the WITH HOLD option for a cursor and the application is
message-driven, you lose the position of that cursor.
v If you specify the WITH HOLD option for a cursor and the application is
operating in DL/I batch or DL/I BMP, you retain the position of that cursor.
7. Use IMS rollback calls, ROLL and ROLB, to back out DB2 and DL/I changes to
the last commit point. These options have the following differences:

|
|
|
|

ROLL
Specifies that all changes since the last commit point are to be backed out
and the program is to be terminated. IMS terminates the program with user
abend code U0778 and without a storage dump.

|
|
|
|

When you issue a ROLL call, the only option you supply is the call
function, ROLL.

|
|

20

Application Programming and SQL Guide
|
|
|
|

ROLLB
Specifies that all changes since the last commit point are to be backed out
and control is to be returned to the program so that it can continue
processing.

|
|
|
|
|
|

A ROLB call has the following options:
v The call function, ROLB
v The name of the I/O PCB
How ROLL and ROLB calls effect DL/I changes in a batch environment
depends on the IMS system log and back out options that are specified, as
shown in the following table.

|

Table 5. Effects of ROLL and ROLLB calls on DL/I changes in a batch environment

|

Options specified

|

Rollback call

System log option

Backout option

|
|
|
|
|
|
|

ROLL

tape

any

disk

BKO=NO

disk

BKO=YES

|
|
|
|
|
|

Result
DL/I does not back
out updates, and
abend U0778 occurs.
DB2 backs out
updates to the
previous checkpoint.
DL/I backs out
updates, and abend
U0778 occurs. DB2
backs out updates to
the previous
checkpoint.

Chapter 1. Planning for and designing DB2 applications

21
|
|

Table 5. Effects of ROLL and ROLLB calls on DL/I changes in a batch
environment (continued)

|

Options specified

|

Rollback call

System log option

Backout option

|
|
|
|
|
|
|
|
|
|
|
|
|

ROLB

tape

any

disk

BKO=NO

disk

BKO=YES

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Result
DL/I does not back
out updates, and an
AL status code is
returned in the PCB.
DB2 backs out
updates to the
previous checkpoint.
The DB2 DL/I
support causes the
application program
to abend when ROLB
fails.
DL/I backs out
database updates,
and control is passed
back to the
application program.
DB2 backs out
updates to the
previous checkpoint.
Restriction: You
cannot specify the
address of an I/O
area as one of the
options on the call; if
you do, your
program receives an
AD status code.
However, you must
have an I/O PCB for
your program.
Specify CMPAT=YES
on the CMPAT
keyword in the
PSBGEN statement
for your program’s
PSB.

Related concepts
“Checkpoints in IMS programs” on page 24

|
|
|

Unit of work in IMS online programs

|
|
|
|

In IMS, a unit of work starts when one of the following events occurs:
v When the program starts
v After a CHKP, SYNC, ROLL, or ROLB call has completed
v For single-mode transactions, when a GU call is issued to the I/O PCB

|

A unit of work ends when one of the following events occurs:

IMS applications can explicitly define units of work by using a CHKP, SYNC,
ROLL, or ROLB call, or, for single-mode transactions, a GU call.

22

Application Programming and SQL Guide
|
|
|
|
|
|
|
|

v The program issues either a subsequent CHKP or SYNC call, or, for single-mode
transactions, a GU call to the I/O PCB. At this point in the processing, the data
is consistent. All data changes that were made since the previous commit point
are made correctly.
v The program issues a subsequent ROLB or ROLL call. At this point in the
processing, your program has determined that the data changes are not correct
and, therefore, that the data changes should not become permanent.
v The program terminates.

|
|

Restriction: The SQL COMMIT and ROLLBACK statements are not valid in an
IMS environment.

|
|
|
|
|
|

A commit point occurs in a program as the result of any one of the following
events:
v The program terminates normally. Normal program termination is always a
commit point.
v The program issues a checkpoint call. Checkpoint calls are a program’s means of
explicitly indicating to IMS that it has reached a commit point in its processing.
v The program issues a SYNC call. A SYNC call is a Fast Path system service call
to request commit-point processing. You can use a SYNC call only in a
non-message-driven Fast Path program.
v For a program that processes messages as its input, a commit point can occur
when the program retrieves a new message. This behavior depends on the mode
that you specify in the APPLCTN macro for the program:
– If you specify single-mode transactions, a commit point in DB2 occurs each
time the program issues a call to retrieve a new message.
– If you specify multiple-mode transactions or you do not specify a mode, a
commit point occurs when the program issues a checkpoint call or when it
terminates normally.

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|

At the time of a commit point, the following actions occur:
v IMS and DB2 can release locks that the program has held since the last commit
point. Releasing these locks makes the data available to other application
programs and users. However, when you define a cursor as WITH HOLD in a
BMP program, DB2 holds those locks until the cursor closes or the program
ends.
v DB2 closes any open cursors that the program has been using.
v IMS and DB2 make the program’s changes to the database permanent.
v If the program processes messages, IMS sends the output messages that the
application program produces to their final destinations. Until the program
reaches a commit point, IMS holds the program’s output messages at a
temporary destination.

|
|
|
|
|
|
|
|

If the program abends before reaching the commit point, the following actions
occur:
v Both IMS and DB2 back out all the changes the program has made to the
database since the last commit point.
v IMS deletes any output messages that the program has produced since the last
commit point (for nonexpress PCBs).
v If the program processes messages, people at terminals and other application
programs receive information from the terminating application program.

|
|
|
|
|
|
|

Chapter 1. Planning for and designing DB2 applications

23
|
|

If the system fails, a unit of work resolves automatically when DB2 and IMS batch
programs reconnect. Any indoubt units of work are resolved at reconnect time.

|
|
|
|

Specifying checkpoint frequency in IMS programs

|

To specify checkpoint frequency in IMS programs:
1. Use a counter in your program to keep track of one of the following items:
v Elapsed time
v The number of root segments that your program accesses

A checkpoint indicates a commit point in IMS programs. You should specify
checkpoint frequency in your program in a way that makes changing it easy in
case the frequency you initially specify is not right.

|
|
|
|
|
|

v The number of updates that your program performs
2. Issue a checkpoint call after a certain time interval, number of root segments, or
number of updates.

|

Checkpoints in IMS programs:

|
|
|
|

Issuing checkpoint calls releases locked resources and establishes a place in the
program from which you can restart the program. The decision about whether
your program should issue checkpoints (and if so, how often) depends on your
program.

|

Generally, the following types of programs should issue checkpoint calls:
v Multiple-mode programs
v Batch-oriented BMPs
v Nonmessage-driven Fast Path programs. (These programs can use a special Fast
Path call, but they can also use symbolic checkpoint calls.)
v Most batch programs
v Programs that run in a data sharing environment. (Data sharing makes it
possible for online and batch application programs in separate IMS systems, in
the same or separate processors, to access databases concurrently. Issuing
checkpoint calls frequently in programs that run in a data sharing environment
is important, because programs in several IMS systems access the database.)

|
|
|
|
|
|
|
|
|
|

|

You do not need to issue checkpoints in the following types of programs:
v Single-mode programs
v Database load programs
v Programs that access the database in read-only mode (defined with the
processing option GO during a PSBGEN) and are short enough to restart from
the beginning
v Programs that, by their nature, must have exclusive use of the database

|
|
|
|
|
|
|
|
|

A CHKP call causes IMS to perform the following actions:
v Inform DB2 that the changes that your program made to the database can
become permanent. DB2 makes the changes to DB2 data permanent, and IMS
makes the changes to IMS data permanent.
v Send a message that contains the checkpoint identification that is given in the
call to the system console operator and to the IMS master terminal operator.
v Return the next input message to the program’s I/O area if the program
processes input messages. In MPPs and transaction-oriented BMPs, a checkpoint
call acts like a call for a new message.

|
|
|
|
|
|

24

Application Programming and SQL Guide
|

v Sign on to DB2 again.

|
|
|

Programs that issue symbolic checkpoint calls can specify as many as seven data
areas in the program that is to be restored at restart. DB2 always recovers to the
last checkpoint. You must restart the program from that point.

|
|
|
|

If you use symbolic checkpoint calls, you can use a restart call (XRST) to restart a
program after an abend. This call restores the program’s data areas to the way they
were when the program terminated abnormally, and it restarts the program from
the last checkpoint call that the program issued before terminating abnormally.

|
|

Restriction: For BMP programs that process DB2 databases, you can restart the
program only from the latest checkpoint and not from any checkpoint, as in IMS.

|

Checkpoints in MPPs and transaction-oriented BMPs

|
|
|
|
|
|
|
|
|

In single-mode programs, checkpoint calls and message retrieval calls (called
get-unique calls) both establish commit points. The checkpoint calls retrieve input
messages and take the place of get-unique calls. BMPs that access non-DL/I
databases and MPPs can issue both get unique calls and checkpoint calls to
establish commit points. However, message-driven BMPs must issue checkpoint
calls rather than get-unique calls to establish commit points, because they can
restart from a checkpoint only. If a program abends after issuing a get-unique call,
IMS backs out the database updates to the most recent commit point, which is the
get-unique call.

|
|
|
|
|
|
|

In multiple-mode BMPs and MPPs, the only commit points are the checkpoint calls
that the program issues and normal program termination. If the program abends
and it has not issued checkpoint calls, IMS backs out the program’s database
updates and cancels the messages that it has created since the beginning of the
program. If the program has issued checkpoint calls, IMS backs out the program’s
changes and cancels the output messages it has created since the most recent
checkpoint call.

|

Checkpoints in batch-oriented BMPs

|
|
|
|

If a batch-oriented BMP does not issue checkpoints frequently enough, IMS can
abend that BMP or another application program for one of the following reasons:
v Other programs cannot get to the data that they need within a specified amount
of time.
If a BMP retrieves and updates many database records between checkpoint calls,
it can monopolize large portions of the databases and cause long waits for other
programs that need those segments. (The exception to this situation is a BMP
with a processing option of GO; IMS does not enqueue segments for programs
with this processing option.) Issuing checkpoint calls releases the segments that
the BMP has enqueued and makes them available to other programs.
v Not enough storage is available for the segments that the program has read and
updated.
If IMS is using program isolation enqueuing, the space that is needed to
enqueue information about the segments that the program has read and updated
must not exceed the amount of storage that is defined for the IMS system. (The
amount of storage available is specified during IMS system definition. ) If a BMP
enqueues too many segments, the amount of storage that is needed for the
enqueued segments can exceed the amount of available storage. In that case,

|
|
|
|
|
|
|
|
|
|
|
|
|
|

Chapter 1. Planning for and designing DB2 applications

25
IMS terminates the program abnormally. You then need to increase the
program’s checkpoint frequency before rerunning the program.

|
|
|
|
|
|
|
|
|

When you issue a DL/I CHKP call from an application program that uses DB2
databases, IMS processes the CHKP call for all DL/I databases, and DB2 commits
all the DB2 database resources. No checkpoint information is recorded for DB2
databases in the IMS log or the DB2 log. The application program must record
relevant information about DB2 databases for a checkpoint, if necessary. One way
to record such information is to put it in a data area that is included in the DL/I
CHKP call.

|
|
|
|
|

Performance might be slowed by the commit processing that DB2 does during a
DL/I CHKP call, because the program needs to re-establish position within a DB2
database. The fastest way to re-establish a position in a DB2 database is to use an
index on the target table, with a key that matches one-to-one with every column in
the SQL predicate.

|
|
|

Recovering data in IMS programs

|

To recover data in IMS programs:

|

Take one or more of the following actions depending on the type of program:

|
|

Program type

Recommended action

|
|
|
|

DL/I batch applications

Use the DL/I batch backout utility to back
out DL/I changes. DB2 automatically backs
out changes whenever the application
program abends.

|
|
|
|
|
|
|

Applications that use symbolic checkpoints

Use a restart call (XRST) to restart a program
after an abend. This call restores the
program’s data areas to the way they were
when the program terminated abnormally,
and it restarts the program from the last
checkpoint call that the program issued
before terminating abnormally.

|
|
|
|
|

BMP programs that access DB2 databases

Restart the program from the latest
checkpoint.
Restriction: You can restart the program
only from the latest checkpoint and not from
any checkpoint, as in IMS.

|
|

Applications that use online IMS systems

No action needed. Recovery and restart are
part of the IMS system

|
|
|

Applications that reside in the batch region

Follow your location’s operational
procedures to control recovery and restart.

In an online IMS system, recovery and restart are part of the IMS system. For a
batch region, your location’s operational procedures control recovery and restart.

Undoing selected changes within a unit of work by using
savepoints

|
|
|
|
|

Savepoints enable you to undo selected changes within a unit of work. Your
application can set any number of savepoints and then specify a specific savepoint
to indicate which changes to undo within the unit of work.

|

To undo selected changes within a unit of work by using savepoints:

26

Application Programming and SQL Guide
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

1. Set any savepoints by using SQL SAVEPOINT statements. Savepoints set a
point to which you can undo changes within a unit of work.
Consider the following abilities and restrictions when setting savepoints:
v You can set a savepoint with the same name multiple times within a unit of
work. Each time that you set the savepoint, the new value of the savepoint
replaces the old value.
v If you do not want a savepoint to have different values within a unit of
work, use the UNIQUE option in the SAVEPOINT statement. If an
application executes a SAVEPOINT statement with the same name as a
savepoint that was previously defined as unique, an SQL error occurs.
v If you set a savepoint before you execute a CONNECT statement, the scope
of that savepoint is the local site. If you set a savepoint after you execute the
CONNECT statement, the scope of that savepoint is the site to which you are
connected.

|
|
|
|
|
|

v When savepoints are active, which they are until the unit of work completes,
you cannot access remote sites by using three-part names or aliases for
three-part names. You can, however, use DRDA® access with explicit
CONNECT statements.
v You cannot use savepoints in global transactions, triggers, user-defined
functions, or stored procedures that are nested within triggers or
user-defined functions.
2. Specify the changes that you want to undo within a unit of work by using the
SQL ROLLBACK TO SAVEPOINT statement.
DB2 undoes all changes since the specified savepoint. If you do not specify a
savepoint name, DB2 rolls back work to the most recently created savepoint.
3. Optional: If you no longer need a savepoint, delete it by using the SQL
RELEASE SAVEPOINT statement.

|
|
|
|
|

Recommendation: If you no longer need a savepoint before the end of a
transaction, release it. Otherwise, savepoints are automatically released at the
end of a unit of work. Releasing savepoints is essential if you need to use
three-part names to access remote locations, because you cannot perform this
action while savepoints are active.

|

Examples

|
|
|
|
|
|
|
|

Rolling back to the most recently created savepoint: When the ROLLBACK TO
SAVEPOINT statement is executed in the following code, DB2 rolls back work to
savepoint B.

|
|
|
|
|
|

Setting savepoints during distributed processing: An application performs the
following tasks:
1. Sets savepoint C1.
2. Does some local processing.
3. Executes a CONNECT statement to connect to a remote site.
4. Sets savepoint C2.

EXEC SQL SAVEPOINT A;
...
EXEC SQL SAVEPOINT B;
...
EXEC SQL ROLLBACK TO SAVEPOINT;

Chapter 1. Planning for and designing DB2 applications

27
|
|
|
|

Because savepoint C1 is set before the application connects to a remote site,
savepoint C1 is known only at the local site. However, because savepoint C2 is set
after the application connects to the remote site, savepoint C2 is known only at the
remote site.

|
|
|
|

Setting multiple savepoints with the same name: Suppose that the following
actions occur within a unit of work:
1. Application A sets savepoint S.
2. Application A calls stored procedure P.
3. Stored procedure P sets savepoint S.
4. Stored procedure P executes the following statement: ROLLBACK TO SAVEPOINT S

|
|

When DB2 executes the ROLLBACK statement, DB2 rolls back work to the
savepoint that was set in the stored procedure, because that value is the most
recent value of savepoint S.
Related reference
″SAVEPOINT″ (DB2 SQL Reference)
″ROLLBACK″ (DB2 SQL Reference)
″RELEASE SAVEPOINT″ (DB2 SQL Reference)

|
|
|
|
|
|
|

Planning for recovery of table spaces that are not logged

|
|
|
|
|

To suppress logging, you can specify the NOT LOGGED option when you create
or alter a table space. However, because logs are generally used in recovery,
planning for recovery of table spaces for which changes are not logged requires
some additional planning.

|
|
|
|
|
|

Although you can plan for recovery, you still need to take some corrective actions
after any system failures to recover the data and fix any affected table spaces. For
example, if a table space that is not logged was open for update at the time that
DB2 terminates, the subsequent restart places that table space in LPL and marks it
with RECOVER-pending status. You need to take corrective action to clear the
RECOVER-pending status.

|

|
|
|
|
|
|
|
|

To plan for recovery of table spaces that are not logged:
1. Ensure that you can recover lost data by performing one of the following
actions:
v Ensure that you have a data recovery source that does not rely on a log
record to recreate any lost data.
v Limit modifications that are not logged to easily repeatable changes that can
be quickly repeated.
2. Avoid placing a table space that is not logged in a RECOVER-pending status.
The following actions place a table space in RECOVER-pending status:
v Issuing a ROLLBACK statement or ROLLBACK TO SAVEPOINT statement
after modifying a table in a table space that is not logged.
v Causing duplicate keys or referential integrity violations when you modify a
table space that is not logged.

|
|
|
|

If the table space is placed in RECOVER-pending status, it is unavailable until
you manually fix it.
3. For table spaces that are not logged and have associated LOB or XML table
spaces, take image copies as a recovery set.

|
|
|
|

28

Application Programming and SQL Guide
|
|
|
|
|
|
|

This action ensures that the base table space and all the associated LOB or XML
table spaces are copied at the same point in time. A subsequent RECOVER TO
LASTCOPY operation for the entire set results in consistent data across the base
table space and all of the associated LOB and XML table spaces.
Related tasks
″Clearing the RECOVER-pending status″ (DB2 Administration Guide)
Related reference

|

″RECOVER″ (DB2 Utility Guide and Reference)

Designing your application to access distributed data
For applications that access data on another database management system (DBMS)
other than your local system, use DRDA access. You should also consider the
limitations and recommendations for such programs when designing them.
If your system is not already set up to use DRDA access, you must first prepare
your system to use DRDA access. One of the tools that can help you during this
process is the private to DRDA protocol REXX™ tool (DSNTP2DP).
To design your application to access distributed data:
1. Ensure that the appropriate authorization ID has been granted authorization at
the remote server to connect to that server and use resources from it.
2. If your application contains SQL statements that run at the requester, include at
the requester a database request module (DBRM) that is bound either directly
to a plan or to a package that is included in the plan’s package list.
3. Include a package at the remote server for any SQL statements that run at that
server.
4. For TSO and batch applications that update data at a remote server, ensure that
one of the following conditions is true:
v No other connections exist.
v All existing connections are to servers that are restricted to read-only
operations.
Restriction: If neither of these conditions are met, the application is restricted
to read-only operations.
If one of these conditions is met, and if the first connection in a logical unit of
work is to a server that supports two-phase commit, that server and all servers
that support two-phase commit can update data. However, if the first
connection is to a server that does not support two-phase commit, only that
server is allowed to update data.
5. For programs that access at least one restricted system, ensure that your
program does not violate any of the limitations for accessing restricted systems.
A restricted system is a DBMS that does not implement two-phase commit
processing.
Accessing restricted systems has the following limitations:
v For programs that access CICS or IMS, you cannot update data on restricted
systems.
v Within a unit of work, you cannot update a restricted system after updating
a non-restricted system.
v Within a unit of work, if you update a restricted system, you cannot update
any other systems.

Chapter 1. Planning for and designing DB2 applications

29
If you are accessing a mixture of systems, some of which might be restricted,
you can perform the following actions:
v Read from any of the systems at any time.
v Update any one system many times in one unit of work.
v Update many systems, including CICS or IMS, in one unit of work, provided
that none of them is a restricted system. If the first system you update in a
unit of work is not restricted, any attempt to update a restricted system in
that unit of work returns an error.
v Update one restricted system in a unit of work, provided that you do not try
to update any other system in the same unit of work. If the first system you
update in a unit of work is restricted, any attempt to update any other
system in that unit of work returns an error.
Related tasks
″Preparing your system for DRDA access″ (DB2 Installation Guide)
Related reference
″The private to DRDA protocol REXX tool (DSNTP2DP)″ (DB2 Installation
Guide)

Remote servers and distributed data
Distributed data is data that resides on a database management system (DBMS)
other than your local system. Your local DBMS is the one on which you bind your
application plan. All other DBMSs are remote.
If you are requesting services from a remote DBMS, that DBMS is a server, and
your local system is a requester or client.
Your application can be connected to many DBMSs at one time; the one that is
currently performing work is the current server. When the local system is
performing work, it also is called the current server.
A remote server can be physically remote, or it can be another subsystem of the
same operating system that your local DBMS runs under. A remote server might be
an instance of DB2 for z/OS, or it might be an instance of one of another product.
A DBMS, whether local or remote, is known to your DB2 system by its location
name. The location name of a remote DBMS is recorded in the communications
database.
Related tasks
″Choosing names for the local subsystem″ (DB2 Installation Guide)

Advantages of DRDA access
Programs that access distributed data should use DRDA access. Not only does
DRDA access have many advantages over DB2 private protocol access, but also
private protocol support will be removed in a future release of DB2.
DRDA access has the following advantages over DB2 private protocol access:
v Integration: DRDA access is available to all DBMSs that implement Distributed
Relational Database Architecture (DRDA). Those DBMSs include supported
releases of DB2 for z/OS, other members of the DB2 family of IBM products,
and many products of other companies.
DB2 private protocol access is available only to supported releases of DB2 for
z/OS.

30

Application Programming and SQL Guide
v SQL compatibility: DRDA access allows any SQL statement that the server can
execute.
DB2 private protocol access supports only data manipulation statements:
INSERT, UPDATE, DELETE, SELECT, OPEN, FETCH, and CLOSE. In addition,
you cannot use any syntax of an SQL statement that was introduced after DB2
Version 5. You also cannot invoke user-defined functions and stored procedures
or use LOBs or distinct types.
v Reduced network load: DRDA access uses a more compact format for sending
data over the network. This process improves the performance on slow network
links.
v Reduced bind processing: A DBRM for statements that are executed by DRDA
access is bound to a package at the server only once. Those statements can
include PREPARE and EXECUTE, so your application can accept dynamic
statements that are to be executed at the server.
Queries that are executed by DB2 private protocol access are bound at the server
whenever they are first executed in a unit of work. Repeated binds can reduce
the performance of a query that is executed often.
v Stored procedures: You can use stored procedures with DRDA access. Because
stored procedures require no message traffic over the network while they are
running, they reduce the biggest obstacle to high performance for distributed
data.
v Scrollable cursors: You can use scrollable cursors if you use DRDA access.
v Savepoints: You can set savepoints only if you use DRDA access with explicit
CONNECT statements. If you set a savepoint and then execute an SQL
statement with a three-part name, an SQL error occurs.
Related tasks
“Undoing selected changes within a unit of work by using savepoints” on page
26

Preparing for coordinated updates to two or more data
sources
Two or more updates are coordinated if they must all commit or all roll back in the
same unit of work.
This situation is common in banking. Suppose that an amount is subtracted from
one account and added to another. The two actions must either both commit or
both roll back at the end of the unit of work.
To prepare for coordinated updates to two or more data sources:
Ensure that all systems that your program accesses implement two-phase commit
processing. This processing ensures that updates to two or more DBMSs are
coordinated automatically.
For example, DB2 and IMS, and DB2 and CICS, jointly implement a two-phase
commit process. You can update an IMS database and a DB2 table in the same unit
of work. If a system or communication failure occurs between committing the
work on IMS and on DB2, the two programs restore the two systems to a
consistent point when activity resumes.
|
|
|

You cannot do true coordinated updates within a DBMS that does not implement
two-phase commit processing, because DB2 prevents you from updating such a
DBMS and any other system within the same unit of work. In this context, update
Chapter 1. Planning for and designing DB2 applications

31
includes the statements INSERT, UPDATE, MERGE, DELETE, CREATE, ALTER,
DROP, GRANT, REVOKE, RENAME, COMMENT, and LABEL.

|
|

However, if you cannot implement two-phase commit processing on all systems
that your program accesses, you can simulate the effect of coordinated updates by
performing the following actions:
1. Update one system and commit that work.
2. Update the second system and commit its work.
3.

Ensure that your program has code to undo the first update if a failure occurs
after the first update is committed and before the second update is committed.
No automatic provision exists for bringing the two systems back to a consistent
point.
Related concepts
″Two-phase commit process″ (DB2 Administration Guide)

Forcing restricted system rules in your program
A restricted system is a DBMS that does not implement two-phase commit
processing. These systems have a number of update restrictions. You can restrict
your program completely to the rules for these restricted systems, regardless of
whether the program is accessing restricted systems or non-restricted systems.
Accessing restricted systems has the following limitations:
v For programs that access CICS or IMS, you cannot update data on restricted
systems.
v Within a unit of work, you cannot update a restricted system after updating a
non-restricted system.
v Within a unit of work, if you update a restricted system, you cannot update any
other systems.
To force restricted system rules in your program:
When you prepare your program, specify the SQL processing option
CONNECT(1). This option applies type 1 CONNECT statement rules.
Restriction: Do not use packages that are precompiled with the CONNECT(1)
option and packages that are precompiled with the CONNECT(2) option in the
same package list. The first CONNECT statement that is executed by your
program determines which rules are in effect for the entire execution: type 1 or
type 2. If your program attempts to execute a later CONNECT statement that is
precompiled with the other type, DB2 returns an error.
Related concepts
“Options for SQL statement processing” on page 853

Maximizing the performance of an application that accesses
distributed data
They key to improving the performance of applications that access remote data is
to limit the number of network transmissions. You should consider if any of the
recommendations for reducing these transmissions makes sense for your
application.
To maximize the performance of an application that accesses distributed data:

32

Application Programming and SQL Guide
1. Write any queries that access distributed data according to the following
recommendations to limit the number of messages that these queries send over
the network:
v Reduce the number of columns and rows in the result table by keeping the
select lists as short as possible and using the WHERE, GROUP BY, and
HAVING clauses to eliminate unwanted data at the remote server.
v Specify the FOR FETCH ONLY or FOR READ ONLY clause when possible.
Retrieving thousands of rows as a continuous stream is reasonable. Sending a
separate message for each one can be significantly slower.
However, be aware the a query that is sent to a remote subsystem almost
always takes longer to execute than the same query that accesses tables of the
same size on the local subsystem for the following reasons:
v Overhead processing, including startup, negotiating session limits, and, for
DB2 private protocol access, the bind required at the remote location
v The time required to send messages across the network
2. For any of the following situations, use the OPTIMIZE FOR n ROWS clause in
your SELECT statements and query result sets from stored procedures:
v The application fetches only a small number of rows from the query result
set.
v The application fetches a large number of rows from a read-only query.
v The application rarely closes the SQL cursor before fetching the entire query
result set.
v The application does not issue statements other than the FETCH statement to
the DB2 server while the SQL cursor is open.
v The application does not execute FETCH statements for multiple cursors that
are open concurrently and defined with the OPTIMIZE FOR n ROWS clause.
v The application does not need to scroll randomly through the data.
The OPTIMIZE FOR n ROWS clause limits the number of data rows that the
server returns on each DRDA network transmission.
Restriction: This clause has no effect on scrollable cursors.
In a DRDA environment, if you specify 1, 2, or 3 for n , DB2 uses the value 16
(instead of n) for network blocking and prefetches 16 rows. As a result,
network usage is more efficient even though DB2 uses the small value of n for
query optimization.
For example, the following SQL statement causes DB2 to prefetch 16 rows of
the result table even though n has a value of 1.
SELECT * FROM EMP

OPTIMIZE FOR 1 ROW ONLY;

3. For queries that have potentially large result tables, but need only a limited
number of rows, specify the FETCH FIRST n ROWS ONLY clause. This clause
limits the number of rows that are returned to a client program.
For example, suppose that you need only one row of the result table. You can
add the FETCH FIRST 1 ROW ONLY clause, as shown in the following
example:
SELECT * FROM EMP

OPTIMIZE FOR 1 ROW ONLY

FETCH FIRST 1 ROW ONLY;

In this case, the FETCH FIRST 1 ROW ONLY clause prevents 15 unnecessary
prefetches.
4. If your program accesses LOB columns in a remote table, use the following
techniques to minimize the number of bytes that are transferred between the
client and the server:
Chapter 1. Planning for and designing DB2 applications

33
v Use LOB locators instead of LOB host variables.
If you need to store only a portion of a LOB value at the client, or if your
client program manipulates the LOB data but does not need a copy of it,
LOB locators are a good choice. When a client program retrieves a LOB
column from a server into a locator, DB2 transfers only the 4-byte locator
value to the client, not the entire LOB value.
v Use stored procedure result sets.
When you return LOB data to a client program from a stored procedure, use
result sets rather than passing the LOB data to the client in parameters.
Using result sets to return data causes less LOB materialization and less
movement of data among address spaces.
v Set the CURRENT RULES special register to DB2.
When a DB2 server receives an OPEN request for a cursor, the server uses
the value in the CURRENT RULES special register to determine the type of
host variables that the associated statement uses to retrieve LOB values. If
you specify a value of DB2 for the CURRENT RULES special register before
you perform a CONNECT, and the first FETCH statement for the cursor uses
a LOB locator to retrieve LOB column values, DB2 lets you use only LOB
locators for all subsequent FETCH statements for that column until you close
the cursor. If the first FETCH statement uses a host variable, DB2 lets you
use only host variables for all subsequent FETCH statements for that column
until you close the cursor. However, if you set the value of CURRENT
RULES to STD, DB2 lets you use the same open cursor to fetch a LOB
column into either a LOB locator or a host variable.
Although a value of STD for the CURRENT RULES special register gives you
more programming flexibility when you retrieve LOB data, you get better
performance if you use a value of DB2. With the STD option, the server must
send and receive network messages for each FETCH statement to indicate
whether the data that is being transferred is a LOB locator or a LOB value.
With the DB2 option, the server knows the size of the LOB data after the first
FETCH, so an extra message about LOB data size is unnecessary. The server
can send multiple blocks of data to the requester at one time, which reduces
the total time for data transfer.
For example, suppose that an end user wants to browse through a large set of
employee records and look at pictures of only a few of those employees. At the
server, you set the CURRENT RULES special register to DB2. In the application,
you declare and open a cursor to select employee records. The application then
fetches all picture data into 4-byte LOB locators. Because DB2 knows that 4
bytes of LOB data is returned for each FETCH statement, DB2 can fill the
network buffers with locators for many pictures. When a user wants to see a
picture for a particular person, the application can retrieve the picture from the
server by assigning the value that is referenced by the LOB locator to a LOB
host variable. This situation is implemented in the following code:
SQL TYPE IS BLOB my_blob[1M];
SQL TYPE IS BLOB AS LOCATOR my_loc;
.
.
.
FETCH C1 INTO :my_loc;
/* Fetch BLOB into LOB locator */
.
.
.
SET :my_blob = :my_loc; /* Assign BLOB to host variable */

Restriction: You must use DRDA access to access LOB columns in a remote
table.
5. Minimize the use of parameter markers.

34

Application Programming and SQL Guide
When using DRDA access, DB2 can streamline the processing of dynamic
queries that do not have parameter markers. When a DB2 requester encounters
a PREPARE statement for such a query, it anticipates that the application is
going to open a cursor. DB2 therefore sends a single message to the server that
contains a combined request for the PREPARE, DESCRIBE, and OPEN
operations. A server that receives this message sequence returns a reply
message sequence that includes the output from the PREPARE, DESCRIBE, and
OPEN operations. As a result, the number of network messages sent and
received for these operations is reduced from two to one. DB2 combines
messages for these queries regardless of whether the bind option
DEFER(PREPARE) is specified.
6. Ensure that each cursor meets one of the following conditions when possible,
so that DB2 uses block fetch to minimize the number of messages that are sent
across the network:
v The cursor is declared with either the FOR FETCH ONLY or FOR READ
ONLY clause.
v The cursor is a non-scrollable cursor, and the result table of the cursor is
read-only.
v The cursor is a scrollable cursor that is declared as INSENSITIVE, and the
result table of the cursor is read-only.
v The cursor is a scrollable cursor that is declared as SENSITIVE, the result
table of the cursor is read-only, and the value of the CURRENTDATA bind
option is NO.
v The result table of the cursor is not read-only, but the cursor is ambiguous,
and the value of the CURRENTDATA bind option is NO.
A cursor is ambiguous when any of the following conditions are true:
– It is not defined with the clauses FOR FETCH ONLY, FOR READ ONLY,
or FOR UPDATE.
– It is not defined on a read-only result table.
– It is not the target of a WHERE CURRENT clause on an SQL UPDATE or
DELETE statement.
– It is in a plan or package that contains the SQL statements PREPARE or
EXECUTE IMMEDIATE.
7. For ODBC and JDBC applications, use the rowset parameter to limit the
number of rows that are returned from a fetch operation.
If a DRDA requester sends the rowset parameter to a DB2 server, the server
performs the following actions:
v Returns no more than the number of rows in the rowset parameter
v Returns extra query blocks if the value of the EXTRA BLOCKS SRV field on
the DISTRIBUTED DATA FACILITY PANEL 2 installation panel on the server
allows extra query blocks to be returned
v Processes the FETCH FIRST n ROWS ONLY clause, if it is specified
v Does not process the OPTIMIZE FOR n ROWS clause
8. Use the recommended values for the following bind options:
Table 6. Recommended bind option values for applications that access distributed data
Bind option

Recommended value and actions

Reason

CURRENTDATA

CURRENTDATA(NO)

Use this bind option to force block fetch for
ambiguous queries.

Chapter 1. Planning for and designing DB2 applications

35
Table 6. Recommended bind option values for applications that access distributed data (continued)
Bind option

Recommended value and actions

Reason

DBPROTOCOL

DBPROTOCOL(DRDA)

If the value of the installation default
database protocol is not DRDA, use this
bind option to cause DB2 to use DRDA
access to execute SQL statements with
three-part names. Statements that use
DRDA access perform better at execution
time for the following reasons:
v Binding occurs when the package is
bound, not during program execution.
v DB2 does not destroy static statement
information at commit time, as it does
with DB2 private protocol access. With
DRDA access, if a commit occurs
between two executions of a statement,
DB2 does not need to prepare the
statement twice.

ISOLATION

Anything but ISOLATION (RR)

When possible, do not bind application
plans and packages with ISOLATION(RR).
If your application does not need to
reference rows that it has already read,
another isolation level might reduce lock
contention and message overhead during
commit processing.

KEEPDYNAMIC

KEEPDYNAMIC(YES)

Use this bind option to improve
performance for queries that use cursors
that are defined with the WITH HOLD
option. With KEEPDYNAMIC(YES), DB2
automatically closes the cursor when no
more data exists for retrieval. The client
does not need to send a network message
to tell DB2 to close the cursor.

NODEFER and DEFER

DEFER(PREPARE)

This option reduces network traffic, because
the PREPARE and EXECUTE statements
and responses are transmitted together.

36

Application Programming and SQL Guide
Table 6. Recommended bind option values for applications that access distributed data (continued)
Bind option

Recommended value and actions

PKLIST and NOPKLIST

Reason

PKLIST

The order in which you specify package
collections in a package list can affect the
Specify the package collections for this bind performance of your application program.
option according to the following
When a local instance of DB2 attempts to
recommendations:
execute an SQL statement at a remote
server, the local DB2 subsystem must
v Reduce the number of packages per
determine which package collection the
collection that DB2 must search. The
SQL statement is in. DB2 must send a
following example specifies only one
message to the server to request that the
package in each collection:
server check each collection ID for the SQL
PKLIST(S1.COLLA.PGM1, S1.COLLB.PGM2)
statement until the statement is found or no
v Reduce the number of package
more collection IDs are in the package list.
collections at each location that DB2 must You can reduce the amount of network
search. The following example specifies
traffic, and thereby improve performance,
only one package collection at each
by reducing the number of package
location:
collections that each server must search.
PKLIST(S1.COLLA.*, S2.COLLB.*)
v Reduce the number of collections that are As an alternative to specifying the package
used for each application. The following collections on the PKLIST bind option, you
can specify the package collection that is
example specifies only one collection to
associated with an SQL statement in your
search:
application program. Execute the SET
PKLIST(*.COLLA.*)
CURRENT PACKAGESET statement before
you execute an SQL statement to tell DB2
Requirement: When you specify the
DEFER(PREPARE) bind option with DRDA which package collection to search for the
statement.
access, the package that contains the
statements whose preparation you want to
defer must be the first qualifying entry in
the package search sequence that DB2 uses.
For example, assume that the package list
for a plan contains two entries:
PKLIST(LOCB.COLLA.*, LOCB.COLLB.*)
If the intended package is in collection
COLLB, ensure that DB2 searches that
collection first by executing the following
SQL statement:
SET CURRENT PACKAGESET = ’COLLB’;
Alternatively, you can list COLLB first in
the PKLIST bind option:
PKLIST(LOCB.COLLB.*, LOCB.COLLA.*)
For the NODEFER(PREPARE) bind option,
the collections in the package list can be in
any order, but if the package is not found
in the first qualifying PKLIST entry,
significant network overhead might result
from DB2 searching through the list.

Chapter 1. Planning for and designing DB2 applications

37
Table 6. Recommended bind option values for applications that access distributed data (continued)
Bind option

Recommended value and actions

Reason

REOPT

Use the following guidelines to decide
which option to choose:

Because of performance costs when DB2
reoptimizes the access path at run time,
minimize reoptimization when possible.

|
|
|
|
|
|
|
|
|
|
|

v Use the REOPT(AUTO) option when the
following conditions are true:
– You are using the dynamic statement
cache.
– You want DB2 to decide if a new
access path is needed.
– Your dynamic SQL statements are
executed many times with possibly
different input variables.
– Similar input variables tend to be
executed consecutively.
v Use the REOPT(ALWAYS) option on only
packages or plans that contain statements
that perform poorly because of a bad
access path. If you specify
REOPT(ALWAYS) when you bind a plan
that contains statements that use DB2
private protocol access to access remote
data, DB2 prepares those statements
twice.
v Use the REOPT(ONCE) option when the
following conditions are true:
– You are using the dynamic statement
cache.
– You have plans or packages that
contain dynamic SQL statements that
perform poorly because of access path
selection.
– Your dynamic SQL statements are
executed many times with possibly
different input variables.
v Use the REOPT(NONE) option when you
bind a plan or package that contains
statements that use DB2 private protocol
access.

Related concepts
″Block fetching result sets″ (DB2 Performance Monitoring and Tuning Guide)
“How DB2 identifies packages at run time” on page 873
Related tasks
″Fetching a limited number of rows: FETCH FIRST n ROWS ONLY″ (DB2
Performance Monitoring and Tuning Guide)
“Saving storage when manipulating LOBs by using LOB locators” on page 667
Related reference
″fetch-first-clause″ (DB2 SQL Reference)
″BIND and REBIND options″ (DB2 Command Reference)

38

Application Programming and SQL Guide
The effect of the OPTIMIZE FOR n ROWS clause in distributed
applications
You can specify the OPTIMIZE FOR n ROWS clause to improve the performance of
certain queries. For queries that access distributed data, this clause can have a
significant performance impact, because it helps limit the amount of data that is
sent over the network and the number of network transmissions.
When you specify the OPTIMIZE FOR n ROWS clause in your query, the number
of rows that DB2 transmits on each network transmission depends on the
following factors:
v If n rows of the SQL result set fit within a single DRDA query block, a DB2
server can send n rows to any DRDA client. In this case, DB2 sends n rows in
each network transmission until the entire query result set is returned.
v If n rows of the SQL result set exceed a single DRDA query block, the number of
rows that are contained in each network transmission depends on the client’s
DRDA software level and configuration. The following conditions apply:
– If the client does not support extra query blocks, the DB2 server automatically
reduces the value of n to match the number of rows that fit within a DRDA
query block.
– If the client supports extra query blocks, the DRDA client can choose to
accept multiple DRDA query blocks in a single data transmission. DRDA
allows the client to establish an upper limit on the number of DRDA query
blocks in each network transmission.
The number of rows that a DB2 server sends is the smaller of the following
values:
- n rows
- the number of rows that fit within the maximum number of extra DRDA
query blocks that the DB2 server returns to a client in a single network
transmission. (This value is specified in the EXTRA BLOCKS SRV field on
installation panel DSNTIP5 at the DB2 server.)
- the number of rows that fit within the client’s extra query block limit,
which is obtained from the DDM MAXBLKEXT parameter that is received
from the client. (When DB2 acts as a DRDA client, the DDM MAXBLKEXT
parameter is set to the value of EXTRA BLOCKS REQ on installation panel
DSNTIP5.)
Depending on the value that you specify for n, the OPTIMIZE FOR n ROWS clause
can improve performance in the following ways:
v If n is less than the number of rows that fit in the DRDA query block,
OPTIMIZE FOR n ROWS can improve performance by preventing the DB2
server from fetching rows that might never be used by the DRDA client
application.
v If n is greater than the number of rows that fit in a DRDA query block,
OPTIMIZE FOR n ROWS lets the DRDA client request multiple blocks of query
data on each network transmission. This use of OPTIMIZE FOR n ROWS can
significantly improve elapsed time for applications that download large amounts
of data.
Although the OPTIMIZE FOR n ROWS clause can improve performance, this same
function can degrade performance if you do not use it properly. The following
examples demonstrate the performance problems that can occur when you do not
use this clause judiciously.

Chapter 1. Planning for and designing DB2 applications

39
In the following figure, the DRDA client opens a cursor and fetches rows from the
cursor. At some point before all rows in the query result set are returned, the
application issues an SQL INSERT statement.
DRDA client

DB2 server

DECLARE C1 CURSOR
FOR SELECT * FROM T1
FOR FETCH ONLY;
OPEN C1;

SQL cursor is opened
Query block with 100
rows is returned

FETCH C1 INTO ...;
FETCH C1 INTO ...;

Server processes
INSERT statement

INSERT INTO ...;

Figure 1. Message flows without the OPTIMIZE FOR n ROWS clause

In this case, DB2 uses normal DRDA message blocking, which has the following
advantages over the message blocking that is used for the OPTIMIZE FOR n
ROWS clause:
v If the application issues an SQL statement other than FETCH (for example, an
INSERT statement in this case), the DRDA client can transmit the SQL statement
immediately, because the DRDA connection is not in use after the SQL OPEN.
v The DRDA query block size places an upper limit on the number of rows that
are fetched unnecessarily. If the SQL application closes the cursor before fetching
all the rows in the query result set, the server fetches only the number of rows
that fit in one query block, which is 100 rows of the result set.
In the following figure, the DRDA client opens a cursor and fetches rows from the
cursor by using OPTIMIZE FOR n ROWS clause. Both the DRDA client and the
DB2 server are configured to support multiple DRDA query blocks. At some time
before the end of the query result set, the application issues an SQL INSERT.

40

Application Programming and SQL Guide
DRDA client

DB2 server

DECLARE C1 CURSOR
FOR SELECT * FROM T1
OPTIMIZE FOR
1000 ROWS;
OPEN C1;

FETCH C1 INTO ...;
FETCH C1 INTO ...;
.
.
.
INSERT INTO ...;

SQL cursor is opened
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Query block with 100
rows is returned
Server processes
INSERT statement

Figure 2. Message flows with the OPTIMIZE FOR 1000 ROWS clause

Because the query uses the OPTIMIZE FOR n ROWS clause, the DRDA connection
is not available when the SQL INSERT is issued. The connection is still being used
to receive the DRDA query blocks for 1000 rows of data. This situation causes the
following performance problems:
v Application elapsed time can increase if the DRDA client waits for a large query
result set to be transmitted before the DRDA connection can be used for other
SQL statements. In this example, the SQL INSERT statement is delayed because
of a large query result set.
v If the application closes the cursor before fetching all the rows in the SQL result
set, the server might fetch a large number of rows unnecessarily.
Related concepts
″Minimizing overhead for retrieving few rows: OPTIMIZE FOR n ROWS″ (DB2
Performance Monitoring and Tuning Guide)
Related reference
″optimize-for-clause″ (DB2 SQL Reference)

Fast implicit close
When you specify the FETCH FIRST n ROWS ONLY clause in a distributed query,
DB2 might use a fast implicit close to improve performance. Fast implicit close is the
process of DB2 closing a cursor after prefetching thenth row or when no more
rows are to be returned.
Chapter 1. Planning for and designing DB2 applications

41
Fast implicit close can improve query performance, because it saves an additional
network transmission between the client and the server.
DB2 uses fast implicit close when all of the following conditions are true:
v The query uses limited block fetch.
v The query does not retrieve any LOBs.
v The cursor is not a scrollable cursor.
v Either of the following conditions is true:
– The cursor is defined with the WITH HOLD option, and the package or plan
that contains the cursor is bound with the KEEPDYNAMIC(YES) option.
– The cursor is not defined with the WITH HOLD option.
Related concepts
″Block fetching result sets″ (DB2 Performance Monitoring and Tuning Guide)

42

Application Programming and SQL Guide
Chapter 2. Connecting to DB2 from your application program
Application programs communicate to DB2 through an attachment facility. You
must invoke an attachment facility, either implicitly or explicitly, before your
program can interact with DB2.
You can use the following attachment facilities in a z/OS environment:
CICS attachment facility
Use this facility to access DB2 from CICS application programs.
IMS attachment facility
Use this facility to access DB2 from IMS application programs.
Time Sharing Option (TSO) attachment facility
Use this facility in a TSO or batch environment to communicate to a local
DB2 subsystem. This facility invokes the DSN command processor.
Call attachment facility (CAF)
Use this facility as an alternative to the TSO attachment facility when your
application needs tight control over the session environment.
Resource Recovery Services attachment facility (RRSAF)
Use this facility for stored procedures that run in a WLM-established
address space or as an alternative to the CAF. This facility has more
capabilities than CAF.
For distributed applications, use the distributed data facility (DDF).
Requirement: Ensure that any application that requests DB2 services satisfies the
following environment characteristics, regardless of the attachment facility that you
use:
v The application must be running in TCB mode. SRB mode is not supported.
v An application task cannot have any Enabled Unlocked Task (EUT) functional
recovery routines (FRRs) active when requesting DB2 services. If an EUT FRR is
active, the DB2 functional recovery can fail, and your application can receive
some unpredictable abends.
v Different attachment facilities cannot be active concurrently within the same
address space. Specifically, the following requirements exist:
– An application must not use CAF or RRSAF in an CICS or IMS address
space.
– An application that runs in an address space that has a CAF connection to
DB2 cannot connect to DB2 by using RRSAF.
– An application that runs in an address space that has an RRSAF connection to
DB2 cannot connect to DB2 by using CAF.
– An application cannot invoke the z/OS AXSET macro after executing the CAF
CONNECT call and before executing the CAF DISCONNECT call.
v One attachment facility cannot start another. For example, your CAF or RRSAF
application cannot use DSN, and a DSN RUN subcommand cannot call your
CAF or RRSAF application.

© Copyright IBM Corp. 1983, 2007

43
v The language interface modules for CAF and RRSAF, DSNALI and DSNRLI, are
shipped with the linkage attributes AMODE(31) and RMODE(ANY). If your
applications load CAF or RRSAF below the 16-MB line, you must link-edit
DSNALI or DSNRLI again.
Related concepts
″DB2 attachment facilities″ (Introduction to DB2 for z/OS)
″Distributed data facility″ (Introduction to DB2 for z/OS)

Invoking the call attachment facility
Invoke the call attachment facility (CAF) when you want your application program
to establish and control its own connection to DB2. Applications that use CAF can
explicitly control the state of their connections to DB2 by using connection
functions that CAF supplies.
Before you can invoke CAF, perform the following actions:
v Ensure that the CAF language interface (DSNALI) is available.
v Ensure that your application satisfies the requirements for programs that access
CAF.
v Ensure that your application satisfies the general environment characteristics for
connecting to DB2.
v Ensure that you are familiar with the following z/OS concepts and facilities:
– The CALL macro and standard module linkage conventions
– Program addressing and residency options (AMODE and RMODE)
– Creating and controlling tasks; multitasking
– Functional recovery facilities such as ESTAE, ESTAI, and FRRs
– Asynchronous events and TSO attention exits (STAX)
– Synchronization techniques such as WAIT/POST.
Applications that use CAF can be written in assembler language, C, COBOL,
Fortran, and PL/I. When choosing a language to code your application in, consider
the following restrictions:
v If you need to use z/OS macros (ATTACH, WAIT, POST, and so on), use a
programming language that supports them or embed them in modules that are
written in assembler language.
v The CAF TRANSLATE function is not available in Fortran. To use this function,
code it in a routine that is written in another language, and then call that routine
from Fortran.
Recommendations: For IMS and DSN applications, consider the following
recommendations:
v For IMS batch applications, do not use CAF. Instead use the DB2 DL/I batch
support. Although it is possible for IMS batch applications to access DB2
databases through CAF, that method does not coordinate the commitment of
work between the IMS and DB2 systems.
v For DSN applications, do not use CAF unless you provide an application
controller to manage the DSN application and replace any needed DSN
functions. You might also have to change the application to communicate
connection failures to the controller correctly. Running DSN applications with
CAF is not advantageous, and the loss of DSN services can affect how well your
program runs.
To invoke CAF:

44

Application Programming and SQL Guide
Perform one of the following actions:
v Explicitly invoke CAF by including in your program CALL DSNALI statements
with the appropriate options.
The first option is a CAF connection function, which describes the action that
you want CAF to take. The effect of any function depends in part on what
functions the program has already run.
Requirement: For C and PL/I applications, you must also include in your
program the compiler directives that are listed in the following table, because
DSNALI is an assembler language program.
Table 7. Compiler directives to include in C and PL/I applications that contain CALL DSNALI
statements
Language

Compiler directive to include

C

#pragma linkage(dsnali, OS)

C++

extern "OS" {
int DSNALI(
char * functn,
...); }

PL/I

DCL DSNALI ENTRY OPTIONS(ASM,INTER,RETCODE;

v Implicitly invoke CAF by including SQL statements or IFI calls in your program
just as you would in any program. The CAF facility establishes the connections
to DB2 with the default values for the subsystem name and plan name.
Restriction: If your program can make its first SQL call from different modules
with different DBRMs, you cannot use a default plan name and thus, you cannot
implicitly invoke CAF. Instead, you must explicitly invoke CAF by using the
OPEN function.
Requirement: If your application includes both SQL and IFI calls, you must
issue at least one SQL call before you issue any IFI calls. This action ensures that
your application uses the correct plan.
Although doing so is not recommended, you can run existing DSN applications
with CAF by allowing them to make implicit connections to DB2. For DB2 to
make an implicit connection successfully, the plan name for the application must
be the same as the member name of the database request module (DBRM) that
DB2 produced when you precompiled the source program that contains the first
SQL call. You must also substitute the DSNALI language interface module for
the TSO language interface module, DSNELI.
If you do not specify the return code and reason code parameters in your CAF
calls or you invoked CAF implicitly, CAF puts a return code in register 15 and a
reason code in register 0.
To determine if an implicit connection was successful, the application program
should examine the return and reason codes immediately after the first executable
SQL statement in the application program by performing one of the following
actions:
v Examining registers 0 and 15 directly.
v Examining the SQLCA, and if the SQLCODE is -991, obtain the return and
reason code from the message text. The return code is the first token, and the
reason code is the second token.

Chapter 2. Connecting to DB2 from your application program

45
If the implicit connection was successful, the application can examine the
SQLCODE for the first, and subsequent, SQL statements.

Examples
Example of a CAF configuration: The following figure shows an conceptual
example of invoking and using CAF. The application contains statements to load
DSNALI, DSNHLI2, and DSNWLI2. The application accesses DB2 by using the
CAF Language Interface. It calls DSNALI to handle CAF requests, DSNWLI to
handle IFI calls, and DSNHLI to handle SQL calls.

Application

Load

LOAD DSNALI
LOAD DSNHLI2
LOAD DSNWLI2
CALL DSNALI
(’CONNECT’)
(’OPEN’)
(’CLOSE’)
(’DISCONNECT’)
CALL DSNWLI
(IFI calls)
CALL DSNHLI
(SQL calls)

CAF
Language
Interface

Call
DSNALI

(Process
connection
requests)

DSNHLI (dummy
application
entry point)
CALL DSNHLI2
(Transfer calls
to real CAF SQL
entry point)

CAF
Mainline
Code

DB2

DSNHLI2
(Process
SQL stmts)

DSNWLI (dummy
application
entry point)
CALL DSNWLI2
(Transfer calls
to real CAF
IFI)

DSNWLI

Figure 3. Sample call attachment facility configuration

Sample programs that use CAF: You can find a sample assembler program
(DSN8CA) and a sample COBOL program (DSN8CC) that use the CAF in library
prefix.SDSNSAMP. A PL/I application (DSN8SPM) calls DSN8CA, and a COBOL
application (DSN8SCM) calls DSN8CC.
Related concepts

46

Application Programming and SQL Guide
“DB2 sample applications” on page 1013

Call attachment facility
An attachment facility enables programs to communicate with DB2. The call
attachment facility (CAF) provides such a connection for programs that run in
z/OS batch, TSO foreground, and TSO background and need tight control over the
session environment.
A program that uses CAF can perform the following actions:
v Access DB2 from z/OS address spaces where TSO, IMS, or CICS do not exist.
v Access DB2 from multiple z/OS tasks in an address space.
v Access the DB2 IFI.
v Run when DB2 is down.
Restriction: The application cannot run SQL when DB2 is down.
v Run with or without the TSO terminal monitor program (TMP).
v Run without being a subtask of the DSN command processor or of any DB2
code.
v Run above or below the 16-MB line. (The CAF code resides below the line.)
v Establish an explicit connection to DB2, through a CALL interface, with control
over the exact state of the connection.
v Establish an implicit connection to DB2, by using SQL statements or IFI calls
without first calling CAF, with a default plan name and subsystem identifier.
v Verify that the application is using the correct release of DB2.
v Supply event control blocks (ECBs), for DB2 to post, that signal startup or
termination.
v Intercept return codes, reason codes, and abend codes from DB2 and translate
them into messages as desired.
Any task in an address space can establish a connection to DB2 through CAF. Only
one connection can exist for each task control block (TCB). A DB2 service request
that is issued by a program that is running under a given task is associated with
that task’s connection to DB2. The service request operates independently of any
DB2 activity under any other task.
Each connected task can run a plan. Multiple tasks in a single address space can
specify the same plan, but each instance of a plan runs independently from the
others. A task can terminate its plan and run a different plan without fully
breaking its connection to DB2.
CAF does not generate task structures.
When you design your application, consider that using multiple simultaneous
connections can increase the possibility of deadlocks and DB2 resource contention.
A tracing facility provides diagnostic messages that aid in debugging programs
and diagnosing errors in the CAF code. In particular, attempts to use CAF
incorrectly cause error messages in the trace stream.
Restriction: CAF does not provide attention processing exits or functional recovery
routines. You can provide whatever attention handling and functional recovery

Chapter 2. Connecting to DB2 from your application program

47
your application needs, but you must use ESTAE/ESTAI type recovery routines
and not Enabled Unlocked Task (EUT) FRR routines.

Properties of CAF connections
CAF enables programs to communicate with DB2. A CAF connection joins any task
in an address space to DB2.
The connection that CAF makes with DB2 has the basic properties that are listed in
the following table.
Table 8. Properties of CAF connections
Property

Value

Comments

Connection name

DB2CALL

You can use the DISPLAY
THREAD command to list
CAF applications that have
the connection name
DB2CALL.

Connection type

BATCH

BATCH connections use a
single phase commit process
that is coordinated by DB2.
Application programs can
also control when statements
are committed by using the
SQL COMMIT and
ROLLBACK statements.

Authorization IDs

Authorization IDs that are
associated with the address
space

DB2 establishes authorization
IDs for each task’s connection
when it processes that
connection. For the BATCH
connection type, DB2 creates
a list of authorization IDs
based on the authorization ID
that is associated with the
address space. This list is the
same for every task. A
location can provide a DB2
connection authorization exit
routine to change the list of
IDs.

Scope

CAF processes connections as none
if each task is entirely
isolated. When a task
requests a function, the CAF
passes the functions to DB2
and is unaware of the
connection status of other
tasks in the address space.
However, the application
program and the DB2
subsystem are aware of the
connection status of multiple
tasks in an address space.

If a connected task terminates normally before the CLOSE function deallocates the
plan, DB2 commits any database changes that the thread made since the last
commit point. If a connected task abends before the CLOSE function deallocates
the plan, DB2 rolls back any database changes since the last commit point. In

48

Application Programming and SQL Guide
either case, DB2 deallocates the plan, if necessary, and terminates the task’s
connection before it allows the task to terminate.
If DB2 abnormally terminates while an application is running, the application is
rolled back to the last commit point. If DB2 terminates while processing a commit
request, DB2 either commits or rolls back any changes at the next restart. The
action taken depends on the state of the commit request when DB2 terminates.
Related concepts
″Connection routines and sign-on routines″ (DB2 Administration Guide)

Attention exit routines for CAF
An attention exit routine enables you to regain control from DB2 during
long-running or erroneous requests. CAF has no attention exit routines, but you
can provide your own if necessary.
An attention exit routine works by detaching the TCB that is currently waiting on
an SQL or IFI request to complete. After the TCB is detached, DB2 detects the
resulting abend and performs termination processing for that task. The termination
processing includes any necessary rollback of transactions.
You can provide your own attention exit routines. However, your routine might
not get control if you request attention while DB2 code is running, because DB2
uses enabled unlocked task (EUT) functional recovery routines (FRRs).

Recovery routines for CAF
You can use abend recovery routines and functional recovery routines (FRRs) to
handle unexpected errors. An abend recovery routine controls what happens when
an abend occurs while DB2 has control. A functional recovery routine can obtain
information about and recover from program errors.
The CAF has no abend recovery routines, but you can provide your own. Any
abend recovery routines that you provide must use tracking indicators to
determine if an abend occurred during DB2 processing. If an abend occurs while
DB2 has control, the recovery routine can take one of the following actions:
v Allow task termination to complete. Do not retry the program. DB2 detects task
termination and terminates the thread with the ABRT parameter. You lose all
database changes back to the last sync point or commit point.
This action is the only action that you can take for abends that are caused by the
CANCEL command or by DETACH. You cannot use additional SQL statements.
If you attempt to execute another SQL statement from the application program
or its recovery routine, you receive a return code of +256 and a reason code of
X’00F30083’.
v In an ESTAE routine, issue a CLOSE function call with the ABRT parameter
followed by a DISCONNECT function call. The ESTAE exit routine can retry so
that you do not need to reinstate the application task.
FRRs must comply with the following requirements and restrictions:
v You can use only enabled unlocked task (EUT) FRRs in your routines that call
DB2. The standard z/OS functional recovery routines (FRRs) apply to only code
that runs in service request block (SRB) mode, and DB2 does not support calls
from SRB mode routines.
v Do not have an EUT FRR active when using CAF, processing SQL requests, or
calling IFI. With z/OS, if you have an active EUT FRR, all DB2 requests fail,
including the initial CONNECT or OPEN request. The requests fail because DB2
Chapter 2. Connecting to DB2 from your application program

49
always creates an ARR-type ESTAE, and z/OS does not allow the creation of
ARR-type ESTAEs when an FRR is active.
v An EUT FRR cannot retry failing DB2 requests. An EUT FRR retry bypasses
ESTAE routines from DB2. The next DB2 request of any type, including a
DISCONNECT request, fails with a return code of +256 and a reason code of
X’00F30050’.

Making the CAF language interface (DSNALI) available
Before you can invoke the call attachment facility (CAF), you must first make
DSNALI available.
Part of CAF is a DB2 load module, DSNALI, which is also known as the CAF
language interface. DSNALI has the alias names DSNHLI2 and DSNWLI2. The
module has five entry points: DSNALI, DSNHLI, DSNHLI2, DSNWLI, and
DSNWLI2. These entry points serve the following functions:
v Entry point DSNALI handles explicit DB2 connection service requests.
v DSNHLI and DSNHLI2 handle SQL calls. Use DSNHLI if your application
program link-edits DSNALI. Use DSNHLI2 if your application program loads
DSNALI.
v DSNWLI and DSNWLI2 handle IFI calls. Use DSNWLI if your application
program link-edits DSNALI. Use DSNWLI2 if your application program loads
DSNALI.
To make DSNALI available:
1. Decide which of the following two methods you want to use to make DSNALI
available:
v Explicitly issuing LOAD requests when your program runs.
By explicitly loading the DSNALI module, you beneficially isolate the
maintenance of your application from future IBM maintenance to the
language interface. If the language interface changes, the change will
probably not affect your load module.
v Including the DSNALI module in your load module when you link-edit your
program.
If you do not need explicit calls to DSNALI for CAF functions, link-editing
DSNALI into your load module has some advantages. When you include
DSNALI during the link-edit, you do not need to code a dummy DSNHLI
entry point in your program or specify the precompiler option ATTACH.
Module DSNALI contains an entry point for DSNHLI, which is identical to
DSNHLI2, and an entry point DSNWLI, which is identical to DSNWLI2.
A disadvantage to link-editing DSNALI into your load module is that any
IBM maintenance to DSNALI requires a new link-edit of your load module.
2. Depending on the method that you chose in step 1, perform one of the
following actions:
v If you want to explicitly issue LOAD requests when your program runs:
In your program, issue z/OS LOAD service requests for entry points
DSNALI and DSNHLI2. If you use IFI services, you must also load
DSNWLI2. The entry point addresses that LOAD returns are saved for later
use with the CALL macro. Indicate to DB2 which entry point to use in one of
the following two ways:
– Specify the precompiler option ATTACH(CAF).
This option causes DB2 to generate calls that specify entry point
DSNHLI2.

50

Application Programming and SQL Guide
Restriction: You cannot use this option if your application is written in
Fortran.
– Code a dummy entry point named DSNHLI within your load module.
If you do not specify the precompiler option ATTACH, the DB2
precompiler generates calls to entry point DSNHLI for each SQL request.
The precompiler does not know about and is independent of the different
DB2 attachment facilities. When the calls generated by the DB2
precompiler pass control to DSNHLI, your code that corresponds to the
dummy entry point must preserve the option list that was passed in R1
and specify the same option list when it calls DSNHLI2.
v If you want to include the DSNALI module in your load module when
you link-edit your program:
Include DSNALI in your load module during a link-edit step. The module
must be in a load module library, which is included either in the SYSLIB
concatenation or another INCLUDE library that is defined in the linkage
editor JCL. Because all language interface modules contain an entry point
declaration for DSNHLI, the linkage editor JCL must contain an INCLUDE
linkage editor control statement for DSNALI; for example, INCLUDE
DB2LIB(DSNALI). By coding these options, you avoid inadvertently picking up
the wrong language interface module.
Related concepts
“Examples of invoking CAF” on page 69

Requirements for programs that use CAF
The call attachment facility (CAF) enables programs to communicate with DB2.
Before you invoke CAF in your program, ensure that your program satisfies any
requirements for using CAF.
When you write programs that use CAF, ensure that they meet the following
requirements:
v The program accounts for the size of the CAF code. The CAF code requires
about 16 KB of virtual storage per address space and an additional 10 KB for
each TCB that uses CAF.
v If your local environment intercepts and replaces the z/OS LOAD SVC that CAF
uses, you must ensure that your version of LOAD manages the load list element
(LLE) and contents directory entry (CDE) chains like the standard z/OS LOAD
macro. CAF uses z/OS SVC LOAD to load two modules as part of the
initialization after your first service request. Both modules are loaded into
fetch-protected storage that has the job-step protection key.
v If you use CAF from IMS batch, you must write data to only one system in any
one unit of work. If you write to both systems within the same unit, a system
failure can leave the two databases inconsistent with no possibility of automatic
recovery. To end a unit of work in DB2, execute the SQL COMMIT statement. To
end a unit of work in IMS, issue the SYNCPOINT command.
You can prepare application programs to run in CAF similar to how you prepare
applications to run in other environments, such as CICS, IMS, and TSO. You can
prepare a CAF application either in the batch environment or by using the DB2
program preparation process. You can use the program preparation system either
through DB2I or through the DSNH CLIST.
Related tasks
Chapter 11, “Preparing an application to run on DB2 for z/OS,” on page 837
Chapter 2. Connecting to DB2 from your application program

51
How CAF modifies the content of registers
If you do not specify the return code and reason code parameters in your CAF
function calls or you invoke CAF implicitly, CAF puts a return code in register 15
and a reason code in register 0. The contents of registers 2 through 14 are
preserved across calls.
The following table lists the standard calling conventions for registers R1, R13, R14,
and R15.
Table 9. Standard usage of registers R1, R13, R14, and R15
Register

Usage

R1

CALL DSNALI parameter list pointer

R13

Address of caller’s save area

R14

Caller’s return address

R15

CAF entry point address

Your CAF program should respect these register conventions.
CAF also supports high-level languages that cannot examine the contents of
individual registers.
Related concepts
“CALL DSNALI statement parameter list” on page 53

Implicit connections to CAF
If the CAF language interface (DSNALI) is available and you do not explicitly
specify CALL DSNALI statements in your application, CAF initiates implicit
CONNECT and OPEN requests to DB2. These requests are subject to the same DB2
return codes and reason codes as explicitly specified requests.
Implicit connections use the following defaults:
Subsystem name
The default name that is specified in the module DSNHDECP. CAF uses
the installation default DSNHDECP, unless your own DSNHDECP module
is in a library in a STEPLIB statement of a JOBLIB concatenation or in the
link list. In a data sharing group, the default subsystem name is the group
attachment name.
Be certain that you know what the default name is and that it names the
specific DB2 subsystem you want to use.
Plan name
The member name of the database request module (DBRM) that DB2
produced when you precompiled the source program that contains the first
SQL call.
Different types of implicit connections exist. The simplest is for an application to
call neither the CONNECT nor OPEN functions. You can also use the CONNECT
function only or the OPEN function only. Each of these calls implicitly connects
your application to DB2. To terminate an implicit connection, you must use the
proper calls.
Related concepts
“Summary of CAF behavior” on page 55

52

Application Programming and SQL Guide
CALL DSNALI statement parameter list
The CALL DSNALI statement explicitly invokes CAF. When you include CALL
DSNALI statements in your program, you must specify all parameters that come
before the return code parameter.
For CALL DSNALI statements, use a standard z/OS CALL parameter list. Register
1 points to a list of fullword addresses that point to the actual parameters. The last
address must contain a 1 in the high-order bit.
In CALL DSNALI statements, you cannot omit any of parameters that come before
the return code parameter by coding zeros or blanks. No defaults exist for those
parameters for explicit connection requests. Defaults are provided for only implicit
connections. All parameters starting with the return code parameter are optional.
When you want to use the default value for a parameter but specify subsequent
parameters, code the CALL DSNALI statement as follows:
v For all languages except assembler language, code zero for that parameter in the
CALL DSNALI statement. For example, suppose that you are coding a
CONNECT call in a COBOL program, and you want to specify all parameters
except the return code parameter. You can write a statement similar to the
following statement:
CALL ’DSNALI’ USING FUNCTN SSID TECB SECB RIBPTR
BY CONTENT ZERO BY REFERENCE REASCODE SRDURA EIBPTR.

v For assembler language, code a comma for that parameter in the CALL DSNALI
statement. For example, to specify all optional parameters except the return code
parameter write a statement similar to the following statement:
CALL DSNALI,(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,,REASCODE,SRDURA,EIBPTR,
GROUPOVERRIDE)

The following figure shows a sample parameter list structure for the CONNECT
function.

Chapter 2. Connecting to DB2 from your application program

53
Figure 4. The parameter list for a CONNECT call

The preceding figure illustrates how you can omit parameters for the CALL
DSNALI statement to control the return code and reason code fields after a
CONNECT call. You can terminate the parameter list at any of the following
points. These termination points apply to all CALL DSNALI statement parameter
lists.
1. Terminates the parameter list without specifying the parameters retcode,
reascodeand srdura and places the return code in register 15 and the reason code
in register 0.
Terminating the parameter list at this point ensures compatibility with CAF
programs that require a return code in register 15 and a reason code in register
0.
2. Terminates the parameter list after the parameter retcode and places the return
code in the parameter list and the reason code in register 0.
Terminating the parameter list at this point enables the application program to
take action, based on the return code, without further examination of the
associated reason code.
3. Terminates the parameter list after the parameter reascode and places the return
code and the reason code in the parameter list.
Terminating the parameter list at this point provides support to high-level
languages that are unable to examine the contents of individual registers.

54

Application Programming and SQL Guide
If you code your CAF application in assembler language, you can specify
reason code parameter and omit the return code parameter.
4. Terminates the parameter list after the parameter srdura.
If you code your CAF application in assembler language, you can specify
parameter and omit the retcode and reascode parameters.
5. Terminates the parameter list after the parameter eibptr.
If you code your CAF application in assembler language, you can specify
parameter and omit the retcode, reascode, or srdura parameters.
6. Terminates the parameter list after the parameter groupoverride.
If you code your CAF application in assembler language, you can specify
parameter and omit the retcode, reascode,srdura, or eibptr parameters.

the

this

this

this

Even if you specify that the return code be placed in the parameter list, it is also
placed in register 15 to accommodate high-level languages that support special
return code processing.
Related concepts
“How CAF modifies the content of registers” on page 52

Summary of CAF behavior
The effect of any CAF function depends in part on what functions the program has
already run. You should plan the CAF function calls that your program makes to
avoid any errors and major structural problems in your application.
The following table summarizes CAF behavior after various inputs from
application programs. The top row lists the possible CAF functions that programs
can call. The first column lists the task’s most recent history of connection requests.
For example, the value “CONNECT followed by OPEN” in the first column means
that the task issued CONNECT and then OPEN with no other CAF calls in
between. The intersection of a row and column shows the effect of the next call if
it follows the corresponding connection history. For example, if the call is OPEN
and the connection history is CONNECT, the effect is OPEN; the OPEN function is
performed. If the call is SQL and the connection history is empty (meaning that the
SQL call is the first CAF function the program), the effect is that implicit
CONNECT and OPEN functions are performed, followed by the SQL function.
Table 10. Effects of CAF calls, as dependent on connection history
Previous
function

Next function
CONNECT

OPEN

SQL

CLOSE

DISCONNECT TRANSLATE
1

Error 2041

Error 2051

DISCONNECT

TRANSLATE

CLOSE2

DISCONNECT

TRANSLATE

CLOSE2

DISCONNECT

TRANSLATE

Empty: first call

CONNECT

OPEN

CONNECT,
Error 203
OPEN, followed
by the SQL or
IFI call

CONNECT

Error 2011

OPEN

OPEN, followed Error 2031
by the SQL or
IFI call

CONNECT
followed by
OPEN

Error 2011

Error 2021

The SQL or IFI
call

CONNECT
followed by SQL
or IFI call

Error 2011

Error 2021

The SQL or IFI
call

Chapter 2. Connecting to DB2 from your application program

55
Table 10. Effects of CAF calls, as dependent on connection history (continued)
Next function

Previous
function

CONNECT
1

OPEN

Error 201

SQL or IFI call

Error 2011

OPEN

SQL
1

Error 2021

Error 202

CLOSE

DISCONNECT TRANSLATE

The SQL or IFI
call

CLOSE

2

Error 2041

TRANSLATE

The SQL or IFI
call

CLOSE2

Error 2041

TRANSLATE3

Notes:
1. An error is shown in this table as Error nnn. The corresponding reason code is
X’00C10nnn’. The message number is DSNAnnnI or DSNAnnnE.
2. The task and address space connections remain active. If the CLOSE call fails
because DB2 was down, the CAF control blocks are reset, the function produces
return code 4 and reason code X’00C10824’, and CAF is ready for more
connection requests when DB2 is up.
3. A TRANSLATE request is accepted, but in this case it is redundant. CAF
automatically issues a TRANSLATE request when an SQL or IFI request fails.
Related reference
“CAF return codes and reason codes” on page 67

CAF connection functions
A CAF connection function specifies the action that you want CAF to take. You
specify these functions when you invoke CAF through CALL DSNALI statements.
You can specify the following CAF functions in a CALL DSNALI statement:
CONNECT
Establishes the task (TCB) as a user of the named DB2 subsystem. When
the first task within an address space issues a connection request, the
address space is also initialized as a user of DB2.
OPEN Allocates a DB2 plan. You must allocate a plan before DB2 can process SQL
statements. If you did not request the CONNECT function, the OPEN
function implicitly establishes the task, and optionally the address space, as
a user of DB2.
CLOSE
Commits or abnormally terminates any database changes and deallocates
the plan. If the OPEN function implicitly requests the CONNECT function,
the CLOSE function removes the task, and possibly the address space, as a
user of DB2.
DISCONNECT
Removes the task as a user of DB2 and, if this task is the last or only task
in the address space with a DB2 connection, terminates the address space
connection to DB2.
TRANSLATE
Returns an SQL code and printable text that describe a DB2 hexadecimal
error reason code. This information is returned to the SQLCA.
Restriction: You cannot call the TRANSLATE function from the Fortran
language.

56

Application Programming and SQL Guide
Recommendation: Because the effect of any CAF function depends on what
functions the program has already run, carefully plan the calls that your program
makes to these CAF connection functions. Read about the summary of CAF
behavior and make these function calls accordingly.
Related concepts
“Summary of CAF behavior” on page 55
“CALL DSNALI statement parameter list” on page 53

CONNECT function for CAF
The CAF CONNECT function initializes a connection to DB2. This function is
different than the SQL CONNECT statement that accesses a remote location within
DB2.
The CONNECT function establishes the caller’s task as a user of DB2 services. If
no other task in the address space currently holds a connection with the specified
subsystem, the CONNECT function also initializes the address space for
communication to the DB2 address spaces. The CONNECT function establishes the
address space’s cross memory authorization to DB2 and builds address space
control blocks. You can issue a CONNECT request from any or all tasks in the
address space, but the address space level is initialized only once when the first
task connects.
Using the CONNECT function is optional. If you do not call the CONNECT
function, the first request from a task, either an OPEN request or an SQL or IFI
call, causes CAF to issue an implicit CONNECT request. If a task is connected
implicitly, the connection to DB2 is terminated either when you call the CLOSE
function or when the task terminates.
Call the CONNECT function in all of the following situations:
v You need to specify a particular subsystem name (ssnm) other than the default
subsystem name.
v You need the value of the CURRENT DEGREE special register to last as long as
the connection (srdura).
v You need to monitor the DB2 startup ECB (startecb), the DB2 termination ECB
(termecb), or the DB2 release level.
v You plan to have multiple tasks in the address space open and close plans or a
single task in the address space open and close plans more than once.
Establishing task and address space level connections involves significant
overhead. Using the CONNECT function to establish a task connection explicitly
minimizes this overhead by ensuring that the connection to DB2 remains after
the CLOSE function deallocates a plan. In this case, the connection terminates
only when you use the DISCONNECT function or when the task terminates.
The CONNECT function also enables the caller to learn the following items:
v That the operator has issued a STOP DB2 command. When this event occurs,
DB2 posts the termination ECB, termecb. Your application can either wait on or
just look at the ECB.
v That DB2 is abnormally terminating. When this event occurs happens, DB2 posts
the termination ECB, termecb.
v That DB2 is available again after a connection attempt that failed because DB2
was down. Your application can either wait or look at the startup ECB, startecb.
DB2 ignores this ECB if it was active at the time of the CONNECT request, or if
the CONNECT request was to a group attachment name.
Chapter 2. Connecting to DB2 from your application program

57
v The current release level of DB2. To find this information, access the RIBREL
field in the release information block (RIB).
Restriction: Do not issue CONNECT requests from a TCB that already has an
active DB2 connection.
Recommendation: Do not mix explicit CONNECT and OPEN requests with
implicitly established connections in the same address space. Either explicitly
specify which DB2 subsystem you want to use or allow all requests to use the
default subsystem.
The following diagram shows the syntax for the CONNECT function.

DSNALI CONNECT function
CALL DSNALI ( function, ssnm, termecb, startecb, ribptr
)
,retcode
,reascode
,srdura
,eibptr
,groupoverride

Parameters point to the following areas:
function
A 12-byte area that contains CONNECT followed by five blanks.
ssnm
A 4-byte DB2 subsystem name or group attachment name (if used in a data
sharing group) to which the connection is made.
If you specify the group attachment name, the program connects to the DB2 on
the z/OS system on which the program is running. When you specify a group
attachment name and a startup ECB, DB2 ignores the startup ECB. If you need
to use a startup ECB, specify a subsystem name, rather than a group
attachment name. That subsystem name must be different than the group
attachment name.
If ssnm is less than four characters long, pad it on the right with blanks to a
length of four characters.
termecb
The application’s event control block (ECB) for DB2 termination. DB2 posts this
ECB when the operator enters the STOP DB2 command or when DB2 is
abnormally terminating. The ECB indicates the type of termination by a POST
code, as shown in the following table:
Table 11. POST codes and related termination types
POST code
8

QUIESCE

12

FORCE

16

58

Termination type

ABTERM

Application Programming and SQL Guide
Before you check termecb in your CAF application program, first check the
return code and reason code from the CONNECT call to ensure that the call
completed successfully.
startecb
The application’s startup ECB. If DB2 has not yet started when the application
issues the call, DB2 posts the ECB when it successfully completes its startup
processing. DB2 posts at most one startup ECB per address space. The ECB is
the one associated with the most recent CONNECT call from that address
space. Your application program must examine any nonzero CAF and DB2
reason codes before issuing a WAIT on this ECB.
If ssnm is a group attachment name, the first DB2 subsystem that starts on the
local z/OS system and matches the specified group attachment name posts the
ECB.
ribptr
A 4-byte area in which CAF places the address of the release information block
(RIB) after the call. You can determine what release level of DB2 you are
currently running by examining the RIBREL field. You can determine the
modification level within the release level by examining the RIBCNUMB and
RIBCINFO fields. If the value in the RIBCNUMB field is greater than zero,
check the RIBCINFO field for modification levels.
If the RIB is not available (for example, if you name a subsystem that does not
exist), DB2 sets the 4-byte area to zeros.
The area to which ribptr points is below the 16-MB line.
Your program does not have to use the release information block, but it cannot
omit the ribptr parameter.
Macro DSNDRIB maps the release information block (RIB). It can be found in
prefix.SDSNMACS(DSNDRIB).
retcode
A 4-byte area in which CAF places the return code.
This field is optional. If you do not specify retcode, CAF places the return code
in register 15 and the reason code in register 0.
reascode
A 4-byte area in which CAF places a reason code.
This field is optional. If you do not specify reascode, CAF places the reason
code in register 0. If you specify reascode, you must also specify retcode.
srdura
A 10-byte area that contains the string ’SRDURA(CD)’. This field is optional. If
you specify srdura, the value in the CURRENT DEGREE special register stays
in effect from the time of the CONNECT call until the time of the
DISCONNECT call. If you do not specify srdura, the value in the CURRENT
DEGREE special register stays in effect from the time of the OPEN call until
the time of the CLOSE call. If you specify this parameter in any language
except assembler, you must also specify retcode and reascode. In assembler
language, you can omit these parameters by specifying commas as
placeholders.
eibptr
A 4-byte area in which CAF puts the address of the environment information
block (EIB). The EIB contains information that you can use if you are
connecting to a DB2 subsystem that is part of a data sharing group. For
Chapter 2. Connecting to DB2 from your application program

59
example, you can determine the name of the data sharing group, the member
to which you are connecting, and whether the subsystem is in new-function
mode. If the DB2 subsystem that you connect to is not part of a data sharing
group, the fields in the EIB that are related to data sharing are blank. If the EIB
is not available (for example, if you name a subsystem that does not exist),
DB2 sets the 4-byte area to zeros.
The area to which eibptr points is below the 16-MB line.
You can omit this parameter when you make a CONNECT call.
If you specify this parameter in any language except assembler, you must also
specify retcode, reascode, and srdura. In assembler language, you can omit
retcode, reascode, and srdura by specifying commas as placeholders.
Macro DSNDEIB maps the EIB. It can be found in
prefix.SDSNMACS(DSNDEIB).
|
|
|
|
|
|
|

groupoverride
An 8-byte area that the application provides. This parameter is optional. If you
do not want group attach to be attempted, specify ’NOGROUP’. This string
indicates that the subsystem name that is specified by ssnm is to be used as a
DB2 subsystem name, even if ssnm matches a group attachment name. If
groupoverride is not provided, ssnm is used as the group attachment name if it
matches a group attachment name.

|
|
|

If you specify this parameter in any language except assembler, you must also
specify retcode, reascode, srdura, and eibptr. In assembler language, you can omit
retcode, reascode, srdura, and eibptr by specifying commas as placeholders.

|
|
|
|
|
|

Recommendation: Avoid using the groupoverride parameter when possible,
because it limits the ability to do dynamic workload routing in a Parallel
Sysplex. However, you should use this parameter in a data sharing
environment when you want to connect to a specific member of a data sharing
group, and the subsystem name of that member is the same as the group
attachment name.

Example of CAF CONNECT function calls
The following table shows a CONNECT call in each language.
Table 12. Examples of CAF CONNECT function calls
Language

Call example

Assembler

CALL
DSNALI,(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,RETCODE,REASCODE,SRDURA,
EIBPTR, GRPOVER)

C1

fnret=dsnali(&functn[0],&ssid[0], &tecb, &secb,&ribptr,&retcode, &reascode, &srdura[0],
&eibptr, &grpover[0]);

COBOL

CALL ’DSNALI’ USING FUNCTN SSID TERMECB STARTECB RIBPTR RETCODE REASCODE SRDURA
EIBPTR GRPOVER.

Fortran

CALL
DSNALI(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,RETCODE,REASCODE,SRDURA,
EIBPTR,GRPOVER)

PL/I1

CALL
DSNALI(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,RETCODE,REASCODE,SRDURA,
EIBPTR,GRPOVER)

Note:

60

Application Programming and SQL Guide
v For C and PL/I applications, you must include the appropriate compiler
directives, because DSNALI is an assembler language program. These compiler
directives are described in the instructions for invoking CAF.
Related tasks
“Invoking the call attachment facility” on page 44

OPEN function for CAF
The OPEN function allocates DB2 resources that are needed to run the specified
plan or issue IFI requests. If the requesting task does not already have a connection
to the named DB2 subsystem, the OPEN function establishes it.
Using the OPEN function is optional. If you do not call the OPEN function, the
actions that the OPEN function perform occur implicitly on the first SQL or IFI call
from the task.
Restriction: Do not use the OPEN function if the task already has a plan allocated.
The following diagram shows the syntax for the OPEN function.

DSNALI OPEN function
CALL DSNALI ( function, ssnm, plan
)
, retcode
, reascode
, groupoverride

Parameters point to the following areas:
function
A 12-byte area that contains the word OPEN followed by eight blanks.
ssnm
A 4-byte DB2 subsystem name or group attachment name (if used in a data
sharing group). The OPEN function allocates the specified plan to this DB2
subsystem. Also, if the requesting task does not already have a connection to
the named DB2 subsystem, the OPEN function establishes it.
You must specify the ssnm parameter, even if the requesting task also issues a
CONNECT call. If a task issues a CONNECT call followed by an OPEN call,
the subsystem names for both calls must be the same.
If ssnm is less than four characters long, pad it on the right with blanks to a
length of four characters.
plan
An 8-byte DB2 plan name.
retcode
A 4-byte area in which CAF places the return code.
This field is optional. If you do not specify retcode,CAF places the return code
in register 15 and the reason code in register 0.

Chapter 2. Connecting to DB2 from your application program

61
reascode
A 4-byte area in which CAF places a reason code.
This field is optional. If you do not specify reascode, CAF places the reason
code in register 0. If you specify reascode, you must also specify retcode.
groupoverride
An 8-byte area that the application provides. This field is optional. If you do
not want group attach to be attempted, specify ’NOGROUP’. This string
indicates that the subsystem name that is specified by ssnm is to be used as a
DB2 subsystem name, even if ssnm matches a group attachment name. If you
do not specify groupoverride, ssnm is used as the group attachment name if it
matches a group attachment name. If you specify this parameter in any
language except assembler, you must also specify retcode and reascode. In
assembler language, you can omit these parameters by specifying commas as
placeholders.

|

Recommendation: Avoid using the groupoverride parameter when possible,
because it limits the ability to do dynamic workload routing in a Parallel
Sysplex. However, you should use this parameter in a data sharing
environment when you want to connect to a specific member of a data sharing
group, and the subsystem name of that member is the same as the group
attachment name.

Examples of CAF OPEN calls
The following table shows an OPEN call in each language.
Table 13. Examples of CAF OPEN calls
Language

Call example

Assembler

CALL

C

1

DSNALI,(FUNCTN,SSID,PLANNAME, RETCODE,REASCODE,GRPOVER)

fnret=dsnali(&functn[0],&ssid[0], &planname[0],&retcode, &reascode,&grpover[0]);

COBOL

CALL

’DSNALI’ USING FUNCTN SSID PLANNAME RETCODE REASCODE GRPOVER.

Fortran

CALL

DSNALI(FUNCTN,SSID,PLANNAME, RETCODE,REASCODE,GRPOVER)

PL/I1

CALL

DSNALI(FUNCTN,SSID,PLANNAME, RETCODE,REASCODE,GRPOVER);

Note:
v For C and PL/I applications, you must include the appropriate compiler
directives, because DSNALI is an assembler language program. These compiler
directives are described in the instructions for invoking CAF.
Related concepts
“Implicit connections to CAF” on page 52
Related tasks
“Invoking the call attachment facility” on page 44

CLOSE function for CAF
The CAF CLOSE function deallocates the plan that was created either explicitly by
a call to the OPEN function or implicitly at the first SQL call. Optionally, the
CLOSE function also disconnects the task, and possibly the address space, from
DB2.
If you did not issue an explicit CONNECT call for the task, the CLOSE function
deletes the task’s connection to DB2. If no other task in the address space has an

62

Application Programming and SQL Guide
active connection to DB2, DB2 also deletes the control block structures that were
created for the address space and removes the cross memory authorization.
Using the CLOSE function is optional. Consider the following rules and
recommendations about when to use and not use the CLOSE function:
v Do not use the CLOSE function when your current task does not have a plan
allocated.
v If you want to use a new plan, you must issue an explicit CLOSE call, followed
by an OPEN call with the new plan name.
v When shutting down your application you can improve the performance of this
shut down by explicitly calling the CLOSE function before the task terminates. If
you omit the CLOSE call, DB2 performs an implicit CLOSE. In this case, DB2
performs the same actions when your task terminates, by using the SYNC
parameter if termination is normal and the ABRT parameter if termination is
abnormal.
v If DB2 terminates, issue an explicit CLOSE call for any task that did not issue a
CONNECT call. This action enables CAF to reset its control blocks to allow for
future connections. This CLOSE call returns the reset accomplished return code
(+004) and reason code X’00C10824’. If you omit the CLOSE call in this case,
when DB2 is back on line, the task’s next connection request fails. You get either
the message YOUR TCB DOES NOT HAVE A CONNECTION, with X’00F30018’
in register 0, or the CAF error message DSNA201I or DSNA202I, depending on
what your application tried to do. The task must then issue a CLOSE call before
it can reconnect to DB2.
v A task that issued an explicit CONNECT call should issue a DISCONNECT call
instead of a CLOSE call. This action causes CAF to reset its control blocks when
DB2 terminates.
The following diagram shows the syntax for the CLOSE function.

DSNALI CLOSE function
CALL DSNALI ( function, termop

)
,

retcode
,

reascode

Parameters point to the following areas:
function
A 12-byte area that contains the word CLOSE followed by seven blanks.
termop
A 4-byte terminate option, with one of the following values:
SYNC Specifies that DB2 is to commit any modified data.
ABRT Specifies that DB2 is to roll back data to the previous commit point.
retcode
A 4-byte area in which CAF is to place the return code.
This field is optional. If you do not specify retcode, CAF places the return code
in register 15 and the reason code in register 0.
Chapter 2. Connecting to DB2 from your application program

63
reascode
A 4-byte area in which CAF places a reason code.
This field is optional. If you do not specify reascode, CAF places the reason
code in register 0. If you specify reascode, you must also specify retcode.

Examples of CAF CLOSE calls
The following table shows a CLOSE call in each language.
Table 14. Examples of CAF CLOSE calls
Language

Call example

Assembler

CALL

C

1

DSNALI,(FUNCTN,TERMOP,RETCODE, REASCODE)

fnret=dsnali(&functn[0], &termop[0], &retcode,&reascode);

COBOL

CALL

’DSNALI’ USING FUNCTN TERMOP RETCODE REASCODE.

Fortran

CALL

DSNALI(FUNCTN,TERMOP, RETCODE,REASCODE)

CALL

DSNALI(FUNCTN,TERMOP, RETCODE,REASCODE);

PL/I

1

Note:
v For C and PL/I applications, you must include the appropriate compiler
directives, because DSNALI is an assembler language program. These compiler
directives are described in the instructions for invoking CAF.
Related tasks
“Invoking the call attachment facility” on page 44

DISCONNECT function for CAF
The CAF DISCONNECT function terminates a connection to DB2.
DISCONNECT removes the calling task’s connection to DB2. If no other task in the
address space has an active connection to DB2, DB2 also deletes the control block
structures that were created for the address space and removes the cross memory
authorization.
If an OPEN call is in effect, which means that a plan is allocated, when the
DISCONNECT call is issued, CAF issues an implicit CLOSE with the SYNC
parameter.
Using the DISCONNECT function is optional. Consider the following rules and
recommendations about when to use and not use the DISCONNECT function:
v Only those tasks that explicitly issued a CONNECT call can issue a
DISCONNECT call. If a CONNECT call was not used, a DISCONNECT call
causes an error.
v When shutting down your application you can improve the performance of this
shut down by explicitly calling the DISCONNECT function before the task
terminates. If you omit the DISCONNECT call, DB2 performs an implicit
DISCONNECT. In this case, DB2 performs the same actions when your task
terminates.
v If DB2 terminates, any task that issued a CONNECT call must issue a
DISCONNECT call to reset the CAF control blocks. The DISCONNECT function
returns the reset accomplished return codes and reason codes (+004 and
X’00C10824’). This action ensures that future connection requests from the task
work when DB2 is back on line.

64

Application Programming and SQL Guide
v A task that did not explicitly issue a CONNECT call must issue a CLOSE call
instead of a DISCONNECT call. This action resets the CAF control blocks when
DB2 terminates.
The following diagram shows the syntax for the DISCONNECT function.

DSNALI DISCONNECT function
CALL DSNALI ( function

)
, retcode
, reascode

The single parameter points to the following area:
function
A 12-byte area that contains the word DISCONNECT followed by two blanks.
retcode
A 4-byte area in which CAF places the return code.
This field is optional. If you do not specify retcode, CAF places the return code
in register 15 and the reason code in register 0.
reascode
A 4-byte area in which CAF places a reason code.
This field is optional. If you do not specify reascode, CAF places the reason
code in register 0. If you specify reascode, you must also specify retcode.

Examples of CAF DISCONNECT calls
The following table shows a DISCONNECT call in each language.
Table 15. Examples of CAF DISCONNECT calls
Language

Call example

Assembler

CALL

C

1

DSNALI(,FUNCTN,RETCODE,REASCODE)

fnret=dsnali(&functn[0], &retcode, &reascode);

COBOL

CALL

’DSNALI’ USING FUNCTN RETCODE REASCODE.

Fortran

CALL

DSNALI(FUNCTN,RETCODE,REASCODE)

CALL

DSNALI(FUNCTN,RETCODE,REASCODE);

PL/I

1

Note:
v For C and PL/I applications, you must include the appropriate compiler
directives, because DSNALI is an assembler language program. These compiler
directives are described in the instructions for invoking CAF.
Related tasks
“Invoking the call attachment facility” on page 44

Chapter 2. Connecting to DB2 from your application program

65
TRANSLATE function for CAF
The TRANSLATE function converts a DB2 hexadecimal error reason code from a
failed OPEN request into an SQL error code and printable error message text. DB2
places the information into the SQLCODE and SQLSTATE host variables or related
fields of the caller’s SQLCA.
The DB2 error reason code that is converted is read from register 0. The
TRANSLATE function does not change the contents of registers 0 and 15, unless
the TRANSLATE request fails; in that case, register 0 is set to X’C10205’ and
register 15 is set to 200.
Consider the following rules and recommendations about when to use and not use
the TRANSLATE function:
v You cannot call the TRANSLATE function from the Fortran language.
v The TRANSLATE function is useful only if you used an explicit CONNECT call
before an OPEN request that fails. For errors that occur during SQL or IFI
requests, the TRANSLATE function performs automatically.
v The TRANSLATE function can translate those codes that begin with X’00F3’, but
it does not translate CAF reason codes that begin with X’00C1’.
If you receive error reason code X’00F30040’ (resource unavailable) after an OPEN
request, the TRANSLATE function returns the name of the unavailable database
object in the last 44 characters of the SQLERRM field.
If the TRANSLATE function does not recognize the error reason code, it returns
SQLCODE -924 (SQLSTATE ’58006’) and places a printable copy of the original
DB2 function code and the return and error reason codes in the SQLERRM field.
The following diagram shows the syntax for the TRANSLATE function.

DSNALI TRANSLATE function
CALL DSNALI ( function, sqlca

)
,

retcode
, reascode

Parameters point to the following areas:
function
A 12-byte area the contains the word TRANSLATE followed by three blanks.
sqlca
The program’s SQL communication area (SQLCA).
retcode
A 4-byte area in which CAF places the return code.
This field is optional. If you do not specify retcode, CAF places the return code
in register 15 and the reason code in register 0.
reascode
A 4-byte area in which CAF places a reason code.

66

Application Programming and SQL Guide
This field is optional. If you do not specify reascode, CAF places the reason
code in register 0. If you specify reascode, you must also specify retcode.

Examples of CAF TRANSLATE calls
The following table shows a TRANSLATE call in each language.
Table 16. Examples of CAF TRANSLATE calls
Language

Call example

Assembler

CALL

C

1

fnret=dsnali(&functn[0], &sqlca, &retcode, &reascode);

COBOL
PL/I

DSNALI,(FUNCTN,SQLCA,RETCODE, REASCODE)

1

CALL

’DSNALI’ USING FUNCTN SQLCA RETCODE REASCODE.

CALL

DSNALI(FUNCTN,SQLCA,RETCODE, REASCODE);

Note:
v For C and PL/I applications, you must include the appropriate compiler
directives, because DSNALI is an assembler language program. These compiler
directives are described in the instructions for invoking CAF.
Related tasks
“Invoking the call attachment facility” on page 44

Turning on a CAF trace
CAF does not capture any diagnostic trace messages unless you tell it to by
turning on a trace.
To turn on a CAF trace:
Allocate a DSNTRACE data set either dynamically or by including a DSNTRACE
DD statement in your JCL. CAF writes diagnostic trace messages to that data set.
The trace message numbers contain the last three digits of the reason codes.
Related concepts
“Examples of invoking CAF” on page 69

CAF return codes and reason codes
CAF provides the return codes and reason codes either to the corresponding
parameters that are specified in a CAF function call or, if you choose not to use
those parameters, to registers 15 and 0.
When the reason code begins with X’00F3’ except for X’00F30006’, you can use the
CAF TRANSLATE function to obtain error message text that can be printed and
displayed. These reason codes are issued by the subsystem support for allied
memories, a part of the DB2 subsystem support subcomponent that services all
DB2 connection and work requests.
For SQL calls, CAF returns standard SQL codes in the SQLCA. CAF returns IFI
return codes and reason codes in the instrumentation facility communication area
(IFCA).
The following table lists the CAF return codes and reason codes.

Chapter 2. Connecting to DB2 from your application program

67
Table 17. CAF return codes and reason codes
Return code

Reason code

Explanation

0

X’00000000’

Successful completion.

4

X’00C10824’

CAF reset complete. CAF is ready to make a new connection.

8

X’00C10831’

Release level mismatch between DB2 and the CAF code.

1

X’00C10201’

Received a second CONNECT request from the same TCB. The first
CONNECT request could have been implicit or explicit.

2001

X’00C10202’

Received a second OPEN request from the same TCB. The first
OPEN request could have been implicit or explicit.

2001

X’00C10203’

CLOSE request issued when no active OPEN request exists.

1

X’00C10204’

DISCONNECT request issued when no active CONNECT request
exists, or the AXSET macro was issued between the CONNECT
request and the DISCONNECT request.

2001

X’00C10205’

TRANSLATE request issued when no connection to DB2 exists.

1

X’00C10206’

Incorrect number of parameters was specified or the end-of-list bit
was off.

2001

X’00C10207’

Unrecognized function parameter.

1

X’00C10208’

Received requests to access two different DB2 subsystems from the
same TCB.

2

CAF system error. Probable error in the attach or DB2.

200

200

200

200
204

Notes:
1. A CAF error probably caused by errors in the parameter lists from the application programs. CAF errors do not
change the current state of your connection to DB2; you can continue processing with a corrected request.
2. System errors cause abends. If tracing is on, a descriptive message is written to the DSNTRACE data set just
before the abend.

Sample CAF scenarios
One or more tasks can use CAF to connect to DB2. This connection can be made
either implicitly or explicitly. For explicit connections, a task calls one or more of
the CAF connection functions.

A single task with implicit connections
The simplest connection scenario is a single task that makes calls to DB2 without
using explicit CALL DSNALI statements. The task implicitly connects to the
default subsystem name and uses the default plan name.
When the task terminates, the following events occur:
v If termination was normal, any database changes are committed.
v If termination was abnormal, any database changes are rolled back.
v The active plan and all database resources are deallocated.
v The task and address space connections to DB2 are terminated.

A single task with explicit connections
The following example pseudocode illustrates a more complex scenario with a
single task.

68

Application Programming and SQL Guide
CONNECT
OPEN
allocate a plan
SQL or IFI call
•••
CLOSE
deallocate the current plan
OPEN
allocate a new plan
SQL or IFI call
•••
CLOSE
DISCONNECT

A task can have a connection to only one DB2 subsystem at any point in time. A
CAF error occurs if the subsystem name in the OPEN call does not match the
subsystem name in the CONNECT call. To switch to a different subsystem, the
application must first disconnect from the current subsystem and then issue a
connect request with a new subsystem name.

Multiple tasks
In the following scenario, multiple tasks within the address space use DB2 services.
Each task must explicitly specify the same subsystem name on either the
CONNECT function request or the OPEN function request. Task 1 makes no SQL
or IFI calls. Its purpose is to monitor the DB2 termination and startup ECBs and to
check the DB2 release level.
TASK 1

TASK 2

TASK 3

TASK n

OPEN
SQL
...
CLOSE
OPEN
SQL
...
CLOSE

OPEN
SQL
...
CLOSE
OPEN
SQL
...
CLOSE

OPEN
SQL
...
CLOSE
OPEN
SQL
...
CLOSE

CONNECT

DISCONNECT

Examples of invoking CAF
The call attachment facility (CAF) enables programs to communicate with DB2. If
you explicitly invoke CAF in your program, you can use the CAF connection
functions to control the state of the connection.

Example JCL for invoking CAF
The following sample JCL shows how to use CAF in a batch (non-TSO)
environment. The DSNTRACE statement in this example is optional.
//jobname
//CAFJCL
//STEPLIB
//

JOB
EXEC
DD
DD

z/OS_jobcard_information
PGM=CAF_application_program
DSN=application_load_library
DSN=DB2_load_library

DD
DD
DD

SYSOUT=*
SYSOUT=*
SYSOUT=*

.
.
.
//SYSPRINT
//DSNTRACE
//SYSUDUMP

Chapter 2. Connecting to DB2 from your application program

69
Example of assembler code that invokes CAF
The following examples show parts of a sample assembler program that uses CAF.
They demonstrate the basic techniques for making CAF calls, but do not show the
code and z/OS macros needed to support those calls. For example, many
applications need a two-task structure so that attention-handling routines can
detach connected subtasks to regain control from DB2. This structure is not shown
in the following code examples. Also, these code examples assume the existence of
a WRITE macro. Wherever this macro is included in the example, substitute code
of your own. You must decide what you want your application to do in those
situations; you probably do not want to write the error messages shown.
Example of loading and deleting the CAF language interface: The following code
segment shows how an application can load entry points DSNALI and DSNHLI2
for the CAF language interface. Storing the entry points in variables LIALI and
LISQL ensures that the application has to load the entry points only once. When
the module is done with DB2, you should delete the entries.
****************************** GET LANGUAGE INTERFACE ENTRY ADDRESSES
LOAD EP=DSNALI
Load the CAF service request EP
ST
R0,LIALI
Save this for CAF service requests
LOAD EP=DSNHLI2
Load the CAF SQL call Entry Point
ST
R0,LISQL
Save this for SQL calls
*
.
*
.
Insert connection service requests and SQL calls here
*
.
DELETE EP=DSNALI
Correctly maintain use count
DELETE EP=DSNHLI2
Correctly maintain use count

Example of connecting to DB2 with CAF: The following example code shows
how to issue explicit requests for certain actions, such as CONNECT, OPEN,
CLOSE, DISCONNECT, and TRANSLATE, and uses the CHEKCODE subroutine to
check the return reason codes from CAF.
****************************** CONNECT ********************************
L
R15,LIALI
Get the Language Interface address
MVC
FUNCTN,CONNECT
Get the function to call
CALL (15),(FUNCTN,SSID,TECB,SECB,RIBPTR),VL,MF=(E,CAFCALL)
BAL
R14,CHEKCODE
Check the return and reason codes
CLC
CONTROL,CONTINUE
Is everything still OK
BNE
EXIT
If CONTROL not ’CONTINUE’, stop loop
USING R8,RIB
Prepare to access the RIB
L
R8,RIBPTR
Access RIB to get DB2 release level
WRITE ’The current DB2 release level is’ RIBREL
****************************** OPEN ***********************************
L
R15,LIALI
Get the Language Interface address
MVC
FUNCTN,OPEN
Get the function to call
CALL (15),(FUNCTN,SSID,PLAN),VL,MF=(E,CAFCALL)
BAL
R14,CHEKCODE
Check the return and reason codes
****************************** SQL ************************************
*
Insert your SQL calls here. The DB2 Precompiler
*
generates calls to entry point DSNHLI. You should
*
specify the precompiler option ATTACH(CAF), or code
*
a dummy entry point named DSNHLI to intercept
*
all SQL calls. A dummy DSNHLI is shown below.
****************************** CLOSE **********************************
CLC
CONTROL,CONTINUE
Is everything still OK?
BNE
EXIT
If CONTROL not ’CONTINUE’, shut down
MVC
TRMOP,ABRT
Assume termination with ABRT parameter
L
R4,SQLCODE
Put the SQLCODE into a register
C
R4,CODE0
Examine the SQLCODE
BZ
SYNCTERM
If zero, then CLOSE with SYNC parameter

70

Application Programming and SQL Guide
C
R4,CODE100
See if SQLCODE was 100
BNE
DISC
If not 100, CLOSE with ABRT parameter
SYNCTERM MVC
TRMOP,SYNC
Good code, terminate with SYNC parameter
DISC
DS
0H
Now build the CAF parmlist
L
R15,LIALI
Get the Language Interface address
MVC
FUNCTN,CLOSE
Get the function to call
CALL (15),(FUNCTN,TRMOP),VL,MF=(E,CAFCALL)
BAL
R14,CHEKCODE
Check the return and reason codes
****************************** DISCONNECT *****************************
CLC
CONTROL,CONTINUE
Is everything still OK
BNE
EXIT
If CONTROL not ’CONTINUE’, stop loop
L
R15,LIALI
Get the Language Interface address
MVC
FUNCTN,DISCON
Get the function to call
CALL (15),(FUNCTN),VL,MF=(E,CAFCALL)
BAL
R14,CHEKCODE
Check the return and reason codes

This example code does not show a task that waits on the DB2 termination ECB. If
you want such a task, you can code it by using the z/OS WAIT macro to monitor
the ECB. You probably want this task to detach the sample code if the termination
ECB is posted. That task can also wait on the DB2 startup ECB. This sample waits
on the startup ECB at its own task level.
This example code assumes that the variables in the following table are already set:
Table 18. Variables that preceding example assembler code assumes are set
Variable

Usage

LIALI

The entry point that handles DB2 connection
service requests.

LISQL

The entry point that handles SQL calls.

SSID

The DB2 subsystem identifier.

TECB

The address of the DB2 termination ECB.

SECB

The address of the DB2 startup ECB.

RIBPTR

A fullword that CAF sets to contain the RIB
address.

PLAN

The plan name to use in the OPEN call.

CONTROL

This variable is used to shut down
processing because of unsatisfactory return
or reason codes. The CHECKCODE
subroutine sets this value.

CAFCALL

List-form parameter area for the CALL
macro.

Example of checking return codes and reason codes when using CAF: The
following example code illustrates a way to check the return codes and the DB2
termination ECB after each connection service request and SQL call. The routine
sets the variable CONTROL to control further processing within the module.
***********************************************************************
* CHEKCODE PSEUDOCODE
*
***********************************************************************
*IF TECB is POSTed with the ABTERM or FORCE codes
* THEN
*
CONTROL = ’SHUTDOWN’
*
WRITE ’DB2 found FORCE or ABTERM, shutting down’
* ELSE
/* Termination ECB was not POSTed */
*
SELECT (RETCODE)
/* Look at the return code
*/
*
WHEN (0) ;
/* Do nothing; everything is OK
*/
Chapter 2. Connecting to DB2 from your application program

71
*
WHEN (4) ;
/* Warning
*/
*
SELECT (REASCODE)
/* Look at the reason code
*/
*
WHEN (’00C10824’X)
/* Ready for another CAF call
*/
*
CONTROL = ’RESTART’ /* Start over, from the top
*/
*
OTHERWISE
*
WRITE ’Found unexpected R0 when R15 was 4’
*
CONTROL = ’SHUTDOWN’
*
END INNER-SELECT
*
WHEN (8,12)
/* Connection failure
*/
*
SELECT (REASCODE)
/* Look at the reason code
*/
*
WHEN (’00C10831’X)
/* DB2 / CAF release level mismatch*/
*
WRITE ’Found a mismatch between DB2 and CAF release levels’
*
WHEN (’00F30002’X,
/* These mean that DB2 is down but */
*
’00F30012’X)
/* will POST SECB when up again
*/
*
DO
*
WRITE ’DB2 is unavailable. I’ll tell you when it’s up.’
*
WAIT SECB
/* Wait for DB2 to come up
*/
*
WRITE ’DB2 is now available.’
*
END
*
/**********************************************************/
*
/* Insert tests for other DB2 connection failures here.
*/
*
/* CAF Externals Specification lists other codes you can */
*
/* receive. Handle them in whatever way is appropriate
*/
*
/* for your application.
*/
*
/**********************************************************/
*
OTHERWISE
/* Found a code we’re not ready for*/
*
WRITE ’Warning: DB2 connection failure. Cause unknown’
*
CALL DSNALI (’TRANSLATE’,SQLCA) /* Fill in SQLCA
*/
*
WRITE SQLCODE and SQLERRM
*
END INNER-SELECT
*
WHEN (200)
*
WRITE ’CAF found user error. See DSNTRACE dataset’
*
WHEN (204)
*
WRITE ’CAF system error. See DSNTRACE data set’
*
OTHERWISE
*
CONTROL = ’SHUTDOWN’
*
WRITE ’Got an unrecognized return code’
*
END MAIN SELECT
*
IF (RETCODE > 4) THEN
/* Was there a connection problem?*/
*
CONTROL = ’SHUTDOWN’
* END CHEKCODE
***********************************************************************
* Subroutine CHEKCODE checks return codes from DB2 and Call Attach.
* When CHEKCODE receives control, R13 should point to the caller’s
* save area.
***********************************************************************
CHEKCODE DS
0H
STM
R14,R12,12(R13)
Prolog
ST
R15,RETCODE
Save the return code
ST
R0,REASCODE
Save the reason code
LA
R15,SAVEAREA
Get save area address
ST
R13,4(,R15)
Chain the save areas
ST
R15,8(,R13)
Chain the save areas
LR
R13,R15
Put save area address in R13
*
********************* HUNT FOR FORCE OR ABTERM ***************
TM
TECB,POSTBIT
See if TECB was POSTed
BZ
DOCHECKS
Branch if TECB was not POSTed
CLC
TECBCODE(3),QUIESCE
Is this "STOP DB2 MODE=FORCE"
BE
DOCHECKS
If not QUIESCE, was FORCE or ABTERM
MVC
CONTROL,SHUTDOWN
Shutdown
WRITE ’Found found FORCE or ABTERM, shutting down’
B
ENDCCODE
Go to the end of CHEKCODE
DOCHECKS DS
0H
Examine RETCODE and REASCODE
*
********************* HUNT FOR 0 *****************************
CLC
RETCODE,ZERO
Was it a zero?
BE
ENDCCODE
Nothing to do in CHEKCODE for zero
*
********************* HUNT FOR 4 *****************************

72

Application Programming and SQL Guide
CLC
RETCODE,FOUR
Was it a 4?
BNE
HUNT8
If not a 4, hunt eights
CLC
REASCODE,C10831
Was it a release level mismatch?
BNE
HUNT824
Branch if not an 831
WRITE ’Found a mismatch between DB2 and CAF release levels’
B
ENDCCODE
We are done. Go to end of CHEKCODE
HUNT824 DS
0H
Now look for ’CAF reset’ reason code
CLC
REASCODE,C10824
Was it 4? Are we ready to restart?
BNE
UNRECOG
If not 824, got unknown code
WRITE ’CAF is now ready for more input’
MVC
CONTROL,RESTART
Indicate that we should re-CONNECT
B
ENDCCODE
We are done. Go to end of CHEKCODE
UNRECOG DS
0H
WRITE ’Got RETCODE = 4 and an unrecognized reason code’
MVC
CONTROL,SHUTDOWN
Shutdown, serious problem
B
ENDCCODE
We are done. Go to end of CHEKCODE
*
********************* HUNT FOR 8 *****************************
HUNT8
DS
0H
CLC
RETCODE,EIGHT
Hunt return code of 8
BE
GOT8OR12
CLC
RETCODE,TWELVE
Hunt return code of 12
BNE
HUNT200
GOT8OR12 DS
0H
Found return code of 8 or 12
WRITE ’Found RETCODE of 8 or 12’
CLC
REASCODE,F30002
Hunt for X’00F30002’
BE
DB2DOWN

*

A4TRANS
*
*
*
*
DB2DOWN

*
HUNT200

*
HUNT204

*
WASSAT

CLC
REASCODE,F30012
Hunt for X’00F30012’
BE
DB2DOWN
WRITE ’DB2 connection failure with an unrecognized REASCODE’
CLC
SQLCODE,ZERO
See if we need TRANSLATE
BNE
A4TRANS
If not blank, skip TRANSLATE
********************* TRANSLATE unrecognized RETCODEs ********
WRITE ’SQLCODE 0 but R15 not, so TRANSLATE to get SQLCODE’
L
R15,LIALI
Get the Language Interface address
CALL (15),(TRANSLAT,SQLCA),VL,MF=(E,CAFCALL)
C
R0,C10205
Did the TRANSLATE work?
BNE
A4TRANS
If not C10205, SQLERRM now filled in
WRITE ’Not able to TRANSLATE the connection failure’
B
ENDCCODE
Go to end of CHEKCODE
DS
0H
SQLERRM must be filled in to get here
Note: your code should probably remove the X’FF’
separators and format the SQLERRM feedback area.
Alternatively, use DB2 Sample Application DSNTIAR
to format a message.
WRITE ’SQLERRM is:’ SQLERRM
B
ENDCCODE
We are done. Go to end of CHEKCODE
DS
0H
Hunt return code of 200
WRITE ’DB2 is down and I will tell you when it comes up’
WAIT ECB=SECB
Wait for DB2 to come up
WRITE ’DB2 is now available’
MVC
CONTROL,RESTART
Indicate that we should re-CONNECT
B
ENDCCODE
********************* HUNT FOR 200 ***************************
DS
0H
Hunt return code of 200
CLC
RETCODE,NUM200
Hunt 200
BNE
HUNT204
WRITE ’CAF found user error, see DSNTRACE data set’
B
ENDCCODE
We are done. Go to end of CHEKCODE
********************* HUNT FOR 204 ***************************
DS
0H
Hunt return code of 204
CLC
RETCODE,NUM204
Hunt 204
BNE
WASSAT
If not 204, got strange code
WRITE ’CAF found system error, see DSNTRACE data set’
B
ENDCCODE
We are done. Go to end of CHEKCODE
********************* UNRECOGNIZED RETCODE *******************
DS
0H
WRITE ’Got an unrecognized RETCODE’
Chapter 2. Connecting to DB2 from your application program

73
MVC
CONTROL,SHUTDOWN
BE
ENDCCODE
ENDCCODE DS
0H
L
R4,RETCODE
C
R4,FOUR
BNH
BYEBYE
MVC
CONTROL,SHUTDOWN
BYEBYE
DS
0H
L
R13,4(,R13)
RETURN (14,12)

Shutdown
We are done. Go to end of CHEKCODE
Should we shut down?
Get a copy of the RETCODE
Have a look at the RETCODE
If RETCODE <= 4 then leave CHEKCODE
Shutdown
Wrap up and leave CHEKCODE
Point to caller’s save area
Return to the caller

Example of invoking CAF when you do not specify the precompiler option
ATTACH(CAF): Each of the four DB2 attachment facilities contains an entry point
named DSNHLI. When you use CAF but do not specify the precompiler option
ATTACH(CAF), SQL statements result in BALR instructions to DSNHLI in your
program. To find the correct DSNHLI entry point without including DSNALI in
your load module, code a subroutine with entry point DSNHLI that passes control
to entry point DSNHLI2 in the DSNALI module. DSNHLI2 is unique to DSNALI
and is at the same location in DSNALI as DSNHLI. DSNALI uses 31-bit
addressing. If the application that calls this intermediate subroutine uses 24-bit
addressing, this subroutine should account for the difference.
In the following example, LISQL is addressable because the calling CSECT used
the same register 12 as CSECT DSNHLI. Your application must also establish
addressability to LISQL.
***********************************************************************
* Subroutine DSNHLI intercepts calls to LI EP=DSNHLI
***********************************************************************
DS
0D
DSNHLI
CSECT
Begin CSECT
STM
R14,R12,12(R13)
Prologue
LA
R15,SAVEHLI
Get save area address
ST
R13,4(,R15)
Chain the save areas
ST
R15,8(,R13)
Chain the save areas
LR
R13,R15
Put save area address in R13
L
R15,LISQL
Get the address of real DSNHLI
BASSM R14,R15
Branch to DSNALI to do an SQL call
*
DSNALI is in 31-bit mode, so use
*
BASSM to assure that the addressing
*
mode is preserved.
L
R13,4(,R13)
Restore R13 (caller’s save area addr)
L
R14,12(,R13)
Restore R14 (return address)
RETURN (1,12)
Restore R1-12, NOT R0 and R15 (codes)

Example of variable declarations when using CAF: The following example code
shows declarations for some of the variables that were used in the previous
subroutines.
****************************** VARIABLES ******************************
SECB
DS
F
DB2 Startup ECB
TECB
DS
F
DB2 Termination ECB
LIALI
DS
F
DSNALI Entry Point address
LISQL
DS
F
DSNHLI2 Entry Point address
SSID
DS
CL4
DB2 Subsystem ID. CONNECT parameter
PLAN
DS
CL8
DB2 Plan name. OPEN parameter
TRMOP
DS
CL4
CLOSE termination option (SYNC|ABRT)
FUNCTN
DS
CL12
CAF function to be called
RIBPTR
DS
F
DB2 puts Release Info Block addr here
RETCODE DS
F
Chekcode saves R15 here
REASCODE DS
F
Chekcode saves R0 here
CONTROL DS
CL8
GO, SHUTDOWN, or RESTART
SAVEAREA DS 18F
Save area for CHEKCODE
****************************** CONSTANTS ******************************
SHUTDOWN DC
CL8’SHUTDOWN’
CONTROL value: Shutdown execution

74

Application Programming and SQL Guide
RESTART DC
CL8’RESTART ’
CONTROL value: Restart execution
CONTINUE DC
CL8’CONTINUE’
CONTROL value: Everything OK, cont
CODE0
DC
F’0’
SQLCODE of 0
CODE100 DC
F’100’
SQLCODE of 100
QUIESCE DC
XL3’000008’
TECB postcode: STOP DB2 MODE=QUIESCE
CONNECT DC
CL12’CONNECT
’ Name of a CAF service. Must be CL12!
OPEN
DC
CL12’OPEN
’ Name of a CAF service. Must be CL12!
CLOSE
DC
CL12’CLOSE
’ Name of a CAF service. Must be CL12!
DISCON
DC
CL12’DISCONNECT ’ Name of a CAF service. Must be CL12!
TRANSLAT DC
CL12’TRANSLATE
’ Name of a CAF service. Must be CL12!
SYNC
DC
CL4’SYNC’
Termination option (COMMIT)
ABRT
DC
CL4’ABRT’
Termination option (ROLLBACK)
****************************** RETURN CODES (R15) FROM CALL ATTACH ****
ZERO
DC
F’0’
0
FOUR
DC
F’4’
4
EIGHT
DC
F’8’
8
TWELVE
DC
F’12’
12 (Call Attach return code in R15)
NUM200
DC
F’200’
200 (User error)
NUM204
DC
F’204’
204 (Call Attach system error)
****************************** REASON CODES (R00) FROM CALL ATTACH ****
C10205
DC
XL4’00C10205’
Call attach could not TRANSLATE
C10831
DC
XL4’00C10831’
Call attach found a release mismatch
C10824
DC
XL4’00C10824’
Call attach ready for more input
F30002
DC
XL4’00F30002’
DB2 subsystem not up
F30011
DC
XL4’00F30011’
DB2 subsystem not up
F30012
DC
XL4’00F30012’
DB2 subsystem not up
F30025
DC
XL4’00F30025’
DB2 is stopping (REASCODE)
*
*
Insert more codes here as necessary for your application
*
****************************** SQLCA and RIB **************************
EXEC SQL INCLUDE SQLCA
DSNDRIB
Get the DB2 Release Information Block
****************************** CALL macro parm list *******************
CAFCALL CALL ,(*,*,*,*,*,*,*,*,*),VL,MF=L

Invoking the Resource Recovery Services attachment facility
The Resource Recovery Services attachment facility (RRSAF) enables your program
to communicate with DB2. Invoke RRSAF as an alternative to invoking CAF or
when using stored procedures that run in a WLM-established address space.
RRSAF has more capabilities than CAF.
Before you invoke RRSAF, perform the following actions:
v Ensure that the RRSAF language interface load module, DSNRLI, is available.
v Ensure that your application satisfies the requirements for programs that access
RRSAF.
v Ensure that your application satisfies the general environment characteristics for
connecting to DB2.
v Ensure that you are familiar with the following z/OS concepts and facilities:
– The CALL macro and standard module linkage conventions
– Program addressing and residency options (AMODE and RMODE)
– Creating and controlling tasks; multitasking
– Functional recovery facilities such as ESTAE, ESTAI, and FRRs
– Synchronization techniques such as WAIT/POST
– z/OS RRS functions, such as SRRCMIT and SRRBACK
Applications that use RRSAF can be written in assembler language, C, COBOL,
Fortran, and PL/I. When choosing a language to code your application in, consider
the following restrictions:
Chapter 2. Connecting to DB2 from your application program

75
v If you use z/OS macros (ATTACH, WAIT, POST, and so on), choose a
programming language that supports them.
v The RRSAF TRANSLATE function is not available in Fortran. To use this
function, code it in a routine that is written in another language, and then call
that routine from Fortran.
To invoke RRSAF:
1. Perform one of the following actions:
v Explicitly invoke RRSAF by including in your program CALL DSNRLI
statements with the appropriate options.
The first option is an RRSAF connection function, which describes the action
that you want RRSAF to take. The effect of any function depends in part on
what functions the program has already performed.
To code RRSAF functions in C, COBOL, Fortran, or PL/I, follow the
individual language’s rules for making calls to assembler language routines.
Specify the return code and reason code parameters in the parameter list for
each RRSAF call.
Requirement: For C, C++, and PL/I applications, you must also include in
your program the compiler directives that are listed in the following table,
because DSNRLI is an assembler language program.
Table 19. Compiler directives to include in C, C++, and PL/I applications that contain CALL
DSNRLI statements
Language

Compiler directive to include

C

#pragma linkage(dsnrli, OS)

C++

extern "OS" {
int DSNRLI(
char * functn,
...); }

PL/I

DCL DSNRLI ENTRY OPTIONS(ASM,INTER,RETCODE);

v Implicitly invoke RRSAF by including SQL statements or IFI calls in your
program just as you would in any program. The RRSAF facility establishes
the connection to DB2 with the default values for the subsystem name, plan
name and authorization ID.
Restriction: If your program can make its first SQL call from different
modules with different DBRMs, you cannot use a default plan name and
thus, you cannot implicitly invoke RRSAF. Instead, you must explicitly
invoke RRSAF by calling the CREATE THREAD function.
Requirement: If your application includes both SQL and IFI calls, you must
issue at least one SQL call before you issue any IFI calls. This action ensures
that your application uses the correct plan.
2. If you implicitly invoked RRSAF, determine if the implicit connection was
successful by examining the return code and reason code immediately after the
first executable SQL statement within the application program. Your program
can check these codes by performing one of the following actions:
v Examine registers 0 and 15 directly.
v Examine the SQLCA, and if the SQLCODE is -981, obtain the return and
reason code from the message text. The return code is the first token, and the
reason code is the second token.

76

Application Programming and SQL Guide
If the implicit connection is successful, the application can examine the
SQLCODE for the first, and subsequent, SQL statements.

Example of an RRSAF configuration
The following figure shows an conceptual example of invoking and using RRSAF.

Figure 5. Sample RRSAF configuration

Resource Recovery Services attachment facility
An attachment facility enables programs to communicate with DB2. The Resource
Recovery Services attachment facility (RRSAF) provides such a connection for
programs that run in z/OS batch, TSO foreground, and TSO background. The
RRSAF is an alternative to CAF and has more functionality.
Chapter 2. Connecting to DB2 from your application program

77
An application program using RRSAF can perform the following actions:
v Use DB2 to process SQL statements, commands, or instrumentation facility
interface (IFI) calls.
v Coordinate DB2 updates with updates made by all other resource managers that
also use z/OS RRS in an z/OS system.
v Use the z/OS System Authorization Facility and an external security product,
such as RACF, to sign on to DB2 with the authorization ID of an end user.
v Sign on to DB2 using a new authorization ID and an existing connection and
plan.
v Access DB2 from multiple z/OS tasks in an address space.
v Switch a DB2 thread among z/OS tasks within a single address space.
v Access the DB2 IFI.
v Run with or without the TSO terminal monitor program (TMP).
v Run without being a subtask of the DSN command processor (or of any DB2
code).
v Run above or below the 16-MB line.
v Establish an explicit connection to DB2, through a call interface, with control
over the exact state of the connection.
v Establish an implicit connection to DB2 (with a default subsystem identifier and
a default plan name) by using SQL statements or IFI calls without first calling
RRSAF.
v Supply event control blocks (ECBs), for DB2 to post, that signal start-up or
termination.
v Intercept return codes, reason codes, and abend codes from DB2 and translate
them into messages as desired.
RRSAF uses z/OS Transaction Management and Recoverable Resource Manager
Services (z/OS RRS).
Any task in an address space can establish a connection to DB2 through RRSAF.
Each task control block (TCB) can have only one connection to DB2. A DB2 service
request that is issued by a program that runs under a given task is associated with
that task’s connection to DB2. The service request operates independently of any
DB2 activity under any other task.
Each connected task can run a plan. Tasks within a single address space can
specify the same plan, but each instance of a plan runs independently from the
others. A task can terminate its plan and run a different plan without completely
breaking its connection to DB2.
RRSAF does not generate task structures.
When you design your application, consider that using multiple simultaneous
connections can increase the possibility of deadlocks and DB2 resource contention.
Restriction: RRSAF does not provide attention processing exits or functional
recovery routines. You can provide whatever attention handling and functional
recovery your application needs, but you must use ESTAE/ESTAI type recovery
routines only.

78

Application Programming and SQL Guide
A tracing facility provides diagnostic messages that help you debug programs and
diagnose errors in the RRSAF code. The trace information is available only in a
SYSABEND or SYSUDUMP dump.
To commit work in RRSAF applications, use the CPIC SRRCMIT function or the
DB2 COMMIT statement. To roll back work, use the CPIC SRRBACK function or
the DB2 ROLLBACK statement.
Use the following guidelines to decide whether to use the DB2 statements or the
CPIC functions for commit and rollback operations:
v Use DB2 COMMIT and ROLLBACK statements when all of the following
conditions are true:
– The only recoverable resource that is accessed by your application is DB2 data
that is managed by a single DB2 instance.
DB2 COMMIT and ROLLBACK statements fail if your RRSAF application
accesses recoverable resources other than DB2 data that is managed by a
single DB2 instance.
– The address space from which syncpoint processing is initiated is the same as
the address space that is connected to DB2.
v If your application accesses other recoverable resources, or syncpoint processing
and DB2 access are initiated from different address spaces, use SRRCMIT and
SRRBACK.
Related reference
″COMMIT″ (DB2 SQL Reference)
″ROLLBACK″ (DB2 SQL Reference)
Related information
z/OS Internet Library at ibm.com

Properties of RRSAF connections
RRSAF enables programs to communicate with DB2 to process SQL statements,
commands, or IFI calls. An RRSAF connection joins any task in an address space to
DB2.
Restriction: Do not mix RRSAF connections with other connection types in a
single address space. The first connection that is made from an address space to
DB2 determines the type of connection allowed.
The connection that RRSAF makes with DB2 has the basic properties that are listed
in the following table.
Table 20. Properties of RRSAF connections
Property

Value

Comments

Connection name

RRSAF

You can use the DISPLAY
THREAD command to list
RRSAF applications that have
the connection name RRSAF.

Connection type

RRSAF

None.

Chapter 2. Connecting to DB2 from your application program

79
Table 20. Properties of RRSAF connections (continued)
Property

Value

Comments

Authorization ID

Authorization IDs that are
associated with each DB2
connection

A connection must have a
primary ID and can have one
or more secondary IDs. Those
identifiers are used for the
following purposes:
v Validating access to DB2
v Checking privileges on
DB2 objects
v Assigning ownership of
DB2 objects
v Identifying the user of a
connection for audit,
performance, and
accounting traces.
RRSAF relies on the z/OS
System Authorization Facility
(SAF) and a security product,
such as RACF, to verify and
authorize the authorization
IDs. An application that
connects to DB2 through
RRSAF must pass those
identifiers to SAF for
verification and authorization
checking. RRSAF retrieves
the identifiers from SAF.
A location can provide an
authorization exit routine for
a DB2 connection to change
the authorization IDs and to
indicate whether the
connection is allowed. The
actual values that are
assigned to the primary and
secondary authorization IDs
can differ from the values
that are provided by a
SIGNON or AUTH SIGNON
request. A site’s DB2 signon
exit routine can access the
primary and secondary
authorization IDs and can
modify the IDs to satisfy the
site’s security requirements.
The exit routine can also
indicate whether the signon
request should be accepted.

80

Application Programming and SQL Guide
Table 20. Properties of RRSAF connections (continued)
Property

Value

Comments

Scope

RRSAF processes connections None.
as if each task is entirely
isolated. When a task
requests a function, RRSAF
passes the function to DB2,
regardless of the connection
status of other tasks in the
address space. However, the
application program and the
DB2 subsystem have access
to the connection status of
multiple tasks in an address
space.

If an application that is connected to DB2 through RRSAF terminates normally
before the TERMINATE THREAD or TERMINATE IDENTIFY functions deallocate
the plan, RRS commits any changes made after the last commit point. If the
application terminates abnormally before the TERMINATE THREAD or
TERMINATE IDENTIFY functions deallocate the plan, z/OS RRS rolls back any
changes made after the last commit point. In either case, DB2 deallocates the plan,
if necessary, and terminates the application’s connection.
If DB2 abends while an application is running, DB2 rolls back changes to the last
commit point. If DB2 terminates while processing a commit request, DB2 either
commits or rolls back any changes at the next restart. The action taken depends on
the state of the commit request when DB2 terminates.

Making the RRSAF language interface (DSNRLI) available
Before you can invoke the Resource Recovery Services attachment facility (RRSAF),
you must first make available the RRSAF language interface load module,
DSNRLI.
Part of RRSAF is a DB2 load module, DSNRLI, which is also known as the RRSAF
language interface module. DSNRLI has the alias names DSNHLIR and DSNWLIR.
The module has five entry points: DSNRLI, DSNHLI, DSNHLIR, DSNWLI, and
DSNWLIR. These entry points serve the following functions:
v Entry point DSNRLI handles explicit DB2 connection service requests.
v DSNHLI and DSNHLIR handle SQL calls. Use DSNHLI if your application
program link-edits RRSAF. Use DSNHLIR if your application program loads
RRSAF.
v DSNWLI and DSNWLIR handle IFI calls. Use DSNWLI if your application
program link-edits RRSAF. Use DSNWLIR if your application program loads
RRSAF.
To make DSNRLI available:
1. Decide which of the following two methods you want to use to make DSNRLI
available:
v Explicitly issuing LOAD requests when your program runs.

Chapter 2. Connecting to DB2 from your application program

81
By explicitly loading the DSNRLI module, you can isolate the maintenance of
your application from future IBM maintenance to the language interface. If
the language interface changes, the change will probably not affect your load
module.
v Including the DSNRLI module in your load module when you link-edit your
program.
A disadvantage of link-editing DSNRLI into your load module is that if IBM
makes a change to DSNRLI, you must link-edit your program again.
2. Depending on the method that you chose in step 1, perform one of the
following actions:
v If you want to explicitly issue LOAD requests when your program runs:
In your program, issue z/OS LOAD service requests for entry points
DSNRLI and DSNHLIR. If you use IFI services, you must also load
DSNWLIR. Save the entry point address that LOAD returns and use it in the
CALL macro.
Indicate to DB2 which entry point to use in one of the following two ways:
– Specify the precompiler option ATTACH(RRSAF).
This option causes DB2 to generate calls that specify entry point
DSNHLIR.
Restriction: You cannot use this option if your application is written in
Fortran.
– Code a dummy entry point named DSNHLI within your load module.
If you do not specify the precompiler option ATTACH, the DB2
precompiler generates calls to entry point DSNHLI for each SQL request.
The precompiler does not know about and is independent of the different
DB2 attachment facilities. When the calls that are generated by the DB2
precompiler pass control to DSNHLI, your code that corresponds to the
dummy entry point must preserve the option list that is passed in register
1 and call DSNHLIR with the same option list.
v If you want to include the DSNRLI module in your load module when
you link-edit your program:
Include DSNRLI in your load module during a link-edit step. For example,
you can use a linkage editor control statement that is similar to the following
statement in your JCL:
INCLUDE DB2LIB(DSNRLI).

By coding this statement, you avoid inadvertently picking up the wrong
language interface module.
When you include the DSNRLI module during the link-edit, do not include a
dummy DSNHLI entry point in your program or specify the precompiler
option ATTACH. Module DSNRLI contains an entry point for DSNHLI,
which is identical to DSNHLIR, and an entry point for DSNWLI, which is
identical to DSNWLIR.
Related concepts
“Program examples for RRSAF” on page 118

Requirements for programs that use RRSAF
The Resource Recovery Services attachment facility (RRSAF) enables programs to
communicate with DB2. Before you invoke RRSAF in your program, ensure that
your program satisfies any requirements for using RRSAF.

82

Application Programming and SQL Guide
When you write programs that use RRSAF, ensure that they meet the following
requirements:
v The program accounts for the size of the RRSAF code. The RRSAF code requires
about 10 KB of virtual storage per address space and an additional 10 KB for
each TCB that uses RRSAF.
v If your local environment intercepts and replaces the z/OS LOAD SVC that
RRSAF uses, you must ensure that your version of LOAD manages the load list
element (LLE) and contents directory entry (CDE) chains like the standard z/OS
LOAD macro. RRSAF uses z/OS SVC LOAD to load a module as part of the
initialization after your first service request. The module is loaded into
fetch-protected storage that has the job-step protection key.
You can prepare application programs to run in RRSAF similar to how you prepare
applications to run in other environments, such as CICS, IMS, and TSO. You can
prepare an RRSAF application either in the batch environment or by using the DB2
program preparation process. You can use the program preparation system either
through DB2I or through the DSNH CLIST.
Related tasks
Chapter 11, “Preparing an application to run on DB2 for z/OS,” on page 837

How RRSAF modifies the content of registers
If you do not specify the return code and reason code parameters in your RRSAF
function calls or you invoke RRSAF implicitly, RRSAF puts a return code in
register 15 and a reason code in register 0. RRSAF preserves the contents of
registers 2 through 14.
If you specify the return code and reason code parameters, RRSAF places the
return code in register 15 and in the return code parameter to accommodate
high-level languages that support special return code processing.
The following table summarizes the register conventions for RRSAF calls.
Table 21. Register conventions for RRSAF calls
Register

Usage

R1

Parameter list pointer

R13

Address of caller’s save area

R14

Caller’s return address

R15

RRSAF entry point address

Implicit connections to RRSAF
RRSAF establishes an implicit connection to DB2 if the RRSAF language interface
load module (DSNRLI) is available, you do not explicitly specify the IDENTIFY
function in a CALL DSNRLI statement in your program, and the application
includes SQL statements or IFI calls.
An implicit connection causes RRSAF to initiate implicit IDENTIFY and CREATE
THREAD requests to DB2. These requests are subject to the same DB2 return codes
and reason codes as explicitly specified requests.
Implicit connections use the following defaults:

Chapter 2. Connecting to DB2 from your application program

83
Subsystem name
The default name that is specified in the module DSNHDECP. RRSAF uses
the installation default DSNHDECP, unless your own DSNHDECP module
is in a library in a STEPLIB statement of the JOBLIB concatenation or in
the link list. In a data sharing group, the default subsystem name is the
group attachment name.
Be certain that you know what the default name is and that it names the
specific DB2 subsystem that you want to use.
Plan name
The member name of the database request module (DBRM) that DB2
produced when you precompiled the source program that contains the first
SQL call.
Authorization ID
The 7-byte user ID that is associated with the address space, unless an
authorized function has built an Accessor Environment Element (ACEE)
for the address space. If an authorized function has built an ACEE, DB2
passes the 8-byte user ID from the ACEE.
For an implicit connection request, your application should not explicitly specify
either the IDENTIFY function or the CREATE THREAD function. Your application
can execute other explicit RRSAF calls after the implicit connection is made. An
implicit connection does not perform any SIGNON processing. Your application
can execute the SIGNON function at any point of consistency. To terminate an
implicit connection, you must use the proper function calls.
For implicit connection requests, register 15 contains the return code, and register 0
contains the reason code. The return code and reason code are also in the message
text for SQLCODE -981.
Related concepts
“Summary of RRSAF behavior” on page 85

CALL DSNRLI statement parameter list
The CALL DSNRLI statement explicitly invokes RRSAF. When you include CALL
DSNRLI statements in your program, you must specify all parameters that come
before the return code parameter.
In CALL DSNRLI statements, you cannot omit any of parameters that come before
the return code parameter by coding zeros or blanks. No defaults exist for those
parameters for explicit connection requests. Defaults are provided for only implicit
connections. All parameters starting with the return code parameter are optional.
When you want to use the default value for a parameter but specify subsequent
parameters, code the CALL DSNRLI statement as follows:
v For all languages except assembler language, code zero for that parameter in the
CALL DSNRLI statement. For example, suppose that you are coding an
IDENTIFY call in a COBOL program, and you want to specify all parameters
except the return code parameter. You can write a statement similar to the
following statement:
CALL ’DSNRLI’ USING IDFYFN SSNM RIBPTR EIBPTR TERMECB STARTECB
BY CONTENT ZERO BY REFERENCE REASCODE.

v For assembler language, code a comma for that parameter in the CALL DSNRLI
statement. For example, suppose that you are coding an IDENTIFY call, and you

84

Application Programming and SQL Guide
want to specify all parameters except the return code parameter. You can write a
statement similar to the following statement:
CALL

DSNRLI,(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB,,REASCODE)

For assembler programs that invoke RRSAF, use a standard parameter list for an
z/OS CALL. Register 1 must contain the address of a list of pointers to the
parameters. Each pointer is a 4-byte address. The last address must contain the
value 1 in the high-order bit.

Summary of RRSAF behavior
The effect of any RRSAF function depends in part on what functions the program
has already run. You should plan the RRSAF function calls that your program
makes to avoid any errors and major structural problems in your application.
The following tables summarize RRSAF behavior after various inputs from
application programs. The contents of each table cell indicate the result of calling
the function in the first column for that row followed by the function in the
current column heading. For example, if you issue TERMINATE THREAD and
then IDENTIFY, RRSAF returns reason code X’00C12201’. Use these tables to
understand the order in which your application must issue RRSAF calls, SQL
statements, and IFI requests.
The RRSAF FIND_DB2_SYSTEMS function is omitted from these tables, because it
does not affect the operation of any of the other functions

|
|

The following table summarizes RRSAF behavior when the next call is to the
IDENTIFY function, the SWITCH TO function, the SIGNON function, or the
CREATE THREAD function.
Table 22. Effect of call order when next call is IDENTIFY, SWITCH TO, SIGNON, or CREATE THREAD
Next function
Previous function

IDENTIFY

SWITCH TO

SIGNON, AUTH SIGNON,
or CONTEXT SIGNON
CREATE THREAD

Empty: first call

IDENTIFY

X’00C12205’1

X’00C12204’1

IDENTIFY

X’00F30049’1

Switch to ssnm

Signon

2

X’00C12217’1

SWITCH TO

IDENTIFY

Switch to ssnm

Signon

2

CREATE THREAD
CREATE THREAD

X’00C12204’1

SIGNON, AUTH SIGNON,
or CONTEXT SIGNON

X’00F30049’

1

Switch to ssnm

Signon

2

CREATE THREAD

X’00F30049’1

Switch to ssnm

Signon

2

X’00C12202’1

TERMINATE THREAD

X’00C12201’1

Switch to ssnm

Signon

2

CREATE THREAD

2

X’00C12202’1

IFI

X’00F30049’

1

Switch to ssnm

Signon

SQL

X’00F30049’1

Switch to ssnm

X’00F30092’13

SRRCMIT or SRRBACK

X’00F30049’1

Switch to ssnm

Signon

2

X’00C12202’1
X’00C12202’1

Notes:
1. Errors are identified by the DB2 reason code that RRSAF returns.
2. Signon means either the SIGNON function, the AUTH SIGNON function, or the CONTEXT SIGNON function.
3. The SIGNON, AUTH SIGNON, or CONTEXT SIGNON functions are not allowed if any SQL operations are
requested after the CREATE THREAD function or after the last SRRCMIT or SRRBACK request.

Chapter 2. Connecting to DB2 from your application program

85
The following table summarizes RRSAF behavior when the next call is an SQL
statement or an IFI call or to the TERMINATE THREAD function, the TERMINATE
IDENTIFY function, or the TRANSLATE function.

|
|
|

Table 23. Effect of call order when next call is SQL or IFI, TERMINATE THREAD, TERMINATE IDENTIFY, or
TRANSLATE
Next function
Previous function

SQL or IFI

TERMINATE THREAD TERMINATE IDENTIFY TRANSLATE

Empty: first call

SQL or IFI call

4

X’00C12204’1

X’00C12204’1

X’00C12204’1

IDENTIFY

SQL or IFI call4

X’00C12203’1

TERMINATE IDENTIFY

TRANSLATE

SQL or IFI call

4

TERMINATE THREAD

TERMINATE IDENTIFY

TRANSLATE

SIGNON, AUTH SIGNON,
or CONTEXT SIGNON

SQL or IFI call

4

TERMINATE THREAD

TERMINATE IDENTIFY

TRANSLATE

CREATE THREAD

SQL or IFI call4

TERMINATE THREAD

TERMINATE IDENTIFY

TRANSLATE

TERMINATE IDENTIFY

TRANSLATE

TERMINATE IDENTIFY

TRANSLATE

13

TRANSLATE

TERMINATE IDENTIFY

TRANSLATE

SWITCH TO

TERMINATE THREAD

SQL or IFI call

4

X’00C12203’

1

SQL or IFI call
SQL or IFI call

IFI
SQL
SRRCMIT or SRRBACK

4
4

X’00F30093’

SQL or IFI call

4

TERMINATE THREAD

TERMINATE THREAD
12

X’00F30093’

Notes:
1. Errors are identified by the DB2 reason code that RRSAF returns.
2. TERMINATE THREAD is not allowed if any SQL operations are requested after the CREATE THREAD function
or after the last SRRCMIT or SRRBACK request.
3. TERMINATE IDENTIFY is not allowed if any SQL operations are requested after the CREATE THREAD function
or after the last SRRCMIT or SRRBACK request.
4. If you are using an implicit connection to RRSAF and issue SQL or IFI calls, RRSAF issues implicit IDENTIFY and
CREATE THREAD requests. If you continue with explicit RRSAF statements, you must follow the standard order
of explicit RRSAF calls. Implicitly connecting to RRSAF does not cause an implicit SIGNON request. Therefore,
you might need to issue an explicit SIGNON request to satisfy the standard order requirement. For example, an
SQL statement followed by an explicit TERMINATE THREAD request results in an error. You must issue an
explicit SIGNON request before issuing the TERMINATE THREAD request.

Related concepts
″X’C1......’ codes″ (DB2 Codes)
″X’F3......’ codes″ (DB2 Codes)

RRSAF connection functions
An RRSAF connection function specifies the action that you want RRSAF to take.
You specify these functions when you invoke RRSAF through CALL DSNRLI
statements.
Related concepts
“Summary of RRSAF behavior” on page 85
“CALL DSNRLI statement parameter list” on page 84

IDENTIFY function for RRSAF
The RRSAF IDENTIFY function initializes a connection to DB2.
The IDENTIFY function establishes the caller’s task as a user of DB2 services. If no
other task in the address space currently is connected to the specified subsystem,
the IDENTIFY function also initializes the address space to communicate with the
DB2 address spaces. The IDENTIFY function establishes the cross-memory
authorization of the address space to DB2 and builds address space control blocks.

86

Application Programming and SQL Guide
The following diagram shows the syntax for the IDENTIFY function.

DSNRLI IDENTIFY function
CALL DSNRLI (

function

,

ssnm

,

ribptr

, eibptr

,

termecb

,

startecb

|

)
,

retcode
,

reascode
,

groupoverride
,

decpptr

Parameters point to the following areas:
function
An 18-byte area that contains IDENTIFY followed by 10 blanks.
ssnm
A 4-byte DB2 subsystem name or group attachment name (if used in a data
sharing group) to which the connection is made. If ssnm is less than four
characters long, pad it on the right with blanks to a length of four characters.
ribptr
A 4-byte area in which RRSAF places the address of the release information
block (RIB) after the call. You can use the RIB to determine the release level of
the DB2 subsystem to which the application is connected. You can determine
the modification level within the release level by examining the RIBCNUMB
and RIBCINFO fields. If the value in the RIBCNUMB field is greater than zero,
check the RIBCINFO field for modification levels.
If the RIB is not available (for example, if ssnm names a subsystem that does
not exist), DB2 sets the 4-byte area to zeros.
The area to which ribptr points is below the 16-MB line.
This parameter is required. However, the application does not need to refer to
the returned information.
eibptr
A 4-byte area in which RRSAF places the address of the environment
information block (EIB) after the call. The EIB contains environment
information, such as the data sharing group, the name of the DB2 member to
which the IDENTIFY request was issued, and whether the subsystem is in
new-function mode. If the DB2 subsystem is not in a data sharing group,
RRSAF sets the data sharing group and member names to blanks. If the EIB is
not available (for example, if ssnm names a subsystem that does not exist),
RRSAF sets the 4-byte area to zeros.
The area to which eibptr points is above the 16-MB line.
This parameter is required. However, the application does not need to refer to
the returned information.
termecb
The address of the application’s event control block (ECB) that is used for DB2
termination. DB2 posts this ECB when the system operator enters the STOP
Chapter 2. Connecting to DB2 from your application program

87
DB2 command or when DB2 is terminating abnormally. Specify a value of 0 if
you do not want to use a termination ECB.
RRSAF puts a POST code in the ECB to indicate the type of termination as
shown in the following table.
Table 24. Post codes for types of DB2 termination
POST code

Termination type

8

QUIESCE

12

FORCE

16

ABTERM

startecb
The address of the application’s startup ECB. If DB2 has not started when the
application issues the IDENTIFY call, DB2 posts the ECB when DB2 has
started. Enter a value of zero if you do not want to use a startup ECB. DB2
posts no more than one startup ECB per address space. The ECB that is posted
is associated with the most recent IDENTIFY call from that address space. The
application program must examine any nonzero RRSAF or DB2 reason codes
before issuing a WAIT request on this ECB.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places a reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode or its default. You can
specify a default for retcode by specifying a comma or zero, depending on the
language.
|
|
|
|
|
|

groupoverride
An 8-byte area that the application provides. This parameter is optional. If you
do not want group attach to be attempted, specify ’NOGROUP’. This string
indicates that the subsystem name that is specified by ssnm is to be used as a
DB2 subsystem name, even if ssnm matches a group attachment name. If
groupoverride is not provided, ssnm is used as the group attachment name if it
matches a group attachment name.

|
|
|
|

If you specify this parameter in any language except assembler, you must also
specify the retcode and reascode parameters. In assembler language, you can
omit the retcode and reascode parameters by specifying commas as
place-holders.

|
|
|
|
|
|

Recommendation: Avoid using the groupoverride parameter when possible,
because it limits the ability to do dynamic workload routing in a Parallel
Sysplex. However, you should use this parameter in a data sharing
environment when you want to connect to a specific member of a data sharing
group, and the subsystem name of that member is the same as the group
attachment name.

|
|

decpptr
A 4-byte area in which RRSAF is to put the address of the DSNHDECP control

88

Application Programming and SQL Guide
|
|
|

block that was loaded by subsystem ssnm when that subsystem was started.
This 4-byte area is a 31-bit pointer. If ssnm is not found, the 4-byte area is set to
0.

|

The area to which decpptr points is above the 16-MB line.

|
|
|
|

If you specify this parameter in any language except assembler, you must also
specify the retcode, reascode, and groupoverride parameters. In assembler
language, you can omit the retcode, reascode, and groupoverride parameters by
specifying commas as placeholders.

Example of RRSAF IDENTIFY function calls
The following table shows an IDENTIFY call in each language.
Table 25. Examples of RRSAF IDENTIFY calls
Language

Call example

Assembler

CALL

C

1

DSNRLI,(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB, RETCODE,REASCODE,GRPOVER,DECPPTR)

fnret=dsnrli(&idfyfn[0],&ssnm[0], &ribptr, &eibptr, &termecb, &startecb, &retcode,
&reascode,&grpover[0],&decpptr);

COBOL

CALL ’DSNRLI’ USING IDFYFN SSNM RIBTPR EIBPTR TERMECB STARTECB RETCODE REASCODE GRPOVER
DECPPTR.

Fortran

CALL

DSNRLI(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB, RETCODE,REASCODE,GRPOVER,DECPPTR)

CALL

DSNRLI(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB, RETCODE,REASCODE,GRPOVER,DECPPTR);

PL/I

1

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.

Internal processing for the IDENTIFY function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

When you call the IDENTIFY function, DB2 performs the following steps:
1. DB2 determines whether the user address space is authorized to connect to
DB2. DB2 invokes the z/OS SAF and passes a primary authorization ID to SAF.
That authorization ID is the 7-byte user ID that is associated with the address
space, unless an authorized function has built an ACEE for the address space.
If an authorized function has built an ACEE, DB2 passes the 8-byte user ID
from the ACEE. SAF calls an external security product, such as RACF, to
determine if the task is authorized to use the following items:
v The DB2 resource class (CLASS=DSNR)
v The DB2 subsystem (SUBSYS=ssnm)
v Connection type RRSAF
2. If that check is successful, DB2 calls the DB2 connection exit routine to perform
additional verification and possibly change the authorization ID.
3. DB2 searches for a matching trusted context in the system cache and then the
catalog based on the following criteria:
v The primary authorization ID matches a trusted context SYSTEM AUTHID.
v The job or started task name matches the JOBNAME attribute that is defined
for the identified trusted context.
If a trusted context is defined, DB2 checks if SECURITY LABEL is defined in
the trusted context. If SECURITY LABEL is defined, DB2 verifies the SECURITY
LABEL with RACF by using the RACROUTE VERIFY request. This security
Chapter 2. Connecting to DB2 from your application program

89
label is used to verify multi-level security for SYSTEM AUTHID.If a matching
trusted context is defined, DB2 establishes the connection as trusted. Otherwise,
the connection is established without any additional privileges.
4. DB2 then sets the connection name to RRSAF and the connection type to
RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75

|
|
|
|
|

SWITCH TO function for RRSAF
The RRSAF SWITCH TO function directs RRSAF, SQL, or IFI requests to a
specified DB2 subsystem. Use the SWITCH TO function to establish connections to
multiple DB2 subsystems from a single task.
The SWITCH TO function is useful only after a successful IDENTIFY call. If you
have established a connection with one DB2 subsystem, you must issue a SWITCH
TO call before you make an IDENTIFY call to another DB2 subsystem. Otherwise,
DB2 returns return code X’200’ and reason code X’00C12201’.
The first time that you make a SWITCH TO call to a new DB2 subsystem, DB2
returns return code 4 and reason code X’00C12205’ as a warning to indicate that
the current task has not yet been identified to the new DB2 subsystem.
The following diagram shows the syntax for the SWITCH TO function.

DSNRLI SWITCH TO function
CALL DSNRLI ( function,ssnm
)
, retcode
, reascode
, groupoverride

Parameters point to the following areas:
function
An 18-byte area that contains SWITCH TO followed by nine blanks.
ssnm
A 4-byte DB2 subsystem name or group attachment name (if used in a data
sharing group) to which the connection is made. If ssnm is less than four
characters long, pad it on the right with blanks to a length of four characters.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.

90

Application Programming and SQL Guide
If you specify this parameter, you must also specify retcode.
|
|
|
|
|
|

groupoverride
An 8-byte area that the application provides. This parameter is optional. If you
do not want group attach to be attempted, specify ’NOGROUP’. This string
indicates that the subsystem name that is specified by ssnm is to be used as a
DB2 subsystem name, even if ssnm matches a group attachment name. If
groupoverride is not provided, ssnm is used as the group attachment name if it
matches a group attachment name.

|
|
|
|

If you specify this parameter in any language except assembler, you must also
specify the retcode and reascode parameters. In assembler language, you can
omit the retcode and reascode parameters by specifying commas as
place-holders.

|
|
|
|
|
|

Recommendation: Avoid using the groupoverride parameter when possible,
because it limits the ability to do dynamic workload routing in a Parallel
Sysplex. However, you should use this parameter in a data sharing
environment when you want to connect to a specific member of a data sharing
group, and the subsystem name of that member is the same as the group
attachment name.

Examples
Examples of RRSAF SWITCH TO calls: The following table shows a SWITCH TO
call in each language.
Table 26. Examples of RRSAF SWITCH TO calls
Language

Call example

Assembler

CALL

C

1

DSNRLI,(SWITCHFN,SSNM,RETCODE,REASCODE,GRPOVER)

fnret=dsnrli(&switchfn[0], &ssnm[0], &retcode, &reascode,&grpover[0]);

COBOL

CALL

’DSNRLI’ USING SWITCHFN RETCODE REASCODE GRPOVER.

Fortran

CALL

DSNRLI(SWITCHFN,RETCODE,REASCODE,GRPOVER)

PL/I1

CALL

DSNRLI(SWITCHFN,RETCODE,REASCODE,GRPOVER);

1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Example of using the SWITCH TO function to interact with multiple DB2
subsystems: The following example shows how you can use the SWITCH TO
function to interact with three DB2 subsystems.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

RRSAF calls for subsystem db21:
IDENTIFY
SIGNON
CREATE THREAD
Execute SQL on subsystem db21
SWITCH TO db22
IF retcode = 4 AND reascode = ’00C12205’X THEN
DO;
RRSAF calls on subsystem db22:
IDENTIFY
SIGNON
CREATE THREAD
END;
Execute SQL on subsystem db22
SWITCH TO db23
IF retcode = 4 AND reascode = ’00C12205’X THEN
Chapter 2. Connecting to DB2 from your application program

91
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

DO;
RRSAF calls on subsystem db23:
IDENTIFY
SIGNON
CREATE THREAD
END;
Execute SQL on subsystem 23
SWITCH TO db21
Execute SQL on subsystem 21
SWITCH TO db22
Execute SQL on subsystem 22
SWITCH TO db21
Execute SQL on subsystem 21
SRRCMIT (to commit the UR)
SWITCH TO db23
Execute SQL on subsystem 23
SWITCH TO db22
Execute SQL on subsystem 22
SWITCH TO db21
Execute SQL on subsystem 21
SRRCMIT (to commit the UR)

Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75

SIGNON function for RRSAF
The RRSAF SIGNON function establishes a primary authorization ID and,
optionally, one or more secondary authorization IDs for a connection.
Requirement: Your program does not need to be an authorized program to issue
the SIGNON call. For that reason, before you issue the SIGNON call, you must
issue the RACF external security interface macro RACROUTE REQUEST=VERIFY
to perform the following actions:
v Define and populate an ACEE to identify the user of the program.
v Associate the ACEE with the user’s TCB.
v Verify that the user is defined to RACF and authorized to use the application.
Generally, you issue a SIGNON call after an IDENTIFY call and before a CREATE
THREAD call. You can also issue a SIGNON call if the application is at a point of
consistency, and one of the following conditions is true:
v The value of reuse in the CREATE THREAD call was RESET.
v The value of reuse in the CREATE THREAD call was INITIAL, no held cursors
are open, the package or plan is bound with KEEPDYNAMIC(NO), and all
special registers are at their initial state. If open held cursors exist or the package
or plan is bound with KEEPDYNAMIC(YES), you can issue a SIGNON call only
if the primary authorization ID has not changed.
|
|
|
|
|

After you issue a SIGNON call, subsequent SQL statements return an error
(SQLCODE -900) if the both of following conditions are true:
v The connection was established as trusted when it was initialized.
v The primary authorization ID that was used when you issued the SIGNON call
is not allowed to use the trusted connection.

|
|
|
|

If a trusted context is defined, DB2 checks if SECURITY LABEL is defined in the
trusted context. If SECURITY LABEL is defined, DB2 verifies the security label
with RACF by using the RACROUTE VERIFY request. This security label is used
to verify multi-level security for SYSTEM AUTHID.
The following diagram shows the syntax for the SIGNON function.

92

Application Programming and SQL Guide
DSNRLI SIGNON function
CALL DSNRLI ( function, correlation-id, accounting-token, accounting-interval
)
,retcode
,reascode
,user
,appl
,ws
,xid
,accounting-string

Parameters point to the following areas:
function
An 18-byte area that contains SIGNON followed by twelve blanks.
correlation-id
A 12-byte area in which you can put a DB2 correlation ID. The correlation ID is
displayed in DB2 accounting and statistics trace records. You can use the
correlation ID to correlate work units. This token appears in the output from
the DISPLAY THREAD command. If you do not want to specify a correlation
ID, fill the 12-byte area with blanks.
accounting-token
A 22-byte area in which you can put a value for a DB2 accounting token. This
value is displayed in DB2 accounting and statistics trace records in the
QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. Setting the
value of the accounting token sets the value of the CURRENT
CLIENT_ACCTNG special register. If accounting-token is less than 22 characters
long, you must pad it on the right with blanks to a length of 22 characters. If
you do not want to specify an accounting token, fill the 22-byte area with
blanks.
Alternatively, you change the value of the DB2 accounting token with RRSAF
functions AUTH SIGNON, CONTEXT SIGNON or SET_CLIENT_ID. You can
retrieve the DB2 accounting token with the CURRENT CLIENT_ACCTNG
special register only if the DDF accounting string is not set.
accounting-interval
A 6-byte area that specifies when DB2 writes an accounting record.
|
|
|
|
|
|
|

If you specify COMMIT in that area, DB2 writes an accounting record each
time that the application issues SRRCMIT without open held cursors. If the
accounting interval is COMMIT and an SRRCMIT is issued while a held cursor
is open, the accounting interval spans that commit and ends at the next valid
accounting interval end point (such as the next SRRCMIT that is issued
without open held cursors, application termination, or SIGNON with a new
authorization ID).
If you specify any other value, DB2 writes an accounting record when the
application terminates or when you call the SIGNON function with a new
authorization ID.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
Chapter 2. Connecting to DB2 from your application program

93
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify this parameter, you must also specify retcode.
user
A 16-byte area that contains the user ID of the client end user. You can use this
parameter to provide the identity of the client end user for accounting and
monitoring purposes. DB2 displays this user ID in the output from the
DISPLAY THREAD command and in DB2 accounting and statistics trace
records. Setting the user ID sets the value of the CURRENT CLIENT_USERID
special register. If user is less than 16 characters long, you must pad it on the
right with blanks to a length of 16 characters.
This parameter is optional. If you specify user, you must also specify retcode
and reascode. If you do not specify user, no user ID is associated with the
connection.
appl
A 32-byte area that contains the application or transaction name of the end
user’s application. You can use this parameter to provide the identity of the
client end user for accounting and monitoring purposes. DB2 displays the
application name in the output from the DISPLAY THREAD command and in
DB2 accounting and statistics trace records. Setting the application name sets
the value of the CURRENT CLIENT_APPLNAME special register. If appl is less
than 32 characters long, you must pad it on the right with blanks to a length of
32 characters.
This parameter is optional. If you specify appl, you must also specify retcode,
reascode, and user. If you do not specify appl, no application or transaction is
associated with the connection.
ws An 18-byte area that contains the workstation name of the client end user. You
can use this parameter to provide the identity of the client end user for
accounting and monitoring purposes. DB2 displays the workstation name in
the output from the DISPLAY THREAD command and in DB2 accounting and
statistics trace records. Setting the workstation name sets the value of the
CURRENT CLIENT_WRKSTNNAME special register. If ws is less than 18
characters long, you must pad it on the right with blanks to a length of 18
characters.
This field is optional. If you specify ws, you must also specify retcode, reascode,
user, and appl. If you do not specify ws, no workstation name is associated with
the connection.
xid
A 4-byte area that indicates whether the thread is part of a global transaction.
A DB2 thread that is part of a global transaction can share locks with other
DB2 threads that are part of the same global transaction and can access and
modify the same data. A global transaction exists until one of the threads that
is part of the global transaction is committed or rolled back.
You can specify one of the following values for xid:
0
1

94

Indicates that the thread is not part of a global transaction. The value 0
must be specified as a binary integer.
Indicates that the thread is part of a global transaction and that DB2
should retrieve the global transaction ID from RRS. If a global

Application Programming and SQL Guide
transaction ID already exists for the task, the thread becomes part of
the associated global transaction. Otherwise, RRS generates a new
global transaction ID. The value 1 must be specified as a binary
integer. Alternatively, if you want DB2 to return the generated global
transaction ID to the caller, specify an address instead of 1.
address The 4-byte address of an area in which you enter a global transaction
ID for the thread. If the global transaction ID already exists, the thread
becomes part of the associated global transaction. Otherwise, RRS
creates a new global transaction with the ID that you specify.
Alternatively, if you want DB2 to generate and return a global
transaction ID, pass the address of a null global transaction ID by
setting the format ID field of the global transaction ID to binary -1
(’FFFFFFF’X). DB2 then replaces the contents of the area with the
generated transaction ID. The area at the specified address must be in
writable storage and have a length of at least 140 bytes to
accommodate the largest possible transaction ID value.
The following table shows the format of a global transaction ID.
Table 27. Format of a user-created global transaction ID
Field description

Length in bytes

Data type

Format ID

4

Integer

Global transaction ID length
(1 - 64)

4

Integer

Branch qualifier length (1 64)

4

Integer

Global transaction ID

1 to 64

Character

Branch qualifier

1 to 64

Character

accounting-string
A one-byte length field and a 255-byte area in which you can put a value for a
DB2 accounting string. This value is placed in the DDF accounting trace
records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If
accounting-string is less than 255 characters, you must pad it on the right with
zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA
DSECT.
This parameter is optional. If you specify accounting-string, you must also
specify retcode, reascode, user, appl and xid. If you do not specify
accounting-string, no accounting string is associated with the connection.
You can also change the value of the accounting string with RRSAF functions
AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID.
You can retrieve the DDF suffix portion of the accounting string with the
CURRENT CLIENT_ACCTNG special register. The suffix portion of
accounting-string can contain a maximum of 200 characters. The QMDASFLN
field contains the accounting suffix length, and the QMDASUFX field contains
the accounting suffix value. If the DDF accounting string is set, you cannot
query the accounting token with the CURRENT CLIENT_ACCTNG special
register.

Example of RRSAF SIGNON calls
The following table shows a SIGNON call in each language.
Chapter 2. Connecting to DB2 from your application program

95
Table 28. Examples of RRSAF SIGNON calls
Language

Call example

assembler

CALL

C

1

DSNRLI,(SGNONFN,CORRID,ACCTTKN,ACCTINT, RETCODE,REASCODE,USERID,APPLNAME,WSNAME,XIDPTR)

fnret=dsnrli(&sgnonfn[0], &corrid[0], &accttkn[0], &acctint[0], &retcode, &reascode,
&userid[0], &applname[0], &wsname[0], &xidptr);

COBOL

CALL ’DSNRLI’ USING SGNONFN CORRID ACCTTKN ACCTINT RETCODE REASCODE USERID APPLNAME WSNAME
XIDPTR.

Fortran

CALL

DSNRLI(SGNONFN,CORRID,ACCTTKN,ACCTINT, RETCODE,REASCODE,USERID,APPLNAME,WSNAME,XIDPTR)

CALL

DSNRLI(SGNONFN,CORRID,ACCTTKN,ACCTINT, RETCODE,REASCODE,USERID,APPLNAME,WSNAME,XIDPTR);

PL/I

1

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75
Related information
z/OS Internet Library at ibm.com

AUTH SIGNON function for RRSAF
The RRSAF AUTH SIGNON function enables an APF-authorized program to pass
to DB2 either a primary authorization ID and, optionally, one or more secondary
authorization IDs, or an ACEE that is used for authorization checking. These IDs
are then associated with the connection.
Generally, you issue an AUTH SIGNON call after an IDENTIFY call and before a
CREATE THREAD call. You can also issue an AUTH SIGNON call if the
application is at a point of consistency, and one of the following conditions is true:
v The value of reuse in the CREATE THREAD call was RESET.
v The value of reuse in the CREATE THREAD call was INITIAL, no held cursors
are open, the package or plan is bound with KEEPDYNAMIC(NO), and all
special registers are at their initial state. If open held cursors exist or the package
or plan is bound with KEEPDYNAMIC(YES), a SIGNON call is permitted only if
the primary authorization ID has not changed.
The following diagram shows the syntax for the AUTH SIGNON function.

DSNRLI AUTH SIGNON function
CALL DSNRLI ( function, correlation-id, accounting-token,
accounting-interval, primary-authid, ACEE-address, secondary-authid
)
,retcode
,reascode
,user
,appl
,ws
,xid
,accounting-string

96

Application Programming and SQL Guide
Parameters point to the following areas:
function
An 18-byte area that contains AUTH SIGNON followed by seven blanks.
correlation-id
A 12-byte area in which you can put a DB2 correlation ID. The correlation ID is
displayed in DB2 accounting and statistics trace records. You can use the
correlation ID to correlate work units. This token appears in output from the
DISPLAY THREAD command. If you do not want to specify a correlation ID,
fill the 12-byte area with blanks.
accounting-token
A 22-byte area in which you can put a value for a DB2 accounting token. This
value is displayed in DB2 accounting and statistics trace records in the
QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. Setting the
value of the accounting token sets the value of the CURRENT
CLIENT_ACCTNG special register. If accounting-token is less than 22 characters
long, you must pad it on the right with blanks to a length of 22 characters. If
you do not want to specify an accounting token, fill the 22-byte area with
blanks.
You can also change the value of the DB2 accounting token with RRSAF
functions SIGNON, CONTEXT SIGNON or SET_CLIENT_ID. You can retrieve
the DB2 accounting token with the CURRENT CLIENT_ACCTNG special
register only if the DDF accounting string is not set.
accounting-interval
A 6-byte area with that specifies when DB2 writes an accounting record.
|
|
|
|
|
|
|

If you specify COMMIT in that area, DB2 writes an accounting record each
time that the application issues SRRCMIT without open held cursors. If the
accounting interval is COMMIT and an SRRCMIT is issued while a held cursor
is open, the accounting interval spans that commit and ends at the next valid
accounting interval end point (such as the next SRRCMIT that is issued
without open held cursors, application termination, or SIGNON with a new
authorization ID).
If you specify any other value, DB2 writes an accounting record when the
application terminates or when you call the SIGNON function with a new
authorization ID.
primary-authid
An 8-byte area in which you can put a primary authorization ID. If you are not
passing the authorization ID to DB2 explicitly, put X’00’ or a blank in the first
byte of the area.
ACEE-address
The 4-byte address of an ACEE that you pass to DB2. If you do not want to
provide an ACEE, specify 0 in this field.
secondary-authid
An 8-byte area in which you can put a secondary authorization ID. If you do
not pass the authorization ID to DB2 explicitly, put X’00’ or a blank in the first
byte of the area. If you enter a secondary authorization ID, you must also enter
a primary authorization ID.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
Chapter 2. Connecting to DB2 from your application program

97
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascoder, you must also specify retcode.
user
A 16-byte area that contains the user ID of the client end user. You can use this
parameter to provide the identity of the client end user for accounting and
monitoring purposes. DB2 displays this user ID in the output from the
DISPLAY THREAD command and in DB2 accounting and statistics trace
records. Setting the user ID sets the value of the CURRENT CLIENT_USERID
special register. If user is less than 16 characters long, you must pad it on the
right with blanks to a length of 16 characters.
This parameter is optional. If you specify user, you must also specify retcode
and reascode. If you do not specify this parameter, no user ID is associated with
the connection.
appl
A 32-byte area that contains the application or transaction name of the end
user’s application. You can use this parameter to provide the identity of the
client end user for accounting and monitoring purposes. DB2 displays the
application name in the output from the DISPLAY THREAD command and in
DB2 accounting and statistics trace records. Setting the application name sets
the value of the CURRENT CLIENT_APPLNAME special register. If appl is less
than 32 characters long, you must pad it on the right with blanks to a length of
32 characters.
This parameter is optional. If you specify appl, you must also specify retcode,
reascode, and user. If you do not specify this parameter, no application or
transaction is associated with the connection.
ws An 18-byte area that contains the workstation name of the client end user. You
can use this parameter to provide the identity of the client end user for
accounting and monitoring purposes. DB2 displays the workstation name in
the output from the DISPLAY THREAD command and in DB2 accounting and
statistics trace records. Setting the workstation name sets the value of the
CURRENT CLIENT_WRKSTNNAME special register. If ws is less than 18
characters long, you must pad it on the right with blanks to a length of 18
characters.
This parameter is optional. If you specify ws, you must also specify retcode,
reascode, user, and appl. If you do not specify this parameter, no workstation
name is associated with the connection.
You can also change the value of the workstation name with RRSAF functions
SIGNON, CONTEXT SIGNON or SET_CLIENT_ID. You can retrieve the
workstation name with the CURRENT CLIENT_WRKSTNNAME special
register.
xid
A 4-byte area that indicates whether the thread is part of a global transaction.
A DB2 thread that is part of a global transaction can share locks with other
DB2 threads that are part of the same global transaction and can access and
modify the same data. A global transaction exists until one of the threads that
is part of the global transaction is committed or rolled back.
You can specify one of the following values for xid:

98

Application Programming and SQL Guide
0

Indicates that the thread is not part of a global transaction. The value 0
must be specified as a binary integer.

1

Indicates that the thread is part of a global transaction and that DB2
should retrieve the global transaction ID from RRS. If a global
transaction ID already exists for the task, the thread becomes part of
the associated global transaction. Otherwise, RRS generates a new
global transaction ID. The value 1 must be specified as a binary
integer. Alternatively, if you want DB2 to return the generated global
transaction ID to the caller, specify an address instead of 1.

address The 4-byte address of an area into which you enter a global transaction
ID for the thread. If the global transaction ID already exists, the thread
becomes part of the associated global transaction. Otherwise, RRS
creates a new global transaction with the ID that you specify.
Alternatively, if you want DB2 to generate and return a global
transaction ID, pass the address of a null global transaction ID by
setting the format ID field of the global transaction ID to binary -1
(’FFFFFFF’X). DB2 then replaces the contents of the area with the
generated transaction ID. The area at the specified address must be in
writable storage and have a length of at least 140 bytes to
accommodate the largest possible transaction ID value.
The format of a global transaction ID is shown in the description of the
RRSAF SIGNON function.
accounting-string
A one-byte length field and a 255-byte area in which you can put a value for a
DB2 accounting string. This value is placed in the DDF accounting trace
records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If
accounting-string is less than 255 characters, you must pad it on the right with
zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA
DSECT.
This parameter is optional. If you specify this accounting-string, you must also
specify retcode, reascode, user, appl and xid. If you do not specify this parameter,
no accounting string is associated with the connection.
You can also change the value of the accounting string with RRSAF functions
AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID.
You can retrieve the DDF suffix portion of the accounting string with the
CURRENT CLIENT_ACCTNG special register. The suffix portion of
accounting-string can contain a maximum of 200 characters. The QMDASFLN
field contains the accounting suffix length, and the QMDASUFX field contains
the accounting suffix value. If the DDF accounting string is set, you cannot
query the accounting token with the CURRENT CLIENT_ACCTNG special
register.

Example of RRSAF AUTH SIGNON calls
The following table shows a AUTH SIGNON call in each language.
Table 29. Examples of RRSAF AUTH SIGNON calls
Language

Call example

Assembler

CALL DSNRLI,(ASGNONFN,CORRID,ACCTTKN,ACCTINT,PAUTHID,ACEEPTR, SAUTHID,RETCODE,REASCODE,
USERID,APPLNAME,WSNAME,XIDPTR)

Chapter 2. Connecting to DB2 from your application program

99
Table 29. Examples of RRSAF AUTH SIGNON calls (continued)
Language
C

1

Call example
fnret=dsnrli(&asgnonfn[0], &corrid[0], &accttkn[0], &acctint[0], &pauthid[0], &aceeptr,
&sauthid[0], &retcode, &reascode, &userid[0], &applname[0], &wsname[0], &xidptr);

COBOL

CALL ’DSNRLI’ USING ASGNONFN CORRID ACCTTKN ACCTINT PAUTHID ACEEPTR SAUTHID RETCODE REASCODE
USERID APPLNAME WSNAME XIDPTR.

Fortran

CALL DSNRLI(ASGNONFN,CORRID,ACCTTKN,ACCTINT,PAUTHID,ACEEPTR, SAUTHID,RETCODE,REASCODE,USERID,
APPLNAME,WSNAME,XIDPTR)

PL/I1

CALL DSNRLI(ASGNONFN,CORRID,ACCTTKN,ACCTINT,PAUTHID,ACEEPTR, SAUTHID,RETCODE,REASCODE,USERID,
APPLNAME,WSNAME,XIDPTR);

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75
Related reference
“SIGNON function for RRSAF” on page 92

CONTEXT SIGNON function for RRSAF
The RRSAF CONTEXT SIGNON function establishes a primary authorization ID
and one or more secondary authorization IDs for a connection.
Requirement: Before you invoke CONTEXT SIGNON, you must have called the
RRS context services function Set Context Data (CTXSDTA) to store a primary
authorization ID and optionally, the address of an ACEE in the context data whose
context key you supply as input to CONTEXT SIGNON.
The CONTEXT SIGNON function uses the context key to retrieve the primary
authorization ID from data that is associated with the current RRS context. DB2
uses the RRS context services function Retrieve Context Data (CTXRDTA) to
retrieve context data that contains the authorization ID and ACEE address. The
context data must have the following format:
Version number
A 4-byte area that contains the version number of the context data. Set this
area to 1.
Server product name
An 8-byte area that contains the name of the server product that set the
context data.
ALET

A 4-byte area that can contain an ALET value. DB2 does not reference this
area.

ACEE address
A 4-byte area that contains an ACEE address or 0 if an ACEE is not
provided. DB2 requires that the ACEE is in the home address space of the
task.
If you pass an ACEE address, the CONTEXT SIGNON function uses the
value in ACEEGRPN as the secondary authorization ID if the length of the
group name (ACEEGRPL) is not 0.

100

Application Programming and SQL Guide
primary-authid
An 8-byte area that contains the primary authorization ID to be used. If the
authorization ID is less than 8 bytes in length, pad it on the right with
blank characters to a length of 8 bytes.
If the new primary authorization ID is not different than the current
primary authorization ID (which was established when the IDENTIFY
function was invoked or at a previous SIGNON invocation), DB2 invokes
only the signon exit. If the value has changed, DB2 establishes a new
primary authorization ID and new SQL authorization ID and then invokes
the signon exit.
Generally, you issue a CONTEXT SIGNON call after an IDENTIFY call and before
a CREATE THREAD call. You can also issue a CONTEXT SIGNON call if the
application is at a point of consistency, and one of the following conditions is true:
v The value of reuse in the CREATE THREAD call was RESET.
v The value of reuse in the CREATE THREAD call was INITIAL, no held cursors
are open, the package or plan is bound with KEEPDYNAMIC(NO), and all
special registers are at their initial state. If open held cursors exist or the package
or plan is bound with KEEPDYNAMIC(YES), a SIGNON call is permitted only if
the primary authorization ID has not changed.
The following diagram shows the syntax for the CONTEXT SIGNON function.

DSNRLI CONTEXT SIGNON function
CALL DSNRLI ( function,

correlation-id,

accounting-token,

accounting-interval,

context-key
)

,retcode
,reascode
,user
,appl
,ws
,xid
,accounting-string

Parameters point to the following areas:
function
An 18-byte area that contains CONTEXT SIGNON followed by four blanks.
correlation-id
A 12-byte area in which you can put a DB2 correlation ID. The correlation ID is
displayed in DB2 accounting and statistics trace records. You can use the
correlation ID to correlate work units. This token appears in output from the
DISPLAY THREAD command. If you do not want to specify a correlation ID,
fill the 12-byte area with blanks.
accounting-token
A 22-byte area in which you can put a value for a DB2 accounting token. This
value is displayed in DB2 accounting and statistics trace records in the
QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. Setting the
value of the accounting token sets the value of the CURRENT
CLIENT_ACCTNG special register. If accounting-token is less than 22 characters

Chapter 2. Connecting to DB2 from your application program

101
long, you must pad it on the right with blanks to a length of 22 characters. If
you do not want to specify an accounting token, fill the 22-byte area with
blanks.
You can also change the value of the DB2 accounting token with RRSAF
functions SIGNON, AUTH SIGNON, or SET_CLIENT_ID. You can retrieve the
DB2 accounting token with the CURRENT CLIENT_ACCTNG special register
only if the DDF accounting string is not set.
accounting-interval
A 6-byte area that specifies when DB2 writes an accounting record.
If you specify COMMIT in that area, DB2 writes an accounting record each
time that the application issues SRRCMIT without open held cursors. If the
accounting interval is COMMIT and an SRRCMIT is issued while a held cursor
is open, the accounting interval spans that commit and ends at the next valid
accounting interval end point (such as the next SRRCMIT that is issued
without open held cursors, application termination, or SIGNON with a new
authorization ID).

|
|
|
|
|
|
|

If you specify any other value, DB2 writes an accounting record when the
application terminates or when you call the SIGNON function with a new
authorization ID.
context-key
A 32-byte area in which you put the context key that you specified when you
called the RRS Set Context Data (CTXSDTA) service to save the primary
authorization ID and an optional ACEE address.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode.
user
A 16-byte area that contains the user ID of the client end user. You can use this
parameter to provide the identity of the client end user for accounting and
monitoring purposes. DB2 displays this user ID in the output from the
DISPLAY THREAD command and in DB2 accounting and statistics trace
records. Setting the user ID sets the value of the CURRENT CLIENT_USERID
special register. If user is less than 16 characters long, you must pad it on the
right with blanks to a length of 16 characters.
This parameter is optional. If you specify user, you must also specify retcode
and reascode. If you do not specify user, no user ID is associated with the
connection.
appl
A 32-byte area that contains the application or transaction name of the end
user’s application. You can use this parameter to provide the identity of the
client end user for accounting and monitoring purposes. DB2 displays the
application name in the output from the DISPLAY THREAD command and in
DB2 accounting and statistics trace records. Setting the application name sets

102

Application Programming and SQL Guide
the value of the CURRENT CLIENT_APPLNAME special register. If appl is less
than 32 characters long, you must pad it on the right with blanks to a length of
32 characters.
This parameter is optional. If you specify appl, you must also specify retcode,
reascode, and user. If you do not specify appl, no application or transaction is
associated with the connection.
ws An 18-byte area that contains the workstation name of the client end user. You
can use this parameter to provide the identity of the client end user for
accounting and monitoring purposes. DB2 displays the workstation name in
the output from the DISPLAY THREAD command and in DB2 accounting and
statistics trace records. Setting the workstation name sets the value of the
CURRENT CLIENT_WRKSTNNAME special register. If ws is less than 18
characters long, you must pad it on the right with blanks to a length of 18
characters.
This parameter is optional. If you specify ws, you must also specify retcode,
reascode, user, and appl. If you do not specify ws, no workstation name is
associated with the connection.
You can also change the value of the workstation name with the RRSAF
functions SIGNON, AUTH SIGNON, or SET_CLIENT_ID. You can retrieve the
workstation name with the CLIENT_WRKSTNNAME special register.
xid
A 4-byte area that indicates whether the thread is part of a global transaction.
A DB2 thread that is part of a global transaction can share locks with other
DB2 threads that are part of the same global transaction and can access and
modify the same data. A global transaction exists until one of the threads that
is part of the global transaction is committed or rolled back.
You can specify one of the following values for xid:
0

Indicates that the thread is not part of a global transaction. The value 0
must be specified as a binary integer.

1

Indicates that the thread is part of a global transaction and that DB2
should retrieve the global transaction ID from RRS. If a global
transaction ID already exists for the task, the thread becomes part of
the associated global transaction. Otherwise, RRS generates a new
global transaction ID. The value 1 must be specified as a binary
integer. Alternatively, if you want DB2 to return the generated global
transaction ID to the caller, specify an address instead of 1.

address The 4-byte address of an area into which you enter a global transaction
ID for the thread. If the global transaction ID already exists, the thread
becomes part of the associated global transaction. Otherwise, RRS
creates a new global transaction with the ID that you specify.
Alternatively, if you want DB2 to generate and return a global
transaction ID, pass the address of a null global transaction ID by
setting the format ID field of the global transaction ID to binary -1
(’FFFFFFF’X). DB2 then replaces the contents of the area with the
generated transaction ID. The area at the specified address must be in
writable storage and have a length of at least 140 bytes to
accommodate the largest possible transaction ID value.
The format of a global transaction ID is shown in the description of the
RRSAF SIGNON function.

Chapter 2. Connecting to DB2 from your application program

103
accounting-string
A one-byte length field and a 255-byte area in which you can put a value for a
DB2 accounting string. This value is placed in the DDF accounting trace
records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If
accounting-string is less than 255 characters, you must pad it on the right with
zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA
DSECT.
This parameter is optional. If you specify this accounting-string, you must also
specify retcode, reascode, user, appl and xid. If you do not specify this parameter,
no accounting string is associated with the connection.
You can also change the value of the accounting string with RRSAF functions
AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID.
You can retrieve the DDF suffix portion of the accounting string with the
CURRENT CLIENT_ACCTNG special register. The suffix portion of
accounting-string can contain a maximum of 200 characters. The QMDASFLN
field contains the accounting suffix length, and the QMDASUFX field contains
the accounting suffix value. If the DDF accounting string is set, you cannot
query the accounting token with the CURRENT CLIENT_ACCTNG special
register.

Example of RRSAF CONTEXT SIGNON calls
The following table shows a CONTEXT SIGNON call in each language.
Table 30. Examples of RRSAF CONTEXT SIGNON calls
Language

Call example

Assembler

CALL DSNRLI,(CSGNONFN,CORRID,ACCTTKN,ACCTINT,CTXTKEY, RETCODE,REASCODE,USERID,APPLNAME,
WSNAME,XIDPTR)

C1

fnret=dsnrli(&csgnonfn[0], &corrid[0], &accttkn[0], &acctint[0], &ctxtkey[0], &retcode,
&reascode, &userid[0], &applname[0], &wsname[0], &xidptr);

COBOL

CALL ’DSNRLI’ USING CSGNONFN CORRID ACCTTKN ACCTINT CTXTKEY RETCODE REASCODE USERID APPLNAME
WSNAME XIDPTR.

Fortran

CALL DSNRLI(CSGNONFN,CORRID,ACCTTKN,ACCTINT,CTXTKEY, RETCODE,REASCODE, USERID,APPLNAME,
WSNAME,XIDPTR)

PL/I1

CALL DSNRLI(CSGNONFN,CORRID,ACCTTKN,ACCTINT,CTXTKEY, RETCODE,REASCODE,USERID,APPLNAME,
WSNAME,XIDPTR);

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75
Related reference
“SIGNON function for RRSAF” on page 92

SET_ID function for RRSAF
The RRSAF SET_ID function sets a new value for the client program ID that can be
used to identify the end user. The function then passes this information to DB2
when the next SQL request is processed.
The following diagram shows the syntax of the SET_ID function.

104

Application Programming and SQL Guide
DSNRLI SET_ID function
CALL DSNRLI ( function, program-id

)
, retcode
, reascode

Parameters point to the following areas:
function
An 18-byte area that contains SET_ID followed by 12 blanks.
program-id
An 80-byte area that contains the caller-provided string to be passed to DB2. If
program-id is less than 80 characters, you must pad it with blanks on the right
to a length of 80 characters.
DB2 places the contents of program-id into IFCID 316 records, along with other
statistics, so that you can identify which program is associated with a
particular SQL statement.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode.

Example of RRSAF SET_ID calls
The following table shows a SET_ID call in each language.
Table 31. Examples of RRSAF SET_ID calls
Language

Call example

Assembler

CALL

C

1

DSNRLI,(SETIDFN,PROGID,RETCODE,REASCODE)

fnret=dsnrli(&setidfn[0], &progid[0], &retcode, &reascode);

COBOL

CALL

’DSNRLI’ USING SETIDFN PROGID RETCODE REASCODE.

Fortran

CALL

DSNRLI(SETIDFN,PROGID,RETCODE,REASCODE)

CALL

DSNRLI(SETIDFN,PROGID,RETCODE,REASCODE);

PL/I

1

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75

Chapter 2. Connecting to DB2 from your application program

105
SET_CLIENT_ID function for RRSAF
The RRSAF SET_CLIENT_ID function sets new values for the client user ID, the
application program name, the workstation name, the accounting token, and the
DDF client accounting string. The function then passes this information to DB2
when the next SQL request is processed.
These values can be used to identify the end user. The calling program defines the
contents of these parameters. DB2 places the parameter values in the output from
the DISPLAY THREAD command and in DB2 accounting and statistics trace
records.
The following diagram shows the syntax of the SET_CLIENT_ID function.

DSNRLI SET_CLIENT_ID function
CALL DSNRLI ( function, accounting-token, user, appl,

ws

)
,retcode
,reascode
,accounting-string

Parameters point to the following areas:
function
An 18-byte area that contains SET_CLIENT_ID followed by 5 blanks.
accounting-token
A 22-byte area in which you can put a value for a DB2 accounting token. This
value is placed in the DB2 accounting and statistics trace records in the
QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. If
accounting-token is less than 22 characters long, you must pad it on the right
with blanks to a length of 22 characters.
You can omit this parameter by specifying a value of 0 in the parameter list.
Alternatively, you can change the value of the DB2 accounting token with the
RRSAF functions SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can
retrieve the DB2 accounting token with the CURRENT CLIENT_ACCTNG
special register only if the DDF accounting string is not set.
user
A 16-byte area that contains the user ID of the client end user. You can use this
parameter to provide the identity of the client end user for accounting and
monitoring purposes. DB2 places this user ID in the output from the DISPLAY
THREAD command and in DB2 accounting and statistics trace records. If user
is less than 16 characters long, you must pad it on the right with blanks to a
length of 16 characters.
You can omit this parameter by specifying a value of 0 in the parameter list.
You can also change the value of the client user ID with the RRSAF functions
SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can retrieve the client
user ID with the CLIENT_USERID special register.

106

Application Programming and SQL Guide
appl
An 32-byte area that contains the application or transaction name of the end
user’s application. You can use this parameter to provide the identity of the
client end user for accounting and monitoring purposes. DB2 places the
application name in the output from the DISPLAY THREAD command and in
DB2 accounting and statistics trace records. If appl is less than 32 characters,
you must pad it on the right with blanks to a length of 32 characters.
You can omit this parameter by specifying a value of 0 in the parameter list.
You can also change the value of the application name with the RRSAF
functions SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can retrieve
the application name with the CLIENT_APPLNAME special register.
ws An 18-byte area that contains the workstation name of the client end user. You
can use this parameter to provide the identity of the client end user for
accounting and monitoring purposes. DB2 places this workstation name in the
output from the DISPLAY THREAD command and in DB2 accounting and
statistics trace records. If ws is less than 18 characters, you must pad it on the
right with blanks to a length of 18 characters.
You can omit this parameter by specifying a value of 0 in the parameter list.
You can also change the value of the workstation name with the RRSAF
functions SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can retrieve
the workstation name with the CLIENT_WRKSTNNAME special register.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode.
accounting-string
A one-byte length field and a 255-byte area in which you can put a value for a
DB2 accounting string. This value is placed in the DDF accounting trace
records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If
accounting-string is less than 255 characters, you must pad it on the right with
zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA
DSECT.
This parameter is optional. If you specify this accounting-string, you must also
specify retcode, reascode, user, appl and xid. If you do not specify this parameter,
no accounting string is associated with the connection.
You can also change the value of the accounting string with RRSAF functions
AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID.
You can retrieve the DDF suffix portion of the accounting string with the
CURRENT CLIENT_ACCTNG special register. The suffix portion of
accounting-string can contain a maximum of 200 characters. The QMDASFLN
field contains the accounting suffix length, and the QMDASUFX field contains
the accounting suffix value. If the DDF accounting string is set, you cannot
query the accounting token with the CURRENT CLIENT_ACCTNG special
register.
Chapter 2. Connecting to DB2 from your application program

107
Example of RRSAF SET_CLIENT_ID calls
The following table shows a SET_CLIENT_ID call in each language.
Table 32. Examples of RRSAF SET_CLIENT_ID calls
Language

Call example

Assembler

CALL

C

1

DSNRLI,(SECLIDFN,ACCT,USER,APPL,WS,RETCODE,REASCODE)

fnret=dsnrli(&seclidfn[0], &acct[0], &user[0], &appl[0], &ws[0], &retcode, &reascode);

COBOL

CALL

’DSNRLI’ USING SECLIDFN ACCT USER APPL WS RETCODE REASCODE.

Fortran

CALL

DSNRLI(SECLIDFN,ACCT,USER,APPL,WS,RETCODE,REASCODE)

CALL

DSNRLI(SECLIDFN,ACCT,USER,APPL,WS,RETCODE,REASCODE);

PL/I

1

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75

CREATE THREAD function for RRSAF
The RRSAF CREATE THREAD function allocates the DB2 resources that are
required for an application to issue SQL or IFI requests. This function must
complete before the application can execute SQL statements or IFI requests.
The following diagram shows the syntax of the CREATE THREAD function.

DSNRLI CREATE THREAD function
CALL DSNRLI ( function, plan, collection, reuse
)
, retcode
, reascode
, pklistptr

Parameters point to the following areas:
function
An 18-byte area that contains CREATE THREAD followed by five blanks.
plan
An 8-byte DB2 plan name. RRSAF allocates the named plan.
If you provide a collection name instead of a plan name, specify the question
mark character (?) in the first byte of this field. DB2 then allocates a special
plan named ?RRSAF and uses the value that you specify for collection . When
DB2 allocates a plan named ?RRSAF, DB2 checks authorization to execute the
package in the same way as it checks authorization to execute a package from
a requester other than DB2 for z/OS.

108

Application Programming and SQL Guide
If you do not provide a collection name in the collection field, you must enter a
valid plan name in this field.
collection
An 18-byte area in which you enter a collection name. DB2 uses the collection
names to locate a package that is associated with the first SQL statement in the
program.
When you provide a collection name and put the question mark character (?)
in the plan field, DB2 allocates a plan named ?RRSAF and a package list that
contains the following two entries:
v The specified collection name.
v An entry that contains * for the location, collection name, and package name.
(This entry lets the application access remote locations and access packages
in collections other than the default collection that is specified at create
thread time.)
The application can use the SET CURRENT PACKAGESET statement to change
the collection ID that DB2 uses to locate a package.
If you provide a plan name in the plan field, DB2 ignores the value in the
collection field.
reuse
An 8-byte area that controls the action that DB2 takes if a SIGNON call is
issued after a CREATE THREAD call. Specify one of the following values in
this field:
RESET
Releases any held cursors and reinitializes the special registers
INITIAL
Does not allow the SIGNON call
This parameter is required. If the 8-byte area does not contain either RESET or
INITIAL, the default value is INITIAL.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode.
pklistptr
A 4-byte field that contains a pointer to a user-supplied data area that contains
a list of collection IDs. A collection ID is an SQL identifier of 1 to 128 letters,
digits, or the underscore character that identifies a collection of packages. The
length of the data area is a maximum of 2050 bytes. The data area contains a
2-byte length field, followed by up to 2048 bytes of collection ID entries,
separated by commas.
When you specify pklistptr and the question mark character (?) in the plan field,
DB2 allocates a special plan named ?RRSAF and a package list that contains
the following entries:
Chapter 2. Connecting to DB2 from your application program

109
v The collection names that you specify in the data area to which pklistptr
points
v An entry that contains * for the location, collection ID, and package name
If you also specify collection, DB2 ignores that value.
Each collection entry must be of the form collection-ID.*, *.collection-ID.*, or *.*.*.
collection-ID and must follow the naming conventions for a collection ID, as
described in the description of the BIND and REBIND options.
DB2 uses the collection names to locate a package that is associated with the
first SQL statement in the program. The entry that contains *.*.* lets the
application access remote locations and access packages in collections other
than the default collection that is specified at create thread time.
The application can use the SET CURRENT PACKAGESET statement to change
the collection ID that DB2 uses to locate a package.
This parameter is optional. If you specify this parameter, you must also specify
retcode and reascode.
If you provide a plan name in the plan field, DB2 ignores the pklistptr value.
Recommendation: Using a package list can have a negative impact on
performance. For better performance, specify a short package list.

Example of RRSAF CREATE THREAD calls
The following table shows a CREATE THREAD call in each language.
Table 33. Examples of RRSAF CREATE THREAD calls
Language

Call example

Assembler

CALL

C

1

DSNRLI,(CRTHRDFN,PLAN,COLLID,REUSE,RETCODE,REASCODE,PKLISTPTR)

fnret=dsnrli(&crthrdfn[0], &plan[0], &collid[0], &reuse[0], &retcode, &reascode, &pklistptr);

COBOL

CALL

’DSNRLI’ USING CRTHRDFN PLAN COLLID REUSE RETCODE REASCODE PKLSTPTR.

Fortran

CALL

DSNRLI(CRTHRDFN,PLAN,COLLID,REUSE,RETCODE,REASCODE,PKLSTPTR)

CALL

DSNRLI(CRTHRDFN,PLAN,COLLID,REUSE,RETCODE,REASCODE,PKLSTPTR);

PL/I

1

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75
″Authorizing plan or package access through applications″ (DB2 Administration
Guide)
Related reference
″BIND and REBIND options″ (DB2 Command Reference)

TERMINATE THREAD function for RRSAF
The RRSAF TERMINATE THREAD function deallocates DB2 resources that are
associated with a plan and were previously allocated for an application by the

110

Application Programming and SQL Guide
CREATE THREAD function. You can then use the CREATE THREAD function to
allocate another plan with the same connection.
If you call the TERMINATE THREAD function and the application is not at a point
of consistency, RRSAF returns reason code X’00C12211’.
The following diagram shows the syntax of the TERMINATE THREAD function.

DSNRLI TERMINATE THREAD function
CALL DSNRLI ( function,

)
, retcode
,

reascode

Parameters point to the following areas:
function
An 18-byte area the contains TERMINATE THREAD followed by two blanks.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode.

Example of RRSAF TERMINATE THREAD calls
The following table shows a TERMINATE THREAD call in each language.
Table 34. Examples of RRSAF TERMINATE THREAD calls
Language

Call example

Assembler

CALL

C

1

DSNRLI,(TRMTHDFN,RETCODE,REASCODE)

fnret=dsnrli(&trmthdfn[0], &retcode, &reascode);

COBOL

CALL

’DSNRLI’ USING TRMTHDFN RETCODE REASCODE.

Fortran

CALL

DSNRLI(TRMTHDFN,RETCODE,REASCODE)

CALL

DSNRLI(TRMTHDFN,RETCODE,REASCODE);

PL/I

1

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75
Chapter 2. Connecting to DB2 from your application program

111
TERMINATE IDENTIFY function for RRSAF
The RRSAF TERMINATE IDENTIFY function terminates a connection to DB2.
Calling the TERMINATE IDENTIFY function is optional. If you do not call it, DB2
performs the same functions when the task terminates.
If DB2 terminates, the application must issue TERMINATE IDENTIFY to reset the
RRSAF control blocks. This action ensures that future connection requests from the
task are successful when DB2 restarts.
The TERMINATE IDENTIFY function removes the calling task’s connection to DB2.
If no other task in the address space has an active connection to DB2, DB2 also
deletes the control block structures that were created for the address space and
removes the cross-memory authorization.
If the application is not at a point of consistency when you call the TERMINATE
IDENTIFY function, RRSAF returns reason code X’00C12211’.
If the application allocated a plan, and you call the TERMINATE IDENTIFY
function without first calling the TERMINATE THREAD function, DB2 deallocates
the plan before terminating the connection.
The following diagram shows the syntax of the TERMINATE IDENTIFY function.

DSNRLI TERMINATE IDENTIFY function
CALL DSNRLI ( function

)
, retcode
, reascode

Parameters point to the following areas:
function
An 18-byte area that contains TERMINATE IDENTIFY.
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode.

Example of RRSAF TERMINATE IDENTIFY calls
The following table shows a TERMINATE IDENTIFY call in each language.

112

Application Programming and SQL Guide
Table 35. Examples of RRSAF TERMINATE IDENTIFY calls
Language

Call example

Assembler

CALL

C

1

DSNRLI,(TMIDFYFN,RETCODE,REASCODE)

fnret=dsnrli(&tmidfyfn[0], &retcode, &reascode);

COBOL

CALL

’DSNRLI’ USING TMIDFYFN RETCODE REASCODE.

Fortran

CALL

DSNRLI(TMIDFYFN,RETCODE,REASCODE)

CALL

DSNRLI(TMIDFYFN,RETCODE,REASCODE);

PL/I

1

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75

TRANSLATE function for RRSAF
The RRSAF TRANSLATE function converts a hexadecimal reason code for a DB2
error into a signed integer SQL code and a printable error message. The SQL code
and message text are placed in the SQLCODE and SQLSTATE host variables or
related fields of the SQLCA.
Consider the following rules and recommendations about when to use and not use
the TRANSLATE function:
v You cannot call the TRANSLATE function from the Fortran language.
v Call the TRANSLATE function only after a successful IDENTIFY operation. For
errors that occur during SQL or IFI requests, the TRANSLATE function performs
automatically.
v The TRANSLATE function translates codes that begin with X’00F3’, but it does
not translate RRSAF reason codes that begin with X’00C1’.
If you receive error reason code X’00F30040’ (resource unavailable) after an OPEN
request, the TRANSLATE function returns the name of the unavailable database
object in the last 44 characters of the SQLERRM field.
If the TRANSLATE function does not recognize the error reason code, it returns
SQLCODE -924 (SQLSTATE ’58006’) and places a printable copy of the original
DB2 function code and the return and error reason codes in the SQLERRM field.
The contents of registers 0 and 15 do not change, unless TRANSLATE fails. In this
case, register 0 is set to X’00C12204’, and register 15 is set to 200.
The following diagram shows the syntax of the TRANSLATE function.

DSNRLI TRANSLATE function
CALL DSNRLI ( function, sqlca

)
,

retcode
, reascode

Chapter 2. Connecting to DB2 from your application program

113
Parameters point to the following areas:
function
An 18-byte area that contains the word TRANSLATE followed by nine blanks.
sqlca
The program’s SQL communication area (SQLCA).
retcode
A 4-byte area in which RRSAF places the return code.
This parameter is optional. If you do not specify retcode, RRSAF places the
return code in register 15 and the reason code in register 0.
reascode
A 4-byte area in which RRSAF places the reason code.
This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.
If you specify reascode, you must also specify retcode.

Example of RRSAF TRANSLATE calls
The following table shows a TRANSLATE call in each language.
Table 36. Examples of RRSAF TRANSLATE calls
Language

Call example

Assembler

CALL

C

1

fnret=dsnrli(&connfn[0], &sqlca, &retcode, &reascode);

COBOL
PL/I

DSNRLI,(XLATFN,SQLCA,RETCODE,REASCODE)

1

CALL

’DSNRLI’ USING XLATFN SQLCA RETCODE REASCODE.

CALL

DSNRLI(XLATFN,SQLCA,RETCODE,REASCODE);

Note:
1. For C, C++, and PL/I applications, you must include the appropriate compiler
directives, because DSNRLI is an assembler language program. These compiler
directives are described in the instructions for invoking RRSAF.
Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75
|
|
|

FIND_DB2_SYSTEMS function for RRSAF

|

The following diagram shows the syntax of the FIND_DB2_SYSTEMS function.

The RRSAF FIND_DB2_SYSTEMS function identifies all active DB2 subsystems on
a z/OS LPAR.

|

114

Application Programming and SQL Guide
|
|
|
|
|

DSNRLI FIND_DB2_SYSTEMS function
CALL DSNRLI ( function , ssnma , activea , arraysz ,
)
, retcode
, reascode

|
|
|
|

Parameters point to the following areas:

|
|

function
An 18-byte area that contains FIND_DB2_SYSTEMS followed by two blanks.

|
|
|
|
|
|

ssnma
A storage area for an array of 4-byte character strings into which RRSAF places
the names of all the DB2 subsystems (SSIDs) that are defined for the current
LPAR. You must provide the storage area. If the array is larger than the
number of DB2 subsystems, RRSAF returns the value ’ ’ (four blanks) in all
unused array members.

|
|
|
|
|
|
|

activea
A storage area for an array of 4-byte values into which RRSAF returns an
indication of whether a defined subsystem is active. Each value is represented
as a fixed 31-bit integer. The value 1 means that the subsystem is active. The
value 0 means that the subsystem is not active. The size of this array must be
the same as the size of the ssnma array. If the array is larger than the number
of DB2 subsystems, RRSAF returns the value -1 in all unused array members.

|
|

The information in the activea array is the information that is available at the
point in time that you requested it and might change at any time.

|
|
|
|
|

arraysz
A 4-byte area, represented as a fixed 31-bit integer, that specifies the number of
entries for the ssnma and activea arrays. If the number of array entries is
insufficient to contain all of the subsystems defined on the current LPAR,
RRSAF uses all available entries and returns return code 4.

|
|
|

retcode
A 4-byte area in which RRSAF is to place the return code for this call to the
FIND_DB2_SYSTEMS function.

|
|

This parameter is optional. If you do not retcode, RRSAF places the return code
in register 15 and the reason code in register 0.

|
|
|

reascode
A 4-byte area in which RRSAF is to place the reason code for this call to the
FIND_DB2_SYSTEMS function.

|
|

This parameter is optional. If you do not specify reascode, RRSAF places the
reason code in register 0.

|

Example values that the FIND_DB2_SYSTEMS function returns

|
|
|
|

Assume that two subsystems are defined on the current LPAR. Subsystem DB2A is
active, and subsystem DB2B is stopped. Suppose that you invoke RRSAF with the
function FIND_DB2_SYSTEMS and a value of 3 for arraysz. The ssnma array and
activea array are set to the following values:

Chapter 2. Connecting to DB2 from your application program

115
|

Table 37. Example values returned in the ssnma and activeaarrays

|

Array element number

Values in ssnma array

Values in activea array

|

1

DB2A

1

|

2

DB2B

0

|
|
|
|

3

(four blanks)

-1

Related tasks
“Invoking the Resource Recovery Services attachment facility” on page 75

RRSAF return codes and reason codes
If you specify return code and reason code parameters in an RRSAF function call,
RRSAF returns the return code and reason code in those parameters. If you do not
specify those parameters or implicitly invoke RRSAF, RRSAF puts the return code
in register 15 and the reason code in register 0.
When the reason code begins with X’00F3’, except for X’00F30006’, you can use the
RRSAF TRANSLATE function to obtain error message text that can be printed and
displayed.
For SQL calls, RRSAF returns standard SQL return codes in the SQLCA. RRSAF
returns IFI return codes and reason codes in the instrumentation facility
communication area (IFCA).
The following table lists the RRSAF return codes.
Table 38. RRSAF return codes
Return code

Explanation

0

The call completed successfully.

4

Status information is available. See the
reason code for details.

>4

The call failed. See the reason code for
details.

Related reference
“TRANSLATE function for RRSAF” on page 113

Sample RRSAF scenarios
One or more tasks can use RRSAF to connect to DB2. This connection can be made
either implicitly or explicitly. For explicit connections, a task calls one or more of
the RRSAF connection functions.

A single task
The following example pseudocode illustrates a single task running in an address
space that explicitly connects to DB2 through RRSAF. z/OS RRS controls commit
processing when the task terminates normally.
IDENTIFY
SIGNON
CREATE THREAD
SQL or IFI
.
.
.
TERMINATE IDENTIFY

116

Application Programming and SQL Guide
Multiple tasks
In the following scenario, multiple tasks in an address space explicitly connect to
DB2 through RRSAF. Task 1 executes no SQL statements and makes no IFI calls. Its
purpose is to monitor DB2 termination and startup ECBs and to check the DB2
release level.
TASK 1

TASK 2

TASK 3

TASK n

IDENTIFY

IDENTIFY
SIGNON
CREATE THREAD
SQL
...
SRRCMIT
SQL
...
SRRCMIT
...

IDENTIFY
SIGNON
CREATE THREAD
SQL
...
SRRCMIT
SQL
...
SRRCMIT
...

IDENTIFY
SIGNON
CREATE THREAD
SQL
...
SRRCMIT
SQL
...
SRRCMIT
...

TERMINATE IDENTIFY

Reusing a DB2 thread
The following example pseudocode shows a DB2 thread that is reused by another
user at a point of consistency. When the application calls the SIGNON function for
user B, DB2 reuses the plan that is allocated by the CREATE THREAD function for
user A.
IDENTIFY
SIGNON user A
CREATE THREAD
SQL
...
SRRCMIT
SIGNON user B
SQL
...
SRRCMIT

Switching DB2 threads between tasks
The following scenario shows how you can switch the threads for four users (A, B,
C, and D) among two tasks (1 and 2).
Task 1

Task 2

CTXBEGC (create context a)
CTXSWCH(a,0)
IDENTIFY
SIGNON user A
CREATE THREAD (Plan A)
SQL
...
CTXSWCH(0,a)

CTXBEGC (create context b)
CTXSWCH(b,0)
IDENTIFY
SIGNON user B
CREATE THREAD (plan B)
SQL
...
CTXSWCH(0,b)

CTXBEGC (create context c)
CTXSWCH(c,0)
IDENTIFY
SIGNON user C
CREATE THREAD (plan C)
SQL
...
CTXSWCH(b,c)

CTXBEGC (create context d)
CTXSWCH(d,0)
IDENTIFY
SIGNON user D
CREATE THREAD (plan D)
SQL
...
CTXSWCH(0,d)

Chapter 2. Connecting to DB2 from your application program

117
SQL (plan B)
...

...
CTXSWCH(a,0)
SQL (plan A)

The applications perform the following steps:
v Task 1 creates context a, switches contexts so that context a is active for task 1,
and calls the IDENTIFY function to initialize a connection to a subsystem. A task
must always call the IDENTIFY function before a context switch can occur. After
the IDENTIFY operation is complete, task 1 allocates a thread for user A, and
performs SQL operations.
At the same time, task 2 creates context b, switches contexts so that context b is
active for task 2, calls the IDENTIFY function to initialize a connection to the
subsystem, allocates a thread for user B, and performs SQL operations.
When the SQL operations complete, both tasks perform RRS context switch
operations. Those operations disconnect each DB2 thread from the task under
which it was running.
v Task 1 then creates context c, calls the IDENTIFY function to initialize a
connection to the subsystem, switches contexts so that context c is active for task
1, allocates a thread for user C, and performs SQL operations for user C.
Task 2 does the same operations for user D.
v When the SQL operations for user C complete, task 1 performs a context switch
operation to perform the following actions:
– Switch the thread for user C away from task 1.
– Switch the thread for user B to task 1.
For a context switch operation to associate a task with a DB2 thread, the DB2
thread must have previously performed an IDENTIFY operation. Therefore,
before the thread for user B can be associated with task 1, task 1 must have
performed an IDENTIFY operation.
v Task 2 performs two context switch operations to perform the following actions:
– Disassociate the thread for user D from task 2.
– Associate the thread for user A with task 2.

Program examples for RRSAF
The Resource Recovery Services attachment facility (RRSAF) enables programs to
communicate with DB2. You can use RRSAF as an alternative to CAF.

Example JCL for invoking RRSAF
The following sample JCL shows how to use RRSAF in a batch environment. The
DSNRRSAF DD statement starts the RRSAF trace. Use that DD statement only if
you are diagnosing a problem.
//jobname
//RRSJCL
//STEPLIB
//

JOB
EXEC
DD
DD

z/OS_jobcard_information
PGM=RRS_application_program
DSN=application_load_library
DSN=DB2_load_library

DD
DD
DD

SYSOUT=*
DUMMY
SYSOUT=*

.
.
.
//SYSPRINT
//DSNRRSAF
//SYSUDUMP

118

Application Programming and SQL Guide
Example of loading and deleting the RRSAF language interface
The following code segment shows how an application loads entry points DSNRLI
and DSNHLIR of the RRSAF language interface. Storing the entry points in
variables LIRLI and LISQL ensures that the application loads the entry points only
once. Delete the loaded modules when the application no longer needs to access
DB2.
****************************** GET LANGUAGE INTERFACE ENTRY ADDRESSES
LOAD EP=DSNRLI
Load the RRSAF service request EP
ST
R0,LIRLI
Save this for RRSAF service requests
LOAD EP=DSNHLIR
Load the RRSAF SQL call Entry Point
ST
R0,LISQL
Save this for SQL calls
*
.
*
.
Insert connection service requests and SQL calls here
*
.
DELETE EP=DSNRLI
Correctly maintain use count
DELETE EP=DSNHLIR
Correctly maintain use count

Example of using dummy entry point DSNHLI for RRSAF
Each of the DB2 attachment facilities contains an entry point named DSNHLI.
When you use RRSAF but do not specify the ATTACH(RRSAF) precompiler
option, the precompiler generates BALR instructions to DSNHLI for SQL
statements in your program. To find the correct DSNHLI entry point without
including DSNRLI in your load module, code a subroutine, with entry point
DSNHLI, that passes control to entry point DSNHLIR in the DSNRLI module.
DSNHLIR is unique to DSNRLI and is at the same location as DSNHLI in
DSNRLI. DSNRLI uses 31-bit addressing. If the application that calls this
intermediate subroutine uses 24-bit addressing, the intermediate subroutine must
account for the difference.
In the following example, LISQL is addressable because the calling CSECT used
the same register 12 as CSECT DSNHLI. Your application must also establish
addressability to LISQL.
***********************************************************************
* Subroutine DSNHLI intercepts calls to LI EP=DSNHLI
***********************************************************************
DS
0D
DSNHLI
CSECT
Begin CSECT
STM
R14,R12,12(R13)
Prologue
LA
R15,SAVEHLI
Get save area address
ST
R13,4(,R15)
Chain the save areas
ST
R15,8(,R13)
Chain the save areas
LR
R13,R15
Put save area address in R13
L
R15,LISQL
Get the address of real DSNHLI
BASSM R14,R15
Branch to DSNRLI to do an SQL call
*
DSNRLI is in 31-bit mode, so use
*
BASSM to assure that the addressing
*
mode is preserved.
L
R13,4(,R13)
Restore R13 (caller’s save area addr)
L
R14,12(,R13)
Restore R14 (return address)
RETURN (1,12)
Restore R1-12, NOT R0 and R15 (codes)

Example of connecting to DB2 with RRSAF
This example uses the variables that are declared in the following code.
****************** VARIABLES SET BY APPLICATION ***********************
LIRLI
DS
F
DSNRLI entry point address
LISQL
DS
F
DSNHLIR entry point address
SSNM
DS
CL4
DB2 subsystem name for IDENTIFY
Chapter 2. Connecting to DB2 from your application program

119
CORRID
DS
CL12
Correlation ID for SIGNON
ACCTTKN DS
CL22
Accounting token for SIGNON
ACCTINT DS
CL6
Accounting interval for SIGNON
PLAN
DS
CL8
DB2 plan name for CREATE THREAD
COLLID
DS
CL18
Collection ID for CREATE THREAD. If
*
PLAN contains a plan name, not used.
REUSE
DS
CL8
Controls SIGNON after CREATE THREAD
CONTROL DS
CL8
Action that application takes based
*
on return code from RRSAF
****************** VARIABLES SET BY DB2 *******************************
STARTECB DS
F
DB2 startup ECB
TERMECB DS
F
DB2 termination ECB
EIBPTR
DS
F
Address of environment info block
RIBPTR
DS
F
Address of release info block
****************************** CONSTANTS ******************************
CONTINUE DC
CL8’CONTINUE’
CONTROL value: Everything OK
IDFYFN
DC
CL18’IDENTIFY
’ Name of RRSAF service
SGNONFN DC
CL18’SIGNON
’ Name of RRSAF service
CRTHRDFN DC
CL18’CREATE THREAD
’ Name of RRSAF service
TRMTHDFN DC
CL18’TERMINATE THREAD ’ Name of RRSAF service
TMIDFYFN DC
CL18’TERMINATE IDENTIFY’ Name of RRSAF service
****************************** SQLCA and RIB **************************
EXEC SQL INCLUDE SQLCA
DSNDRIB
Map the DB2 Release Information Block
******************* Parameter list for RRSAF calls ********************
RRSAFCLL CALL ,(*,*,*,*,*,*,*,*),VL,MF=L

The following example code shows how to issue requests for the RRSAF functions
IDENTIFY, SIGNON, CREATE THREAD, TERMINATE THREAD, and
TERMINATE IDENTIFY. This example does not show a task that waits on the DB2
termination ECB. You can code such a task and use the z/OS WAIT macro to
monitor the ECB. The task that waits on the termination ECB should detach the
sample code if the termination ECB is posted. That task can also wait on the DB2
startup ECB. This example waits on the startup ECB at its own task level.
***************************** IDENTIFY ********************************
L
R15,LIRLI
Get the Language Interface address
CALL (15),(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB),VL,MF=X
(E,RRSAFCLL)
BAL
R14,CHEKCODE
Call a routine (not shown) to check
*
return and reason codes
CLC
CONTROL,CONTINUE
Is everything still OK
BNE
EXIT
If CONTROL not ’CONTINUE’, stop loop
USING R8,RIB
Prepare to access the RIB
L
R8,RIBPTR
Access RIB to get DB2 release level
WRITE ’The current DB2 release level is’ RIBREL
***************************** SIGNON **********************************
L
R15,LIRLI
Get the Language Interface address
CALL (15),(SGNONFN,CORRID,ACCTTKN,ACCTINT),VL,MF=(E,RRSAFCLL)
BAL
R14,CHEKCODE
Check the return and reason codes
*************************** CREATE THREAD *****************************
L
R15,LIRLI
Get the Language Interface address
CALL (15),(CRTHRDFN,PLAN,COLLID,REUSE),VL,MF=(E,RRSAFCLL)
BAL
R14,CHEKCODE
Check the return and reason codes
****************************** SQL ************************************
*
Insert your SQL calls here. The DB2 Precompiler
*
generates calls to entry point DSNHLI. You should
*
code a dummy entry point of that name to intercept
*
all SQL calls. A dummy DSNHLI is shown in the following
*
section.
************************ TERMINATE THREAD *****************************
CLC
CONTROL,CONTINUE
Is everything still OK?
BNE
EXIT
If CONTROL not ’CONTINUE’, shut down
L
R15,LIRLI
Get the Language Interface address
CALL (15),(TRMTHDFN),VL,MF=(E,RRSAFCLL)
BAL
R14,CHEKCODE
Check the return and reason codes

120

Application Programming and SQL Guide
************************ TERMINATE IDENTIFY ***************************
CLC
CONTROL,CONTINUE
Is everything still OK
BNE
EXIT
If CONTROL not ’CONTINUE’, stop loop
L
R15,LIRLI
Get the Language Interface address
CALL (15),(TMIDFYFN),VL,MF=(E,RRSAFCLL)
BAL
R14,CHEKCODE
Check the return and reason codes

Controlling the CICS attachment facility from an application
Use the CICS attachment facility to access DB2 from CICS application programs.
You can start and stop the CICS attachment facility from within an application
program.
To control the CICS attachment facility:
1. To start the CICS attachment facility, perform one of the following actions:
v Include the following statement in your application:
EXEC CICS LINK PROGRAM(’DSN2COM0’)

v Use the system programming interface SET DB2CONN for the CICS
Transaction Server.
2. To stop the CICS attachment facility, perform one of the following actions:
v Include the following statement in your application:
EXEC CICS LINK PROGRAM(’DSN2COM2’)

v Use the system programming interface SET DB2CONN for the CICS
Transaction Server.
Related information
CICS Transaction Server Library at ibm.com

Detecting whether the CICS attachment facility is operational
Before you execute SQL in a CICS program, you should test if the CICS attachment
facility is available. You do not need to do this test if the CICS attachment facility
is started and you are using standby mode.
When an SQL statement is executed, and the CICS attachment facility is in standby
mode, the attachment issues SQLCODE -923 with a reason code that indicates that
DB2 is not available.
To detect whether the CICS attachment facility is operational:
Use the INQUIRE EXITPROGRAM command for the CICS Transaction Server in
your application.
The following example shows how to use this command. In this example, the
INQUIRE EXITPROGRAM command tests whether the resource manager for SQL,
DSNCSQL, is up and running. CICS returns the results in the EIBRESP field of the
EXEC interface block (EIB) and in the field whose name is the argument of the
CONNECTST parameter (in this case, STST). If the EIBRESP value indicates that
the command completed normally and the STST value indicates that the resource
manager is available, you can then execute SQL statements.
STST
DS
ENTNAME DS
EXITPROG DS
.
.
.
MVC

F
CL8
CL8
ENTNAME,=CL8’DSNCSQL’
Chapter 2. Connecting to DB2 from your application program

121
MVC
EXITPROG,=CL8’DSN2EXT1’
EXEC CICS INQUIRE EXITPROGRAM(EXITPROG)
ENTRYNAME(ENTNAME) CONNECTST(STST) NOHANDLE
CLC
EIBRESP,DFHRESP(NORMAL)
BNE
NOTREADY
CLC
STST,DFHVALUE(CONNECTED)
BNE
NOTREADY
UPNREADY DS
0H
attach is up
NOTREADY DS
0H
attach isn’t up yet

X

If you use the INQUIRE EXITPROGRAM command to avoid AEY9 abends and the
CICS attachment facility is down, the storm drain effect can occur. The storm drain
effect is a condition that occurs when a system continues to receive work, even
though that system is down.
Related concepts
″Storm-drain effect″ (DB2 Data Sharing: Planning and Administration)
Related reference
″-923″ (DB2 Codes)
Related information
CICS Transaction Server Library at ibm.com

Improving thread reuse in CICS applications
In general, you want transactions to reuse threads whenever possible, because each
thread creation is associated with a high processor cost.
To improve thread reuse in CICS applications:
Close all cursors that are declared with the WITH HOLD option before each sync
point. DB2 does not automatically close them. A thread for an application that
contains an open cursor cannot be reused. You should close all cursors
immediately after you finish using them.
Related concepts
“Held and non-held cursors” on page 629

122

Application Programming and SQL Guide
Chapter 3. Including DB2 queries in an application program
A query is an SQL statement that returns data from a DB2 database. Your program
can communicate this SQL statement to DB2 in one of several ways. After
processing the statement, DB2 sends back a return code, which your program
should then test to determine the result of the operation.
To include DB2 queries in an application program:
1. Choose one of the following methods for communicating with DB2:
v Static SQL
v Embedded dynamic SQL
v Open Database Connectivity (ODBC)
v JDBC application support
v SQLJ application support
ODBC lets you access data through ODBC function calls in your application.
You execute SQL statements by passing them to DB2 through a ODBC function
call. ODBC eliminates the need for precompiling and binding your application
and increases the portability of your application by using the ODBC interface.
If you are writing your applications in Java™, you can use JDBC application
support to access DB2. JDBC is similar to ODBC but is designed specifically for
use with Java. In addition to using JDBC, you can use SQLJ application support
to access DB2. SQLJ is designed to simplify the coding of DB2 calls for Java
applications.
2. Optional: Declare the tables and views that you use. You can use DCLGEN to
generate these declarations.
3. Optional: Define an SQL communications area (SQLCA).
You can use an SQLCA to check whether an SQL statement executed
successfully. Alternatively, you can use any of the other methods for checking
the execution of SQL statements.
4. Define at least one SQL descriptor area (SQLDA).
5. Declare any of the following data items for passing data between DB2 and a
host language:
v host variables
v host variable arrays
v host structures
Ensure that you use the appropriate data types.
6. Code SQL statements to access DB2 data. Ensure that you delimit these
statements properly.
Consider using cursors to select a set of rows and then process the set either
one row at a time or one rowset at a time.
7. Check the execution of the SQL statements.
8. Handle any SQL error codes.
Related concepts
“Dynamic SQL” on page 258
“DCLGEN (declarations generator)” on page 125
″JDBC application programming″ (DB2 Application Programming Guide and
Reference for Java)
© Copyright IBM Corp. 1983, 2007

123
″SQLJ application programming″ (DB2 Application Programming Guide and
Reference for Java)
″Introduction to DB2 ODBC″ (DB2 ODBC Guide and Reference)
Related tasks
“Retrieving a set of rows by using a cursor” on page 626
“Delimiting an SQL statement” on page 258

Declaring table and view definitions
Before your program issues SQL statements that select, insert, update, or delete
data, the program should declare the tables and views that it accesses.
To do this, include an SQL DECLARE statement in your program.
You do not need to declare tables or views, but doing so offers advantages. One
advantage is documentation. For example, the DECLARE statement specifies the
structure of the table or view you are working with, and the data type of each
column. You can refer to the DECLARE statement for the column names and data
types in the table or view. Another advantage is that the DB2 precompiler uses
your declarations to make sure that you have used correct column names and data
types in your SQL statements. The DB2 precompiler issues a warning message
when the column names and data types do not correspond to the SQL DECLARE
statements in your program.
One way to declare a table or view is to code a DECLARE statement in the
WORKING-STORAGE SECTION or LINKAGE SECTION within the DATA
DIVISION of your COBOL program. Specify the name of the table and list each
column and its data type. When you declare a table or view, you specify
DECLARE table-name TABLE regardless of whether the table-name refers to a table
or a view.
For example, the DECLARE TABLE statement for the DSN8910.DEPT table looks
like the following DECLARE statement in COBOL:
EXEC SQL
DECLARE DSN8910.DEPT TABLE
(DEPTNO
CHAR(3)
DEPTNAME VARCHAR(36)
MGRNO
CHAR(6)
ADMRDEPT CHAR(3)
LOCATION CHAR(16)
END-EXEC.

NOT NULL,
NOT NULL,
,
NOT NULL,
)

As an alternative to coding the DECLARE statement yourself, you can use
DCLGEN, the declarations generator that is supplied with DB2. For more
information about using DCLGEN, see “DCLGEN (declarations generator)” on
page 125.
When you declare a table or view that contains a column with a distinct type,
declare that column with the source type of the distinct type, rather than with the
distinct type itself. When you declare the column with the source type, DB2 can
check embedded SQL statements that reference that column at precompile time.

124

Application Programming and SQL Guide
DCLGEN (declarations generator)
Your program needs to declare the tables and views that it accesses. DCLGEN, the
declarations generator supplied with DB2, produces this DECLARE statement for
C, COBOL, and PL/I programs, so that you do not need to code the statement
yourself.
For information about the syntax of DCLGEN, see the topic “DCLGEN
(DECLARATIONS GENERATOR) (DSN)” in DB2 Command Reference.
DCLGEN generates a table declaration and puts it into a member of a partitioned
data set that you can include in your program. When you use DCLGEN to
generate a table’s declaration, DB2 gets the relevant information from the DB2
catalog, which contains information about the table’s definition and the definition
of each column within the table. DCLGEN uses this information to produce a
complete SQL DECLARE statement for the table or view and a corresponding
PL/I, C structure declaration, or COBOL record description. You can use DCLGEN
for table declarations only if the table you are declaring already exists.
You must use DCLGEN before you precompile your program. Supply the table or
view name to DCLGEN before you precompile your program. To use the
declarations generated by DCLGEN in your program, use the SQL INCLUDE
statement. For more information about the INCLUDE statement, see the topic
“INCLUDE” in DB2 SQL Reference.
DB2 must be active before you can use DCLGEN. You can start DCLGEN in
several different ways:
v From ISPF through DB2I. Select the DCLGEN option on the DB2I Primary
Option Menu panel.
v Directly from TSO. To do this, sign on to TSO, issue the TSO command DSN,
and then issue the subcommand DCLGEN.
v From a CLIST, running in TSO foreground or background, that issues DSN and
then DCLGEN.
v With JCL. Supply the required information, using JCL, and run DCLGEN in
batch. In the prefix.SDSNSAMP library, sample jobs DSNTEJ2C and DSNTEJ2P
show how to use JCL to run DCLGEN. For more information about the syntax
of the DSN subcommand DCLGEN, see the topic “DCLGEN (DECLARATIONS
GENERATOR) (DSN)” in DB2 Command Reference.
If you want to start DCLGEN in the foreground, and your table names include
DBCS characters, you must provide and display double-byte characters. If you
do not have a terminal that displays DBCS characters, you can enter DBCS
characters using the hex mode of ISPF edit.

Type declarations that DCLGEN produces for C, COBOL, and
PL/I
DCLGEN produces DECLARE statements for C, COBOL, and PL/I programs.
DCLGEN derives the variable names and data types for these statements based on
the source tables in the database.
The following table lists the type declarations that DCLGEN produces for C,
COBOL, and PL/I based on the corresponding SQL data types that are contained
in the source tables. In this table, var represents variable names that DCLGEN
provides.

Chapter 3. Including DB2 queries in an application program

125
Table 39. Declarations generated by DCLGEN
SQL data type1

C

COBOL

PL/I

SMALLINT

short int

PIC S9(4) USAGE COMP

BIN FIXED(15)

INTEGER

long int

PIC S9(9) USAGE COMP

BIN FIXED(31)

PIC S9(p-s)V9(s) USAGE COMP-3

DEC FIXED(p,s)

DECIMAL(p,s) or
NUMERIC(p,s)

decimal(p,s)

2

If p>15, the PL/I
compiler must
support this
precision, or a
warning is
generated.

REAL or FLOAT(n) float
1 <= n <= 21

USAGE COMP-1

BIN FLOAT(n)

DOUBLE
PRECISION,
DOUBLE, or
FLOAT(n)

double

USAGE COMP-2

BIN FLOAT(n)

CHAR(1)

char

PIC X(1)

CHAR(1)

CHAR(n)

char var [n+1]

PIC X(n)

CHAR(n)

VARCHAR(n)

struct
{short int var_len;
char var_data[n];
} var;

10 var.
49 var_LEN PIC 9(4)
USAGE COMP.
49 var_TEXT PIC X(n).

CHAR(n) VAR

CLOB(n)3

SQL TYPE IS CLOB_LOCATOR

USAGE SQL TYPE IS CLOB-LOCATOR

SQL TYPE IS
CLOB_LOCATOR

GRAPHIC(1)

sqldbchar

PIC G(1)

GRAPHIC(1)

GRAPHIC(n)

sqldbchar var[n+1];

PIC G(n) USAGE
DISPLAY-1.4
or
PIC N(n).4

GRAPHIC(n)

VARGRAPHIC(n)

struct VARGRAPH
{short len;
sqldbchar data[n];
} var;

10 var.
49 var_LEN PIC 9(4)
USAGE COMP.
49 var_TEXT PIC G(n)
USAGE DISPLAY-1.4
or
10 var.
49 var_LEN PIC 9(4)
USAGE COMP.
49 var_TEXT PIC N(n).4

GRAPHIC(n) VAR

DBCLOB(n)3

SQL TYPE IS DBCLOB_LOCATOR

USAGE SQL TYPE IS DBCLOB-LOCATOR

SQL TYPE IS
DBCLOB_LOCATOR

| BINARY(n)
|

SQL TYPE IS BINARY(n)

USAGE SQL TYPE IS BINARY(n)

SQL TYPE IS
BINARY(n)

| VARBINARY(n)
|

SQL TYPE IS VARBINARY(n)

USAGE SQL TYPE IS VARBINARY(n)

SQL TYPE IS
VARBINARY(n)

BLOB(n)3

SQL TYPE IS BLOB_LOCATOR

USAGE SQL TYPE IS BLOB-LOCATOR

SQL TYPE IS
BLOB_LOCATOR

DATE

char var[11]5

PIC X(10)5

CHAR(10)5

TIME

char var[9]6

PIC X(8)6

CHAR(8)6

TIMESTAMP

char var[27]

PIC X(26)

CHAR(26)

n>1

126

Application Programming and SQL Guide
Table 39. Declarations generated by DCLGEN (continued)
SQL data type1

|
|

COBOL

PL/I

ROWID

|

C
SQL TYPE IS ROWID

USAGE SQL TYPE IS ROWID

SQL TYPE IS
ROWID

BIGINT

long long int

PIC S9(18) USAGE COMP

FIXED BIN(63)

SQL TYPE IS XML AS CLOB(1M)

SQL TYPE IS XML AS CLOB(1M)

SQL TYPE IS XML
AS CLOB(1M)

XML

7

Notes:
1. For a distinct type, DCLGEN generates the host language equivalent of the source data type.
2. If your C compiler does not support the decimal data type, edit your DCLGEN output, and replace the decimal
data declarations with declarations of type double.
3. For a BLOB, CLOB, or DBCLOB data type, DCLGEN generates a LOB locator.
4. DCLGEN chooses the format based on the character you specify as the DBCS symbol on the COBOL Defaults
panel.
5. This declaration is used unless a date installation exit routine exists for formatting dates, in which case the length
is that specified for the LOCAL DATE LENGTH installation option.
6. This declaration is used unless a time installation exit routine exists for formatting times, in which case the length
is that specified for the LOCAL TIME LENGTH installation option.

|

7. The default setting for XML is 1M; however, you might need to adjust it.

For more information about the DCLGEN subcommand, see the topic “DCLGEN
(DECLARATIONS GENERATOR) (DSN)” in DB2 Command Reference.

Example: Adding a table declaration and host-variable structure
to a library
You can use DCLGEN to generate table declarations for C, COBOL, and PL/I
programs. If you store these declarations in a library, you can later pull them into
your program with a single SQL INCLUDE statement.
This example adds an SQL table declaration and a corresponding host-variable
structure to a library. This example is based on the following scenario:
v The library name is prefix.TEMP.COBOL.
v The member is a new member named VPHONE.
v The table is a local table named DSN8910.VPHONE.
v The host-variable structure is for COBOL.
v The structure receives the default name DCLVPHONE.
Information that you must enter is in bold-faced type.
Step 1. Specify COBOL as the host language
Select option D on the ISPF/PDF menu to display the DB2I Defaults panel.
Specify IBMCOB as the application language, as shown in Figure 6 on page 128,
and press Enter.

Chapter 3. Including DB2 queries in an application program

127
DSNEOP01
COMMAND ===>_

DB2I DEFAULTS PANEL 1

Change defaults as desired:
1
2
3
4
5
6
7
8
9
10
11

DB2 NAME ............. ===>
DB2 CONNECTION RETRIES ===>
APPLICATION LANGUAGE
===>
LINES/PAGE OF LISTING ===>
MESSAGE LEVEL ........ ===>
SQL STRING DELIMITER
===>
DECIMAL POINT ........ ===>
STOP IF RETURN CODE >= ===>
NUMBER OF ROWS
===>
CHANGE HELP BOOK NAMES?===>
AS USER
===>

PRESS: ENTER to process

DSN
0
IBMCOB
80
I
DEFAULT
.
8
20
NO

(Subsystem identifier)
(How many retries for DB2 connection)
(ASM, C, CPP, IBMCOB, FORTRAN, PLI)
(A number from 5 to 999)
(Information, Warning, Error, Severe)
(DEFAULT, ’ or ")
(. or ,)
(Lowest terminating return code)
(For ISPF Tables)
(YES to change HELP data set names)
(Userid to associate with the trusted
connection)

END to cancel

HELP for more information

Figure 6. DB2I defaults panel—changing the application language

The COBOL Defaults panel is then displayed, as shown in Figure 7. Fill in the
COBOL Defaults panel as necessary. Press Enter to save the new defaults, if any,
and return to the DB2I Primary Option menu.
DSNEOP02
COMMAND ===>_

DB2I DEFAULTS PANEL 2

Change defaults as desired:
1

2
3

DB2I
===>
===>
===>
===>

JOB STATEMENT:
(Optional if your site has a SUBMIT exit)
//ADMF001A JOB (ACCOUNT),’NAME’
//*
//*
//*

COBOL DEFAULTS:
COBOL STRING DELIMITER ===> DEFAULT
DBCS SYMBOL FOR DCLGEN ===> G

(For IBMCOB)
(DEFAULT, ’ or ")
(G/N - Character in PIC clause)

Figure 7. The COBOL defaults panel. Shown only if the field APPLICATION LANGUAGE on the DB2I Defaults panel is
IBMCOB.

Step 2. Create the table declaration and host structure
Select the DCLGEN option on the DB2I Primary Option menu, and press Enter to
display the DCLGEN panel.
Fill in the fields as shown in Figure 8 on page 129, and then press Enter.

128

Application Programming and SQL Guide
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

DSNEDP01
===>

DCLGEN

SSID: DSN

Enter table name for which declarations are required:
1 SOURCE TABLE NAME ===> DSN8910.VPHONE
2

TABLE OWNER ..... ===>

3 AT LOCATION ..... ===>
(Optional)
Enter destination data set:
(Can be sequential or partitioned)
4 DATA SET NAME ... ===> TEMP(VPHONEC)
5 DATA SET PASSWORD ===>
(If password protected)
Enter options as desired:
6 ACTION .......... ===> ADD
(ADD new or REPLACE old declaration)
7 COLUMN LABEL .... ===> NO
(Enter YES for column label)
8 STRUCTURE NAME .. ===>
(Optional)
9 FIELD NAME PREFIX ===>
(Optional)
10 DELIMIT DBCS .... ===> YES
(Enter YES to delimit DBCS identifiers)
11 COLUMN SUFFIX ... ===> NO
(Enter YES to append column name)
12 INDICATOR VARS .. ===> NO
(Enter YES for indicator variables)
13 ADDITIONAL OPTIONS===> NO
(Enter YES to change additional options)
PRESS: ENTER to process

END to exit

HELP for more information

Figure 8. DCLGEN panel—selecting source table and destination data set

If the operation succeeds, a message is displayed at the top of your screen, as
shown in Figure 9.
DSNE905I EXECUTION COMPLETE, MEMBER VPHONEC ADDED
***

Figure 9. Successful completion message

DB2 again displays the DCLGEN screen, as shown in Figure 10. Press Enter to
return to the DB2I Primary Option menu.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

DSNEDP01
===>

DCLGEN

SSID: DSN

Enter table name for which declarations are required:
1 SOURCE TABLE NAME ===> DSN8910.VPHONE
2

TABLE OWNER ..... ===>

3 AT LOCATION ..... ===>
(Optional)
Enter destination data set:
(Can be sequential or partitioned)
4 DATA SET NAME ... ===> TEMP(VPHONEC)
5 DATA SET PASSWORD ===>
(If password protected)
Enter options as desired:
6 ACTION .......... ===> ADD
(ADD new or REPLACE old declaration)
7 COLUMN LABEL .... ===> NO
(Enter YES for column label)
8 STRUCTURE NAME .. ===>
(Optional)
9 FIELD NAME PREFIX ===>
(Optional)
10 DELIMIT DBCS .... ===> YES
(Enter YES to delimit DBCS identifiers)
11 COLUMN SUFFIX ... ===> NO
(Enter YES to append column name)
12 INDICATOR VARS .. ===> NO
(Enter YES for indicator variables)
13 ADDITIONAL OPTIONS===> NO
(Enter YES to change additional options)
PRESS: ENTER to process

END to exit

HELP for more information

Figure 10. DCLGEN panel—displaying system and user return codes

Step 3. Examine the results
To browse or edit the results, exit from DB2I, and select either the browse or the
edit option from the ISPF/PDF menu to view the results.
Chapter 3. Including DB2 queries in an application program

129
For this example, the data set to edit is prefix.TEMP.COBOL(VPHONEC), which is
shown in the following example.
***** DCLGEN TABLE(DSN8910.VPHONE)
***
*****
LIBRARY(SYSADM.TEMP.COBOL(VPHONEC))
***
*****
QUOTE
***
***** ... IS THE DCLGEN COMMAND THAT MADE THE FOLLOWING STATEMENTS ***
EXEC SQL DECLARE DSN8910.VPHONE TABLE
( LASTNAME
VARCHAR(15) NOT NULL,
FIRSTNAME
VARCHAR(12) NOT NULL,
MIDDLEINITIAL
CHAR(1) NOT NULL,
PHONENUMBER
VARCHAR(4) NOT NULL,
EMPLOYEENUMBER
CHAR(6) NOT NULL,
DEPTNUMBER
CHAR(3) NOT NULL,
DEPTNAME
VARCHAR(36) NOT NULL
) END-EXEC.
***** COBOL DECLARATION FOR TABLE DSN8910.VPHONE
******
01 DCLVPHONE.
10 LASTNAME.
49 LASTNAME-LEN
PIC S9(4) USAGE COMP.
49 LASTNAME-TEXT
PIC X(15).
10 FIRSTNAME.
49 FIRSTNAME-LEN
PIC S9(4) USAGE COMP.
49 FIRSTNAME-TEXT
PIC X(12).
10 MIDDLEINITIAL
PIC X(1).
10 PHONENUMBER.
49 PHONENUMBER-LEN
PIC S9(4) USAGE COMP.
49 PHONENUMBER-TEXT PIC X(4).
10 EMPLOYEENUMBER
PIC X(6).
10 DEPTNUMBER
PIC X(3).
10 DEPTNAME.
49 DEPTNAME-LEN
PIC S9(4) USAGE COMP.
49 DEPTNAME-TEXT
PIC X(36).
***** THE NUMBER OF COLUMNS DESCRIBED BY THIS DECLARATION IS 7 ******

Generating declarations for your table by using DCLGEN
Your program needs to declare the tables and views that it accesses. For C,
COBOL, and PL/I programs you can use DCLGEN to produce these required
declarations, so that you do not need to code the statements yourself.
The easiest way to start DCLGEN is through DB2I. Figure 11 on page 131 shows
the DCLGEN panel you reach by selecting the DCLGEN option on the DB2I
Primary Option Menu panel. For more instructions on using DB2I, see “DB2I
primary option menu” on page 902.

130

Application Programming and SQL Guide
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

DSNEDP01
===>

DCLGEN

SSID: DSN

Enter table name for which declarations are required:
1 SOURCE TABLE NAME ===>
2

TABLE OWNER ..... ===>

3 AT LOCATION ..... ===>
Enter destination data set:
4 DATA SET NAME ... ===>
5 DATA SET PASSWORD ===>
Enter options as desired:
6 ACTION .......... ===> ADD
7 COLUMN LABEL .... ===> NO
8 STRUCTURE NAME .. ===>
9 FIELD NAME PREFIX ===>
10 DELIMIT DBCS .... ===> YES
11 COLUMN SUFFIX ... ===> NO
12 INDICATOR VARS .. ===> NO
13 ADDITIONAL OPTIONS===> YES
PRESS: ENTER to process

(Optional)
(Can be sequential or partitioned)
(If password protected)
(ADD new or REPLACE old declaration)
(Enter YES for column label)
(Optional)
(Optional)
(Enter YES to delimit DBCS identifiers)
(Enter YES to append column name)
(Enter YES for indicator variables)
(Enter YES to change additional options)

END to exit

HELP for more information

Figure 11. DCLGEN panel

Fill in the DCLGEN panel as follows:
1 SOURCE TABLE NAME
Is the unqualified name of the table, view, or created temporary table for
which you want DCLGEN to produce SQL data declarations. The table can
be stored at your DB2 location or at another DB2 location. To specify a
table name at another DB2 location, enter the table qualifier in the TABLE
OWNER field and the location name in the AT LOCATION field. DCLGEN
generates a three-part table name from the SOURCE TABLE NAME,
TABLE OWNER, and AT LOCATION fields. You can also use an alias for a
table name.
To specify a table name that contains special characters or blanks, enclose
the name in apostrophes. If the name contains apostrophes, you must
double each one(’ ’). For example, to specify a table named DON’S TABLE,
enter the following:
’DON’’S TABLE’

You do not need to enclose DBCS table names in apostrophes. If you do
not enclose the table name in apostrophes, DB2 converts lowercase
characters to uppercase.
The underscore is not handled as a special character in DCLGEN. For
example, the table name JUNE_PROFITS does not need to be enclosed in
apostrophes. Because COBOL field names cannot contain underscores,
DCLGEN substitutes hyphens (-) for single-byte underscores in COBOL
field names that are built from the table name.
|
|
|
|

2 TABLE OWNER
Is the schema qualifier of the source table. If you do not specify this value
and the table is a local table, DB2 assumes that the table qualifier is your
TSO logon ID. If the table is at a remote location, you must specify this
value.
3 AT LOCATION
Is the location of a table or view at another DB2 subsystem. If you specify
this parameter, you must also specify a qualified name in the SOURCE
Chapter 3. Including DB2 queries in an application program

131
TABLE NAME field. The value of the AT LOCATION field becomes a
prefix for the table name on the SQL DECLARE statement, as follows:
location_name, schema_name, table_name

For example, for the location PLAINS_GA:
PLAINS_GA.CARTER.CROP_YIELD_89

The default is the local location name. This field applies to DB2 private
protocol access only. The location you name must be another DB2 for
z/OS.
4 DATA SET NAME
Is the name of the data set you allocated to contain the declarations that
DCLGEN produces. You must supply a name; no default exists.
The data set must already exist, be accessible to DCLGEN, and can be
either sequential or partitioned. If you do not enclose the data set name in
apostrophes, DCLGEN adds a standard TSO prefix (user ID) and suffix
(language). DCLGEN knows what the host language is from the DB2I
defaults panel.
For example, for library name LIBNAME(MEMBNAME), the name
becomes:
userid.libname.language(membname)

For library name LIBNAME, the name becomes:
userid.libname.language

If this data set is password protected, you must supply the password in
the DATA SET PASSWORD field.
5 DATA SET PASSWORD
Is the password for the data set in the DATA SET NAME field, if the data
set is password protected. It is not displayed on your terminal, and it is
not recognized if you issued it from a previous session.
6 ACTION
Tells DCLGEN what to do with the output when it is sent to a partitioned
data set. (The option is ignored if the data set you specify in the DATA
SET NAME field is sequential.)
ADD indicates that an old version of the output does not exist and
creates a new member with the specified data set name. This is the
default.
REPLACE replaces an old version, if it already exists. If the member
does not exist, this option creates a new member.
7 COLUMN LABEL
Tells DCLGEN whether to include labels that are declared on any columns
of the table or view as comments in the data declarations. (The SQL
statement LABEL creates column labels to use as supplements to column
names.) Use:
YES to include column labels.
NO to ignore column labels. This is the default.
8 STRUCTURE NAME
Is the name of the generated data structure. The name can be up to 31
characters. If the name is not a DBCS string, and the first character is not
alphabetic, then enclose the name in apostrophes. If you use special
characters, be careful to avoid name conflicts.

132

Application Programming and SQL Guide
If you leave this field blank, DCLGEN generates a name that contains the
table or view name with a prefix of DCL. If the language is COBOL or
PL/I, and the table or view name consists of a DBCS string, the prefix
consists of DBCS characters.
For C, lowercase characters you enter in this field do not fold to uppercase.
9 FIELD NAME PREFIX
Specifies a prefix that DCLGEN uses to form field names in the output. For
example, if you choose ABCDE, the field names generated are ABCDE1,
ABCDE2, and so on.
DCLGEN accepts a field name prefix of up to 28 bytes that can include
special and double-byte characters. If you specify a single-byte or
mixed-string prefix and the first character is not alphabetic, apostrophes
must enclose the prefix. If you use special characters, avoid name conflicts.
For COBOL and PL/I, if the name is a DBCS string, DCLGEN generates
DBCS equivalents of the suffix numbers. For C, lowercase characters you
enter in this field do not fold to uppercase.
If you leave this field blank, the field names are the same as the column
names in the table or view.
10 DELIMIT DBCS
Tells DCLGEN whether to delimit DBCS table names and column names in
the table declaration. Use:
YES to enclose the DBCS table and column names with SQL delimiters.
NO to not delimit the DBCS table and column names.
11 COLUMN SUFFIX
Tells DCLGEN whether to form field names by attaching the column name
as a suffix to the value you specify in FIELD NAME PREFIX. For example,
if you specify YES, the field name prefix is NEW, and the column name is
EMPNO, the field name is NEWEMPNO.
If you specify YES, you must also enter a value in FIELD NAME PREFIX.
If you do not enter a field name prefix, DCLGEN issues a warning
message and uses the column names as the field names.
The default is NO, which does not use the column name as a suffix and
allows the value in FIELD NAME PREFIX to control the field names, if
specified.
12 INDICATOR VARS
Tells DCLGEN whether to generate an array of indicator variables for the
host variable structure.
If you specify YES, the array name is the table name with a prefix of I (or
DBCS letter <I> if the table name consists solely of double-byte characters).
The form of the data declaration depends on the language:
For a C program: short int Itable-name[n];
For a COBOL program: 01 Itable-name PIC S9(4) USAGE COMP OCCURS
n TIMES.
For a PL/I program: DCL Itable-name(n) BIN FIXED(15);
n is the number of columns in the table. For example, suppose you define
the following table:
CREATE TABLE HASNULLS (CHARCOL1 CHAR(1), CHARCOL2 CHAR(1));

You request an array of indicator variables for a COBOL program.
DCLGEN might generate the following host variable declaration:
Chapter 3. Including DB2 queries in an application program

133
01

DCLHASNULLS.
10 CHARCOL1
PIC X(1).
10 CHARCOL2
PIC X(1).
01 IHASNULLS PIC S9(4) USAGE COMP OCCURS 2 TIMES.

The default is NO, which does not generate an indicator variable array.
|
|
|

13 ADDITIONAL OPTIONS
Indicates whether to display the panel for additional DCLGEN options.
The default is YES.

|
|

If you specified YES in the ADDITIONAL OPTIONS field, the ADDITIONAL
DCLGEN OPTIONS panel is displayed as follows:

|
DSNEDP02
ADDITIONAL DCLGEN OPTIONS
SSID: DSN
===>
|
|
Enter options as desired:
|
1 RIGHT MARGIN .... ===> 72
(Enter 72 or 80)
|
|
2 FOR BIT DATA .... ===> NO
(Enter YES to declare SQL variables for
|
FOR BIT DATA columns)
|
|
PRESS: ENTER to process
END to exit
HELP for more information
|
|
|
| Figure 12. ADDITIONAL DCLGEN OPTIONS panel
|
Fill in the ADDITIONAL DCLGEN OPTIONS panel as follows:
|
1 RIGHT MARGIN
Specifies the break point for statement tokens that must be wrapped to one
or more subsequent records. You can specify column 72 or column 80.

|
|
|

The default is 72.

|

|
|

2 FOR BIT DATA
Specifies whether DCLGEN is to generate a DECLARE VARIABLE
statement of SQL variables for columns that are declared as FOR BIT
DATA. This statement is required in DB2 applications that meet all of the
following criteria:
v are written in COBOL
v have host variables for FOR BIT DATA columns

|
|

v are prepared using the SQLCCSID option of the integrated DB2
coprocessor.

|

The choices are YES and NO. The default is NO.

|
|

If the table or view does not have FOR BIT DATA columns, DCLGEN does
not generate this statement.

|
|
|
|
|

DCLGEN generates a table or column name in the DECLARE statement as a
non-delimited identifier unless at least one of the following conditions is true:
v The name contains special characters and is not a DBCS string.
v The name is a DBCS string, and you have requested delimited DBCS names.
If you are using an SQL reserved word as an identifier, you must edit the
DCLGEN output in order to add the appropriate SQL delimiters.
DCLGEN produces output that is intended to meet the needs of most users, but
occasionally, you will need to edit the DCLGEN output to work in your specific
case. For example, DCLGEN is unable to determine whether a column that is

134

Application Programming and SQL Guide
defined as NOT NULL also contains the DEFAULT clause, so you must edit the
DCLGEN output to add the DEFAULT clause to the appropriate column
definitions.

Including data declarations from DCLGEN in your program
After you use DCLGEN to produce the required table and view declarations for
your C, COBOL, or PL/I program, you need to include these declarations in your
program.
Use the following SQL INCLUDE statement to place the generated table
declaration and COBOL record description in your source program:
EXEC SQL
INCLUDE member-name
END-EXEC.

For example, to include a description for the table DSN8910.EMP, code:
EXEC SQL
INCLUDE DECEMP
END-EXEC.

In this example, DECEMP is a name of a member of a partitioned data set that
contains the table declaration and a corresponding COBOL record description of
the table DSN8910.EMP. (A COBOL record description is a two-level host structure
that corresponds to the columns of a table’s row. To get a current description of the
table, use DCLGEN to generate the table’s declaration and store it as member
DECEMP in a library (usually a partitioned data set) just before you precompile
the program.

Defining the SQL communications area
An assembler, C, C++, COBOL, Fortran, or PL/I program can include an SQL
communications area (SQLCA) instead of including individual SQLCODE and
SQLSTATE host variables. For REXX procedures that contain SQL statements, DB2
automatically includes an SQLCA in the procedure when DB2 prepares it.
An assembler, C, COBOL, Fortran, or PL/I program that contains SQL statements
must either include an SQLCA, which contains the SQLCODE and SQLSTATE
variables, or declare one or both of the following host variables:
v An SQLCODE variable, which is declared as shown in the following table.
Table 40. SQLCODE variable declarations
Language

How the SQLCODE variable is declared

assembler

as a fullword integer

C

as a long integer
Example:
long SQLCODE;

COBOL
Fortran
PL/I

as PIC S9(9) BINARY, PIC S9(9) COMP-4,
PIC S9(9) COMP-5, or PICTURE S9(9) COMP
1

as INTEGER*4
as BIN FIXED (31)

Note:
1. In Fortran, this variable is called SQLCOD.
Chapter 3. Including DB2 queries in an application program

135
v An SQLSTATE variable, which is declared as shown in the following table.
Table 41. SQLSTATE variable declarations
Language

How the SQLSTATE variable is declared

assembler

as a character string of length 5 (CL5)

C

as a character array of length 6
Example:
char SQLSTATE[6];

COBOL
Fortran

as PICTURE X(5)
1

PL/I

as CHARACTER*5
as CHARACTER(5)

Note:
1. In Fortran, this variable can also be called SQLSTA.
DB2 sets the SQLCODE (or SQLCOD) and SQLSTATE (or SQLSTA) values after
each SQL statement executes. An application should check these values to
determine whether the last SQL statement was successful. All SQL statements in
the program must be within the scope of the declaration of the SQLCODE and
SQLSTATE variables.
Whether you define the SQLCODE or SQLSTATE variable or an SQLCA in your
program depends on whether you specify the precompiler option STDSQL(YES) to
conform to the SQL standard, or STDSQL(NO) to conform to DB2 rules:
v If you specify the precompiler option STDSQL(YES): Do not define an SQLCA.
If you do, DB2 ignores your SQLCA, and your SQLCA definition causes
compile-time errors.
If you declare an SQLSTATE variable, it must not be an element of a structure.
You must declare the host variables SQLCODE (or SQLCOD) and SQLSTATE (or
SQLSTA) within a BEGIN DECLARE SECTION and END DECLARE SECTION
statement in your program declarations.
COBOL: When you use the precompiler option STDSQL(YES), you must declare
an SQLCODE variable. DB2 declares an SQLCA area for you in the
WORKING-STORAGE SECTION. DB2 controls the structure and location of the
SQLCA.
v If you specify the precompiler option STDSQL(NO): Include an SQLCA
explicitly.
REXX applications behave differently. When DB2 prepares a REXX procedure that
contains SQL statements, DB2 automatically includes an SQL communication area
(SQLCA) in the procedure. The REXX SQLCA differs from the SQLCA for other
languages in the following ways:
v The REXX SQLCA consists of a set of separate variables, rather than a structure.
If you use the ADDRESS DSNREXX ’CONNECT’ ssid syntax to connect to DB2, the
SQLCA variables are a set of simple variables.
If you connect to DB2 using the CALL SQLDBS ’ATTACH TO’ syntax, the SQLCA
variables are compound variables that begin with the stem SQLCA.
To define the SQL communications area:
1. Code the SQLCA directly in the program or use the following SQL INCLUDE
statement to request a standard SQLCA declaration.

136

Application Programming and SQL Guide
EXEC SQL INCLUDE SQLCA

For C and C++ applications, this standard declaration includes both a structure
definition and a static data area named ’sqlca’.
Restriction: You cannot use the INCLUDE SQLCA statement to include an
SQLCA in a REXX program.
2. Implement the following language-specific requirements:
Table 42. Language-specific requirements for defining the SQLCA
Language

Requirement

Assembler

If your program is reentrant, you must
include the SQLCA within a unique data
area that is acquired for your task (a DSECT).
For example, at the beginning of your
program, specify:
PROGAREA DSECT
EXEC SQL INCLUDE SQLCA
As an alternative, you can create a separate
storage area for the SQLCA and provide
addressability to that area.

COBOL

You can specify INCLUDE SQLCA or a
declaration for SQLCODE wherever you can
specify a 77 level or a record description
entry in the WORKING-STORAGE
SECTION. When you use the DB2
precompiler, you can declare a stand-alone
SQLCODE variable in either the
WORKING-STORAGE SECTION or
LINKAGE SECTION. When using the DB2
coprocessor, you can declare a stand-alone
SQLCODE variable in the
WORKING-STORAGE SECTION, LINKAGE
SECTION or LOCAL-STORAGE SECTION.

Related tasks
“Accessing the DB2 REXX language support application programming
interfaces” on page 296
Related reference
″INCLUDE″ (DB2 SQL Reference)
″Description of SQLCA fields″ (DB2 SQL Reference)
″The REXX SQLCA″ (DB2 SQL Reference)
“Descriptions of SQL processing options” on page 854

Defining SQL descriptor areas
If your program includes certain SQL statements, you must define at least one SQL
descriptor area (SQLDA).
The following statements require an SQLDA:
v CALL ... USING DESCRIPTOR descriptor-name
v DESCRIBE statement-name INTO descriptor-name
v DESCRIBE CURSOR host-variable INTO descriptor-name
v DESCRIBE INPUT statement-name INTO descriptor-name
v DESCRIBE PROCEDURE host-variable INTO descriptor-name
Chapter 3. Including DB2 queries in an application program

137
v
v
v
v
v

DESCRIBE TABLE host-variable INTO descriptor-name
EXECUTE ... USING DESCRIPTOR descriptor-name
FETCH ... USING DESCRIPTOR descriptor-name
OPEN ... USING DESCRIPTOR descriptor-name
PREPARE ... INTO descriptor-name

Unlike the SQLCA, a program can have more than one SQLDA, and an SQLDA
can have any valid name.
To define SQL descriptor areas:
1. For assembler, C, C++, and PL/I programs, code the SQLDA directly in the
program or use the following SQL INCLUDE statement to request a standard
SQLDA declaration:
EXEC SQL INCLUDE SQLDA

For C and C++ programs, you can place an SQLDA declaration wherever C
allows a structure definition. Normal C scoping rules apply. The standard
declaration includes only a structure definition with the name ’sqlda’.
Requirement: You must place SQLDA declarations before the first SQL
statement that references the data descriptor, unless you use the TWOPASS
precompiler option . For the DB2 coprocessor, only the ONEPASS precompiler
option is allowed.
Restriction: DB2 does not support the INCLUDE SQLDA statement for Fortran
or REXX programs.
Restriction: The SQL INCLUDE statement does not provide an SQLDA
mapping for COBOL.
2. For COBOL programs that are compiled with any supported compiler, define
the SQLDA by using one of the following two methods:
v Code the SQLDA declarations in your program. When you use the DB2
precompiler, you must place SQLDA declarations in the
WORKING-STORAGE SECTION or LINKAGE SECTION of your program,
wherever you can specify a record description entry in that section. When
you use the DB2 coprocessor, you must place SQLDA declarations in the
WORKING-STORAGE SECTION, LINKAGE SECTION or LOCAL-STORAGE
SECTION of your program, wherever you can specify a record description
entry in that section.
v Call a subroutine that is written in C, PL/I, or assembler language and that
uses the INCLUDE SQLDA statement to define the SQLDA. The subroutine
can also include SQL statements for any dynamic SQL functions you need.

|
|
|
|
|
|
|
|

Requirement: You must place SQLDA declarations before the first SQL
statement that references the data descriptor, unless you use the TWOPASS
precompiler option . For the DB2 coprocessor, only the ONEPASS precompiler
option is allowed.
3. For Fortran programs, call a subroutine that is written in C, PL/I or assembler
language and that uses the INCLUDE SQLDA statement to define the SQLDA
and that also includes the necessary SQL statements for the dynamic SQL
functions you want to perform.

138

Application Programming and SQL Guide
Requirement: You must place SQLDA declarations before the first SQL
statement that references the data descriptor, unless you use the TWOPASS
precompiler option . For the DB2 coprocessor, only the ONEPASS precompiler
option is allowed.
4. For REXX programs, code the SQLDA declarations in your program. Each
SQLDA consists of a set of REXX variables with a common stem. The stem
must be a REXX variable name that contains no periods and is the same as the
value of descriptor-name that you specify when you use the SQLDA in an SQL
statement.
Related reference
″INCLUDE″ (DB2 SQL Reference)
″Description of SQLCA fields″ (DB2 SQL Reference)
″The REXX SQLCA″ (DB2 SQL Reference)
“Descriptions of SQL processing options” on page 854

Putting parameter information in an SQLDA by using DESCRIBE
INPUT
Your program can get data type information about parameter markers by asking
DB2 to set the fields in the SQLDA.
You can use the DESCRIBE INPUT statement to let DB2 put the data type
information for parameter markers in an SQLDA.
Before you execute DESCRIBE INPUT, you must allocate an SQLDA with enough
instances of SQLVAR to represent all parameter markers in the SQL statements you
want to describe.
After you execute DESCRIBE INPUT, you code the application in the same way as
any other application in which you execute a prepared statement using an SQLDA.
First, you obtain the addresses of the input host variables and their indicator
variables and insert those addresses into the SQLDATA and SQLIND fields. Then
you execute the prepared SQL statement.
Example using the SQLDA: Suppose that you want to execute this statement
dynamically:
DELETE FROM DSN8910.EMP WHERE EMPNO = ?

The code to set up an SQLDA, obtain parameter information using DESCRIBE
INPUT, and execute the statement looks like this:
SQLDAPTR=ADDR(INSQLDA);
/* Get pointer to SQLDA
SQLDAID=’SQLDA’;
/* Fill in SQLDA eye-catcher
SQLDABC=LENGTH(INSQLDA);
/* Fill in SQLDA length
SQLN=1;
/* Fill in number of SQLVARs
SQLD=0;
/* Initialize # of SQLVARs used
DO IX=1 TO SQLN;
/* Initialize the SQLVAR
SQLTYPE(IX)=0;
SQLLEN(IX)=0;
SQLNAME(IX)=’’;
END;
SQLSTMT=’DELETE FROM DSN8910.EMP WHERE EMPNO = ?’;
EXEC SQL PREPARE SQLOBJ FROM SQLSTMT;
EXEC SQL DESCRIBE INPUT SQLOBJ INTO :INSQLDA;
SQLDATA(1)=ADDR(HVEMP);
/* Get input data address
SQLIND(1)=ADDR(HVEMPIND);
/* Get indicator address
EXEC SQL EXECUTE SQLOBJ USING DESCRIPTOR :INSQLDA;

*/
*/
*/
*/
*/
*/

*/
*/

Chapter 3. Including DB2 queries in an application program

139
Declaring host variables, host variable arrays, and host structures
You can use host variables, host variable arrays, and host structures in SQL
statements in your program to pass data between DB2 and your application.
Restriction: You do not declare host variables in REXX.
To declare host variables, host variable arrays, and host structures:
1. For all languages except REXX, consider the following general rules and
restrictions:
v If you specify the ONEPASS precompiler option, you must explicitly declare
each host variable and each host variable array before using them in an SQL
statement. If you specify the TWOPASS precompiler option, you must
declare each host variable before using it in the DECLARE CURSOR
statement.
Restriction: The DB2 coprocessor for C/C++ supports only the ONEPASS
option.
Restriction: For Fortran, you cannot implicitly declare any host variables
through default typing or by using the IMPLICIT statement.
v If you specify the STDSQL(YES) precompiler option, you must precede the
host language statements that define the host variables and host variable
arrays with the BEGIN DECLARE SECTION statement, and follow the host
language statements with the END DECLARE SECTION statement.
Otherwise, these statements are optional.
v Precede all host variables and all host variable arrays in an SQL statement
with a colon (:).
Restriction: In PL/I, if the SQL statement meets any of the following
conditions, do not precede a host variable or host variable array in that
statement with a colon:
– The SQL statement is an EXECUTE IMMEDIATE or PREPARE statement.
– The SQL statement is in a program that also contains a DECLARE
VARIABLE statement.
– The host variable is part of a string expression, but the host variable is not
the only component of the string expression.
v Ensure that any SQL statement that uses a host variable or host variable
array is within the scope of the statement that declares that variable or array.
v If you are using the DB2 precompiler, ensure that the names of host variables
and host variable arrays are unique within the program, even if the variables
and variable arrays are in different blocks, classes, procedures, functions, or
subroutines. You can qualify the names with a structure name to make them
unique.

|
|
|
|
|

140

Application Programming and SQL Guide
2. Consider the following language-specific rules and guidelines:
Table 43. Language-specific rules and guidelines for host variables, host variable arrays, and
host structures
Language

Rules and guidelines

Assembler

You can declare host variables in normal
assembler style (DC or DS), depending on
the data type and the limitations on that data
type. You can specify a value on DC or DS
declarations (for example, DC H’5’). The DB2
precompiler examines only packed decimal
declarations.

C/C++

v You can have more than one host variable
declaration section in your program.
v When you code SQL statements in a C++
program, you can use class members as
host variables. Class members that are
used as host variables are accessible to any
SQL statement within the class. However,
you cannot use class objects as host
variables.

COBOL

v You must explicitly declare all host
variables and host variable arrays that are
used in SQL statements in the
WORKING-STORAGE SECTION or
LINKAGE SECTION of your program’s
DATA DIVISION. You must explicitly
declare each host variable and host
variable array before using them in an
SQL statement.
v

Fortran

You can specify OCCURS when defining
an indicator structure, a host variable
array, or an indicator variable array. You
cannot specify OCCURS for any other type
of host variable.

v When you declare a character host
variable, do not use an expression to
define the length of the character variable.
You can use a character host variable with
an undefined length (for example,
CHARACTER *(*)). The length of any such
variable is determined when the associated
SQL statement executes.
v Host variables must be scalar variables;
they cannot be elements of vectors or
arrays (subscripted variables).
v Be careful when calling subroutines that
might change the attributes of a host
variable. Such alteration can cause an error
while the program is running.

Chapter 3. Including DB2 queries in an application program

141
Table 43. Language-specific rules and guidelines for host variables, host variable arrays, and
host structures (continued)
Language

Rules and guidelines

REXX

v You do not declare host variables in REXX.
When you need a new variable, you use it
in a REXX command. When you use a
REXX variable as a host variable in an
SQL statement, you must precede the
variable with a colon.
v A REXX host variable can be a simple or
compound variable. DB2 REXX Language
Support evaluates compound variables
before DB2 processes SQL statements that
contain the variables. In the following
example, the host variable that is passed to
DB2 is :x.1.2:
a=1
b=2
EXECSQL ’OPEN C1 USING :x.a.b’

Related reference
“Descriptions of SQL processing options” on page 854

Host variables, host variable arrays, and host structures
A host variable is a single data item. A host variable array is a data array. A host
structure is a group of host variables that can be referenced with a single name.
Ahost variable is a single data item that is declared in the host language to be used
within an SQL statement. You can use host variables to perform the following
actions:
v Retrieve data into the host variable for your application program’s use
v Place data into the host variable to insert into a table or to change the contents
of a row
v Use the data in the host variable when evaluating a WHERE or HAVING clause
v Assign the value that is in the host variable to a special register, such as
CURRENT SQLID and CURRENT DEGREE
v Insert null values into columns by using a host indicator variable that contains a
negative value
v Use the data in the host variable in statements that process dynamic SQL, such
as EXECUTE, PREPARE, and OPEN
|
|
|
|
|

A host variable array is a data array that is declared in the host language to be used
within an SQL statement. You can use host variable arrays to perform the
following actions:
v Retrieve data into host variable arrays for your application program’s use
v Place data into host variable arrays to insert rows into a table

|
|

You typically define host variable arrays for use with multiple-row FETCH,
INSERT, and MERGE statements.
A host structure is a group of host variables that can be referenced with a single
name. You can use host structures in all host languages except REXX. Host

142

Application Programming and SQL Guide
structures are defined by statements of the host language. You can refer to a host
structure in any context where you would refer to the list of host variables in the
structure. A host structure reference is equivalent to a reference to each of the host
variables within the structure in the order in which they are defined in the
structure declaration.

Host variables in an SQL statement
Use host variables in embedded SQL statements to represent a single value that the
program does not know until the program runs. Host variables are useful for
storing retrieved data or for passing values that are to be assigned or used for
comparisons.
To use a host variable in an SQL statement, you can specify any valid host variable
name that is declared according to the rules of the host language. You must declare
the name of the host variable in the host program before you use it.
To optimize performance, make sure that the host language declaration maps as
closely as possible to the data type of the associated data in the database.
You can use a host variable to represent a data value, but you cannot use it to
represent a table, view, or column name. (You can specify table, view, or column
names at run time using dynamic SQL. See “Dynamic SQL” on page 258 for more
information.)
Host variables follow the naming conventions of the host language. A colon (:)
must precede host variables that are used in SQL statements so DB2 can
distinguish a variable name from a column name. A colon must not precede host
variables outside of SQL statements.
Assignments and comparisons using different data types: For assignments and
comparisons involving a DB2 column and a host variable of a different data type
or length, you can expect conversions to occur. For more information about the
rules that are used when you assign retrieved data to a host variable or compare
retrieved data to a value in a host variable, see “Assignment and comparison”
inDB2 SQL Reference.

Retrieving a single row of data in host variables
If you know that your query returns only one row, you can specify one or more
host variables to contain the column values.
You can use one or more host variables to specify a program data area that is to
contain the column values of a retrieved row. The INTO clause of the SELECT
statement names one or more host variables to contain the retrieved column
values. The named variables correspond one-to-one with the list of column names
in the SELECT statement.
If you do not know how many rows DB2 will return, or if you expect more than
one row to return, you must use an alternative to the SELECT ... INTO statement.
The DB2 cursor enables an application to return a set of rows and fetch either one
row at a time or one rowset at a time from the result table. For information about
using cursors, see “Retrieving a set of rows by using a cursor” on page 626.
Example: Retrieving a single row: Suppose you are retrieving the LASTNAME and
WORKDEPT column values from the DSN8910.EMP table for a particular

Chapter 3. Including DB2 queries in an application program

143
employee. You can define a host variable in your program to hold each column
and then name the host variables with an INTO clause, as in the following COBOL
example:
MOVE ’000110’ TO CBLEMPNO.
EXEC SQL
SELECT LASTNAME, WORKDEPT
INTO :CBLNAME, :CBLDEPT
FROM DSN8910.EMP
WHERE EMPNO = :CBLEMPNO
END-EXEC.

Note that the host variable CBLEMPNO is preceded by a colon (:) in the SQL
statement, but it is not preceded by a colon in the COBOL MOVE statement. In the
DATA DIVISION section of a COBOL program, you must declare the host
variables CBLEMPNO, CBLNAME, and CBLDEPT to be compatible with the data
types in the columns EMPNO, LASTNAME, and WORKDEPT of the
DSN8910.EMP table.
You can use a host variable to specify a value in a search condition. For this
example, you have defined a host variable CBLEMPNO for the employee number,
so that you can retrieve the name and the work department of the employee
whose number is the same as the value of the host variable, CBLEMPNO; in this
case, 000110.
If the SELECT ... INTO statement returns more than one row, an error occurs, and
any data that is returned is undefined and unpredictable.
To prevent undefined and unpredictable data from being returned, you can use the
FETCH FIRST 1 ROW ONLY clause to ensure that only one row is returned. For
example:
EXEC SQL
SELECT LASTNAME, WORKDEPT
INTO :CBLNAME, :CBLDEPT
FROM DSN8910.EMP
FETCH FIRST 1 ROW ONLY
END-EXEC.

You can include an ORDER BY clause in the preceding example. This gives your
application some control over which row is returned when you use a FETCH
FIRST 1 ROW ONLY clause in a SELECT INTO statement.
EXEC SQL
SELECT LASTNAME, WORKDEPT
INTO :CBLNAME, :CBLDEPT
FROM DSN8810.EMP
ORDER BY LASTNAME
FETCH FIRST 1 ROW ONLY
END-EXEC.

When you specify both the ORDER BY clause and the FETCH FIRST clause,
ordering is done first and then the first row is returned. This means that the
ORDER BY clause determines which row is returned. If you specify both the
ORDER BY clause and the FETCH FIRST clause, ordering is performed on the
entire result set before the first row is returned.
Example: Specifying expressions in the SELECT clause: When you specify a list of
items in the SELECT clause, you can use more than the column names of tables
and views. You can request a set of column values mixed with host variable values
and constants. For example:

144

Application Programming and SQL Guide
MOVE 4476 TO RAISE.
MOVE ’000220’ TO PERSON.
EXEC SQL
SELECT EMPNO, LASTNAME, SALARY, :RAISE, SALARY + :RAISE
INTO :EMP-NUM, :PERSON-NAME, :EMP-SAL, :EMP-RAISE, :EMP-TTL
FROM DSN8910.EMP
WHERE EMPNO = :PERSON
END-EXEC.

The following results have column headings that represent the names of the host
variables:
EMP-NUM
=======
000220

PERSON-NAME
===========
LUTZ

EMP-SAL
=======
29840

EMP-RAISE
=========
4476

EMP-TTL
=======
34316

Example: Specifying summary values in the SELECT clause: You can request
summary values to be returned from aggregate functions. For example:
MOVE ’D11’ TO DEPTID.
EXEC SQL
SELECT WORKDEPT, AVG(SALARY)
INTO :WORK-DEPT, :AVG-SALARY
FROM DSN8910.EMP
WHERE WORKDEPT = :DEPTID
END-EXEC.

Updating data by using host variables
When you want to update a value in a DB2 table, but you do not know the exact
value until the program runs, use host variables in your SQL statement. DB2 can
change a table value to match the current value of the host variable.
To do this, use the host variable name in the SET clause of the UPDATE statement.
Example: Updating a single row: The following example changes an employee’s
phone number:
MOVE ’4246’ TO NEWPHONE.
MOVE ’000110’ TO EMPID.
EXEC SQL
UPDATE DSN8910.EMP
SET PHONENO = :NEWPHONE
WHERE EMPNO = :EMPID
END-EXEC.

Example: Updating multiple rows: The following example gives the employees in a
particular department a salary increase of 10%:
MOVE ’D11’ TO DEPTID.
EXEC SQL
UPDATE DSN8910.EMP
SET SALARY = 1.10 * SALARY
WHERE WORKDEPT = :DEPTID
END-EXEC.

Inserting data by using column values that use host variables
When you want to insert data into a DB2 table, but you do not know at least some
of the values to insert until the program runs, use host variables in your INSERT
statement.
You can insert a single row of data into a DB2 table by using the INSERT
statement with column values in the VALUES clause. A column value can be a host
variable, a constant, or any valid combination of host variables and constants.

Chapter 3. Including DB2 queries in an application program

145
To insert multiple rows, you can use the form of the INSERT statement that selects
values from another table or view. You can also use a form of the INSERT
statement that inserts multiple rows from values that are provided in host variable
arrays. For more information, see “Inserting multiple rows of data from host
variable arrays” on page 182.
Example: The following example inserts a single row into the activity table:
EXEC SQL
INSERT INTO DSN8910.ACT
VALUES (:HV-ACTNO, :HV-ACTKWD, :HV-ACTDESC)
END-EXEC.

Changing the coded character set ID of host variables
All DB2 string data, other than binary data, has an encoding scheme and a coded
character set ID (CCSID) associated with it. You can associate an encoding scheme
and a CCSID with individual host variables. Any data in those host variable is
then associated with that encoding scheme and CCSID.
You can use the DECLARE VARIABLE statement to associate an encoding scheme
and a CCSID with individual host variables. The DECLARE VARIABLE statement
has the following effects on a host variable:
v When you use the host variable to update a table, the local subsystem or the
remote server assumes that the data in the host variable is encoded with the
CCSID and encoding scheme that the DECLARE VARIABLE statement assigns.
v When you retrieve data from a local or remote table into the host variable, the
retrieved data is converted to the CCSID and encoding scheme that are assigned
by the DECLARE VARIABLE statement.
You can use the DECLARE VARIABLE statement in static or dynamic SQL
applications. However, you cannot use the DECLARE VARIABLE statement to
control the CCSID and encoding scheme of data that you retrieve or update using
an SQLDA.
When you use a DECLARE VARIABLE statement in a program, put the DECLARE
VARIABLE statement after the corresponding host variable declaration and before
your first reference to that host variable.
Example: Using a DECLARE VARIABLE statement to change the encoding scheme
of retrieved data: Suppose that you are writing a C program that runs on a DB2
for z/OS subsystem. The subsystem has an EBCDIC application encoding scheme.
The C program retrieves data from the following columns of a local table that is
defined with CCSID UNICODE.
PARTNUM CHAR(10)
JPNNAME GRAPHIC(10)
ENGNAME VARCHAR(30)

Because the application encoding scheme for the subsystem is EBCDIC, the
retrieved data is EBCDIC. To make the retrieved data Unicode, use DECLARE
VARIABLE statements to specify that the data that is retrieved from these columns
is encoded in the default Unicode CCSIDs for the subsystem. Suppose that you
want to retrieve the character data in Unicode CCSID 1208 and the graphic data in
Unicode CCSID 1200. Use DECLARE VARIABLE statements like these:
EXEC SQL BEGIN DECLARE SECTION;
char hvpartnum[11];
EXEC SQL DECLARE :hvpartnum VARIABLE CCSID 1208;
sqldbchar hvjpnname[11];
EXEC SQL DECLARE :hvjpnname VARIABLE CCSID 1200;

146

Application Programming and SQL Guide
struct {
short len;
char d[30];
} hvengname;
EXEC SQL DECLARE :hvengname VARIABLE CCSID 1208;
EXEC SQL END DECLARE SECTION;

The BEGIN DECLARE SECTION and END DECLARE SECTION statements mark
the beginning and end of a host variable declare section.

Ensuring that DB2 correctly interprets character input data in
REXX programs
DB2 REXX Language Support can incorrectly interpret character literals as graphic
or numeric literals unless you mark them correctly.
To ensure that DB2 REXX Language Support does not interpret character literals as
graphic or numeric literals, precede and follow character literals with a double
quotation mark, followed by a single quotation mark, followed by another double
quotation mark ("’").
Enclosing the string in apostrophes is not adequate because REXX removes the
apostrophes when it assigns a literal to a variable. For example, suppose that you
want to pass the value in host variable stringvar to DB2. The value that you want
to pass is the string ’100’. The first thing that you need to do is to assign the string
to the host variable. You might write a REXX command like this:
stringvar = ’100’

After the command executes, stringvar contains the characters 100 (without the
apostrophes). DB2 REXX Language Support then passes the numeric value 100 to
DB2, which is not what you intended.
However, suppose that you write the command like this:
stringvar = "’"100"’"

In this case, REXX assigns the string ’100’ to stringvar, including the single
quotation marks. DB2 REXX Language Support then passes the string ’100’ to DB2,
which is the desired result.

Passing the data type of an input data type to DB2 for REXX
programs
In certain situations, you want to tell DB2 the data type to use for input data in a
REXX program. For example, if you are assigning or comparing input data to
columns of type SMALLINT, CHAR, or GRAPHIC, you should tell DB2 to use
those data types.
DB2 does not assign data types of SMALLINT, CHAR, or GRAPHIC to input data.
If you assign or compare this data to columns of type SMALLINT, CHAR, or
GRAPHIC, DB2 must do more work than if the data types of the input data and
columns match.
To indicate the data type of input data to DB2, use an SQLDA.
Example: Specifying CHAR: Suppose you want to tell DB2 that the data with
which you update the MIDINIT column of the EMP table is of type CHAR, rather
than VARCHAR. You need to set up an SQLDA that contains a description of a
CHAR column, and then prepare and execute the UPDATE statement using that
SQLDA:
Chapter 3. Including DB2 queries in an application program

147
INSQLDA.SQLD = 1
INSQLDA.1.SQLTYPE = 453

/*
/*
/*
/*
/*
/*

SQLDA contains one variable
Type of the variable is CHAR,
and the value can be null
Length of the variable is 1
Value in variable is H
Input variable is not null

INSQLDA.1.SQLLEN = 1
INSQLDA.1.SQLDATA = ’H’
INSQLDA.1.SQLIND = 0
SQLSTMT="UPDATE EMP" ,
"SET MIDINIT = ?" ,
"WHERE EMPNO = ’000200’"
"EXECSQL PREPARE S100 FROM :SQLSTMT"
"EXECSQL EXECUTE S100 USING DESCRIPTOR :INSQLDA"

*/
*/
*/
*/
*/
*/

Example: Specifying DECIMAL with precision and scale: Suppose you want to tell
DB2 that the data is of type DECIMAL with precision and nonzero scale. You need
to set up an SQLDA that contains a description of a DECIMAL column:
INSQLDA.SQLD = 1
INSQLDA.1.SQLTYPE = 484
INSQLDA.1.SQLLEN.SQLPRECISION = 18
INSQLDA.1.SQLLEN.SQLSCALE = 8
INSQLDA.1.SQLDATA = 9876543210.87654321

/*
/*
/*
/*
/*

SQLDA contains one variable
Type of variable is DECIMAL
Precision of variable is 18
Scale of variable is 8
Value in variable

*/
*/
*/
*/
*/

Assembler syntax for host variable declarations
In assembler programs, you can specify numeric, character, graphic, binary, LOB,
XML, and ROWID host variables. You can also specify result set, table, and LOB
locators and LOB and XML file reference variables.
Only some of the valid assembler declarations are valid host variable declarations.
If the declaration for a host variable is not valid, any SQL statement that references
the variable might result in the message UNDECLARED HOST VARIABLE.
Numeric host variables: The following diagram shows the syntax for declarations
of numeric host variables. The numeric value specifies the scale of the packed
decimal variable. If value does not include a decimal point, the scale is 0.

148

Application Programming and SQL Guide
|

variable-name

DC
DS

H
1

L2
F
L4
FD
L8
’value’

P
Ln
E
L4
EH
L4
EB
L4
ED
L4
D
L8
DH
L8
DB
L8
DD
L8
LD
L16

For floating-point data types (E, EH, EB, D, DH, and DB), DB2 uses the FLOAT
precompiler option to determine whether the host variable is in IEEE binary
floating-point or z/Architecture® hexadecimal floating-point format. If the
precompiler option is FLOAT(S390), you need to define your floating-point host
variables as E, EH, D, or DH. If the precompiler option is FLOAT(IEEE), you need
to define your floating-point host variables as EB or DB. DB2 converts all
floating-point input data to z/Architecture hexadecimal floating-point format
before storing it. For more information about z/Architecture hexadecimal
floating-point format, see z/Architecture Principles of Operation.
|
|

The FLOAT precompiler options do not apply to the decimal floating-point host
variable types ED, DD, or LD.
For the decimal floating-point host variable types ED, DD, LD, you can specify the
following special values: MIN, MAX, NAN, SNAN, and INFINITY. For
descriptions of these special values, see High Level Assembler for MVS and VM and
VSE Language Reference at http://www.ibm.com/software/awdtools/hlasm/
library.html.
Character host variables: The three valid forms for character host variables are:
v Fixed-length strings
v Varying-length strings
v CLOBs
The following figures show the syntax for forms other than CLOBs.
The following diagram shows the syntax for declarations of fixed-length character
strings.

Chapter 3. Including DB2 queries in an application program

149
variable-name

DC
DS

C
1

Ln

The following diagram shows the syntax for declarations of varying-length
character strings.
variable-name

DC
DS

H
1

,

CLn

L2

1

Graphic host variables: The three valid forms for graphic host variables are:
v Fixed-length strings
v Varying-length strings
v DBCLOBs
The following figures show the syntax for forms other than DBCLOBs. In the
syntax diagrams, value denotes one or more DBCS characters, and the symbols <
and > represent shift-out and shift-in characters.
The following diagram shows the syntax for declarations of fixed-length graphic
strings.
variable-name

DC
DS

G
Ln
’<value>’
Ln’<value>’

The following diagram shows the syntax for declarations of varying-length graphic
strings.
variable-name

DS
DC

H

,
L2

’m’

GLn
’<value>’

Binary host variables: The following diagram shows the syntax for declarations of
binary host variables.
(1)
variable-name DS X

Ln

Notes:
1

1 ≤ n ≤255

Varbinary host variables: The following diagram shows the syntax for declarations
of varbinary host variables.
(1)
variable-name DS H

Notes:
1

150

1 ≤ n ≤ 32704

Application Programming and SQL Guide

L2 , X Ln
Result set locators: The following diagram shows the syntax for declarations of
result set locators.
variable-name

DC
DS

F
1

L4

Table Locators: The following diagram shows the syntax for declarations of table
locators. See “Accessing transition tables in a user-defined function or stored
procedure” on page 473 for a discussion of how to use these host variables.
variable-name SQL TYPE IS TABLE LIKE table-name AS LOCATOR

|
|
|
|

LOB variables, locators, and file reference variables: The following diagram shows
the syntax for declarations of BLOB, CLOB, and DBCLOB host variables, locators,
and file reference variables. See “Large objects (LOBs)” on page 390 for a
discussion of how to use LOB host variables.
variable-name SQL TYPE IS

|
|
|
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

length
K
M
G

XML data host and file reference variablesThe following diagram shows the
syntax for declarations of BLOB, CLOB, and DBCLOB host variables, and file
reference variables, for XML data types.
variable-name SQL TYPE IS XML AS

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

length
K
M
G

|
|

If you specify the length of the LOB in terms of KB, MB, or GB, you must leave no
spaces between the length and K, M, or G.
ROWIDs: The following diagram shows the syntax for declarations of ROWID
host variables. See “Large objects (LOBs)” on page 390 for a discussion of how to
use these host variables.
variable-name SQL TYPE IS ROWID

Chapter 3. Including DB2 queries in an application program

151
Notes on assembler variable declaration and usage
You should be aware of the following considerations when you declare assembler
variables.
Host graphic data type: You can use the assembler data type “host graphic” in
SQL statements when the precompiler option GRAPHIC is in effect. However, you
cannot use assembler DBCS literals in SQL statements, even when GRAPHIC is in
effect.
Character host variables: If you declare a host variable as a character string
without a length, for example DC C ’ABCD’, DB2 interprets it as length 1. To get
the correct length, give a length attribute (for example, DC CL4’ABCD’).
Floating-point host variables: All floating-point data is stored in DB2 in
z/Architecture hexadecimal floating-point format. However, your host variable
data can be in z/Architecture hexadecimal floating-point format or IEEE binary
floating-point format. DB2 uses the FLOAT precompiler option to determine
whether your floating-point host variables are in IEEE binary floating-point format
or z/Architecture hexadecimal floating-point format. DB2 does no checking to
determine whether the host variable declarations or format of the host variable
contents match the precompiler option. Therefore, you need to ensure that your
floating-point host variable types and contents match the precompiler option.
Special purpose assembler data types: The locator data types are assembler
language data types and SQL data types. You cannot use locators as column types.
For information about how to use these data types, see the following topics:
Table locator
“Accessing transition tables in a user-defined function or stored procedure”
on page 473
LOB locators
“Large objects (LOBs)” on page 390
LOB file reference variables
“Large objects (LOBs)” on page 390
Overflow: Be careful of overflow. For example, suppose you retrieve an INTEGER
column value into a DS H host variable, and the column value is larger than 32767.
You get an overflow warning or an error, depending on whether you provided an
indicator variable.
Truncation: Be careful of truncation. For example, if you retrieve an 80-character
CHAR column value into a host variable declared as DS CL70, the rightmost ten
characters of the retrieved string are truncated. If you retrieve a floating-point or
decimal column value into a host variable declared as DS F, it removes any
fractional part of the value.

C and C++ syntax for host variable declarations
In C and C++ programs, you can specify numeric, character, graphic, binary, LOB,
XML, and ROWID host variables. You can also specify result set, table, and LOB
locators and LOB and XML file reference variables.
Only some of the valid C declarations are valid host variable declarations. If the
declaration for a variable is not valid, any SQL statement that references the
variable might result in the message UNDECLARED HOST VARIABLE.

152

Application Programming and SQL Guide
Numeric host variables in C or C++
The following diagram shows the syntax for declarations of numeric host variables.
|
auto
extern
static

const
volatile

float
double
int
short
sqlint32
int
long
int
long long
decimal ( precision

)
, scale

,
variable-name
*pointer-name

;
=expression

Notes:
1. The DB2 coprocessor is required if you use the pointer notation of the host
variable.

Character host variables in C or C++
The four valid forms for character host variables are:
v Single-character form
v NUL-terminated character form
v VARCHAR structured form
v CLOBs
The following diagrams show the syntax for forms other than CLOBs.
The following diagram shows the syntax for declarations of single-character host
variables.
,
char
auto
extern
static

const
volatile

unsigned

variable-name
*pointer-name

;
=expression

Notes:
1. The DB2 coprocessor is required if you use the pointer notation of the host
variable.
The following diagram shows the syntax for declarations of NUL-terminated
character host variables.

Chapter 3. Including DB2 queries in an application program

153
char
auto
extern
static

const
volatile

unsigned

,
variable-name
*pointer-name

[

length ]

;
=expression

Notes:
1. On input, the string contained by the variable must be NUL-terminated.
2. On output, the string is NUL-terminated.
3. A NUL-terminated character host variable maps to a varying-length character
string (except for the NUL).
4. The DB2 coprocessor is required if you use the pointer notation of the host
variable.
The following diagram shows the syntax for declarations of varying-length
character host variables that use the VARCHAR structured form.
int
struct
auto
extern
static

const
volatile

{

short

var-1

;

tag

char var-2 [ length ]

;

}

unsigned

,
variable-name
*pointer-name

;
={expression, expression}

Notes:
1. You cannot use var-1 and var-2 as host variables in an SQL statement.
2. You can use the struct tag to define other variables, but you cannot use them as
host variables in SQL.
3. The DB2 coprocessor is required if you use the pointer notation of the host
variable.
Example: The following examples show valid and invalid declarations of the
VARCHAR structured form:
EXEC SQL BEGIN DECLARE SECTION;
/* valid declaration of host variable VARCHAR vstring */
struct VARCHAR {
short len;
char s[10];

154

Application Programming and SQL Guide
} vstring;
/* invalid declaration of host variable VARCHAR wstring */
struct VARCHAR wstring;

Graphic host variables in C or C++
The four valid forms for graphic host variables are:
v Single-graphic form
v NUL-terminated graphic form
v VARGRAPHIC structured form.
v DBCLOBs
Recommendation: Instead of using the C data type wchar_t to define graphic and
vargraphic host variables, use one of the following techniques:
v Define the sqldbchar data type by using the following typedef statement:
typedef unsigned short sqldbchar;

v Use the sqldbchar data type that is defined in the typedef statement in the
header files that are supplied by DB2.
v Use the C data type unsigned short.
The following diagrams show the syntax for forms other than DBCLOBs.
The following diagram shows the syntax for declarations of single-graphic host
variables.
,
sqldbchar
auto
extern
static

const
volatile

variable-name
*pointer-name

;
=expression

The single-graphic form declares a fixed-length graphic string of length 1. You
cannot use array notation in variable-name.
The following diagram shows the syntax for declarations of NUL-terminated
graphic host variables.
,
sqldbchar
auto
extern
static

const
volatile

variable-name
*pointer-name

[ length ]

;
=expression

Notes:
1. length must be a decimal integer constant greater than 1 and not greater than
16352.
2. On input, the string in variable-name must be NUL-terminated.
3. On output, the string is NUL-terminated.
4. The NUL-terminated graphic form does not accept single-byte characters into
variable-name.
5. The DB2 coprocessor is required if you use the pointer notation of the host
variable.

Chapter 3. Including DB2 queries in an application program

155
The following diagram shows the syntax for declarations of graphic host variables
that use the VARGRAPHIC structured form.
int
struct
auto
extern
static

const
volatile

sqldbchar var-2 [ length ]

{

short

var-1

;

tag

;

}

,
variable-name
*pointer-name

;
={ expression, expression}

Notes:
1. length must be a decimal integer constant greater than 1 and not greater than
16352.
2. var-1 must be less than or equal to length.
3. You cannot use var-1 and var-2 as host variables in an SQL statement.
4. You can use the struct tag to define other variables, but you cannot use them as
host variables in SQL.
5. The DB2 coprocessor is required if you use the pointer notation of the host
variable.
Example: The following examples show valid and invalid declarations of graphic
host variables that use the VARGRAPHIC structured form:
EXEC SQL BEGIN DECLARE SECTION;
/* valid declaration of host variable structured vgraph */
struct VARGRAPH {
short len;
sqldbchar d[10];
} vgraph;
/* invalid declaration of host variable structured wgraph */
struct VARGRAPH wgraph;

Binary host variables in C or C++
|
|
|
|

The three valid forms of BINARY host variables are:
v Fixed-length strings
v Varying-length strings
v BLOBs

|
|

The following diagram shows the syntax for declarations of BINARY host
variables. The following diagrams show the syntax for forms other than BLOBs.

156

Application Programming and SQL Guide
|

,
SQL TYPE IS BINARY ( length )
auto
extern
static

variable-name

;

const
volatile

|
|
|

Notes:
1. For BINARY host variables, the length must be in the range from 1 to 255.

|
|

The following diagram shows the syntax for declarations of VARBINARY host
variables.

|
|

SQL TYPE IS
auto
extern
static

|
|

const
volatile

(1)
VARBINARY
BINARY VARYING

( length )

,
variable-name

;
= { init-len , ″

init-data ″

}

|
|

Notes:

|
|

1

|

The C language does not have variables that correspond to the SQL binary data
types BINARY and VARBINARY. To create host variables that can be used with
these data types, use the SQL TYPE IS clause. The SQL precompiler replaces this
declaration with the C language structure in the output source member.

|
|
|
|

When you refer to a BINARY or VARBINARY host variable in an SQL statement,
you must use the variable that you specify in the SQL TYPE declaration. When
you refer to the host variable in a host language statement, you must use the
variable that DB2 generates.

|
|

Example: The following table shows examples of variables that DB2 generates
when you declare binary host variables.

|

Table 44. Examples of BINARY and VARBINARY variable declarations for C

|

You declare this variable

DB2 generates this variable

|

SQL TYPE IS BINARY(10) bin_var;

char bin_var[10]

|
|
|
|
|

SQL TYPE IS VARBINARY(10) vbin_var;

struct {
short length;
char data[10];
} vbin_var;

|
|
|
|
|

Important: Be careful when you use binary host variables with C and C++. The
SQL TYPE declaration for BINARY and VARBINARY does not account for the
NUL-terminator that C expects because binary strings are not NUL-terminated
strings. Furthermore, the binary host variable might contain zeroes at any point in
the string.

For VARBINARY host variables, the length must be in the range from 1 to
32 704.

Chapter 3. Including DB2 queries in an application program

157
Result set locators in C or C++
The following diagram shows the syntax for declarations of result set locators.
SQL TYPE IS RESULT_SET_LOCATOR VARYING
auto
extern
static
register

const
volatile

,
variable-name
*pointer-name

;
= init-value

Table locators in C or C++
The following diagram shows the syntax for declarations of table locators. See
“Accessing transition tables in a user-defined function or stored procedure” on
page 473 for a discussion of how to use these host variables.

auto
extern
static
register

const
volatile

SQL TYPE IS TABLE LIKE table-name AS LOCATOR

,
variable-name
*pointer-name

;
=init-value

LOB variables and locators in C or C++
The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variables and locators. See “Large objects (LOBs)” on page 390 for a
discussion of how to use these host variables.
SQL TYPE IS
auto
extern
static
register

158

Application Programming and SQL Guide

const
volatile
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

( length

)
K
M
G

,
variable-name
*pointer-name

;
(1)
=init-value

Notes:
|
|
|
|

1

Specify the initial value as a series of expressions. For example, specify
={expression, expression}. For BLOB_FILE, CLOB_FILE, and
DBCLOB_FILE, specify ={name_length, data_length, file_option_map,
file_name}.

XML data host and file reference variables in C or C++
|
|

The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variables, and file reference variables, for XML data types.
For examples of how to use XML host variables, see “XML column updates in
embedded SQL applications” on page 324 and “XML data retrieval in embedded
SQL applications” on page 327.

|

SQL TYPE IS
auto
extern
static
register

XML
XML
XML
XML
XML
XML

const
volatile

AS
AS
AS
AS
AS
AS

BLOB
CLOB
DBCLOB
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

,
(1)
variable-name
*pointer-name

;
=init-value

Notes:
|
|
|
|

1

Specify the initial value as a series of expressions. For example, specify
={expression, expression}. For BLOB_FILE, CLOB_FILE, and
DBCLOB_FILE, specify ={name_length, data_length, file_option_map,
file_name}.

Chapter 3. Including DB2 queries in an application program

159
ROWIDs in C or C++
The following diagram shows the syntax for declarations of ROWID host variables.
See “Large objects (LOBs)” on page 390 for a discussion of how to use these host
variables.

auto
extern
static
register

const
volatile

variable-name
*pointer-name

SQL TYPE IS ROWID ;

Notes on C variable declaration and usage
You should be aware of the following considerations when you declare C variables.
C data types with no SQL equivalent: C supports some data types and storage
classes with no SQL equivalents, for example, register storage class, typedef, and
long long,.
SQL data types with no C equivalent: If your C compiler does not have a decimal
data type, no exact equivalent exists for the SQL DECIMAL data type. In this case,
to hold the value of such a variable, you can use:
v An integer or floating-point variable, which converts the value. If you choose
integer, you will lose the fractional part of the number. If the decimal number
can exceed the maximum value for an integer, or if you want to preserve a
fractional value, you can use floating-point numbers. Floating-point numbers are
approximations of real numbers. Therefore, when you assign a decimal number
to a floating-point variable, the result might be different from the original
number.
v A character-string host variable. Use the CHAR function to get a string
representation of a decimal number.
v The DECIMAL function to explicitly convert a value to a decimal data type, as
in this example:
long duration=10100;
char result_dt[11];

/* 1 year and 1 month */

EXEC SQL SELECT START_DATE + DECIMAL(:duration,8,0)
INTO :result_dt FROM TABLE1;

The SQL data type DECFLOAT also has no equivalent in C.

|

Floating-point host variables: All floating-point data is stored in DB2 in
z/Architecture hexadecimal floating-point format. However, your host variable
data can be in z/Architecture hexadecimal floating-point format or IEEE binary
floating-point format. DB2 uses the FLOAT precompiler option to determine
whether your floating-point host variables are in IEEE binary floating-point or
z/Architecture hexadecimal floating-point format. DB2 does no checking to
determine whether the contents of a host variable match the precompiler option.
Therefore, you need to ensure that your floating-point data format matches the
precompiler option.
Graphic host variables: You can define graphic host variables by using one of the
following techniques:
v Define the sqldbchar data type by using the following typedef statement:

|
|
|

160

Application Programming and SQL Guide
|
|
|
|
|
|
|
|
|
|

typedef unsigned short sqldbchar;

Use sqldbchar instead of wchar_t. Using sqldbchar or unsigned short lets you
manipulate DBCS and Unicode UTF-16 data in the same format in which it is
stored in DB2. Using sqldbchar also makes applications easier to port to other
DB2 platforms.
v Use the C data type unsigned short.
v Use the typedef statements in one of the following files or libraries:
1. SQL library, sql.h
2. DB2 CLI library, sqlcli.h
3. SQLUDF file in data set DSN910.SDSNC.H

|

Special locator C data types: The following locator data types are special SQL data
types that do not have C equivalents:
v Result set locator
v Table locator
v LOB locators

|

You cannot use them to define column types.

|
|
|
|

String host variables: For NUL-terminated string host variables, use the SQL
processing options PADNTSTR and NOPADNTSTR to specify whether the variable
should be padded with blanks. For a description of these options, see Table 148 on
page 854. The option that you specify determines where the NUL-terminator is
placed.
If you assign a string of length n to a NUL-terminated string host variable, the
variable has one of the values that is shown in the following table.
Table 45. Value of a NUL-terminated string host variable that is assigned a string of length n
If the length of the NUL-terminated string
host variable is...
Less than or equal to n

The variable is set to...
The source string up to a length of n-1 and a
NUL at the end of the string. 1
DB2 sets SQLWARN[1] to W and any
indicator variable that you provide to the
original length of the source string.

Equal to n+1

The source string and a NUL at the end of
the string. 1

Greater than n+1 and the source is a
fixed-length string

If PADNTSTR is in effect
The source string, blanks to pad the
value, and a NUL at the end of the
string.
If NOPADNTSTR is in effect
The source string and a NUL at the end
of the string.

Greater than n+1 and the source is a
varying-length string

The source string and a NUL at the end of
the string. 1

Note:
1. In these cases, whether NOPADNTSTR or PADNTSTR is in effect is irrelevant.

Chapter 3. Including DB2 queries in an application program

161
PREPARE or DESCRIBE statements: You cannot use a host variable that is of the
NUL-terminated form in either a PREPARE or DESCRIBE statement when you use
the DB2 precompiler. However, if you use the DB2 coprocessor for either C or C++,
you can use host variables of the NUL-terminated form in PREPARE, DESCRIBE,
and EXECUTE IMMEDIATE statements.
L-literals: DB2 tolerates L-literals in C application programs. DB2 allows properly
formed L-literals, although it does not check for all the restrictions that the C
compiler imposes on the L-literal. You can use DB2 graphic string constants in SQL
statements to work with the L-literal. Do not use L-literals in SQL statements.
Overflow: Be careful of overflow. For example, suppose you retrieve an INTEGER
column value into a short integer host variable and the column value is larger than
32767. You get an overflow warning or an error, depending on whether you
provide an indicator variable.
Truncation: Be careful of truncation. Ensure that the host variable you declare can
contain the data and a NUL terminator, if needed. Retrieving a floating-point or
decimal column value into a long integer host variable removes any fractional part
of the value.

Notes on syntax differences for constants in C or C++
You should be aware of the following syntax differences for constants.
Decimal constants versus real constants: In C, a string of digits with a decimal
point is interpreted as a real constant. In an SQL statement, such a string is
interpreted as a decimal constant. You must use exponential notation when
specifying a real (that is, floating-point) constant in an SQL statement.
In C, a real (floating-point) constant can have a suffix of f or F to show a data type
of float or a suffix of l or L to show a type of long double. A floating-point constant
in an SQL statement must not use these suffixes.
Integer constants: In C, you can provide integer constants in hexadecimal form if
the first two characters are 0x or 0X. You cannot use this form in an SQL statement.
In C, an integer constant can have a suffix of u or U to show that it is an unsigned
integer. An integer constant can have a suffix of l or L to show a long integer. You
cannot use these suffixes in SQL statements.
Character and string constants: In C, character constants and string constants can
use escape sequences. You cannot use the escape sequences in SQL statements.
Apostrophes and quotation marks have different meanings in C and SQL. In C,
you can use double quotation marks to delimit string constants, and apostrophes
to delimit character constants. The following examples illustrate the use of
quotation marks and apostrophes in C.
v Quotation marks
printf(

"%d lines read. n", num_lines);

v Apostrophes
#define NUL ’0’

In SQL, you can use double quotation marks to delimit identifiers and apostrophes
to delimit string constants. The following examples illustrate the use of
apostrophes and quotation marks in SQL.
v Quotation marks

162

Application Programming and SQL Guide
SELECT "COL#1" FROM TBL1;

v Apostrophes
SELECT COL1 FROM TBL1 WHERE COL2 = ’BELL’;

Character data in SQL is distinct from integer data. Character data in C is a
subtype of integer data.

COBOL syntax for host variable declarations
In COBOL programs, you can specify numeric, character, graphic, binary, LOB,
XML, and ROWID host variables. You can also specify result set and table locators
and LOB and XML file reference variables.
Only some of the valid COBOL declarations are valid host variable declarations. If
the declaration for a variable is not valid, then any SQL statement that references
the variable might result in the message UNDECLARED HOST VARIABLE.

Numeric host variables
The three valid forms of numeric host variables are:
v Floating-point numbers
v Integers and small integers
v Decimal numbers
The following diagram shows the syntax for declarations of floating-point or real
host variables.
01
77
level-1

variable-name

COMPUTATIONAL-1
COMP-1
COMPUTATIONAL-2
COMP-2

IS
USAGE

.
IS
VALUE

numeric-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. COMPUTATIONAL-1 and COMP-1 are equivalent.
3. COMPUTATIONAL-2 and COMP-2 are equivalent.
The following diagram shows the syntax for declarations of integer and small
integer host variables.
|

IS
01
77
level-1

variable-name

PICTURE
PIC

S9(4)
S9999
S9(9)
S999999999
S9(18)

Chapter 3. Including DB2 queries in an application program

163
BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

IS
USAGE

IS
VALUE

numeric-constant

.

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. The COBOL binary integer data types BINARY, COMPUTATIONAL, COMP,
COMPUTATIONAL-4, and COMP-4 are equivalent.
3. COMPUTATIONAL-5 (and COMP-5) are equivalent to the other COBOL binary
integer data types if you compile the other data types with TRUNC(BIN).
4. Any specification for scale is ignored.
The following diagram shows the syntax for declarations of decimal host variables.
IS
01
77
level-1

variable-name

PICTURE
PIC

picture-string

IS
USAGE

PACKED-DECIMAL
COMPUTATIONAL-3
COMP-3
IS
DISPLAY
NATIONAL

SIGN

CHARACTER
LEADING SEPARATE

.
IS
VALUE

numeric-constant

Character host variables
The three valid forms of character host variables are:
v Fixed-length strings
v Varying-length strings
v CLOBs
The following diagrams show the syntax for forms other than CLOBs.

164

Application Programming and SQL Guide
The following diagram shows the syntax for declarations of fixed-length character
host variables.
IS
01
77
level-1

variable-name

PICTURE
PIC

picture-string

.
DISPLAY

IS

IS

VALUE

character-constant

USAGE

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. The picture-string that is associated with these forms must be X(m) (or XX...X,
with m instances of X), with 1 <= m <= 32767 for fixed-length strings. However,
the maximum length of the CHAR data type (fixed-length character string) in
DB2 is 255 bytes.
The following diagram shows the syntax for declarations of varying-length
character host variables.
01
level-1

variable-name

.

IS
49 var-1

PICTURE
PIC

S9(4)
S9999

IS
USAGE

BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

.
IS
VALUE

numeric-constant

IS
49 var-2

PICTURE
PIC

picture-string

.
DISPLAY
IS

IS
VALUE

character-constant

USAGE

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
Chapter 3. Including DB2 queries in an application program

165
2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL
with TRUNC(STD) only recognizes values up to 9999. This can cause data
truncation errors when COBOL statements execute and might effectively limit
the maximum length of variable-length character strings to 9999. Consider
using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data
truncation.
3. For fixed-length strings, the picture-string must be X(m) (or XX...X, with m
instances of X), with 1 <= m <= 32767; for other strings, m cannot be greater
than the maximum size of a varying-length character string.
4. You cannot directly reference var-1 and var-2 as host variables.
5. You cannot use an intervening REDEFINE at level 49.

Graphic character host variables
The three valid forms for graphic character host variables are:
v Fixed-length strings
v Varying-length strings
v DBCLOBs
The following diagrams show the syntax for forms other than DBCLOBs.
The following diagram shows the syntax for declarations of fixed-length graphic
host variables.
IS
01
77
level-1

variable-name

PICTURE
PIC

DISPLAY-1
NATIONAL

IS

picture-string

.
IS

USAGE

VALUE

graphic-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
3. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the DB2 coprocessor.
The following diagram shows the syntax for declarations of varying-length graphic
host variables.
01
level-1

variable-name

.

IS
49 var-1

PICTURE
PIC

S9(4)
S9999

IS
USAGE

166

Application Programming and SQL Guide
BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

.
IS
VALUE

numeric-constant

IS
49 var-2

PICTURE
PIC

picture-string
IS
USAGE

DISPLAY-1
NATIONAL

.
IS
VALUE

graphic-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL
with TRUNC(STD) only recognizes values up to 9999. This can cause data
truncation errors when COBOL statements execute and might effectively limit
the maximum length of variable-length character strings to 9999. Consider
using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data
truncation.
3. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
4. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the DB2 coprocessor.
5. You cannot directly reference var-1 and var-2 as host variables.
Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. PACKED-DECIMAL, COMPUTATIONAL-3, and COMP-3 are equivalent. The
picture-string that is that is associated with these types must have the form
S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9) or S9(i)V.
3. The picture-string that is associated with SIGN LEADING SEPARATE must have
the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9 or S9...9V with i
instances of 9).

Binary host variables
|
|
|
|

The three valid forms of BINARY host variables are:
v Fixed-length strings
v Varying-length strings
v BLOBs

|
|

The following diagram shows the syntax for declarations of BINARY and
VARBINARY host variables.
Chapter 3. Including DB2 queries in an application program

167
|
|

IS
USAGE
01 variable-name

|
|

( length )

SQL TYPE IS

BINARY
VARBINARY
BINARY VARYING

.

|
Notes:
1. For BINARY host variables, the length must be in the range from 1 to 255. For
VARBINARY host variables, the length must be in the range from 1 to 32 704.

|
|
|

COBOL does not have variables that correspond to the SQL binary types BINARY
and VARBINARY. To create host variables that can be used with these data types,
use the SQL TYPE IS clause. The SQL precompiler replaces this declaration with a
COBOL language structure in the output source member.
|
|
|
|

When you refer to a BINARY or VARBINARY host variable in an SQL statement,
you must use the variable that you specify in the SQL TYPE declaration. When
you refer to the host variable in a host language statement, you must use the
variable that DB2 generates.

|
|

Example: The following table shows examples of variables that DB2 generates
when you declare binary host variables.

| Table 46. Examples of BINARY and VARBINARY variable declarations for COBOL
| You declare this variable

DB2 generates this variable

| 01 BIN-VAR USAGE IS SQL TYPE IS BINARY(10).

01 BIN-VAR PIC X(10).

| 01 VBIN-VAR USAGE IS SQL TYPE IS VARBINARY(10).
|
|
|

01 VBIN-VAR.
49 VBIN-VAR-LEN PIC S9(4) USAGE BINARY.
49 VBIN-VAR-TEXT PIC X(10).

Result set locators
The following diagram shows the syntax for declarations of result set locators.
01

variable-name

SQL TYPE IS RESULT-SET-LOCATOR

VARYING

.

IS
USAGE

Table Locators
The following diagram shows the syntax for declarations of table locators. See
“Accessing transition tables in a user-defined function or stored procedure” on
page 473 for a discussion of how to use these host variables.
01
level-1

variable-name

SQL TYPE IS TABLE LIKE table-name AS LOCATOR .
IS
USAGE

Note: level-1 indicates a COBOL level between 2 and 48.

168

Application Programming and SQL Guide
LOB variables and file reference variables
|
|
|
|
|

The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB variables and file reference variables. See “Large objects (LOBs)” on page
390 for a discussion of how to use these host variables.
01
level-1

variable-name

SQL TYPE IS
IS
USAGE

|
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB-LOCATOR
CLOB-LOCATOR
DBCLOB-LOCATOR
BLOB-FILE
CLOB-FILE
DBCLOB-FILE

( length

)

.

K
M
G

|
|
|
|
|

The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variables, and file reference variables for XML data types.
01
level-1

variable-name

SQL TYPE IS XML AS
IS
USAGE

|
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB-FILE
CLOB-FILE
DBCLOB-FILE

( length

)

.

K
M
G

|
|

Note: level-1 indicates a COBOL level between 2 and 48.

ROWIDs
The following diagram shows the syntax for declarations of ROWID host variables.
See “Large objects (LOBs)” on page 390 for a discussion of how to use these host
variables.
01
level-1

variable-name

SQL TYPE IS ROWID .
IS
USAGE

Note: level-1 indicates a COBOL level between 2 and 48.

Chapter 3. Including DB2 queries in an application program

169
Notes on COBOL variable declaration and usage
You should be aware of the following considerations when you declare COBOL
host variables.

Controlling the CCSID
IBM Enterprise COBOL for z/OS and the DB2 coprocessor support:
v The NATIONAL data type that is used for declaring Unicode values in the
UTF-16 format (that is, CCSID 1200).
v The COBOL CODEPAGE compiler option that is used to specify the default
EBCDIC CCSID of character data items.
v The SQLCCSID compiler option to control whether the CODEPAGE compiler
option will influence the processing of SQL host variables in your COBOL
programs (available in Enterprise COBOL V3R4 or later).
If you declare a host variable HV1 as USAGE NATIONAL, DB2 always handles
HV1 as if you had used this DECLARE VARIABLE statement:
DECLARE :HV1 VARIABLE CCSID 1200

When you specify the SQLCCSID compiler option, the COBOL DB2 coprocessor
uses the CCSID that is specified in the CODEPAGE compiler option to indicate
that all host variables of character data type, other than NATIONAL, are specified
with that CCSID unless they are explicitly overridden by a DECLARE VARIABLE
statement.
Example: Assume that the COBOL CODEPAGE compiler option is specified as
CODEPAGE(1141). The following code shows how you can control the CCSID:
DATA DIVISION.
01 HV1 PIC N(10) USAGE NATIONAL.
01 HV2 PIC X(20) USAGE DISPLAY.
01 HV3 PIC X(30) USAGE DISPLAY.
...
EXEC SQL
DECLARE :HV3 VARIABLE CCSID 1047
END-EXEC.
...
PROCEDURE DIVISION.
...
EXEC SQL
SELECT C1, C2, C3 INTO :HV1, :HV2, :HV3 FROM T1
END-EXEC.

The CCSID for each of these host variables is:
HV1

1200

HV2

1141

HV3

1047

When you specify the COBOL NOSQLCCSID compiler option, the CCSID that is
specified in the CODEPAGE compiler option is used only for processing COBOL
statements within the COBOL program; that CCSID is not used for the processing
of host variables in SQL statements. DB2 uses the CCSIDs specified through DB2
mechanisms and defaults as host variable data value encodings.

170

Application Programming and SQL Guide
Assume that the COBOL NOSQLCCSID option is specified, the COBOL
CODEPAGE compiler option is specified as CODEPAGE(1141), and the DB2 default
single byte CCSID is set to 37. The CCSIDs for the host variables in this example
or with the precompiler become:
HV1

1200

HV2

37

HV3

1047

For further details on the COBOL SQLCCSID and NOSQLCCSID options, see the
Enterprise COBOL for z/OS Programming Guide on the Enterprise COBOL for z/OS
library Web page at http://www.ibm.com/software/awdtools/cobol/zos/library/.

SQL data types with no COBOL equivalent
If you are using a COBOL compiler that does not support decimal numbers of
more than 18 digits, use one of the following data types to hold values of greater
than 18 digits:
v A decimal variable with a precision less than or equal to 18, if the actual data
values fit. If you retrieve a decimal value into a decimal variable with a scale
that is less than the source column in the database, the fractional part of the
value might be truncated.
v An integer or a floating-point variable, which converts the value. If you choose
integer, you lose the fractional part of the number. If the decimal number might
exceed the maximum value for an integer, or if you want to preserve a fractional
value, you can use floating-point numbers. Floating-point numbers are
approximations of real numbers. Therefore, when you assign a decimal number
to a floating-point variable, the result might be different from the original
number.
v A character-string host variable. Use the CHAR function to retrieve a decimal
value into it.
|

The SQL data type DECFLOAT also has no equivalent in COBOL.

Special purpose COBOL data types
The following locator data types are COBOL data types and SQL data types:
v Result set locator
v Table locator
v LOB locators
v LOB file reference variables
You cannot use locators as column types.

Level 77 data description entries
One or more REDEFINES entries can follow any level 77 data description entry.
However, you cannot use the names in these entries in SQL statements. Entries
with the name FILLER are ignored.

SMALLINT and INTEGER data types
In COBOL, you declare the SMALLINT and INTEGER data types as a number of
decimal digits. DB2 uses the full size of the integers (in a way that is similar to
Chapter 3. Including DB2 queries in an application program

171
processing with the TRUNC(BIN) compiler option) and can place larger values in
the host variable than would be allowed in the specified number of digits in the
COBOL declaration. If you compile with TRUNC(OPT) or TRUNC(STD), ensure
that the size of numbers in your application is within the declared number of
digits.
For small integers that can exceed 9999, use S9(4) COMP-5 or compile with
TRUNC(BIN). For large integers that can exceed 999 999 999, use S9(10) COMP-3
to obtain the decimal data type. If you use COBOL for integers that exceed the
COBOL PICTURE, specify the column as decimal to ensure that the data types
match and perform well.

Overflow
Be careful of overflow. For example, suppose you retrieve an INTEGER column
value into a PICTURE S9(4) host variable and the column value is larger than
32767 or smaller than -32768. You get an overflow warning or an error, depending
on whether you specify an indicator variable.

VARCHAR, VARGRAPHIC, and VARBINARY data types
If your varying-length string host variables receive values whose length is greater
than 9999 bytes, compile the applications in which you use those host variables
with the option TRUNC(BIN). TRUNC(BIN) lets the length field for the string
receive a value of up to 32767 bytes.

Truncation
Be careful of truncation. For example, if you retrieve an 80-character CHAR
column value into a PICTURE X(70) host variable, the rightmost 10 characters of
the retrieved string are truncated. Retrieving a double precision floating-point or
decimal column value into a PIC S9(8) COMP host variable removes any fractional
part of the value.
Similarly, retrieving a column value with DECIMAL data type into a COBOL
decimal variable with a lower precision might truncate the value.

Fortran syntax for host variable declations
In Fortran programs, you can specify numeric, character, LOB, and ROWID host
variables. You can also specify result set and LOB locators.
Only some of the valid Fortran declarations are valid host variable declarations. If
the declaration for a variable is not valid, any SQL statement that references the
variable might result in the message UNDECLARED HOST VARIABLE.
Numeric host variables: The following diagram shows the syntax for declarations
of numeric host variables.

172

Application Programming and SQL Guide
,
INTEGER*2

variable-name
*4

/

numeric-constant /

INTEGER
*4
REAL
REAL*8
DOUBLE PRECISION

Character host variables: The following diagram shows the syntax for declarations
of character host variables other than CLOBs.
,
CHARACTER

variable-name
*n

*n

/

character-constant

/

Result set locators: The following diagram shows the syntax for declarations of
result set locators.
,
SQL TYPE IS RESULT_SET_LOCATOR VARYING

variable-name

LOB Variables and Locators: The following diagram shows the syntax for
declarations of BLOB and CLOB host variables and locators. See “Large objects
(LOBs)” on page 390 for a discussion of how to use these host variables.
SQL TYPE IS

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
BLOB_LOCATOR
CLOB_LOCATOR

( length

)
K
M
G

variable-name

ROWIDs: The following diagram shows the syntax for declarations of ROWID
variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use
these host variables.
SQL TYPE IS ROWID variable-name

Notes on Fortran variable declaration and usage
You should be aware of the following when you declare Fortran variables.
Fortran data types with no SQL equivalent: Fortran supports some data types
with no SQL equivalent (for example, REAL*16 and COMPLEX). In most cases,
you can use Fortran statements to convert between the unsupported data types
and the data types that SQL allows.
Chapter 3. Including DB2 queries in an application program

173
SQL data types with no Fortran equivalent: Fortran does not provide an
equivalent for the decimal data type. To hold the value of such a variable, you can
use:
v An integer or floating-point variable, which converts the value. If you choose
integer, however, you lose the fractional part of the number. If the decimal
number can exceed the maximum value for an integer or you want to preserve a
fractional value, you can use floating-point numbers. Floating-point numbers are
approximations of real numbers. When you assign a decimal number to a
floating-point variable, the result could be different from the original number.
v A character string host variable. Use the CHAR function to retrieve a decimal
value into it.
The SQL data type DECFLOAT also has no equivalent in Fortran.

|

Special-purpose Fortran data types: The following locator data types are Fortran
data types and SQL data types:
v Result set locator
v LOB locators
You cannot use locators as column types.
Overflow: Be careful of overflow. For example, if you retrieve an INTEGER column
value into a INTEGER*2 host variable and the column value is larger than 32767 or
-32768, you get an overflow warning or an error, depending on whether you
provided an indicator variable.
Truncation: Be careful of truncation. For example, if you retrieve an 80-character
CHAR column value into a CHARACTER*70 host variable, the rightmost ten
characters of the retrieved string are truncated.
Retrieving a double-precision floating-point or decimal column value into an
INTEGER*4 host variable removes any fractional value.
Processing Unicode data: Because Fortran does not support graphic data types,
Fortran applications can process only Unicode tables that use UTF-8 encoding.

Notes on syntax differences for constants
You should be aware of the following syntax differences for constants.
Real constants: Fortran interprets a string of digits with a decimal point to be a
real constant. An SQL statement interprets such a string to be a decimal constant.
Therefore, use exponent notation when specifying a real (that is, floating-point)
constant in an SQL statement.
Exponent indicators: In Fortran, a real (floating-point) constant having a length of
8 bytes uses a D as the exponent indicator (for example, 3.14159D+04). An 8-byte
floating-point constant in an SQL statement must use an E (for example,
3.14159E+04).

PL/I syntax for host variable declarations
In PL/I programs, you can specify numeric, character, graphic, binary, LOB, XML,
and ROWID host variables. You can also specify result set, table, and LOB locators
and LOB and XML file reference variables.

174

Application Programming and SQL Guide
Only some of the valid PL/I declarations are valid host variable declarations. The
precompiler uses the data attribute defaults that are specified in the PL/I
DEFAULT statement. If the declaration for a host variable is not valid, any SQL
statement that references the variable might result in the message UNDECLARED
HOST VARIABLE.
The precompiler uses only the names and data attributes of the variables; it ignores
the alignment, scope, and storage attributes. Even though the precompiler ignores
alignment, scope, and storage, if you ignore the restrictions on their use, you might
have problems compiling the PL/I source code that the precompiler generates.
These restrictions are as follows:
v A declaration with the EXTERNAL scope attribute and the STATIC storage
attribute must also have the INITIAL storage attribute.
v If you use the BASED storage attribute, you must follow it with a PL/I
element-locator-expression.
v Host variables can be STATIC, CONTROLLED, BASED, or AUTOMATIC storage
class, or options. However, CICS requires that programs be reentrant.

Numeric host variables
The following diagram shows the syntax for declarations of numeric host variables.
DECLARE
DCL

variable-name
,
(

variable-name

)

BINARY
BIN
DECIMAL
DEC

FIXED
( precision

)
,scale

FLOAT ( precision )

Alignment and/or Scope and/or Storage

Note:
1. You can specify host variable attributes in any order that is acceptable to PL/I.
For example, BIN FIXED(31), BINARY FIXED(31), BIN(31) FIXED, and FIXED
BIN(31) are all acceptable.
2. You can specify a scale only for DECIMAL FIXED.

Character host variables
The following diagram shows the syntax for declarations of character host
variables, other than CLOBs.
DECLARE
DCL

variable-name
,
(

variable-name

)

Chapter 3. Including DB2 queries in an application program

175
CHARACTER
CHAR

( length )
VARYING
VAR

Alignment and/or Scope and/or Storage

Graphic host variables
The following diagram shows the syntax for declarations of graphic host variables,
other than DBCLOBs.
DECLARE
DCL

variable-name
,
(

variable-name

)

GRAPHIC ( length )
VARYING
VAR

Alignment and/or Scope and/or Storage

Binary host variables
The three valid forms of BINARY host variables are:
v Fixed-length strings
v Varying-length strings
v BLOBs
The following diagram shows the syntax for declarations of BINARY host
variables.
DECLARE
DCL

variable-name
,

SQL TYPE IS

BINARY
VARBINARY
BINARY VARYING

( variable-name )
( length )

;

Notes:
1. For BINARY host variables, the length must be in the range from 1 to 255. For
VARBINARY host variables, the length must be in the range from 1 to 32 704.
PL/I does not have variables that correspond to the SQL binary data types
BINARY and VARBINARY. To create host variables that can be used with these
data types, use the SQL TYPE IS clause.
When you refer to a BINARY or VARBINARY host variable in an SQL statement,
you must use the variable that you specify in the SQL TYPE declaration. When
you refer to the host variable in a host language statement, you must use the
variable that DB2 generates.

176

Application Programming and SQL Guide
Example: The following table shows examples of variables that DB2 generates
when you declare binary host variables.
Table 47. Examples of BINARY and VARBINARY variable declarations for C
You declare this variable

DB2 generates this variable

DCL BIN_VAR SQL TYPE IS BINARY(10);

DCL BIN_VAR CHAR(10);

DCL VBIN_VAR SQL TYPE IS VARBINARY(10);

DCL VBIN_VAR CHAR(10) VAR;

Result set locators
The following diagram shows the syntax for declarations of result set locators.
DECLARE
DCL

variable-name
,
(

variable-name

)

SQL TYPE IS RESULT_SET_LOCATOR VARYING

Alignment and/or Scope and/or Storage

Table locators
The following diagram shows the syntax for declarations of table locators. See
“Accessing transition tables in a user-defined function or stored procedure” on
page 473 for a discussion of how to use these host variables.
DCL
DECLARE

variable-name
,
(

variable-name

)

SQL TYPE IS TABLE LIKE table-name AS LOCATOR

LOB variables, locators, and file reference variables
|
|
|
|
|

The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variables, locators, and file reference variables. See “Large objects
(LOBs)” on page 390 for a discussion of how to use these host variables. A single
PL/I declaration that contains a LOB variable declaration is limited to no more
than 1000 lines of source code.
DCL
DECLARE

variable-name
,
(

variable-name

SQL TYPE IS

)

Chapter 3. Including DB2 queries in an application program

177
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

(

length

)
K
M
G

Note: Variable attributes such as STATIC and AUTOMATIC are ignored if
specified on a LOB variable declaration.
The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variables and file reference variables for XML data types.

|
|
|
|

DCL
DECLARE

variable-name
,
(

|
|

SQL TYPE IS XML AS

variable-name

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

(

)
length

)
K
M
G

|
Note: Variable attributes such as STATIC and AUTOMATIC are ignored if
specified on a LOB variable declaration.

|
|

ROWIDs
The following diagram shows the syntax for declarations of ROWID host variables.
See “Large objects (LOBs)” on page 390 for a discussion of how to use these host
variables.
DCL
DECLARE

variable-name
,
(

variable-name

SQL TYPE IS ROWID

)

Notes on PL/I variable declaration and usage
You should be aware of the following when you declare PL/I variables.

178

Application Programming and SQL Guide
PL/I data types with no SQL equivalent: PL/I supports some data types with no
SQL equivalent (COMPLEX and BIT variables, for example). In most cases, you can
use PL/I statements to convert between the unsupported PL/I data types and the
data types that SQL supports.
SQL data types with no PL/I equivalent: If the PL/I compiler you are using does
not support a decimal data type with a precision greater than 15, use the following
types of variables for decimal data:
v Decimal variables with precision less than or equal to 15, if the actual data
values fit. If you retrieve a decimal value into a decimal variable with a scale
that is less than the source column in the database, the fractional part of the
value might truncate.
v An integer or a floating-point variable, which converts the value. If you choose
integer, you lose the fractional part of the number. If the decimal number can
exceed the maximum value for an integer or you want to preserve a fractional
value, you can use floating-point numbers. Floating-point numbers are
approximations of real numbers. When you assign a decimal number to a
floating- point variable, the result could be different from the original number.
v A character string host variable. Use the CHAR function to retrieve a decimal
value into it.
Floating-point host variables: All floating-point data is stored in DB2 in
z/Architecture hexadecimal floating-point format. However, your host variable
data can be in z/Architecture hexadecimal floating-point format or IEEE binary
floating-point format. DB2 uses the FLOAT precompiler option to determine
whether your floating-point host variables are in IEEE binary floating-point format
or z/Architecture hexadecimal floating-point format. DB2 does no checking to
determine whether the host variable declarations or format of the host variable
contents match the precompiler option. Therefore, you need to ensure that your
floating-point host variable types and contents match the precompiler option.
Special purpose PL/I data types: The following locator data types are PL/I data
types as well as SQL data types:
v Result set locator
v Table locator
v LOB locators
You cannot use locators as column types.
PL/I scoping rules: The precompiler does not support PL/I scoping rules.
Overflow: Be careful of overflow. For example, if you retrieve an INTEGER column
value into a BIN FIXED(15) host variable and the column value is larger than
32767 or smaller than -32768, you get an overflow warning or an error, depending
on whether you provided an indicator variable.
Truncation: Be careful of truncation. For example, if you retrieve an 80-character
CHAR column value into a CHAR(70) host variable, the rightmost ten characters
of the retrieved string are truncated.
Retrieving a double-precision floating-point or decimal column value into a BIN
FIXED(31) host variable removes any fractional part of the value.
Similarly, retrieving a column value with a DECIMAL data type into a PL/I
decimal variable with a lower precision might truncate the value.
Chapter 3. Including DB2 queries in an application program

179
Pointers as host variables in C and C++
If you use the DB2 coprocessor, you can use pointer host variables with statically
or dynamically allocated storage. These pointer host variables can point to numeric
data, non-numeric data, or a structure.
To declare pointer host variables, use an asterisk (*) to indicate that the variable is
a pointer. To reference a pointer host variable in an SQL statement, specify the
pointer host variable exactly as it was declared.
You can use the following types of pointer host variables:
scalar pointer host variable
A host variable that points to numeric or non-numeric scalar data.
The following table shows example declarations of scalar pointer host
variables and example references to such variables.
Table 48. Example declarations of and references to scalar pointer host variables
Declaration

Description

Reference

short *hvshortp;

hvshortp is a pointer host variable that
points to two bytes of storage.

EXEC SQL set:*hvshortp=123;

double *hvdoubp;

hvdoubp is a pointer host variable that
points to eight bytes of storage.

EXEC SQL set:*hvdoubp=456;

char (*hvcharpn) [20];

hvcharpn is a pointer host variable that
points to a nul-terminated character array
of up to 20 bytes.

EXEC SQL set:
*hvcharpn=’nul_terminated’;
1

Note:
1. When you reference pointers to nul-terminated character arrays, you do
not have to include the parentheses that were part of the declaration.
Restriction: You cannot use pointer host variables that point to character
data of an unknown length. For example, the following specification is not
supported: char * hvcharpu.
Instead, for character pointer host variables, you must specify the length of
the data by using a bounded character pointer host variable. A bounded
character pointer host variable is a host variable that is declared as a structure
with the following two elements:
v A 4-byte field that contains the length of the storage area.
v A pointer to the non-numeric dynamic storage area.
Example of a bounded character pointer host variable: The following
example declares a bounded character pointer host variable called
hvbcharp with two elements: len and data:
struct {
unsigned long len;
char * data;
} hvbcharp;

The following example references this bounded character pointer host
variable:

180

Application Programming and SQL Guide
hvcharp.len = dynlen; 1
hvcharp.data = (char 8) malloc (hvcharp.len); 2
EXEC SQL set :hvcharp = ’data buffer with length’;

3

Note:
1. dynlen can be either a compile time constant or a variable with a value
that is assigned at run time.
2. Storage is dynamically allocated for hvcharp.data.
3. The SQL statement references the name of the structure, not an element
within the structure.
array pointer host variables
A host variable that is an array of pointers.
The following table shows example declarations of array pointer host
variables and examples references to such variables.
Table 49. Example declarations of and references to array pointer host variables
Declaration

Description

Reference

short * hvarrpl[6]

hvarrp1 is an array of 6 pointers that point EXEC SQL set:*hvarrpl[n]=123;
to two bytes of storage each.

double * hvarrp2[3]

hvarrp2 is an array of 3 pointers that point EXEC SQL set:*hvarrp2[n]=456;
to 8 bytes of storage each.

struct {
unsigned long len;
char * data; }
hvbarrp3[5];

hvbarrp3 is an array of 5 bounded
character pointers.

EXEC SQL set :hvarrp3[n] =
’data buffer with length’
1

structure array host variable
A host variable that points to a structure.
Example: The following example declares a table structure called tbl_struct.
struct tbl_struct
{
char colname[20];
small int colno;
small int coltype;
small int collen;
};

The following example declares a pointer to the structure tbl_struct.
Storage is allocated dynamically for up to n rows.
struct tbl_struct *ptr_tbl_struct =
(struct tbl_struct *) malloc (sizeof (struct tbl_struct) * n);

To reference this data is SQL statements, use the pointer as shown in the
following example. Assume that tbl_sel_cur is a declared cursor.
for (L_col_cnt = 0; L_col_cnt < n; L_con_cnt++)
{ ...
EXEC SQL FETCH tbl_sel_cur INTO :ptr_tbl_struct [L_col_cnt]
...
}

Restriction: You cannot use untyped pointers. For example, the following
declaration is not supported: void * untypedprt .

Chapter 3. Including DB2 queries in an application program

181
Host variable arrays in an SQL statement
Use host variable arrays in embedded SQL statements to represent values that the
program does not know until the query is executed. Host variable arrays are useful
for storing a set of retrieved values or for passing a set of values that are to be
inserted into a table.
To use a host variable array in an SQL statement, specify any valid host variable
array that is declared according to the host language rules that are described in
“Embedding SQL statements in your application” on page 243. You can specify
host variable arrays in C or C++, COBOL, and PL/I. You must declare the array in
the host program before you use it.
|
|
|
|

Assembler support for multiple-row FETCH is limited to the FETCH statement
with the INTO DESCRIPTOR clause. For example:

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Assembler support for multiple-row INSERT is limited to the following cases:

|
|

Restriction: Assembler does not support multiple-row MERGE. You cannot specify
MERGE statements that reference host variable arrays.

|
|

The DB2 precompiler does not recognize declarations of host variable arrays for
assembler; it recognizes these declarations only in C, COBOL, and PL/I.

EXEC SQL FETCH NEXT ROWSET FROM C1 FOR 10 ROWS
INTO DESCRIPTOR :SQLDA

X

v static multiple-row INSERT statement with scalar values (scalar host variables or
scalar expressions) in the VALUES clause. For example:
EXEC SQL INSERT INTO T1 VALUES (1, CURRENT DATE, ’TEST’)
FOR 10 ROWS

X

v dynamic multiple-row INSERT executed with the USING DESCRIPTOR clause
on the EXECUTE statement. For example:
ATR
S1

DS
CL20
ATTRIBUTES FOR PREPARE
DS
H,CL30
VARCHAR STATEMENT STRING
MVC
ATR(20),=C’FOR MULTIPLE ROWS ’
MVC
S1(2),=H’25’
MVC
S1+2(30),=C’INSERT INTO T1 VALUES (?) ’
EXEC SQL PREPARE STMT ATTRIBUTES :ATR FROM :S1
EXEC SQL EXECUTE STMT USING DESCRIPTOR :SQLDA FOR 10 ROWS
where the descriptor is set up correctly in advance according to the
specifications for dynamic execution of a multiple-row INSERT statement
with a descriptor

Retrieving multiple rows of data into host variable arrays
If you know that your query returns multiple rows, you can specify host variable
arrays to store the retrieved column values.
You can use host variable arrays to specify a program data area to contain multiple
rows of column values. A DB2 rowset cursor enables an application to retrieve and
process a set of rows from the result table of the cursor. For information about
using rowset cursors, see “Accessing data by using a rowset-positioned cursor” on
page 636.

Inserting multiple rows of data from host variable arrays
When you want to insert multiple rows of data into a DB2 table, but you do not
know at least some of the values to insert until the program runs, use host variable
arrays in your INSERT statement.

182

Application Programming and SQL Guide
|
|
|
|
|
|
|

You can use a form of the INSERT statement or MERGE statement to insert
multiple rows from values that are provided in host variable arrays. Each array
contains values for a column of the target table. The first value in an array
corresponds to the value for that column for the first inserted row, the second
value in the array corresponds to the value for the column in the second inserted
row, and so on. DB2 determines the attributes of the values based on the
declaration of the array.
Example: You can insert the number of rows that are specified in the host variable
NUM-ROWS by using the following INSERT statement:
EXEC SQL
INSERT INTO DSN8910.ACT
(ACTNO, ACTKWD, ACTDESC)
VALUES (:HVA1, :HVA2, :HVA3)
FOR :NUM-ROWS ROWS
END-EXEC.

Assume that the host variable arrays HVA1, HVA2, and HVA3 have been declared
and populated with the values that are to be inserted into the ACTNO, ACTKWD,
and ACTDESC columns. The NUM-ROWS host variable specifies the number of
rows that are to be inserted, which must be less than or equal to the dimension of
each host variable array.

C and C++ syntax for host variable array declarations
In C and C++ programs, you can specify numeric, character, graphic, binary, LOB,
XML, and ROWID host variable arrays. You can also specify LOB locators and
LOB and XML file reference variables.
Only some of the valid C declarations are valid host variable array declarations. If
the declaration for a variable array is not valid, then any SQL statement that
references the variable array might result in the message UNDECLARED HOST
VARIABLE ARRAY.
|
|
|
|
|

For both C and C++, you cannot specify the _packed attribute on the structure
declarations for varying-length character arrays, varying-length graphic arrays, or
LOB arrays that are to be used in multiple-row INSERT, FETCH, and MERGE
statements. In addition, the #pragma pack(1) directive cannot be in effect if you
plan to use these arrays in multiple-row statements.

Numeric host variable arrays in C or C++
The following diagram shows the syntax for declarations of numeric host variable
arrays.

auto
extern
static

const
volatile

unsigned

Chapter 3. Including DB2 queries in an application program

183
float
double
int
long
short
int
long long
decimal (

precision

)
, scale

,
variable-name [ dimension ]

;
,
= {

expression

}

Note:
1. dimension must be an integer constant between 1 and 32767.
Example: The following example shows a declaration of a numeric host variable
array:
EXEC SQL BEGIN DECLARE SECTION;
/* declaration of numeric host variable array */
long serial_num[10];
...
EXEC SQL END DECLARE SECTION;

Character host variable arrays in C or C++
The three valid forms for character host variable arrays are:
v NUL-terminated character form
v VARCHAR structured form
v CLOBs
The following diagrams show the syntax for forms other than CLOBs.
The following diagram shows the syntax for declarations of NUL-terminated
character host variable arrays.
char
auto
extern
static

const
volatile

unsigned

,
variable-name

[

dimension

]

[

length

]

;
,
=

{

expression

}

Notes:
1. On input, the strings contained in the variable arrays must be NUL-terminated.

184

Application Programming and SQL Guide
2. On output, the strings are NUL-terminated.
3. The strings in a NUL-terminated character host variable array map to
varying-length character strings (except for the NUL).
4. dimension must be an integer constant between 1 and 32767.
The following diagram shows the syntax for declarations of varying-length
character host variable arrays that use the VARCHAR structured form.
int
struct
auto
extern
static

{

short

var-1

;

const
volatile

char var-2 [ length ]

;

}

unsigned

,
variable-name [ dimension ]

;
,
= {

|
|

expression

}

Notes:
1. var-1 must be a scalar numeric variable, and var-2 must be a scalar CHAR array
variable.
2. You can use the struct tag to define other variables, but you cannot use them as
host variable arrays in SQL.
3. dimension must be an integer constant between 1 and 32767.
Example: The following examples show valid and invalid declarations of
VARCHAR host variable arrays:
EXEC SQL BEGIN DECLARE SECTION;
/* valid declaration of VARCHAR host variable array */
struct VARCHAR {
short len;
char s[18];
} name[10];
/* invalid declaration of VARCHAR host variable array */
struct VARCHAR name[10];

Binary host variable arrays in C or C++
|
|
|

The following diagram shows the syntax for declarations of binary host variable
arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use
these host variable arrays.

|

Chapter 3. Including DB2 queries in an application program

185
|
|

SQL TYPE IS
auto
extern
static
register

|
|

BINARY
VARBINARY

const
volatile

(length)

,
variable-name [ dimension ]

;

|
Note:
1. dimension must be an integer constant between 1 and 32767.

|

Graphic host variable arrays in C or C++
The two valid forms for graphic host variable arrays are:
v NUL-terminated graphic form
v VARGRAPHIC structured form.
Recommendation: Instead of using the C data type wchar_t to define graphic and
vargraphic host variable arrays, use one of the following techniques:
v Define the sqldbchar data type by using the following typedef statement:
typedef unsigned short sqldbchar;

v Use the sqldbchar data type that is defined in the typedef statement in the
header files that are supplied by DB2.
v Use the C data type unsigned short.
The following diagram shows the syntax for declarations of NUL-terminated
graphic host variable arrays.
sqldbchar
auto
extern
static

const
volatile

unsigned

,
variable-name

[

dimension

]

[

length

]

;
,
=

{

expression

}

Notes:
1. length must be a decimal integer constant greater than 1 and not greater than
16352.
2. On input, the strings contained in the variable arrays must be NUL-terminated.
3. On output, the string is NUL-terminated.
4. The NUL-terminated graphic form does not accept single-byte characters into
the variable array.
5. dimension must be an integer constant between 1 and 32767.

186

Application Programming and SQL Guide
The following diagram shows the syntax for declarations of graphic host variable
arrays that use the VARGRAPHIC structured form.
int
struct
auto
extern
static

{

short

var-1

;

const
volatile

sqldbchar var-2 [ length ]

;

}

unsigned

,
variable-name [ dimension ]

;
,
= {

expression

}

Notes:
1. length must be a decimal integer constant greater than 1 and not greater than
16352.
2. var-1 must be a scalar numeric variable, and var-2 must be a scalar char array
variable.
3. You can use the struct tag to define other variables, but you cannot use them as
host variable arrays in SQL.
4. dimension must be an integer constant between 1 and 32767.
Example: The following examples show valid and invalid declarations of graphic
host variable arrays that use the VARGRAPHIC structured form:
EXEC SQL BEGIN DECLARE SECTION;
/* valid declaration of host variable array vgraph */
struct VARGRAPH {
short len;
sqldbchar d[10];
} vgraph[20];
/* invalid declaration of host variable array vgraph */
struct VARGRAPH vgraph[20];

LOB, locator, file reference, and XML variable arrays in C or C++
The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variable arrays and locators. See “Large objects (LOBs)” on page 390
for a discussion of how to use LOB variables.
SQL TYPE IS
auto
extern
static
register

const
volatile

Chapter 3. Including DB2 queries in an application program

187
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

(

length

)
K
M
G

,
variable-name [ dimension ]

;
,
= {

expression

}

Note:
1. dimension must be an integer constant between 1 and 32767.
The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variable arrays, and file reference variable arrays for XML data
types
SQL TYPE IS XML AS
auto
extern
static
register

|

const
volatile

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

(

length

)
K
M
G

,
variable-name [ dimension ]

;
,
= {

Note:

188

Application Programming and SQL Guide

expression

}
1. dimension must be an integer constant between 1 and 32767.

ROWID variable arrays in C or C++
The following diagram shows the syntax for declarations of ROWID variable
arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use
these host variable arrays.
,
SQL TYPE IS ROWID
auto
extern
static
register

variable-name

[

dimension

]

;

const
volatile

Note:
1. dimension must be an integer constant between 1 and 32767.

COBOL syntax for host variable array declarations
In COBOL programs, you can specify numeric, character, graphic, LOB, XML, and
ROWID host variable arrays. You can also specify LOB locators and LOB and XML
file reference variables.
Only some of the valid COBOL declarations are valid host variable array
declarations. If the declaration for a variable array is not valid, any SQL statement
that references the variable array might result in the message UNDECLARED
HOST VARIABLE ARRAY.
Numeric host variable arrays: The three valid forms of numeric host variable
arrays are:
v Floating-point numbers
v Integers and small integers
v Decimal numbers
The following diagram shows the syntax for declarations of floating-point host
variable arrays.
level-1 variable-name

COMPUTATIONAL-1
COMP-1
COMPUTATIONAL-2
COMP-2

IS
USAGE

OCCURS dimension

.
TIMES

IS
VALUE

numeric-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. COMPUTATIONAL-1 and COMP-1 are equivalent.
3. COMPUTATIONAL-2 and COMP-2 are equivalent.
4. dimension must be an integer constant between 1 and 32767.
The following diagram shows the syntax for declarations of integer and small
integer host variable arrays.
Chapter 3. Including DB2 queries in an application program

189
IS
level-1 variable-name

PICTURE
PIC

S9(4)
S9999
S9(9)
S999999999

BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

IS
USAGE

OCCURS dimension
TIMES

.
IS
VALUE

numeric-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. The COBOL binary integer data types BINARY, COMPUTATIONAL, COMP,
COMPUTATIONAL-4, and COMP-4 are equivalent.
3. COMPUTATIONAL-5 (and COMP-5) are equivalent to the other COBOL binary
integer data types if you compile the other data types with TRUNC(BIN).
4. Any specification for scale is ignored.
5. dimension must be an integer constant between 1 and 32767.
The following diagram shows the syntax for declarations of decimal host variable
arrays.
IS
level-1 variable-name

PICTURE
PIC

picture-string

IS
USAGE

PACKED-DECIMAL
COMPUTATIONAL-3
COMP-3
IS
DISPLAY
NATIONAL

SIGN

CHARACTER
LEADING SEPARATE

OCCURS dimension

.
TIMES

IS
VALUE

numeric-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.

190

Application Programming and SQL Guide
2. PACKED-DECIMAL, COMPUTATIONAL-3, and COMP-3 are equivalent. The
picture-string that is associated with these types must have the form S9(i)V9(d)
(or S9...9V9...9, with i and d instances of 9) or S9(i)V.
3. The picture-string that is associated with SIGN LEADING SEPARATE must have
the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9 or S9...9V with i
instances of 9).
4. dimension must be an integer constant between 1 and 32767.
Character host variable arrays: The three valid forms of character host variable
arrays are:
v Fixed-length character strings
v Varying-length character strings
v CLOBs
The following diagrams show the syntax for forms other than CLOBs.
The following diagram shows the syntax for declarations of fixed-length character
string arrays.
IS
level-1 variable-name

PICTURE
PIC

picture-string

OCCURS dimension
DISPLAY

TIMES

IS
USAGE

.
IS
VALUE

character-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. The picture-string that is associated with these forms must be X(m) (or XX...X,
with m instances of X), with 1 <= m <= 32767 for fixed-length strings. However,
the maximum length of the CHAR data type (fixed-length character string) in
DB2 is 255 bytes.
3. dimension must be an integer constant between 1 and 32767.
The following diagram shows the syntax for declarations of varying-length
character string arrays.
level-1 variable-name OCCURS dimension

.
TIMES

IS
49 var-1

PICTURE
PIC

S9(4)
S9999

IS
USAGE

Chapter 3. Including DB2 queries in an application program

191
BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

SYNCHRONIZED
SYNC

IS
VALUE

numeric-constant

.

IS
49 var-2

PICTURE
PIC

picture-string

.
DISPLAY
IS

IS
VALUE

character-constant

USAGE

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL
with TRUNC(STD) recognizes only values up to 9999. This can cause data
truncation errors when COBOL statements execute and might effectively limit
the maximum length of variable-length character strings to 9999. Consider
using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data
truncation.
3. The picture-string that is associated with these forms must be X(m) (or XX...X,
with m instances of X), with 1 <= m <= 32767 for fixed-length strings; for other
strings, m cannot be greater than the maximum size of a varying-length
character string.
4. You cannot directly reference var-1 and var-2 as host variable arrays.
5. You cannot use an intervening REDEFINE at level 49.
6. dimension must be an integer constant between 1 and 32767.
Example: The following example shows declarations of a fixed-length character
array and a varying-length character array:
01

OUTPUT-VARS.
05 NAME OCCURS 10 TIMES.
49 NAME-LEN
PIC S9(4) COMP-4 SYNC.
49 NAME-DATA PIC X(40).
05 SERIAL-NUMBER PIC S9(9) COMP-4 OCCURS 10 TIMES.

Graphic character host variable arrays: The three valid forms for graphic character
host variable arrays are:
v Fixed-length strings
v Varying-length strings
v DBCLOBs
The following diagrams show the syntax for forms other than DBCLOBs.

192

Application Programming and SQL Guide
The following diagram shows the syntax for declarations of fixed-length graphic
string arrays.
IS
level-1 variable-name

PICTURE
PIC

picture-string

IS
USAGE

DISPLAY-1
NATIONAL

OCCURS dimension
TIMES
.

IS
VALUE

graphic-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
3. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the DB2 coprocessor.
4. dimension must be an integer constant between 1 and 32767.
The following diagram shows the syntax for declarations of varying-length graphic
string arrays.
level-1

variable-name OCCURS dimension

.
TIMES

IS
49 var-1

PICTURE
PIC

S9(4)
S9999

IS
USAGE

BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

SYNCHRONIZED
SYNC

IS
VALUE

numeric-constant

.

49 var-2

PICTURE
PIC

Chapter 3. Including DB2 queries in an application program

193
IS

IS
picture-string USAGE

DISPLAY-1
NATIONAL
.

IS
VALUE

graphic-constant

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL
with TRUNC(STD) recognizes only values up to 9999. This can cause data
truncation errors when COBOL statements execute and might effectively limit
the maximum length of variable-length character strings to 9999. Consider
using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data
truncation.
3. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
4. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the DB2 coprocessor.
5. You cannot directly reference var-1 and var-2 as host variable arrays.
6. dimension must be an integer constant between 1 and 32767.
LOB, locator, file reference, and XML variables arrays: The following diagram
shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable,
locator, and file reference arrays. See “Large objects (LOBs)” on page 390 for a
discussion of how to use LOB variables.

|
|
|
|

level-1 variable-name

SQL TYPE IS
IS
USAGE

|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB-LOCATOR
CLOB-LOCATOR
DBCLOB-LOCATOR
BLOB_FILE
CLOB_FILE
DBCLOB_FILE
OCCURS dimension

(

length

)
K
M
G

.
TIMES

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. dimension must be an integer constant between 1 and 32767.

194

Application Programming and SQL Guide
|
|
|
|

The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variable and file reference arrays for XML data types.
level-1 variable-name

SQL TYPE IS XML AS
IS
USAGE

|
|

|
|
|
|
|
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB-FILE
CLOB-FILE
DBCLOB-FILE
OCCURS dimension

( length

)
K
M
G

.
TIMES

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. dimension must be an integer constant between 1 and 32767.
ROWIDs: The following diagram shows the syntax for declarations of ROWID
variable arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to
use these host variables.
level-1 variable-name

SQL TYPE IS ROWID OCCURS dimension
IS

.
TIMES

USAGE

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. dimension must be an integer constant between 1 and 32767.

PL/I syntax for host variable array declarations
In PL/I programs, you can specify numeric, character, graphic, binary, LOB, XML,
and ROWID host variable arrays. You can also specify LOB locators and LOB and
XML file reference variables.
Only some of the valid PL/I declarations are valid host variable array declarations.
The precompiler uses the data attribute defaults that are specified in the PL/I
DEFAULT statement. If the declaration for a variable array is not valid, then any
SQL statement that references the host variable array might result in the message
UNDECLARED HOST VARIABLE ARRAY.
The precompiler uses only the names and data attributes of the variable arrays; it
ignores the alignment, scope, and storage attributes. Even though the precompiler
ignores alignment, scope, and storage, if you ignore the restrictions on their use,
you might have problems compiling the PL/I source code that the precompiler
generates. These restrictions are as follows:
v A declaration with the EXTERNAL scope attribute and the STATIC storage
attribute must also have the INITIAL storage attribute.
Chapter 3. Including DB2 queries in an application program

195
v If you use the BASED storage attribute, you must follow it with a PL/I
element-locator-expression.
v Host variables can be STATIC, CONTROLLED, BASED, or AUTOMATIC storage
class or options. However, CICS requires that programs be reentrant.
Declaring host variable arrays: You must specify the ALIGNED attribute when
you declare varying-length character arrays or varying-length graphic arrays that
are to be used in multiple-row INSERT and FETCH statements.
Numeric host variable arrays: The following diagram shows the syntax for
declarations of numeric host variable arrays.
DECLARE
DCL

variable-name
,
(

( dimension )

variable-name

)

,
(
BINARY
BIN
DECIMAL
DEC

variable-name ( dimension )

)

FIXED
( precision

)
,scale

FLOAT ( precision )

Alignment and/or Scope and/or Storage

Note:
1. You can specify host variable array attributes in any order that is acceptable to
PL/I. For example, BIN FIXED(31), BINARY FIXED(31), BIN(31) FIXED, and
FIXED BIN(31) are all acceptable.
2. You can specify the scale for only DECIMAL FIXED.
3. dimension must be an integer constant between 1 and 32767.
Example: The following example shows a declaration of an indicator array:
DCL IND_ARRAY(100) BIN FIXED(15);

/* DCL ARRAY of 100 indicator variables */

Character host variable arrays: The following diagram shows the syntax for
declarations of character host variable arrays, other than CLOBs.
DECLARE
DCL

variable-name
,
(

variable-name

( dimension )

)

,
(
CHARACTER
CHAR

variable-name ( dimension )

)

( length )
VARYING
VAR

Alignment and/or Scope and/or Storage

Note:
1. dimension must be an integer constant between 1 and 32767.

196

Application Programming and SQL Guide
Example: The following example shows the declarations needed to retrieve 10
rows of the department number and name from the department table:
DCL DEPTNO(10)
DCL DEPTNAME(10)

CHAR(3);
CHAR(29) VAR;

/* Array of ten CHAR(3) variables */
/* Array of ten VARCHAR(29) variables */

Graphic host variable arrays: The following diagram shows the syntax for
declarations of graphic host variable arrays, other than DBCLOBs.
DECLARE
DCL

variable-name
,
(

( dimension )

variable-name

)

,
(

variable-name ( dimension )

)

GRAPHIC ( length )
VARYING
VAR

Alignment and/or Scope and/or Storage

Note:
1. dimension must be an integer constant between 1 and 32767.
|
|
|
|

Binary host variable arrays: The following diagram shows the syntax for
declarations of binary variable arrays.
DCL
DECLARE

variable-name
,
(

variable-name

( dimension )

)

,
(

|
|
|
|
|
|
|

SQL TYPE IS

variable-name ( dimension )

)

BINARY
VARBINARY

LOB, locator, file reference, and XML variable arrays: The following diagram
shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable,
locator, and file reference variable arrays. See “Large objects (LOBs)” on page 390
for a discussion of how to use these host variables.
DCL
DECLARE

variable-name
,
(

variable-name

( dimension )

SQL TYPE IS

)

,
(

variable-name ( dimension )

)

Chapter 3. Including DB2 queries in an application program

197
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

(

length

)
K
M
G

Note:
1. dimension must be an integer constant between 1 and 32767.
The following diagram shows the syntax for declarations of BLOB, CLOB, and
DBCLOB host variable arrays, and file reference variable arrays for XML data
types.

|
|
|
|
|

DCL
DECLARE

variable-name
,
(

variable-name

( dimension )

)

,
(

|
|

variable-name ( dimension )

SQL TYPE IS XML AS

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

)
(

length

)
K
M
G

|
Note:
1. dimension must be an integer constant between 1 and 32767.

|
|

ROWIDs: The following diagram shows the syntax for declarations of ROWID
variable arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to
use these host variables.
DCL
DECLARE

variable-name
,
(

variable-name

( dimension )

)

,
(
SQL TYPE IS ROWID

198

Application Programming and SQL Guide

variable-name ( dimension )

)
Note:
1. dimension must be an integer constant between 1 and 32767.

Host structures in an SQL statement
A host structure is a group of host variables that can be referenced with a single
name. You define host structures with statements in the host language.
You can substitute a host structure for one or more host variables. You can also use
indicator variables (or indicator structures) with host structures.
You can use host structures in all host languages except REXX.

Host structures in C or C++
A C host structure contains an ordered group of data fields. For example:
struct {char c1[3];
struct {short len;
char data[5];
}c2;
char c3[2];
}target;

In this example, target is the name of a host structure consisting of the c1, c2, and
c3 fields. c1 and c3 are character arrays, and c2 is the host variable equivalent to
the SQL VARCHAR data type. The target host structure can be part of another host
structure but must be the deepest level of the nested structure.
The following diagram shows the syntax for declarations of host structures.
struct
auto
extern
static

const
volatile

packed

{
tag

Chapter 3. Including DB2 queries in an application program

199
|
float
double

var-1 ;

}

int
short
sqlint32
int
long
int
long long
decimal ( precision
, scale )
varchar structure
binary structure
vargraphic structure
SQL TYPE IS ROWID
LOB data type
char var-2
unsigned
[ length ]
sqldbchar var-5
;
[ length ]
variable-name

;

;
=expression

The following diagram shows the syntax for VARCHAR structures that are used
within declarations of host structures.
int
struct

{
tag

short

var-3 ;

signed

char var-4 [ length ] ; }
unsigned

The following diagram shows the syntax for VARGRAPHIC structures that are
used within declarations of host structures.
int
struct

{
tag

short

var-6 ; sqldbchar var-7 [ length ] ; }

signed

The following diagram shows the syntax for binary structures that are used within
declarations of host structures.

|
|
|

SQL TYPE IS

BINARY
VARBINARY
BINARY VARYING

(length)

|
The following diagram shows the syntax for LOB data types that are used within
declarations of host structures.

|

200

Application Programming and SQL Guide
SQL TYPE IS

|
|
|

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR

( length

)
K
M
G

The following diagram shows the syntax for LOB data types that are used within
declarations of host structures for XML data.
SQL TYPE IS XML AS

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

( length

)
K
M
G

|
|

Host structures in COBOL
A COBOL host structure is a named set of host variables defined in your
program’s WORKING-STORAGE SECTION or LINKAGE SECTION. COBOL host
structures have a maximum of two levels, even though the host structure might
occur within a structure with multiple levels. However, you can declare a
varying-length character string, which must be level 49.
A host structure name can be a group name whose subordinate levels name
elementary data items. In the following example, B is the name of a host structure
consisting of the elementary items C1 and C2.
01 A
02 B
03 C1 PICTURE ...
03 C2 PICTURE ...

When you write an SQL statement using a qualified host variable name (perhaps
to identify a field within a structure), use the name of the structure followed by a
period and the name of the field. For example, specify B.C1 rather than C1 OF B or
C1 IN B.
The DB2 precompiler does not recognize host variables or host structures on any
subordinate levels after one of the following items:
v A COBOL item that begins in area A
v Any SQL statement (except SQL INCLUDE)
v Any SQL statement within an included member
When the DB2 precompiler encounters one of the preceding items in a host
structure, it considers the structure to be complete.
The following diagram shows the syntax for declarations of host structures.

Chapter 3. Including DB2 queries in an application program

201
level-1

variable-name

level-2

var-1

.

numeric-usage .
IS
PICTURE
integer-decimal-usage .
PIC
picture-string
char-inner-variable .
varchar-inner-variables
vargraphic-inner-variables
SQL TYPE IS ROWID .
IS
USAGE
SQL TYPE IS TABLE LIKE table-name AS LOCATOR
IS
USAGE
LOB data type .
IS
USAGE

.

The following diagram shows the syntax for numeric-usage items that are used
within declarations of host structures.
COMPUTATIONAL-1
COMP-1
COMPUTATIONAL-2
COMP-2

IS
USAGE

IS
VALUE

constant

The following diagram shows the syntax for integer and decimal usage items that
are used within declarations of host structures.

IS
USAGE
BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP
PACKED-DECIMAL
COMPUTATIONAL-3
COMP-3
IS
DISPLAY
NATIONAL

SIGN

LEADING SEPARATE
CHARACTER

IS
VALUE

constant

The following diagram shows the syntax for CHAR inner variables that are used
within declarations of host structures.

202

Application Programming and SQL Guide
IS
PICTURE
PIC

picture-string
DISPLAY
IS
USAGE

IS
VALUE

constant

The following diagram shows the syntax for VARCHAR inner variables that are
used within declarations of host structures.
(1)
49

IS
var-2

PICTURE
PIC

S9(4)
S9999

IS
USAGE

BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

.
IS
VALUE

numeric-constant

Notes:
|

1

The number 49 has a special meaning to DB2. Do not specify another number.
IS
49 var-3

PICTURE
PIC

picture-string

.
DISPLAY
IS

IS
VALUE

character-constant

USAGE

The following diagram shows the syntax for VARGRAPHIC inner variables that
are used within declarations of host structures.
IS
49 var-4

PICTURE
PIC

S9(4)
S9999

IS
USAGE

Chapter 3. Including DB2 queries in an application program

203
BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

.
IS
VALUE

numeric-constant

IS
49 var-5

PICTURE
PIC

picture-string
IS
USAGE

DISPLAY-1
NATIONAL

.
IS
VALUE

graphic-constant

Notes:
1. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
2. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the DB2 coprocessor.
The following diagram shows the syntax for LOB variables, locators, and file
reference variables that are used within declarations of host structures.
|

SQL TYPE IS

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB-LOCATOR
CLOB-LOCATOR
DBCLOB-LOCATOR
BLOB-FILE
CLOB-FILE
DBCLOB-FILE

(

length

)
K
M
G

Notes:
1. level-1 indicates a COBOL level between 1 and 47.
2. level-2 indicates a COBOL level between 2 and 48.
3. For elements within a structure, use any level 02 through 48 (rather than 01 or
77), up to a maximum of two levels.
4. Using a FILLER or optional FILLER item within a host structure declaration
can invalidate the whole structure.
The following diagram shows the syntax for LOB variables and file reference
variables that are used within declarations of host structures for XML.

|
|

204

Application Programming and SQL Guide
|

SQL TYPE IS XML AS

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB-FILE
CLOB-FILE
DBCLOB-FILE

( length

)
K
M
G

|
|
|
|
|
|
|
|

Notes:
1. level-1 indicates a COBOL level between 1 and 47.
2. level-2 indicates a COBOL level between 2 and 48.
3. For elements within a structure, use any level 02 through 48 (rather than 01 or
77), up to a maximum of two levels.
4. Using a FILLER or optional FILLER item within a host structure declaration
can invalidate the whole structure.

Host structures in PL/I
A PL/I host structure name can be a structure name whose subordinate levels
name scalars. For example:
DCL 1 A,
2 B,
3 C1 CHAR(...),
3 C2 CHAR(...);

In this example, B is the name of a host structure consisting of the scalars C1 and
C2.
You can use the structure name as shorthand notation for a list of scalars. You can
qualify a host variable with a structure name (for example, STRUCTURE.FIELD).
Host structures are limited to two levels. You can think of a host structure for DB2
data as a named group of host variables.
You must terminate the host structure variable by ending the declaration with a
semicolon. For example:
DCL 1 A,
2 B CHAR,
2 (C, D) CHAR;
DCL (E, F) CHAR;

You can specify host variable attributes in any order that is acceptable to PL/I. For
example, BIN FIXED(31), BIN(31) FIXED, and FIXED BIN(31) are all acceptable.
The following diagram shows the syntax for declarations of host structures.
DECLARE
DCL

level-1 variable-name

,
Scope and/or storage

Chapter 3. Including DB2 queries in an application program

205
,
level-2

var-1
,
(

data-type-specification

var-2

;

)

The following diagram shows the syntax for data types that are used within
declarations of host structures.
|

CHARACTER
CHAR

(

integer )

VARYING
VAR

GRAPHIC
( integer )
BINARY
BIN
DECIMAL
DEC

VARYING
VAR

FIXED
( precision

)
, scale

FLOAT
( precision )

SQL TYPE IS ROWID
LOB data type

The following diagram shows the syntax for LOB data types that are used within
declarations of host structures.
|

SQL TYPE IS

CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BINARY LARGE OBJECT
BLOB
CLOB_LOCATOR
DBCLOB_LOCATOR
BLOB_LOCATOR
CLOB_FILE
DBCLOB_FILE
BLOB_FILE

(

length

)
K
M
G

The following diagram shows the syntax for LOB data types that are used within
declarations of host structures for XML data.

|
|
|

SQL TYPE IS XML AS

BINARY LARGE OBJECT
BLOB
CHARACTER LARGE OBJECT
CHAR LARGE OBJECT
CLOB
DBCLOB
BLOB_FILE
CLOB_FILE
DBCLOB_FILE

( length

)
K
M
G

|

Retrieving a single row of data into a host structure

|

If you know that your query returns multiple column values for only one row, you
can specify a host structure to contain the column values.

206

Application Programming and SQL Guide
In the following example, assume that your COBOL program includes the
following SQL statement:
EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT
INTO :EMPNO, :FIRSTNME, :MIDINIT, :LASTNAME, :WORKDEPT
FROM DSN8910.VEMP
WHERE EMPNO = :EMPID
END-EXEC.

If you want to avoid listing host variables, you can substitute the name of a
structure, say :PEMP, that contains :EMPNO, :FIRSTNME, :MIDINIT, :LASTNAME,
and :WORKDEPT. The example then reads:
EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT
INTO :PEMP
FROM DSN8910.VEMP
WHERE EMPNO = :EMPID
END-EXEC.

You can declare a host structure yourself, or you can use DCLGEN to generate a
COBOL record description, PL/I structure declaration, or C structure declaration
that corresponds to the columns of a table. For more detailed information about
coding a host structure in your program, see “Example: Adding a table declaration
and host-variable structure to a library” on page 127. For more information about
using DCLGEN and the restrictions that apply to the C language, see “DCLGEN
(declarations generator)” on page 125.

Indicator variables and indicator variable arrays
An indicator variable is associated with a particular host variable. Each indicator
variable contains a small integer value that indicates some information about the
associated host variable. An indicator variable array serves the same purpose for a
host variable array.
Indicator variables are small integers that you can use to:
v Determine whether the value of an associated output host variable is null or
indicate that the value of an input host variable is null
v Determine the original length of a character string that was truncated during
assignment to a host variable
v Determine that a character value could not be converted during assignment to a
host variable
v Determine the seconds portion of a time value that was truncated during
assignment to a host variable
Retrieving data and testing the indicator variable: When DB2 retrieves the value
of a column into a host variable, you can test the indicator variable that is
associated with that host variable:
v If the value of the indicator variable is less than zero, the column value is null.
The value of the host variable does not change from its previous value. If it is
null because of a numeric or character conversion error, or an arithmetic
expression error, DB2 sets the indicator variable to -2. See “Arithmetic and
conversion errors” on page 317 for more information.
v If the indicator variable contains a positive integer, the retrieved value is
truncated, and the integer is the original length of the string.
v If the value of the indicator variable is zero, the column value is nonnull. If the
column value is a character string, the retrieved value is not truncated.
Chapter 3. Including DB2 queries in an application program

207
An error occurs if you do not use an indicator variable and DB2 retrieves a null
value.
You can specify an indicator variable, preceded by a colon, immediately after the
host variable. Optionally, you can use the word INDICATOR between the host
variable and its indicator variable. Thus, the following two examples are
equivalent:
EXEC SQL
SELECT PHONENO
INTO :CBLPHONE:INDNULL
FROM DSN8910.EMP
WHERE EMPNO = :EMPID
END-EXEC.

EXEC SQL
SELECT PHONENO
INTO :CBLPHONE INDICATOR :INDNULL
FROM DSN8910.EMP
WHERE EMPNO = :EMPID
END-EXEC.

You can then test INDNULL for a negative value. If it is negative, the
corresponding value of PHONENO is null, and you can disregard the contents of
CBLPHONE.
When you use a cursor to fetch a column value, you can use the same technique to
determine whether the column value is null.
Inserting null values into columns by using host variable indicators:You can use
an indicator variable to insert a null value from a host variable into a column.
When DB2 processes INSERT, UPDATE, and MERGE statements, it checks the
indicator variable (if one exists). If the indicator variable is negative, the column
value is null. If the indicator variable is greater than -1, the associated host variable
contains a value for the column.

|
|
|
|
|
|

For example, suppose your program reads an employee ID and a new phone
number, and must update the employee table with the new number. The new
number could be missing if the old number is incorrect, but a new number is not
yet available. If the new value for column PHONENO might be null, you can use
an indicator variable in the UPDATE statement. For example:
EXEC SQL
UPDATE DSN8910.EMP
SET PHONENO = :NEWPHONE:PHONEIND
WHERE EMPNO = :EMPID
END-EXEC.

When NEWPHONE contains a non-null value, set PHONEIND to zero by
preceding the UPDATE statement with the following line:
MOVE 0 TO PHONEIND.

When NEWPHONE contains a null value, set PHONEIND to a negative value by
preceding the UPDATE statement with the following line:
MOVE -1 TO PHONEIND.

Testing for a null column value: You cannot determine whether a column value is
null by comparing it to a host variable with an indicator variable that is set to -1.
To test whether a column has a null value, use the IS NULL predicate or the IS
DISTINCT FROM predicate. For example, the following code does not select the
employees who have no phone number:
MOVE -1 TO PHONE-IND.
EXEC SQL
SELECT LASTNAME

208

Application Programming and SQL Guide
INTO :PGM-LASTNAME
FROM DSN8910.EMP
WHERE PHONENO = :PHONE-HV:PHONE-IND
END-EXEC.

You can use the IS NULL predicate to select employees who have no phone
number, as in the following statement:
EXEC SQL
SELECT LASTNAME
INTO :PGM-LASTNAME
FROM DSN8910.EMP
WHERE PHONENO IS NULL
END-EXEC.

To select employees whose phone numbers are equal to the value of :PHONE-HV
and employees who have no phone number (as in the second example), you would
need to code two predicates, one to handle the non-null values and another to
handle the null values, as in the following statement:
EXEC SQL
SELECT LASTNAME
INTO :PGM-LASTNAME
FROM DSN8910.EMP
WHERE (PHONENO = :PHONE-HV AND PHONENO IS NOT NULL AND :PHONE-HV IS NOT NULL)
OR
(PHONENO IS NULL AND :PHONE-HV:PHONE-IND IS NULL)
END-EXEC.

You can simplify the preceding example by coding the statement using the NOT
form of the IS DISTINCT FROM predicate, as in the following statement:
EXEC SQL
SELECT LASTNAME
INTO :PGM-LASTNAME
FROM DSN8910.EMP
WHERE PHONENO IS NOT DISTINCT FROM :PHONE-HV:PHONE-IND
END-EXEC.

Using indicator variable arrays with host variable arrays
You can use indicator variable arrays with host variable arrays in the same way
that you use indicator variables with host variables. An indicator variable array
must have at least as many entries as its host variable array.

Using indicator variables with host structures
You can define an indicator structure (an array of halfword integer variables) to
support a host structure. You define indicator structures in the DATA DIVISION
section of your COBOL program. If the column values your program retrieves into
a host structure can be null, you can attach an indicator structure name to the host
structure name. This name enables DB2 to notify your program about each null
value it returns to a host variable in the host structure. For example:
01 PEMP-ROW.
10 EMPNO
10 FIRSTNME.
49 FIRSTNME-LEN
49 FIRSTNME-TEXT
10 MIDINIT
10 LASTNAME.
49 LASTNAME-LEN
49 LASTNAME-TEXT
10 WORKDEPT

PIC X(6).
PIC S9(4) USAGE COMP.
PIC X(12).
PIC X(1).
PIC S9(4) USAGE COMP.
PIC X(15).
PIC X(3).
Chapter 3. Including DB2 queries in an application program

209
10 EMP-BIRTHDATE
PIC X(10).
01 INDICATOR-TABLE.
PIC S9(4) COMP OCCURS 6 TIMES.
. 02 EMP-IND
.
.
MOVE ’000230’ TO EMPNO.
.
.
.
EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, BIRTHDATE
INTO :PEMP-ROW:EMP-IND
FROM DSN8910.EMP
WHERE EMPNO = :EMPNO
END-EXEC.

In this example, EMP-IND is an array containing six values, which you can test for
negative values. If, for example, EMP-IND(6) contains a negative value, the
corresponding host variable in the host structure (EMP-BIRTHDATE) contains a
null value.
Because this example selects rows from the table DSN8910.EMP, some of the values
in EMP-IND are always zero. The first four columns of each row are defined NOT
NULL. In the preceding example, DB2 selects the values for a row of data into a
host structure. You must use a corresponding structure for the indicator variables
to determine which (if any) selected column values are null. For information on
using the IS NULL keyword phrase in WHERE clauses, see “Retrieving data by
using the SELECT statement” on page 584.

Indicator variables in assembler
An indicator variable is a 2-byte integer (DS HL2). If you provide an indicator
variable for the variable X, when DB2 retrieves a null value for X, it puts a
negative value in the indicator variable and does not update X. Your program
should check the indicator variable before using X. If the indicator variable is
negative, you know that X is null and any value you find in X is irrelevant.
When your program uses X to assign a null value to a column, the program
should set the indicator variable to a negative number. DB2 then assigns a null
value to the column and ignores any value in X.
You declare indicator variables in the same way as host variables. You can mix the
declarations of the two types of variables in any way that seems appropriate.
Example: The following example shows a FETCH statement with the declarations
of the host variables that are needed for the FETCH statement:
EXEC SQL FETCH CLS_CURSOR INTO :CLSCD,
:DAY :DAYIND,
:BGN :BGNIND,
:END :ENDIND

X
X
X

You can declare variables as follows:
CLSCD
DAY
BGN
END
DAYIND
BGNIND
ENDIND

DS
DS
DS
DS
DS
DS
DS

CL7
HL2
CL8
CL8
HL2
HL2
HL2

INDICATOR VARIABLE FOR DAY
INDICATOR VARIABLE FOR BGN
INDICATOR VARIABLE FOR END

The following figure shows the syntax for declarations of indicator host variables.

210

Application Programming and SQL Guide
variable-name

DC
DS

H
1

L2

Figure 13. Indicator variable

Indicator variables and indicator variable arrays in C or C++
An indicator variable is a 2-byte integer (short int). An indicator variable array is
an array of 2-byte integers (short int). You use indicator variables and indicator
variable arrays in similar ways.
Using indicator variables: If you provide an indicator variable for the variable X,
when DB2 retrieves a null value for X, it puts a negative value in the indicator
variable and does not update X. Your program should check the indicator variable
before using X. If the indicator variable is negative, you know that X is null and
any value you find in X is irrelevant.
When your program uses X to assign a null value to a column, the program
should set the indicator variable to a negative number. DB2 then assigns a null
value to the column and ignores any value in X.
Using indicator variable arrays: When you retrieve data into a host variable array,
if a value in its indicator array is negative, you can disregard the contents of the
corresponding element in the host variable array.
Declaring indicator variables: You declare indicator variables in the same way as
host variables. You can mix the declarations of the two types of variables in any
way that seems appropriate.
Example: The following example shows a FETCH statement with the declarations
of the host variables that are needed for the FETCH statement:
EXEC SQL FETCH CLS_CURSOR INTO :ClsCd,
:Day :DayInd,
:Bgn :BgnInd,
:End :EndInd;

You can declare variables as follows:
EXEC SQL BEGIN DECLARE SECTION;
char ClsCd[8];
char Bgn[9];
char End[9];
short Day, DayInd, BgnInd, EndInd;
EXEC SQL END DECLARE SECTION;

The following figure shows the syntax for declarations of an indicator variable.

Chapter 3. Including DB2 queries in an application program

211
,
int
short
auto
extern
static

const
volatile

variable-name

signed

;
=

expression

Figure 14. Indicator variable

Declaring indicator variable arrays: The following figure shows the syntax for
declarations of an indicator array or a host structure indicator array.

int
short
auto
extern
static

const
volatile

signed

,
variable-name [ dimension ]

;
= expression

Figure 15. Host structure indicator array

Note: The dimension must be an integer constant between 1 and 32767.

Indicator variables and indicator variable arrays in COBOL
An indicator variable is a 2-byte integer (PIC S9(4) USAGE BINARY). An indicator
variable array is an array of 2-byte integers (PIC S9(4) USAGE BINARY). You use
indicator variables and indicator variable arrays in similar ways.
Using indicator variables: If you provide an indicator variable for the variable X,
when DB2 retrieves a null value for X, it puts a negative value in the indicator
variable and does not update X. Your program should check the indicator variable
before using X. If the indicator variable is negative, you know that X is null and
any value you find in X is irrelevant.
When your program uses X to assign a null value to a column, the program
should set the indicator variable to a negative number. DB2 then assigns a null
value to the column and ignores any value in X.
Using indicator variable arrays: When you retrieve data into a host variable array,
if a value in its indicator array is negative, you can disregard the contents of the
corresponding element in the host variable array.
Declaring indicator variables: You declare indicator variables in the same way as
host variables. You can mix the declarations of the two types of variables in any
way that seems appropriate. You can define indicator variables as scalar variables
or as array elements in a structure form or as an array variable using a single level
OCCURS clause.

212

Application Programming and SQL Guide
Example: The following example shows a FETCH statement with the declarations
of the host variables that are needed for the FETCH statement:
EXEC SQL FETCH CLS_CURSOR INTO :CLS-CD,
:DAY :DAY-IND,
:BGN :BGN-IND,
:END :END-IND
END-EXEC.

You can declare the variables as follows:
77
77
77
77
77
77
77

CLS-CD
DAY
BGN
END
DAY-IND
BGN-IND
END-IND

PIC
PIC
PIC
PIC
PIC
PIC
PIC

X(7).
S9(4)
X(8).
X(8).
S9(4)
S9(4)
S9(4)

BINARY.
BINARY.
BINARY.
BINARY.

The following figure shows the syntax for declarations of indicator variables.

IS
01
77

variable-name

PICTURE
PIC

S9(4)
S9999

IS
USAGE

BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

.
IS
VALUE

constant

Figure 16. Indicator variable

Declaring indicator variable arrays: The following figure shows the syntax for
valid indicator array declarations.

IS
level-1 variable-name

PICTURE
PIC

S9(4)
S9999

IS
USAGE

BINARY
COMPUTATIONAL-4
COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

OCCURS dimension

.
TIMES

IS
VALUE

constant

Figure 17. Host structure indicator array

Note:

Chapter 3. Including DB2 queries in an application program

213
1. level-1 must be an integer between 2 and 48.
2. dimension must be an integer constant between 1 and 32767.

Indicator variables in Fortran
An indicator variable is a 2-byte integer (INTEGER*2). If you provide an indicator
variable for the variable X, when DB2 retrieves a null value for X, it puts a
negative value in the indicator variable and does not update X. Your program
should check the indicator variable before using X. If the indicator variable is
negative, you know that X is null and any value you find in X is irrelevant.
When your program uses X to assign a null value to a column, the program
should set the indicator variable to a negative number. DB2 then assigns a null
value to the column and ignores any value in X.
You declare indicator variables in the same way as host variables. You can mix the
declarations of the two types of variables in any way that seems appropriate.
Example: The following example shows a FETCH statement with the declarations
of the host variables that are needed for the FETCH statement:
EXEC SQL FETCH CLS_CURSOR INTO :CLSCD,
:DAY :DAYIND,
:BGN :BGNIND,
:END :ENDIND

C
C
C

You can declare variables as follows:
CHARACTER*7
INTEGER*2
CHARACTER*8
INTEGER*2

CLSCD
DAY
BGN, END
DAYIND, BGNIND, ENDIND

The following figure shows the syntax for declarations of indicator variables.

,
INTEGER*2

variable-name
/ numeric-constant /

Figure 18. Indicator variable

Indicator variables and indicator variable arrays in PL/I
An indicator variable is a 2-byte integer (or an integer declared as BIN FIXED(15)).
An indicator variable array is an array of 2-byte integers. You use indicator
variables and indicator variable arrays in similar ways.
Using indicator variables: If you provide an indicator variable for the variable X,
when DB2 retrieves a null value for X, it puts a negative value in the indicator
variable and does not update X. Your program should check the indicator variable
before using X. If the indicator variable is negative, you know that X is null and
any value you find in X is irrelevant.
When your program uses X to assign a null value to a column, the program
should set the indicator variable to a negative number. DB2 then assigns a null
value to the column and ignores any value in X.

214

Application Programming and SQL Guide
Using indicator variable arrays: When you retrieve data into a host variable array,
if a value in its indicator array is negative, you can disregard the contents of the
corresponding element in the host variable array.
Declaring indicator variables: You declare indicator variables in the same way as
host variables. You can mix the declarations of the two types of variables in any
way that seems appropriate.
Example: The following example shows a FETCH statement with the declarations
of the host variables that are needed for the FETCH statement:
EXEC SQL FETCH CLS_CURSOR INTO :CLS_CD,
:DAY :DAY_IND,
:BGN :BGN_IND,
:END :END_IND;

You can declare the variables as follows:
DCL
DCL
DCL
DCL
DCL

CLS_CD
DAY
BGN
END
(DAY_IND,

CHAR(7);
BIN FIXED(15);
CHAR(8);
CHAR(8);
BGN_IND, END_IND)

BIN FIXED(15);

You can specify host variable attributes in any order that is acceptable to PL/I. For
example, BIN FIXED(31), BIN(31) FIXED, and FIXED BIN(31) are all acceptable.
The following figure shows the syntax for declarations of indicator variables.

,
DECLARE
DCL

(

variable-name

)

BINARY
BIN

FIXED(15) ;

Figure 19. Indicator variable

Declaring indicator arrays: The following figure shows the syntax for declarations
of indicator arrays.

DECLARE
DCL

variable-name (
,
(

dimension )

BINARY
BIN

variable-name ( dimension )

FIXED(15)

)
;

Alignment and/or Scope and/or Storage

Figure 20. Indicator array

Note:
1. dimension must be an integer constant between 1 and 32767.

Indicator variables in REXX
When you retrieve a null value from a column, DB2 puts a negative value in an
indicator variable to indicate that the data in the corresponding host variable is
Chapter 3. Including DB2 queries in an application program

215
null. When you pass a null value to DB2, you assign a negative value to an
indicator variable to indicate that the corresponding host variable has a null value.
The way that you use indicator variables for input host variables in REXX
procedures is slightly different from the way that you use indicator variables in
other languages. When you want to pass a null value to a DB2 column, in addition
to putting a negative value in an indicator variable, you also need to put a valid
value in the corresponding host variable. For example, to set a value of
WORKDEPT in table EMP to null, use statements like these:
SQLSTMT="UPDATE EMP" ,
"SET WORKDEPT = ?"
HVWORKDEPT=’000’
INDWORKDEPT=-1
"EXECSQL PREPARE S100 FROM :SQLSTMT"
"EXECSQL EXECUTE S100 USING :HVWORKDEPT :INDWORKDEPT"

After you retrieve data from a column that can contain null values, you should
always check the indicator variable that corresponds to the output host variable for
that column. If the indicator variable value is negative, the retrieved value is null,
so you can disregard the value in the host variable.
In the following program, the phone number for employee Haas is selected into
variable HVPhone. After the SELECT statement executes, if no phone number for
employee Haas is found, indicator variable INDPhone contains -1.
’SUBCOM DSNREXX’
IF RC THEN ,
S_RC = RXSUBCOM(’ADD’,’DSNREXX’,’DSNREXX’)
ADDRESS DSNREXX
’CONNECT’ ’DSN’
SQLSTMT = ,
"SELECT PHONENO FROM DSN8910.EMP WHERE LASTNAME=’HAAS’"
"EXECSQL DECLARE C1 CURSOR FOR S1"
"EXECSQL PREPARE S1 FROM :SQLSTMT"
Say "SQLCODE from PREPARE is "SQLCODE
"EXECSQL OPEN C1"
Say "SQLCODE from OPEN is "SQLCODE
"EXECSQL FETCH C1 INTO :HVPhone :INDPhone"
Say "SQLCODE from FETCH is "SQLCODE
If INDPhone < 0 Then ,
Say ’Phone number for Haas is null.’
"EXECSQL CLOSE C1"
Say "SQLCODE from CLOSE is "SQLCODE
S_RC = RXSUBCOM(’DELETE’,’DSNREXX’,’DSNREXX’)

Indicator arrays for retrieving data
When you retrieve data into a host variable array, you can check the values in the
associated indicator array to determine how to handle each data item.
If a value in the associated indicator array is negative, you can disregard the
contents of the corresponding element in the host variable array. If a value in an
indicator array is:
-1
-2

DB2 returns a null value because an error occurred in numeric conversion
or in an arithmetic expression in the corresponding row.

-3

216

The corresponding row in the column that is being retrieved is null.

DB2 returns a null value because a hole was detected for the
corresponding row during a multiple-row FETCH operation.

Application Programming and SQL Guide
For information about the multiple-row FETCH operation, see “Executing SQL
statements by using a rowset cursor” on page 637. For information about holes in
the result table of a cursor, see “Holes in the result table of a scrollable cursor” on
page 644.

Specifying an indicator array
You must associate an indicator array with a particular host variable array. The
indicator array contains small integers that indicate some information about each
value in the specified host variable array.
You can specify an indicator variable array, preceded by a colon, immediately after
the host variable array. Optionally, you can use the word INDICATOR between the
host variable array and its indicator variable array.
Example: Suppose that you declare a scrollable rowset cursor by using the
following statement:
EXEC SQL
DECLARE CURS1 SCROLL CURSOR WITH ROWSET POSITIONING FOR
SELECT PHONENO
FROM DSN8810.EMP
END-EXEC.

For information about using rowset cursors, see “Accessing data by using a
rowset-positioned cursor” on page 636.
The following two specifications of indicator arrays in the multiple-row FETCH
statement are equivalent:
EXEC SQL
FETCH NEXT ROWSET CURS1
FOR 10 ROWS
INTO :CBLPHONE :INDNULL
END-EXEC.

EXEC SQL
FETCH NEXT ROWSET CURS1
FOR 10 ROWS
INTO :CBLPHONE INDICATOR :INDNULL
END-EXEC.

After the multiple-row FETCH statement, you can test each element of the
INDNULL array for a negative value. If an element is negative, you can disregard
the contents of the corresponding element in the CBLPHONE host variable array.

Inserting null values by using indicator arrays
An indicator array is associated with a particular host variable array. If you need
to insert null values into a column, using an indicator array is an easy way to do
so.
You can use a negative value in an indicator array to insert a null value into a
column.
Example: Assume that host variable arrays hva1 and hva2 have been populated
with values that are to be inserted into the ACTNO and ACTKWD columns.
Assume the ACTDESC column allows nulls. To set the ACTDESC column to null,
assign -1 to the elements in its indicator array:
/* Initialize each indicator array */
for (i=0; i<10; i++) {
ind1[i] = 0;
ind2[i] = 0;
ind3[i] = -1;
}

Chapter 3. Including DB2 queries in an application program

217
EXEC SQL
INSERT INTO DSN8910.ACT
(ACTNO, ACTKWD, ACTDESC)
VALUES (:hva1:ind1, :hva2:ind2, :hva3:ind3)
FOR 10 ROWS;

DB2 ignores the values in the hva3 array and assigns the values in the ARTDESC
column to null for the 10 rows that are inserted.

Errors during output host variable processing
Output host variable processing is the process of moving data that is retrieved from
DB2 to an application. Errors that occur while processing output host variables do
not affect the position of the cursor, and are usually caused by a problem in
converting from one data type to another.
Example: Suppose that an integer value of 32768 is fetched into a smallint host
variable. The conversion might cause an error if you provide insufficient
conversion information to DB2.
If an indicator variable is provided during output host variable processing or if
data type conversion is not required, a positive SQLCODE is returned for the row
in most cases. In other cases where data conversion problems occur, a negative
SQLCODE is returned for that row. Regardless of the SQLCODE for the row, no
new values are assigned to the host variable or to subsequent variables for that
row. Any values that are already assigned to variables remain assigned.
Even when a negative SQLCODE is returned for a row, statement processing
continues and a positive SQLCODE is returned for the statement (SQLSTATE
01668, SQLCODE +354). To determine which rows cause errors when SQLCODE =
+354, you can use GET DIAGNOSTICS.
Example: Suppose that no indicator variables are provided for values that are
returned by the following statement:
FETCH FIRST ROWSET FROM C1 FOR 10 ROWS INTO :hva_col1, :hva_col2;

For each row with an error, a negative SQLCODE is recorded and processing
continues until the 10 rows are fetched. When SQLCODE = +354 is returned for
the statement, you can use GET DIAGNOSTICS to determine which errors occur
for which rows. The following statement returns num_rows = 10 and num_cond =
3:
GET DIAGNOSTICS :num_rows = ROW_COUNT, :num_cond = NUMBER;

To investigate the three conditions, use the following statements:
Statement A
GET DIAGNOSTICS CONDITION 3 :sqlstate = RETURNED_SQLSTATE, :sqlcode =
DB2_RETURNED_SQLCODE, :row_num = DB2_ROW_NUMBER;

Output A
sqlstate = 22003
sqlcode = -304
row_num = 5

Statement B
GET DIAGNOSTICS CONDITION 2 :sqlstate = RETURNED_SQLSTATE, :sqlcode =
DB2_RETURNED_SQLCODE, :row_num = DB2_ROW_NUMBER;

Output B

218

Application Programming and SQL Guide
sqlstate = 22003
sqlcode = -802
row_num = 7

Statement C
GET DIAGNOSTICS CONDITION 1 :sqlstate = RETURNED_SQLSTATE, :sqlcode =
DB2_RETURNED_SQLCODE, :row_num = DB2_ROW_NUMBER;

Output C
sqlstate = 01668
sqlcode = +354
row_num = 0

The fifth row has a data mapping error (-304) for column 1 and the seventh row
has a data mapping error (-802)for column 2. These rows do not contain valid data,
and they should not be used.

Compatibility of SQL and language data types
The data types of the host variables that are used in SQL statements must be
compatible with the data types of the columns with which you intend to use them.

|
|
|
|
|
|
|
|
|
|
|
|
|

When deciding the data types of host variables, consider the following rules and
recommendations:
v Numeric data types are compatible with each other:
Assembler: A SMALLINT, INTEGER, BIGINT, DECIMAL, or FLOAT column is
compatible with a numeric assembler host variable.
C/C++: A SMALLINT, INTEGER, BIGINT, DECIMAL, or FLOAT column is
compatible with any C host variable that is defined as type short int, long int,
long long, long long int, sqlint64, decimal, float, or double.
Fortran: An INTEGER column is compatible with any Fortran host variable that
is defined as INTEGER*2, INTEGER*4, REAL, REAL*4, REAL*8, or DOUBLE
PRECISION.
PL/I: A SMALLINT, INTEGER, BIGINT, DECIMAL, or FLOAT column is
compatible with a PL/I host variable of BIN FIXED(15), BIN FIXED(31),
DECIMAL(s,p), or BIN FLOAT(n), where n is from 1 to 53, or DEC FLOAT(m)
where m is from 1 to 16.
v Character data types are compatible with each other:
Assembler: A CHAR, VARCHAR, or CLOB column is compatible with a
fixed-length or varying-length assembler character host variable.
C/C++: A CHAR, VARCHAR, or CLOB column is compatible with a
single-character, NUL-terminated, or VARCHAR structured form of a C
character host variable.
COBOL: A CHAR, VARCHAR, or CLOB column is compatible with a
fixed-length or varying-length COBOL character host variable.
Fortran: A CHAR, VARCHAR, or CLOB column is compatible with Fortran
character host variable.
PL/I: A CHAR, VARCHAR, or CLOB column is compatible with a fixed-length
or varying-length PL/I character host variable.
v Character data types are partially compatible with CLOB locators. You can
perform the following assignments:
– Assign a value in a CLOB locator to a CHAR or VARCHAR column
– Use a SELECT INTO statement to assign a CHAR or VARCHAR column to a
CLOB locator host variable.
Chapter 3. Including DB2 queries in an application program

219
– Assign a CHAR or VARCHAR output parameter from a user-defined function
or stored procedure to a CLOB locator host variable.
– Use a SET assignment statement to assign a CHAR or VARCHAR transition
variable to a CLOB locator host variable.
– Use a VALUES INTO statement to assign a CHAR or VARCHAR function
parameter to a CLOB locator host variable.
However, you cannot use a FETCH statement to assign a value in a CHAR or
VARCHAR column to a CLOB locator host variable.
v Graphic data types are compatible with each other:
Assembler: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible
with a fixed-length or varying-length assembler graphic character host variable.
C/C++: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible with a
single character, NUL-terminated, or VARGRAPHIC structured form of a C
graphic host variable.
COBOL: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible with a
fixed-length or varying-length COBOL graphic string host variable.
PL/I: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible with a
fixed-length or varying-length PL/I graphic character host variable.
v Graphic data types are partially compatible with DBCLOB locators. You can
perform the following assignments:
– Assign a value in a DBCLOB locator to a GRAPHIC or VARGRAPHIC
column
– Use a SELECT INTO statement to assign a GRAPHIC or VARGRAPHIC
column to a DBCLOB locator host variable.
– Assign a GRAPHIC or VARGRAPHIC output parameter from a user-defined
function or stored procedure to a DBCLOB locator host variable.
– Use a SET assignment statement to assign a GRAPHIC or VARGRAPHIC
transition variable to a DBCLOB locator host variable.
– Use a VALUES INTO statement to assign a GRAPHIC or VARGRAPHIC
function parameter to a DBCLOB locator host variable.

|
|

However, you cannot use a FETCH statement to assign a value in a GRAPHIC
or VARGRAPHIC column to a DBCLOB locator host variable.
v Binary data types are compatible with each other.
v Binary data types are partially compatible with BLOB locators. You can perform
the following assignments:
– Assign a value in a BLOB locator to a BINARY or VARBINARY column.
– Use a SELECT INTO statement to assign a BINARY or VARBINARY column
to a BLOB locator host variable.
– Assign a BINARY or VARBINARY output parameter from a user-defined
function or stored procedure to a BLOB locator host variable.
– Use a SET assignment statement to assign a BINARY or VARBINARY
transition variable to a BLOB locator host variable.
– Use a VALUES INTO statement to assign a BINARY or VARBINARY function
parameter to a BLOB locator host variable.

|
|
|
|

However, you cannot use a FETCH statement to assign a value in a BINARY or
VARBINARY column to a BLOB locator host variable.
v Fortran: A BINARY, VARBINARY, or BLOB column or BLOB locator is
compatible only with a BLOB host variable.

|
|
|
|
|
|
|
|
|
|

220

Application Programming and SQL Guide
v C: For varying-length BIT data, use BINARY. Some C string manipulation
functions process NUL-terminated strings and other functions process strings
that are not NUL-terminated. The C string manipulation functions that process
NUL-terminated strings cannot handle bit data because these functions might
misinterpret a NUL character to be a NUL-terminator.
v Datetime data types are compatible with character host variables.
Assembler: A DATE, TIME, or TIMESTAMP column is compatible with a
fixed-length or varying-length assembler character host variable.
C/C++: A DATE, TIME, or TIMESTAMP column is compatible with a
single-character, NUL-terminated, or VARCHAR structured form of a C
character host variable.
COBOL: A DATE, TIME, or TIMESTAMP column is compatible with a
fixed-length or varying length COBOL character host variable.
Fortran: A DATE, TIME, or TIMESTAMP column is compatible with a Fortran
character host variable.
PL/I: A DATE, TIME, or TIMESTAMP column is compatible with a fixed-length
or varying-length PL/I character host variable.
v The ROWID column is compatible only with a ROWID host variable.
v A host variable is compatible with a distinct type if the host variable type is
compatible with the source type of the distinct type.
v XML columns are compatible with the XML host variable types, character types,
and binary string types.
Recommendation: Use the XML host variable types for data from XML columns.
v Assembler:You can assign LOB data to a file reference variable (BLOB_FILE,
CLOB_FILE, and DBCLOB_FILE).

|
|
|
|
|

When necessary, DB2 automatically converts a fixed-length string to a
varying-length string, or a varying-length string to a fixed-length string.
Related concepts
“Host variable data types for XML data in embedded SQL applications” on
page 320
“Distinct types” on page 436

Equivalent SQL and assembler data types
When you declare host variables in your assembler programs, the precompiler uses
equivalent SQL data types. When you retrieve data of a particular SQL data type
into a host variable, you need to ensure that the host variable is of an equivalent
data type.
The following table describes the SQL data type and the base SQLTYPE and
SQLLEN values that the precompiler uses for host variables in SQL statements.
Table 50. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
assembler programs
Assembler host variable data type

SQLTYPE of host
variable1

SQLLEN of
host variable

SQL data type

DS HL2

500

2

SMALLINT

DS FL4

496

4

INTEGER

Chapter 3. Including DB2 queries in an application program

221
Table 50. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
assembler programs (continued)
SQLTYPE of host
variable1

SQLLEN of
host variable

DS P’value’
DS PLn’value’ or
DS PLn
1<=n<=16

484

p in byte 1, s in
byte 2

DECIMAL(p,s)

|
|
|
|
|

short decimal FLOAT:

996

4

DECFLOAT

|
|
|
|
|

long decimal FLOAT:

996

8

DECFLOAT

|
|
|
|
|

extended decimal FLOAT:

996

16

DECFLOAT

DS EL4
DS EHL4
DS EBL4

480

4

REAL or FLOAT (n)
1<=n<=21

DS DL8
DS DHL8
DS DBL8

480

8

DOUBLE PRECISION,
or FLOAT (n)
22<=n<=53

| DS FDL8
|
| DS FD

492

8

BIGINT

| SQL TYPE IS BINARY(n)
|
| 1<=n<=255

912

n

BINARY(n)

| SQL TYPE IS VARBINARY(n) or
|
| SQL TYPE IS BINARY(n) VARYING
| 1<=n<=32704

908

n

VARBINARY(n)

DS CLn
1<=n<=255

452

n

CHAR(n)

DS HL2,CLn
1<=n<=255

448

n

VARCHAR(n)

DS HL2,CLn
n>255

456

n

VARCHAR(n)

DS GLm
2<=m<=254

468

n

GRAPHIC(n)

Assembler host variable data type

SQL data type

SDFP DC ED
SDFP DC EDL4
SDFP DC EDL4’11.11’
LDFP DC DD
LDFP DC DDL8
LDFP DC DDL8’22.22’
EDFP DC LD
EDFP DC LDL16
EDFP DC LDL16’33.33’

3
2

DS HL2,GLm
2<=m<=254

464

n

VARGRAPHIC(n)
3

2

DS HL2,GLm
m>254

472

n

VARGRAPHIC(n)
3

2

222

Application Programming and SQL Guide
Table 50. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
assembler programs (continued)
Assembler host variable data type

SQLTYPE of host
variable1

SQLLEN of
host variable

SQL data type

DS FL4

972

4

Result set locator4

SQL TYPE IS
TABLE LIKE
table-name
AS LOCATOR

976

4

Table locator4

SQL TYPE IS
BLOB_LOCATOR

960

4

BLOB locator4

SQL TYPE IS
CLOB_LOCATOR

964

4

CLOB locator4

SQL TYPE IS
DBCLOB_LOCATOR

968

4

DBCLOB locator4

SQL TYPE IS
BLOB(n)
1≤n≤2147483647

404

n

BLOB(n)

SQL TYPE IS
CLOB(n)
1≤n≤2147483647

408

n

CLOB(n)

SQL TYPE IS
DBCLOB(n)
1≤n≤1073741823

412

n

DBCLOB(n)

|

SQL TYPE IS XML AS BLOB(n)

404

0

XML

|

SQL TYPE IS XML AS CLOB(n)

408

0

XML

|

SQL TYPE IS XML AS DBCLOB(n)

412

0

XML

|
|

SQL TYPE IS BLOB_FILE

916/917

267

BLOB file reference

4

|
|

SQL TYPE IS CLOB_FILE

920/921

267

CLOB file reference

4

|
|

SQL TYPE IS DBCLOB_FILE

924/925

267

DBCLOB file reference

SQL TYPE IS XML AS BLOB_FILE

916/917

267

XML BLOB file reference

4

SQL TYPE IS XML AS CLOB_FILE

920/921

267

XML CLOB file reference

4

SQL TYPE IS XML AS DBCLOB_FILE

924/925

267

XML DBCLOB file reference

SQL TYPE IS ROWID

904

40

ROWID

3

4

4

Notes:
1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1.
2. m is the number of bytes.
3. n is the number of double-byte characters.
4. This data type cannot be used as a column type.

The following table shows equivalent assembler host variables for each SQL data
type. Use this table to determine the assembler data type for host variables that
you define to receive output from the database. For example, if you retrieve
TIMESTAMP data, you can define variable DS CLn.

Chapter 3. Including DB2 queries in an application program

223
This table shows direct conversions between SQL data types and assembler data
types. However, a number of SQL data types are compatible. When you do
assignments or comparisons of data that have compatible data types, DB2 converts
those compatible data types.
Table 51. Assembler host variable equivalents that you can use when retrieving data of a
particular SQL data type
SQL data type
SMALLINT

DS HL2

INTEGER

DS F

BIGINT

DS FD OR DS FDL8

DECIMAL(p,s) or
NUMERIC(p,s)

|
|

Assembler host variable
equivalent

DS P’value’ DS PLn’value’
p is precision; s is scale. 1<=p<=31 and
DS PLn
0<=s<=p. 1<=n<=16. value is a literal value
that includes a decimal point. You must
use Ln, value, or both. Using only value is
recommended.

Notes

DS FDL8 requires High Level Assembler
(HLASM), Release 4 or later.

Precision: If you use Ln, it is 2n-1;
otherwise, it is the number of digits in
value. Scale: If you use value, it is the
number of digits to the right of the
decimal point; otherwise, it is 0.
For efficient use of indexes: Use value. If
p is even, do not use Ln and be sure the
precision of value is p and the scale of
value is s. If p is odd, you can use Ln
(although it is not advised), but you must
choose n so that 2n-1=p, and value so that
the scale is s. Include a decimal point in
value, even when the scale of value is 0.
REAL or FLOAT(n)

DS EL4 DS EHL4 DS
EBL41

1<=n<=21

DOUBLE
PRECISION,
DOUBLE, or
FLOAT(n)

DS DL8 DS DHL8 DS
DBL81

22<=n<=53

DECFLOAT

DC EDL4 DC DDL8 DC
LDL16

CHAR(n)

DS CLn

VARCHAR(n)

DS HL2,CLn

GRAPHIC(n)

DS GLm

m is expressed in bytes. n is the number
of double-byte characters. 1<=n<=127

VARGRAPHIC(n)

DS HL2,GLx DS
HL2’m’,GLx’<value>’

x and m are expressed in bytes. n is the
number of double-byte characters. < and
> represent shift-out and shift-in
characters.

|

BINARY(n)

SQL TYPE IS BINARY(n) 1<=n<=255

|
|
|
|

VARBINARY(n)

SQL TYPE IS
VARBINARY(n) or SQL
TYPE IS BINARY(n)
VARYING

|
|

224

Application Programming and SQL Guide

1<=n<=255

1<=n<=32704
Table 51. Assembler host variable equivalents that you can use when retrieving data of a
particular SQL data type (continued)
SQL data type

Assembler host variable
equivalent

DATE

DS CLn

If you are using a date exit routine, n is
determined by that routine; otherwise, n
must be at least 10.

TIME

DS CLn

If you are using a time exit routine, n is
determined by that routine. Otherwise, n
must be at least 6; to include seconds, n
must be at least 8.

TIMESTAMP

DS CLn

n must be at least 19. To include
microseconds, n must be 26; if n is less
than 26, truncation occurs on the
microseconds part.

Result set locator

DS F

Use this data type only to receive result
sets. Do not use this data type as a
column type.

Table locator

SQL TYPE IS TABLE
LIKE table-name AS
LOCATOR

Use this data type only in a user-defined
function or stored procedure to receive
rows of a transition table. Do not use this
data type as a column type.

BLOB locator

SQL TYPE IS
BLOB_LOCATOR

Use this data type only to manipulate
data in BLOB columns. Do not use this
data type as a column type.

CLOB locator

SQL TYPE IS
CLOB_LOCATOR

Use this data type only to manipulate
data in CLOB columns. Do not use this
data type as a column type.

DBCLOB locator

SQL TYPE IS
DBCLOB_LOCATOR

Use this data type only to manipulate
data in DBCLOB columns. Do not use this
data type as a column type.

BLOB(n)

SQL TYPE IS BLOB(n)

1≤n≤2147483647

CLOB(n)

SQL TYPE IS CLOB(n)

1≤n≤2147483647

DBCLOB(n)

SQL TYPE IS DBCLOB(n) n is the number of double-byte characters.
1≤n≤1073741823

|
|

XML

SQL TYPE IS XML AS
BLOB(n)

1≤n≤2147483647

|
|

XML

SQL TYPE IS XML AS
CLOB(n)

1≤n≤2147483647

|
|

XML

SQL TYPE IS XML AS
DBCLOB(n)

n is the number of double-byte characters.
1≤n≤1073741823

|
|
|

BLOB file reference

SQL TYPE IS BLOB_FILE Use this data type only to manipulate
data in BLOB columns. Do not use this
data type as a column type.

|
|
|

CLOB file reference

SQL TYPE IS CLOB_FILE Use this data type only to manipulate
data in CLOB columns. Do not use this
data type as a column type.

|
|
|

DBCLOB file
reference

SQL TYPE IS
DBCLOB_FILE

Notes

Use this data type only to manipulate
data in DBCLOB columns. Do not use this
data type as a column type.

Chapter 3. Including DB2 queries in an application program

225
Table 51. Assembler host variable equivalents that you can use when retrieving data of a
particular SQL data type (continued)
SQL data type

Assembler host variable
equivalent

|
|
|

XML BLOB file
reference

SQL TYPE IS XML AS
BLOB_FILE

Use this data type only to manipulate
XML data as BLOB files. Do not use this
data type as a column type.

|
|
|

XML CLOB file
reference

SQL TYPE IS XML AS
CLOB_FILE

Use this data type only to manipulate
XML data as CLOB files. Do not use this
data type as a column type.

|
|
|

XML DBCLOB file
reference

SQL TYPE IS XML AS
DBCLOB_FILE

Use this data type only to manipulate
XML data as DBCLOB files. Do not use
this data type as a column type.

ROWID

SQL TYPE IS ROWID

Notes

Notes:

|
|
|

1. Although stored procedures and user-defined functions can use IEEE floating-point host
variables, you cannot declare a user-defined function or stored procedure parameter as
IEEE.

Related concepts
“LOB host variable, LOB locator, and LOB file reference variable declarations”
on page 661
“Host variable data types for XML data in embedded SQL applications” on
page 320

Equivalent SQL and C data types
When you declare host variables in your C programs, the precompiler uses
equivalent SQL data types. When you retrieve data of a particular SQL data type
into a host variable, you need to ensure that the host variable is of an equivalent
data type.
The following table describes the SQL data type and the base SQLTYPE and
SQLLEN values that the precompiler uses for host variables in SQL statements.
Table 52. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses
for host variables in C programs
SQLTYPE of host
C host variable data type variable1

SQLLEN of host
variable

SQL data type

short int

SMALLINT

496

4

INTEGER

long long
long long int
sqlint64

492

8

BIGINT5

decimal(p,s)2

484

p in byte 1, s in
byte 2

DECIMAL(p,s)2

float

480

4

FLOAT (single
precision)

double

226

2

long int

|
|
|

500

480

8

FLOAT (double
precision)

Application Programming and SQL Guide
Table 52. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses
for host variables in C programs (continued)
SQLTYPE of host
C host variable data type variable1

|

SQL data type

912

n

BINARY(n)

908

n

VARBINARY(n)

Single-character form

452

1

CHAR(1)

NUL-terminated
character form

460

n

VARCHAR (n-1)

VARCHAR structured
form 1<=n<=255

448

n

VARCHAR(n)

VARCHAR structured
form
n>255

456

n

VARCHAR(n)

Single-graphic form

468

1

GRAPHIC(1)

NUL-terminated
graphic form

400

n

VARGRAPHIC (n-1)

VARGRAPHIC
structured form
1<=n<128

464

n

VARGRAPHIC(n)

VARGRAPHIC
structured form
n>127

472

n

VARGRAPHIC(n)

972

4

Result set locator3

SQL TYPE IS
TABLE LIKE
table-name
AS LOCATOR

976

4

Table locator3

SQL TYPE IS
BLOB_LOCATOR

960

4

BLOB locator3

SQL TYPE IS
CLOB_LOCATOR

964

4

CLOB locator3

SQL TYPE IS
DBCLOB_LOCATOR

968

4

DBCLOB locator3

SQL TYPE IS
BLOB(n)
1≤n≤2147483647

404

n

BLOB(n)

v

|
|
|
|
|

SQLLEN of host
variable

SQL TYPE IS
BINARY(n),
1<=n<=255
v

|
|
|
|

SQL TYPE IS
VARBINARY(n),
1<=n<=32704

v
SQL TYPE IS
RESULT_SET
_LOCATOR

Chapter 3. Including DB2 queries in an application program

227
Table 52. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses
for host variables in C programs (continued)
SQLTYPE of host
C host variable data type variable1

SQLLEN of host
variable

SQL data type

SQL TYPE IS
CLOB(n)
1≤n≤2147483647

408

n

CLOB(n)

SQL TYPE IS
DBCLOB(n)
1≤n≤1073741823

412

n

DBCLOB(n)4

|
|

SQL TYPE IS XML AS
BLOB(n)

404

0

XML

|
|

SQL TYPE IS XML AS
CLOB(n)

408

0

XML

|
|

SQL TYPE IS XML AS
DBCLOB(n)

412

0

XML

|

SQL TYPE IS BLOB_FILE

916/917

267

BLOB file reference

3

|

SQL TYPE IS CLOB_FILE

920/921

267

CLOB file reference

3

|
|

SQL TYPE IS
DBCLOB_FILE

924/925

267

DBCLOB file reference

|
|

SQL TYPE IS XML AS
BLOB_FILE

916/917

267

XML BLOB file
reference 3

|
|

SQL TYPE IS XML AS
CLOB_FILE

920/921

267

XML CLOB file
reference 3

|
|

SQL TYPE IS XML AS
DBCLOB_FILE

924/925

267

XML DBCLOB file
reference 3

904

40

ROWID

SQL TYPE IS ROWID

3

Notes:
1. If a host variable includes an indicator variable, the SQLTYPE value is the base
SQLTYPE value plus 1.
2. p is the precision; in SQL terminology, this the total number of digits. In C, this is called
the size.
s is the scale; in SQL terminology, this is the number of digits to the right of the decimal
point. In C, this is called the precision.
C++ does not support the decimal data type.
3. Do not use this data type as a column type.
4. n is the number of double-byte characters.
5. No exact equivalent. Use DECIMAL(19,0).

|
|
|

6. Starting in Version 9, the C data type long long no longer maps to the SQL data type
DEC (19,0). Instead, the C data type long long maps to the SQL data type BIGINT. This
new mapping applies if the application is precompiled again.

The following table shows equivalent C host variables for each SQL data type. Use
this table to determine the C data type for host variables that you define to receive
output from the database. For example, if you retrieve TIMESTAMP data, you can
define a variable of NUL-terminated character form or VARCHAR structured form

228

Application Programming and SQL Guide
This table shows direct conversions between SQL data types and C data types.
However, a number of SQL data types are compatible. When you do assignments
or comparisons of data that have compatible data types, DB2 converts those
compatible data types.
Table 53. C host variable equivalents that you can use when retrieving data of a particular SQL data type
SQL data type

C host variable equivalent

SMALLINT

short int

INTEGER

long int

DECIMAL(p,s) or
NUMERIC(p,s)

decimal

You can use the double data type if your
C compiler does not have a decimal data
type; however, double is not an exact
equivalent.

REAL or FLOAT(n)

float

1<=n<=21

DOUBLE PRECISION or
FLOAT(n)

double

22<=n<=53

|

DECLOAT

No equivalent

|

BIGINT

long long, long long int, and sqlint64

|

BINARY(n)

SQL TYPE IS BINARY(n)

1<=n<=255

|
|
|
|
|
|

Notes

If data can contain character NULs (0),
certain C and C++ library functions might
not handle the data correctly. Ensure that
your application handles the data
properly.
VARBINARY(n)

SQL TYPE IS VARBINARY(n)

1<=n<=32 704

CHAR(1)

single-character form

CHAR(n)

no exact equivalent

If n>1, use NUL-terminated character form

VARCHAR(n)

NUL-terminated character form

If data can contain character NULs (0),
use VARCHAR structured form. Allow at
least n+1 to accommodate the
NUL-terminator.

VARCHAR structured form
GRAPHIC(1)

single-graphic form

GRAPHIC(n)

no exact equivalent

If n>1, use NUL-terminated graphic form.
n is the number of double-byte characters.

VARGRAPHIC(n)

NUL-terminated graphic form

If data can contain graphic NUL values
(00), use VARGRAPHIC structured
form. Allow at least n+1 to accommodate
the NUL-terminator. n is the number of
double-byte characters.

VARGRAPHIC structured form

n is the number of double-byte characters.

NUL-terminated character form

If you are using a date exit routine, that
routine determines the length. Otherwise,
allow at least 11 characters to
accommodate the NUL-terminator.

VARCHAR structured form

If you are using a date exit routine, that
routine determines the length. Otherwise,
allow at least 10 characters.

DATE

Chapter 3. Including DB2 queries in an application program

229
Table 53. C host variable equivalents that you can use when retrieving data of a particular SQL data type (continued)
SQL data type

C host variable equivalent

Notes

TIME

NUL-terminated character form

If you are using a time exit routine, the
length is determined by that routine.
Otherwise, the length must be at least 7;
to include seconds, the length must be at
least 9 to accommodate the
NUL-terminator.

VARCHAR structured form

If you are using a time exit routine, the
length is determined by that routine.
Otherwise, the length must be at least 6;
to include seconds, the length must be at
least 8.

NUL-terminated character form

The length must be at least 20. To include
microseconds, the length must be 27. If the
length is less than 27, truncation occurs on
the microseconds part.

VARCHAR structured form

The length must be at least 19. To include
microseconds, the length must be 26. If the
length is less than 26, truncation occurs on
the microseconds part.

Result set locator

SQL TYPE IS RESULT_SET_LOCATOR

Use this data type only for receiving result
sets. Do not use this data type as a
column type.

Table locator

SQL TYPE IS TABLE LIKE table-name AS
LOCATOR

Use this data type only in a user-defined
function or stored procedure to receive
rows of a transition table. Do not use this
data type as a column type.

BLOB locator

SQL TYPE IS BLOB_LOCATOR

Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.

CLOB locator

SQL TYPE IS CLOB_LOCATOR

Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.

DBCLOB locator

SQL TYPE IS DBCLOB_LOCATOR

Use this data type only to manipulate data
in DBCLOB columns. Do not use this data
type as a column type.

BLOB(n)

SQL TYPE IS BLOB(n)

1≤n≤2147483647

CLOB(n)

SQL TYPE IS CLOB(n)

1≤n≤2147483647

DBCLOB(n)

SQL TYPE IS DBCLOB(n)

n is the number of double-byte characters.
1≤n≤1073741823

| XML

SQL TYPE IS XML AS BLOB(n)

1≤n≤2147483647

| XML

SQL TYPE IS XML AS CLOB(n)

1≤n≤2147483647

| XML
|

SQL TYPE IS XML AS DBCLOB(n)

n is the number of double-byte characters.
1≤n≤1073741823

| BLOB file reference
|
|

SQL TYPE IS BLOB_FILE

Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.

| CLOB file reference
|
|

SQL TYPE IS CLOB_FILE

Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.

TIMESTAMP

230

Application Programming and SQL Guide
Table 53. C host variable equivalents that you can use when retrieving data of a particular SQL data type (continued)
SQL data type

C host variable equivalent

Notes

|
|
|

DBCLOB file reference

SQL TYPE IS DBCLOB_FILE

Use this data type only to manipulate data
in DBCLOB columns. Do not use this data
type as a column type.

|
|
|

XML BLOB file reference

SQL TYPE IS XML AS BLOB_FILE

Use this data type only to manipulate
XML data as BLOB files. Do not use this
data type as a column type.

|
|
|

XML CLOB file reference

SQL TYPE IS XML AS CLOB_FILE

Use this data type only to manipulate
XML data as CLOB files. Do not use this
data type as a column type.

|
|
|

XML DBCLOB file reference

SQL TYPE IS XML AS DBCLOB_FILE

Use this data type only to manipulate
XML data as DBCLOB files. Do not use
this data type as a column type.

ROWID

SQL TYPE IS ROWID

Related concepts
“LOB host variable, LOB locator, and LOB file reference variable declarations”
on page 661
“Host variable data types for XML data in embedded SQL applications” on
page 320

Equivalent SQL and COBOL data types
When you declare host variables in your COBOL programs, the precompiler uses
equivalent SQL data types. When you retrieve data of a particular SQL data type
into a host variable, you need to ensure that the host variable is of an equivalent
data type.
The following table describes the SQL data type and the base SQLTYPE and
SQLLEN values that the precompiler uses for host variables in SQL statements.
Table 54. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
COBOL programs
SQLTYPE of host
COBOL host variable data type variable1

SQLLEN of host variable

SQL data type

COMP-1

480

4

REAL or FLOAT(n) 1<=n<=21

COMP-2

480

8

DOUBLE PRECISION, or
FLOAT(n) 22<=n<=53

S9(i)V9(d) COMP-3 or S9(i)V9(d)
PACKED-DECIMAL

484

i+d in byte 1, d in byte 2

DECIMAL(i+d,d) or
NUMERIC(i+d,d)

S9(i)V9(d) DISPLAY SIGN
LEADING SEPARATE

504

i+d in byte 1, d in byte 2

No exact equivalent. Use
DECIMAL(i+d,d) or
NUMERIC(i+d,d)

S9(i)V9(d) NATIONAL SIGN
LEADING SEPARATE

504

i+d in byte 1, d in byte 2

No exact equivalent. Use
DECIMAL(i+d,d) or
NUMERIC(i+d,d)

S9(4) COMP-4, S9(4) COMP-5,
S9(4) COMP, or S9(4) BINARY

500

2

SMALLINT

S9(9) COMP-4, S9(9) COMP-5,
S9(9) COMP, or S9(9) BINARY

496

4

INTEGER

Chapter 3. Including DB2 queries in an application program

231
Table 54. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
COBOL programs (continued)
SQLTYPE of host
COBOL host variable data type variable1

| S9(18) COMP-4, S9(18) COMP-5, 492
| S9(18) COMP, or S9(18) BINARY

SQLLEN of host variable

SQL data type

8

BIGINT

Fixed-length character data

452

n

CHAR(n)

Varying-length character data
1<=n<=255

448

n

VARCHAR(n)

Varying-length character data
m>255

456

m

VARCHAR(m)

Fixed-length graphic data

468

m

GRAPHIC(m)

Varying-length graphic data
1<=m<=127

464

m

VARGRAPHIC(m)

Varying-length graphic data
m>127

472

m

VARGRAPHIC(m)

| SQL TYPE is BINARY(n),
| 1<=n<=255

912

n

BINARY(n)

| SQL TYPE is VARBINARY(n),
| 1<=n<=32 704

908

n

VARBINARY(n)

SQL TYPE IS
RESULT-SET-LOCATOR

972

4

Result set locator2

SQL TYPE IS TABLE LIKE
table-name AS LOCATOR

976

4

Table locator2

SQL TYPE IS BLOB-LOCATOR

960

4

BLOB locator2

SQL TYPE IS CLOB-LOCATOR

964

4

CLOB locator2

SQL TYPE IS
DBCLOB-LOCATOR

968

4

DBCLOB locator2

USAGE IS SQL TYPE IS
BLOB(n) 1≤n≤2147483647

404

n

BLOB(n)

USAGE IS SQL TYPE IS
CLOB(n) 1≤n≤2147483647

408

n

CLOB(n)

USAGE IS SQL TYPE IS
DBCLOB(m) 1≤m≤10737418233

412

n

DBCLOB(m)3

| SQL TYPE IS XML AS BLOB(n)

404

0

XML

| SQL TYPE IS XML AS CLOB(n)

408

0

XML

| SQL TYPE IS XML AS
| DBCLOB(n)

412

0

XML

| SQL TYPE IS BLOB-FILE

916/917

267

BLOB file reference2

| SQL TYPE IS CLOB-FILE

920/921

267

CLOB file reference2

| SQL TYPE IS DBCLOB-FILE

924/925

267

DBCLOB file reference2

| SQL TYPE IS XML AS
| BLOB-FILE

916/917

267

XML BLOB file reference2

| SQL TYPE IS XML AS
| CLOB-FILE

920/921

267

XML CLOB file reference2

| SQL TYPE IS XML AS
| DBCLOB-FILE

924/925

267

XML DBCLOB file reference2

904

40

ROWID

SQL TYPE IS ROWID

232

Application Programming and SQL Guide
Table 54. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
COBOL programs (continued)
SQLTYPE of host
COBOL host variable data type variable1

SQLLEN of host variable

SQL data type

Notes:
1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1.
2. Do not use this data type as a column type.
3. m is the number of double-byte characters.

The following table shows equivalent COBOL host variables for each SQL data
type. Use this table to determine the COBOL data type for host variables that you
define to receive output from the database. For example, if you retrieve
TIMESTAMP data, you can define a fixed-length character string variable of length
n
This table shows direct conversions between SQL data types and COBOL data
types. However, a number of SQL data types are compatible. When you do
assignments or comparisons of data that have compatible data types, DB2 converts
those compatible data types.
Table 55. COBOL host variable equivalents that you can use when retrieving data of a particular SQL data type
SQL data type
SMALLINT

S9(4) COMP-4,
S9(4) COMP-5,
S9(4) COMP,
or S9(4) BINARY

INTEGER

S9(9) COMP-4,
S9(9) COMP-5,
S9(9) COMP,
or S9(9) BINARY

DECIMAL(p,s) or
NUMERIC(p,s)

S9(p-s)V9(s) COMP-3 or
S9(p-s)V9(s)
PACKED-DECIMAL
DISPLAY SIGN
LEADING SEPARATE
NATIONAL SIGN
LEADING SEPARATE

p is precision; s is scale. 0<=s<=p<=31. If
s=0, use S9(p)V or S9(p). If s=p, use SV9(s).
If the COBOL compiler does not support
31–digit decimal numbers, no exact
equivalent exists. Use COMP-2.

REAL or FLOAT (n)

COMP-1

1<=n<=21

DOUBLE PRECISION,
DOUBLE or FLOAT (n)

|
|

COBOL host variable equivalent

Notes

COMP-2

22<=n<=53

BIGINT

S9(18) COMP-4, S9(18) COMP-5, S9(18)
COMP, or S9(18) BINARY

CHAR(n)

Fixed-length character string. For example, 1<=n<=255
01 VAR-NAME PIC X(n).

VARCHAR(n)

Varying-length character string. For
example,

The inner variables must have a level of
49.

01 VAR-NAME.
49 VAR-LEN PIC S9(4)
USAGE BINARY.
49 VAR-TEXT PIC X(n).

Chapter 3. Including DB2 queries in an application program

233
Table 55. COBOL host variable equivalents that you can use when retrieving data of a particular SQL data
type (continued)
SQL data type

COBOL host variable equivalent

Notes

GRAPHIC(n)

Fixed-length graphic string. For example,
01 VAR-NAME PIC G(n)
USAGE IS DISPLAY-1.

n refers to the number of double-byte
characters, not to the number of bytes.
1<=n<=127

Varying-length graphic string. For
example,

n refers to the number of double-byte
characters, not to the number of bytes.

VARGRAPHIC(n)

01 VAR-NAME.
49 VAR-LEN PIC S9(4)
USAGE BINARY.
49 VAR-TEXT PIC G(n)
USAGE IS DISPLAY-1.

The inner variables must have a level of
49.

| BINARY(n)

SQL TYPE IS BINARY(n)

1<=n<=255

| VARBINARY(n)

SQL TYPE IS VARBINARY(n)

1<=n<=32 704

Fixed-length character string of length n.
For example,

If you are using a date exit routine, n is
determined by that routine. Otherwise, n
must be at least 10.

DATE

01 VAR-NAME PIC X(n).
TIME

Fixed-length character string of length n.
For example,
01 VAR-NAME PIC X(n).

TIMESTAMP

Fixed-length character string of length n.
For example,
01 VAR-NAME PIC X(n).

If you are using a time exit routine, n is
determined by that routine. Otherwise, n
must be at least 6; to include seconds, n
must be at least 8.
n must be at least 19. To include
microseconds, n must be 26; if n is less
than 26, truncation occurs on the
microseconds part.

Result set locator

SQL TYPE IS
RESULT-SET-LOCATOR

Use this data type only for receiving result
sets. Do not use this data type as a
column type.

Table locator

SQL TYPE IS
TABLE LIKE
table-name
AS LOCATOR

Use this data type only in a user-defined
function or stored procedure to receive
rows of a transition table. Do not use this
data type as a column type.

BLOB locator

USAGE IS SQL TYPE IS
BLOB-LOCATOR

Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.

CLOB locator

USAGE IS SQL TYPE IS
CLOB-LOCATOR

Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.

DBCLOB locator

USAGE IS SQL TYPE IS
DBCLOB-LOCATOR

Use this data type only to manipulate data
in DBCLOB columns. Do not use this data
type as a column type.

BLOB(n)

USAGE IS SQL TYPE IS
BLOB(n)

1≤n≤2147483647

CLOB(n)

USAGE IS SQL TYPE IS
CLOB(n)

1≤n≤2147483647

DBCLOB(n)

USAGE IS SQL TYPE IS
DBCLOB(n)

n is the number of double-byte characters.
1≤n≤1073741823

| XML

SQL TYPE IS XML AS BLOB(n)

1≤n≤2147483647

| XML

SQL TYPE IS XML AS CLOB(n)

1≤n≤2147483647

234

Application Programming and SQL Guide
Table 55. COBOL host variable equivalents that you can use when retrieving data of a particular SQL data
type (continued)
SQL data type

COBOL host variable equivalent

Notes

|
|

XML

SQL TYPE IS XML AS DBCLOB(n)

n is the number of double-byte characters.
1≤n≤1073741823

|
|
|
|
|

BLOB file reference

USAGE IS SQL TYPE IS
BLOB-FILE

Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.

|
|
|
|
|

CLOB file reference

USAGE IS SQL TYPE IS
CLOB-FILE

Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.

|
|
|
|
|

DBCLOB file reference

USAGE IS SQL TYPE IS
DBCLOB-FILE

Use this data type only to manipulate data
in DBCLOB columns. Do not use this data
type as a column type.

|
|
|

XML BLOB file reference

SQL TYPE IS XML AS BLOB-FILE

Use this data type only to manipulate
XML data as BLOB files. Do not use this
data type as a column type.

|
|
|

XML CLOB file reference

SQL TYPE IS XML AS CLOB-FILE

Use this data type only to manipulate
XML data as CLOB files. Do not use this
data type as a column type.

|
|
|

XML DBCLOB file reference

SQL TYPE IS XML AS DBCLOB-FILE

Use this data type only to manipulate
XML data as DBCLOB files. Do not use
this data type as a column type.

ROWID

SQL TYPE IS ROWID

Related concepts
“LOB host variable, LOB locator, and LOB file reference variable declarations”
on page 661
“Host variable data types for XML data in embedded SQL applications” on
page 320

Equivalent SQL and Fortran data types
When you declare host variables in your Fortran programs, the precompiler uses
equivalent SQL data types. When you retrieve data of a particular SQL data type
into a host variable, you need to ensure that the host variable is of an equivalent
data type.
The following table describes the SQL data type and the base SQLTYPE and
SQLLEN values that the precompiler uses for host variables in SQL statements.
Table 56. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
Fortran programs
Fortran host variable data type

SQLTYPE of host
variable1

SQLLEN of host variable

SQL data type

INTEGER*2

500

2

SMALLINT

INTEGER*4

496

4

INTEGER

REAL*4

480

4

FLOAT (single precision)

REAL*8

480

8

FLOAT (double precision)

CHARACTER*n

452

n

CHAR(n)

Chapter 3. Including DB2 queries in an application program

235
Table 56. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in
Fortran programs (continued)
SQLTYPE of host
variable1

SQLLEN of host variable

SQL data type

SQL TYPE IS
RESULT_SET_LOCATOR

972

4

Result set locator. Do not use
this data type as a column type.

SQL TYPE IS BLOB_LOCATOR

960

4

BLOB locator. Do not use this
data type as a column type.

SQL TYPE IS CLOB_LOCATOR

964

4

CLOB locator. Do not use this
data type as a column type.

SQL TYPE IS BLOB(n)
1≤n≤2147483647

404

n

BLOB(n)

SQL TYPE IS CLOB(n)
1≤n≤2147483647

408

n

CLOB(n)

SQL TYPE IS ROWID

904

40

ROWID

Fortran host variable data type

Notes:
1. If a host variable includes an indicator variable, the SQLTYPE value is the base
SQLTYPE value plus 1.
The following table shows equivalent Fortran host variables for each SQL data
type. Use this table to determine the Fortran data type for host variables that you
define to receive output from the database. For example, if you retrieve
TIMESTAMP data, you can define a variable of type CHARACTER*n.
This table shows direct conversions between SQL data types and Fortran data
types. However, a number of SQL data types are compatible. When you do
assignments or comparisons of data that have compatible data types, DB2 converts
those compatible data types.
Table 57. Fortran host variable equivalents that you can use when retrieving data of a particular SQL data type
SQL data type

Fortran host variable equivalent

SMALLINT

INTEGER*2

INTEGER

INTEGER*4

| BIGINT

Notes

not supported

DECIMAL(p,s) or
NUMERIC(p,s)

no exact equivalent

Use REAL*8

FLOAT(n) single precision

REAL*4

1<=n<=21

FLOAT(n) double precision

REAL*8

22<=n<=53

CHAR(n)

CHARACTER*n

1<=n<=255

VARCHAR(n)

no exact equivalent

Use a character host variable that is large
enough to contain the largest expected
VARCHAR value.

| BINARY

not supported

| VARBINARY

not supported

GRAPHIC(n)

not supported

VARGRAPHIC(n)

not supported

236

Application Programming and SQL Guide
Table 57. Fortran host variable equivalents that you can use when retrieving data of a particular SQL data
type (continued)
SQL data type

Notes

DATE

CHARACTER*n

If you are using a date exit routine, n is
determined by that routine; otherwise, n
must be at least 10.

TIME

CHARACTER*n

If you are using a time exit routine, n is
determined by that routine. Otherwise, n
must be at least 6; to include seconds, n
must be at least 8.

TIMESTAMP

CHARACTER*n

n must be at least 19. To include
microseconds, n must be 26; if n is less
than 26, truncation occurs on the
microseconds part.

Result set locator

SQL TYPE IS RESULT_SET_LOCATOR

Use this data type only for receiving result
sets. Do not use this data type as a
column type.

BLOB locator

SQL TYPE IS BLOB_LOCATOR

Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.1

CLOB locator

SQL TYPE IS CLOB_LOCATOR

Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.1

DBCLOB locator

not supported

BLOB(n)

SQL TYPE IS BLOB(n)

1≤n≤21474836471

CLOB(n)

SQL TYPE IS CLOB(n)

1≤n≤21474836471

DBCLOB(n)

not supported

ROWID

|

Fortran host variable equivalent

SQL TYPE IS ROWID

XML

not supported

Related concepts
“LOB host variable, LOB locator, and LOB file reference variable declarations”
on page 661

Equivalent SQL and PL/I data types
When you declare host variables in your PL/I programs, the precompiler uses
equivalent SQL data types. When you retrieve data of a particular SQL data type
into a host variable, you need to ensure that the host variable is of an equivalent
data type.
The following table describes the SQL data type and the base SQLTYPE and
SQLLEN values that the precompiler uses for host variables in SQL statements.
Table 58. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in PL/I
programs
PL/I host variable data type

SQLLEN of host variable

SQL data type

BIN FIXED(n) 1<=n<=15

500

2

SMALLINT

BIN FIXED(n) 16<=n<=31

|

SQLTYPE of host
variable1

496

4

INTEGER

FIXED BIN(63)

492

8

BIGINT

Chapter 3. Including DB2 queries in an application program

237
Table 58. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in PL/I
programs (continued)
SQLTYPE of host
variable1

SQLLEN of host variable

SQL data type

DEC FIXED(p,s) 0<=p<=31 and
0<=s<=p2

484

p in byte 1, s in byte 2

DECIMAL(p,s)

BIN FLOAT(p) 1<=p<=21

480

4

REAL or FLOAT(n) 1<=n<=21

BIN FLOAT(p) 22<=p<=53

480

8

DOUBLE PRECISION or
FLOAT(n) 22<=n<=53

DEC FLOAT(m) 1<=m<=6

480

4

FLOAT (single precision)

DEC FLOAT(m) 7<=m<=16

480

8

FLOAT (double precision)

CHAR(n)

452

n

CHAR(n)

CHAR(n) VARYING 1<=n<=255

448

n

VARCHAR(n)

CHAR(n) VARYING n>255

456

n

VARCHAR(n)

GRAPHIC(n)

468

n

GRAPHIC(n)

GRAPHIC(n) VARYING
1<=n<=127

464

n

VARGRAPHIC(n)

GRAPHIC(n) VARYING n>127

472

n

VARGRAPHIC(n)

| SQL TYPE IS BINARY(n),
| 1<=n<=255

912

n

BINARY(n)

| SQL TYPE IS VARBINARY(n),
| 1<=n<=32 704

908

n

VARBINARY(n)

SQL TYPE IS
RESULT_SET_LOCATOR

972

4

Result set locator3

SQL TYPE IS TABLE LIKE
table-name AS LOCATOR

976

4

Table locator3

SQL TYPE IS BLOB_LOCATOR

960

4

BLOB locator3

SQL TYPE IS CLOB_LOCATOR

964

4

CLOB locator3

SQL TYPE IS
DBCLOB_LOCATOR

968

4

DBCLOB locator3

SQL TYPE IS BLOB(n)
1≤n≤2147483647

404

n

BLOB(n)

SQL TYPE IS CLOB(n)
1≤n≤2147483647

408

n

CLOB(n)

SQL TYPE IS DBCLOB(n)
1≤n≤10737418234

412

n

DBCLOB(n)4

| SQL TYPE IS XML AS BLOB(n)

404

0

XML

| SQL TYPE IS XML AS CLOB(n)

408

0

XML

| SQL TYPE IS XML AS
| DBCLOB(n)

412

0

XML

| SQL TYPE IS BLOB_FILE

916/917

267

BLOB file reference3

| SQL TYPE IS CLOB_FILE

920/921

267

CLOB file reference3

| SQL TYPE IS DBCLOB_FILE

924/925

267

DBCLOB file reference3

| SQL TYPE IS XML AS
| BLOB_FILE

916/917

267

XML BLOB file reference3

| SQL TYPE IS XML AS
| CLOB_FILE

920/921

267

XML CLOB file reference3

PL/I host variable data type

238

Application Programming and SQL Guide
Table 58. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in PL/I
programs (continued)
SQLTYPE of host
variable1

SQLLEN of host variable

SQL data type

SQL TYPE IS XML AS
DBCLOB_FILE

924/925

267

XML DBCLOB file reference3

SQL TYPE IS ROWID

904

40

ROWID

PL/I host variable data type

|
|

Notes:
1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1.
2. If p=0, DB2 interprets it as DECIMAL(31). For example, DB2 interprets a PL/I data type of DEC FIXED(0,0) to be
DECIMAL(31,0), which equates to the SQL data type of DECIMAL(31,0).
3. Do not use this data type as a column type.
4. n is the number of double-byte characters.

The following table shows equivalent PL/I host variables for each SQL data type.
Use this table to determine the PL/I data type for host variables that you define to
receive output from the database. For example, if you retrieve TIMESTAMP data,
you can define a variable of type CHAR(n).
This table shows direct conversions between SQL data types and PL/I data types.
However, a number of SQL data types are compatible. When you do assignments
or comparisons of data that have compatible data types, DB2 converts those
compatible data types.
Table 59. PL/I host variable equivalents that you can use when retrieving data of a particular SQL data type
SQL data type

Notes

SMALLINT

BIN FIXED(n)

1<=n<=15

INTEGER

BIN FIXED(n)

16<=n<=31

BIGINT

FIXED BIN(63)

DECIMAL(p,s) or
NUMERIC(p,s)

|

PL/I host variable equivalent

If p<16: DEC FIXED(p) or DEC
FIXED(p,s)

p is precision; s is scale. 1<=p<=31 and
0<=s<=p
If p>15, the PL/I compiler must support
31-digit decimal variables.

REAL or FLOAT(n)

BIN FLOAT(p) or DEC FLOAT(m)

1<=n<=21, 1<=p<=21, and 1<=m<=6

DOUBLE PRECISION,
DOUBLE, or FLOAT(n)

BIN FLOAT(p) or DEC FLOAT(m)

22<=n<=53, 22<=p<=53, and 7<=m<=16

CHAR(n)

CHAR(n)

1<=n<=255

VARCHAR(n)

CHAR(n) VAR

GRAPHIC(n)

GRAPHIC(n)

n refers to the number of double-byte
characters, not to the number of bytes.
1<=n<=127

VARGRAPHIC(n)

GRAPHIC(n) VAR

n refers to the number of double-byte
characters, not to the number of bytes.

|

BINARY(n)

SQL TYPE IS BINARY(n)

1<=n<=255

|

VARBINARY(n)

SQL TYPE IS VARBINARY(n)

1<=n<=32 704

DATE

CHAR(n)

If you are using a date exit routine, that
routine determines n; otherwise, n must be
at least 10.

Chapter 3. Including DB2 queries in an application program

239
Table 59. PL/I host variable equivalents that you can use when retrieving data of a particular SQL data
type (continued)
SQL data type

PL/I host variable equivalent

Notes

TIME

CHAR(n)

If you are using a time exit routine, that
routine determines n. Otherwise, n must
be at least 6; to include seconds, n must be
at least 8.

TIMESTAMP

CHAR(n)

n must be at least 19. To include
microseconds, n must be 26; if n is less
than 26, the microseconds part is
truncated.

Result set locator

SQL TYPE IS RESULT_SET_LOCATOR

Use this data type only for receiving result
sets. Do not use this data type as a
column type.

Table locator

SQL TYPE IS TABLE LIKE table-name AS
LOCATOR

Use this data type only in a user-defined
function or stored procedure to receive
rows of a transition table. Do not use this
data type as a column type.

BLOB locator

SQL TYPE IS BLOB_LOCATOR

Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.1

CLOB locator

SQL TYPE IS CLOB_LOCATOR

Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.1

DBCLOB locator

SQL TYPE IS DBCLOB_LOCATOR

Use this data type only to manipulate data
in DBCLOB columns. Do not use this data
type as a column type.1

BLOB(n)

SQL TYPE IS BLOB(n)

1≤n≤21474836471

CLOB(n)

SQL TYPE IS CLOB(n)

1≤n≤21474836471

DBCLOB(n)

SQL TYPE IS DBCLOB(n)

n is the number of double-byte characters.
1≤n≤10737418231

| XML

SQL TYPE IS XML AS BLOB(n)

1≤n≤2147483647

2

| XML

SQL TYPE IS XML AS CLOB(n)

1≤n≤2147483647

2

| XML
|

SQL TYPE IS XML AS DBCLOB(n)

n is the number of double-byte characters.
1≤n≤1073741823 2

| BLOB file reference
|
|

SQL TYPE IS BLOB_FILE

Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.1

| CLOB file reference
|
|

SQL TYPE IS CLOB_FILE

Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.1

| DBCLOB file reference
|
|

SQL TYPE IS DBCLOB_FILE

Use this data type only to manipulate data
in DBCLOB columns. Do not use this data
type as a column type.1

| XML BLOB file reference
|
|

SQL TYPE IS XML AS BLOB_FILE

Use this data type only to manipulate
XML data as BLOB files. Do not use this
data type as a column type. 2

| XML CLOB file reference
|
|

SQL TYPE IS XML AS CLOB_FILE

Use this data type only to manipulate
XML data as CLOB files. Do not use this
data type as a column type. 2

240

Application Programming and SQL Guide
Table 59. PL/I host variable equivalents that you can use when retrieving data of a particular SQL data
type (continued)
SQL data type

Notes

XML DBCLOB file reference

SQL TYPE IS XML AS DBCLOB_FILE

Use this data type only to manipulate
XML data as DBCLOB files. Do not use
this data type as a column type.2

ROWID

|
|
|

PL/I host variable equivalent

SQL TYPE IS ROWID

Related concepts
“LOB host variable, LOB locator, and LOB file reference variable declarations”
on page 661
“Host variable data types for XML data in embedded SQL applications” on
page 320

Determining equivalent SQL and REXX data types
All REXX data is string data. Therefore, when a REXX procedure assigns input
data to a column, DB2 converts the data from a string type to the column type.
When a REXX procedure assigns column data to an output variable, DB2 converts
the data from the column type to a string type.
When you assign input data to a DB2 table column, you can either let DB2
determine the type that your input data represents, or you can use an SQLDA to
tell DB2 the intended type of the input data.

Data types that DB2 assigns to REXX input
When a REXX procedure assigns data to a column, it can either let DB2 determine
the data type or use an SQLDA to specify the intended data type. If the procedure
lets DB2 assign a data type for the input data, DB2 bases its choice on the input
string format.
The following table shows the SQL data types that DB2 assigns to input data and
the corresponding formats for that data. The two SQLTYPE values that are listed
for each data type are the value for a column that does not accept null values and
the value for a column that accepts null values.
Table 60. SQL input data types and REXX data formats
SQL data type
assigned by DB2
INTEGER

|
|
|
|

SQLTYPE for
data type
496/497

A string of numerics that does not contain a decimal point or exponent
identifier. The first character can be a plus (+) or minus (-) sign. The
number that is represented must be between -2147483647 and 2147483647,
inclusive.

BIGINT

492/493

A string of numbers that does not contain a decimal point or an exponent
identifier. The first character can be a plus (+) or minus (-) sign. The
number that is represented must be between -9223372036854775808 and
-2147483648, inclusive, or between 2147483648 and 9223372036854775807.

REXX input data format

Chapter 3. Including DB2 queries in an application program

241
Table 60. SQL input data types and REXX data formats (continued)
SQL data type
assigned by DB2

SQLTYPE for
data type

REXX input data format

DECIMAL(p,s)

484/485

One of the following formats:
v A string of numerics that contains a decimal point but no exponent
identifier. p represents the precision and s represents the scale of the
decimal number that the string represents. The first character can be a
plus (+) or minus (-) sign.

|
|
|
|

v A string of numerics that does not contain a decimal point or an
exponent identifier. The first character can be a plus (+) or minus (-)
sign. The number that is represented is less than -9223372036854775808
or greater than 9223372036854775807.
FLOAT

480/481

A string that represents a number in scientific notation. The string consists
of a series of numerics followed by an exponent identifier (an E or e
followed by an optional plus (+) or minus (-) sign and a series of
numerics). The string can begin with a plus (+) or minus (-) sign.

VARCHAR(n)

448/449

One of the following formats:
v A string of length n, enclosed in single or double quotation marks.
v The character X or x, followed by a string enclosed in single or double
quotation marks. The string within the quotation marks has a length of
2*n bytes and is the hexadecimal representation of a string of n
characters.
v A string of length n that does not have a numeric or graphic format, and
does not satisfy either of the previous conditions.

VARGRAPHIC(n)

464/465

One of the following formats:
v The character G, g, N, or n, followed by a string enclosed in single or
double quotation marks. The string within the quotation marks begins
with a shift-out character (X’0E’) and ends with a shift-in character
(X’0F’). Between the shift-out character and shift-in character are n
double-byte characters.
v The characters GX, Gx, gX, or gx, followed by a string enclosed in single
or double quotation marks. The string within the quotation marks has a
length of 4*n bytes and is the hexadecimal representation of a string of n
double-byte characters.

For example, when DB2 executes the following statements to update the MIDINIT
column of the EMP table, DB2 must determine a data type for HVMIDINIT:
SQLSTMT="UPDATE EMP" ,
"SET MIDINIT = ?" ,
"WHERE EMPNO = ’000200’"
"EXECSQL PREPARE S100 FROM :SQLSTMT"
HVMIDINIT=’H’
"EXECSQL EXECUTE S100 USING" ,
":HVMIDINIT"

Because the data that is assigned to HVMIDINIT has a format that fits a character
data type, DB2 REXX Language Support assigns a VARCHAR type to the input
data.
If you do not assign a value to a host variable before you assign the host variable
to a column, DB2 returns an error code.

242

Application Programming and SQL Guide
Embedding SQL statements in your application
You can code SQL statements in an assembler, C, C++, COBOL, Fortran, or PL/I
program or REXX procedure wherever you can use executable statements.

Embedding SQL statements in assembler applications
You can code SQL statements in an assembler program wherever you can use
executable statements.
Each SQL statement in an assembler program must begin with EXEC SQL. The
EXEC and SQL keywords must appear on one line, but the remainder of the
statement can appear on subsequent lines.
You might code an UPDATE statement in an assembler program as follows:
EXEC SQL UPDATE DSN8910.DEPT
SET MGRNO = :MGRNUM
WHERE DEPTNO = :INTDEPT

X
X

Comments: You cannot include assembler comments in SQL statements. However,
you can include SQL comments in any embedded SQL statement.
Continuation for SQL statements: The line continuation rules for SQL statements
are the same as those for assembler statements, except that you must specify EXEC
SQL within one line. Any part of the statement that does not fit on one line can
appear on subsequent lines, beginning at the continuation margin (column 16, the
default). Every line of the statement, except the last, must have a continuation
character (a non-blank character) immediately after the right margin in column 72.
Declaring tables and views: Your assembler program should include a DECLARE
statement to describe each table and view the program accesses.
Including code: To include SQL statements or assembler host variable declaration
statements from a member of a partitioned data set, place the following SQL
statement in the source code where you want to include the statements:
EXEC SQL INCLUDE member-name

You cannot nest SQL INCLUDE statements.
Margins: Use the precompiler option MARGINS to set a left margin, a right
margin, and a continuation margin. The default values for these margins are
columns 1, 71, and 16, respectively. If EXEC SQL starts before the specified left
margin, the DB2 precompiler does not recognize the SQL statement. If you use the
default margins, you can place an SQL statement anywhere between columns 2
and 71.
Multiple-row FETCH statements: You can use only the FETCH ... USING
DESCRIPTOR form of the multiple-row FETCH statement in an assembler
program. The DB2 precompiler does not recognize declarations of host variable
arrays for an assembler program.
Names: You can use any valid assembler name for a host variable. However, do
not use external entry names or access plan names that begin with ’DSN’ or host
variable names that begin with ’SQL’. These names are reserved for DB2.

Chapter 3. Including DB2 queries in an application program

243
The first character of a host variable that is used in embedded SQL cannot be an
underscore. However, you can use an underscore as the first character in a symbol
that is not used in embedded SQL.
Statement labels: You can prefix an SQL statement with a label. The first line of an
SQL statement can use a label beginning in the left margin (column 1). If you do
not use a label, leave column 1 blank.
WHENEVER statement: The target for the GOTO clause in an SQL WHENEVER
statement must be a label in the assembler source code and must be within the
scope of the SQL statements that WHENEVER affects.
Special assembler considerations: The following considerations apply to programs
written in assembler:
v To allow for reentrant programs, the precompiler puts all the variables and
structures it generates within a DSECT called SQLDSECT, and it generates an
assembler symbol called SQLDLEN. SQLDLEN contains the length of the
DSECT. Your program must allocate an area of the size indicated by SQLDLEN,
initialize it, and provide addressability to it as the DSECT SQLDSECT. The
precompiler does not generate code to allocate the storage for SQLDSECT; the
application program must allocate the storage.
CICS: An example of code to support reentrant programs, running under CICS,
follows:

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

DFHEISTG DSECT
DFHEISTG
EXEC SQL INCLUDE SQLCA
*
DS
0F
SQDWSREG EQU
R7
SQDWSTOR DS
(SQLDLEN)C RESERVE STORAGE TO BE USED FOR SQLDSECT
.
.
.
XXPROGRM DFHEIENT CODEREG=R12,EIBREG=R11,DATAREG=R13
*
*
* SQL WORKING STORAGE
LA
SQDWSREG,SQDWSTOR
GET ADDRESS OF SQLDSECT
USING SQLDSECT,SQDWSREG
AND TELL ASSEMBLER ABOUT IT
*

In this example, the actual storage allocation is done by the DFHEIENT macro.
TSO: The sample program in prefix.SDSNSAMP(DSNTIAD) contains an example
of how to acquire storage for the SQLDSECT in a program that runs in a TSO
environment. The following example code contains pieces from
prefix.SDSNSAMP(DSNTIAD) with explanations in the comments.

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

DSNTIAD

CSECT
SAVE
LR
USING
LR

(14,12)
R12,R15
DSNTIAD,R12
R7,R1

CONTROL SECTION NAME
ANY SAVE SEQUENCE
CODE ADDRESSABILITY
TELL THE ASSEMBLER
SAVE THE PARM POINTER

*
* Allocate storage of size PRGSIZ1+SQLDSIZ, where:
* - PRGSIZ1 is the size of the DSNTIAD program area
* - SQLDSIZ is the size of the SQLDSECT, and declared
*
when the DB2 precompiler includes the SQLDSECT
*
L
R6,PRGSIZ1
GET SPACE FOR USER PROGRAM
A
R6,SQLDSIZ
GET SPACE FOR SQLDSECT
GETMAIN R,LV=(6)
GET STORAGE FOR PROGRAM VARIABLES

244

Application Programming and SQL Guide
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

LR
R10,R1
POINT TO IT
*
* Initialize the storage
*
LR
R2,R10
POINT TO THE FIELD
LR
R3,R6
GET ITS LENGTH
SR
R4,R4
CLEAR THE INPUT ADDRESS
SR
R5,R5
CLEAR THE INPUT LENGTH
MVCL R2,R4
CLEAR OUT THE FIELD
*
* Map the storage for DSNTIAD program area
*
ST
R13,FOUR(R10)
CHAIN THE SAVEAREA PTRS
ST
R10,EIGHT(R13)
CHAIN SAVEAREA FORWARD
LR
R13,R10
POINT TO THE SAVEAREA
USING PRGAREA1,R13
SET ADDRESSABILITY
*
* Map the storage for the SQLDSECT
*
LR
R9,R13
POINT TO THE PROGAREA
A
R9,PRGSIZ1
THEN PAST TO THE SQLDSECT
USING SQLDSECT,R9
SET ADDRESSABILITY
...
LTORG
**********************************************************************
*
*
*
DECLARE VARIABLES, WORK AREAS
*
*
*
**********************************************************************
PRGAREA1 DSECT
WORKING STORAGE FOR THE PROGRAM
...
DS
0D
PRGSIZE1 EQU
*-PRGAREA1
DYNAMIC WORKAREA SIZE
...
DSNTIAD CSECT
RETURN TO CSECT FOR CONSTANT
PRGSIZ1 DC
A(PRGSIZE1)
SIZE OF PROGRAM WORKING STORAGE
CA
DSECT
EXEC SQL INCLUDE SQLCA
...

v DB2 does not process set symbols in SQL statements.
v Generated code can include more than two continuations per comment.
v Generated code uses literal constants (for example, =F’-84’), so an LTORG
statement might be necessary.
v Generated code uses registers 0, 1, 14, and 15. Register 13 points to a save area
that the called program uses. Register 15 does not contain a return code after a
call that is generated by an SQL statement.
CICS: A CICS application program uses the DFHEIENT macro to generate the
entry point code. When using this macro, consider the following:
– If you use the default DATAREG in the DFHEIENT macro, register 13 points
to the save area.
– If you use any other DATAREG in the DFHEIENT macro, you must provide
addressability to a save area.
For example, to use SAVED, you can code instructions to save, load, and
restore register 13 around each SQL statement as in the following example.
ST
13,SAVER13
LA
13,SAVED
EXEC SQL . . .
L
13,SAVER13

SAVE REGISTER 13
POINT TO SAVE AREA
RESTORE REGISTER 13

Chapter 3. Including DB2 queries in an application program

245
v If you have an addressability error in precompiler-generated code because of
input or output host variables in an SQL statement, check to make sure that you
have enough base registers.
v Do not put CICS translator options in the assembly source code. Instead, pass
the options to the translator by using the PARM field.

|
|
|
|
|

Embedding SQL statements in C or C++ applications

|
|
|

You can code SQL statements in a C program wherever you can use executable
statements.

|
|
|

Each SQL statement in a C program must begin with EXEC SQL and end with a
semicolon (;). The EXEC and SQL keywords must appear on one line, but the
remainder of the statement can appear on subsequent lines.

|
|
|
|

In general, because C is case sensitive, use uppercase letters to enter all SQL
keywords. However, if you use the FOLD precompiler suboption, DB2 folds
lowercase letters in SBCS SQL ordinary identifiers to uppercase. For information
about host language precompiler options, see Table 148 on page 854.

|
|
|
|
|
|
|
|

You must keep the case of host variable names consistent throughout the program.
For example, if a host variable name is lowercase in its declaration, it must be
lowercase in all SQL statements. You might code an UPDATE statement in a C
program as follows:

|
|
|
|
|

Comments: You can include C comments (/* ... */) within SQL statements
wherever you can use a blank, except between the keywords EXEC and SQL. You
can use single-line comments (starting with //) in C language statements, but not
in embedded SQL. You can use SQL comments within embedded SQL statements.
You can nest comments.

EXEC SQL
UPDATE DSN8910.DEPT
SET MGRNO = :mgr_num
WHERE DEPTNO = :int_dept;

To include EBCDIC DBCS characters in comments, you must delimit the characters
by a shift-out and shift-in control character; the first shift-in character in the DBCS
string signals the end of the DBCS string.
Continuation for SQL statements: You can use a backslash to continue a
character-string constant or delimited identifier on the following line. However,
EBCDIC DBCS string constants cannot be continued on a second line.
Declaring tables and views: Your C program should use the DECLARE TABLE
statement to describe each table and view the program accesses. You can use the
DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE
statements. For more information, see “DCLGEN (declarations generator)” on page
125.
Including SQL statements and variable declarations in source code that is to be
processed by the DB2 precompiler: To include SQL statements or C host variable
declarations from a member of a partitioned data set, add the following SQL
statement to the source code where you want to include the statements:

|
|

EXEC SQL INCLUDE member-name;

246

Application Programming and SQL Guide
You cannot nest SQL INCLUDE statements. Do not use C #include statements to
include SQL statements or C host variable declarations.
|
|
|
|
|

Margins: Code SQL statements in columns 1 through 72, unless you specify other
margins to the DB2 precompiler. If EXEC SQL is not within the specified margins,
the DB2 precompiler does not recognize the SQL statement. The margin rules do
not apply to the DB2 coprocessor. The DB2 coprocessor allows variable length
source input.

|
|
|
|

Names: You can use any valid C name for a host variable, subject to the following
restrictions:
v Do not use DBCS characters.
v Do not use external entry names or access plan names that begin with ’DSN’,
and do not use host variable names or macro names that begin with ’SQL’ (in
any combination of uppercase or lowercase letters). These names are reserved
for DB2.
Nulls and NULs: C and SQL differ in the way they use the word null. The C
language has a null character (NUL), a null pointer (NULL), and a null statement
(just a semicolon). The C NUL is a single character that compares equal to 0. The C
NULL is a special reserved pointer value that does not point to any valid data
object. The SQL null value is a special value that is distinct from all non-null
values and denotes the absence of a (nonnull) value. NUL (or NUL-terminator) is
the null character in C and C++, and NULL is the SQL null value.

|
|

Sequence numbers: The DB2 precompiler generates statements without sequence
numbers. (The DB2 coprocessor does not perform this action, because the source is
read and modified by the compiler. )
Statement labels: You can precede SQL statements with a label.
Trigraph characters: Some characters from the C character set are not available on
all keyboards. You can enter these characters into a C source program using a
sequence of three characters called a trigraph. The trigraph characters that DB2
supports are the same as those that the C compiler supports.
WHENEVER statement: The target for the GOTO clause in an SQL WHENEVER
statement must be within the scope of any SQL statements that the statement
WHENEVER affects.

|
|
|
|

Special C considerations:
v Using the C/370™ multi-tasking facility, in which multiple tasks execute SQL
statements, causes unpredictable results.
v Except for the DB2 coprocessor, you must run the DB2 precompiler before
running the C preprocessor.
v Except for the DB2 coprocessor, DB2 precompiler does not support C
preprocessor directives.
v If you use conditional compiler directives that contain C code, either place them
after the first C token in your application program, or include them in the C
program using the #include preprocessor directive.
Refer to the appropriate C documentation for more information about C
preprocessor directives.

Chapter 3. Including DB2 queries in an application program

247
Embedding SQL statements in COBOL applications
You can code SQL statements in certain COBOL program sections.
The allowable sections are shown in the following table.
Table 61. Allowable SQL statements for COBOL program sections
SQL statement

Program section

BEGIN DECLARE SECTION
END DECLARE SECTION
INCLUDE SQLCA

WORKING-STORAGE SECTION1 or LINKAGE
SECTION

INCLUDE text-file-name

PROCEDURE DIVISION or DATA DIVISION2

DECLARE TABLE
DECLARE CURSOR

DATA DIVISION or PROCEDURE DIVISION

DECLARE VARIABLE

WORKING-STORAGE SECTION1

Other

|

WORKING-STORAGE SECTION1 or LINKAGE
SECTION

PROCEDURE DIVISION

Notes:

|
|

1. If you use the DB2 coprocessor, you can use the LOCAL-STORAGE SECTION wherever
WORKING-STORAGE SECTION is listed in the table.
2. When including host variable declarations, the INCLUDE statement must be in the
WORKING-STORAGE SECTION or the LINKAGE SECTION.

You cannot put SQL statements in the DECLARATIVES section of a COBOL
program.
Each SQL statement in a COBOL program must begin with EXEC SQL and end
with END-EXEC. If you are using the DB2 precompiler, the EXEC and SQL
keywords must appear on one line, but the remainder of the statement can appear
on subsequent lines. If you are using the DB2 coprocessor, the EXEC and SQL
keywords can be on different lines. Do not include any tokens between the two
keywords EXEC and SQL except for COBOL comments, including debugging lines.
Do not include SQL comments between the keywords EXEC and SQL.

|
|
|
|
|
|
|

If the SQL statement appears between two COBOL statements, the period after
END-EXEC is optional and might not be appropriate. If the statement appears in
an IF...THEN set of COBOL statements, omit the ending period to avoid
inadvertently ending the IF statement.
You might code an UPDATE statement in a COBOL program as follows:
EXEC SQL
UPDATE DSN8910.DEPT
SET MGRNO = :MGR-NUM
WHERE DEPTNO = :INT-DEPT
END-EXEC.

Comments: You can include COBOL comment lines (* in column 7) in SQL
statements wherever you can use a blank. If you are using the DB2 precompiler,
you cannot include COBOL comment lines between the keywords EXEC and SQL.
The precompiler treats COBOL debugging lines and page-eject lines (/ in column
7) as comment lines. The DB2 coprocessor treats the debugging lines based on the
COBOL rules, which depend on the WITH DEBUGGING mode setting.

|
|
|
|
|
|

248

Application Programming and SQL Guide
|
|
|

For an SQL INCLUDE statement, the DB2 precompiler treats any text that follows
the period after END-EXEC, and on the same line as END-EXEC, as a comment.
The DB2 coprocessor treats this text as part of the COBOL program syntax.
In addition, you can include SQL comments (’--’) in any embedded SQL statement.

|
|
|

Debugging lines: The DB2 precompiler ignores the ’D’ in column 7 on debugging
lines and treats it as a blank. The DB2 coprocessor follows the COBOL language
rules regarding debugging lines.
Continuation for SQL statements: The rules for continuing a character string
constant from one line to the next in an SQL statement embedded in a COBOL
program are the same as those for continuing a non-numeric literal in COBOL.
However, you can use either a quote or an apostrophe as the first nonblank
character in area B of the continuation line. The same rule applies for the
continuation of delimited identifiers and does not depend on the string delimiter
option.
To conform with SQL standard, delimit a character string constant with an
apostrophe, and use a quote as the first nonblank character in area B of the
continuation line for a character string constant.
Continued lines of an SQL statement can be in columns 8 through 72 when using
the DB2 precompiler and columns 12 through 72 when using the DB2 coprocessor.

|
|
|

COPY: If you use the DB2 precompiler, do not use a COBOL COPY statement
within host variable declarations. If you use the DB2 coprocessor, you can use
COBOL COPY.
REPLACE: If you use the DB2 precompiler, the REPLACE statement has no effect
on SQL statements. It affects only the COBOL statements that the precompiler
generates.
If you use the DB2 coprocessor, the REPLACE statement replaces text strings in
SQL statements as well as in generated COBOL statements.
Declaring tables and views: Your COBOL program should include the statement
DECLARE TABLE to describe each table and view the program accesses. You can
use the DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE
statements. You should include the DCLGEN members in the DATA DIVISION.
For more information, see “DCLGEN (declarations generator)” on page 125.
Dynamic SQL in a COBOL program: In general, COBOL programs can easily
handle dynamic SQL statements. COBOL programs can handle SELECT statements
if the data types and the number of fields returned are fixed. If you want to use
variable-list SELECT statements, use an SQLDA. See “Defining SQL descriptor
areas” on page 137 for more information on SQLDA.
Including code: To include SQL statements or COBOL host variable declarations
from a member of a partitioned data set, use the following SQL statement in the
source code where you want to include the statements:
EXEC SQL INCLUDE member-name END-EXEC.

If you are using the DB2 precompiler, you cannot nest SQL INCLUDE statements.
In this case, do not use COBOL verbs to include SQL statements or host variable
declarations, and do not use the SQL INCLUDE statement to include CICS
Chapter 3. Including DB2 queries in an application program

249
preprocessor related code. In general, if you are using the DB2 precompiler, use the
SQL INCLUDE statement only for SQL-related coding. If you are using the COBOL
DB2 coprocessor, none of these restrictions apply.
Margins: You must code SQL statements that begin with EXEC SQL in columns 12
through 72. Otherwise the DB2 precompiler does not recognize the SQL statement.
Names: You can use any valid COBOL name for a host variable. Do not use
external entry names or access plan names that begin with ’DSN’, and do not use
host variable names that begin with ’SQL’. These names are reserved for DB2.
Sequence numbers: The source statements that the DB2 precompiler generates do
not include sequence numbers.
Statement labels: You can precede executable SQL statements in the PROCEDURE
DIVISION with a paragraph name, if you wish.
WHENEVER statement: The target for the GOTO clause in an SQL statement
WHENEVER must be a section name or unqualified paragraph name in the
PROCEDURE DIVISION.
Special COBOL considerations: The following considerations apply to programs
written in COBOL:
v In a COBOL program that uses elements in a multi-level structure as host
variable names, the DB2 precompiler generates the lowest two-level names.
v Using the COBOL compiler options DYNAM and NODYNAM depends on the
operating environment.
TSO and IMSYou can specify the option DYNAM when compiling a COBOL
program if you use the following guidelines. IMS and DB2 share a common alias
name, DSNHLI, for the language interface module. You must do the following
when you concatenate your libraries:
– If you use IMS with the COBOL option DYNAM, be sure to concatenate the
IMS library first.
– If you run your application program only under DB2, be sure to concatenate
the DB2 library first.
CICS, CAF, and RRSAFYou must specify the NODYNAM option when you
compile a COBOL program that either includes CICS statements or is translated
by a separate CICS translator or the integrated CICS translator. In these cases,
you cannot specify the DYNAM option. If your CICS program has a subroutine
that is not translated by a separate CICS translator or the integrated CICS
translator but contains SQL statements, you can specify the DYNAM option.
However, in this case, you must concatenate the CICS libraries before the DB2
libraries.

|
|
|
|
|
|
|
|

You can compile COBOL stored procedures with either the DYNAM option or
the NODYNAM option. If you use DYNAM, ensure that the correct DB2
language interface module is loaded dynamically by performing one of the
following actions:
– Use the ATTACH(RRSAF) precompiler option.
– Copy the DSNRLI module into a load library that is concatenated in front of
the DB2 libraries. Use the member name DSNHLI.
v To avoid truncating numeric values, use either of the following methods:
– Use the COMP-5 data type for binary integer host variables.
– Specify the COBOL compiler option:

250

Application Programming and SQL Guide
- TRUNC(OPT) if you are certain that the data being moved to each binary
variable by the application does not have a larger precision than is defined
in the PICTURE clause of the binary variable.
- TRUNC(BIN) if the precision of data being moved to each binary variable
might exceed the value in the PICTURE clause.
DB2 assigns values to binary integer host variables as if you had specified the
COBOL compiler option TRUNC(BIN) or used the COMP-5 data type.
v If you are using the DB2 precompiler and your COBOL program contains
several entry points or is called several times, the USING clause of the entry
statement that executes before the first SQL statement executes must contain the
SQLCA and all linkage section entries that any SQL statement uses as host
variables.
v If you use the DB2 precompiler, no compiler directives should appear between
the PROCEDURE DIVISION and the DECLARATIVES statement.
v Do not use COBOL figurative constants (such as ZERO and SPACE), symbolic
characters, reference modification, and subscripts within SQL statements.
v Observe the rules for naming SQL identifiers. For information about those rules,
see the topic “SQL identifiers” in DB2 SQL Reference. However, for COBOL only,
the names of SQL identifiers can follow the rules for naming COBOL words, if
the names do not exceed the allowable length for the DB2 object. For example,
the name 1ST-TIME is a valid cursor name because it is a valid COBOL word,
but the name 1ST_TIME is not valid because it is not a valid SQL identifier or a
valid COBOL word.
v Observe these rules for hyphens:
– Surround hyphens used as subtraction operators with spaces. DB2 usually
interprets a hyphen with no spaces around it as part of a host variable name.
v If you include an SQL statement in a COBOL PERFORM ... THRU paragraph and
also specify the SQL statement WHENEVER ... GO, the COBOL compiler returns
the warning message IGYOP3094. That message might indicate a problem. This
usage is not recommended.
v If you are using the DB2 precompiler, all SQL statements and any host variables
they reference must be within the first program when using nested programs or
batch compilation.
v If you are using the DB2 precompiler, your COBOL programs must have a
DATA DIVISION and a PROCEDURE DIVISION. Both divisions and the
WORKING-STORAGE section must be present in programs that contain SQL
statements.
PSPI

If your program uses the DB2 precompiler and uses parameters that are
defined in LINKAGE SECTION as host variables to DB2 and the address of the
input parameter might change on subsequent invocations of your program, your
program must reset the variable SQL-INIT-FLAG. This flag is generated by the
DB2 precompiler. Resetting this flag indicates that the storage must initialize when
the next SQL statement executes. To reset the flag, insert the statement MOVE
ZERO TO SQL-INIT-FLAG in the called program’s PROCEDURE DIVISION, ahead
of any executable SQL statements that use the host variables. If you use the
COBOL DB2 coprocessor, the called program does not need to reset
SQL-INIT-FLAG. PSPI

Chapter 3. Including DB2 queries in an application program

251
Embedding SQL statements in Fortran applications
You can code SQL statements in a Fortran program wherever you can place
executable statements. If the SQL statement is within an IF statement, the
precompiler generates any necessary THEN and END IF statements.
Fortran source statements must be fixed-length 80-byte records. The DB2
precompiler does not support free-form source input.
Each SQL statement in a Fortran program must begin with EXEC SQL. The EXEC
and SQL keywords must appear on one line, but the remainder of the statement
can appear on subsequent lines.
You might code the UPDATE statement in a Fortran program as follows:
EXEC SQL
UPDATE DSN8910.DEPT
SET MGRNO = :MGRNUM
WHERE DEPTNO = :INTDEPT

C
C
C

You cannot follow an SQL statement with another SQL statement or Fortran
statement on the same line.
Fortran does not require blanks to delimit words within a statement, but the SQL
language requires blanks. The rules for embedded SQL follow the rules for SQL
syntax, which require you to use one or more blanks as a delimiter.
Comments: You can include Fortran comment lines within embedded SQL
statements wherever you can use a blank, except between the keywords EXEC and
SQL. You can include SQL comments in any embedded SQL statement.
The DB2 precompiler does not support the exclamation point (!) as a comment
recognition character in Fortran programs.
Continuation for SQL statements: The line continuation rules for SQL statements
are the same as those for Fortran statements, except that you must specify EXEC
SQL on one line. The SQL examples in this topic have Cs in the sixth column to
indicate that they are continuations of EXEC SQL.
Declaring tables and views: Your Fortran program should also include the
DECLARE TABLE statement to describe each table and view the program accesses.
Dynamic SQL in a Fortran program: In general, Fortran programs can easily
handle dynamic SQL statements. SELECT statements can be handled if the data
types and the number of returned fields are fixed. If you want to use variable-list
SELECT statements, you need to use an SQLDA, as described in “Defining SQL
descriptor areas” on page 137.
You can use a Fortran character variable in the statements PREPARE and
EXECUTE IMMEDIATE, even if it is fixed-length.
Including code: To include SQL statements or Fortran host variable declarations
from a member of a partitioned data set, use the following SQL statement in the
source code where you want to include the statements:
EXEC SQL INCLUDE member-name

You cannot nest SQL INCLUDE statements. You cannot use the Fortran INCLUDE
compiler directive to include SQL statements or Fortran host variable declarations.

252

Application Programming and SQL Guide
Margins: Code the SQL statements between columns 7 through 72, inclusive. If
EXEC SQL starts before the specified left margin, the DB2 precompiler does not
recognize the SQL statement.
Names: You can use any valid Fortran name for a host variable. Do not use
external entry names that begin with ’DSN’ or host variable names that begin with
’SQL’. These names are reserved for DB2.
Do not use the word DEBUG, except when defining a Fortran DEBUG packet. Do
not use the words FUNCTION, IMPLICIT, PROGRAM, and SUBROUTINE to
define variables.
Sequence numbers: The source statements that the DB2 precompiler generates do
not include sequence numbers.
Statement labels: You can specify statement numbers for SQL statements in
columns 1 to 5. However, during program preparation, a labeled SQL statement
generates a Fortran CONTINUE statement with that label before it generates the
code that executes the SQL statement. Therefore, a labeled SQL statement should
never be the last statement in a DO loop. In addition, you should not label SQL
statements (such as INCLUDE and BEGIN DECLARE SECTION) that occur before
the first executable SQL statement, because an error might occur.
WHENEVER statement: The target for the GOTO clause in the SQL WHENEVER
statement must be a label in the Fortran source code and must refer to a statement
in the same subprogram. The WHENEVER statement only applies to SQL
statements in the same subprogram.
Special Fortran considerations: The following considerations apply to programs
written in Fortran:
v You cannot use the @PROCESS statement in your source code. Instead, specify
the compiler options in the PARM field.
v You cannot use the SQL INCLUDE statement to include the following
statements: PROGRAM, SUBROUTINE, BLOCK, FUNCTION, or IMPLICIT.
DB2 supports Version 3 Release 1 (or later) of VS Fortran with the following
restrictions:
v The parallel option is not supported. Applications that contain SQL statements
must not use Fortran parallelism.
v You cannot use the byte data type within embedded SQL, because byte is not a
recognizable host data type.

Embedding SQL statements in PL/I applications
You can code SQL statements in a PL/I program wherever you can use executable
statements.
The first statement of the PL/I program must be the PROCEDURE statement with
OPTIONS(MAIN), unless the program is a stored procedure. A stored procedure
application can run as a subroutine.
Each SQL statement in a PL/I program must begin with EXEC SQL and end with
a semicolon (;). The EXEC and SQL keywords must appear must appear on one
line, but the remainder of the statement can appear on subsequent lines.

Chapter 3. Including DB2 queries in an application program

253
You might code an UPDATE statement in a PL/I program as follows:
EXEC SQL UPDATE DSN8910.DEPT
SET MGRNO = :MGR_NUM
WHERE DEPTNO = :INT_DEPT ;

Comments: You can include PL/I comments in embedded SQL statements
wherever you can use a blank, except between the keywords EXEC and SQL. You
can also include SQL comments in any SQL statement.
To include DBCS characters in comments, you must delimit the characters by a
shift-out and shift-in control character; the first shift-in character in the DBCS
string signals the end of the DBCS string.
Continuation for SQL statements: The line continuation rules for SQL statements
are the same as those for other PL/I statements, except that you must specify
EXEC SQL on one line.
Declaring tables and views: Your PL/I program should include a DECLARE
TABLE statement to describe each table and view the program accesses. You can
use the DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE
statements. For more information, see “DCLGEN (declarations generator)” on page
125.
Including code: You can use SQL statements or PL/I host variable declarations
from a member of a partitioned data set by using the following SQL statement in
the source code where you want to include the statements:
EXEC SQL INCLUDE member-name;

You cannot nest SQL INCLUDE statements. Do not use the PL/I %INCLUDE
statement to include SQL statements or host variable DCL statements. You must
use the PL/I preprocessor to resolve any %INCLUDE statements before you use
the DB2 precompiler. Do not use PL/I preprocessor directives within SQL
statements.
Margins: Code SQL statements in columns 2 through 72, unless you have specified
other margins to the DB2 precompiler. If EXEC SQL starts before the specified left
margin, the DB2 precompiler does not recognize the SQL statement.
Names: You can use any valid PL/I name for a host variable. Do not use external
entry names or access plan names that begin with ’DSN’, and do not use host
variable names that begin with ’SQL’. These names are reserved for DB2.
Sequence numbers: The source statements that the DB2 precompiler generates do
not include sequence numbers. IEL0378I messages from the PL/I compiler identify
lines of code without sequence numbers. You can ignore these messages.
Statement labels: You can specify a statement label for executable SQL statements.
However, the INCLUDE text-file-name and END DECLARE SECTION statements
cannot have statement labels.
Whenever statement: The target for the GOTO clause in an SQL statement
WHENEVER must be a label in the PL/I source code and must be within the
scope of any SQL statements that WHENEVER affects.
Using double-byte character set (DBCS) characters: The following considerations
apply to using DBCS in PL/I programs with SQL statements:

254

Application Programming and SQL Guide
v If you use DBCS in the PL/I source, DB2 rules for the following language
elements apply:
– Graphic strings
– Graphic string constants
– Host identifiers
– Mixed data in character strings
– MIXED DATA option
v The PL/I preprocessor transforms the format of DBCS constants. If you do not
want that transformation, run the DB2 precompiler before the preprocessor.
v If you use graphic string constants or mixed data in dynamically prepared SQL
statements, and if your application requires the PL/I Version 2 (or later)
compiler, the dynamically prepared statements must use the PL/I mixed
constant format.
– If you prepare the statement from a host variable, change the string
assignment to a PL/I mixed string.
– If you prepare the statement from a PL/I string, change that to a host
variable, and then change the string assignment to a PL/I mixed string.
Example:
SQLSTMT = ’SELECT <dbdb> FROM table-name’M;
EXEC SQL PREPARE STMT FROM :SQLSTMT;

v
v

v

v

For instructions on preparing SQL statements dynamically, see “Dynamic SQL”
on page 258.
If you want a DBCS identifier to resemble a PL/I graphic string, you must use a
delimited identifier.
If you include DBCS characters in comments, you must delimit the characters
with a shift-out and shift-in control character. The first shift-in character signals
the end of the DBCS string.
You can declare host variable names that use DBCS characters in PL/I
application programs. The rules for using DBCS variable names in PL/I follow
existing rules for DBCS SQL ordinary identifiers, except for length. The
maximum length for a host variable is 128 Unicode bytes in DB2. For
information about the rules for DBCS SQL ordinary identifiers, see the topic
“SQL identifiers” in DB2 SQL Reference.
Restrictions:
– DBCS variable names must contain DBCS characters only. Mixing single-byte
character set (SBCS) characters with DBCS characters in a DBCS variable
name produces unpredictable results.
– A DBCS variable name cannot continue to the next line.
The PL/I preprocessor changes non-Kanji DBCS characters into extended binary
coded decimal interchange code (EBCDIC) SBCS characters. To avoid this
change, use Kanji DBCS characters for DBCS variable names, or run the PL/I
compiler without the PL/I preprocessor.

Special PL/I considerations: The following considerations apply to programs
written in PL/I:
v When compiling a PL/I program that includes SQL statements, you must use
the PL/I compiler option CHARSET (60 EBCDIC).
v In unusual cases, the generated comments in PL/I can contain a semicolon. The
semicolon generates compiler message IEL0239I, which you can ignore.

Chapter 3. Including DB2 queries in an application program

255
v The generated code in a PL/I declaration can contain the ADDR function of a
field defined as character varying. This produces either message IBM105l l or
IBM1180l W, both of which you can ignore.
v The precompiler generated code in PL/I source can contain the NULL()
function. This produces message IEL0533I, which you can ignore unless you also
use NULL as a PL/I variable. If you use NULL as a PL/I variable in a DB2
application, you must also declare NULL as a built-in function (DCL NULL
BUILTIN;) to avoid PL/I compiler errors.
v The PL/I macro processor can generate SQL statements or host variable DCL
statements if you run the macro processor before running the DB2 precompiler.
If you use the PL/I macro processor, do not use the PL/I *PROCESS statement
in the source to pass options to the PL/I compiler. You can specify the needed
options on the COPTION parameter of the DSNH command or the option
PARM.PLI=options of the EXEC statement in the DSNHPLI procedure.
v Using the PL/I multitasking facility, in which multiple tasks execute SQL
statements, causes unpredictable results.

Embedding SQL statements in REXX procedures
You can code SQL statements in a REXX procedure wherever you can use REXX
commands.
DB2 REXX Language Support allows all SQL statements that DB2 for z/OS
supports, except the following statements:
v BEGIN DECLARE SECTION
v DECLARE STATEMENT
v END DECLARE SECTION
v INCLUDE
v SELECT INTO
v WHENEVER
Each SQL statement in a REXX procedure must begin with EXECSQL, in either
upper-, lower-, or mixed-case. One of the following items must follow EXECSQL:
v An SQL statement enclosed in single or double quotation marks.
v A REXX variable that contains an SQL statement. The REXX variable must not
be preceded by a colon.
For example, you can use either of the following methods to execute the COMMIT
statement in a REXX procedure:
EXECSQL "COMMIT"
rexxvar="COMMIT"
EXECSQL rexxvar

You cannot execute a SELECT, INSERT, UPDATE, MERGE, or DELETE statement
that contains host variables. Instead, you must execute PREPARE on the statement,
with parameter markers substituted for the host variables, and then use the host
variables in an EXECUTE, OPEN, or FETCH statement. See “Host variables, host
variable arrays, and host structures” on page 142 for more information.

|
|
|
|
|

An SQL statement follows rules that apply to REXX commands. The SQL statement
can optionally end with a semicolon and can be enclosed in single or double
quotation marks, as in the following example:
’EXECSQL COMMIT’;

256

Application Programming and SQL Guide
Comments: You cannot include REXX comments (/* ... */) or SQL comments (--)
within SQL statements. However, you can include REXX comments anywhere else
in the procedure.
Continuation for SQL statements: SQL statements that span lines follow REXX
rules for statement continuation. You can break the statement into several strings,
each of which fits on a line, and separate the strings with commas or with
concatenation operators followed by commas. For example, either of the following
statements is valid:
EXECSQL ,
"UPDATE DSN8910.DEPT" ,
"SET MGRNO = ’000010’" ,
"WHERE DEPTNO = ’D11’"
"EXECSQL " || ,
" UPDATE DSN8910.DEPT " || ,
" SET MGRNO = ’000010’" || ,
" WHERE DEPTNO = ’D11’"

Including code: The EXECSQL INCLUDE statement is not valid for REXX. You
therefore cannot include externally defined SQL statements in a procedure.
Margins: Like REXX commands, SQL statements can begin and end anywhere on a
line.
Names: You can use any valid REXX name that does not end with a period as a
host variable. However, host variable names should not begin with ’SQL’, ’RDI’,
’DSN’, ’RXSQL’, or ’QRW’. Variable names can be at most 64 bytes.
Nulls: A REXX null value and an SQL null value are different. The REXX language
has a null string (a string of length 0) and a null clause (a clause that contains only
blanks and comments). The SQL null value is a special value that is distinct from
all nonnull values and denotes the absence of a value. Assigning a REXX null
value to a DB2 column does not make the column value null.
Statement labels: You can precede an SQL statement with a label, in the same way
that you label REXX commands.
Handling errors and warnings: DB2 does not support the SQL WHENEVER
statement in a REXX procedure. To handle SQL errors and warnings, use the
following methods:
v To test for SQL errors or warnings, test the SQLCODE or SQLSTATE value and
the SQLWARN. values after each EXECSQL call. This method does not detect
errors in the REXX interface to DB2.
v To test for SQL errors or warnings or errors or warnings from the REXX
interface to DB2, test the REXX RC variable after each EXECSQL call. The
following table lists the values of the RC variable.
You can also use the REXX SIGNAL ON ERROR and SIGNAL ON FAILURE
keyword instructions to detect negative values of the RC variable and transfer
control to an error routine.
Table 62. REXX return codes after SQL statements
Return code

Meaning

0

No SQL warning or error occurred.

+1

An SQL warning occurred.

-1

An SQL error occurred.
Chapter 3. Including DB2 queries in an application program

257
Table 62. REXX return codes after SQL statements (continued)
Return code

Meaning

-3

The first token after ADDRESS DSNREXX is in error. For a description of
the tokens allowed, see “Accessing the DB2 REXX language support
application programming interfaces” on page 296.

Delimiting an SQL statement
You must delimit SQL statements in your program so that DB2 knows when a
particular SQL statement ends.
For languages other than REXX, delimit an SQL statement in your program with
the beginning keyword EXEC SQL and a statement terminator. The terminators for
the languages that are described in this information are the following:
Language
SQL Statement Terminator
Assembler
End of line or end of last continued line
C and C++
Semicolon (;)
COBOL
END-EXEC.
Fortran
End of line or end of last continued line
PL/I

Semicolon (;)

For REXX, precede the statement with EXECSQL. If the statement is in a literal
string, enclose it in single or double quotation marks.
Example: Use EXEC SQL and END-EXEC. to delimit an SQL statement in a COBOL
program:
EXEC SQL
an SQL statement
END-EXEC.

Including dynamic SQL in your program
Dynamic SQL is prepared and executed while the program is running. Before you
use dynamic SQL, you should consider whether static SQL or dynamic SQL is the
best technique for your application. Also consider the type of dynamic SQL that
you want to use.

Dynamic SQL
Dynamic SQL statements are prepared and executed while the program is running.
Use dynamic SQL when you do not know what SQL statements your application
needs to execute before run time.
Before you decide to use dynamic SQL, you should consider whether using static
SQL or dynamic SQL is the best technique for your application.
For most DB2 users, static SQL, which is embedded in a host language program
and bound before the program runs, provides a straightforward, efficient path to

258

Application Programming and SQL Guide
DB2 data. You can use static SQL when you know before run time what SQL
statements your application needs to execute.

|
|

Dynamic SQL prepares and executes the SQL statements within a program, while
the program is running. Four types of dynamic SQL are:
v Interactive SQL
A user enters SQL statements through SPUFI or the command line processor.
DB2 prepares and executes those statements as dynamic SQL statements.
v Embedded dynamic SQL
Your application puts the SQL source in host variables and includes PREPARE
and EXECUTE statements that tell DB2 to prepare and run the contents of those
host variables at run time. You must precompile and bind programs that include
embedded dynamic SQL.
v Deferred embedded SQL
Deferred embedded SQL statements are neither fully static nor fully dynamic.
Like static statements, deferred embedded SQL statements are embedded within
applications, but like dynamic statements, they are prepared at run time. DB2
processes deferred embedded SQL statements with bind-time rules. For example,
DB2 uses the authorization ID and qualifier determined at bind time as the plan
or package owner. Deferred embedded SQL statements are used for DB2 private
protocol access to remote data.
v Dynamic SQL executed through ODBC functions
Your application contains ODBC function calls that pass dynamic SQL
statements as arguments. You do not need to precompile and bind programs
that use ODBC function calls.
Differences between static and dynamic SQL:
Static and dynamic SQL are each appropriate for different circumstances. You
should consider the differences between the two when determining whether static
SQL or dynamic SQL is best for your application.
Flexibility of static SQL with host variables
When you use static SQL, you cannot change the form of SQL statements unless
you make changes to the program. However, you can increase the flexibility of
static statements by using host variables.
Example: In the following example, the UPDATE statement can update the salary
of any employee. At bind time, you know that salaries must be updated, but you
do not know until run time whose salaries should be updated, and by how much.
01

IOAREA.
02 EMPID
02 NEW-SALARY

PIC X(06).
PIC S9(7)V9(2) COMP-3.
.
.
.
(Other declarations)
READ CARDIN RECORD INTO IOAREA
. AT END MOVE ’N’ TO INPUT-SWITCH.
.
.
(Other COBOL statements)
EXEC SQL
UPDATE DSN8910.EMP
SET SALARY = :NEW-SALARY
WHERE EMPNO = :EMPID
END-EXEC.

Chapter 3. Including DB2 queries in an application program

259
The statement (UPDATE) does not change, nor does its basic structure, but the
input can change the results of the UPDATE statement.
Flexibility of dynamic SQL
What if a program must use different types and structures of SQL statements? If
there are so many types and structures that it cannot contain a model of each one,
your program might need dynamic SQL.
|

You can use one of the following programs to execute dynamic SQL:

|
|

DB2 Query Management Facility (DB2 QMF)
Provides an alternative interface to DB2 that accepts almost any SQL statement

|
|
|

SPUFI
Accepts SQL statements from an input data set, and then processes and
executes them dynamically

|
|

command line processor
Accepts SQL statements from a UNIX® System Services environment.
Limitations of dynamic SQL
You cannot use some of the SQL statements dynamically.
Dynamic SQL processing
A program that provides for dynamic SQL accepts as input, or generates, an SQL
statement in the form of a character string. You can simplify the programming if
you can plan the program not to use SELECT statements, or to use only those that
return a known number of values of known types. In the most general case, in
which you do not know in advance about the SQL statements that will execute, the
program typically takes these steps:
1. Translates the input data, including any parameter markers, into an SQL
statement
2. Prepares the SQL statement to execute and acquires a description of the result
table
3. Obtains, for SELECT statements, enough main storage to contain retrieved data
4. Executes the statement or fetches the rows of data
5. Processes the information returned
6. Handles SQL return codes.
Performance of static and dynamic SQL
To access DB2 data, an SQL statement requires an access path. Two big factors in
the performance of an SQL statement are the amount of time that DB2 uses to
determine the access path at run time and whether the access path is efficient. DB2
determines the access path for a statement at either of these times:
v When you bind the plan or package that contains the SQL statement
v When the SQL statement executes
The time at which DB2 determines the access path depends on these factors:
v Whether the statement is executed statically or dynamically
v Whether the statement contains input host variables

260

Application Programming and SQL Guide
Static SQL statements with no input host variables
For static SQL statements that do not contain input host variables, DB2 determines
the access path when you bind the plan or package. This combination yields the
best performance because the access path is already determined when the program
executes.
Static SQL statements with input host variables
|
|
|
|
|
|

For static SQL statements that have input host variables, the time at which DB2
determines the access path depends on which bind option you specify:
REOPT(NONE), REOPT(ONCE), or REOPT(ALWAYS). REOPT(NONE) is the
default. Do not specify REOPT(AUTO); this option is applicable only to dynamic
statements. DB2 ignores REOPT(AUTO) for static SQL statements, because DB2 can
cache only dynamic statements.
If you specify REOPT(NONE), DB2 determines the access path at bind time, just as
it does when there are no input variables.
DB2 ignores REOPT(ONCE) for static SQL statements because DB2 can cache only
dynamic SQL statements
If you specify REOPT(ALWAYS), DB2 determines the access path at bind time and
again at run time, using the values in these types of input variables:
v Host variables
v Parameter markers
v Special registers
This means that DB2 must spend extra time determining the access path for
statements at run time, but if DB2 determines a significantly better access path
using the variable values, you might see an overall performance improvement. In
general, using REOPT(ALWAYS) can make static SQL statements with input
variables perform like dynamic SQL statements with constants.
Dynamic SQL statements
For dynamic SQL statements, DB2 determines the access path at run time, when
the statement is prepared. This can make the performance worse than that of static
SQL statements. However, if you execute the same SQL statement often, you can
use the dynamic statement cache to decrease the number of times that those
dynamic statements must be prepared.

|
|
|

Dynamic SQL statements with input host variables: When you bind applications
that contain dynamic SQL statements with input host variables, use the
REOPT(ALWAYS) option, the REOPT(ONCE) option, or the REOPT(AUTO) option.
Use REOPT(ALWAYS) when you are not using the dynamic statement cache. DB2
determines the access path for statements at each EXECUTE or OPEN of the
statement. This ensure the best access path for a statement, but using
REOPT(ALWAYS) can increase the cost of frequently used dynamic SQL
statements.

|
|
|
|

Use REOPT(ONCE) or REOPT(AUTO) when you are using the dynamic statements
cache:
v If you specify REOPT(ONCE), DB2 determines and the access path for
statements only at the first EXECUTE or OPEN of the statement. It saves that
Chapter 3. Including DB2 queries in an application program

261
|
|
|
|
|
|
|
|

access path in the dynamic statement cache and uses it until the statement is
invalidated or removed from the cache. This reuse of the access path reduces the
cost of frequently used dynamic SQL statements that contain input host
variables; however, it does not account for changes to parameter marker values
for dynamic statements.
v If you specify REOPT(AUTO), DB2 determines the access path at run time. For
each execution of a statement with parameter markers, DB2 generates a new
access path if it determines that a new access path will improve performance.

|
|
|
|
|
|
|
|

You should code your PREPARE statements to minimize overhead. With
REOPT(AUTO), REOPT(ALWAYS), and REOPT(ONCE), DB2 prepares an SQL
statement at the same time as it processes OPEN or EXECUTE for the statement.
That is, DB2 processes the statement as if you specify DEFER(PREPARE). However,
in the following cases, DB2 prepares the statement twice:
v If you execute the DESCRIBE statement before the PREPARE statement in your
program
v If you use the PREPARE statement with the INTO parameter

|
|
|

For the first prepare, DB2 determines the access path without using input variable
values. For the second prepare, DB2 uses the input variable values to determine
the access path. This extra prepare can decrease performance.
If you specify REOPT(ALWAYS), DB2 prepares the statement twice each time it is
run.
If you specify REOPT(ONCE), DB2 prepares the statement twice only when the
statement has never been saved in the cache. If the statement has been prepared
and saved in the cache, DB2 will use the saved version of the statement to
complete the DESCRIBE statement.
If you specify REOPT(AUTO), DB2 initially prepares the statement without using
input variable values. If the statement has been saved in the cache, for the
subsequent OPEN or EXECUTE, DB2 determines if a new access path is needed
according to the input variable values.
For a statement that uses a cursor, you can avoid the double prepare by placing
the DESCRIBE statement after the OPEN statement in your program.
If you use predictive governing, and a dynamic SQL statement that is bound with
either REOPT(ALWAYS) or REOPT(ONCE) exceeds a predictive governing warning
threshold, your application does not receive a warning SQLCODE. However, it will
receive an error SQLCODE from the OPEN or EXECUTE statement.
Possible host languages for dynamic SQL applications:
Programs that use dynamic SQL are usually written in assembler, C, PL/I, REXX,
and COBOL. All SQL in REXX programs is dynamic SQL.
You can write non-SELECT and fixed-list SELECT statements in any of the DB2
supported languages. A program containing a varying-list SELECT statement is
more difficult to write in Fortran, because the program cannot run without the
help of a subroutine to manage address variables (pointers) and storage allocation.
Most of the examples in this topic are in PL/I. Longer examples in the form of
complete programs are available in the sample applications:

262

Application Programming and SQL Guide
DSNTEP2
Processes both SELECT and non-SELECT statements dynamically. (PL/I).
DSNTIAD
Processes only non-SELECT statements dynamically. (Assembler).
DSNTIAUL
Processes SELECT statements dynamically. (Assembler).
Library prefix.SDSNSAMP contains the sample programs. You can view the
programs online, or you can print them using ISPF, IEBPTPCH, or your own
printing program.
Using dynamic SQL in COBOL: You can use all forms of dynamic SQL in all
supported versions of COBOL. For a detailed description and a working example
of the method, see “Sample COBOL dynamic SQL program” on page 334.

Including dynamic SQL for non-SELECT statements in your
program
The easiest way to use dynamic SQL is to use non-SELECT statements. Because
you do not need to dynamically allocate any main storage, you can write your
program in any host language, including Fortran.
For a sample program written in C that contains dynamic SQL with non-SELECT
statements, see “Sample dynamic and static SQL in a C program” on page 331.
Your program must take the following steps:
1. Include an SQLCA. The requirements for an SQL communications area
(SQLCA) are the same as for static SQL statements. For REXX, DB2 includes the
SQLCA automatically.
2. Load the input SQL statement into a data area. The procedure for building or
reading the input SQL statement is not discussed here; the statement depends
on your environment and sources of information. You can read in complete
SQL statements, or you can get information to build the statement from data
sets, a user at a terminal, previously set program variables, or tables in the
database. If you attempt to execute an SQL statement dynamically that DB2
does not allow, you get an SQL error.
3. Execute the statement. You can use either of these methods:
v “Dynamically executing an SQL statement by using EXECUTE IMMEDIATE”
on page 283
v “Dynamically executing an SQL statement by using PREPARE and
EXECUTE” on page 284.
4. Handle any errors that might result. The requirements are the same as those for
static SQL statements. The return code from the most recently executed SQL
statement appears in the host variables SQLCODE and SQLSTATE or
corresponding fields of the SQLCA. See “Checking the execution of SQL
statements” on page 298 for information about the SQLCA and the fields it
contains.

Including dynamic SQL for fixed-list SELECT statements in your
program
A fixed-list SELECT statement returns rows that contain a known number of
values of a known type. When you use this type of statement, you know in
advance exactly what kinds of host variables you need to declare to store the
results.

Chapter 3. Including DB2 queries in an application program

263
(For information about the contrasting situation, in which you do not know in
advance what host-variable structure you might need, see “Including dynamic SQL
for varying-list SELECT statements in your program” on page 266.)
The term “fixed-list” does not imply that you must know in advance how many
rows of data will be returned. However, you must know the number of columns
and the data types of those columns. A fixed-list SELECT statement returns a result
table that can contain any number of rows; your program looks at those rows one
at a time, using the FETCH statement. Each successive fetch returns the same
number of values as the last, and the values have the same data types each time.
Therefore, you can specify host variables as you do for static SQL.
An advantage of the fixed-list SELECT is that you can write it in any of the
programming languages that DB2 supports. Varying-list dynamic SELECT
statements require assembler, C, PL/I, and COBOL.
For a sample program that is written in C and that illustrates dynamic SQL with
fixed-list SELECT statements, see “Sample dynamic and static SQL in a C
program” on page 331.
To execute a fixed-list SELECT statement dynamically, your program must:
1. Include an SQLCA.
2. Load the input SQL statement into a data area. The preceding two steps are
exactly the same as described under “Including dynamic SQL for non-SELECT
statements in your program” on page 263.
3. Declare a cursor for the statement name.
4. Prepare the statement.
5. Open the cursor.
6. Fetch rows from the result table.
7. Close the cursor.
8. Handle any resulting errors. This step is the same as for static SQL, except for
the number and types of errors that can result.
Example: Suppose that your program retrieves last names and phone numbers by
dynamically executing SELECT statements of this form:
SELECT LASTNAME, PHONENO FROM DSN8910.EMP
WHERE ... ;

The program reads the statements from a terminal, and the user determines the
WHERE clause.
As with non-SELECT statements, your program puts the statements into a
varying-length character variable; call it DSTRING. Eventually you prepare a
statement from DSTRING, but first you must declare a cursor for the statement
and give it a name.
Declaring a cursor for the statement name:
Dynamic SELECT statements cannot use INTO. Therefore, you must use a cursor
to put the results into host variables.
Example: When you declare the cursor, use the statement name (call it STMT), and
give the cursor itself a name (for example, C1):
EXEC SQL DECLARE C1 CURSOR FOR STMT;

264

Application Programming and SQL Guide
Preparing the statement:
Prepare a statement (STMT) from DSTRING.
Example: This is one possible PREPARE statement:
EXEC SQL PREPARE STMT FROM :DSTRING ATTRIBUTES :ATTRVAR;

ATTRVAR contains attributes that you want to add to the SELECT statement, such
as FETCH FIRST 10 ROWS ONLY or OPTIMIZE for 1 ROW. In general, if the
SELECT statement has attributes that conflict with the attributes in the PREPARE
statement, the attributes on the SELECT statement take precedence over the
attributes on the PREPARE statement. However, in this example, the SELECT
statement in DSTRING has no attributes specified, so DB2 uses the attributes in
ATTRVAR for the SELECT statement.
As with non-SELECT statements, the fixed-list SELECT could contain parameter
markers. However, this example does not need them.
To execute STMT, your program must open the cursor, fetch rows from the result
table, and close the cursor.
Opening the cursor:
The OPEN statement evaluates the SELECT statement named STMT.
Example: Without parameter markers, use this statement:
EXEC SQL OPEN C1;

If STMT contains parameter markers, you must use the USING clause of OPEN to
provide values for all of the parameter markers in STMT.
Example: If four parameter markers are in STMT, you need the following
statement:
EXEC SQL OPEN C1 USING :PARM1, :PARM2, :PARM3, :PARM4;

Fetching rows from the result table:
Example: Your program could repeatedly execute a statement such as this:
EXEC SQL FETCH C1 INTO :NAME, :PHONE;

The key feature of this statement is the use of a list of host variables to receive the
values returned by FETCH. The list has a known number of items (in this case,
two items, :NAME and :PHONE) of known data types (both are character strings,
of lengths 15 and 4, respectively).
You can use this list in the FETCH statement only because you planned the
program to use only fixed-list SELECTs. Every row that cursor C1 points to must
contain exactly two character values of appropriate length. If the program is to
handle anything else, it must use the techniques described under “Including
dynamic SQL for varying-list SELECT statements in your program” on page 266.
Closing the cursor:
This step is the same as for static SQL.

Chapter 3. Including DB2 queries in an application program

265
Example: A WHENEVER NOT FOUND statement in your program can name a
routine that contains this statement:
EXEC SQL CLOSE C1;

Including dynamic SQL for varying-list SELECT statements in
your program
A varying-list SELECT statement returns rows that contain an unknown number of
values of unknown type. When you use this type of statement, you do not know
in advance exactly what kinds of host variables you need to declare to store the
results.
. (For the much simpler situation, in which you do know, see “Including dynamic
SQL for fixed-list SELECT statements in your program” on page 263.) Because the
varying-list SELECT statement requires pointer variables for the SQL descriptor
area, you cannot issue it from a Fortran program. A Fortran program can call a
subroutine written in a language that supports pointer variables (such as PL/I or
assembler), if you need to use a varying-list SELECT statement.
What your application program must do for varying-list SELECT statements: To
execute a varying-list SELECT statement dynamically, your program must follow
these steps:
1. Include an SQLCA.
DB2 performs this step for a REXX procedure.
2. Load the input SQL statement into a data area.
Those first two steps are exactly the same as described under “Including
dynamic SQL for non-SELECT statements in your program” on page 263; the
next step is new:
3. Prepare and execute the statement. This step is more complex than for fixed-list
SELECTs. It involves the following steps:
a. Include an SQLDA (SQL descriptor area).
DB2 performs this step for a REXX procedure.
b. Declare a cursor and prepare the variable statement.
c. Obtain information about the data type of each column of the result table.
d. Determine the main storage needed to hold a row of retrieved data.
You do not perform this step for a REXX procedure.
e. Put storage addresses in the SQLDA to tell where to put each item of
retrieved data.
f. Open the cursor.
g. Fetch a row.
h. Eventually close the cursor and free main storage.
Additional complications exist for statements with parameter markers.
4. Handle any errors that might result.
Preparing a varying-list SELECT statement:
Suppose that your program dynamically executes SQL statements, but this time
without any limits on their form. Your program reads the statements from a
terminal, and you know nothing about them in advance. They might not even be
SELECT statements.

266

Application Programming and SQL Guide
As with non-SELECT statements, your program puts the statements into a
varying-length character variable; call it DSTRING. Your program goes on to
prepare a statement from the variable and then give the statement a name; call it
STMT.
Now, the program must find out whether the statement is a SELECT. If it is, the
program must also find out how many values are in each row, and what their data
types are. The information comes from an SQL descriptor area (SQLDA).
An SQL descriptor area:
The SQLDA is a structure that is used to communicate with your program, and
storage for it is usually allocated dynamically at run time.
To include the SQLDA in a PL/I or C program, use:
EXEC SQL INCLUDE SQLDA;

For assembler, use this in the storage definition area of a CSECT:
EXEC SQL INCLUDE SQLDA

For COBOL, use:
EXEC SQL INCLUDE SQLDA END-EXEC.

You cannot include an SQLDA in a Fortran, or REXX program.
For more information about the SQLDA, see the topic “SQL descriptor area
(SQLDA)” in DB2 SQL Reference.
Obtaining information about the SQL statement:
An SQLDA can contain a variable number of occurrences of SQLVAR, each of
which is a set of five fields that describe one column in the result table of a
SELECT statement.
The number of occurrences of SQLVAR depends on the following factors:
v The number of columns in the result table you want to describe.
v Whether you want the PREPARE or DESCRIBE to put both column names and
labels in your SQLDA. This is the option USING BOTH in the PREPARE or
DESCRIBE statement.
v Whether any columns in the result table are LOB types or distinct types.
The following table shows the minimum number of SQLVAR instances you need
for a result table that contains n columns.
Table 63. Minimum number of SQLVARs for a result table with n columns
Type of DESCRIBE and contents of result
table

Not USING BOTH

USING BOTH

No distinct types or LOBs

n

2*n

Distinct types but no LOBs

2*n

3*n

LOBs but no distinct types

2*n

2*n

LOBs and distinct types

2*n

3*n

Chapter 3. Including DB2 queries in an application program

267
An SQLDA with n occurrences of SQLVAR is referred to as a single SQLDA, an
SQLDA with 2*n occurrences of SQLVAR a double SQLDA, an SQLDA with 3*n
occurrences of SQLVAR a triple SQLDA.
A program that admits SQL statements of every kind for dynamic execution has
two choices:
v Provide the largest SQLDA that it could ever need. The maximum number of
columns in a result table is 750, so an SQLDA for 750 columns occupies 33 016
bytes for a single SQLDA, 66 016 bytes for a double SQLDA, or 99 016 bytes for
a triple SQLDA. Most SELECT statements do not retrieve 750 columns, so the
program does not usually use most of that space.
v Provide a smaller SQLDA, with fewer occurrences of SQLVAR. From this the
program can find out whether the statement was a SELECT and, if it was, how
many columns are in its result table. If more columns are in the result than the
SQLDA can hold, DB2 returns no descriptions. When this happens, the program
must acquire storage for a second SQLDA that is long enough to hold the
column descriptions, and ask DB2 for the descriptions again. Although this
technique is more complicated to program than the first, it is more general.
How many columns should you allow? You must choose a number that is large
enough for most of your SELECT statements, but not too wasteful of space; 40 is
a good compromise. To illustrate what you must do for statements that return
more columns than allowed, the example in this discussion uses an SQLDA that
is allocated for at least 100 columns.
Declaring a cursor for the statement:
As before, you need a cursor for the dynamic SELECT. For example, write:
EXEC SQL
DECLARE C1 CURSOR FOR STMT;

Preparing the statement using the minimum SQLDA:
Suppose that your program declares an SQLDA structure with the name
MINSQLDA, having 100 occurrences of SQLVAR and SQLN set to 100. To prepare
a statement from the character string in DSTRING and also enter its description
into MINSQLDA, write this:
EXEC SQL PREPARE STMT FROM :DSTRING;
EXEC SQL DESCRIBE STMT INTO :MINSQLDA;

Equivalently, you can use the INTO clause in the PREPARE statement:
EXEC SQL
PREPARE STMT INTO :MINSQLDA FROM :DSTRING;

Do not use the USING clause in either of these examples. At the moment, only the
minimum SQLDA is in use. The following figure shows the contents of the
minimum SQLDA in use.

Header

SQLDAID

SQLDABC

100

SQLD

Figure 21. The minimum SQLDA structure

SQLN determines what SQLVAR gets:

268

Application Programming and SQL Guide
The SQLN field, which you must set before using DESCRIBE (or PREPARE INTO),
tells how many occurrences of SQLVAR the SQLDA is allocated for. If DESCRIBE
needs more than that, the results of the DESCRIBE depend on the contents of the
result table. Let n indicate the number of columns in the result table. Then:
v If the result table contains at least one distinct type column but no LOB
columns, you do not specify USING BOTH, and n<=SQLN<2*n, then DB2
returns base SQLVAR information in the first n SQLVAR occurrences, but no
distinct type information. Base SQLVAR information includes:
– Data type code
– Length attribute (except for LOBs)
– Column name or label
– Host variable address
– Indicator variable address
v Otherwise, if SQLN is less than the minimum number of SQLVARs specified in
Table 63 on page 267, then DB2 returns no information in the SQLVARs.
Regardless of whether your SQLDA is big enough, whenever you execute
DESCRIBE, DB2 returns the following values, which you can use to build an
SQLDA of the correct size:
v SQLD is 0 if the SQL statement is not a SELECT. Otherwise, SQLD is the
number of columns in the result table. The number of SQLVAR occurrences you
need for the SELECT depends on the value in the seventh byte of SQLDAID.
v The seventh byte of SQLDAID is 2 if each column in the result table requires
two SQLVAR entries. The seventh byte of SQLDAID is 3 if each column in the
result table requires three SQLVAR entries.
If the statement is not a SELECT:
To find out if the statement is a SELECT, your program can query the SQLD field
in MINSQLDA. If the field contains 0, the statement is not a SELECT, the
statement is already prepared, and your program can execute it. If no parameter
markers are in the statement, you can use:
EXEC SQL EXECUTE STMT;

(If the statement does contain parameter markers, you must use an SQL descriptor
area; for instructions, see “Including dynamic SQL for varying-list SELECT
statements in your program” on page 266.)
Acquiring storage for a second SQLDA if needed:
Now you can allocate storage for a second, full-size SQLDA; call it FULSQLDA.
The following figure shows its structure.

Chapter 3. Including DB2 queries in an application program

269
Figure 22. The full-size SQLDA structure

FULSQLDA has a fixed-length header of 16 bytes in length, followed by a
varying-length section that consists of structures with the SQLVAR format. If the
result table contains LOB columns or distinct type columns, a varying-length
section that consists of structures with the SQLVAR2 format follows the structures
with SQLVAR format. All SQLVAR structures and SQLVAR2 structures are 44 bytes
long. For more information about the two SQLVAR formats, see the topic
“DESCRIBE OUTPUT” in DB2 SQL Reference. The number of SQLVAR and
SQLVAR2 elements you need is in the SQLD field of MINSQLDA, and the total
length you need for FULSQLDA (16 + SQLD * 44) is in the SQLDABC field of
MINSQLDA. Allocate that amount of storage.
Describing the SELECT statement again:
After allocating sufficient space for FULSQLDA, your program must take these
steps:
1. Put the total number of SQLVAR and SQLVAR2 occurrences in FULSQLDA into
the SQLN field of FULSQLDA. This number appears in the SQLD field of
MINSQLDA.
2. Describe the statement again into the new SQLDA:
EXEC SQL DESCRIBE STMT INTO :FULSQLDA;

After the DESCRIBE statement executes, each occurrence of SQLVAR in the
full-size SQLDA (FULSQLDA in our example) contains a description of one
column of the result table in five fields. If an SQLVAR occurrence describes a LOB
column or distinct type column, the corresponding SQLVAR2 occurrence contains
additional information specific to the LOB or distinct type.
The following figure shows an SQLDA that describes two columns that are not
LOB columns or distinct type columns.

270

Application Programming and SQL Guide
SQLDA

SQLDA header

8816

200

200

SQLVAR element 1 (44 bytes)

452

3

Undefined

0

8

WORKDEPT

SQLVAR element 2 (44 bytes)

453

4

Undefined

0

7

PHONENO

Figure 23. Contents of FULSQLDA after executing DESCRIBE

Acquiring storage to hold a row:
Before fetching rows of the result table, your program must:
1. Analyze each SQLVAR description to determine how much space you need for
the column value.
2. Derive the address of some storage area of the required size.
3. Put this address in the SQLDATA field.
If the SQLTYPE field indicates that the value can be null, the program must also
put the address of an indicator variable in the SQLIND field. The following figures
show the SQL descriptor area after you take certain actions.
In Figure 23, the DESCRIBE statement inserted all the values except the first
occurrence of the number 200. The program inserted the number 200 before it
executed DESCRIBE to tell how many occurrences of SQLVAR to allow. If the
result table of the SELECT has more columns than this, the SQLVAR fields describe
nothing.
The first SQLVAR pertains to the first column of the result table (the WORKDEPT
column). SQLVAR element 1 contains fixed-length character strings and does not
allow null values (SQLTYPE=452); the length attribute is 3. For information about
SQLTYPE values, see the topic “SQLTYPE and SQLLEN” in DB2 SQL Reference.
The following figure shows the SQLDA after your program acquires storage for the
column values and their indicators, and puts the addresses in the SQLDATA fields
of the SQLDA.

SQLDA

SQLDA header

8816

200

200

SQLVAR element 1 (44 bytes)

452

3

Addr FLDA

Addr FLDAI

8

WORKDEPT

SQLVAR element 2 (44 bytes)

453

4

Addr FLDB

Addr FLDBI

7

PHONENO

FLDA
CHAR(3)

FLDB
CHAR(4)

Indicator variables
(halfword)
FLDAI
FLDBI

Figure 24. SQL descriptor area after analyzing descriptions and acquiring storage

The following figure shows the SQLDA after your program executes a FETCH
statement.

Chapter 3. Including DB2 queries in an application program

271
SQLDA

SQLDA header

8816

200

200

SQLVAR element 1 (44 bytes)

452

3

Addr FLDA

Addr FLDAI

8

WORKDEPT

SQLVAR element 2 (44 bytes)

453

4

Addr FLDB

Addr FLDBI

7

PHONENO

FLDA
CHAR(3)

Indicator variables
(halfword)
FLDAI
FLDBI

FLDB
CHAR(4)

E11

4502

0

0

Figure 25. SQL descriptor area after executing FETCH

The following table describes the values in the descriptor area.
Table 64. Values inserted in the SQLDA
Value

Field

Description

SQLDA

SQLDAID

An “eye-catcher”

8816

SQLDABC

The size of the SQLDA in bytes (16 + 44 * 200)

200

SQLN

The number of occurrences of SQLVAR, set by the
program

200

SQLD

The number of occurrences of SQLVAR actually used
by the DESCRIBE statement

452

SQLTYPE

The value of SQLTYPE in the first occurrence of
SQLVAR. It indicates that the first column contains
fixed-length character strings, and does not allow
nulls.

3

SQLLEN

The length attribute of the column

Undefined or
CCSID value

SQLDATA

Bytes 3 and 4 contain the CCSID of a string column.
Undefined for other types of columns.

Undefined

SQLIND

8

SQLNAME

The number of characters in the column name

WORKDEPT

SQLNAME+2

The column name of the first column

Putting storage addresses in the SQLDA:
After analyzing the description of each column, your program must replace the
content of each SQLDATA field with the address of a storage area large enough to
hold values from that column. Similarly, for every column that allows nulls, the
program must replace the content of the SQLIND field. The content must be the
address of a halfword that you can use as an indicator variable for the column.
The program can acquire storage for this purpose, of course, but the storage areas
used do not have to be contiguous.
Figure 24 on page 271 shows the content of the descriptor area before the program
obtains any rows of the result table. Addresses of fields and indicator variables are
already in the SQLVAR.
Changing the CCSID for retrieved data:
All DB2 string data has an encoding scheme and CCSID associated with it. When
you select string data from a table, the selected data generally has the same

272

Application Programming and SQL Guide
encoding scheme and CCSID as the table. If the application uses some method,
such as issuing the DECLARE VARIABLE statement, to change the CCSID of the
selected data, the data is converted from the CCSID of the table to the CCSID that
is specified by the application.
You can set the default application encoding scheme for a plan or package by
specifying the value in the APPLICATION ENCODING field of the panel
DEFAULTS FOR BIND PACKAGE or DEFAULTS FOR BIND PLAN. The default
application encoding scheme for the DB2 subsystem is the value that was specified
in the APPLICATION ENCODING field of installation panel DSNTIPF.
If you want to retrieve the data in an encoding scheme and CCSID other than the
default values, you can use one of the following techniques:
v For dynamic SQL, set the CURRENT APPLICATION ENCODING SCHEME
special register before you execute the SELECT statements. For example, to set
the CCSID and encoding scheme for retrieved data to the default CCSID for
Unicode, execute this SQL statement:
EXEC SQL SET CURRENT APPLICATION ENCODING SCHEME =’UNICODE’;

The initial value of this special register is the application encoding scheme that
is determined by the BIND option.
v For static and dynamic SQL statements that use host variables and host variable
arrays, use the DECLARE VARIABLE statement to associate CCSIDs with the
host variables into which you retrieve the data. See “Changing the coded
character set ID of host variables” on page 146 for information about this
technique.
v For static and dynamic SQL statements that use a descriptor, set the CCSID for
the retrieved data in the SQLDA. The following text describes that technique.
To change the encoding scheme for SQL statements that use a descriptor, set up the
SQLDA, and then make these additional changes to the SQLDA:
1. Put the character + in the sixth byte of field SQLDAID.
2. For each SQLVAR entry:
a. Set the length field of SQLNAME to 8.
b. Set the first two bytes of the data field of SQLNAME to X’0000’.
c. Set the third and fourth bytes of the data field of SQLNAME to the CCSID,
in hexadecimal, in which you want the results to display, or to X’0000’.
X’0000’ indicates that DB2 should use the default CCSID If you specify a
nonzero CCSID, it must meet one of the following conditions:
v A row in catalog table SYSSTRINGS has a matching value for
OUTCCSID.
v The Unicode conversion services support conversion to that CCSID. See
z/OS C/C++ Programming Guide for information about the conversions
supported.
If you are modifying the CCSID to retrieve the contents of an ASCII,
EBCDIC, or Unicode table on a DB2 for z/OS system, and you previously
executed a DESCRIBE statement on the SELECT statement that you are
using to retrieve the data, the SQLDATA fields in the SQLDA that you used
for the DESCRIBE contain the ASCII or Unicode CCSID for that table. To set
the data portion of the SQLNAME fields for the SELECT, move the contents
of each SQLDATA field in the SQLDA from the DESCRIBE to each
SQLNAME field in the SQLDA for the SELECT. If you are using the same

Chapter 3. Including DB2 queries in an application program

273
SQLDA for the DESCRIBE and the SELECT, be sure to move the contents of
the SQLDATA field to SQLNAME before you modify the SQLDATA field
for the SELECT.
For REXX, you set the CCSID in the stem.n.SQLUSECCSID field instead of
setting the SQLDAID and SQLNAME fields.
For example, suppose that the table that contains WORKDEPT and PHONENO is
defined with CCSID ASCII. To retrieve data for columns WORKDEPT and
PHONENO in ASCII CCSID 437 (X’01B5’), change the SQLDA as shown in the
following figure.

SQLDA header

SQLDA+

8816

200

200

SQLVAR element 1 (44 bytes)

452

3

Addr FLDA

Addr FLDAI

8

X’000001B500000000’

SQLVAR element 2 (44 bytes)

453

4

Addr FLDB

Addr FLDBI

8

X’000001B500000000’

FLDA
CHAR(3)

FLDB
CHAR(4)

Indicator variables
(halfword)
FLDAI
FLDBI

Figure 26. SQL descriptor area for retrieving data in ASCII CCSID 437

Specifying that DESCRIBE use column labels in the SQLNAME field:
By default, DESCRIBE describes each column in the SQLNAME field by the
column name. You can tell it to use column labels instead.
Restriction: You cannot use column labels with set operators (UNION,
INTERSECT, and EXCEPT).
To specify that DESCRIBE use column labels in the SQLNAME field, specify one of
the following options when you issue the DESCRIBE statement:
USING LABELS
Specifies that SQLNAME is to contain labels. If a column has no label,
SQLNAME contains nothing.
USING ANY
Specifies that SQLNAME is to contain labels wherever they exist. If a column
has no label, SQLNAME contains the column name.
USING BOTH
Specifies that SQLNAME is to contain both labels and column names, when
both exist.
In this case, FULSQLDA must contain a second set of occurrences of SQLVAR.
The first set contains descriptions of all the columns with column names; the
second set contains descriptions with column labels.
If you choose this option, perform the following actions:
v Allocate a longer SQLDA for the second DESCRIBE statement ((16 + SQLD *
88 bytes) instead of (16 + SQLD * 44))
v Put double the number of columns (SLQD * 2) in the SQLN field of the
second SQLDA.

274

Application Programming and SQL Guide
These actions ensure that enough space is available. Otherwise, if not enough
space is available, DESCRIBE does not enter descriptions of any of the
columns.
EXEC SQL
DESCRIBE STMT INTO :FULSQLDA USING LABELS;

|
|
|
|

Some columns, such as those derived from functions or expressions, have neither
name nor label; SQLNAME contains nothing for those columns. For example, if
you use a UNION to combine two columns that do not have the same name and
do not use a label, SQLNAME contains a string of length zero.
Describing tables with LOB and distinct type columns:
In general, the steps that you perform when you prepare an SQLDA to select rows
from a table with LOB and distinct type columns are similar to the steps that you
perform if the table has no columns of this type. The only difference is that you
need to analyze some additional fields in the SQLDA for LOB or distinct type
columns.
Example: Suppose that you want to execute this SELECT statement:
SELECT USER, A_DOC FROM DOCUMENTS;

The USER column cannot contain nulls and is of distinct type ID, defined like this:
CREATE DISTINCT TYPE SCHEMA1.ID AS CHAR(20);

The A_DOC column can contain nulls and is of type CLOB(1M).
The result table for this statement has two columns, but you need four SQLVAR
occurrences in your SQLDA because the result table contains a LOB type and a
distinct type. Suppose that you prepare and describe this statement into
FULSQLDA, which is large enough to hold four SQLVAR occurrences. FULSQLDA
looks like the following figure .

SQLDA 2

SQLDA header

192

4

4

SQLVAR element 1 (44 bytes)

452

20

Undefined

0

4

USER

SQLVAR element 2 (44 bytes)

409

0

Undefined

0

5

A_DOC

7

SCH1.ID

SQLVAR2 element 1 (44 bytes)
SQLVAR2 element 2 (44 bytes)

1 048 576

11

SYSIBM.CLOB

Figure 27. SQL descriptor area after describing a CLOB and distinct type

The next steps are the same as for result tables without LOBs or distinct types:
1. Analyze each SQLVAR description to determine the maximum amount of space
you need for the column value.
For a LOB type, retrieve the length from the SQLLONGL field instead of the
SQLLEN field.
2. Derive the address of some storage area of the required size.
For a LOB data type, you also need a 4-byte storage area for the length of the
LOB data. You can allocate this 4-byte area at the beginning of the LOB data or
in a different location.
3. Put this address in the SQLDATA field.

Chapter 3. Including DB2 queries in an application program

275
For a LOB data type, if you allocated a separate area to hold the length of the
LOB data, put the address of the length field in SQLDATAL. If the length field
is at beginning of the LOB data area, put 0 in SQLDATAL. When you use a file
reference variable for a LOB column, the indicator variable indicates whether
the data in the file is null, not whether the data to which SQLDATA points is
null.
4. If the SQLTYPE field indicates that the value can be null, the program must
also put the address of an indicator variable in the SQLIND field.
The following figure shows the contents of FULSQLDA after you fill in pointers to
the storage locations.

Figure 28. SQL descriptor area after analyzing CLOB and distinct type descriptions and acquiring storage

The following figure shows the contents of FULSQLDA after you execute a FETCH
statement.

Figure 29. SQL descriptor area after executing FETCH on a table with CLOB and distinct type columns

Setting an XML host variable in an SQLDA:

276

Application Programming and SQL Guide
Instead of specifying host variables to store XML values from a table, you can
create an SQLDA to point to the data areas where DB2 puts the retrieved data. The
SQLDA needs to describe the data type for each data area.
To set an XML host variable in an SQLDA:
1. Allocate an appropriate SQLDA. For instructions on how to allocate an SQLDA,
see the topic “DESCRIBE OUTPUT” in DB2 SQL Reference.
2. Issue a DESCRIBE statement for the SQL statement whose result set you want
to store. The DESCRIBE statement populates the SQLDA based on the column
definitions. In the SQLDA, an SQLVAR entry is populated for each column in
the result set. (Multiple SQLVAR entries are populated for LOB columns and
columns with distinct types.) For columns of type XML the associated SQLVAR
entry is populated as follows:
Table 65. SQLVAR field values for XML columns
SQLVAR field

Value for an XML column

sqltype
SQLTYPE

988 for a column that is not nullable
or 989 for a nullable column
0

sqllen
SQLLEN
0
sqldata
SQLDATA
0
sqlind
SQLIND
The unqualified name or label of the column
sqlname
SQLNAME

3. Check the SQLTYPE field of each SQLVAR entry. If the SQLTYPE field is 988 or
989, the column in the result set is an XML column.
4. For each XML column, make the following changes to the associated SQLVAR
entry:
a. Change the SQLTYPE field to indicate the data type of the host variable to
receive the XML data. You can retrieve the XML data into a host variable of
type XML AS BLOB, XML AS CLOB, or XML AS DBCLOB, or a compatible
string data type.
If the target host variable type is XML AS BLOB, XML AS CLOB, or XML
AS DBCLOB, set the SQLTYPE field to one of the following values:
404
XML AS BLOB
405
nullable XML AS BLOB
408
XML AS CLOB
409
nullable XML AS CLOB

Chapter 3. Including DB2 queries in an application program

277
412
XML AS DBCLOB
413
nullable XML AS DBCLOB
If the target host variable type is a string data type, set the SQLTYPE field
to a valid string value. For a list of valid string values, see the topic “Field
descriptions” in DB2 SQL Reference.
Restriction: You cannot use the XML type (988/989) as a target host
variable type.
b. If the target host variable type is XML AS BLOB, XML AS CLOB, or XML
AS DBCLOB, change the first two bytes in the SQLNAME field to X’0000’
and the fifth and sixth bytes to X’0100’. These bytes indicate that the value
to be received is an XML value.
5. Populate the extended SQLVAR fields for each XML column as you would for a
LOB column, as indicated in the following table.
Table 66. Fields for an extended SQLVAR entry for an XML host variable
SQLVAR field

Value for an XML host variable
length attribute for the XML host variable

len.sqllonglen
SQLLONGL
SQLLONGLEN
*

Reserved
pointer to the length of the XML host variable

sqldatalen
SQLDATAL
SQLDATALEN
not used
sqldatatype_name
SQLTNAME
SQLDATATYPENAME

You can now use the SQLDA to retrieve the XML data into a host variable of type
XML AS BLOB, XML AS CLOB, or XML AS DBCLOB, or a compatible string data
type.
Executing a varying-list SELECT statement dynamically:
You can easily retrieve rows of the result table using a varying-list SELECT
statement. The statements differ only a little from those for the fixed-list example.
Open the cursor: If the SELECT statement contains no parameter marker, this step
is simple enough. For example:
EXEC SQL OPEN C1;

Fetch rows from the result table: This statement differs from the corresponding
one for the case of a fixed-list select. Write:
EXEC SQL
FETCH C1 USING DESCRIPTOR :FULSQLDA;

The key feature of this statement is the clause USING DESCRIPTOR :FULSQLDA.
That clause names an SQL descriptor area in which the occurrences of SQLVAR

278

Application Programming and SQL Guide
point to other areas. Those other areas receive the values that FETCH returns. It is
possible to use that clause only because you previously set up FULSQLDA to look
like Figure 23 on page 271.
Figure 25 on page 272 shows the result of the FETCH. The data areas identified in
the SQLVAR fields receive the values from a single row of the result table.
Successive executions of the same FETCH statement put values from successive
rows of the result table into these same areas.
Close the cursor: This step is the same as for the fixed-list case. When no more
rows need to be processed, execute the following statement:
EXEC SQL CLOSE C1;

When COMMIT ends the unit of work containing OPEN, the statement in STMT
reverts to the unprepared state. Unless you defined the cursor using the WITH
HOLD option, you must prepare the statement again before you can reopen the
cursor.
Executing arbitrary statements with parameter markers:
Consider, as an example, a program that executes dynamic SQL statements of
several kinds, including varying-list SELECT statements, any of which might
contain a variable number of parameter markers. This program might present your
users with lists of choices: choices of operation (update, select, delete); choices of
table names; choices of columns to select or update. The program also enables the
users to enter lists of employee numbers to apply to the chosen operation. From
this, the program constructs SQL statements of several forms, one of which looks
like this:
SELECT .... FROM DSN8910.EMP
WHERE EMPNO IN (?,?,?,...?);

The program then executes these statements dynamically.
When the number and types of parameters are known: In the preceding example,
you do not know in advance the number of parameter markers, and perhaps the
kinds of parameter they represent. You can use techniques described previously if
you know the number and types of parameters, as in the following examples:
v If the SQL statement is not SELECT, name a list of host variables in the
EXECUTE statement:
WRONG:

EXEC SQL EXECUTE STMT;

RIGHT:

EXEC SQL EXECUTE STMT USING :VAR1, :VAR2, :VAR3;

v If the SQL statement is SELECT, name a list of host variables in the OPEN
statement:
WRONG:

EXEC SQL OPEN C1;

RIGHT:

EXEC SQL OPEN C1 USING :VAR1, :VAR2, :VAR3;

In both cases, the number and types of host variables named must agree with the
number of parameter markers in STMT and the types of parameter they represent.
The first variable (VAR1 in the examples) must have the type expected for the first
parameter marker in the statement, the second variable must have the type
expected for the second marker, and so on. There must be at least as many
variables as parameter markers.
Chapter 3. Including DB2 queries in an application program

279
When the number and types of parameters are not known: When you do not
know the number and types of parameters, you can adapt the SQL descriptor area.
Your program can include an unlimited number of SQLDAs, and you can use them
for different purposes. Suppose that an SQLDA, arbitrarily named DPARM,
describes a set of parameters.
The structure of DPARM is the same as that of any other SQLDA. The number of
occurrences of SQLVAR can vary, as in previous examples. In this case, every
parameter marker must have one SQLVAR. Each occurrence of SQLVAR describes
one host variable that replaces one parameter marker at run time. DB2 replaces the
parameter markers when a non-SELECT statement executes or when a cursor is
opened for a SELECT statement.
You must fill in certain fields in DPARM before using EXECUTE or OPEN; you
can ignore the other fields.
Field

Use when describing host variables for parameter markers

SQLDAID
The seventh byte indicates whether more than one SQLVAR entry is used
for each parameter marker. If this byte is not blank, at least one parameter
marker represents a distinct type or LOB value, so the SQLDA has more
than one set of SQLVAR entries.
You do not set this field for a REXX SQLDA.
SQLDABC
The length of the SQLDA, which is equal to SQLN * 44 + 16. You do not
set this field for a REXX SQLDA.
SQLN The number of occurrences of SQLVAR allocated for DPARM. You do not
set this field for a REXX SQLDA.
SQLD The number of occurrences of SQLVAR actually used. This number must
not be less than the number of parameter markers. In each occurrence of
SQLVAR, put information in the following fields: SQLTYPE, SQLLEN,
SQLDATA, SQLIND.
SQLTYPE
The code for the type of variable, and whether it allows nulls.
SQLLEN
The length of the host variable.
SQLDATA
The address of the host variable.
For REXX, this field contains the value of the host variable.
SQLIND
The address of an indicator variable, if needed.
For REXX, this field contains a negative number if the value in SQLDATA
is null.
SQLNAME
Ignore.
Using the SQLDA with EXECUTE or OPEN: To indicate that the SQLDA called
DPARM describes the host variables substituted for the parameter markers at run
time, use a USING DESCRIPTOR clause with EXECUTE or OPEN.
v For a non-SELECT statement, write:

280

Application Programming and SQL Guide
EXEC SQL EXECUTE STMT USING DESCRIPTOR :DPARM;

v For a SELECT statement, write:
EXEC SQL OPEN C1 USING DESCRIPTOR :DPARM;

How bind options REOPT(ALWAYS), REOPT(AUTO) and REOPT(ONCE) affect
dynamic SQL:
When you specify the bind option REOPT(ALWAYS), DB2 reoptimizes the access
path at run time for SQL statements that contain host variables, parameter
markers, or special registers. The option REOPT(ALWAYS) has the following effects
on dynamic SQL statements:
v When you specify the option REOPT(ALWAYS), DB2 automatically uses
DEFER(PREPARE), which means that DB2 waits to prepare a statement until it
encounters an OPEN or EXECUTE statement.
v When you execute a DESCRIBE statement and then an EXECUTE statement on a
non-SELECT statement, DB2 prepares the statement twice: Once for the
DESCRIBE statement and once for the EXECUTE statement. DB2 uses the values
in the input variables only during the second PREPARE. These multiple
PREPAREs can cause performance to degrade if your program contains many
dynamic non-SELECT statements. To improve performance, consider putting the
code that contains those statements in a separate package and then binding that
package with the option REOPT(NONE).
v If you execute a DESCRIBE statement before you open a cursor for that
statement, DB2 prepares the statement twice. If, however, you execute a
DESCRIBE statement after you open the cursor, DB2 prepares the statement only
once. To improve the performance of a program bound with the option
REOPT(ALWAYS), execute the DESCRIBE statement after you open the cursor.
To prevent an automatic DESCRIBE before a cursor is opened, do not use a
PREPARE statement with the INTO clause.
v If you use predictive governing for applications bound with REOPT(ALWAYS),
DB2 does not return a warning SQLCODE when dynamic SQL statements
exceed the predictive governing warning threshold. DB2 does return an error
SQLCODE when dynamic SQL statements exceed the predictive governing error
threshold. DB2 returns the error SQLCODE for an EXECUTE or OPEN
statement.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

When you specify the bind option REOPT(AUTO), DB2 optimizes the access path
for SQL statements at the first EXECUTE or OPEN. Each time a statement is
executed, DB2 determines if a new access path is needed to improve the
performance of the statement. If a new access path will improve the performance,
DB2 generates one. The option REOPT(AUTO) has the following effects on
dynamic SQL statements:
v When you specify the bind option REOPT(AUTO), DB2 optimizes the access
path for SQL statements at the first EXECUTE or OPEN. Each time a statement
is executed, DB2 determines if a new access path is needed to improve the
performance of the statement. If a new access path will improve the
performance, DB2 generates one.
v When you specify the option REOPT(ONCE), DB2 automatically uses
DEFER(PREPARE), which means that DB2 waits to prepare a statement until it
encounters an OPEN or EXECUTE statement.
v When DB2 prepares a statement using REOPT(AUTO), it saves the access path
in the dynamic statement cache. This access path is used each time the statement
is run, until DB2 determines that a new access path is needed to improve the

Chapter 3. Including DB2 queries in an application program

281
performance or the statement that is in the cache is invalidated (or removed
from the cache) and needs to be rebound.
v The DESCRIBE statement has the following effects on dynamic statements that
are bound with REOPT(AUTO):
– When you execute a DESCRIBE statement before an EXECUTE statement on a
non-SELECT statement, DB2 prepares the statement an extra time if it is not
already saved in the cache: Once for the DESCRIBE statement and once for
the EXECUTE statement. DB2 uses the values of the input variables only
during the second time the statement is prepared. It then saves the statement
in the cache. If you execute a DESCRIBE statement before an EXECUTE
statement on a non-SELECT statement that has already been saved in the
cache, DB2 will always prepare the non-SELECT statement for the DESCRIBE
statement, and will prepare the statement again on EXECUTE only if DB2
determines that a new access path different from the one already saved in the
cache can improve the performance.
– If you execute DESCRIBE on a statement before you open a cursor for that
statement, DB2 always prepares the statement on DESCRIBE. However, DB2
will not prepare the statement again on OPEN if the statement has already
been saved in the cache and DB2 doesn’t think that a new access path is
needed at OPEN time. If you execute DESCRIBE on a statement after you
open a cursor for that statement, DB2 prepared the statement only once if it is
not already saved in the cache. If the statement is already saved in the cache
and you execute DESCRIBE after you open a cursor for that statement, DB2
does not prepare the statement, it used the statement that is saved in the
cache.
v If you use predictive governing for applications that are bound with
REOPT(AUTO), DB2 does not return a warning SQLCODE when dynamic SQL
statements exceed the predictive governing warning threshold. DB2 does return
an error SQLCODE when dynamic SQL statements exceed the predictive
governing error threshold. DB2 returns the error SQLCODE for an EXECUTE or
OPEN statement.

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

When you specify the bind option REOPT(ONCE), DB2 optimizes the access path
only once, at the first EXECUTE or OPEN, for SQL statements that contain host
variables, parameter markers, or special registers. The option REOPT(ONCE) has
the following effects on dynamic SQL statements:
v When you specify the option REOPT(ONCE), DB2 automatically uses
DEFER(PREPARE), which means that DB2 waits to prepare a statement until it
encounters an OPEN or EXECUTE statement.
v When DB2 prepares a statement using REOPT(ONCE), it saves the access path
in the dynamic statement cache. This access path is used each time the statement
is run, until the statement that is in the cache is invalidated (or removed from
the cache) and needs to be rebound.
v The DESCRIBE statement has the following effects on dynamic statements that
are bound with REOPT(ONCE):
– When you execute a DESCRIBE statement before an EXECUTE statement on a
non-SELECT statement, DB2 prepares the statement twice if it is not already
saved in the cache: Once for the DESCRIBE statement and once for the
EXECUTE statement. DB2 uses the values of the input variables only during
the second time the statement is prepared. It then saves the statement in the
cache. If you execute a DESCRIBE statement before an EXECUTE statement
on a non-SELECT statement that has already been saved in the cache, DB2
prepares the non-SELECT statement only for the DESCRIBE statement.

282

Application Programming and SQL Guide
– If you execute DESCRIBE on a statement before you open a cursor for that
statement, DB2 always prepares the statement on DESCRIBE. However, DB2
will not prepare the statement again on OPEN if the statement has already
been saved in the cache. If you execute DESCRIBE on a statement after you
open a cursor for that statement, DB2 prepared the statement only once if it is
not already saved in the cache. If the statement is already saved in the cache
and you execute DESCRIBE after you open a cursor for that statement, DB2
does not prepare the statement, it used the statement that is saved in the
cache.
To improve the performance of a program that is bound with REOPT(ONCE),
execute the DESCRIBE statement after you open a cursor. To prevent an
automatic DESCRIBE before a cursor is opened, do not use a PREPARE
statement with the INTO clause.
v If you use predictive governing for applications that are bound with
REOPT(ONCE), DB2 does not return a warning SQLCODE when dynamic SQL
statements exceed the predictive governing warning threshold. DB2 does return
an error SQLCODE when dynamic SQL statements exceed the predictive
governing error threshold. DB2 returns the error SQLCODE for an EXECUTE or
OPEN statement.

Dynamically executing an SQL statement by using EXECUTE
IMMEDIATE
In certain situations, you want your program to prepare and dynamically execute a
statement immediately after reading it.
Suppose that you design a program to read SQL DELETE statements, similar to
these, from a terminal:
DELETE FROM DSN8910.EMP WHERE EMPNO = ’000190’
DELETE FROM DSN8910.EMP WHERE EMPNO = ’000220’

After reading a statement, the program is to run it immediately.
Recall that you must prepare (precompile and bind) static SQL statements before
you can use them. You cannot prepare dynamic SQL statements in advance. The
SQL statement EXECUTE IMMEDIATE causes an SQL statement to prepare and
execute, dynamically, at run time.
Declaring the host variableBefore you prepare and execute an SQL statement, you
can read it into a host variable. If the maximum length of the SQL statement is 32
KB, declare the host variable as a character or graphic host variable according to
the following rules for the host languages:
|
|
|

v In assembler, PL/I, COBOL and C, you must declare a string host variable as a
varying-length string.
v In Fortran, it must be a fixed-length string variable.
If the length is greater than 32 KB, you must declare the host variable as a CLOB
or DBCLOB, and the maximum is 2 MB.
Example: Using a varying-length character host variable: This excerpt is from a C
program that reads a DELETE statement into the host variable dstring and executes
the statement:
EXEC SQL BEGIN DECLARE SECTION;
...
struct VARCHAR {
short len;
char s[40];
Chapter 3. Including DB2 queries in an application program

283
} dstring;
EXEC SQL END DECLARE SECTION;
...
/* Read a DELETE statement into the host variable dstring. */
gets(dstring);
EXEC SQL EXECUTE IMMEDIATE :dstring;
...

EXECUTE IMMEDIATE causes the DELETE statement to be prepared and executed
immediately.
Declaring a CLOB or DBLOB host variable: You declare CLOB and DBCLOB host
variables according to the rules described in “LOB host variable, LOB locator, and
LOB file reference variable declarations” on page 661.
The precompiler generates a structure that contains two elements, a 4-byte length
field and a data field of the specified length. The names of these fields vary
depending on the host language:
v In PL/I, assembler, and Fortran, the names are variable_LENGTH and
variable_DATA.
v In COBOL, the names are variable–LENGTH and variable–DATA.
v In C, the names are variable.LENGTH and variable.DATA.
Example: Using a CLOB host variable: This excerpt is from a C program that
copies an UPDATE statement into the host variable string1 and executes the
statement:
EXEC SQL BEGIN DECLARE SECTION;
...
SQL TYPE IS CLOB(4k) string1;
EXEC SQL END DECLARE SECTION;
...
/* Copy a statement into the host variable string1. */
strcpy(string1.data, "UPDATE DSN8610.EMP SET SALARY = SALARY * 1.1");
string1.length = 44;
EXEC SQL EXECUTE IMMEDIATE :string1;
...

EXECUTE IMMEDIATE causes the UPDATE statement to be prepared and
executed immediately.

Dynamically executing an SQL statement by using PREPARE and
EXECUTE
As an alternative to executing an SQL statement immediately after it is read, you
can prepare and execute the SQL statement in two steps. This two-step method is
useful when you need to execute an SQL statement multiple times with different
values.
Suppose that you want to execute DELETE statements repeatedly using a list of
employee numbers. Consider how you would do it if you could write the DELETE
statement as a static SQL statement:
< Read a value for EMP from the list. >
DO UNTIL (EMP = 0);
EXEC SQL
DELETE FROM DSN8910.EMP WHERE EMPNO = :EMP ;
< Read a value for EMP from the list. >
END;

The loop repeats until it reads an EMP value of 0.

284

Application Programming and SQL Guide
If you know in advance that you will use only the DELETE statement and only the
table DSN8910.EMP, you can use the more efficient static SQL. Suppose further
that several different tables have rows that are identified by employee numbers,
and that users enter a table name as well as a list of employee numbers to delete.
Although variables can represent the employee numbers, they cannot represent the
table name, so you must construct and execute the entire statement dynamically.
Your program must now do these things differently:
v Use parameter markers instead of host variables
v Use the PREPARE statement
v Use EXECUTE instead of EXECUTE IMMEDIATE
Parameter markers with PREPARE and EXECUTE: Dynamic SQL statements
cannot use host variables. Therefore, you cannot dynamically execute an SQL
statement that contains host variables. Instead, substitute a parameter marker,
indicated by a question mark (?), for each host variable in the statement.
You can indicate to DB2 that a parameter marker represents a host variable of a
certain data type by specifying the parameter marker as the argument of a CAST
specification. When the statement executes, DB2 converts the host variable to the
data type in the CAST specification. A parameter marker that you include in a
CAST specification is called a typed parameter marker. A parameter marker without
a CAST specification is called an untyped parameter marker.
Recommendation: Because DB2 can evaluate an SQL statement with typed
parameter markers more efficiently than a statement with untyped parameter
markers, use typed parameter markers whenever possible. Under certain
circumstances you must use typed parameter markers. For information about rules
for using untyped or typed parameter markers, see the topic “PREPARE” in DB2
SQL Reference.
Example using parameter markers: Suppose that you want to prepare this
statement:
DELETE FROM DSN8910.EMP WHERE EMPNO = :EMP;

You need to prepare a string like this:
DELETE FROM DSN8910.EMP WHERE EMPNO = CAST(? AS CHAR(6))

You associate host variable :EMP with the parameter marker when you execute the
prepared statement. Suppose that S1 is the prepared statement. Then the EXECUTE
statement looks like this:
EXECUTE S1 USING :EMP;

Using the PREPARE statement: Before you prepare an SQL statement, you can
assign it to a host variable. If the length of the statement is greater than 32 KB, you
must declare the host variable as a CLOB or DBCLOB. For more information about
declaring the host variable, see “Dynamically executing an SQL statement by using
EXECUTE IMMEDIATE” on page 283.
You can think of PREPARE and EXECUTE as an EXECUTE IMMEDIATE done in
two steps. The first step, PREPARE, turns a character string into an SQL statement,
and then assigns it a name of your choosing.
Example using the PREPARE statement: Assume that the character host variable
:DSTRING has the value “DELETE FROM DSN8910.EMP WHERE EMPNO = ?”.
To prepare an SQL statement from that string and assign it the name S1, write:
Chapter 3. Including DB2 queries in an application program

285
EXEC SQL PREPARE S1 FROM :DSTRING;

The prepared statement still contains a parameter marker, for which you must
supply a value when the statement executes. After the statement is prepared, the
table name is fixed, but the parameter marker enables you to execute the same
statement many times with different values of the employee number.
Using the EXECUTE statement: The EXECUTE statement executes a prepared SQL
statement by naming a list of one or more host variables, one or more host variable
arrays, or a host structure. This list supplies values for all of the parameter
markers.
After you prepare a statement, you can execute it many times within the same unit
of work. In most cases, COMMIT or ROLLBACK destroys statements prepared in a
unit of work. Then, you must prepare them again before you can execute them
again. However, if you declare a cursor for a dynamic statement and use the
option WITH HOLD, a commit operation does not destroy the prepared statement
if the cursor is still open. You can execute the statement in the next unit of work
without preparing it again.
Example using the EXECUTE statement: To execute the prepared statement S1 just
once, using a parameter value contained in the host variable :EMP, write:
EXEC SQL EXECUTE S1 USING :EMP;

Preparing and executing the example DELETE statement: The example in this
topic began with a DO loop that executed a static SQL statement repeatedly:
< Read a value for EMP from the list. >
DO UNTIL (EMP = 0);
EXEC SQL
DELETE FROM DSN8910.EMP WHERE EMPNO = :EMP ;
< Read a value for EMP from the list. >
END;

You can now write an equivalent example for a dynamic SQL statement:
< Read a statement containing parameter markers into DSTRING.>
EXEC SQL PREPARE S1 FROM :DSTRING;
< Read a value for EMP from the list. >
DO UNTIL (EMPNO = 0);
EXEC SQL EXECUTE S1 USING :EMP;
< Read a value for EMP from the list. >
END;

The PREPARE statement prepares the SQL statement and calls it S1. The EXECUTE
statement executes S1 repeatedly, using different values for EMP.
Using more than one parameter marker: The prepared statement (S1 in the
example) can contain more than one parameter marker. If it does, the USING
clause of EXECUTE specifies a list of variables or a host structure. The variables
must contain values that match the number and data types of parameters in S1 in
the proper order. You must know the number and types of parameters in advance
and declare the variables in your program, or you can use an SQLDA (SQL
descriptor area).

Dynamically executing a data change statement
Dynamically executing data change statements with host variable arrays is useful if
you want to enter rows of data into different tables or enter a different number of
rows. The process is similar for both INSERT and MERGE statements.

|
|
|

286

Application Programming and SQL Guide
For example, suppose that you want to repeatedly execute a multiple-row INSERT
statement with a list of activity IDs, activity keywords, and activity descriptions
that are provided by the user. You can use the following static SQL INSERT
statement to insert multiple rows of data into the activity table:
EXEC SQL
INSERT INTO DSN8910.ACT
VALUES (:hva_actno, :hva_actkwd, :hva_actdesc)
FOR :num_rows ROWS;

However, if you want to enter the rows of data into different tables or enter
different numbers of rows, you can construct the INSERT statement dynamically.
This topic describes the following methods that you can use to execute a data
change statement dynamically:
v By using host variable arrays that contain the data to be inserted
v By using a descriptor to describe the host variable arrays that contain the data
Dynamically executing a data change statement by using host variable arrays:
To dynamically execute a data change statement by using host variable arrays,
perform the following actions in your program:
1. Assign the appropriate INSERT or MERGE statement to a host variable. If
needed, use the CAST specification to explicitly assign types to parameter
markers that represent host variable arrays.
Example: For the activity table, the following string contains an INSERT
statement that is to be prepared:
INSERT INTO DSN8910.ACT
VALUES (CAST(? AS SMALLINT), CAST(? AS CHAR(6)), CAST(? AS VARCHAR(20)))

2. Assign any attributes for the SQL statement to a host variable.
3. Include a PREPARE statement for the SQL statement.
4. Include an EXECUTE statement with the FOR n ROWS clause.
Each host variable in the USING clause of the EXECUTE statement represents
an array of values for the corresponding column of the target of the SQL
statement. You can vary the number of rows without needing to prepare the
SQL statement again.
Example: The following code prepares and executes an INSERT statement:
/* Copy the INSERT string into the host variable sqlstmt */
strcpy(sqlstmt, "INSERT INTO DSN8910.ACT VALUES (CAST(? AS SMALLINT),");
strcat(sqlstmt, " CAST(? AS CHAR(6)), CAST(? AS VARCHAR(20)))");
/* Copy the INSERT attributes into the host variable attrvar */
strcpy(attrvar, "FOR MULTIPLE ROWS");
/* Prepare and execute my_insert using the host variable arrays */
EXEC SQL PREPARE my_insert ATTRIBUTES :attrvar FROM :sqlstmt;
EXEC SQL EXECUTE my_insert USING :hva1, :hva2, :hva3 FOR :num_rows ROWS;

Dynamically executing a data change statement by using descriptors:
You can use an SQLDA structure to specify data types and other information about
the host variable arrays that contain the values to insert.
To dynamically execute a data change statement by using descriptors, perform the
following actions in your program:
1. Set the following fields in the SQLDA structure for your INSERT statement.
Chapter 3. Including DB2 queries in an application program

287
v SQLN
v SQLABC
v SQLD
v SQLVAR
v SQLNAME
Example: Assume that your program includes the standard SQLDA structure
declaration and declarations for the program variables that point to the SQLDA
structure. For C application programs, the following example code sets the
SQLDA fields:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

strcpy(sqldaptr->sqldaid,"SQLDA");
sqldaptr->sqldabc = 192;
/* number of bytes of storage allocated for the SQLDA */
sqldaptr->sqln = 4;
/* number of SQLVAR occurrences */
sqldaptr->sqld = 4;
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]));
/* Point to first SQLVAR */
varptr->sqltype = 500;
/* data type SMALLINT */
varptr->sqllen = 2;
varptr->sqldata = (char *) hva1;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "x00x00x00x00x00x01x00x14",varptr->sqlname.length);
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 1); /* Point to next SQLVAR */
varptr->sqltype = 452;
/* data type CHAR(6) */
varptr->sqllen = 6;
varptr->sqldata = (char *) hva2;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "x00x00x00x00x00x01x00x14",varptr->sqlname.length);
varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 2); /* Point to next SQLVAR */
varptr->sqltype = 448;
/* data type VARCHAR(20) */
varptr->sqllen = 20;
varptr->sqldata = (char *) hva3;
varptr->sqlname.length = 8;
memcpy(varptr->sqlname.data, "x00x00x00x00x00x01x00x14",varptr->sqlname.length);

The SQLDA structure has the following fields:
v SQLDABC indicates the number of bytes of storage that are allocated for the
SQLDA. The storage includes a 16-byte header and 44 bytes for each
SQLVAR field. The value is SQLN x 44 + 16, or 192 for this example.
v SQLN is the number of SQLVAR occurrences, plus one for use by DB2 for
the host variable that contains the number n in the FOR n ROWS clause.
v SQLD is the number of variables in the SQLDA that are used by DB2 when
processing the INSERT statement.
v An SQLVAR occurrence specifies the attributes of an element of a host
variable array that corresponds to a value provided for a target column of
the INSERT. Within each SQLVAR:
– SQLTYPE indicates the data type of the elements of the host variable
array.
– SQLLEN indicates the length of a single element of the host variable array.
– SQLDATA points to the corresponding host variable array. Assume that
your program allocates the dynamic variable arrays hva1, hva2, and hva3.
– SQLNAME has two parts: the LENGTH and the DATA. The LENGTH is
8. The first two bytes of the DATA field is X’0000’. Bytes 5 and 6 of the
DATA field are a flag indicating whether the variable is an array or a FOR
n ROWS value. Bytes 7 and 8 are a two-byte binary integer representation
of the dimension of the array.

|
|
|
|
|

For more information about the SQLDA, see “Including dynamic SQL for
varying-list SELECT statements in your program” on page 266 and the topic
“SQL descriptor area (SQLDA)” in DB2 SQL Reference.

288

Application Programming and SQL Guide
2. Assign the appropriate INSERT or MERGE statement to a host variable.
Example: The following string contains an INSERT statement that is to be
prepared:
INSERT INTO DSN8910.ACT VALUES (?, ?, ?)

3. Assign any attributes for the SQL statement to a host variable.
4. Include a PREPARE statement for the SQL statement.
5. Include an EXECUTE statement with the FOR n ROWS clause. The host
variable in the USING clause of the EXECUTE statement names the SQLDA
that describes the parameter markers in the INSERT statement.
Example: The following code prepares and executes an INSERT statement:
/* Copy the INSERT string into the host variable sqlstmt */
strcpy(sqlstmt, "INSERT INTO DSN8910.ACT VALUES (?, ?, ?)");
/* Copy the INSERT attributes into the host variable attrvar */
strcpy(attrvar, "FOR MULTIPLE ROWS");
/* Prepare and execute my_insert using the descriptor */
EXEC SQL PREPARE my_insert ATTRIBUTES :attrvar FROM :sqlstmt;
EXEC SQL EXECUTE my_insert USING DESCRIPTOR :*sqldaptr FOR :num_rows ROWS;

Enabling the dynamic statement cache
The dynamic statement cache is a pool in which DB2 saves prepared SQL
statements that can be shared among different threads, plans, and packages. By
sharing these statements, applications can avoid unnecessary preparation processes
and thus improve performance. You must enable the dynamic statement cache
before it can be used.
To enable the dynamic statement cache to save prepared statements, specify YES
on the CACHE DYNAMIC SQL field of installation panel DSNTIP8. For more
information about installation panel DSNTIP8, see the topic “Performance and
optimization panel: DSNTIP8” in DB2 Installation Guide.
Dynamic SQL statements that DB2 can cache:
The dynamic statement cache is a pool in which DB2 saves prepared SQL
statements that can be shared among different threads, plans, and packages to
improve performance. Only certain dynamic SQL statements can be saved in this
cache.
As the DB2 ability to optimize SQL has improved, the cost of preparing a dynamic
SQL statement has grown. Applications that use dynamic SQL might be forced to
pay this cost more than once. When an application performs a commit operation, it
must issue another PREPARE statement if that SQL statement is to be executed
again. For a SELECT statement, the ability to declare a cursor WITH HOLD
provides some relief but requires that the cursor be open at the commit point.
WITH HOLD also causes some locks to be held for any objects that the prepared
statement is dependent on. Also, WITH HOLD offers no relief for SQL statements
that are not SELECT statements.
DB2 can save prepared dynamic statements in a cache. The cache is a dynamic
statement cache pool that all application processes can use to save and retrieve
prepared dynamic statements. After an SQL statement has been prepared and is
automatically saved in the cache, subsequent prepare requests for that same SQL

Chapter 3. Including DB2 queries in an application program

289
statement can avoid the costly preparation process by using the statement that is in
the cache. Statements that are saved in the cache can be shared among different
threads, plans, or packages.
Example: Assume that your application program contains a dynamic SQL
statement, STMT1, which is prepared and executed multiple times. If you are using
the dynamic statement cache when STMT1 is prepared for the first time, it is
placed in the cache. When your application program encounters the identical
PREPARE statement for STMT1, DB2 uses the already prepared STMT1 that is
saved in the dynamic statement cache. The following example shows the identical
STMT1 that might appear in your application program:
PREPARE
EXECUTE
COMMIT
.
.
.
PREPARE
EXECUTE
COMMIT
.
.
.

STMT1 FROM ...
STMT1

Statement is prepared and the prepared
statement is put in the cache.

STMT1 FROM ...
STMT1

Identical statement. DB2 uses the prepared
statement from the cache.

Eligible statements: The following SQL statements can be saved in the cache:
SELECT
UPDATE
INSERT
DELETE
MERGE

|

Distributed and local SQL statements are eligible to be saved. Prepared, dynamic
statements that use DB2 private protocol access are also eligible to be saved.
Restrictions: Even though static statements that use DB2 private protocol access
are dynamic at the remote site, those statements can not be saved in the cache.
Statements in plans or packages that are bound with REOPT(ALWAYS) can not be
saved in the cache. Statements in plans and packages that are bound with
REOPT(ONCE) or REOPT(AUTO) can be saved in the cache. See “Including
dynamic SQL for varying-list SELECT statements in your program” on page 266
for more information about REOPT(ALWAYS), REOPT(AUTO), and
REOPT(ONCE).

|
|
|
|
|
|

Prepared statements cannot be shared among data sharing members. Because each
member has its own EDM pool, a cached statement on one member is not
available to an application that runs on another member.
Conditions for statement sharing:
If a prepared version of an identical SQL statement already exists in the dynamic
statement cache, certain conditions must still be met before DB2 can reuse that
prepared statement.
Suppose that S1 and S2 are source statements, and P1 is the prepared version of
S1. P1 is in the dynamic statement cache.
The following conditions must be met before DB2 can use statement P1 instead of
preparing statement S2:
v S1 and S2 must be identical. The statements must pass a character by character
comparison and must be the same length. If the PREPARE statement for either

290

Application Programming and SQL Guide
statement contains an ATTRIBUTES clause, DB2 concatenates the values in the
ATTRIBUTES clause to the statement string before comparing the strings. That
is, if A1 is the set of attributes for S1 and A2 is the set of attributes for S2, DB2
compares S1||A1 to S2||A2.
If the statement strings are not identical, DB2 cannot use the statement in the
cache.
For example, assume that S1 and S2 are specified as follows:
’UPDATE EMP SET SALARY=SALARY+50’

In this case, DB2 can use P1 instead of preparing S2.
However, assume that S1 is specified as follows:
’UPDATE EMP SET SALARY=SALARY+50’

Assume also that S2 is specified as follows:
’UPDATE EMP SET SALARY=SALARY+50 ’

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

In this case, DB2 cannot use P1 for S2. DB2 prepares S2 and saves the prepared
version of S2 in the cache.
v The authorization ID or role that was used to prepare S1 must be used to
prepare S2:
– When a plan or package has run behavior, the authorization ID is the current
SQLID value.
For secondary authorization IDs:
- The application process that searches the cache must have the same
secondary authorization ID list as the process that inserted the entry into
the cache or must have a superset of that list.
- If the process that originally prepared the statement and inserted it into the
cache used one of the privileges held by the primary authorization ID to
accomplish the prepare, that ID must either be part of the secondary
authorization ID list of the process searching the cache, or it must be the
primary authorization ID of that process.
– When a plan or package has bind behavior, the authorization ID is the plan
owner’s ID. For a DDF server thread, the authorization ID is the package
owner’s ID.
– When a package has define behavior, then the authorization ID is the
user-defined function or stored procedure owner.
– When a package has invoke behavior, then the authorization ID is the
authorization ID under which the statement that invoked the user-defined
function or stored procedure executed.
– If the application process has a role associated with it, DB2 uses the role to
search the cache instead of the authorization IDs. If the trusted context that
associated the role with the application process is defined with the WITH
ROLE AS OBJECT OWNER clause, the role value is used as the default for
the CURRENT SCHEMA special register and the SQL path.
For an explanation of bind, run, define, and invoke behavior, see
“DYNAMICRULES bind option” on page 881.
v When the plan or package that contains S2 is bound, the values of these bind
options must be the same as when the plan or package that contains S1 was
bound:
CURRENTDATA
DYNAMICRULES
ISOLATION
Chapter 3. Including DB2 queries in an application program

291
SQLRULES
QUALIFIER
v When S2 is prepared, the values of the following special registers must be the
same as when S1 was prepared:
CURRENT DECFLOAT ROUNDING MODE
CURRENT DEGREE
CURRENT RULES
CURRENT PRECISION
CURRENT REFRESH AGE
CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION
CURRENT LOCALE LC_CTYPE

|

|

Exception: If you set the CACHEDYN_FREELOCAL subsystem parameter to 1 and
a storage shortage occurs, DB2 frees the cached dynamic statements. In this case,
DB2 cannot use P1 instead of preparing statement S2, because P1 no longer exists
in the statement cache.
Finding information about statements in the statement cache:
As part of an online monitoring strategy, you can examine all statements in the
dynamic statement cache and concentrate on improving specific statements for
specific performance characteristics.
The EXPLAIN STATEMENT CACHE ALL statement puts statement cache
information into the DSN_STATEMENT_CACHE_TABLE table for all queries in
the cache that qualify based on the user’s SQLID. If the SQLID has SYSADM
authority, all statements are put into the table.
EXPLAIN STATEMENT CACHE ALL provides
DSN_STATEMENT_CACHE_TABLE with a snapshot of the cache.
Example: If you are concerned about CPU time, you can select from the
STAT_CPU column in the DSN_STATEMENT_CACHE_TABLE table to identify the
queries that consume the most CPU time. Then you can work to improve the
performance of those specific queries. For information about creating the
DSN_STATEMENT_CACHE_TABLE table and about the columns in the table, see
the topic “EXPLAIN” in DB2 SQL Reference.

Keeping prepared statements after commit points
If your program issues the same dynamic SQL statement in different commit
scopes, consider specifying that DB2 keep the prepared versions of these
statements after the commit points. This behavior can improve performance. By
default, DB2 does not keep these statements after commit points.
The bind option KEEPDYNAMIC(YES) lets you hold dynamic statements past a
commit point for an application process. An application can issue a PREPARE for a
statement once and omit subsequent PREPAREs for that statement. The following
example illustrates an application that is written to use KEEPDYNAMIC(YES).
PREPARE
EXECUTE
COMMIT
.
.
.
EXECUTE
COMMIT
.
.
.
EXECUTE
COMMIT

292

STMT1 FROM ...
STMT1

Statement is prepared.

STMT1

Application does not issue PREPARE.

STMT1

Again, no PREPARE needed.

Application Programming and SQL Guide
To understand how the KEEPDYNAMIC bind option works, you need to
differentiate between the executable form of a dynamic SQL statement, which is
the prepared statement, and the character string form of the statement, which is
the statement string.
Relationship between KEEPDYNAMIC(YES) and statement caching: When the
dynamic statement cache is not active, and you run an application bound with
KEEPDYNAMIC(YES), DB2 saves only the statement string for a prepared
statement after a commit operation. On a subsequent OPEN, EXECUTE, or
DESCRIBE, DB2 must prepare the statement again before performing the requested
operation. The following example illustrates this concept.
PREPARE
EXECUTE
COMMIT
.
.
.
EXECUTE
COMMIT
.
.
.
EXECUTE
COMMIT

STMT1 FROM ...
STMT1

Statement is prepared and put in memory.

STMT1

Application does not issue PREPARE.
DB2 prepares the statement again.

STMT1

Again, no PREPARE needed.

When the dynamic statement cache is active, and you run an application bound
with KEEPDYNAMIC(YES), DB2 retains a copy of both the prepared statement
and the statement string. The prepared statement is cached locally for the
application process. In general, the statement is globally cached in the EDM pool,
to benefit other application processes. If the application issues an OPEN,
EXECUTE, or DESCRIBE after a commit operation, the application process uses its
local copy of the prepared statement to avoid a prepare and a search of the cache.
The following example illustrates this process.
PREPARE
EXECUTE
COMMIT
.
.
.
EXECUTE
COMMIT
.
.
.
EXECUTE
COMMIT
.
.
.
PREPARE

STMT1 FROM ...
STMT1

Statement is prepared and put in memory.

STMT1

Application does not issue PREPARE.
DB2 uses the prepared statement in memory.

STMT1

Again, no PREPARE needed.
DB2 uses the prepared statement in memory.

STMT1 FROM ...

Statement is prepared and put in memory.

The local instance of the prepared SQL statement is kept in ssnmDBM1 storage
until one of the following occurs:
v The application process ends.
v A rollback operation occurs.
v The application issues an explicit PREPARE statement with the same statement
name.
If the application does issue a PREPARE for the same SQL statement name that
has a kept dynamic statement associated with it, the kept statement is discarded
and DB2 prepares the new statement.
v The statement is removed from memory because the statement has not been
used recently, and the number of kept dynamic SQL statements reaches the
subsystem default as set during installation.
Handling implicit prepare errors: If a statement is needed during the lifetime of an
application process, and the statement has been removed from the local cache, DB2
might be able to retrieve it from the global cache. If the statement is not in the
Chapter 3. Including DB2 queries in an application program

293
global cache, DB2 must implicitly prepare the statement again. The application
does not need to issue a PREPARE statement. However, if the application issues an
OPEN, EXECUTE, or DESCRIBE for the statement, the application must be able to
handle the possibility that DB2 is doing the prepare implicitly. Any error that
occurs during this prepare is returned on the OPEN, EXECUTE, or DESCRIBE.
How KEEPDYNAMIC affects applications that use distributed data: If a requester
does not issue a PREPARE after a COMMIT, the package at the DB2 for z/OS
server must be bound with KEEPDYNAMIC(YES). If both requester and server are
DB2 for z/OS subsystems, the DB2 requester assumes that the KEEPDYNAMIC
value for the package at the server is the same as the value for the plan at the
requester.
The KEEPDYNAMIC option has performance implications for DRDA clients that
specify WITH HOLD on their cursors:
v If KEEPDYNAMIC(NO) is specified, a separate network message is required
when the DRDA client issues the SQL CLOSE for the cursor.
v If KEEPDYNAMIC(YES) is specified, the DB2 for z/OS server automatically
closes the cursor when SQLCODE +100 is detected, which means that the client
does not have to send a separate message to close the held cursor. This reduces
network traffic for DRDA applications that use held cursors. It also reduces the
duration of locks that are associated with the held cursor.
Considerations for data sharing: If one member of a data sharing group has
enabled the cache but another has not, and an application is bound with
KEEPDYNAMIC(YES), DB2 must implicitly prepare the statement again if the
statement is assigned to a member without the cache. This can mean a slight
reduction in performance.

Limiting CPU time for dynamic SQL statements by using the
resource limit facility
The resource limit facility (or governor) limits the amount of CPU time an SQL
statement can take, which prevents SQL statements from making excessive
requests.
The predictive governing function of the resource limit facility provides an
estimate of the processing cost of SQL statements before they run. To predict the
cost of an SQL statement, you execute EXPLAIN to put information about the
statement cost in DSN_STATEMNT_TABLE.
The governor controls only the dynamic SQL manipulative statements SELECT,
UPDATE, DELETE, and INSERT. Each dynamic SQL statement used in a program
is subject to the same limits. The limit can be a reactive governing limit or a
predictive governing limit. If the statement exceeds a reactive governing limit, the
statement receives an error SQL code. If the statement exceeds a predictive
governing limit, it receives a warning or error SQL code. “Predictive governing” on
page 295 explains more about predictive governing SQL codes.
Your system administrator can establish the limits for individual plans or packages,
for individual users, or for all users who do not have personal limits.
Follow the procedures defined by your location for adding, dropping, or
modifying entries in the resource limit specification table. For more information
about the resource limit specification tables, see the topic “Resource limit tables” in
DB2 Performance Monitoring and Tuning Guide.

294

Application Programming and SQL Guide
Reactive governing:
The reactive governing function of the resource limit facility stops any dynamic
SQL statements that overuse system resources. When a statement exceeds a
reactive governing threshold, the application program receives SQLCODE -905. The
application must then determine what to do next.
If the failed statement involves an SQL cursor, the cursor’s position remains
unchanged. The application can then close that cursor. All other operations with
the cursor do not run and the same SQL error code occurs.
If the failed SQL statement does not involve a cursor, then all changes that the
statement made are undone before the error code returns to the application. The
application can either issue another SQL statement or commit all work done so far.
Predictive governing:
The predictive governing function of the resource limit facility provides an
estimate of the processing cost of SQL statements before they run.
If your installation uses predictive governing, you need to modify your
applications to check for the +495 and -495 SQLCODEs that predictive governing
can generate after a PREPARE statement executes. The +495 SQLCODE in
combination with deferred prepare requires that DB2 do some special processing to
ensure that existing applications are not affected by this new warning SQLCODE.
For information about setting up the resource limit facility for predictive
governing, see the topic “The resource limit facility (governor)” in DB2 Performance
Monitoring and Tuning Guide.
Handling the +495 SQLCODEIf your requester uses deferred prepare, the
presence of parameter markers determines when the application receives the +495
SQLCODE. When parameter markers are present, DB2 cannot do PREPARE,
OPEN, and FETCH processing in one message. If SQLCODE +495 is returned, no
OPEN or FETCH processing occurs until your application requests it.
v If there are parameter markers, the +495 is returned on the OPEN (not the
PREPARE).
v If there are no parameter markers, the +495 is returned on the PREPARE.
Normally with deferred prepare, the PREPARE, OPEN, and first FETCH of the
data are returned to the requester. For a predictive governor warning of +495, you
would ideally like to have the option to choose beforehand whether you want the
OPEN and FETCH of the data to occur. For down-level requesters, you do not
have this option.
Using predictive governing and down-level DRDA requesters
If SQLCODE +495 is returned to the requester, OPEN processing continues but the
first block of data is not returned with the OPEN. Thus, if your application does
not continue with the query, you have already incurred the performance cost of
OPEN processing.
Using predictive governing and enabled requesters
If your application does not defer the prepare, SQLCODE +495 is returned to the
requester and OPEN processing does not occur.
Chapter 3. Including DB2 queries in an application program

295
If your application does defer prepare processing, the application receives the +495
at its usual time (OPEN or PREPARE). If you have parameter markers with
deferred prepare, you receive the +495 at OPEN time as you normally do.
However, an additional message is exchanged.
Recommendation: Do not use deferred prepare for applications that use parameter
markers and that are predictively governed at the server side.

Conventions used in examples of coding SQL statements
The examples in this information use certain conventions and assumptions. Some
of the examples vary from these conventions. Exceptions are noted where they
occur.
The SQL statements in this information use the following conventions:
v The SQL statement is part of a C or COBOL application program. Each SQL
example is displayed on several lines, with each clause of the statement on a
separate line.
v The use of the precompiler options APOST and APOSTSQL are assumed
(although they are not the defaults). Therefore, apostrophes (’) are used to
delimit character string literals within SQL and host language statements.
v The SQL statements access data in the sample tables provided with DB2. The
tables contain data that a manufacturing company might keep about its
employees and its current projects.
v An SQL example does not necessarily show the complete syntax of an SQL
statement. For the complete description and syntax of any SQL statement, see
the topic “Statements” in DB2 SQL Reference.
v Examples do not take referential constraints into account.
Related reference
″DB2 sample tables″ (Introduction to DB2 for z/OS)

Macros for assembler applications
Data set DSN910.SDSNMACS contains all DB2 macros that are available for use.

Accessing the DB2 REXX language support application
programming interfaces
DB2 REXX Language Support includes several application programming interfaces
that enable your REXX procedure to connect to a DB2 subsystem and execute SQL
statements.
DB2 REXX Language Support includes the following application programming
interfaces:
CONNECT
Connects the REXX procedure to a DB2 subsystem. You must execute
CONNECT before you can execute SQL statements. The syntax of CONNECT
is:

296

Application Programming and SQL Guide
’CONNECT’

’subsystem-ID’
REXX-variable

ADDRESS DSNREXX

Note: CALL SQLDBS ’ATTACH TO’ ssid is equivalent to ADDRESS DSNREXX ’CONNECT’ ssid.

EXECSQL
Executes SQL statements in REXX procedures. The syntax of EXECSQL is:

EXECSQL
ADDRESS DSNREXX

″SQL-statement″
REXX-variable

Notes:
1. CALL SQLEXEC is equivalent to EXECSQL.
2. EXECSQL can be enclosed in single or double quotation marks.

DISCONNECT
Disconnects the REXX procedure from a DB2 subsystem. You should execute
DISCONNECT to release resources that are held by DB2. The syntax of
DISCONNECT is:

’DISCONNECT’
ADDRESS DSNREXX

Note: CALL SQLDBS ’DETACH’ is equivalent to DISCONNECT.

These application programming interfaces are available through the DSNREXX
host command environment. To make DSNREXX available to the application,
invoke the RXSUBCOM function. The syntax is:

RXSUBCOM (

’ADD’
’DELETE’

, ’DSNREXX’

, ’DSNREXX’

)

The ADD function adds DSNREXX to the REXX host command environment table.
The DELETE function deletes DSNREXX from the REXX host command
environment table.
The following figure shows an example of REXX code that makes DSNREXX
available to an application.
’SUBCOM DSNREXX’
/* HOST CMD ENV AVAILABLE?
IF RC THEN
/* IF NOT, MAKE IT AVAILABLE
S_RC = RXSUBCOM(’ADD’,’DSNREXX’,’DSNREXX’)
/* ADD HOST CMD ENVIRONMENT
ADDRESS DSNREXX
/* SEND ALL COMMANDS OTHER
/* THAN REXX INSTRUCTIONS TO
/* DSNREXX

*/
*/
*/
*/
*/
*/

Chapter 3. Including DB2 queries in an application program

297
/* CALL CONNECT, EXECSQL, AND */
/* DISCONNECT INTERFACES
*/
.
.
.
S_RC = RXSUBCOM(’DELETE’,’DSNREXX’,’DSNREXX’)
/* WHEN DONE WITH
*/
/* DSNREXX, REMOVE IT.
*/

Setting the isolation level of SQL statements in a REXX
procedure
Isolation levels specify the locking behavior for SQL statements. You can set the
isolation level for SQL statements in your REXX procedures to repeatable read
(RR), read stability (RS), cursor stability (CS), or uncommitted read (UR).
To set the isolation level of SQL statements in a REXX procedure:
Execute the SET CURRENT PACKAGESET statement to select one of the following
DB2 REXX Language Support packages with the isolation level that you need.
Table 67. DB2 REXX Language Support packages and associated isolation levels
Package namea

Isolation level

DSNREXRR

Repeatable read (RR)

DSNREXRS

Read stability (RS)

DSNREXCS

Cursor stability (CS)

DSNREXUR

Uncommitted read (UR)

Note:
1. These packages enable your procedure to access DB2 and are bound when you
install DB2 REXX Language Support.
For example, to change the isolation level to cursor stability, execute the following
SQL statement:
"EXECSQL SET CURRENT PACKAGESET=’DSNREXCS’"

Checking the execution of SQL statements
After executing an SQL statement, your program should check for any errors codes
before you commit the data and handle the errors that they represent.
You can check the execution of SQL statements in one of the following ways:
v By displaying specific fields in the SQLCA.
v By testing SQLCODE or SQLSTATE for specific values.
v By using the WHENEVER statement in your application program.
v By testing indicator variables to detect numeric errors; see “Arithmetic and
conversion errors” on page 317.
v By using the GET DIAGNOSTICS statement in your application program to
return all the condition information that results from the execution of an SQL
statement.
v By calling DSNTIAR to display the contents of the SQLCA; see “Displaying
SQLCA fields by calling DSNTIAR” on page 299.

298

Application Programming and SQL Guide
Checking the execution of SQL statements by using the
SQLCA
One way to check whether an SQL statement executed successfully is to use the
SQL communication area (SQLCA). This area is set apart for communication with
DB2.
If you use the SQLCA, include the necessary instructions to display information
that is contained in the SQLCA in your application program. Alternatively, you can
use the GET DIAGNOSTICS statement, which is an SQL standard, to diagnose
problems.
v When DB2 processes an SQL statement, it places return codes that indicate the
success or failure of the statement execution in SQLCODE and SQLSTATE. For
details, see “Checking the execution of SQL statements by using SQLCODE and
SQLSTATE” on page 303.
v When DB2 processes a FETCH statement, and the FETCH is successful, the
contents of SQLERRD(3) in the SQLCA is set to the number of returned rows.
v When DB2 processes a multiple-row FETCH statement, the contents of
SQLCODE is set to +100 if the last row in the table has been returned with the
set of rows. For details, see “Accessing data by using a rowset-positioned
cursor” on page 636.

|
|
|

v When DB2 processes an UPDATE, INSERT, or DELETE statement, and the
statement execution is successful, the contents of SQLERRD(3) in the SQLCA is
set to the number of rows that are updated, inserted, or deleted.
v When DB2 processes a TRUNCATE statement and the statement execution is
successful, SQLERRD(3) in the SQLCA is set to -1. The number of rows that are
deleted is not returned.
v If SQLWARN0 contains W, DB2 has set at least one of the SQL warning flags
(SQLWARN1 through SQLWARNA):
– SQLWARN1 contains N for non-scrollable cursors and S for scrollable cursors
after an OPEN CURSOR or ALLOCATE CURSOR statement.
– SQLWARN4 contains I for insensitive scrollable cursors, S for sensitive static
scrollable cursors, and D for sensitive dynamic scrollable cursors, after an
OPEN CURSOR or ALLOCATE CURSOR statement, or blank if the cursor is
not scrollable.
– SQLWARN5 contains a character value of 1 (read only), 2 (read and delete),
or 4 (read, delete, and update) to indicate the operation that is allowed on the
result table of the cursor.
For a description of all the fields in the SQLCA, see the topic “Description of
SQLCA fields” in DB2 SQL Reference.

Displaying SQLCA fields by calling DSNTIAR
If you choose to use the SQLCA as a way of checking whether an SQL statement
executed successfully, your program needs to read the data in the appropriate
SQLCA fields. One easy way to read these fields is to use the assembler subroutine
DSNTIAR.
You should check for errors codes before you commit data, and handle the errors
that they represent. The assembler subroutine DSNTIAR helps you to obtain a
formatted form of the SQLCA and a text message based on the SQLCODE field of
the SQLCA. You can retrieve this same message text by using the MESSAGE_TEXT

Chapter 3. Including DB2 queries in an application program

299
condition item field of the GET DIAGNOSTICS statement. Programs that require
long token message support should code the GET DIAGNOSTICS statement
instead of DSNTIAR.
DSNTIAR takes data from the SQLCA, formats it into a message, and places the
result in a message output area that you provide in your application program.
Each time you use DSNTIAR, it overwrites any previous messages in the message
output area. You should move or print the messages before using DSNTIAR again,
and before the contents of the SQLCA change, to get an accurate view of the
SQLCA.
DSNTIAR expects the SQLCA to be in a certain format. If your application
modifies the SQLCA format before you call DSNTIAR, the results are
unpredictable.
DSNTIAR:
The assembler subroutine DSNTIAR helps you to obtain a formatted form of the
SQLCA and a text message based on the SQLCODE field of the SQLCA.
DSNTIAR can run either above or below the 16-MB line of virtual storage. The
DSNTIAR object module that comes with DB2 has the attributes AMODE(31) and
RMODE(ANY). At install time, DSNTIAR links as AMODE(31) and RMODE(ANY).
DSNTIAR runs in 31-bit mode if any of the following conditions is true:
v DSNTIAR is linked with other modules that also have the attributes AMODE(31)
and RMODE(ANY).
v DSNTIAR is linked into an application that specifies the attributes AMODE(31)
and RMODE(ANY) in its link-edit JCL.
v An application loads DSNTIAR.
When loading DSNTIAR from another program, be careful how you branch to
DSNTIAR. For example, if the calling program is in 24-bit addressing mode and
DSNTIAR is loaded above the 16-MB line, you cannot use the assembler BALR
instruction or CALL macro to call DSNTIAR, because they assume that DSNTIAR
is in 24-bit mode. Instead, you must use an instruction that is capable of branching
into 31-bit mode, such as BASSM.
You can dynamically link (load) and call DSNTIAR directly from a language that
does not handle 31-bit addressing. To do this, link a second version of DSNTIAR
with the attributes AMODE(24) and RMODE(24) into another load module library.
Alternatively, you can write an intermediate assembler language program that calls
DSNTIAR in 31-bit mode and then call that intermediate program in 24-bit mode
from your application.
For more information on the allowed and default AMODE and RMODE settings
for a particular language, see the application programming guide for that
language. For details on how the attributes AMODE and RMODE of an application
are determined, see the linkage editor and loader user’s guide for the language in
which you have written the application.
Defining a message output area:
If a program calls DSNTIAR, the program must allocate enough storage in the
message output area to hold all of the message text.

300

Application Programming and SQL Guide
You will probably need no more than 10 lines, 80-bytes each, for your message
output area. An application program can have only one message output area.
You must define the message output area in VARCHAR format. In this varying
character format, a 2-byte length field precedes the data. The length field indicates
to DSNTIAR how many total bytes are in the output message area; the minimum
length of the output area is 240-bytes.
The following figure shows the format of the message output area, where length is
the 2-byte total length field, and the length of each line matches the logical record
length (lrecl) you specify to DSNTIAR.
Line:
1
2

.
.
.
n-1
n
Field sizes (in bytes):
2

Logical record length

Figure 30. Format of the message output area

When you call DSNTIAR, you must name an SQLCA and an output message area
in the DSNTIAR parameters. You must also provide the logical record length (lrecl)
as a value between 72 and 240 bytes. DSNTIAR assumes the message area contains
fixed-length records of length lrecl.
DSNTIAR places up to 10 lines in the message area. If the text of a message is
longer than the record length you specify on DSNTIAR, the output message splits
into several records, on word boundaries if possible. The split records are indented.
All records begin with a blank character for carriage control. If you have more
lines than the message output area can contain, DSNTIAR issues a return code of
4. A completely blank record marks the end of the message output area.
Possible return codes from DSNTIAR:
The assembler subroutine DSNTIAR helps your program read the information in
the SQLCA. The subroutine also returns its own return code.
Code

Meaning

0

Successful execution.

4

More data available than could fit into the provided message area.

8

Logical record length not between 72 and 240, inclusive.

12

Message area not large enough. The message length was 240 or greater.

16

Error in TSO message routine.

20

Module DSNTIA1 could not be loaded.
Chapter 3. Including DB2 queries in an application program

301
SQLCA data error.

24

A scenario for using DSNTIAR:
You can use the assembler subroutine DSNTIAR to generate the error message text
in the SQLCA.
Suppose you want your DB2 COBOL application to check for deadlocks and
timeouts, and you want to make sure your cursors are closed before continuing.
You use the statement WHENEVER SQLERROR to transfer control to an error
routine when your application receives a negative SQLCODE.
In your error routine, you write a section that checks for SQLCODE -911 or -913.
You can receive either of these SQLCODEs when a deadlock or timeout occurs.
When one of these errors occurs, the error routine closes your cursors by issuing
the statement:
EXEC SQL CLOSE cursor-name

An SQLCODE of 0 or -501 resulting from that statement indicates that the close
was successful.
To use DSNTIAR to generate the error message text, first follow these steps:
1. Choose a logical record length (lrecl) of the output lines. For this example,
assume lrecl is 72 (to fit on a terminal screen) and is stored in the variable
named ERROR-TEXT-LEN.
2. Define a message area in your COBOL application. Assuming you want an area
for up to 10 lines of length 72, you should define an area of 720 bytes, plus a
2-byte area that specifies the total length of the message output area.
01

77

ERROR-MESSAGE.
02 ERROR-LEN
02 ERROR-TEXT
ERROR-TEXT-LEN

PIC S9(4)
PIC X(72)

COMP VALUE +720.
OCCURS 10 TIMES
INDEXED BY ERROR-INDEX.
PIC S9(9) COMP VALUE +72.

For this example, the name of the message area is ERROR-MESSAGE.
3. Make sure you have an SQLCA. For this example, assume the name of the
SQLCA is SQLCA.
To display the contents of the SQLCA when SQLCODE is 0 or -501, call DSNTIAR
after the SQL statement that produces SQLCODE 0 or -501:
CALL ’DSNTIAR’ USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN.

You can then print the message output area just as you would any other variable.
Your message might look like this:
DSNT408I SQLCODE = -501, ERROR: THE CURSOR IDENTIFIED IN A FETCH OR
CLOSE STATEMENT IS NOT OPEN
DSNT418I SQLSTATE
= 24501 SQLSTATE RETURN CODE
DSNT415I SQLERRP
= DSNXERT SQL PROCEDURE DETECTING ERROR
DSNT416I SQLERRD
= -315 0 0 -1 0 0 SQL DIAGNOSTIC INFORMATION
DSNT416I SQLERRD
= X’FFFFFEC5’ X’00000000’ X’00000000’
X’FFFFFFFF’ X’00000000’ X’00000000’ SQL DIAGNOSTIC
INFORMATION

302

Application Programming and SQL Guide
Checking the execution of SQL statements by using
SQLCODE and SQLSTATE
Whenever an SQL statement executes, the SQLCODE and SQLSTATE fields of the
SQLCA receive a return code. Portable applications should use SQLSTATE instead
of SQLCODE, although SQLCODE values can provide additional DB2-specific
information about an SQL error or warning.
SQLCODE: DB2 returns the following codes in SQLCODE:
v If SQLCODE = 0, execution was successful.
v If SQLCODE > 0, execution was successful with a warning.
v If SQLCODE < 0, execution was not successful.
SQLCODE 100 indicates that no data was found.
The meaning of SQLCODEs other than 0 and 100 varies with the particular
product implementing SQL.
SQLSTATE: SQLSTATE enables an application program to check for errors in the
same way for different IBM database management systems. For a complete list of
possible SQLSTATE values, see the topic “SQLSTATE values—common error
codes” in DB2 Codes.
Using SQLCODE and SQLSTATE: An advantage to using the SQLCODE field is
that it can provide more specific information than the SQLSTATE. Many of the
SQLCODEs have associated tokens in the SQLCA that indicate, for example, which
object incurred an SQL error. However, an SQL standard application uses only
SQLSTATE.
You can declare SQLCODE and SQLSTATE (SQLCOD and SQLSTA in Fortran) as
stand-alone host variables. If you specify the STDSQL(YES) precompiler option,
these host variables receive the return codes, and you should not include an
SQLCA in your program.

Checking the execution of SQL statements by using the
WHENEVER statement
The WHENEVER statement causes DB2 to check the SQLCA and continue
processing your program, or branch to another area in your program if an error,
exception, or warning occurs. The condition handling area of your program can
then examine SQLCODE or SQLSTATE to react specifically to the error or
exception.
The WHENEVER statement is not supported for REXX. For information on REXX
error handling, see “Embedding SQL statements in your application” on page 243.
The WHENEVER statement enables you to specify what to do if a general
condition is true. You can specify more than one WHENEVER statement in your
program. When you do this, the first WHENEVER statement applies to all
subsequent SQL statements in the source program until the next WHENEVER
statement.
The WHENEVER statement looks like this:
EXEC SQL
WHENEVER condition action
END-EXEC

Chapter 3. Including DB2 queries in an application program

303
The condition of the WHENEVER statement is one of these three values:
SQLWARNING
Indicates what to do when SQLWARN0 = W or SQLCODE contains a
positive value other than 100. DB2 can set SQLWARN0 for several
reasons—for example, if a column value is truncated when moved into a
host variable. Your program might not regard this as an error.
SQLERROR
Indicates what to do when DB2 returns an error code as the result of an
SQL statement (SQLCODE < 0).
NOT FOUND
Indicates what to do when DB2 cannot find a row to satisfy your SQL
statement or when there are no more rows to fetch (SQLCODE = 100).
The action of the WHENEVER statement is one of these two values:
CONTINUE
Specifies the next sequential statement of the source program.
GOTO or GO TO host-label
Specifies the statement identified by host-label. For host-label, substitute a
single token, preceded by an optional colon. The form of the token
depends on the host language. In COBOL, for example, it can be
section-name or an unqualified paragraph-name.
The WHENEVER statement must precede the first SQL statement it is to affect.
However, if your program checks SQLCODE directly, you must check SQLCODE
after each SQL statement.

Checking the execution of SQL statements by using the GET
DIAGNOSTICS statement
One way to check whether an SQL statement executed successfully is to ask DB2
to return the diagnostic information about the last SQL statement that was
executed.
You can use the GET DIAGNOSTICS statement to return diagnostic information
about the last SQL statement that was executed. You can request individual items
of diagnostic information from the following groups of items:
v Statement items, which contain information about the SQL statement as a whole
v Condition items, which contain information about each error or warning that
occurred during the execution of the SQL statement
v Connection items, which contain information about the SQL statement if it was a
CONNECT statement
In addition to requesting individual items, you can request that GET
DIAGNOSTICS return ALL diagnostic items that are set during the execution of
the last SQL statement as a single string. For more information about the GET
DIAGNOSTICS statement, see the topic “GET DIAGNOSTICS” in DB2 SQL
Reference.
In SQL procedures, you can also retrieve diagnostic information by using handlers.
Handlers tell the procedure what to do if a particular error occurs. For more
information about handlers, see “Handlers in an SQL procedure” on page 505.

|
|
|

304

Application Programming and SQL Guide
|
|
|
|
|
|

Use the GET DIAGNOSTICS statement to handle multiple SQL errors that might
result from the execution of a single SQL statement. First, check SQLSTATE (or
SQLCODE) to determine whether diagnostic information should be retrieved by
using GET DIAGNOSTICS. This method is especially useful for diagnosing
problems that result from a multiple-row INSERT that is specified as NOT
ATOMIC CONTINUE ON SQLEXCEPTIONand multiple row MERGE statements.
Even if you use only the GET DIAGNOSTICS statement in your application
program to check for conditions, you must either include the instructions required
to use the SQLCA or you must declare SQLSTATE (or SQLCODE) separately in
your program.
Restriction: If you issue a GET DIAGNOSTICS statement immediately following
an SQL statement that uses private protocol access, DB2 returns an error.
When you use the GET DIAGNOSTICS statement, you assign the requested
diagnostic information to host variables. Declare each target host variable with a
data type that is compatible with the data type of the requested item. For a
description of available items and their data types, see “Data types for GET
DIAGNOSTICS items” on page 307.
To retrieve condition information, you must first retrieve the number of condition
items (that is, the number of errors and warnings that DB2 detected during the
execution of the last SQL statement). The number of condition items is at least one.
If the last SQL statement returned SQLSTATE ’00000’ (or SQLCODE 0), the number
of condition items is one.
Example: Using GET DIAGNOSTICS with multiple-row INSERT: You want to
display diagnostic information for each condition that might occur during the
execution of a multiple-row INSERT statement in your application program. You
specify the INSERT statement as NOT ATOMIC CONTINUE ON SQLEXCEPTION,
which means that execution continues regardless of the failure of any single-row
insertion. DB2 does not insert the row that was processed at the time of the error.
In the following example, the first GET DIAGNOSTICS statement returns the
number of rows inserted and the number of conditions returned. The second GET
DIAGNOSTICS statement returns the following items for each condition:
SQLCODE, SQLSTATE, and the number of the row (in the rowset that was being
inserted) for which the condition occurred.
EXEC SQL BEGIN DECLARE SECTION;
long row_count, num_condns, i;
long ret_sqlcode, row_num;
char ret_sqlstate[6];
...
EXEC SQL END DECLARE SECTION;
...
EXEC SQL
INSERT INTO DSN8910.ACT
(ACTNO, ACTKWD, ACTDESC)
VALUES (:hva1, :hva2, :hva3)
FOR 10 ROWS
NOT ATOMIC CONTINUE ON SQLEXCEPTION;
EXEC SQL GET DIAGNOSTICS
:row_count = ROW_COUNT, :num_condns = NUMBER;
printf("Number of rows inserted = %dn", row_count);
for (i=1; i<=num_condns; i++) {
EXEC SQL GET DIAGNOSTICS CONDITION :i
Chapter 3. Including DB2 queries in an application program

305
:ret_sqlcode = DB2_RETURNED_SQLCODE,
:ret_sqlstate = RETURNED_SQLSTATE,
:row_num
= DB2_ROW_NUMBER;
printf("SQLCODE = %d, SQLSTATE = %s, ROW NUMBER = %dn",
ret_sqlcode, ret_sqlstate, row_num);
}

In the activity table, the ACTNO column is defined as SMALLINT. Suppose that
you declare the host variable array hva1 as an array with data type long, and you
populate the array so that the value for the fourth element is 32768.
If you check the SQLCA values after the INSERT statement, the value of
SQLCODE is equal to 0, the value of SQLSTATE is ’00000’, and the value of
SQLERRD(3) is 9 for the number of rows that were inserted. However, the INSERT
statement specified that 10 rows were to be inserted.
The GET DIAGNOSTICS statement provides you with the information that you
need to correct the data for the row that was not inserted. The printed output from
your program looks like this:
Number of rows inserted = 9
SQLCODE = -302, SQLSTATE = 22003, ROW NUMBER = 4

The value 32768 for the input variable is too large for the target column ACTNO.
You can print the MESSAGE_TEXT condition item. For information about
SQLCODE -302, see the topic “Error SQL codes” in DB2 Codes.
Retrieving statement and condition items:
When you use the GET DIAGNOSTICS statement, you assign the requested
diagnostic information to host variables. Declare each target host variable with a
data type that is compatible with the data type of the requested item.
To retrieve condition information, you must first retrieve the number of condition
items (that is, the number of errors and warnings that DB2 detected during the
execution of the last SQL statement). The number of condition items is at least one.
If the last SQL statement returned SQLSTATE ’00000’ (or SQLCODE 0), the number
of condition items is one.
Example: Using GET DIAGNOSTICS with multiple-row INSERT: You want to
display diagnostic information for each condition that might occur during the
execution of a multiple-row INSERT statement in your application program. You
specify the INSERT statement as NOT ATOMIC CONTINUE ON SQLEXCEPTION,
which means that execution continues regardless of the failure of any single-row
insertion. DB2 does not insert the row that was processed at the time of the error.
In the following example code, the first GET DIAGNOSTICS statement returns the
number of rows inserted and the number of conditions returned. The second GET
DIAGNOSTICS statement returns the following items for each condition:
SQLCODE, SQLSTATE, and the number of the row (in the rowset that was being
inserted) for which the condition occurred
EXEC SQL BEGIN DECLARE SECTION;
long row_count, num_condns, i;
long ret_sqlcode, row_num;
char ret_sqlstate[6];
...
EXEC SQL END DECLARE SECTION;
...
EXEC SQL

306

Application Programming and SQL Guide
INSERT INTO DSN8810.ACT
(ACTNO, ACTKWD, ACTDESC)
VALUES (:hva1, :hva2, :hva3)
FOR 10 ROWS
NOT ATOMIC CONTINUE ON SQLEXCEPTION;
EXEC SQL GET DIAGNOSTICS
:row_count = ROW_COUNT, :num_condns = NUMBER;
printf("Number of rows inserted = %dn", row_count);
for (i=1; i<=num_condns; i++) {
EXEC SQL GET DIAGNOSTICS CONDITION :i
:ret_sqlcode = DB2_RETURNED_SQLCODE,
:ret_sqlstate = RETURNED_SQLSTATE,
:row_num
= DB2_ROW_NUMBER;
printf("SQLCODE = %d, SQLSTATE = %s, ROW NUMBER = %dn",
ret_sqlcode, ret_sqlstate, row_num);
}

In the activity table, the ACTNO column is defined as SMALLINT. Suppose that
you declare the host variable array hva1 as an array with data type long, and you
populate the array so that the value for the fourth element is 32768.
If you check the SQLCA values after the INSERT statement, the value of
SQLCODE is equal to 0, the value of SQLSTATE is ’00000’, and the value if
SQLERRD(3) is 9 for the number of rows that were inserted. However, the INSERT
statement specified that 10 rows were to be inserted.
The GET DIAGNOSTICS statement provides you with the information that you
need to correct the data for the row that was not inserted. The printed output from
your program looks like this:
Number of rows inserted = 9
SQLCODE = -302, SQLSTATE = 22003, ROW NUMBER = 4

The value 32768 for the input variable is too large for the target column ACTNO.
You can print the MESSAGE_TEXT condition item, or see DB2 Codes for
information about SQLCODE -302.

Data types for GET DIAGNOSTICS items
You can use the GET DIAGNOSTICS statement to request statement, condition,
and connection information about the last SQL statement that was executed. You
must declare each target host variable with a data type that is compatible with the
data type of the requested item.
The following tables specify the data types for the statement, condition, and
connection information items that you can request by using the GET
DIAGNOSTICS statement.
Table 68. Data types for GET DIAGNOSTICS items that return statement information
Item

Description

Data type

DB2_GET_DIAGNOSTICS_DIAGNOSTICS

After a GET DIAGNOSTICS statement, VARCHAR(32672)
if any error or warning occurred, this
item contains all of the diagnostics as a
single string.

DB2_LAST_ROW

After a multiple-row FETCH statement, INTEGER
this item contains a value of +100 if the
last row in the table is in the rowset
that was returned.

Chapter 3. Including DB2 queries in an application program

307
Table 68. Data types for GET DIAGNOSTICS items that return statement information (continued)
Item

Description

Data type

DB2_NUMBER_PARAMETER_MARKERS

After a PREPARE statement, this item
contains the number of parameter
markers in the prepared statement.

INTEGER

DB2_NUMBER_RESULT_SETS

After a CALL statement that invokes a INTEGER
stored procedure, this item contains the
number of result sets that are returned
by the procedure.

DB2_NUMBER_ROWS

After an OPEN or FETCH statement
DECIMAL(31,0)
for which the size of the result table is
known, this item contains the number
of rows in the result table. After a
PREPARE statement, this item contains
the estimated number of rows in the
result table for the prepared statement.
For SENSITIVE DYNAMIC cursors,
this item contains the approximate
number of rows.

DB2_RETURN_STATUS

After a CALL statement that invokes
an SQL procedure, this item contains
the return status if the procedure
contains a RETURN statement.

INTEGER

DB2_SQL_ATTR_CURSOR_HOLD

After an ALLOCATE or OPEN
statement, this item indicates whether
the cursor can be held open across
multiple units of work (Y or N).

CHAR(1)

DB2_SQL_ATTR_CURSOR_ROWSET

After an ALLOCATE or OPEN
statement, this item indicates whether
the cursor can use rowset positioning
(Y or N).

CHAR(1)

DB2_SQL_ATTR_CURSOR_SCROLLABLE

After an ALLOCATE or OPEN
statement, this item indicates whether
the cursor is scrollable (Y or N).

CHAR(1)

| DB2_SQL_ATTR_CURSOR_SENSITIVITY
|
|
|

After an ALLOCATE or OPEN
statement, this item indicates whether
the cursor shows updates made by
other processes (sensitivity I or S).

CHAR(1)

| DB2_SQL_ATTR_CURSOR_TYPE
|
|
|
|
|

After an ALLOCATE or OPEN
CHAR(1)
statement, this item indicates whether
the cursor is forward (F), declared
static (S for INSENSITIVE or
SENSITIVE STATIC, or dynamic (D for
SENSITIVE DYNAMIC).

MORE

After any SQL statement, this item
indicates whether some conditions
items were discarded because of
insufficient storage (Y or N).

CHAR(1)

NUMBER

After any SQL statement, this item
contains the number of condition
items. If no warning or error occurred,
or if no previous SQL statement has
been executed, the number that is
returned is 1.

INTEGER

308

Application Programming and SQL Guide
Table 68. Data types for GET DIAGNOSTICS items that return statement information (continued)
Item

Description

ROW_COUNT

After an insert, update, delete, or fetch, DECIMAL(31,0)
this item contains the number of rows
that are deleted, inserted, updated, or
fetched. After PREPARE, this item
contains the estimated number of
result rows in the prepared statement.
After TRUNCATE, it contains -1.

|

Data type

Table 69. Data types for GET DIAGNOSTICS items that return condition information
Item

Description

Data type

CATALOG_NAME

This item contains the server name of the
table that owns a constraint that caused an
error, or that caused an access rule or check
violation.

VARCHAR(128)

CONDITION_NUMBER

This item contains the number of the
condition.

INTEGER

CURSOR_NAME

This item contains the name of a cursor in
an invalid cursor state.

VARCHAR(128)

DB2_ERROR_CODE1

This item contains an internal error code.

INTEGER

DB2_ERROR_CODE2

This item contains an internal error code.

INTEGER

DB2_ERROR_CODE3

This item contains an internal error code.

INTEGER

DB2_ERROR_CODE4

This item contains an internal error code.

INTEGER

DB2_INTERNAL_ERROR_POINTER

For some errors, this item contains a
negative value that is an internal error
pointer.

INTEGER

DB2_MESSAGE_ID

This item contains the message ID that
CHAR(10)
corresponds to the message that is contained
in the MESSAGE_TEXT diagnostic item.

DB2_MODULE_DETECTING_ERROR

After any SQL statement, this item indicates
which module detected the error.

CHAR(8)

DB2_ORDINAL_TOKEN_n

After any SQL statement, this item contains
the nth token, where n is a value from 1 to
100.

VARCHAR(515)

DB2_REASON_CODE

After any SQL statement, this item contains INTEGER
the reason code for errors that have a reason
code token in the message text.

DB2_RETURNED_SQLCODE

After any SQL statement, this item contains
the SQLCODE for the condition.

INTEGER

DB2_ROW_NUMBER

After any SQL statement that involves
multiple rows, this item contains the row
number on which DB2 detected the
condition.

DECIMAL(31,0)

DB2_TOKEN_COUNT

After any SQL statement, this item contains
the number of tokens available for the
condition.

INTEGER

MESSAGE_TEXT

After any SQL statement, this item contains
the message text associated with the
SQLCODE.

VARCHAR(32672)

Chapter 3. Including DB2 queries in an application program

309
Table 69. Data types for GET DIAGNOSTICS items that return condition information (continued)
Item

Description

Data type

RETURNED_SQLSTATE

After any SQL statement, this item contains
the SQLSTATE for the condition.

CHAR(5)

SERVER_NAME

After a CONNECT, DISCONNECT, or SET
VARCHAR(128)
CONNECTION statement, this item contains
the name of the server specified in the
statement.

Table 70. Data types for GET DIAGNOSTICS items that return connection information
Item

Description

DB2_AUTHENTICATION_TYPE

This item contains the authentication type (S, CHAR(1)
C, D, E, or blank). For more information
about the values for
DB2_AUTHENTICATION_TYPE, see the
topic “GET DIAGNOSTICS” in DB2 SQL
Reference.

Data type

DB2_AUTHORIZATION_ID

This item contains the authorization ID that
is used by the connected server.

DB2_CONNECTION_STATE

This item indicates whether the connection is INTEGER
unconnected (-1), local (0), or remote (1).

DB2_CONNECTION_STATUS

This item indicates whether updates can be
INTEGER
committed for the current unit of work (1 for
Yes, 2 for No).

DB2_ENCRYPTION_TYPE

This item contains one of the following
values that indicates the level of encryption
for the connection:
A
Only the authentication tokens
(authid and password) are
encrypted
D
All of the data for the connection is
encrypted

CHAR(1)

DB2_SERVER_CLASS_NAME

After a CONNECT or SET CONNECTION
statement, this item contains the DB2 server
class name.

VARCHAR(128)

DB2_PRODUCT_ID

This item contains the DB2 product
signature.

VARCHAR(8)

VARCHAR(128)

Handling SQL error codes
You can use the subroutine DSNTIAR or the GET DIAGNOSTICS statement to
convert an SQL return code into a text message.
Handling SQL error return codes in assembler
You can use the subroutine DSNTIAR to convert an SQL return code into a text
message. DSNTIAR takes data from the SQLCA, formats it into a message, and
places the result in a message output area that you provide in your application
program. For concepts and more information about the behavior of DSNTIAR, see
“Displaying SQLCA fields by calling DSNTIAR” on page 299.
You can also use the MESSAGE_TEXT condition item field of the GET
DIAGNOSTICS statement to convert an SQL return code into a text message.

310

Application Programming and SQL Guide
Programs that require long token message support should code the GET
DIAGNOSTICS statement instead of DSNTIAR. For more information about GET
DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET
DIAGNOSTICS statement” on page 304.
DSNTIAR syntax:
CALL DSNTIAR,(sqlca, message, lrecl),MF=(E,PARM)
The DSNTIAR parameters have the following meanings:
sqlca
An SQL communication area.
message
An output area, defined as a varying-length string, in which DSNTIAR places
the message text. The first halfword contains the length of the remaining area;
its minimum value is 240.
The output lines of text, each line being the length specified in lrecl, are put
into this area. For example, you could specify the format of the output area as:
LINES
LRECL

EQU
EQU

10
132

.
.
.
MSGLRECL DC
MESSAGE DS
ORG
MESSAGEL DC
MESSAGE1 DS
MESSAGE2 DS

AL4(LRECL)
H,CL(LINES*LRECL)
MESSAGE
AL2(LINES*LRECL)
CL(LRECL)
text line 1
CL(LRECL)
text line 2

.
.
.
MESSAGEn DS

CL(LRECL)

text line n

.
.
.
CALL DSNTIAR,(SQLCA,MESSAGE,MSGLRECL),MF=(E,PARM)

where MESSAGE is the name of the message output area, LINES is the
number of lines in the message output area, and LRECL is the length of each
line.
lrecl
A fullword containing the logical record length of output messages, between 72
and 240.
The expression MF=(E,PARM) is an z/OS macro parameter that indicates dynamic
execution. PARM is the name of a data area that contains a list of pointers to the
call parameters of DSNTIAR.
See “DB2 sample applications” on page 1013 for instructions on how to access and
print the source code for the sample program.
CICS: If your CICS application requires CICS storage handling, you must use the
subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax:
CALL DSNTIAC,(eib,commarea,sqlca,msg,lrecl),MF=(E,PARM)

DSNTIAC has extra parameters, which you must use for calls to routines that use
CICS commands.
Chapter 3. Including DB2 queries in an application program

311
eib

EXEC interface block

commarea
communication area
For more information on these parameters, see the appropriate application
programming guide for CICS. The remaining parameter descriptions are the same
as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the
same way.
You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you
must also define them in the CSD. For an example of CSD entry generation
statements for use with DSNTIAC, see member DSN8FRDO in the data set
prefix.SDSNSAMP.
The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and
link-edits DSNTIAC, are also in the data set prefix.SDSNSAMP.
Handling SQL error return codes in C or C++
You can use the subroutine DSNTIAR to convert an SQL return code into a text
message. DSNTIAR takes data from the SQLCA, formats it into a message, and
places the result in a message output area that you provide in your application
program. For concepts and more information about the behavior of DSNTIAR, see
“Displaying SQLCA fields by calling DSNTIAR” on page 299.
You can also use the MESSAGE_TEXT condition item field of the GET
DIAGNOSTICS statement to convert an SQL return code into a text message.
Programs that require long token message support should code the GET
DIAGNOSTICS statement instead of DSNTIAR. For more information about GET
DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET
DIAGNOSTICS statement” on page 304.
DSNTIAR syntax:
rc = dsntiar(&sqlca, &message, &lrecl);
The DSNTIAR parameters have the following meanings:
&sqlca
An SQL communication area.
&message
An output area, in VARCHAR format, in which DSNTIAR places the message
text. The first halfword contains the length of the remaining area; its minimum
value is 240.
The output lines of text, each line being the length specified in &lrecl, are put
into this area. For example, you could specify the format of the output area as:
#define data_len 132
#define data_dim 10
struct error_struct {
short int error_len;
char error_text[data_dim][data_len];
. } error_message = {data_dim * data_len};
.
.
rc = dsntiar(&sqlca, &error_message, &data_len);

312

Application Programming and SQL Guide
where error_message is the name of the message output area, data_dim is the
number of lines in the message output area, and data_len is the length of each
line.
&lrecl
A fullword containing the logical record length of output messages, between 72
and 240.
To inform your compiler that DSNTIAR is an assembler language program, include
one of the following statements in your application.
For C, include:
#pragma linkage (dsntiar,OS)

For C++, include a statement similar to this:
extern "OS" short int dsntiar(struct sqlca *sqlca,
struct error_struct *error_message,
int *data_len);

Examples of calling DSNTIAR from an application appear in the DB2 sample C
program DSN8BD3 and in the sample C++ program DSN8BE3. Both are in the
library DSN8910.SDSNSAMP. See “DB2 sample applications” on page 1013 for
instructions on how to access and print the source code for the sample programs.
CICS: If your CICS application requires CICS storage handling, you must use the
subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax:
rc = DSNTIAC(&eib, &commarea, &sqlca, &message, &lrecl);

DSNTIAC has extra parameters, which you must use for calls to routines that use
CICS commands.
&eib

EXEC interface block

&commarea
communication area
For more information on these parameters, see the appropriate application
programming guide for CICS. The remaining parameter descriptions are the same
as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the
same way.
You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you
must also define them in the CSD. For an example of CSD entry generation
statements for use with DSNTIAC, see job DSNTEJ5A.
The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and
link-edits DSNTIAC, are in the data set prefix.SDSNSAMP.
Handling SQL error return codes in COBOL:
You can use the MESSAGE_TEXT condition item field of the GET DIAGNOSTICS
statement to convert an SQL return code into a text message. Programs that require
long token message support should code the GET DIAGNOSTICS statement
instead of DSNTIAR. For more information about GET DIAGNOSTICS, see
“Checking the execution of SQL statements by using the GET DIAGNOSTICS
statement” on page 304.

Chapter 3. Including DB2 queries in an application program

313
You can use the subroutine DSNTIAR to convert an SQL return code into a text
message. DSNTIAR takes data from the SQLCA, formats it into a message, and
places the result in a message output area that you provide in your application
program. For concepts and more information on the behavior of DSNTIAR, see
“Displaying SQLCA fields by calling DSNTIAR” on page 299.
DSNTIAR syntax:
CALL ’DSNTIAR’ USING sqlca message lrecl.
The DSNTIAR parameters have the following meanings:
sqlca
An SQL communication area.
message
An output area, in VARCHAR format, in which DSNTIAR places the message
text. The first halfword contains the length of the remaining area; its minimum
value is 240.
The output lines of text, each line being the length specified in lrecl, are put
into this area. For example, you could specify the format of the output area as:
01

ERROR-MESSAGE.
02 ERROR-LEN
02 ERROR-TEXT

PIC S9(4) COMP VALUE +1320.
PIC X(132) OCCURS 10 TIMES
INDEXED BY ERROR-INDEX.
PIC S9(9) COMP VALUE +132.

77 ERROR-TEXT-LEN
.
.
.
CALL ’DSNTIAR’ USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN.

where ERROR-MESSAGE is the name of the message output area containing
10 lines of length 132 each, and ERROR-TEXT-LEN is the length of each line.
lrecl
A fullword containing the logical record length of output messages, between 72
and 240.
An example of calling DSNTIAR from an application appears in the DB2 sample
assembler program DSN8BC3, which is contained in the library
DSN8910.SDSNSAMP. See “DB2 sample applications” on page 1013 for instructions
on how to access and print the source code for the sample program.
CICSIf you call DSNTIAR dynamically from a CICS COBOL application program,
be sure you do the following:
v Compile the COBOL application with the NODYNAM option.
v Define DSNTIAR in the CSD.
If your CICS application requires CICS storage handling, you must use the
subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax:
CALL ’DSNTIAC’ USING eib commarea sqlca msg lrecl.

DSNTIAC has extra parameters, which you must use for calls to routines that use
CICS commands.
eib

EXEC interface block

commarea
communication area

314

Application Programming and SQL Guide
For more information on these parameters, see the appropriate application
programming guide for CICS. The remaining parameter descriptions are the same
as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the
same way.
You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you
must also define them in the CSD. For an example of CSD entry generation
statements for use with DSNTIAC, see job DSNTEJ5A.
The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and
link-edits DSNTIAC, are in the data set prefix.SDSNSAMP.
Handling SQL error return codes in Fortran:
You can use the subroutine DSNTIR to convert an SQL return code into a text
message. DSNTIR builds a parameter list and calls DSNTIAR for you. DSNTIAR
takes data from the SQLCA, formats it into a message, and places the result in a
message output area that you provide in your application program. For concepts
and more information on the behavior of DSNTIAR, see “Displaying SQLCA fields
by calling DSNTIAR” on page 299.
You can also use the MESSAGE_TEXT condition item field of the GET
DIAGNOSTICS statement to convert an SQL return code into a text message.
Programs that require long token message support should code the GET
DIAGNOSTICS statement instead of DSNTIAR. For more information about GET
DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET
DIAGNOSTICS statement” on page 304.
DSNTIR syntax:
CALL DSNTIR ( error-length, message, return-code )
The DSNTIR parameters have the following meanings:
error-length
The total length of the message output area.
message
An output area, in VARCHAR format, in which DSNTIAR places the message
text. The first halfword contains the length of the remaining area; its minimum
value is 240.
The output lines of text are put into this area. For example, you could specify
the format of the output area as:
INTEGER
ERRLEN /1320/
CHARACTER*132 ERRTXT(10)
INTEGER
ICODE
.
.
.
CALL DSNTIR ( ERRLEN, ERRTXT, ICODE )

where ERRLEN is the total length of the message output area, ERRTXT is the
name of the message output area, and ICODE is the return code.
return-code
Accepts a return code from DSNTIAR.
An example of calling DSNTIR (which then calls DSNTIAR) from an application
appears in the DB2 sample assembler program DSN8BF3, which is contained in the
Chapter 3. Including DB2 queries in an application program

315
library DSN8910.SDSNSAMP. See “DB2 sample applications” on page 1013 for
instructions on how to access and print the source code for the sample program.
Handling SQL error return codes in PL/I:
You can use the subroutine DSNTIAR to convert an SQL return code into a text
message. DSNTIAR takes data from the SQLCA, formats it into a message, and
places the result in a message output area that you provide in your application
program. For concepts and more information on the behavior of DSNTIAR, see
“Displaying SQLCA fields by calling DSNTIAR” on page 299.
You can also use the MESSAGE_TEXT condition item field of the GET
DIAGNOSTICS statement to convert an SQL return code into a text message.
Programs that require long token message support should code the GET
DIAGNOSTICS statement instead of DSNTIAR. For more information about GET
DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET
DIAGNOSTICS statement” on page 304.
DSNTIAR syntax:
CALL DSNTIAR ( sqlca, message, lrecl );
The DSNTIAR parameters have the following meanings:
sqlca
An SQL communication area.
message
An output area, in VARCHAR format, in which DSNTIAR places the message
text. The first halfword contains the length of the remaining area; its minimum
value is 240.
The output lines of text, each line being the length specified in lrecl, are put
into this area. For example, you could specify the format of the output area as:
DCL DATA_LEN FIXED BIN(31) INIT(132);
DCL DATA_DIM FIXED BIN(31) INIT(10);
DCL 1 ERROR_MESSAGE AUTOMATIC,
3 ERROR_LEN
FIXED BIN(15) UNAL INIT((DATA_LEN*DATA_DIM)),
3 ERROR_TEXT(DATA_DIM) CHAR(DATA_LEN);
.
.
.
CALL DSNTIAR ( SQLCA, ERROR_MESSAGE, DATA_LEN );

where ERROR_MESSAGE is the name of the message output area, DATA_DIM
is the number of lines in the message output area, and DATA_LEN is the
length of each line.
lrecl
A fullword containing the logical record length of output messages, between 72
and 240.
Because DSNTIAR is an assembler language program, you must include the
following directives in your PL/I application:
DCL DSNTIAR ENTRY OPTIONS (ASM,INTER,RETCODE);

An example of calling DSNTIAR from an application appears in the DB2 sample
assembler program DSN8BP3, contained in the library DSN8910.SDSNSAMP. See
“DB2 sample applications” on page 1013 for instructions on how to access and
print the source code for the sample program.

316

Application Programming and SQL Guide
CICS: If your CICS application requires CICS storage handling, you must use the
subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax:
CALL DSNTIAC (eib, commarea, sqlca, msg, lrecl);

DSNTIAC has extra parameters, which you must use for calls to routines that use
CICS commands.
eib

EXEC interface block

commarea
communication area
For more information on these parameters, see the appropriate application
programming guide for CICS. The remaining parameter descriptions are the same
as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the
same way.
You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you
must also define them in the CSD. For an example of CSD entry generation
statements for use with DSNTIAC, see job DSNTEJ5A.
The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and
link-edits DSNTIAC, are in the data set prefix.SDSNSAMP.

Arithmetic and conversion errors
You can track arithmetic and conversion errors by using indicator variables. An
indicator variable contains a small integer value that indicates some information
about the associated host variable.
Numeric or character conversion errors or arithmetic expression errors can set an
indicator variable to -2. For example, division by zero and arithmetic overflow do
not necessarily halt the execution of a SELECT statement. If you use indicator
variables and an error occurs in the SELECT list, the statement can continue to
execute and return good data for rows in which the error does not occur.
For rows in which a conversion or arithmetic expression error does occur, the
indicator variable indicates that one or more selected items have no meaningful
value. The indicator variable flags this error with a -2 for the affected host variable
and an SQLCODE of +802 (SQLSTATE ’01519’) in the SQLCA.

Writing applications that enable users to create and modify tables
You can write a DB2 application that enables users to create new tables, add
columns to them, increase the length of character columns, rearrange the columns,
and delete columns.
Question: How can I write an SQL application that allows users to create new
tables, add columns to them, increase the length of character columns, rearrange
the columns, and delete columns?
|
|
|
|
|
|

Answer: Your program can dynamically execute CREATE TABLE and ALTER
TABLE statements entered by users to create new tables, add columns to existing
tables, or change the data types of existing columns. Added columns initially
contain either the null value or a default value. Both statements, like any data
definition statement, are relatively expensive to execute; consider the effects of
locks.
Chapter 3. Including DB2 queries in an application program

317
You cannot rearrange or delete columns in a table without dropping the entire
table. You can, however, create a view on the table, which includes only the
columns you want, in the order you want. This has the same effect as redefining
the table.
For a description of dynamic SQL execution, see “Dynamic SQL” on page 258.

Saving SQL statements that are translated from end user requests
If your program translates requests from end users into SQL statements and allows
users to save their requests, your program can improve performance by saving
those translated statements.
Question: A program translates requests from end users into SQL statements before
executing them, and users can save a request. How can the corresponding SQL
statement be saved?
Answer: You can save the corresponding SQL statements in a table with a column
having a data type of VARCHAR(n), where n is the maximum length of any SQL
statement. You must save the source SQL statements, not the prepared versions.
That means that you must retrieve and then prepare each statement before
executing the version stored in the table. In essence, your program prepares an
SQL statement from a character string and executes it dynamically. (For a
description of dynamic SQL, see “Dynamic SQL” on page 258.)

Retrieving data from DB2 tables in REXX programs
Although all output data in REXX programs is string data, you can determine the
data type that the data represents from its format and from the data type of the
column from which the data was retrieved.
The following table gives the format for each type of output data.
Table 71. SQL output data types and REXX data formats
SQL data type

| SMALLINTINTEGERBIGINT
|
|
|
DECIMAL(p,s)

REXX output data format
A string of numerics that does not contain leading zeroes, a decimal point, or
an exponent identifier. If the string represents a negative number, it begins
with a minus (-) sign. The numeric value is between -9223372036854775808 and
9223372036854775807, inclusive.
A string of numerics with one of the following formats:
v Contains a decimal point but not an exponent identifier. The string is
padded with zeroes to match the scale of the corresponding table column. If
the value represents a negative number, it begins with a minus (-) sign.
v Does not contain a decimal point or an exponent identifier. The numeric
value is less than -2147483647 or greater than 2147483647. If the value is
negative, it begins with a minus (-) sign.

FLOAT(n) REALDOUBLE

318

A string that represents a number in scientific notation. The string consists of a
numeric, a decimal point, a series of numerics, and an exponent identifier. The
exponent identifier is an E followed by a minus (-) sign and a series of
numerics if the number is between -1 and 1. Otherwise, the exponent identifier
is an E followed by a series of numerics. If the string represents a negative
number, it begins with a minus (-) sign.

Application Programming and SQL Guide
Table 71. SQL output data types and REXX data formats (continued)
SQL data type

|
|
|
|
|
|

REXX output data format

DECFLOAT

REXX emulates the DECFLOAT data type with DOUBLE, so support for
DECFLOAT is limited to the REXX support for DOUBLE. The following special
values are not supported:
v INFINITY
v SNAN
v NAN

CHAR(n)VARCHAR(n)

A character string of length n bytes. The string is not enclosed in single or
double quotation marks.

GRAPHIC(n) VARGRAPHIC(n)

A string of length 2*n bytes. Each pair of bytes represents a double-byte
character. This string does not contain a leading G, is not enclosed in quotation
marks, and does not contain shift-out or shift-in characters.

Because you cannot use the SELECT INTO statement in a REXX procedure, to
retrieve data from a DB2 table you must prepare a SELECT statement, open a
cursor for the prepared statement, and then fetch rows into host variables or an
SQLDA using the cursor. The following example demonstrates how you can
retrieve data from a DB2 table using an SQLDA:
SQLSTMT= ,
’SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME,’ ,
’ WORKDEPT, PHONENO, HIREDATE, JOB,’ ,
’ EDLEVEL, SEX, BIRTHDATE, SALARY,’ ,
’ BONUS, COMM’ ,
’ FROM EMP’
EXECSQL DECLARE C1 CURSOR FOR S1
EXECSQL PREPARE S1 INTO :OUTSQLDA FROM :SQLSTMT
EXECSQL OPEN C1
Do Until(SQLCODE ¬= 0)
EXECSQL FETCH C1 USING DESCRIPTOR :OUTSQLDA
If SQLCODE = 0 Then Do
Line = ’’
Do I = 1 To OUTSQLDA.SQLD
Line = Line OUTSQLDA.I.SQLDATA
End I
Say Line
End
End

XML data in embedded SQL applications
Embedded SQL applications that are written in assembler language, C, C++,
COBOL, or PL/I can update and retrieve data in XML columns.
In embedded SQL applications, you can:
v Store an entire XML document in an XML column using INSERT or UPDATE
statements.
v Retrieve an entire XML document from an XML column using SELECT
statements.
v Retrieve a sequence from a document in an XML column by using the SQL
XMLQUERY function within a SELECT or FETCH statement, to retrieve the
sequence into a serialized XML string in the database, and then retrieve the data
into an application variable.
Recommendation: Follow these guidelines when you write embedded SQL
applications:
Chapter 3. Including DB2 queries in an application program

319
v Avoid using the XMLPARSE and XMLSERIALIZE functions.
Let DB2 do the conversions between the external and internal XML formats
implicitly.
v Use XML host variables for input and output.
Doing so allows DB2 to process values as XML data instead of character or
binary string data. If the application cannot use XML host variables, it should
use binary string host variables to minimize character conversion issues.
v Avoid character conversion by using UTF-8 host variables for input and output
of XML values whenever possible.

Host variable data types for XML data in embedded SQL
applications
DB2 provides XML host variable types for Assembler, C, C++, COBOL, and PL/I.
Those types are:
v XML AS BLOB
v XML AS CLOB
v XML AS DBCLOB
v XML AS BLOB_FILE
v XML AS CLOB_FILE
v XML AS DBCLOB_FILE
The XML host variable types are compatible only with the XML column data type.
You can use BLOB, CLOB, DBCLOB, CHAR, VARCHAR, GRAPHIC,
VARGRAPHIC, BINARY, or VARBINARY host variables to update XML columns.
You can convert the host variable data types to the XML type using the
XMLPARSE function, or you can let the DB2 database server perform the
conversion implicitly.
You can use BLOB, CLOB, DBCLOB, CHAR, VARCHAR, GRAPHIC,
VARGRAPHIC, BINARY, or VARBINARY host variables to retrieve data from XML
columns. You can convert the XML data to the host variable type using the
XMLSERIALIZE function, or you can let the DB2 database server perform the
conversion implicitly.
The following examples show you how to declare XML host variables in each
supported language. In each table, the left column contains the declaration that
you code in your application program. The right column contains the declaration
that DB2 generates.

Declarations of XML host variables in assembler
The following table shows assembler language declarations for some typical XML
types.
Table 72. Example of assembler XML variable declarations
You declare this variable

DB2 generates this variable

BLOB_XML SQL TYPE IS XML AS BLOB 1M

BLOB_XML DS
0FL4
BLOB_XML_LENGTH DS FL4
BLOB_XML_DATA DS CL655351
ORG
*+(983041)

320

Application Programming and SQL Guide
Table 72. Example of assembler XML variable declarations (continued)
You declare this variable

DB2 generates this variable

CLOB_XML SQL TYPE IS XML AS CLOB 40000K

CLOB_XML DS
0FL4
CLOB_XML_LENGTH DS FL4
CLOB_XML_DATA DS CL655351
ORG
*+(40894465)

DBCLOB_XML SQL TYPE IS XML AS DBCLOB 4000K

DBCLOB_XML DS
0FL4
DBCLOB_XML_LENGTH DS FL4
DBCLOB_XML_DATA DS GL655342
ORG
*+(4030466)

|
|
|
|
|
|

BLOB_XML_FILE SQL TYPE IS XML AS BLOB_FILE

BLOB_XML_FILE DS
0FL4
BLOB_XML_FILE_NAME_LENGTH DS FL4
BLOB_XML_FILE_DATA_LENGTH DS FL4
BLOB_XML_FILE_FILE_OPTIONS DS FL4
BLOB_XML_FILE_NAME DS CL255

|
|
|
|
|
|

CLOB_XML_FILE SQL TYPE IS XML AS CLOB_FILE

CLOB_XML_FILE DS
0FL4
CLOB_XML_FILE_NAME_LENGTH DS FL4
CLOB_XML_FILE_DATA_LENGTH DS FL4
CLOB_XML_FILE_FILE_OPTIONS DS FL4
CLOB_XML_FILE_NAME DS CL255

|
|
|
|
|
|

DBCLOB_XML_FILE SQL TYPE IS XML AS DBCLOB_FILE

DBCLOB_XML_FILE DS
0FL4
DBCLOB_XML_FILE_NAME_LENGTH DS FL4
DBCLOB_XML_FILE_DATA_LENGTH DS FL4
DBCLOB_XML_FILE_FILE_OPTIONS DS FL4
DBCLOB_XML_FILE_NAME DS CL255

Notes:
1. Because assembler language allows character declarations of no more than 65535 bytes, DB2 separates the host
language declarations for XML AS BLOB and XML AS CLOB host variables that are longer than 65535 bytes into
two parts.
2. Because assembler language allows graphic declarations of no more than 65534 bytes, DB2 separates the host
language declarations for XML AS DBCLOB host variables that are longer than 65534 bytes into two parts.

Declarations of XML host variables in C
The following table shows C and C++ language declarations that are generated by
the DB2 precompiler for some typical XML types. The declarations that the DB2
coprocessor generates might be different.
Table 73. Examples of C language variable declarations
You declare this variable

DB2 generates this variable

SQL TYPE IS XML AS BLOB (1M) blob_xml;

struct
{ unsigned long length;
char data??(1048576??);
} blob_xml;

SQL TYPE IS XML AS CLOB(40000K) clob_xml;

struct
{ unsigned long length;
char data??(40960000??);
} clob_xml;

SQL TYPE IS XML AS DBCLOB (4000K) dbclob_xml;

struct
{ unsigned long length;
unsigned short data??(4096000??);
} dbclob_xml;

Chapter 3. Including DB2 queries in an application program

321
Table 73. Examples of C language variable declarations (continued)
You declare this variable

DB2 generates this variable

| SQL TYPE IS XML AS BLOB_FILE blob_xml_file;
|
|
|
|
|
|

struct {
unsigned long name_length;
unsigned long data_length;
unsigned long file_options;
char name??(255??);
} blob_xml_file;

| SQL TYPE IS XML AS CLOB_FILE clob_xml_file;
|
|
|
|
|
|

struct {
unsigned long name_length;
unsigned long data_length;
unsigned long file_options;
char name??(255??);
} clob_xml_file;

| SQL TYPE IS XML AS DBCLOB_FILE dbclob_xml_file;
|
|
|
|
|
|

struct {
unsigned long name_length;
unsigned long data_length;
unsigned long file_options;
char name??(255??);
} dbclob_xml_file;

Declarations of XML host variables in COBOL
The declarations that are generated for COBOL differ, depending on whether you
use the DB2 precompiler or the DB2 coprocessor.
The following table shows COBOL declarations that the DB2 precompiler generates
for some typical XML types.
Table 74. Examples of COBOL variable declarations by the DB2 precompiler
You declare this variable

DB2 precompiler generates this variable

01

BLOB-XML USAGE IS
SQL TYPE IS XML AS BLOB(1M).

01

CLOB-XML USAGE IS
SQL TYPE IS XML AS CLOB(40000K).

01

01

322

Application Programming and SQL Guide

BLOB-XML.
BLOB-XML-LENGTH
PIC 9(9) COMP.
02 BLOB-XML-DATA.
49 FILLER PIC X(32767).1
49 FILLER PIC X(32767).
Repeat 30 times
.
.
.
49 FILLER
PIC X(1048576-32*32767).
02

CLOB-XML.
CLOB-XML-LENGTH
PIC 9(9) COMP.
02 CLOB-XML-DATA.
49 FILLER PIC X(32767).1
49 FILLER PIC X(32767).
Repeat 1248 times
.
.
.
49 FILLER
PIC X(40960000-1250*32767).
02
Table 74. Examples of COBOL variable declarations by the DB2 precompiler (continued)
You declare this variable

DB2 precompiler generates this variable

01 DBCLOB-XML USAGE IS
SQL TYPE IS XML AS DBCLOB(4000K).

01

|
|
|
|
|

01 BLOB-XML-FILE USAGE IS SQL
TYPE IS XML AS BLOB-FILE.

01

|
|
|
|
|

01

CLOB-XML-FILE USAGE IS SQL
TYPE IS XML AS CLOB-FILE.

01

|
|
|
|
|

01

DBCLOB-XML-FILE USAGE IS SQL
TYPE IS XML AS DBCLOB-FILE.

01

DBCLOB-XML.
DBCLOB-XML-LENGTH
PIC 9(9) COMP.
02 DBCLOB-XML-DATA.
49 FILLER PIC G(32767)
USAGE DISPLAY-1.2
49 FILLER PIC G(32767)
USAGE DISPLAY-1.
Repeat 123 times
.
.
.
49 FILLER
PIC G(4096000-125*32767)
USAGE DISPLAY-1.
02

49
49
49
49

BLOB-XML-FILE.
BLOB-XML-FILE-NAME-LENGTH PIC S9(9) COMP-5 SYNC.
BLOB-XML-FILE-DATA-LENGTH PIC S9(9) COMP-5.
BLOB-XML-FILE-FILE-OPTION PIC S9(9) COMP-5.
BLOB-XML-FILE-NAME PIC X(255).

49
49
49
49

CLOB-XML-FILE.
CLOB-XML-FILE-NAME-LENGTH PIC S9(9) COMP-5 SYNC.
CLOB-XML-FILE-DATA-LENGTH PIC S9(9) COMP-5.
CLOB-XML-FILE-FILE-OPTION PIC S9(9) COMP-5.
CLOB-XML-FILE-NAME PIC X(255).

49
49
49
49

DBCLOB-XML-FILE.
DBCLOB-XML-FILE-NAME-LENGTH PIC S9(9) COMP-5 SYNC.
DBCLOB-XML-FILE-DATA-LENGTH PIC S9(9) COMP-5.
DBCLOB-XML-FILE-FILE-OPTION PIC S9(9) COMP-5.
DBCLOB-XML-FILE-NAME PIC X(255).

Notes:
1. For XML AS BLOB or XML AS CLOB host variables that are greater than 32767 bytes in length, DB2 creates
multiple host language declarations of 32767 or fewer bytes.
2. For XML AS DBCLOB host variables that are greater than 32767 double-byte characters in length, DB2 creates
multiple host language declarations of 32767 or fewer double-byte characters.

Declarations of XML host variables in PL/I
The declarations that are generated for PL/I differ, depending on whether you use
the DB2 precompiler or the DB2 coprocessor.
The following table shows PL/I declarations that the DB2 precompiler generates
for some typical XML types.
Table 75. Examples of PL/I variable declarations
You declare this variable

DB2 precompiler generates this variable

DCL BLOB_XML
SQL TYPE IS XML AS BLOB (1M);

DCL
1
2
2

BLOB_XML,
BLOB_XML_LENGTH BIN FIXED(31),
BLOB_XML_DATA,1
3
BLOB_XML_DATA1 (32) CHAR(32767),
3
BLOB_XML_DATA2 CHAR(32);

Chapter 3. Including DB2 queries in an application program

323
Table 75. Examples of PL/I variable declarations (continued)
You declare this variable

DB2 precompiler generates this variable

DCL CLOB_XML
SQL TYPE IS XML AS CLOB (40000K);

DCL
1
2
2

DCL DBCLOB_XML
SQL TYPE IS XML AS DBCLOB (4000K);

CLOB_XML,
CLOB_XML_LENGTH BIN FIXED(31),
CLOB_XML_DATA,1
3
CLOB_XML_DATA1 (1250) CHAR(32767),
3
CLOB_XML_DATA2 CHAR(1250);

DCL
1
2
2

| DCL BLOB_XML_FILE
|
SQL TYPE IS XML AS BLOB_FILE;
|
|
|
|

DCL

| DCL CLOB_XML_FILE
SQL TYPE IS XML AS CLOB_FILE;
|
|
|
|
|

DCL

| DCL DBCLOB_XML_FILE SQL TYPE IS XML AS
DBCLOB_FILE;
|
|
|
|
|

DBCLOB_XML,
DBCLOB_XML_LENGTH BIN FIXED(31),
DBCLOB_XML_DATA,2
3
DBCLOB_XML_DATA1 (250 ) GRAPHIC(16383),
3
DBCLOB_XML_DATA2 GRAPHIC(250);

DCL

1
2
2
2
2

BLOB_XML_FILE,
BLOB_XML_FILE_NAME_LENGTH BIN FIXED(31) ALIGNED,
BLOB_XML_FILE_DATA_LENGTH BIN FIXED(31),
BLOB_XML_FILE_FILE_OPTIONS BIN FIXED(31),
BLOB_XML_FILE_NAME CHAR(255);

2
2
2
2

CLOB_XML_FILE,
CLOB_XML_FILE_NAME_LENGTH BIN FIXED(31) ALIGNED,
CLOB_XML_FILE_DATA_LENGTH BIN FIXED(31),
CLOB_XML_FILE_FILE_OPTIONS BIN FIXED(31),
CLOB_XML_FILE_NAME CHAR(255);

2
2
2
2

DBCLOB_XML_FILE,
DBCLOB_XML_FILE_NAME_LENGTH BIN FIXED(31) ALIGNED,
DBCLOB_XML_FILE_DATA_LENGTH BIN FIXED(31),
DBCLOB_XML_FILE_FILE_OPTIONS BIN FIXED(31),
DBCLOB_XML_FILE_NAME CHAR(255);

1

1

Notes:

| 1. For XML AS BLOB or XML AS CLOB host variables that are greater than 32767 bytes in length, DB2 creates host
language declarations in the following way:
|
v If the length of the XML is greater than 32767 bytes and evenly divisible by 32767, DB2 creates an array of
|
32767-byte strings. The dimension of the array is length/32767.
|
v If the length of the XML is greater than 32767 bytes but not evenly divisible by 32767, DB2 creates two
|
declarations: The first is an array of 32767 byte strings, where the dimension of the array, n, is length/32767.
|
The second is a character string of length length-n*32767.
|
| 2. For XML AS DBCLOB host variables that are greater than 16383 double-byte characters in length, DB2 creates
host language declarations in the following way:
|
v If the length of the XML is greater than 16383 characters and evenly divisible by 16383, DB2 creates an array of
|
16383-character strings. The dimension of the array is length/16383.
|
v If the length of the XML is greater than 16383 characters but not evenly divisible by 16383, DB2 creates two
|
declarations: The first is an array of 16383 byte strings, where the dimension of the array, m, is length/16383.
|
The second is a character string of length length-m*16383.
|

XML column updates in embedded SQL applications
When you update or insert data into XML columns of a DB2 table, the input data
must be in the serialized string format.
The encoding of XML data can be derived from the data itself, which is known as
internally encoded data, or from external sources, which is known as externally
encoded data. XML data that is sent to the database server as binary data is treated

324

Application Programming and SQL Guide
as internally encoded data. XML data that is sent to the database server as
character data is treated as externally encoded data.
Externally encoded data can have internal encoding. That is, the data might be sent
to the database server as character data, but the data contains encoding
information. DB2 does not enforce consistency of the internal and external
encoding. When the internal and external encoding information differs, the
external encoding takes precedence. However, if there is a difference between the
external and internal encoding, intervening character conversion might have
occurred on the data, and there might be data loss.
Character data in XML columns is stored in UTF-8 encoding. The database server
handles conversion of the data from its internal or external encoding to UTF-8.
The following examples demonstrate how to update XML columns in assembler, C,
COBOL, and PL/I applications. The examples use a table named MYCUSTOMER,
which is a copy of the sample CUSTOMER table.
Example: The following example shows an assembler program that inserts data
from XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML
column. The XML AS BLOB data is inserted as binary data, so the database server
honors the internal encoding. The XML AS CLOB and CLOB data is inserted as
character data, so the database server honors the external encoding.
**********************************************************************
* UPDATE AN XML COLUMN WITH DATA IN AN XML AS CLOB HOST VARIABLE
*
**********************************************************************
EXEC SQL
UPDATE MYCUSTOMER
SET INFO = :XMLBUF
WHERE CID = 1000
**********************************************************************
* UPDATE AN XML COLUMN WITH DATA IN AN XML AS BLOB HOST VARIABLE
*
**********************************************************************
EXEC SQL
UPDATE MYCUSTOMER
SET INFO = :XMLBLOB
WHERE CID = 1000
**********************************************************************
* UPDATE AN XML COLUMN WITH DATA IN A CLOB HOST VARIABLE. USE
*
* THE XMLPARSE FUNCTION TO CONVERT THE DATA TO THE XML TYPE.
*
**********************************************************************
EXEC SQL
UPDATE MYCUSTOMER
SET INFO = XMLPARSE(DOCUMENT :CLOBBUF)
WHERE CID = 1000
...
LTORG
******************************
* HOST VARIABLE DECLARATIONS *
******************************
XMLBUF
SQL TYPE IS XML AS CLOB 10K
XMLBLOB SQL TYPE IS XML AS BLOB 10K
CLOBBUF SQL TYPE IS CLOB 10K

+
+
+

+
+
+

+
+
+

Example: The following example shows a C language program that inserts data
from XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML
column. The XML AS BLOB data is inserted as binary data, so the database server
honors the internal encoding. The XML AS CLOB and CLOB data is inserted as
character data, so the database server honors the external encoding.

Chapter 3. Including DB2 queries in an application program

325
/******************************/
/* Host variable declarations */
/******************************/
EXEC SQL BEGIN DECLARE SECTION;
SQL TYPE IS XML AS CLOB( 10K ) xmlBuf;
SQL TYPE IS XML AS BLOB( 10K ) xmlblob;
SQL TYPE IS CLOB( 10K ) clobBuf;
EXEC SQL END DECLARE SECTION;
/******************************************************************/
/* Update an XML column with data in an XML AS CLOB host variable */
/******************************************************************/
EXEC SQL UPDATE MYCUSTOMER SET INFO = :xmlBuf where CID = 1000;
/******************************************************************/
/* Update an XML column with data in an XML AS BLOB host variable */
/******************************************************************/
EXEC SQL UPDATE MYCUSTOMER SET INFO = :xmlblob where CID = 1000;
/******************************************************************/
/* Update an XML column with data in a CLOB host variable. Use
*/
/* the XMLPARSE function to convert the data to the XML type.
*/
/******************************************************************/
EXEC SQL UPDATE MYCUSTOMER SET INFO = XMLPARSE(DOCUMENT :clobBuf) where CID = 1000;

Example: The following example shows a COBOL program that inserts data from
XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML column.
The XML AS BLOB data is inserted as binary data, so the database server honors
the internal encoding. The XML AS CLOB and CLOB data is inserted as character
data, so the database server honors the external encoding.
******************************
* Host variable declarations *
******************************
01 XMLBUF USAGE IS SQL TYPE IS XML as CLOB(10K).
01 XMLBLOB USAGE IS SQL TYPE IS XML AS BLOB(10K).
01 CLOBBUF USAGE IS SQL TYPE IS CLOB(10K).
*******************************************************************
* Update an XML column with data in an XML AS CLOB host variable *
*******************************************************************
EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBUF where CID = 1000.
*******************************************************************
* Update an XML column with data in an XML AS BLOB host variable *
*******************************************************************
EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBLOB where CID = 1000.
*******************************************************************
* Update an XML column with data in a CLOB host variable. Use
*
* the XMLPARSE function to convert the data to the XML type.
*
*******************************************************************
EXEC SQL UPDATE MYCUSTOMER SET INFO = XMLPARSE(DOCUMENT :CLOBBUF) where CID = 1000.

Example: The following example shows a PL/I program that inserts data from
XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML column.
The XML AS BLOB data is inserted as binary data, so the database server honors
the internal encoding. The XML AS CLOB and CLOB data is inserted as character
data, so the database server honors the external encoding.
/******************************/
/* Host variable declarations */
/******************************/
DCL
XMLBUF SQL TYPE IS XML AS CLOB(10K),
XMLBLOB SQL TYPE IS XML AS BLOB(10K),
CLOBBUF SQL TYPE IS CLOB(10K);
/*******************************************************************/
/* Update an XML column with data in an XML AS CLOB host variable */
/*******************************************************************/
EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBUF where CID = 1000;
/*******************************************************************/

326

Application Programming and SQL Guide
/* Update an XML column with data in an XML AS BLOB host variable */
/*******************************************************************/
EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBLOB where CID = 1000;
/*******************************************************************/
/* Update an XML column with data in a CLOB host variable. Use
*/
/* the XMLPARSE function to convert the data to the XML type.
*/
/*******************************************************************/
EXEC SQL UPDATE MYCUSTOMER SET INFO = XMLPARSE(DOCUMENT :CLOBBUF) where CID = 1000;

XML data retrieval in embedded SQL applications
In an embedded SQL application, if you retrieve the data into a character host
variable, DB2 converts the data from UTF-8 encoding to the application encoding.
If you retrieve the data into binary host variable, DB2 does not convert the data to
another encoding.
The output data is in the serialized string format.
DB2 might add an XML encoding specification to the retrieved data, depending on
whether you call the XMLSERIALIZE function when you retrieve the data. If you
do not call the XMLSERIALIZE function, DB2 adds the correct XML encoding
specification to the retrieved data. If you call the XMLSERIALIZE function, DB2
adds an internal XML encoding declaration for UTF-8 encoding if you specify
INCLUDING XMLDECLARATION in the function call. When you use
INCLUDING XMLDECLARATION, you need to ensure that the retrieved data is
not converted from UTF-8 encoding to another encoding.
The following examples demonstrate how to retrieve data from XML columns in
assembler, C, COBOL, and PL/I applications. The examples use a table named
MYCUSTOMER, which is a copy of the sample CUSTOMER table.
Example: The following example shows an assembler program that retrieves data
from an XML column into XML AS BLOB, XML AS CLOB, and CLOB host
variables. The data that is retrieved into an XML AS BLOB host variable is
retrieved as binary data, so the database server generates an XML declaration with
UTF-8 encoding. The data that is retrieved into an XML AS CLOB host variable is
retrieved as character data, so the database server generates an XML declaration
with an internal encoding declaration that is consistent with the external encoding.
The data that is retrieved into a CLOB host variable is retrieved as character data,
so the database server generates an XML declaration with an internal encoding
declaration. That declaration might not be consistent with the external encoding.
**********************************************************************
* RETRIEVE XML COLUMN DATA INTO AN XML AS CLOB HOST VARIABLE
*
**********************************************************************
EXEC SQL
SELECT INFO
INTO :XMLBUF
FROM MYCUSTOMER
WHERE CID = 1000
**********************************************************************
* RETRIEVE XML COLUMN DATA INTO AN XML AS BLOB HOST VARIABLE
*
**********************************************************************
EXEC SQL
SELECT INFO
INTO :XMLBLOB
FROM MYCUSTOMER
WHERE CID = 1000
**********************************************************************
* RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE.
*
* BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE
*
* XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML
*

+
+
+
+

+
+
+
+

Chapter 3. Including DB2 queries in an application program

327
* TYPE TO THE CLOB TYPE.
*
**********************************************************************
EXEC SQL
SELECT XMLSERIALIZE(INFO AS CLOB(10K))
INTO :CLOBBUF
FROM MYCUSTOMER
WHERE CID = 1000
...
LTORG
******************************
* HOST VARIABLE DECLARATIONS *
******************************
XMLBUF
SQL TYPE IS XML AS CLOB 10K
XMLBLOB
SQL TYPE IS XML AS BLOB 10K
CLOBBUF
SQL TYPE IS CLOB 10K

+
+
+
+

Example: The following example shows a C language program that retrieves data
from an XML column into XML AS BLOB, XML AS CLOB, and CLOB host
variables. The data that is retrieved into an XML AS BLOB host variable is
retrieved as binary data, so the database server generates an XML declaration with
UTF-8 encoding. The data that is retrieved into an XML AS CLOB host variable is
retrieved as character data, so the database server generates an XML declaration
with an internal encoding declaration that is consistent with the external encoding.
The data that is retrieved into a CLOB host variable is retrieved as character data,
so the database server generates an XML declaration with an internal encoding
declaration. That declaration might not be consistent with the external encoding.
/******************************/
/* Host variable declarations */
/******************************/
EXEC SQL BEGIN DECLARE SECTION;
SQL TYPE IS XML AS CLOB( 10K ) xmlBuf;
SQL TYPE IS XML AS BLOB( 10K ) xmlBlob;
SQL TYPE IS CLOB( 10K ) clobBuf;
EXEC SQL END DECLARE SECTION;
/**********************************************************************/
/* Retrieve data from an XML column into an XML AS CLOB host variable */
/**********************************************************************/
EXEC SQL SELECT INFO
INTO :xmlBuf from myTable where CID = 1000;
/**********************************************************************/
/* Retrieve data from an XML column into an XML AS BLOB host variable */
/**********************************************************************/
EXEC SQL SELECT INFO
INTO :xmlBlob from myTable where CID = 1000;
/**********************************************************************/
/* RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE.
*/
/* BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE
*/
/* XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML
*/
/* TYPE TO THE CLOB TYPE.
*/
/**********************************************************************/
EXEC SQL SELECT XMLSERIALIZE(INFO AS CLOB(10K))
INTO :clobBuf from myTable where CID = 1000;

Example: The following example shows a COBOL program that retrieves data
from an XML column into XML AS BLOB, XML AS CLOB, and CLOB host
variables. The data that is retrieved into an XML AS BLOB host variable is
retrieved as binary data, so the database server generates an XML declaration with
UTF-8 encoding. The data that is retrieved into an XML AS CLOB host variable is
retrieved as character data, so the database server generates an XML declaration
with an internal encoding declaration that is consistent with the external encoding.
The data that is retrieved into a CLOB host variable is retrieved as character data,
so the database server generates an XML declaration with an internal encoding
declaration. That declaration might not be consistent with the external encoding.

328

Application Programming and SQL Guide
******************************
* Host variable declarations *
******************************
01 XMLBUF USAGE IS SQL TYPE IS XML AS CLOB(10K).
01 XMLBLOB USAGE IS SQL TYPE IS XML AS BLOB(10K).
01 CLOBBUF USAGE IS SQL TYPE IS CLOB(10K).
**********************************************************************
* Retrieve data from an XML column into an XML AS CLOB host variable *
**********************************************************************
EXEC SQL SELECT INFO
INTO :XMLBUF FROM MYTABLE WHERE CID = 1000.
**********************************************************************
* Retrieve data from an XML column into an XML AS BLOB host variable *
**********************************************************************
EXEC SQL SELECT INFO
INTO :XMLBLOB FROM MYTABLE WHERE CID = 1000.
**********************************************************************
* RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE.
*
* BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE
*
* XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML
*
* TYPE TO THE CLOB TYPE.
*
**********************************************************************
EXEC SQL SELECT XMLSERIALIZE(INFO AS CLOB(10K))
INTO :CLOBBUF FROM MYTABLE WHERE ID= 1000.

Example: The following example shows a PL/I program that retrieves data from
an XML column into XML AS BLOB, XML AS CLOB, and CLOB host variables.
The data that is retrieved into an XML AS BLOB host variable is retrieved as
binary data, so the database server generates an XML declaration with UTF-8
encoding. The data that is retrieved into an XML AS CLOB host variable is
retrieved as character data, so the database server generates an XML declaration
with an internal encoding declaration that is consistent with the external encoding.
The data that is retrieved into a CLOB host variable is retrieved as character data,
so the database server generates an XML declaration with an internal encoding
declaration. That declaration might not be consistent with the external encoding.
/******************************/
/* Host variable declarations */
/******************************/
DCL
XMLBUF SQL TYPE IS XML AS CLOB(10K),
XMLBLOB SQL TYPE IS XML AS BLOB(10K),
CLOBBUF SQL TYPE IS CLOB(10K);
/**********************************************************************/
/* Retrieve data from an XML column into an XML AS CLOB host variable */
/**********************************************************************/
EXEC SQL SELECT INFO
INTO :XMLBUF FROM MYTABLE WHERE CID = 1000;
/**********************************************************************/
/* Retrieve data from an XML column into an XML AS BLOB host variable */
/**********************************************************************/
EXEC SQL SELECT INFO
INTO :XMLBLOB FROM MYTABLE WHERE CID = 1000;
/**********************************************************************/
/* RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE.
*/
/* BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE
*/
/* XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML
*/
/* TYPE TO THE CLOB TYPE.
*/
/**********************************************************************/
EXEC SQL SELECT XMLSERIALIZE(INFO AS CLOB(10K))
INTO :CLOBBUF FROM MYTABLE WHERE CID = 1000;

Object-oriented extensions in COBOL
When you use object-oriented extensions in a COBOL application, you need to
consider where to place SQL statements, the SQLCA, the SQLDA, and host
variable declarations, and the rules for host variables.

Chapter 3. Including DB2 queries in an application program

329
Where to place SQL statements in your application: A COBOL source data set or
member can contain the following elements:
v Multiple programs
v Multiple class definitions, each of which contains multiple methods
You can put SQL statements in only the first program or class in the source data
set or member. However, you can put SQL statements in multiple methods within
a class. If an application consists of multiple data sets or members, each of the data
sets or members can contain SQL statements.
Where to place the SQLCA, SQLDA, and host variable declarations: You can put
the SQLCA, SQLDA, and SQL host variable declarations in the
WORKING-STORAGE SECTION of a program, class, or method. An SQLCA or
SQLDA in a class WORKING-STORAGE SECTION is global for all the methods of
the class. An SQLCA or SQLDA in a method WORKING-STORAGE SECTION is
local to that method only.
If a class and a method within the class both contain an SQLCA or SQLDA, the
method uses the SQLCA or SQLDA that is local.
Rules for host variables: You can declare COBOL variables that are used as host
variables in the WORKING-STORAGE SECTION or LINKAGE-SECTION of a
program, class, or method. You can also declare host variables in the
LOCAL-STORAGE SECTION of a method. The scope of a host variable is the
method, class, or program within which it is defined.

Cursors and statement names in REXX
In REXX applications that contain SQL statements, you must use a predefined set
of names for cursors or prepared statements.
The following names are valid for cursors and prepared statements in REXX
applications:
c1 to c100
Cursor names for DECLARE CURSOR, OPEN, CLOSE, and FETCH statements.
By default, c1 to c100 are defined with the WITH RETURN clause, and c51 to
c100 are defined with the WITH HOLD clause. You can use the ATTRIBUTES
clause of the PREPARE statement to override these attributes or add additional
attributes. For example, you might want to add attributes to make your cursor
scrollable.
c101 to c200
Cursor names for ALLOCATE, DESCRIBE, FETCH, and CLOSE statements that
are used to retrieve result sets in a program that calls a stored procedure.
s1 to s100
Prepared statement names for DECLARE STATEMENT, PREPARE, DESCRIBE,
and EXECUTE statements.
Use only the predefined names for cursors and statements. When you associate a
cursor name with a statement name in a DECLARE CURSOR statement, the cursor
name and the statement must have the same number. For example, if you declare
cursor c1, you need to declare it for statement s1:
EXECSQL ’DECLARE C1 CURSOR FOR S1’

Do not use any of the predefined names as host variables names.

330

Application Programming and SQL Guide
Programming examples
You can write DB2 programs in assembler language, C, C++, COBOL, Fortran,
PL/I or REXX. These programs can access a local or remote DB2 subsystem and
can execute static or dynamic SQL statements. This information contains several
such programming examples.
To prepare and run these applications, use the JCL in DSN910.SDSNSAMP as a
model for your JCL. For a list JCL procedures for preparing sample programs, see
“DB2 sample applications” on page 1013. For information on the appropriate
compiler options to use for each language, see the following topics in DB2
Installation Guide:
v “Special considerations for COBOL programs”
v “Special considerations for C and C++ programs”
v “Special considerations for PL/I programs”

Sample dynamic and static SQL in a C program
Programs that access DB2 can contain static SQL, dynamic SQL, or both. This
example shows a C program that contains both static and dynamic SQL.
The following figure illustrates dynamic SQL and static SQL embedded in a C
program. Each section of the program is identified with a comment. Section 1 of
the program shows static SQL; sections 2, 3, and 4 show dynamic SQL. The
function of each section is explained in detail in the prologue to the program.
/**********************************************************************/
/* Descriptive name = Dynamic SQL sample using C language
*/
/*
*/
/* Function = To show examples of the use of dynamic and static
*/
/*
SQL.
*/
/*
*/
/* Notes = This example assumes that the EMP and DEPT tables are
*/
/*
defined. They need not be the same as the DB2 Sample
*/
/*
tables.
*/
/*
*/
/* Module type
= C program
*/
/*
Processor
= DB2 precompiler, C compiler
*/
/*
Module size = see link edit
*/
/*
Attributes = not reentrant or reusable
*/
/*
*/
/*
Input
=
*/
/*
*/
/*
symbolic label/name = DEPT
*/
/*
description = arbitrary table
*/
/*
symbolic label/name = EMP
*/
/*
description = arbitrary table
*/
/*
*/
/*
Output
=
*/
/*
*/
/*
symbolic label/name = SYSPRINT
*/
/*
description = print results via printf
*/
/*
*/
/* Exit-normal = return code 0 normal completion
*/
/*
*/
/* Exit-error =
*/
/*
*/
/*
Return code
= SQLCA
*/
/*
*/
/*
Abend codes
= none
*/
/*
*/
/* External references = none
*/
Chapter 3. Including DB2 queries in an application program

331
/*
/*
/*
/*

*/
*/
*/
*/

Control-blocks
=
SQLCA
- sql communication area

/* Logic specification:
*/
/*
*/
/* There are four SQL sections.
*/
/*
*/
/* 1) STATIC SQL 1: using static cursor with a SELECT statement.
*/
/*
Two output host variables.
*/
/* 2) Dynamic SQL 2: Fixed-list SELECT, using same SELECT statement
*/
/*
used in SQL 1 to show the difference. The prepared string
*/
/*
:iptstr can be assigned with other dynamic-able SQL statements. */
/* 3) Dynamic SQL 3: Insert with parameter markers.
*/
/*
Using four parameter markers which represent four input host
*/
/*
variables within a host structure.
*/
/* 4) Dynamic SQL 4: EXECUTE IMMEDIATE
*/
/*
A GRANT statement is executed immediately by passing it to DB2 */
/*
via a varying string host variable. The example shows how to
*/
/*
set up the host variable before passing it.
*/
/*
*/
/**********************************************************************/
#include "stdio.h"
#include "stdefs.h"
EXEC SQL INCLUDE SQLCA;
EXEC SQL INCLUDE SQLDA;
EXEC SQL BEGIN DECLARE SECTION;
short edlevel;
struct { short len;
char x1[56];
} stmtbf1, stmtbf2, inpstr;
struct { short len;
char x1[15];
} lname;
short hv1;
struct { char deptno[4];
struct { short len;
char x[36];
} deptname;
char mgrno[7];
char admrdept[4];
} hv2;
short ind[4];
EXEC SQL END
DECLARE SECTION;
EXEC SQL DECLARE EMP TABLE
(EMPNO
CHAR(6)
FIRSTNAME
VARCHAR(12)
MIDINIT
CHAR(1)
LASTNAME
VARCHAR(15)
WORKDEPT
CHAR(3)
PHONENO
CHAR(4)
HIREDATE
DECIMAL(6)
JOBCODE
DECIMAL(3)
EDLEVEL
SMALLINT
SEX
CHAR(1)
BIRTHDATE
DECIMAL(6)
SALARY
DECIMAL(8,2)
FORFNAME
VARGRAPHIC(12)
FORMNAME
GRAPHIC(1)
FORLNAME
VARGRAPHIC(15)
FORADDR
VARGRAPHIC(256) )
EXEC SQL DECLARE DEPT TABLE
(
DEPTNO
DEPTNAME

332

Application Programming and SQL Guide

CHAR(3)
VARCHAR(36)

,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
;

,
,
MGRNO
ADMRDEPT

CHAR(6)
CHAR(3)

,
);

main ()
{
printf("??/n***
begin of program
***");
EXEC SQL WHENEVER SQLERROR GO TO HANDLERR;
EXEC SQL WHENEVER SQLWARNING GO TO HANDWARN;
EXEC SQL WHENEVER NOT FOUND GO TO NOTFOUND;
/******************************************************************/
/* Assign values to host variables which will be input to DB2
*/
/******************************************************************/
strcpy(hv2.deptno,"M92");
strcpy(hv2.deptname.x,"DDL");
hv2.deptname.len = strlen(hv2.deptname.x);
strcpy(hv2.mgrno,"123456");
strcpy(hv2.admrdept,"abc");
/******************************************************************/
/* Static SQL 1: DECLARE CURSOR, OPEN, FETCH, CLOSE
*/
/* Select into :edlevel, :lname
*/
/******************************************************************/
printf("??/n***
begin declare
***");
EXEC SQL DECLARE C1 CURSOR FOR SELECT EDLEVEL, LASTNAME FROM EMP
WHERE EMPNO = ’000010’;
printf("??/n***
begin open
***");
EXEC SQL OPEN C1;
printf("??/n***
begin fetch
EXEC SQL FETCH C1 INTO :edlevel, :lname;
printf("??/n*** returned values
printf("??/n??/nedlevel =
printf("??/nlname =

***");
***");

printf("??/n***
begin close
***");
EXEC SQL CLOSE C1;
/******************************************************************/
/* Dynamic SQL 2: PREPARE, DECLARE CURSOR, OPEN, FETCH, CLOSE
*/
/* Select into :edlevel, :lname
*/
/******************************************************************/
sprintf (inpstr.x1,
"SELECT EDLEVEL, LASTNAME FROM EMP WHERE EMPNO = ’000010’");
inpstr.len = strlen(inpstr.x1);
printf("??/n***
begin prepare
***");
EXEC SQL PREPARE STAT1 FROM :inpstr;
printf("??/n***
begin declare
***");
EXEC SQL DECLARE C2 CURSOR FOR STAT1;
printf("??/n***
begin open
***");
EXEC SQL OPEN C2;
printf("??/n***
begin fetch
EXEC SQL FETCH C2 INTO :edlevel, :lname;
printf("??/n*** returned values
printf("??/n??/nedlevel =
printf("??/nlname =

***");
***");

printf("??/n***
begin close
***");
EXEC SQL CLOSE C2;
/******************************************************************/
/* Dynamic SQL 3: PREPARE with parameter markers
*/
/* Insert into with four values.
*/
/******************************************************************/
sprintf (stmtbf1.x1,
"INSERT INTO DEPT VALUES (?,?,?,?)");
stmtbf1.len = strlen(stmtbf1.x1);
printf("??/n***
begin prepare
***");
EXEC SQL PREPARE s1 FROM :stmtbf1;
printf("??/n***
begin execute
***");
EXEC SQL EXECUTE s1 USING :hv2:ind;
Chapter 3. Including DB2 queries in an application program

333
printf("??/n***
following are expected insert results
***");
printf("??/n hv2.deptno =
printf("??/n hv2.deptname.len =
printf("??/n hv2.deptname.x =
printf("??/n hv2.mgrno =
printf("??/n hv2.admrdept =
EXEC SQL COMMIT;
/******************************************************************/
/* Dynamic SQL 4: EXECUTE IMMEDIATE
*/
/* Grant select
*/
/******************************************************************/
sprintf (stmtbf2.x1,
"GRANT SELECT ON EMP TO USERX");
stmtbf2.len = strlen(stmtbf2.x1);
printf("??/n***
begin execute immediate
***");
EXEC SQL EXECUTE IMMEDIATE :stmtbf2;
printf("??/n***
end of program
***");
goto progend;
HANDWARN: HANDLERR: NOTFOUND: ;
printf("??/n SQLCODE =
printf("??/n SQLWARN0 =
printf("??/n SQLWARN1 =
printf("??/n SQLWARN2 =
printf("??/n SQLWARN3 =
printf("??/n SQLWARN4 =
printf("??/n SQLWARN5 =
printf("??/n SQLWARN6 =
printf("??/n SQLWARN7 =
progend: ;
}

Sample COBOL dynamic SQL program
This example shows how to code dynamic varying-list SELECT statements in a
COBOL program. Varying-List SELECT statements are statements for which you do
not know the number of columns returned and their data types when you write
the program.
“Dynamic SQL” on page 258 describes three variations of dynamic SQL statements:
v Non-SELECT statements
v Fixed-List SELECT statements
In this case, you know the number of columns returned and their data types
when you write the program.
v Varying-List SELECT statements.
In this case, you do not know the number of columns returned and their data
types when you write the program.
This section documents a technique of coding varying list SELECT statements in
COBOL. For a list of the supported versions of COBOL, see DB2 Program Directory
.
This example program does not support BLOB, CLOB, or DBCLOB data types.

Pointers and based variables in the sample COBOL program
COBOL has a POINTER type and a SET statement that provide pointers and based
variables.
The SET statement sets a pointer from the address of an area in the linkage section
or another pointer; the statement can also set the address of an area in the linkage

334

Application Programming and SQL Guide
section. DSN8BCU2 in “Example of the sample COBOL program” provides these
uses of the SET statement. The SET statement does not permit the use of an
address in the WORKING-STORAGE section.

Storage allocation for the sample COBOL program
COBOL does not provide a means to allocate main storage within a program. You
can achieve the same end by having an initial program which allocates the storage,
and then calls a second program that manipulates the pointer. (COBOL does not
permit you to directly manipulate the pointer because errors and abends are likely
to occur.)
The initial program is extremely simple. It includes a working storage section that
allocates the maximum amount of storage needed. This program then calls the
second program, passing the area or areas on the CALL statement. The second
program defines the area in the linkage section and can then use pointers within
the area.
If you need to allocate parts of storage, the best method is to use indexes or
subscripts. You can use subscripts for arithmetic and comparison operations.

Example of the sample COBOL program
The following example shows an example of the initial program DSN8BCU1 that
allocates the storage and calls the second program DSN8BCU2. DSN8BCU2 then
defines the passed storage areas in its linkage section and includes the USING
clause on its PROCEDURE DIVISION statement.
Defining the pointers, then redefining them as numeric, permits some
manipulation of the pointers that you cannot perform directly. For example, you
cannot add the column length to the record pointer, but you can add the column
length to the numeric value that redefines the pointer.
The following example is the initial program that allocates storage.
**** DSN8BCU1- DB2 SAMPLE BATCH COBOL UNLOAD PROGRAM ***********
*
*
* MODULE NAME = DSN8BCU1
*
*
*
* DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION
*
*
UNLOAD PROGRAM
*
*
BATCH
*
*
ENTERPRISE COBOL FOR Z/OS
*
*
*
* FUNCTION = THIS MODULE PROVIDES THE STORAGE NEEDED BY
*
*
DSN8BCU2 AND CALLS THAT PROGRAM.
*
*
*
* NOTES =
*
*
DEPENDENCIES = NONE.
*
*
*
*
RESTRICTIONS =
*
*
THE MAXIMUM NUMBER OF COLUMNS IS 750,
*
*
WHICH IS THE SQL LIMIT.
*
*
*
*
DATA RECORDS ARE LIMITED TO 32700 BYTES,
*
*
INCLUDING DATA, LENGTHS FOR VARCHAR DATA,
*
*
AND SPACE FOR NULL INDICATORS.
*
*
*
* MODULE TYPE = COBOL PROGRAM
*
*
PROCESSOR
= ENTERPRISE COBOL FOR Z/OS
*
*
*
Chapter 3. Including DB2 queries in an application program

335
*
*
*

MODULE SIZE = SEE LINK EDIT
ATTRIBUTES = REENTRANT

*
*
*

*
ENTRY POINT = DSN8BCU1
*
*
PURPOSE = SEE FUNCTION
*
*
LINKAGE = INVOKED FROM DSN RUN
*
*
INPUT
= NONE
*
*
OUTPUT = NONE
*
*
*
*
EXIT-NORMAL = RETURN CODE 0 NORMAL COMPLETION
*
*
*
*
EXIT-ERROR =
*
*
RETURN CODE = NONE
*
*
ABEND CODES = NONE
*
*
ERROR-MESSAGES = NONE
*
*
*
*
EXTERNAL REFERENCES =
*
*
ROUTINES/SERVICES =
*
*
DSN8BCU2 - ACTUAL UNLOAD PROGRAM
*
*
*
*
DATA-AREAS
=
NONE
*
*
CONTROL-BLOCKS
=
NONE
*
*
*
*
TABLES = NONE
*
*
CHANGE-ACTIVITY = NONE
*
*
*
* *PSEUDOCODE*
*
*
*
*
PROCEDURE
*
*
CALL DSN8BCU2.
*
*
END.
*
*---------------------------------------------------------------*
/
IDENTIFICATION DIVISION.
*----------------------PROGRAM-ID.
DSN8BCU1
*
ENVIRONMENT DIVISION.
*
CONFIGURATION SECTION.
DATA DIVISION.
*
WORKING-STORAGE SECTION.
*
01 WORKAREA-IND.
02 WORKIND PIC S9(4) COMP OCCURS 750 TIMES.
01 RECWORK.
02 RECWORK-LEN PIC S9(8) COMP VALUE 32700.
02 RECWORK-CHAR PIC X(1) OCCURS 32700 TIMES.
*
PROCEDURE DIVISION.
*
CALL ’DSN8BCU2’ USING WORKAREA-IND RECWORK.
GOBACK.

The following example is the called program that does pointer manipulation.
**** DSN8BCU2- DB2 SAMPLE BATCH COBOL UNLOAD PROGRAM
*
*
MODULE NAME = DSN8BCU2
*
*
DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION
*
UNLOAD PROGRAM
*
BATCH
*
ENTERPRISE COBOL FOR Z/OS
*
*

336

Application Programming and SQL Guide

***********
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

FUNCTION = THIS MODULE ACCEPTS A TABLE NAME OR VIEW NAME
AND UNLOADS THE DATA IN THAT TABLE OR VIEW.
READ IN A TABLE NAME FROM SYSIN.
PUT DATA FROM THE TABLE INTO DD SYSREC01.
WRITE RESULTS TO SYSPRINT.
NOTES =
DEPENDENCIES = NONE.
RESTRICTIONS =
THE SQLDA IS LIMITED TO 33016 BYTES.
THIS SIZE ALLOWS FOR THE DB2 MAXIMUM
OF 750 COLUMNS.
DATA RECORDS ARE LIMITED TO 32700 BYTES,
INCLUDING DATA, LENGTHS FOR VARCHAR DATA,
AND SPACE FOR NULL INDICATORS.
TABLE OR VIEW NAMES ARE ACCEPTED, AND ONLY
ONE NAME IS ALLOWED PER RUN.
MODULE TYPE = COBOL PROGRAM
PROCESSOR
= DB2 PRECOMPILER

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

*
*
*
*
*
ENTRY POINT = DSN8BCU2
*
PURPOSE = SEE FUNCTION
*
LINKAGE =
*
CALL ’DSN8BCU2’ USING WORKAREA-IND RECWORK.
*
*
INPUT
= SYMBOLIC LABEL/NAME = WORKAREA-IND
*
DESCRIPTION = INDICATOR VARIABLE ARRAY
*
01 WORKAREA-IND.
*
02 WORKIND PIC S9(4) COMP OCCURS 750 TIMES. *
*
SYMBOLIC LABEL/NAME = RECWORK
*
DESCRIPTION = WORK AREA FOR OUTPUT RECORD
*
01 RECWORK.
*
02 RECWORK-LEN PIC S9(8) COMP.
*
*
SYMBOLIC LABEL/NAME = SYSIN
*
DESCRIPTION = INPUT REQUESTS - TABLE OR VIEW
*
*
MODULE SIZE = SEE LINK EDIT
ATTRIBUTES = REENTRANT

OUTPUT

= SYMBOLIC LABEL/NAME = SYSPRINT
DESCRIPTION = PRINTED RESULTS

*
*
*
SYMBOLIC LABEL/NAME = SYSREC01
*
DESCRIPTION = UNLOADED TABLE DATA
*
*
EXIT-NORMAL = RETURN CODE 0 NORMAL COMPLETION
*
EXIT-ERROR =
*
RETURN CODE = NONE
*
ABEND CODES = NONE
*
ERROR-MESSAGES =
*
DSNT490I SAMPLE COBOL DATA UNLOAD PROGRAM RELEASE 3.0*
- THIS IS THE HEADER, INDICATING A NORMAL *
- START FOR THIS PROGRAM.
*
DSNT493I SQL ERROR, SQLCODE = NNNNNNNN
*
- AN SQL ERROR OR WARNING WAS ENCOUNTERED *
- ADDITIONAL INFORMATION FROM DSNTIAR
*
- FOLLOWS THIS MESSAGE.
*
DSNT495I SUCCESSFUL UNLOAD XXXXXXXX ROWS OF
*
TABLE TTTTTTTT
*
- THE UNLOAD WAS SUCCESSFUL. XXXXXXXX IS *
Chapter 3. Including DB2 queries in an application program

337
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

- THE NUMBER OF ROWS UNLOADED. TTTTTTTT
- IS THE NAME OF THE TABLE OR VIEW FROM
- WHICH IT WAS UNLOADED.
DSNT496I UNRECOGNIZED DATA TYPE CODE OF NNNNN
- THE PREPARE RETURNED AN INVALID DATA
- TYPE CODE. NNNNN IS THE CODE, PRINTED
- IN DECIMAL. USUALLY AN ERROR IN
- THIS ROUTINE OR A NEW DATA TYPE.
DSNT497I RETURN CODE FROM MESSAGE ROUTINE DSNTIAR
- THE MESSAGE FORMATTING ROUTINE DETECTED
- AN ERROR. SEE THAT ROUTINE FOR RETURN
- CODE INFORMATION. USUALLY AN ERROR IN
- THIS ROUTINE.
DSNT498I ERROR, NO VALID COLUMNS FOUND
- THE PREPARE RETURNED DATA WHICH DID NOT
- PRODUCE A VALID OUTPUT RECORD.
- USUALLY AN ERROR IN THIS ROUTINE.
DSNT499I NO ROWS FOUND IN TABLE OR VIEW
- THE CHOSEN TABLE OR VIEWS DID NOT
- RETURN ANY ROWS.
ERROR MESSAGES FROM MODULE DSNTIAR
- WHEN AN ERROR OCCURS, THIS MODULE
- PRODUCES CORRESPONDING MESSAGES.
EXTERNAL REFERENCES =
ROUTINES/SERVICES =
DSNTIAR - TRANSLATE SQLCA INTO MESSAGES
DATA-AREAS
=
NONE
CONTROL-BLOCKS
=
SQLCA
- SQL COMMUNICATION AREA
TABLES = NONE
CHANGE-ACTIVITY = NONE

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

* *PSEUDOCODE*
*
*
PROCEDURE
*
*
EXEC SQL DECLARE DT CURSOR FOR SEL END-EXEC.
*
*
EXEC SQL DECLARE SEL STATEMENT END-EXEC.
*
*
INITIALIZE THE DATA, OPEN FILES.
*
*
OBTAIN STORAGE FOR THE SQLDA AND THE DATA RECORDS.
*
*
READ A TABLE NAME.
*
*
OPEN SYSREC01.
*
*
BUILD THE SQL STATEMENT TO BE EXECUTED
*
*
EXEC SQL PREPARE SQL STATEMENT INTO SQLDA END-EXEC.
*
*
SET UP ADDRESSES IN THE SQLDA FOR DATA.
*
*
INITIALIZE DATA RECORD COUNTER TO 0.
*
*
EXEC SQL OPEN DT END-EXEC.
*
*
DO WHILE SQLCODE IS 0.
*
*
EXEC SQL FETCH DT USING DESCRIPTOR SQLDA END-EXEC.
*
*
ADD IN MARKERS TO DENOTE NULLS.
*
*
WRITE THE DATA TO SYSREC01.
*
*
INCREMENT DATA RECORD COUNTER.
*
*
END.
*
*
EXEC SQL CLOSE DT END-EXEC.
*
*
INDICATE THE RESULTS OF THE UNLOAD OPERATION.
*
*
CLOSE THE SYSIN, SYSPRINT, AND SYSREC01 FILES.
*
*
END.
*
*---------------------------------------------------------------*
/
IDENTIFICATION DIVISION.
*----------------------PROGRAM-ID.
DSN8BCU2
*
ENVIRONMENT DIVISION.
*-------------------CONFIGURATION SECTION.
INPUT-OUTPUT SECTION.

338

Application Programming and SQL Guide
FILE-CONTROL.
SELECT SYSIN
ASSIGN TO DA-S-SYSIN.
SELECT SYSPRINT
ASSIGN TO UT-S-SYSPRINT.
SELECT SYSREC01
ASSIGN TO DA-S-SYSREC01.
*
DATA DIVISION.
*------------*
FILE SECTION.
FD
SYSIN
RECORD CONTAINS 80 CHARACTERS
BLOCK CONTAINS 0 RECORDS
LABEL RECORDS ARE OMITTED
RECORDING MODE IS F.
01 CARDREC
PIC X(80).
*
FD SYSPRINT
RECORD CONTAINS 120 CHARACTERS
LABEL RECORDS ARE OMITTED
DATA RECORD IS MSGREC
RECORDING MODE IS F.
01 MSGREC
PIC X(120).
*
FD

01

SYSREC01
RECORD CONTAINS 5 TO 32704 CHARACTERS
LABEL RECORDS ARE OMITTED
DATA RECORD IS REC01
RECORDING MODE IS V.
REC01.
02 REC01-LEN PIC S9(8) COMP.
02 REC01-CHAR PIC X(1) OCCURS 1 TO 32700 TIMES
DEPENDING ON REC01-LEN.

/
WORKING-STORAGE SECTION.
*
*****************************************************
* STRUCTURE FOR INPUT
*
*****************************************************
01 IOAREA.
02 TNAME
PIC X(72).
02 FILLER
PIC X(08).
01 STMTBUF.
49 STMTLEN
PIC S9(4) COMP VALUE 92.
49 STMTCHAR
PIC X(92).
01 STMTBLD.
02 FILLER
PIC X(20) VALUE ’SELECT * FROM’.
02 STMTTAB
PIC X(72).
*
*****************************************************
* REPORT HEADER STRUCTURE
*
*****************************************************
01 HEADER.
02 FILLER PIC X(35)
VALUE ’ DSNT490I SAMPLE COBOL DATA UNLOAD ’.
02 FILLER PIC X(85) VALUE ’PROGRAM RELEASE 3.0’.
01 MSG-SQLERR.
02 FILLER PIC X(31)
VALUE ’ DSNT493I SQL ERROR, SQLCODE = ’.
02 MSG-MINUS
PIC X(1).
02 MSG-PRINT-CODE PIC 9(8).
02 FILLER PIC X(81) VALUE ’
’.
01 UNLOADED.
02 FILLER PIC X(28)
VALUE ’ DSNT495I SUCCESSFUL UNLOAD ’.
Chapter 3. Including DB2 queries in an application program

339
01

01

02 ROWS
PIC 9(8).
02 FILLER PIC X(15) VALUE ’ ROWS OF TABLE ’.
02 TABLENAM PIC X(72) VALUE ’
’.
BADTYPE.
02 FILLER PIC X(42)
VALUE ’ DSNT496I UNRECOGNIZED DATA TYPE CODE OF ’.
02 TYPCOD PIC 9(8).
02 FILLER PIC X(71) VALUE ’
’.
MSGRETCD.
02 FILLER PIC X(42)
VALUE ’ DSNT497I RETURN CODE FROM MESSAGE ROUTINE’.
02 FILLER PIC X(9) VALUE ’DSNTIAR ’.
02 RETCODE
PIC 9(8).
02 FILLER PIC X(62) VALUE ’
’.

01

MSGNOCOL.
02 FILLER PIC X(120)
VALUE ’ DSNT498I ERROR, NO VALID COLUMNS FOUND’.
01 MSG-NOROW.
02 FILLER PIC X(120)
VALUE ’ DSNT499I NO ROWS FOUND IN TABLE OR VIEW’.
*****************************************************
* WORKAREAS
*
*****************************************************
77 NOT-FOUND
PIC S9(8) COMP VALUE +100.
*****************************************************
* VARIABLES FOR ERROR-MESSAGE FORMATTING
*
00
*****************************************************
01 ERROR-MESSAGE.
02 ERROR-LEN
PIC S9(4) COMP VALUE +960.
02 ERROR-TEXT PIC X(120) OCCURS 8 TIMES
INDEXED BY ERROR-INDEX.
77 ERROR-TEXT-LEN
PIC S9(8) COMP VALUE +120.
*****************************************************
* SQL DESCRIPTOR AREA
*
*****************************************************
EXEC SQL INCLUDE SQLDA END-EXEC.
*
* DATA TYPES FOUND IN SQLTYPE, AFTER REMOVING THE NULL BIT
*
77 VARCTYPE
PIC S9(4) COMP VALUE +448.
77 CHARTYPE
PIC S9(4) COMP VALUE +452.
77 VARLTYPE
PIC S9(4) COMP VALUE +456.
77 VARGTYPE
PIC S9(4) COMP VALUE +464.
77 GTYPE
PIC S9(4) COMP VALUE +468.
77 LVARGTYP
PIC S9(4) COMP VALUE +472.
77 FLOATYPE
PIC S9(4) COMP VALUE +480.
77 DECTYPE
PIC S9(4) COMP VALUE +484.
77 INTTYPE
PIC S9(4) COMP VALUE +496.
77 HWTYPE
PIC S9(4) COMP VALUE +500.
77 DATETYP
PIC S9(4) COMP VALUE +384.
77 TIMETYP
PIC S9(4) COMP VALUE +388.
77 TIMESTMP
PIC S9(4) COMP VALUE +392.
*
*****************************************************
*
THE REDEFINES CLAUSES BELOW ARE FOR 31-BIT ADDRESSING.
*
IF YOUR COMPILER SUPPORTS ONLY 24-BIT ADDRESSING,
*
CHANGE THE DECLARATIONS TO THESE:
*
01 RECNUM REDEFINES RECPTR PICTURE S9(8) COMPUTATIONAL.
*
01 IRECNUM REDEFINES IRECPTR PICTURE S9(8) COMPUTATIONAL.
*****************************************************
01 RECPTR POINTER.
01 RECNUM REDEFINES RECPTR PICTURE S9(9) COMPUTATIONAL.
01 IRECPTR POINTER.
01 IRECNUM REDEFINES IRECPTR PICTURE S9(9) COMPUTATIONAL.
01 I
PICTURE S9(4) COMPUTATIONAL.

340

Application Programming and SQL Guide
01
01
01
01
01
01
01
01
01
01

J
PICTURE S9(4) COMPUTATIONAL.
DUMMY PICTURE S9(4) COMPUTATIONAL.
MYTYPE PICTURE S9(4) COMPUTATIONAL.
COLUMN-IND PICTURE S9(4) COMPUTATIONAL.
COLUMN-LEN PICTURE S9(4) COMPUTATIONAL.
COLUMN-PREC PICTURE S9(4) COMPUTATIONAL.
COLUMN-SCALE PICTURE S9(4) COMPUTATIONAL.
INDCOUNT
PIC S9(4) COMPUTATIONAL.
ROWCOUNT
PIC S9(4) COMPUTATIONAL.
WORKAREA2.
02 WORKINDPTR POINTER
OCCURS 750 TIMES.
*****************************************************
* DECLARE CURSOR AND STATEMENT FOR DYNAMIC SQL
*****************************************************
*
EXEC SQL DECLARE DT CURSOR FOR SEL END-EXEC.
EXEC SQL DECLARE SEL STATEMENT
END-EXEC.
*
*****************************************************
* SQL INCLUDE FOR SQLCA
*
*****************************************************
EXEC SQL INCLUDE SQLCA END-EXEC.
*
77 ONE
PIC S9(4) COMP VALUE +1.
77 TWO
PIC S9(4) COMP VALUE +2.
77 FOUR
PIC S9(4) COMP VALUE +4.
77 QMARK
PIC X(1)
VALUE ’?’.
*
LINKAGE SECTION.
01 LINKAREA-IND.
02 IND
PIC
S9(4) COMP OCCURS 750 TIMES.
01 LINKAREA-REC.
02 REC1-LEN PIC S9(8) COMP.
02 REC1-CHAR PIC X(1) OCCURS 1 TO 32700 TIMES
DEPENDING ON REC1-LEN.
01 LINKAREA-QMARK.
02 INDREC PIC
X(1).
/
PROCEDURE DIVISION USING LINKAREA-IND LINKAREA-REC.
*
*****************************************************
* SQL RETURN CODE HANDLING
*
*****************************************************
EXEC SQL WHENEVER SQLERROR
GOTO DBERROR END-EXEC.
EXEC SQL WHENEVER SQLWARNING GOTO DBERROR END-EXEC.
EXEC SQL WHENEVER NOT FOUND CONTINUE
END-EXEC.
*
*****************************************************
* MAIN PROGRAM ROUTINE
*
*****************************************************
SET IRECPTR TO ADDRESS OF REC1-CHAR(1).
*
**OPEN FILES
OPEN INPUT SYSIN
OUTPUT SYSPRINT
OUTPUT SYSREC01.
*
**WRITE HEADER
WRITE MSGREC FROM HEADER
AFTER ADVANCING 2 LINES.
*
**GET FIRST INPUT
READ SYSIN RECORD INTO IOAREA.
*
**MAIN ROUTINE
PERFORM PROCESS-INPUT THROUGH IND-RESULT.
*
PROG-END.
*
**CLOSE FILES
CLOSE SYSIN
SYSPRINT
Chapter 3. Including DB2 queries in an application program

341
SYSREC01.
GOBACK.
/
***************************************************************
*
*
*
PERFORMED SECTION:
*
*
PROCESSING FOR THE TABLE OR VIEW JUST READ
*
*
*
***************************************************************
PROCESS-INPUT.
*
MOVE TNAME TO STMTTAB.
MOVE STMTBLD TO STMTCHAR.
EXEC SQL PREPARE SEL INTO :SQLDA FROM :STMTBUF END-EXEC.
***************************************************************
*
*
*
SET UP ADDRESSES IN THE SQLDA FOR DATA.
*
*
*
***************************************************************
IF SQLD = ZERO THEN
WRITE MSGREC FROM MSGNOCOL
AFTER ADVANCING 2 LINES
GO TO IND-RESULT.
MOVE ZERO TO ROWCOUNT.
MOVE ZERO TO REC1-LEN.
SET RECPTR TO IRECPTR.
MOVE ONE TO I.
PERFORM COLADDR UNTIL I > SQLD.
****************************************************************
*
*
*
SET LENGTH OF OUTPUT RECORD.
*
*
EXEC SQL OPEN DT END-EXEC.
*
*
DO WHILE SQLCODE IS 0.
*
*
EXEC SQL FETCH DT USING DESCRIPTOR :SQLDA END-EXEC. *
*
ADD IN MARKERS TO DENOTE NULLS.
*
*
WRITE THE DATA TO SYSREC01.
*
*
INCREMENT DATA RECORD COUNTER.
*
*
END.
*
*
*
****************************************************************
*
**OPEN CURSOR
EXEC SQL OPEN DT END-EXEC.
PERFORM BLANK-REC.
EXEC SQL FETCH DT USING DESCRIPTOR :SQLDA END-EXEC.
*
**NO ROWS FOUND
*
**PRINT ERROR MESSAGE
IF SQLCODE = NOT-FOUND
WRITE MSGREC FROM MSG-NOROW
AFTER ADVANCING 2 LINES
ELSE
*
**WRITE ROW AND
*
**CONTINUE UNTIL
*
**NO MORE ROWS
PERFORM WRITE-AND-FETCH
UNTIL SQLCODE IS NOT EQUAL TO ZERO.
*
EXEC SQL WHENEVER NOT FOUND GOTO CLOSEDT
END-EXEC.
*
CLOSEDT.
EXEC SQL CLOSE DT END-EXEC.
*
****************************************************************
*
*
*
INDICATE THE RESULTS OF THE UNLOAD OPERATION.
*
*
*
****************************************************************
IND-RESULT.

342

Application Programming and SQL Guide
MOVE TNAME TO TABLENAM.
MOVE ROWCOUNT TO ROWS.
WRITE MSGREC FROM UNLOADED
AFTER ADVANCING 2 LINES.
GO TO PROG-END.
*
WRITE-AND-FETCH.
*
ADD IN MARKERS TO DENOTE NULLS.
MOVE ONE TO INDCOUNT.
PERFORM NULLCHK UNTIL INDCOUNT = SQLD.
MOVE REC1-LEN TO REC01-LEN.
WRITE REC01 FROM LINKAREA-REC.
ADD ONE TO ROWCOUNT.
PERFORM BLANK-REC.
EXEC SQL FETCH DT USING DESCRIPTOR :SQLDA END-EXEC.
*
NULLCHK.
IF IND(INDCOUNT) < 0 THEN
SET ADDRESS OF LINKAREA-QMARK TO WORKINDPTR(INDCOUNT)
MOVE QMARK TO INDREC.
ADD ONE TO INDCOUNT.
*****************************************************
*
BLANK OUT RECORD TEXT FIRST
*
*****************************************************
BLANK-REC.
MOVE ONE TO J.
PERFORM BLANK-MORE UNTIL J > REC1-LEN.
BLANK-MORE.
MOVE ’ ’ TO REC1-CHAR(J).
ADD ONE TO J.
*
COLADDR.
SET SQLDATA(I) TO RECPTR.
****************************************************************
*
*
DETERMINE THE LENGTH OF THIS COLUMN (COLUMN-LEN)
*
THIS DEPENDS ON THE DATA TYPE. MOST DATA TYPES HAVE
*
THE LENGTH SET, BUT VARCHAR, GRAPHIC, VARGRAPHIC, AND
*
DECIMAL DATA NEED TO HAVE THE BYTES CALCULATED.
*
THE NULL ATTRIBUTE MUST BE SEPARATED TO SIMPLIFY MATTERS.
*
****************************************************************
MOVE SQLLEN(I) TO COLUMN-LEN.
*
COLUMN-IND IS 0 FOR NO NULLS AND 1 FOR NULLS
DIVIDE SQLTYPE(I) BY TWO GIVING DUMMY REMAINDER COLUMN-IND.
*
MYTYPE IS JUST THE SQLTYPE WITHOUT THE NULL BIT
MOVE SQLTYPE(I) TO MYTYPE.
SUBTRACT COLUMN-IND FROM MYTYPE.
*
SET THE COLUMN LENGTH, DEPENDENT ON DATA TYPE
EVALUATE MYTYPE
WHEN
CHARTYPE CONTINUE,
WHEN
DATETYP
CONTINUE,
WHEN
TIMETYP
CONTINUE,
WHEN
TIMESTMP CONTINUE,
WHEN
FLOATYPE CONTINUE,
WHEN
VARCTYPE
ADD TWO TO COLUMN-LEN,
WHEN
VARLTYPE
ADD TWO TO COLUMN-LEN,
WHEN
GTYPE
MULTIPLY COLUMN-LEN BY TWO GIVING COLUMN-LEN,
WHEN
VARGTYPE
PERFORM CALC-VARG-LEN,
WHEN
LVARGTYP
PERFORM CALC-VARG-LEN,
WHEN
HWTYPE
MOVE TWO TO COLUMN-LEN,
Chapter 3. Including DB2 queries in an application program

343
WHEN

INTTYPE
MOVE FOUR TO COLUMN-LEN,
WHEN
DECTYPE
PERFORM CALC-DECIMAL-LEN,
WHEN
OTHER
PERFORM UNRECOGNIZED-ERROR,
END-EVALUATE.
ADD COLUMN-LEN TO RECNUM.
ADD COLUMN-LEN TO REC1-LEN.
****************************************************************
*
*
*
IF THIS COLUMN CAN BE NULL, AN INDICATOR VARIABLE IS
*
*
NEEDED. WE ALSO RESERVE SPACE IN THE OUTPUT RECORD TO
*
*
NOTE THAT THE VALUE IS NULL.
*
*
*
****************************************************************
MOVE ZERO TO IND(I).
IF COLUMN-IND = ONE THEN
SET SQLIND(I) TO ADDRESS OF IND(I)
SET WORKINDPTR(I) TO RECPTR
ADD ONE TO RECNUM
ADD ONE TO REC1-LEN.
*
ADD ONE TO I.
*
PERFORMED PARAGRAPH TO CALCULATE COLUMN LENGTH
*
FOR A DECIMAL DATA TYPE COLUMN
CALC-DECIMAL-LEN.
DIVIDE COLUMN-LEN BY 256 GIVING COLUMN-PREC
REMAINDER COLUMN-SCALE.
MOVE COLUMN-PREC TO COLUMN-LEN.
ADD ONE TO COLUMN-LEN.
DIVIDE COLUMN-LEN BY TWO GIVING COLUMN-LEN.
*
PERFORMED PARAGRAPH TO CALCULATE COLUMN LENGTH
*
FOR A VARGRAPHIC DATA TYPE COLUMN
CALC-VARG-LEN.
MULTIPLY COLUMN-LEN BY TWO GIVING COLUMN-LEN.
ADD TWO TO COLUMN-LEN.
*
PERFORMED PARAGRAPH TO NOTE AN UNRECOGNIZED
*
DATA TYPE COLUMN
UNRECOGNIZED-ERROR.
*
*
ERROR MESSAGE FOR UNRECOGNIZED DATA TYPE
*
MOVE SQLTYPE(I) TO TYPCOD.
WRITE MSGREC FROM BADTYPE
AFTER ADVANCING 2 LINES.
GO TO IND-RESULT.
*
*****************************************************
* SQL ERROR OCCURRED - GET MESSAGE
*
*****************************************************
DBERROR.
*
**SQL ERROR
MOVE SQLCODE TO MSG-PRINT-CODE.
IF SQLCODE < 0 THEN MOVE ’-’ TO MSG-MINUS.
WRITE MSGREC FROM MSG-SQLERR
AFTER ADVANCING 2 LINES.
CALL ’DSNTIAR’ USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN.
IF RETURN-CODE = ZERO
PERFORM ERROR-PRINT VARYING ERROR-INDEX
FROM 1 BY 1 UNTIL ERROR-INDEX GREATER THAN 8
ELSE
*
**ERROR FOUND IN DSNTIAR
*
**PRINT ERROR MESSAGE
MOVE RETURN-CODE TO RETCODE
WRITE MSGREC FROM MSGRETCD
AFTER ADVANCING 2 LINES.

344

Application Programming and SQL Guide
GO TO PROG-END.
*
*****************************************************
*
PRINT MESSAGE TEXT
*
*****************************************************
ERROR-PRINT.
WRITE MSGREC FROM ERROR-TEXT (ERROR-INDEX)
AFTER ADVANCING 1 LINE.

Sample COBOL program using DRDA access with CONNECT
statements
This example demonstrates how to access distributed data by using DRDA access
in a COBOL program.
The following figure contains a sample COBOL program that uses two-phase
commit and DRDA to access distributed data.
IDENTIFICATION DIVISION.
PROGRAM-ID. TWOPHASE.
AUTHOR.
REMARKS.
*****************************************************************
*
*
* MODULE NAME = TWOPHASE
*
*
*
* DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION USING
*
*
TWO PHASE COMMIT AND THE DRDA DISTRIBUTED *
*
ACCESS METHOD WITH CONNECT STATEMENTS
*
*
*
* COPYRIGHT = 5665-DB2 (C) COPYRIGHT IBM CORP 1982, 1989
*
* REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
*
*
*
* STATUS = VERSION 5
*
*
*
* FUNCTION = THIS MODULE DEMONSTRATES DISTRIBUTED DATA ACCESS
*
*
USING 2 PHASE COMMIT BY TRANSFERRING AN EMPLOYEE
*
*
FROM ONE LOCATION TO ANOTHER.
*
*
*
*
NOTE: THIS PROGRAM ASSUMES THE EXISTENCE OF THE
*
*
TABLE SYSADM.EMP AT LOCATIONS STLEC1 AND
*
*
STLEC2.
*
*
*
* MODULE TYPE = COBOL PROGRAM
*
*
PROCESSOR
= DB2 PRECOMPILER, ENTERPRISE COBOL FOR Z/OS
*
*
MODULE SIZE = SEE LINK EDIT
*
*
ATTRIBUTES = NOT REENTRANT OR REUSABLE
*
*
*
* ENTRY POINT =
*
*
PURPOSE = TO ILLUSTRATE 2 PHASE COMMIT
*
*
LINKAGE = INVOKE FROM DSN RUN
*
*
INPUT
= NONE
*
*
OUTPUT =
*
*
SYMBOLIC LABEL/NAME = SYSPRINT
*
*
DESCRIPTION = PRINT OUT THE DESCRIPTION OF EACH *
*
STEP AND THE RESULTANT SQLCA
*
*
*
* EXIT NORMAL = RETURN CODE 0 FROM NORMAL COMPLETION
*
*
*
* EXIT ERROR = NONE
*
*
*
* EXTERNAL REFERENCES =
*
*
ROUTINE SERVICES = NONE
*
*
DATA-AREAS
= NONE
*
*
CONTROL-BLOCKS
=
*
*
SQLCA
SQL COMMUNICATION AREA
*
Chapter 3. Including DB2 queries in an application program

345
*
* TABLES = NONE
*
* CHANGE-ACTIVITY = NONE
*
*
*
* PSEUDOCODE
*
*
MAINLINE.
*
Perform CONNECT-TO-SITE-1 to establish
*
a connection to the local connection.
*
If the previous operation was successful Then
*
Do.
*
| Perform PROCESS-CURSOR-SITE-1 to obtain the
*
| information about an employee that is
*
| transferring to another location.
*
| If the information about the employee was obtained
*
| successfully Then
*
| Do.
*
| | Perform UPDATE-ADDRESS to update the information
*
| |
to contain current information about the
*
| |
employee.
*
| | Perform CONNECT-TO-SITE-2 to establish
*
| |
a connection to the site where the employee is
*
| |
transferring to.
*
| |
If the connection is established successfully
*
| |
Then
*
| |
Do.
*
| |
| Perform PROCESS-SITE-2 to insert the
*
| |
|
employee information at the location
*
| |
|
where the employee is transferring to.
*
| |
End if the connection was established
*
| |
successfully.
*
| End if the employee information was obtained
*
|
successfully.
*
End if the previous operation was successful.
*
Perform COMMIT-WORK to COMMIT the changes made to STLEC1
*
and STLEC2.
*
*
PROG-END.
*
Close the printer.
*
Return.
*
*
CONNECT-TO-SITE-1.
*
Provide a text description of the following step.
*
Establish a connection to the location where the
*
employee is transferring from.
*
Print the SQLCA out.
*
*
PROCESS-CURSOR-SITE-1.
*
Provide a text description of the following step.
*
Open a cursor that will be used to retrieve information
*
about the transferring employee from this site.
*
Print the SQLCA out.
*
If the cursor was opened successfully Then
*
Do.
*
| Perform FETCH-DELETE-SITE-1 to retrieve and
*
| delete the information about the transferring
*
| employee from this site.
*
| Perform CLOSE-CURSOR-SITE-1 to close the cursor.
*
End if the cursor was opened successfully.
*

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

*
*
*

346

*
*
*
*
*
*
*

*
*
*

FETCH-DELETE-SITE-1.
Provide a text description of the following step.
Fetch information about the transferring employee.

Application Programming and SQL Guide
*
Print the SQLCA out.
*
*
If the information was retrieved successfully Then
*
*
Do.
*
*
| Perform DELETE-SITE-1 to delete the employee
*
*
| at this site.
*
*
End if the information was retrieved successfully.
*
*
*
*
DELETE-SITE-1.
*
*
Provide a text description of the following step.
*
*
Delete the information about the transferring employee
*
*
from this site.
*
*
Print the SQLCA out.
*
*
*
*
CLOSE-CURSOR-SITE-1.
*
*
Provide a text description of the following step.
*
*
Close the cursor used to retrieve information about
*
*
the transferring employee.
*
*
Print the SQLCA out.
*
*
*
*
UPDATE-ADDRESS.
*
*
Update the address of the employee.
*
*
Update the city of the employee.
*
*
Update the location of the employee.
*
*
*
*
CONNECT-TO-SITE-2.
*
*
Provide a text description of the following step.
*
*
Establish a connection to the location where the
*
*
employee is transferring to.
*
*
Print the SQLCA out.
*
*
*
*
PROCESS-SITE-2.
*
*
Provide a text description of the following step.
*
*
Insert the employee information at the location where
*
*
the employee is being transferred to.
*
*
Print the SQLCA out.
*
*
*
*
COMMIT-WORK.
*
*
COMMIT all the changes made to STLEC1 and STLEC2.
*
*
*
*****************************************************************
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT PRINTER, ASSIGN TO S-OUT1.
DATA DIVISION.
FILE SECTION.
FD PRINTER
RECORD CONTAINS 120 CHARACTERS
DATA RECORD IS PRT-TC-RESULTS
LABEL RECORD IS OMITTED.
01 PRT-TC-RESULTS.
03 PRT-BLANK
PIC X(120).
WORKING-STORAGE SECTION.
*****************************************************************
* Variable declarations
*
*****************************************************************
01

H-EMPTBL.
05 H-EMPNO
PIC X(6).
05 H-NAME.
49 H-NAME-LN
PIC S9(4) COMP-4.
49 H-NAME-DA
PIC X(32).
05 H-ADDRESS.
Chapter 3. Including DB2 queries in an application program

347
05
05
05
05
05
05
05
05
05
05
05
05
01

49 H-ADDRESS-LN
PIC S9(4) COMP-4.
49 H-ADDRESS-DA
PIC X(36).
H-CITY.
49 H-CITY-LN
PIC S9(4) COMP-4.
49 H-CITY-DA
PIC X(36).
H-EMPLOC
PIC X(4).
H-SSNO
PIC X(11).
H-BORN
PIC X(10).
H-SEX
PIC X(1).
H-HIRED
PIC X(10).
H-DEPTNO
PIC X(3).
H-JOBCODE PIC S9(3)V COMP-3.
H-SRATE
PIC S9(5) COMP.
H-EDUC
PIC S9(5) COMP.
H-SAL
PIC S9(6)V9(2) COMP-3.
H-VALIDCHK PIC S9(6)V COMP-3.

H-EMPTBL-IND-TABLE.
02 H-EMPTBL-IND

PIC S9(4) COMP OCCURS 15 TIMES.

*****************************************************************
* Includes for the variables used in the COBOL standard
*
* language procedures and the SQLCA.
*
*****************************************************************
EXEC SQL INCLUDE COBSVAR END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
*****************************************************************
* Declaration for the table that contains employee information *
*****************************************************************
EXEC SQL DECLARE SYSADM.EMP TABLE
(EMPNO
CHAR(6) NOT NULL,
NAME
VARCHAR(32),
ADDRESS VARCHAR(36) ,
CITY
VARCHAR(36) ,
EMPLOC CHAR(4) NOT NULL,
SSNO
CHAR(11),
BORN
DATE,
SEX
CHAR(1),
HIRED
CHAR(10),
DEPTNO CHAR(3) NOT NULL,
JOBCODE DECIMAL(3),
SRATE
SMALLINT,
EDUC
SMALLINT,
SAL
VALCHK
END-EXEC.

DECIMAL(8,2) NOT NULL,
DECIMAL(6))

*****************************************************************
* Constants
*
*****************************************************************
77
77
77
77
77

SITE-1
SITE-2
TEMP-EMPNO
TEMP-ADDRESS-LN
TEMP-CITY-LN

PIC
PIC
PIC
PIC
PIC

X(16)
X(16)
X(6)
99
99

VALUE
VALUE
VALUE
VALUE
VALUE

’STLEC1’.
’STLEC2’.
’080000’.
15.
18.

*****************************************************************
* Declaration of the cursor that will be used to retrieve
*
* information about a transferring employee
*
*****************************************************************
EXEC SQL DECLARE C1 CURSOR FOR
SELECT EMPNO, NAME, ADDRESS, CITY, EMPLOC,

348

Application Programming and SQL Guide
SSNO, BORN, SEX, HIRED, DEPTNO, JOBCODE,
SRATE, EDUC, SAL, VALCHK
FROM
SYSADM.EMP
WHERE EMPNO = :TEMP-EMPNO
END-EXEC.
PROCEDURE DIVISION.
A101-HOUSE-KEEPING.
OPEN OUTPUT PRINTER.
*****************************************************************
* An employee is transferring from location STLEC1 to STLEC2.
*
* Retrieve information about the employee from STLEC1, delete
*
* the employee from STLEC1 and insert the employee at STLEC2
*
* using the information obtained from STLEC1.
*
*****************************************************************
MAINLINE.
PERFORM CONNECT-TO-SITE-1
IF SQLCODE IS EQUAL TO 0
PERFORM PROCESS-CURSOR-SITE-1
IF SQLCODE IS EQUAL TO 0
PERFORM UPDATE-ADDRESS
PERFORM CONNECT-TO-SITE-2
IF SQLCODE IS EQUAL TO 0
PERFORM PROCESS-SITE-2.
PERFORM COMMIT-WORK.
PROG-END.
CLOSE PRINTER.
GOBACK.
*****************************************************************
* Establish a connection to STLEC1
*
*****************************************************************
CONNECT-TO-SITE-1.
MOVE ’CONNECT TO STLEC1
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
CONNECT TO :SITE-1
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* When a connection has been established successfully at STLEC1,*
* open the cursor that will be used to retrieve information
*
* about the transferring employee.
*
*****************************************************************
PROCESS-CURSOR-SITE-1.
MOVE ’OPEN CURSOR C1
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
OPEN C1
END-EXEC.
PERFORM PTSQLCA.
IF SQLCODE IS EQUAL TO ZERO
PERFORM FETCH-DELETE-SITE-1
PERFORM CLOSE-CURSOR-SITE-1.
*****************************************************************
* Retrieve information about the transferring employee.
*
* Provided that the employee exists, perform DELETE-SITE-1 to
*
* delete the employee from STLEC1.
*
*****************************************************************
Chapter 3. Including DB2 queries in an application program

349
FETCH-DELETE-SITE-1.
MOVE ’FETCH C1
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
FETCH C1 INTO :H-EMPTBL:H-EMPTBL-IND
END-EXEC.
PERFORM PTSQLCA.
IF SQLCODE IS EQUAL TO ZERO
PERFORM DELETE-SITE-1.
*****************************************************************
* Delete the employee from STLEC1.
*
*****************************************************************
DELETE-SITE-1.
MOVE ’DELETE EMPLOYEE ’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
MOVE ’DELETE EMPLOYEE
’ TO STNAME
EXEC SQL
DELETE FROM SYSADM.EMP
WHERE EMPNO = :TEMP-EMPNO
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* Close the cursor used to retrieve information about the
*
* transferring employee.
*
*****************************************************************
CLOSE-CURSOR-SITE-1.
MOVE ’CLOSE CURSOR C1
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
CLOSE C1
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* Update certain employee information in order to make it
*
* current.
*
*****************************************************************
UPDATE-ADDRESS.
MOVE TEMP-ADDRESS-LN
MOVE ’1500 NEW STREET’
MOVE TEMP-CITY-LN
MOVE ’NEW CITY, CA 97804’
MOVE ’SJCA’

TO
TO
TO
TO
TO

H-ADDRESS-LN.
H-ADDRESS-DA.
H-CITY-LN.
H-CITY-DA.
H-EMPLOC.

*****************************************************************
* Establish a connection to STLEC2
*
*****************************************************************
CONNECT-TO-SITE-2.
MOVE ’CONNECT TO STLEC2
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
CONNECT TO :SITE-2
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* Using the employee information that was retrieved from STLEC1 *
* and updated previously, insert the employee at STLEC2.

350

Application Programming and SQL Guide

*
*****************************************************************
PROCESS-SITE-2.
MOVE ’INSERT EMPLOYEE
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
INSERT INTO SYSADM.EMP VALUES
(:H-EMPNO,
:H-NAME,
:H-ADDRESS,
:H-CITY,
:H-EMPLOC,
:H-SSNO,
:H-BORN,
:H-SEX,
:H-HIRED,
:H-DEPTNO,
:H-JOBCODE,
:H-SRATE,
:H-EDUC,
:H-SAL,
:H-VALIDCHK)
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* COMMIT any changes that were made at STLEC1 and STLEC2.
*
*****************************************************************
COMMIT-WORK.
MOVE ’COMMIT WORK
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
COMMIT
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* Include COBOL standard language procedures
*
*****************************************************************
INCLUDE-SUBS.
EXEC SQL INCLUDE COBSSUB END-EXEC.

Sample COBOL program using private protocol access
This example demonstrates how to access distributed data by using DB2 private
protocol access in a COBOL program
The following sample program demonstrates distributed access data using DB2
private protocol access with two-phase commit.
IDENTIFICATION DIVISION.
PROGRAM-ID. TWOPHASE.
AUTHOR.
REMARKS.
*****************************************************************
*
*
* MODULE NAME = TWOPHASE
*
*
*
* DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION USING
*
*
TWO PHASE COMMIT AND DRDA WITH
*
*
THREE-PART NAMES
*
*
*
* COPYRIGHT = 5665-DB2 (C) COPYRIGHT IBM CORP 1982, 1989
*
Chapter 3. Including DB2 queries in an application program

351
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083

*
*
STATUS = VERSION 5
*
*
FUNCTION = THIS MODULE DEMONSTRATES DISTRIBUTED DATA ACCESS
*
USING 2 PHASE COMMIT BY TRANSFERRING AN EMPLOYEE
*
FROM ONE LOCATION TO ANOTHER.
*
*
NOTE: THIS PROGRAM ASSUMES THE EXISTENCE OF THE
*
TABLE SYSADM.EMP AT LOCATIONS STLEC1 AND
*
STLEC2.
*
*
MODULE TYPE = COBOL PROGRAM
*
PROCESSOR
= DB2 PRECOMPILER, ENTERPRISE COBOL FOR Z/OS
*
MODULE SIZE = SEE LINK EDIT
*
ATTRIBUTES = NOT REENTRANT OR REUSABLE
*
*
ENTRY POINT =
*
PURPOSE = TO ILLUSTRATE 2 PHASE COMMIT
*
LINKAGE = INVOKE FROM DSN RUN
*
INPUT
= NONE
*
OUTPUT =
*
SYMBOLIC LABEL/NAME = SYSPRINT
*
DESCRIPTION = PRINT OUT THE DESCRIPTION OF EACH *
STEP AND THE RESULTANT SQLCA
*
*
EXIT NORMAL = RETURN CODE 0 FROM NORMAL COMPLETION
*
*
EXIT ERROR = NONE
*
*
EXTERNAL REFERENCES =
*
ROUTINE SERVICES = NONE
*
DATA-AREAS
= NONE
*
CONTROL-BLOCKS
=
*
SQLCA
SQL COMMUNICATION AREA
*
*
TABLES = NONE
*
*
CHANGE-ACTIVITY = NONE
*
*
*

*
* PSEUDOCODE
*
*
MAINLINE.
*
Perform PROCESS-CURSOR-SITE-1 to obtain the information
*
about an employee that is transferring to another
*
location.
*
If the information about the employee was obtained
*
successfully Then
*
Do.
*
| Perform UPDATE-ADDRESS to update the information to
*
| contain current information about the employee.
*
| Perform PROCESS-SITE-2 to insert the employee
*
| information at the location where the employee is
*
| transferring to.
*
End if the employee information was obtained
*
successfully.
*
Perform COMMIT-WORK to COMMIT the changes made to STLEC1
*
and STLEC2.
*
*
PROG-END.
*
Close the printer.
*
Return.
*
*
PROCESS-CURSOR-SITE-1.
*
Provide a text description of the following step.

352

Application Programming and SQL Guide

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

Open a cursor that will be used to retrieve information
about the transferring employee from this site.
Print the SQLCA out.
If the cursor was opened successfully Then
Do.
| Perform FETCH-DELETE-SITE-1 to retrieve and
| delete the information about the transferring
| employee from this site.
| Perform CLOSE-CURSOR-SITE-1 to close the cursor.
End if the cursor was opened successfully.
FETCH-DELETE-SITE-1.
Provide a text description of the following step.
Fetch information about the transferring employee.
Print the SQLCA out.
If the information was retrieved successfully Then
Do.
| Perform DELETE-SITE-1 to delete the employee
| at this site.
End if the information was retrieved successfully.
DELETE-SITE-1.
Provide a text description of the following step.
Delete the information about the transferring employee
from this site.
Print the SQLCA out.
CLOSE-CURSOR-SITE-1.
Provide a text description of the following step.
Close the cursor used to retrieve information about
the transferring employee.
Print the SQLCA out.

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

*
UPDATE-ADDRESS.
*
*
Update the address of the employee.
*
*
Update the city of the employee.
*
*
Update the location of the employee.
*
*
*
*
PROCESS-SITE-2.
*
*
Provide a text description of the following step.
*
*
Insert the employee information at the location where
*
*
the employee is being transferred to.
*
*
Print the SQLCA out.
*
*
*
*
COMMIT-WORK.
*
*
COMMIT all the changes made to STLEC1 and STLEC2.
*
*
*
*****************************************************************
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT PRINTER, ASSIGN TO S-OUT1.
DATA DIVISION.
FILE SECTION.
FD PRINTER
RECORD CONTAINS 120 CHARACTERS
DATA RECORD IS PRT-TC-RESULTS
LABEL RECORD IS OMITTED.
01 PRT-TC-RESULTS.
03 PRT-BLANK
PIC X(120).
WORKING-STORAGE SECTION.
*****************************************************************
Chapter 3. Including DB2 queries in an application program

353
* Variable declarations
*
*****************************************************************
01

H-EMPTBL.
05 H-EMPNO
PIC X(6).
05 H-NAME.
49 H-NAME-LN
PIC S9(4) COMP-4.
49 H-NAME-DA
PIC X(32).
05 H-ADDRESS.
49 H-ADDRESS-LN
PIC S9(4) COMP-4.
49 H-ADDRESS-DA
PIC X(36).
05 H-CITY.
49 H-CITY-LN
PIC S9(4) COMP-4.
49 H-CITY-DA
PIC X(36).
05 H-EMPLOC
PIC X(4).
05 H-SSNO
PIC X(11).
05 H-BORN
PIC X(10).
05 H-SEX
PIC X(1).
05 H-HIRED
PIC X(10).
05 H-DEPTNO
PIC X(3).
05 H-JOBCODE PIC S9(3)V COMP-3.
05 H-SRATE
PIC S9(5) COMP.
05 H-EDUC
PIC S9(5) COMP.
05 H-SAL
PIC S9(6)V9(2) COMP-3.
05 H-VALIDCHK PIC S9(6)V COMP-3.

01

H-EMPTBL-IND-TABLE.
02 H-EMPTBL-IND

PIC S9(4) COMP OCCURS 15 TIMES.

*****************************************************************
* Includes for the variables used in the COBOL standard
*
* language procedures and the SQLCA.
*
*****************************************************************
EXEC SQL INCLUDE COBSVAR END-EXEC.
EXEC SQL INCLUDE SQLCA END-EXEC.
*****************************************************************
* Declaration for the table that contains employee information *
*****************************************************************
EXEC SQL DECLARE SYSADM.EMP TABLE
(EMPNO
CHAR(6) NOT NULL,
NAME
VARCHAR(32),
ADDRESS VARCHAR(36) ,
CITY
VARCHAR(36) ,
EMPLOC CHAR(4) NOT NULL,
SSNO
CHAR(11),
BORN
DATE,
SEX
CHAR(1),
HIRED
CHAR(10),
DEPTNO CHAR(3) NOT NULL,
JOBCODE DECIMAL(3),
SRATE
SMALLINT,
EDUC
SMALLINT,
SAL
DECIMAL(8,2) NOT NULL,
VALCHK DECIMAL(6))
END-EXEC.
*****************************************************************
* Constants
*
*****************************************************************
77
77
77

354

TEMP-EMPNO
TEMP-ADDRESS-LN
TEMP-CITY-LN

Application Programming and SQL Guide

PIC X(6)
PIC 99
PIC 99

VALUE ’080000’.
VALUE 15.
VALUE 18.
*****************************************************************
* Declaration of the cursor that will be used to retrieve
*
* information about a transferring employee
*
*****************************************************************
EXEC SQL DECLARE C1 CURSOR FOR
SELECT EMPNO, NAME, ADDRESS, CITY, EMPLOC,
SSNO, BORN, SEX, HIRED, DEPTNO, JOBCODE,
SRATE, EDUC, SAL, VALCHK
FROM
STLEC1.SYSADM.EMP
WHERE EMPNO = :TEMP-EMPNO
END-EXEC.
PROCEDURE DIVISION.
A101-HOUSE-KEEPING.
OPEN OUTPUT PRINTER.
*****************************************************************
* An employee is transferring from location STLEC1 to STLEC2.
*
* Retrieve information about the employee from STLEC1, delete
*
* the employee from STLEC1 and insert the employee at STLEC2
*
* using the information obtained from STLEC1.
*
*****************************************************************
MAINLINE.
PERFORM PROCESS-CURSOR-SITE-1
IF SQLCODE IS EQUAL TO 0
PERFORM UPDATE-ADDRESS
PERFORM PROCESS-SITE-2.
PERFORM COMMIT-WORK.
PROG-END.
CLOSE PRINTER.
GOBACK.
*****************************************************************
* Open the cursor that will be used to retrieve information
*
* about the transferring employee.
*
*****************************************************************
PROCESS-CURSOR-SITE-1.
MOVE ’OPEN CURSOR C1
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
OPEN C1
END-EXEC.
PERFORM PTSQLCA.
IF SQLCODE IS EQUAL TO ZERO
PERFORM FETCH-DELETE-SITE-1
PERFORM CLOSE-CURSOR-SITE-1.
*****************************************************************
* Retrieve information about the transferring employee.
*
* Provided that the employee exists, perform DELETE-SITE-1 to
*
* delete the employee from STLEC1.
*
*****************************************************************
FETCH-DELETE-SITE-1.
MOVE ’FETCH C1
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
FETCH C1 INTO :H-EMPTBL:H-EMPTBL-IND
END-EXEC.

Chapter 3. Including DB2 queries in an application program

355
PERFORM PTSQLCA.
IF SQLCODE IS EQUAL TO ZERO
PERFORM DELETE-SITE-1.
*****************************************************************
* Delete the employee from STLEC1.
*
*****************************************************************
DELETE-SITE-1.
MOVE ’DELETE EMPLOYEE ’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
MOVE ’DELETE EMPLOYEE
’ TO STNAME
EXEC SQL
DELETE FROM STLEC1.SYSADM.EMP
WHERE EMPNO = :TEMP-EMPNO
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* Close the cursor used to retrieve information about the
*
* transferring employee.
*
*****************************************************************
CLOSE-CURSOR-SITE-1.
MOVE ’CLOSE CURSOR C1
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
CLOSE C1
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* Update certain employee information in order to make it
*
* current.
*
*****************************************************************
UPDATE-ADDRESS.
MOVE TEMP-ADDRESS-LN
TO H-ADDRESS-LN.
MOVE ’1500 NEW STREET’
TO H-ADDRESS-DA.
MOVE TEMP-CITY-LN
TO H-CITY-LN.
MOVE ’NEW CITY, CA 97804’ TO H-CITY-DA.
MOVE ’SJCA’
TO H-EMPLOC.
*****************************************************************
* Using the employee information that was retrieved from STLEC1 *
* and updated previously, insert the employee at STLEC2.
*****************************************************************
PROCESS-SITE-2.
MOVE ’INSERT EMPLOYEE
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
INSERT INTO STLEC2.SYSADM.EMP VALUES
(:H-EMPNO,
:H-NAME,
:H-ADDRESS,
:H-CITY,
:H-EMPLOC,
:H-SSNO,
:H-BORN,
:H-SEX,
:H-HIRED,
:H-DEPTNO,
:H-JOBCODE,
:H-SRATE,

356

Application Programming and SQL Guide

*
:H-EDUC,
:H-SAL,
:H-VALIDCHK)
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* COMMIT any changes that were made at STLEC1 and STLEC2.
*
*****************************************************************
COMMIT-WORK.
MOVE ’COMMIT WORK
’ TO STNAME
WRITE PRT-TC-RESULTS FROM STNAME
EXEC SQL
COMMIT
END-EXEC.
PERFORM PTSQLCA.
*****************************************************************
* Include COBOL standard language procedures
*
*****************************************************************
INCLUDE-SUBS.
EXEC SQL INCLUDE COBSSUB END-EXEC.

Sample DB2 REXX application
This example REXX application accepts a table name as input and produces a
SELECT, INSERT, or UPDATE SQL statement or a LOAD utility statement for the
specified table as output.
The following example shows a complete DB2 REXX application named DRAW.
DRAW must be invoked from the command line of an ISPF edit session. DRAW
takes a table or view name as input and produces a SELECT, INSERT, or UPDATE
SQL statement or a LOAD utility control statement that includes the columns of
the table as output.

DRAW syntax:
%DRAW object-name (
SSID=ssid
TYPE=

SELECT
INSERT
UPDATE
LOAD

DRAW parameters:
object-name
The name of the table or view for which DRAW builds an SQL statement or
utility control statement. The name can be a one-, two-, or three-part name.
The table or view to which object-name refers must exist before DRAW can run.
object-name is a required parameter.
SSID=ssid
Specifies the name of the local DB2 subsystem.
S can be used as an abbreviation for SSID.
Chapter 3. Including DB2 queries in an application program

357
If you invoke DRAW from the command line of the edit session in SPUFI,
SSID=ssid is an optional parameter. DRAW uses the subsystem ID from the
DB2I Defaults panel.
TYPE=operation-type
The type of statement that DRAW builds.
T can be used as an abbreviation for TYPE.
operation-type has one of the following values:
SELECT
Builds a SELECT statement in which the result table contains all
columns of object-name.
S can be used as an abbreviation for SELECT.
INSERT
Builds a template for an INSERT statement that inserts values into all
columns of object-name. The template contains comments that indicate
where the user can place column values.
I can be used as an abbreviation for INSERT.
UPDATE
Builds a template for an UPDATE statement that updates columns of
object-name. The template contains comments that indicate where the
user can place column values and qualify the update operation for
selected rows.
U can be used as an abbreviation for UPDATE.
LOAD
Builds a template for a LOAD utility control statement for object-name.
L can be used as an abbreviation for LOAD.
TYPE=operation-type is an optional parameter. The default is TYPE=SELECT.
DRAW data sets:
Edit data set
The data set from which you issue the DRAW command when you are in an
ISPF edit session. If you issue the DRAW command from a SPUFI session, this
data set is the data set that you specify in field 1 of the main SPUFI panel
(DSNESP01). The output from the DRAW command goes into this data set.
DRAW return codes:
Return code
Meaning
0

Successful completion.

12

An error occurred when DRAW edited the input file.

20

One of the following errors occurred:
v No input parameters were specified.
v One of the input parameters was not valid.
v An SQL error occurred when the output statement was generated.

Examples of DRAW invocation:

358

Application Programming and SQL Guide
Generate a SELECT statement for table DSN8910.EMP at the local subsystem. Use
the default DB2I subsystem ID.
The DRAW invocation is:
DRAW DSN8910.EMP (TYPE=SELECT

The output is:
SELECT "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" ,
"PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" ,
"SALARY" , "BONUS" , "COMM"
FROM DSN8910.EMP

Generate a template for an INSERT statement that inserts values into table
DSN8910.EMP at location SAN_JOSE. The local subsystem ID is DSN.
The DRAW invocation is:
DRAW SAN_JOSE.DSN8910.EMP (TYPE=INSERT SSID=DSN

The output is:
INSERT INTO SAN_JOSE.DSN8910.EMP ( "EMPNO" , "FIRSTNME" , "MIDINIT" ,
"LASTNAME" , "WORKDEPT" , "PHONENO" , "HIREDATE" , "JOB" ,
"EDLEVEL" , "SEX" , "BIRTHDATE" , "SALARY" , "BONUS" , "COMM" )
VALUES (
-- ENTER VALUES BELOW
COLUMN NAME
DATA TYPE
, -- EMPNO
CHAR(6) NOT NULL
, -- FIRSTNME
VARCHAR(12) NOT NULL
, -- MIDINIT
CHAR(1) NOT NULL
, -- LASTNAME
VARCHAR(15) NOT NULL
, -- WORKDEPT
CHAR(3)
, -- PHONENO
CHAR(4)
, -- HIREDATE
DATE
, -- JOB
CHAR(8)
, -- EDLEVEL
SMALLINT
, -- SEX
CHAR(1)
, -- BIRTHDATE
DATE
, -- SALARY
DECIMAL(9,2)
, -- BONUS
DECIMAL(9,2)
) -- COMM
DECIMAL(9,2)

Generate a template for an UPDATE statement that updates values of table
DSN8910.EMP. The local subsystem ID is DSN.
The DRAW invocation is:
DRAW DSN8910.EMP (TYPE=UPDATE SSID=DSN

The output is:
UPDATE DSN8910.EMP
-- COLUMN NAME
"EMPNO"=
, "FIRSTNME"=
, "MIDINIT"=
, "LASTNAME"=
, "WORKDEPT"=
, "PHONENO"=
, "HIREDATE"=
, "JOB"=
, "EDLEVEL"=
, "SEX"=
, "BIRTHDATE"=

SET
ENTER VALUES BELOW
------------

DATA TYPE
CHAR(6) NOT
VARCHAR(12)
CHAR(1) NOT
VARCHAR(15)
CHAR(3)
CHAR(4)
DATE
CHAR(8)
SMALLINT
CHAR(1)
DATE

NULL
NOT NULL
NULL
NOT NULL

Chapter 3. Including DB2 queries in an application program

359
, "SALARY"=
, "BONUS"=
, "COMM"=
WHERE

-- DECIMAL(9,2)
-- DECIMAL(9,2)
-- DECIMAL(9,2)

Generate a LOAD control statement to load values into table DSN8910.EMP. The
local subsystem ID is DSN.
The draw invocation is:
DRAW DSN8910.EMP (TYPE=LOAD SSID=DSN

The output is:
LOAD DATA INDDN SYSREC INTO TABLE DSN8910.EMP
( "EMPNO"
POSITION(
1) CHAR(6)
, "FIRSTNME"
POSITION(
8) VARCHAR
, "MIDINIT"
POSITION(
21) CHAR(1)
, "LASTNAME"
POSITION(
23) VARCHAR
, "WORKDEPT"
POSITION(
39) CHAR(3)
NULLIF(
39)=’?’
, "PHONENO"
POSITION(
43) CHAR(4)
NULLIF(
43)=’?’
, "HIREDATE"
POSITION(
48) DATE EXTERNAL
NULLIF(
48)=’?’
, "JOB"
POSITION(
59) CHAR(8)
NULLIF(
59)=’?’
, "EDLEVEL"
POSITION(
68) SMALLINT
NULLIF(
68)=’?’
, "SEX"
POSITION(
71) CHAR(1)
NULLIF(
71)=’?’
, "BIRTHDATE"
POSITION(
73) DATE EXTERNAL
NULLIF(
73)=’?’
, "SALARY"
POSITION(
84) DECIMAL EXTERNAL(9,2)
NULLIF(
84)=’?’
, "BONUS"
POSITION(
90) DECIMAL EXTERNAL(9,2)
NULLIF(
90)=’?’
, "COMM"
POSITION(
96) DECIMAL EXTERNAL(9,2)
NULLIF(
96)=’?’
)

DRAW source code:
/* REXX ***************************************************************/
L1 = WHEREAMI()
/*
DRAW creates basic SQL queries by retrieving the description of a
table. You must specify the name of the table or view to be queried.
You can specify the type of query you want to compose. You might need
to specify the name of the DB2 subsystem.
>>--DRAW-----tablename-----|---------------------------|-------><
|-(-|-Ssid=subsystem-name-|-|
|
+-Select-+
|
|-Type=-|-Insert-|----|
|-Update-|
+--Load--+
Ssid=subsystem-name
subsystem-name specified the name of a DB2 subsystem.
Select
Composes a basic query for selecting data from the columns of a
table or view. If TYPE is not specified, SELECT is assumed.
Using SELECT with the DRAW command produces a query that would
retrieve all rows and all columns from the specified table. You
can then modify the query as needed.
A SELECT query of EMP composed by DRAW looks like this:
SELECT "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" ,
"PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" ,

360

Application Programming and SQL Guide
"SALARY" , "BONUS" , "COMM"
FROM DSN8910.EMP
If you include a location qualifier, the query looks like this:
SELECT "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" ,
"PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" ,
"SALARY" , "BONUS" , "COMM"
FROM STLEC1.DSN8910.EMP
To use this SELECT query, type the other clauses you need. If
you are selecting from more than one table, use a DRAW command
for each table name you want represented.
Insert
Composes a basic query to insert data into the columns of a table
or view.
The following example shows an INSERT query of EMP that
DRAW composed:
INSERT INTO DSN8910.EMP ( "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" ,
"WORKDEPT" , "PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" ,
"BIRTHDATE" , "SALARY" , "BONUS" , "COMM" )
VALUES (
-- ENTER VALUES BELOW
COLUMN NAME
DATA TYPE
, -- EMPNO
CHAR(6) NOT NULL
, -- FIRSTNME
VARCHAR(12) NOT NULL
, -- MIDINIT
CHAR(1) NOT NULL
, -- LASTNAME
VARCHAR(15) NOT NULL
, -- WORKDEPT
CHAR(3)
, -- PHONENO
CHAR(4)
, -- HIREDATE
DATE
, -- JOB
CHAR(8)
, -- EDLEVEL
SMALLINT
, -- SEX
CHAR(1)
, -- BIRTHDATE
DATE
, -- SALARY
DECIMAL(9,2)
, -- BONUS
DECIMAL(9,2)
) -- COMM
DECIMAL(9,2)
To insert values into EMP, type values to the left of the
column names.
Update
Composes a basic query to change the data in a table or view.
The following example shows an UPDATE query of EMP composed
by DRAW:
UPDATE DSN8910.EMP SET
-- COLUMN NAME
ENTER VALUES BELOW
DATA TYPE
"EMPNO"=
-- CHAR(6) NOT NULL
, "FIRSTNME"=
-- VARCHAR(12) NOT NULL
, "MIDINIT"=
-- CHAR(1) NOT NULL
, "LASTNAME"=
-- VARCHAR(15) NOT NULL
, "WORKDEPT"=
-- CHAR(3)
, "PHONENO"=
-- CHAR(4)
, "HIREDATE"=
-- DATE
, "JOB"=
-- CHAR(8)
, "EDLEVEL"=
-- SMALLINT
, "SEX"=
-- CHAR(1)
, "BIRTHDATE"=
-- DATE
, "SALARY"=
-- DECIMAL(9,2)
, "BONUS"=
-- DECIMAL(9,2)
, "COMM"=
-- DECIMAL(9,2)
WHERE
To use this UPDATE query, type the changes you want to make to
the right of the column names, and delete the lines you don’t
need. Be sure to complete the WHERE clause.
Load
Composes a load statement to load the data in a table.
The following example shows a LOAD statement of EMP composed
by DRAW:
LOAD DATA INDDN SYSREC INTO TABLE DSN8910 .EMP
( "EMPNO"
POSITION(
1) CHAR(6)
Chapter 3. Including DB2 queries in an application program

361
,
,
,
,

"FIRSTNME"
"MIDINIT"
"LASTNAME"
"WORKDEPT"

, "PHONENO"
, "HIREDATE"
, "JOB"
, "EDLEVEL"
, "SEX"
, "BIRTHDATE"
, "SALARY"
, "BONUS"
, "COMM"

POSITION(
POSITION(
POSITION(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(
POSITION(
NULLIF(

8) VARCHAR
21) CHAR(1)
23) VARCHAR
39) CHAR(3)
39)=’?’
43) CHAR(4)
43)=’?’
48) DATE EXTERNAL
48)=’?’
59) CHAR(8)
59)=’?’
68) SMALLINT
68)=’?’
71) CHAR(1)
71)=’?’
73) DATE EXTERNAL
73)=’?’
84) DECIMAL EXTERNAL(9,2)
84)=’?’
90) DECIMAL EXTERNAL(9,2)
90)=’?’
96) DECIMAL EXTERNAL(9,2)
96)=’?’

)
To use this LOAD statement, type the changes you want to make,
and delete the lines you don’t need.
*/
L2 = WHEREAMI()
/**********************************************************************/
/* TRACE ?R
*/
/**********************************************************************/
Address ISPEXEC
"ISREDIT MACRO (ARGS) NOPROCESS"
If ARGS = "" Then
Do
Do I = L1+2 To L2-2;Say SourceLine(I);End
Exit (20)
End
Parse Upper Var Args Table "(" Parms
Parms = Translate(Parms," ",",")
Type = "SELECT" /* Default */
SSID = ""
/* Default */
"VGET (DSNEOV01)"
If RC = 0 Then SSID = DSNEOV01
If (Parms <> "") Then
Do Until(Parms = "")
Parse Var Parms Var "=" Value Parms
If Var = "T" | Var = "TYPE" Then Type = Value
Else
If Var = "S" | Var = "SSID" Then SSID = Value
Else
Exit (20)
End
"CONTROL ERRORS RETURN"
"ISREDIT (LEFTBND,RIGHTBND) = BOUNDS"
"ISREDIT (LRECL) = DATA_WIDTH" /*LRECL*/
BndSize = RightBnd - LeftBnd + 1
If BndSize > 72 Then BndSize = 72
"ISREDIT PROCESS DEST"
Select
When rc = 0 Then
’ISREDIT (ZDEST) = LINENUM .ZDEST’
When rc <= 8 Then /* No A or B entered */
Do
zedsmsg = ’Enter "A"/"B" line cmd’
zedlmsg = ’DRAW requires an "A" or "B" line command’
’SETMSG MSG(ISRZ001)’

362

Application Programming and SQL Guide
Exit
End
When rc <
Exit 12
When rc =
zdest =
Otherwise
Exit 12
End

12
20 Then /* Conflicting line commands - edit sets message */
20 Then
0

SQLTYPE. = "UNKNOWN TYPE"
VCHTYPE = 448; SQLTYPES.VCHTYPE = ’VARCHAR’
CHTYPE
= 452; SQLTYPES.CHTYPE
= ’CHAR’
LVCHTYPE = 456; SQLTYPES.LVCHTYPE = ’VARCHAR’
VGRTYP
= 464; SQLTYPES.VGRTYP
= ’VARGRAPHIC’
GRTYP
= 468; SQLTYPES.GRTYP
= ’GRAPHIC’
LVGRTYP = 472; SQLTYPES.LVGRTYP = ’VARGRAPHIC’
FLOTYPE = 480; SQLTYPES.FLOTYPE = ’FLOAT’
DCTYPE
= 484; SQLTYPES.DCTYPE
= ’DECIMAL’
INTYPE
= 496; SQLTYPES.INTYPE
= ’INTEGER’
SMTYPE
= 500; SQLTYPES.SMTYPE
= ’SMALLINT’
DATYPE
= 384; SQLTYPES.DATYPE
= ’DATE’
TITYPE
= 388; SQLTYPES.TITYPE
= ’TIME’
TSTYPE
= 392; SQLTYPES.TSTYPE
= ’TIMESTAMP’
Address TSO "SUBCOM DSNREXX"
/* HOST CMD ENV AVAILABLE? */
IF RC THEN
/* NO, LET’S MAKE ONE
*/
S_RC = RXSUBCOM(’ADD’,’DSNREXX’,’DSNREXX’) /* ADD HOST CMD ENV */
Address DSNREXX "CONNECT" SSID
If SQLCODE ^= 0 Then Call SQLCA
Address DSNREXX "EXECSQL DESCRIBE TABLE :TABLE INTO :SQLDA"
If SQLCODE ^= 0 Then Call SQLCA
Address DSNREXX "EXECSQL COMMIT"
Address DSNREXX "DISCONNECT"
If SQLCODE ^= 0 Then Call SQLCA
Select
When (Left(Type,1) = "S") Then
Call DrawSelect
When (Left(Type,1) = "I") Then
Call DrawInsert
When (Left(Type,1) = "U") Then
Call DrawUpdate
When (Left(Type,1) = "L") Then
Call DrawLoad
Otherwise EXIT (20)
End
Do I = LINE.0 To 1 By -1
LINE = COPIES(" ",LEFTBND-1)||LINE.I
’ISREDIT LINE_AFTER ’zdest’ = DATALINE (Line)’
End
line1 = zdest + 1
’ISREDIT CURSOR = ’line1 0
Exit
/**********************************************************************/
WHEREAMI:; RETURN SIGL
/**********************************************************************/
/* Draw SELECT
*/
/**********************************************************************/
DrawSelect:
Line.0 = 0
Line = "SELECT"
Do I = 1 To SQLDA.SQLD
If I > 1 Then Line = Line ’,’
ColName = ’"’SQLDA.I.SQLNAME’"’
Null = SQLDA.I.SQLTYPE//2
If Length(Line)+Length(ColName)+LENGTH(" ,") > BndSize THEN
Do
L = Line.0 + 1; Line.0 = L
Chapter 3. Including DB2 queries in an application program

363
Line.L = Line
Line = "
"
End
Line = Line ColName
End I
If Line ^= "" Then
Do
L = Line.0 + 1; Line.0 = L
Line.L = Line
Line = "
"
End
L = Line.0 + 1; Line.0 = L
Line.L = "FROM" TABLE
Return
/**********************************************************************/
/* Draw INSERT
*/
/**********************************************************************/
DrawInsert:
Line.0 = 0
Line = "INSERT INTO" TABLE "("
Do I = 1 To SQLDA.SQLD
If I > 1 Then Line = Line ’,’
ColName = ’"’SQLDA.I.SQLNAME’"’
If Length(Line)+Length(ColName) > BndSize THEN
Do
L = Line.0 + 1; Line.0 = L
Line.L = Line
Line = "
"
End
Line = Line ColName
If I = SQLDA.SQLD Then Line = Line ’)’
End I
If Line ^= "" Then
Do
L = Line.0 + 1; Line.0 = L
Line.L = Line
Line = "
"
End
L = Line.0 + 1; Line.0 = L
Line.L = "
VALUES ("
L = Line.0 + 1; Line.0 = L
Line.L = ,
"-- ENTER VALUES BELOW
COLUMN NAME
DATA TYPE"
Do I = 1 To SQLDA.SQLD
If SQLDA.SQLD > 1 & I < SQLDA.SQLD Then
Line = "
, --"
Else
Line = "
) --"
Line = Line Left(SQLDA.I.SQLNAME,18)
Type = SQLDA.I.SQLTYPE
Null = Type//2
If Null Then Type = Type - 1
Len
= SQLDA.I.SQLLEN
Prcsn = SQLDA.I.SQLLEN.SQLPRECISION
Scale = SQLDA.I.SQLLEN.SQLSCALE
Select
When (Type = CHTYPE
,
|Type = VCHTYPE ,
|Type = LVCHTYPE ,
|Type = GRTYP
,
|Type = VGRTYP
,
|Type = LVGRTYP ) THEN
Type = SQLTYPES.Type"("STRIP(LEN)")"
When (Type = FLOTYPE ) THEN
Type = SQLTYPES.Type"("STRIP((LEN*4)-11) ")"
When (Type = DCTYPE
) THEN
Type = SQLTYPES.Type"("STRIP(PRCSN)","STRIP(SCALE)")"

364

Application Programming and SQL Guide
Otherwise
Type = SQLTYPES.Type
End
Line = Line Type
If Null = 0 Then
Line = Line "NOT NULL"
L = Line.0 + 1; Line.0 = L
Line.L = Line
End I
Return
/**********************************************************************/
/* Draw UPDATE
*/
/**********************************************************************/
DrawUpdate:
Line.0 = 1
Line.1 = "UPDATE" TABLE "SET"
L = Line.0 + 1; Line.0 = L
Line.L = ,
"-- COLUMN NAME
ENTER VALUES BELOW
DATA TYPE"
Do I = 1 To SQLDA.SQLD
If I = 1 Then
Line = " "
Else
Line = " ,"
Line = Line Left(’"’SQLDA.I.SQLNAME’"=’,21)
Line = Line Left(" ",20)
Type = SQLDA.I.SQLTYPE
Null = Type//2
If Null Then Type = Type - 1
Len
= SQLDA.I.SQLLEN
Prcsn = SQLDA.I.SQLLEN.SQLPRECISION
Scale = SQLDA.I.SQLLEN.SQLSCALE
Select
When (Type = CHTYPE
,
|Type = VCHTYPE ,
|Type = LVCHTYPE ,
|Type = GRTYP
,
|Type = VGRTYP
,
|Type = LVGRTYP ) THEN
Type = SQLTYPES.Type"("STRIP(LEN)")"
When (Type = FLOTYPE ) THEN
Type = SQLTYPES.Type"("STRIP((LEN*4)-11) ")"
When (Type = DCTYPE
) THEN
Type = SQLTYPES.Type"("STRIP(PRCSN)","STRIP(SCALE)")"
Otherwise
Type = SQLTYPES.Type
End
Line = Line "--" Type
If Null = 0 Then
Line = Line "NOT NULL"
L = Line.0 + 1; Line.0 = L
Line.L = Line
End I
L = Line.0 + 1; Line.0 = L
Line.L = "WHERE"
Return
/**********************************************************************/
/* Draw LOAD
*/
/**********************************************************************/
DrawLoad:
Line.0 = 1
Line.1 = "LOAD DATA INDDN SYSREC INTO TABLE" TABLE
Position = 1
Do I = 1 To SQLDA.SQLD
If I = 1 Then
Line = " ("
Chapter 3. Including DB2 queries in an application program

365
Else
Line = " ,"
Line = Line Left(’"’SQLDA.I.SQLNAME’"’,20)
Line = Line "POSITION("RIGHT(POSITION,5)")"
Type = SQLDA.I.SQLTYPE
Null = Type//2
If Null Then Type = Type - 1
Len
= SQLDA.I.SQLLEN
Prcsn = SQLDA.I.SQLLEN.SQLPRECISION
Scale = SQLDA.I.SQLLEN.SQLSCALE
Select
When (Type = CHTYPE
,
|Type = GRTYP
) THEN
Type = SQLTYPES.Type"("STRIP(LEN)")"
When (Type = FLOTYPE ) THEN
Type = SQLTYPES.Type"("STRIP((LEN*4)-11) ")"
When (Type = DCTYPE
) THEN
Do
Type = SQLTYPES.Type "EXTERNAL"
Type = Type"("STRIP(PRCSN)","STRIP(SCALE)")"
Len = (PRCSN+2)%2
End
When (Type = DATYPE
,
|Type = TITYPE
,
|Type = TSTYPE
) THEN
Type = SQLTYPES.Type "EXTERNAL"
Otherwise
Type = SQLTYPES.Type
End
If
(Type = GRTYP
,
|Type = VGRTYP
,
|Type = LVGRTYP ) THEN
Len = Len * 2
If
(Type = VCHTYPE ,
|Type = LVCHTYPE ,
|Type = VGRTYP
,
|Type = LVGRTYP ) THEN
Len = Len + 2
Line = Line Type
L = Line.0 + 1; Line.0 = L
Line.L = Line
If Null = 1 Then
Do
Line = " "
Line = Line Left(’’,20)
Line = Line " NULLIF("RIGHT(POSITION,5)")=’?’"
L = Line.0 + 1; Line.0 = L
Line.L = Line
End
Position = Position + Len + 1
End I
L = Line.0 + 1; Line.0 = L
Line.L = " )"
Return
/**********************************************************************/
/* Display SQLCA
*/
/**********************************************************************/
SQLCA:
"ISREDIT LINE_AFTER "zdest" = MSGLINE ’SQLSTATE="SQLSTATE"’"
"ISREDIT LINE_AFTER "zdest" = MSGLINE ’SQLWARN ="SQLWARN.0",",
|| SQLWARN.1",",
|| SQLWARN.2",",
|| SQLWARN.3",",
|| SQLWARN.4",",
|| SQLWARN.5",",
|| SQLWARN.6",",
|| SQLWARN.7",",

366

Application Programming and SQL Guide
"ISREDIT

"ISREDIT
"ISREDIT
"ISREDIT
Exit 20

|| SQLWARN.8",",
|| SQLWARN.9",",
|| SQLWARN.10"’"
LINE_AFTER "zdest" =
|| SQLERRD.2",",
|| SQLERRD.3",",
|| SQLERRD.4",",
|| SQLERRD.5",",
|| SQLERRD.6"’"
LINE_AFTER "zdest" =
LINE_AFTER "zdest" =
LINE_AFTER "zdest" =

MSGLINE ’SQLERRD ="SQLERRD.1",",

MSGLINE ’SQLERRP ="SQLERRP"’"
MSGLINE ’SQLERRMC ="SQLERRMC"’"
MSGLINE ’SQLCODE ="SQLCODE"’"

Example programs that call stored procedures
These examples can be used as models when you write applications that call
stored procedures. In addition to these example programs, DSN910.SDSNSAMP
contains sample jobs DSNTEJ6P and DSNTEJ6S and programs DSN8EP1 and
DSN8EP2, which you can run.

Example C program that calls a stored procedure
This example shows how to call the C language version of the GETPRML stored
procedure that uses the GENERAL WITH NULLS linkage convention. Because the
stored procedure returns result sets, this program checks for result sets and
retrieves the contents of the result sets.
The following figure contains the example C program that calls the GETPRML
stored procedure.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
/************************************************************/
/* Include the SQLCA and SQLDA
*/
/************************************************************/
EXEC SQL INCLUDE SQLCA;
EXEC SQL INCLUDE SQLDA;
/************************************************************/
/* Declare variables that are not SQL-related.
*/
/************************************************************/
short int i;
/* Loop counter
*/
/************************************************************/
/* Declare the following:
*/
/* - Parameters used to call stored procedure GETPRML
*/
/* - An SQLDA for DESCRIBE PROCEDURE
*/
/* - An SQLDA for DESCRIBE CURSOR
*/
/* - Result set variable locators for up to three result
*/
/*
sets
*/
/************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
char procnm[19];
/* INPUT parm -- PROCEDURE name */
char schema[9];
/* INPUT parm -- User’s schema */
long int out_code;
/* OUTPUT -- SQLCODE from the
*/
/*
SELECT operation.
*/
struct {
short int parmlen;
char parmtxt[254];
} parmlst;
/* OUTPUT -- RUNOPTS values
*/
/*
for the matching row in
*/
/*
catalog table SYSROUTINES */
struct indicators {
short int procnm_ind;
Chapter 3. Including DB2 queries in an application program

367
short int schema_ind;
short int out_code_ind;
short int parmlst_ind;
} parmind;
/* Indicator variable structure */
struct sqlda *proc_da;
/* SQLDA for DESCRIBE PROCEDURE */
struct sqlda *res_da;
/* SQLDA for DESCRIBE CURSOR
static volatile
SQL TYPE IS RESULT_SET_LOCATOR *loc1, *loc2, *loc3;
/* Locator variables
EXEC SQL END DECLARE SECTION;

*/
*/

/*************************************************************/
/* Allocate the SQLDAs to be used for DESCRIBE
*/
/* PROCEDURE and DESCRIBE CURSOR. Assume that at most
*/
/* three cursors are returned and that each result set
*/
/* has no more than five columns.
*/
/*************************************************************/
proc_da = (struct sqlda *)malloc(SQLDASIZE(3));
res_da = (struct sqlda *)malloc(SQLDASIZE(5));
/************************************************************/
/* Call the GETPRML stored procedure to retrieve the
*/
/* RUNOPTS values for the stored procedure.
In this
*/
/* example, we request the PARMLIST definition for the
*/
/* stored procedure named DSN8EP2.
*/
/*
*/
/* The call should complete with SQLCODE +466 because
*/
/* GETPRML returns result sets.
*/
/************************************************************/
strcpy(procnm,"dsn8ep2
");
/* Input parameter -- PROCEDURE to be found
*/
strcpy(schema,"
");
/* Input parameter -- Schema name for proc
*/
parmind.procnm_ind=0;
parmind.schema_ind=0;
parmind.out_code_ind=0;
/* Indicate that none of the input parameters */
/* have null values
*/
parmind.parmlst_ind=-1;
/* The parmlst parameter is an output parm.
*/
/* Mark PARMLST parameter as null, so the DB2 */
/* requester doesn’t have to send the entire */
/* PARMLST variable to the server. This
*/
/* helps reduce network I/O time, because
*/
/* PARMLST is fairly large.
*/
EXEC SQL
CALL GETPRML(:procnm INDICATOR :parmind.procnm_ind,
:schema INDICATOR :parmind.schema_ind,
:out_code INDICATOR :parmind.out_code_ind,
:parmlst INDICATOR :parmind.parmlst_ind);
if(SQLCODE!=+466)
/* If SQL CALL failed,
*/
{
/*
print the SQLCODE and any
*/
/*
message tokens
*/
printf("SQL CALL failed due to SQLCODE =
printf("sqlca.sqlerrmc = ");
for(i=0;i<sqlca.sqlerrml;i++)
printf("i]);
printf("n");
}

368

Application Programming and SQL Guide
else
/* If the CALL worked,
*/
if(out_code!=0)
/* Did GETPRML hit an error?
*/
printf("GETPRML failed due to RC =
/**********************************************************/
/* If everything worked, do the following:
*/
/* - Print out the parameters returned.
*/
/* - Retrieve the result sets returned.
*/
/**********************************************************/
else
{
printf("RUNOPTS =
/* Print out the runopts list
*/
/********************************************************/
/* Use the statement DESCRIBE PROCEDURE to
*/
/* return information about the result sets in the
*/
/* SQLDA pointed to by proc_da:
*/
/* - SQLD contains the number of result sets that were */
/*
returned by the stored procedure.
*/
/* - Each SQLVAR entry has the following information
*/
/*
about a result set:
*/
/*
- SQLNAME contains the name of the cursor that
*/
/*
the stored procedure uses to return the result
*/
/*
set.
*/
/*
- SQLIND contains an estimate of the number of
*/
/*
rows in the result set.
*/
/*
- SQLDATA contains the result locator value for
*/
/*
the result set.
*/
/********************************************************/
EXEC SQL DESCRIBE PROCEDURE INTO :*proc_da;
/********************************************************/
/* Assume that you have examined SQLD and determined
*/
/* that there is one result set. Use the statement
*/
/* ASSOCIATE LOCATORS to establish a result set locator */
/* for the result set.
*/
/********************************************************/
EXEC SQL ASSOCIATE LOCATORS (:loc1) WITH PROCEDURE GETPRML;
/********************************************************/
/* Use the statement ALLOCATE CURSOR to associate a
*/
/* cursor for the result set.
*/
/********************************************************/
EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :loc1;
/********************************************************/
/* Use the statement DESCRIBE CURSOR to determine the
*/
/* columns in the result set.
*/
/********************************************************/
EXEC SQL DESCRIBE CURSOR C1 INTO :*res_da;
/********************************************************/
/* Call a routine (not shown here) to do the following: */
/* - Allocate a buffer for data and indicator values
*/
/*
fetched from the result table.
*/
/* - Update the SQLDATA and SQLIND fields in each
*/
/*
SQLVAR of *res_da with the addresses at which to
*/
/*
to put the fetched data and values of indicator
*/
/*
variables.
*/
/********************************************************/
alloc_outbuff(res_da);
/********************************************************/
/* Fetch the data from the result table.
*/
/********************************************************/
while(SQLCODE==0)

Chapter 3. Including DB2 queries in an application program

369
EXEC SQL FETCH C1 USING DESCRIPTOR :*res_da;
}
return;
}

Example COBOL program that calls a stored procedure
This example shows how to call the GETPRML stored procedure that uses the
GENERAL WITH NULLS linkage convention from a COBOL program on an z/OS
system. Because the stored procedure returns result sets, this program checks for
result sets and retrieves the contents of the result sets.
The following figure contains the example COBOL program that calls the
GETPRML stored procedure.
IDENTIFICATION DIVISION.
PROGRAM-ID.
CALPRML.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT REPOUT
ASSIGN TO UT-S-SYSPRINT.
DATA DIVISION.
FILE SECTION.
FD REPOUT
RECORD CONTAINS 127 CHARACTERS
LABEL RECORDS ARE OMITTED
DATA RECORD IS REPREC.
01 REPREC
PIC X(127).
WORKING-STORAGE SECTION.
*****************************************************
* MESSAGES FOR SQL CALL
*
*****************************************************
01 SQLREC.
02 BADMSG
PIC X(34) VALUE
’ SQL CALL FAILED DUE TO SQLCODE = ’.
02 BADCODE
PIC +9(5) USAGE DISPLAY.
02 FILLER
PIC X(80) VALUE SPACES.
01 ERRMREC.
02 ERRMMSG
PIC X(12) VALUE ’ SQLERRMC = ’.
02 ERRMCODE PIC X(70).
02 FILLER
PIC X(38) VALUE SPACES.
01 CALLREC.
02 CALLMSG
PIC X(28) VALUE
’ GETPRML FAILED DUE TO RC = ’.
02 CALLCODE PIC +9(5) USAGE DISPLAY.
02 FILLER
PIC X(42) VALUE SPACES.
01 RSLTREC.
02 RSLTMSG
PIC X(15) VALUE
’ TABLE NAME IS ’.
02 TBLNAME
PIC X(18) VALUE SPACES.
02 FILLER
PIC X(87) VALUE SPACES.
*****************************************************
* WORK AREAS
*
*****************************************************
01 PROCNM
PIC X(18).
01 SCHEMA
PIC X(8).
01 OUT-CODE
PIC S9(9) USAGE COMP.
01 PARMLST.
49 PARMLEN
PIC S9(4) USAGE COMP.
49 PARMTXT
PIC X(254).
01 PARMBUF REDEFINES PARMLST.
49 PARBLEN
PIC S9(4) USAGE COMP.

370

Application Programming and SQL Guide
49 PARMARRY
PIC X(127) OCCURS 2 TIMES.
NAME.
49 NAMELEN
PIC S9(4) USAGE COMP.
49 NAMETXT
PIC X(18).
77 PARMIND
PIC S9(4) COMP.
77 I
PIC S9(4) COMP.
77 NUMLINES
PIC S9(4) COMP.
*****************************************************
* DECLARE A RESULT SET LOCATOR FOR THE RESULT SET
*
* THAT IS RETURNED.
*
*****************************************************
01 LOC
USAGE SQL TYPE IS
RESULT-SET-LOCATOR VARYING.
01

*****************************************************
* SQL INCLUDE FOR SQLCA
*
*****************************************************
EXEC SQL INCLUDE SQLCA END-EXEC.
PROCEDURE DIVISION.
*-----------------PROG-START.
OPEN OUTPUT REPOUT.
*
OPEN OUTPUT FILE
MOVE ’DSN8EP2
’ TO PROCNM.
*
INPUT PARAMETER -- PROCEDURE TO BE FOUND
MOVE SPACES TO SCHEMA.
*
INPUT PARAMETER -- SCHEMA IN SYSROUTINES
MOVE -1 TO PARMIND.
*
THE PARMLST PARAMETER IS AN OUTPUT PARM.
*
MARK PARMLST PARAMETER AS NULL, SO THE DB2
*
REQUESTER DOESN’T HAVE TO SEND THE ENTIRE
*
PARMLST VARIABLE TO THE SERVER. THIS
*
HELPS REDUCE NETWORK I/O TIME, BECAUSE
*
PARMLST IS FAIRLY LARGE.
EXEC SQL
CALL GETPRML(:PROCNM,
:SCHEMA,
:OUT-CODE,
:PARMLST INDICATOR :PARMIND)
END-EXEC.
*

MAKE THE CALL
IF SQLCODE NOT EQUAL TO +466 THEN
*
IF CALL RETURNED BAD SQLCODE
MOVE SQLCODE TO BADCODE
WRITE REPREC FROM SQLREC
MOVE SQLERRMC TO ERRMCODE
WRITE REPREC FROM ERRMREC
ELSE
PERFORM GET-PARMS
PERFORM GET-RESULT-SET.
PROG-END.
CLOSE REPOUT.
*
CLOSE OUTPUT FILE
GOBACK.
PARMPRT.
MOVE SPACES TO REPREC.
WRITE REPREC FROM PARMARRY(I)
AFTER ADVANCING 1 LINE.
GET-PARMS.
*
IF THE CALL WORKED,
IF OUT-CODE NOT EQUAL TO 0 THEN
*
DID GETPRML HIT AN ERROR?
MOVE OUT-CODE TO CALLCODE
WRITE REPREC FROM CALLREC
ELSE
*
EVERYTHING WORKED
Chapter 3. Including DB2 queries in an application program

371
DIVIDE 127 INTO PARMLEN GIVING NUMLINES ROUNDED
FIND OUT HOW MANY LINES TO PRINT
PERFORM PARMPRT VARYING I
FROM 1 BY 1 UNTIL I GREATER THAN NUMLINES.
GET-RESULT-SET.
*****************************************************
* ASSUME YOU KNOW THAT ONE RESULT SET IS RETURNED, *
* AND YOU KNOW THE FORMAT OF THAT RESULT SET.
*
* ALLOCATE A CURSOR FOR THE RESULT SET, AND FETCH
*
* THE CONTENTS OF THE RESULT SET.
*
*****************************************************
EXEC SQL ASSOCIATE LOCATORS (:LOC)
WITH PROCEDURE GETPRML
END-EXEC.
*
LINK THE RESULT SET TO THE LOCATOR
EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :LOC
END-EXEC.
*
LINK THE CURSOR TO THE RESULT SET
PERFORM GET-ROWS VARYING I
FROM 1 BY 1 UNTIL SQLCODE EQUAL TO +100.
GET-ROWS.
EXEC SQL FETCH C1 INTO :NAME
END-EXEC.
MOVE NAME TO TBLNAME.
WRITE REPREC FROM RSLTREC
AFTER ADVANCING 1 LINE.
*

Example PL/I program that calls a stored procedure
This example shows how to call the GETPRML stored procedure that uses the
GENERAL WITH NULLS linkage convention from a PL/I program on an z/OS
system.
The following figure contains the example PL/I program that calls the GETPRML
stored procedure.

372

Application Programming and SQL Guide
*PROCESS SYSTEM(MVS);
CALPRML:
PROC OPTIONS(MAIN);
/************************************************************/
/* Declare the parameters used to call the GETPRML
*/
/* stored procedure.
*/
/************************************************************/
DECLARE PROCNM CHAR(18),
/* INPUT parm -- PROCEDURE name */
SCHEMA CHAR(8),
/* INPUT parm -- User’s schema */
OUT_CODE FIXED BIN(31),
/* OUTPUT -- SQLCODE from the
*/
/*
SELECT operation.
*/
PARMLST CHAR(254)
/* OUTPUT -- RUNOPTS for
*/
VARYING,
/*
the matching row in the
*/
/*
catalog table SYSROUTINES */
PARMIND FIXED BIN(15);
/* PARMLST indicator variable
*/
/************************************************************/
/* Include the SQLCA
*/
/************************************************************/
EXEC SQL INCLUDE SQLCA;
/************************************************************/
/* Call the GETPRML stored procedure to retrieve the
*/
/* RUNOPTS values for the stored procedure.
In this
*/
/* example, we request the RUNOPTS values for the
*/
/* stored procedure named DSN8EP2.
*/
/************************************************************/
PROCNM = ’DSN8EP2’;
/* Input parameter -- PROCEDURE to be found
*/
SCHEMA = ’ ’;
/* Input parameter -- SCHEMA in SYSROUTINES
*/
PARMIND = -1; /* The PARMLST parameter is an output parm.
*/
/* Mark PARMLST parameter as null, so the DB2 */
/* requester doesn’t have to send the entire */
/* PARMLST variable to the server. This
*/
/* helps reduce network I/O time, because
*/
/* PARMLST is fairly large.
*/
EXEC SQL
CALL GETPRML(:PROCNM,
:SCHEMA,
:OUT_CODE,
:PARMLST INDICATOR :PARMIND);
IF SQLCODE¬=0 THEN
/* If SQL CALL failed,
DO;
PUT SKIP EDIT(’SQL CALL failed due to SQLCODE = ’,
SQLCODE) (A(34),A(14));
PUT SKIP EDIT(’SQLERRM = ’,
SQLERRM) (A(10),A(70));
END;
ELSE
/* If the CALL worked,
IF OUT_CODE¬=0 THEN
/* Did GETPRML hit an error?
PUT SKIP EDIT(’GETPRML failed due to RC = ’,
OUT_CODE) (A(33),A(14));
ELSE
/* Everything worked.
PUT SKIP EDIT(’RUNOPTS = ’, PARMLST) (A(11),A(200));
RETURN;
END CALPRML;

*/

*/
*/
*/

Figure 31. Calling a stored procedure from a PL/I program

Chapter 3. Including DB2 queries in an application program

373
Example C stored procedure with a GENERAL linkage
convention
This example shows how to call a stored procedure that uses the GENERAL
linkage convention from a C program.
This example stored procedure does the following:
v Searches the DB2 catalog table SYSROUTINES for a row that matches the input
parameters from the client program. The two input parameters contain values
for NAME and SCHEMA.
v Searches the DB2 catalog table SYSTABLES for all tables in which the value of
CREATOR matches the value of input parameter SCHEMA. The stored
procedure uses a cursor to return the table names.
The linkage convention used for this stored procedure is GENERAL.
The output parameters from this stored procedure contain the SQLCODE from the
SELECT statement and the value of the RUNOPTS column from SYSROUTINES.
The CREATE PROCEDURE statement for this stored procedure might look like
this:
CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN,
OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT)
LANGUAGE C
DETERMINISTIC
READS SQL DATA
EXTERNAL NAME "GETPRML"
COLLID GETPRML
ASUTIME NO LIMIT
PARAMETER STYLE GENERAL
STAY RESIDENT NO
RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)"
WLM ENVIRONMENT SAMPPROG
PROGRAM TYPE MAIN
SECURITY DB2
RESULT SETS 2
COMMIT ON RETURN NO;

The following example is a C stored procedure with linkage convention GENERAL
#pragma runopts(plist(os))
#include <stdlib.h>
EXEC SQL INCLUDE SQLCA;
/***************************************************************/
/* Declare C variables for SQL operations on the parameters.
*/
/* These are local variables to the C program, which you must */
/* copy to and from the parameter list provided to the stored */
/* procedure.
*/
/***************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
char PROCNM[19];
char SCHEMA[9];
char PARMLST[255];
EXEC SQL END DECLARE SECTION;
/***************************************************************/
/* Declare cursors for returning result sets to the caller.
*/
/***************************************************************/
EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR
SELECT NAME
FROM SYSIBM.SYSTABLES

374

Application Programming and SQL Guide
WHERE CREATOR=:SCHEMA;
main(argc,argv)
int argc;
char *argv[];
{
/********************************************************/
/* Copy the input parameters into the area reserved in */
/* the program for SQL processing.
*/
/********************************************************/
strcpy(PROCNM, argv[1]);
strcpy(SCHEMA, argv[2]);
/********************************************************/
/* Issue the SQL SELECT against the SYSROUTINES
*/
/* DB2 catalog table.
*/
/********************************************************/
strcpy(PARMLST, "");
/* Clear PARMLST
*/
EXEC SQL
SELECT RUNOPTS INTO :PARMLST
FROM SYSIBM.ROUTINES
WHERE NAME=:PROCNM AND
SCHEMA=:SCHEMA;
/********************************************************/
/* Copy SQLCODE to the output parameter list.
*/
/********************************************************/
*(int *) argv[3] = SQLCODE;
/********************************************************/
/* Copy the PARMLST value returned by the SELECT back to*/
/* the parameter list provided to this stored procedure.*/
/********************************************************/
strcpy(argv[4], PARMLST);
/********************************************************/
/* Open cursor C1 to cause DB2 to return a result set
*/
/* to the caller.
*/
/********************************************************/
EXEC SQL OPEN C1;
}

Example C stored procedure with a GENERAL WITH NULLS
linkage convention
This example shows how to call a stored procedure that uses the GENERAL WITH
NULLS linkage convention from a C program.
This example stored procedure does the following:
v Searches the DB2 catalog table SYSROUTINES for a row that matches the input
parameters from the client program. The two input parameters contain values
for NAME and SCHEMA.
v Searches the DB2 catalog table SYSTABLES for all tables in which the value of
CREATOR matches the value of input parameter SCHEMA. The stored
procedure uses a cursor to return the table names.
The linkage convention for this stored procedure is GENERAL WITH NULLS.
The output parameters from this stored procedure contain the SQLCODE from the
SELECT operation, and the value of the RUNOPTS column retrieved from the
SYSROUTINES table.
The CREATE PROCEDURE statement for this stored procedure might look like
this:
Chapter 3. Including DB2 queries in an application program

375
CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN,
OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT)
LANGUAGE C
DETERMINISTIC
READS SQL DATA
EXTERNAL NAME "GETPRML"
COLLID GETPRML
ASUTIME NO LIMIT
PARAMETER STYLE GENERAL WITH NULLS
STAY RESIDENT NO
RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)"
WLM ENVIRONMENT SAMPPROG
PROGRAM TYPE MAIN
SECURITY DB2
RESULT SETS 2
COMMIT ON RETURN NO;

The following example is a C stored procedure with linkage convention GENERAL
WITH NULLS.
#pragma runopts(plist(os))
#include <stdlib.h>
EXEC SQL INCLUDE SQLCA;
/***************************************************************/
/* Declare C variables used for SQL operations on the
*/
/* parameters. These are local variables to the C program,
*/
/* which you must copy to and from the parameter list provided */
/* to the stored procedure.
*/
/***************************************************************/
EXEC SQL BEGIN DECLARE SECTION;
char PROCNM[19];
char SCHEMA[9];
char PARMLST[255];
struct INDICATORS {
short int PROCNM_IND;
short int SCHEMA_IND;
short int OUT_CODE_IND;
short int PARMLST_IND;
} PARM_IND;
EXEC SQL END DECLARE SECTION;
/***************************************************************/
/* Declare cursors for returning result sets to the caller.
*/
/***************************************************************/
EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR
SELECT NAME
FROM SYSIBM.SYSTABLES
WHERE CREATOR=:SCHEMA;
main(argc,argv)
int argc;
char *argv[];
{
/********************************************************/
/* Copy the input parameters into the area reserved in */
/* the local program for SQL processing.
*/
/********************************************************/
strcpy(PROCNM, argv[1]);
strcpy(SCHEMA, argv[2]);
/********************************************************/

376

Application Programming and SQL Guide
/* Copy null indicator values for the parameter list.
*/
/********************************************************/
memcpy(&PARM_IND,(struct INDICATORS *) argv[5],
sizeof(PARM_IND));
/********************************************************/
/* If any input parameter is NULL, return an error
*/
/* return code and assign a NULL value to PARMLST.
*/
/********************************************************/
if (PARM_IND.PROCNM_IND<0 ||
PARM_IND.SCHEMA_IND<0 || {
*(int *) argv[3] = 9999;
/* set output return code */
PARM_IND.OUT_CODE_IND = 0;
/* value is not NULL
*/
PARM_IND.PARMLST_IND = -1;
/* PARMLST is NULL
*/
}
else {
/********************************************************/
/* If the input parameters are not NULL, issue the SQL */
/* SELECT against the SYSIBM.SYSROUTINES catalog
*/
/* table.
*/
/********************************************************/
strcpy(PARMLST, "");
/* Clear PARMLST
*/
EXEC SQL
SELECT RUNOPTS INTO :PARMLST
FROM SYSIBM.SYSROUTINES
WHERE NAME=:PROCNM AND
SCHEMA=:SCHEMA;
/********************************************************/
/* Copy SQLCODE to the output parameter list.
*/
/********************************************************/
*(int *) argv[3] = SQLCODE;
PARM_IND.OUT_CODE_IND = 0;
/* OUT_CODE is not NULL */
}
/********************************************************/
/* Copy the RUNOPTS value back to the output parameter */
/* area.
*/
/********************************************************/
strcpy(argv[4], PARMLST);
/********************************************************/
/* Copy the null indicators back to the output parameter*/
/* area.
*/
/********************************************************/
memcpy((struct INDICATORS *) argv[5],&PARM_IND,
sizeof(PARM_IND));
/********************************************************/
/* Open cursor C1 to cause DB2 to return a result set
*/
/* to the caller.
*/
/********************************************************/
EXEC SQL OPEN C1;
}

Example COBOL stored procedure with a GENERAL linkage
convention
This example shows how to call a stored procedure that uses the GENERAL
linkage convention from a COBOL program.
This example stored procedure does the following:
v Searches the catalog table SYSROUTINES for a row matching the input
parameters from the client program. The two input parameters contain values
for NAME and SCHEMA.

Chapter 3. Including DB2 queries in an application program

377
v Searches the DB2 catalog table SYSTABLES for all tables in which the value of
CREATOR matches the value of input parameter SCHEMA. The stored
procedure uses a cursor to return the table names.
This stored procedure is able to return a NULL value for the output host variables.
The linkage convention for this stored procedure is GENERAL.
The output parameters from this stored procedure contain the SQLCODE from the
SELECT operation, and the value of the RUNOPTS column retrieved from the
SYSROUTINES table.
The CREATE PROCEDURE statement for this stored procedure might look like
this:
CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN,
OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT)
LANGUAGE COBOL
DETERMINISTIC
READS SQL DATA
EXTERNAL NAME "GETPRML"
COLLID GETPRML
ASUTIME NO LIMIT
PARAMETER STYLE GENERAL
STAY RESIDENT NO
RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)"
WLM ENVIRONMENT SAMPPROG
PROGRAM TYPE MAIN
SECURITY DB2
RESULT SETS 2
COMMIT ON RETURN NO;
CBL RENT
IDENTIFICATION DIVISION.
PROGRAM-ID. GETPRML.
AUTHOR. EXAMPLE.
DATE-WRITTEN.
03/25/98.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
EXEC SQL INCLUDE SQLCA END-EXEC.
***************************************************
*
DECLARE A HOST VARIABLE TO HOLD INPUT SCHEMA
***************************************************
01 INSCHEMA PIC X(8).
***************************************************
*
DECLARE CURSOR FOR RETURNING RESULT SETS
***************************************************
*
EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR
SELECT NAME FROM SYSIBM.SYSTABLES WHERE CREATOR=:INSCHEMA
END-EXEC.
*
LINKAGE SECTION.
***************************************************
*
DECLARE THE INPUT PARAMETERS FOR THE PROCEDURE
***************************************************
01 PROCNM PIC X(18).
01 SCHEMA PIC X(8).

378

Application Programming and SQL Guide
*******************************************************
* DECLARE THE OUTPUT PARAMETERS FOR THE PROCEDURE
*******************************************************
01 OUT-CODE PIC S9(9) USAGE BINARY.
01 PARMLST.
49 PARMLST-LEN PIC S9(4) USAGE BINARY.
49 PARMLST-TEXT PIC X(254).
PROCEDURE DIVISION USING PROCNM, SCHEMA,
OUT-CODE, PARMLST.
*******************************************************
* Issue the SQL SELECT against the SYSIBM.SYSROUTINES
* DB2 catalog table.
*******************************************************
EXEC SQL
SELECT RUNOPTS INTO :PARMLST
FROM SYSIBM.ROUTINES
WHERE NAME=:PROCNM AND
SCHEMA=:SCHEMA
END-EXEC.
*******************************************************
* COPY SQLCODE INTO THE OUTPUT PARAMETER AREA
*******************************************************
MOVE SQLCODE TO OUT-CODE.
*******************************************************
* OPEN CURSOR C1 TO CAUSE DB2 TO RETURN A RESULT SET
* TO THE CALLER.
*******************************************************
EXEC SQL OPEN C1
END-EXEC.
PROG-END.
GOBACK.

Example COBOL stored procedure with a GENERAL WITH
NULLS linkage convention
This example shows how to call a stored procedure that uses the GENERAL WITH
NULLS linkage convention from a COBOL program.
This example stored procedure does the following:
v Searches the DB2 SYSIBM.SYSROUTINES catalog table for a row that matches
the input parameters from the client program. The two input parameters contain
values for NAME and SCHEMA.
v Searches the DB2 catalog table SYSTABLES for all tables in which the value of
CREATOR matches the value of input parameter SCHEMA. The stored
procedure uses a cursor to return the table names.
The linkage convention for this stored procedure is GENERAL WITH NULLS.
The output parameters from this stored procedure contain the SQLCODE from the
SELECT operation, and the value of the RUNOPTS column retrieved from the
SYSIBM.SYSROUTINES table.
The CREATE PROCEDURE statement for this stored procedure might look like
this:
CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN,
OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT)
LANGUAGE COBOL
DETERMINISTIC
READS SQL DATA
EXTERNAL NAME "GETPRML"
Chapter 3. Including DB2 queries in an application program

379
COLLID GETPRML
ASUTIME NO LIMIT
PARAMETER STYLE GENERAL WITH NULLS
STAY RESIDENT NO
RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)"
WLM ENVIRONMENT SAMPPROG
PROGRAM TYPE MAIN
SECURITY DB2
RESULT SETS 2
COMMIT ON RETURN NO;

The following example is a COBOL stored procedure with linkage convention
GENERAL WITH NULLS.
CBL RENT
IDENTIFICATION DIVISION.
PROGRAM-ID. GETPRML.
AUTHOR. EXAMPLE.
DATE-WRITTEN.
03/25/98.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
DATA DIVISION.
FILE SECTION.
*
WORKING-STORAGE SECTION.
*
EXEC SQL INCLUDE SQLCA END-EXEC.
*
***************************************************
*
DECLARE A HOST VARIABLE TO HOLD INPUT SCHEMA
***************************************************
01 INSCHEMA PIC X(8).
***************************************************
*
DECLARE CURSOR FOR RETURNING RESULT SETS
***************************************************
*
EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR
SELECT NAME FROM SYSIBM.SYSTABLES WHERE CREATOR=:INSCHEMA
END-EXEC.
*
LINKAGE SECTION.
***************************************************
*
DECLARE THE INPUT PARAMETERS FOR THE PROCEDURE
***************************************************
01 PROCNM PIC X(18).
01 SCHEMA PIC X(8).
***************************************************
*
DECLARE THE OUTPUT PARAMETERS FOR THE PROCEDURE
***************************************************
01 OUT-CODE PIC S9(9) USAGE BINARY.
01 PARMLST.
49 PARMLST-LEN PIC S9(4) USAGE BINARY.
49 PARMLST-TEXT PIC X(254).
***************************************************
*
DECLARE THE STRUCTURE CONTAINING THE NULL
*
INDICATORS FOR THE INPUT AND OUTPUT PARAMETERS.
***************************************************
01 IND-PARM.
03 PROCNM-IND
PIC S9(4) USAGE BINARY.
03 SCHEMA-IND
PIC S9(4) USAGE BINARY.
03 OUT-CODE-IND PIC S9(4) USAGE BINARY.
03 PARMLST-IND PIC S9(4) USAGE BINARY.
PROCEDURE DIVISION USING PROCNM, SCHEMA,
OUT-CODE, PARMLST, IND-PARM.
*******************************************************

380

Application Programming and SQL Guide
* If any input parameter is null, return a null value
* for PARMLST and set the output return code to 9999.
*******************************************************
IF PROCNM-IND < 0 OR
SCHEMA-IND < 0
MOVE 9999 TO OUT-CODE
MOVE 0 TO OUT-CODE-IND
MOVE -1 TO PARMLST-IND
ELSE
*******************************************************
* Issue the SQL SELECT against the SYSIBM.SYSROUTINES
* DB2 catalog table.
*******************************************************
EXEC SQL
SELECT RUNOPTS INTO :PARMLST
FROM SYSIBM.SYSROUTINES
WHERE NAME=:PROCNM AND
SCHEMA=:SCHEMA
END-EXEC
MOVE 0 TO PARMLST-IND
*******************************************************
* COPY SQLCODE INTO THE OUTPUT PARAMETER AREA
*******************************************************
MOVE SQLCODE TO OUT-CODE
MOVE 0 TO OUT-CODE-IND.
*
*******************************************************
* OPEN CURSOR C1 TO CAUSE DB2 TO RETURN A RESULT SET
* TO THE CALLER.
*******************************************************
EXEC SQL OPEN C1
END-EXEC.
PROG-END.
GOBACK.

Example PL/I stored procedure with a GENERAL linkage
convention
This example shows how to call a stored procedure that uses the GENERAL
linkage convention from a PL/I program.
This example stored procedure searches the DB2 SYSIBM.SYSROUTINES catalog
table for a row that matches the input parameters from the client program. The
two input parameters contain values for NAME and SCHEMA.
The linkage convention for this stored procedure is GENERAL.
The output parameters from this stored procedure contain the SQLCODE from the
SELECT operation, and the value of the RUNOPTS column retrieved from the
SYSIBM.SYSROUTINES table.
The CREATE PROCEDURE statement for this stored procedure might look like
this:
CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN,
OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT)
LANGUAGE PLI
DETERMINISTIC
READS SQL DATA
EXTERNAL NAME "GETPRML"
COLLID GETPRML
ASUTIME NO LIMIT
PARAMETER STYLE GENERAL
STAY RESIDENT NO
RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)"
Chapter 3. Including DB2 queries in an application program

381
WLM ENVIRONMENT SAMPPROG
PROGRAM TYPE MAIN
SECURITY DB2
RESULT SETS 0
COMMIT ON RETURN NO;

The following example is a PL/I stored procedure with linkage convention
GENERAL.
*PROCESS SYSTEM(MVS);
GETPRML:
PROC(PROCNM, SCHEMA, OUT_CODE, PARMLST)
OPTIONS(MAIN NOEXECOPS REENTRANT);
DECLARE PROCNM CHAR(18),
SCHEMA CHAR(8),

/* INPUT parm -- PROCEDURE name */
/* INPUT parm -- User’s SCHEMA */

OUT_CODE FIXED BIN(31), /*
/*
PARMLST CHAR(254)
/*
VARYING;
/*
/*

OUTPUT -- SQLCODE from
the SELECT operation.
OUTPUT -- RUNOPTS for
the matching row in
SYSIBM.SYSROUTINES

*/
*/
*/
*/
*/

EXEC SQL INCLUDE SQLCA;
/************************************************************/
/* Execute SELECT from SYSIBM.SYSROUTINES in the catalog.
*/
/************************************************************/
EXEC SQL
SELECT RUNOPTS INTO :PARMLST
FROM SYSIBM.SYSROUTINES
WHERE NAME=:PROCNM AND
SCHEMA=:SCHEMA;
OUT_CODE = SQLCODE;
RETURN;
END GETPRML;

/* return SQLCODE to caller

*/

Example PL/I stored procedure with a GENERAL WITH NULLS
linkage convention
This example shows how to call a stored procedure that uses the GENERAL WITH
NULLS linkage convention from a PL/I program.
This example stored procedure searches the DB2 SYSIBM.SYSROUTINES catalog
table for a row that matches the input parameters from the client program. The
two input parameters contain values for NAME and SCHEMA.
The linkage convention for this stored procedure is GENERAL WITH NULLS.
The output parameters from this stored procedure contain the SQLCODE from the
SELECT operation, and the value of the RUNOPTS column retrieved from the
SYSIBM.SYSROUTINES table.
The CREATE PROCEDURE statement for this stored procedure might look like
this:
CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN,
OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT)
LANGUAGE PLI
DETERMINISTIC
READS SQL DATA
EXTERNAL NAME "GETPRML"
COLLID GETPRML

382

Application Programming and SQL Guide
ASUTIME NO LIMIT
PARAMETER STYLE GENERAL WITH NULLS
STAY RESIDENT NO
RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)"
WLM ENVIRONMENT SAMPPROG
PROGRAM TYPE MAIN
SECURITY DB2
RESULT SETS 0
COMMIT ON RETURN NO;

The following example is a PL/I stored procedure with linkage convention
GENERAL WITH NULLS.
*PROCESS SYSTEM(MVS);
GETPRML:
PROC(PROCNM, SCHEMA, OUT_CODE, PARMLST, INDICATORS)
OPTIONS(MAIN NOEXECOPS REENTRANT);
DECLARE PROCNM CHAR(18),
SCHEMA CHAR(8),

/* INPUT parm -- PROCEDURE name */
/* INPUT parm -- User’s schema */

OUT_CODE FIXED BIN(31), /* OUTPUT -- SQLCODE from
/*
the SELECT operation.
PARMLST CHAR(254)
/* OUTPUT -- PARMLIST for
VARYING;
/* the matching row in
/* SYSIBM.SYSROUTINES
DECLARE 1 INDICATORS,
/* Declare null indicators for
/* input and output parameters.
3 PROCNM_IND
FIXED BIN(15),
3 SCHEMA_IND
FIXED BIN(15),
3 OUT_CODE_IND FIXED BIN(15),
3 PARMLST_IND FIXED BIN(15);

*/
*/
*/
*/
*/
*/
*/

EXEC SQL INCLUDE SQLCA;
IF PROCNM_IND<0 |
SCHEMA_IND<0 THEN
DO;
OUT_CODE = 9999;
OUT_CODE_IND = 0;

/* If any input parm is NULL,
/* Set output return code.

*/
*/

/* Output return code is not NULL.*/
PARMLST_IND = -1;
/* Assign NULL value to PARMLST. */
END;
ELSE
/* If input parms are not NULL,
*/
DO;
/*
*/
/************************************************************/
/* Issue the SQL SELECT against the SYSIBM.SYSROUTINES
*/
/* DB2 catalog table.
*/
/************************************************************/
EXEC SQL
SELECT RUNOPTS INTO :PARMLST
FROM SYSIBM.SYSROUTINES
WHERE NAME=:PROCNM AND
SCHEMA=:SCHEMA;
PARMLST_IND = 0;
/* Mark PARMLST as not NULL.
*/
OUT_CODE = SQLCODE;
OUT_CODE_IND = 0;
OUT_CODE_IND = 0;
END;
RETURN;

/* return SQLCODE to caller

*/

/* Output return code is not NULL.*/

END GETPRML;

Chapter 3. Including DB2 queries in an application program

383
384

Application Programming and SQL Guide
Chapter 4. Creating and modifying DB2 objects
Your application program can create and manipulate DB2 objects, such as tables,
views, triggers, distinct types, user-defined functions, and stored procedures. You
must have the appropriate authorizations to create such objects.

Creating tables
Creating a table provides a logically place to store related data on a DB2
subsystem.
To create a table, use a CREATE TABLE statement that includes the following
elements:
v The name of the table
v A list of the columns that make up the table. For each column, specify the
following information:
– The column’s name (for example, SERIAL).
– The data type and length attribute (for example, CHAR(8)).
– Optionally, a default value.
– Optionally, a referential constraint or check constraint.
Separate each column description from the next with a comma, and enclose the
entire list of column descriptions in parentheses.
Example:The following SQL statement creates a table named PRODUCT:
CREATE TABLE PRODUCT
(SERIAL
CHAR(8)
NOT NULL,
DESCRIPTION VARCHAR(60) DEFAULT,
MFGCOST
DECIMAL(8,2),
MFGDEPT
CHAR(3),
MARKUP
SMALLINT,
SALESDEPT
CHAR(3),
CURDATE
DATE
DEFAULT);

For more information about referential constraints, see “Referential constraints” on
page 396
For more information about check constraints, see “Check constraints” on page
394.
Identifying column defaults and constraining column inputs:
If you want to constrain the input or identify the default of a column, you can use
the following values:
v NOT NULL, when the column cannot contain null values.
v UNIQUE, when the value for each row must be unique, and the column cannot
contain null values.
v DEFAULT, when the column has one of the following DB2-assigned defaults:
– For numeric columns, 0 (zero) is the default value.
– For character or graphic fixed-length strings, blank is the default value.
– For binary fixed-length strings, a set of hexadecimal zeros is the default value.
© Copyright IBM Corp. 1983, 2007

385
– For variable-length strings, including LOB strings, the empty string (a string
of zero-length) is the default value.
– For datetime columns, the current value of the associated special register is
the default value.
v DEFAULT value, when you want to identify one of the following values as the
default value:
– A constant
– NULL
– SESSION_USER, which specifies the value of the SESSION_USER special
register at the time when a default value is needed for the column
– CURRENT SQLID, which specifies the value of the CURRENT SQLID special
register at the time when a default value is needed for the column
– The name of a cast function that casts a default value (of a built-in data type)
to the distinct type of a column

Data types
When you create a DB2 table, you define each column to have a specific data type.
The data type of a column determines what you can and cannot do with the
column.
When you perform operations on columns, the data must be compatible with the
data type of the referenced column. For example, you cannot insert character data,
such as a last name, into a column whose data type is numeric. Similarly, you
cannot compare columns that contain incompatible data types.
The data type for a column can be a distinct type, which is a user-defined data
type, or a DB2 built-in data type. As shown in the following figure, DB2 built-in
data types have four general categories: datetime, string, numeric, and row
identifier (ROWID).

386

Application Programming and SQL Guide
Figure 32. DB2 built-in data types

For more detailed information about each built-in data type, see the topic “Data
types” in DB2 SQL Reference. For information about distinct types, see “Distinct
types” on page 436.
The following table shows whether operands of any two data types are compatible,
Y (Yes), or incompatible, N (No). Notes are indicated either as a superscript
number next to Y or N or as a value in the column of the table.
Table 76. Supported casts between built-in data types
To data type1

|
|
|
|
|
|
|
|
|

Cast from
data type –

S
M
A
L
L
I
N
T

SMALLINT

Y

Y

Y

Y

Y

Y

Y

Y

INTEGER

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

DECIMAL

Y

Y

Y

Y

Y

Y

Y

Y

T
I
M
E
S
T
A
M
P

Y

BIGINT

V
A
R
B
I
N
A
R
Y

Y

Y

I
N
T
E
G
E
R

B
I
G
I
N
T

D
E
C
I
M
A
L

D
E
C
F
L
O
A
T

V
A
R
G
R
A
P
H
I
C

R
E
A
L

D
O
U
B
L
E

C
H
A
R

V
A
R
C
H
A
R

C
L
O
B

G
R
A
P
H
I
C

D
B
C
L
O
B

B
I
N
A
R
Y

B
L
O
B

D
A
T
E

T
I
M
E

Chapter 4. Creating and modifying DB2 objects

R
O
W X
I M
D L

387
Table 76. Supported casts between built-in data types (continued)
To data type1
V
A
R
G
R
A
P
H
I
C

|
|
|
|
|
|
|
| Cast from
| data type –

S
M
A
L
L
I
N
T

| DECFLOAT

Y

Y

Y

Y

Y

Y

Y

Y

Y

REAL

Y

Y

Y

Y

Y

Y

Y

Y

Y

DOUBLE

Y

Y

Y

Y

Y

Y

Y

Y

Y

CHAR

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

VARCHAR

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

I
N
T
E
G
E
R

B
I
G
I
N
T

D
E
C
I
M
A
L

D
E
C
F
L
O
A
T

R
E
A
L

D
O
U
B
L
E

CLOB

C
H
A
R

Y

V
A
R
C
H
A
R

Y
2

Y
2

B
I
N
A
R
Y

D
A
T
E

T
I
M
E

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

B
L
O
B

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y

Y3 Y3

Y3

Y

R
O
W X
I M
D L

Y

2

Y

Y

Y

Y

Y

Y

Y

Y

Y

VARGRAPHIC

Y

Y

Y

Y

Y

Y

Y

Y2

Y2

Y2

Y

Y

Y

Y

Y

Y

2

2

2

Y

Y

Y

Y

Y

Y

BINARY

Y

Y

Y

VARBINARY

Y

Y

Y

BLOB

Y

Y

Y

Y

Y

DATE

Y
Y

Y

TIMESTAMP

Y

Y

ROWID

Y

Y

Y

TIME

Y

D
B
C
L
O
B

T
I
M
E
S
T
A
M
P

GRAPHIC

DBCLOB

Y

C
L
O
B

G
R
A
P
H
I
C

V
A
R
B
I
N
A
R
Y

Y

| XML

Y

Y
Y
Y
Y

Y

Y

Y

Y
Y
Y

Note:
1. Other synonyms for the listed data types are considered to be the same as the synonym listed. Some exceptions
exist when the cast involves character string data if the subtype is FOR BIT DATA.
2. The result length for these casts is 3 * LENGTH(graphic string).
3. These data types are castable between each other only if the data is Unicode.

Storing LOB data in a table
Because DB2 handles LOB data differently than other kinds of data, in some cases,
you need to take additional actions when defining LOB columns and inserting the
LOB data.
To store LOB data in DB2:
1. Define one or more columns of the appropriate LOB type and optionally a row
identifier (ROWID) column by executing a CREATE TABLE statement or one or
more ALTER TABLE statements.

388

Application Programming and SQL Guide
|
|
|
|

|
|
|
|

Define only one ROWID column, even if the table is to have multiple LOB
columns. If you do not create a ROWID column before you define a LOB
column, DB2 creates an implicitly hidden ROWID column and appends it as
the last column of the table.
If you add a ROWID column after you add a LOB column, the table has two
ROWID columns: the implicitly-created, hidden, column and the
explicitly-created column. In this case, DB2 ensures that the values of the two
ROWID columns are always identical.
If DB2 implicitly creates the table space for this table or CURRENT RULES is
set to STD, DB2 creates the necessary auxiliary objects for you and you can
skip steps 2 and 3. The LOB table space that DB2 creates inherits the
COMPRESS value of the base table space.
2. If you explicitly created the table space for this table and the CURRENT RULES
special register is not set to STD, create a LOB table space and auxiliary table
by using the CREATE LOB TABLESPACE and CREATE AUXILIARY TABLE
statements.
v If your base table is nonpartitioned, create one LOB table space and for each
column create one auxiliary table.
v If your base table is partitioned, create one LOB table space for each partition
and one auxiliary table for each column. For example, if your base table has
three partitions, you must create three LOB table spaces and three auxiliary
tables for each LOB column.
3. If you explicitly created the table space for this table and the CURRENT RULES
special register is not set to STD, create one index for each auxiliary table by
using the CREATE INDEX statement.
4. Insert the LOB data into DB2 by using one of the following techniques:
v If the total length of a LOB column and the base table row is less than 32 KB,
use the LOAD utility and specify the base table.
v Otherwise, use INSERT, UPDATE, or MERGE statements and specify the
base table. If you use the INSERT statement, ensure that you application has
enough storage available to hold the entire value that is to be put into the
LOB column.
Example: Adding a CLOB column: Suppose that you want to add a resume for
each employee to the employee table. The employee resumes are no more than 5
MB in size. Because the employee resumes contain single-byte characters, you can
define the resumes to DB2 as CLOBs. You therefore need to add a column of data
type CLOB with a length of 5 MB to the employee table. If you want to define a
ROWID column explicitly, you must define it before you define the CLOB column.
First, execute an ALTER TABLE statement to add the ROWID column, and then
execute another ALTER TABLE statement to add the CLOB column. The following
statements create these columns:
ALTER TABLE EMP
ADD ROW_ID ROWID NOT NULL GENERATED ALWAYS;
COMMIT;
ALTER TABLE EMP
ADD EMP_RESUME CLOB(5M);
COMMIT;

|
|
|

If you explicitly created the table space for this table and the CURRENT RULES
special register is not set to STD, you then need to define a LOB table space and an
auxiliary table to hold the employee resumes. You also need to define an index on

Chapter 4. Creating and modifying DB2 objects

389
|
|
|
|
|
|
|
|
|
|
|
|
|
|

the auxiliary table. You must define the LOB table space in the same database as
the associated base table. The following statements create these objects:

|

You can then load your employee resumes into DB2. In your application, you can
define a host variable to hold the resume, copy the resume data from a file into the
host variable, and then execute an UPDATE statement to copy the data into DB2.
Although the LOB data is stored in the auxiliary table, your UPDATE statement
specifies the name of the base table. The following code declares a host variable to
store the resume in the C language:

CREATE LOB TABLESPACE RESUMETS
IN DSN8D91A
LOG NO
COMPRESS YES;
COMMIT;
CREATE AUXILIARY TABLE EMP_RESUME_TAB
IN DSN8D91A.RESUMETS
STORES DSN8910.EMP
COLUMN EMP_RESUME;
CREATE UNIQUE INDEX XEMP_RESUME
ON EMP_RESUME_TAB;
COMMIT;

SQL TYPE is CLOB (5M) resumedata;

The following UPDATE statement copies the data into DB2:
UPDATE EMP SET EMP_RESUME=:resumedata
WHERE EMPNO=:employeenum;

In this statement, employeenum is a host variable that identifies the employee who
is associated with a resume.

Large objects (LOBs)
The term large object and the acronym LOB refer to DB2 objects that you can use to
store large amounts of data. A LOB is a varying-length character string that can
contain up to 2 GB - 1 of data.
The three LOB data types are:
v Binary large object (BLOB)
Use a BLOB to store binary data such as pictures, voice, and mixed media.
v Character large object (CLOB)
Use a CLOB to store SBCS or mixed character data, such as documents.
v Double-byte character large object (DBCLOB)
Use a DBCLOB to store data that consists of only DBCS data.
You can use DB2 to store LOB data, but this data is stored differently than other
kinds of data.
Although a table can have a LOB column, the actual LOB data is stored in a
another table, which called the auxiliary table. This auxiliary table exists in a
separate table space called a LOB table space. One auxiliary table must exist for
each LOB column. The table with the LOB column is called the base table. The
base table has a ROWID column that DB2 uses to locate the data in the auxiliary
table. The auxiliary table must have exactly one index.

Implicitly hidden ROWID columns
If you do not create a ROWID column before you define a LOB column, DB2
creates an implicitly hidden ROWID column for you. This column is accessible

390

Application Programming and SQL Guide
only if you reference the column directly. It is not included in the results of
SELECT * statements or DESCRIBE statements.
DB2 assigns the GENERATED ALWAYS attribute and the name
DB2_GENERATED_ROWID_FOR_LOBSnn to a an implicitly hidden ROWID
column. DB2 appends the identifier nn only if the column name already exists in
the table. If so, DB2 appends 00 and increments by 1 until the name is unique
within the row.
For more information about when DB2 creates implicitly hidden ROWID columns,
see the following topics in DB2 SQL Reference:
v “CREATE TABLE”
v “ALTER TABLE”
v “ALTER VIEW”
For more information about selecting hidden columns, see the topic “select-clause”
in DB2 SQL Reference.

Identity columns
An identity column contains a unique numeric value for each row in the table.
DB2 can automatically generate sequential numeric values for this column as rows
are inserted into the table. Thus, identity columns are ideal for primary key values,
such as employee numbers or product numbers.
Using identity columns as keys:
If you define a column with the AS IDENTITY attribute, and with the
GENERATED ALWAYS and NO CYCLE attributes, DB2 automatically generates a
monotonically increasing or decreasing sequential number for the value of that
column when a new row is inserted into the table. However, for DB2 to guarantee
that the values of the identity column are unique, you should define a unique
index on that column.
You can use identity columns for primary keys that are typically unique sequential
numbers, for example, order numbers or employee numbers. By doing so, you can
avoid the concurrency problems that can result when an application generates its
own unique counter outside the database.
Recommendation: Set the values of the foreign keys in the dependent tables after
loading the parent table. If you use an identity column as a parent key in a
referential integrity structure, loading data into that structure could be quite
complicated. The values for the identity column are not known until the table is
loaded because the column is defined as GENERATED ALWAYS.
You
v If
v If
v If

might have gaps in identity column values for the following reasons:
other applications are inserting values into the same identity column
DB2 terminates abnormally before it assigns all the cached values
your application rolls back a transaction that inserts identity values

Defining an identity column:
You can define an identity column as either GENERATED BY DEFAULT or
GENERATED ALWAYS:

Chapter 4. Creating and modifying DB2 objects

391
v If you define the column as GENERATED BY DEFAULT, you can insert a value,
and DB2 provides a default value if you do not supply one.
v If you define the column as GENERATED ALWAYS, DB2 always generates a
value for the column, and you cannot insert data into that column. If you want
the values to be unique, you must define the identity column with GENERATED
ALWAYS and NO CYCLE and define a unique index on that column.
For more information, see “Rules for inserting data into an identity column” on
page 564.
The values that DB2 generates for an identity column depend on how the column
is defined. The START WITH option determines the first value that DB2 generates.
The values advance by the INCREMENT BY value in ascending or descending
order.
The MINVALUE and MAXVALUE options determine the minimum and maximum
values that DB2 generates. The CYCLE or NO CYCLE option determines whether
DB2 wraps values when it has generated all values between the START WITH
value and MAXVALUE if the values are ascending, or between the START WITH
value and MINVALUE if the values are descending.
Example: Suppose that table T1 is defined with GENERATED ALWAYS and
CYCLE:
CREATE TABLE T1
(CHARCOL1 CHAR(1),
IDENTCOL1 SMALLINT GENERATED ALWAYS AS IDENTITY
(START WITH -1,
INCREMENT BY 1,
CYCLE,
MINVALUE -3,
MAXVALUE 3));

Now suppose that you execute the following INSERT statement eight times:
INSERT INTO T1 (CHARCOL1) VALUES (’A’);

When DB2 generates values for IDENTCOL1, it starts with -1 and increments by 1
until it reaches the MAXVALUE of 3 on the fifth INSERT. To generate the value for
the sixth INSERT, DB2 cycles back to MINVALUE, which is -3. T1 looks like this
after the eight INSERTs are executed:
CHARCOL1
========
A
A
A
A
A
A
A
A

IDENTCOL1
=========
-1
0
1
2
3
-3
-2
-1

The value of IDENTCOL1 for the eighth INSERT repeats the value of IDENTCOL1
for the first INSERT.
Identity columns as primary keys:
The SELECT from INSERT statement enables you to insert a row into a parent
table with its primary key defined as a DB2-generated identity column, and
retrieve the value of the primary or parent key. You can then use this generated

392

Application Programming and SQL Guide
value as a foreign key in a dependent table. For information about the SELECT
from INSERT statement, see “Selecting values while inserting data” on page 569.
In addition, you can use the IDENTITY_VAL_LOCAL function to return the most
recently assigned value for an identity column. For more information about the
IDENTITY_VAL_LOCAL function, see the topic “IDENTITY_VAL_LOCAL” in DB2
SQL Reference.
Example: Using SELECT from INSERT: Suppose that an EMPLOYEE table and a
DEPARTMENT table are defined in the following way:
CREATE TABLE EMPLOYEE
(EMPNO
INTEGER GENERATED ALWAYS AS IDENTITY
PRIMARY KEY NOT NULL,
NAME
CHAR(30) NOT NULL,
SALARY
DECIMAL(7,2) NOT NULL,
WORKDEPT
SMALLINT);
CREATE TABLE DEPARTMENT
(DEPTNO
SMALLINT NOT NULL PRIMARY KEY,
DEPTNAME
VARCHAR(30),
MGRNO
INTEGER NOT NULL,
CONSTRAINT REF_EMPNO FOREIGN KEY (MGRNO)
REFERENCES EMPLOYEE (EMPNO) ON DELETE RESTRICT);
ALTER TABLE EMPLOYEE ADD
CONSTRAINT REF_DEPTNO FOREIGN KEY (WORKDEPT)
REFERENCES DEPARTMENT (DEPTNO) ON DELETE SET NULL;

When you insert a new employee into the EMPLOYEE table, to retrieve the value
for the EMPNO column, you can use the following SELECT from INSERT
statement:
EXEC SQL
SELECT EMPNO INTO :hv_empno
FROM FINAL TABLE (INSERT INTO EMPLOYEE (NAME, SALARY, WORKDEPT)
VALUES (’New Employee’, 75000.00, 11));

The SELECT statement returns the DB2-generated identity value for the EMPNO
column in the host variable :hv_empno.
You can then use the value in :hv_empno to update the MGRNO column in the
DEPARTMENT table with the new employee as the department manager:
EXEC SQL
UPDATE DEPARTMENT
SET MGRNO = :hv_empno
WHERE DEPTNO = 11;

Creating tables for data integrity
You can use entities such as constraints, triggers, and unique indexes to ensure that
only valid data is added to your tables. For example, you might need to ensure
that all items in your inventory table have valid item numbers and prevent items
without valid item numbers from being added.

Ways to maintain data integrity
When you add or modify data in a DB2 table, you need to ensure that the data is
valid. Two techniques that you can use to ensure valid data are constraints and
triggers.
Constraints are rules that limit the values that you can insert, delete, or update in a
table. There are two types of constraints:
Chapter 4. Creating and modifying DB2 objects

393
v Check constraints determine the values that a column can contain. Check
constraints are discussed in “Check constraints.”
v Referential constraints preserve relationships between tables. Referential
constraints are discussed in “Referential constraints” on page 396. A specific type
of referential constraints, the informational referential constraint, is discussed in
“Informational referential constraints” on page 398.
Triggers are a series of actions that are invoked when a table is updated. Triggers
are discussed in “Creating triggers” on page 417.
Check constraints:
A check constraint is a rule that specifies the values that are allowed in one or more
columns of every row of a base table. For example, you can define a check
constraint to ensure that all values in a column that contains ages are positive
numbers.
Check constraints designate the values that specific columns of a base table can
contain, providing you a method of controlling the integrity of data entered into
tables. You can create tables with check constraints using the CREATE TABLE
statement, or you can add the constraints with the ALTER TABLE statement.
However, if the check integrity is compromised or cannot be guaranteed for a
table, the table space or partition that contains the table is placed in a check
pending state. Check integrity is the condition that exists when each row of a table
conforms to the check constraints defined on that table.
For example, you might want to make sure that no salary can be below 15000
dollars. To do this, you can create the following check constraint:
CREATE TABLE EMPSAL
(ID
INTEGER
SALARY
INTEGER

NOT NULL,
CHECK (SALARY >= 15000));

Using check constraints makes your programming task easier, because you do not
need to enforce those constraints within application programs or with a validation
routine. Define check constraints on one or more columns in a table when that
table is created or altered.
Check constraint considerations
The syntax of a check constraint is checked when the constraint is defined, but the
meaning of the constraint is not checked. The following examples show mistakes
that are not caught. Column C1 is defined as INTEGER NOT NULL.
Allowable but mistaken check constraints:
v A self-contradictory check constraint:
CHECK (C1 > 5 AND C1 < 2)

v Two check constraints that contradict each other:
CHECK (C1 > 5)
CHECK (C1 < 2)

v Two check constraints, one of which is redundant:
CHECK (C1 > 0)
CHECK (C1 >= 1)

v A check constraint that contradicts the column definition:
CHECK (C1 IS NULL)

394

Application Programming and SQL Guide
v A check constraint that repeats the column definition:
CHECK (C1 IS NOT NULL)

A check constraint is not checked for consistency with other types of constraints.
For example, a column in a dependent table can have a referential constraint with
a delete rule of SET NULL. You can also define a check constraint that prohibits
nulls in the column. As a result, an attempt to delete a parent row fails, because
setting the dependent row to null violates the check constraint.
Similarly, a check constraint is not checked for consistency with a validation
routine, which is applied to a table before a check constraint. If the routine requires
a column to be greater than or equal to 10 and a check constraint requires the same
column to be less than 10, table inserts are not possible. Plans and packages do not
need to be rebound after check constraints are defined on or removed from a table.
When check constraints are enforced

|
|

After check constraints are defined on a table, any change must satisfy those
constraints if it is made by:
v The LOAD utility with the option ENFORCE CONSTRAINT
v An SQL insert operation
v An SQL update operation
A row satisfies a check constraint if its condition evaluates either to true or to
unknown. A condition can evaluate to unknown for a row if one of the named
columns contains the null value for that row.
Any constraint defined on columns of a base table applies to the views defined on
that base table.
When you use ALTER TABLE to add a check constraint to already populated
tables, the enforcement of the check constraint is determined by the value of the
CURRENT RULES special register as follows:
v If the value is STD, the check constraint is enforced immediately when it is
defined. If a row does not conform, the check constraint is not added to the
table and an error occurs.
v If the value is DB2, the check constraint is added to the table description but its
enforcement is deferred. Because there might be rows in the table that violate
the check constraint, the table is placed in CHECK-pending status.
CHECK-pending status:
To maintain data integrity DB2 enforces check constraints and referential
constraints on data in a table. When either of these constraints are violated or
might be violated, DB2 places the table space or partition that contains the table in
CHECK-pending status.
Table check violations place a table space or partition in CHECK-pending status
when any of these conditions exist:
v A check constraint is defined on a populated table using the ALTER TABLE
statement, and the value of the CURRENT RULES special register is DB2.
v The LOAD utility is run with CONSTRAINTS NO, and check constraints are
defined on the table.
v CHECK DATA is run on a table that contains violations of check constraints.
v A point-in-time RECOVER introduces violations of check constraints.
Chapter 4. Creating and modifying DB2 objects

395
Referential constraints:
A referential constraint is a rule that specifies that the only valid values for a
particular column are those values that exist in another specified table column. For
example, this constraint can ensure that all customer IDs in a transaction table exist
in the ID column of a customer table.
A table can serve as the “master list” of all occurrences of an entity. In the sample
application, the employee table serves that purpose for employees; the numbers
that appear in that table are the only valid employee numbers. Likewise, the
department table provides a master list of all valid department numbers; the
project activity table provides a master list of activities performed for projects; and
so on.
The following figure shows the relationships that exist among the tables in the
sample application. Arrows point from parent tables to dependent tables.

CASCADE
DEPT
SET
NULL
RESTRICT

SET
NULL
EMP
RESTRICT
CASCADE

ACT

PROJ
RESTRICT

RESTRICT

RESTRICT

PROJACT
RESTRICT
EMPPROJACT

Figure 33. Relationships among tables in the sample application

When a table refers to an entity for which there is a master list, it should identify
an occurrence of the entity that actually appears in the master list; otherwise, either
the reference is invalid or the master list is incomplete. Referential constraints
enforce the relationship between a table and a master list.
Restrictions on cycles of dependent tables:
A cycle is a set of two or more tables that are ordered so that each is a dependent
of the one before it, and the first is a dependent of the last. Every table in the cycle
is a descendent of itself. DB2 restricts certain operations on cycles.
In the sample application, the employee and department tables are a cycle; each is
a dependent of the other.

396

Application Programming and SQL Guide
DB2 does not allow you to create a cycle in which a delete operation on a table
involves that same table. Enforcing that principle creates rules about adding a
foreign key to a table:
v In a cycle of two tables, neither delete rule can be CASCADE.
v In a cycle of more than two tables, two or more delete rules must not be
CASCADE. For example, in a cycle with three tables, two of the delete rules
must be other than CASCADE. This concept is illustrated in The following
figure. The cycle on the left is valid because two or more of the delete rules are
not CASCADE. The cycle on the right is invalid because it contains two
cascading deletes.

Valid
cycle

Invalid
cycle

TABLE1
RESTRICT

TABLE2

CASCADE

SET NULL

TABLE3

TABLE1
CASCADE

CASCADE

TABLE2

SET NULL

TABLE3

Figure 34. Valid and invalid delete cycles

Alternatively, a delete operation on a self-referencing table must involve the same
table, and the delete rule there must be CASCADE or NO ACTION.
Recommendation: Avoid creating a cycle in which all the delete rules are
RESTRICT and none of the foreign keys allows nulls. If you do this, no row of any
of the tables can ever be deleted.
Referential constraints on tables with multilevel security with row-level granularity:
You cannot use referential constraints on a security label column, which is used for
multilevel security with row-level granularity. However, you can use referential
constraints on other columns in the row.
DB2 does not enforce multilevel security with row-level granularity when it is
already enforcing referential constraints. Referential constraints are enforced when
the following situations occur:
v An insert operation is applied to a dependent table.
v An update operation is applied to a foreign key of a dependent table, or to the
parent key of a parent table.
v A delete operation is applied to a parent table. In addition to all referential
constraints being enforced, the DB2 system enforces all delete rules for all
dependent rows that are affected by the delete operation. If all referential
constraints and delete rules are not satisfied, the delete operation will not
succeed.
v The LOAD utility with the ENFORCE CONSTRAINTS option is run on a
dependent table.
v The CHECK DATA utility is run.
For more information about multilevel security with row-level granularity, see the
topic “Multilevel security” in DB2 Administration Guide.

Chapter 4. Creating and modifying DB2 objects

397
Informational referential constraints:
An informational referential constraint is a referential constraint that DB2 does not
enforce during normal operations. Use these constraints only when referential
integrity can be enforced by another means, such as when retrieving data from
other sources. These constraints might improve performance by enabling the query
to qualify for automatic query rewrite.
DB2 ignores informational referential constraints during insert, update, and delete
operations. Some utilities ignore these constraints; other utilities recognize them.
For example, CHECK DATA and LOAD ignore these constraints. QUIESCE
TABLESPACESET recognizes these constraints by quiescing all table spaces related
to the specified table space.
You should use this type of referential constraint only when an application process
verifies the data in a referential integrity relationship. For example, when inserting
a row in a dependent table, the application should verify that a foreign key exists
as a primary or unique key in the parent table. To define an informational
referential constraint, use the NOT ENFORCED option of the referential constraint
definition in a CREATE TABLE or ALTER TABLE statement. For more information
about the NOT ENFORCED option, see the topic “CREATE TABLE” in DB2 SQL
Reference.
Informational referential constraints are often useful, especially in a data
warehouse environment, for several reasons:
v To avoid the overhead of enforcement by DB2.
Typically, data in a data warehouse has been extracted and cleansed from other
sources. Referential integrity might already be guaranteed. In this situation,
enforcement by DB2 is unnecessary.
v To allow more queries to qualify for automatic query rewrite.
Automatic query rewrite is a process that examines a submitted query that
references source tables and, if appropriate, rewrites the query so that it executes
against a materialized query table that has been derived from those source
tables. This process uses informational referential constraints to determine
whether the query can use a materialized query table. Automatic query rewrite
results in a significant reduction in query run time, especially for
decision-support queries that operate over huge amounts of data. For more
information about materialized query tables and automatic query rewrite, see
the topic “Using materialized query tables” in DB2 Performance Monitoring and
Tuning Guide.

Defining a parent key and unique index
A parent key is either a primary key or a unique key in the parent table of a
referential constraint. The values of a parent key determine the valid values of the
foreign key in the constraint. You must create a unique index on a parent key.
The primary key of a table, if one exists, uniquely identifies each occurrence of an
entity in the table. The PRIMARY KEY clause of the CREATE TABLE or ALTER
TABLE statements identifies the column or columns of the primary key. Each
identified column must be defined as NOT NULL.
Another way to allow only unique values in a column is to specify the UNIQUE
clause when you create or alter a table. For more information about the UNIQUE
clause, see the topics “CREATE TABLE” and “ALTER TABLE” in DB2 SQL
Reference.

|
|
|
|

398

Application Programming and SQL Guide
A table that is to be a parent of dependent tables must have a primary or a unique
key; the foreign keys of the dependent tables refer to the primary or unique key.
Otherwise, a primary key is optional. Consider defining a primary key if each row
of your table does pertain to a unique occurrence of some entity. If you define a
primary key, an index must be created (the primary index) on the same set of
columns, in the same order as those columns. If you are defining referential
constraints for DB2 to enforce, read “Ways to maintain data integrity” on page 393
before creating or altering any of the tables involved.
A table can have no more than one primary key. A primary key has the same
restrictions as index keys:
v The key can include no more than 64 columns.
v You cannot specify a column name twice.
v The sum of the column length attributes cannot be greater than 2000.
You define a list of columns as the primary key of a table with the PRIMARY KEY
clause in the CREATE TABLE statement.
To add a primary key to an existing table, use the PRIMARY KEY clause in an
ALTER TABLE statement. In this case, a unique index must already exist.
Recommendations for defining primary keys:
Consider the following items when you plan for primary keys:
v The theoretical model of a relational database suggests that every table should
have a primary key to uniquely identify the entities it describes. However, you
must weigh that model against the potential cost of index maintenance
overhead. DB2 does not require you to define a primary key for tables with no
dependents.
v Choose a primary key whose values will not change over time. Choosing a
primary key with persistent values enforces the good practice of having unique
identifiers that remain the same for the lifetime of the entity occurrence.
v A primary key column should not have default values unless the primary key is
a single TIMESTAMP column.
v Choose the minimum number of columns to ensure uniqueness of the primary
key.
v A view that can be updated that is defined on a table with a primary key should
include all columns of the key. Although this is necessary only if the view is
used for inserts, the unique identification of rows can be useful if the view is
used for updates, deletes, or selects.
v Drop a primary key later if you change your database or application using SQL.
Parent key columns:
A parent key is either a primary key or a unique key in the parent table of a
referential constraint. This key consists of a column or set of columns. The values
of a parent key determine the valid values of the foreign key in the constraint.
If every row in a table represents relationships for a unique entity, the table should
have one column or a set of columns that provides a unique identifier for the rows
of the table. This column (or set of columns) is called the parent key of the table. To
ensure that the parent key does not contain duplicate values, you must create a
unique index on the column or columns that constitute the parent key. Defining
the parent key is called entity integrity, because it requires each entity to have a
unique key.
Chapter 4. Creating and modifying DB2 objects

399
In some cases, using a timestamp as part of the key can be helpful, for example
when a table does not have a “natural” unique key or if arrival sequence is the
key.
Primary keys for some of the sample tables are:
Table Key Column
Employee table
EMPNO
Department table
DEPTNO
Project table
PROJNO
Table 77 shows part of the project table which has the primary key column,
PROJNO.
Table 77. Part of the project table with the primary key column, PROJNO
PROJNO

PROJNAME

DEPTNO

MA2100

WELD LINE AUTOMATION

D01

MA2110

W L PROGRAMMING

D11

Table 78 shows part of the project activity table, which has a primary key that
contains more than one column. The primary key is a composite key, which consists
of the PRONNO, ACTNO, and ACSTDATE columns.
Table 78. Part of the Project activities table with a composite primary key
PROJNO

ACTNO

ACSTAFF

ACSTDATE

ACENDATE

AD3100

10

.50

1982-01-01

1982-07-01

AD3110

10

1.00

1982-01-01

1983-01-01

AD3111

60

.50

1982-03-15

1982-04-15

Defining a foreign key
Use foreign keys to enforce referential relationships between tables. A foreign key
is a column or set of columns that reference the parent key in the parent table.
You define a list of columns as a foreign key of a table with the FOREIGN KEY
clause in the CREATE TABLE statement.
A foreign key can refer to either a unique or a primary key of the parent table. If
the foreign key refers to a non-primary unique key, you must specify the column
names of the key explicitly. If the column names of the key are not specified
explicitly, the default is to refer to the column names of the primary key of the
parent table.
The column names you specify identify the columns of the parent key. The
privilege set must include the ALTER or the REFERENCES privilege on the
columns of the parent key. A unique index must exist on the parent key columns of
the parent table.
The relationship name: You can choose a constraint name for the relationship that
is defined by a foreign key. If you do not choose a name, DB2 generates one from

400

Application Programming and SQL Guide
the name of the first column of the foreign key, in the same way that it generates
the name of an implicitly created table space.
For example, the names of the relationships in which the employee-to-project
activity table is a dependent would, by default, be recorded (in column RELNAME
of SYSIBM.SYSFOREIGNKEYS) as EMPNO and PROJNO. The following example
shows a CREATE TABLE statement that specifies constraint names REPAPA and
REPAE for the foreign keys in the employee-to-project activity table.
CREATE TABLE DSN8910.EMPPROJACT
(EMPNO
CHAR(6)
NOT NULL,
PROJNO
CHAR(6)
NOT NULL,
ACTNO
SMALLINT
NOT NULL,
CONSTRAINT REPAPA FOREIGN KEY (PROJNO, ACTNO)
REFERENCES DSN8910.PROJACT ON DELETE RESTRICT,
CONSTRAINT REPAE FOREIGN KEY (EMPNO)
REFERENCES DSN8910.EMP ON DELETE RESTRICT)
IN DATABASE DSN8D91A;

The name is used in error messages, queries to the catalog, and DROP FOREIGN
KEY statements. Hence, you might want to choose one if you are experimenting
with your database design and have more than one foreign key beginning with the
same column (otherwise DB2 generates the name).
Indexes on foreign keys: Although not required, an index on a foreign key is
strongly recommended if rows of the parent table are often deleted. The validity of
the delete statement, and its possible effect on the dependent table, can be checked
through the index.
You can create an index on the columns of a foreign key in the same way you
create one on any other set of columns. Most often it is not a unique index. If you
do create a unique index on a foreign key, it introduces an additional constraint on
the values of the columns.
To let an index on the foreign key be used on the dependent table for a delete
operation on a parent table, the columns of the index on the foreign key must be
identical to and in the same order as the columns in the foreign key.
A foreign key can also be the primary key; then the primary index is also a unique
index on the foreign key. In that case, every row of the parent table has at most
one dependent row. The dependent table might be used to hold information that
pertains to only a few of the occurrences of the entity described by the parent
table. For example, a dependent of the employee table might contain information
that applies only to employees working in a different country.
The primary key can share columns of the foreign key if the first n columns of the
foreign key are the same as the primary key’s columns. Again, the primary index
serves as an index on the foreign key. In the sample project activity table, the
primary index (on PROJNO, ACTNO, ACSTDATE) serves as an index on the
foreign key on PROJNO. It does not serve as an index on the foreign key on
ACTNO, because ACTNO is not the first column of the index.
The FOREIGN KEY clause in ALTER TABLE:
You can add a foreign key to an existing table; in fact, that is sometimes the only
way to proceed. To make a table self-referencing, you must add a foreign key after
creating it.

Chapter 4. Creating and modifying DB2 objects

401
When a foreign key is added to a populated table, the table space is put into check
pending status.

Maintaining referential integrity when using data encryption
If you use encrypted data in a referential constraint, the primary key of the parent
table and the foreign key of the dependent table must have the same encrypted
value.
The encrypted value should be extracted from the parent table (the primary key)
and used for the dependent table (the foreign key). You can do this in one of the
following two ways:
v Use the FINAL TABLE clause on a SELECT from UPDATE, SELECT from
INSERT, or SELECT from MERGE statement.
v Use the ENCRYPT_TDES function to encrypt the foreign key using the same
password as the primary key. The encrypted value of the foreign key will be the
same as the encrypted value of the primary key.

|
|

The SET ENCRYPTION PASSWORD statement sets the password that will be used
for the ENCRYPT_TDES function.
For more information about the SET ENCRYPTION PASSWORD special register,
see the topic “ENCRYPTION PASSWORD” in DB2 SQL Reference.
For more information about the ENCRYPT_TDES statement, see the topic
“ENCRYPT_TDES” in DB2 SQL Reference.

Creating work tables for the EMP and DEPT sample tables
Before testing SQL statements that insert, update, and delete rows in the
DSN8910.EMP and DSN8910.DEPT sample tables, you should create duplicates of
these tables, so that the original sample tables remain intact. These duplicate tables
are called work tables.
This topic shows how to create the department and employee work tables and
how to fill a work table with the contents of another table:
Each of these topics assumes that you logged on by using your own authorization
ID. The authorization ID qualifies the name of each object that you create. For
example, if your authorization ID is SMITH, and you create table YDEPT, the name
of the table is SMITH.YDEPT. If you want to access table DSN8910.DEPT, you
must refer to it by its complete name. If you want to access your own table
YDEPT, you need only to refer to it as YDEPT.
Use the following statements to create a new department table called YDEPT,
modeled after the existing table, DSN8910.DEPT, and an index for YDEPT:
CREATE TABLE YDEPT
LIKE DSN8910.DEPT;
CREATE UNIQUE INDEX YDEPTX
ON YDEPT (DEPTNO);

If you want DEPTNO to be a primary key, as in the sample table, explicitly define
the key. Use an ALTER TABLE statement, as in the following example:
ALTER TABLE YDEPT
PRIMARY KEY(DEPTNO);

402

Application Programming and SQL Guide
You can use an INSERT statement to copy the rows of the result table of a
fullselect from one table to another. The following statement copies all of the rows
from DSN8910.DEPT to your own YDEPT work table:
INSERT INTO YDEPT
SELECT *
FROM DSN8910.DEPT;

For information about using the INSERT statement, see “Inserting rows by using
the INSERT statement” on page 561.
You can use the following statements to create a new employee table called YEMP:
CREATE TABLE YEMP
(EMPNO
CHAR(6)
FIRSTNME VARCHAR(12)
MIDINIT
CHAR(1)
LASTNAME VARCHAR(15)
WORKDEPT CHAR(3)

PRIMARY KEY NOT NULL,
NOT NULL,
NOT NULL,
NOT NULL,
REFERENCES YDEPT
ON DELETE SET NULL,
PHONENO
CHAR(4)
UNIQUE NOT NULL,
HIREDATE DATE
,
JOB
CHAR(8)
,
EDLEVEL
SMALLINT
,
SEX
CHAR(1)
,
BIRTHDATE DATE
,
SALARY
DECIMAL(9, 2)
,
BONUS
DECIMAL(9, 2)
,
COMM
DECIMAL(9, 2)
);

This statement also creates a referential constraint between the foreign key in
YEMP (WORKDEPT) and the primary key in YDEPT (DEPTNO). It also restricts all
phone numbers to unique numbers.
If you want to change a table definition after you create it, use the ALTER TABLE
statement with a RENAME clause. If you want to change a table name after you
create it, use the RENAME statement.
You can change a table definition by using the ALTER TABLE statement only in
certain ways. For example, you can add and drop constraints on columns in a
table. You can also change the data type of a column within character data types,
within numeric data types, and within graphic data types. You can add a column
to a table. However, you cannot use the ALTER TABLE statement to drop a
column from a table.
For more information about changing a table definition by using ALTER TABLE,
see the topic “Altering DB2 tables” in DB2 Administration Guide. For more
information about the syntax of the ALTER TABLE statement, see the topic
“ALTER TABLE” in DB2 SQL Reference. For more information about the syntax of
the RENAME statement, see the topic “RENAME” in DB2 SQL Reference.

Creating created temporary tables
Use created temporary tables when you need to store data for only the life of an
application process, but you want to share the table definition. DB2 does not
perform logging and locking operations for created temporary tables, so that SQL
statements that use these tables can execute queries efficiently.
Each application process has its own instance of the created temporary table.

Chapter 4. Creating and modifying DB2 objects

403
You create the definition of a created temporary table using the SQL CREATE
GLOBAL TEMPORARY TABLE statement.
Example: The following statement creates the definition of a table called
TEMPPROD:
CREATE GLOBAL TEMPORARY TABLE TEMPPROD
(SERIAL
CHAR(8)
NOT NULL,
DESCRIPTION VARCHAR(60) NOT NULL,
MFGCOST
DECIMAL(8,2),
MFGDEPT
CHAR(3),
MARKUP
SMALLINT,
SALESDEPT
CHAR(3),
CURDATE
DATE
NOT NULL);

Example: You can also create this same definition by copying the definition of a
base table (named PROD) by using the LIKE clause:
CREATE GLOBAL TEMPORARY TABLE TEMPPROD LIKE PROD;

The SQL statements in the previous examples create identical definitions for the
TEMPPROD table, but these tables differ slightly from the PROD sample table
PROD. The PROD sample table contains two columns, DESCRIPTION and
CURDATE, that are defined as NOT NULL WITH DEFAULT. Because created
temporary tables do not support non-null default values, the DESCRIPTION and
CURDATE columns in the TEMPPROD table are defined as NOT NULL and do
not have defaults.
After you run one of the two CREATE statements, the definition of TEMPPROD
exists, but no instances of the table exist. To create an instance of TEMPPROD, you
must use TEMPPROD in an application. DB2 creates an instance of the table when
TEMPPROD is specified in one of the following SQL statements:
v OPEN
v SELECT
v INSERT
v DELETE
Restriction: You cannot use the MERGE statement with created temporary tables.
An instance of a created temporary table exists at the current server until one of
the following actions occurs:
v The application process ends.
v The remote server connection through which the instance was created
terminates.
v The unit of work in which the instance was created completes.
When you run a ROLLBACK statement, DB2 deletes the instance of the created
temporary table. When you run a COMMIT statement, DB2 deletes the instance
of the created temporary table unless a cursor for accessing the created
temporary table is defined with the WITH HOLD clause and is open.
Example: Suppose that you create a definition of TEMPPROD and then run an
application that contains the following statements:
EXEC
EXEC
EXEC
.
.
.
EXEC
.
.
.
EXEC

404

SQL DECLARE C1 CURSOR FOR SELECT * FROM TEMPPROD;
SQL INSERT INTO TEMPPROD SELECT * FROM PROD;
SQL OPEN C1;
SQL COMMIT;
SQL CLOSE C1;

Application Programming and SQL Guide
When you run the INSERT statement, DB2 creates an instance of TEMPPROD and
populates that instance with rows from table PROD. When the COMMIT statement
runs, DB2 deletes all rows from TEMPPROD. However, assume that you change
the declaration of cursor C1 to the following declaration:
EXEC SQL DECLARE C1 CURSOR WITH HOLD
FOR SELECT * FROM TEMPPROD;

In this case, DB2 does not delete the contents of TEMPPROD until the application
ends because C1, a cursor that is defined with the WITH HOLD clause, is open
when the COMMIT statement runs. In either case, DB2 drops the instance of
TEMPPROD when the application ends.
To drop the definition of TEMPPROD, you must run the following statement:
DROP TABLE TEMPPROD;

Temporary tables
Use temporary tables when you need to store data for only the duration of an
application process. Depending on whether you want to share the table definition,
you can create a created temporary table or a declared temporary table.
The two kinds of temporary tables are:
v Created temporary tables, which you define using a CREATE GLOBAL
TEMPORARY TABLE statement
v Declared temporary tables, which you define using a DECLARE GLOBAL
TEMPORARY TABLE statement
SQL statements that use temporary tables can run faster because of the following
reasons:
v DB2 does no logging (for created temporary tables) or limited logging (for
declared temporary tables).
v DB2 does no locking (for created temporary tables) or limited locking (for
declared temporary tables).
Temporary tables are especially useful when you need to sort or query
intermediate result tables that contain a large number of rows, but you want to
store only a small subset of those rows permanently.
Temporary tables can also return result sets from stored procedures. The following
topics provide more details about created temporary tables and declared temporary
tables:
v “Creating created temporary tables” on page 403
v “Creating declared temporary tables”
For more information, see “Writing an external procedure to return result sets to a
DRDA client” on page 545.

Creating declared temporary tables
Use declared temporary tables when you need to store data for only the life of an
application process and do not need to share the table definition. The definition of
this table exists only while the application process runs. DB2 performs limited
logging and locking operations for declared temporary tables.
You create an instance of a declared temporary table by using the SQL DECLARE
GLOBAL TEMPORARY TABLE statement. That instance is known only to the

Chapter 4. Creating and modifying DB2 objects

405
application process in which the table is declared, so you can declare temporary
tables with the same name in different applications. The qualifier for a declared
temporary table is SESSION.
Before you can define declared temporary tables, you must have a WORKFILE
database that has at least one table space with a 32-KB page size.

|
|

To create a declared temporary table, specify the DECLARE GLOBAL
TEMPORARY TABLE statement. In that statement, specify the columns that the
table is to contain by performing one of the following actions:
v Specify all the columns in the table.
Unlike columns of created temporary tables, columns of declared temporary
tables can include the WITH DEFAULT clause.
v Use a LIKE clause to copy the definition of a base table, created temporary table,
or view.
If the base table, created temporary table, or view from which you select
columns has identity columns, you can specify that the corresponding columns
in the declared temporary table are also identity columns. To include these
identity columns, specify the INCLUDING IDENTITY COLUMN ATTRIBUTES
clause when you define the declared temporary table.
If the source table has a row change timestamp column, you can specify that
those column attributes are inherited in the declared temporary table by
specifying INCLUDING ROW CHANGE TIMESTAMP COLUMN ATTRIBUTES.
v Use a fullselect to choose specific columns from a base table, created temporary
table, or view.
If you want the declared temporary table columns to inherit the defaults for
columns of the table or view that is named in the fullselect, specify the
INCLUDING COLUMN DEFAULTS clause. If you want the declared temporary
table columns to have default values that correspond to their data types, specify
the USING TYPE DEFAULTS clause.

|
|
|

Example: The following statement defines a declared temporary table called
TEMPPROD by explicitly specifying the columns.
DECLARE GLOBAL
(SERIAL
DESCRIPTION
PRODCOUNT
MFGCOST
MFGDEPT
MARKUP
SALESDEPT
CURDATE

TEMPORARY TABLE TEMPPROD
CHAR(8)
NOT NULL WITH DEFAULT ’99999999’,
VARCHAR(60) NOT NULL,
INTEGER GENERATED ALWAYS AS IDENTITY,
DECIMAL(8,2),
CHAR(3),
SMALLINT,
CHAR(3),
DATE
NOT NULL);

Example: The following statement defines a declared temporary table called
TEMPPROD by copying the definition of a base table. The base table has an
identity column that the declared temporary table also uses as an identity column.
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD LIKE BASEPROD
INCLUDING IDENTITY COLUMN ATTRIBUTES;

Example: The following statement defines a declared temporary table called
TEMPPROD by selecting columns from a view. The view has an identity column
that the declared temporary table also uses as an identity column. The declared
temporary table inherits its default column values from the default column values
of a base table on which the view is based.

406

Application Programming and SQL Guide
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD
AS (SELECT * FROM PRODVIEW)
DEFINITION ONLY
INCLUDING IDENTITY COLUMN ATTRIBUTES
INCLUDING COLUMN DEFAULTS;

After you run a DECLARE GLOBAL TEMPORARY TABLE statement, the
definition of the declared temporary table exists as long as the application process
runs.
If you need to delete the definition before the application process completes, you
can do that with the DROP TABLE statement. For example, to drop the definition
of TEMPPROD, run the following statement:
DROP TABLE SESSION.TEMPPROD;

DB2 creates an empty instance of a declared temporary table when it runs the
DECLARE GLOBAL TEMPORARY TABLE statement. You can then perform the
following actions:
v Populate the declared temporary table by using INSERT statements
v Modify the table using searched or positioned UPDATE or DELETE statements
v Query the table using SELECT statements
v Create indexes on the declared temporary table
The ON COMMIT clause that you specify in the DECLARE GLOBAL
TEMPORARY TABLE statement determines whether DB2 keeps or deletes all the
rows from the table when you run a COMMIT statement in an application with a
declared temporary table. ON COMMIT DELETE ROWS, which is the default,
causes all rows to be deleted from the table at a commit point, unless a held cursor
is open on the table at the commit point. ON COMMIT PRESERVE ROWS causes
the rows to remain past the commit point.
Example: Suppose that you run the following statement in an application program:
EXEC SQL DECLARE GLOBAL TEMPORARY TABLE TEMPPROD
AS (SELECT * FROM BASEPROD)
DEFINITION ONLY
INCLUDING IDENTITY COLUMN ATTRIBUTES
INCLUDING COLUMN DEFAULTS
ON COMMIT PRESERVE ROWS;
EXEC SQL INSERT INTO SESSION.TEMPPROD SELECT * FROM BASEPROD;
.
.
.
EXEC SQL COMMIT;
.
.
.

When DB2 runs the preceding DECLARE GLOBAL TEMPORARY TABLE
statement, DB2 creates an empty instance of TEMPPROD. The INSERT statement
populates that instance with rows from table BASEPROD. The qualifier, SESSION,
must be specified in any statement that references TEMPPROD. When DB2
executes the COMMIT statement, DB2 keeps all rows in TEMPPROD because
TEMPPROD is defined with ON COMMIT PRESERVE ROWS. When the program
ends, DB2 drops TEMPPROD.

Providing a unique key for a table
Use ROWID columns or identity columns to store unique values for each row in a
table.

Chapter 4. Creating and modifying DB2 objects

407
Question: How can I provide a unique identifier for a table that has no unique
column?
Answer: Add a column with the data type ROWID or an identity column. ROWID
columns and identity columns contain a unique value for each row in the table.
You can define the column as GENERATED ALWAYS, which means that you
cannot insert values into the column, or GENERATED BY DEFAULT, which means
that DB2 generates a value if you do not specify one. If you define the ROWID or
identity column as GENERATED BY DEFAULT, you need to define a unique index
that includes only that column to guarantee uniqueness.
|

Fixing tables with incomplete definitions

|
|
|
|

If a table has an incomplete definition, you cannot load the table, insert data,
retrieve data, update data, delete data, or create foreign keys that reference the
primary key. You can drop the table, create the primary index, and drop or create
other indexes.

|
|

To check if a table has an incomplete definition, look at the TABLESTATUS column
in SYSIBM.SYSTABLES. The value P indicates that the definition is incomplete.

|
|
|
|
|

A table definition is incomplete in any of the following circumstances:
v If the table is defined with a primary or unique key and all of the following
conditions are true:
– The table space for the table was explicitly created.
– The statement is not being run with schema processor.
– The table does not have a primary or unique index for the defined primary or
unique key.

|
|
|
|
|
|

|

v If the table has a ROWID column that is defined as generated by default and
all of the following conditions are true:
– The table space for the table was explicitly created.
– The SET CURRENT RULES special register is not set to STD.
– No index is defined on the ROWID column.
v If the table has a LOB column and all of the following conditions are true:
– The table space for the table was explicitly created.
– The SET CURRENT RULES special register is not set to STD.
– No auxiliary LOB objects are defined for the LOB column.

|
|
|

You can complete the table definition by performing one of the following actions,
depending on why the table definition was incomplete:
v Creating a primary index or altering the table to drop the primary key.

|
|

v Creating a unique index or altering the table to drop the unique key.
v Defining an index on the ROWID column.
v Creating the necessary LOB objects.

|
|
|
|

|
|
|
|
|

Example of creating a primary index: To create the primary index for the project
activity table, issue the following SQL statement:

|
|

If you later drop the primary index, the table reverts to incomplete definition
status.

CREATE UNIQUE INDEX XPROJAC1
ON DSN8910.PROJACT (PROJNO, ACTNO, ACSTDATE);

408

Application Programming and SQL Guide
Dropping tables
When you drop a table, you delete the data and the table definition. You also
delete all synonyms, views, indexes, and referential and check constraints that are
associated with that table.
The following SQL statement drops the YEMP table:
DROP TABLE YEMP;

Use the DROP TABLE statement with care: Dropping a table is not equivalent to
deleting all its rows. When you drop a table, you lose more than its data and its
definition. You lose all synonyms, views, indexes, and referential and check
constraints that are associated with that table. You also lose all authorities that are
granted on the table.
For more information about the syntax of the DROP statement, see the topic
“DROP” in DB2 SQL Reference.

Defining a view
A view is a named specification of a result table. Use views to control which users
have access to certain data or to simplify writing SQL statements.
Use the CREATE VIEW statement to define a view and give the view a name, just
as you do for a table. The view that is created with the following statement shows
each department manager’s name with the department data in the DSN8910.DEPT
table.
CREATE VIEW VDEPTM AS
SELECT DEPTNO, MGRNO, LASTNAME, ADMRDEPT
FROM DSN8910.DEPT, DSN8910.EMP
WHERE DSN8910.EMP.EMPNO = DSN8910.DEPT.MGRNO;

When a program accesses the data that is defined by a view, DB2 uses the view
definition to return a set of rows that the program can access with SQL statements.
Example: To see the departments that are administered by department D01 and the
managers of those departments, run the following statement, which returns
information from the VDEPTM view:
SELECT DEPTNO, LASTNAME
FROM VDEPTM
WHERE ADMRDEPT = ’DO1’;

|
|
|
|
|
|

When you create a view, you can reference the SESSION_USER and CURRENT
SQLID special registers in the CREATE VIEW statement. When referencing the
view, DB2 uses the value of the SESSION_USER or CURRENT SQLID special
register that belongs to the user of the SQL statement (SELECT, UPDATE, INSERT,
or DELETE) rather than the creator of the view. In other words, a reference to a
special register in a view definition refers to its run-time value.
A column in a view might be based on a column in a base table that is an identity
column. The column in the view is also an identity column,except under any of the
following circumstances:
v The column appears more than once in the view.
v The view is based on a join of two or more tables.
v The view is based on the union of two or more tables.

Chapter 4. Creating and modifying DB2 objects

409
v Any column in the view is derived from an expression that refers to an identity
column.
You can use views to limit access to certain kinds of data, such as salary
information. Alternatively, you can use the IMPLICITLY HIDDEN clause of a
CREATE TABLE statement define a column of a table to be hidden from some
operations.

|
|
|
|

You can also use views for the following actions:
v Make a subset of a table’s data available to an application. For example, a view
based on the employee table might contain rows only for a particular
department.
v Combine columns from two or more tables and make the combined data
available to an application. By using a SELECT statement that matches values in
one table with those in another table, you can create a view that presents data
from both tables. However, you can only select data from this type of view. You
cannot update, delete, or insert data using a view that joins two or more
tables.
v Combine rows from two or more tables and make the combined data available
to an application. By using two or more subselects that are connected by a set
operator such as UNION, you can create a view that presents data from several
tables. However, you can only select data from this type of view. You cannot
update, delete, or insert data using a view that contains UNION operations.
v Present computed data, and make the resulting data available to an application.
You can compute such data using any function or operation that you can use in
a SELECT statement.

Views
A view does not contain data; it is a stored definition of a set of rows and
columns. A view can present any or all of the data in one or more tables and, in
most cases, is interchangeable with a table.
Although you cannot modify an existing view, you can drop it and create a new
one if your base tables change in a way that affects the view. Dropping and
creating views does not affect the base tables or their data.

Restrictions when changing data through a view
Some views are read-only and thus cannot be used to update the table data. For
those views that are updatable, several restrictions apply.
Consider the following restrictions when changing data through a view:
v You must have the appropriate authorization to insert, update, or delete rows
using the view.
v When you use a view to insert a row into a table, the view definition must
specify all the columns in the base table that do not have a default value. The
row that is being inserted must contain a value for each of those columns.
v Views that you can use to update data are subject to the same referential
constraints and check constraints as the tables that you used to define the views.
You can use the WITH CHECK option of the CREATE VIEW statement to
specify the constraint that every row that is inserted or updated through the

410

Application Programming and SQL Guide
view must conform to the definition of the view. You can select every row that is
inserted or updated through a view that is created with the WITH CHECK
option.
|
|

For complex views, you can make insert, update and delete operations possible by
defining INSTEAD OF triggers.
For more information about INSTEAD OF triggers, see “Inserting, updating, and
deleting data in views by using INSTEAD OF triggers” on page 426.
For more information about read-only views, see the topic “CREATE VIEW” in
DB2 SQL Reference.

Dropping a view
When you drop a view, you also drop all views that are defined on that view. The
base table is not affected.
Example: The following SQL statement drops the VDEPTM view:
DROP VIEW VDEPTM;

Creating a common table expression
Creating a common table expression saves you the overhead of creating and
dropping a regular view that you need to use only once. Also, during statement
preparation, DB2 does not need to access the catalog for the view, which saves you
additional overhead.
Use the WITH clause to create a common table expression.
You can use a common table expression in a SELECT statement by using the WITH
clause at the beginning of the statement.
Example: WITH clause in a SELECT statement: The following statement finds the
department with the highest total pay. The query involves two levels of
aggregation. First, you need to determine the total pay for each department by
using the SUM function and order the results by using the GROUP BY clause. You
then need to find the department with highest total pay based on the total pay for
each department.
WITH DTOTAL (deptno, totalpay) AS
(SELECT deptno, sum(salary+bonus)
FROM DSN8810.EMP
GROUP BY deptno)
SELECT deptno
FROM DTOTAL
WHERE totalpay = (SELECT max(totalpay)
FROM DTOTAL);

The result table for the common table expression, DTOTAL, contains the
department number and total pay for each department in the employee table. The
fullselect in the previous example uses the result table for DTOTAL to find the
department with the highest total pay. The result table for the entire statement
looks similar to the following results:
DEPTNO
======
D11

Chapter 4. Creating and modifying DB2 objects

411
Using common table expressions with views:
You can use common table expressions before a fullselect in a CREATE VIEW
statement. This technique is useful if you need to use the results of a common
table expression in more than one query.
Example: Using a WITH clause in a CREATE VIEW statement: The following
statement finds the departments that have a greater-than-average total pay and
saves the results as the view RICH_DEPT:
CREATE VIEW RICH_DEPT (deptno) AS
WITH DTOTAL (deptno, totalpay) AS
(SELECT deptno, sum(salary+bonus)
FROM DSN8910.EMP
GROUP BY deptno)
SELECT deptno
FROM DTOTAL
WHERE totalpay > (SELECT AVG(totalpay)
FROM DTOTAL);

The fullselect in the previous example uses the result table for DTOTAL to find the
departments that have a greater-than-average total pay. The result table is saved as
the RICH_DEPT view and looks similar to the following results:
DEPTNO
======
A00
D11
D21

Using common table expressions when you use INSERT:
You can use common table expressions before a fullselect in an INSERT statement.
Example: Using a common table expression in an INSERT statement: The
following statement uses the result table for VITALDEPT to find the manager’s
number for each department that has a greater-than-average number of senior
engineers. Each manager’s number is then inserted into the vital_mgr table.
INSERT INTO vital_mgr (mgrno)
WITH VITALDEPT (deptno, se_count) AS
(SELECT deptno, count(*)
FROM DSN8910.EMP
WHERE job = ’senior engineer’
GROUP BY deptno)
SELECT d.manager
FROM DSN8910.DEPT d, VITALDEPT s
WHERE d.deptno = s.deptno
AND s.se_count > (SELECT AVG(se_count)
FROM VITALDEPT);

Common table expressions
Acommon table expression is like a temporary view that is defined and used for the
duration of an SQL statement.
You can define a common table expression wherever you can have a fullselect
statement. For example, you can include a common table expression in a SELECT,
INSERT, or CREATE VIEW statement.

|
|
|

Each common table expression must have a unique name and be defined only
once. However, you can reference a common table expression many times in the
same SQL statement. Unlike regular views or nested table expressions, which

412

Application Programming and SQL Guide
derive their result tables for each reference, all references to common table
expressions in a given statement share the same result table.
You can use a common table expression in the following situations:
v When you want to avoid creating a view (when general use of the view is not
required, and positioned updates or deletes are not used)
v When the desired result table is based on host variables
v When the same result table needs to be shared in a fullselect
v When the results need to be derived using recursion

Examples of recursive common table expressions
Recursive SQL is very useful in bill of materials (BOM) applications. These
examples illustrate some of the capability of a recursive common table expression
for BOM applications.
Consider a table of parts with associated subparts and the quantity of subparts
required by each part. For more information about recursive SQL, refer to
“Creating recursive SQL by using common table expressions” on page 612.
For the examples in this topic, create the following table:
CREATE TABLE PARTLIST
(PART VARCHAR(8),
SUBPART VARCHAR(8),
QUANTITY INTEGER);

Assume that the PARTLIST table is populated with the values that are in Table 79:
Table 79. PARTLIST table
PART

SUBPART

QUANTITY

00

01

5

00

05

3

01

02

2

01

03

3

01

04

4

01

06

3

02

05

7

02

06

6

03

07

6

04

08

10

04

09

11

05

10

10

05

11

10

06

12

10

06

13

10

07

14

8

07

12

8

Chapter 4. Creating and modifying DB2 objects

413
Example 1: Single level explosion: Single level explosion answers the question,
″What parts are needed to build the part identified by ’01’?″. The list will include
the direct subparts, subparts of the subparts and so on. However, if a part is used
multiple times, its subparts are only listed once.
WITH RPL (PART, SUBPART, QUANTITY) AS
(SELECT ROOT.PART, ROOT.SUBPART, ROOT.QUANTITY
FROM PARTLIST ROOT
WHERE ROOT.PART = ’01’
UNION ALL
SELECT CHILD.PART, CHILD.SUBPART, CHILD.QUANTITY
FROM RPL PARENT, PARTLIST CHILD
WHERE PARENT.SUBPART = CHILD.PART)
SELECT DISTINCT PART, SUBPART, QUANTITY
FROM RPL
ORDER BY PART, SUBPART, QUANTITY;

The preceding query includes a common table expression, identified by the name
RPL, that expresses the recursive part of this query. It illustrates the basic elements
of a recursive common table expression.
The first operand (fullselect) of the UNION, referred to as the initialization
fullselect, gets the direct subparts of part ’01’. The FROM clause of this fullselect
refers to the source table and will never refer to itself (RPL in this case). The result
of this first fullselect goes into the common table expression RPL. As in this
example, the UNION must always be a UNION ALL.
The second operand (fullselect) of the UNION uses RPL to compute subparts of
subparts by using the FROM clause to refer to the common table expression RPL
and the source table PARTLIST with a join of a part from the source table (child) to
a subpart of the current result contained in RPL (parent). The result goes then back
to RPL again. The second operand of UNION is used repeatedly until no more
subparts exist.
The SELECT DISTINCT in the main fullselect of this query ensures the same
part/subpart is not listed more than once.
The result of the query is shown in Table 80:
Table 80. Result table for example 1
PART

QUANTITY

01

02

2

01

03

3

01

04

4

01

06

3

02

05

7

02

06

6

03

07

6

04

08

10

04

09

11

05

10

10

05

11

10

06

12

10

06

414

SUBPART

13

10

Application Programming and SQL Guide
Table 80. Result table for example 1 (continued)
PART

SUBPART

QUANTITY

07

12

8

17

14

8

Observe in the result that part ’01’ contains subpart ’02’ which contains subpart
’06’ and so on. Further, boo pdfe that part ’06’ is reached twice, once through part
’01’ directly and another time through part ’02’. In the output, however, the
subparts of part ’06’ are listed only once (this is the result of using a SELECT
DISTINCT).
Remember that with recursive common table expressions it is possible to introduce
an infinite loop. In this example, an infinite loop would be created if the search
condition of the second operand that joins the parent and child tables was coded
as follows:
WHERE PARENT.SUBPART = CHILD.SUBPART

This infinite loop is created by not coding what is intended. You should carefully
determining what to code so that there is a definite end of the recursion cycle.
The result produced by this example could be produced in an application program
without using a recursive common table expression. However, such an application
would require coding a different query for every level of recursion. Furthermore,
the application would need to put all of the results back in the database to order
the final result. This approach complicates the application logic and does not
perform well. The application logic becomes more difficult and inefficient for other
bill of material queries, such as summarized and indented explosion queries.
Example 2: Summarized explosion: A summarized explosion answers the
question, ″What is the total quantity of each part required to build part ’01’?″ The
main difference from a single level explosion is the need to aggregate the
quantities. A single level explosion indicates the quantity of subparts required for
the part whenever it is required. It does not indicate how many of each subpart is
needed to build part ’01’.
WITH RPL (PART, SUBPART, QUANTITY) AS
(
SELECT ROOT.PART, ROOT.SUBPART, ROOT.QUANTITY
FROM PARTLIST ROOT
WHERE ROOT.PART = ’01’
UNION ALL
SELECT PARENT.PART, CHILD.SUBPART,
PARENT.QUANTITY*CHILD.QUANTITY
FROM RPL PARENT, PARTLIST CHILD
WHERE PARENT.SUBPART = CHILD.PART
)
SELECT PART, SUBPART, SUM(QUANTITY) AS "Total QTY Used"
FROM RPL
GROUP BY PART, SUBPART
ORDER BY PART, SUBPART;

In the preceding query, the select list of the second operand of the UNION in the
recursive common table expression, identified by the name RPL, shows the
aggregation of the quantity. To determine how many of each subpart is used, the
quantity of the parent is multiplied by the quantity per parent of a child. If a part
is used multiple times in different places, it requires another final aggregation. This

Chapter 4. Creating and modifying DB2 objects

415
is done by the grouping the parts and subparts in the common table expression
RPL and using the SUM column function in the select list of the main fullselect.
The result of the query is shown in Table 81:
Table 81. Result table for example 2
PART

SUBPART

Total QTY Used

01

02

2

01

03

3

01

04

4

01

05

14

01

06

15

01

07

18

01

08

40

01

09

44

01

10

140

01

11

140

01

12

294

01

13

150

01

14

144

Consider the total quantity for subpart ’06’. The value of 15 is derived from a
quantity of 3 directly for part ’01’ and a quantity of 6 for part ’02’ which is needed
two times by part ’01’.
Example 3: Controlling depth: You can control the depth of a recursive query to
answer the question, ″What are the first two levels of parts that are needed to
build part ’01’?″ For the sake of clarity in this example, the level of each part is
included in the result table.
WITH RPL (LEVEL, PART, SUBPART, QUANTITY) AS
(
SELECT 1, ROOT.PART, ROOT.SUBPART, ROOT.QUANTITY
FROM PARTLIST ROOT
WHERE ROOT.PART = ’01’
UNION ALL
SELECT PARENT.LEVEL+1, CHILD.PART, CHILD.SUBPART, CHILD.QUANTITY
FROM RPL PARENT, PARTLIST CHILD
WHERE PARENT.SUBPART = CHILD.PART
AND PARENT.LEVEL < 2
)
SELECT PART, LEVEL, SUBPART, QUANTITY
FROM RPL;

This query is similar to the query in example 1. The column LEVEL is introduced
to count the level each subpart is from the original part. In the initialization
fullselect, the value for the LEVEL column is initialized to 1. In the subsequent
fullselect, the level from the parent table increments by 1. To control the number of
levels in the result, the second fullselect includes the condition that the level of the
parent must be less than 2. This ensures that the second fullselect only processes
children to the second level.

416

Application Programming and SQL Guide
The result of the query is shown in Table 82:
Table 82. Result table for example 3
PART

LEVEL

SUBPART

QUANTITY

01

1

02

2

01

1

03

3

01

1

04

4

01

1

06

3

02

2

05

7

02

2

06

6

03

2

07

6

04

2

08

10

04

2

09

11

06

2

12

10

06

2

13

10

Creating triggers
A trigger is a set of SQL statements that execute when a certain event occurs in a
table. Use triggers to control changes in DB2 databases. Triggers are more powerful
than constraints, because they can monitor a broader range of changes and
perform a broader range of actions than constraints can.
Using triggers for active data:
For example, a constraint can disallow an update to the salary column of the
employee table if the new value is over a certain amount. A trigger can monitor
the amount by which the salary changes, as well as the salary value. If the change
is above a certain amount, the trigger might substitute a valid value and call a
user-defined function to send a boo pdfe to an administrator about the invalid
update.
Triggers also move application logic into DB2, which can result in faster
application development and easier maintenance. For example, you can write
applications to control salary changes in the employee table, but each application
program that changes the salary column must include logic to check those changes.
A better method is to define a trigger that controls changes to the salary column.
Then DB2 does the checking for any application that modifies salaries.
Example of creating and using a trigger:
Triggers automatically execute a set of SQL statements whenever a specified event
occurs. These SQL statements can perform tasks such as validation and editing of
table changes, reading and modifying tables, or invoking functions or stored
procedures that perform operations both inside and outside DB2.
You create triggers using the CREATE TRIGGER statement. The following figure
shows an example of a CREATE TRIGGER statement.
1
CREATE TRIGGER REORDER
2
3
4
AFTER UPDATE OF ON_HAND, MAX_STOCKED ON PARTS
Chapter 4. Creating and modifying DB2 objects

417
5
REFERENCING NEW AS N_ROW
6
FOR EACH ROW MODE DB2SQL
7
WHEN (N_ROW.ON_HAND < 0.10 * N_ROW.MAX_STOCKED)
8
BEGIN ATOMIC
CALL ISSUE_SHIP_REQUEST(N_ROW.MAX_STOCKED N_ROW.ON_HAND,
N_ROW.PARTNO);
END

The parts of this trigger are:
1

Trigger name (REORDER)

2

Trigger activation time (AFTER)

3

Triggering event (UPDATE)

4

Subject table name (PARTS)

5

New transition variable correlation name (N_ROW)

6

Granularity (FOR EACH ROW)

7

Trigger condition (WHEN...)

8

Trigger body (BEGIN ATOMIC...END;)

When you execute this CREATE TRIGGER statement, DB2 creates a trigger
package called REORDER and associates the trigger package with table PARTS.
DB2 records the timestamp when it creates the trigger. If you define other triggers
on the PARTS table, DB2 uses this timestamp to determine which trigger to
activate first. The trigger is now ready to use.
After DB2 updates columns ON_HAND or MAX_STOCKED in any row of table
PARTS, trigger REORDER is activated. The trigger calls a stored procedure called
ISSUE_SHIP_REQUEST if, after a row is updated, the quantity of parts on hand is
less than 10% of the maximum quantity stocked. In the trigger condition, the
qualifier N_ROW represents a value in a modified row after the triggering event.
When you no longer want to use trigger REORDER, you can delete the trigger by
executing the statement:
DROP TRIGGER REORDER;

Executing this statement drops trigger REORDER and its associated trigger
package named REORDER.
If you drop table PARTS, DB2 also drops trigger REORDER and its trigger
package.
Parts of a trigger:
A trigger contains the following parts:
v trigger name
v subject table
v trigger activation time
v triggering event
v granularity
v transition variables

418

Application Programming and SQL Guide
v transition tables
v triggered action
Trigger name:
Use an ordinary identifier to name your trigger. You can use a qualifier or let DB2
determine the qualifier. When DB2 creates a trigger package for the trigger, it uses
the qualifier for the collection ID of the trigger package. DB2 uses these rules to
determine the qualifier:
v If you use static SQL to execute the CREATE TRIGGER statement, DB2 uses the
authorization ID in the bind option QUALIFIER for the plan or package that
contains the CREATE TRIGGER statement. If the bind command does not
include the QUALIFIER option, DB2 uses the owner of the package or plan.
|
|

v If you use dynamic SQL to execute the CREATE TRIGGER statement, DB2 uses
the authorization ID in special register CURRENT SCHEMA.
Subject table:
When you perform an insert, update, or delete operation on this table, the trigger
is activated. You must name a local table in the CREATE TRIGGER statement. You
cannot define a trigger on a catalog table or on a view.
Trigger activation time:
The two choices for trigger activation time are NO CASCADE BEFORE and
AFTER. NO CASCADE BEFORE means that the trigger is activated before DB2
makes any changes to the subject table, and that the triggered action does not
activate any other triggers. AFTER means that the trigger is activated after DB2
makes changes to the subject table and can activate other triggers. Triggers with an
activation time of NO CASCADE BEFORE are known as before triggers. Triggers
with an activation time of AFTER are known as after triggers.
Triggering event:
Every trigger is associated with an event. A trigger is activated when the triggering
event occurs in the subject table. The triggering event is one of the following SQL
operations:
v insert
v update
v delete
A triggering event can also be an update or delete operation that occurs as the
result of a referential constraint with ON DELETE SET NULL or ON DELETE
CASCADE.
Triggers are not activated as the result of updates made to tables by DB2 utilities,
with the exception of the LOAD utility when it is specified with the RESUME YES
and SHRLEVEL CHANGE options. For more information about these options, see
the topic “LOAD” in DB2 Utility Guide and Reference.
When the triggering event for a trigger is an update operation, the trigger is called
an update trigger. Similarly, triggers for insert operations are called insert triggers,
and triggers for delete operations are called delete triggers.

Chapter 4. Creating and modifying DB2 objects

419
The SQL statement that performs the triggering SQL operation is called the
triggering SQL statement. Each triggering event is associated with one subject table
and one SQL operation.
The following trigger is defined with an insert triggering event:
CREATE TRIGGER NEW_HIRE
AFTER INSERT ON EMP
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1;
END

If the triggering SQL operation is an update operation, the event can be associated
with specific columns of the subject table. In this case, the trigger is activated only
if the update operation updates any of the specified columns.
The following trigger, PAYROLL1, which invokes user-defined function named
PAYROLL_LOG, is activated only if an update operation is performed on the
SALARY or BONUS column of table PAYROLL:
CREATE TRIGGER PAYROLL1
AFTER UPDATE OF SALARY, BONUS ON PAYROLL
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
VALUES(PAYROLL_LOG(USER, ’UPDATE’, CURRENT TIME, CURRENT DATE));
END

Granularity:
The triggering SQL statement might modify multiple rows in the table. The
granularity of the trigger determines whether the trigger is activated only once for
the triggering SQL statement or once for every row that the SQL statement
modifies. The granularity values are:
v FOR EACH ROW
The trigger is activated once for each row that DB2 modifies in the subject table.
If the triggering SQL statement modifies no rows, the trigger is not activated.
However, if the triggering SQL statement updates a value in a row to the same
value, the trigger is activated. For example, if an UPDATE trigger is defined on
table COMPANY_STATS, the following SQL statement will activate the trigger.
UPDATE COMPANY_STATS SET NBEMP = NBEMP;

v FOR EACH STATEMENT
The trigger is activated once when the triggering SQL statement executes. The
trigger is activated even if the triggering SQL statement modifies no rows.
Triggers with a granularity of FOR EACH ROW are known as row triggers.
Triggers with a granularity of FOR EACH STATEMENT are known as statement
triggers. Statement triggers can only be after triggers.
The following statement is an example of a row trigger:
CREATE TRIGGER NEW_HIRE
AFTER INSERT ON EMP
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1;
END

Trigger NEW_HIRE is activated once for every row inserted into the employee
table.

420

Application Programming and SQL Guide
Transition variables:
When you code a row trigger, you might need to refer to the values of columns in
each updated row of the subject table. To do this, specify transition variables in the
REFERENCING clause of your CREATE TRIGGER statement. The two types of
transition variables are:
v Old transition variables, specified with the OLD transition-variable clause, capture
the values of columns before the triggering SQL statement updates them. You
can define old transition variables for update and delete triggers.
v New transition variables, specified with the NEW transition-variable clause,
capture the values of columns after the triggering SQL statement updates them.
You can define new transition variables for update and insert triggers.
The following example uses transition variables and invocations of the
IDENTITY_VAL_LOCAL function to access values that are assigned to identity
columns.
Suppose that you have created tables T and S, with the following definitions:
CREATE TABLE T
(ID SMALLINT GENERATED BY DEFAULT AS IDENTITY (START WITH 100),
C2 SMALLINT,
C3 SMALLINT,
C4 SMALLINT);
CREATE TABLE S
(ID SMALLINT GENERATED ALWAYS AS IDENTITY,
C1 SMALLINT);

Define a before insert trigger on T that uses the IDENTITY_VAL_LOCAL built-in
function to retrieve the current value of identity column ID, and uses transition
variables to update the other columns of T with the identity column value.
CREATE TRIGGER TR1
NO CASCADE BEFORE INSERT
ON T REFERENCING NEW AS N
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
SET N.C3 =N.ID;
SET N.C4 =IDENTITY_VAL_LOCAL();
SET N.ID =N.C2 *10;
SET N.C2 =IDENTITY_VAL_LOCAL();
END

Now suppose that you execute the following INSERT statement:
INSERT INTO S (C1) VALUES (5);

This statement inserts a row into S with a value of 5 for column C1 and a value of
1 for identity column ID. Next, suppose that you execute the following SQL
statement, which activates trigger TR1:
INSERT INTO T (C2)
VALUES (IDENTITY_VAL_LOCAL());

This insert statement, and the subsequent activation of trigger TR1, have the
following results:
v The INSERT statement obtains the most recent value that was assigned to an
identity column (1), and inserts that value into column C2 of table T. 1 is the
value that DB2 inserted into identity column ID of table S.
v When the INSERT statement executes, DB2 inserts the value 100 into identity
column ID column of C2.
Chapter 4. Creating and modifying DB2 objects

421
v The first statement in the body of trigger TR1 inserts the value of transition
variable N.ID (100) into column C3. N.ID is the value that identity column ID
contains after the INSERT statement executes.
v The second statement in the body of trigger TR1 inserts the null value into
column C4. By definition, the result of the IDENTITY_VAL_LOCAL function in
the triggered action of a before insert trigger is the null value.
v The third statement in the body of trigger TR1 inserts 10 times the value of
transition variable N.C2 (10*1) into identity column ID of table T. N.C2 is the
value that column C2 contains after the INSERT is executed.
v The fourth statement in the body of trigger TR1 inserts the null value into
column C2. By definition, the result of the IDENTITY_VAL_LOCAL function in
the triggered action of a before insert trigger is the null value.
Transition tables:
If you want to refer to the entire set of rows that a triggering SQL statement
modifies, rather than to individual rows, use a transition table. Like transition
variables, transition tables can appear in the REFERENCING clause of a CREATE
TRIGGER statement. Transition tables are valid for both row triggers and statement
triggers. The two types of transition tables are:
v Old transition tables, specified with the OLD TABLE transition-table-name clause,
capture the values of columns before the triggering SQL statement updates
them. You can define old transition tables for update and delete triggers.
v New transition tables, specified with the NEW TABLE transition-table-name
clause, capture the values of columns after the triggering SQL statement updates
them. You can define new transition variables for update and insert triggers.
The scope of old and new transition table names is the trigger body. If another
table exists that has the same name as a transition table, any unqualified reference
to that name in the trigger body points to the transition table. To reference the
other table in the trigger body, you must use the fully qualified table name.
The following example uses a new transition table to capture the set of rows that
are inserted into the INVOICE table:
CREATE TRIGGER LRG_ORDR
AFTER INSERT ON INVOICE
REFERENCING NEW TABLE AS N_TABLE
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
SELECT LARGE_ORDER_ALERT(CUST_NO,
TOTAL_PRICE, DELIVERY_DATE)
FROM N_TABLE WHERE TOTAL_PRICE > 10000;
END

The SELECT statement in LRG_ORDER causes user-defined function
LARGE_ORDER_ALERT to execute for each row in transition table N_TABLE that
satisfies the WHERE clause (TOTAL_PRICE > 10000).
Triggered action:
When a trigger is activated, a triggered action occurs. Every trigger has one
triggered action, which consists of a trigger condition and a trigger body.
Trigger condition:

422

Application Programming and SQL Guide
If you want the triggered action to occur only when certain conditions are true,
code a trigger condition. A trigger condition is similar to a predicate in a SELECT,
except that the trigger condition begins with WHEN, rather than WHERE. If you
do not include a trigger condition in your triggered action, the trigger body
executes every time the trigger is activated.
For a row trigger, DB2 evaluates the trigger condition once for each modified row
of the subject table. For a statement trigger, DB2 evaluates the trigger condition
once for each execution of the triggering SQL statement.
If the trigger condition of a before trigger has a fullselect, the fullselect cannot
reference the subject table.
The following example shows a trigger condition that causes the trigger body to
execute only when the number of ordered items is greater than the number of
available items:
CREATE TRIGGER CK_AVAIL
NO CASCADE BEFORE INSERT ON ORDERS
REFERENCING NEW AS NEW_ORDER
FOR EACH ROW MODE DB2SQL
WHEN (NEW_ORDER.QUANTITY >
(SELECT ON_HAND FROM PARTS
WHERE NEW_ORDER.PARTNO=PARTS.PARTNO))
BEGIN ATOMIC
VALUES(ORDER_ERROR(NEW_ORDER.PARTNO,
NEW_ORDER.QUANTITY));
END

Trigger body:
In the trigger body, you code the SQL statements that you want to execute
whenever the trigger condition is true. If the trigger body consists of more than
one statement, it must begin with BEGIN ATOMIC and end with END. You cannot
include host variables or parameter markers in your trigger body. If the trigger
body contains a WHERE clause that references transition variables, the comparison
operator cannot be LIKE.
The statements you can use in a trigger body depend on the activation time of the
trigger. For a list of valid SQL statements for triggers, see the ″Allowable SQL
statements″ table in the topic “CREATE TRIGGER” in DB2 SQL Reference.
The following list provides more detailed information about SQL statements that
are valid in triggers:
v fullselect, CALL, and VALUES
Use a fullselect or the VALUES statement in a trigger body to conditionally or
unconditionally invoke a user-defined function. Use the CALL statement to
invoke a stored procedure. See “Invoking stored procedures and user-defined
functions from triggers” on page 425 for more information on invoking
user-defined functions and stored procedures from triggers.
A fullselect in the trigger body of a before trigger cannot reference the subject
table.
v SIGNAL
Use the SIGNAL statement in the trigger body to report an error condition and
back out any changes that are made by the trigger, as well as actions that result
from referential constraints on the subject table. When DB2 executes the SIGNAL

Chapter 4. Creating and modifying DB2 objects

423
statement, it returns an SQLCA to the application with SQLCODE -438. The
SQLCA also includes the following values, which you supply in the SIGNAL
statement:
– A 5-character value that DB2 uses as the SQLSTATE
– An error message that DB2 places in the SQLERRMC field
In the following example, the SIGNAL statement causes DB2 to return an
SQLCA with SQLSTATE 75001 and terminate the salary update operation if an
employee’s salary increase is over 20%:
CREATE TRIGGER SAL_ADJ
BEFORE UPDATE OF SALARY ON EMP
REFERENCING OLD AS OLD_EMP
NEW AS NEW_EMP
FOR EACH ROW MODE DB2SQL
WHEN (NEW_EMP.SALARY > (OLD_EMP.SALARY * 1.20))
BEGIN ATOMIC
SIGNAL SQLSTATE ’75001’
(’Invalid Salary Increase - Exceeds 20%’);
END

v SET transition-variable
Because before triggers operate on rows of a table before those rows are
modified, you cannot perform operations in the body of a before trigger that
directly modify the subject table. You can, however, use the SET
transition-variable statement to modify the values in a row before those values go
into the table. For example, this trigger uses a new transition variable to fill in
today’s date for the new employee’s hire date:
CREATE TRIGGER HIREDATE
NO CASCADE BEFORE INSERT ON EMP
REFERENCING NEW AS NEW_VAR
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
SET NEW_VAR.HIRE_DATE = CURRENT_DATE;
END

v INSERT, DELETE (searched), UPDATE (searched), and MERGE
Because you can include INSERT, DELETE (searched), UPDATE (searched), and
MERGE statements in your trigger body, execution of the trigger body might
cause activation of other triggers. See “Trigger cascading” on page 428 for more
information.

|
|
|
|
|

If any SQL statement in the trigger body fails during trigger execution, DB2 rolls
back all changes that are made by the triggering SQL statement and the triggered
SQL statements. However, if the trigger body executes actions that are outside of
DB2’s control or are not under the same commit coordination as the DB2
subsystem in which the trigger executes, DB2 cannot undo those actions. Examples
of external actions that are not under DB2’s control are:
v Performing updates that are not under RRS commit control
v Sending an electronic mail message
If the trigger executes external actions that are under the same commit
coordination as the DB2 subsystem under which the trigger executes, and an error
occurs during trigger execution, DB2 places the application process that issued the
triggering statement in a must-rollback state. The application must then execute a
rollback operation to roll back those external actions. Examples of external actions
that are under the same commit coordination as the triggering SQL operation are:
v Executing a distributed update operation
v From a user-defined function or stored procedure, executing an external action
that affects an external resource manager that is under RRS commit control.

424

Application Programming and SQL Guide
Invoking stored procedures and user-defined functions from
triggers
A trigger body can include only SQL statements. To perform actions or use logic
that is not available in SQL statements, create user-defined functions or stored
procedures that can be invoked from within the trigger body.
“User-defined functions” on page 443 contains detailed information on how to
write and prepare user-defined functions and stored procedures.
|
|
|

Because a before trigger must not modify any table, functions and procedures that
you invoke from a trigger cannot include INSERT, UPDATE, DELETE, or MERGE
statements that modify the subject table.
To invoke a user-defined function from a trigger, code a SELECT statement or
VALUES statement. Use a SELECT statement to execute the function conditionally.
The number of times the user-defined function executes depends on the number of
rows in the result table of the SELECT statement. For example, in this trigger, the
SELECT statement causes user-defined function LARGE_ORDER_ALERT to
execute for each row in transition table N_TABLE with an order of more than
10000:
CREATE TRIGGER LRG_ORDR
AFTER INSERT ON INVOICE
REFERENCING NEW TABLE AS N_TABLE
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
SELECT LARGE_ORDER_ALERT(CUST_NO, TOTAL_PRICE, DELIVERY_DATE)
FROM N_TABLE WHERE TOTAL_PRICE > 10000;
END

Use the VALUES statement to execute a function unconditionally; that is, once for
each execution of a statement trigger or once for each row in a row trigger. In this
example, user-defined function PAYROLL_LOG executes every time an update
operation occurs that activates trigger PAYROLL1:
CREATE TRIGGER PAYROLL1
AFTER UPDATE ON PAYROLL
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
VALUES(PAYROLL_LOG(USER, ’UPDATE’,
CURRENT TIME, CURRENT DATE));
END

To invoke a stored procedure from a trigger, use a CALL statement. The
parameters of this stored procedure call must be constants, transition variables,
table locators, or expressions.
Passing transition tables to user-defined functions and stored procedures:
When you call a user-defined function or stored procedure from a trigger, you
might want to give the function or procedure access to the entire set of modified
rows. That is, you want to pass a pointer to the old or new transition table. You do
this using table locators.
Most of the code for using a table locator is in the function or stored procedure
that receives the locator. “Accessing transition tables in a user-defined function or
stored procedure” on page 473 explains how a function defines a table locator and
uses it to receive a transition table. To pass the transition table from a trigger,
specify the parameter TABLE transition-table-name when you invoke the function or
Chapter 4. Creating and modifying DB2 objects

425
stored procedure. This causes DB2 to pass a table locator for the transition table to
the user-defined function or stored procedure. For example, this trigger passes a
table locator for a transition table NEWEMPS to stored procedure CHECKEMP:
CREATE TRIGGER EMPRAISE
AFTER UPDATE ON EMP
REFERENCING NEW TABLE AS NEWEMPS
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
CALL CHECKEMP(TABLE NEWEMPS);
END

Inserting, updating, and deleting data in views by using
INSTEAD OF triggers

|
|
|
|
|
|

INSTEAD OF triggers are triggers that execute instead of the INSERT, UPDATE, or
DELETE statement that activates the trigger. You can define these triggers on views
only. Use INSTEAD OF triggers to insert, update, and delete data in complex
views.

|
|
|
|
|
|
|
|

Complex views are those views that are defined on expressions or multiple tables.
In some cases, those views are read only. In these cases, INSTEAD OF triggers
make the insert, update and delete operations possible. If the complex view is not
read only, you can request an insert, update, or delete operation. However, DB2
automatically decides how to perform that operation on the base tables that are
referenced in the view. With INSTEAD OF triggers, you can define exactly how
DB2 is to execute an insert, update, or delete operation on the view. You no longer
leave the decision to DB2.

|

To insert, update, or delete data in a view by using INSTEAD OF triggers:
1. Define one or more INSTEAD OF triggers on the view by using a CREATE
TRIGGER statement.
You can create one trigger for each of the following operations: INSERT,
UPDATE, and DELETE. These triggers define the action that DB2 is to take for
each of these operations.
For information about the syntax of the CREATE TRIGGER statement, see the
topic “CREATE TRIGGERS” in DB2 SQL Reference.
2. Submit a INSERT, UPDATE, or DELETE statement on the view.
DB2 executes the appropriate INSTEAD OF trigger.

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

Example: Suppose that you create the following view on the sample tables
DSN8910.EMP and DSN8910.DEPT:

|
|
|
|
|
|
|
|
|
|
|
|

Suppose that you also define the following three INSTEAD OF triggers:

CREATE VIEW EMPV (EMPNO, FIRSTNME, MIDINIT, LASTNAME, PHONENO, HIREDATE,DEPTNAME)
AS SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, PHONENO, HIREDATE, DEPTNAME
FROM DSN8910.EMP, DSN8910.DEPT WHERE DSN8910.EMP.WORKDEPT
= DSN8910.DEPT.DEPTNO

CREATE TRIGGER EMPV_INSERT INSTEAD OF INSERT ON EMPV
REFERENCING NEW AS NEWEMP
FOR EACH ROW MODE DB2SQL
INSERT INTO DSN8910.EMP (EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT,
PHONENO, HIREDATE)
VALUES(NEWEMP.EMPNO, NEWEMP.FIRSTNME, NEWEMP.MIDINIT, NEWEMP.LASTNAME,
COALESCE((SELECT D.DEPTNO FROM DSN8910.DEPT AS D
WHERE D.DEPTNAME = NEWEMP.DEPTNAME),
RAISE_ERROR(’70001’, ’Unknown department name’)),
NEWEMP.PHONENO, NEWEMP.HIREDATE)

426

Application Programming and SQL Guide
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

CREATE TRIGGER EMPV_UPDATE INSTEAD OF UPDATE ON EMPV
REFERENCING NEW AS NEWEMP OLD AS OLDEMP
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
UPDATE DSN8910.EMP AS E
SET (E.FIRSTNME, E.MIDINIT, E.LASTNAME, E.WORKDEPT, E.PHONENO,
E.HIREDATE)
= (NEWEMP.FIRSTNME, NEWEMP.MIDINIT, NEWEMP.LASTNAME,
COALESCE((SELECT D.DEPTNO FROM DSN8910.DEPT AS D
WHERE D.DEPTNAME = OLDEMP.DEPTNAME),
RAISE_ERROR (’70001’, ’Unknown department name’))
NEWEMP.PHONENO, NEWEMP.HIREDATE)
WHERE NEWEMP.EMPNO = E.EMPNO;
UPDATE DSN8910.DEPT D SET D.DEPTNAME=NEWEMP.DEPTNAME
WHERE D.DEPTNAME=OLDEMP.DEPTNAME;
END

|
|

Because the view is on a query with an inner join, the view is read only. However,
the INSTEAD OF triggers makes insert, update, and delete operations possible.

|
|

Table 83 describes what happens for various insert, update, and delete operations
on the EMPV view.

|

Table 83. Results of INSTEAD OF triggers

|

SQL statement

Result

|
|
|
|
|
|
|
|
|
|

INSERT INTO EMPV VALUES (...)

The EMPV_INSERT trigger is activated. This
trigger inserts the row into the base table
DSN8910.EMP if the department name
matches a value in the WORKDEPT column
in the DSN8910.DEPT table. Otherwise, an
error is returned. If a query had been used
instead of a VALUES clause on the INSERT
statement, the trigger body would be
processed for each row from the query.

|
|
|
|
|
|

UPDATE EMPV
SET DEPTNAME=’PLANNING & STRATEGY’
WHERE DEPTNAME=’PLANNING’

The EMPV_UPDATE trigger is activated. This
trigger updates the DEPTNAME column in
the DSN8910.DEPT for the any qualifying
rows.

|
|
|
|
|
|

DELETE FROM EMPV
WHERE HIREDATE<’1910-01-01’

The EMPV_DELETE trigger is activated. This
trigger deletes the qualifying rows from the
DSN8910.EMP table.

|

CREATE TRIGGER EMPV_DELETE INSTEAD OF DELETE ON EMPV
REFERENCING OLD AS OLDEMP
FOR EACH ROW MODE DB2SQL
DELETE FROM DSN8910.EMP AS E WHERE E.EMPNO = OLDEMP.EMPNO

Trigger packages
A trigger package is a special type of package that is created only when you
execute a CREATE TRIGGER statement. A trigger package executes only when its
associated trigger is activated.
As with any other package, DB2 marks a trigger package invalid when you drop a
table, index, or view on which the trigger package depends. DB2 executes an
automatic rebind the next time the trigger is activated. However, if the automatic
rebind fails, DB2 does not mark the trigger package as inoperative.

Chapter 4. Creating and modifying DB2 objects

427
Unlike other packages, a trigger package is freed if you drop the table on which
the trigger is defined, so you can recreate the trigger package only by recreating
the table and the trigger.
You can use the subcommand REBIND TRIGGER PACKAGE to rebind a trigger
package that DB2 has marked as inoperative. You can also use REBIND TRIGGER
PACKAGE to change the option values with which DB2 originally bound the
trigger package. You can change only a limited subset of the default bind options
that DB2 used when creating the package. For a description of these options, see
the topic “REBIND TRIGGER PACKAGE (DSN)” in DB2 Command Reference.

Trigger cascading
When a trigger performs an SQL operation, it might modify the subject table or
other tables with triggers, so DB2 also activates those triggers. This situation is
called trigger cascading.
A trigger that is activated as the result of another trigger can be activated at the
same level as the original trigger or at a different level. Two triggers, A and B, are
activated at different levels if trigger B is activated after trigger A is activated and
completes before trigger A completes. If trigger B is activated after trigger A is
activated and completes after trigger A completes, then the triggers are at the same
level.
For example, in these cases, trigger A and trigger B are activated at the same level:
v Table X has two triggers that are defined on it, A and B. A is a before trigger and
B is an after trigger. An update to table X causes both trigger A and trigger B to
activate.
v Trigger A updates table X, which has a referential constraint with table Y, which
has trigger B defined on it. The referential constraint causes table Y to be
updated, which activates trigger B.
In these cases, trigger A and trigger B are activated at different levels:
v Trigger A is defined on table X, and trigger B is defined on table Y. Trigger B is
an update trigger. An update to table X activates trigger A, which contains an
UPDATE statement on table B in its trigger body. This UPDATE statement
activates trigger B.
v Trigger A calls a stored procedure. The stored procedure contains an INSERT
statement for table X, which has insert trigger B defined on it. When the INSERT
statement on table X executes, trigger B is activated.
When triggers are activated at different levels, it is called trigger cascading. Trigger
cascading can occur only for after triggers because DB2 does not support cascading
of before triggers.
To prevent the possibility of endless trigger cascading, DB2 supports only 16 levels
of cascading of triggers, stored procedures, and user-defined functions. If a trigger,
user-defined function, or stored procedure at the 17th level is activated, DB2
returns SQLCODE -724 and backs out all SQL changes in the 16 levels of
cascading. However, as with any other SQL error that occurs during trigger
execution, if any action occurs that is outside the control of DB2, that action is not
backed out.
You can write a monitor program that issues IFI READS requests to collect DB2
trace information about the levels of cascading of triggers, user-defined functions,

428

Application Programming and SQL Guide
and stored procedures in your programs. For information on how to write a
monitor program, see the topic “Invoking IFI from your program” in DB2
Performance Monitoring and Tuning Guide.

Order of multiple triggers
You can create multiple triggers for the same subject table, event, and activation
time. The order in which those triggers are activated is the order in which the
triggers were created.
DB2 records the timestamp when each CREATE TRIGGER statement executes.
When an event occurs in a table that activates more than one trigger, DB2 uses the
stored timestamps to determine which trigger to activate first.
DB2 always activates all before triggers that are defined on a table before the after
triggers that are defined on that table, but within the set of before triggers, the
activation order is by timestamp, and within the set of after triggers, the activation
order is by timestamp.
In this example, triggers NEWHIRE1 and NEWHIRE2 have the same triggering
event (INSERT), the same subject table (EMP), and the same activation time
(AFTER). Suppose that the CREATE TRIGGER statement for NEWHIRE1 is run
before the CREATE TRIGGER statement for NEWHIRE2:
CREATE TRIGGER NEWHIRE1
AFTER INSERT ON EMP
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1;
END
CREATE TRIGGER NEWHIRE2
AFTER INSERT ON EMP
REFERENCING NEW AS N_EMP
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
UPDATE DEPTS SET NBEMP = NBEMP + 1
WHERE DEPT_ID = N_EMP.DEPT_ID;
END

When an insert operation occurs on table EMP, DB2 activates NEWHIRE1 first
because NEWHIRE1 was created first. Now suppose that someone drops and
re-creates NEWHIRE1. NEWHIRE1 now has a later timestamp than NEWHIRE2,
so the next time an insert operation occurs on EMP, NEWHIRE2 is activated before
NEWHIRE1.
If two row triggers are defined for the same action, the trigger that was created
earlier is activated first for all affected rows. Then the second trigger is activated
for all affected rows. In the previous example, suppose that an INSERT statement
with a fullselect inserts 10 rows into table EMP. NEWHIRE1 is activated for all 10
rows, then NEWHIRE2 is activated for all 10 rows.

Interactions between triggers and referential constraints
When you create triggers, you need to understand the interactions among the
triggers and constraints on your tables and the effect that the order of processing
of those constraints and triggers can have on the results.
In general, the following steps occur when triggering SQL statement S1 performs
an insert, update, or delete operation on table T1:
Chapter 4. Creating and modifying DB2 objects

429
1. DB2 determines the rows of T1 to modify. Call that set of rows M1. The
contents of M1 depend on the SQL operation:
v For a delete operation, all rows that satisfy the search condition of the
statement for a searched delete operation, or the current row for a positioned
delete operation
v For an insert operation, the row identified by the VALUES statement, or the
rows identified by the result table of a SELECT clause within the INSERT
statement
v For an update operation, all rows that satisfy the search condition of the
statement for a searched update operation, or the current row for a
positioned update operation
2. DB2 processes all before triggers that are defined on T1, in order of creation.
Each before trigger executes the triggered action once for each row in M1. If
M1 is empty, the triggered action does not execute.
If an error occurs when the triggered action executes, DB2 rolls back all
changes that are made by S1.
3. DB2 makes the changes that are specified in statement S1 to table T1, unless an
INSTEAD OF trigger is defined for that action. If an appropriate INSTEAD OF
trigger is defined, DB2 executes the trigger instead of the statement and skips
the remaining steps in this list.

|
|
|
|
|

If an error occurs, DB2 rolls back all changes that are made by S1.
4. If M1 is not empty, DB2 applies all the following constraints and checks that
are defined on table T1:
v Referential constraints
v Check constraints
v Checks that are due to updates of the table through views defined WITH
CHECK OPTION
Application of referential constraints with rules of DELETE CASCADE or
DELETE SET NULL are activated before delete triggers or before update
triggers on the dependent tables.
If any constraint is violated, DB2 rolls back all changes that are made by
constraint actions or by statement S1.
5. DB2 processes all after triggers that are defined on T1, and all after triggers on
tables that are modified as the result of referential constraint actions, in order of
creation.
Each after row trigger executes the triggered action once for each row in M1. If
M1 is empty, the triggered action does not execute.
Each after statement trigger executes the triggered action once for each
execution of S1, even if M1 is empty.
If any triggered actions contain SQL insert, update, or delete operations, DB2
repeats steps 1 through 5 for each operation.
If an error occurs when the triggered action executes, or if a triggered action is at
the 17th level of trigger cascading, DB2 rolls back all changes that are made in step
5 and all previous steps.
For example, table DEPT is a parent table of EMP, with these conditions:
v The DEPTNO column of DEPT is the primary key.
v The WORKDEPT column of EMP is the foreign key.
v The constraint is ON DELETE SET NULL.
Suppose the following trigger is defined on EMP:

430

Application Programming and SQL Guide
CREATE TRIGGER EMPRAISE
AFTER UPDATE ON EMP
REFERENCING NEW TABLE AS NEWEMPS
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
VALUES(CHECKEMP(TABLE NEWEMPS));
END

Also suppose that an SQL statement deletes the row with department number E21
from DEPT. Because of the constraint, DB2 finds the rows in EMP with a
WORKDEPT value of E21 and sets WORKDEPT in those rows to null. This is
equivalent to an update operation on EMP, which has update trigger EMPRAISE.
Therefore, because EMPRAISE is an after trigger, EMPRAISE is activated after the
constraint action sets WORKDEPT values to null.

Interactions between triggers and tables that have multilevel
security with row-level granularity
A BEFORE trigger affects the value of the transition variable that is associated with
a security label column.
If a subject table has a security label column, the column in the transition table or
transition variable that corresponds to the security label column in the subject table
does not inherit the security label attribute. This means that the multilevel security
check with row-level granularity is not enforced for the transition table or the
transition variable. If you add a security label column to a subject table using the
ALTER TABLE statement, the rules are the same as when you add any column to a
subject table because the column in the transition table or the transition variable
that corresponds to the security label column does not inherit the security label
attribute.
If the ID you are using does not have write-down privilege and you execute an
insert or update operation, the security label value of your ID is assigned to the
security label column for the rows that you are inserting or updating.
When a BEFORE trigger is activated, the value of the transition variable that
corresponds to the security label column is the security label of the ID if either of
the following conditions is true:
v The user does not have write-down privilege
v The value for the security label column is not specified
If the user does not have write-down privilege, and the trigger changes the
transition variable that corresponds to the security label column, the value of the
security label column is changed back to the security label value of the user before
the row is written to the page. For more information about multilevel security with
row-level granularity, see the topic “Multilevel security” in DB2 Administration
Guide.

Triggers that return inconsistent results
When you create triggers and write SQL statements that activate those triggers,
you need to ensure that executing those statements on the same set of data always
produces the same results.
Two common reasons that you can get inconsistent results are:
v Positioned UPDATE or DELETE statements that use uncorrelated subqueries
cause triggers to operate on a larger result table than you intended.
Chapter 4. Creating and modifying DB2 objects

431
v DB2 does not always process rows in the same order, so triggers that propagate
rows of a table can generate different result tables at different times.
The following examples demonstrate these situations.
Example: Effect of an uncorrelated subquery on a triggered action: Suppose that
tables T1 and T2 look like this:
Table T1
A1
==
1
2

Table T2
B1
==
1
2

The following trigger is defined on T1:
CREATE TRIGGER TR1
AFTER UPDATE OF T1
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
DELETE FROM T2 WHERE B1 = 2;
END

Now suppose that an application executes the following statements to perform a
positioned update operation:
EXEC SQL BEGIN DECLARE SECTION;
long hv1;
EXEC SQL END DECLARE SECTION;
.
.
.
EXEC SQL DECLARE C1 CURSOR FOR
SELECT A1 FROM T1
WHERE A1 IN (SELECT B1 FROM T2)
. FOR UPDATE OF A1;
.
.
EXEC SQL OPEN C1;
.
.
.
while(SQLCODE>=0 && SQLCODE!=100)
{
EXEC SQL FETCH C1 INTO :hv1;
UPDATE T1 SET A1=5 WHERE CURRENT OF C1;
}

When DB2 executes the FETCH statement that positions cursor C1 for the first
time, DB2 evaluates the subselect, SELECT B1 FROM T2, to produce a result table
that contains the two rows of column T2:
1
2

When DB2 executes the positioned UPDATE statement for the first time, trigger
TR1 is activated. When the body of trigger TR1 executes, the row with value 2 is
deleted from T2. However, because SELECT B1 FROM T2 is evaluated only once,
when the FETCH statement is executed again, DB2 finds the second row of T1,
even though the second row of T2 was deleted. The FETCH statement positions
the cursor to the second row of T1, and the second row of T1 is updated. The
update operation causes the trigger to be activated again, which causes DB2 to
attempt to delete the second row of T2, even though that row was already deleted.
To avoid processing of the second row after it should have been deleted, use a
correlated subquery in the cursor declaration:

432

Application Programming and SQL Guide
DCL C1 CURSOR FOR
SELECT A1 FROM T1 X
WHERE EXISTS (SELECT B1 FROM T2 WHERE X.A1 = B1)
FOR UPDATE OF A1;

In this case, the subquery, SELECT B1 FROM T2 WHERE X.A1 = B1, is evaluated
for each FETCH statement. The first time that the FETCH statement executes, it
positions the cursor to the first row of T1. The positioned UPDATE operation
activates the trigger, which deletes the second row of T2. Therefore, when the
FETCH statement executes again, no row is selected, so no update operation or
triggered action occurs.
Example: Effect of row processing order on a triggered action: The following
example shows how the order of processing rows can change the outcome of an
after row trigger.
Suppose that tables T1, T2, and T3 look like this:
Table T1
A1
==
1
2

Table T2
B1
==
(empty)

Table T3
C1
==
(empty)

The following trigger is defined on T1:
CREATE TRIGGER TR1
AFTER UPDATE ON T1
REFERENCING NEW AS N
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
INSERT INTO T2 VALUES(N.C1);
INSERT INTO T3 (SELECT B1 FROM T2);
END

Now suppose that a program executes the following UPDATE statement:
UPDATE T1 SET A1 = A1 + 1;

The contents of tables T2 and T3 after the UPDATE statement executes depend on
the order in which DB2 updates the rows of T1.
If DB2 updates the first row of T1 first, after the UPDATE statement and the
trigger execute for the first time, the values in the three tables are:
Table T1
A1
==
2
2

Table T2
B1
==
2

Table T3
C1
==
2

After the second row of T1 is updated, the values in the three tables are:
Table T1
A1
==
2
3

Table T2
B1
==
2
3

Table T3
C1
==
2
2
3

However, if DB2 updates the second row of T1 first, after the UPDATE statement
and the trigger execute for the first time, the values in the three tables are:

Chapter 4. Creating and modifying DB2 objects

433
Table T1
A1
==
1
3

Table T2
B1
==
3

Table T3
C1
==
3

After the first row of T1 is updated, the values in the three tables are:
Table T1
A1
==
2
3

Table T2
B1
==
3
2

Table T3
C1
==
3
3
2

Sequence objects
A sequence is a user-defined object that generates a sequence of numeric values
according to the specification with which the sequence was created. Sequences,
unlike identity columns, are not associated with tables. Applications refer to a
sequence object to get its current or next value.
The sequence of numeric values is generated in a monotonically ascending or
descending order. The relationship between sequences and tables is controlled by
the application, not by DB2.
Your application can reference a sequence object and coordinate the value as keys
across multiple rows and tables. However, a table column that gets its values from
a sequence object does not necessarily have unique values in that column. Even if
the sequence object has been defined with the NO CYCLE clause, some other
application might insert values into that table column other than values you obtain
by referencing that sequence object.
DB2 always generates sequence numbers in order of request. However, in a data
sharing group where the sequence values are cached by multiple DB2 members
simultaneously, the sequence value assignments might not be in numeric order.
Additionally, you might have gaps in sequence number values for the following
reasons:
v If DB2 terminates abnormally before it assigns all the cached values
v If your application rolls back a transaction that increments the sequence
v If the statement containing NEXT VALUE fails after it increments the sequence
You create a sequence object with the CREATE SEQUENCE statement, alter it with
the ALTER SEQUENCE statement, and drop it with the DROP SEQUENCE
statement. You grant access to a sequence with the GRANT (privilege) ON
SEQUENCE statement, and revoke access to the sequence with the REVOKE
(privilege) ON SEQUENCE statement.
The values that DB2 generates for a sequence depend on how the sequence is
created. The START WITH option determines the first value that DB2 generates.
The values advance by the INCREMENT BY value in ascending or descending
order.
The MINVALUE and MAXVALUE options determine the minimum and maximum
values that DB2 generates. The CYCLE or NO CYCLE option determines whether
DB2 wraps values when it has generated all values between the START WITH
value and MAXVALUE if the values are ascending, or between the START WITH
value and MINVALUE if the values are descending.

434

Application Programming and SQL Guide
Keys across multiple tables: You can use the same sequence number as a key
value in two separate tables by first generating the sequence value with a NEXT
VALUE expression to insert the first row in the first table. You can then reference
this same sequence value with a PREVIOUS VALUE expression to insert the other
rows in the second table.
Example: Suppose that an ORDERS table and an ORDER_ITEMS table are defined
in the following way:
CREATE TABLE ORDERS
(ORDERNO
INTEGER NOT NULL,
ORDER_DATE DATE DEFAULT,
CUSTNO
SMALLINT
PRIMARY KEY (ORDERNO));
CREATE TABLE ORDER_ITEMS
(ORDERNO
INTEGER NOT NULL,
PARTNO
INTEGER NOT NULL,
QUANTITY
SMALLINT NOT NULL,
PRIMARY KEY (ORDERNO,PARTNO),
CONSTRAINT REF_ORDERNO FOREIGN KEY (ORDERNO)
REFERENCES ORDERS (ORDERNO) ON DELETE CASCADE);

You create a sequence named ORDER_SEQ to use as key values for both the
ORDERS and ORDER_ITEMS tables:
CREATE SEQUENCE ORDER_SEQ AS INTEGER
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
CACHE 20;

You can then use the same sequence number as a primary key value for the
ORDERS table and as part of the primary key value for the ORDER_ITEMS table:
INSERT INTO ORDERS (ORDERNO, CUSTNO)
VALUES (NEXT VALUE FOR ORDER_SEQ, 12345);
INSERT INTO ORDER_ITEMS (ORDERNO, PARTNO, QUANTITY)
VALUES (PREVIOUS VALUE FOR ORDER_SEQ, 987654, 2);

The NEXT VALUE expression in the first INSERT statement generates a sequence
number value for the sequence object ORDER_SEQ. The PREVIOUS VALUE
expression in the second INSERT statement retrieves that same value because it
was the sequence number most recently generated for that sequence object within
the current application process.

DB2 object relational extensions
With the object extensions of DB2, you can incorporate object-oriented concepts
and methodologies into your relational database by extending DB2 with richer sets
of data types and funct
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide
DB2 Application programming and sql guide

DB2 Application programming and sql guide

  • 1.
    DB2 Version 9.1for z/OS Application Programming and SQL Guide SC18-9841-01
  • 3.
    DB2 Version 9.1for z/OS Application Programming and SQL Guide SC18-9841-01
  • 4.
    Note Before using thisinformation and the product it supports, be sure to read the general information under “Notices” at the end of this information. Second edition (October 2007) This edition applies to DB2 Version 9.1 for z/OS (DB2 V9.1 for z/OS), product number 5635-DB2, and to any subsequent releases until otherwise indicated in new editions. Make sure you are using the correct edition for the level of the product. Specific changes are indicated by a vertical bar to the left of a change. A vertical bar to the left of a figure caption indicates that the figure has changed. Editorial changes that have no technical significance are not noted. © Copyright International Business Machines Corporation 1983, 2007. All rights reserved. US Government Users Restricted Rights – Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  • 5.
    Contents About this information. . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi DB2 Utilities Suite . . . . . . . . . Who should read this information . . . . Terminology and citations . . . . . . . How to read syntax diagrams . . . . . Accessibility features for DB2 Version 9.1 for How to send your comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi . xi . xi . . . . . . . . . . . . . . . . . . . . . . . . xii z/OS . . . . . . . . . . . . . . . . . . . . . . xiii . . . . . . . . . . . . . . . . . . . . . . . . xiv Chapter 1. Planning for and designing DB2 applications . . . . . . . . . . . . . . . 1 | | Application and SQL release incompatibilities . . . . . . . . . . . . . Determining the value of any SQL processing options that affect the design of your Determining the binding method . . . . . . . . . . . . . . . . . Changes that invalidate plans or packages . . . . . . . . . . . . . Determining the value of any bind options that affect the design of your program Designing your application to promote concurrency . . . . . . . . . . . Designing your application for recovery . . . . . . . . . . . . . . . Unit of work in TSO . . . . . . . . . . . . . . . . . . . . Unit of work in CICS . . . . . . . . . . . . . . . . . . . . Planning for program recovery in IMS programs . . . . . . . . . . . Undoing selected changes within a unit of work by using savepoints . . . . Planning for recovery of table spaces that are not logged . . . . . . . . Designing your application to access distributed data . . . . . . . . . . Remote servers and distributed data . . . . . . . . . . . . . . . Advantages of DRDA access . . . . . . . . . . . . . . . . . . Preparing for coordinated updates to two or more data sources . . . . . . Forcing restricted system rules in your program . . . . . . . . . . . Maximizing the performance of an application that accesses distributed data . . . . program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 11 12 14 16 16 17 18 18 19 26 28 29 30 30 31 32 32 Chapter 2. Connecting to DB2 from your application program . . . . . . . . . . . . 43 Invoking the call attachment facility . . . . . . . . . Call attachment facility . . . . . . . . . . . . Making the CAF language interface (DSNALI) available . Requirements for programs that use CAF . . . . . . How CAF modifies the content of registers . . . . . . Implicit connections to CAF . . . . . . . . . . . CALL DSNALI statement parameter list . . . . . . . Summary of CAF behavior . . . . . . . . . . . CAF connection functions . . . . . . . . . . . Turning on a CAF trace . . . . . . . . . . . . CAF return codes and reason codes . . . . . . . . Sample CAF scenarios . . . . . . . . . . . . . Examples of invoking CAF . . . . . . . . . . . Invoking the Resource Recovery Services attachment facility . Resource Recovery Services attachment facility . . . . Making the RRSAF language interface (DSNRLI) available Requirements for programs that use RRSAF . . . . . How RRSAF modifies the content of registers . . . . . Implicit connections to RRSAF . . . . . . . . . . CALL DSNRLI statement parameter list . . . . . . . Summary of RRSAF behavior . . . . . . . . . . RRSAF connection functions . . . . . . . . . . . RRSAF return codes and reason codes . . . . . . . Sample RRSAF scenarios . . . . . . . . . . . Program examples for RRSAF . . . . . . . . . . Controlling the CICS attachment facility from an application © Copyright IBM Corp. 1983, 2007 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 47 50 51 52 52 53 55 56 67 67 68 69 75 77 81 82 83 83 84 85 86 116 116 118 121 iii
  • 6.
    Detecting whether theCICS attachment facility is operational . Improving thread reuse in CICS applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 . 122 Chapter 3. Including DB2 queries in an application program . . . . . . . . . . . . 123 Declaring table and view definitions. . . . . . . . . . . . . . . . . . . DCLGEN (declarations generator) . . . . . . . . . . . . . . . . . . Generating declarations for your table by using DCLGEN . . . . . . . . . . Including data declarations from DCLGEN in your program . . . . . . . . . Defining the SQL communications area . . . . . . . . . . . . . . . . . . Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . . . . Putting parameter information in an SQLDA by using DESCRIBE INPUT . . . . . . Declaring host variables, host variable arrays, and host structures . . . . . . . . . Host variables, host variable arrays, and host structures . . . . . . . . . . . Host variables in an SQL statement . . . . . . . . . . . . . . . . . . Host variable arrays in an SQL statement . . . . . . . . . . . . . . . . Retrieving multiple rows of data into host variable arrays . . . . . . . . . . Inserting multiple rows of data from host variable arrays. . . . . . . . . . . C and C++ syntax for host variable array declarations . . . . . . . . . . . . COBOL syntax for host variable array declarations . . . . . . . . . . . . . PL/I syntax for host variable array declarations . . . . . . . . . . . . . . Host structures in an SQL statement . . . . . . . . . . . . . . . . . . Indicator variables and indicator variable arrays . . . . . . . . . . . . . . Compatibility of SQL and language data types . . . . . . . . . . . . . . . Equivalent SQL and assembler data types . . . . . . . . . . . . . . . . Equivalent SQL and C data types. . . . . . . . . . . . . . . . . . . Equivalent SQL and COBOL data types . . . . . . . . . . . . . . . . Equivalent SQL and Fortran data types . . . . . . . . . . . . . . . . . Equivalent SQL and PL/I data types . . . . . . . . . . . . . . . . . Determining equivalent SQL and REXX data types . . . . . . . . . . . . . Data types that DB2 assigns to REXX input . . . . . . . . . . . . . . . Embedding SQL statements in your application . . . . . . . . . . . . . . . Embedding SQL statements in assembler applications . . . . . . . . . . . . Embedding SQL statements in C or C++ applications . . . . . . . . . . . . Embedding SQL statements in COBOL applications . . . . . . . . . . . . Embedding SQL statements in Fortran applications . . . . . . . . . . . . . Embedding SQL statements in PL/I applications . . . . . . . . . . . . . Embedding SQL statements in REXX procedures . . . . . . . . . . . . . Delimiting an SQL statement . . . . . . . . . . . . . . . . . . . . Including dynamic SQL in your program . . . . . . . . . . . . . . . . Conventions used in examples of coding SQL statements . . . . . . . . . . . Macros for assembler applications . . . . . . . . . . . . . . . . . . Accessing the DB2 REXX language support application programming interfaces . . . Setting the isolation level of SQL statements in a REXX procedure . . . . . . . . Checking the execution of SQL statements . . . . . . . . . . . . . . . . . Checking the execution of SQL statements by using the SQLCA . . . . . . . . Checking the execution of SQL statements by using SQLCODE and SQLSTATE . . . Checking the execution of SQL statements by using the WHENEVER statement . . . Checking the execution of SQL statements by using the GET DIAGNOSTICS statement Handling SQL error codes . . . . . . . . . . . . . . . . . . . . . . Arithmetic and conversion errors . . . . . . . . . . . . . . . . . . . Writing applications that enable users to create and modify tables . . . . . . . . . Saving SQL statements that are translated from end user requests . . . . . . . . . Retrieving data from DB2 tables in REXX programs . . . . . . . . . . . . . XML data in embedded SQL applications . . . . . . . . . . . . . . . . . Host variable data types for XML data in embedded SQL applications . . . . . . XML column updates in embedded SQL applications . . . . . . . . . . . . XML data retrieval in embedded SQL applications . . . . . . . . . . . . . Object-oriented extensions in COBOL . . . . . . . . . . . . . . . . . . Cursors and statement names in REXX . . . . . . . . . . . . . . . . . . Programming examples . . . . . . . . . . . . . . . . . . . . . . . Sample dynamic and static SQL in a C program . . . . . . . . . . . . . . iv Application Programming and SQL Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 125 130 135 135 137 139 140 142 143 182 182 182 183 189 195 199 207 219 221 226 231 235 237 241 241 243 243 246 248 252 253 256 258 258 296 296 296 298 298 299 303 303 304 310 317 317 318 318 319 320 324 327 329 330 331 331
  • 7.
    Sample COBOL dynamicSQL program . . . . . . . . . . . . Sample COBOL program using DRDA access with CONNECT statements Sample COBOL program using private protocol access . . . . . . Sample DB2 REXX application. . . . . . . . . . . . . . . Example programs that call stored procedures . . . . . . . . . Chapter 4. Creating and modifying DB2 objects | | | | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 345 351 357 367 . . . . . . . . . . . . . . . . . 385 Creating tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Storing LOB data in a table . . . . . . . . . . . . . . . . . . . . . . . . Identity columns . . . . . . . . . . . . . . . . . . . . . . . . . . . Creating tables for data integrity . . . . . . . . . . . . . . . . . . . . . . Creating work tables for the EMP and DEPT sample tables . . . . . . . . . . . . . Creating created temporary tables . . . . . . . . . . . . . . . . . . . . . Creating declared temporary tables . . . . . . . . . . . . . . . . . . . . . Providing a unique key for a table . . . . . . . . . . . . . . . . . . . . . . Fixing tables with incomplete definitions . . . . . . . . . . . . . . . . . . . . Dropping tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . Defining a view . . . . . . . . . . . . . . . . . . . . . . . . . . . . Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dropping a view . . . . . . . . . . . . . . . . . . . . . . . . . . . . Creating a common table expression . . . . . . . . . . . . . . . . . . . . . . Common table expressions . . . . . . . . . . . . . . . . . . . . . . . . Examples of recursive common table expressions . . . . . . . . . . . . . . . . Creating triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . Invoking stored procedures and user-defined functions from triggers . . . . . . . . . . Inserting, updating, and deleting data in views by using INSTEAD OF triggers . . . . . . Trigger packages . . . . . . . . . . . . . . . . . . . . . . . . . . . Trigger cascading . . . . . . . . . . . . . . . . . . . . . . . . . . . Order of multiple triggers . . . . . . . . . . . . . . . . . . . . . . . . Interactions between triggers and referential constraints . . . . . . . . . . . . . . Interactions between triggers and tables that have multilevel security with row-level granularity Triggers that return inconsistent results . . . . . . . . . . . . . . . . . . . . Sequence objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . DB2 object relational extensions . . . . . . . . . . . . . . . . . . . . . . . Creating a distinct type . . . . . . . . . . . . . . . . . . . . . . . . . . Distinct types . . . . . . . . . . . . . . . . . . . . . . . . . . . . Example of distinct types, user-defined functions, and LOBs . . . . . . . . . . . . Defining a user-defined function . . . . . . . . . . . . . . . . . . . . . . . User-defined functions . . . . . . . . . . . . . . . . . . . . . . . . . Components of a user-defined function definition . . . . . . . . . . . . . . . . Writing an external user-defined function . . . . . . . . . . . . . . . . . . . Making a user-defined function reentrant . . . . . . . . . . . . . . . . . . . Using special registers in a user-defined function or a stored procedure . . . . . . . . . Accessing transition tables in a user-defined function or stored procedure . . . . . . . . Preparing an external user-defined function for execution . . . . . . . . . . . . . Abnormal termination of an external user-defined function . . . . . . . . . . . . . Saving information between invocations of a user-defined function by using a scratchpad . . . Example of creating and using a user-defined scalar function . . . . . . . . . . . . User-defined function samples that ship with DB2 . . . . . . . . . . . . . . . . Determining the authorization cache size for stored procedures and user-defined functions . . Creating a stored procedure . . . . . . . . . . . . . . . . . . . . . . . . Stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . Setting up the stored procedures environment . . . . . . . . . . . . . . . . . Creating a native SQL procedure . . . . . . . . . . . . . . . . . . . . . . Changing an existing version of a native SQL procedure . . . . . . . . . . . . . . Regenerating an existing version of a native SQL procedure . . . . . . . . . . . . . Removing an existing version of a native SQL procedure . . . . . . . . . . . . . . Deploying a native SQL procedure to other DB2 for z/OS servers . . . . . . . . . . . Creating an external SQL procedure . . . . . . . . . . . . . . . . . . . . . Creating an external stored procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 386 388 391 393 402 403 405 407 408 409 409 410 411 411 412 413 417 425 426 427 428 429 429 431 431 434 435 436 436 438 440 443 445 447 470 471 473 477 477 477 479 479 480 481 481 494 500 526 526 527 527 528 541 Contents v
  • 8.
    Creating multiple versionsof external procedures and external SQL procedures . . . COMMIT and ROLLBACK statements in a stored procedure . . . . . . . . . Special registers in a stored procedure . . . . . . . . . . . . . . . . . Restrictions for stored procedures . . . . . . . . . . . . . . . . . . Writing a program or stored procedure to receive the result sets from a stored procedure Chapter 5. Adding and modifying data | | | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553 553 554 554 554 . . . . . . . . . . . . . . . . . . . . . 561 Inserting data into tables . . . . . . . . . . . Inserting rows by using the INSERT statement . . . Inserting data and updating data in a single operation Selecting values while inserting data . . . . . . Adding data to the end of a table . . . . . . . . Storing data that does not have a tabular format . . . Updating table data . . . . . . . . . . . . . Selecting values while updating data . . . . . . Updating thousands of rows . . . . . . . . . Deleting data from tables . . . . . . . . . . . Selecting values while deleting data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 561 567 569 575 576 576 577 578 578 580 Chapter 6. Accessing data . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 | | | | | Determining which tables you have access to . . . . . . . . . . . . . . Displaying information about the columns for a given table . . . . . . . . . Retrieving data by using the SELECT statement . . . . . . . . . . . . . Selecting derived columns . . . . . . . . . . . . . . . . . . . Selecting XML data . . . . . . . . . . . . . . . . . . . . . Formatting the result table . . . . . . . . . . . . . . . . . . . Combining result tables from multiple SELECT statements . . . . . . . . Summarizing group values . . . . . . . . . . . . . . . . . . . Finding rows that were changed within a specified period of time . . . . . Joining data from more than one table . . . . . . . . . . . . . . . Optimizing retrieval for a small set of rows . . . . . . . . . . . . . Creating recursive SQL by using common table expressions . . . . . . . . Updating data as it is retrieved from the database . . . . . . . . . . . Avoiding decimal arithmetic errors . . . . . . . . . . . . . . . . Implications of using SELECT * . . . . . . . . . . . . . . . . . Subqueries . . . . . . . . . . . . . . . . . . . . . . . . Restrictions when using distinct types with UNION, EXCEPT, and INTERSECT . Comparison of distinct types . . . . . . . . . . . . . . . . . . Nested SQL statements . . . . . . . . . . . . . . . . . . . . Retrieving a set of rows by using a cursor . . . . . . . . . . . . . . . Cursors . . . . . . . . . . . . . . . . . . . . . . . . . Accessing data by using a row-positioned cursor . . . . . . . . . . . Accessing data by using a rowset-positioned cursor . . . . . . . . . . Retrieving rows by using a scrollable cursor . . . . . . . . . . . . . Accessing XML or LOB data quickly by using FETCH WITH CONTINUE . . . Determining the attributes of a cursor by using the SQLCA . . . . . . . . Determining the attributes of a cursor by using the GET DIAGNOSTICS statement Scrolling through previously retrieved data . . . . . . . . . . . . . Updating previously retrieved data . . . . . . . . . . . . . . . . FETCH statement interaction between row and rowset positioning . . . . . Examples of fetching rows by using cursors . . . . . . . . . . . . . Specifying direct row access by using row IDs . . . . . . . . . . . . . ROWID columns . . . . . . . . . . . . . . . . . . . . . . Ways to manipulate LOB data . . . . . . . . . . . . . . . . . . . LOB host variable, LOB locator, and LOB file reference variable declarations . . LOB materialization . . . . . . . . . . . . . . . . . . . . . Saving storage when manipulating LOBs by using LOB locators . . . . . . Deferring evaluation of a LOB expression to improve performance . . . . . LOB file reference variables . . . . . . . . . . . . . . . . . . Referencing a sequence object . . . . . . . . . . . . . . . . . . . vi Application Programming and SQL Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 583 584 587 587 588 593 598 600 600 611 612 613 613 614 615 623 624 625 626 627 631 636 641 646 649 650 650 652 652 653 658 660 660 661 667 667 669 671 673
  • 9.
    | | Retrieving thousands ofrows . . . . . Determining when a row was changed . . Checking whether an XML column contains Accessing DB2 data that is not in a table . Ensuring that queries perform sufficiently . Items to include in a batch DL/I program . . . . . . . . . . . . . a certain value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674 674 675 675 675 676 Chapter 7. Invoking a user-defined function . . . . . . . . . . . . . . . . . . . 679 Determining the authorization ID for invoking user-defined functions . . . . Ensuring that DB2 executes the intended user-defined function. . . . . . . Function resolution . . . . . . . . . . . . . . . . . . . . Checking how DB2 resolves functions by using DSN_FUNCTION_TABLE . . Restrictions when passing arguments with distinct types to functions . . . . Cases when DB2 casts arguments for a user-defined function . . . . . . . Maximizing the number of user-defined functions and stored procedures that can . . . . . . run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . concurrently . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 681 682 685 687 689 690 Chapter 8. Calling a stored procedure from your application . . . . . . . . . . . . 693 | Parameter list for stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . . Linkage conventions for stored procedures . . . . . . . . . . . . . . . . . . . . . . . Improving stored procedure performance by using indicator variables . . . . . . . . . . . . . . Compatible data types for parameters that are passed to stored procedures . . . . . . . . . . . . Preparing a client program for a stored procedure . . . . . . . . . . . . . . . . . . . . . How DB2 determines which stored procedure to run . . . . . . . . . . . . . . . . . . . . Calling different versions of a stored procedure from a single application . . . . . . . . . . . . . Invoking multiple instances of a stored procedure . . . . . . . . . . . . . . . . . . . . . Stored procedures that access non-DB2 resources . . . . . . . . . . . . . . . . . . . . . Designating the active version of a native SQL procedure . . . . . . . . . . . . . . . . . . Temporarily overriding the active version of a native SQL procedure . . . . . . . . . . . . . . . Specifying the number of stored procedures that can run concurrently . . . . . . . . . . . . . . DB2-supplied stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . WLM environment refresh stored procedure (WLM_REFRESH) . . . . . . . . . . . . . . . The DSNACICS stored procedure . . . . . . . . . . . . . . . . . . . . . . . . . The DSNAIMS stored procedure . . . . . . . . . . . . . . . . . . . . . . . . . . The DB2 EXPLAIN stored procedure . . . . . . . . . . . . . . . . . . . . . . . . Deprecated: Store an XML document from an MQ message queue in DB2 tables (DXXMQINSERT) . . . Deprecated: Store an XML document from an MQ message queue in DB2 tables (DXXMQSHRED) . . . . Deprecated: Store a large XML document from an MQ message queue in DB2 tables (DXXMQINSERTCLOB) Deprecated: Store a large XML document from an MQ message queue in DB2 tables (DXXMQSHREDCLOB) Deprecated: Store XML documents from an MQ message queue in DB2 tables (DXXMQINSERTALL) . . . Deprecated: Store XML documents from an MQ message queue in DB2 tables (DXXMQSHREDALL) . . . Deprecated: Store large XML documents from an MQ message queue in DB2 tables (DXXMQSHREDALLCLOB) . . . . . . . . . . . . . . . . . . . . . . . . . . . Deprecated: Store large XML documents from an MQ message queue in DB2 tables (DXXMQINSERTALLCLOB) . . . . . . . . . . . . . . . . . . . . . . . . . . . Deprecated: Send XML documents to an MQ message queue (DXXMQGEN) . . . . . . . . . . . Deprecated: Send XML documents to an MQ message queue (DXXMQRETRIEVE) . . . . . . . . . Deprecated: Send large XML documents to an MQ message queue (DXXMQGENCLOB) . . . . . . . Deprecated: Send XML documents to an MQ message queue (DXXMQRETRIEVECLOB) . . . . . . . The XML schema registration stored procedure (XSR_REGISTER) . . . . . . . . . . . . . . . The add XML schema document stored procedure (XSR_ADDSCHEMADOC) . . . . . . . . . . . The XML schema registration completion stored procedure (XSR_COMPLETE) . . . . . . . . . . The XML schema removal stored procedure (XSR_REMOVE) . . . . . . . . . . . . . . . . The XML decomposition stored procedure (XDBDECOMPXML) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696 697 712 713 721 722 722 723 724 725 726 726 727 729 731 739 744 746 749 751 754 . 756 . 758 . 761 . . . . . . . . . . 763 766 769 773 777 780 781 783 784 785 Chapter 9. Coding methods for distributed data . . . . . . . . . . . . . . . . . 787 Accessing distributed data by using three-part table names . . . . . . . . Accessing remote declared temporary tables by using three-part table names . Accessing distributed data by using explicit CONNECT statements . . . . . Specifying a location alias name for multiple sites . . . . . . . . . . Releasing connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Contents . . . . . 787 789 789 790 791 vii
  • 10.
    | | | | Transmitting mixed data.. . . . . . . . . . . . . . . . . . . . . . . . Identifying the server at run time . . . . . . . . . . . . . . . . . . . . . SQL limitations at dissimilar servers . . . . . . . . . . . . . . . . . . . . . Support for executing long SQL statements in a distributed environment . . . . . . . . Distributed queries against ASCII or Unicode tables . . . . . . . . . . . . . . . Restrictions when using scrollable cursors to access distributed data . . . . . . . . . . Restrictions when using rowset-positioned cursors to access distributed data . . . . . . . WebSphere MQ with DB2 . . . . . . . . . . . . . . . . . . . . . . . . WebSphere MQ messages . . . . . . . . . . . . . . . . . . . . . . . DB2 MQ functions and DB2 MQ XML stored procedures . . . . . . . . . . . . . Generating XML documents from existing tables and sending them to an MQ message queue Shredding XML documents from an MQ message queue . . . . . . . . . . . . . DB2 MQ tables . . . . . . . . . . . . . . . . . . . . . . . . . . . Converting applications to use the MQI functions . . . . . . . . . . . . . . . Basic messaging with WebSphere MQ . . . . . . . . . . . . . . . . . . . Sending messages with WebSphere MQ . . . . . . . . . . . . . . . . . . Retrieving messages with WebSphere MQ . . . . . . . . . . . . . . . . . . Application to application connectivity with WebSphere MQ . . . . . . . . . . . Asynchronous messaging in DB2 for z/OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 791 792 792 793 793 794 794 794 798 804 804 804 813 814 815 815 817 820 Chapter 10. DB2 as a Web services consumer and provider . . . . . . . . . . . . 833 The SOAPHTTPV and SOAPHTTPC user-defined functions . SQLSTATEs for DB2 as a Web services consumer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 833 . 835 Chapter 11. Preparing an application to run on DB2 for z/OS . . . . . . . . . . . . 837 | Setting the DB2I defaults . . . . . . . . . . . . . . . . . . . . . . . Processing SQL statements . . . . . . . . . . . . . . . . . . . . . . . Processing SQL statements by using the DB2 precompiler . . . . . . . . . . . Processing SQL statements by using the DB2 coprocessor. . . . . . . . . . . . Translating command-level statements in a CICS program . . . . . . . . . . . Differences between the DB2 precompiler and the DB2 coprocessor . . . . . . . . CCSID conversion of source programs . . . . . . . . . . . . . . . . . . Options for SQL statement processing . . . . . . . . . . . . . . . . . . Program preparation options for remote packages . . . . . . . . . . . . . . Compiling and link-editing an application . . . . . . . . . . . . . . . . . . Binding an application . . . . . . . . . . . . . . . . . . . . . . . . Binding a DBRM to a package . . . . . . . . . . . . . . . . . . . . . Binding an application plan . . . . . . . . . . . . . . . . . . . . . Bind process for remote access . . . . . . . . . . . . . . . . . . . . Binding a batch program . . . . . . . . . . . . . . . . . . . . . . Converting an existing plan into packages to run remotely . . . . . . . . . . . Setting the program level . . . . . . . . . . . . . . . . . . . . . . DYNAMICRULES bind option . . . . . . . . . . . . . . . . . . . . Determining the authorization cache size for plans . . . . . . . . . . . . . . Determining the authorization cache size for packages . . . . . . . . . . . . Dynamic plan selection . . . . . . . . . . . . . . . . . . . . . . . Rebinding an application . . . . . . . . . . . . . . . . . . . . . . . Rebinding a package . . . . . . . . . . . . . . . . . . . . . . . . Rebinding a plan . . . . . . . . . . . . . . . . . . . . . . . . . Rebinding lists of plans and packages . . . . . . . . . . . . . . . . . . Generating lists of REBIND commands . . . . . . . . . . . . . . . . . . Automatic rebinding . . . . . . . . . . . . . . . . . . . . . . . . Specifying the rules that apply to SQL behavior at run time . . . . . . . . . . . . DB2 program preparation overview . . . . . . . . . . . . . . . . . . . . Input and output data sets for DL/I batch jobs . . . . . . . . . . . . . . . . DB2-supplied JCL procedures for preparing an application . . . . . . . . . . . . JCL to include the appropriate interface code when using the DB2-supplied JCL procedures Tailoring DB2-supplied JCL procedures for preparing CICS programs . . . . . . . DB2I primary option menu . . . . . . . . . . . . . . . . . . . . . . . DB2I panels that are used for program preparation . . . . . . . . . . . . . . . viii Application Programming and SQL Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839 840 842 848 850 851 853 853 862 864 865 866 871 875 879 879 880 881 882 883 883 885 885 886 887 887 893 894 895 897 900 900 901 902 903
  • 11.
    DB2 Program Preparationpanel . . . . . . . . . . . . DB2I Defaults Panel 1 . . . . . . . . . . . . . . . DB2I Defaults Panel 2 . . . . . . . . . . . . . . . Precompile panel . . . . . . . . . . . . . . . . . Bind Package panel . . . . . . . . . . . . . . . . Bind Plan panel . . . . . . . . . . . . . . . . . Defaults for Bind Package panel and Defaults for Bind Plan panel. System Connection Types panel . . . . . . . . . . . . Panels for entering lists of values . . . . . . . . . . . . Program Preparation: Compile, Link, and Run panel . . . . . DB2I panels that are used to rebind and free plans and packages . . Bind/Rebind/Free Selection panel . . . . . . . . . . . Rebind Package panel . . . . . . . . . . . . . . . Rebind Trigger Package panel . . . . . . . . . . . . . Rebind Plan panel . . . . . . . . . . . . . . . . . Free Package panel . . . . . . . . . . . . . . . . Free Plan panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905 909 911 912 915 918 921 926 927 928 930 930 932 933 935 937 938 Chapter 12. Running an application on DB2 for z/OS . . . . . . . . . . . . . . . 939 | | DSN command processor . . . . . . . . . . . . . . . . DB2I Run panel . . . . . . . . . . . . . . . . . . . Running a program in TSO foreground . . . . . . . . . . . . Running a DB2 REXX application . . . . . . . . . . . . . Invoking programs through the Interactive System Productivity Facility . ISPF . . . . . . . . . . . . . . . . . . . . . . Invoking a single SQL program through ISPF and DSN . . . . . Invoking multiple SQL programs through ISPF and DSN . . . . . Loading and running a batch program . . . . . . . . . . . . Authorization for running a batch DL/I program . . . . . . . Restarting a batch program . . . . . . . . . . . . . . . Running stored procedures from the command line processor . . . . Command line processor CALL statement . . . . . . . . . . Example of running a batch DB2 application in TSO . . . . . . . Example of calling applications in a command procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939 940 941 942 942 943 944 945 946 947 947 950 950 951 952 Chapter 13. Testing and debugging an application program on DB2 for z/OS . . . . . 955 Designing a test data structure . . . . . . . . . . . . . . . . . . . . . . . . . . Analyzing application data needs . . . . . . . . . . . . . . . . . . . . . . . . Authorization for test tables and applications. . . . . . . . . . . . . . . . . . . . . Example SQL statements to create a comprehensive test structure . . . . . . . . . . . . . . Populating the test tables with data . . . . . . . . . . . . . . . . . . . . . . . . . Methods for testing SQL statements . . . . . . . . . . . . . . . . . . . . . . . . . Executing SQL by using SPUFI . . . . . . . . . . . . . . . . . . . . . . . . . . SPUFI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Content of a SPUFI input data set . . . . . . . . . . . . . . . . . . . . . . . . The SPUFI panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Changing SPUFI defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . Setting the SQL terminator character in a SPUFI input data set . . . . . . . . . . . . . . . Controlling toleration of warnings in SPUFI . . . . . . . . . . . . . . . . . . . . . Output from SPUFI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Testing an external user-defined function . . . . . . . . . . . . . . . . . . . . . . . Testing a user-defined function by using the Debug Tool for z/OS . . . . . . . . . . . . . Testing a user-defined function by routing the debugging messages to SYSPRINT . . . . . . . . Testing a user-defined function by using driver applications . . . . . . . . . . . . . . . . Testing a user-defined function by using SQL INSERT statements . . . . . . . . . . . . . . Debugging a stored procedure. . . . . . . . . . . . . . . . . . . . . . . . . . . Debugging stored procedures with the Debug Tool and IBM VisualAge COBOL . . . . . . . . . Debugging a C language stored procedure with the Debug Tool and C/C++ Productivity Tools for z/OS Debugging with the Unified Debugger . . . . . . . . . . . . . . . . . . . . . . . Debugging stored procedures with the Debug Tool for z/OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Contents . . . . . . . . . . . . . . . . . . . . . . . . 955 955 956 957 958 958 959 962 963 963 965 970 971 971 973 973 975 975 976 976 977 978 978 979 ix
  • 12.
    Recording stored proceduredebugging messages Driver applications for debugging procedures . DB2 tables that contain debugging information . Debugging an application program . . . . . . Locating the problem in an application . . . . Techniques for debugging programs in TSO . . Techniques for debugging programs in IMS . . Techniques for debugging programs in CICS . . Finding a violated referential or check constraint . in a file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 981 981 981 982 982 987 987 988 992 Chapter 14. DB2 sample applications and data . . . . . . . . . . . . . . . . . . 993 DB2 sample tables . . . . . . . . . . . . . . . . . . . . Activity table (DSN8910.ACT) . . . . . . . . . . . . . . . Department table (DSN8910.DEPT) . . . . . . . . . . . . . Employee table (DSN8910.EMP) . . . . . . . . . . . . . . Employee photo and resume table (DSN8910.EMP_PHOTO_RESUME) . Project table (DSN8910.PROJ) . . . . . . . . . . . . . . Project activity table (DSN8910.PROJACT) . . . . . . . . . . Employee to project activity table (DSN8910.EMPPROJACT) . . . . Unicode sample table (DSN8910.DEMO_UNICODE) . . . . . . . Relationships among the sample tables . . . . . . . . . . . Views on the sample tables . . . . . . . . . . . . . . . Storage of sample application tables . . . . . . . . . . . . DB2 sample applications . . . . . . . . . . . . . . . . . Types of sample applications . . . . . . . . . . . . . . . Application languages and environments for the sample applications . Sample applications in TSO . . . . . . . . . . . . . . . Sample applications in IMS . . . . . . . . . . . . . . . Sample applications in CICS . . . . . . . . . . . . . . . DSNTIAUL. . . . . . . . . . . . . . . . . . . . . DSNTIAD . . . . . . . . . . . . . . . . . . . . . DSNTEP2 and DSNTEP4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993 . 993 . 994 . 995 . 999 . 1000 . 1001 . 1002 . 1003 . 1004 . 1005 . 1009 . 1013 . 1015 . 1017 . 1018 . 1020 . 1021 . 1021 . 1026 . 1028 Information resources for DB2 for z/OS and related products . . . . . . . . . . . 1035 How to obtain DB2 information . . . . . . . . . . . . . . . . . . . . . . . . 1041 How to use the DB2 library . . . . . . . . . . . . . . . . . . . . . . . . . . 1045 Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049 Programming Interface Information . . . . . . . . . . . . . . . . General-use Programming Interface and Associated Guidance Information . . Product-sensitive Programming Interface and Associated Guidance Information . Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050 1050 1051 1051 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1053 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1097 x Application Programming and SQL Guide
  • 13.
    About this information Thisinformation discusses how to design and write application programs that access DB2 for z/OS (DB2®), a highly flexible relational database management system (DBMS). Visit the following Web site for information about ordering DB2 books and obtaining other valuable information about DB2 for z/OS: http:// publib.boulder.ibm.com/infocenter/imzic DB2 Utilities Suite Important: In this version of DB2 for z/OS®, the DB2 Utilities Suite is available as an optional product. You must separately order and purchase a license to such utilities, and discussion of those utility functions in this publication is not intended to otherwise imply that you have a license to them. The DB2 Utilities Suite is designed to work with the DFSORT™ program, which you are licensed to use in support of the DB2 utilities even if you do not otherwise license DFSORT for general use. If your primary sort product is not DFSORT, consider the following informational APARs mandatory reading: v II14047/II14213: USE OF DFSORT BY DB2 UTILITIES v II13495: HOW DFSORT TAKES ADVANTAGE OF 64-BIT REAL ARCHITECTURE These informational APARs are periodically updated. Related information DB2 utilities packaging Who should read this information This information is for DB2 application developers who are familiar with Structured Query Language (SQL) and who know one or more programming languages that DB2 supports. Terminology and citations In this information, DB2 Version 9.1 for z/OS is referred to as ″DB2 for z/OS.″ In cases where the context makes the meaning clear, DB2 for z/OS is referred to as ″DB2.″ When this information refers to titles of DB2 for z/OS books, a short title is used. (For example, ″See DB2 SQL Reference″ is a citation to IBM® DB2 Version 9.1 for z/OS SQL Reference.) When referring to a DB2 product other than DB2 for z/OS, this information uses the product’s full name to avoid ambiguity. The following terms are used as indicated: DB2 Represents either the DB2 licensed program or a particular DB2 subsystem. OMEGAMON Refers to any of the following products: © Copyright IBM Corp. 1983, 2007 xi
  • 14.
    v v v v IBM IBM IBM IBM Tivoli® OMEGAMON® XEfor DB2 Performance Expert on z/OS Tivoli OMEGAMON XE for DB2 Performance Monitor on z/OS DB2 Performance Expert for Multiplatforms and Workgroups DB2 Buffer Pool Analyzer for z/OS C, C++, and C language Represent the C or C++ programming language. CICS Represents CICS® Transaction Server for z/OS. IMS Represents the IMS™ Database Manager or IMS Transaction Manager. MVS | Represents the MVS™ element of the z/OS operating system, which is equivalent to the Base Control Program (BCP) component of the z/OS operating system. RACF Represents the functions that are provided by the RACF® component of the z/OS Security Server. How to read syntax diagrams Certain conventions apply to the syntax diagrams that are used in IBM documentation. Apply the following rules when reading the syntax diagrams that are used in DB2 for z/OS documentation: v Read the syntax diagrams from left to right, from top to bottom, following the path of the line. The ─── symbol indicates the beginning of a statement. The ─── symbol indicates that the statement syntax is continued on the next line. The ─── symbol indicates that a statement is continued from the previous line. The ─── symbol indicates the end of a statement. v Required items appear on the horizontal line (the main path). required_item v Optional items appear below the main path. required_item optional_item If an optional item appears above the main path, that item has no effect on the execution of the statement and is used only for readability. optional_item required_item v If you can choose from two or more items, they appear vertically, in a stack. If you must choose one of the items, one item of the stack appears on the main path. required_item xii Application Programming and SQL Guide required_choice1 required_choice2
  • 15.
    If choosing oneof the items is optional, the entire stack appears below the main path. required_item optional_choice1 optional_choice2 If one of the items is the default, it appears above the main path and the remaining choices are shown below. default_choice required_item optional_choice optional_choice v An arrow returning to the left, above the main line, indicates an item that can be repeated. required_item repeatable_item If the repeat arrow contains a comma, you must separate repeated items with a comma. , required_item | | | repeatable_item A repeat arrow above a stack indicates that you can repeat the items in the stack. v Sometimes a diagram must be split into fragments. The syntax fragment is shown separately from the main syntax diagram, but the contents of the fragment should be read as if they are on the main path of the diagram. | | required_item | fragment-name: | fragment-name required_item optional_name | | | | v With the exception of XPath keywords, keywords appear in uppercase (for example, FROM). Keywords must be spelled exactly as shown. XPath keywords are defined as lowercase names, and must be spelled exactly as shown. Variables appear in all lowercase letters (for example, column-name). They represent user-supplied names or values. v If punctuation marks, parentheses, arithmetic operators, or other such symbols are shown, you must enter them as part of the syntax. Accessibility features for DB2 Version 9.1 for z/OS Accessibility features help a user who has a physical disability, such as restricted mobility or limited vision, to use information technology products successfully. About this information xiii
  • 16.
    Accessibility features The followinglist includes the major accessibility features in z/OS products, including DB2 Version 9.1 for z/OS. These features support: v Keyboard-only operation. v Interfaces that are commonly used by screen readers and screen magnifiers. v Customization of display attributes such as color, contrast, and font size Tip: The Information Management Software for z/OS Solutions Information Center (which includes information for DB2 Version 9.1 for z/OS) and its related publications are accessibility-enabled for the IBM Home Page Reader. You can operate all features using the keyboard instead of the mouse. Keyboard navigation You can access DB2 Version 9.1 for z/OS ISPF panel functions by using a keyboard or keyboard shortcut keys. For information about navigating the DB2 Version 9.1 for z/OS ISPF panels using TSO/E or ISPF, refer to the z/OS TSO/E Primer, the z/OS TSO/E User’s Guide, and the z/OS ISPF User’s Guide. These guides describe how to navigate each interface, including the use of keyboard shortcuts or function keys (PF keys). Each guide includes the default settings for the PF keys and explains how to modify their functions. Related accessibility information Online documentation for DB2 Version 9.1 for z/OS is available in the Information Management Software for z/OS Solutions Information Center, which is available at the following Web site: http://publib.boulder.ibm.com/infocenter/dzichelp IBM and accessibility See the IBM Accessibility Center at http://www.ibm.com/able for more information about the commitment that IBM has to accessibility. How to send your comments Your feedback helps IBM to provide quality information. Please send any comments that you have about this book or other DB2 for z/OS documentation. You can use the following methods to provide comments: v Send your comments by e-mail to db2zinfo@us.ibm.com and include the name of the product, the version number of the product, and the number of the book. If you are commenting on specific text, please list the location of the text (for example, a chapter and section title or a help topic title). v You can send comments from the Web. Visit the library Web site at: www.ibm.com/software/db2zos/library.html This Web site has an online reader comment form that you can use to send comments. v You can also send comments by using the feedback link at the footer of each page in the Information Management Software for z/OS Solutions Information Center at http://publib.boulder.ibm.com/infocenter/db2zhelp. xiv Application Programming and SQL Guide
  • 17.
    Chapter 1. Planningfor and designing DB2 applications Whether you are writing a new DB2 application or migrating an existing application from a previous release of DB2, you need to make some planning and design decisions before you write or run the program. If you are migrating an existing application from a previous release of DB2, read the application and SQL release incompatibilities and make any necessary changes in the application. If v v v you are writing a new DB2 application, first determine the following items: the value of some of the SQL processing options the binding method the value of some of the bind options Then make sure that your program implements the appropriate recommendations so that it promotes concurrency, can handle recovery and restart situations, and can efficiently access distributed data. | Application and SQL release incompatibilities | | When you migrate to Version 9.1, be aware of the following application and SQL release incompatibilities. | | | Adjust applications that depend on error information that is returned from DB2-supplied stored procedures and user-defined functions | | | | | | | Adjust applications that depend on error information that is returned from DB2-supplied stored procedures and user-defined functions. In Version 9.1, a number of the DB2-supplied stored procedures and user-defined functions return different error information from the information that they returned in previous releases of DB2. The DB2-supplied stored procedures and user-defined functions have been enhanced to return the more meaningful SQLCODEs from the SQL statements in the bodies of the routines. | Qualify user-defined function names | | | | | | If you use a user-defined function that has the same name as a built in function that has been added to Version 9.1, ensure that you fully qualify the function name. If the function name is unqualified and SYSIBM precedes the schema that you used for this function in the SQL path, DB2 invokes one of the built-in functions. For a list of built-in functions, including those that have been added in Version 9.1, see the topic “Functions”. | Fully define objects | | | | | Ensure that you do not have any incomplete object definitions in your DB2 Version 8 catalog. For example, if a table has a primary or unique key defined but the enforcing primary or unique key index does not exist, the table definition is considered incomplete. You need to complete or drop all such objects before you begin migration because their behavior will be different in Version 9.1. For © Copyright IBM Corp. 1983, 2007 1
  • 18.
    | | | example, if youattempt to create an enforcing primary key index to complete a table definition in Version 9.1 and the residing table space is implicitly created, the index will be treated as a regular index instead of an enforcing index. | SQL reserved words | | Version 9.1 has several new SQL reserved words. Refer to DB2 SQL Reference for the list, and adjust your applications accordingly. | | Changes to PL/I applications with no DECLARE VARIABLE statements | | | | | For PL/I applications with no DECLARE VARIABLE statements, the rules for host variables and string constants in the FROM clause of a PREPARE or EXECUTE IMMEDIATE statement have changed. A host variable must be a varying-length string variable that is preceded by a colon. A PL/I string cannot be preceded by a colon. | Changes in BIND PACKAGE and BIND PLAN defaults | | | | | The default value for bind option CURRENTDATA is changed from YES to NO. This applies to the BIND PLAN and the BIND PACKAGE subcommands, as well as the CREATE TRIGGER for trigger packages, and the CREATE PROCEDURE and the ALTER PROCEDURE ADD VERSION SQL statements for SQL PL procedure packages. Specifying NO for CURRENTDATA is the best option for performance. | | | | The default value for bind option ISOLATION is changed from RR to CS. This applies to the BIND PLAN and the remote BIND PACKAGE subcommands. For the BIND PACKAGE subcommand, the current default (plan value) stays. The default change does not apply to implicitly-built CTs (for example, DISTSERV CTs). | | Although you can specify DBPROTOCOL(PRIVATE) for the DBPROTOCOL parameter of the BIND option, DB2 issues a new warning message, DSNT226I. | | | | All BIND statements for plans and packages that are bound during the installation or migration process specify the ISOLATION parameter explicitly, except for routines that do not fetch data. The current settings are maintained for compatibility. | | Automatic rebind of plans and packages created before DB2 Version 4 | | | | | If you have plans and packages that were bound on DB2 Version 4 and before and you specified YES or COEXIST in the AUTO BIND field of panel DSNTIPO, DB2 Version 9.1 autobinds these packages. Thus, you might experience an execution delay the first time that such a plan is loaded. Also, DB2 might change the access path due to the autobind, potentially resulting in a more efficient access path. | | | If you specified NO in the AUTO BIND field of panel DSNTIPO, DB2 Version 9.1 returns SQLCODE -908, SQLSTATE 23510 for each attempt to use such a package or plan until it is rebound. 2 Application Programming and SQL Guide
  • 19.
    | | Changed behavior ofthe INSERT statement with the OVERRIDING USER VALUES clause | | | When the INSERT statement is specified with the OVERRIDING USER VALUES clause, the value for the insert operation is ignored for columns that are defined with the GENERATED BY DEFAULT attribute. | DESCRIBE no longer returns LONG type values | | | | Because DB2 no longer stores LONG type values in the catalog, when you execute a DESCRIBE statement against a column with a LONG VARCHAR or LONG VARGRAPHIC data type, the DESCRIBE statement returns the values as VARCHAR or VARGRAPHIC data type. | | | | The DSNTIAUL sample program was updated through APAR PK46518 to account for this change. You need to apply APAR PK46518 and precompile, bind compile, and link-edit DSNTIAUL to make it compatible with the changed DESCRIBE behavior. | | DB2 enforces the restrictions about where a host variable array can be specified | | | | | | | | host-variable-array is the meta-variable for host variable arrays in syntax diagrams. host-variable-array is included only in the syntax for multi-row FETCH, multi-row INSERT, multi-row MERGE, and EXECUTE in support of a dynamic multi-row INSERT or MERGE statement. host-variable-array is not included in the syntax diagram for expression , so a host variable array cannot be used in other contexts. In previous releases, if you specified host-variable-array in an unsupported context, you received no errors. In Version 9.1, if a host variable array is referenced in an unsupported context, DB2 issues an error. | | For more information about where you can specify the host-variable-array variable, see DB2 SQL Reference. | | DEBUGSESSION system privilege required for continued debugging of SQL procedures | | | | | After you migrate to new-function mode, users that debug external SQL procedures need the DEBUGSESSION system privilege. Only users of the new Unified Debugger enabled client platforms need this system privilege. Users of the Version 8 SQL Debugger-enabled client platforms do not need this system privilege. | Changes to the result length of the DECRYPT function | | | | The result length of the DECRYPT function is shortened to 8 bytes less than the length of the input value. If the result expands because of a difference between input and result CCSIDs, you must cast the encrypted data to a larger VARCHAR value before the DECRYPT function is run. | | COLTYPE column in SYSIBM.SYSCOLUMNS and SYSIBM.SYSCOLUMNS_HIST for LONG column types | | | When new tables are created with LONG VARCHAR or LONG VARGRAPHIC columns, the COLTYPE values in SYSIBM.SYSCOLUMNS and SYSIBM.SYSCOLUMNS_HIST contain VARCHAR or VARG. Chapter 1. Planning for and designing DB2 applications 3
  • 20.
    | | | CREATEDBY column inSYSIBM.SYSDATATYPES, SYSIBM.SYSROUTINES, SYSIBM.SYSSEQUENCES, and SYSIBM.SYSTRIGGERS | | | | The CREATEDBY column might contain a different value than in previous releases of DB2. The column might contain a different value in static CREATE statements for distinct types, functions, and procedures or when a dynamic SQL statement sets the CURRENT SQLID value to a value other than USER. | Drop and recreate SYSPROC.DSNWZP | | | Drop and recreate SYSPROC.DSNWZP as part of running job DSNTIJSG or alter it to specify READS SQL DATA, as shown in the following SQL statement: | | | | On data sharing systems, SYSPROC.DSNWZP needs to be dropped and recreated as part of migrating the first member, but not for subsequent members. DSNTIJSG grants execute access on DSNWZP to PUBLIC. If necessary, change PUBLIC to a specific authorization ID. | | DB2 returns all DSNWZP output in the same format as DB2 parameters | | | | | | In previous releases, DSNWZP returned the current setting of several system parameters in a format other than the one used by the system parameter macros. For example, DSN6SPRM expected the setting for EDMPOOL in kilobytes, and DSNWZP returned it in bytes. In Version 9.1, DB2 returns all DSNWZP output in the same format as DB2 parameters. Modify programs that call DSNWZP if they compensate for the format differences. | | DB2 enforces the restriction that row IDs are not compatible with character strings when they are used with a set operator | | | | In previous releases, DB2 did not always enforce the restriction that row IDs are not compatible with character strings. In Version 9.1, DB2 enforces the restriction that row IDs are not compatible with string types when they are used with a set operator (UNION, INTERSECT, or EXCEPT). | | You can no longer explicitly create a database name as DSNxxxxx | | | After you migrate to compatibility mode, if you explicitly create a database name with eight characters that begins with DSN and is followed by exactly five digits, DB2 issues an SQLCODE -20074 (SQLSTATE 42939). | | Database privileges on the DSNDB04 database now give you those privileges on all implicitly-created databases | | | | | Because database privileges on the DSNDB04 database now give you those privileges on all implicitly created databases, careful consideration is needed before you grant database privileges on DSNDB04. For example, in Version 9.1, if you have the STOPDB privilege on DSNDB04, you also have the STOPDB privilege on all implicitly-created databases. ALTER PROCEDURE SYSPROC.DSNWZP READS SQL DATA; 4 Application Programming and SQL Guide
  • 21.
    | | Implicitly-created objects thatare associated with LOB columns require additional privileges | | | | In previous releases, implicitly-created objects that are associated with LOB columns did not require CREATETAB and CREATETS privileges on the database of the base table or USE privilege on the buffer pool and storage group that is used by the LOB objects. In Version 9.1, these privileges are required. | Adjust applications to use LRHCLR instead of LGDISCLR | | | | The LGDISCLR field in the DSNDQJ00 macro has been removed. Update applications that used the LGDISCLR value in the DSNDQJ00 mapping macro to determine whether a log record is a compensation log record to use the LRHCLR value instead. | Changed behavior for the CREATE statement | | | You can no longer create databases with the AS TEMP clause or table spaces that specify TEMP as the target database. The TEMP database is no longer used by DB2. The WORKFILE database is the only temporary database. | The DECLARE statement and the work file database | | | | If you have applications in Version 8 that issue DECLARE SENSITIVE STATIC SCROLL CURSOR or DECLARE GLOBAL TEMPORARY TABLE statements, ensure that the work file database exists and that it has at least one table space with a 32-KB page size to avoid errors. | Plan for the XML data type | | | Drop any user-defined data types with the name XML to prevent problems with the new Version 9 built-in XML data type. You can recreate the existing user-defined data types with new names. | Changes to XMLNAMESPACES | | | | In Version 8, in the XMLNAMESPACES function, if the XML-namespace-uri argument had a value of http://www.w3.org/XML/1998/namespace or http://www.w3.org/2000/xmlns/, DB2 did not issue an error. In Version 9.1, starting in compatibility mode, DB2 issues an error. | Changes to serialization of empty elements | | | | In Version 8, DB2 serialized empty XML elements in a different way than it serializes them in Version 9.1. In Version 8, empty element ″a″ was serialized as <a></a>. In Version 9.1, starting in compatibility mode, empty element ″a″ is serialized as <a/>. | Adjust monitor programs that access OP buffers | | | | | Adjust assignment strategies of monitor programs that access OP buffers. In Version 8, traces were left in a disabled state, which consumed CPU for trace data that could not be retrieved. In Version 9.1, traces that are started with a destination of OPX choose the next available buffer that is not in use and traces are no longer left in a disabled state. Chapter 1. Planning for and designing DB2 applications 5
  • 22.
    | | | | | | | In addition, inVersion 8, when the thread that owned an OP buffer terminated, OP traces were left in a disabled state and could be reactivated by starting another trace to that buffer. In Version 9.1, if an OP buffer terminates and the only destinations for the trace records are OP buffers, the traces that are started to that buffer are stopped. If an OP buffer terminates and the trace is started to both OP and non-OP destinations, the traces that are started to that buffer are modified to use non-OP destinations only. | | The message format of DSNW128I and DSNW129I has changed, so modify automation that is based on those message formats. | Changed behavior for system-required objects | | | | | After you migrate to Version 9.1 new-function mode, if the containing table space is implicitly-created, you cannot drop any system-required objects, except for the LOB table space, even if you explicitly created these objects in a previous release. The following statements will not work properly if the system-required objects were implicitly created by DB2: | | | | | CREATE AUXILIARY TABLE If you issue a CREATE AUXILIARY TABLE statement and an auxiliary table that was implicitly created by DB2 already exists for the same base table, the CREATE AUXILIARY TABLE statement fails and DB2 issues SQLCODE -646, SQLSTATE 55017, and reason code 3. | | | | | CREATE LOB TABLESPACE If you issue a CREATE LOB TABLESPACE statement to create a LOB table space in an implicitly created database, the CREATE LOB TABLESPACE statement fails and DB2 issues SQLCODE -2035, SQLSTATE 429BW, and reason code 1. | | | | | CREATE DATABASE If you specify a database name with eight characters that begins with DSN and is followed by exactly five digits in a CREATE DATABASE statement, the CREATE DATABASE statement fails and DB2 issues SQLCODE -20074, SQLSTATE 42939. | | | | CREATE INDEX If you create an index on a primary key, unique key, or ROWID column that is defined as GENERATED BY DEFAULT, the index will be treated as a regular index instead of an enforcing index. | | | | | CREATE AUXILIARY INDEX If you issue a CREATE AUXILIARY INDEX statement and an auxiliary index that was implicitly created by DB2 already exists for the same base table, the CREATE AUXILIARY INDEX statement fails and DB2 issues SQLCODE -748, SQLCODE 54048, and reason code 3. | | | | | | | | | CREATE If you issue a CREATE statement and do not specify an IN clause or table space name, and the default buffer pool is not large enough, DB2 chooses a 4-KB, 8-KB, 16-KB, or 32-KB buffer pool, depending on the record size. If you issue a CREATE statement and do not specify an IN clause or table space name, DB2 implicitly creates a segmented or partitioned-by-growth table space, depending on the value of TABLE SPACE TYPE on installation panel DSNTIP7. If you drop the table, DB2 also drops the containing table space. 6 Application Programming and SQL Guide
  • 23.
    | | | | | DROP TABLE If youissue a DROP TABLE statement to drop an auxiliary table from a table space that was implicitly created by DB2, the DROP TABLE statement fails and DB2 issues SQLCODE -2035, SQLSTATE 429BW, and reason code 2. | | | | DROP TABLESPACE If you issue a DROP TABLESPACE statement to drop an implicitly-created LOB table space, the DROP TABLESPACE statement fails and DB2 issues SQLCODE -2035, SQLSTATE 429BW, and reason code 2. | | | | | | | | DROP INDEX If you issue a DROP INDEX statement to drop an enforcing primary key, unique key, or ROWID index from a table space that was implicitly created, the DROP INDEX statement fails and DB2 issues SQLCODE -669, SQLSTATE 42917, and reason code 2. If you issue a DROP INDEX statement to drop an auxiliary index from a table space that was implicitly created, the DROP INDEX statement fails and DB2 issues SQLCODE -2035, SQLSTATE 429BW, and reason code 2. | | Changes to INSERT, UPDATE, or DELETE statements on some indexes | | | In Version 9.1, you cannot execute INSERT, UPDATE, or DELETE statements that affect an index in the same commit scope as ALTER INDEX statements on that index. | | Availability of LOB or XML values in JDBC or SQLJ applications with progressive streaming | | | | | | | In previous releases, if a JDBC or SQLJ application retrieved LOB data into an application variable, the contents of the application variable were still available after the cursor was moved or closed. DB2 Version 9.1 for z/OS supports streaming. The IBM DB2 Driver for JDBC and SQLJ uses progressive streaming as the default for retrieval of LOB or XML values. When progressive streaming is in effect, the contents of LOB or XML variables are no longer available after the cursor is moved or closed. | | LOBs with a maximum length greater than 1 GB can now be logged | | | In previous releases, only LOBs with a maximum length of 1 GB or less could be logged. In Version 9.1, LOBs with a maximum length that is greater than 1 GB can be logged. | | | | DB2 returns an error when a LOB value is specified for an argument to a stored procedure and the argument value is longer than the target parameter and the excess is not trailing blanks | | | | In previous releases, DB2 did not return an error when a LOB value was specified for an argument to a stored procedure and the argument value was longer than the target parameter and the excess was not trailing blanks. DB2 truncated the data and the procedure executed. In Version 9.1, DB2 returns an error. Chapter 1. Planning for and designing DB2 applications 7
  • 24.
    | Changes to VARCHARfunction formatting of decimal data | | | | In Version 9.1, the formatting of decimal data has changed for the VARCHAR function and CAST specification with a VARCHAR result type. When the input data is decimal, any leading zeroes in the input value are removed, and leading zeroes are not added to an input value that did not already contain leading zeroes. | Changes to VARCHAR_FORMAT function length attribute | | In Version 9.1, the length attribute of the result is the length attribute of the format string, up to a maximum of 100. | | ’W’ is no longer recognized as a valid format element of the VARCHAR_FORMAT function format string | | | | | ’W’ is no longer recognized as a valid format element. Use WW instead. Drop and recreate existing views and materialized queries that are defined with Version 9.1 and that use the ’W’ format element with the VARCHAR_FORMAT function. Rebind existing bound statements that are bound with Version 9.1 and that use the ’W’ format element with the VARCHAR_FORMAT function. | | Leading or trailing blanks from the VARCHAR_FORMAT function format string are no longer removed | | | | | | | Leading or trailing blanks from the format string for the VARCHAR_FORMAT function are no longer removed. Existing view definitions are recalculated as part of Version 9.1, so the new rules take effect. You can continue to use existing materialized query statements, but they use the old rules and remove leading and trailing blanks. Existing references to the VARCHAR_FORMAT function in bound statements only get the new behavior when they have been bound or rebound in Version 9.1. | | DB2 issues warnings when some BEFORE or AFTER triggers are created | | | DB2 Version 9.1 for z/OS issues a warning when a BEFORE or AFTER trigger is created and a trigger transition variable is passed as an argument for a parameter on a CALL statement that is within the trigger body. | DB2 drops certain indexes when a unique constraint is dropped | | | | In previous releases, if a unique constraint was dropped, DB2 did not drop the index that enforced uniqueness. In Version 9.1, if a table is in an implicitly-created table space, and a unique constraint on that table is dropped, DB2 drops the index that enforces uniqueness. | | Changes to the upper limit to the size of the row that is used by sort to evaluate column functions | | | The maximum limit of a row (data and key columns) that is used by sort to evaluate MULTIPLE DISTINCT and GROUP BY column functions is decreased to 32600. If you exceed the limit, DB2 issues an error. 8 Application Programming and SQL Guide
  • 25.
    | | DB2 enforces restrictionon specifying a CAST FROM clause for some forms of CREATE FUNCTION statements | | | | | | | | The CAST FROM clause is included only in the syntax diagram for the CREATE FUNCTION statement for an external scalar function. The CAST FROM clause is not included in the syntax diagrams for the other variations of CREATE FUNCTION (external table function, sourced function, or SQL function); the clause cannot be used for these other variations. In previous releases, if you specified a CAST FROM clause in an unsupported context, you received no errors. In Version 9.1 if a CAST FROM clause is specified in an unsupported context, DB2 issues an error. | | DB2 enforces restrictions on specifying the AS LOCATOR clause and TABLE LIKE clause | | | | | | | The AS LOCATOR clause for LOBs is included in the syntax diagram for the CREATE FUNCTION statement for an SQL function. This clause is not supported in other contexts when identifying an existing SQL function such as in an ALTER, COMMENT, DROP, GRANT, or REVOKE statement. In previous releases, if you specified an AS LOCATOR clause for LOBs in an unsupported context, you might not have received an error. In Version 9.1 if an AS LOCATOR clause for LOBs is specified in an unsupported context, DB2 issues an error. | | | | | | | | | The TABLE LIKE clause for a trigger transition table is included only in the syntax diagram for the CREATE FUNCTION statement for an external scalar function, external table function, or sourced function. This clause is not supported for SQL functions or in other contexts when identifying an existing function such as in an ALTER, COMMENT, DROP, GRANT, or REVOKE statement, or in the SOURCE clause of a CREATE FUNCTION statement. In previous releases, if you specified a TABLE LIKE clause for a trigger transition table in an unsupported context, you might not have received an error. In Version 9.1 if a TABLE LIKE clause for a trigger transition table is specified in an unsupported context, DB2 issues an error. | | DB2 enforces restriction on the CCSID parameter for the DECRYPT_BIT and DECRYPT_BINARY functions | | | | | The CCSID parameter is not supported by the DECRYPT_BIT and DECRYPT_BINARY built-in functions. In previous releases, if you specified an argument for the CCSID parameter for these functions, you received no errors. In Version 9.1 if an argument is specified for the CCSID parameter in an unsupported context, DB2 issues an error. | | Changed behavior of CREATE PROCEDURE for an SQL procedure | | | | | | With the introduction of native SQL procedures in Version 9.1, the semantics of the CREATE PROCEDURE statement for an SQL procedure has changed. Starting in Version 9.1, all SQL procedures that are created without the FENCED option or the EXTERNAL option in the CREATE PROCEDURE statement are native SQL procedures. In previous releases of DB2, if you did not specify either of these options, the procedures were created as external SQL procedures. | | | If you do specify FENCED or EXTERNAL, the meanings are the same as in previous releases of DB2. Both of these keywords mean that an external SQL procedure is to be created. Chapter 1. Planning for and designing DB2 applications 9
  • 26.
    | | Resolution of parameternames, variable names and column names in SQL procedures | | | | | | | | In Version 9.1, the rules used for name resolution within a native SQL procedure differ from the rules that were used for SQL procedures in prior releases. Because an SQL parameter or SQL variable can have the same name as a column name, you should explicitly qualify the names of any SQL parameters, SQL variables or columns that have non-unique names. For more information about how the names of these items are resolved, see the topic “References to SQL parameters and SQL variables”. The rules used for name resolution within external SQL procedures remains unchanged. | Clearing of the diagnostics area | | | | | | | | | | In Version 9.1, when an SQL statement other than GET DIAGNOSTICS or compound-statement is processed, the current diagnostics area is cleared before DB2 processes the SQL statement. Clearing of the diagnostics area can result in different values being returned for RETURNED_SQLSTATE and DB2_RETURNED_SQLCODE for a GET DIAGNOSTICS statement than what would be returned if the GET DIAGNOSTICS statement were issued from within an external SQL procedure, or an SQL procedure with Version 8. Additionally, there might be some differences in the values returned for the SQLSTATE and SQLCODE SQL variables than would have been returned from an external SQL procedure, or an SQL procedure with Version 8. | | SQLSTATE and SQLCODE SQL variables after a GET DIAGNOSTICS statement | | In Version 9.1, the SQLSTATE and SQLCODE SQL variables are not cleared following a GET DIAGNOSTICS statement. | Coding multiple SQL statements in a handler body | | | | | | Previous releases of DB2 did not allow for a compound statement within a handler. A workaround to include multiple statements within a handler (without support for a compound statement in a handler) was to use another control statement, such as an IF statement, which in turn contained multiple statements. Version 9.1 now supports a compound statement within a handler body. The compound statement is recommended for including multiple statements within a handler body. | Unhandled warnings | | In Version 9.1, when a procedure completes processing with an unhandled warning, DB2 returns the unhandled warning to the calling application. | Changed messages from SQL procedures | | | | | In Version 9.1, DB2 issues different messages for the new native SQL procedures than it does for external SQL procedures. For external SQL procedures, DB2 continues to issue DSNHxxxx messages. For native SQL procedures, DB2 issues SQL return codes. The relationship between these messages is shown in the following table: 10 Application Programming and SQL Guide
  • 27.
    | | Table 1. Relationshipbetween DSNHxxxx messages that are issued for external SQL procedures and SQLCODEs that are issued for native SQL procedures | DSNHxxxx message1 SQLCODE2 | DSNH051I -051 | DSNH385I +385 | DSNH590I -590 | DSNH4408I -408 | DSNH4777I -777 | DSNH4778I -778 | DSNH4779I -779 | DSNH4780I -780 | DSNH4781I -781 | DSNH4782I -782 | DSNH4785I -785 | | DSNH4787I -787 | | | | Note: 1. These messages are used for external SQL procedures, which can be defined by specifying EXTERNAL or FENCED in Version 9.1. 2. These messages are used for native SQL procedures in Version 9.1. | Enhanced data type checking for zero-length characters | | In Version 9.1, when you specify Char(0), DB2 issues SQLCODE -804 regardless of the null indicator value. | | | Determining the value of any SQL processing options that affect the design of your program | | | | When you process SQL statements in an application program, you can specify options that describe the basic characteristics of the program or indicate how you want the output listings to look. Although most of these options do not affect how you design or code the program, a few options do. | | | | SQL processing options specify program characteristics such as the following items: v The host language in which the program is written v The maximum precision of decimal numbers in the program v How many lines are on a page of the precompiler listing | In many cases, you may want to accept the default value provided. | | To determine the value of any SQL processing options that affect the design of your program: | | | | | Review the list of SQL processing options and decide the values for any options that affect the way that you write your program. For example, you need to know if you are using NOFOR or STDSQL(YES) before you begin coding. Related concepts “DB2 program preparation overview” on page 895 Chapter 1. Planning for and designing DB2 applications 11
  • 28.
    Related reference “Descriptions ofSQL processing options” on page 854 | | | | Determining the binding method | | | | Before you can run an application, you must bind a plan. You can bind all of your database request modules (DBRMs) into a single application plan or you can first bind packages and then bind those packages into a plan. The bind method that you choose can affect your application design. | | | | | | You can choose one of the following binding methods: v Bind all of your DBRMs into a single application plan. v Bind all of your DBRMs into separate packages. Then bind all those packages into a single application plan. | | | The use of packages affects your application design. For example, you might decide to put certain SQL statements together in the same program, precompile them into the same DBRM, and then bind them into a single package. | To determine the binding method: | | Consider the advantages and disadvantages of each binding method, which are described in the following table. v Bind some of your DBRMs into separate packages. Then bind those packages and any other DBRMs for that program into an application plan. | Table 2. Advantages and disadvantages of each binding method | Binding method Advantages Disadvantages | Bind all of your DBRMs | into a single application | plan. | | | This method has fewer steps and is appropriate in some cases. This method is suitable for small applications that are unlikely to change or that require all resources to be acquired when the plan is allocated, rather than when your program first uses them. Maintenance is difficult. This method has the disadvantage that a change to one DBRM requires rebinding the entire plan, even though most DBRMs are unchanged. 12 Application Programming and SQL Guide
  • 29.
    | Table 2. Advantagesand disadvantages of each binding method (continued) | Binding method Advantages | | | | | | | | | | | | | | | | | Bind all of your DBRMs into separate packages. Then bind all those packages into a single application plan Maintenance is easier. When you use packages, you do not need to bind the entire plan again when you change one SQL statement. You need to bind only the package that is associated with the changed SQL statement. Disadvantages Too many packages might be difficult to track. Input to binding a package is a single DBRM only. A one-to-one correspondence between programs and packages might You can incrementally develop your program without easily enable you to keep track rebinding the plan. A collection is a group of associated of each. However, your packages. Binding packages into package collections application might consist of too enables you to add packages to an existing application many packages to track easily. plan without having to bind the plan again. If you include a collection name in the package list when you bind a plan, any package in the collection becomes available to the plan. The collection can be empty when you first bind the plan. Later, you can add packages to the collection and drop or replace existing packages without binding the plan again. | | | | | | | | | | | | | | You can maintain several versions of a package within the same plan. Maintaining several versions of a plan without using packages requires a separate plan for each version, and therefore, separate plan names and RUN commands. Isolating separate versions of a program into packages requires only one plan and helps to simplify program migration and fallback. For example, you can maintain separate development, test, and production levels of a program by binding each level of the program as a separate version of a package, all within a single plan. You cannot bind or rebind a package or a plan while it is running. However, you can bind a different version of a package that is running. | | | | | | | | | You can use different bind options for different DBRMs. The options of the BIND PLAN command apply to all DBRMs that are bound directly to the plan. The options of the BIND PACKAGE command apply to only the single DBRM that is bound to that package. The package options need not all be the same as the plan options, and they need not be the same as the options for other packages that are used by the same plan. | | | | | | | | You can use different name qualifiers for different groups of SQL statements. You can use a bind option to name a qualifier for the unqualified object names in SQL statements in a plan or package. By using packages, you can use different qualifiers for SQL statements in different parts of your application. By rebinding, you can redirect your SQL statements, for example, from a test table to a production table. | | | | | | Unused packages are not locked. Packages and plans are locked when you bind or run them. Packages that run under a plan are not locked until the plan uses them. If you run a plan and some packages in the package list never run, those packages are never locked. Chapter 1. Planning for and designing DB2 applications 13
  • 30.
    | Table 2.Advantages and disadvantages of each binding method (continued) | Binding method Advantages Disadvantages | | | | | | | | | | | | This method helps you migrate to using packages. Binding DBRMs directly to the plan and specifying a package list is a suitable method for maintaining existing applications. You can add a package list when you rebind an existing plan. To migrate gradually to the use of packages, bind DBRMs as packages when you need to make changes. Depending on your application design, you might not gain some of the advantages of using packages. Bind some of your DBRMs into separate packages. Then bind those packages and any other DBRMs for that program into an application plan. Related concepts “DB2 program preparation overview” on page 895 Related tasks “Binding an application” on page 865 Changes that invalidate plans or packages | | | | Changes to your program or database objects can invalidate plans and packages. Consider the effect of these changes when you determine the binding method for your program. | | | A change to your program probably invalidates one or more of your packages and perhaps your entire plan. For some changes, you must bind a new object; for others, rebinding is sufficient. | | | | | A plan or package can also become invalid for reasons that do not depend on operations in your program. For example, when an index is dropped that is used in an access path by one of your queries, a plan or package can become invalid. In those cases, DB2 might rebind the plan or package automatically the next time that the plan or package is used. | | The following table lists the actions that you must take when changes are made to your program or database objects. | Table 3. Changes that require plans or packages to be rebound. | Change made Required action | | | Run RUNSTATS to update catalog statistics Rebind the package or plan by using the REBIND command. Rebinding might improve the access path that DB2 uses. | | | | Add an index to a table Rebind the package or plan by using the REBIND command. Rebinding causes DB2 to consider using the index when accessing this table. | | | | | | Change the bind options | | | Change both statements in the host language Precompile, compile, and link the application and SQL statements program. Issue the BIND command with ACTION(REPLACE) for the package or plan. 14 Application Programming and SQL Guide 1 Rebind the package or plan by using the REBIND command and specifying the new value for the bind option. If the option that you want to change is not available for the REBIND command, issue the BIND command with ACTION(REPLACE) instead.
  • 31.
    | Table 3. Changesthat require plans or packages to be rebound. (continued) | Change made Required action | | | | | Drop a table, index, or other object, and recreate the object If a table with a trigger is dropped, recreate the trigger if you recreate the table. Otherwise, no change is required. DB2 attempts to automatically rebind the plan or package the next time it is run. | | | | Drop an object that a package depends on No action is required. If the package or plan becomes invalid, DB2 automatically rebinds the plan or package the next time that it is allocated. | | | | | | | | | | | | The package might become invalid according to the following criteria: | | | In all cases, the plan does not become invalid until it has a DBRM that references the dropped object. v If the package is not appended to any running plan, the package becomes invalid. v If the package is appended to a running plan, and the drop occurs within that plan, the package becomes invalid. However, if the package is appended to a running plan, and the drop occurs outside of that plan, the object is not dropped, and the package does not become invalid. | | | | | | Revoke an authorization to use an object No action is required. DB2 attempts to automatically rebind the plan or package the next time it is run. Automatic rebind fails if authorization is still not available. In this case, you must rebind the package or plan by using the REBIND command. | | | | | | Rename a column in a table on which a plan or package is dependent No action is required. DB2 automatically rebinds invalidated plans and packages. If automatic rebind is unsuccessful, modify, recompile, and rebind the affected applications. | Note: 1. In the case of changing the bind options, the change is not actually made until you perform the required action. Related concepts “Automatic rebinding” on page 893 “Trigger packages” on page 427 Related tasks “Rebinding an application” on page 885 | | | | | | | Chapter 1. Planning for and designing DB2 applications 15
  • 32.
    | | | Determining the valueof any bind options that affect the design of your program | | | | Several options of the BIND PACKAGE and BIND PLAN commands can affect your program design. For example, you can use a bind option to ensure that a package or plan can run only from a particular CICS connection or IMS region; your code does not need to enforce this situation. | To determine the value of any bind options that affect the design of your program: | | | | | | | Review the list of bind options and decide the values for any options that affect the way that you write your program. For example, you should decide the values of the ACQUIRE and RELEASE options before you write your program. These options determine when your application acquires and releases locks on the objects it uses. Related reference ″BIND and REBIND options″ (DB2 Command Reference) | | Designing your application to promote concurrency | | | You should design your program so that it protects the integrity of the data, but does not prevent other processes from accessing the same data for long periods of time. | | | | Concurrency is the ability of more than one application process to access the same data at essentially the same time. Concurrency must be controlled to prevent lost updates and such possibly undesirable effects as unrepeatable reads and access to uncommitted data. | | | | | | | | | | | | To design your application to promote concurrency: 1. Understand the techniques that DB2 uses to control concurrency. One basic way that DB2 controls concurrency is by using locks for units of work. When a unit of work completes, all locks that were implicitly acquired by that unit of work are released, which enables a new unit of work to begin. The amount of processing time that is used by a unit of work in your program affects the length of time that DB2 prevents other users from accessing that locked data. When several programs try to use the same data concurrently, each program’s unit of work should be as short as possible to minimize the interference between the programs. Other techniques are discussed in the performance information about improving concurrency. 2. Follow the recommendations for application design for concurrency. Related tasks ″Programming for concurrency″ (DB2 Performance Monitoring and Tuning Guide) ″Programming your applications for concurrency″ (DB2 Performance Monitoring and Tuning Guide) | | | | | | 16 Application Programming and SQL Guide
  • 33.
    | | Designing your applicationfor recovery | | | If your application fails or DB2 terminates abnormally, you need to ensure the integrity of any data that was manipulated in your application. You should consider possible recovery situations when you design your application. | To design your application for recovery: 1. Put any changes that logically need to be made at the same time in the same unit of work. This action ensures that in case DB2 terminates abnormally or your application fails, the data is left in a consistent state. A unit of work is a logically distinct procedure that contains steps that change the data. If all the steps complete successfully, you want the data changes to become permanent. But, if any of the steps fail, you want all modified data to return to the original value before the procedure began. For example, suppose two employees in the sample table DSN8910.EMP exchange offices. You need to exchange their office phone numbers in the PHONENO column. You need to use two UPDATE statements to make each phone number current. Both statements, taken together, are a unit of work. You want both statements to complete successfully. For example, if only one statement is successful, you want both phone numbers rolled back to their original values before attempting another update. | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 2. Consider how often you should commit any changes to the data. If your program abends or the system fails, DB2 backs out all uncommitted data changes. Changed data returns to its original condition without interfering with other system activities. For IMS and CICS applications, if the system fails, DB2 data does not always return to a consistent state immediately. DB2 does not process indoubt data (data that is neither uncommitted nor committed) until you restart IMS or the CICS attachment facility. To ensure that DB2 and IMS are synchronized, restart both DB2 and IMS. To ensure that DB2 and CICS are synchronized, restart both DB2 and the CICS attachment facility. 3. Consider whether your application should intercept abends. If your application intercepts abends, DB2 commits work, because it is unaware that an abend has occurred. If you want DB2 to roll back work automatically when an abend occurs in your program, do not let the program or run-time environment intercept the abend. If your program uses Language Environment®, and you want DB2 to roll back work automatically when an abend occurs in the program, specify the run-time options ABTERMENC(ABEND) and TRAP(ON). 4. For TSO applications only: Issue COMMIT statements before you connect to another DBMS. If the system fails at this point, DB2 cannot know whether your transaction is complete. In this case, as in the case of a failure during a one-phase commit operation for a single subsystem, you must make your own provision for maintaining data integrity. 5. For TSO applications only: Determine if you want to provide an abend exit routine in your program. If you provide this routine, it must use tracking indicators to determine if an abend occurs during DB2 processing. If an abend does occur when DB2 has control, you must allow task termination to complete. DB2 detects task termination and terminates the thread with the ABRT parameter. Do not re-run the program. Chapter 1. Planning for and designing DB2 applications 17
  • 34.
    Allowing task terminationto complete is the only action that you can take for abends that are caused by the CANCEL command or by DETACH. You cannot use additional SQL statements at this point. If you attempt to execute another SQL statement from the application program or its recovery routine, unexpected errors can occur. Related concepts ″Unit of work″ (DB2 SQL Reference) | | | | | | | Unit of work in TSO | | | Applications that use the TSO attachment facility can explicitly define units of work by using the SQL COMMIT and ROLLBACK statements. | | | | | In TSO applications, a unit of work starts when the first updates of a DB2 object occur. A unit of work ends when one of the following conditions occurs: v The program issues a subsequent COMMIT statement. At this point in the processing, your program has determined that the data is consistent; all data changes that were made since the previous commit point were made correctly. v The program issues a subsequent ROLLBACK statement. At this point in the processing, your program has determined that the data changes were not made correctly and, therefore, should not be permanent. A ROLLBACK statement causes any data changes that were made since the last commit point to be backed out. v The program terminates and returns to the DSN command processor, which returns to the TSO Terminal Monitor Program (TMP). | | | | | | | The first and third conditions in the preceding list are called a commit point. A commit point occurs when you issue a COMMIT statement or your program terminates normally. Related reference ″COMMIT″ (DB2 SQL Reference) ″ROLLBACK″ (DB2 SQL Reference) | | | | | | Unit of work in CICS | | | | CICS applications can explicitly define units of work by using the CICS SYNCPOINT command. Alternatively, units of work are defined implicitly by several logic breaking points. | | | | | | | | | All the processing that occurs in your program between two commit points is known as a logical unit of work (LUW) or unit of work. In CICS applications, a unit of work is marked as complete by a commit or synchronization (sync) point, which is defined in one of following ways: v Implicitly at the end of a transaction, which is signaled by a CICS RETURN command at the highest logical level. | | | v Explicitly by CICS SYNCPOINT commands that the program issues at logically appropriate points in the transaction. v Implicitly through a DL/I PSB termination (TERM) call or command. v Implicitly when a batch DL/I program issues a DL/I checkpoint call. This call can occur when the batch DL/I program shares a database with CICS applications through the database sharing facility. | | For example, consider a program that subtracts the quantity of items sold from an inventory file and then adds that quantity to a reorder file. When both transactions 18 Application Programming and SQL Guide
  • 35.
    | | | | | complete (and notbefore) and the data in the two files is consistent, the program can then issue a DL/I TERM call or a SYNCPOINT command. If one of the steps fails, you want the data to return to the value it had before the unit of work began. That is, you want it rolled back to a previous point of consistency. You can achieve this state by using the SYNCPOINT command with the ROLLBACK option. | | | | | By using a SYNCPOINT command with the ROLLBACK option, you can back out uncommitted data changes. For example, a program that updates a set of related rows sometimes encounters an error after updating several of them. The program can use the SYNCPOINT command with the ROLLBACK option to undo all of the updates without giving up control. | | | The SQL COMMIT and ROLLBACK statements are not valid in a CICS environment. You can coordinate DB2 with CICS functions that are used in programs, so that DB2 and non-DB2 data are consistent. | Planning for program recovery in IMS programs | | | | To be prepared for recovery situations for IMS programs that access DB2 data, you need to make several design decisions that are specific to IMS programs. These decisions are in addition to the general recommendations that you should follow when designing your application for recovery. | | Both IMS and DB2 handle recovery in an IMS application program that accesses DB2 data. IMS coordinates the process, and DB2 handles recovery for DB2 data. | To plan for program recovery in IMS programs: 1. For a program that processes messages as its input, decide whether to specify single-mode or multiple-mode transactions on the TRANSACT statement of the APPLCTN macro for the program. | | | | | | | | | | | | | | | | | | | | | | | | | | | Single-mode Indicates that a commit point in DB2 occurs each time the program issues a call to retrieve a new message. Specifying single-mode can simplify recovery; if the program abends, you can restart the program from the most recent call for a new message. When IMS restarts the program, the program starts by processing the next message. Multiple-mode Indicates that a commit point occurs when the program issues a checkpoint call or when it terminates normally. Those two events are the only times during the program that IMS sends the program’s output messages to their destinations. Because fewer commit points are processed in multiple-mode programs than in single-mode programs, multiple-mode programs could perform slightly better than single-mode programs. When a multiple-mode program abends, IMS can restart it only from a checkpoint call. Instead of having only the most recent message to reprocess, a program might have several messages to reprocess. The number of messages to process depends on when the program issued the last checkpoint call. DB2 does some processing with single- and multiple-mode programs. When a multiple-mode program issues a call to retrieve a new message, DB2 performs an authorization check and closes all open cursors in the program. 2. Decide whether to issue checkpoint calls (CHKP) and if so, how often to issue them. Each call indicates to IMS that the program has reached a sync point and establishes a place in the program from which you can restart the program. Chapter 1. Planning for and designing DB2 applications 19
  • 36.
    | | | | | | | | | Consider the followingfactors when deciding when to use checkpoint calls: v How long it takes to back out and recover that unit of work. The program must issue checkpoints frequently enough to make the program easy to back out and recover. v How long database resources are locked in DB2 and IMS. v For multiple-mode programs: How you want the output messages grouped. Checkpoint calls establish how a multiple-mode program groups its output messages. Programs must issue checkpoints frequently enough to avoid building up too many output messages. | | | | | | | | | Restriction: You cannot use SQL COMMIT and ROLLBACK statements in the DB2 DL/I batch support environment, because IMS coordinates the unit of work. 3. Issue CLOSE CURSOR statements before any checkpoint calls or GU calls to the message queue, not after. 4. After any checkpoint calls, set the value of any special registers that were reset if their values are needed after the checkpoint: A CHKP call causes IMS to sign on to DB2 again, which resets the special registers that are shown in the following table. | Table 4. Special registers that are reset by a checkpoint call. | | Special register Value to which it is reset after a checkpoint call | CURRENT PACKAGESET blanks | CURRENT SERVER blanks | CURRENT SQLID blanks | | | | | | | | CURRENT DEGREE 1 5. After any commit points, reopen the cursors that you want and re-establish positioning | | | | | | 6. Decide whether to specify the WITH HOLD option for any cursors. This option determines whether the program retains the position of the cursor in the DB2 database after you issue IMS CHKP calls. You always lose the program database positioning in DL/I after an IMS CHKP call. The program database positioning in DB2 is affected according to the following criteria: v If you do not specify the WITH HOLD option for a cursor, you lose the position of that cursor. v If you specify the WITH HOLD option for a cursor and the application is message-driven, you lose the position of that cursor. v If you specify the WITH HOLD option for a cursor and the application is operating in DL/I batch or DL/I BMP, you retain the position of that cursor. 7. Use IMS rollback calls, ROLL and ROLB, to back out DB2 and DL/I changes to the last commit point. These options have the following differences: | | | | ROLL Specifies that all changes since the last commit point are to be backed out and the program is to be terminated. IMS terminates the program with user abend code U0778 and without a storage dump. | | | | When you issue a ROLL call, the only option you supply is the call function, ROLL. | | 20 Application Programming and SQL Guide
  • 37.
    | | | | ROLLB Specifies that allchanges since the last commit point are to be backed out and control is to be returned to the program so that it can continue processing. | | | | | | A ROLB call has the following options: v The call function, ROLB v The name of the I/O PCB How ROLL and ROLB calls effect DL/I changes in a batch environment depends on the IMS system log and back out options that are specified, as shown in the following table. | Table 5. Effects of ROLL and ROLLB calls on DL/I changes in a batch environment | Options specified | Rollback call System log option Backout option | | | | | | | ROLL tape any disk BKO=NO disk BKO=YES | | | | | | Result DL/I does not back out updates, and abend U0778 occurs. DB2 backs out updates to the previous checkpoint. DL/I backs out updates, and abend U0778 occurs. DB2 backs out updates to the previous checkpoint. Chapter 1. Planning for and designing DB2 applications 21
  • 38.
    | | Table 5. Effectsof ROLL and ROLLB calls on DL/I changes in a batch environment (continued) | Options specified | Rollback call System log option Backout option | | | | | | | | | | | | | ROLB tape any disk BKO=NO disk BKO=YES | | | | | | | | | | | | | | | | | | | | | | | | | | | | Result DL/I does not back out updates, and an AL status code is returned in the PCB. DB2 backs out updates to the previous checkpoint. The DB2 DL/I support causes the application program to abend when ROLB fails. DL/I backs out database updates, and control is passed back to the application program. DB2 backs out updates to the previous checkpoint. Restriction: You cannot specify the address of an I/O area as one of the options on the call; if you do, your program receives an AD status code. However, you must have an I/O PCB for your program. Specify CMPAT=YES on the CMPAT keyword in the PSBGEN statement for your program’s PSB. Related concepts “Checkpoints in IMS programs” on page 24 | | | Unit of work in IMS online programs | | | | In IMS, a unit of work starts when one of the following events occurs: v When the program starts v After a CHKP, SYNC, ROLL, or ROLB call has completed v For single-mode transactions, when a GU call is issued to the I/O PCB | A unit of work ends when one of the following events occurs: IMS applications can explicitly define units of work by using a CHKP, SYNC, ROLL, or ROLB call, or, for single-mode transactions, a GU call. 22 Application Programming and SQL Guide
  • 39.
    | | | | | | | | v The programissues either a subsequent CHKP or SYNC call, or, for single-mode transactions, a GU call to the I/O PCB. At this point in the processing, the data is consistent. All data changes that were made since the previous commit point are made correctly. v The program issues a subsequent ROLB or ROLL call. At this point in the processing, your program has determined that the data changes are not correct and, therefore, that the data changes should not become permanent. v The program terminates. | | Restriction: The SQL COMMIT and ROLLBACK statements are not valid in an IMS environment. | | | | | | A commit point occurs in a program as the result of any one of the following events: v The program terminates normally. Normal program termination is always a commit point. v The program issues a checkpoint call. Checkpoint calls are a program’s means of explicitly indicating to IMS that it has reached a commit point in its processing. v The program issues a SYNC call. A SYNC call is a Fast Path system service call to request commit-point processing. You can use a SYNC call only in a non-message-driven Fast Path program. v For a program that processes messages as its input, a commit point can occur when the program retrieves a new message. This behavior depends on the mode that you specify in the APPLCTN macro for the program: – If you specify single-mode transactions, a commit point in DB2 occurs each time the program issues a call to retrieve a new message. – If you specify multiple-mode transactions or you do not specify a mode, a commit point occurs when the program issues a checkpoint call or when it terminates normally. | | | | | | | | | | | | | | | | At the time of a commit point, the following actions occur: v IMS and DB2 can release locks that the program has held since the last commit point. Releasing these locks makes the data available to other application programs and users. However, when you define a cursor as WITH HOLD in a BMP program, DB2 holds those locks until the cursor closes or the program ends. v DB2 closes any open cursors that the program has been using. v IMS and DB2 make the program’s changes to the database permanent. v If the program processes messages, IMS sends the output messages that the application program produces to their final destinations. Until the program reaches a commit point, IMS holds the program’s output messages at a temporary destination. | | | | | | | | If the program abends before reaching the commit point, the following actions occur: v Both IMS and DB2 back out all the changes the program has made to the database since the last commit point. v IMS deletes any output messages that the program has produced since the last commit point (for nonexpress PCBs). v If the program processes messages, people at terminals and other application programs receive information from the terminating application program. | | | | | | | Chapter 1. Planning for and designing DB2 applications 23
  • 40.
    | | If the systemfails, a unit of work resolves automatically when DB2 and IMS batch programs reconnect. Any indoubt units of work are resolved at reconnect time. | | | | Specifying checkpoint frequency in IMS programs | To specify checkpoint frequency in IMS programs: 1. Use a counter in your program to keep track of one of the following items: v Elapsed time v The number of root segments that your program accesses A checkpoint indicates a commit point in IMS programs. You should specify checkpoint frequency in your program in a way that makes changing it easy in case the frequency you initially specify is not right. | | | | | | v The number of updates that your program performs 2. Issue a checkpoint call after a certain time interval, number of root segments, or number of updates. | Checkpoints in IMS programs: | | | | Issuing checkpoint calls releases locked resources and establishes a place in the program from which you can restart the program. The decision about whether your program should issue checkpoints (and if so, how often) depends on your program. | Generally, the following types of programs should issue checkpoint calls: v Multiple-mode programs v Batch-oriented BMPs v Nonmessage-driven Fast Path programs. (These programs can use a special Fast Path call, but they can also use symbolic checkpoint calls.) v Most batch programs v Programs that run in a data sharing environment. (Data sharing makes it possible for online and batch application programs in separate IMS systems, in the same or separate processors, to access databases concurrently. Issuing checkpoint calls frequently in programs that run in a data sharing environment is important, because programs in several IMS systems access the database.) | | | | | | | | | | | You do not need to issue checkpoints in the following types of programs: v Single-mode programs v Database load programs v Programs that access the database in read-only mode (defined with the processing option GO during a PSBGEN) and are short enough to restart from the beginning v Programs that, by their nature, must have exclusive use of the database | | | | | | | | | A CHKP call causes IMS to perform the following actions: v Inform DB2 that the changes that your program made to the database can become permanent. DB2 makes the changes to DB2 data permanent, and IMS makes the changes to IMS data permanent. v Send a message that contains the checkpoint identification that is given in the call to the system console operator and to the IMS master terminal operator. v Return the next input message to the program’s I/O area if the program processes input messages. In MPPs and transaction-oriented BMPs, a checkpoint call acts like a call for a new message. | | | | | | 24 Application Programming and SQL Guide
  • 41.
    | v Sign onto DB2 again. | | | Programs that issue symbolic checkpoint calls can specify as many as seven data areas in the program that is to be restored at restart. DB2 always recovers to the last checkpoint. You must restart the program from that point. | | | | If you use symbolic checkpoint calls, you can use a restart call (XRST) to restart a program after an abend. This call restores the program’s data areas to the way they were when the program terminated abnormally, and it restarts the program from the last checkpoint call that the program issued before terminating abnormally. | | Restriction: For BMP programs that process DB2 databases, you can restart the program only from the latest checkpoint and not from any checkpoint, as in IMS. | Checkpoints in MPPs and transaction-oriented BMPs | | | | | | | | | In single-mode programs, checkpoint calls and message retrieval calls (called get-unique calls) both establish commit points. The checkpoint calls retrieve input messages and take the place of get-unique calls. BMPs that access non-DL/I databases and MPPs can issue both get unique calls and checkpoint calls to establish commit points. However, message-driven BMPs must issue checkpoint calls rather than get-unique calls to establish commit points, because they can restart from a checkpoint only. If a program abends after issuing a get-unique call, IMS backs out the database updates to the most recent commit point, which is the get-unique call. | | | | | | | In multiple-mode BMPs and MPPs, the only commit points are the checkpoint calls that the program issues and normal program termination. If the program abends and it has not issued checkpoint calls, IMS backs out the program’s database updates and cancels the messages that it has created since the beginning of the program. If the program has issued checkpoint calls, IMS backs out the program’s changes and cancels the output messages it has created since the most recent checkpoint call. | Checkpoints in batch-oriented BMPs | | | | If a batch-oriented BMP does not issue checkpoints frequently enough, IMS can abend that BMP or another application program for one of the following reasons: v Other programs cannot get to the data that they need within a specified amount of time. If a BMP retrieves and updates many database records between checkpoint calls, it can monopolize large portions of the databases and cause long waits for other programs that need those segments. (The exception to this situation is a BMP with a processing option of GO; IMS does not enqueue segments for programs with this processing option.) Issuing checkpoint calls releases the segments that the BMP has enqueued and makes them available to other programs. v Not enough storage is available for the segments that the program has read and updated. If IMS is using program isolation enqueuing, the space that is needed to enqueue information about the segments that the program has read and updated must not exceed the amount of storage that is defined for the IMS system. (The amount of storage available is specified during IMS system definition. ) If a BMP enqueues too many segments, the amount of storage that is needed for the enqueued segments can exceed the amount of available storage. In that case, | | | | | | | | | | | | | | Chapter 1. Planning for and designing DB2 applications 25
  • 42.
    IMS terminates theprogram abnormally. You then need to increase the program’s checkpoint frequency before rerunning the program. | | | | | | | | | When you issue a DL/I CHKP call from an application program that uses DB2 databases, IMS processes the CHKP call for all DL/I databases, and DB2 commits all the DB2 database resources. No checkpoint information is recorded for DB2 databases in the IMS log or the DB2 log. The application program must record relevant information about DB2 databases for a checkpoint, if necessary. One way to record such information is to put it in a data area that is included in the DL/I CHKP call. | | | | | Performance might be slowed by the commit processing that DB2 does during a DL/I CHKP call, because the program needs to re-establish position within a DB2 database. The fastest way to re-establish a position in a DB2 database is to use an index on the target table, with a key that matches one-to-one with every column in the SQL predicate. | | | Recovering data in IMS programs | To recover data in IMS programs: | Take one or more of the following actions depending on the type of program: | | Program type Recommended action | | | | DL/I batch applications Use the DL/I batch backout utility to back out DL/I changes. DB2 automatically backs out changes whenever the application program abends. | | | | | | | Applications that use symbolic checkpoints Use a restart call (XRST) to restart a program after an abend. This call restores the program’s data areas to the way they were when the program terminated abnormally, and it restarts the program from the last checkpoint call that the program issued before terminating abnormally. | | | | | BMP programs that access DB2 databases Restart the program from the latest checkpoint. Restriction: You can restart the program only from the latest checkpoint and not from any checkpoint, as in IMS. | | Applications that use online IMS systems No action needed. Recovery and restart are part of the IMS system | | | Applications that reside in the batch region Follow your location’s operational procedures to control recovery and restart. In an online IMS system, recovery and restart are part of the IMS system. For a batch region, your location’s operational procedures control recovery and restart. Undoing selected changes within a unit of work by using savepoints | | | | | Savepoints enable you to undo selected changes within a unit of work. Your application can set any number of savepoints and then specify a specific savepoint to indicate which changes to undo within the unit of work. | To undo selected changes within a unit of work by using savepoints: 26 Application Programming and SQL Guide
  • 43.
    | | | | | | | | | | | | | | | | | | | | | 1. Set anysavepoints by using SQL SAVEPOINT statements. Savepoints set a point to which you can undo changes within a unit of work. Consider the following abilities and restrictions when setting savepoints: v You can set a savepoint with the same name multiple times within a unit of work. Each time that you set the savepoint, the new value of the savepoint replaces the old value. v If you do not want a savepoint to have different values within a unit of work, use the UNIQUE option in the SAVEPOINT statement. If an application executes a SAVEPOINT statement with the same name as a savepoint that was previously defined as unique, an SQL error occurs. v If you set a savepoint before you execute a CONNECT statement, the scope of that savepoint is the local site. If you set a savepoint after you execute the CONNECT statement, the scope of that savepoint is the site to which you are connected. | | | | | | v When savepoints are active, which they are until the unit of work completes, you cannot access remote sites by using three-part names or aliases for three-part names. You can, however, use DRDA® access with explicit CONNECT statements. v You cannot use savepoints in global transactions, triggers, user-defined functions, or stored procedures that are nested within triggers or user-defined functions. 2. Specify the changes that you want to undo within a unit of work by using the SQL ROLLBACK TO SAVEPOINT statement. DB2 undoes all changes since the specified savepoint. If you do not specify a savepoint name, DB2 rolls back work to the most recently created savepoint. 3. Optional: If you no longer need a savepoint, delete it by using the SQL RELEASE SAVEPOINT statement. | | | | | Recommendation: If you no longer need a savepoint before the end of a transaction, release it. Otherwise, savepoints are automatically released at the end of a unit of work. Releasing savepoints is essential if you need to use three-part names to access remote locations, because you cannot perform this action while savepoints are active. | Examples | | | | | | | | Rolling back to the most recently created savepoint: When the ROLLBACK TO SAVEPOINT statement is executed in the following code, DB2 rolls back work to savepoint B. | | | | | | Setting savepoints during distributed processing: An application performs the following tasks: 1. Sets savepoint C1. 2. Does some local processing. 3. Executes a CONNECT statement to connect to a remote site. 4. Sets savepoint C2. EXEC SQL SAVEPOINT A; ... EXEC SQL SAVEPOINT B; ... EXEC SQL ROLLBACK TO SAVEPOINT; Chapter 1. Planning for and designing DB2 applications 27
  • 44.
    | | | | Because savepoint C1is set before the application connects to a remote site, savepoint C1 is known only at the local site. However, because savepoint C2 is set after the application connects to the remote site, savepoint C2 is known only at the remote site. | | | | Setting multiple savepoints with the same name: Suppose that the following actions occur within a unit of work: 1. Application A sets savepoint S. 2. Application A calls stored procedure P. 3. Stored procedure P sets savepoint S. 4. Stored procedure P executes the following statement: ROLLBACK TO SAVEPOINT S | | When DB2 executes the ROLLBACK statement, DB2 rolls back work to the savepoint that was set in the stored procedure, because that value is the most recent value of savepoint S. Related reference ″SAVEPOINT″ (DB2 SQL Reference) ″ROLLBACK″ (DB2 SQL Reference) ″RELEASE SAVEPOINT″ (DB2 SQL Reference) | | | | | | | Planning for recovery of table spaces that are not logged | | | | | To suppress logging, you can specify the NOT LOGGED option when you create or alter a table space. However, because logs are generally used in recovery, planning for recovery of table spaces for which changes are not logged requires some additional planning. | | | | | | Although you can plan for recovery, you still need to take some corrective actions after any system failures to recover the data and fix any affected table spaces. For example, if a table space that is not logged was open for update at the time that DB2 terminates, the subsequent restart places that table space in LPL and marks it with RECOVER-pending status. You need to take corrective action to clear the RECOVER-pending status. | | | | | | | | | To plan for recovery of table spaces that are not logged: 1. Ensure that you can recover lost data by performing one of the following actions: v Ensure that you have a data recovery source that does not rely on a log record to recreate any lost data. v Limit modifications that are not logged to easily repeatable changes that can be quickly repeated. 2. Avoid placing a table space that is not logged in a RECOVER-pending status. The following actions place a table space in RECOVER-pending status: v Issuing a ROLLBACK statement or ROLLBACK TO SAVEPOINT statement after modifying a table in a table space that is not logged. v Causing duplicate keys or referential integrity violations when you modify a table space that is not logged. | | | | If the table space is placed in RECOVER-pending status, it is unavailable until you manually fix it. 3. For table spaces that are not logged and have associated LOB or XML table spaces, take image copies as a recovery set. | | | | 28 Application Programming and SQL Guide
  • 45.
    | | | | | | | This action ensuresthat the base table space and all the associated LOB or XML table spaces are copied at the same point in time. A subsequent RECOVER TO LASTCOPY operation for the entire set results in consistent data across the base table space and all of the associated LOB and XML table spaces. Related tasks ″Clearing the RECOVER-pending status″ (DB2 Administration Guide) Related reference | ″RECOVER″ (DB2 Utility Guide and Reference) Designing your application to access distributed data For applications that access data on another database management system (DBMS) other than your local system, use DRDA access. You should also consider the limitations and recommendations for such programs when designing them. If your system is not already set up to use DRDA access, you must first prepare your system to use DRDA access. One of the tools that can help you during this process is the private to DRDA protocol REXX™ tool (DSNTP2DP). To design your application to access distributed data: 1. Ensure that the appropriate authorization ID has been granted authorization at the remote server to connect to that server and use resources from it. 2. If your application contains SQL statements that run at the requester, include at the requester a database request module (DBRM) that is bound either directly to a plan or to a package that is included in the plan’s package list. 3. Include a package at the remote server for any SQL statements that run at that server. 4. For TSO and batch applications that update data at a remote server, ensure that one of the following conditions is true: v No other connections exist. v All existing connections are to servers that are restricted to read-only operations. Restriction: If neither of these conditions are met, the application is restricted to read-only operations. If one of these conditions is met, and if the first connection in a logical unit of work is to a server that supports two-phase commit, that server and all servers that support two-phase commit can update data. However, if the first connection is to a server that does not support two-phase commit, only that server is allowed to update data. 5. For programs that access at least one restricted system, ensure that your program does not violate any of the limitations for accessing restricted systems. A restricted system is a DBMS that does not implement two-phase commit processing. Accessing restricted systems has the following limitations: v For programs that access CICS or IMS, you cannot update data on restricted systems. v Within a unit of work, you cannot update a restricted system after updating a non-restricted system. v Within a unit of work, if you update a restricted system, you cannot update any other systems. Chapter 1. Planning for and designing DB2 applications 29
  • 46.
    If you areaccessing a mixture of systems, some of which might be restricted, you can perform the following actions: v Read from any of the systems at any time. v Update any one system many times in one unit of work. v Update many systems, including CICS or IMS, in one unit of work, provided that none of them is a restricted system. If the first system you update in a unit of work is not restricted, any attempt to update a restricted system in that unit of work returns an error. v Update one restricted system in a unit of work, provided that you do not try to update any other system in the same unit of work. If the first system you update in a unit of work is restricted, any attempt to update any other system in that unit of work returns an error. Related tasks ″Preparing your system for DRDA access″ (DB2 Installation Guide) Related reference ″The private to DRDA protocol REXX tool (DSNTP2DP)″ (DB2 Installation Guide) Remote servers and distributed data Distributed data is data that resides on a database management system (DBMS) other than your local system. Your local DBMS is the one on which you bind your application plan. All other DBMSs are remote. If you are requesting services from a remote DBMS, that DBMS is a server, and your local system is a requester or client. Your application can be connected to many DBMSs at one time; the one that is currently performing work is the current server. When the local system is performing work, it also is called the current server. A remote server can be physically remote, or it can be another subsystem of the same operating system that your local DBMS runs under. A remote server might be an instance of DB2 for z/OS, or it might be an instance of one of another product. A DBMS, whether local or remote, is known to your DB2 system by its location name. The location name of a remote DBMS is recorded in the communications database. Related tasks ″Choosing names for the local subsystem″ (DB2 Installation Guide) Advantages of DRDA access Programs that access distributed data should use DRDA access. Not only does DRDA access have many advantages over DB2 private protocol access, but also private protocol support will be removed in a future release of DB2. DRDA access has the following advantages over DB2 private protocol access: v Integration: DRDA access is available to all DBMSs that implement Distributed Relational Database Architecture (DRDA). Those DBMSs include supported releases of DB2 for z/OS, other members of the DB2 family of IBM products, and many products of other companies. DB2 private protocol access is available only to supported releases of DB2 for z/OS. 30 Application Programming and SQL Guide
  • 47.
    v SQL compatibility:DRDA access allows any SQL statement that the server can execute. DB2 private protocol access supports only data manipulation statements: INSERT, UPDATE, DELETE, SELECT, OPEN, FETCH, and CLOSE. In addition, you cannot use any syntax of an SQL statement that was introduced after DB2 Version 5. You also cannot invoke user-defined functions and stored procedures or use LOBs or distinct types. v Reduced network load: DRDA access uses a more compact format for sending data over the network. This process improves the performance on slow network links. v Reduced bind processing: A DBRM for statements that are executed by DRDA access is bound to a package at the server only once. Those statements can include PREPARE and EXECUTE, so your application can accept dynamic statements that are to be executed at the server. Queries that are executed by DB2 private protocol access are bound at the server whenever they are first executed in a unit of work. Repeated binds can reduce the performance of a query that is executed often. v Stored procedures: You can use stored procedures with DRDA access. Because stored procedures require no message traffic over the network while they are running, they reduce the biggest obstacle to high performance for distributed data. v Scrollable cursors: You can use scrollable cursors if you use DRDA access. v Savepoints: You can set savepoints only if you use DRDA access with explicit CONNECT statements. If you set a savepoint and then execute an SQL statement with a three-part name, an SQL error occurs. Related tasks “Undoing selected changes within a unit of work by using savepoints” on page 26 Preparing for coordinated updates to two or more data sources Two or more updates are coordinated if they must all commit or all roll back in the same unit of work. This situation is common in banking. Suppose that an amount is subtracted from one account and added to another. The two actions must either both commit or both roll back at the end of the unit of work. To prepare for coordinated updates to two or more data sources: Ensure that all systems that your program accesses implement two-phase commit processing. This processing ensures that updates to two or more DBMSs are coordinated automatically. For example, DB2 and IMS, and DB2 and CICS, jointly implement a two-phase commit process. You can update an IMS database and a DB2 table in the same unit of work. If a system or communication failure occurs between committing the work on IMS and on DB2, the two programs restore the two systems to a consistent point when activity resumes. | | | You cannot do true coordinated updates within a DBMS that does not implement two-phase commit processing, because DB2 prevents you from updating such a DBMS and any other system within the same unit of work. In this context, update Chapter 1. Planning for and designing DB2 applications 31
  • 48.
    includes the statementsINSERT, UPDATE, MERGE, DELETE, CREATE, ALTER, DROP, GRANT, REVOKE, RENAME, COMMENT, and LABEL. | | However, if you cannot implement two-phase commit processing on all systems that your program accesses, you can simulate the effect of coordinated updates by performing the following actions: 1. Update one system and commit that work. 2. Update the second system and commit its work. 3. Ensure that your program has code to undo the first update if a failure occurs after the first update is committed and before the second update is committed. No automatic provision exists for bringing the two systems back to a consistent point. Related concepts ″Two-phase commit process″ (DB2 Administration Guide) Forcing restricted system rules in your program A restricted system is a DBMS that does not implement two-phase commit processing. These systems have a number of update restrictions. You can restrict your program completely to the rules for these restricted systems, regardless of whether the program is accessing restricted systems or non-restricted systems. Accessing restricted systems has the following limitations: v For programs that access CICS or IMS, you cannot update data on restricted systems. v Within a unit of work, you cannot update a restricted system after updating a non-restricted system. v Within a unit of work, if you update a restricted system, you cannot update any other systems. To force restricted system rules in your program: When you prepare your program, specify the SQL processing option CONNECT(1). This option applies type 1 CONNECT statement rules. Restriction: Do not use packages that are precompiled with the CONNECT(1) option and packages that are precompiled with the CONNECT(2) option in the same package list. The first CONNECT statement that is executed by your program determines which rules are in effect for the entire execution: type 1 or type 2. If your program attempts to execute a later CONNECT statement that is precompiled with the other type, DB2 returns an error. Related concepts “Options for SQL statement processing” on page 853 Maximizing the performance of an application that accesses distributed data They key to improving the performance of applications that access remote data is to limit the number of network transmissions. You should consider if any of the recommendations for reducing these transmissions makes sense for your application. To maximize the performance of an application that accesses distributed data: 32 Application Programming and SQL Guide
  • 49.
    1. Write anyqueries that access distributed data according to the following recommendations to limit the number of messages that these queries send over the network: v Reduce the number of columns and rows in the result table by keeping the select lists as short as possible and using the WHERE, GROUP BY, and HAVING clauses to eliminate unwanted data at the remote server. v Specify the FOR FETCH ONLY or FOR READ ONLY clause when possible. Retrieving thousands of rows as a continuous stream is reasonable. Sending a separate message for each one can be significantly slower. However, be aware the a query that is sent to a remote subsystem almost always takes longer to execute than the same query that accesses tables of the same size on the local subsystem for the following reasons: v Overhead processing, including startup, negotiating session limits, and, for DB2 private protocol access, the bind required at the remote location v The time required to send messages across the network 2. For any of the following situations, use the OPTIMIZE FOR n ROWS clause in your SELECT statements and query result sets from stored procedures: v The application fetches only a small number of rows from the query result set. v The application fetches a large number of rows from a read-only query. v The application rarely closes the SQL cursor before fetching the entire query result set. v The application does not issue statements other than the FETCH statement to the DB2 server while the SQL cursor is open. v The application does not execute FETCH statements for multiple cursors that are open concurrently and defined with the OPTIMIZE FOR n ROWS clause. v The application does not need to scroll randomly through the data. The OPTIMIZE FOR n ROWS clause limits the number of data rows that the server returns on each DRDA network transmission. Restriction: This clause has no effect on scrollable cursors. In a DRDA environment, if you specify 1, 2, or 3 for n , DB2 uses the value 16 (instead of n) for network blocking and prefetches 16 rows. As a result, network usage is more efficient even though DB2 uses the small value of n for query optimization. For example, the following SQL statement causes DB2 to prefetch 16 rows of the result table even though n has a value of 1. SELECT * FROM EMP OPTIMIZE FOR 1 ROW ONLY; 3. For queries that have potentially large result tables, but need only a limited number of rows, specify the FETCH FIRST n ROWS ONLY clause. This clause limits the number of rows that are returned to a client program. For example, suppose that you need only one row of the result table. You can add the FETCH FIRST 1 ROW ONLY clause, as shown in the following example: SELECT * FROM EMP OPTIMIZE FOR 1 ROW ONLY FETCH FIRST 1 ROW ONLY; In this case, the FETCH FIRST 1 ROW ONLY clause prevents 15 unnecessary prefetches. 4. If your program accesses LOB columns in a remote table, use the following techniques to minimize the number of bytes that are transferred between the client and the server: Chapter 1. Planning for and designing DB2 applications 33
  • 50.
    v Use LOBlocators instead of LOB host variables. If you need to store only a portion of a LOB value at the client, or if your client program manipulates the LOB data but does not need a copy of it, LOB locators are a good choice. When a client program retrieves a LOB column from a server into a locator, DB2 transfers only the 4-byte locator value to the client, not the entire LOB value. v Use stored procedure result sets. When you return LOB data to a client program from a stored procedure, use result sets rather than passing the LOB data to the client in parameters. Using result sets to return data causes less LOB materialization and less movement of data among address spaces. v Set the CURRENT RULES special register to DB2. When a DB2 server receives an OPEN request for a cursor, the server uses the value in the CURRENT RULES special register to determine the type of host variables that the associated statement uses to retrieve LOB values. If you specify a value of DB2 for the CURRENT RULES special register before you perform a CONNECT, and the first FETCH statement for the cursor uses a LOB locator to retrieve LOB column values, DB2 lets you use only LOB locators for all subsequent FETCH statements for that column until you close the cursor. If the first FETCH statement uses a host variable, DB2 lets you use only host variables for all subsequent FETCH statements for that column until you close the cursor. However, if you set the value of CURRENT RULES to STD, DB2 lets you use the same open cursor to fetch a LOB column into either a LOB locator or a host variable. Although a value of STD for the CURRENT RULES special register gives you more programming flexibility when you retrieve LOB data, you get better performance if you use a value of DB2. With the STD option, the server must send and receive network messages for each FETCH statement to indicate whether the data that is being transferred is a LOB locator or a LOB value. With the DB2 option, the server knows the size of the LOB data after the first FETCH, so an extra message about LOB data size is unnecessary. The server can send multiple blocks of data to the requester at one time, which reduces the total time for data transfer. For example, suppose that an end user wants to browse through a large set of employee records and look at pictures of only a few of those employees. At the server, you set the CURRENT RULES special register to DB2. In the application, you declare and open a cursor to select employee records. The application then fetches all picture data into 4-byte LOB locators. Because DB2 knows that 4 bytes of LOB data is returned for each FETCH statement, DB2 can fill the network buffers with locators for many pictures. When a user wants to see a picture for a particular person, the application can retrieve the picture from the server by assigning the value that is referenced by the LOB locator to a LOB host variable. This situation is implemented in the following code: SQL TYPE IS BLOB my_blob[1M]; SQL TYPE IS BLOB AS LOCATOR my_loc; . . . FETCH C1 INTO :my_loc; /* Fetch BLOB into LOB locator */ . . . SET :my_blob = :my_loc; /* Assign BLOB to host variable */ Restriction: You must use DRDA access to access LOB columns in a remote table. 5. Minimize the use of parameter markers. 34 Application Programming and SQL Guide
  • 51.
    When using DRDAaccess, DB2 can streamline the processing of dynamic queries that do not have parameter markers. When a DB2 requester encounters a PREPARE statement for such a query, it anticipates that the application is going to open a cursor. DB2 therefore sends a single message to the server that contains a combined request for the PREPARE, DESCRIBE, and OPEN operations. A server that receives this message sequence returns a reply message sequence that includes the output from the PREPARE, DESCRIBE, and OPEN operations. As a result, the number of network messages sent and received for these operations is reduced from two to one. DB2 combines messages for these queries regardless of whether the bind option DEFER(PREPARE) is specified. 6. Ensure that each cursor meets one of the following conditions when possible, so that DB2 uses block fetch to minimize the number of messages that are sent across the network: v The cursor is declared with either the FOR FETCH ONLY or FOR READ ONLY clause. v The cursor is a non-scrollable cursor, and the result table of the cursor is read-only. v The cursor is a scrollable cursor that is declared as INSENSITIVE, and the result table of the cursor is read-only. v The cursor is a scrollable cursor that is declared as SENSITIVE, the result table of the cursor is read-only, and the value of the CURRENTDATA bind option is NO. v The result table of the cursor is not read-only, but the cursor is ambiguous, and the value of the CURRENTDATA bind option is NO. A cursor is ambiguous when any of the following conditions are true: – It is not defined with the clauses FOR FETCH ONLY, FOR READ ONLY, or FOR UPDATE. – It is not defined on a read-only result table. – It is not the target of a WHERE CURRENT clause on an SQL UPDATE or DELETE statement. – It is in a plan or package that contains the SQL statements PREPARE or EXECUTE IMMEDIATE. 7. For ODBC and JDBC applications, use the rowset parameter to limit the number of rows that are returned from a fetch operation. If a DRDA requester sends the rowset parameter to a DB2 server, the server performs the following actions: v Returns no more than the number of rows in the rowset parameter v Returns extra query blocks if the value of the EXTRA BLOCKS SRV field on the DISTRIBUTED DATA FACILITY PANEL 2 installation panel on the server allows extra query blocks to be returned v Processes the FETCH FIRST n ROWS ONLY clause, if it is specified v Does not process the OPTIMIZE FOR n ROWS clause 8. Use the recommended values for the following bind options: Table 6. Recommended bind option values for applications that access distributed data Bind option Recommended value and actions Reason CURRENTDATA CURRENTDATA(NO) Use this bind option to force block fetch for ambiguous queries. Chapter 1. Planning for and designing DB2 applications 35
  • 52.
    Table 6. Recommendedbind option values for applications that access distributed data (continued) Bind option Recommended value and actions Reason DBPROTOCOL DBPROTOCOL(DRDA) If the value of the installation default database protocol is not DRDA, use this bind option to cause DB2 to use DRDA access to execute SQL statements with three-part names. Statements that use DRDA access perform better at execution time for the following reasons: v Binding occurs when the package is bound, not during program execution. v DB2 does not destroy static statement information at commit time, as it does with DB2 private protocol access. With DRDA access, if a commit occurs between two executions of a statement, DB2 does not need to prepare the statement twice. ISOLATION Anything but ISOLATION (RR) When possible, do not bind application plans and packages with ISOLATION(RR). If your application does not need to reference rows that it has already read, another isolation level might reduce lock contention and message overhead during commit processing. KEEPDYNAMIC KEEPDYNAMIC(YES) Use this bind option to improve performance for queries that use cursors that are defined with the WITH HOLD option. With KEEPDYNAMIC(YES), DB2 automatically closes the cursor when no more data exists for retrieval. The client does not need to send a network message to tell DB2 to close the cursor. NODEFER and DEFER DEFER(PREPARE) This option reduces network traffic, because the PREPARE and EXECUTE statements and responses are transmitted together. 36 Application Programming and SQL Guide
  • 53.
    Table 6. Recommendedbind option values for applications that access distributed data (continued) Bind option Recommended value and actions PKLIST and NOPKLIST Reason PKLIST The order in which you specify package collections in a package list can affect the Specify the package collections for this bind performance of your application program. option according to the following When a local instance of DB2 attempts to recommendations: execute an SQL statement at a remote server, the local DB2 subsystem must v Reduce the number of packages per determine which package collection the collection that DB2 must search. The SQL statement is in. DB2 must send a following example specifies only one message to the server to request that the package in each collection: server check each collection ID for the SQL PKLIST(S1.COLLA.PGM1, S1.COLLB.PGM2) statement until the statement is found or no v Reduce the number of package more collection IDs are in the package list. collections at each location that DB2 must You can reduce the amount of network search. The following example specifies traffic, and thereby improve performance, only one package collection at each by reducing the number of package location: collections that each server must search. PKLIST(S1.COLLA.*, S2.COLLB.*) v Reduce the number of collections that are As an alternative to specifying the package used for each application. The following collections on the PKLIST bind option, you can specify the package collection that is example specifies only one collection to associated with an SQL statement in your search: application program. Execute the SET PKLIST(*.COLLA.*) CURRENT PACKAGESET statement before you execute an SQL statement to tell DB2 Requirement: When you specify the DEFER(PREPARE) bind option with DRDA which package collection to search for the statement. access, the package that contains the statements whose preparation you want to defer must be the first qualifying entry in the package search sequence that DB2 uses. For example, assume that the package list for a plan contains two entries: PKLIST(LOCB.COLLA.*, LOCB.COLLB.*) If the intended package is in collection COLLB, ensure that DB2 searches that collection first by executing the following SQL statement: SET CURRENT PACKAGESET = ’COLLB’; Alternatively, you can list COLLB first in the PKLIST bind option: PKLIST(LOCB.COLLB.*, LOCB.COLLA.*) For the NODEFER(PREPARE) bind option, the collections in the package list can be in any order, but if the package is not found in the first qualifying PKLIST entry, significant network overhead might result from DB2 searching through the list. Chapter 1. Planning for and designing DB2 applications 37
  • 54.
    Table 6. Recommendedbind option values for applications that access distributed data (continued) Bind option Recommended value and actions Reason REOPT Use the following guidelines to decide which option to choose: Because of performance costs when DB2 reoptimizes the access path at run time, minimize reoptimization when possible. | | | | | | | | | | | v Use the REOPT(AUTO) option when the following conditions are true: – You are using the dynamic statement cache. – You want DB2 to decide if a new access path is needed. – Your dynamic SQL statements are executed many times with possibly different input variables. – Similar input variables tend to be executed consecutively. v Use the REOPT(ALWAYS) option on only packages or plans that contain statements that perform poorly because of a bad access path. If you specify REOPT(ALWAYS) when you bind a plan that contains statements that use DB2 private protocol access to access remote data, DB2 prepares those statements twice. v Use the REOPT(ONCE) option when the following conditions are true: – You are using the dynamic statement cache. – You have plans or packages that contain dynamic SQL statements that perform poorly because of access path selection. – Your dynamic SQL statements are executed many times with possibly different input variables. v Use the REOPT(NONE) option when you bind a plan or package that contains statements that use DB2 private protocol access. Related concepts ″Block fetching result sets″ (DB2 Performance Monitoring and Tuning Guide) “How DB2 identifies packages at run time” on page 873 Related tasks ″Fetching a limited number of rows: FETCH FIRST n ROWS ONLY″ (DB2 Performance Monitoring and Tuning Guide) “Saving storage when manipulating LOBs by using LOB locators” on page 667 Related reference ″fetch-first-clause″ (DB2 SQL Reference) ″BIND and REBIND options″ (DB2 Command Reference) 38 Application Programming and SQL Guide
  • 55.
    The effect ofthe OPTIMIZE FOR n ROWS clause in distributed applications You can specify the OPTIMIZE FOR n ROWS clause to improve the performance of certain queries. For queries that access distributed data, this clause can have a significant performance impact, because it helps limit the amount of data that is sent over the network and the number of network transmissions. When you specify the OPTIMIZE FOR n ROWS clause in your query, the number of rows that DB2 transmits on each network transmission depends on the following factors: v If n rows of the SQL result set fit within a single DRDA query block, a DB2 server can send n rows to any DRDA client. In this case, DB2 sends n rows in each network transmission until the entire query result set is returned. v If n rows of the SQL result set exceed a single DRDA query block, the number of rows that are contained in each network transmission depends on the client’s DRDA software level and configuration. The following conditions apply: – If the client does not support extra query blocks, the DB2 server automatically reduces the value of n to match the number of rows that fit within a DRDA query block. – If the client supports extra query blocks, the DRDA client can choose to accept multiple DRDA query blocks in a single data transmission. DRDA allows the client to establish an upper limit on the number of DRDA query blocks in each network transmission. The number of rows that a DB2 server sends is the smaller of the following values: - n rows - the number of rows that fit within the maximum number of extra DRDA query blocks that the DB2 server returns to a client in a single network transmission. (This value is specified in the EXTRA BLOCKS SRV field on installation panel DSNTIP5 at the DB2 server.) - the number of rows that fit within the client’s extra query block limit, which is obtained from the DDM MAXBLKEXT parameter that is received from the client. (When DB2 acts as a DRDA client, the DDM MAXBLKEXT parameter is set to the value of EXTRA BLOCKS REQ on installation panel DSNTIP5.) Depending on the value that you specify for n, the OPTIMIZE FOR n ROWS clause can improve performance in the following ways: v If n is less than the number of rows that fit in the DRDA query block, OPTIMIZE FOR n ROWS can improve performance by preventing the DB2 server from fetching rows that might never be used by the DRDA client application. v If n is greater than the number of rows that fit in a DRDA query block, OPTIMIZE FOR n ROWS lets the DRDA client request multiple blocks of query data on each network transmission. This use of OPTIMIZE FOR n ROWS can significantly improve elapsed time for applications that download large amounts of data. Although the OPTIMIZE FOR n ROWS clause can improve performance, this same function can degrade performance if you do not use it properly. The following examples demonstrate the performance problems that can occur when you do not use this clause judiciously. Chapter 1. Planning for and designing DB2 applications 39
  • 56.
    In the followingfigure, the DRDA client opens a cursor and fetches rows from the cursor. At some point before all rows in the query result set are returned, the application issues an SQL INSERT statement. DRDA client DB2 server DECLARE C1 CURSOR FOR SELECT * FROM T1 FOR FETCH ONLY; OPEN C1; SQL cursor is opened Query block with 100 rows is returned FETCH C1 INTO ...; FETCH C1 INTO ...; Server processes INSERT statement INSERT INTO ...; Figure 1. Message flows without the OPTIMIZE FOR n ROWS clause In this case, DB2 uses normal DRDA message blocking, which has the following advantages over the message blocking that is used for the OPTIMIZE FOR n ROWS clause: v If the application issues an SQL statement other than FETCH (for example, an INSERT statement in this case), the DRDA client can transmit the SQL statement immediately, because the DRDA connection is not in use after the SQL OPEN. v The DRDA query block size places an upper limit on the number of rows that are fetched unnecessarily. If the SQL application closes the cursor before fetching all the rows in the query result set, the server fetches only the number of rows that fit in one query block, which is 100 rows of the result set. In the following figure, the DRDA client opens a cursor and fetches rows from the cursor by using OPTIMIZE FOR n ROWS clause. Both the DRDA client and the DB2 server are configured to support multiple DRDA query blocks. At some time before the end of the query result set, the application issues an SQL INSERT. 40 Application Programming and SQL Guide
  • 57.
    DRDA client DB2 server DECLAREC1 CURSOR FOR SELECT * FROM T1 OPTIMIZE FOR 1000 ROWS; OPEN C1; FETCH C1 INTO ...; FETCH C1 INTO ...; . . . INSERT INTO ...; SQL cursor is opened Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Query block with 100 rows is returned Server processes INSERT statement Figure 2. Message flows with the OPTIMIZE FOR 1000 ROWS clause Because the query uses the OPTIMIZE FOR n ROWS clause, the DRDA connection is not available when the SQL INSERT is issued. The connection is still being used to receive the DRDA query blocks for 1000 rows of data. This situation causes the following performance problems: v Application elapsed time can increase if the DRDA client waits for a large query result set to be transmitted before the DRDA connection can be used for other SQL statements. In this example, the SQL INSERT statement is delayed because of a large query result set. v If the application closes the cursor before fetching all the rows in the SQL result set, the server might fetch a large number of rows unnecessarily. Related concepts ″Minimizing overhead for retrieving few rows: OPTIMIZE FOR n ROWS″ (DB2 Performance Monitoring and Tuning Guide) Related reference ″optimize-for-clause″ (DB2 SQL Reference) Fast implicit close When you specify the FETCH FIRST n ROWS ONLY clause in a distributed query, DB2 might use a fast implicit close to improve performance. Fast implicit close is the process of DB2 closing a cursor after prefetching thenth row or when no more rows are to be returned. Chapter 1. Planning for and designing DB2 applications 41
  • 58.
    Fast implicit closecan improve query performance, because it saves an additional network transmission between the client and the server. DB2 uses fast implicit close when all of the following conditions are true: v The query uses limited block fetch. v The query does not retrieve any LOBs. v The cursor is not a scrollable cursor. v Either of the following conditions is true: – The cursor is defined with the WITH HOLD option, and the package or plan that contains the cursor is bound with the KEEPDYNAMIC(YES) option. – The cursor is not defined with the WITH HOLD option. Related concepts ″Block fetching result sets″ (DB2 Performance Monitoring and Tuning Guide) 42 Application Programming and SQL Guide
  • 59.
    Chapter 2. Connectingto DB2 from your application program Application programs communicate to DB2 through an attachment facility. You must invoke an attachment facility, either implicitly or explicitly, before your program can interact with DB2. You can use the following attachment facilities in a z/OS environment: CICS attachment facility Use this facility to access DB2 from CICS application programs. IMS attachment facility Use this facility to access DB2 from IMS application programs. Time Sharing Option (TSO) attachment facility Use this facility in a TSO or batch environment to communicate to a local DB2 subsystem. This facility invokes the DSN command processor. Call attachment facility (CAF) Use this facility as an alternative to the TSO attachment facility when your application needs tight control over the session environment. Resource Recovery Services attachment facility (RRSAF) Use this facility for stored procedures that run in a WLM-established address space or as an alternative to the CAF. This facility has more capabilities than CAF. For distributed applications, use the distributed data facility (DDF). Requirement: Ensure that any application that requests DB2 services satisfies the following environment characteristics, regardless of the attachment facility that you use: v The application must be running in TCB mode. SRB mode is not supported. v An application task cannot have any Enabled Unlocked Task (EUT) functional recovery routines (FRRs) active when requesting DB2 services. If an EUT FRR is active, the DB2 functional recovery can fail, and your application can receive some unpredictable abends. v Different attachment facilities cannot be active concurrently within the same address space. Specifically, the following requirements exist: – An application must not use CAF or RRSAF in an CICS or IMS address space. – An application that runs in an address space that has a CAF connection to DB2 cannot connect to DB2 by using RRSAF. – An application that runs in an address space that has an RRSAF connection to DB2 cannot connect to DB2 by using CAF. – An application cannot invoke the z/OS AXSET macro after executing the CAF CONNECT call and before executing the CAF DISCONNECT call. v One attachment facility cannot start another. For example, your CAF or RRSAF application cannot use DSN, and a DSN RUN subcommand cannot call your CAF or RRSAF application. © Copyright IBM Corp. 1983, 2007 43
  • 60.
    v The languageinterface modules for CAF and RRSAF, DSNALI and DSNRLI, are shipped with the linkage attributes AMODE(31) and RMODE(ANY). If your applications load CAF or RRSAF below the 16-MB line, you must link-edit DSNALI or DSNRLI again. Related concepts ″DB2 attachment facilities″ (Introduction to DB2 for z/OS) ″Distributed data facility″ (Introduction to DB2 for z/OS) Invoking the call attachment facility Invoke the call attachment facility (CAF) when you want your application program to establish and control its own connection to DB2. Applications that use CAF can explicitly control the state of their connections to DB2 by using connection functions that CAF supplies. Before you can invoke CAF, perform the following actions: v Ensure that the CAF language interface (DSNALI) is available. v Ensure that your application satisfies the requirements for programs that access CAF. v Ensure that your application satisfies the general environment characteristics for connecting to DB2. v Ensure that you are familiar with the following z/OS concepts and facilities: – The CALL macro and standard module linkage conventions – Program addressing and residency options (AMODE and RMODE) – Creating and controlling tasks; multitasking – Functional recovery facilities such as ESTAE, ESTAI, and FRRs – Asynchronous events and TSO attention exits (STAX) – Synchronization techniques such as WAIT/POST. Applications that use CAF can be written in assembler language, C, COBOL, Fortran, and PL/I. When choosing a language to code your application in, consider the following restrictions: v If you need to use z/OS macros (ATTACH, WAIT, POST, and so on), use a programming language that supports them or embed them in modules that are written in assembler language. v The CAF TRANSLATE function is not available in Fortran. To use this function, code it in a routine that is written in another language, and then call that routine from Fortran. Recommendations: For IMS and DSN applications, consider the following recommendations: v For IMS batch applications, do not use CAF. Instead use the DB2 DL/I batch support. Although it is possible for IMS batch applications to access DB2 databases through CAF, that method does not coordinate the commitment of work between the IMS and DB2 systems. v For DSN applications, do not use CAF unless you provide an application controller to manage the DSN application and replace any needed DSN functions. You might also have to change the application to communicate connection failures to the controller correctly. Running DSN applications with CAF is not advantageous, and the loss of DSN services can affect how well your program runs. To invoke CAF: 44 Application Programming and SQL Guide
  • 61.
    Perform one ofthe following actions: v Explicitly invoke CAF by including in your program CALL DSNALI statements with the appropriate options. The first option is a CAF connection function, which describes the action that you want CAF to take. The effect of any function depends in part on what functions the program has already run. Requirement: For C and PL/I applications, you must also include in your program the compiler directives that are listed in the following table, because DSNALI is an assembler language program. Table 7. Compiler directives to include in C and PL/I applications that contain CALL DSNALI statements Language Compiler directive to include C #pragma linkage(dsnali, OS) C++ extern "OS" { int DSNALI( char * functn, ...); } PL/I DCL DSNALI ENTRY OPTIONS(ASM,INTER,RETCODE; v Implicitly invoke CAF by including SQL statements or IFI calls in your program just as you would in any program. The CAF facility establishes the connections to DB2 with the default values for the subsystem name and plan name. Restriction: If your program can make its first SQL call from different modules with different DBRMs, you cannot use a default plan name and thus, you cannot implicitly invoke CAF. Instead, you must explicitly invoke CAF by using the OPEN function. Requirement: If your application includes both SQL and IFI calls, you must issue at least one SQL call before you issue any IFI calls. This action ensures that your application uses the correct plan. Although doing so is not recommended, you can run existing DSN applications with CAF by allowing them to make implicit connections to DB2. For DB2 to make an implicit connection successfully, the plan name for the application must be the same as the member name of the database request module (DBRM) that DB2 produced when you precompiled the source program that contains the first SQL call. You must also substitute the DSNALI language interface module for the TSO language interface module, DSNELI. If you do not specify the return code and reason code parameters in your CAF calls or you invoked CAF implicitly, CAF puts a return code in register 15 and a reason code in register 0. To determine if an implicit connection was successful, the application program should examine the return and reason codes immediately after the first executable SQL statement in the application program by performing one of the following actions: v Examining registers 0 and 15 directly. v Examining the SQLCA, and if the SQLCODE is -991, obtain the return and reason code from the message text. The return code is the first token, and the reason code is the second token. Chapter 2. Connecting to DB2 from your application program 45
  • 62.
    If the implicitconnection was successful, the application can examine the SQLCODE for the first, and subsequent, SQL statements. Examples Example of a CAF configuration: The following figure shows an conceptual example of invoking and using CAF. The application contains statements to load DSNALI, DSNHLI2, and DSNWLI2. The application accesses DB2 by using the CAF Language Interface. It calls DSNALI to handle CAF requests, DSNWLI to handle IFI calls, and DSNHLI to handle SQL calls. Application Load LOAD DSNALI LOAD DSNHLI2 LOAD DSNWLI2 CALL DSNALI (’CONNECT’) (’OPEN’) (’CLOSE’) (’DISCONNECT’) CALL DSNWLI (IFI calls) CALL DSNHLI (SQL calls) CAF Language Interface Call DSNALI (Process connection requests) DSNHLI (dummy application entry point) CALL DSNHLI2 (Transfer calls to real CAF SQL entry point) CAF Mainline Code DB2 DSNHLI2 (Process SQL stmts) DSNWLI (dummy application entry point) CALL DSNWLI2 (Transfer calls to real CAF IFI) DSNWLI Figure 3. Sample call attachment facility configuration Sample programs that use CAF: You can find a sample assembler program (DSN8CA) and a sample COBOL program (DSN8CC) that use the CAF in library prefix.SDSNSAMP. A PL/I application (DSN8SPM) calls DSN8CA, and a COBOL application (DSN8SCM) calls DSN8CC. Related concepts 46 Application Programming and SQL Guide
  • 63.
    “DB2 sample applications”on page 1013 Call attachment facility An attachment facility enables programs to communicate with DB2. The call attachment facility (CAF) provides such a connection for programs that run in z/OS batch, TSO foreground, and TSO background and need tight control over the session environment. A program that uses CAF can perform the following actions: v Access DB2 from z/OS address spaces where TSO, IMS, or CICS do not exist. v Access DB2 from multiple z/OS tasks in an address space. v Access the DB2 IFI. v Run when DB2 is down. Restriction: The application cannot run SQL when DB2 is down. v Run with or without the TSO terminal monitor program (TMP). v Run without being a subtask of the DSN command processor or of any DB2 code. v Run above or below the 16-MB line. (The CAF code resides below the line.) v Establish an explicit connection to DB2, through a CALL interface, with control over the exact state of the connection. v Establish an implicit connection to DB2, by using SQL statements or IFI calls without first calling CAF, with a default plan name and subsystem identifier. v Verify that the application is using the correct release of DB2. v Supply event control blocks (ECBs), for DB2 to post, that signal startup or termination. v Intercept return codes, reason codes, and abend codes from DB2 and translate them into messages as desired. Any task in an address space can establish a connection to DB2 through CAF. Only one connection can exist for each task control block (TCB). A DB2 service request that is issued by a program that is running under a given task is associated with that task’s connection to DB2. The service request operates independently of any DB2 activity under any other task. Each connected task can run a plan. Multiple tasks in a single address space can specify the same plan, but each instance of a plan runs independently from the others. A task can terminate its plan and run a different plan without fully breaking its connection to DB2. CAF does not generate task structures. When you design your application, consider that using multiple simultaneous connections can increase the possibility of deadlocks and DB2 resource contention. A tracing facility provides diagnostic messages that aid in debugging programs and diagnosing errors in the CAF code. In particular, attempts to use CAF incorrectly cause error messages in the trace stream. Restriction: CAF does not provide attention processing exits or functional recovery routines. You can provide whatever attention handling and functional recovery Chapter 2. Connecting to DB2 from your application program 47
  • 64.
    your application needs,but you must use ESTAE/ESTAI type recovery routines and not Enabled Unlocked Task (EUT) FRR routines. Properties of CAF connections CAF enables programs to communicate with DB2. A CAF connection joins any task in an address space to DB2. The connection that CAF makes with DB2 has the basic properties that are listed in the following table. Table 8. Properties of CAF connections Property Value Comments Connection name DB2CALL You can use the DISPLAY THREAD command to list CAF applications that have the connection name DB2CALL. Connection type BATCH BATCH connections use a single phase commit process that is coordinated by DB2. Application programs can also control when statements are committed by using the SQL COMMIT and ROLLBACK statements. Authorization IDs Authorization IDs that are associated with the address space DB2 establishes authorization IDs for each task’s connection when it processes that connection. For the BATCH connection type, DB2 creates a list of authorization IDs based on the authorization ID that is associated with the address space. This list is the same for every task. A location can provide a DB2 connection authorization exit routine to change the list of IDs. Scope CAF processes connections as none if each task is entirely isolated. When a task requests a function, the CAF passes the functions to DB2 and is unaware of the connection status of other tasks in the address space. However, the application program and the DB2 subsystem are aware of the connection status of multiple tasks in an address space. If a connected task terminates normally before the CLOSE function deallocates the plan, DB2 commits any database changes that the thread made since the last commit point. If a connected task abends before the CLOSE function deallocates the plan, DB2 rolls back any database changes since the last commit point. In 48 Application Programming and SQL Guide
  • 65.
    either case, DB2deallocates the plan, if necessary, and terminates the task’s connection before it allows the task to terminate. If DB2 abnormally terminates while an application is running, the application is rolled back to the last commit point. If DB2 terminates while processing a commit request, DB2 either commits or rolls back any changes at the next restart. The action taken depends on the state of the commit request when DB2 terminates. Related concepts ″Connection routines and sign-on routines″ (DB2 Administration Guide) Attention exit routines for CAF An attention exit routine enables you to regain control from DB2 during long-running or erroneous requests. CAF has no attention exit routines, but you can provide your own if necessary. An attention exit routine works by detaching the TCB that is currently waiting on an SQL or IFI request to complete. After the TCB is detached, DB2 detects the resulting abend and performs termination processing for that task. The termination processing includes any necessary rollback of transactions. You can provide your own attention exit routines. However, your routine might not get control if you request attention while DB2 code is running, because DB2 uses enabled unlocked task (EUT) functional recovery routines (FRRs). Recovery routines for CAF You can use abend recovery routines and functional recovery routines (FRRs) to handle unexpected errors. An abend recovery routine controls what happens when an abend occurs while DB2 has control. A functional recovery routine can obtain information about and recover from program errors. The CAF has no abend recovery routines, but you can provide your own. Any abend recovery routines that you provide must use tracking indicators to determine if an abend occurred during DB2 processing. If an abend occurs while DB2 has control, the recovery routine can take one of the following actions: v Allow task termination to complete. Do not retry the program. DB2 detects task termination and terminates the thread with the ABRT parameter. You lose all database changes back to the last sync point or commit point. This action is the only action that you can take for abends that are caused by the CANCEL command or by DETACH. You cannot use additional SQL statements. If you attempt to execute another SQL statement from the application program or its recovery routine, you receive a return code of +256 and a reason code of X’00F30083’. v In an ESTAE routine, issue a CLOSE function call with the ABRT parameter followed by a DISCONNECT function call. The ESTAE exit routine can retry so that you do not need to reinstate the application task. FRRs must comply with the following requirements and restrictions: v You can use only enabled unlocked task (EUT) FRRs in your routines that call DB2. The standard z/OS functional recovery routines (FRRs) apply to only code that runs in service request block (SRB) mode, and DB2 does not support calls from SRB mode routines. v Do not have an EUT FRR active when using CAF, processing SQL requests, or calling IFI. With z/OS, if you have an active EUT FRR, all DB2 requests fail, including the initial CONNECT or OPEN request. The requests fail because DB2 Chapter 2. Connecting to DB2 from your application program 49
  • 66.
    always creates anARR-type ESTAE, and z/OS does not allow the creation of ARR-type ESTAEs when an FRR is active. v An EUT FRR cannot retry failing DB2 requests. An EUT FRR retry bypasses ESTAE routines from DB2. The next DB2 request of any type, including a DISCONNECT request, fails with a return code of +256 and a reason code of X’00F30050’. Making the CAF language interface (DSNALI) available Before you can invoke the call attachment facility (CAF), you must first make DSNALI available. Part of CAF is a DB2 load module, DSNALI, which is also known as the CAF language interface. DSNALI has the alias names DSNHLI2 and DSNWLI2. The module has five entry points: DSNALI, DSNHLI, DSNHLI2, DSNWLI, and DSNWLI2. These entry points serve the following functions: v Entry point DSNALI handles explicit DB2 connection service requests. v DSNHLI and DSNHLI2 handle SQL calls. Use DSNHLI if your application program link-edits DSNALI. Use DSNHLI2 if your application program loads DSNALI. v DSNWLI and DSNWLI2 handle IFI calls. Use DSNWLI if your application program link-edits DSNALI. Use DSNWLI2 if your application program loads DSNALI. To make DSNALI available: 1. Decide which of the following two methods you want to use to make DSNALI available: v Explicitly issuing LOAD requests when your program runs. By explicitly loading the DSNALI module, you beneficially isolate the maintenance of your application from future IBM maintenance to the language interface. If the language interface changes, the change will probably not affect your load module. v Including the DSNALI module in your load module when you link-edit your program. If you do not need explicit calls to DSNALI for CAF functions, link-editing DSNALI into your load module has some advantages. When you include DSNALI during the link-edit, you do not need to code a dummy DSNHLI entry point in your program or specify the precompiler option ATTACH. Module DSNALI contains an entry point for DSNHLI, which is identical to DSNHLI2, and an entry point DSNWLI, which is identical to DSNWLI2. A disadvantage to link-editing DSNALI into your load module is that any IBM maintenance to DSNALI requires a new link-edit of your load module. 2. Depending on the method that you chose in step 1, perform one of the following actions: v If you want to explicitly issue LOAD requests when your program runs: In your program, issue z/OS LOAD service requests for entry points DSNALI and DSNHLI2. If you use IFI services, you must also load DSNWLI2. The entry point addresses that LOAD returns are saved for later use with the CALL macro. Indicate to DB2 which entry point to use in one of the following two ways: – Specify the precompiler option ATTACH(CAF). This option causes DB2 to generate calls that specify entry point DSNHLI2. 50 Application Programming and SQL Guide
  • 67.
    Restriction: You cannotuse this option if your application is written in Fortran. – Code a dummy entry point named DSNHLI within your load module. If you do not specify the precompiler option ATTACH, the DB2 precompiler generates calls to entry point DSNHLI for each SQL request. The precompiler does not know about and is independent of the different DB2 attachment facilities. When the calls generated by the DB2 precompiler pass control to DSNHLI, your code that corresponds to the dummy entry point must preserve the option list that was passed in R1 and specify the same option list when it calls DSNHLI2. v If you want to include the DSNALI module in your load module when you link-edit your program: Include DSNALI in your load module during a link-edit step. The module must be in a load module library, which is included either in the SYSLIB concatenation or another INCLUDE library that is defined in the linkage editor JCL. Because all language interface modules contain an entry point declaration for DSNHLI, the linkage editor JCL must contain an INCLUDE linkage editor control statement for DSNALI; for example, INCLUDE DB2LIB(DSNALI). By coding these options, you avoid inadvertently picking up the wrong language interface module. Related concepts “Examples of invoking CAF” on page 69 Requirements for programs that use CAF The call attachment facility (CAF) enables programs to communicate with DB2. Before you invoke CAF in your program, ensure that your program satisfies any requirements for using CAF. When you write programs that use CAF, ensure that they meet the following requirements: v The program accounts for the size of the CAF code. The CAF code requires about 16 KB of virtual storage per address space and an additional 10 KB for each TCB that uses CAF. v If your local environment intercepts and replaces the z/OS LOAD SVC that CAF uses, you must ensure that your version of LOAD manages the load list element (LLE) and contents directory entry (CDE) chains like the standard z/OS LOAD macro. CAF uses z/OS SVC LOAD to load two modules as part of the initialization after your first service request. Both modules are loaded into fetch-protected storage that has the job-step protection key. v If you use CAF from IMS batch, you must write data to only one system in any one unit of work. If you write to both systems within the same unit, a system failure can leave the two databases inconsistent with no possibility of automatic recovery. To end a unit of work in DB2, execute the SQL COMMIT statement. To end a unit of work in IMS, issue the SYNCPOINT command. You can prepare application programs to run in CAF similar to how you prepare applications to run in other environments, such as CICS, IMS, and TSO. You can prepare a CAF application either in the batch environment or by using the DB2 program preparation process. You can use the program preparation system either through DB2I or through the DSNH CLIST. Related tasks Chapter 11, “Preparing an application to run on DB2 for z/OS,” on page 837 Chapter 2. Connecting to DB2 from your application program 51
  • 68.
    How CAF modifiesthe content of registers If you do not specify the return code and reason code parameters in your CAF function calls or you invoke CAF implicitly, CAF puts a return code in register 15 and a reason code in register 0. The contents of registers 2 through 14 are preserved across calls. The following table lists the standard calling conventions for registers R1, R13, R14, and R15. Table 9. Standard usage of registers R1, R13, R14, and R15 Register Usage R1 CALL DSNALI parameter list pointer R13 Address of caller’s save area R14 Caller’s return address R15 CAF entry point address Your CAF program should respect these register conventions. CAF also supports high-level languages that cannot examine the contents of individual registers. Related concepts “CALL DSNALI statement parameter list” on page 53 Implicit connections to CAF If the CAF language interface (DSNALI) is available and you do not explicitly specify CALL DSNALI statements in your application, CAF initiates implicit CONNECT and OPEN requests to DB2. These requests are subject to the same DB2 return codes and reason codes as explicitly specified requests. Implicit connections use the following defaults: Subsystem name The default name that is specified in the module DSNHDECP. CAF uses the installation default DSNHDECP, unless your own DSNHDECP module is in a library in a STEPLIB statement of a JOBLIB concatenation or in the link list. In a data sharing group, the default subsystem name is the group attachment name. Be certain that you know what the default name is and that it names the specific DB2 subsystem you want to use. Plan name The member name of the database request module (DBRM) that DB2 produced when you precompiled the source program that contains the first SQL call. Different types of implicit connections exist. The simplest is for an application to call neither the CONNECT nor OPEN functions. You can also use the CONNECT function only or the OPEN function only. Each of these calls implicitly connects your application to DB2. To terminate an implicit connection, you must use the proper calls. Related concepts “Summary of CAF behavior” on page 55 52 Application Programming and SQL Guide
  • 69.
    CALL DSNALI statementparameter list The CALL DSNALI statement explicitly invokes CAF. When you include CALL DSNALI statements in your program, you must specify all parameters that come before the return code parameter. For CALL DSNALI statements, use a standard z/OS CALL parameter list. Register 1 points to a list of fullword addresses that point to the actual parameters. The last address must contain a 1 in the high-order bit. In CALL DSNALI statements, you cannot omit any of parameters that come before the return code parameter by coding zeros or blanks. No defaults exist for those parameters for explicit connection requests. Defaults are provided for only implicit connections. All parameters starting with the return code parameter are optional. When you want to use the default value for a parameter but specify subsequent parameters, code the CALL DSNALI statement as follows: v For all languages except assembler language, code zero for that parameter in the CALL DSNALI statement. For example, suppose that you are coding a CONNECT call in a COBOL program, and you want to specify all parameters except the return code parameter. You can write a statement similar to the following statement: CALL ’DSNALI’ USING FUNCTN SSID TECB SECB RIBPTR BY CONTENT ZERO BY REFERENCE REASCODE SRDURA EIBPTR. v For assembler language, code a comma for that parameter in the CALL DSNALI statement. For example, to specify all optional parameters except the return code parameter write a statement similar to the following statement: CALL DSNALI,(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,,REASCODE,SRDURA,EIBPTR, GROUPOVERRIDE) The following figure shows a sample parameter list structure for the CONNECT function. Chapter 2. Connecting to DB2 from your application program 53
  • 70.
    Figure 4. Theparameter list for a CONNECT call The preceding figure illustrates how you can omit parameters for the CALL DSNALI statement to control the return code and reason code fields after a CONNECT call. You can terminate the parameter list at any of the following points. These termination points apply to all CALL DSNALI statement parameter lists. 1. Terminates the parameter list without specifying the parameters retcode, reascodeand srdura and places the return code in register 15 and the reason code in register 0. Terminating the parameter list at this point ensures compatibility with CAF programs that require a return code in register 15 and a reason code in register 0. 2. Terminates the parameter list after the parameter retcode and places the return code in the parameter list and the reason code in register 0. Terminating the parameter list at this point enables the application program to take action, based on the return code, without further examination of the associated reason code. 3. Terminates the parameter list after the parameter reascode and places the return code and the reason code in the parameter list. Terminating the parameter list at this point provides support to high-level languages that are unable to examine the contents of individual registers. 54 Application Programming and SQL Guide
  • 71.
    If you codeyour CAF application in assembler language, you can specify reason code parameter and omit the return code parameter. 4. Terminates the parameter list after the parameter srdura. If you code your CAF application in assembler language, you can specify parameter and omit the retcode and reascode parameters. 5. Terminates the parameter list after the parameter eibptr. If you code your CAF application in assembler language, you can specify parameter and omit the retcode, reascode, or srdura parameters. 6. Terminates the parameter list after the parameter groupoverride. If you code your CAF application in assembler language, you can specify parameter and omit the retcode, reascode,srdura, or eibptr parameters. the this this this Even if you specify that the return code be placed in the parameter list, it is also placed in register 15 to accommodate high-level languages that support special return code processing. Related concepts “How CAF modifies the content of registers” on page 52 Summary of CAF behavior The effect of any CAF function depends in part on what functions the program has already run. You should plan the CAF function calls that your program makes to avoid any errors and major structural problems in your application. The following table summarizes CAF behavior after various inputs from application programs. The top row lists the possible CAF functions that programs can call. The first column lists the task’s most recent history of connection requests. For example, the value “CONNECT followed by OPEN” in the first column means that the task issued CONNECT and then OPEN with no other CAF calls in between. The intersection of a row and column shows the effect of the next call if it follows the corresponding connection history. For example, if the call is OPEN and the connection history is CONNECT, the effect is OPEN; the OPEN function is performed. If the call is SQL and the connection history is empty (meaning that the SQL call is the first CAF function the program), the effect is that implicit CONNECT and OPEN functions are performed, followed by the SQL function. Table 10. Effects of CAF calls, as dependent on connection history Previous function Next function CONNECT OPEN SQL CLOSE DISCONNECT TRANSLATE 1 Error 2041 Error 2051 DISCONNECT TRANSLATE CLOSE2 DISCONNECT TRANSLATE CLOSE2 DISCONNECT TRANSLATE Empty: first call CONNECT OPEN CONNECT, Error 203 OPEN, followed by the SQL or IFI call CONNECT Error 2011 OPEN OPEN, followed Error 2031 by the SQL or IFI call CONNECT followed by OPEN Error 2011 Error 2021 The SQL or IFI call CONNECT followed by SQL or IFI call Error 2011 Error 2021 The SQL or IFI call Chapter 2. Connecting to DB2 from your application program 55
  • 72.
    Table 10. Effectsof CAF calls, as dependent on connection history (continued) Next function Previous function CONNECT 1 OPEN Error 201 SQL or IFI call Error 2011 OPEN SQL 1 Error 2021 Error 202 CLOSE DISCONNECT TRANSLATE The SQL or IFI call CLOSE 2 Error 2041 TRANSLATE The SQL or IFI call CLOSE2 Error 2041 TRANSLATE3 Notes: 1. An error is shown in this table as Error nnn. The corresponding reason code is X’00C10nnn’. The message number is DSNAnnnI or DSNAnnnE. 2. The task and address space connections remain active. If the CLOSE call fails because DB2 was down, the CAF control blocks are reset, the function produces return code 4 and reason code X’00C10824’, and CAF is ready for more connection requests when DB2 is up. 3. A TRANSLATE request is accepted, but in this case it is redundant. CAF automatically issues a TRANSLATE request when an SQL or IFI request fails. Related reference “CAF return codes and reason codes” on page 67 CAF connection functions A CAF connection function specifies the action that you want CAF to take. You specify these functions when you invoke CAF through CALL DSNALI statements. You can specify the following CAF functions in a CALL DSNALI statement: CONNECT Establishes the task (TCB) as a user of the named DB2 subsystem. When the first task within an address space issues a connection request, the address space is also initialized as a user of DB2. OPEN Allocates a DB2 plan. You must allocate a plan before DB2 can process SQL statements. If you did not request the CONNECT function, the OPEN function implicitly establishes the task, and optionally the address space, as a user of DB2. CLOSE Commits or abnormally terminates any database changes and deallocates the plan. If the OPEN function implicitly requests the CONNECT function, the CLOSE function removes the task, and possibly the address space, as a user of DB2. DISCONNECT Removes the task as a user of DB2 and, if this task is the last or only task in the address space with a DB2 connection, terminates the address space connection to DB2. TRANSLATE Returns an SQL code and printable text that describe a DB2 hexadecimal error reason code. This information is returned to the SQLCA. Restriction: You cannot call the TRANSLATE function from the Fortran language. 56 Application Programming and SQL Guide
  • 73.
    Recommendation: Because theeffect of any CAF function depends on what functions the program has already run, carefully plan the calls that your program makes to these CAF connection functions. Read about the summary of CAF behavior and make these function calls accordingly. Related concepts “Summary of CAF behavior” on page 55 “CALL DSNALI statement parameter list” on page 53 CONNECT function for CAF The CAF CONNECT function initializes a connection to DB2. This function is different than the SQL CONNECT statement that accesses a remote location within DB2. The CONNECT function establishes the caller’s task as a user of DB2 services. If no other task in the address space currently holds a connection with the specified subsystem, the CONNECT function also initializes the address space for communication to the DB2 address spaces. The CONNECT function establishes the address space’s cross memory authorization to DB2 and builds address space control blocks. You can issue a CONNECT request from any or all tasks in the address space, but the address space level is initialized only once when the first task connects. Using the CONNECT function is optional. If you do not call the CONNECT function, the first request from a task, either an OPEN request or an SQL or IFI call, causes CAF to issue an implicit CONNECT request. If a task is connected implicitly, the connection to DB2 is terminated either when you call the CLOSE function or when the task terminates. Call the CONNECT function in all of the following situations: v You need to specify a particular subsystem name (ssnm) other than the default subsystem name. v You need the value of the CURRENT DEGREE special register to last as long as the connection (srdura). v You need to monitor the DB2 startup ECB (startecb), the DB2 termination ECB (termecb), or the DB2 release level. v You plan to have multiple tasks in the address space open and close plans or a single task in the address space open and close plans more than once. Establishing task and address space level connections involves significant overhead. Using the CONNECT function to establish a task connection explicitly minimizes this overhead by ensuring that the connection to DB2 remains after the CLOSE function deallocates a plan. In this case, the connection terminates only when you use the DISCONNECT function or when the task terminates. The CONNECT function also enables the caller to learn the following items: v That the operator has issued a STOP DB2 command. When this event occurs, DB2 posts the termination ECB, termecb. Your application can either wait on or just look at the ECB. v That DB2 is abnormally terminating. When this event occurs happens, DB2 posts the termination ECB, termecb. v That DB2 is available again after a connection attempt that failed because DB2 was down. Your application can either wait or look at the startup ECB, startecb. DB2 ignores this ECB if it was active at the time of the CONNECT request, or if the CONNECT request was to a group attachment name. Chapter 2. Connecting to DB2 from your application program 57
  • 74.
    v The currentrelease level of DB2. To find this information, access the RIBREL field in the release information block (RIB). Restriction: Do not issue CONNECT requests from a TCB that already has an active DB2 connection. Recommendation: Do not mix explicit CONNECT and OPEN requests with implicitly established connections in the same address space. Either explicitly specify which DB2 subsystem you want to use or allow all requests to use the default subsystem. The following diagram shows the syntax for the CONNECT function. DSNALI CONNECT function CALL DSNALI ( function, ssnm, termecb, startecb, ribptr ) ,retcode ,reascode ,srdura ,eibptr ,groupoverride Parameters point to the following areas: function A 12-byte area that contains CONNECT followed by five blanks. ssnm A 4-byte DB2 subsystem name or group attachment name (if used in a data sharing group) to which the connection is made. If you specify the group attachment name, the program connects to the DB2 on the z/OS system on which the program is running. When you specify a group attachment name and a startup ECB, DB2 ignores the startup ECB. If you need to use a startup ECB, specify a subsystem name, rather than a group attachment name. That subsystem name must be different than the group attachment name. If ssnm is less than four characters long, pad it on the right with blanks to a length of four characters. termecb The application’s event control block (ECB) for DB2 termination. DB2 posts this ECB when the operator enters the STOP DB2 command or when DB2 is abnormally terminating. The ECB indicates the type of termination by a POST code, as shown in the following table: Table 11. POST codes and related termination types POST code 8 QUIESCE 12 FORCE 16 58 Termination type ABTERM Application Programming and SQL Guide
  • 75.
    Before you checktermecb in your CAF application program, first check the return code and reason code from the CONNECT call to ensure that the call completed successfully. startecb The application’s startup ECB. If DB2 has not yet started when the application issues the call, DB2 posts the ECB when it successfully completes its startup processing. DB2 posts at most one startup ECB per address space. The ECB is the one associated with the most recent CONNECT call from that address space. Your application program must examine any nonzero CAF and DB2 reason codes before issuing a WAIT on this ECB. If ssnm is a group attachment name, the first DB2 subsystem that starts on the local z/OS system and matches the specified group attachment name posts the ECB. ribptr A 4-byte area in which CAF places the address of the release information block (RIB) after the call. You can determine what release level of DB2 you are currently running by examining the RIBREL field. You can determine the modification level within the release level by examining the RIBCNUMB and RIBCINFO fields. If the value in the RIBCNUMB field is greater than zero, check the RIBCINFO field for modification levels. If the RIB is not available (for example, if you name a subsystem that does not exist), DB2 sets the 4-byte area to zeros. The area to which ribptr points is below the 16-MB line. Your program does not have to use the release information block, but it cannot omit the ribptr parameter. Macro DSNDRIB maps the release information block (RIB). It can be found in prefix.SDSNMACS(DSNDRIB). retcode A 4-byte area in which CAF places the return code. This field is optional. If you do not specify retcode, CAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which CAF places a reason code. This field is optional. If you do not specify reascode, CAF places the reason code in register 0. If you specify reascode, you must also specify retcode. srdura A 10-byte area that contains the string ’SRDURA(CD)’. This field is optional. If you specify srdura, the value in the CURRENT DEGREE special register stays in effect from the time of the CONNECT call until the time of the DISCONNECT call. If you do not specify srdura, the value in the CURRENT DEGREE special register stays in effect from the time of the OPEN call until the time of the CLOSE call. If you specify this parameter in any language except assembler, you must also specify retcode and reascode. In assembler language, you can omit these parameters by specifying commas as placeholders. eibptr A 4-byte area in which CAF puts the address of the environment information block (EIB). The EIB contains information that you can use if you are connecting to a DB2 subsystem that is part of a data sharing group. For Chapter 2. Connecting to DB2 from your application program 59
  • 76.
    example, you candetermine the name of the data sharing group, the member to which you are connecting, and whether the subsystem is in new-function mode. If the DB2 subsystem that you connect to is not part of a data sharing group, the fields in the EIB that are related to data sharing are blank. If the EIB is not available (for example, if you name a subsystem that does not exist), DB2 sets the 4-byte area to zeros. The area to which eibptr points is below the 16-MB line. You can omit this parameter when you make a CONNECT call. If you specify this parameter in any language except assembler, you must also specify retcode, reascode, and srdura. In assembler language, you can omit retcode, reascode, and srdura by specifying commas as placeholders. Macro DSNDEIB maps the EIB. It can be found in prefix.SDSNMACS(DSNDEIB). | | | | | | | groupoverride An 8-byte area that the application provides. This parameter is optional. If you do not want group attach to be attempted, specify ’NOGROUP’. This string indicates that the subsystem name that is specified by ssnm is to be used as a DB2 subsystem name, even if ssnm matches a group attachment name. If groupoverride is not provided, ssnm is used as the group attachment name if it matches a group attachment name. | | | If you specify this parameter in any language except assembler, you must also specify retcode, reascode, srdura, and eibptr. In assembler language, you can omit retcode, reascode, srdura, and eibptr by specifying commas as placeholders. | | | | | | Recommendation: Avoid using the groupoverride parameter when possible, because it limits the ability to do dynamic workload routing in a Parallel Sysplex. However, you should use this parameter in a data sharing environment when you want to connect to a specific member of a data sharing group, and the subsystem name of that member is the same as the group attachment name. Example of CAF CONNECT function calls The following table shows a CONNECT call in each language. Table 12. Examples of CAF CONNECT function calls Language Call example Assembler CALL DSNALI,(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,RETCODE,REASCODE,SRDURA, EIBPTR, GRPOVER) C1 fnret=dsnali(&functn[0],&ssid[0], &tecb, &secb,&ribptr,&retcode, &reascode, &srdura[0], &eibptr, &grpover[0]); COBOL CALL ’DSNALI’ USING FUNCTN SSID TERMECB STARTECB RIBPTR RETCODE REASCODE SRDURA EIBPTR GRPOVER. Fortran CALL DSNALI(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,RETCODE,REASCODE,SRDURA, EIBPTR,GRPOVER) PL/I1 CALL DSNALI(FUNCTN,SSID,TERMECB,STARTECB,RIBPTR,RETCODE,REASCODE,SRDURA, EIBPTR,GRPOVER) Note: 60 Application Programming and SQL Guide
  • 77.
    v For Cand PL/I applications, you must include the appropriate compiler directives, because DSNALI is an assembler language program. These compiler directives are described in the instructions for invoking CAF. Related tasks “Invoking the call attachment facility” on page 44 OPEN function for CAF The OPEN function allocates DB2 resources that are needed to run the specified plan or issue IFI requests. If the requesting task does not already have a connection to the named DB2 subsystem, the OPEN function establishes it. Using the OPEN function is optional. If you do not call the OPEN function, the actions that the OPEN function perform occur implicitly on the first SQL or IFI call from the task. Restriction: Do not use the OPEN function if the task already has a plan allocated. The following diagram shows the syntax for the OPEN function. DSNALI OPEN function CALL DSNALI ( function, ssnm, plan ) , retcode , reascode , groupoverride Parameters point to the following areas: function A 12-byte area that contains the word OPEN followed by eight blanks. ssnm A 4-byte DB2 subsystem name or group attachment name (if used in a data sharing group). The OPEN function allocates the specified plan to this DB2 subsystem. Also, if the requesting task does not already have a connection to the named DB2 subsystem, the OPEN function establishes it. You must specify the ssnm parameter, even if the requesting task also issues a CONNECT call. If a task issues a CONNECT call followed by an OPEN call, the subsystem names for both calls must be the same. If ssnm is less than four characters long, pad it on the right with blanks to a length of four characters. plan An 8-byte DB2 plan name. retcode A 4-byte area in which CAF places the return code. This field is optional. If you do not specify retcode,CAF places the return code in register 15 and the reason code in register 0. Chapter 2. Connecting to DB2 from your application program 61
  • 78.
    reascode A 4-byte areain which CAF places a reason code. This field is optional. If you do not specify reascode, CAF places the reason code in register 0. If you specify reascode, you must also specify retcode. groupoverride An 8-byte area that the application provides. This field is optional. If you do not want group attach to be attempted, specify ’NOGROUP’. This string indicates that the subsystem name that is specified by ssnm is to be used as a DB2 subsystem name, even if ssnm matches a group attachment name. If you do not specify groupoverride, ssnm is used as the group attachment name if it matches a group attachment name. If you specify this parameter in any language except assembler, you must also specify retcode and reascode. In assembler language, you can omit these parameters by specifying commas as placeholders. | Recommendation: Avoid using the groupoverride parameter when possible, because it limits the ability to do dynamic workload routing in a Parallel Sysplex. However, you should use this parameter in a data sharing environment when you want to connect to a specific member of a data sharing group, and the subsystem name of that member is the same as the group attachment name. Examples of CAF OPEN calls The following table shows an OPEN call in each language. Table 13. Examples of CAF OPEN calls Language Call example Assembler CALL C 1 DSNALI,(FUNCTN,SSID,PLANNAME, RETCODE,REASCODE,GRPOVER) fnret=dsnali(&functn[0],&ssid[0], &planname[0],&retcode, &reascode,&grpover[0]); COBOL CALL ’DSNALI’ USING FUNCTN SSID PLANNAME RETCODE REASCODE GRPOVER. Fortran CALL DSNALI(FUNCTN,SSID,PLANNAME, RETCODE,REASCODE,GRPOVER) PL/I1 CALL DSNALI(FUNCTN,SSID,PLANNAME, RETCODE,REASCODE,GRPOVER); Note: v For C and PL/I applications, you must include the appropriate compiler directives, because DSNALI is an assembler language program. These compiler directives are described in the instructions for invoking CAF. Related concepts “Implicit connections to CAF” on page 52 Related tasks “Invoking the call attachment facility” on page 44 CLOSE function for CAF The CAF CLOSE function deallocates the plan that was created either explicitly by a call to the OPEN function or implicitly at the first SQL call. Optionally, the CLOSE function also disconnects the task, and possibly the address space, from DB2. If you did not issue an explicit CONNECT call for the task, the CLOSE function deletes the task’s connection to DB2. If no other task in the address space has an 62 Application Programming and SQL Guide
  • 79.
    active connection toDB2, DB2 also deletes the control block structures that were created for the address space and removes the cross memory authorization. Using the CLOSE function is optional. Consider the following rules and recommendations about when to use and not use the CLOSE function: v Do not use the CLOSE function when your current task does not have a plan allocated. v If you want to use a new plan, you must issue an explicit CLOSE call, followed by an OPEN call with the new plan name. v When shutting down your application you can improve the performance of this shut down by explicitly calling the CLOSE function before the task terminates. If you omit the CLOSE call, DB2 performs an implicit CLOSE. In this case, DB2 performs the same actions when your task terminates, by using the SYNC parameter if termination is normal and the ABRT parameter if termination is abnormal. v If DB2 terminates, issue an explicit CLOSE call for any task that did not issue a CONNECT call. This action enables CAF to reset its control blocks to allow for future connections. This CLOSE call returns the reset accomplished return code (+004) and reason code X’00C10824’. If you omit the CLOSE call in this case, when DB2 is back on line, the task’s next connection request fails. You get either the message YOUR TCB DOES NOT HAVE A CONNECTION, with X’00F30018’ in register 0, or the CAF error message DSNA201I or DSNA202I, depending on what your application tried to do. The task must then issue a CLOSE call before it can reconnect to DB2. v A task that issued an explicit CONNECT call should issue a DISCONNECT call instead of a CLOSE call. This action causes CAF to reset its control blocks when DB2 terminates. The following diagram shows the syntax for the CLOSE function. DSNALI CLOSE function CALL DSNALI ( function, termop ) , retcode , reascode Parameters point to the following areas: function A 12-byte area that contains the word CLOSE followed by seven blanks. termop A 4-byte terminate option, with one of the following values: SYNC Specifies that DB2 is to commit any modified data. ABRT Specifies that DB2 is to roll back data to the previous commit point. retcode A 4-byte area in which CAF is to place the return code. This field is optional. If you do not specify retcode, CAF places the return code in register 15 and the reason code in register 0. Chapter 2. Connecting to DB2 from your application program 63
  • 80.
    reascode A 4-byte areain which CAF places a reason code. This field is optional. If you do not specify reascode, CAF places the reason code in register 0. If you specify reascode, you must also specify retcode. Examples of CAF CLOSE calls The following table shows a CLOSE call in each language. Table 14. Examples of CAF CLOSE calls Language Call example Assembler CALL C 1 DSNALI,(FUNCTN,TERMOP,RETCODE, REASCODE) fnret=dsnali(&functn[0], &termop[0], &retcode,&reascode); COBOL CALL ’DSNALI’ USING FUNCTN TERMOP RETCODE REASCODE. Fortran CALL DSNALI(FUNCTN,TERMOP, RETCODE,REASCODE) CALL DSNALI(FUNCTN,TERMOP, RETCODE,REASCODE); PL/I 1 Note: v For C and PL/I applications, you must include the appropriate compiler directives, because DSNALI is an assembler language program. These compiler directives are described in the instructions for invoking CAF. Related tasks “Invoking the call attachment facility” on page 44 DISCONNECT function for CAF The CAF DISCONNECT function terminates a connection to DB2. DISCONNECT removes the calling task’s connection to DB2. If no other task in the address space has an active connection to DB2, DB2 also deletes the control block structures that were created for the address space and removes the cross memory authorization. If an OPEN call is in effect, which means that a plan is allocated, when the DISCONNECT call is issued, CAF issues an implicit CLOSE with the SYNC parameter. Using the DISCONNECT function is optional. Consider the following rules and recommendations about when to use and not use the DISCONNECT function: v Only those tasks that explicitly issued a CONNECT call can issue a DISCONNECT call. If a CONNECT call was not used, a DISCONNECT call causes an error. v When shutting down your application you can improve the performance of this shut down by explicitly calling the DISCONNECT function before the task terminates. If you omit the DISCONNECT call, DB2 performs an implicit DISCONNECT. In this case, DB2 performs the same actions when your task terminates. v If DB2 terminates, any task that issued a CONNECT call must issue a DISCONNECT call to reset the CAF control blocks. The DISCONNECT function returns the reset accomplished return codes and reason codes (+004 and X’00C10824’). This action ensures that future connection requests from the task work when DB2 is back on line. 64 Application Programming and SQL Guide
  • 81.
    v A taskthat did not explicitly issue a CONNECT call must issue a CLOSE call instead of a DISCONNECT call. This action resets the CAF control blocks when DB2 terminates. The following diagram shows the syntax for the DISCONNECT function. DSNALI DISCONNECT function CALL DSNALI ( function ) , retcode , reascode The single parameter points to the following area: function A 12-byte area that contains the word DISCONNECT followed by two blanks. retcode A 4-byte area in which CAF places the return code. This field is optional. If you do not specify retcode, CAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which CAF places a reason code. This field is optional. If you do not specify reascode, CAF places the reason code in register 0. If you specify reascode, you must also specify retcode. Examples of CAF DISCONNECT calls The following table shows a DISCONNECT call in each language. Table 15. Examples of CAF DISCONNECT calls Language Call example Assembler CALL C 1 DSNALI(,FUNCTN,RETCODE,REASCODE) fnret=dsnali(&functn[0], &retcode, &reascode); COBOL CALL ’DSNALI’ USING FUNCTN RETCODE REASCODE. Fortran CALL DSNALI(FUNCTN,RETCODE,REASCODE) CALL DSNALI(FUNCTN,RETCODE,REASCODE); PL/I 1 Note: v For C and PL/I applications, you must include the appropriate compiler directives, because DSNALI is an assembler language program. These compiler directives are described in the instructions for invoking CAF. Related tasks “Invoking the call attachment facility” on page 44 Chapter 2. Connecting to DB2 from your application program 65
  • 82.
    TRANSLATE function forCAF The TRANSLATE function converts a DB2 hexadecimal error reason code from a failed OPEN request into an SQL error code and printable error message text. DB2 places the information into the SQLCODE and SQLSTATE host variables or related fields of the caller’s SQLCA. The DB2 error reason code that is converted is read from register 0. The TRANSLATE function does not change the contents of registers 0 and 15, unless the TRANSLATE request fails; in that case, register 0 is set to X’C10205’ and register 15 is set to 200. Consider the following rules and recommendations about when to use and not use the TRANSLATE function: v You cannot call the TRANSLATE function from the Fortran language. v The TRANSLATE function is useful only if you used an explicit CONNECT call before an OPEN request that fails. For errors that occur during SQL or IFI requests, the TRANSLATE function performs automatically. v The TRANSLATE function can translate those codes that begin with X’00F3’, but it does not translate CAF reason codes that begin with X’00C1’. If you receive error reason code X’00F30040’ (resource unavailable) after an OPEN request, the TRANSLATE function returns the name of the unavailable database object in the last 44 characters of the SQLERRM field. If the TRANSLATE function does not recognize the error reason code, it returns SQLCODE -924 (SQLSTATE ’58006’) and places a printable copy of the original DB2 function code and the return and error reason codes in the SQLERRM field. The following diagram shows the syntax for the TRANSLATE function. DSNALI TRANSLATE function CALL DSNALI ( function, sqlca ) , retcode , reascode Parameters point to the following areas: function A 12-byte area the contains the word TRANSLATE followed by three blanks. sqlca The program’s SQL communication area (SQLCA). retcode A 4-byte area in which CAF places the return code. This field is optional. If you do not specify retcode, CAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which CAF places a reason code. 66 Application Programming and SQL Guide
  • 83.
    This field isoptional. If you do not specify reascode, CAF places the reason code in register 0. If you specify reascode, you must also specify retcode. Examples of CAF TRANSLATE calls The following table shows a TRANSLATE call in each language. Table 16. Examples of CAF TRANSLATE calls Language Call example Assembler CALL C 1 fnret=dsnali(&functn[0], &sqlca, &retcode, &reascode); COBOL PL/I DSNALI,(FUNCTN,SQLCA,RETCODE, REASCODE) 1 CALL ’DSNALI’ USING FUNCTN SQLCA RETCODE REASCODE. CALL DSNALI(FUNCTN,SQLCA,RETCODE, REASCODE); Note: v For C and PL/I applications, you must include the appropriate compiler directives, because DSNALI is an assembler language program. These compiler directives are described in the instructions for invoking CAF. Related tasks “Invoking the call attachment facility” on page 44 Turning on a CAF trace CAF does not capture any diagnostic trace messages unless you tell it to by turning on a trace. To turn on a CAF trace: Allocate a DSNTRACE data set either dynamically or by including a DSNTRACE DD statement in your JCL. CAF writes diagnostic trace messages to that data set. The trace message numbers contain the last three digits of the reason codes. Related concepts “Examples of invoking CAF” on page 69 CAF return codes and reason codes CAF provides the return codes and reason codes either to the corresponding parameters that are specified in a CAF function call or, if you choose not to use those parameters, to registers 15 and 0. When the reason code begins with X’00F3’ except for X’00F30006’, you can use the CAF TRANSLATE function to obtain error message text that can be printed and displayed. These reason codes are issued by the subsystem support for allied memories, a part of the DB2 subsystem support subcomponent that services all DB2 connection and work requests. For SQL calls, CAF returns standard SQL codes in the SQLCA. CAF returns IFI return codes and reason codes in the instrumentation facility communication area (IFCA). The following table lists the CAF return codes and reason codes. Chapter 2. Connecting to DB2 from your application program 67
  • 84.
    Table 17. CAFreturn codes and reason codes Return code Reason code Explanation 0 X’00000000’ Successful completion. 4 X’00C10824’ CAF reset complete. CAF is ready to make a new connection. 8 X’00C10831’ Release level mismatch between DB2 and the CAF code. 1 X’00C10201’ Received a second CONNECT request from the same TCB. The first CONNECT request could have been implicit or explicit. 2001 X’00C10202’ Received a second OPEN request from the same TCB. The first OPEN request could have been implicit or explicit. 2001 X’00C10203’ CLOSE request issued when no active OPEN request exists. 1 X’00C10204’ DISCONNECT request issued when no active CONNECT request exists, or the AXSET macro was issued between the CONNECT request and the DISCONNECT request. 2001 X’00C10205’ TRANSLATE request issued when no connection to DB2 exists. 1 X’00C10206’ Incorrect number of parameters was specified or the end-of-list bit was off. 2001 X’00C10207’ Unrecognized function parameter. 1 X’00C10208’ Received requests to access two different DB2 subsystems from the same TCB. 2 CAF system error. Probable error in the attach or DB2. 200 200 200 200 204 Notes: 1. A CAF error probably caused by errors in the parameter lists from the application programs. CAF errors do not change the current state of your connection to DB2; you can continue processing with a corrected request. 2. System errors cause abends. If tracing is on, a descriptive message is written to the DSNTRACE data set just before the abend. Sample CAF scenarios One or more tasks can use CAF to connect to DB2. This connection can be made either implicitly or explicitly. For explicit connections, a task calls one or more of the CAF connection functions. A single task with implicit connections The simplest connection scenario is a single task that makes calls to DB2 without using explicit CALL DSNALI statements. The task implicitly connects to the default subsystem name and uses the default plan name. When the task terminates, the following events occur: v If termination was normal, any database changes are committed. v If termination was abnormal, any database changes are rolled back. v The active plan and all database resources are deallocated. v The task and address space connections to DB2 are terminated. A single task with explicit connections The following example pseudocode illustrates a more complex scenario with a single task. 68 Application Programming and SQL Guide
  • 85.
    CONNECT OPEN allocate a plan SQLor IFI call ••• CLOSE deallocate the current plan OPEN allocate a new plan SQL or IFI call ••• CLOSE DISCONNECT A task can have a connection to only one DB2 subsystem at any point in time. A CAF error occurs if the subsystem name in the OPEN call does not match the subsystem name in the CONNECT call. To switch to a different subsystem, the application must first disconnect from the current subsystem and then issue a connect request with a new subsystem name. Multiple tasks In the following scenario, multiple tasks within the address space use DB2 services. Each task must explicitly specify the same subsystem name on either the CONNECT function request or the OPEN function request. Task 1 makes no SQL or IFI calls. Its purpose is to monitor the DB2 termination and startup ECBs and to check the DB2 release level. TASK 1 TASK 2 TASK 3 TASK n OPEN SQL ... CLOSE OPEN SQL ... CLOSE OPEN SQL ... CLOSE OPEN SQL ... CLOSE OPEN SQL ... CLOSE OPEN SQL ... CLOSE CONNECT DISCONNECT Examples of invoking CAF The call attachment facility (CAF) enables programs to communicate with DB2. If you explicitly invoke CAF in your program, you can use the CAF connection functions to control the state of the connection. Example JCL for invoking CAF The following sample JCL shows how to use CAF in a batch (non-TSO) environment. The DSNTRACE statement in this example is optional. //jobname //CAFJCL //STEPLIB // JOB EXEC DD DD z/OS_jobcard_information PGM=CAF_application_program DSN=application_load_library DSN=DB2_load_library DD DD DD SYSOUT=* SYSOUT=* SYSOUT=* . . . //SYSPRINT //DSNTRACE //SYSUDUMP Chapter 2. Connecting to DB2 from your application program 69
  • 86.
    Example of assemblercode that invokes CAF The following examples show parts of a sample assembler program that uses CAF. They demonstrate the basic techniques for making CAF calls, but do not show the code and z/OS macros needed to support those calls. For example, many applications need a two-task structure so that attention-handling routines can detach connected subtasks to regain control from DB2. This structure is not shown in the following code examples. Also, these code examples assume the existence of a WRITE macro. Wherever this macro is included in the example, substitute code of your own. You must decide what you want your application to do in those situations; you probably do not want to write the error messages shown. Example of loading and deleting the CAF language interface: The following code segment shows how an application can load entry points DSNALI and DSNHLI2 for the CAF language interface. Storing the entry points in variables LIALI and LISQL ensures that the application has to load the entry points only once. When the module is done with DB2, you should delete the entries. ****************************** GET LANGUAGE INTERFACE ENTRY ADDRESSES LOAD EP=DSNALI Load the CAF service request EP ST R0,LIALI Save this for CAF service requests LOAD EP=DSNHLI2 Load the CAF SQL call Entry Point ST R0,LISQL Save this for SQL calls * . * . Insert connection service requests and SQL calls here * . DELETE EP=DSNALI Correctly maintain use count DELETE EP=DSNHLI2 Correctly maintain use count Example of connecting to DB2 with CAF: The following example code shows how to issue explicit requests for certain actions, such as CONNECT, OPEN, CLOSE, DISCONNECT, and TRANSLATE, and uses the CHEKCODE subroutine to check the return reason codes from CAF. ****************************** CONNECT ******************************** L R15,LIALI Get the Language Interface address MVC FUNCTN,CONNECT Get the function to call CALL (15),(FUNCTN,SSID,TECB,SECB,RIBPTR),VL,MF=(E,CAFCALL) BAL R14,CHEKCODE Check the return and reason codes CLC CONTROL,CONTINUE Is everything still OK BNE EXIT If CONTROL not ’CONTINUE’, stop loop USING R8,RIB Prepare to access the RIB L R8,RIBPTR Access RIB to get DB2 release level WRITE ’The current DB2 release level is’ RIBREL ****************************** OPEN *********************************** L R15,LIALI Get the Language Interface address MVC FUNCTN,OPEN Get the function to call CALL (15),(FUNCTN,SSID,PLAN),VL,MF=(E,CAFCALL) BAL R14,CHEKCODE Check the return and reason codes ****************************** SQL ************************************ * Insert your SQL calls here. The DB2 Precompiler * generates calls to entry point DSNHLI. You should * specify the precompiler option ATTACH(CAF), or code * a dummy entry point named DSNHLI to intercept * all SQL calls. A dummy DSNHLI is shown below. ****************************** CLOSE ********************************** CLC CONTROL,CONTINUE Is everything still OK? BNE EXIT If CONTROL not ’CONTINUE’, shut down MVC TRMOP,ABRT Assume termination with ABRT parameter L R4,SQLCODE Put the SQLCODE into a register C R4,CODE0 Examine the SQLCODE BZ SYNCTERM If zero, then CLOSE with SYNC parameter 70 Application Programming and SQL Guide
  • 87.
    C R4,CODE100 See if SQLCODEwas 100 BNE DISC If not 100, CLOSE with ABRT parameter SYNCTERM MVC TRMOP,SYNC Good code, terminate with SYNC parameter DISC DS 0H Now build the CAF parmlist L R15,LIALI Get the Language Interface address MVC FUNCTN,CLOSE Get the function to call CALL (15),(FUNCTN,TRMOP),VL,MF=(E,CAFCALL) BAL R14,CHEKCODE Check the return and reason codes ****************************** DISCONNECT ***************************** CLC CONTROL,CONTINUE Is everything still OK BNE EXIT If CONTROL not ’CONTINUE’, stop loop L R15,LIALI Get the Language Interface address MVC FUNCTN,DISCON Get the function to call CALL (15),(FUNCTN),VL,MF=(E,CAFCALL) BAL R14,CHEKCODE Check the return and reason codes This example code does not show a task that waits on the DB2 termination ECB. If you want such a task, you can code it by using the z/OS WAIT macro to monitor the ECB. You probably want this task to detach the sample code if the termination ECB is posted. That task can also wait on the DB2 startup ECB. This sample waits on the startup ECB at its own task level. This example code assumes that the variables in the following table are already set: Table 18. Variables that preceding example assembler code assumes are set Variable Usage LIALI The entry point that handles DB2 connection service requests. LISQL The entry point that handles SQL calls. SSID The DB2 subsystem identifier. TECB The address of the DB2 termination ECB. SECB The address of the DB2 startup ECB. RIBPTR A fullword that CAF sets to contain the RIB address. PLAN The plan name to use in the OPEN call. CONTROL This variable is used to shut down processing because of unsatisfactory return or reason codes. The CHECKCODE subroutine sets this value. CAFCALL List-form parameter area for the CALL macro. Example of checking return codes and reason codes when using CAF: The following example code illustrates a way to check the return codes and the DB2 termination ECB after each connection service request and SQL call. The routine sets the variable CONTROL to control further processing within the module. *********************************************************************** * CHEKCODE PSEUDOCODE * *********************************************************************** *IF TECB is POSTed with the ABTERM or FORCE codes * THEN * CONTROL = ’SHUTDOWN’ * WRITE ’DB2 found FORCE or ABTERM, shutting down’ * ELSE /* Termination ECB was not POSTed */ * SELECT (RETCODE) /* Look at the return code */ * WHEN (0) ; /* Do nothing; everything is OK */ Chapter 2. Connecting to DB2 from your application program 71
  • 88.
    * WHEN (4) ; /*Warning */ * SELECT (REASCODE) /* Look at the reason code */ * WHEN (’00C10824’X) /* Ready for another CAF call */ * CONTROL = ’RESTART’ /* Start over, from the top */ * OTHERWISE * WRITE ’Found unexpected R0 when R15 was 4’ * CONTROL = ’SHUTDOWN’ * END INNER-SELECT * WHEN (8,12) /* Connection failure */ * SELECT (REASCODE) /* Look at the reason code */ * WHEN (’00C10831’X) /* DB2 / CAF release level mismatch*/ * WRITE ’Found a mismatch between DB2 and CAF release levels’ * WHEN (’00F30002’X, /* These mean that DB2 is down but */ * ’00F30012’X) /* will POST SECB when up again */ * DO * WRITE ’DB2 is unavailable. I’ll tell you when it’s up.’ * WAIT SECB /* Wait for DB2 to come up */ * WRITE ’DB2 is now available.’ * END * /**********************************************************/ * /* Insert tests for other DB2 connection failures here. */ * /* CAF Externals Specification lists other codes you can */ * /* receive. Handle them in whatever way is appropriate */ * /* for your application. */ * /**********************************************************/ * OTHERWISE /* Found a code we’re not ready for*/ * WRITE ’Warning: DB2 connection failure. Cause unknown’ * CALL DSNALI (’TRANSLATE’,SQLCA) /* Fill in SQLCA */ * WRITE SQLCODE and SQLERRM * END INNER-SELECT * WHEN (200) * WRITE ’CAF found user error. See DSNTRACE dataset’ * WHEN (204) * WRITE ’CAF system error. See DSNTRACE data set’ * OTHERWISE * CONTROL = ’SHUTDOWN’ * WRITE ’Got an unrecognized return code’ * END MAIN SELECT * IF (RETCODE > 4) THEN /* Was there a connection problem?*/ * CONTROL = ’SHUTDOWN’ * END CHEKCODE *********************************************************************** * Subroutine CHEKCODE checks return codes from DB2 and Call Attach. * When CHEKCODE receives control, R13 should point to the caller’s * save area. *********************************************************************** CHEKCODE DS 0H STM R14,R12,12(R13) Prolog ST R15,RETCODE Save the return code ST R0,REASCODE Save the reason code LA R15,SAVEAREA Get save area address ST R13,4(,R15) Chain the save areas ST R15,8(,R13) Chain the save areas LR R13,R15 Put save area address in R13 * ********************* HUNT FOR FORCE OR ABTERM *************** TM TECB,POSTBIT See if TECB was POSTed BZ DOCHECKS Branch if TECB was not POSTed CLC TECBCODE(3),QUIESCE Is this "STOP DB2 MODE=FORCE" BE DOCHECKS If not QUIESCE, was FORCE or ABTERM MVC CONTROL,SHUTDOWN Shutdown WRITE ’Found found FORCE or ABTERM, shutting down’ B ENDCCODE Go to the end of CHEKCODE DOCHECKS DS 0H Examine RETCODE and REASCODE * ********************* HUNT FOR 0 ***************************** CLC RETCODE,ZERO Was it a zero? BE ENDCCODE Nothing to do in CHEKCODE for zero * ********************* HUNT FOR 4 ***************************** 72 Application Programming and SQL Guide
  • 89.
    CLC RETCODE,FOUR Was it a4? BNE HUNT8 If not a 4, hunt eights CLC REASCODE,C10831 Was it a release level mismatch? BNE HUNT824 Branch if not an 831 WRITE ’Found a mismatch between DB2 and CAF release levels’ B ENDCCODE We are done. Go to end of CHEKCODE HUNT824 DS 0H Now look for ’CAF reset’ reason code CLC REASCODE,C10824 Was it 4? Are we ready to restart? BNE UNRECOG If not 824, got unknown code WRITE ’CAF is now ready for more input’ MVC CONTROL,RESTART Indicate that we should re-CONNECT B ENDCCODE We are done. Go to end of CHEKCODE UNRECOG DS 0H WRITE ’Got RETCODE = 4 and an unrecognized reason code’ MVC CONTROL,SHUTDOWN Shutdown, serious problem B ENDCCODE We are done. Go to end of CHEKCODE * ********************* HUNT FOR 8 ***************************** HUNT8 DS 0H CLC RETCODE,EIGHT Hunt return code of 8 BE GOT8OR12 CLC RETCODE,TWELVE Hunt return code of 12 BNE HUNT200 GOT8OR12 DS 0H Found return code of 8 or 12 WRITE ’Found RETCODE of 8 or 12’ CLC REASCODE,F30002 Hunt for X’00F30002’ BE DB2DOWN * A4TRANS * * * * DB2DOWN * HUNT200 * HUNT204 * WASSAT CLC REASCODE,F30012 Hunt for X’00F30012’ BE DB2DOWN WRITE ’DB2 connection failure with an unrecognized REASCODE’ CLC SQLCODE,ZERO See if we need TRANSLATE BNE A4TRANS If not blank, skip TRANSLATE ********************* TRANSLATE unrecognized RETCODEs ******** WRITE ’SQLCODE 0 but R15 not, so TRANSLATE to get SQLCODE’ L R15,LIALI Get the Language Interface address CALL (15),(TRANSLAT,SQLCA),VL,MF=(E,CAFCALL) C R0,C10205 Did the TRANSLATE work? BNE A4TRANS If not C10205, SQLERRM now filled in WRITE ’Not able to TRANSLATE the connection failure’ B ENDCCODE Go to end of CHEKCODE DS 0H SQLERRM must be filled in to get here Note: your code should probably remove the X’FF’ separators and format the SQLERRM feedback area. Alternatively, use DB2 Sample Application DSNTIAR to format a message. WRITE ’SQLERRM is:’ SQLERRM B ENDCCODE We are done. Go to end of CHEKCODE DS 0H Hunt return code of 200 WRITE ’DB2 is down and I will tell you when it comes up’ WAIT ECB=SECB Wait for DB2 to come up WRITE ’DB2 is now available’ MVC CONTROL,RESTART Indicate that we should re-CONNECT B ENDCCODE ********************* HUNT FOR 200 *************************** DS 0H Hunt return code of 200 CLC RETCODE,NUM200 Hunt 200 BNE HUNT204 WRITE ’CAF found user error, see DSNTRACE data set’ B ENDCCODE We are done. Go to end of CHEKCODE ********************* HUNT FOR 204 *************************** DS 0H Hunt return code of 204 CLC RETCODE,NUM204 Hunt 204 BNE WASSAT If not 204, got strange code WRITE ’CAF found system error, see DSNTRACE data set’ B ENDCCODE We are done. Go to end of CHEKCODE ********************* UNRECOGNIZED RETCODE ******************* DS 0H WRITE ’Got an unrecognized RETCODE’ Chapter 2. Connecting to DB2 from your application program 73
  • 90.
    MVC CONTROL,SHUTDOWN BE ENDCCODE ENDCCODE DS 0H L R4,RETCODE C R4,FOUR BNH BYEBYE MVC CONTROL,SHUTDOWN BYEBYE DS 0H L R13,4(,R13) RETURN (14,12) Shutdown Weare done. Go to end of CHEKCODE Should we shut down? Get a copy of the RETCODE Have a look at the RETCODE If RETCODE <= 4 then leave CHEKCODE Shutdown Wrap up and leave CHEKCODE Point to caller’s save area Return to the caller Example of invoking CAF when you do not specify the precompiler option ATTACH(CAF): Each of the four DB2 attachment facilities contains an entry point named DSNHLI. When you use CAF but do not specify the precompiler option ATTACH(CAF), SQL statements result in BALR instructions to DSNHLI in your program. To find the correct DSNHLI entry point without including DSNALI in your load module, code a subroutine with entry point DSNHLI that passes control to entry point DSNHLI2 in the DSNALI module. DSNHLI2 is unique to DSNALI and is at the same location in DSNALI as DSNHLI. DSNALI uses 31-bit addressing. If the application that calls this intermediate subroutine uses 24-bit addressing, this subroutine should account for the difference. In the following example, LISQL is addressable because the calling CSECT used the same register 12 as CSECT DSNHLI. Your application must also establish addressability to LISQL. *********************************************************************** * Subroutine DSNHLI intercepts calls to LI EP=DSNHLI *********************************************************************** DS 0D DSNHLI CSECT Begin CSECT STM R14,R12,12(R13) Prologue LA R15,SAVEHLI Get save area address ST R13,4(,R15) Chain the save areas ST R15,8(,R13) Chain the save areas LR R13,R15 Put save area address in R13 L R15,LISQL Get the address of real DSNHLI BASSM R14,R15 Branch to DSNALI to do an SQL call * DSNALI is in 31-bit mode, so use * BASSM to assure that the addressing * mode is preserved. L R13,4(,R13) Restore R13 (caller’s save area addr) L R14,12(,R13) Restore R14 (return address) RETURN (1,12) Restore R1-12, NOT R0 and R15 (codes) Example of variable declarations when using CAF: The following example code shows declarations for some of the variables that were used in the previous subroutines. ****************************** VARIABLES ****************************** SECB DS F DB2 Startup ECB TECB DS F DB2 Termination ECB LIALI DS F DSNALI Entry Point address LISQL DS F DSNHLI2 Entry Point address SSID DS CL4 DB2 Subsystem ID. CONNECT parameter PLAN DS CL8 DB2 Plan name. OPEN parameter TRMOP DS CL4 CLOSE termination option (SYNC|ABRT) FUNCTN DS CL12 CAF function to be called RIBPTR DS F DB2 puts Release Info Block addr here RETCODE DS F Chekcode saves R15 here REASCODE DS F Chekcode saves R0 here CONTROL DS CL8 GO, SHUTDOWN, or RESTART SAVEAREA DS 18F Save area for CHEKCODE ****************************** CONSTANTS ****************************** SHUTDOWN DC CL8’SHUTDOWN’ CONTROL value: Shutdown execution 74 Application Programming and SQL Guide
  • 91.
    RESTART DC CL8’RESTART ’ CONTROLvalue: Restart execution CONTINUE DC CL8’CONTINUE’ CONTROL value: Everything OK, cont CODE0 DC F’0’ SQLCODE of 0 CODE100 DC F’100’ SQLCODE of 100 QUIESCE DC XL3’000008’ TECB postcode: STOP DB2 MODE=QUIESCE CONNECT DC CL12’CONNECT ’ Name of a CAF service. Must be CL12! OPEN DC CL12’OPEN ’ Name of a CAF service. Must be CL12! CLOSE DC CL12’CLOSE ’ Name of a CAF service. Must be CL12! DISCON DC CL12’DISCONNECT ’ Name of a CAF service. Must be CL12! TRANSLAT DC CL12’TRANSLATE ’ Name of a CAF service. Must be CL12! SYNC DC CL4’SYNC’ Termination option (COMMIT) ABRT DC CL4’ABRT’ Termination option (ROLLBACK) ****************************** RETURN CODES (R15) FROM CALL ATTACH **** ZERO DC F’0’ 0 FOUR DC F’4’ 4 EIGHT DC F’8’ 8 TWELVE DC F’12’ 12 (Call Attach return code in R15) NUM200 DC F’200’ 200 (User error) NUM204 DC F’204’ 204 (Call Attach system error) ****************************** REASON CODES (R00) FROM CALL ATTACH **** C10205 DC XL4’00C10205’ Call attach could not TRANSLATE C10831 DC XL4’00C10831’ Call attach found a release mismatch C10824 DC XL4’00C10824’ Call attach ready for more input F30002 DC XL4’00F30002’ DB2 subsystem not up F30011 DC XL4’00F30011’ DB2 subsystem not up F30012 DC XL4’00F30012’ DB2 subsystem not up F30025 DC XL4’00F30025’ DB2 is stopping (REASCODE) * * Insert more codes here as necessary for your application * ****************************** SQLCA and RIB ************************** EXEC SQL INCLUDE SQLCA DSNDRIB Get the DB2 Release Information Block ****************************** CALL macro parm list ******************* CAFCALL CALL ,(*,*,*,*,*,*,*,*,*),VL,MF=L Invoking the Resource Recovery Services attachment facility The Resource Recovery Services attachment facility (RRSAF) enables your program to communicate with DB2. Invoke RRSAF as an alternative to invoking CAF or when using stored procedures that run in a WLM-established address space. RRSAF has more capabilities than CAF. Before you invoke RRSAF, perform the following actions: v Ensure that the RRSAF language interface load module, DSNRLI, is available. v Ensure that your application satisfies the requirements for programs that access RRSAF. v Ensure that your application satisfies the general environment characteristics for connecting to DB2. v Ensure that you are familiar with the following z/OS concepts and facilities: – The CALL macro and standard module linkage conventions – Program addressing and residency options (AMODE and RMODE) – Creating and controlling tasks; multitasking – Functional recovery facilities such as ESTAE, ESTAI, and FRRs – Synchronization techniques such as WAIT/POST – z/OS RRS functions, such as SRRCMIT and SRRBACK Applications that use RRSAF can be written in assembler language, C, COBOL, Fortran, and PL/I. When choosing a language to code your application in, consider the following restrictions: Chapter 2. Connecting to DB2 from your application program 75
  • 92.
    v If youuse z/OS macros (ATTACH, WAIT, POST, and so on), choose a programming language that supports them. v The RRSAF TRANSLATE function is not available in Fortran. To use this function, code it in a routine that is written in another language, and then call that routine from Fortran. To invoke RRSAF: 1. Perform one of the following actions: v Explicitly invoke RRSAF by including in your program CALL DSNRLI statements with the appropriate options. The first option is an RRSAF connection function, which describes the action that you want RRSAF to take. The effect of any function depends in part on what functions the program has already performed. To code RRSAF functions in C, COBOL, Fortran, or PL/I, follow the individual language’s rules for making calls to assembler language routines. Specify the return code and reason code parameters in the parameter list for each RRSAF call. Requirement: For C, C++, and PL/I applications, you must also include in your program the compiler directives that are listed in the following table, because DSNRLI is an assembler language program. Table 19. Compiler directives to include in C, C++, and PL/I applications that contain CALL DSNRLI statements Language Compiler directive to include C #pragma linkage(dsnrli, OS) C++ extern "OS" { int DSNRLI( char * functn, ...); } PL/I DCL DSNRLI ENTRY OPTIONS(ASM,INTER,RETCODE); v Implicitly invoke RRSAF by including SQL statements or IFI calls in your program just as you would in any program. The RRSAF facility establishes the connection to DB2 with the default values for the subsystem name, plan name and authorization ID. Restriction: If your program can make its first SQL call from different modules with different DBRMs, you cannot use a default plan name and thus, you cannot implicitly invoke RRSAF. Instead, you must explicitly invoke RRSAF by calling the CREATE THREAD function. Requirement: If your application includes both SQL and IFI calls, you must issue at least one SQL call before you issue any IFI calls. This action ensures that your application uses the correct plan. 2. If you implicitly invoked RRSAF, determine if the implicit connection was successful by examining the return code and reason code immediately after the first executable SQL statement within the application program. Your program can check these codes by performing one of the following actions: v Examine registers 0 and 15 directly. v Examine the SQLCA, and if the SQLCODE is -981, obtain the return and reason code from the message text. The return code is the first token, and the reason code is the second token. 76 Application Programming and SQL Guide
  • 93.
    If the implicitconnection is successful, the application can examine the SQLCODE for the first, and subsequent, SQL statements. Example of an RRSAF configuration The following figure shows an conceptual example of invoking and using RRSAF. Figure 5. Sample RRSAF configuration Resource Recovery Services attachment facility An attachment facility enables programs to communicate with DB2. The Resource Recovery Services attachment facility (RRSAF) provides such a connection for programs that run in z/OS batch, TSO foreground, and TSO background. The RRSAF is an alternative to CAF and has more functionality. Chapter 2. Connecting to DB2 from your application program 77
  • 94.
    An application programusing RRSAF can perform the following actions: v Use DB2 to process SQL statements, commands, or instrumentation facility interface (IFI) calls. v Coordinate DB2 updates with updates made by all other resource managers that also use z/OS RRS in an z/OS system. v Use the z/OS System Authorization Facility and an external security product, such as RACF, to sign on to DB2 with the authorization ID of an end user. v Sign on to DB2 using a new authorization ID and an existing connection and plan. v Access DB2 from multiple z/OS tasks in an address space. v Switch a DB2 thread among z/OS tasks within a single address space. v Access the DB2 IFI. v Run with or without the TSO terminal monitor program (TMP). v Run without being a subtask of the DSN command processor (or of any DB2 code). v Run above or below the 16-MB line. v Establish an explicit connection to DB2, through a call interface, with control over the exact state of the connection. v Establish an implicit connection to DB2 (with a default subsystem identifier and a default plan name) by using SQL statements or IFI calls without first calling RRSAF. v Supply event control blocks (ECBs), for DB2 to post, that signal start-up or termination. v Intercept return codes, reason codes, and abend codes from DB2 and translate them into messages as desired. RRSAF uses z/OS Transaction Management and Recoverable Resource Manager Services (z/OS RRS). Any task in an address space can establish a connection to DB2 through RRSAF. Each task control block (TCB) can have only one connection to DB2. A DB2 service request that is issued by a program that runs under a given task is associated with that task’s connection to DB2. The service request operates independently of any DB2 activity under any other task. Each connected task can run a plan. Tasks within a single address space can specify the same plan, but each instance of a plan runs independently from the others. A task can terminate its plan and run a different plan without completely breaking its connection to DB2. RRSAF does not generate task structures. When you design your application, consider that using multiple simultaneous connections can increase the possibility of deadlocks and DB2 resource contention. Restriction: RRSAF does not provide attention processing exits or functional recovery routines. You can provide whatever attention handling and functional recovery your application needs, but you must use ESTAE/ESTAI type recovery routines only. 78 Application Programming and SQL Guide
  • 95.
    A tracing facilityprovides diagnostic messages that help you debug programs and diagnose errors in the RRSAF code. The trace information is available only in a SYSABEND or SYSUDUMP dump. To commit work in RRSAF applications, use the CPIC SRRCMIT function or the DB2 COMMIT statement. To roll back work, use the CPIC SRRBACK function or the DB2 ROLLBACK statement. Use the following guidelines to decide whether to use the DB2 statements or the CPIC functions for commit and rollback operations: v Use DB2 COMMIT and ROLLBACK statements when all of the following conditions are true: – The only recoverable resource that is accessed by your application is DB2 data that is managed by a single DB2 instance. DB2 COMMIT and ROLLBACK statements fail if your RRSAF application accesses recoverable resources other than DB2 data that is managed by a single DB2 instance. – The address space from which syncpoint processing is initiated is the same as the address space that is connected to DB2. v If your application accesses other recoverable resources, or syncpoint processing and DB2 access are initiated from different address spaces, use SRRCMIT and SRRBACK. Related reference ″COMMIT″ (DB2 SQL Reference) ″ROLLBACK″ (DB2 SQL Reference) Related information z/OS Internet Library at ibm.com Properties of RRSAF connections RRSAF enables programs to communicate with DB2 to process SQL statements, commands, or IFI calls. An RRSAF connection joins any task in an address space to DB2. Restriction: Do not mix RRSAF connections with other connection types in a single address space. The first connection that is made from an address space to DB2 determines the type of connection allowed. The connection that RRSAF makes with DB2 has the basic properties that are listed in the following table. Table 20. Properties of RRSAF connections Property Value Comments Connection name RRSAF You can use the DISPLAY THREAD command to list RRSAF applications that have the connection name RRSAF. Connection type RRSAF None. Chapter 2. Connecting to DB2 from your application program 79
  • 96.
    Table 20. Propertiesof RRSAF connections (continued) Property Value Comments Authorization ID Authorization IDs that are associated with each DB2 connection A connection must have a primary ID and can have one or more secondary IDs. Those identifiers are used for the following purposes: v Validating access to DB2 v Checking privileges on DB2 objects v Assigning ownership of DB2 objects v Identifying the user of a connection for audit, performance, and accounting traces. RRSAF relies on the z/OS System Authorization Facility (SAF) and a security product, such as RACF, to verify and authorize the authorization IDs. An application that connects to DB2 through RRSAF must pass those identifiers to SAF for verification and authorization checking. RRSAF retrieves the identifiers from SAF. A location can provide an authorization exit routine for a DB2 connection to change the authorization IDs and to indicate whether the connection is allowed. The actual values that are assigned to the primary and secondary authorization IDs can differ from the values that are provided by a SIGNON or AUTH SIGNON request. A site’s DB2 signon exit routine can access the primary and secondary authorization IDs and can modify the IDs to satisfy the site’s security requirements. The exit routine can also indicate whether the signon request should be accepted. 80 Application Programming and SQL Guide
  • 97.
    Table 20. Propertiesof RRSAF connections (continued) Property Value Comments Scope RRSAF processes connections None. as if each task is entirely isolated. When a task requests a function, RRSAF passes the function to DB2, regardless of the connection status of other tasks in the address space. However, the application program and the DB2 subsystem have access to the connection status of multiple tasks in an address space. If an application that is connected to DB2 through RRSAF terminates normally before the TERMINATE THREAD or TERMINATE IDENTIFY functions deallocate the plan, RRS commits any changes made after the last commit point. If the application terminates abnormally before the TERMINATE THREAD or TERMINATE IDENTIFY functions deallocate the plan, z/OS RRS rolls back any changes made after the last commit point. In either case, DB2 deallocates the plan, if necessary, and terminates the application’s connection. If DB2 abends while an application is running, DB2 rolls back changes to the last commit point. If DB2 terminates while processing a commit request, DB2 either commits or rolls back any changes at the next restart. The action taken depends on the state of the commit request when DB2 terminates. Making the RRSAF language interface (DSNRLI) available Before you can invoke the Resource Recovery Services attachment facility (RRSAF), you must first make available the RRSAF language interface load module, DSNRLI. Part of RRSAF is a DB2 load module, DSNRLI, which is also known as the RRSAF language interface module. DSNRLI has the alias names DSNHLIR and DSNWLIR. The module has five entry points: DSNRLI, DSNHLI, DSNHLIR, DSNWLI, and DSNWLIR. These entry points serve the following functions: v Entry point DSNRLI handles explicit DB2 connection service requests. v DSNHLI and DSNHLIR handle SQL calls. Use DSNHLI if your application program link-edits RRSAF. Use DSNHLIR if your application program loads RRSAF. v DSNWLI and DSNWLIR handle IFI calls. Use DSNWLI if your application program link-edits RRSAF. Use DSNWLIR if your application program loads RRSAF. To make DSNRLI available: 1. Decide which of the following two methods you want to use to make DSNRLI available: v Explicitly issuing LOAD requests when your program runs. Chapter 2. Connecting to DB2 from your application program 81
  • 98.
    By explicitly loadingthe DSNRLI module, you can isolate the maintenance of your application from future IBM maintenance to the language interface. If the language interface changes, the change will probably not affect your load module. v Including the DSNRLI module in your load module when you link-edit your program. A disadvantage of link-editing DSNRLI into your load module is that if IBM makes a change to DSNRLI, you must link-edit your program again. 2. Depending on the method that you chose in step 1, perform one of the following actions: v If you want to explicitly issue LOAD requests when your program runs: In your program, issue z/OS LOAD service requests for entry points DSNRLI and DSNHLIR. If you use IFI services, you must also load DSNWLIR. Save the entry point address that LOAD returns and use it in the CALL macro. Indicate to DB2 which entry point to use in one of the following two ways: – Specify the precompiler option ATTACH(RRSAF). This option causes DB2 to generate calls that specify entry point DSNHLIR. Restriction: You cannot use this option if your application is written in Fortran. – Code a dummy entry point named DSNHLI within your load module. If you do not specify the precompiler option ATTACH, the DB2 precompiler generates calls to entry point DSNHLI for each SQL request. The precompiler does not know about and is independent of the different DB2 attachment facilities. When the calls that are generated by the DB2 precompiler pass control to DSNHLI, your code that corresponds to the dummy entry point must preserve the option list that is passed in register 1 and call DSNHLIR with the same option list. v If you want to include the DSNRLI module in your load module when you link-edit your program: Include DSNRLI in your load module during a link-edit step. For example, you can use a linkage editor control statement that is similar to the following statement in your JCL: INCLUDE DB2LIB(DSNRLI). By coding this statement, you avoid inadvertently picking up the wrong language interface module. When you include the DSNRLI module during the link-edit, do not include a dummy DSNHLI entry point in your program or specify the precompiler option ATTACH. Module DSNRLI contains an entry point for DSNHLI, which is identical to DSNHLIR, and an entry point for DSNWLI, which is identical to DSNWLIR. Related concepts “Program examples for RRSAF” on page 118 Requirements for programs that use RRSAF The Resource Recovery Services attachment facility (RRSAF) enables programs to communicate with DB2. Before you invoke RRSAF in your program, ensure that your program satisfies any requirements for using RRSAF. 82 Application Programming and SQL Guide
  • 99.
    When you writeprograms that use RRSAF, ensure that they meet the following requirements: v The program accounts for the size of the RRSAF code. The RRSAF code requires about 10 KB of virtual storage per address space and an additional 10 KB for each TCB that uses RRSAF. v If your local environment intercepts and replaces the z/OS LOAD SVC that RRSAF uses, you must ensure that your version of LOAD manages the load list element (LLE) and contents directory entry (CDE) chains like the standard z/OS LOAD macro. RRSAF uses z/OS SVC LOAD to load a module as part of the initialization after your first service request. The module is loaded into fetch-protected storage that has the job-step protection key. You can prepare application programs to run in RRSAF similar to how you prepare applications to run in other environments, such as CICS, IMS, and TSO. You can prepare an RRSAF application either in the batch environment or by using the DB2 program preparation process. You can use the program preparation system either through DB2I or through the DSNH CLIST. Related tasks Chapter 11, “Preparing an application to run on DB2 for z/OS,” on page 837 How RRSAF modifies the content of registers If you do not specify the return code and reason code parameters in your RRSAF function calls or you invoke RRSAF implicitly, RRSAF puts a return code in register 15 and a reason code in register 0. RRSAF preserves the contents of registers 2 through 14. If you specify the return code and reason code parameters, RRSAF places the return code in register 15 and in the return code parameter to accommodate high-level languages that support special return code processing. The following table summarizes the register conventions for RRSAF calls. Table 21. Register conventions for RRSAF calls Register Usage R1 Parameter list pointer R13 Address of caller’s save area R14 Caller’s return address R15 RRSAF entry point address Implicit connections to RRSAF RRSAF establishes an implicit connection to DB2 if the RRSAF language interface load module (DSNRLI) is available, you do not explicitly specify the IDENTIFY function in a CALL DSNRLI statement in your program, and the application includes SQL statements or IFI calls. An implicit connection causes RRSAF to initiate implicit IDENTIFY and CREATE THREAD requests to DB2. These requests are subject to the same DB2 return codes and reason codes as explicitly specified requests. Implicit connections use the following defaults: Chapter 2. Connecting to DB2 from your application program 83
  • 100.
    Subsystem name The defaultname that is specified in the module DSNHDECP. RRSAF uses the installation default DSNHDECP, unless your own DSNHDECP module is in a library in a STEPLIB statement of the JOBLIB concatenation or in the link list. In a data sharing group, the default subsystem name is the group attachment name. Be certain that you know what the default name is and that it names the specific DB2 subsystem that you want to use. Plan name The member name of the database request module (DBRM) that DB2 produced when you precompiled the source program that contains the first SQL call. Authorization ID The 7-byte user ID that is associated with the address space, unless an authorized function has built an Accessor Environment Element (ACEE) for the address space. If an authorized function has built an ACEE, DB2 passes the 8-byte user ID from the ACEE. For an implicit connection request, your application should not explicitly specify either the IDENTIFY function or the CREATE THREAD function. Your application can execute other explicit RRSAF calls after the implicit connection is made. An implicit connection does not perform any SIGNON processing. Your application can execute the SIGNON function at any point of consistency. To terminate an implicit connection, you must use the proper function calls. For implicit connection requests, register 15 contains the return code, and register 0 contains the reason code. The return code and reason code are also in the message text for SQLCODE -981. Related concepts “Summary of RRSAF behavior” on page 85 CALL DSNRLI statement parameter list The CALL DSNRLI statement explicitly invokes RRSAF. When you include CALL DSNRLI statements in your program, you must specify all parameters that come before the return code parameter. In CALL DSNRLI statements, you cannot omit any of parameters that come before the return code parameter by coding zeros or blanks. No defaults exist for those parameters for explicit connection requests. Defaults are provided for only implicit connections. All parameters starting with the return code parameter are optional. When you want to use the default value for a parameter but specify subsequent parameters, code the CALL DSNRLI statement as follows: v For all languages except assembler language, code zero for that parameter in the CALL DSNRLI statement. For example, suppose that you are coding an IDENTIFY call in a COBOL program, and you want to specify all parameters except the return code parameter. You can write a statement similar to the following statement: CALL ’DSNRLI’ USING IDFYFN SSNM RIBPTR EIBPTR TERMECB STARTECB BY CONTENT ZERO BY REFERENCE REASCODE. v For assembler language, code a comma for that parameter in the CALL DSNRLI statement. For example, suppose that you are coding an IDENTIFY call, and you 84 Application Programming and SQL Guide
  • 101.
    want to specifyall parameters except the return code parameter. You can write a statement similar to the following statement: CALL DSNRLI,(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB,,REASCODE) For assembler programs that invoke RRSAF, use a standard parameter list for an z/OS CALL. Register 1 must contain the address of a list of pointers to the parameters. Each pointer is a 4-byte address. The last address must contain the value 1 in the high-order bit. Summary of RRSAF behavior The effect of any RRSAF function depends in part on what functions the program has already run. You should plan the RRSAF function calls that your program makes to avoid any errors and major structural problems in your application. The following tables summarize RRSAF behavior after various inputs from application programs. The contents of each table cell indicate the result of calling the function in the first column for that row followed by the function in the current column heading. For example, if you issue TERMINATE THREAD and then IDENTIFY, RRSAF returns reason code X’00C12201’. Use these tables to understand the order in which your application must issue RRSAF calls, SQL statements, and IFI requests. The RRSAF FIND_DB2_SYSTEMS function is omitted from these tables, because it does not affect the operation of any of the other functions | | The following table summarizes RRSAF behavior when the next call is to the IDENTIFY function, the SWITCH TO function, the SIGNON function, or the CREATE THREAD function. Table 22. Effect of call order when next call is IDENTIFY, SWITCH TO, SIGNON, or CREATE THREAD Next function Previous function IDENTIFY SWITCH TO SIGNON, AUTH SIGNON, or CONTEXT SIGNON CREATE THREAD Empty: first call IDENTIFY X’00C12205’1 X’00C12204’1 IDENTIFY X’00F30049’1 Switch to ssnm Signon 2 X’00C12217’1 SWITCH TO IDENTIFY Switch to ssnm Signon 2 CREATE THREAD CREATE THREAD X’00C12204’1 SIGNON, AUTH SIGNON, or CONTEXT SIGNON X’00F30049’ 1 Switch to ssnm Signon 2 CREATE THREAD X’00F30049’1 Switch to ssnm Signon 2 X’00C12202’1 TERMINATE THREAD X’00C12201’1 Switch to ssnm Signon 2 CREATE THREAD 2 X’00C12202’1 IFI X’00F30049’ 1 Switch to ssnm Signon SQL X’00F30049’1 Switch to ssnm X’00F30092’13 SRRCMIT or SRRBACK X’00F30049’1 Switch to ssnm Signon 2 X’00C12202’1 X’00C12202’1 Notes: 1. Errors are identified by the DB2 reason code that RRSAF returns. 2. Signon means either the SIGNON function, the AUTH SIGNON function, or the CONTEXT SIGNON function. 3. The SIGNON, AUTH SIGNON, or CONTEXT SIGNON functions are not allowed if any SQL operations are requested after the CREATE THREAD function or after the last SRRCMIT or SRRBACK request. Chapter 2. Connecting to DB2 from your application program 85
  • 102.
    The following tablesummarizes RRSAF behavior when the next call is an SQL statement or an IFI call or to the TERMINATE THREAD function, the TERMINATE IDENTIFY function, or the TRANSLATE function. | | | Table 23. Effect of call order when next call is SQL or IFI, TERMINATE THREAD, TERMINATE IDENTIFY, or TRANSLATE Next function Previous function SQL or IFI TERMINATE THREAD TERMINATE IDENTIFY TRANSLATE Empty: first call SQL or IFI call 4 X’00C12204’1 X’00C12204’1 X’00C12204’1 IDENTIFY SQL or IFI call4 X’00C12203’1 TERMINATE IDENTIFY TRANSLATE SQL or IFI call 4 TERMINATE THREAD TERMINATE IDENTIFY TRANSLATE SIGNON, AUTH SIGNON, or CONTEXT SIGNON SQL or IFI call 4 TERMINATE THREAD TERMINATE IDENTIFY TRANSLATE CREATE THREAD SQL or IFI call4 TERMINATE THREAD TERMINATE IDENTIFY TRANSLATE TERMINATE IDENTIFY TRANSLATE TERMINATE IDENTIFY TRANSLATE 13 TRANSLATE TERMINATE IDENTIFY TRANSLATE SWITCH TO TERMINATE THREAD SQL or IFI call 4 X’00C12203’ 1 SQL or IFI call SQL or IFI call IFI SQL SRRCMIT or SRRBACK 4 4 X’00F30093’ SQL or IFI call 4 TERMINATE THREAD TERMINATE THREAD 12 X’00F30093’ Notes: 1. Errors are identified by the DB2 reason code that RRSAF returns. 2. TERMINATE THREAD is not allowed if any SQL operations are requested after the CREATE THREAD function or after the last SRRCMIT or SRRBACK request. 3. TERMINATE IDENTIFY is not allowed if any SQL operations are requested after the CREATE THREAD function or after the last SRRCMIT or SRRBACK request. 4. If you are using an implicit connection to RRSAF and issue SQL or IFI calls, RRSAF issues implicit IDENTIFY and CREATE THREAD requests. If you continue with explicit RRSAF statements, you must follow the standard order of explicit RRSAF calls. Implicitly connecting to RRSAF does not cause an implicit SIGNON request. Therefore, you might need to issue an explicit SIGNON request to satisfy the standard order requirement. For example, an SQL statement followed by an explicit TERMINATE THREAD request results in an error. You must issue an explicit SIGNON request before issuing the TERMINATE THREAD request. Related concepts ″X’C1......’ codes″ (DB2 Codes) ″X’F3......’ codes″ (DB2 Codes) RRSAF connection functions An RRSAF connection function specifies the action that you want RRSAF to take. You specify these functions when you invoke RRSAF through CALL DSNRLI statements. Related concepts “Summary of RRSAF behavior” on page 85 “CALL DSNRLI statement parameter list” on page 84 IDENTIFY function for RRSAF The RRSAF IDENTIFY function initializes a connection to DB2. The IDENTIFY function establishes the caller’s task as a user of DB2 services. If no other task in the address space currently is connected to the specified subsystem, the IDENTIFY function also initializes the address space to communicate with the DB2 address spaces. The IDENTIFY function establishes the cross-memory authorization of the address space to DB2 and builds address space control blocks. 86 Application Programming and SQL Guide
  • 103.
    The following diagramshows the syntax for the IDENTIFY function. DSNRLI IDENTIFY function CALL DSNRLI ( function , ssnm , ribptr , eibptr , termecb , startecb | ) , retcode , reascode , groupoverride , decpptr Parameters point to the following areas: function An 18-byte area that contains IDENTIFY followed by 10 blanks. ssnm A 4-byte DB2 subsystem name or group attachment name (if used in a data sharing group) to which the connection is made. If ssnm is less than four characters long, pad it on the right with blanks to a length of four characters. ribptr A 4-byte area in which RRSAF places the address of the release information block (RIB) after the call. You can use the RIB to determine the release level of the DB2 subsystem to which the application is connected. You can determine the modification level within the release level by examining the RIBCNUMB and RIBCINFO fields. If the value in the RIBCNUMB field is greater than zero, check the RIBCINFO field for modification levels. If the RIB is not available (for example, if ssnm names a subsystem that does not exist), DB2 sets the 4-byte area to zeros. The area to which ribptr points is below the 16-MB line. This parameter is required. However, the application does not need to refer to the returned information. eibptr A 4-byte area in which RRSAF places the address of the environment information block (EIB) after the call. The EIB contains environment information, such as the data sharing group, the name of the DB2 member to which the IDENTIFY request was issued, and whether the subsystem is in new-function mode. If the DB2 subsystem is not in a data sharing group, RRSAF sets the data sharing group and member names to blanks. If the EIB is not available (for example, if ssnm names a subsystem that does not exist), RRSAF sets the 4-byte area to zeros. The area to which eibptr points is above the 16-MB line. This parameter is required. However, the application does not need to refer to the returned information. termecb The address of the application’s event control block (ECB) that is used for DB2 termination. DB2 posts this ECB when the system operator enters the STOP Chapter 2. Connecting to DB2 from your application program 87
  • 104.
    DB2 command orwhen DB2 is terminating abnormally. Specify a value of 0 if you do not want to use a termination ECB. RRSAF puts a POST code in the ECB to indicate the type of termination as shown in the following table. Table 24. Post codes for types of DB2 termination POST code Termination type 8 QUIESCE 12 FORCE 16 ABTERM startecb The address of the application’s startup ECB. If DB2 has not started when the application issues the IDENTIFY call, DB2 posts the ECB when DB2 has started. Enter a value of zero if you do not want to use a startup ECB. DB2 posts no more than one startup ECB per address space. The ECB that is posted is associated with the most recent IDENTIFY call from that address space. The application program must examine any nonzero RRSAF or DB2 reason codes before issuing a WAIT request on this ECB. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places a reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode or its default. You can specify a default for retcode by specifying a comma or zero, depending on the language. | | | | | | groupoverride An 8-byte area that the application provides. This parameter is optional. If you do not want group attach to be attempted, specify ’NOGROUP’. This string indicates that the subsystem name that is specified by ssnm is to be used as a DB2 subsystem name, even if ssnm matches a group attachment name. If groupoverride is not provided, ssnm is used as the group attachment name if it matches a group attachment name. | | | | If you specify this parameter in any language except assembler, you must also specify the retcode and reascode parameters. In assembler language, you can omit the retcode and reascode parameters by specifying commas as place-holders. | | | | | | Recommendation: Avoid using the groupoverride parameter when possible, because it limits the ability to do dynamic workload routing in a Parallel Sysplex. However, you should use this parameter in a data sharing environment when you want to connect to a specific member of a data sharing group, and the subsystem name of that member is the same as the group attachment name. | | decpptr A 4-byte area in which RRSAF is to put the address of the DSNHDECP control 88 Application Programming and SQL Guide
  • 105.
    | | | block that wasloaded by subsystem ssnm when that subsystem was started. This 4-byte area is a 31-bit pointer. If ssnm is not found, the 4-byte area is set to 0. | The area to which decpptr points is above the 16-MB line. | | | | If you specify this parameter in any language except assembler, you must also specify the retcode, reascode, and groupoverride parameters. In assembler language, you can omit the retcode, reascode, and groupoverride parameters by specifying commas as placeholders. Example of RRSAF IDENTIFY function calls The following table shows an IDENTIFY call in each language. Table 25. Examples of RRSAF IDENTIFY calls Language Call example Assembler CALL C 1 DSNRLI,(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB, RETCODE,REASCODE,GRPOVER,DECPPTR) fnret=dsnrli(&idfyfn[0],&ssnm[0], &ribptr, &eibptr, &termecb, &startecb, &retcode, &reascode,&grpover[0],&decpptr); COBOL CALL ’DSNRLI’ USING IDFYFN SSNM RIBTPR EIBPTR TERMECB STARTECB RETCODE REASCODE GRPOVER DECPPTR. Fortran CALL DSNRLI(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB, RETCODE,REASCODE,GRPOVER,DECPPTR) CALL DSNRLI(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB, RETCODE,REASCODE,GRPOVER,DECPPTR); PL/I 1 Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Internal processing for the IDENTIFY function | | | | | | | | | | | | | | | | | | | | | When you call the IDENTIFY function, DB2 performs the following steps: 1. DB2 determines whether the user address space is authorized to connect to DB2. DB2 invokes the z/OS SAF and passes a primary authorization ID to SAF. That authorization ID is the 7-byte user ID that is associated with the address space, unless an authorized function has built an ACEE for the address space. If an authorized function has built an ACEE, DB2 passes the 8-byte user ID from the ACEE. SAF calls an external security product, such as RACF, to determine if the task is authorized to use the following items: v The DB2 resource class (CLASS=DSNR) v The DB2 subsystem (SUBSYS=ssnm) v Connection type RRSAF 2. If that check is successful, DB2 calls the DB2 connection exit routine to perform additional verification and possibly change the authorization ID. 3. DB2 searches for a matching trusted context in the system cache and then the catalog based on the following criteria: v The primary authorization ID matches a trusted context SYSTEM AUTHID. v The job or started task name matches the JOBNAME attribute that is defined for the identified trusted context. If a trusted context is defined, DB2 checks if SECURITY LABEL is defined in the trusted context. If SECURITY LABEL is defined, DB2 verifies the SECURITY LABEL with RACF by using the RACROUTE VERIFY request. This security Chapter 2. Connecting to DB2 from your application program 89
  • 106.
    label is usedto verify multi-level security for SYSTEM AUTHID.If a matching trusted context is defined, DB2 establishes the connection as trusted. Otherwise, the connection is established without any additional privileges. 4. DB2 then sets the connection name to RRSAF and the connection type to RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 | | | | | SWITCH TO function for RRSAF The RRSAF SWITCH TO function directs RRSAF, SQL, or IFI requests to a specified DB2 subsystem. Use the SWITCH TO function to establish connections to multiple DB2 subsystems from a single task. The SWITCH TO function is useful only after a successful IDENTIFY call. If you have established a connection with one DB2 subsystem, you must issue a SWITCH TO call before you make an IDENTIFY call to another DB2 subsystem. Otherwise, DB2 returns return code X’200’ and reason code X’00C12201’. The first time that you make a SWITCH TO call to a new DB2 subsystem, DB2 returns return code 4 and reason code X’00C12205’ as a warning to indicate that the current task has not yet been identified to the new DB2 subsystem. The following diagram shows the syntax for the SWITCH TO function. DSNRLI SWITCH TO function CALL DSNRLI ( function,ssnm ) , retcode , reascode , groupoverride Parameters point to the following areas: function An 18-byte area that contains SWITCH TO followed by nine blanks. ssnm A 4-byte DB2 subsystem name or group attachment name (if used in a data sharing group) to which the connection is made. If ssnm is less than four characters long, pad it on the right with blanks to a length of four characters. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. 90 Application Programming and SQL Guide
  • 107.
    If you specifythis parameter, you must also specify retcode. | | | | | | groupoverride An 8-byte area that the application provides. This parameter is optional. If you do not want group attach to be attempted, specify ’NOGROUP’. This string indicates that the subsystem name that is specified by ssnm is to be used as a DB2 subsystem name, even if ssnm matches a group attachment name. If groupoverride is not provided, ssnm is used as the group attachment name if it matches a group attachment name. | | | | If you specify this parameter in any language except assembler, you must also specify the retcode and reascode parameters. In assembler language, you can omit the retcode and reascode parameters by specifying commas as place-holders. | | | | | | Recommendation: Avoid using the groupoverride parameter when possible, because it limits the ability to do dynamic workload routing in a Parallel Sysplex. However, you should use this parameter in a data sharing environment when you want to connect to a specific member of a data sharing group, and the subsystem name of that member is the same as the group attachment name. Examples Examples of RRSAF SWITCH TO calls: The following table shows a SWITCH TO call in each language. Table 26. Examples of RRSAF SWITCH TO calls Language Call example Assembler CALL C 1 DSNRLI,(SWITCHFN,SSNM,RETCODE,REASCODE,GRPOVER) fnret=dsnrli(&switchfn[0], &ssnm[0], &retcode, &reascode,&grpover[0]); COBOL CALL ’DSNRLI’ USING SWITCHFN RETCODE REASCODE GRPOVER. Fortran CALL DSNRLI(SWITCHFN,RETCODE,REASCODE,GRPOVER) PL/I1 CALL DSNRLI(SWITCHFN,RETCODE,REASCODE,GRPOVER); 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Example of using the SWITCH TO function to interact with multiple DB2 subsystems: The following example shows how you can use the SWITCH TO function to interact with three DB2 subsystems. | | | | | | | | | | | | | | | | RRSAF calls for subsystem db21: IDENTIFY SIGNON CREATE THREAD Execute SQL on subsystem db21 SWITCH TO db22 IF retcode = 4 AND reascode = ’00C12205’X THEN DO; RRSAF calls on subsystem db22: IDENTIFY SIGNON CREATE THREAD END; Execute SQL on subsystem db22 SWITCH TO db23 IF retcode = 4 AND reascode = ’00C12205’X THEN Chapter 2. Connecting to DB2 from your application program 91
  • 108.
    | | | | | | | | | | | | | | | | | | | | | DO; RRSAF calls onsubsystem db23: IDENTIFY SIGNON CREATE THREAD END; Execute SQL on subsystem 23 SWITCH TO db21 Execute SQL on subsystem 21 SWITCH TO db22 Execute SQL on subsystem 22 SWITCH TO db21 Execute SQL on subsystem 21 SRRCMIT (to commit the UR) SWITCH TO db23 Execute SQL on subsystem 23 SWITCH TO db22 Execute SQL on subsystem 22 SWITCH TO db21 Execute SQL on subsystem 21 SRRCMIT (to commit the UR) Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 SIGNON function for RRSAF The RRSAF SIGNON function establishes a primary authorization ID and, optionally, one or more secondary authorization IDs for a connection. Requirement: Your program does not need to be an authorized program to issue the SIGNON call. For that reason, before you issue the SIGNON call, you must issue the RACF external security interface macro RACROUTE REQUEST=VERIFY to perform the following actions: v Define and populate an ACEE to identify the user of the program. v Associate the ACEE with the user’s TCB. v Verify that the user is defined to RACF and authorized to use the application. Generally, you issue a SIGNON call after an IDENTIFY call and before a CREATE THREAD call. You can also issue a SIGNON call if the application is at a point of consistency, and one of the following conditions is true: v The value of reuse in the CREATE THREAD call was RESET. v The value of reuse in the CREATE THREAD call was INITIAL, no held cursors are open, the package or plan is bound with KEEPDYNAMIC(NO), and all special registers are at their initial state. If open held cursors exist or the package or plan is bound with KEEPDYNAMIC(YES), you can issue a SIGNON call only if the primary authorization ID has not changed. | | | | | After you issue a SIGNON call, subsequent SQL statements return an error (SQLCODE -900) if the both of following conditions are true: v The connection was established as trusted when it was initialized. v The primary authorization ID that was used when you issued the SIGNON call is not allowed to use the trusted connection. | | | | If a trusted context is defined, DB2 checks if SECURITY LABEL is defined in the trusted context. If SECURITY LABEL is defined, DB2 verifies the security label with RACF by using the RACROUTE VERIFY request. This security label is used to verify multi-level security for SYSTEM AUTHID. The following diagram shows the syntax for the SIGNON function. 92 Application Programming and SQL Guide
  • 109.
    DSNRLI SIGNON function CALLDSNRLI ( function, correlation-id, accounting-token, accounting-interval ) ,retcode ,reascode ,user ,appl ,ws ,xid ,accounting-string Parameters point to the following areas: function An 18-byte area that contains SIGNON followed by twelve blanks. correlation-id A 12-byte area in which you can put a DB2 correlation ID. The correlation ID is displayed in DB2 accounting and statistics trace records. You can use the correlation ID to correlate work units. This token appears in the output from the DISPLAY THREAD command. If you do not want to specify a correlation ID, fill the 12-byte area with blanks. accounting-token A 22-byte area in which you can put a value for a DB2 accounting token. This value is displayed in DB2 accounting and statistics trace records in the QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. Setting the value of the accounting token sets the value of the CURRENT CLIENT_ACCTNG special register. If accounting-token is less than 22 characters long, you must pad it on the right with blanks to a length of 22 characters. If you do not want to specify an accounting token, fill the 22-byte area with blanks. Alternatively, you change the value of the DB2 accounting token with RRSAF functions AUTH SIGNON, CONTEXT SIGNON or SET_CLIENT_ID. You can retrieve the DB2 accounting token with the CURRENT CLIENT_ACCTNG special register only if the DDF accounting string is not set. accounting-interval A 6-byte area that specifies when DB2 writes an accounting record. | | | | | | | If you specify COMMIT in that area, DB2 writes an accounting record each time that the application issues SRRCMIT without open held cursors. If the accounting interval is COMMIT and an SRRCMIT is issued while a held cursor is open, the accounting interval spans that commit and ends at the next valid accounting interval end point (such as the next SRRCMIT that is issued without open held cursors, application termination, or SIGNON with a new authorization ID). If you specify any other value, DB2 writes an accounting record when the application terminates or when you call the SIGNON function with a new authorization ID. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. Chapter 2. Connecting to DB2 from your application program 93
  • 110.
    reascode A 4-byte areain which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify this parameter, you must also specify retcode. user A 16-byte area that contains the user ID of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays this user ID in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the user ID sets the value of the CURRENT CLIENT_USERID special register. If user is less than 16 characters long, you must pad it on the right with blanks to a length of 16 characters. This parameter is optional. If you specify user, you must also specify retcode and reascode. If you do not specify user, no user ID is associated with the connection. appl A 32-byte area that contains the application or transaction name of the end user’s application. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays the application name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the application name sets the value of the CURRENT CLIENT_APPLNAME special register. If appl is less than 32 characters long, you must pad it on the right with blanks to a length of 32 characters. This parameter is optional. If you specify appl, you must also specify retcode, reascode, and user. If you do not specify appl, no application or transaction is associated with the connection. ws An 18-byte area that contains the workstation name of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays the workstation name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the workstation name sets the value of the CURRENT CLIENT_WRKSTNNAME special register. If ws is less than 18 characters long, you must pad it on the right with blanks to a length of 18 characters. This field is optional. If you specify ws, you must also specify retcode, reascode, user, and appl. If you do not specify ws, no workstation name is associated with the connection. xid A 4-byte area that indicates whether the thread is part of a global transaction. A DB2 thread that is part of a global transaction can share locks with other DB2 threads that are part of the same global transaction and can access and modify the same data. A global transaction exists until one of the threads that is part of the global transaction is committed or rolled back. You can specify one of the following values for xid: 0 1 94 Indicates that the thread is not part of a global transaction. The value 0 must be specified as a binary integer. Indicates that the thread is part of a global transaction and that DB2 should retrieve the global transaction ID from RRS. If a global Application Programming and SQL Guide
  • 111.
    transaction ID alreadyexists for the task, the thread becomes part of the associated global transaction. Otherwise, RRS generates a new global transaction ID. The value 1 must be specified as a binary integer. Alternatively, if you want DB2 to return the generated global transaction ID to the caller, specify an address instead of 1. address The 4-byte address of an area in which you enter a global transaction ID for the thread. If the global transaction ID already exists, the thread becomes part of the associated global transaction. Otherwise, RRS creates a new global transaction with the ID that you specify. Alternatively, if you want DB2 to generate and return a global transaction ID, pass the address of a null global transaction ID by setting the format ID field of the global transaction ID to binary -1 (’FFFFFFF’X). DB2 then replaces the contents of the area with the generated transaction ID. The area at the specified address must be in writable storage and have a length of at least 140 bytes to accommodate the largest possible transaction ID value. The following table shows the format of a global transaction ID. Table 27. Format of a user-created global transaction ID Field description Length in bytes Data type Format ID 4 Integer Global transaction ID length (1 - 64) 4 Integer Branch qualifier length (1 64) 4 Integer Global transaction ID 1 to 64 Character Branch qualifier 1 to 64 Character accounting-string A one-byte length field and a 255-byte area in which you can put a value for a DB2 accounting string. This value is placed in the DDF accounting trace records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If accounting-string is less than 255 characters, you must pad it on the right with zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA DSECT. This parameter is optional. If you specify accounting-string, you must also specify retcode, reascode, user, appl and xid. If you do not specify accounting-string, no accounting string is associated with the connection. You can also change the value of the accounting string with RRSAF functions AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID. You can retrieve the DDF suffix portion of the accounting string with the CURRENT CLIENT_ACCTNG special register. The suffix portion of accounting-string can contain a maximum of 200 characters. The QMDASFLN field contains the accounting suffix length, and the QMDASUFX field contains the accounting suffix value. If the DDF accounting string is set, you cannot query the accounting token with the CURRENT CLIENT_ACCTNG special register. Example of RRSAF SIGNON calls The following table shows a SIGNON call in each language. Chapter 2. Connecting to DB2 from your application program 95
  • 112.
    Table 28. Examplesof RRSAF SIGNON calls Language Call example assembler CALL C 1 DSNRLI,(SGNONFN,CORRID,ACCTTKN,ACCTINT, RETCODE,REASCODE,USERID,APPLNAME,WSNAME,XIDPTR) fnret=dsnrli(&sgnonfn[0], &corrid[0], &accttkn[0], &acctint[0], &retcode, &reascode, &userid[0], &applname[0], &wsname[0], &xidptr); COBOL CALL ’DSNRLI’ USING SGNONFN CORRID ACCTTKN ACCTINT RETCODE REASCODE USERID APPLNAME WSNAME XIDPTR. Fortran CALL DSNRLI(SGNONFN,CORRID,ACCTTKN,ACCTINT, RETCODE,REASCODE,USERID,APPLNAME,WSNAME,XIDPTR) CALL DSNRLI(SGNONFN,CORRID,ACCTTKN,ACCTINT, RETCODE,REASCODE,USERID,APPLNAME,WSNAME,XIDPTR); PL/I 1 Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 Related information z/OS Internet Library at ibm.com AUTH SIGNON function for RRSAF The RRSAF AUTH SIGNON function enables an APF-authorized program to pass to DB2 either a primary authorization ID and, optionally, one or more secondary authorization IDs, or an ACEE that is used for authorization checking. These IDs are then associated with the connection. Generally, you issue an AUTH SIGNON call after an IDENTIFY call and before a CREATE THREAD call. You can also issue an AUTH SIGNON call if the application is at a point of consistency, and one of the following conditions is true: v The value of reuse in the CREATE THREAD call was RESET. v The value of reuse in the CREATE THREAD call was INITIAL, no held cursors are open, the package or plan is bound with KEEPDYNAMIC(NO), and all special registers are at their initial state. If open held cursors exist or the package or plan is bound with KEEPDYNAMIC(YES), a SIGNON call is permitted only if the primary authorization ID has not changed. The following diagram shows the syntax for the AUTH SIGNON function. DSNRLI AUTH SIGNON function CALL DSNRLI ( function, correlation-id, accounting-token, accounting-interval, primary-authid, ACEE-address, secondary-authid ) ,retcode ,reascode ,user ,appl ,ws ,xid ,accounting-string 96 Application Programming and SQL Guide
  • 113.
    Parameters point tothe following areas: function An 18-byte area that contains AUTH SIGNON followed by seven blanks. correlation-id A 12-byte area in which you can put a DB2 correlation ID. The correlation ID is displayed in DB2 accounting and statistics trace records. You can use the correlation ID to correlate work units. This token appears in output from the DISPLAY THREAD command. If you do not want to specify a correlation ID, fill the 12-byte area with blanks. accounting-token A 22-byte area in which you can put a value for a DB2 accounting token. This value is displayed in DB2 accounting and statistics trace records in the QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. Setting the value of the accounting token sets the value of the CURRENT CLIENT_ACCTNG special register. If accounting-token is less than 22 characters long, you must pad it on the right with blanks to a length of 22 characters. If you do not want to specify an accounting token, fill the 22-byte area with blanks. You can also change the value of the DB2 accounting token with RRSAF functions SIGNON, CONTEXT SIGNON or SET_CLIENT_ID. You can retrieve the DB2 accounting token with the CURRENT CLIENT_ACCTNG special register only if the DDF accounting string is not set. accounting-interval A 6-byte area with that specifies when DB2 writes an accounting record. | | | | | | | If you specify COMMIT in that area, DB2 writes an accounting record each time that the application issues SRRCMIT without open held cursors. If the accounting interval is COMMIT and an SRRCMIT is issued while a held cursor is open, the accounting interval spans that commit and ends at the next valid accounting interval end point (such as the next SRRCMIT that is issued without open held cursors, application termination, or SIGNON with a new authorization ID). If you specify any other value, DB2 writes an accounting record when the application terminates or when you call the SIGNON function with a new authorization ID. primary-authid An 8-byte area in which you can put a primary authorization ID. If you are not passing the authorization ID to DB2 explicitly, put X’00’ or a blank in the first byte of the area. ACEE-address The 4-byte address of an ACEE that you pass to DB2. If you do not want to provide an ACEE, specify 0 in this field. secondary-authid An 8-byte area in which you can put a secondary authorization ID. If you do not pass the authorization ID to DB2 explicitly, put X’00’ or a blank in the first byte of the area. If you enter a secondary authorization ID, you must also enter a primary authorization ID. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. Chapter 2. Connecting to DB2 from your application program 97
  • 114.
    reascode A 4-byte areain which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascoder, you must also specify retcode. user A 16-byte area that contains the user ID of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays this user ID in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the user ID sets the value of the CURRENT CLIENT_USERID special register. If user is less than 16 characters long, you must pad it on the right with blanks to a length of 16 characters. This parameter is optional. If you specify user, you must also specify retcode and reascode. If you do not specify this parameter, no user ID is associated with the connection. appl A 32-byte area that contains the application or transaction name of the end user’s application. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays the application name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the application name sets the value of the CURRENT CLIENT_APPLNAME special register. If appl is less than 32 characters long, you must pad it on the right with blanks to a length of 32 characters. This parameter is optional. If you specify appl, you must also specify retcode, reascode, and user. If you do not specify this parameter, no application or transaction is associated with the connection. ws An 18-byte area that contains the workstation name of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays the workstation name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the workstation name sets the value of the CURRENT CLIENT_WRKSTNNAME special register. If ws is less than 18 characters long, you must pad it on the right with blanks to a length of 18 characters. This parameter is optional. If you specify ws, you must also specify retcode, reascode, user, and appl. If you do not specify this parameter, no workstation name is associated with the connection. You can also change the value of the workstation name with RRSAF functions SIGNON, CONTEXT SIGNON or SET_CLIENT_ID. You can retrieve the workstation name with the CURRENT CLIENT_WRKSTNNAME special register. xid A 4-byte area that indicates whether the thread is part of a global transaction. A DB2 thread that is part of a global transaction can share locks with other DB2 threads that are part of the same global transaction and can access and modify the same data. A global transaction exists until one of the threads that is part of the global transaction is committed or rolled back. You can specify one of the following values for xid: 98 Application Programming and SQL Guide
  • 115.
    0 Indicates that thethread is not part of a global transaction. The value 0 must be specified as a binary integer. 1 Indicates that the thread is part of a global transaction and that DB2 should retrieve the global transaction ID from RRS. If a global transaction ID already exists for the task, the thread becomes part of the associated global transaction. Otherwise, RRS generates a new global transaction ID. The value 1 must be specified as a binary integer. Alternatively, if you want DB2 to return the generated global transaction ID to the caller, specify an address instead of 1. address The 4-byte address of an area into which you enter a global transaction ID for the thread. If the global transaction ID already exists, the thread becomes part of the associated global transaction. Otherwise, RRS creates a new global transaction with the ID that you specify. Alternatively, if you want DB2 to generate and return a global transaction ID, pass the address of a null global transaction ID by setting the format ID field of the global transaction ID to binary -1 (’FFFFFFF’X). DB2 then replaces the contents of the area with the generated transaction ID. The area at the specified address must be in writable storage and have a length of at least 140 bytes to accommodate the largest possible transaction ID value. The format of a global transaction ID is shown in the description of the RRSAF SIGNON function. accounting-string A one-byte length field and a 255-byte area in which you can put a value for a DB2 accounting string. This value is placed in the DDF accounting trace records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If accounting-string is less than 255 characters, you must pad it on the right with zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA DSECT. This parameter is optional. If you specify this accounting-string, you must also specify retcode, reascode, user, appl and xid. If you do not specify this parameter, no accounting string is associated with the connection. You can also change the value of the accounting string with RRSAF functions AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID. You can retrieve the DDF suffix portion of the accounting string with the CURRENT CLIENT_ACCTNG special register. The suffix portion of accounting-string can contain a maximum of 200 characters. The QMDASFLN field contains the accounting suffix length, and the QMDASUFX field contains the accounting suffix value. If the DDF accounting string is set, you cannot query the accounting token with the CURRENT CLIENT_ACCTNG special register. Example of RRSAF AUTH SIGNON calls The following table shows a AUTH SIGNON call in each language. Table 29. Examples of RRSAF AUTH SIGNON calls Language Call example Assembler CALL DSNRLI,(ASGNONFN,CORRID,ACCTTKN,ACCTINT,PAUTHID,ACEEPTR, SAUTHID,RETCODE,REASCODE, USERID,APPLNAME,WSNAME,XIDPTR) Chapter 2. Connecting to DB2 from your application program 99
  • 116.
    Table 29. Examplesof RRSAF AUTH SIGNON calls (continued) Language C 1 Call example fnret=dsnrli(&asgnonfn[0], &corrid[0], &accttkn[0], &acctint[0], &pauthid[0], &aceeptr, &sauthid[0], &retcode, &reascode, &userid[0], &applname[0], &wsname[0], &xidptr); COBOL CALL ’DSNRLI’ USING ASGNONFN CORRID ACCTTKN ACCTINT PAUTHID ACEEPTR SAUTHID RETCODE REASCODE USERID APPLNAME WSNAME XIDPTR. Fortran CALL DSNRLI(ASGNONFN,CORRID,ACCTTKN,ACCTINT,PAUTHID,ACEEPTR, SAUTHID,RETCODE,REASCODE,USERID, APPLNAME,WSNAME,XIDPTR) PL/I1 CALL DSNRLI(ASGNONFN,CORRID,ACCTTKN,ACCTINT,PAUTHID,ACEEPTR, SAUTHID,RETCODE,REASCODE,USERID, APPLNAME,WSNAME,XIDPTR); Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 Related reference “SIGNON function for RRSAF” on page 92 CONTEXT SIGNON function for RRSAF The RRSAF CONTEXT SIGNON function establishes a primary authorization ID and one or more secondary authorization IDs for a connection. Requirement: Before you invoke CONTEXT SIGNON, you must have called the RRS context services function Set Context Data (CTXSDTA) to store a primary authorization ID and optionally, the address of an ACEE in the context data whose context key you supply as input to CONTEXT SIGNON. The CONTEXT SIGNON function uses the context key to retrieve the primary authorization ID from data that is associated with the current RRS context. DB2 uses the RRS context services function Retrieve Context Data (CTXRDTA) to retrieve context data that contains the authorization ID and ACEE address. The context data must have the following format: Version number A 4-byte area that contains the version number of the context data. Set this area to 1. Server product name An 8-byte area that contains the name of the server product that set the context data. ALET A 4-byte area that can contain an ALET value. DB2 does not reference this area. ACEE address A 4-byte area that contains an ACEE address or 0 if an ACEE is not provided. DB2 requires that the ACEE is in the home address space of the task. If you pass an ACEE address, the CONTEXT SIGNON function uses the value in ACEEGRPN as the secondary authorization ID if the length of the group name (ACEEGRPL) is not 0. 100 Application Programming and SQL Guide
  • 117.
    primary-authid An 8-byte areathat contains the primary authorization ID to be used. If the authorization ID is less than 8 bytes in length, pad it on the right with blank characters to a length of 8 bytes. If the new primary authorization ID is not different than the current primary authorization ID (which was established when the IDENTIFY function was invoked or at a previous SIGNON invocation), DB2 invokes only the signon exit. If the value has changed, DB2 establishes a new primary authorization ID and new SQL authorization ID and then invokes the signon exit. Generally, you issue a CONTEXT SIGNON call after an IDENTIFY call and before a CREATE THREAD call. You can also issue a CONTEXT SIGNON call if the application is at a point of consistency, and one of the following conditions is true: v The value of reuse in the CREATE THREAD call was RESET. v The value of reuse in the CREATE THREAD call was INITIAL, no held cursors are open, the package or plan is bound with KEEPDYNAMIC(NO), and all special registers are at their initial state. If open held cursors exist or the package or plan is bound with KEEPDYNAMIC(YES), a SIGNON call is permitted only if the primary authorization ID has not changed. The following diagram shows the syntax for the CONTEXT SIGNON function. DSNRLI CONTEXT SIGNON function CALL DSNRLI ( function, correlation-id, accounting-token, accounting-interval, context-key ) ,retcode ,reascode ,user ,appl ,ws ,xid ,accounting-string Parameters point to the following areas: function An 18-byte area that contains CONTEXT SIGNON followed by four blanks. correlation-id A 12-byte area in which you can put a DB2 correlation ID. The correlation ID is displayed in DB2 accounting and statistics trace records. You can use the correlation ID to correlate work units. This token appears in output from the DISPLAY THREAD command. If you do not want to specify a correlation ID, fill the 12-byte area with blanks. accounting-token A 22-byte area in which you can put a value for a DB2 accounting token. This value is displayed in DB2 accounting and statistics trace records in the QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. Setting the value of the accounting token sets the value of the CURRENT CLIENT_ACCTNG special register. If accounting-token is less than 22 characters Chapter 2. Connecting to DB2 from your application program 101
  • 118.
    long, you mustpad it on the right with blanks to a length of 22 characters. If you do not want to specify an accounting token, fill the 22-byte area with blanks. You can also change the value of the DB2 accounting token with RRSAF functions SIGNON, AUTH SIGNON, or SET_CLIENT_ID. You can retrieve the DB2 accounting token with the CURRENT CLIENT_ACCTNG special register only if the DDF accounting string is not set. accounting-interval A 6-byte area that specifies when DB2 writes an accounting record. If you specify COMMIT in that area, DB2 writes an accounting record each time that the application issues SRRCMIT without open held cursors. If the accounting interval is COMMIT and an SRRCMIT is issued while a held cursor is open, the accounting interval spans that commit and ends at the next valid accounting interval end point (such as the next SRRCMIT that is issued without open held cursors, application termination, or SIGNON with a new authorization ID). | | | | | | | If you specify any other value, DB2 writes an accounting record when the application terminates or when you call the SIGNON function with a new authorization ID. context-key A 32-byte area in which you put the context key that you specified when you called the RRS Set Context Data (CTXSDTA) service to save the primary authorization ID and an optional ACEE address. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode. user A 16-byte area that contains the user ID of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays this user ID in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the user ID sets the value of the CURRENT CLIENT_USERID special register. If user is less than 16 characters long, you must pad it on the right with blanks to a length of 16 characters. This parameter is optional. If you specify user, you must also specify retcode and reascode. If you do not specify user, no user ID is associated with the connection. appl A 32-byte area that contains the application or transaction name of the end user’s application. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays the application name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the application name sets 102 Application Programming and SQL Guide
  • 119.
    the value ofthe CURRENT CLIENT_APPLNAME special register. If appl is less than 32 characters long, you must pad it on the right with blanks to a length of 32 characters. This parameter is optional. If you specify appl, you must also specify retcode, reascode, and user. If you do not specify appl, no application or transaction is associated with the connection. ws An 18-byte area that contains the workstation name of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 displays the workstation name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. Setting the workstation name sets the value of the CURRENT CLIENT_WRKSTNNAME special register. If ws is less than 18 characters long, you must pad it on the right with blanks to a length of 18 characters. This parameter is optional. If you specify ws, you must also specify retcode, reascode, user, and appl. If you do not specify ws, no workstation name is associated with the connection. You can also change the value of the workstation name with the RRSAF functions SIGNON, AUTH SIGNON, or SET_CLIENT_ID. You can retrieve the workstation name with the CLIENT_WRKSTNNAME special register. xid A 4-byte area that indicates whether the thread is part of a global transaction. A DB2 thread that is part of a global transaction can share locks with other DB2 threads that are part of the same global transaction and can access and modify the same data. A global transaction exists until one of the threads that is part of the global transaction is committed or rolled back. You can specify one of the following values for xid: 0 Indicates that the thread is not part of a global transaction. The value 0 must be specified as a binary integer. 1 Indicates that the thread is part of a global transaction and that DB2 should retrieve the global transaction ID from RRS. If a global transaction ID already exists for the task, the thread becomes part of the associated global transaction. Otherwise, RRS generates a new global transaction ID. The value 1 must be specified as a binary integer. Alternatively, if you want DB2 to return the generated global transaction ID to the caller, specify an address instead of 1. address The 4-byte address of an area into which you enter a global transaction ID for the thread. If the global transaction ID already exists, the thread becomes part of the associated global transaction. Otherwise, RRS creates a new global transaction with the ID that you specify. Alternatively, if you want DB2 to generate and return a global transaction ID, pass the address of a null global transaction ID by setting the format ID field of the global transaction ID to binary -1 (’FFFFFFF’X). DB2 then replaces the contents of the area with the generated transaction ID. The area at the specified address must be in writable storage and have a length of at least 140 bytes to accommodate the largest possible transaction ID value. The format of a global transaction ID is shown in the description of the RRSAF SIGNON function. Chapter 2. Connecting to DB2 from your application program 103
  • 120.
    accounting-string A one-byte lengthfield and a 255-byte area in which you can put a value for a DB2 accounting string. This value is placed in the DDF accounting trace records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If accounting-string is less than 255 characters, you must pad it on the right with zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA DSECT. This parameter is optional. If you specify this accounting-string, you must also specify retcode, reascode, user, appl and xid. If you do not specify this parameter, no accounting string is associated with the connection. You can also change the value of the accounting string with RRSAF functions AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID. You can retrieve the DDF suffix portion of the accounting string with the CURRENT CLIENT_ACCTNG special register. The suffix portion of accounting-string can contain a maximum of 200 characters. The QMDASFLN field contains the accounting suffix length, and the QMDASUFX field contains the accounting suffix value. If the DDF accounting string is set, you cannot query the accounting token with the CURRENT CLIENT_ACCTNG special register. Example of RRSAF CONTEXT SIGNON calls The following table shows a CONTEXT SIGNON call in each language. Table 30. Examples of RRSAF CONTEXT SIGNON calls Language Call example Assembler CALL DSNRLI,(CSGNONFN,CORRID,ACCTTKN,ACCTINT,CTXTKEY, RETCODE,REASCODE,USERID,APPLNAME, WSNAME,XIDPTR) C1 fnret=dsnrli(&csgnonfn[0], &corrid[0], &accttkn[0], &acctint[0], &ctxtkey[0], &retcode, &reascode, &userid[0], &applname[0], &wsname[0], &xidptr); COBOL CALL ’DSNRLI’ USING CSGNONFN CORRID ACCTTKN ACCTINT CTXTKEY RETCODE REASCODE USERID APPLNAME WSNAME XIDPTR. Fortran CALL DSNRLI(CSGNONFN,CORRID,ACCTTKN,ACCTINT,CTXTKEY, RETCODE,REASCODE, USERID,APPLNAME, WSNAME,XIDPTR) PL/I1 CALL DSNRLI(CSGNONFN,CORRID,ACCTTKN,ACCTINT,CTXTKEY, RETCODE,REASCODE,USERID,APPLNAME, WSNAME,XIDPTR); Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 Related reference “SIGNON function for RRSAF” on page 92 SET_ID function for RRSAF The RRSAF SET_ID function sets a new value for the client program ID that can be used to identify the end user. The function then passes this information to DB2 when the next SQL request is processed. The following diagram shows the syntax of the SET_ID function. 104 Application Programming and SQL Guide
  • 121.
    DSNRLI SET_ID function CALLDSNRLI ( function, program-id ) , retcode , reascode Parameters point to the following areas: function An 18-byte area that contains SET_ID followed by 12 blanks. program-id An 80-byte area that contains the caller-provided string to be passed to DB2. If program-id is less than 80 characters, you must pad it with blanks on the right to a length of 80 characters. DB2 places the contents of program-id into IFCID 316 records, along with other statistics, so that you can identify which program is associated with a particular SQL statement. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode. Example of RRSAF SET_ID calls The following table shows a SET_ID call in each language. Table 31. Examples of RRSAF SET_ID calls Language Call example Assembler CALL C 1 DSNRLI,(SETIDFN,PROGID,RETCODE,REASCODE) fnret=dsnrli(&setidfn[0], &progid[0], &retcode, &reascode); COBOL CALL ’DSNRLI’ USING SETIDFN PROGID RETCODE REASCODE. Fortran CALL DSNRLI(SETIDFN,PROGID,RETCODE,REASCODE) CALL DSNRLI(SETIDFN,PROGID,RETCODE,REASCODE); PL/I 1 Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 Chapter 2. Connecting to DB2 from your application program 105
  • 122.
    SET_CLIENT_ID function forRRSAF The RRSAF SET_CLIENT_ID function sets new values for the client user ID, the application program name, the workstation name, the accounting token, and the DDF client accounting string. The function then passes this information to DB2 when the next SQL request is processed. These values can be used to identify the end user. The calling program defines the contents of these parameters. DB2 places the parameter values in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. The following diagram shows the syntax of the SET_CLIENT_ID function. DSNRLI SET_CLIENT_ID function CALL DSNRLI ( function, accounting-token, user, appl, ws ) ,retcode ,reascode ,accounting-string Parameters point to the following areas: function An 18-byte area that contains SET_CLIENT_ID followed by 5 blanks. accounting-token A 22-byte area in which you can put a value for a DB2 accounting token. This value is placed in the DB2 accounting and statistics trace records in the QWHCTOKEN field, which is mapped by DSNDQWHC DSECT. If accounting-token is less than 22 characters long, you must pad it on the right with blanks to a length of 22 characters. You can omit this parameter by specifying a value of 0 in the parameter list. Alternatively, you can change the value of the DB2 accounting token with the RRSAF functions SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can retrieve the DB2 accounting token with the CURRENT CLIENT_ACCTNG special register only if the DDF accounting string is not set. user A 16-byte area that contains the user ID of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 places this user ID in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. If user is less than 16 characters long, you must pad it on the right with blanks to a length of 16 characters. You can omit this parameter by specifying a value of 0 in the parameter list. You can also change the value of the client user ID with the RRSAF functions SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can retrieve the client user ID with the CLIENT_USERID special register. 106 Application Programming and SQL Guide
  • 123.
    appl An 32-byte areathat contains the application or transaction name of the end user’s application. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 places the application name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. If appl is less than 32 characters, you must pad it on the right with blanks to a length of 32 characters. You can omit this parameter by specifying a value of 0 in the parameter list. You can also change the value of the application name with the RRSAF functions SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can retrieve the application name with the CLIENT_APPLNAME special register. ws An 18-byte area that contains the workstation name of the client end user. You can use this parameter to provide the identity of the client end user for accounting and monitoring purposes. DB2 places this workstation name in the output from the DISPLAY THREAD command and in DB2 accounting and statistics trace records. If ws is less than 18 characters, you must pad it on the right with blanks to a length of 18 characters. You can omit this parameter by specifying a value of 0 in the parameter list. You can also change the value of the workstation name with the RRSAF functions SIGNON, AUTH SIGNON, or CONTEXT SIGNON. You can retrieve the workstation name with the CLIENT_WRKSTNNAME special register. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode. accounting-string A one-byte length field and a 255-byte area in which you can put a value for a DB2 accounting string. This value is placed in the DDF accounting trace records in the QMDASQLI field, which is mapped by DSNDQMDA DSECT. If accounting-string is less than 255 characters, you must pad it on the right with zeros to a length of 255 bytes. The entire 256 bytes is mapped by DSNDQMDA DSECT. This parameter is optional. If you specify this accounting-string, you must also specify retcode, reascode, user, appl and xid. If you do not specify this parameter, no accounting string is associated with the connection. You can also change the value of the accounting string with RRSAF functions AUTH SIGNON, CONTEXT SIGNON, or SET_CLIENT_ID. You can retrieve the DDF suffix portion of the accounting string with the CURRENT CLIENT_ACCTNG special register. The suffix portion of accounting-string can contain a maximum of 200 characters. The QMDASFLN field contains the accounting suffix length, and the QMDASUFX field contains the accounting suffix value. If the DDF accounting string is set, you cannot query the accounting token with the CURRENT CLIENT_ACCTNG special register. Chapter 2. Connecting to DB2 from your application program 107
  • 124.
    Example of RRSAFSET_CLIENT_ID calls The following table shows a SET_CLIENT_ID call in each language. Table 32. Examples of RRSAF SET_CLIENT_ID calls Language Call example Assembler CALL C 1 DSNRLI,(SECLIDFN,ACCT,USER,APPL,WS,RETCODE,REASCODE) fnret=dsnrli(&seclidfn[0], &acct[0], &user[0], &appl[0], &ws[0], &retcode, &reascode); COBOL CALL ’DSNRLI’ USING SECLIDFN ACCT USER APPL WS RETCODE REASCODE. Fortran CALL DSNRLI(SECLIDFN,ACCT,USER,APPL,WS,RETCODE,REASCODE) CALL DSNRLI(SECLIDFN,ACCT,USER,APPL,WS,RETCODE,REASCODE); PL/I 1 Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 CREATE THREAD function for RRSAF The RRSAF CREATE THREAD function allocates the DB2 resources that are required for an application to issue SQL or IFI requests. This function must complete before the application can execute SQL statements or IFI requests. The following diagram shows the syntax of the CREATE THREAD function. DSNRLI CREATE THREAD function CALL DSNRLI ( function, plan, collection, reuse ) , retcode , reascode , pklistptr Parameters point to the following areas: function An 18-byte area that contains CREATE THREAD followed by five blanks. plan An 8-byte DB2 plan name. RRSAF allocates the named plan. If you provide a collection name instead of a plan name, specify the question mark character (?) in the first byte of this field. DB2 then allocates a special plan named ?RRSAF and uses the value that you specify for collection . When DB2 allocates a plan named ?RRSAF, DB2 checks authorization to execute the package in the same way as it checks authorization to execute a package from a requester other than DB2 for z/OS. 108 Application Programming and SQL Guide
  • 125.
    If you donot provide a collection name in the collection field, you must enter a valid plan name in this field. collection An 18-byte area in which you enter a collection name. DB2 uses the collection names to locate a package that is associated with the first SQL statement in the program. When you provide a collection name and put the question mark character (?) in the plan field, DB2 allocates a plan named ?RRSAF and a package list that contains the following two entries: v The specified collection name. v An entry that contains * for the location, collection name, and package name. (This entry lets the application access remote locations and access packages in collections other than the default collection that is specified at create thread time.) The application can use the SET CURRENT PACKAGESET statement to change the collection ID that DB2 uses to locate a package. If you provide a plan name in the plan field, DB2 ignores the value in the collection field. reuse An 8-byte area that controls the action that DB2 takes if a SIGNON call is issued after a CREATE THREAD call. Specify one of the following values in this field: RESET Releases any held cursors and reinitializes the special registers INITIAL Does not allow the SIGNON call This parameter is required. If the 8-byte area does not contain either RESET or INITIAL, the default value is INITIAL. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode. pklistptr A 4-byte field that contains a pointer to a user-supplied data area that contains a list of collection IDs. A collection ID is an SQL identifier of 1 to 128 letters, digits, or the underscore character that identifies a collection of packages. The length of the data area is a maximum of 2050 bytes. The data area contains a 2-byte length field, followed by up to 2048 bytes of collection ID entries, separated by commas. When you specify pklistptr and the question mark character (?) in the plan field, DB2 allocates a special plan named ?RRSAF and a package list that contains the following entries: Chapter 2. Connecting to DB2 from your application program 109
  • 126.
    v The collectionnames that you specify in the data area to which pklistptr points v An entry that contains * for the location, collection ID, and package name If you also specify collection, DB2 ignores that value. Each collection entry must be of the form collection-ID.*, *.collection-ID.*, or *.*.*. collection-ID and must follow the naming conventions for a collection ID, as described in the description of the BIND and REBIND options. DB2 uses the collection names to locate a package that is associated with the first SQL statement in the program. The entry that contains *.*.* lets the application access remote locations and access packages in collections other than the default collection that is specified at create thread time. The application can use the SET CURRENT PACKAGESET statement to change the collection ID that DB2 uses to locate a package. This parameter is optional. If you specify this parameter, you must also specify retcode and reascode. If you provide a plan name in the plan field, DB2 ignores the pklistptr value. Recommendation: Using a package list can have a negative impact on performance. For better performance, specify a short package list. Example of RRSAF CREATE THREAD calls The following table shows a CREATE THREAD call in each language. Table 33. Examples of RRSAF CREATE THREAD calls Language Call example Assembler CALL C 1 DSNRLI,(CRTHRDFN,PLAN,COLLID,REUSE,RETCODE,REASCODE,PKLISTPTR) fnret=dsnrli(&crthrdfn[0], &plan[0], &collid[0], &reuse[0], &retcode, &reascode, &pklistptr); COBOL CALL ’DSNRLI’ USING CRTHRDFN PLAN COLLID REUSE RETCODE REASCODE PKLSTPTR. Fortran CALL DSNRLI(CRTHRDFN,PLAN,COLLID,REUSE,RETCODE,REASCODE,PKLSTPTR) CALL DSNRLI(CRTHRDFN,PLAN,COLLID,REUSE,RETCODE,REASCODE,PKLSTPTR); PL/I 1 Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 ″Authorizing plan or package access through applications″ (DB2 Administration Guide) Related reference ″BIND and REBIND options″ (DB2 Command Reference) TERMINATE THREAD function for RRSAF The RRSAF TERMINATE THREAD function deallocates DB2 resources that are associated with a plan and were previously allocated for an application by the 110 Application Programming and SQL Guide
  • 127.
    CREATE THREAD function.You can then use the CREATE THREAD function to allocate another plan with the same connection. If you call the TERMINATE THREAD function and the application is not at a point of consistency, RRSAF returns reason code X’00C12211’. The following diagram shows the syntax of the TERMINATE THREAD function. DSNRLI TERMINATE THREAD function CALL DSNRLI ( function, ) , retcode , reascode Parameters point to the following areas: function An 18-byte area the contains TERMINATE THREAD followed by two blanks. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode. Example of RRSAF TERMINATE THREAD calls The following table shows a TERMINATE THREAD call in each language. Table 34. Examples of RRSAF TERMINATE THREAD calls Language Call example Assembler CALL C 1 DSNRLI,(TRMTHDFN,RETCODE,REASCODE) fnret=dsnrli(&trmthdfn[0], &retcode, &reascode); COBOL CALL ’DSNRLI’ USING TRMTHDFN RETCODE REASCODE. Fortran CALL DSNRLI(TRMTHDFN,RETCODE,REASCODE) CALL DSNRLI(TRMTHDFN,RETCODE,REASCODE); PL/I 1 Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 Chapter 2. Connecting to DB2 from your application program 111
  • 128.
    TERMINATE IDENTIFY functionfor RRSAF The RRSAF TERMINATE IDENTIFY function terminates a connection to DB2. Calling the TERMINATE IDENTIFY function is optional. If you do not call it, DB2 performs the same functions when the task terminates. If DB2 terminates, the application must issue TERMINATE IDENTIFY to reset the RRSAF control blocks. This action ensures that future connection requests from the task are successful when DB2 restarts. The TERMINATE IDENTIFY function removes the calling task’s connection to DB2. If no other task in the address space has an active connection to DB2, DB2 also deletes the control block structures that were created for the address space and removes the cross-memory authorization. If the application is not at a point of consistency when you call the TERMINATE IDENTIFY function, RRSAF returns reason code X’00C12211’. If the application allocated a plan, and you call the TERMINATE IDENTIFY function without first calling the TERMINATE THREAD function, DB2 deallocates the plan before terminating the connection. The following diagram shows the syntax of the TERMINATE IDENTIFY function. DSNRLI TERMINATE IDENTIFY function CALL DSNRLI ( function ) , retcode , reascode Parameters point to the following areas: function An 18-byte area that contains TERMINATE IDENTIFY. retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode. Example of RRSAF TERMINATE IDENTIFY calls The following table shows a TERMINATE IDENTIFY call in each language. 112 Application Programming and SQL Guide
  • 129.
    Table 35. Examplesof RRSAF TERMINATE IDENTIFY calls Language Call example Assembler CALL C 1 DSNRLI,(TMIDFYFN,RETCODE,REASCODE) fnret=dsnrli(&tmidfyfn[0], &retcode, &reascode); COBOL CALL ’DSNRLI’ USING TMIDFYFN RETCODE REASCODE. Fortran CALL DSNRLI(TMIDFYFN,RETCODE,REASCODE) CALL DSNRLI(TMIDFYFN,RETCODE,REASCODE); PL/I 1 Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 TRANSLATE function for RRSAF The RRSAF TRANSLATE function converts a hexadecimal reason code for a DB2 error into a signed integer SQL code and a printable error message. The SQL code and message text are placed in the SQLCODE and SQLSTATE host variables or related fields of the SQLCA. Consider the following rules and recommendations about when to use and not use the TRANSLATE function: v You cannot call the TRANSLATE function from the Fortran language. v Call the TRANSLATE function only after a successful IDENTIFY operation. For errors that occur during SQL or IFI requests, the TRANSLATE function performs automatically. v The TRANSLATE function translates codes that begin with X’00F3’, but it does not translate RRSAF reason codes that begin with X’00C1’. If you receive error reason code X’00F30040’ (resource unavailable) after an OPEN request, the TRANSLATE function returns the name of the unavailable database object in the last 44 characters of the SQLERRM field. If the TRANSLATE function does not recognize the error reason code, it returns SQLCODE -924 (SQLSTATE ’58006’) and places a printable copy of the original DB2 function code and the return and error reason codes in the SQLERRM field. The contents of registers 0 and 15 do not change, unless TRANSLATE fails. In this case, register 0 is set to X’00C12204’, and register 15 is set to 200. The following diagram shows the syntax of the TRANSLATE function. DSNRLI TRANSLATE function CALL DSNRLI ( function, sqlca ) , retcode , reascode Chapter 2. Connecting to DB2 from your application program 113
  • 130.
    Parameters point tothe following areas: function An 18-byte area that contains the word TRANSLATE followed by nine blanks. sqlca The program’s SQL communication area (SQLCA). retcode A 4-byte area in which RRSAF places the return code. This parameter is optional. If you do not specify retcode, RRSAF places the return code in register 15 and the reason code in register 0. reascode A 4-byte area in which RRSAF places the reason code. This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. If you specify reascode, you must also specify retcode. Example of RRSAF TRANSLATE calls The following table shows a TRANSLATE call in each language. Table 36. Examples of RRSAF TRANSLATE calls Language Call example Assembler CALL C 1 fnret=dsnrli(&connfn[0], &sqlca, &retcode, &reascode); COBOL PL/I DSNRLI,(XLATFN,SQLCA,RETCODE,REASCODE) 1 CALL ’DSNRLI’ USING XLATFN SQLCA RETCODE REASCODE. CALL DSNRLI(XLATFN,SQLCA,RETCODE,REASCODE); Note: 1. For C, C++, and PL/I applications, you must include the appropriate compiler directives, because DSNRLI is an assembler language program. These compiler directives are described in the instructions for invoking RRSAF. Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 | | | FIND_DB2_SYSTEMS function for RRSAF | The following diagram shows the syntax of the FIND_DB2_SYSTEMS function. The RRSAF FIND_DB2_SYSTEMS function identifies all active DB2 subsystems on a z/OS LPAR. | 114 Application Programming and SQL Guide
  • 131.
    | | | | | DSNRLI FIND_DB2_SYSTEMS function CALLDSNRLI ( function , ssnma , activea , arraysz , ) , retcode , reascode | | | | Parameters point to the following areas: | | function An 18-byte area that contains FIND_DB2_SYSTEMS followed by two blanks. | | | | | | ssnma A storage area for an array of 4-byte character strings into which RRSAF places the names of all the DB2 subsystems (SSIDs) that are defined for the current LPAR. You must provide the storage area. If the array is larger than the number of DB2 subsystems, RRSAF returns the value ’ ’ (four blanks) in all unused array members. | | | | | | | activea A storage area for an array of 4-byte values into which RRSAF returns an indication of whether a defined subsystem is active. Each value is represented as a fixed 31-bit integer. The value 1 means that the subsystem is active. The value 0 means that the subsystem is not active. The size of this array must be the same as the size of the ssnma array. If the array is larger than the number of DB2 subsystems, RRSAF returns the value -1 in all unused array members. | | The information in the activea array is the information that is available at the point in time that you requested it and might change at any time. | | | | | arraysz A 4-byte area, represented as a fixed 31-bit integer, that specifies the number of entries for the ssnma and activea arrays. If the number of array entries is insufficient to contain all of the subsystems defined on the current LPAR, RRSAF uses all available entries and returns return code 4. | | | retcode A 4-byte area in which RRSAF is to place the return code for this call to the FIND_DB2_SYSTEMS function. | | This parameter is optional. If you do not retcode, RRSAF places the return code in register 15 and the reason code in register 0. | | | reascode A 4-byte area in which RRSAF is to place the reason code for this call to the FIND_DB2_SYSTEMS function. | | This parameter is optional. If you do not specify reascode, RRSAF places the reason code in register 0. | Example values that the FIND_DB2_SYSTEMS function returns | | | | Assume that two subsystems are defined on the current LPAR. Subsystem DB2A is active, and subsystem DB2B is stopped. Suppose that you invoke RRSAF with the function FIND_DB2_SYSTEMS and a value of 3 for arraysz. The ssnma array and activea array are set to the following values: Chapter 2. Connecting to DB2 from your application program 115
  • 132.
    | Table 37. Examplevalues returned in the ssnma and activeaarrays | Array element number Values in ssnma array Values in activea array | 1 DB2A 1 | 2 DB2B 0 | | | | 3 (four blanks) -1 Related tasks “Invoking the Resource Recovery Services attachment facility” on page 75 RRSAF return codes and reason codes If you specify return code and reason code parameters in an RRSAF function call, RRSAF returns the return code and reason code in those parameters. If you do not specify those parameters or implicitly invoke RRSAF, RRSAF puts the return code in register 15 and the reason code in register 0. When the reason code begins with X’00F3’, except for X’00F30006’, you can use the RRSAF TRANSLATE function to obtain error message text that can be printed and displayed. For SQL calls, RRSAF returns standard SQL return codes in the SQLCA. RRSAF returns IFI return codes and reason codes in the instrumentation facility communication area (IFCA). The following table lists the RRSAF return codes. Table 38. RRSAF return codes Return code Explanation 0 The call completed successfully. 4 Status information is available. See the reason code for details. >4 The call failed. See the reason code for details. Related reference “TRANSLATE function for RRSAF” on page 113 Sample RRSAF scenarios One or more tasks can use RRSAF to connect to DB2. This connection can be made either implicitly or explicitly. For explicit connections, a task calls one or more of the RRSAF connection functions. A single task The following example pseudocode illustrates a single task running in an address space that explicitly connects to DB2 through RRSAF. z/OS RRS controls commit processing when the task terminates normally. IDENTIFY SIGNON CREATE THREAD SQL or IFI . . . TERMINATE IDENTIFY 116 Application Programming and SQL Guide
  • 133.
    Multiple tasks In thefollowing scenario, multiple tasks in an address space explicitly connect to DB2 through RRSAF. Task 1 executes no SQL statements and makes no IFI calls. Its purpose is to monitor DB2 termination and startup ECBs and to check the DB2 release level. TASK 1 TASK 2 TASK 3 TASK n IDENTIFY IDENTIFY SIGNON CREATE THREAD SQL ... SRRCMIT SQL ... SRRCMIT ... IDENTIFY SIGNON CREATE THREAD SQL ... SRRCMIT SQL ... SRRCMIT ... IDENTIFY SIGNON CREATE THREAD SQL ... SRRCMIT SQL ... SRRCMIT ... TERMINATE IDENTIFY Reusing a DB2 thread The following example pseudocode shows a DB2 thread that is reused by another user at a point of consistency. When the application calls the SIGNON function for user B, DB2 reuses the plan that is allocated by the CREATE THREAD function for user A. IDENTIFY SIGNON user A CREATE THREAD SQL ... SRRCMIT SIGNON user B SQL ... SRRCMIT Switching DB2 threads between tasks The following scenario shows how you can switch the threads for four users (A, B, C, and D) among two tasks (1 and 2). Task 1 Task 2 CTXBEGC (create context a) CTXSWCH(a,0) IDENTIFY SIGNON user A CREATE THREAD (Plan A) SQL ... CTXSWCH(0,a) CTXBEGC (create context b) CTXSWCH(b,0) IDENTIFY SIGNON user B CREATE THREAD (plan B) SQL ... CTXSWCH(0,b) CTXBEGC (create context c) CTXSWCH(c,0) IDENTIFY SIGNON user C CREATE THREAD (plan C) SQL ... CTXSWCH(b,c) CTXBEGC (create context d) CTXSWCH(d,0) IDENTIFY SIGNON user D CREATE THREAD (plan D) SQL ... CTXSWCH(0,d) Chapter 2. Connecting to DB2 from your application program 117
  • 134.
    SQL (plan B) ... ... CTXSWCH(a,0) SQL(plan A) The applications perform the following steps: v Task 1 creates context a, switches contexts so that context a is active for task 1, and calls the IDENTIFY function to initialize a connection to a subsystem. A task must always call the IDENTIFY function before a context switch can occur. After the IDENTIFY operation is complete, task 1 allocates a thread for user A, and performs SQL operations. At the same time, task 2 creates context b, switches contexts so that context b is active for task 2, calls the IDENTIFY function to initialize a connection to the subsystem, allocates a thread for user B, and performs SQL operations. When the SQL operations complete, both tasks perform RRS context switch operations. Those operations disconnect each DB2 thread from the task under which it was running. v Task 1 then creates context c, calls the IDENTIFY function to initialize a connection to the subsystem, switches contexts so that context c is active for task 1, allocates a thread for user C, and performs SQL operations for user C. Task 2 does the same operations for user D. v When the SQL operations for user C complete, task 1 performs a context switch operation to perform the following actions: – Switch the thread for user C away from task 1. – Switch the thread for user B to task 1. For a context switch operation to associate a task with a DB2 thread, the DB2 thread must have previously performed an IDENTIFY operation. Therefore, before the thread for user B can be associated with task 1, task 1 must have performed an IDENTIFY operation. v Task 2 performs two context switch operations to perform the following actions: – Disassociate the thread for user D from task 2. – Associate the thread for user A with task 2. Program examples for RRSAF The Resource Recovery Services attachment facility (RRSAF) enables programs to communicate with DB2. You can use RRSAF as an alternative to CAF. Example JCL for invoking RRSAF The following sample JCL shows how to use RRSAF in a batch environment. The DSNRRSAF DD statement starts the RRSAF trace. Use that DD statement only if you are diagnosing a problem. //jobname //RRSJCL //STEPLIB // JOB EXEC DD DD z/OS_jobcard_information PGM=RRS_application_program DSN=application_load_library DSN=DB2_load_library DD DD DD SYSOUT=* DUMMY SYSOUT=* . . . //SYSPRINT //DSNRRSAF //SYSUDUMP 118 Application Programming and SQL Guide
  • 135.
    Example of loadingand deleting the RRSAF language interface The following code segment shows how an application loads entry points DSNRLI and DSNHLIR of the RRSAF language interface. Storing the entry points in variables LIRLI and LISQL ensures that the application loads the entry points only once. Delete the loaded modules when the application no longer needs to access DB2. ****************************** GET LANGUAGE INTERFACE ENTRY ADDRESSES LOAD EP=DSNRLI Load the RRSAF service request EP ST R0,LIRLI Save this for RRSAF service requests LOAD EP=DSNHLIR Load the RRSAF SQL call Entry Point ST R0,LISQL Save this for SQL calls * . * . Insert connection service requests and SQL calls here * . DELETE EP=DSNRLI Correctly maintain use count DELETE EP=DSNHLIR Correctly maintain use count Example of using dummy entry point DSNHLI for RRSAF Each of the DB2 attachment facilities contains an entry point named DSNHLI. When you use RRSAF but do not specify the ATTACH(RRSAF) precompiler option, the precompiler generates BALR instructions to DSNHLI for SQL statements in your program. To find the correct DSNHLI entry point without including DSNRLI in your load module, code a subroutine, with entry point DSNHLI, that passes control to entry point DSNHLIR in the DSNRLI module. DSNHLIR is unique to DSNRLI and is at the same location as DSNHLI in DSNRLI. DSNRLI uses 31-bit addressing. If the application that calls this intermediate subroutine uses 24-bit addressing, the intermediate subroutine must account for the difference. In the following example, LISQL is addressable because the calling CSECT used the same register 12 as CSECT DSNHLI. Your application must also establish addressability to LISQL. *********************************************************************** * Subroutine DSNHLI intercepts calls to LI EP=DSNHLI *********************************************************************** DS 0D DSNHLI CSECT Begin CSECT STM R14,R12,12(R13) Prologue LA R15,SAVEHLI Get save area address ST R13,4(,R15) Chain the save areas ST R15,8(,R13) Chain the save areas LR R13,R15 Put save area address in R13 L R15,LISQL Get the address of real DSNHLI BASSM R14,R15 Branch to DSNRLI to do an SQL call * DSNRLI is in 31-bit mode, so use * BASSM to assure that the addressing * mode is preserved. L R13,4(,R13) Restore R13 (caller’s save area addr) L R14,12(,R13) Restore R14 (return address) RETURN (1,12) Restore R1-12, NOT R0 and R15 (codes) Example of connecting to DB2 with RRSAF This example uses the variables that are declared in the following code. ****************** VARIABLES SET BY APPLICATION *********************** LIRLI DS F DSNRLI entry point address LISQL DS F DSNHLIR entry point address SSNM DS CL4 DB2 subsystem name for IDENTIFY Chapter 2. Connecting to DB2 from your application program 119
  • 136.
    CORRID DS CL12 Correlation ID forSIGNON ACCTTKN DS CL22 Accounting token for SIGNON ACCTINT DS CL6 Accounting interval for SIGNON PLAN DS CL8 DB2 plan name for CREATE THREAD COLLID DS CL18 Collection ID for CREATE THREAD. If * PLAN contains a plan name, not used. REUSE DS CL8 Controls SIGNON after CREATE THREAD CONTROL DS CL8 Action that application takes based * on return code from RRSAF ****************** VARIABLES SET BY DB2 ******************************* STARTECB DS F DB2 startup ECB TERMECB DS F DB2 termination ECB EIBPTR DS F Address of environment info block RIBPTR DS F Address of release info block ****************************** CONSTANTS ****************************** CONTINUE DC CL8’CONTINUE’ CONTROL value: Everything OK IDFYFN DC CL18’IDENTIFY ’ Name of RRSAF service SGNONFN DC CL18’SIGNON ’ Name of RRSAF service CRTHRDFN DC CL18’CREATE THREAD ’ Name of RRSAF service TRMTHDFN DC CL18’TERMINATE THREAD ’ Name of RRSAF service TMIDFYFN DC CL18’TERMINATE IDENTIFY’ Name of RRSAF service ****************************** SQLCA and RIB ************************** EXEC SQL INCLUDE SQLCA DSNDRIB Map the DB2 Release Information Block ******************* Parameter list for RRSAF calls ******************** RRSAFCLL CALL ,(*,*,*,*,*,*,*,*),VL,MF=L The following example code shows how to issue requests for the RRSAF functions IDENTIFY, SIGNON, CREATE THREAD, TERMINATE THREAD, and TERMINATE IDENTIFY. This example does not show a task that waits on the DB2 termination ECB. You can code such a task and use the z/OS WAIT macro to monitor the ECB. The task that waits on the termination ECB should detach the sample code if the termination ECB is posted. That task can also wait on the DB2 startup ECB. This example waits on the startup ECB at its own task level. ***************************** IDENTIFY ******************************** L R15,LIRLI Get the Language Interface address CALL (15),(IDFYFN,SSNM,RIBPTR,EIBPTR,TERMECB,STARTECB),VL,MF=X (E,RRSAFCLL) BAL R14,CHEKCODE Call a routine (not shown) to check * return and reason codes CLC CONTROL,CONTINUE Is everything still OK BNE EXIT If CONTROL not ’CONTINUE’, stop loop USING R8,RIB Prepare to access the RIB L R8,RIBPTR Access RIB to get DB2 release level WRITE ’The current DB2 release level is’ RIBREL ***************************** SIGNON ********************************** L R15,LIRLI Get the Language Interface address CALL (15),(SGNONFN,CORRID,ACCTTKN,ACCTINT),VL,MF=(E,RRSAFCLL) BAL R14,CHEKCODE Check the return and reason codes *************************** CREATE THREAD ***************************** L R15,LIRLI Get the Language Interface address CALL (15),(CRTHRDFN,PLAN,COLLID,REUSE),VL,MF=(E,RRSAFCLL) BAL R14,CHEKCODE Check the return and reason codes ****************************** SQL ************************************ * Insert your SQL calls here. The DB2 Precompiler * generates calls to entry point DSNHLI. You should * code a dummy entry point of that name to intercept * all SQL calls. A dummy DSNHLI is shown in the following * section. ************************ TERMINATE THREAD ***************************** CLC CONTROL,CONTINUE Is everything still OK? BNE EXIT If CONTROL not ’CONTINUE’, shut down L R15,LIRLI Get the Language Interface address CALL (15),(TRMTHDFN),VL,MF=(E,RRSAFCLL) BAL R14,CHEKCODE Check the return and reason codes 120 Application Programming and SQL Guide
  • 137.
    ************************ TERMINATE IDENTIFY*************************** CLC CONTROL,CONTINUE Is everything still OK BNE EXIT If CONTROL not ’CONTINUE’, stop loop L R15,LIRLI Get the Language Interface address CALL (15),(TMIDFYFN),VL,MF=(E,RRSAFCLL) BAL R14,CHEKCODE Check the return and reason codes Controlling the CICS attachment facility from an application Use the CICS attachment facility to access DB2 from CICS application programs. You can start and stop the CICS attachment facility from within an application program. To control the CICS attachment facility: 1. To start the CICS attachment facility, perform one of the following actions: v Include the following statement in your application: EXEC CICS LINK PROGRAM(’DSN2COM0’) v Use the system programming interface SET DB2CONN for the CICS Transaction Server. 2. To stop the CICS attachment facility, perform one of the following actions: v Include the following statement in your application: EXEC CICS LINK PROGRAM(’DSN2COM2’) v Use the system programming interface SET DB2CONN for the CICS Transaction Server. Related information CICS Transaction Server Library at ibm.com Detecting whether the CICS attachment facility is operational Before you execute SQL in a CICS program, you should test if the CICS attachment facility is available. You do not need to do this test if the CICS attachment facility is started and you are using standby mode. When an SQL statement is executed, and the CICS attachment facility is in standby mode, the attachment issues SQLCODE -923 with a reason code that indicates that DB2 is not available. To detect whether the CICS attachment facility is operational: Use the INQUIRE EXITPROGRAM command for the CICS Transaction Server in your application. The following example shows how to use this command. In this example, the INQUIRE EXITPROGRAM command tests whether the resource manager for SQL, DSNCSQL, is up and running. CICS returns the results in the EIBRESP field of the EXEC interface block (EIB) and in the field whose name is the argument of the CONNECTST parameter (in this case, STST). If the EIBRESP value indicates that the command completed normally and the STST value indicates that the resource manager is available, you can then execute SQL statements. STST DS ENTNAME DS EXITPROG DS . . . MVC F CL8 CL8 ENTNAME,=CL8’DSNCSQL’ Chapter 2. Connecting to DB2 from your application program 121
  • 138.
    MVC EXITPROG,=CL8’DSN2EXT1’ EXEC CICS INQUIREEXITPROGRAM(EXITPROG) ENTRYNAME(ENTNAME) CONNECTST(STST) NOHANDLE CLC EIBRESP,DFHRESP(NORMAL) BNE NOTREADY CLC STST,DFHVALUE(CONNECTED) BNE NOTREADY UPNREADY DS 0H attach is up NOTREADY DS 0H attach isn’t up yet X If you use the INQUIRE EXITPROGRAM command to avoid AEY9 abends and the CICS attachment facility is down, the storm drain effect can occur. The storm drain effect is a condition that occurs when a system continues to receive work, even though that system is down. Related concepts ″Storm-drain effect″ (DB2 Data Sharing: Planning and Administration) Related reference ″-923″ (DB2 Codes) Related information CICS Transaction Server Library at ibm.com Improving thread reuse in CICS applications In general, you want transactions to reuse threads whenever possible, because each thread creation is associated with a high processor cost. To improve thread reuse in CICS applications: Close all cursors that are declared with the WITH HOLD option before each sync point. DB2 does not automatically close them. A thread for an application that contains an open cursor cannot be reused. You should close all cursors immediately after you finish using them. Related concepts “Held and non-held cursors” on page 629 122 Application Programming and SQL Guide
  • 139.
    Chapter 3. IncludingDB2 queries in an application program A query is an SQL statement that returns data from a DB2 database. Your program can communicate this SQL statement to DB2 in one of several ways. After processing the statement, DB2 sends back a return code, which your program should then test to determine the result of the operation. To include DB2 queries in an application program: 1. Choose one of the following methods for communicating with DB2: v Static SQL v Embedded dynamic SQL v Open Database Connectivity (ODBC) v JDBC application support v SQLJ application support ODBC lets you access data through ODBC function calls in your application. You execute SQL statements by passing them to DB2 through a ODBC function call. ODBC eliminates the need for precompiling and binding your application and increases the portability of your application by using the ODBC interface. If you are writing your applications in Java™, you can use JDBC application support to access DB2. JDBC is similar to ODBC but is designed specifically for use with Java. In addition to using JDBC, you can use SQLJ application support to access DB2. SQLJ is designed to simplify the coding of DB2 calls for Java applications. 2. Optional: Declare the tables and views that you use. You can use DCLGEN to generate these declarations. 3. Optional: Define an SQL communications area (SQLCA). You can use an SQLCA to check whether an SQL statement executed successfully. Alternatively, you can use any of the other methods for checking the execution of SQL statements. 4. Define at least one SQL descriptor area (SQLDA). 5. Declare any of the following data items for passing data between DB2 and a host language: v host variables v host variable arrays v host structures Ensure that you use the appropriate data types. 6. Code SQL statements to access DB2 data. Ensure that you delimit these statements properly. Consider using cursors to select a set of rows and then process the set either one row at a time or one rowset at a time. 7. Check the execution of the SQL statements. 8. Handle any SQL error codes. Related concepts “Dynamic SQL” on page 258 “DCLGEN (declarations generator)” on page 125 ″JDBC application programming″ (DB2 Application Programming Guide and Reference for Java) © Copyright IBM Corp. 1983, 2007 123
  • 140.
    ″SQLJ application programming″(DB2 Application Programming Guide and Reference for Java) ″Introduction to DB2 ODBC″ (DB2 ODBC Guide and Reference) Related tasks “Retrieving a set of rows by using a cursor” on page 626 “Delimiting an SQL statement” on page 258 Declaring table and view definitions Before your program issues SQL statements that select, insert, update, or delete data, the program should declare the tables and views that it accesses. To do this, include an SQL DECLARE statement in your program. You do not need to declare tables or views, but doing so offers advantages. One advantage is documentation. For example, the DECLARE statement specifies the structure of the table or view you are working with, and the data type of each column. You can refer to the DECLARE statement for the column names and data types in the table or view. Another advantage is that the DB2 precompiler uses your declarations to make sure that you have used correct column names and data types in your SQL statements. The DB2 precompiler issues a warning message when the column names and data types do not correspond to the SQL DECLARE statements in your program. One way to declare a table or view is to code a DECLARE statement in the WORKING-STORAGE SECTION or LINKAGE SECTION within the DATA DIVISION of your COBOL program. Specify the name of the table and list each column and its data type. When you declare a table or view, you specify DECLARE table-name TABLE regardless of whether the table-name refers to a table or a view. For example, the DECLARE TABLE statement for the DSN8910.DEPT table looks like the following DECLARE statement in COBOL: EXEC SQL DECLARE DSN8910.DEPT TABLE (DEPTNO CHAR(3) DEPTNAME VARCHAR(36) MGRNO CHAR(6) ADMRDEPT CHAR(3) LOCATION CHAR(16) END-EXEC. NOT NULL, NOT NULL, , NOT NULL, ) As an alternative to coding the DECLARE statement yourself, you can use DCLGEN, the declarations generator that is supplied with DB2. For more information about using DCLGEN, see “DCLGEN (declarations generator)” on page 125. When you declare a table or view that contains a column with a distinct type, declare that column with the source type of the distinct type, rather than with the distinct type itself. When you declare the column with the source type, DB2 can check embedded SQL statements that reference that column at precompile time. 124 Application Programming and SQL Guide
  • 141.
    DCLGEN (declarations generator) Yourprogram needs to declare the tables and views that it accesses. DCLGEN, the declarations generator supplied with DB2, produces this DECLARE statement for C, COBOL, and PL/I programs, so that you do not need to code the statement yourself. For information about the syntax of DCLGEN, see the topic “DCLGEN (DECLARATIONS GENERATOR) (DSN)” in DB2 Command Reference. DCLGEN generates a table declaration and puts it into a member of a partitioned data set that you can include in your program. When you use DCLGEN to generate a table’s declaration, DB2 gets the relevant information from the DB2 catalog, which contains information about the table’s definition and the definition of each column within the table. DCLGEN uses this information to produce a complete SQL DECLARE statement for the table or view and a corresponding PL/I, C structure declaration, or COBOL record description. You can use DCLGEN for table declarations only if the table you are declaring already exists. You must use DCLGEN before you precompile your program. Supply the table or view name to DCLGEN before you precompile your program. To use the declarations generated by DCLGEN in your program, use the SQL INCLUDE statement. For more information about the INCLUDE statement, see the topic “INCLUDE” in DB2 SQL Reference. DB2 must be active before you can use DCLGEN. You can start DCLGEN in several different ways: v From ISPF through DB2I. Select the DCLGEN option on the DB2I Primary Option Menu panel. v Directly from TSO. To do this, sign on to TSO, issue the TSO command DSN, and then issue the subcommand DCLGEN. v From a CLIST, running in TSO foreground or background, that issues DSN and then DCLGEN. v With JCL. Supply the required information, using JCL, and run DCLGEN in batch. In the prefix.SDSNSAMP library, sample jobs DSNTEJ2C and DSNTEJ2P show how to use JCL to run DCLGEN. For more information about the syntax of the DSN subcommand DCLGEN, see the topic “DCLGEN (DECLARATIONS GENERATOR) (DSN)” in DB2 Command Reference. If you want to start DCLGEN in the foreground, and your table names include DBCS characters, you must provide and display double-byte characters. If you do not have a terminal that displays DBCS characters, you can enter DBCS characters using the hex mode of ISPF edit. Type declarations that DCLGEN produces for C, COBOL, and PL/I DCLGEN produces DECLARE statements for C, COBOL, and PL/I programs. DCLGEN derives the variable names and data types for these statements based on the source tables in the database. The following table lists the type declarations that DCLGEN produces for C, COBOL, and PL/I based on the corresponding SQL data types that are contained in the source tables. In this table, var represents variable names that DCLGEN provides. Chapter 3. Including DB2 queries in an application program 125
  • 142.
    Table 39. Declarationsgenerated by DCLGEN SQL data type1 C COBOL PL/I SMALLINT short int PIC S9(4) USAGE COMP BIN FIXED(15) INTEGER long int PIC S9(9) USAGE COMP BIN FIXED(31) PIC S9(p-s)V9(s) USAGE COMP-3 DEC FIXED(p,s) DECIMAL(p,s) or NUMERIC(p,s) decimal(p,s) 2 If p>15, the PL/I compiler must support this precision, or a warning is generated. REAL or FLOAT(n) float 1 <= n <= 21 USAGE COMP-1 BIN FLOAT(n) DOUBLE PRECISION, DOUBLE, or FLOAT(n) double USAGE COMP-2 BIN FLOAT(n) CHAR(1) char PIC X(1) CHAR(1) CHAR(n) char var [n+1] PIC X(n) CHAR(n) VARCHAR(n) struct {short int var_len; char var_data[n]; } var; 10 var. 49 var_LEN PIC 9(4) USAGE COMP. 49 var_TEXT PIC X(n). CHAR(n) VAR CLOB(n)3 SQL TYPE IS CLOB_LOCATOR USAGE SQL TYPE IS CLOB-LOCATOR SQL TYPE IS CLOB_LOCATOR GRAPHIC(1) sqldbchar PIC G(1) GRAPHIC(1) GRAPHIC(n) sqldbchar var[n+1]; PIC G(n) USAGE DISPLAY-1.4 or PIC N(n).4 GRAPHIC(n) VARGRAPHIC(n) struct VARGRAPH {short len; sqldbchar data[n]; } var; 10 var. 49 var_LEN PIC 9(4) USAGE COMP. 49 var_TEXT PIC G(n) USAGE DISPLAY-1.4 or 10 var. 49 var_LEN PIC 9(4) USAGE COMP. 49 var_TEXT PIC N(n).4 GRAPHIC(n) VAR DBCLOB(n)3 SQL TYPE IS DBCLOB_LOCATOR USAGE SQL TYPE IS DBCLOB-LOCATOR SQL TYPE IS DBCLOB_LOCATOR | BINARY(n) | SQL TYPE IS BINARY(n) USAGE SQL TYPE IS BINARY(n) SQL TYPE IS BINARY(n) | VARBINARY(n) | SQL TYPE IS VARBINARY(n) USAGE SQL TYPE IS VARBINARY(n) SQL TYPE IS VARBINARY(n) BLOB(n)3 SQL TYPE IS BLOB_LOCATOR USAGE SQL TYPE IS BLOB-LOCATOR SQL TYPE IS BLOB_LOCATOR DATE char var[11]5 PIC X(10)5 CHAR(10)5 TIME char var[9]6 PIC X(8)6 CHAR(8)6 TIMESTAMP char var[27] PIC X(26) CHAR(26) n>1 126 Application Programming and SQL Guide
  • 143.
    Table 39. Declarationsgenerated by DCLGEN (continued) SQL data type1 | | COBOL PL/I ROWID | C SQL TYPE IS ROWID USAGE SQL TYPE IS ROWID SQL TYPE IS ROWID BIGINT long long int PIC S9(18) USAGE COMP FIXED BIN(63) SQL TYPE IS XML AS CLOB(1M) SQL TYPE IS XML AS CLOB(1M) SQL TYPE IS XML AS CLOB(1M) XML 7 Notes: 1. For a distinct type, DCLGEN generates the host language equivalent of the source data type. 2. If your C compiler does not support the decimal data type, edit your DCLGEN output, and replace the decimal data declarations with declarations of type double. 3. For a BLOB, CLOB, or DBCLOB data type, DCLGEN generates a LOB locator. 4. DCLGEN chooses the format based on the character you specify as the DBCS symbol on the COBOL Defaults panel. 5. This declaration is used unless a date installation exit routine exists for formatting dates, in which case the length is that specified for the LOCAL DATE LENGTH installation option. 6. This declaration is used unless a time installation exit routine exists for formatting times, in which case the length is that specified for the LOCAL TIME LENGTH installation option. | 7. The default setting for XML is 1M; however, you might need to adjust it. For more information about the DCLGEN subcommand, see the topic “DCLGEN (DECLARATIONS GENERATOR) (DSN)” in DB2 Command Reference. Example: Adding a table declaration and host-variable structure to a library You can use DCLGEN to generate table declarations for C, COBOL, and PL/I programs. If you store these declarations in a library, you can later pull them into your program with a single SQL INCLUDE statement. This example adds an SQL table declaration and a corresponding host-variable structure to a library. This example is based on the following scenario: v The library name is prefix.TEMP.COBOL. v The member is a new member named VPHONE. v The table is a local table named DSN8910.VPHONE. v The host-variable structure is for COBOL. v The structure receives the default name DCLVPHONE. Information that you must enter is in bold-faced type. Step 1. Specify COBOL as the host language Select option D on the ISPF/PDF menu to display the DB2I Defaults panel. Specify IBMCOB as the application language, as shown in Figure 6 on page 128, and press Enter. Chapter 3. Including DB2 queries in an application program 127
  • 144.
    DSNEOP01 COMMAND ===>_ DB2I DEFAULTSPANEL 1 Change defaults as desired: 1 2 3 4 5 6 7 8 9 10 11 DB2 NAME ............. ===> DB2 CONNECTION RETRIES ===> APPLICATION LANGUAGE ===> LINES/PAGE OF LISTING ===> MESSAGE LEVEL ........ ===> SQL STRING DELIMITER ===> DECIMAL POINT ........ ===> STOP IF RETURN CODE >= ===> NUMBER OF ROWS ===> CHANGE HELP BOOK NAMES?===> AS USER ===> PRESS: ENTER to process DSN 0 IBMCOB 80 I DEFAULT . 8 20 NO (Subsystem identifier) (How many retries for DB2 connection) (ASM, C, CPP, IBMCOB, FORTRAN, PLI) (A number from 5 to 999) (Information, Warning, Error, Severe) (DEFAULT, ’ or ") (. or ,) (Lowest terminating return code) (For ISPF Tables) (YES to change HELP data set names) (Userid to associate with the trusted connection) END to cancel HELP for more information Figure 6. DB2I defaults panel—changing the application language The COBOL Defaults panel is then displayed, as shown in Figure 7. Fill in the COBOL Defaults panel as necessary. Press Enter to save the new defaults, if any, and return to the DB2I Primary Option menu. DSNEOP02 COMMAND ===>_ DB2I DEFAULTS PANEL 2 Change defaults as desired: 1 2 3 DB2I ===> ===> ===> ===> JOB STATEMENT: (Optional if your site has a SUBMIT exit) //ADMF001A JOB (ACCOUNT),’NAME’ //* //* //* COBOL DEFAULTS: COBOL STRING DELIMITER ===> DEFAULT DBCS SYMBOL FOR DCLGEN ===> G (For IBMCOB) (DEFAULT, ’ or ") (G/N - Character in PIC clause) Figure 7. The COBOL defaults panel. Shown only if the field APPLICATION LANGUAGE on the DB2I Defaults panel is IBMCOB. Step 2. Create the table declaration and host structure Select the DCLGEN option on the DB2I Primary Option menu, and press Enter to display the DCLGEN panel. Fill in the fields as shown in Figure 8 on page 129, and then press Enter. 128 Application Programming and SQL Guide
  • 145.
    | | | | | | | | | | | | | | | | | | | | | | | DSNEDP01 ===> DCLGEN SSID: DSN Enter tablename for which declarations are required: 1 SOURCE TABLE NAME ===> DSN8910.VPHONE 2 TABLE OWNER ..... ===> 3 AT LOCATION ..... ===> (Optional) Enter destination data set: (Can be sequential or partitioned) 4 DATA SET NAME ... ===> TEMP(VPHONEC) 5 DATA SET PASSWORD ===> (If password protected) Enter options as desired: 6 ACTION .......... ===> ADD (ADD new or REPLACE old declaration) 7 COLUMN LABEL .... ===> NO (Enter YES for column label) 8 STRUCTURE NAME .. ===> (Optional) 9 FIELD NAME PREFIX ===> (Optional) 10 DELIMIT DBCS .... ===> YES (Enter YES to delimit DBCS identifiers) 11 COLUMN SUFFIX ... ===> NO (Enter YES to append column name) 12 INDICATOR VARS .. ===> NO (Enter YES for indicator variables) 13 ADDITIONAL OPTIONS===> NO (Enter YES to change additional options) PRESS: ENTER to process END to exit HELP for more information Figure 8. DCLGEN panel—selecting source table and destination data set If the operation succeeds, a message is displayed at the top of your screen, as shown in Figure 9. DSNE905I EXECUTION COMPLETE, MEMBER VPHONEC ADDED *** Figure 9. Successful completion message DB2 again displays the DCLGEN screen, as shown in Figure 10. Press Enter to return to the DB2I Primary Option menu. | | | | | | | | | | | | | | | | | | | | | | | | | | | DSNEDP01 ===> DCLGEN SSID: DSN Enter table name for which declarations are required: 1 SOURCE TABLE NAME ===> DSN8910.VPHONE 2 TABLE OWNER ..... ===> 3 AT LOCATION ..... ===> (Optional) Enter destination data set: (Can be sequential or partitioned) 4 DATA SET NAME ... ===> TEMP(VPHONEC) 5 DATA SET PASSWORD ===> (If password protected) Enter options as desired: 6 ACTION .......... ===> ADD (ADD new or REPLACE old declaration) 7 COLUMN LABEL .... ===> NO (Enter YES for column label) 8 STRUCTURE NAME .. ===> (Optional) 9 FIELD NAME PREFIX ===> (Optional) 10 DELIMIT DBCS .... ===> YES (Enter YES to delimit DBCS identifiers) 11 COLUMN SUFFIX ... ===> NO (Enter YES to append column name) 12 INDICATOR VARS .. ===> NO (Enter YES for indicator variables) 13 ADDITIONAL OPTIONS===> NO (Enter YES to change additional options) PRESS: ENTER to process END to exit HELP for more information Figure 10. DCLGEN panel—displaying system and user return codes Step 3. Examine the results To browse or edit the results, exit from DB2I, and select either the browse or the edit option from the ISPF/PDF menu to view the results. Chapter 3. Including DB2 queries in an application program 129
  • 146.
    For this example,the data set to edit is prefix.TEMP.COBOL(VPHONEC), which is shown in the following example. ***** DCLGEN TABLE(DSN8910.VPHONE) *** ***** LIBRARY(SYSADM.TEMP.COBOL(VPHONEC)) *** ***** QUOTE *** ***** ... IS THE DCLGEN COMMAND THAT MADE THE FOLLOWING STATEMENTS *** EXEC SQL DECLARE DSN8910.VPHONE TABLE ( LASTNAME VARCHAR(15) NOT NULL, FIRSTNAME VARCHAR(12) NOT NULL, MIDDLEINITIAL CHAR(1) NOT NULL, PHONENUMBER VARCHAR(4) NOT NULL, EMPLOYEENUMBER CHAR(6) NOT NULL, DEPTNUMBER CHAR(3) NOT NULL, DEPTNAME VARCHAR(36) NOT NULL ) END-EXEC. ***** COBOL DECLARATION FOR TABLE DSN8910.VPHONE ****** 01 DCLVPHONE. 10 LASTNAME. 49 LASTNAME-LEN PIC S9(4) USAGE COMP. 49 LASTNAME-TEXT PIC X(15). 10 FIRSTNAME. 49 FIRSTNAME-LEN PIC S9(4) USAGE COMP. 49 FIRSTNAME-TEXT PIC X(12). 10 MIDDLEINITIAL PIC X(1). 10 PHONENUMBER. 49 PHONENUMBER-LEN PIC S9(4) USAGE COMP. 49 PHONENUMBER-TEXT PIC X(4). 10 EMPLOYEENUMBER PIC X(6). 10 DEPTNUMBER PIC X(3). 10 DEPTNAME. 49 DEPTNAME-LEN PIC S9(4) USAGE COMP. 49 DEPTNAME-TEXT PIC X(36). ***** THE NUMBER OF COLUMNS DESCRIBED BY THIS DECLARATION IS 7 ****** Generating declarations for your table by using DCLGEN Your program needs to declare the tables and views that it accesses. For C, COBOL, and PL/I programs you can use DCLGEN to produce these required declarations, so that you do not need to code the statements yourself. The easiest way to start DCLGEN is through DB2I. Figure 11 on page 131 shows the DCLGEN panel you reach by selecting the DCLGEN option on the DB2I Primary Option Menu panel. For more instructions on using DB2I, see “DB2I primary option menu” on page 902. 130 Application Programming and SQL Guide
  • 147.
    | | | | | | | | | | | | | | | | | | | | | | | DSNEDP01 ===> DCLGEN SSID: DSN Enter tablename for which declarations are required: 1 SOURCE TABLE NAME ===> 2 TABLE OWNER ..... ===> 3 AT LOCATION ..... ===> Enter destination data set: 4 DATA SET NAME ... ===> 5 DATA SET PASSWORD ===> Enter options as desired: 6 ACTION .......... ===> ADD 7 COLUMN LABEL .... ===> NO 8 STRUCTURE NAME .. ===> 9 FIELD NAME PREFIX ===> 10 DELIMIT DBCS .... ===> YES 11 COLUMN SUFFIX ... ===> NO 12 INDICATOR VARS .. ===> NO 13 ADDITIONAL OPTIONS===> YES PRESS: ENTER to process (Optional) (Can be sequential or partitioned) (If password protected) (ADD new or REPLACE old declaration) (Enter YES for column label) (Optional) (Optional) (Enter YES to delimit DBCS identifiers) (Enter YES to append column name) (Enter YES for indicator variables) (Enter YES to change additional options) END to exit HELP for more information Figure 11. DCLGEN panel Fill in the DCLGEN panel as follows: 1 SOURCE TABLE NAME Is the unqualified name of the table, view, or created temporary table for which you want DCLGEN to produce SQL data declarations. The table can be stored at your DB2 location or at another DB2 location. To specify a table name at another DB2 location, enter the table qualifier in the TABLE OWNER field and the location name in the AT LOCATION field. DCLGEN generates a three-part table name from the SOURCE TABLE NAME, TABLE OWNER, and AT LOCATION fields. You can also use an alias for a table name. To specify a table name that contains special characters or blanks, enclose the name in apostrophes. If the name contains apostrophes, you must double each one(’ ’). For example, to specify a table named DON’S TABLE, enter the following: ’DON’’S TABLE’ You do not need to enclose DBCS table names in apostrophes. If you do not enclose the table name in apostrophes, DB2 converts lowercase characters to uppercase. The underscore is not handled as a special character in DCLGEN. For example, the table name JUNE_PROFITS does not need to be enclosed in apostrophes. Because COBOL field names cannot contain underscores, DCLGEN substitutes hyphens (-) for single-byte underscores in COBOL field names that are built from the table name. | | | | 2 TABLE OWNER Is the schema qualifier of the source table. If you do not specify this value and the table is a local table, DB2 assumes that the table qualifier is your TSO logon ID. If the table is at a remote location, you must specify this value. 3 AT LOCATION Is the location of a table or view at another DB2 subsystem. If you specify this parameter, you must also specify a qualified name in the SOURCE Chapter 3. Including DB2 queries in an application program 131
  • 148.
    TABLE NAME field.The value of the AT LOCATION field becomes a prefix for the table name on the SQL DECLARE statement, as follows: location_name, schema_name, table_name For example, for the location PLAINS_GA: PLAINS_GA.CARTER.CROP_YIELD_89 The default is the local location name. This field applies to DB2 private protocol access only. The location you name must be another DB2 for z/OS. 4 DATA SET NAME Is the name of the data set you allocated to contain the declarations that DCLGEN produces. You must supply a name; no default exists. The data set must already exist, be accessible to DCLGEN, and can be either sequential or partitioned. If you do not enclose the data set name in apostrophes, DCLGEN adds a standard TSO prefix (user ID) and suffix (language). DCLGEN knows what the host language is from the DB2I defaults panel. For example, for library name LIBNAME(MEMBNAME), the name becomes: userid.libname.language(membname) For library name LIBNAME, the name becomes: userid.libname.language If this data set is password protected, you must supply the password in the DATA SET PASSWORD field. 5 DATA SET PASSWORD Is the password for the data set in the DATA SET NAME field, if the data set is password protected. It is not displayed on your terminal, and it is not recognized if you issued it from a previous session. 6 ACTION Tells DCLGEN what to do with the output when it is sent to a partitioned data set. (The option is ignored if the data set you specify in the DATA SET NAME field is sequential.) ADD indicates that an old version of the output does not exist and creates a new member with the specified data set name. This is the default. REPLACE replaces an old version, if it already exists. If the member does not exist, this option creates a new member. 7 COLUMN LABEL Tells DCLGEN whether to include labels that are declared on any columns of the table or view as comments in the data declarations. (The SQL statement LABEL creates column labels to use as supplements to column names.) Use: YES to include column labels. NO to ignore column labels. This is the default. 8 STRUCTURE NAME Is the name of the generated data structure. The name can be up to 31 characters. If the name is not a DBCS string, and the first character is not alphabetic, then enclose the name in apostrophes. If you use special characters, be careful to avoid name conflicts. 132 Application Programming and SQL Guide
  • 149.
    If you leavethis field blank, DCLGEN generates a name that contains the table or view name with a prefix of DCL. If the language is COBOL or PL/I, and the table or view name consists of a DBCS string, the prefix consists of DBCS characters. For C, lowercase characters you enter in this field do not fold to uppercase. 9 FIELD NAME PREFIX Specifies a prefix that DCLGEN uses to form field names in the output. For example, if you choose ABCDE, the field names generated are ABCDE1, ABCDE2, and so on. DCLGEN accepts a field name prefix of up to 28 bytes that can include special and double-byte characters. If you specify a single-byte or mixed-string prefix and the first character is not alphabetic, apostrophes must enclose the prefix. If you use special characters, avoid name conflicts. For COBOL and PL/I, if the name is a DBCS string, DCLGEN generates DBCS equivalents of the suffix numbers. For C, lowercase characters you enter in this field do not fold to uppercase. If you leave this field blank, the field names are the same as the column names in the table or view. 10 DELIMIT DBCS Tells DCLGEN whether to delimit DBCS table names and column names in the table declaration. Use: YES to enclose the DBCS table and column names with SQL delimiters. NO to not delimit the DBCS table and column names. 11 COLUMN SUFFIX Tells DCLGEN whether to form field names by attaching the column name as a suffix to the value you specify in FIELD NAME PREFIX. For example, if you specify YES, the field name prefix is NEW, and the column name is EMPNO, the field name is NEWEMPNO. If you specify YES, you must also enter a value in FIELD NAME PREFIX. If you do not enter a field name prefix, DCLGEN issues a warning message and uses the column names as the field names. The default is NO, which does not use the column name as a suffix and allows the value in FIELD NAME PREFIX to control the field names, if specified. 12 INDICATOR VARS Tells DCLGEN whether to generate an array of indicator variables for the host variable structure. If you specify YES, the array name is the table name with a prefix of I (or DBCS letter <I> if the table name consists solely of double-byte characters). The form of the data declaration depends on the language: For a C program: short int Itable-name[n]; For a COBOL program: 01 Itable-name PIC S9(4) USAGE COMP OCCURS n TIMES. For a PL/I program: DCL Itable-name(n) BIN FIXED(15); n is the number of columns in the table. For example, suppose you define the following table: CREATE TABLE HASNULLS (CHARCOL1 CHAR(1), CHARCOL2 CHAR(1)); You request an array of indicator variables for a COBOL program. DCLGEN might generate the following host variable declaration: Chapter 3. Including DB2 queries in an application program 133
  • 150.
    01 DCLHASNULLS. 10 CHARCOL1 PIC X(1). 10CHARCOL2 PIC X(1). 01 IHASNULLS PIC S9(4) USAGE COMP OCCURS 2 TIMES. The default is NO, which does not generate an indicator variable array. | | | 13 ADDITIONAL OPTIONS Indicates whether to display the panel for additional DCLGEN options. The default is YES. | | If you specified YES in the ADDITIONAL OPTIONS field, the ADDITIONAL DCLGEN OPTIONS panel is displayed as follows: | DSNEDP02 ADDITIONAL DCLGEN OPTIONS SSID: DSN ===> | | Enter options as desired: | 1 RIGHT MARGIN .... ===> 72 (Enter 72 or 80) | | 2 FOR BIT DATA .... ===> NO (Enter YES to declare SQL variables for | FOR BIT DATA columns) | | PRESS: ENTER to process END to exit HELP for more information | | | | Figure 12. ADDITIONAL DCLGEN OPTIONS panel | Fill in the ADDITIONAL DCLGEN OPTIONS panel as follows: | 1 RIGHT MARGIN Specifies the break point for statement tokens that must be wrapped to one or more subsequent records. You can specify column 72 or column 80. | | | The default is 72. | | | 2 FOR BIT DATA Specifies whether DCLGEN is to generate a DECLARE VARIABLE statement of SQL variables for columns that are declared as FOR BIT DATA. This statement is required in DB2 applications that meet all of the following criteria: v are written in COBOL v have host variables for FOR BIT DATA columns | | v are prepared using the SQLCCSID option of the integrated DB2 coprocessor. | The choices are YES and NO. The default is NO. | | If the table or view does not have FOR BIT DATA columns, DCLGEN does not generate this statement. | | | | | DCLGEN generates a table or column name in the DECLARE statement as a non-delimited identifier unless at least one of the following conditions is true: v The name contains special characters and is not a DBCS string. v The name is a DBCS string, and you have requested delimited DBCS names. If you are using an SQL reserved word as an identifier, you must edit the DCLGEN output in order to add the appropriate SQL delimiters. DCLGEN produces output that is intended to meet the needs of most users, but occasionally, you will need to edit the DCLGEN output to work in your specific case. For example, DCLGEN is unable to determine whether a column that is 134 Application Programming and SQL Guide
  • 151.
    defined as NOTNULL also contains the DEFAULT clause, so you must edit the DCLGEN output to add the DEFAULT clause to the appropriate column definitions. Including data declarations from DCLGEN in your program After you use DCLGEN to produce the required table and view declarations for your C, COBOL, or PL/I program, you need to include these declarations in your program. Use the following SQL INCLUDE statement to place the generated table declaration and COBOL record description in your source program: EXEC SQL INCLUDE member-name END-EXEC. For example, to include a description for the table DSN8910.EMP, code: EXEC SQL INCLUDE DECEMP END-EXEC. In this example, DECEMP is a name of a member of a partitioned data set that contains the table declaration and a corresponding COBOL record description of the table DSN8910.EMP. (A COBOL record description is a two-level host structure that corresponds to the columns of a table’s row. To get a current description of the table, use DCLGEN to generate the table’s declaration and store it as member DECEMP in a library (usually a partitioned data set) just before you precompile the program. Defining the SQL communications area An assembler, C, C++, COBOL, Fortran, or PL/I program can include an SQL communications area (SQLCA) instead of including individual SQLCODE and SQLSTATE host variables. For REXX procedures that contain SQL statements, DB2 automatically includes an SQLCA in the procedure when DB2 prepares it. An assembler, C, COBOL, Fortran, or PL/I program that contains SQL statements must either include an SQLCA, which contains the SQLCODE and SQLSTATE variables, or declare one or both of the following host variables: v An SQLCODE variable, which is declared as shown in the following table. Table 40. SQLCODE variable declarations Language How the SQLCODE variable is declared assembler as a fullword integer C as a long integer Example: long SQLCODE; COBOL Fortran PL/I as PIC S9(9) BINARY, PIC S9(9) COMP-4, PIC S9(9) COMP-5, or PICTURE S9(9) COMP 1 as INTEGER*4 as BIN FIXED (31) Note: 1. In Fortran, this variable is called SQLCOD. Chapter 3. Including DB2 queries in an application program 135
  • 152.
    v An SQLSTATEvariable, which is declared as shown in the following table. Table 41. SQLSTATE variable declarations Language How the SQLSTATE variable is declared assembler as a character string of length 5 (CL5) C as a character array of length 6 Example: char SQLSTATE[6]; COBOL Fortran as PICTURE X(5) 1 PL/I as CHARACTER*5 as CHARACTER(5) Note: 1. In Fortran, this variable can also be called SQLSTA. DB2 sets the SQLCODE (or SQLCOD) and SQLSTATE (or SQLSTA) values after each SQL statement executes. An application should check these values to determine whether the last SQL statement was successful. All SQL statements in the program must be within the scope of the declaration of the SQLCODE and SQLSTATE variables. Whether you define the SQLCODE or SQLSTATE variable or an SQLCA in your program depends on whether you specify the precompiler option STDSQL(YES) to conform to the SQL standard, or STDSQL(NO) to conform to DB2 rules: v If you specify the precompiler option STDSQL(YES): Do not define an SQLCA. If you do, DB2 ignores your SQLCA, and your SQLCA definition causes compile-time errors. If you declare an SQLSTATE variable, it must not be an element of a structure. You must declare the host variables SQLCODE (or SQLCOD) and SQLSTATE (or SQLSTA) within a BEGIN DECLARE SECTION and END DECLARE SECTION statement in your program declarations. COBOL: When you use the precompiler option STDSQL(YES), you must declare an SQLCODE variable. DB2 declares an SQLCA area for you in the WORKING-STORAGE SECTION. DB2 controls the structure and location of the SQLCA. v If you specify the precompiler option STDSQL(NO): Include an SQLCA explicitly. REXX applications behave differently. When DB2 prepares a REXX procedure that contains SQL statements, DB2 automatically includes an SQL communication area (SQLCA) in the procedure. The REXX SQLCA differs from the SQLCA for other languages in the following ways: v The REXX SQLCA consists of a set of separate variables, rather than a structure. If you use the ADDRESS DSNREXX ’CONNECT’ ssid syntax to connect to DB2, the SQLCA variables are a set of simple variables. If you connect to DB2 using the CALL SQLDBS ’ATTACH TO’ syntax, the SQLCA variables are compound variables that begin with the stem SQLCA. To define the SQL communications area: 1. Code the SQLCA directly in the program or use the following SQL INCLUDE statement to request a standard SQLCA declaration. 136 Application Programming and SQL Guide
  • 153.
    EXEC SQL INCLUDESQLCA For C and C++ applications, this standard declaration includes both a structure definition and a static data area named ’sqlca’. Restriction: You cannot use the INCLUDE SQLCA statement to include an SQLCA in a REXX program. 2. Implement the following language-specific requirements: Table 42. Language-specific requirements for defining the SQLCA Language Requirement Assembler If your program is reentrant, you must include the SQLCA within a unique data area that is acquired for your task (a DSECT). For example, at the beginning of your program, specify: PROGAREA DSECT EXEC SQL INCLUDE SQLCA As an alternative, you can create a separate storage area for the SQLCA and provide addressability to that area. COBOL You can specify INCLUDE SQLCA or a declaration for SQLCODE wherever you can specify a 77 level or a record description entry in the WORKING-STORAGE SECTION. When you use the DB2 precompiler, you can declare a stand-alone SQLCODE variable in either the WORKING-STORAGE SECTION or LINKAGE SECTION. When using the DB2 coprocessor, you can declare a stand-alone SQLCODE variable in the WORKING-STORAGE SECTION, LINKAGE SECTION or LOCAL-STORAGE SECTION. Related tasks “Accessing the DB2 REXX language support application programming interfaces” on page 296 Related reference ″INCLUDE″ (DB2 SQL Reference) ″Description of SQLCA fields″ (DB2 SQL Reference) ″The REXX SQLCA″ (DB2 SQL Reference) “Descriptions of SQL processing options” on page 854 Defining SQL descriptor areas If your program includes certain SQL statements, you must define at least one SQL descriptor area (SQLDA). The following statements require an SQLDA: v CALL ... USING DESCRIPTOR descriptor-name v DESCRIBE statement-name INTO descriptor-name v DESCRIBE CURSOR host-variable INTO descriptor-name v DESCRIBE INPUT statement-name INTO descriptor-name v DESCRIBE PROCEDURE host-variable INTO descriptor-name Chapter 3. Including DB2 queries in an application program 137
  • 154.
    v v v v v DESCRIBE TABLE host-variableINTO descriptor-name EXECUTE ... USING DESCRIPTOR descriptor-name FETCH ... USING DESCRIPTOR descriptor-name OPEN ... USING DESCRIPTOR descriptor-name PREPARE ... INTO descriptor-name Unlike the SQLCA, a program can have more than one SQLDA, and an SQLDA can have any valid name. To define SQL descriptor areas: 1. For assembler, C, C++, and PL/I programs, code the SQLDA directly in the program or use the following SQL INCLUDE statement to request a standard SQLDA declaration: EXEC SQL INCLUDE SQLDA For C and C++ programs, you can place an SQLDA declaration wherever C allows a structure definition. Normal C scoping rules apply. The standard declaration includes only a structure definition with the name ’sqlda’. Requirement: You must place SQLDA declarations before the first SQL statement that references the data descriptor, unless you use the TWOPASS precompiler option . For the DB2 coprocessor, only the ONEPASS precompiler option is allowed. Restriction: DB2 does not support the INCLUDE SQLDA statement for Fortran or REXX programs. Restriction: The SQL INCLUDE statement does not provide an SQLDA mapping for COBOL. 2. For COBOL programs that are compiled with any supported compiler, define the SQLDA by using one of the following two methods: v Code the SQLDA declarations in your program. When you use the DB2 precompiler, you must place SQLDA declarations in the WORKING-STORAGE SECTION or LINKAGE SECTION of your program, wherever you can specify a record description entry in that section. When you use the DB2 coprocessor, you must place SQLDA declarations in the WORKING-STORAGE SECTION, LINKAGE SECTION or LOCAL-STORAGE SECTION of your program, wherever you can specify a record description entry in that section. v Call a subroutine that is written in C, PL/I, or assembler language and that uses the INCLUDE SQLDA statement to define the SQLDA. The subroutine can also include SQL statements for any dynamic SQL functions you need. | | | | | | | | Requirement: You must place SQLDA declarations before the first SQL statement that references the data descriptor, unless you use the TWOPASS precompiler option . For the DB2 coprocessor, only the ONEPASS precompiler option is allowed. 3. For Fortran programs, call a subroutine that is written in C, PL/I or assembler language and that uses the INCLUDE SQLDA statement to define the SQLDA and that also includes the necessary SQL statements for the dynamic SQL functions you want to perform. 138 Application Programming and SQL Guide
  • 155.
    Requirement: You mustplace SQLDA declarations before the first SQL statement that references the data descriptor, unless you use the TWOPASS precompiler option . For the DB2 coprocessor, only the ONEPASS precompiler option is allowed. 4. For REXX programs, code the SQLDA declarations in your program. Each SQLDA consists of a set of REXX variables with a common stem. The stem must be a REXX variable name that contains no periods and is the same as the value of descriptor-name that you specify when you use the SQLDA in an SQL statement. Related reference ″INCLUDE″ (DB2 SQL Reference) ″Description of SQLCA fields″ (DB2 SQL Reference) ″The REXX SQLCA″ (DB2 SQL Reference) “Descriptions of SQL processing options” on page 854 Putting parameter information in an SQLDA by using DESCRIBE INPUT Your program can get data type information about parameter markers by asking DB2 to set the fields in the SQLDA. You can use the DESCRIBE INPUT statement to let DB2 put the data type information for parameter markers in an SQLDA. Before you execute DESCRIBE INPUT, you must allocate an SQLDA with enough instances of SQLVAR to represent all parameter markers in the SQL statements you want to describe. After you execute DESCRIBE INPUT, you code the application in the same way as any other application in which you execute a prepared statement using an SQLDA. First, you obtain the addresses of the input host variables and their indicator variables and insert those addresses into the SQLDATA and SQLIND fields. Then you execute the prepared SQL statement. Example using the SQLDA: Suppose that you want to execute this statement dynamically: DELETE FROM DSN8910.EMP WHERE EMPNO = ? The code to set up an SQLDA, obtain parameter information using DESCRIBE INPUT, and execute the statement looks like this: SQLDAPTR=ADDR(INSQLDA); /* Get pointer to SQLDA SQLDAID=’SQLDA’; /* Fill in SQLDA eye-catcher SQLDABC=LENGTH(INSQLDA); /* Fill in SQLDA length SQLN=1; /* Fill in number of SQLVARs SQLD=0; /* Initialize # of SQLVARs used DO IX=1 TO SQLN; /* Initialize the SQLVAR SQLTYPE(IX)=0; SQLLEN(IX)=0; SQLNAME(IX)=’’; END; SQLSTMT=’DELETE FROM DSN8910.EMP WHERE EMPNO = ?’; EXEC SQL PREPARE SQLOBJ FROM SQLSTMT; EXEC SQL DESCRIBE INPUT SQLOBJ INTO :INSQLDA; SQLDATA(1)=ADDR(HVEMP); /* Get input data address SQLIND(1)=ADDR(HVEMPIND); /* Get indicator address EXEC SQL EXECUTE SQLOBJ USING DESCRIPTOR :INSQLDA; */ */ */ */ */ */ */ */ Chapter 3. Including DB2 queries in an application program 139
  • 156.
    Declaring host variables,host variable arrays, and host structures You can use host variables, host variable arrays, and host structures in SQL statements in your program to pass data between DB2 and your application. Restriction: You do not declare host variables in REXX. To declare host variables, host variable arrays, and host structures: 1. For all languages except REXX, consider the following general rules and restrictions: v If you specify the ONEPASS precompiler option, you must explicitly declare each host variable and each host variable array before using them in an SQL statement. If you specify the TWOPASS precompiler option, you must declare each host variable before using it in the DECLARE CURSOR statement. Restriction: The DB2 coprocessor for C/C++ supports only the ONEPASS option. Restriction: For Fortran, you cannot implicitly declare any host variables through default typing or by using the IMPLICIT statement. v If you specify the STDSQL(YES) precompiler option, you must precede the host language statements that define the host variables and host variable arrays with the BEGIN DECLARE SECTION statement, and follow the host language statements with the END DECLARE SECTION statement. Otherwise, these statements are optional. v Precede all host variables and all host variable arrays in an SQL statement with a colon (:). Restriction: In PL/I, if the SQL statement meets any of the following conditions, do not precede a host variable or host variable array in that statement with a colon: – The SQL statement is an EXECUTE IMMEDIATE or PREPARE statement. – The SQL statement is in a program that also contains a DECLARE VARIABLE statement. – The host variable is part of a string expression, but the host variable is not the only component of the string expression. v Ensure that any SQL statement that uses a host variable or host variable array is within the scope of the statement that declares that variable or array. v If you are using the DB2 precompiler, ensure that the names of host variables and host variable arrays are unique within the program, even if the variables and variable arrays are in different blocks, classes, procedures, functions, or subroutines. You can qualify the names with a structure name to make them unique. | | | | | 140 Application Programming and SQL Guide
  • 157.
    2. Consider thefollowing language-specific rules and guidelines: Table 43. Language-specific rules and guidelines for host variables, host variable arrays, and host structures Language Rules and guidelines Assembler You can declare host variables in normal assembler style (DC or DS), depending on the data type and the limitations on that data type. You can specify a value on DC or DS declarations (for example, DC H’5’). The DB2 precompiler examines only packed decimal declarations. C/C++ v You can have more than one host variable declaration section in your program. v When you code SQL statements in a C++ program, you can use class members as host variables. Class members that are used as host variables are accessible to any SQL statement within the class. However, you cannot use class objects as host variables. COBOL v You must explicitly declare all host variables and host variable arrays that are used in SQL statements in the WORKING-STORAGE SECTION or LINKAGE SECTION of your program’s DATA DIVISION. You must explicitly declare each host variable and host variable array before using them in an SQL statement. v Fortran You can specify OCCURS when defining an indicator structure, a host variable array, or an indicator variable array. You cannot specify OCCURS for any other type of host variable. v When you declare a character host variable, do not use an expression to define the length of the character variable. You can use a character host variable with an undefined length (for example, CHARACTER *(*)). The length of any such variable is determined when the associated SQL statement executes. v Host variables must be scalar variables; they cannot be elements of vectors or arrays (subscripted variables). v Be careful when calling subroutines that might change the attributes of a host variable. Such alteration can cause an error while the program is running. Chapter 3. Including DB2 queries in an application program 141
  • 158.
    Table 43. Language-specificrules and guidelines for host variables, host variable arrays, and host structures (continued) Language Rules and guidelines REXX v You do not declare host variables in REXX. When you need a new variable, you use it in a REXX command. When you use a REXX variable as a host variable in an SQL statement, you must precede the variable with a colon. v A REXX host variable can be a simple or compound variable. DB2 REXX Language Support evaluates compound variables before DB2 processes SQL statements that contain the variables. In the following example, the host variable that is passed to DB2 is :x.1.2: a=1 b=2 EXECSQL ’OPEN C1 USING :x.a.b’ Related reference “Descriptions of SQL processing options” on page 854 Host variables, host variable arrays, and host structures A host variable is a single data item. A host variable array is a data array. A host structure is a group of host variables that can be referenced with a single name. Ahost variable is a single data item that is declared in the host language to be used within an SQL statement. You can use host variables to perform the following actions: v Retrieve data into the host variable for your application program’s use v Place data into the host variable to insert into a table or to change the contents of a row v Use the data in the host variable when evaluating a WHERE or HAVING clause v Assign the value that is in the host variable to a special register, such as CURRENT SQLID and CURRENT DEGREE v Insert null values into columns by using a host indicator variable that contains a negative value v Use the data in the host variable in statements that process dynamic SQL, such as EXECUTE, PREPARE, and OPEN | | | | | A host variable array is a data array that is declared in the host language to be used within an SQL statement. You can use host variable arrays to perform the following actions: v Retrieve data into host variable arrays for your application program’s use v Place data into host variable arrays to insert rows into a table | | You typically define host variable arrays for use with multiple-row FETCH, INSERT, and MERGE statements. A host structure is a group of host variables that can be referenced with a single name. You can use host structures in all host languages except REXX. Host 142 Application Programming and SQL Guide
  • 159.
    structures are definedby statements of the host language. You can refer to a host structure in any context where you would refer to the list of host variables in the structure. A host structure reference is equivalent to a reference to each of the host variables within the structure in the order in which they are defined in the structure declaration. Host variables in an SQL statement Use host variables in embedded SQL statements to represent a single value that the program does not know until the program runs. Host variables are useful for storing retrieved data or for passing values that are to be assigned or used for comparisons. To use a host variable in an SQL statement, you can specify any valid host variable name that is declared according to the rules of the host language. You must declare the name of the host variable in the host program before you use it. To optimize performance, make sure that the host language declaration maps as closely as possible to the data type of the associated data in the database. You can use a host variable to represent a data value, but you cannot use it to represent a table, view, or column name. (You can specify table, view, or column names at run time using dynamic SQL. See “Dynamic SQL” on page 258 for more information.) Host variables follow the naming conventions of the host language. A colon (:) must precede host variables that are used in SQL statements so DB2 can distinguish a variable name from a column name. A colon must not precede host variables outside of SQL statements. Assignments and comparisons using different data types: For assignments and comparisons involving a DB2 column and a host variable of a different data type or length, you can expect conversions to occur. For more information about the rules that are used when you assign retrieved data to a host variable or compare retrieved data to a value in a host variable, see “Assignment and comparison” inDB2 SQL Reference. Retrieving a single row of data in host variables If you know that your query returns only one row, you can specify one or more host variables to contain the column values. You can use one or more host variables to specify a program data area that is to contain the column values of a retrieved row. The INTO clause of the SELECT statement names one or more host variables to contain the retrieved column values. The named variables correspond one-to-one with the list of column names in the SELECT statement. If you do not know how many rows DB2 will return, or if you expect more than one row to return, you must use an alternative to the SELECT ... INTO statement. The DB2 cursor enables an application to return a set of rows and fetch either one row at a time or one rowset at a time from the result table. For information about using cursors, see “Retrieving a set of rows by using a cursor” on page 626. Example: Retrieving a single row: Suppose you are retrieving the LASTNAME and WORKDEPT column values from the DSN8910.EMP table for a particular Chapter 3. Including DB2 queries in an application program 143
  • 160.
    employee. You candefine a host variable in your program to hold each column and then name the host variables with an INTO clause, as in the following COBOL example: MOVE ’000110’ TO CBLEMPNO. EXEC SQL SELECT LASTNAME, WORKDEPT INTO :CBLNAME, :CBLDEPT FROM DSN8910.EMP WHERE EMPNO = :CBLEMPNO END-EXEC. Note that the host variable CBLEMPNO is preceded by a colon (:) in the SQL statement, but it is not preceded by a colon in the COBOL MOVE statement. In the DATA DIVISION section of a COBOL program, you must declare the host variables CBLEMPNO, CBLNAME, and CBLDEPT to be compatible with the data types in the columns EMPNO, LASTNAME, and WORKDEPT of the DSN8910.EMP table. You can use a host variable to specify a value in a search condition. For this example, you have defined a host variable CBLEMPNO for the employee number, so that you can retrieve the name and the work department of the employee whose number is the same as the value of the host variable, CBLEMPNO; in this case, 000110. If the SELECT ... INTO statement returns more than one row, an error occurs, and any data that is returned is undefined and unpredictable. To prevent undefined and unpredictable data from being returned, you can use the FETCH FIRST 1 ROW ONLY clause to ensure that only one row is returned. For example: EXEC SQL SELECT LASTNAME, WORKDEPT INTO :CBLNAME, :CBLDEPT FROM DSN8910.EMP FETCH FIRST 1 ROW ONLY END-EXEC. You can include an ORDER BY clause in the preceding example. This gives your application some control over which row is returned when you use a FETCH FIRST 1 ROW ONLY clause in a SELECT INTO statement. EXEC SQL SELECT LASTNAME, WORKDEPT INTO :CBLNAME, :CBLDEPT FROM DSN8810.EMP ORDER BY LASTNAME FETCH FIRST 1 ROW ONLY END-EXEC. When you specify both the ORDER BY clause and the FETCH FIRST clause, ordering is done first and then the first row is returned. This means that the ORDER BY clause determines which row is returned. If you specify both the ORDER BY clause and the FETCH FIRST clause, ordering is performed on the entire result set before the first row is returned. Example: Specifying expressions in the SELECT clause: When you specify a list of items in the SELECT clause, you can use more than the column names of tables and views. You can request a set of column values mixed with host variable values and constants. For example: 144 Application Programming and SQL Guide
  • 161.
    MOVE 4476 TORAISE. MOVE ’000220’ TO PERSON. EXEC SQL SELECT EMPNO, LASTNAME, SALARY, :RAISE, SALARY + :RAISE INTO :EMP-NUM, :PERSON-NAME, :EMP-SAL, :EMP-RAISE, :EMP-TTL FROM DSN8910.EMP WHERE EMPNO = :PERSON END-EXEC. The following results have column headings that represent the names of the host variables: EMP-NUM ======= 000220 PERSON-NAME =========== LUTZ EMP-SAL ======= 29840 EMP-RAISE ========= 4476 EMP-TTL ======= 34316 Example: Specifying summary values in the SELECT clause: You can request summary values to be returned from aggregate functions. For example: MOVE ’D11’ TO DEPTID. EXEC SQL SELECT WORKDEPT, AVG(SALARY) INTO :WORK-DEPT, :AVG-SALARY FROM DSN8910.EMP WHERE WORKDEPT = :DEPTID END-EXEC. Updating data by using host variables When you want to update a value in a DB2 table, but you do not know the exact value until the program runs, use host variables in your SQL statement. DB2 can change a table value to match the current value of the host variable. To do this, use the host variable name in the SET clause of the UPDATE statement. Example: Updating a single row: The following example changes an employee’s phone number: MOVE ’4246’ TO NEWPHONE. MOVE ’000110’ TO EMPID. EXEC SQL UPDATE DSN8910.EMP SET PHONENO = :NEWPHONE WHERE EMPNO = :EMPID END-EXEC. Example: Updating multiple rows: The following example gives the employees in a particular department a salary increase of 10%: MOVE ’D11’ TO DEPTID. EXEC SQL UPDATE DSN8910.EMP SET SALARY = 1.10 * SALARY WHERE WORKDEPT = :DEPTID END-EXEC. Inserting data by using column values that use host variables When you want to insert data into a DB2 table, but you do not know at least some of the values to insert until the program runs, use host variables in your INSERT statement. You can insert a single row of data into a DB2 table by using the INSERT statement with column values in the VALUES clause. A column value can be a host variable, a constant, or any valid combination of host variables and constants. Chapter 3. Including DB2 queries in an application program 145
  • 162.
    To insert multiplerows, you can use the form of the INSERT statement that selects values from another table or view. You can also use a form of the INSERT statement that inserts multiple rows from values that are provided in host variable arrays. For more information, see “Inserting multiple rows of data from host variable arrays” on page 182. Example: The following example inserts a single row into the activity table: EXEC SQL INSERT INTO DSN8910.ACT VALUES (:HV-ACTNO, :HV-ACTKWD, :HV-ACTDESC) END-EXEC. Changing the coded character set ID of host variables All DB2 string data, other than binary data, has an encoding scheme and a coded character set ID (CCSID) associated with it. You can associate an encoding scheme and a CCSID with individual host variables. Any data in those host variable is then associated with that encoding scheme and CCSID. You can use the DECLARE VARIABLE statement to associate an encoding scheme and a CCSID with individual host variables. The DECLARE VARIABLE statement has the following effects on a host variable: v When you use the host variable to update a table, the local subsystem or the remote server assumes that the data in the host variable is encoded with the CCSID and encoding scheme that the DECLARE VARIABLE statement assigns. v When you retrieve data from a local or remote table into the host variable, the retrieved data is converted to the CCSID and encoding scheme that are assigned by the DECLARE VARIABLE statement. You can use the DECLARE VARIABLE statement in static or dynamic SQL applications. However, you cannot use the DECLARE VARIABLE statement to control the CCSID and encoding scheme of data that you retrieve or update using an SQLDA. When you use a DECLARE VARIABLE statement in a program, put the DECLARE VARIABLE statement after the corresponding host variable declaration and before your first reference to that host variable. Example: Using a DECLARE VARIABLE statement to change the encoding scheme of retrieved data: Suppose that you are writing a C program that runs on a DB2 for z/OS subsystem. The subsystem has an EBCDIC application encoding scheme. The C program retrieves data from the following columns of a local table that is defined with CCSID UNICODE. PARTNUM CHAR(10) JPNNAME GRAPHIC(10) ENGNAME VARCHAR(30) Because the application encoding scheme for the subsystem is EBCDIC, the retrieved data is EBCDIC. To make the retrieved data Unicode, use DECLARE VARIABLE statements to specify that the data that is retrieved from these columns is encoded in the default Unicode CCSIDs for the subsystem. Suppose that you want to retrieve the character data in Unicode CCSID 1208 and the graphic data in Unicode CCSID 1200. Use DECLARE VARIABLE statements like these: EXEC SQL BEGIN DECLARE SECTION; char hvpartnum[11]; EXEC SQL DECLARE :hvpartnum VARIABLE CCSID 1208; sqldbchar hvjpnname[11]; EXEC SQL DECLARE :hvjpnname VARIABLE CCSID 1200; 146 Application Programming and SQL Guide
  • 163.
    struct { short len; chard[30]; } hvengname; EXEC SQL DECLARE :hvengname VARIABLE CCSID 1208; EXEC SQL END DECLARE SECTION; The BEGIN DECLARE SECTION and END DECLARE SECTION statements mark the beginning and end of a host variable declare section. Ensuring that DB2 correctly interprets character input data in REXX programs DB2 REXX Language Support can incorrectly interpret character literals as graphic or numeric literals unless you mark them correctly. To ensure that DB2 REXX Language Support does not interpret character literals as graphic or numeric literals, precede and follow character literals with a double quotation mark, followed by a single quotation mark, followed by another double quotation mark ("’"). Enclosing the string in apostrophes is not adequate because REXX removes the apostrophes when it assigns a literal to a variable. For example, suppose that you want to pass the value in host variable stringvar to DB2. The value that you want to pass is the string ’100’. The first thing that you need to do is to assign the string to the host variable. You might write a REXX command like this: stringvar = ’100’ After the command executes, stringvar contains the characters 100 (without the apostrophes). DB2 REXX Language Support then passes the numeric value 100 to DB2, which is not what you intended. However, suppose that you write the command like this: stringvar = "’"100"’" In this case, REXX assigns the string ’100’ to stringvar, including the single quotation marks. DB2 REXX Language Support then passes the string ’100’ to DB2, which is the desired result. Passing the data type of an input data type to DB2 for REXX programs In certain situations, you want to tell DB2 the data type to use for input data in a REXX program. For example, if you are assigning or comparing input data to columns of type SMALLINT, CHAR, or GRAPHIC, you should tell DB2 to use those data types. DB2 does not assign data types of SMALLINT, CHAR, or GRAPHIC to input data. If you assign or compare this data to columns of type SMALLINT, CHAR, or GRAPHIC, DB2 must do more work than if the data types of the input data and columns match. To indicate the data type of input data to DB2, use an SQLDA. Example: Specifying CHAR: Suppose you want to tell DB2 that the data with which you update the MIDINIT column of the EMP table is of type CHAR, rather than VARCHAR. You need to set up an SQLDA that contains a description of a CHAR column, and then prepare and execute the UPDATE statement using that SQLDA: Chapter 3. Including DB2 queries in an application program 147
  • 164.
    INSQLDA.SQLD = 1 INSQLDA.1.SQLTYPE= 453 /* /* /* /* /* /* SQLDA contains one variable Type of the variable is CHAR, and the value can be null Length of the variable is 1 Value in variable is H Input variable is not null INSQLDA.1.SQLLEN = 1 INSQLDA.1.SQLDATA = ’H’ INSQLDA.1.SQLIND = 0 SQLSTMT="UPDATE EMP" , "SET MIDINIT = ?" , "WHERE EMPNO = ’000200’" "EXECSQL PREPARE S100 FROM :SQLSTMT" "EXECSQL EXECUTE S100 USING DESCRIPTOR :INSQLDA" */ */ */ */ */ */ Example: Specifying DECIMAL with precision and scale: Suppose you want to tell DB2 that the data is of type DECIMAL with precision and nonzero scale. You need to set up an SQLDA that contains a description of a DECIMAL column: INSQLDA.SQLD = 1 INSQLDA.1.SQLTYPE = 484 INSQLDA.1.SQLLEN.SQLPRECISION = 18 INSQLDA.1.SQLLEN.SQLSCALE = 8 INSQLDA.1.SQLDATA = 9876543210.87654321 /* /* /* /* /* SQLDA contains one variable Type of variable is DECIMAL Precision of variable is 18 Scale of variable is 8 Value in variable */ */ */ */ */ Assembler syntax for host variable declarations In assembler programs, you can specify numeric, character, graphic, binary, LOB, XML, and ROWID host variables. You can also specify result set, table, and LOB locators and LOB and XML file reference variables. Only some of the valid assembler declarations are valid host variable declarations. If the declaration for a host variable is not valid, any SQL statement that references the variable might result in the message UNDECLARED HOST VARIABLE. Numeric host variables: The following diagram shows the syntax for declarations of numeric host variables. The numeric value specifies the scale of the packed decimal variable. If value does not include a decimal point, the scale is 0. 148 Application Programming and SQL Guide
  • 165.
    | variable-name DC DS H 1 L2 F L4 FD L8 ’value’ P Ln E L4 EH L4 EB L4 ED L4 D L8 DH L8 DB L8 DD L8 LD L16 For floating-point datatypes (E, EH, EB, D, DH, and DB), DB2 uses the FLOAT precompiler option to determine whether the host variable is in IEEE binary floating-point or z/Architecture® hexadecimal floating-point format. If the precompiler option is FLOAT(S390), you need to define your floating-point host variables as E, EH, D, or DH. If the precompiler option is FLOAT(IEEE), you need to define your floating-point host variables as EB or DB. DB2 converts all floating-point input data to z/Architecture hexadecimal floating-point format before storing it. For more information about z/Architecture hexadecimal floating-point format, see z/Architecture Principles of Operation. | | The FLOAT precompiler options do not apply to the decimal floating-point host variable types ED, DD, or LD. For the decimal floating-point host variable types ED, DD, LD, you can specify the following special values: MIN, MAX, NAN, SNAN, and INFINITY. For descriptions of these special values, see High Level Assembler for MVS and VM and VSE Language Reference at http://www.ibm.com/software/awdtools/hlasm/ library.html. Character host variables: The three valid forms for character host variables are: v Fixed-length strings v Varying-length strings v CLOBs The following figures show the syntax for forms other than CLOBs. The following diagram shows the syntax for declarations of fixed-length character strings. Chapter 3. Including DB2 queries in an application program 149
  • 166.
    variable-name DC DS C 1 Ln The following diagramshows the syntax for declarations of varying-length character strings. variable-name DC DS H 1 , CLn L2 1 Graphic host variables: The three valid forms for graphic host variables are: v Fixed-length strings v Varying-length strings v DBCLOBs The following figures show the syntax for forms other than DBCLOBs. In the syntax diagrams, value denotes one or more DBCS characters, and the symbols < and > represent shift-out and shift-in characters. The following diagram shows the syntax for declarations of fixed-length graphic strings. variable-name DC DS G Ln ’<value>’ Ln’<value>’ The following diagram shows the syntax for declarations of varying-length graphic strings. variable-name DS DC H , L2 ’m’ GLn ’<value>’ Binary host variables: The following diagram shows the syntax for declarations of binary host variables. (1) variable-name DS X Ln Notes: 1 1 ≤ n ≤255 Varbinary host variables: The following diagram shows the syntax for declarations of varbinary host variables. (1) variable-name DS H Notes: 1 150 1 ≤ n ≤ 32704 Application Programming and SQL Guide L2 , X Ln
  • 167.
    Result set locators:The following diagram shows the syntax for declarations of result set locators. variable-name DC DS F 1 L4 Table Locators: The following diagram shows the syntax for declarations of table locators. See “Accessing transition tables in a user-defined function or stored procedure” on page 473 for a discussion of how to use these host variables. variable-name SQL TYPE IS TABLE LIKE table-name AS LOCATOR | | | | LOB variables, locators, and file reference variables: The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variables, locators, and file reference variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use LOB host variables. variable-name SQL TYPE IS | | | | BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_LOCATOR CLOB_LOCATOR DBCLOB_LOCATOR BLOB_FILE CLOB_FILE DBCLOB_FILE length K M G XML data host and file reference variablesThe following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variables, and file reference variables, for XML data types. variable-name SQL TYPE IS XML AS BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_FILE CLOB_FILE DBCLOB_FILE length K M G | | If you specify the length of the LOB in terms of KB, MB, or GB, you must leave no spaces between the length and K, M, or G. ROWIDs: The following diagram shows the syntax for declarations of ROWID host variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. variable-name SQL TYPE IS ROWID Chapter 3. Including DB2 queries in an application program 151
  • 168.
    Notes on assemblervariable declaration and usage You should be aware of the following considerations when you declare assembler variables. Host graphic data type: You can use the assembler data type “host graphic” in SQL statements when the precompiler option GRAPHIC is in effect. However, you cannot use assembler DBCS literals in SQL statements, even when GRAPHIC is in effect. Character host variables: If you declare a host variable as a character string without a length, for example DC C ’ABCD’, DB2 interprets it as length 1. To get the correct length, give a length attribute (for example, DC CL4’ABCD’). Floating-point host variables: All floating-point data is stored in DB2 in z/Architecture hexadecimal floating-point format. However, your host variable data can be in z/Architecture hexadecimal floating-point format or IEEE binary floating-point format. DB2 uses the FLOAT precompiler option to determine whether your floating-point host variables are in IEEE binary floating-point format or z/Architecture hexadecimal floating-point format. DB2 does no checking to determine whether the host variable declarations or format of the host variable contents match the precompiler option. Therefore, you need to ensure that your floating-point host variable types and contents match the precompiler option. Special purpose assembler data types: The locator data types are assembler language data types and SQL data types. You cannot use locators as column types. For information about how to use these data types, see the following topics: Table locator “Accessing transition tables in a user-defined function or stored procedure” on page 473 LOB locators “Large objects (LOBs)” on page 390 LOB file reference variables “Large objects (LOBs)” on page 390 Overflow: Be careful of overflow. For example, suppose you retrieve an INTEGER column value into a DS H host variable, and the column value is larger than 32767. You get an overflow warning or an error, depending on whether you provided an indicator variable. Truncation: Be careful of truncation. For example, if you retrieve an 80-character CHAR column value into a host variable declared as DS CL70, the rightmost ten characters of the retrieved string are truncated. If you retrieve a floating-point or decimal column value into a host variable declared as DS F, it removes any fractional part of the value. C and C++ syntax for host variable declarations In C and C++ programs, you can specify numeric, character, graphic, binary, LOB, XML, and ROWID host variables. You can also specify result set, table, and LOB locators and LOB and XML file reference variables. Only some of the valid C declarations are valid host variable declarations. If the declaration for a variable is not valid, any SQL statement that references the variable might result in the message UNDECLARED HOST VARIABLE. 152 Application Programming and SQL Guide
  • 169.
    Numeric host variablesin C or C++ The following diagram shows the syntax for declarations of numeric host variables. | auto extern static const volatile float double int short sqlint32 int long int long long decimal ( precision ) , scale , variable-name *pointer-name ; =expression Notes: 1. The DB2 coprocessor is required if you use the pointer notation of the host variable. Character host variables in C or C++ The four valid forms for character host variables are: v Single-character form v NUL-terminated character form v VARCHAR structured form v CLOBs The following diagrams show the syntax for forms other than CLOBs. The following diagram shows the syntax for declarations of single-character host variables. , char auto extern static const volatile unsigned variable-name *pointer-name ; =expression Notes: 1. The DB2 coprocessor is required if you use the pointer notation of the host variable. The following diagram shows the syntax for declarations of NUL-terminated character host variables. Chapter 3. Including DB2 queries in an application program 153
  • 170.
    char auto extern static const volatile unsigned , variable-name *pointer-name [ length ] ; =expression Notes: 1. Oninput, the string contained by the variable must be NUL-terminated. 2. On output, the string is NUL-terminated. 3. A NUL-terminated character host variable maps to a varying-length character string (except for the NUL). 4. The DB2 coprocessor is required if you use the pointer notation of the host variable. The following diagram shows the syntax for declarations of varying-length character host variables that use the VARCHAR structured form. int struct auto extern static const volatile { short var-1 ; tag char var-2 [ length ] ; } unsigned , variable-name *pointer-name ; ={expression, expression} Notes: 1. You cannot use var-1 and var-2 as host variables in an SQL statement. 2. You can use the struct tag to define other variables, but you cannot use them as host variables in SQL. 3. The DB2 coprocessor is required if you use the pointer notation of the host variable. Example: The following examples show valid and invalid declarations of the VARCHAR structured form: EXEC SQL BEGIN DECLARE SECTION; /* valid declaration of host variable VARCHAR vstring */ struct VARCHAR { short len; char s[10]; 154 Application Programming and SQL Guide
  • 171.
    } vstring; /* invaliddeclaration of host variable VARCHAR wstring */ struct VARCHAR wstring; Graphic host variables in C or C++ The four valid forms for graphic host variables are: v Single-graphic form v NUL-terminated graphic form v VARGRAPHIC structured form. v DBCLOBs Recommendation: Instead of using the C data type wchar_t to define graphic and vargraphic host variables, use one of the following techniques: v Define the sqldbchar data type by using the following typedef statement: typedef unsigned short sqldbchar; v Use the sqldbchar data type that is defined in the typedef statement in the header files that are supplied by DB2. v Use the C data type unsigned short. The following diagrams show the syntax for forms other than DBCLOBs. The following diagram shows the syntax for declarations of single-graphic host variables. , sqldbchar auto extern static const volatile variable-name *pointer-name ; =expression The single-graphic form declares a fixed-length graphic string of length 1. You cannot use array notation in variable-name. The following diagram shows the syntax for declarations of NUL-terminated graphic host variables. , sqldbchar auto extern static const volatile variable-name *pointer-name [ length ] ; =expression Notes: 1. length must be a decimal integer constant greater than 1 and not greater than 16352. 2. On input, the string in variable-name must be NUL-terminated. 3. On output, the string is NUL-terminated. 4. The NUL-terminated graphic form does not accept single-byte characters into variable-name. 5. The DB2 coprocessor is required if you use the pointer notation of the host variable. Chapter 3. Including DB2 queries in an application program 155
  • 172.
    The following diagramshows the syntax for declarations of graphic host variables that use the VARGRAPHIC structured form. int struct auto extern static const volatile sqldbchar var-2 [ length ] { short var-1 ; tag ; } , variable-name *pointer-name ; ={ expression, expression} Notes: 1. length must be a decimal integer constant greater than 1 and not greater than 16352. 2. var-1 must be less than or equal to length. 3. You cannot use var-1 and var-2 as host variables in an SQL statement. 4. You can use the struct tag to define other variables, but you cannot use them as host variables in SQL. 5. The DB2 coprocessor is required if you use the pointer notation of the host variable. Example: The following examples show valid and invalid declarations of graphic host variables that use the VARGRAPHIC structured form: EXEC SQL BEGIN DECLARE SECTION; /* valid declaration of host variable structured vgraph */ struct VARGRAPH { short len; sqldbchar d[10]; } vgraph; /* invalid declaration of host variable structured wgraph */ struct VARGRAPH wgraph; Binary host variables in C or C++ | | | | The three valid forms of BINARY host variables are: v Fixed-length strings v Varying-length strings v BLOBs | | The following diagram shows the syntax for declarations of BINARY host variables. The following diagrams show the syntax for forms other than BLOBs. 156 Application Programming and SQL Guide
  • 173.
    | , SQL TYPE ISBINARY ( length ) auto extern static variable-name ; const volatile | | | Notes: 1. For BINARY host variables, the length must be in the range from 1 to 255. | | The following diagram shows the syntax for declarations of VARBINARY host variables. | | SQL TYPE IS auto extern static | | const volatile (1) VARBINARY BINARY VARYING ( length ) , variable-name ; = { init-len , ″ init-data ″ } | | Notes: | | 1 | The C language does not have variables that correspond to the SQL binary data types BINARY and VARBINARY. To create host variables that can be used with these data types, use the SQL TYPE IS clause. The SQL precompiler replaces this declaration with the C language structure in the output source member. | | | | When you refer to a BINARY or VARBINARY host variable in an SQL statement, you must use the variable that you specify in the SQL TYPE declaration. When you refer to the host variable in a host language statement, you must use the variable that DB2 generates. | | Example: The following table shows examples of variables that DB2 generates when you declare binary host variables. | Table 44. Examples of BINARY and VARBINARY variable declarations for C | You declare this variable DB2 generates this variable | SQL TYPE IS BINARY(10) bin_var; char bin_var[10] | | | | | SQL TYPE IS VARBINARY(10) vbin_var; struct { short length; char data[10]; } vbin_var; | | | | | Important: Be careful when you use binary host variables with C and C++. The SQL TYPE declaration for BINARY and VARBINARY does not account for the NUL-terminator that C expects because binary strings are not NUL-terminated strings. Furthermore, the binary host variable might contain zeroes at any point in the string. For VARBINARY host variables, the length must be in the range from 1 to 32 704. Chapter 3. Including DB2 queries in an application program 157
  • 174.
    Result set locatorsin C or C++ The following diagram shows the syntax for declarations of result set locators. SQL TYPE IS RESULT_SET_LOCATOR VARYING auto extern static register const volatile , variable-name *pointer-name ; = init-value Table locators in C or C++ The following diagram shows the syntax for declarations of table locators. See “Accessing transition tables in a user-defined function or stored procedure” on page 473 for a discussion of how to use these host variables. auto extern static register const volatile SQL TYPE IS TABLE LIKE table-name AS LOCATOR , variable-name *pointer-name ; =init-value LOB variables and locators in C or C++ The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variables and locators. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. SQL TYPE IS auto extern static register 158 Application Programming and SQL Guide const volatile
  • 175.
    | BINARY LARGE OBJECT BLOB CHARACTERLARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_LOCATOR CLOB_LOCATOR DBCLOB_LOCATOR BLOB_FILE CLOB_FILE DBCLOB_FILE ( length ) K M G , variable-name *pointer-name ; (1) =init-value Notes: | | | | 1 Specify the initial value as a series of expressions. For example, specify ={expression, expression}. For BLOB_FILE, CLOB_FILE, and DBCLOB_FILE, specify ={name_length, data_length, file_option_map, file_name}. XML data host and file reference variables in C or C++ | | The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variables, and file reference variables, for XML data types. For examples of how to use XML host variables, see “XML column updates in embedded SQL applications” on page 324 and “XML data retrieval in embedded SQL applications” on page 327. | SQL TYPE IS auto extern static register XML XML XML XML XML XML const volatile AS AS AS AS AS AS BLOB CLOB DBCLOB BLOB_FILE CLOB_FILE DBCLOB_FILE , (1) variable-name *pointer-name ; =init-value Notes: | | | | 1 Specify the initial value as a series of expressions. For example, specify ={expression, expression}. For BLOB_FILE, CLOB_FILE, and DBCLOB_FILE, specify ={name_length, data_length, file_option_map, file_name}. Chapter 3. Including DB2 queries in an application program 159
  • 176.
    ROWIDs in Cor C++ The following diagram shows the syntax for declarations of ROWID host variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. auto extern static register const volatile variable-name *pointer-name SQL TYPE IS ROWID ; Notes on C variable declaration and usage You should be aware of the following considerations when you declare C variables. C data types with no SQL equivalent: C supports some data types and storage classes with no SQL equivalents, for example, register storage class, typedef, and long long,. SQL data types with no C equivalent: If your C compiler does not have a decimal data type, no exact equivalent exists for the SQL DECIMAL data type. In this case, to hold the value of such a variable, you can use: v An integer or floating-point variable, which converts the value. If you choose integer, you will lose the fractional part of the number. If the decimal number can exceed the maximum value for an integer, or if you want to preserve a fractional value, you can use floating-point numbers. Floating-point numbers are approximations of real numbers. Therefore, when you assign a decimal number to a floating-point variable, the result might be different from the original number. v A character-string host variable. Use the CHAR function to get a string representation of a decimal number. v The DECIMAL function to explicitly convert a value to a decimal data type, as in this example: long duration=10100; char result_dt[11]; /* 1 year and 1 month */ EXEC SQL SELECT START_DATE + DECIMAL(:duration,8,0) INTO :result_dt FROM TABLE1; The SQL data type DECFLOAT also has no equivalent in C. | Floating-point host variables: All floating-point data is stored in DB2 in z/Architecture hexadecimal floating-point format. However, your host variable data can be in z/Architecture hexadecimal floating-point format or IEEE binary floating-point format. DB2 uses the FLOAT precompiler option to determine whether your floating-point host variables are in IEEE binary floating-point or z/Architecture hexadecimal floating-point format. DB2 does no checking to determine whether the contents of a host variable match the precompiler option. Therefore, you need to ensure that your floating-point data format matches the precompiler option. Graphic host variables: You can define graphic host variables by using one of the following techniques: v Define the sqldbchar data type by using the following typedef statement: | | | 160 Application Programming and SQL Guide
  • 177.
    | | | | | | | | | | typedef unsigned shortsqldbchar; Use sqldbchar instead of wchar_t. Using sqldbchar or unsigned short lets you manipulate DBCS and Unicode UTF-16 data in the same format in which it is stored in DB2. Using sqldbchar also makes applications easier to port to other DB2 platforms. v Use the C data type unsigned short. v Use the typedef statements in one of the following files or libraries: 1. SQL library, sql.h 2. DB2 CLI library, sqlcli.h 3. SQLUDF file in data set DSN910.SDSNC.H | Special locator C data types: The following locator data types are special SQL data types that do not have C equivalents: v Result set locator v Table locator v LOB locators | You cannot use them to define column types. | | | | String host variables: For NUL-terminated string host variables, use the SQL processing options PADNTSTR and NOPADNTSTR to specify whether the variable should be padded with blanks. For a description of these options, see Table 148 on page 854. The option that you specify determines where the NUL-terminator is placed. If you assign a string of length n to a NUL-terminated string host variable, the variable has one of the values that is shown in the following table. Table 45. Value of a NUL-terminated string host variable that is assigned a string of length n If the length of the NUL-terminated string host variable is... Less than or equal to n The variable is set to... The source string up to a length of n-1 and a NUL at the end of the string. 1 DB2 sets SQLWARN[1] to W and any indicator variable that you provide to the original length of the source string. Equal to n+1 The source string and a NUL at the end of the string. 1 Greater than n+1 and the source is a fixed-length string If PADNTSTR is in effect The source string, blanks to pad the value, and a NUL at the end of the string. If NOPADNTSTR is in effect The source string and a NUL at the end of the string. Greater than n+1 and the source is a varying-length string The source string and a NUL at the end of the string. 1 Note: 1. In these cases, whether NOPADNTSTR or PADNTSTR is in effect is irrelevant. Chapter 3. Including DB2 queries in an application program 161
  • 178.
    PREPARE or DESCRIBEstatements: You cannot use a host variable that is of the NUL-terminated form in either a PREPARE or DESCRIBE statement when you use the DB2 precompiler. However, if you use the DB2 coprocessor for either C or C++, you can use host variables of the NUL-terminated form in PREPARE, DESCRIBE, and EXECUTE IMMEDIATE statements. L-literals: DB2 tolerates L-literals in C application programs. DB2 allows properly formed L-literals, although it does not check for all the restrictions that the C compiler imposes on the L-literal. You can use DB2 graphic string constants in SQL statements to work with the L-literal. Do not use L-literals in SQL statements. Overflow: Be careful of overflow. For example, suppose you retrieve an INTEGER column value into a short integer host variable and the column value is larger than 32767. You get an overflow warning or an error, depending on whether you provide an indicator variable. Truncation: Be careful of truncation. Ensure that the host variable you declare can contain the data and a NUL terminator, if needed. Retrieving a floating-point or decimal column value into a long integer host variable removes any fractional part of the value. Notes on syntax differences for constants in C or C++ You should be aware of the following syntax differences for constants. Decimal constants versus real constants: In C, a string of digits with a decimal point is interpreted as a real constant. In an SQL statement, such a string is interpreted as a decimal constant. You must use exponential notation when specifying a real (that is, floating-point) constant in an SQL statement. In C, a real (floating-point) constant can have a suffix of f or F to show a data type of float or a suffix of l or L to show a type of long double. A floating-point constant in an SQL statement must not use these suffixes. Integer constants: In C, you can provide integer constants in hexadecimal form if the first two characters are 0x or 0X. You cannot use this form in an SQL statement. In C, an integer constant can have a suffix of u or U to show that it is an unsigned integer. An integer constant can have a suffix of l or L to show a long integer. You cannot use these suffixes in SQL statements. Character and string constants: In C, character constants and string constants can use escape sequences. You cannot use the escape sequences in SQL statements. Apostrophes and quotation marks have different meanings in C and SQL. In C, you can use double quotation marks to delimit string constants, and apostrophes to delimit character constants. The following examples illustrate the use of quotation marks and apostrophes in C. v Quotation marks printf( "%d lines read. n", num_lines); v Apostrophes #define NUL ’0’ In SQL, you can use double quotation marks to delimit identifiers and apostrophes to delimit string constants. The following examples illustrate the use of apostrophes and quotation marks in SQL. v Quotation marks 162 Application Programming and SQL Guide
  • 179.
    SELECT "COL#1" FROMTBL1; v Apostrophes SELECT COL1 FROM TBL1 WHERE COL2 = ’BELL’; Character data in SQL is distinct from integer data. Character data in C is a subtype of integer data. COBOL syntax for host variable declarations In COBOL programs, you can specify numeric, character, graphic, binary, LOB, XML, and ROWID host variables. You can also specify result set and table locators and LOB and XML file reference variables. Only some of the valid COBOL declarations are valid host variable declarations. If the declaration for a variable is not valid, then any SQL statement that references the variable might result in the message UNDECLARED HOST VARIABLE. Numeric host variables The three valid forms of numeric host variables are: v Floating-point numbers v Integers and small integers v Decimal numbers The following diagram shows the syntax for declarations of floating-point or real host variables. 01 77 level-1 variable-name COMPUTATIONAL-1 COMP-1 COMPUTATIONAL-2 COMP-2 IS USAGE . IS VALUE numeric-constant Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. COMPUTATIONAL-1 and COMP-1 are equivalent. 3. COMPUTATIONAL-2 and COMP-2 are equivalent. The following diagram shows the syntax for declarations of integer and small integer host variables. | IS 01 77 level-1 variable-name PICTURE PIC S9(4) S9999 S9(9) S999999999 S9(18) Chapter 3. Including DB2 queries in an application program 163
  • 180.
    BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP IS USAGE IS VALUE numeric-constant . Notes: 1. level-1 indicatesa COBOL level between 2 and 48. 2. The COBOL binary integer data types BINARY, COMPUTATIONAL, COMP, COMPUTATIONAL-4, and COMP-4 are equivalent. 3. COMPUTATIONAL-5 (and COMP-5) are equivalent to the other COBOL binary integer data types if you compile the other data types with TRUNC(BIN). 4. Any specification for scale is ignored. The following diagram shows the syntax for declarations of decimal host variables. IS 01 77 level-1 variable-name PICTURE PIC picture-string IS USAGE PACKED-DECIMAL COMPUTATIONAL-3 COMP-3 IS DISPLAY NATIONAL SIGN CHARACTER LEADING SEPARATE . IS VALUE numeric-constant Character host variables The three valid forms of character host variables are: v Fixed-length strings v Varying-length strings v CLOBs The following diagrams show the syntax for forms other than CLOBs. 164 Application Programming and SQL Guide
  • 181.
    The following diagramshows the syntax for declarations of fixed-length character host variables. IS 01 77 level-1 variable-name PICTURE PIC picture-string . DISPLAY IS IS VALUE character-constant USAGE Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. The picture-string that is associated with these forms must be X(m) (or XX...X, with m instances of X), with 1 <= m <= 32767 for fixed-length strings. However, the maximum length of the CHAR data type (fixed-length character string) in DB2 is 255 bytes. The following diagram shows the syntax for declarations of varying-length character host variables. 01 level-1 variable-name . IS 49 var-1 PICTURE PIC S9(4) S9999 IS USAGE BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP . IS VALUE numeric-constant IS 49 var-2 PICTURE PIC picture-string . DISPLAY IS IS VALUE character-constant USAGE Notes: 1. level-1 indicates a COBOL level between 2 and 48. Chapter 3. Including DB2 queries in an application program 165
  • 182.
    2. DB2 usesthe full length of the S9(4) BINARY variable even though COBOL with TRUNC(STD) only recognizes values up to 9999. This can cause data truncation errors when COBOL statements execute and might effectively limit the maximum length of variable-length character strings to 9999. Consider using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation. 3. For fixed-length strings, the picture-string must be X(m) (or XX...X, with m instances of X), with 1 <= m <= 32767; for other strings, m cannot be greater than the maximum size of a varying-length character string. 4. You cannot directly reference var-1 and var-2 as host variables. 5. You cannot use an intervening REDEFINE at level 49. Graphic character host variables The three valid forms for graphic character host variables are: v Fixed-length strings v Varying-length strings v DBCLOBs The following diagrams show the syntax for forms other than DBCLOBs. The following diagram shows the syntax for declarations of fixed-length graphic host variables. IS 01 77 level-1 variable-name PICTURE PIC DISPLAY-1 NATIONAL IS picture-string . IS USAGE VALUE graphic-constant Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater than the maximum size of a varying-length graphic string. 3. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is supported only through the DB2 coprocessor. The following diagram shows the syntax for declarations of varying-length graphic host variables. 01 level-1 variable-name . IS 49 var-1 PICTURE PIC S9(4) S9999 IS USAGE 166 Application Programming and SQL Guide
  • 183.
    BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP . IS VALUE numeric-constant IS 49 var-2 PICTURE PIC picture-string IS USAGE DISPLAY-1 NATIONAL . IS VALUE graphic-constant Notes: 1. level-1indicates a COBOL level between 2 and 48. 2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL with TRUNC(STD) only recognizes values up to 9999. This can cause data truncation errors when COBOL statements execute and might effectively limit the maximum length of variable-length character strings to 9999. Consider using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation. 3. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater than the maximum size of a varying-length graphic string. 4. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is supported only through the DB2 coprocessor. 5. You cannot directly reference var-1 and var-2 as host variables. Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. PACKED-DECIMAL, COMPUTATIONAL-3, and COMP-3 are equivalent. The picture-string that is that is associated with these types must have the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9) or S9(i)V. 3. The picture-string that is associated with SIGN LEADING SEPARATE must have the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9 or S9...9V with i instances of 9). Binary host variables | | | | The three valid forms of BINARY host variables are: v Fixed-length strings v Varying-length strings v BLOBs | | The following diagram shows the syntax for declarations of BINARY and VARBINARY host variables. Chapter 3. Including DB2 queries in an application program 167
  • 184.
    | | IS USAGE 01 variable-name | | ( length) SQL TYPE IS BINARY VARBINARY BINARY VARYING . | Notes: 1. For BINARY host variables, the length must be in the range from 1 to 255. For VARBINARY host variables, the length must be in the range from 1 to 32 704. | | | COBOL does not have variables that correspond to the SQL binary types BINARY and VARBINARY. To create host variables that can be used with these data types, use the SQL TYPE IS clause. The SQL precompiler replaces this declaration with a COBOL language structure in the output source member. | | | | When you refer to a BINARY or VARBINARY host variable in an SQL statement, you must use the variable that you specify in the SQL TYPE declaration. When you refer to the host variable in a host language statement, you must use the variable that DB2 generates. | | Example: The following table shows examples of variables that DB2 generates when you declare binary host variables. | Table 46. Examples of BINARY and VARBINARY variable declarations for COBOL | You declare this variable DB2 generates this variable | 01 BIN-VAR USAGE IS SQL TYPE IS BINARY(10). 01 BIN-VAR PIC X(10). | 01 VBIN-VAR USAGE IS SQL TYPE IS VARBINARY(10). | | | 01 VBIN-VAR. 49 VBIN-VAR-LEN PIC S9(4) USAGE BINARY. 49 VBIN-VAR-TEXT PIC X(10). Result set locators The following diagram shows the syntax for declarations of result set locators. 01 variable-name SQL TYPE IS RESULT-SET-LOCATOR VARYING . IS USAGE Table Locators The following diagram shows the syntax for declarations of table locators. See “Accessing transition tables in a user-defined function or stored procedure” on page 473 for a discussion of how to use these host variables. 01 level-1 variable-name SQL TYPE IS TABLE LIKE table-name AS LOCATOR . IS USAGE Note: level-1 indicates a COBOL level between 2 and 48. 168 Application Programming and SQL Guide
  • 185.
    LOB variables andfile reference variables | | | | | The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB variables and file reference variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. 01 level-1 variable-name SQL TYPE IS IS USAGE | | BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB-LOCATOR CLOB-LOCATOR DBCLOB-LOCATOR BLOB-FILE CLOB-FILE DBCLOB-FILE ( length ) . K M G | | | | | The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variables, and file reference variables for XML data types. 01 level-1 variable-name SQL TYPE IS XML AS IS USAGE | | BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB-FILE CLOB-FILE DBCLOB-FILE ( length ) . K M G | | Note: level-1 indicates a COBOL level between 2 and 48. ROWIDs The following diagram shows the syntax for declarations of ROWID host variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. 01 level-1 variable-name SQL TYPE IS ROWID . IS USAGE Note: level-1 indicates a COBOL level between 2 and 48. Chapter 3. Including DB2 queries in an application program 169
  • 186.
    Notes on COBOLvariable declaration and usage You should be aware of the following considerations when you declare COBOL host variables. Controlling the CCSID IBM Enterprise COBOL for z/OS and the DB2 coprocessor support: v The NATIONAL data type that is used for declaring Unicode values in the UTF-16 format (that is, CCSID 1200). v The COBOL CODEPAGE compiler option that is used to specify the default EBCDIC CCSID of character data items. v The SQLCCSID compiler option to control whether the CODEPAGE compiler option will influence the processing of SQL host variables in your COBOL programs (available in Enterprise COBOL V3R4 or later). If you declare a host variable HV1 as USAGE NATIONAL, DB2 always handles HV1 as if you had used this DECLARE VARIABLE statement: DECLARE :HV1 VARIABLE CCSID 1200 When you specify the SQLCCSID compiler option, the COBOL DB2 coprocessor uses the CCSID that is specified in the CODEPAGE compiler option to indicate that all host variables of character data type, other than NATIONAL, are specified with that CCSID unless they are explicitly overridden by a DECLARE VARIABLE statement. Example: Assume that the COBOL CODEPAGE compiler option is specified as CODEPAGE(1141). The following code shows how you can control the CCSID: DATA DIVISION. 01 HV1 PIC N(10) USAGE NATIONAL. 01 HV2 PIC X(20) USAGE DISPLAY. 01 HV3 PIC X(30) USAGE DISPLAY. ... EXEC SQL DECLARE :HV3 VARIABLE CCSID 1047 END-EXEC. ... PROCEDURE DIVISION. ... EXEC SQL SELECT C1, C2, C3 INTO :HV1, :HV2, :HV3 FROM T1 END-EXEC. The CCSID for each of these host variables is: HV1 1200 HV2 1141 HV3 1047 When you specify the COBOL NOSQLCCSID compiler option, the CCSID that is specified in the CODEPAGE compiler option is used only for processing COBOL statements within the COBOL program; that CCSID is not used for the processing of host variables in SQL statements. DB2 uses the CCSIDs specified through DB2 mechanisms and defaults as host variable data value encodings. 170 Application Programming and SQL Guide
  • 187.
    Assume that theCOBOL NOSQLCCSID option is specified, the COBOL CODEPAGE compiler option is specified as CODEPAGE(1141), and the DB2 default single byte CCSID is set to 37. The CCSIDs for the host variables in this example or with the precompiler become: HV1 1200 HV2 37 HV3 1047 For further details on the COBOL SQLCCSID and NOSQLCCSID options, see the Enterprise COBOL for z/OS Programming Guide on the Enterprise COBOL for z/OS library Web page at http://www.ibm.com/software/awdtools/cobol/zos/library/. SQL data types with no COBOL equivalent If you are using a COBOL compiler that does not support decimal numbers of more than 18 digits, use one of the following data types to hold values of greater than 18 digits: v A decimal variable with a precision less than or equal to 18, if the actual data values fit. If you retrieve a decimal value into a decimal variable with a scale that is less than the source column in the database, the fractional part of the value might be truncated. v An integer or a floating-point variable, which converts the value. If you choose integer, you lose the fractional part of the number. If the decimal number might exceed the maximum value for an integer, or if you want to preserve a fractional value, you can use floating-point numbers. Floating-point numbers are approximations of real numbers. Therefore, when you assign a decimal number to a floating-point variable, the result might be different from the original number. v A character-string host variable. Use the CHAR function to retrieve a decimal value into it. | The SQL data type DECFLOAT also has no equivalent in COBOL. Special purpose COBOL data types The following locator data types are COBOL data types and SQL data types: v Result set locator v Table locator v LOB locators v LOB file reference variables You cannot use locators as column types. Level 77 data description entries One or more REDEFINES entries can follow any level 77 data description entry. However, you cannot use the names in these entries in SQL statements. Entries with the name FILLER are ignored. SMALLINT and INTEGER data types In COBOL, you declare the SMALLINT and INTEGER data types as a number of decimal digits. DB2 uses the full size of the integers (in a way that is similar to Chapter 3. Including DB2 queries in an application program 171
  • 188.
    processing with theTRUNC(BIN) compiler option) and can place larger values in the host variable than would be allowed in the specified number of digits in the COBOL declaration. If you compile with TRUNC(OPT) or TRUNC(STD), ensure that the size of numbers in your application is within the declared number of digits. For small integers that can exceed 9999, use S9(4) COMP-5 or compile with TRUNC(BIN). For large integers that can exceed 999 999 999, use S9(10) COMP-3 to obtain the decimal data type. If you use COBOL for integers that exceed the COBOL PICTURE, specify the column as decimal to ensure that the data types match and perform well. Overflow Be careful of overflow. For example, suppose you retrieve an INTEGER column value into a PICTURE S9(4) host variable and the column value is larger than 32767 or smaller than -32768. You get an overflow warning or an error, depending on whether you specify an indicator variable. VARCHAR, VARGRAPHIC, and VARBINARY data types If your varying-length string host variables receive values whose length is greater than 9999 bytes, compile the applications in which you use those host variables with the option TRUNC(BIN). TRUNC(BIN) lets the length field for the string receive a value of up to 32767 bytes. Truncation Be careful of truncation. For example, if you retrieve an 80-character CHAR column value into a PICTURE X(70) host variable, the rightmost 10 characters of the retrieved string are truncated. Retrieving a double precision floating-point or decimal column value into a PIC S9(8) COMP host variable removes any fractional part of the value. Similarly, retrieving a column value with DECIMAL data type into a COBOL decimal variable with a lower precision might truncate the value. Fortran syntax for host variable declations In Fortran programs, you can specify numeric, character, LOB, and ROWID host variables. You can also specify result set and LOB locators. Only some of the valid Fortran declarations are valid host variable declarations. If the declaration for a variable is not valid, any SQL statement that references the variable might result in the message UNDECLARED HOST VARIABLE. Numeric host variables: The following diagram shows the syntax for declarations of numeric host variables. 172 Application Programming and SQL Guide
  • 189.
    , INTEGER*2 variable-name *4 / numeric-constant / INTEGER *4 REAL REAL*8 DOUBLE PRECISION Characterhost variables: The following diagram shows the syntax for declarations of character host variables other than CLOBs. , CHARACTER variable-name *n *n / character-constant / Result set locators: The following diagram shows the syntax for declarations of result set locators. , SQL TYPE IS RESULT_SET_LOCATOR VARYING variable-name LOB Variables and Locators: The following diagram shows the syntax for declarations of BLOB and CLOB host variables and locators. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. SQL TYPE IS BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB BLOB_LOCATOR CLOB_LOCATOR ( length ) K M G variable-name ROWIDs: The following diagram shows the syntax for declarations of ROWID variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. SQL TYPE IS ROWID variable-name Notes on Fortran variable declaration and usage You should be aware of the following when you declare Fortran variables. Fortran data types with no SQL equivalent: Fortran supports some data types with no SQL equivalent (for example, REAL*16 and COMPLEX). In most cases, you can use Fortran statements to convert between the unsupported data types and the data types that SQL allows. Chapter 3. Including DB2 queries in an application program 173
  • 190.
    SQL data typeswith no Fortran equivalent: Fortran does not provide an equivalent for the decimal data type. To hold the value of such a variable, you can use: v An integer or floating-point variable, which converts the value. If you choose integer, however, you lose the fractional part of the number. If the decimal number can exceed the maximum value for an integer or you want to preserve a fractional value, you can use floating-point numbers. Floating-point numbers are approximations of real numbers. When you assign a decimal number to a floating-point variable, the result could be different from the original number. v A character string host variable. Use the CHAR function to retrieve a decimal value into it. The SQL data type DECFLOAT also has no equivalent in Fortran. | Special-purpose Fortran data types: The following locator data types are Fortran data types and SQL data types: v Result set locator v LOB locators You cannot use locators as column types. Overflow: Be careful of overflow. For example, if you retrieve an INTEGER column value into a INTEGER*2 host variable and the column value is larger than 32767 or -32768, you get an overflow warning or an error, depending on whether you provided an indicator variable. Truncation: Be careful of truncation. For example, if you retrieve an 80-character CHAR column value into a CHARACTER*70 host variable, the rightmost ten characters of the retrieved string are truncated. Retrieving a double-precision floating-point or decimal column value into an INTEGER*4 host variable removes any fractional value. Processing Unicode data: Because Fortran does not support graphic data types, Fortran applications can process only Unicode tables that use UTF-8 encoding. Notes on syntax differences for constants You should be aware of the following syntax differences for constants. Real constants: Fortran interprets a string of digits with a decimal point to be a real constant. An SQL statement interprets such a string to be a decimal constant. Therefore, use exponent notation when specifying a real (that is, floating-point) constant in an SQL statement. Exponent indicators: In Fortran, a real (floating-point) constant having a length of 8 bytes uses a D as the exponent indicator (for example, 3.14159D+04). An 8-byte floating-point constant in an SQL statement must use an E (for example, 3.14159E+04). PL/I syntax for host variable declarations In PL/I programs, you can specify numeric, character, graphic, binary, LOB, XML, and ROWID host variables. You can also specify result set, table, and LOB locators and LOB and XML file reference variables. 174 Application Programming and SQL Guide
  • 191.
    Only some ofthe valid PL/I declarations are valid host variable declarations. The precompiler uses the data attribute defaults that are specified in the PL/I DEFAULT statement. If the declaration for a host variable is not valid, any SQL statement that references the variable might result in the message UNDECLARED HOST VARIABLE. The precompiler uses only the names and data attributes of the variables; it ignores the alignment, scope, and storage attributes. Even though the precompiler ignores alignment, scope, and storage, if you ignore the restrictions on their use, you might have problems compiling the PL/I source code that the precompiler generates. These restrictions are as follows: v A declaration with the EXTERNAL scope attribute and the STATIC storage attribute must also have the INITIAL storage attribute. v If you use the BASED storage attribute, you must follow it with a PL/I element-locator-expression. v Host variables can be STATIC, CONTROLLED, BASED, or AUTOMATIC storage class, or options. However, CICS requires that programs be reentrant. Numeric host variables The following diagram shows the syntax for declarations of numeric host variables. DECLARE DCL variable-name , ( variable-name ) BINARY BIN DECIMAL DEC FIXED ( precision ) ,scale FLOAT ( precision ) Alignment and/or Scope and/or Storage Note: 1. You can specify host variable attributes in any order that is acceptable to PL/I. For example, BIN FIXED(31), BINARY FIXED(31), BIN(31) FIXED, and FIXED BIN(31) are all acceptable. 2. You can specify a scale only for DECIMAL FIXED. Character host variables The following diagram shows the syntax for declarations of character host variables, other than CLOBs. DECLARE DCL variable-name , ( variable-name ) Chapter 3. Including DB2 queries in an application program 175
  • 192.
    CHARACTER CHAR ( length ) VARYING VAR Alignmentand/or Scope and/or Storage Graphic host variables The following diagram shows the syntax for declarations of graphic host variables, other than DBCLOBs. DECLARE DCL variable-name , ( variable-name ) GRAPHIC ( length ) VARYING VAR Alignment and/or Scope and/or Storage Binary host variables The three valid forms of BINARY host variables are: v Fixed-length strings v Varying-length strings v BLOBs The following diagram shows the syntax for declarations of BINARY host variables. DECLARE DCL variable-name , SQL TYPE IS BINARY VARBINARY BINARY VARYING ( variable-name ) ( length ) ; Notes: 1. For BINARY host variables, the length must be in the range from 1 to 255. For VARBINARY host variables, the length must be in the range from 1 to 32 704. PL/I does not have variables that correspond to the SQL binary data types BINARY and VARBINARY. To create host variables that can be used with these data types, use the SQL TYPE IS clause. When you refer to a BINARY or VARBINARY host variable in an SQL statement, you must use the variable that you specify in the SQL TYPE declaration. When you refer to the host variable in a host language statement, you must use the variable that DB2 generates. 176 Application Programming and SQL Guide
  • 193.
    Example: The followingtable shows examples of variables that DB2 generates when you declare binary host variables. Table 47. Examples of BINARY and VARBINARY variable declarations for C You declare this variable DB2 generates this variable DCL BIN_VAR SQL TYPE IS BINARY(10); DCL BIN_VAR CHAR(10); DCL VBIN_VAR SQL TYPE IS VARBINARY(10); DCL VBIN_VAR CHAR(10) VAR; Result set locators The following diagram shows the syntax for declarations of result set locators. DECLARE DCL variable-name , ( variable-name ) SQL TYPE IS RESULT_SET_LOCATOR VARYING Alignment and/or Scope and/or Storage Table locators The following diagram shows the syntax for declarations of table locators. See “Accessing transition tables in a user-defined function or stored procedure” on page 473 for a discussion of how to use these host variables. DCL DECLARE variable-name , ( variable-name ) SQL TYPE IS TABLE LIKE table-name AS LOCATOR LOB variables, locators, and file reference variables | | | | | The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variables, locators, and file reference variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. A single PL/I declaration that contains a LOB variable declaration is limited to no more than 1000 lines of source code. DCL DECLARE variable-name , ( variable-name SQL TYPE IS ) Chapter 3. Including DB2 queries in an application program 177
  • 194.
    | BINARY LARGE OBJECT BLOB CHARACTERLARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_LOCATOR CLOB_LOCATOR DBCLOB_LOCATOR BLOB_FILE CLOB_FILE DBCLOB_FILE ( length ) K M G Note: Variable attributes such as STATIC and AUTOMATIC are ignored if specified on a LOB variable declaration. The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variables and file reference variables for XML data types. | | | | DCL DECLARE variable-name , ( | | SQL TYPE IS XML AS variable-name BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_FILE CLOB_FILE DBCLOB_FILE ( ) length ) K M G | Note: Variable attributes such as STATIC and AUTOMATIC are ignored if specified on a LOB variable declaration. | | ROWIDs The following diagram shows the syntax for declarations of ROWID host variables. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. DCL DECLARE variable-name , ( variable-name SQL TYPE IS ROWID ) Notes on PL/I variable declaration and usage You should be aware of the following when you declare PL/I variables. 178 Application Programming and SQL Guide
  • 195.
    PL/I data typeswith no SQL equivalent: PL/I supports some data types with no SQL equivalent (COMPLEX and BIT variables, for example). In most cases, you can use PL/I statements to convert between the unsupported PL/I data types and the data types that SQL supports. SQL data types with no PL/I equivalent: If the PL/I compiler you are using does not support a decimal data type with a precision greater than 15, use the following types of variables for decimal data: v Decimal variables with precision less than or equal to 15, if the actual data values fit. If you retrieve a decimal value into a decimal variable with a scale that is less than the source column in the database, the fractional part of the value might truncate. v An integer or a floating-point variable, which converts the value. If you choose integer, you lose the fractional part of the number. If the decimal number can exceed the maximum value for an integer or you want to preserve a fractional value, you can use floating-point numbers. Floating-point numbers are approximations of real numbers. When you assign a decimal number to a floating- point variable, the result could be different from the original number. v A character string host variable. Use the CHAR function to retrieve a decimal value into it. Floating-point host variables: All floating-point data is stored in DB2 in z/Architecture hexadecimal floating-point format. However, your host variable data can be in z/Architecture hexadecimal floating-point format or IEEE binary floating-point format. DB2 uses the FLOAT precompiler option to determine whether your floating-point host variables are in IEEE binary floating-point format or z/Architecture hexadecimal floating-point format. DB2 does no checking to determine whether the host variable declarations or format of the host variable contents match the precompiler option. Therefore, you need to ensure that your floating-point host variable types and contents match the precompiler option. Special purpose PL/I data types: The following locator data types are PL/I data types as well as SQL data types: v Result set locator v Table locator v LOB locators You cannot use locators as column types. PL/I scoping rules: The precompiler does not support PL/I scoping rules. Overflow: Be careful of overflow. For example, if you retrieve an INTEGER column value into a BIN FIXED(15) host variable and the column value is larger than 32767 or smaller than -32768, you get an overflow warning or an error, depending on whether you provided an indicator variable. Truncation: Be careful of truncation. For example, if you retrieve an 80-character CHAR column value into a CHAR(70) host variable, the rightmost ten characters of the retrieved string are truncated. Retrieving a double-precision floating-point or decimal column value into a BIN FIXED(31) host variable removes any fractional part of the value. Similarly, retrieving a column value with a DECIMAL data type into a PL/I decimal variable with a lower precision might truncate the value. Chapter 3. Including DB2 queries in an application program 179
  • 196.
    Pointers as hostvariables in C and C++ If you use the DB2 coprocessor, you can use pointer host variables with statically or dynamically allocated storage. These pointer host variables can point to numeric data, non-numeric data, or a structure. To declare pointer host variables, use an asterisk (*) to indicate that the variable is a pointer. To reference a pointer host variable in an SQL statement, specify the pointer host variable exactly as it was declared. You can use the following types of pointer host variables: scalar pointer host variable A host variable that points to numeric or non-numeric scalar data. The following table shows example declarations of scalar pointer host variables and example references to such variables. Table 48. Example declarations of and references to scalar pointer host variables Declaration Description Reference short *hvshortp; hvshortp is a pointer host variable that points to two bytes of storage. EXEC SQL set:*hvshortp=123; double *hvdoubp; hvdoubp is a pointer host variable that points to eight bytes of storage. EXEC SQL set:*hvdoubp=456; char (*hvcharpn) [20]; hvcharpn is a pointer host variable that points to a nul-terminated character array of up to 20 bytes. EXEC SQL set: *hvcharpn=’nul_terminated’; 1 Note: 1. When you reference pointers to nul-terminated character arrays, you do not have to include the parentheses that were part of the declaration. Restriction: You cannot use pointer host variables that point to character data of an unknown length. For example, the following specification is not supported: char * hvcharpu. Instead, for character pointer host variables, you must specify the length of the data by using a bounded character pointer host variable. A bounded character pointer host variable is a host variable that is declared as a structure with the following two elements: v A 4-byte field that contains the length of the storage area. v A pointer to the non-numeric dynamic storage area. Example of a bounded character pointer host variable: The following example declares a bounded character pointer host variable called hvbcharp with two elements: len and data: struct { unsigned long len; char * data; } hvbcharp; The following example references this bounded character pointer host variable: 180 Application Programming and SQL Guide
  • 197.
    hvcharp.len = dynlen;1 hvcharp.data = (char 8) malloc (hvcharp.len); 2 EXEC SQL set :hvcharp = ’data buffer with length’; 3 Note: 1. dynlen can be either a compile time constant or a variable with a value that is assigned at run time. 2. Storage is dynamically allocated for hvcharp.data. 3. The SQL statement references the name of the structure, not an element within the structure. array pointer host variables A host variable that is an array of pointers. The following table shows example declarations of array pointer host variables and examples references to such variables. Table 49. Example declarations of and references to array pointer host variables Declaration Description Reference short * hvarrpl[6] hvarrp1 is an array of 6 pointers that point EXEC SQL set:*hvarrpl[n]=123; to two bytes of storage each. double * hvarrp2[3] hvarrp2 is an array of 3 pointers that point EXEC SQL set:*hvarrp2[n]=456; to 8 bytes of storage each. struct { unsigned long len; char * data; } hvbarrp3[5]; hvbarrp3 is an array of 5 bounded character pointers. EXEC SQL set :hvarrp3[n] = ’data buffer with length’ 1 structure array host variable A host variable that points to a structure. Example: The following example declares a table structure called tbl_struct. struct tbl_struct { char colname[20]; small int colno; small int coltype; small int collen; }; The following example declares a pointer to the structure tbl_struct. Storage is allocated dynamically for up to n rows. struct tbl_struct *ptr_tbl_struct = (struct tbl_struct *) malloc (sizeof (struct tbl_struct) * n); To reference this data is SQL statements, use the pointer as shown in the following example. Assume that tbl_sel_cur is a declared cursor. for (L_col_cnt = 0; L_col_cnt < n; L_con_cnt++) { ... EXEC SQL FETCH tbl_sel_cur INTO :ptr_tbl_struct [L_col_cnt] ... } Restriction: You cannot use untyped pointers. For example, the following declaration is not supported: void * untypedprt . Chapter 3. Including DB2 queries in an application program 181
  • 198.
    Host variable arraysin an SQL statement Use host variable arrays in embedded SQL statements to represent values that the program does not know until the query is executed. Host variable arrays are useful for storing a set of retrieved values or for passing a set of values that are to be inserted into a table. To use a host variable array in an SQL statement, specify any valid host variable array that is declared according to the host language rules that are described in “Embedding SQL statements in your application” on page 243. You can specify host variable arrays in C or C++, COBOL, and PL/I. You must declare the array in the host program before you use it. | | | | Assembler support for multiple-row FETCH is limited to the FETCH statement with the INTO DESCRIPTOR clause. For example: | | | | | | | | | | | | | | | | | Assembler support for multiple-row INSERT is limited to the following cases: | | Restriction: Assembler does not support multiple-row MERGE. You cannot specify MERGE statements that reference host variable arrays. | | The DB2 precompiler does not recognize declarations of host variable arrays for assembler; it recognizes these declarations only in C, COBOL, and PL/I. EXEC SQL FETCH NEXT ROWSET FROM C1 FOR 10 ROWS INTO DESCRIPTOR :SQLDA X v static multiple-row INSERT statement with scalar values (scalar host variables or scalar expressions) in the VALUES clause. For example: EXEC SQL INSERT INTO T1 VALUES (1, CURRENT DATE, ’TEST’) FOR 10 ROWS X v dynamic multiple-row INSERT executed with the USING DESCRIPTOR clause on the EXECUTE statement. For example: ATR S1 DS CL20 ATTRIBUTES FOR PREPARE DS H,CL30 VARCHAR STATEMENT STRING MVC ATR(20),=C’FOR MULTIPLE ROWS ’ MVC S1(2),=H’25’ MVC S1+2(30),=C’INSERT INTO T1 VALUES (?) ’ EXEC SQL PREPARE STMT ATTRIBUTES :ATR FROM :S1 EXEC SQL EXECUTE STMT USING DESCRIPTOR :SQLDA FOR 10 ROWS where the descriptor is set up correctly in advance according to the specifications for dynamic execution of a multiple-row INSERT statement with a descriptor Retrieving multiple rows of data into host variable arrays If you know that your query returns multiple rows, you can specify host variable arrays to store the retrieved column values. You can use host variable arrays to specify a program data area to contain multiple rows of column values. A DB2 rowset cursor enables an application to retrieve and process a set of rows from the result table of the cursor. For information about using rowset cursors, see “Accessing data by using a rowset-positioned cursor” on page 636. Inserting multiple rows of data from host variable arrays When you want to insert multiple rows of data into a DB2 table, but you do not know at least some of the values to insert until the program runs, use host variable arrays in your INSERT statement. 182 Application Programming and SQL Guide
  • 199.
    | | | | | | | You can usea form of the INSERT statement or MERGE statement to insert multiple rows from values that are provided in host variable arrays. Each array contains values for a column of the target table. The first value in an array corresponds to the value for that column for the first inserted row, the second value in the array corresponds to the value for the column in the second inserted row, and so on. DB2 determines the attributes of the values based on the declaration of the array. Example: You can insert the number of rows that are specified in the host variable NUM-ROWS by using the following INSERT statement: EXEC SQL INSERT INTO DSN8910.ACT (ACTNO, ACTKWD, ACTDESC) VALUES (:HVA1, :HVA2, :HVA3) FOR :NUM-ROWS ROWS END-EXEC. Assume that the host variable arrays HVA1, HVA2, and HVA3 have been declared and populated with the values that are to be inserted into the ACTNO, ACTKWD, and ACTDESC columns. The NUM-ROWS host variable specifies the number of rows that are to be inserted, which must be less than or equal to the dimension of each host variable array. C and C++ syntax for host variable array declarations In C and C++ programs, you can specify numeric, character, graphic, binary, LOB, XML, and ROWID host variable arrays. You can also specify LOB locators and LOB and XML file reference variables. Only some of the valid C declarations are valid host variable array declarations. If the declaration for a variable array is not valid, then any SQL statement that references the variable array might result in the message UNDECLARED HOST VARIABLE ARRAY. | | | | | For both C and C++, you cannot specify the _packed attribute on the structure declarations for varying-length character arrays, varying-length graphic arrays, or LOB arrays that are to be used in multiple-row INSERT, FETCH, and MERGE statements. In addition, the #pragma pack(1) directive cannot be in effect if you plan to use these arrays in multiple-row statements. Numeric host variable arrays in C or C++ The following diagram shows the syntax for declarations of numeric host variable arrays. auto extern static const volatile unsigned Chapter 3. Including DB2 queries in an application program 183
  • 200.
    float double int long short int long long decimal ( precision ) ,scale , variable-name [ dimension ] ; , = { expression } Note: 1. dimension must be an integer constant between 1 and 32767. Example: The following example shows a declaration of a numeric host variable array: EXEC SQL BEGIN DECLARE SECTION; /* declaration of numeric host variable array */ long serial_num[10]; ... EXEC SQL END DECLARE SECTION; Character host variable arrays in C or C++ The three valid forms for character host variable arrays are: v NUL-terminated character form v VARCHAR structured form v CLOBs The following diagrams show the syntax for forms other than CLOBs. The following diagram shows the syntax for declarations of NUL-terminated character host variable arrays. char auto extern static const volatile unsigned , variable-name [ dimension ] [ length ] ; , = { expression } Notes: 1. On input, the strings contained in the variable arrays must be NUL-terminated. 184 Application Programming and SQL Guide
  • 201.
    2. On output,the strings are NUL-terminated. 3. The strings in a NUL-terminated character host variable array map to varying-length character strings (except for the NUL). 4. dimension must be an integer constant between 1 and 32767. The following diagram shows the syntax for declarations of varying-length character host variable arrays that use the VARCHAR structured form. int struct auto extern static { short var-1 ; const volatile char var-2 [ length ] ; } unsigned , variable-name [ dimension ] ; , = { | | expression } Notes: 1. var-1 must be a scalar numeric variable, and var-2 must be a scalar CHAR array variable. 2. You can use the struct tag to define other variables, but you cannot use them as host variable arrays in SQL. 3. dimension must be an integer constant between 1 and 32767. Example: The following examples show valid and invalid declarations of VARCHAR host variable arrays: EXEC SQL BEGIN DECLARE SECTION; /* valid declaration of VARCHAR host variable array */ struct VARCHAR { short len; char s[18]; } name[10]; /* invalid declaration of VARCHAR host variable array */ struct VARCHAR name[10]; Binary host variable arrays in C or C++ | | | The following diagram shows the syntax for declarations of binary host variable arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variable arrays. | Chapter 3. Including DB2 queries in an application program 185
  • 202.
    | | SQL TYPE IS auto extern static register | | BINARY VARBINARY const volatile (length) , variable-name[ dimension ] ; | Note: 1. dimension must be an integer constant between 1 and 32767. | Graphic host variable arrays in C or C++ The two valid forms for graphic host variable arrays are: v NUL-terminated graphic form v VARGRAPHIC structured form. Recommendation: Instead of using the C data type wchar_t to define graphic and vargraphic host variable arrays, use one of the following techniques: v Define the sqldbchar data type by using the following typedef statement: typedef unsigned short sqldbchar; v Use the sqldbchar data type that is defined in the typedef statement in the header files that are supplied by DB2. v Use the C data type unsigned short. The following diagram shows the syntax for declarations of NUL-terminated graphic host variable arrays. sqldbchar auto extern static const volatile unsigned , variable-name [ dimension ] [ length ] ; , = { expression } Notes: 1. length must be a decimal integer constant greater than 1 and not greater than 16352. 2. On input, the strings contained in the variable arrays must be NUL-terminated. 3. On output, the string is NUL-terminated. 4. The NUL-terminated graphic form does not accept single-byte characters into the variable array. 5. dimension must be an integer constant between 1 and 32767. 186 Application Programming and SQL Guide
  • 203.
    The following diagramshows the syntax for declarations of graphic host variable arrays that use the VARGRAPHIC structured form. int struct auto extern static { short var-1 ; const volatile sqldbchar var-2 [ length ] ; } unsigned , variable-name [ dimension ] ; , = { expression } Notes: 1. length must be a decimal integer constant greater than 1 and not greater than 16352. 2. var-1 must be a scalar numeric variable, and var-2 must be a scalar char array variable. 3. You can use the struct tag to define other variables, but you cannot use them as host variable arrays in SQL. 4. dimension must be an integer constant between 1 and 32767. Example: The following examples show valid and invalid declarations of graphic host variable arrays that use the VARGRAPHIC structured form: EXEC SQL BEGIN DECLARE SECTION; /* valid declaration of host variable array vgraph */ struct VARGRAPH { short len; sqldbchar d[10]; } vgraph[20]; /* invalid declaration of host variable array vgraph */ struct VARGRAPH vgraph[20]; LOB, locator, file reference, and XML variable arrays in C or C++ The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable arrays and locators. See “Large objects (LOBs)” on page 390 for a discussion of how to use LOB variables. SQL TYPE IS auto extern static register const volatile Chapter 3. Including DB2 queries in an application program 187
  • 204.
    | BINARY LARGE OBJECT BLOB CHARACTERLARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_LOCATOR CLOB_LOCATOR DBCLOB_LOCATOR BLOB_FILE CLOB_FILE DBCLOB_FILE ( length ) K M G , variable-name [ dimension ] ; , = { expression } Note: 1. dimension must be an integer constant between 1 and 32767. The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable arrays, and file reference variable arrays for XML data types SQL TYPE IS XML AS auto extern static register | const volatile BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_FILE CLOB_FILE DBCLOB_FILE ( length ) K M G , variable-name [ dimension ] ; , = { Note: 188 Application Programming and SQL Guide expression }
  • 205.
    1. dimension mustbe an integer constant between 1 and 32767. ROWID variable arrays in C or C++ The following diagram shows the syntax for declarations of ROWID variable arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variable arrays. , SQL TYPE IS ROWID auto extern static register variable-name [ dimension ] ; const volatile Note: 1. dimension must be an integer constant between 1 and 32767. COBOL syntax for host variable array declarations In COBOL programs, you can specify numeric, character, graphic, LOB, XML, and ROWID host variable arrays. You can also specify LOB locators and LOB and XML file reference variables. Only some of the valid COBOL declarations are valid host variable array declarations. If the declaration for a variable array is not valid, any SQL statement that references the variable array might result in the message UNDECLARED HOST VARIABLE ARRAY. Numeric host variable arrays: The three valid forms of numeric host variable arrays are: v Floating-point numbers v Integers and small integers v Decimal numbers The following diagram shows the syntax for declarations of floating-point host variable arrays. level-1 variable-name COMPUTATIONAL-1 COMP-1 COMPUTATIONAL-2 COMP-2 IS USAGE OCCURS dimension . TIMES IS VALUE numeric-constant Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. COMPUTATIONAL-1 and COMP-1 are equivalent. 3. COMPUTATIONAL-2 and COMP-2 are equivalent. 4. dimension must be an integer constant between 1 and 32767. The following diagram shows the syntax for declarations of integer and small integer host variable arrays. Chapter 3. Including DB2 queries in an application program 189
  • 206.
    IS level-1 variable-name PICTURE PIC S9(4) S9999 S9(9) S999999999 BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP IS USAGE OCCURS dimension TIMES . IS VALUE numeric-constant Notes: 1.level-1 indicates a COBOL level between 2 and 48. 2. The COBOL binary integer data types BINARY, COMPUTATIONAL, COMP, COMPUTATIONAL-4, and COMP-4 are equivalent. 3. COMPUTATIONAL-5 (and COMP-5) are equivalent to the other COBOL binary integer data types if you compile the other data types with TRUNC(BIN). 4. Any specification for scale is ignored. 5. dimension must be an integer constant between 1 and 32767. The following diagram shows the syntax for declarations of decimal host variable arrays. IS level-1 variable-name PICTURE PIC picture-string IS USAGE PACKED-DECIMAL COMPUTATIONAL-3 COMP-3 IS DISPLAY NATIONAL SIGN CHARACTER LEADING SEPARATE OCCURS dimension . TIMES IS VALUE numeric-constant Notes: 1. level-1 indicates a COBOL level between 2 and 48. 190 Application Programming and SQL Guide
  • 207.
    2. PACKED-DECIMAL, COMPUTATIONAL-3,and COMP-3 are equivalent. The picture-string that is associated with these types must have the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9) or S9(i)V. 3. The picture-string that is associated with SIGN LEADING SEPARATE must have the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9 or S9...9V with i instances of 9). 4. dimension must be an integer constant between 1 and 32767. Character host variable arrays: The three valid forms of character host variable arrays are: v Fixed-length character strings v Varying-length character strings v CLOBs The following diagrams show the syntax for forms other than CLOBs. The following diagram shows the syntax for declarations of fixed-length character string arrays. IS level-1 variable-name PICTURE PIC picture-string OCCURS dimension DISPLAY TIMES IS USAGE . IS VALUE character-constant Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. The picture-string that is associated with these forms must be X(m) (or XX...X, with m instances of X), with 1 <= m <= 32767 for fixed-length strings. However, the maximum length of the CHAR data type (fixed-length character string) in DB2 is 255 bytes. 3. dimension must be an integer constant between 1 and 32767. The following diagram shows the syntax for declarations of varying-length character string arrays. level-1 variable-name OCCURS dimension . TIMES IS 49 var-1 PICTURE PIC S9(4) S9999 IS USAGE Chapter 3. Including DB2 queries in an application program 191
  • 208.
    BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP SYNCHRONIZED SYNC IS VALUE numeric-constant . IS 49 var-2 PICTURE PIC picture-string . DISPLAY IS IS VALUE character-constant USAGE Notes: 1. level-1indicates a COBOL level between 2 and 48. 2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL with TRUNC(STD) recognizes only values up to 9999. This can cause data truncation errors when COBOL statements execute and might effectively limit the maximum length of variable-length character strings to 9999. Consider using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation. 3. The picture-string that is associated with these forms must be X(m) (or XX...X, with m instances of X), with 1 <= m <= 32767 for fixed-length strings; for other strings, m cannot be greater than the maximum size of a varying-length character string. 4. You cannot directly reference var-1 and var-2 as host variable arrays. 5. You cannot use an intervening REDEFINE at level 49. 6. dimension must be an integer constant between 1 and 32767. Example: The following example shows declarations of a fixed-length character array and a varying-length character array: 01 OUTPUT-VARS. 05 NAME OCCURS 10 TIMES. 49 NAME-LEN PIC S9(4) COMP-4 SYNC. 49 NAME-DATA PIC X(40). 05 SERIAL-NUMBER PIC S9(9) COMP-4 OCCURS 10 TIMES. Graphic character host variable arrays: The three valid forms for graphic character host variable arrays are: v Fixed-length strings v Varying-length strings v DBCLOBs The following diagrams show the syntax for forms other than DBCLOBs. 192 Application Programming and SQL Guide
  • 209.
    The following diagramshows the syntax for declarations of fixed-length graphic string arrays. IS level-1 variable-name PICTURE PIC picture-string IS USAGE DISPLAY-1 NATIONAL OCCURS dimension TIMES . IS VALUE graphic-constant Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater than the maximum size of a varying-length graphic string. 3. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is supported only through the DB2 coprocessor. 4. dimension must be an integer constant between 1 and 32767. The following diagram shows the syntax for declarations of varying-length graphic string arrays. level-1 variable-name OCCURS dimension . TIMES IS 49 var-1 PICTURE PIC S9(4) S9999 IS USAGE BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP SYNCHRONIZED SYNC IS VALUE numeric-constant . 49 var-2 PICTURE PIC Chapter 3. Including DB2 queries in an application program 193
  • 210.
    IS IS picture-string USAGE DISPLAY-1 NATIONAL . IS VALUE graphic-constant Notes: 1. level-1indicates a COBOL level between 2 and 48. 2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL with TRUNC(STD) recognizes only values up to 9999. This can cause data truncation errors when COBOL statements execute and might effectively limit the maximum length of variable-length character strings to 9999. Consider using the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation. 3. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater than the maximum size of a varying-length graphic string. 4. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is supported only through the DB2 coprocessor. 5. You cannot directly reference var-1 and var-2 as host variable arrays. 6. dimension must be an integer constant between 1 and 32767. LOB, locator, file reference, and XML variables arrays: The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable, locator, and file reference arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use LOB variables. | | | | level-1 variable-name SQL TYPE IS IS USAGE | BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB-LOCATOR CLOB-LOCATOR DBCLOB-LOCATOR BLOB_FILE CLOB_FILE DBCLOB_FILE OCCURS dimension ( length ) K M G . TIMES Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. dimension must be an integer constant between 1 and 32767. 194 Application Programming and SQL Guide
  • 211.
    | | | | The following diagramshows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable and file reference arrays for XML data types. level-1 variable-name SQL TYPE IS XML AS IS USAGE | | | | | | | | BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB-FILE CLOB-FILE DBCLOB-FILE OCCURS dimension ( length ) K M G . TIMES Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. dimension must be an integer constant between 1 and 32767. ROWIDs: The following diagram shows the syntax for declarations of ROWID variable arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. level-1 variable-name SQL TYPE IS ROWID OCCURS dimension IS . TIMES USAGE Notes: 1. level-1 indicates a COBOL level between 2 and 48. 2. dimension must be an integer constant between 1 and 32767. PL/I syntax for host variable array declarations In PL/I programs, you can specify numeric, character, graphic, binary, LOB, XML, and ROWID host variable arrays. You can also specify LOB locators and LOB and XML file reference variables. Only some of the valid PL/I declarations are valid host variable array declarations. The precompiler uses the data attribute defaults that are specified in the PL/I DEFAULT statement. If the declaration for a variable array is not valid, then any SQL statement that references the host variable array might result in the message UNDECLARED HOST VARIABLE ARRAY. The precompiler uses only the names and data attributes of the variable arrays; it ignores the alignment, scope, and storage attributes. Even though the precompiler ignores alignment, scope, and storage, if you ignore the restrictions on their use, you might have problems compiling the PL/I source code that the precompiler generates. These restrictions are as follows: v A declaration with the EXTERNAL scope attribute and the STATIC storage attribute must also have the INITIAL storage attribute. Chapter 3. Including DB2 queries in an application program 195
  • 212.
    v If youuse the BASED storage attribute, you must follow it with a PL/I element-locator-expression. v Host variables can be STATIC, CONTROLLED, BASED, or AUTOMATIC storage class or options. However, CICS requires that programs be reentrant. Declaring host variable arrays: You must specify the ALIGNED attribute when you declare varying-length character arrays or varying-length graphic arrays that are to be used in multiple-row INSERT and FETCH statements. Numeric host variable arrays: The following diagram shows the syntax for declarations of numeric host variable arrays. DECLARE DCL variable-name , ( ( dimension ) variable-name ) , ( BINARY BIN DECIMAL DEC variable-name ( dimension ) ) FIXED ( precision ) ,scale FLOAT ( precision ) Alignment and/or Scope and/or Storage Note: 1. You can specify host variable array attributes in any order that is acceptable to PL/I. For example, BIN FIXED(31), BINARY FIXED(31), BIN(31) FIXED, and FIXED BIN(31) are all acceptable. 2. You can specify the scale for only DECIMAL FIXED. 3. dimension must be an integer constant between 1 and 32767. Example: The following example shows a declaration of an indicator array: DCL IND_ARRAY(100) BIN FIXED(15); /* DCL ARRAY of 100 indicator variables */ Character host variable arrays: The following diagram shows the syntax for declarations of character host variable arrays, other than CLOBs. DECLARE DCL variable-name , ( variable-name ( dimension ) ) , ( CHARACTER CHAR variable-name ( dimension ) ) ( length ) VARYING VAR Alignment and/or Scope and/or Storage Note: 1. dimension must be an integer constant between 1 and 32767. 196 Application Programming and SQL Guide
  • 213.
    Example: The followingexample shows the declarations needed to retrieve 10 rows of the department number and name from the department table: DCL DEPTNO(10) DCL DEPTNAME(10) CHAR(3); CHAR(29) VAR; /* Array of ten CHAR(3) variables */ /* Array of ten VARCHAR(29) variables */ Graphic host variable arrays: The following diagram shows the syntax for declarations of graphic host variable arrays, other than DBCLOBs. DECLARE DCL variable-name , ( ( dimension ) variable-name ) , ( variable-name ( dimension ) ) GRAPHIC ( length ) VARYING VAR Alignment and/or Scope and/or Storage Note: 1. dimension must be an integer constant between 1 and 32767. | | | | Binary host variable arrays: The following diagram shows the syntax for declarations of binary variable arrays. DCL DECLARE variable-name , ( variable-name ( dimension ) ) , ( | | | | | | | SQL TYPE IS variable-name ( dimension ) ) BINARY VARBINARY LOB, locator, file reference, and XML variable arrays: The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable, locator, and file reference variable arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. DCL DECLARE variable-name , ( variable-name ( dimension ) SQL TYPE IS ) , ( variable-name ( dimension ) ) Chapter 3. Including DB2 queries in an application program 197
  • 214.
    | BINARY LARGE OBJECT BLOB CHARACTERLARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_LOCATOR CLOB_LOCATOR DBCLOB_LOCATOR BLOB_FILE CLOB_FILE DBCLOB_FILE ( length ) K M G Note: 1. dimension must be an integer constant between 1 and 32767. The following diagram shows the syntax for declarations of BLOB, CLOB, and DBCLOB host variable arrays, and file reference variable arrays for XML data types. | | | | | DCL DECLARE variable-name , ( variable-name ( dimension ) ) , ( | | variable-name ( dimension ) SQL TYPE IS XML AS BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_FILE CLOB_FILE DBCLOB_FILE ) ( length ) K M G | Note: 1. dimension must be an integer constant between 1 and 32767. | | ROWIDs: The following diagram shows the syntax for declarations of ROWID variable arrays. See “Large objects (LOBs)” on page 390 for a discussion of how to use these host variables. DCL DECLARE variable-name , ( variable-name ( dimension ) ) , ( SQL TYPE IS ROWID 198 Application Programming and SQL Guide variable-name ( dimension ) )
  • 215.
    Note: 1. dimension mustbe an integer constant between 1 and 32767. Host structures in an SQL statement A host structure is a group of host variables that can be referenced with a single name. You define host structures with statements in the host language. You can substitute a host structure for one or more host variables. You can also use indicator variables (or indicator structures) with host structures. You can use host structures in all host languages except REXX. Host structures in C or C++ A C host structure contains an ordered group of data fields. For example: struct {char c1[3]; struct {short len; char data[5]; }c2; char c3[2]; }target; In this example, target is the name of a host structure consisting of the c1, c2, and c3 fields. c1 and c3 are character arrays, and c2 is the host variable equivalent to the SQL VARCHAR data type. The target host structure can be part of another host structure but must be the deepest level of the nested structure. The following diagram shows the syntax for declarations of host structures. struct auto extern static const volatile packed { tag Chapter 3. Including DB2 queries in an application program 199
  • 216.
    | float double var-1 ; } int short sqlint32 int long int long long decimal( precision , scale ) varchar structure binary structure vargraphic structure SQL TYPE IS ROWID LOB data type char var-2 unsigned [ length ] sqldbchar var-5 ; [ length ] variable-name ; ; =expression The following diagram shows the syntax for VARCHAR structures that are used within declarations of host structures. int struct { tag short var-3 ; signed char var-4 [ length ] ; } unsigned The following diagram shows the syntax for VARGRAPHIC structures that are used within declarations of host structures. int struct { tag short var-6 ; sqldbchar var-7 [ length ] ; } signed The following diagram shows the syntax for binary structures that are used within declarations of host structures. | | | SQL TYPE IS BINARY VARBINARY BINARY VARYING (length) | The following diagram shows the syntax for LOB data types that are used within declarations of host structures. | 200 Application Programming and SQL Guide
  • 217.
    SQL TYPE IS | | | BINARYLARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_LOCATOR CLOB_LOCATOR DBCLOB_LOCATOR ( length ) K M G The following diagram shows the syntax for LOB data types that are used within declarations of host structures for XML data. SQL TYPE IS XML AS BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_FILE CLOB_FILE DBCLOB_FILE ( length ) K M G | | Host structures in COBOL A COBOL host structure is a named set of host variables defined in your program’s WORKING-STORAGE SECTION or LINKAGE SECTION. COBOL host structures have a maximum of two levels, even though the host structure might occur within a structure with multiple levels. However, you can declare a varying-length character string, which must be level 49. A host structure name can be a group name whose subordinate levels name elementary data items. In the following example, B is the name of a host structure consisting of the elementary items C1 and C2. 01 A 02 B 03 C1 PICTURE ... 03 C2 PICTURE ... When you write an SQL statement using a qualified host variable name (perhaps to identify a field within a structure), use the name of the structure followed by a period and the name of the field. For example, specify B.C1 rather than C1 OF B or C1 IN B. The DB2 precompiler does not recognize host variables or host structures on any subordinate levels after one of the following items: v A COBOL item that begins in area A v Any SQL statement (except SQL INCLUDE) v Any SQL statement within an included member When the DB2 precompiler encounters one of the preceding items in a host structure, it considers the structure to be complete. The following diagram shows the syntax for declarations of host structures. Chapter 3. Including DB2 queries in an application program 201
  • 218.
    level-1 variable-name level-2 var-1 . numeric-usage . IS PICTURE integer-decimal-usage . PIC picture-string char-inner-variable. varchar-inner-variables vargraphic-inner-variables SQL TYPE IS ROWID . IS USAGE SQL TYPE IS TABLE LIKE table-name AS LOCATOR IS USAGE LOB data type . IS USAGE . The following diagram shows the syntax for numeric-usage items that are used within declarations of host structures. COMPUTATIONAL-1 COMP-1 COMPUTATIONAL-2 COMP-2 IS USAGE IS VALUE constant The following diagram shows the syntax for integer and decimal usage items that are used within declarations of host structures. IS USAGE BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP PACKED-DECIMAL COMPUTATIONAL-3 COMP-3 IS DISPLAY NATIONAL SIGN LEADING SEPARATE CHARACTER IS VALUE constant The following diagram shows the syntax for CHAR inner variables that are used within declarations of host structures. 202 Application Programming and SQL Guide
  • 219.
    IS PICTURE PIC picture-string DISPLAY IS USAGE IS VALUE constant The following diagramshows the syntax for VARCHAR inner variables that are used within declarations of host structures. (1) 49 IS var-2 PICTURE PIC S9(4) S9999 IS USAGE BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP . IS VALUE numeric-constant Notes: | 1 The number 49 has a special meaning to DB2. Do not specify another number. IS 49 var-3 PICTURE PIC picture-string . DISPLAY IS IS VALUE character-constant USAGE The following diagram shows the syntax for VARGRAPHIC inner variables that are used within declarations of host structures. IS 49 var-4 PICTURE PIC S9(4) S9999 IS USAGE Chapter 3. Including DB2 queries in an application program 203
  • 220.
    BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP . IS VALUE numeric-constant IS 49 var-5 PICTURE PIC picture-string IS USAGE DISPLAY-1 NATIONAL . IS VALUE graphic-constant Notes: 1. Forfixed-length strings, the picture-string is G(m) or N(m) (or, m instances of GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater than the maximum size of a varying-length graphic string. 2. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is supported only through the DB2 coprocessor. The following diagram shows the syntax for LOB variables, locators, and file reference variables that are used within declarations of host structures. | SQL TYPE IS BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB-LOCATOR CLOB-LOCATOR DBCLOB-LOCATOR BLOB-FILE CLOB-FILE DBCLOB-FILE ( length ) K M G Notes: 1. level-1 indicates a COBOL level between 1 and 47. 2. level-2 indicates a COBOL level between 2 and 48. 3. For elements within a structure, use any level 02 through 48 (rather than 01 or 77), up to a maximum of two levels. 4. Using a FILLER or optional FILLER item within a host structure declaration can invalidate the whole structure. The following diagram shows the syntax for LOB variables and file reference variables that are used within declarations of host structures for XML. | | 204 Application Programming and SQL Guide
  • 221.
    | SQL TYPE ISXML AS BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB-FILE CLOB-FILE DBCLOB-FILE ( length ) K M G | | | | | | | | Notes: 1. level-1 indicates a COBOL level between 1 and 47. 2. level-2 indicates a COBOL level between 2 and 48. 3. For elements within a structure, use any level 02 through 48 (rather than 01 or 77), up to a maximum of two levels. 4. Using a FILLER or optional FILLER item within a host structure declaration can invalidate the whole structure. Host structures in PL/I A PL/I host structure name can be a structure name whose subordinate levels name scalars. For example: DCL 1 A, 2 B, 3 C1 CHAR(...), 3 C2 CHAR(...); In this example, B is the name of a host structure consisting of the scalars C1 and C2. You can use the structure name as shorthand notation for a list of scalars. You can qualify a host variable with a structure name (for example, STRUCTURE.FIELD). Host structures are limited to two levels. You can think of a host structure for DB2 data as a named group of host variables. You must terminate the host structure variable by ending the declaration with a semicolon. For example: DCL 1 A, 2 B CHAR, 2 (C, D) CHAR; DCL (E, F) CHAR; You can specify host variable attributes in any order that is acceptable to PL/I. For example, BIN FIXED(31), BIN(31) FIXED, and FIXED BIN(31) are all acceptable. The following diagram shows the syntax for declarations of host structures. DECLARE DCL level-1 variable-name , Scope and/or storage Chapter 3. Including DB2 queries in an application program 205
  • 222.
    , level-2 var-1 , ( data-type-specification var-2 ; ) The following diagramshows the syntax for data types that are used within declarations of host structures. | CHARACTER CHAR ( integer ) VARYING VAR GRAPHIC ( integer ) BINARY BIN DECIMAL DEC VARYING VAR FIXED ( precision ) , scale FLOAT ( precision ) SQL TYPE IS ROWID LOB data type The following diagram shows the syntax for LOB data types that are used within declarations of host structures. | SQL TYPE IS CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BINARY LARGE OBJECT BLOB CLOB_LOCATOR DBCLOB_LOCATOR BLOB_LOCATOR CLOB_FILE DBCLOB_FILE BLOB_FILE ( length ) K M G The following diagram shows the syntax for LOB data types that are used within declarations of host structures for XML data. | | | SQL TYPE IS XML AS BINARY LARGE OBJECT BLOB CHARACTER LARGE OBJECT CHAR LARGE OBJECT CLOB DBCLOB BLOB_FILE CLOB_FILE DBCLOB_FILE ( length ) K M G | Retrieving a single row of data into a host structure | If you know that your query returns multiple column values for only one row, you can specify a host structure to contain the column values. 206 Application Programming and SQL Guide
  • 223.
    In the followingexample, assume that your COBOL program includes the following SQL statement: EXEC SQL SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT INTO :EMPNO, :FIRSTNME, :MIDINIT, :LASTNAME, :WORKDEPT FROM DSN8910.VEMP WHERE EMPNO = :EMPID END-EXEC. If you want to avoid listing host variables, you can substitute the name of a structure, say :PEMP, that contains :EMPNO, :FIRSTNME, :MIDINIT, :LASTNAME, and :WORKDEPT. The example then reads: EXEC SQL SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT INTO :PEMP FROM DSN8910.VEMP WHERE EMPNO = :EMPID END-EXEC. You can declare a host structure yourself, or you can use DCLGEN to generate a COBOL record description, PL/I structure declaration, or C structure declaration that corresponds to the columns of a table. For more detailed information about coding a host structure in your program, see “Example: Adding a table declaration and host-variable structure to a library” on page 127. For more information about using DCLGEN and the restrictions that apply to the C language, see “DCLGEN (declarations generator)” on page 125. Indicator variables and indicator variable arrays An indicator variable is associated with a particular host variable. Each indicator variable contains a small integer value that indicates some information about the associated host variable. An indicator variable array serves the same purpose for a host variable array. Indicator variables are small integers that you can use to: v Determine whether the value of an associated output host variable is null or indicate that the value of an input host variable is null v Determine the original length of a character string that was truncated during assignment to a host variable v Determine that a character value could not be converted during assignment to a host variable v Determine the seconds portion of a time value that was truncated during assignment to a host variable Retrieving data and testing the indicator variable: When DB2 retrieves the value of a column into a host variable, you can test the indicator variable that is associated with that host variable: v If the value of the indicator variable is less than zero, the column value is null. The value of the host variable does not change from its previous value. If it is null because of a numeric or character conversion error, or an arithmetic expression error, DB2 sets the indicator variable to -2. See “Arithmetic and conversion errors” on page 317 for more information. v If the indicator variable contains a positive integer, the retrieved value is truncated, and the integer is the original length of the string. v If the value of the indicator variable is zero, the column value is nonnull. If the column value is a character string, the retrieved value is not truncated. Chapter 3. Including DB2 queries in an application program 207
  • 224.
    An error occursif you do not use an indicator variable and DB2 retrieves a null value. You can specify an indicator variable, preceded by a colon, immediately after the host variable. Optionally, you can use the word INDICATOR between the host variable and its indicator variable. Thus, the following two examples are equivalent: EXEC SQL SELECT PHONENO INTO :CBLPHONE:INDNULL FROM DSN8910.EMP WHERE EMPNO = :EMPID END-EXEC. EXEC SQL SELECT PHONENO INTO :CBLPHONE INDICATOR :INDNULL FROM DSN8910.EMP WHERE EMPNO = :EMPID END-EXEC. You can then test INDNULL for a negative value. If it is negative, the corresponding value of PHONENO is null, and you can disregard the contents of CBLPHONE. When you use a cursor to fetch a column value, you can use the same technique to determine whether the column value is null. Inserting null values into columns by using host variable indicators:You can use an indicator variable to insert a null value from a host variable into a column. When DB2 processes INSERT, UPDATE, and MERGE statements, it checks the indicator variable (if one exists). If the indicator variable is negative, the column value is null. If the indicator variable is greater than -1, the associated host variable contains a value for the column. | | | | | | For example, suppose your program reads an employee ID and a new phone number, and must update the employee table with the new number. The new number could be missing if the old number is incorrect, but a new number is not yet available. If the new value for column PHONENO might be null, you can use an indicator variable in the UPDATE statement. For example: EXEC SQL UPDATE DSN8910.EMP SET PHONENO = :NEWPHONE:PHONEIND WHERE EMPNO = :EMPID END-EXEC. When NEWPHONE contains a non-null value, set PHONEIND to zero by preceding the UPDATE statement with the following line: MOVE 0 TO PHONEIND. When NEWPHONE contains a null value, set PHONEIND to a negative value by preceding the UPDATE statement with the following line: MOVE -1 TO PHONEIND. Testing for a null column value: You cannot determine whether a column value is null by comparing it to a host variable with an indicator variable that is set to -1. To test whether a column has a null value, use the IS NULL predicate or the IS DISTINCT FROM predicate. For example, the following code does not select the employees who have no phone number: MOVE -1 TO PHONE-IND. EXEC SQL SELECT LASTNAME 208 Application Programming and SQL Guide
  • 225.
    INTO :PGM-LASTNAME FROM DSN8910.EMP WHEREPHONENO = :PHONE-HV:PHONE-IND END-EXEC. You can use the IS NULL predicate to select employees who have no phone number, as in the following statement: EXEC SQL SELECT LASTNAME INTO :PGM-LASTNAME FROM DSN8910.EMP WHERE PHONENO IS NULL END-EXEC. To select employees whose phone numbers are equal to the value of :PHONE-HV and employees who have no phone number (as in the second example), you would need to code two predicates, one to handle the non-null values and another to handle the null values, as in the following statement: EXEC SQL SELECT LASTNAME INTO :PGM-LASTNAME FROM DSN8910.EMP WHERE (PHONENO = :PHONE-HV AND PHONENO IS NOT NULL AND :PHONE-HV IS NOT NULL) OR (PHONENO IS NULL AND :PHONE-HV:PHONE-IND IS NULL) END-EXEC. You can simplify the preceding example by coding the statement using the NOT form of the IS DISTINCT FROM predicate, as in the following statement: EXEC SQL SELECT LASTNAME INTO :PGM-LASTNAME FROM DSN8910.EMP WHERE PHONENO IS NOT DISTINCT FROM :PHONE-HV:PHONE-IND END-EXEC. Using indicator variable arrays with host variable arrays You can use indicator variable arrays with host variable arrays in the same way that you use indicator variables with host variables. An indicator variable array must have at least as many entries as its host variable array. Using indicator variables with host structures You can define an indicator structure (an array of halfword integer variables) to support a host structure. You define indicator structures in the DATA DIVISION section of your COBOL program. If the column values your program retrieves into a host structure can be null, you can attach an indicator structure name to the host structure name. This name enables DB2 to notify your program about each null value it returns to a host variable in the host structure. For example: 01 PEMP-ROW. 10 EMPNO 10 FIRSTNME. 49 FIRSTNME-LEN 49 FIRSTNME-TEXT 10 MIDINIT 10 LASTNAME. 49 LASTNAME-LEN 49 LASTNAME-TEXT 10 WORKDEPT PIC X(6). PIC S9(4) USAGE COMP. PIC X(12). PIC X(1). PIC S9(4) USAGE COMP. PIC X(15). PIC X(3). Chapter 3. Including DB2 queries in an application program 209
  • 226.
    10 EMP-BIRTHDATE PIC X(10). 01INDICATOR-TABLE. PIC S9(4) COMP OCCURS 6 TIMES. . 02 EMP-IND . . MOVE ’000230’ TO EMPNO. . . . EXEC SQL SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, BIRTHDATE INTO :PEMP-ROW:EMP-IND FROM DSN8910.EMP WHERE EMPNO = :EMPNO END-EXEC. In this example, EMP-IND is an array containing six values, which you can test for negative values. If, for example, EMP-IND(6) contains a negative value, the corresponding host variable in the host structure (EMP-BIRTHDATE) contains a null value. Because this example selects rows from the table DSN8910.EMP, some of the values in EMP-IND are always zero. The first four columns of each row are defined NOT NULL. In the preceding example, DB2 selects the values for a row of data into a host structure. You must use a corresponding structure for the indicator variables to determine which (if any) selected column values are null. For information on using the IS NULL keyword phrase in WHERE clauses, see “Retrieving data by using the SELECT statement” on page 584. Indicator variables in assembler An indicator variable is a 2-byte integer (DS HL2). If you provide an indicator variable for the variable X, when DB2 retrieves a null value for X, it puts a negative value in the indicator variable and does not update X. Your program should check the indicator variable before using X. If the indicator variable is negative, you know that X is null and any value you find in X is irrelevant. When your program uses X to assign a null value to a column, the program should set the indicator variable to a negative number. DB2 then assigns a null value to the column and ignores any value in X. You declare indicator variables in the same way as host variables. You can mix the declarations of the two types of variables in any way that seems appropriate. Example: The following example shows a FETCH statement with the declarations of the host variables that are needed for the FETCH statement: EXEC SQL FETCH CLS_CURSOR INTO :CLSCD, :DAY :DAYIND, :BGN :BGNIND, :END :ENDIND X X X You can declare variables as follows: CLSCD DAY BGN END DAYIND BGNIND ENDIND DS DS DS DS DS DS DS CL7 HL2 CL8 CL8 HL2 HL2 HL2 INDICATOR VARIABLE FOR DAY INDICATOR VARIABLE FOR BGN INDICATOR VARIABLE FOR END The following figure shows the syntax for declarations of indicator host variables. 210 Application Programming and SQL Guide
  • 227.
    variable-name DC DS H 1 L2 Figure 13. Indicatorvariable Indicator variables and indicator variable arrays in C or C++ An indicator variable is a 2-byte integer (short int). An indicator variable array is an array of 2-byte integers (short int). You use indicator variables and indicator variable arrays in similar ways. Using indicator variables: If you provide an indicator variable for the variable X, when DB2 retrieves a null value for X, it puts a negative value in the indicator variable and does not update X. Your program should check the indicator variable before using X. If the indicator variable is negative, you know that X is null and any value you find in X is irrelevant. When your program uses X to assign a null value to a column, the program should set the indicator variable to a negative number. DB2 then assigns a null value to the column and ignores any value in X. Using indicator variable arrays: When you retrieve data into a host variable array, if a value in its indicator array is negative, you can disregard the contents of the corresponding element in the host variable array. Declaring indicator variables: You declare indicator variables in the same way as host variables. You can mix the declarations of the two types of variables in any way that seems appropriate. Example: The following example shows a FETCH statement with the declarations of the host variables that are needed for the FETCH statement: EXEC SQL FETCH CLS_CURSOR INTO :ClsCd, :Day :DayInd, :Bgn :BgnInd, :End :EndInd; You can declare variables as follows: EXEC SQL BEGIN DECLARE SECTION; char ClsCd[8]; char Bgn[9]; char End[9]; short Day, DayInd, BgnInd, EndInd; EXEC SQL END DECLARE SECTION; The following figure shows the syntax for declarations of an indicator variable. Chapter 3. Including DB2 queries in an application program 211
  • 228.
    , int short auto extern static const volatile variable-name signed ; = expression Figure 14. Indicatorvariable Declaring indicator variable arrays: The following figure shows the syntax for declarations of an indicator array or a host structure indicator array. int short auto extern static const volatile signed , variable-name [ dimension ] ; = expression Figure 15. Host structure indicator array Note: The dimension must be an integer constant between 1 and 32767. Indicator variables and indicator variable arrays in COBOL An indicator variable is a 2-byte integer (PIC S9(4) USAGE BINARY). An indicator variable array is an array of 2-byte integers (PIC S9(4) USAGE BINARY). You use indicator variables and indicator variable arrays in similar ways. Using indicator variables: If you provide an indicator variable for the variable X, when DB2 retrieves a null value for X, it puts a negative value in the indicator variable and does not update X. Your program should check the indicator variable before using X. If the indicator variable is negative, you know that X is null and any value you find in X is irrelevant. When your program uses X to assign a null value to a column, the program should set the indicator variable to a negative number. DB2 then assigns a null value to the column and ignores any value in X. Using indicator variable arrays: When you retrieve data into a host variable array, if a value in its indicator array is negative, you can disregard the contents of the corresponding element in the host variable array. Declaring indicator variables: You declare indicator variables in the same way as host variables. You can mix the declarations of the two types of variables in any way that seems appropriate. You can define indicator variables as scalar variables or as array elements in a structure form or as an array variable using a single level OCCURS clause. 212 Application Programming and SQL Guide
  • 229.
    Example: The followingexample shows a FETCH statement with the declarations of the host variables that are needed for the FETCH statement: EXEC SQL FETCH CLS_CURSOR INTO :CLS-CD, :DAY :DAY-IND, :BGN :BGN-IND, :END :END-IND END-EXEC. You can declare the variables as follows: 77 77 77 77 77 77 77 CLS-CD DAY BGN END DAY-IND BGN-IND END-IND PIC PIC PIC PIC PIC PIC PIC X(7). S9(4) X(8). X(8). S9(4) S9(4) S9(4) BINARY. BINARY. BINARY. BINARY. The following figure shows the syntax for declarations of indicator variables. IS 01 77 variable-name PICTURE PIC S9(4) S9999 IS USAGE BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP . IS VALUE constant Figure 16. Indicator variable Declaring indicator variable arrays: The following figure shows the syntax for valid indicator array declarations. IS level-1 variable-name PICTURE PIC S9(4) S9999 IS USAGE BINARY COMPUTATIONAL-4 COMP-4 COMPUTATIONAL-5 COMP-5 COMPUTATIONAL COMP OCCURS dimension . TIMES IS VALUE constant Figure 17. Host structure indicator array Note: Chapter 3. Including DB2 queries in an application program 213
  • 230.
    1. level-1 mustbe an integer between 2 and 48. 2. dimension must be an integer constant between 1 and 32767. Indicator variables in Fortran An indicator variable is a 2-byte integer (INTEGER*2). If you provide an indicator variable for the variable X, when DB2 retrieves a null value for X, it puts a negative value in the indicator variable and does not update X. Your program should check the indicator variable before using X. If the indicator variable is negative, you know that X is null and any value you find in X is irrelevant. When your program uses X to assign a null value to a column, the program should set the indicator variable to a negative number. DB2 then assigns a null value to the column and ignores any value in X. You declare indicator variables in the same way as host variables. You can mix the declarations of the two types of variables in any way that seems appropriate. Example: The following example shows a FETCH statement with the declarations of the host variables that are needed for the FETCH statement: EXEC SQL FETCH CLS_CURSOR INTO :CLSCD, :DAY :DAYIND, :BGN :BGNIND, :END :ENDIND C C C You can declare variables as follows: CHARACTER*7 INTEGER*2 CHARACTER*8 INTEGER*2 CLSCD DAY BGN, END DAYIND, BGNIND, ENDIND The following figure shows the syntax for declarations of indicator variables. , INTEGER*2 variable-name / numeric-constant / Figure 18. Indicator variable Indicator variables and indicator variable arrays in PL/I An indicator variable is a 2-byte integer (or an integer declared as BIN FIXED(15)). An indicator variable array is an array of 2-byte integers. You use indicator variables and indicator variable arrays in similar ways. Using indicator variables: If you provide an indicator variable for the variable X, when DB2 retrieves a null value for X, it puts a negative value in the indicator variable and does not update X. Your program should check the indicator variable before using X. If the indicator variable is negative, you know that X is null and any value you find in X is irrelevant. When your program uses X to assign a null value to a column, the program should set the indicator variable to a negative number. DB2 then assigns a null value to the column and ignores any value in X. 214 Application Programming and SQL Guide
  • 231.
    Using indicator variablearrays: When you retrieve data into a host variable array, if a value in its indicator array is negative, you can disregard the contents of the corresponding element in the host variable array. Declaring indicator variables: You declare indicator variables in the same way as host variables. You can mix the declarations of the two types of variables in any way that seems appropriate. Example: The following example shows a FETCH statement with the declarations of the host variables that are needed for the FETCH statement: EXEC SQL FETCH CLS_CURSOR INTO :CLS_CD, :DAY :DAY_IND, :BGN :BGN_IND, :END :END_IND; You can declare the variables as follows: DCL DCL DCL DCL DCL CLS_CD DAY BGN END (DAY_IND, CHAR(7); BIN FIXED(15); CHAR(8); CHAR(8); BGN_IND, END_IND) BIN FIXED(15); You can specify host variable attributes in any order that is acceptable to PL/I. For example, BIN FIXED(31), BIN(31) FIXED, and FIXED BIN(31) are all acceptable. The following figure shows the syntax for declarations of indicator variables. , DECLARE DCL ( variable-name ) BINARY BIN FIXED(15) ; Figure 19. Indicator variable Declaring indicator arrays: The following figure shows the syntax for declarations of indicator arrays. DECLARE DCL variable-name ( , ( dimension ) BINARY BIN variable-name ( dimension ) FIXED(15) ) ; Alignment and/or Scope and/or Storage Figure 20. Indicator array Note: 1. dimension must be an integer constant between 1 and 32767. Indicator variables in REXX When you retrieve a null value from a column, DB2 puts a negative value in an indicator variable to indicate that the data in the corresponding host variable is Chapter 3. Including DB2 queries in an application program 215
  • 232.
    null. When youpass a null value to DB2, you assign a negative value to an indicator variable to indicate that the corresponding host variable has a null value. The way that you use indicator variables for input host variables in REXX procedures is slightly different from the way that you use indicator variables in other languages. When you want to pass a null value to a DB2 column, in addition to putting a negative value in an indicator variable, you also need to put a valid value in the corresponding host variable. For example, to set a value of WORKDEPT in table EMP to null, use statements like these: SQLSTMT="UPDATE EMP" , "SET WORKDEPT = ?" HVWORKDEPT=’000’ INDWORKDEPT=-1 "EXECSQL PREPARE S100 FROM :SQLSTMT" "EXECSQL EXECUTE S100 USING :HVWORKDEPT :INDWORKDEPT" After you retrieve data from a column that can contain null values, you should always check the indicator variable that corresponds to the output host variable for that column. If the indicator variable value is negative, the retrieved value is null, so you can disregard the value in the host variable. In the following program, the phone number for employee Haas is selected into variable HVPhone. After the SELECT statement executes, if no phone number for employee Haas is found, indicator variable INDPhone contains -1. ’SUBCOM DSNREXX’ IF RC THEN , S_RC = RXSUBCOM(’ADD’,’DSNREXX’,’DSNREXX’) ADDRESS DSNREXX ’CONNECT’ ’DSN’ SQLSTMT = , "SELECT PHONENO FROM DSN8910.EMP WHERE LASTNAME=’HAAS’" "EXECSQL DECLARE C1 CURSOR FOR S1" "EXECSQL PREPARE S1 FROM :SQLSTMT" Say "SQLCODE from PREPARE is "SQLCODE "EXECSQL OPEN C1" Say "SQLCODE from OPEN is "SQLCODE "EXECSQL FETCH C1 INTO :HVPhone :INDPhone" Say "SQLCODE from FETCH is "SQLCODE If INDPhone < 0 Then , Say ’Phone number for Haas is null.’ "EXECSQL CLOSE C1" Say "SQLCODE from CLOSE is "SQLCODE S_RC = RXSUBCOM(’DELETE’,’DSNREXX’,’DSNREXX’) Indicator arrays for retrieving data When you retrieve data into a host variable array, you can check the values in the associated indicator array to determine how to handle each data item. If a value in the associated indicator array is negative, you can disregard the contents of the corresponding element in the host variable array. If a value in an indicator array is: -1 -2 DB2 returns a null value because an error occurred in numeric conversion or in an arithmetic expression in the corresponding row. -3 216 The corresponding row in the column that is being retrieved is null. DB2 returns a null value because a hole was detected for the corresponding row during a multiple-row FETCH operation. Application Programming and SQL Guide
  • 233.
    For information aboutthe multiple-row FETCH operation, see “Executing SQL statements by using a rowset cursor” on page 637. For information about holes in the result table of a cursor, see “Holes in the result table of a scrollable cursor” on page 644. Specifying an indicator array You must associate an indicator array with a particular host variable array. The indicator array contains small integers that indicate some information about each value in the specified host variable array. You can specify an indicator variable array, preceded by a colon, immediately after the host variable array. Optionally, you can use the word INDICATOR between the host variable array and its indicator variable array. Example: Suppose that you declare a scrollable rowset cursor by using the following statement: EXEC SQL DECLARE CURS1 SCROLL CURSOR WITH ROWSET POSITIONING FOR SELECT PHONENO FROM DSN8810.EMP END-EXEC. For information about using rowset cursors, see “Accessing data by using a rowset-positioned cursor” on page 636. The following two specifications of indicator arrays in the multiple-row FETCH statement are equivalent: EXEC SQL FETCH NEXT ROWSET CURS1 FOR 10 ROWS INTO :CBLPHONE :INDNULL END-EXEC. EXEC SQL FETCH NEXT ROWSET CURS1 FOR 10 ROWS INTO :CBLPHONE INDICATOR :INDNULL END-EXEC. After the multiple-row FETCH statement, you can test each element of the INDNULL array for a negative value. If an element is negative, you can disregard the contents of the corresponding element in the CBLPHONE host variable array. Inserting null values by using indicator arrays An indicator array is associated with a particular host variable array. If you need to insert null values into a column, using an indicator array is an easy way to do so. You can use a negative value in an indicator array to insert a null value into a column. Example: Assume that host variable arrays hva1 and hva2 have been populated with values that are to be inserted into the ACTNO and ACTKWD columns. Assume the ACTDESC column allows nulls. To set the ACTDESC column to null, assign -1 to the elements in its indicator array: /* Initialize each indicator array */ for (i=0; i<10; i++) { ind1[i] = 0; ind2[i] = 0; ind3[i] = -1; } Chapter 3. Including DB2 queries in an application program 217
  • 234.
    EXEC SQL INSERT INTODSN8910.ACT (ACTNO, ACTKWD, ACTDESC) VALUES (:hva1:ind1, :hva2:ind2, :hva3:ind3) FOR 10 ROWS; DB2 ignores the values in the hva3 array and assigns the values in the ARTDESC column to null for the 10 rows that are inserted. Errors during output host variable processing Output host variable processing is the process of moving data that is retrieved from DB2 to an application. Errors that occur while processing output host variables do not affect the position of the cursor, and are usually caused by a problem in converting from one data type to another. Example: Suppose that an integer value of 32768 is fetched into a smallint host variable. The conversion might cause an error if you provide insufficient conversion information to DB2. If an indicator variable is provided during output host variable processing or if data type conversion is not required, a positive SQLCODE is returned for the row in most cases. In other cases where data conversion problems occur, a negative SQLCODE is returned for that row. Regardless of the SQLCODE for the row, no new values are assigned to the host variable or to subsequent variables for that row. Any values that are already assigned to variables remain assigned. Even when a negative SQLCODE is returned for a row, statement processing continues and a positive SQLCODE is returned for the statement (SQLSTATE 01668, SQLCODE +354). To determine which rows cause errors when SQLCODE = +354, you can use GET DIAGNOSTICS. Example: Suppose that no indicator variables are provided for values that are returned by the following statement: FETCH FIRST ROWSET FROM C1 FOR 10 ROWS INTO :hva_col1, :hva_col2; For each row with an error, a negative SQLCODE is recorded and processing continues until the 10 rows are fetched. When SQLCODE = +354 is returned for the statement, you can use GET DIAGNOSTICS to determine which errors occur for which rows. The following statement returns num_rows = 10 and num_cond = 3: GET DIAGNOSTICS :num_rows = ROW_COUNT, :num_cond = NUMBER; To investigate the three conditions, use the following statements: Statement A GET DIAGNOSTICS CONDITION 3 :sqlstate = RETURNED_SQLSTATE, :sqlcode = DB2_RETURNED_SQLCODE, :row_num = DB2_ROW_NUMBER; Output A sqlstate = 22003 sqlcode = -304 row_num = 5 Statement B GET DIAGNOSTICS CONDITION 2 :sqlstate = RETURNED_SQLSTATE, :sqlcode = DB2_RETURNED_SQLCODE, :row_num = DB2_ROW_NUMBER; Output B 218 Application Programming and SQL Guide
  • 235.
    sqlstate = 22003 sqlcode= -802 row_num = 7 Statement C GET DIAGNOSTICS CONDITION 1 :sqlstate = RETURNED_SQLSTATE, :sqlcode = DB2_RETURNED_SQLCODE, :row_num = DB2_ROW_NUMBER; Output C sqlstate = 01668 sqlcode = +354 row_num = 0 The fifth row has a data mapping error (-304) for column 1 and the seventh row has a data mapping error (-802)for column 2. These rows do not contain valid data, and they should not be used. Compatibility of SQL and language data types The data types of the host variables that are used in SQL statements must be compatible with the data types of the columns with which you intend to use them. | | | | | | | | | | | | | When deciding the data types of host variables, consider the following rules and recommendations: v Numeric data types are compatible with each other: Assembler: A SMALLINT, INTEGER, BIGINT, DECIMAL, or FLOAT column is compatible with a numeric assembler host variable. C/C++: A SMALLINT, INTEGER, BIGINT, DECIMAL, or FLOAT column is compatible with any C host variable that is defined as type short int, long int, long long, long long int, sqlint64, decimal, float, or double. Fortran: An INTEGER column is compatible with any Fortran host variable that is defined as INTEGER*2, INTEGER*4, REAL, REAL*4, REAL*8, or DOUBLE PRECISION. PL/I: A SMALLINT, INTEGER, BIGINT, DECIMAL, or FLOAT column is compatible with a PL/I host variable of BIN FIXED(15), BIN FIXED(31), DECIMAL(s,p), or BIN FLOAT(n), where n is from 1 to 53, or DEC FLOAT(m) where m is from 1 to 16. v Character data types are compatible with each other: Assembler: A CHAR, VARCHAR, or CLOB column is compatible with a fixed-length or varying-length assembler character host variable. C/C++: A CHAR, VARCHAR, or CLOB column is compatible with a single-character, NUL-terminated, or VARCHAR structured form of a C character host variable. COBOL: A CHAR, VARCHAR, or CLOB column is compatible with a fixed-length or varying-length COBOL character host variable. Fortran: A CHAR, VARCHAR, or CLOB column is compatible with Fortran character host variable. PL/I: A CHAR, VARCHAR, or CLOB column is compatible with a fixed-length or varying-length PL/I character host variable. v Character data types are partially compatible with CLOB locators. You can perform the following assignments: – Assign a value in a CLOB locator to a CHAR or VARCHAR column – Use a SELECT INTO statement to assign a CHAR or VARCHAR column to a CLOB locator host variable. Chapter 3. Including DB2 queries in an application program 219
  • 236.
    – Assign aCHAR or VARCHAR output parameter from a user-defined function or stored procedure to a CLOB locator host variable. – Use a SET assignment statement to assign a CHAR or VARCHAR transition variable to a CLOB locator host variable. – Use a VALUES INTO statement to assign a CHAR or VARCHAR function parameter to a CLOB locator host variable. However, you cannot use a FETCH statement to assign a value in a CHAR or VARCHAR column to a CLOB locator host variable. v Graphic data types are compatible with each other: Assembler: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible with a fixed-length or varying-length assembler graphic character host variable. C/C++: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible with a single character, NUL-terminated, or VARGRAPHIC structured form of a C graphic host variable. COBOL: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible with a fixed-length or varying-length COBOL graphic string host variable. PL/I: A GRAPHIC, VARGRAPHIC, or DBCLOB column is compatible with a fixed-length or varying-length PL/I graphic character host variable. v Graphic data types are partially compatible with DBCLOB locators. You can perform the following assignments: – Assign a value in a DBCLOB locator to a GRAPHIC or VARGRAPHIC column – Use a SELECT INTO statement to assign a GRAPHIC or VARGRAPHIC column to a DBCLOB locator host variable. – Assign a GRAPHIC or VARGRAPHIC output parameter from a user-defined function or stored procedure to a DBCLOB locator host variable. – Use a SET assignment statement to assign a GRAPHIC or VARGRAPHIC transition variable to a DBCLOB locator host variable. – Use a VALUES INTO statement to assign a GRAPHIC or VARGRAPHIC function parameter to a DBCLOB locator host variable. | | However, you cannot use a FETCH statement to assign a value in a GRAPHIC or VARGRAPHIC column to a DBCLOB locator host variable. v Binary data types are compatible with each other. v Binary data types are partially compatible with BLOB locators. You can perform the following assignments: – Assign a value in a BLOB locator to a BINARY or VARBINARY column. – Use a SELECT INTO statement to assign a BINARY or VARBINARY column to a BLOB locator host variable. – Assign a BINARY or VARBINARY output parameter from a user-defined function or stored procedure to a BLOB locator host variable. – Use a SET assignment statement to assign a BINARY or VARBINARY transition variable to a BLOB locator host variable. – Use a VALUES INTO statement to assign a BINARY or VARBINARY function parameter to a BLOB locator host variable. | | | | However, you cannot use a FETCH statement to assign a value in a BINARY or VARBINARY column to a BLOB locator host variable. v Fortran: A BINARY, VARBINARY, or BLOB column or BLOB locator is compatible only with a BLOB host variable. | | | | | | | | | | 220 Application Programming and SQL Guide
  • 237.
    v C: Forvarying-length BIT data, use BINARY. Some C string manipulation functions process NUL-terminated strings and other functions process strings that are not NUL-terminated. The C string manipulation functions that process NUL-terminated strings cannot handle bit data because these functions might misinterpret a NUL character to be a NUL-terminator. v Datetime data types are compatible with character host variables. Assembler: A DATE, TIME, or TIMESTAMP column is compatible with a fixed-length or varying-length assembler character host variable. C/C++: A DATE, TIME, or TIMESTAMP column is compatible with a single-character, NUL-terminated, or VARCHAR structured form of a C character host variable. COBOL: A DATE, TIME, or TIMESTAMP column is compatible with a fixed-length or varying length COBOL character host variable. Fortran: A DATE, TIME, or TIMESTAMP column is compatible with a Fortran character host variable. PL/I: A DATE, TIME, or TIMESTAMP column is compatible with a fixed-length or varying-length PL/I character host variable. v The ROWID column is compatible only with a ROWID host variable. v A host variable is compatible with a distinct type if the host variable type is compatible with the source type of the distinct type. v XML columns are compatible with the XML host variable types, character types, and binary string types. Recommendation: Use the XML host variable types for data from XML columns. v Assembler:You can assign LOB data to a file reference variable (BLOB_FILE, CLOB_FILE, and DBCLOB_FILE). | | | | | When necessary, DB2 automatically converts a fixed-length string to a varying-length string, or a varying-length string to a fixed-length string. Related concepts “Host variable data types for XML data in embedded SQL applications” on page 320 “Distinct types” on page 436 Equivalent SQL and assembler data types When you declare host variables in your assembler programs, the precompiler uses equivalent SQL data types. When you retrieve data of a particular SQL data type into a host variable, you need to ensure that the host variable is of an equivalent data type. The following table describes the SQL data type and the base SQLTYPE and SQLLEN values that the precompiler uses for host variables in SQL statements. Table 50. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in assembler programs Assembler host variable data type SQLTYPE of host variable1 SQLLEN of host variable SQL data type DS HL2 500 2 SMALLINT DS FL4 496 4 INTEGER Chapter 3. Including DB2 queries in an application program 221
  • 238.
    Table 50. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in assembler programs (continued) SQLTYPE of host variable1 SQLLEN of host variable DS P’value’ DS PLn’value’ or DS PLn 1<=n<=16 484 p in byte 1, s in byte 2 DECIMAL(p,s) | | | | | short decimal FLOAT: 996 4 DECFLOAT | | | | | long decimal FLOAT: 996 8 DECFLOAT | | | | | extended decimal FLOAT: 996 16 DECFLOAT DS EL4 DS EHL4 DS EBL4 480 4 REAL or FLOAT (n) 1<=n<=21 DS DL8 DS DHL8 DS DBL8 480 8 DOUBLE PRECISION, or FLOAT (n) 22<=n<=53 | DS FDL8 | | DS FD 492 8 BIGINT | SQL TYPE IS BINARY(n) | | 1<=n<=255 912 n BINARY(n) | SQL TYPE IS VARBINARY(n) or | | SQL TYPE IS BINARY(n) VARYING | 1<=n<=32704 908 n VARBINARY(n) DS CLn 1<=n<=255 452 n CHAR(n) DS HL2,CLn 1<=n<=255 448 n VARCHAR(n) DS HL2,CLn n>255 456 n VARCHAR(n) DS GLm 2<=m<=254 468 n GRAPHIC(n) Assembler host variable data type SQL data type SDFP DC ED SDFP DC EDL4 SDFP DC EDL4’11.11’ LDFP DC DD LDFP DC DDL8 LDFP DC DDL8’22.22’ EDFP DC LD EDFP DC LDL16 EDFP DC LDL16’33.33’ 3 2 DS HL2,GLm 2<=m<=254 464 n VARGRAPHIC(n) 3 2 DS HL2,GLm m>254 472 n VARGRAPHIC(n) 3 2 222 Application Programming and SQL Guide
  • 239.
    Table 50. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in assembler programs (continued) Assembler host variable data type SQLTYPE of host variable1 SQLLEN of host variable SQL data type DS FL4 972 4 Result set locator4 SQL TYPE IS TABLE LIKE table-name AS LOCATOR 976 4 Table locator4 SQL TYPE IS BLOB_LOCATOR 960 4 BLOB locator4 SQL TYPE IS CLOB_LOCATOR 964 4 CLOB locator4 SQL TYPE IS DBCLOB_LOCATOR 968 4 DBCLOB locator4 SQL TYPE IS BLOB(n) 1≤n≤2147483647 404 n BLOB(n) SQL TYPE IS CLOB(n) 1≤n≤2147483647 408 n CLOB(n) SQL TYPE IS DBCLOB(n) 1≤n≤1073741823 412 n DBCLOB(n) | SQL TYPE IS XML AS BLOB(n) 404 0 XML | SQL TYPE IS XML AS CLOB(n) 408 0 XML | SQL TYPE IS XML AS DBCLOB(n) 412 0 XML | | SQL TYPE IS BLOB_FILE 916/917 267 BLOB file reference 4 | | SQL TYPE IS CLOB_FILE 920/921 267 CLOB file reference 4 | | SQL TYPE IS DBCLOB_FILE 924/925 267 DBCLOB file reference SQL TYPE IS XML AS BLOB_FILE 916/917 267 XML BLOB file reference 4 SQL TYPE IS XML AS CLOB_FILE 920/921 267 XML CLOB file reference 4 SQL TYPE IS XML AS DBCLOB_FILE 924/925 267 XML DBCLOB file reference SQL TYPE IS ROWID 904 40 ROWID 3 4 4 Notes: 1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1. 2. m is the number of bytes. 3. n is the number of double-byte characters. 4. This data type cannot be used as a column type. The following table shows equivalent assembler host variables for each SQL data type. Use this table to determine the assembler data type for host variables that you define to receive output from the database. For example, if you retrieve TIMESTAMP data, you can define variable DS CLn. Chapter 3. Including DB2 queries in an application program 223
  • 240.
    This table showsdirect conversions between SQL data types and assembler data types. However, a number of SQL data types are compatible. When you do assignments or comparisons of data that have compatible data types, DB2 converts those compatible data types. Table 51. Assembler host variable equivalents that you can use when retrieving data of a particular SQL data type SQL data type SMALLINT DS HL2 INTEGER DS F BIGINT DS FD OR DS FDL8 DECIMAL(p,s) or NUMERIC(p,s) | | Assembler host variable equivalent DS P’value’ DS PLn’value’ p is precision; s is scale. 1<=p<=31 and DS PLn 0<=s<=p. 1<=n<=16. value is a literal value that includes a decimal point. You must use Ln, value, or both. Using only value is recommended. Notes DS FDL8 requires High Level Assembler (HLASM), Release 4 or later. Precision: If you use Ln, it is 2n-1; otherwise, it is the number of digits in value. Scale: If you use value, it is the number of digits to the right of the decimal point; otherwise, it is 0. For efficient use of indexes: Use value. If p is even, do not use Ln and be sure the precision of value is p and the scale of value is s. If p is odd, you can use Ln (although it is not advised), but you must choose n so that 2n-1=p, and value so that the scale is s. Include a decimal point in value, even when the scale of value is 0. REAL or FLOAT(n) DS EL4 DS EHL4 DS EBL41 1<=n<=21 DOUBLE PRECISION, DOUBLE, or FLOAT(n) DS DL8 DS DHL8 DS DBL81 22<=n<=53 DECFLOAT DC EDL4 DC DDL8 DC LDL16 CHAR(n) DS CLn VARCHAR(n) DS HL2,CLn GRAPHIC(n) DS GLm m is expressed in bytes. n is the number of double-byte characters. 1<=n<=127 VARGRAPHIC(n) DS HL2,GLx DS HL2’m’,GLx’<value>’ x and m are expressed in bytes. n is the number of double-byte characters. < and > represent shift-out and shift-in characters. | BINARY(n) SQL TYPE IS BINARY(n) 1<=n<=255 | | | | VARBINARY(n) SQL TYPE IS VARBINARY(n) or SQL TYPE IS BINARY(n) VARYING | | 224 Application Programming and SQL Guide 1<=n<=255 1<=n<=32704
  • 241.
    Table 51. Assemblerhost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type Assembler host variable equivalent DATE DS CLn If you are using a date exit routine, n is determined by that routine; otherwise, n must be at least 10. TIME DS CLn If you are using a time exit routine, n is determined by that routine. Otherwise, n must be at least 6; to include seconds, n must be at least 8. TIMESTAMP DS CLn n must be at least 19. To include microseconds, n must be 26; if n is less than 26, truncation occurs on the microseconds part. Result set locator DS F Use this data type only to receive result sets. Do not use this data type as a column type. Table locator SQL TYPE IS TABLE LIKE table-name AS LOCATOR Use this data type only in a user-defined function or stored procedure to receive rows of a transition table. Do not use this data type as a column type. BLOB locator SQL TYPE IS BLOB_LOCATOR Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type. CLOB locator SQL TYPE IS CLOB_LOCATOR Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type. DBCLOB locator SQL TYPE IS DBCLOB_LOCATOR Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type. BLOB(n) SQL TYPE IS BLOB(n) 1≤n≤2147483647 CLOB(n) SQL TYPE IS CLOB(n) 1≤n≤2147483647 DBCLOB(n) SQL TYPE IS DBCLOB(n) n is the number of double-byte characters. 1≤n≤1073741823 | | XML SQL TYPE IS XML AS BLOB(n) 1≤n≤2147483647 | | XML SQL TYPE IS XML AS CLOB(n) 1≤n≤2147483647 | | XML SQL TYPE IS XML AS DBCLOB(n) n is the number of double-byte characters. 1≤n≤1073741823 | | | BLOB file reference SQL TYPE IS BLOB_FILE Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type. | | | CLOB file reference SQL TYPE IS CLOB_FILE Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type. | | | DBCLOB file reference SQL TYPE IS DBCLOB_FILE Notes Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type. Chapter 3. Including DB2 queries in an application program 225
  • 242.
    Table 51. Assemblerhost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type Assembler host variable equivalent | | | XML BLOB file reference SQL TYPE IS XML AS BLOB_FILE Use this data type only to manipulate XML data as BLOB files. Do not use this data type as a column type. | | | XML CLOB file reference SQL TYPE IS XML AS CLOB_FILE Use this data type only to manipulate XML data as CLOB files. Do not use this data type as a column type. | | | XML DBCLOB file reference SQL TYPE IS XML AS DBCLOB_FILE Use this data type only to manipulate XML data as DBCLOB files. Do not use this data type as a column type. ROWID SQL TYPE IS ROWID Notes Notes: | | | 1. Although stored procedures and user-defined functions can use IEEE floating-point host variables, you cannot declare a user-defined function or stored procedure parameter as IEEE. Related concepts “LOB host variable, LOB locator, and LOB file reference variable declarations” on page 661 “Host variable data types for XML data in embedded SQL applications” on page 320 Equivalent SQL and C data types When you declare host variables in your C programs, the precompiler uses equivalent SQL data types. When you retrieve data of a particular SQL data type into a host variable, you need to ensure that the host variable is of an equivalent data type. The following table describes the SQL data type and the base SQLTYPE and SQLLEN values that the precompiler uses for host variables in SQL statements. Table 52. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in C programs SQLTYPE of host C host variable data type variable1 SQLLEN of host variable SQL data type short int SMALLINT 496 4 INTEGER long long long long int sqlint64 492 8 BIGINT5 decimal(p,s)2 484 p in byte 1, s in byte 2 DECIMAL(p,s)2 float 480 4 FLOAT (single precision) double 226 2 long int | | | 500 480 8 FLOAT (double precision) Application Programming and SQL Guide
  • 243.
    Table 52. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in C programs (continued) SQLTYPE of host C host variable data type variable1 | SQL data type 912 n BINARY(n) 908 n VARBINARY(n) Single-character form 452 1 CHAR(1) NUL-terminated character form 460 n VARCHAR (n-1) VARCHAR structured form 1<=n<=255 448 n VARCHAR(n) VARCHAR structured form n>255 456 n VARCHAR(n) Single-graphic form 468 1 GRAPHIC(1) NUL-terminated graphic form 400 n VARGRAPHIC (n-1) VARGRAPHIC structured form 1<=n<128 464 n VARGRAPHIC(n) VARGRAPHIC structured form n>127 472 n VARGRAPHIC(n) 972 4 Result set locator3 SQL TYPE IS TABLE LIKE table-name AS LOCATOR 976 4 Table locator3 SQL TYPE IS BLOB_LOCATOR 960 4 BLOB locator3 SQL TYPE IS CLOB_LOCATOR 964 4 CLOB locator3 SQL TYPE IS DBCLOB_LOCATOR 968 4 DBCLOB locator3 SQL TYPE IS BLOB(n) 1≤n≤2147483647 404 n BLOB(n) v | | | | | SQLLEN of host variable SQL TYPE IS BINARY(n), 1<=n<=255 v | | | | SQL TYPE IS VARBINARY(n), 1<=n<=32704 v SQL TYPE IS RESULT_SET _LOCATOR Chapter 3. Including DB2 queries in an application program 227
  • 244.
    Table 52. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in C programs (continued) SQLTYPE of host C host variable data type variable1 SQLLEN of host variable SQL data type SQL TYPE IS CLOB(n) 1≤n≤2147483647 408 n CLOB(n) SQL TYPE IS DBCLOB(n) 1≤n≤1073741823 412 n DBCLOB(n)4 | | SQL TYPE IS XML AS BLOB(n) 404 0 XML | | SQL TYPE IS XML AS CLOB(n) 408 0 XML | | SQL TYPE IS XML AS DBCLOB(n) 412 0 XML | SQL TYPE IS BLOB_FILE 916/917 267 BLOB file reference 3 | SQL TYPE IS CLOB_FILE 920/921 267 CLOB file reference 3 | | SQL TYPE IS DBCLOB_FILE 924/925 267 DBCLOB file reference | | SQL TYPE IS XML AS BLOB_FILE 916/917 267 XML BLOB file reference 3 | | SQL TYPE IS XML AS CLOB_FILE 920/921 267 XML CLOB file reference 3 | | SQL TYPE IS XML AS DBCLOB_FILE 924/925 267 XML DBCLOB file reference 3 904 40 ROWID SQL TYPE IS ROWID 3 Notes: 1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1. 2. p is the precision; in SQL terminology, this the total number of digits. In C, this is called the size. s is the scale; in SQL terminology, this is the number of digits to the right of the decimal point. In C, this is called the precision. C++ does not support the decimal data type. 3. Do not use this data type as a column type. 4. n is the number of double-byte characters. 5. No exact equivalent. Use DECIMAL(19,0). | | | 6. Starting in Version 9, the C data type long long no longer maps to the SQL data type DEC (19,0). Instead, the C data type long long maps to the SQL data type BIGINT. This new mapping applies if the application is precompiled again. The following table shows equivalent C host variables for each SQL data type. Use this table to determine the C data type for host variables that you define to receive output from the database. For example, if you retrieve TIMESTAMP data, you can define a variable of NUL-terminated character form or VARCHAR structured form 228 Application Programming and SQL Guide
  • 245.
    This table showsdirect conversions between SQL data types and C data types. However, a number of SQL data types are compatible. When you do assignments or comparisons of data that have compatible data types, DB2 converts those compatible data types. Table 53. C host variable equivalents that you can use when retrieving data of a particular SQL data type SQL data type C host variable equivalent SMALLINT short int INTEGER long int DECIMAL(p,s) or NUMERIC(p,s) decimal You can use the double data type if your C compiler does not have a decimal data type; however, double is not an exact equivalent. REAL or FLOAT(n) float 1<=n<=21 DOUBLE PRECISION or FLOAT(n) double 22<=n<=53 | DECLOAT No equivalent | BIGINT long long, long long int, and sqlint64 | BINARY(n) SQL TYPE IS BINARY(n) 1<=n<=255 | | | | | | Notes If data can contain character NULs (0), certain C and C++ library functions might not handle the data correctly. Ensure that your application handles the data properly. VARBINARY(n) SQL TYPE IS VARBINARY(n) 1<=n<=32 704 CHAR(1) single-character form CHAR(n) no exact equivalent If n>1, use NUL-terminated character form VARCHAR(n) NUL-terminated character form If data can contain character NULs (0), use VARCHAR structured form. Allow at least n+1 to accommodate the NUL-terminator. VARCHAR structured form GRAPHIC(1) single-graphic form GRAPHIC(n) no exact equivalent If n>1, use NUL-terminated graphic form. n is the number of double-byte characters. VARGRAPHIC(n) NUL-terminated graphic form If data can contain graphic NUL values (00), use VARGRAPHIC structured form. Allow at least n+1 to accommodate the NUL-terminator. n is the number of double-byte characters. VARGRAPHIC structured form n is the number of double-byte characters. NUL-terminated character form If you are using a date exit routine, that routine determines the length. Otherwise, allow at least 11 characters to accommodate the NUL-terminator. VARCHAR structured form If you are using a date exit routine, that routine determines the length. Otherwise, allow at least 10 characters. DATE Chapter 3. Including DB2 queries in an application program 229
  • 246.
    Table 53. Chost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type C host variable equivalent Notes TIME NUL-terminated character form If you are using a time exit routine, the length is determined by that routine. Otherwise, the length must be at least 7; to include seconds, the length must be at least 9 to accommodate the NUL-terminator. VARCHAR structured form If you are using a time exit routine, the length is determined by that routine. Otherwise, the length must be at least 6; to include seconds, the length must be at least 8. NUL-terminated character form The length must be at least 20. To include microseconds, the length must be 27. If the length is less than 27, truncation occurs on the microseconds part. VARCHAR structured form The length must be at least 19. To include microseconds, the length must be 26. If the length is less than 26, truncation occurs on the microseconds part. Result set locator SQL TYPE IS RESULT_SET_LOCATOR Use this data type only for receiving result sets. Do not use this data type as a column type. Table locator SQL TYPE IS TABLE LIKE table-name AS LOCATOR Use this data type only in a user-defined function or stored procedure to receive rows of a transition table. Do not use this data type as a column type. BLOB locator SQL TYPE IS BLOB_LOCATOR Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type. CLOB locator SQL TYPE IS CLOB_LOCATOR Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type. DBCLOB locator SQL TYPE IS DBCLOB_LOCATOR Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type. BLOB(n) SQL TYPE IS BLOB(n) 1≤n≤2147483647 CLOB(n) SQL TYPE IS CLOB(n) 1≤n≤2147483647 DBCLOB(n) SQL TYPE IS DBCLOB(n) n is the number of double-byte characters. 1≤n≤1073741823 | XML SQL TYPE IS XML AS BLOB(n) 1≤n≤2147483647 | XML SQL TYPE IS XML AS CLOB(n) 1≤n≤2147483647 | XML | SQL TYPE IS XML AS DBCLOB(n) n is the number of double-byte characters. 1≤n≤1073741823 | BLOB file reference | | SQL TYPE IS BLOB_FILE Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type. | CLOB file reference | | SQL TYPE IS CLOB_FILE Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type. TIMESTAMP 230 Application Programming and SQL Guide
  • 247.
    Table 53. Chost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type C host variable equivalent Notes | | | DBCLOB file reference SQL TYPE IS DBCLOB_FILE Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type. | | | XML BLOB file reference SQL TYPE IS XML AS BLOB_FILE Use this data type only to manipulate XML data as BLOB files. Do not use this data type as a column type. | | | XML CLOB file reference SQL TYPE IS XML AS CLOB_FILE Use this data type only to manipulate XML data as CLOB files. Do not use this data type as a column type. | | | XML DBCLOB file reference SQL TYPE IS XML AS DBCLOB_FILE Use this data type only to manipulate XML data as DBCLOB files. Do not use this data type as a column type. ROWID SQL TYPE IS ROWID Related concepts “LOB host variable, LOB locator, and LOB file reference variable declarations” on page 661 “Host variable data types for XML data in embedded SQL applications” on page 320 Equivalent SQL and COBOL data types When you declare host variables in your COBOL programs, the precompiler uses equivalent SQL data types. When you retrieve data of a particular SQL data type into a host variable, you need to ensure that the host variable is of an equivalent data type. The following table describes the SQL data type and the base SQLTYPE and SQLLEN values that the precompiler uses for host variables in SQL statements. Table 54. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in COBOL programs SQLTYPE of host COBOL host variable data type variable1 SQLLEN of host variable SQL data type COMP-1 480 4 REAL or FLOAT(n) 1<=n<=21 COMP-2 480 8 DOUBLE PRECISION, or FLOAT(n) 22<=n<=53 S9(i)V9(d) COMP-3 or S9(i)V9(d) PACKED-DECIMAL 484 i+d in byte 1, d in byte 2 DECIMAL(i+d,d) or NUMERIC(i+d,d) S9(i)V9(d) DISPLAY SIGN LEADING SEPARATE 504 i+d in byte 1, d in byte 2 No exact equivalent. Use DECIMAL(i+d,d) or NUMERIC(i+d,d) S9(i)V9(d) NATIONAL SIGN LEADING SEPARATE 504 i+d in byte 1, d in byte 2 No exact equivalent. Use DECIMAL(i+d,d) or NUMERIC(i+d,d) S9(4) COMP-4, S9(4) COMP-5, S9(4) COMP, or S9(4) BINARY 500 2 SMALLINT S9(9) COMP-4, S9(9) COMP-5, S9(9) COMP, or S9(9) BINARY 496 4 INTEGER Chapter 3. Including DB2 queries in an application program 231
  • 248.
    Table 54. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in COBOL programs (continued) SQLTYPE of host COBOL host variable data type variable1 | S9(18) COMP-4, S9(18) COMP-5, 492 | S9(18) COMP, or S9(18) BINARY SQLLEN of host variable SQL data type 8 BIGINT Fixed-length character data 452 n CHAR(n) Varying-length character data 1<=n<=255 448 n VARCHAR(n) Varying-length character data m>255 456 m VARCHAR(m) Fixed-length graphic data 468 m GRAPHIC(m) Varying-length graphic data 1<=m<=127 464 m VARGRAPHIC(m) Varying-length graphic data m>127 472 m VARGRAPHIC(m) | SQL TYPE is BINARY(n), | 1<=n<=255 912 n BINARY(n) | SQL TYPE is VARBINARY(n), | 1<=n<=32 704 908 n VARBINARY(n) SQL TYPE IS RESULT-SET-LOCATOR 972 4 Result set locator2 SQL TYPE IS TABLE LIKE table-name AS LOCATOR 976 4 Table locator2 SQL TYPE IS BLOB-LOCATOR 960 4 BLOB locator2 SQL TYPE IS CLOB-LOCATOR 964 4 CLOB locator2 SQL TYPE IS DBCLOB-LOCATOR 968 4 DBCLOB locator2 USAGE IS SQL TYPE IS BLOB(n) 1≤n≤2147483647 404 n BLOB(n) USAGE IS SQL TYPE IS CLOB(n) 1≤n≤2147483647 408 n CLOB(n) USAGE IS SQL TYPE IS DBCLOB(m) 1≤m≤10737418233 412 n DBCLOB(m)3 | SQL TYPE IS XML AS BLOB(n) 404 0 XML | SQL TYPE IS XML AS CLOB(n) 408 0 XML | SQL TYPE IS XML AS | DBCLOB(n) 412 0 XML | SQL TYPE IS BLOB-FILE 916/917 267 BLOB file reference2 | SQL TYPE IS CLOB-FILE 920/921 267 CLOB file reference2 | SQL TYPE IS DBCLOB-FILE 924/925 267 DBCLOB file reference2 | SQL TYPE IS XML AS | BLOB-FILE 916/917 267 XML BLOB file reference2 | SQL TYPE IS XML AS | CLOB-FILE 920/921 267 XML CLOB file reference2 | SQL TYPE IS XML AS | DBCLOB-FILE 924/925 267 XML DBCLOB file reference2 904 40 ROWID SQL TYPE IS ROWID 232 Application Programming and SQL Guide
  • 249.
    Table 54. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in COBOL programs (continued) SQLTYPE of host COBOL host variable data type variable1 SQLLEN of host variable SQL data type Notes: 1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1. 2. Do not use this data type as a column type. 3. m is the number of double-byte characters. The following table shows equivalent COBOL host variables for each SQL data type. Use this table to determine the COBOL data type for host variables that you define to receive output from the database. For example, if you retrieve TIMESTAMP data, you can define a fixed-length character string variable of length n This table shows direct conversions between SQL data types and COBOL data types. However, a number of SQL data types are compatible. When you do assignments or comparisons of data that have compatible data types, DB2 converts those compatible data types. Table 55. COBOL host variable equivalents that you can use when retrieving data of a particular SQL data type SQL data type SMALLINT S9(4) COMP-4, S9(4) COMP-5, S9(4) COMP, or S9(4) BINARY INTEGER S9(9) COMP-4, S9(9) COMP-5, S9(9) COMP, or S9(9) BINARY DECIMAL(p,s) or NUMERIC(p,s) S9(p-s)V9(s) COMP-3 or S9(p-s)V9(s) PACKED-DECIMAL DISPLAY SIGN LEADING SEPARATE NATIONAL SIGN LEADING SEPARATE p is precision; s is scale. 0<=s<=p<=31. If s=0, use S9(p)V or S9(p). If s=p, use SV9(s). If the COBOL compiler does not support 31–digit decimal numbers, no exact equivalent exists. Use COMP-2. REAL or FLOAT (n) COMP-1 1<=n<=21 DOUBLE PRECISION, DOUBLE or FLOAT (n) | | COBOL host variable equivalent Notes COMP-2 22<=n<=53 BIGINT S9(18) COMP-4, S9(18) COMP-5, S9(18) COMP, or S9(18) BINARY CHAR(n) Fixed-length character string. For example, 1<=n<=255 01 VAR-NAME PIC X(n). VARCHAR(n) Varying-length character string. For example, The inner variables must have a level of 49. 01 VAR-NAME. 49 VAR-LEN PIC S9(4) USAGE BINARY. 49 VAR-TEXT PIC X(n). Chapter 3. Including DB2 queries in an application program 233
  • 250.
    Table 55. COBOLhost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type COBOL host variable equivalent Notes GRAPHIC(n) Fixed-length graphic string. For example, 01 VAR-NAME PIC G(n) USAGE IS DISPLAY-1. n refers to the number of double-byte characters, not to the number of bytes. 1<=n<=127 Varying-length graphic string. For example, n refers to the number of double-byte characters, not to the number of bytes. VARGRAPHIC(n) 01 VAR-NAME. 49 VAR-LEN PIC S9(4) USAGE BINARY. 49 VAR-TEXT PIC G(n) USAGE IS DISPLAY-1. The inner variables must have a level of 49. | BINARY(n) SQL TYPE IS BINARY(n) 1<=n<=255 | VARBINARY(n) SQL TYPE IS VARBINARY(n) 1<=n<=32 704 Fixed-length character string of length n. For example, If you are using a date exit routine, n is determined by that routine. Otherwise, n must be at least 10. DATE 01 VAR-NAME PIC X(n). TIME Fixed-length character string of length n. For example, 01 VAR-NAME PIC X(n). TIMESTAMP Fixed-length character string of length n. For example, 01 VAR-NAME PIC X(n). If you are using a time exit routine, n is determined by that routine. Otherwise, n must be at least 6; to include seconds, n must be at least 8. n must be at least 19. To include microseconds, n must be 26; if n is less than 26, truncation occurs on the microseconds part. Result set locator SQL TYPE IS RESULT-SET-LOCATOR Use this data type only for receiving result sets. Do not use this data type as a column type. Table locator SQL TYPE IS TABLE LIKE table-name AS LOCATOR Use this data type only in a user-defined function or stored procedure to receive rows of a transition table. Do not use this data type as a column type. BLOB locator USAGE IS SQL TYPE IS BLOB-LOCATOR Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type. CLOB locator USAGE IS SQL TYPE IS CLOB-LOCATOR Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type. DBCLOB locator USAGE IS SQL TYPE IS DBCLOB-LOCATOR Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type. BLOB(n) USAGE IS SQL TYPE IS BLOB(n) 1≤n≤2147483647 CLOB(n) USAGE IS SQL TYPE IS CLOB(n) 1≤n≤2147483647 DBCLOB(n) USAGE IS SQL TYPE IS DBCLOB(n) n is the number of double-byte characters. 1≤n≤1073741823 | XML SQL TYPE IS XML AS BLOB(n) 1≤n≤2147483647 | XML SQL TYPE IS XML AS CLOB(n) 1≤n≤2147483647 234 Application Programming and SQL Guide
  • 251.
    Table 55. COBOLhost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type COBOL host variable equivalent Notes | | XML SQL TYPE IS XML AS DBCLOB(n) n is the number of double-byte characters. 1≤n≤1073741823 | | | | | BLOB file reference USAGE IS SQL TYPE IS BLOB-FILE Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type. | | | | | CLOB file reference USAGE IS SQL TYPE IS CLOB-FILE Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type. | | | | | DBCLOB file reference USAGE IS SQL TYPE IS DBCLOB-FILE Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type. | | | XML BLOB file reference SQL TYPE IS XML AS BLOB-FILE Use this data type only to manipulate XML data as BLOB files. Do not use this data type as a column type. | | | XML CLOB file reference SQL TYPE IS XML AS CLOB-FILE Use this data type only to manipulate XML data as CLOB files. Do not use this data type as a column type. | | | XML DBCLOB file reference SQL TYPE IS XML AS DBCLOB-FILE Use this data type only to manipulate XML data as DBCLOB files. Do not use this data type as a column type. ROWID SQL TYPE IS ROWID Related concepts “LOB host variable, LOB locator, and LOB file reference variable declarations” on page 661 “Host variable data types for XML data in embedded SQL applications” on page 320 Equivalent SQL and Fortran data types When you declare host variables in your Fortran programs, the precompiler uses equivalent SQL data types. When you retrieve data of a particular SQL data type into a host variable, you need to ensure that the host variable is of an equivalent data type. The following table describes the SQL data type and the base SQLTYPE and SQLLEN values that the precompiler uses for host variables in SQL statements. Table 56. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in Fortran programs Fortran host variable data type SQLTYPE of host variable1 SQLLEN of host variable SQL data type INTEGER*2 500 2 SMALLINT INTEGER*4 496 4 INTEGER REAL*4 480 4 FLOAT (single precision) REAL*8 480 8 FLOAT (double precision) CHARACTER*n 452 n CHAR(n) Chapter 3. Including DB2 queries in an application program 235
  • 252.
    Table 56. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in Fortran programs (continued) SQLTYPE of host variable1 SQLLEN of host variable SQL data type SQL TYPE IS RESULT_SET_LOCATOR 972 4 Result set locator. Do not use this data type as a column type. SQL TYPE IS BLOB_LOCATOR 960 4 BLOB locator. Do not use this data type as a column type. SQL TYPE IS CLOB_LOCATOR 964 4 CLOB locator. Do not use this data type as a column type. SQL TYPE IS BLOB(n) 1≤n≤2147483647 404 n BLOB(n) SQL TYPE IS CLOB(n) 1≤n≤2147483647 408 n CLOB(n) SQL TYPE IS ROWID 904 40 ROWID Fortran host variable data type Notes: 1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1. The following table shows equivalent Fortran host variables for each SQL data type. Use this table to determine the Fortran data type for host variables that you define to receive output from the database. For example, if you retrieve TIMESTAMP data, you can define a variable of type CHARACTER*n. This table shows direct conversions between SQL data types and Fortran data types. However, a number of SQL data types are compatible. When you do assignments or comparisons of data that have compatible data types, DB2 converts those compatible data types. Table 57. Fortran host variable equivalents that you can use when retrieving data of a particular SQL data type SQL data type Fortran host variable equivalent SMALLINT INTEGER*2 INTEGER INTEGER*4 | BIGINT Notes not supported DECIMAL(p,s) or NUMERIC(p,s) no exact equivalent Use REAL*8 FLOAT(n) single precision REAL*4 1<=n<=21 FLOAT(n) double precision REAL*8 22<=n<=53 CHAR(n) CHARACTER*n 1<=n<=255 VARCHAR(n) no exact equivalent Use a character host variable that is large enough to contain the largest expected VARCHAR value. | BINARY not supported | VARBINARY not supported GRAPHIC(n) not supported VARGRAPHIC(n) not supported 236 Application Programming and SQL Guide
  • 253.
    Table 57. Fortranhost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type Notes DATE CHARACTER*n If you are using a date exit routine, n is determined by that routine; otherwise, n must be at least 10. TIME CHARACTER*n If you are using a time exit routine, n is determined by that routine. Otherwise, n must be at least 6; to include seconds, n must be at least 8. TIMESTAMP CHARACTER*n n must be at least 19. To include microseconds, n must be 26; if n is less than 26, truncation occurs on the microseconds part. Result set locator SQL TYPE IS RESULT_SET_LOCATOR Use this data type only for receiving result sets. Do not use this data type as a column type. BLOB locator SQL TYPE IS BLOB_LOCATOR Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type.1 CLOB locator SQL TYPE IS CLOB_LOCATOR Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type.1 DBCLOB locator not supported BLOB(n) SQL TYPE IS BLOB(n) 1≤n≤21474836471 CLOB(n) SQL TYPE IS CLOB(n) 1≤n≤21474836471 DBCLOB(n) not supported ROWID | Fortran host variable equivalent SQL TYPE IS ROWID XML not supported Related concepts “LOB host variable, LOB locator, and LOB file reference variable declarations” on page 661 Equivalent SQL and PL/I data types When you declare host variables in your PL/I programs, the precompiler uses equivalent SQL data types. When you retrieve data of a particular SQL data type into a host variable, you need to ensure that the host variable is of an equivalent data type. The following table describes the SQL data type and the base SQLTYPE and SQLLEN values that the precompiler uses for host variables in SQL statements. Table 58. SQL data types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in PL/I programs PL/I host variable data type SQLLEN of host variable SQL data type BIN FIXED(n) 1<=n<=15 500 2 SMALLINT BIN FIXED(n) 16<=n<=31 | SQLTYPE of host variable1 496 4 INTEGER FIXED BIN(63) 492 8 BIGINT Chapter 3. Including DB2 queries in an application program 237
  • 254.
    Table 58. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in PL/I programs (continued) SQLTYPE of host variable1 SQLLEN of host variable SQL data type DEC FIXED(p,s) 0<=p<=31 and 0<=s<=p2 484 p in byte 1, s in byte 2 DECIMAL(p,s) BIN FLOAT(p) 1<=p<=21 480 4 REAL or FLOAT(n) 1<=n<=21 BIN FLOAT(p) 22<=p<=53 480 8 DOUBLE PRECISION or FLOAT(n) 22<=n<=53 DEC FLOAT(m) 1<=m<=6 480 4 FLOAT (single precision) DEC FLOAT(m) 7<=m<=16 480 8 FLOAT (double precision) CHAR(n) 452 n CHAR(n) CHAR(n) VARYING 1<=n<=255 448 n VARCHAR(n) CHAR(n) VARYING n>255 456 n VARCHAR(n) GRAPHIC(n) 468 n GRAPHIC(n) GRAPHIC(n) VARYING 1<=n<=127 464 n VARGRAPHIC(n) GRAPHIC(n) VARYING n>127 472 n VARGRAPHIC(n) | SQL TYPE IS BINARY(n), | 1<=n<=255 912 n BINARY(n) | SQL TYPE IS VARBINARY(n), | 1<=n<=32 704 908 n VARBINARY(n) SQL TYPE IS RESULT_SET_LOCATOR 972 4 Result set locator3 SQL TYPE IS TABLE LIKE table-name AS LOCATOR 976 4 Table locator3 SQL TYPE IS BLOB_LOCATOR 960 4 BLOB locator3 SQL TYPE IS CLOB_LOCATOR 964 4 CLOB locator3 SQL TYPE IS DBCLOB_LOCATOR 968 4 DBCLOB locator3 SQL TYPE IS BLOB(n) 1≤n≤2147483647 404 n BLOB(n) SQL TYPE IS CLOB(n) 1≤n≤2147483647 408 n CLOB(n) SQL TYPE IS DBCLOB(n) 1≤n≤10737418234 412 n DBCLOB(n)4 | SQL TYPE IS XML AS BLOB(n) 404 0 XML | SQL TYPE IS XML AS CLOB(n) 408 0 XML | SQL TYPE IS XML AS | DBCLOB(n) 412 0 XML | SQL TYPE IS BLOB_FILE 916/917 267 BLOB file reference3 | SQL TYPE IS CLOB_FILE 920/921 267 CLOB file reference3 | SQL TYPE IS DBCLOB_FILE 924/925 267 DBCLOB file reference3 | SQL TYPE IS XML AS | BLOB_FILE 916/917 267 XML BLOB file reference3 | SQL TYPE IS XML AS | CLOB_FILE 920/921 267 XML CLOB file reference3 PL/I host variable data type 238 Application Programming and SQL Guide
  • 255.
    Table 58. SQLdata types, SQLLEN values, and SQLTYPE values that the precompiler uses for host variables in PL/I programs (continued) SQLTYPE of host variable1 SQLLEN of host variable SQL data type SQL TYPE IS XML AS DBCLOB_FILE 924/925 267 XML DBCLOB file reference3 SQL TYPE IS ROWID 904 40 ROWID PL/I host variable data type | | Notes: 1. If a host variable includes an indicator variable, the SQLTYPE value is the base SQLTYPE value plus 1. 2. If p=0, DB2 interprets it as DECIMAL(31). For example, DB2 interprets a PL/I data type of DEC FIXED(0,0) to be DECIMAL(31,0), which equates to the SQL data type of DECIMAL(31,0). 3. Do not use this data type as a column type. 4. n is the number of double-byte characters. The following table shows equivalent PL/I host variables for each SQL data type. Use this table to determine the PL/I data type for host variables that you define to receive output from the database. For example, if you retrieve TIMESTAMP data, you can define a variable of type CHAR(n). This table shows direct conversions between SQL data types and PL/I data types. However, a number of SQL data types are compatible. When you do assignments or comparisons of data that have compatible data types, DB2 converts those compatible data types. Table 59. PL/I host variable equivalents that you can use when retrieving data of a particular SQL data type SQL data type Notes SMALLINT BIN FIXED(n) 1<=n<=15 INTEGER BIN FIXED(n) 16<=n<=31 BIGINT FIXED BIN(63) DECIMAL(p,s) or NUMERIC(p,s) | PL/I host variable equivalent If p<16: DEC FIXED(p) or DEC FIXED(p,s) p is precision; s is scale. 1<=p<=31 and 0<=s<=p If p>15, the PL/I compiler must support 31-digit decimal variables. REAL or FLOAT(n) BIN FLOAT(p) or DEC FLOAT(m) 1<=n<=21, 1<=p<=21, and 1<=m<=6 DOUBLE PRECISION, DOUBLE, or FLOAT(n) BIN FLOAT(p) or DEC FLOAT(m) 22<=n<=53, 22<=p<=53, and 7<=m<=16 CHAR(n) CHAR(n) 1<=n<=255 VARCHAR(n) CHAR(n) VAR GRAPHIC(n) GRAPHIC(n) n refers to the number of double-byte characters, not to the number of bytes. 1<=n<=127 VARGRAPHIC(n) GRAPHIC(n) VAR n refers to the number of double-byte characters, not to the number of bytes. | BINARY(n) SQL TYPE IS BINARY(n) 1<=n<=255 | VARBINARY(n) SQL TYPE IS VARBINARY(n) 1<=n<=32 704 DATE CHAR(n) If you are using a date exit routine, that routine determines n; otherwise, n must be at least 10. Chapter 3. Including DB2 queries in an application program 239
  • 256.
    Table 59. PL/Ihost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type PL/I host variable equivalent Notes TIME CHAR(n) If you are using a time exit routine, that routine determines n. Otherwise, n must be at least 6; to include seconds, n must be at least 8. TIMESTAMP CHAR(n) n must be at least 19. To include microseconds, n must be 26; if n is less than 26, the microseconds part is truncated. Result set locator SQL TYPE IS RESULT_SET_LOCATOR Use this data type only for receiving result sets. Do not use this data type as a column type. Table locator SQL TYPE IS TABLE LIKE table-name AS LOCATOR Use this data type only in a user-defined function or stored procedure to receive rows of a transition table. Do not use this data type as a column type. BLOB locator SQL TYPE IS BLOB_LOCATOR Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type.1 CLOB locator SQL TYPE IS CLOB_LOCATOR Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type.1 DBCLOB locator SQL TYPE IS DBCLOB_LOCATOR Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type.1 BLOB(n) SQL TYPE IS BLOB(n) 1≤n≤21474836471 CLOB(n) SQL TYPE IS CLOB(n) 1≤n≤21474836471 DBCLOB(n) SQL TYPE IS DBCLOB(n) n is the number of double-byte characters. 1≤n≤10737418231 | XML SQL TYPE IS XML AS BLOB(n) 1≤n≤2147483647 2 | XML SQL TYPE IS XML AS CLOB(n) 1≤n≤2147483647 2 | XML | SQL TYPE IS XML AS DBCLOB(n) n is the number of double-byte characters. 1≤n≤1073741823 2 | BLOB file reference | | SQL TYPE IS BLOB_FILE Use this data type only to manipulate data in BLOB columns. Do not use this data type as a column type.1 | CLOB file reference | | SQL TYPE IS CLOB_FILE Use this data type only to manipulate data in CLOB columns. Do not use this data type as a column type.1 | DBCLOB file reference | | SQL TYPE IS DBCLOB_FILE Use this data type only to manipulate data in DBCLOB columns. Do not use this data type as a column type.1 | XML BLOB file reference | | SQL TYPE IS XML AS BLOB_FILE Use this data type only to manipulate XML data as BLOB files. Do not use this data type as a column type. 2 | XML CLOB file reference | | SQL TYPE IS XML AS CLOB_FILE Use this data type only to manipulate XML data as CLOB files. Do not use this data type as a column type. 2 240 Application Programming and SQL Guide
  • 257.
    Table 59. PL/Ihost variable equivalents that you can use when retrieving data of a particular SQL data type (continued) SQL data type Notes XML DBCLOB file reference SQL TYPE IS XML AS DBCLOB_FILE Use this data type only to manipulate XML data as DBCLOB files. Do not use this data type as a column type.2 ROWID | | | PL/I host variable equivalent SQL TYPE IS ROWID Related concepts “LOB host variable, LOB locator, and LOB file reference variable declarations” on page 661 “Host variable data types for XML data in embedded SQL applications” on page 320 Determining equivalent SQL and REXX data types All REXX data is string data. Therefore, when a REXX procedure assigns input data to a column, DB2 converts the data from a string type to the column type. When a REXX procedure assigns column data to an output variable, DB2 converts the data from the column type to a string type. When you assign input data to a DB2 table column, you can either let DB2 determine the type that your input data represents, or you can use an SQLDA to tell DB2 the intended type of the input data. Data types that DB2 assigns to REXX input When a REXX procedure assigns data to a column, it can either let DB2 determine the data type or use an SQLDA to specify the intended data type. If the procedure lets DB2 assign a data type for the input data, DB2 bases its choice on the input string format. The following table shows the SQL data types that DB2 assigns to input data and the corresponding formats for that data. The two SQLTYPE values that are listed for each data type are the value for a column that does not accept null values and the value for a column that accepts null values. Table 60. SQL input data types and REXX data formats SQL data type assigned by DB2 INTEGER | | | | SQLTYPE for data type 496/497 A string of numerics that does not contain a decimal point or exponent identifier. The first character can be a plus (+) or minus (-) sign. The number that is represented must be between -2147483647 and 2147483647, inclusive. BIGINT 492/493 A string of numbers that does not contain a decimal point or an exponent identifier. The first character can be a plus (+) or minus (-) sign. The number that is represented must be between -9223372036854775808 and -2147483648, inclusive, or between 2147483648 and 9223372036854775807. REXX input data format Chapter 3. Including DB2 queries in an application program 241
  • 258.
    Table 60. SQLinput data types and REXX data formats (continued) SQL data type assigned by DB2 SQLTYPE for data type REXX input data format DECIMAL(p,s) 484/485 One of the following formats: v A string of numerics that contains a decimal point but no exponent identifier. p represents the precision and s represents the scale of the decimal number that the string represents. The first character can be a plus (+) or minus (-) sign. | | | | v A string of numerics that does not contain a decimal point or an exponent identifier. The first character can be a plus (+) or minus (-) sign. The number that is represented is less than -9223372036854775808 or greater than 9223372036854775807. FLOAT 480/481 A string that represents a number in scientific notation. The string consists of a series of numerics followed by an exponent identifier (an E or e followed by an optional plus (+) or minus (-) sign and a series of numerics). The string can begin with a plus (+) or minus (-) sign. VARCHAR(n) 448/449 One of the following formats: v A string of length n, enclosed in single or double quotation marks. v The character X or x, followed by a string enclosed in single or double quotation marks. The string within the quotation marks has a length of 2*n bytes and is the hexadecimal representation of a string of n characters. v A string of length n that does not have a numeric or graphic format, and does not satisfy either of the previous conditions. VARGRAPHIC(n) 464/465 One of the following formats: v The character G, g, N, or n, followed by a string enclosed in single or double quotation marks. The string within the quotation marks begins with a shift-out character (X’0E’) and ends with a shift-in character (X’0F’). Between the shift-out character and shift-in character are n double-byte characters. v The characters GX, Gx, gX, or gx, followed by a string enclosed in single or double quotation marks. The string within the quotation marks has a length of 4*n bytes and is the hexadecimal representation of a string of n double-byte characters. For example, when DB2 executes the following statements to update the MIDINIT column of the EMP table, DB2 must determine a data type for HVMIDINIT: SQLSTMT="UPDATE EMP" , "SET MIDINIT = ?" , "WHERE EMPNO = ’000200’" "EXECSQL PREPARE S100 FROM :SQLSTMT" HVMIDINIT=’H’ "EXECSQL EXECUTE S100 USING" , ":HVMIDINIT" Because the data that is assigned to HVMIDINIT has a format that fits a character data type, DB2 REXX Language Support assigns a VARCHAR type to the input data. If you do not assign a value to a host variable before you assign the host variable to a column, DB2 returns an error code. 242 Application Programming and SQL Guide
  • 259.
    Embedding SQL statementsin your application You can code SQL statements in an assembler, C, C++, COBOL, Fortran, or PL/I program or REXX procedure wherever you can use executable statements. Embedding SQL statements in assembler applications You can code SQL statements in an assembler program wherever you can use executable statements. Each SQL statement in an assembler program must begin with EXEC SQL. The EXEC and SQL keywords must appear on one line, but the remainder of the statement can appear on subsequent lines. You might code an UPDATE statement in an assembler program as follows: EXEC SQL UPDATE DSN8910.DEPT SET MGRNO = :MGRNUM WHERE DEPTNO = :INTDEPT X X Comments: You cannot include assembler comments in SQL statements. However, you can include SQL comments in any embedded SQL statement. Continuation for SQL statements: The line continuation rules for SQL statements are the same as those for assembler statements, except that you must specify EXEC SQL within one line. Any part of the statement that does not fit on one line can appear on subsequent lines, beginning at the continuation margin (column 16, the default). Every line of the statement, except the last, must have a continuation character (a non-blank character) immediately after the right margin in column 72. Declaring tables and views: Your assembler program should include a DECLARE statement to describe each table and view the program accesses. Including code: To include SQL statements or assembler host variable declaration statements from a member of a partitioned data set, place the following SQL statement in the source code where you want to include the statements: EXEC SQL INCLUDE member-name You cannot nest SQL INCLUDE statements. Margins: Use the precompiler option MARGINS to set a left margin, a right margin, and a continuation margin. The default values for these margins are columns 1, 71, and 16, respectively. If EXEC SQL starts before the specified left margin, the DB2 precompiler does not recognize the SQL statement. If you use the default margins, you can place an SQL statement anywhere between columns 2 and 71. Multiple-row FETCH statements: You can use only the FETCH ... USING DESCRIPTOR form of the multiple-row FETCH statement in an assembler program. The DB2 precompiler does not recognize declarations of host variable arrays for an assembler program. Names: You can use any valid assembler name for a host variable. However, do not use external entry names or access plan names that begin with ’DSN’ or host variable names that begin with ’SQL’. These names are reserved for DB2. Chapter 3. Including DB2 queries in an application program 243
  • 260.
    The first characterof a host variable that is used in embedded SQL cannot be an underscore. However, you can use an underscore as the first character in a symbol that is not used in embedded SQL. Statement labels: You can prefix an SQL statement with a label. The first line of an SQL statement can use a label beginning in the left margin (column 1). If you do not use a label, leave column 1 blank. WHENEVER statement: The target for the GOTO clause in an SQL WHENEVER statement must be a label in the assembler source code and must be within the scope of the SQL statements that WHENEVER affects. Special assembler considerations: The following considerations apply to programs written in assembler: v To allow for reentrant programs, the precompiler puts all the variables and structures it generates within a DSECT called SQLDSECT, and it generates an assembler symbol called SQLDLEN. SQLDLEN contains the length of the DSECT. Your program must allocate an area of the size indicated by SQLDLEN, initialize it, and provide addressability to it as the DSECT SQLDSECT. The precompiler does not generate code to allocate the storage for SQLDSECT; the application program must allocate the storage. CICS: An example of code to support reentrant programs, running under CICS, follows: | | | | | | | | | | | | | | | | | | | | | | | | | | | | DFHEISTG DSECT DFHEISTG EXEC SQL INCLUDE SQLCA * DS 0F SQDWSREG EQU R7 SQDWSTOR DS (SQLDLEN)C RESERVE STORAGE TO BE USED FOR SQLDSECT . . . XXPROGRM DFHEIENT CODEREG=R12,EIBREG=R11,DATAREG=R13 * * * SQL WORKING STORAGE LA SQDWSREG,SQDWSTOR GET ADDRESS OF SQLDSECT USING SQLDSECT,SQDWSREG AND TELL ASSEMBLER ABOUT IT * In this example, the actual storage allocation is done by the DFHEIENT macro. TSO: The sample program in prefix.SDSNSAMP(DSNTIAD) contains an example of how to acquire storage for the SQLDSECT in a program that runs in a TSO environment. The following example code contains pieces from prefix.SDSNSAMP(DSNTIAD) with explanations in the comments. | | | | | | | | | | | | | | | | | | | DSNTIAD CSECT SAVE LR USING LR (14,12) R12,R15 DSNTIAD,R12 R7,R1 CONTROL SECTION NAME ANY SAVE SEQUENCE CODE ADDRESSABILITY TELL THE ASSEMBLER SAVE THE PARM POINTER * * Allocate storage of size PRGSIZ1+SQLDSIZ, where: * - PRGSIZ1 is the size of the DSNTIAD program area * - SQLDSIZ is the size of the SQLDSECT, and declared * when the DB2 precompiler includes the SQLDSECT * L R6,PRGSIZ1 GET SPACE FOR USER PROGRAM A R6,SQLDSIZ GET SPACE FOR SQLDSECT GETMAIN R,LV=(6) GET STORAGE FOR PROGRAM VARIABLES 244 Application Programming and SQL Guide
  • 261.
    | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | LR R10,R1 POINT TO IT * *Initialize the storage * LR R2,R10 POINT TO THE FIELD LR R3,R6 GET ITS LENGTH SR R4,R4 CLEAR THE INPUT ADDRESS SR R5,R5 CLEAR THE INPUT LENGTH MVCL R2,R4 CLEAR OUT THE FIELD * * Map the storage for DSNTIAD program area * ST R13,FOUR(R10) CHAIN THE SAVEAREA PTRS ST R10,EIGHT(R13) CHAIN SAVEAREA FORWARD LR R13,R10 POINT TO THE SAVEAREA USING PRGAREA1,R13 SET ADDRESSABILITY * * Map the storage for the SQLDSECT * LR R9,R13 POINT TO THE PROGAREA A R9,PRGSIZ1 THEN PAST TO THE SQLDSECT USING SQLDSECT,R9 SET ADDRESSABILITY ... LTORG ********************************************************************** * * * DECLARE VARIABLES, WORK AREAS * * * ********************************************************************** PRGAREA1 DSECT WORKING STORAGE FOR THE PROGRAM ... DS 0D PRGSIZE1 EQU *-PRGAREA1 DYNAMIC WORKAREA SIZE ... DSNTIAD CSECT RETURN TO CSECT FOR CONSTANT PRGSIZ1 DC A(PRGSIZE1) SIZE OF PROGRAM WORKING STORAGE CA DSECT EXEC SQL INCLUDE SQLCA ... v DB2 does not process set symbols in SQL statements. v Generated code can include more than two continuations per comment. v Generated code uses literal constants (for example, =F’-84’), so an LTORG statement might be necessary. v Generated code uses registers 0, 1, 14, and 15. Register 13 points to a save area that the called program uses. Register 15 does not contain a return code after a call that is generated by an SQL statement. CICS: A CICS application program uses the DFHEIENT macro to generate the entry point code. When using this macro, consider the following: – If you use the default DATAREG in the DFHEIENT macro, register 13 points to the save area. – If you use any other DATAREG in the DFHEIENT macro, you must provide addressability to a save area. For example, to use SAVED, you can code instructions to save, load, and restore register 13 around each SQL statement as in the following example. ST 13,SAVER13 LA 13,SAVED EXEC SQL . . . L 13,SAVER13 SAVE REGISTER 13 POINT TO SAVE AREA RESTORE REGISTER 13 Chapter 3. Including DB2 queries in an application program 245
  • 262.
    v If youhave an addressability error in precompiler-generated code because of input or output host variables in an SQL statement, check to make sure that you have enough base registers. v Do not put CICS translator options in the assembly source code. Instead, pass the options to the translator by using the PARM field. | | | | | Embedding SQL statements in C or C++ applications | | | You can code SQL statements in a C program wherever you can use executable statements. | | | Each SQL statement in a C program must begin with EXEC SQL and end with a semicolon (;). The EXEC and SQL keywords must appear on one line, but the remainder of the statement can appear on subsequent lines. | | | | In general, because C is case sensitive, use uppercase letters to enter all SQL keywords. However, if you use the FOLD precompiler suboption, DB2 folds lowercase letters in SBCS SQL ordinary identifiers to uppercase. For information about host language precompiler options, see Table 148 on page 854. | | | | | | | | You must keep the case of host variable names consistent throughout the program. For example, if a host variable name is lowercase in its declaration, it must be lowercase in all SQL statements. You might code an UPDATE statement in a C program as follows: | | | | | Comments: You can include C comments (/* ... */) within SQL statements wherever you can use a blank, except between the keywords EXEC and SQL. You can use single-line comments (starting with //) in C language statements, but not in embedded SQL. You can use SQL comments within embedded SQL statements. You can nest comments. EXEC SQL UPDATE DSN8910.DEPT SET MGRNO = :mgr_num WHERE DEPTNO = :int_dept; To include EBCDIC DBCS characters in comments, you must delimit the characters by a shift-out and shift-in control character; the first shift-in character in the DBCS string signals the end of the DBCS string. Continuation for SQL statements: You can use a backslash to continue a character-string constant or delimited identifier on the following line. However, EBCDIC DBCS string constants cannot be continued on a second line. Declaring tables and views: Your C program should use the DECLARE TABLE statement to describe each table and view the program accesses. You can use the DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE statements. For more information, see “DCLGEN (declarations generator)” on page 125. Including SQL statements and variable declarations in source code that is to be processed by the DB2 precompiler: To include SQL statements or C host variable declarations from a member of a partitioned data set, add the following SQL statement to the source code where you want to include the statements: | | EXEC SQL INCLUDE member-name; 246 Application Programming and SQL Guide
  • 263.
    You cannot nestSQL INCLUDE statements. Do not use C #include statements to include SQL statements or C host variable declarations. | | | | | Margins: Code SQL statements in columns 1 through 72, unless you specify other margins to the DB2 precompiler. If EXEC SQL is not within the specified margins, the DB2 precompiler does not recognize the SQL statement. The margin rules do not apply to the DB2 coprocessor. The DB2 coprocessor allows variable length source input. | | | | Names: You can use any valid C name for a host variable, subject to the following restrictions: v Do not use DBCS characters. v Do not use external entry names or access plan names that begin with ’DSN’, and do not use host variable names or macro names that begin with ’SQL’ (in any combination of uppercase or lowercase letters). These names are reserved for DB2. Nulls and NULs: C and SQL differ in the way they use the word null. The C language has a null character (NUL), a null pointer (NULL), and a null statement (just a semicolon). The C NUL is a single character that compares equal to 0. The C NULL is a special reserved pointer value that does not point to any valid data object. The SQL null value is a special value that is distinct from all non-null values and denotes the absence of a (nonnull) value. NUL (or NUL-terminator) is the null character in C and C++, and NULL is the SQL null value. | | Sequence numbers: The DB2 precompiler generates statements without sequence numbers. (The DB2 coprocessor does not perform this action, because the source is read and modified by the compiler. ) Statement labels: You can precede SQL statements with a label. Trigraph characters: Some characters from the C character set are not available on all keyboards. You can enter these characters into a C source program using a sequence of three characters called a trigraph. The trigraph characters that DB2 supports are the same as those that the C compiler supports. WHENEVER statement: The target for the GOTO clause in an SQL WHENEVER statement must be within the scope of any SQL statements that the statement WHENEVER affects. | | | | Special C considerations: v Using the C/370™ multi-tasking facility, in which multiple tasks execute SQL statements, causes unpredictable results. v Except for the DB2 coprocessor, you must run the DB2 precompiler before running the C preprocessor. v Except for the DB2 coprocessor, DB2 precompiler does not support C preprocessor directives. v If you use conditional compiler directives that contain C code, either place them after the first C token in your application program, or include them in the C program using the #include preprocessor directive. Refer to the appropriate C documentation for more information about C preprocessor directives. Chapter 3. Including DB2 queries in an application program 247
  • 264.
    Embedding SQL statementsin COBOL applications You can code SQL statements in certain COBOL program sections. The allowable sections are shown in the following table. Table 61. Allowable SQL statements for COBOL program sections SQL statement Program section BEGIN DECLARE SECTION END DECLARE SECTION INCLUDE SQLCA WORKING-STORAGE SECTION1 or LINKAGE SECTION INCLUDE text-file-name PROCEDURE DIVISION or DATA DIVISION2 DECLARE TABLE DECLARE CURSOR DATA DIVISION or PROCEDURE DIVISION DECLARE VARIABLE WORKING-STORAGE SECTION1 Other | WORKING-STORAGE SECTION1 or LINKAGE SECTION PROCEDURE DIVISION Notes: | | 1. If you use the DB2 coprocessor, you can use the LOCAL-STORAGE SECTION wherever WORKING-STORAGE SECTION is listed in the table. 2. When including host variable declarations, the INCLUDE statement must be in the WORKING-STORAGE SECTION or the LINKAGE SECTION. You cannot put SQL statements in the DECLARATIVES section of a COBOL program. Each SQL statement in a COBOL program must begin with EXEC SQL and end with END-EXEC. If you are using the DB2 precompiler, the EXEC and SQL keywords must appear on one line, but the remainder of the statement can appear on subsequent lines. If you are using the DB2 coprocessor, the EXEC and SQL keywords can be on different lines. Do not include any tokens between the two keywords EXEC and SQL except for COBOL comments, including debugging lines. Do not include SQL comments between the keywords EXEC and SQL. | | | | | | | If the SQL statement appears between two COBOL statements, the period after END-EXEC is optional and might not be appropriate. If the statement appears in an IF...THEN set of COBOL statements, omit the ending period to avoid inadvertently ending the IF statement. You might code an UPDATE statement in a COBOL program as follows: EXEC SQL UPDATE DSN8910.DEPT SET MGRNO = :MGR-NUM WHERE DEPTNO = :INT-DEPT END-EXEC. Comments: You can include COBOL comment lines (* in column 7) in SQL statements wherever you can use a blank. If you are using the DB2 precompiler, you cannot include COBOL comment lines between the keywords EXEC and SQL. The precompiler treats COBOL debugging lines and page-eject lines (/ in column 7) as comment lines. The DB2 coprocessor treats the debugging lines based on the COBOL rules, which depend on the WITH DEBUGGING mode setting. | | | | | | 248 Application Programming and SQL Guide
  • 265.
    | | | For an SQLINCLUDE statement, the DB2 precompiler treats any text that follows the period after END-EXEC, and on the same line as END-EXEC, as a comment. The DB2 coprocessor treats this text as part of the COBOL program syntax. In addition, you can include SQL comments (’--’) in any embedded SQL statement. | | | Debugging lines: The DB2 precompiler ignores the ’D’ in column 7 on debugging lines and treats it as a blank. The DB2 coprocessor follows the COBOL language rules regarding debugging lines. Continuation for SQL statements: The rules for continuing a character string constant from one line to the next in an SQL statement embedded in a COBOL program are the same as those for continuing a non-numeric literal in COBOL. However, you can use either a quote or an apostrophe as the first nonblank character in area B of the continuation line. The same rule applies for the continuation of delimited identifiers and does not depend on the string delimiter option. To conform with SQL standard, delimit a character string constant with an apostrophe, and use a quote as the first nonblank character in area B of the continuation line for a character string constant. Continued lines of an SQL statement can be in columns 8 through 72 when using the DB2 precompiler and columns 12 through 72 when using the DB2 coprocessor. | | | COPY: If you use the DB2 precompiler, do not use a COBOL COPY statement within host variable declarations. If you use the DB2 coprocessor, you can use COBOL COPY. REPLACE: If you use the DB2 precompiler, the REPLACE statement has no effect on SQL statements. It affects only the COBOL statements that the precompiler generates. If you use the DB2 coprocessor, the REPLACE statement replaces text strings in SQL statements as well as in generated COBOL statements. Declaring tables and views: Your COBOL program should include the statement DECLARE TABLE to describe each table and view the program accesses. You can use the DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE statements. You should include the DCLGEN members in the DATA DIVISION. For more information, see “DCLGEN (declarations generator)” on page 125. Dynamic SQL in a COBOL program: In general, COBOL programs can easily handle dynamic SQL statements. COBOL programs can handle SELECT statements if the data types and the number of fields returned are fixed. If you want to use variable-list SELECT statements, use an SQLDA. See “Defining SQL descriptor areas” on page 137 for more information on SQLDA. Including code: To include SQL statements or COBOL host variable declarations from a member of a partitioned data set, use the following SQL statement in the source code where you want to include the statements: EXEC SQL INCLUDE member-name END-EXEC. If you are using the DB2 precompiler, you cannot nest SQL INCLUDE statements. In this case, do not use COBOL verbs to include SQL statements or host variable declarations, and do not use the SQL INCLUDE statement to include CICS Chapter 3. Including DB2 queries in an application program 249
  • 266.
    preprocessor related code.In general, if you are using the DB2 precompiler, use the SQL INCLUDE statement only for SQL-related coding. If you are using the COBOL DB2 coprocessor, none of these restrictions apply. Margins: You must code SQL statements that begin with EXEC SQL in columns 12 through 72. Otherwise the DB2 precompiler does not recognize the SQL statement. Names: You can use any valid COBOL name for a host variable. Do not use external entry names or access plan names that begin with ’DSN’, and do not use host variable names that begin with ’SQL’. These names are reserved for DB2. Sequence numbers: The source statements that the DB2 precompiler generates do not include sequence numbers. Statement labels: You can precede executable SQL statements in the PROCEDURE DIVISION with a paragraph name, if you wish. WHENEVER statement: The target for the GOTO clause in an SQL statement WHENEVER must be a section name or unqualified paragraph name in the PROCEDURE DIVISION. Special COBOL considerations: The following considerations apply to programs written in COBOL: v In a COBOL program that uses elements in a multi-level structure as host variable names, the DB2 precompiler generates the lowest two-level names. v Using the COBOL compiler options DYNAM and NODYNAM depends on the operating environment. TSO and IMSYou can specify the option DYNAM when compiling a COBOL program if you use the following guidelines. IMS and DB2 share a common alias name, DSNHLI, for the language interface module. You must do the following when you concatenate your libraries: – If you use IMS with the COBOL option DYNAM, be sure to concatenate the IMS library first. – If you run your application program only under DB2, be sure to concatenate the DB2 library first. CICS, CAF, and RRSAFYou must specify the NODYNAM option when you compile a COBOL program that either includes CICS statements or is translated by a separate CICS translator or the integrated CICS translator. In these cases, you cannot specify the DYNAM option. If your CICS program has a subroutine that is not translated by a separate CICS translator or the integrated CICS translator but contains SQL statements, you can specify the DYNAM option. However, in this case, you must concatenate the CICS libraries before the DB2 libraries. | | | | | | | | You can compile COBOL stored procedures with either the DYNAM option or the NODYNAM option. If you use DYNAM, ensure that the correct DB2 language interface module is loaded dynamically by performing one of the following actions: – Use the ATTACH(RRSAF) precompiler option. – Copy the DSNRLI module into a load library that is concatenated in front of the DB2 libraries. Use the member name DSNHLI. v To avoid truncating numeric values, use either of the following methods: – Use the COMP-5 data type for binary integer host variables. – Specify the COBOL compiler option: 250 Application Programming and SQL Guide
  • 267.
    - TRUNC(OPT) ifyou are certain that the data being moved to each binary variable by the application does not have a larger precision than is defined in the PICTURE clause of the binary variable. - TRUNC(BIN) if the precision of data being moved to each binary variable might exceed the value in the PICTURE clause. DB2 assigns values to binary integer host variables as if you had specified the COBOL compiler option TRUNC(BIN) or used the COMP-5 data type. v If you are using the DB2 precompiler and your COBOL program contains several entry points or is called several times, the USING clause of the entry statement that executes before the first SQL statement executes must contain the SQLCA and all linkage section entries that any SQL statement uses as host variables. v If you use the DB2 precompiler, no compiler directives should appear between the PROCEDURE DIVISION and the DECLARATIVES statement. v Do not use COBOL figurative constants (such as ZERO and SPACE), symbolic characters, reference modification, and subscripts within SQL statements. v Observe the rules for naming SQL identifiers. For information about those rules, see the topic “SQL identifiers” in DB2 SQL Reference. However, for COBOL only, the names of SQL identifiers can follow the rules for naming COBOL words, if the names do not exceed the allowable length for the DB2 object. For example, the name 1ST-TIME is a valid cursor name because it is a valid COBOL word, but the name 1ST_TIME is not valid because it is not a valid SQL identifier or a valid COBOL word. v Observe these rules for hyphens: – Surround hyphens used as subtraction operators with spaces. DB2 usually interprets a hyphen with no spaces around it as part of a host variable name. v If you include an SQL statement in a COBOL PERFORM ... THRU paragraph and also specify the SQL statement WHENEVER ... GO, the COBOL compiler returns the warning message IGYOP3094. That message might indicate a problem. This usage is not recommended. v If you are using the DB2 precompiler, all SQL statements and any host variables they reference must be within the first program when using nested programs or batch compilation. v If you are using the DB2 precompiler, your COBOL programs must have a DATA DIVISION and a PROCEDURE DIVISION. Both divisions and the WORKING-STORAGE section must be present in programs that contain SQL statements. PSPI If your program uses the DB2 precompiler and uses parameters that are defined in LINKAGE SECTION as host variables to DB2 and the address of the input parameter might change on subsequent invocations of your program, your program must reset the variable SQL-INIT-FLAG. This flag is generated by the DB2 precompiler. Resetting this flag indicates that the storage must initialize when the next SQL statement executes. To reset the flag, insert the statement MOVE ZERO TO SQL-INIT-FLAG in the called program’s PROCEDURE DIVISION, ahead of any executable SQL statements that use the host variables. If you use the COBOL DB2 coprocessor, the called program does not need to reset SQL-INIT-FLAG. PSPI Chapter 3. Including DB2 queries in an application program 251
  • 268.
    Embedding SQL statementsin Fortran applications You can code SQL statements in a Fortran program wherever you can place executable statements. If the SQL statement is within an IF statement, the precompiler generates any necessary THEN and END IF statements. Fortran source statements must be fixed-length 80-byte records. The DB2 precompiler does not support free-form source input. Each SQL statement in a Fortran program must begin with EXEC SQL. The EXEC and SQL keywords must appear on one line, but the remainder of the statement can appear on subsequent lines. You might code the UPDATE statement in a Fortran program as follows: EXEC SQL UPDATE DSN8910.DEPT SET MGRNO = :MGRNUM WHERE DEPTNO = :INTDEPT C C C You cannot follow an SQL statement with another SQL statement or Fortran statement on the same line. Fortran does not require blanks to delimit words within a statement, but the SQL language requires blanks. The rules for embedded SQL follow the rules for SQL syntax, which require you to use one or more blanks as a delimiter. Comments: You can include Fortran comment lines within embedded SQL statements wherever you can use a blank, except between the keywords EXEC and SQL. You can include SQL comments in any embedded SQL statement. The DB2 precompiler does not support the exclamation point (!) as a comment recognition character in Fortran programs. Continuation for SQL statements: The line continuation rules for SQL statements are the same as those for Fortran statements, except that you must specify EXEC SQL on one line. The SQL examples in this topic have Cs in the sixth column to indicate that they are continuations of EXEC SQL. Declaring tables and views: Your Fortran program should also include the DECLARE TABLE statement to describe each table and view the program accesses. Dynamic SQL in a Fortran program: In general, Fortran programs can easily handle dynamic SQL statements. SELECT statements can be handled if the data types and the number of returned fields are fixed. If you want to use variable-list SELECT statements, you need to use an SQLDA, as described in “Defining SQL descriptor areas” on page 137. You can use a Fortran character variable in the statements PREPARE and EXECUTE IMMEDIATE, even if it is fixed-length. Including code: To include SQL statements or Fortran host variable declarations from a member of a partitioned data set, use the following SQL statement in the source code where you want to include the statements: EXEC SQL INCLUDE member-name You cannot nest SQL INCLUDE statements. You cannot use the Fortran INCLUDE compiler directive to include SQL statements or Fortran host variable declarations. 252 Application Programming and SQL Guide
  • 269.
    Margins: Code theSQL statements between columns 7 through 72, inclusive. If EXEC SQL starts before the specified left margin, the DB2 precompiler does not recognize the SQL statement. Names: You can use any valid Fortran name for a host variable. Do not use external entry names that begin with ’DSN’ or host variable names that begin with ’SQL’. These names are reserved for DB2. Do not use the word DEBUG, except when defining a Fortran DEBUG packet. Do not use the words FUNCTION, IMPLICIT, PROGRAM, and SUBROUTINE to define variables. Sequence numbers: The source statements that the DB2 precompiler generates do not include sequence numbers. Statement labels: You can specify statement numbers for SQL statements in columns 1 to 5. However, during program preparation, a labeled SQL statement generates a Fortran CONTINUE statement with that label before it generates the code that executes the SQL statement. Therefore, a labeled SQL statement should never be the last statement in a DO loop. In addition, you should not label SQL statements (such as INCLUDE and BEGIN DECLARE SECTION) that occur before the first executable SQL statement, because an error might occur. WHENEVER statement: The target for the GOTO clause in the SQL WHENEVER statement must be a label in the Fortran source code and must refer to a statement in the same subprogram. The WHENEVER statement only applies to SQL statements in the same subprogram. Special Fortran considerations: The following considerations apply to programs written in Fortran: v You cannot use the @PROCESS statement in your source code. Instead, specify the compiler options in the PARM field. v You cannot use the SQL INCLUDE statement to include the following statements: PROGRAM, SUBROUTINE, BLOCK, FUNCTION, or IMPLICIT. DB2 supports Version 3 Release 1 (or later) of VS Fortran with the following restrictions: v The parallel option is not supported. Applications that contain SQL statements must not use Fortran parallelism. v You cannot use the byte data type within embedded SQL, because byte is not a recognizable host data type. Embedding SQL statements in PL/I applications You can code SQL statements in a PL/I program wherever you can use executable statements. The first statement of the PL/I program must be the PROCEDURE statement with OPTIONS(MAIN), unless the program is a stored procedure. A stored procedure application can run as a subroutine. Each SQL statement in a PL/I program must begin with EXEC SQL and end with a semicolon (;). The EXEC and SQL keywords must appear must appear on one line, but the remainder of the statement can appear on subsequent lines. Chapter 3. Including DB2 queries in an application program 253
  • 270.
    You might codean UPDATE statement in a PL/I program as follows: EXEC SQL UPDATE DSN8910.DEPT SET MGRNO = :MGR_NUM WHERE DEPTNO = :INT_DEPT ; Comments: You can include PL/I comments in embedded SQL statements wherever you can use a blank, except between the keywords EXEC and SQL. You can also include SQL comments in any SQL statement. To include DBCS characters in comments, you must delimit the characters by a shift-out and shift-in control character; the first shift-in character in the DBCS string signals the end of the DBCS string. Continuation for SQL statements: The line continuation rules for SQL statements are the same as those for other PL/I statements, except that you must specify EXEC SQL on one line. Declaring tables and views: Your PL/I program should include a DECLARE TABLE statement to describe each table and view the program accesses. You can use the DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE statements. For more information, see “DCLGEN (declarations generator)” on page 125. Including code: You can use SQL statements or PL/I host variable declarations from a member of a partitioned data set by using the following SQL statement in the source code where you want to include the statements: EXEC SQL INCLUDE member-name; You cannot nest SQL INCLUDE statements. Do not use the PL/I %INCLUDE statement to include SQL statements or host variable DCL statements. You must use the PL/I preprocessor to resolve any %INCLUDE statements before you use the DB2 precompiler. Do not use PL/I preprocessor directives within SQL statements. Margins: Code SQL statements in columns 2 through 72, unless you have specified other margins to the DB2 precompiler. If EXEC SQL starts before the specified left margin, the DB2 precompiler does not recognize the SQL statement. Names: You can use any valid PL/I name for a host variable. Do not use external entry names or access plan names that begin with ’DSN’, and do not use host variable names that begin with ’SQL’. These names are reserved for DB2. Sequence numbers: The source statements that the DB2 precompiler generates do not include sequence numbers. IEL0378I messages from the PL/I compiler identify lines of code without sequence numbers. You can ignore these messages. Statement labels: You can specify a statement label for executable SQL statements. However, the INCLUDE text-file-name and END DECLARE SECTION statements cannot have statement labels. Whenever statement: The target for the GOTO clause in an SQL statement WHENEVER must be a label in the PL/I source code and must be within the scope of any SQL statements that WHENEVER affects. Using double-byte character set (DBCS) characters: The following considerations apply to using DBCS in PL/I programs with SQL statements: 254 Application Programming and SQL Guide
  • 271.
    v If youuse DBCS in the PL/I source, DB2 rules for the following language elements apply: – Graphic strings – Graphic string constants – Host identifiers – Mixed data in character strings – MIXED DATA option v The PL/I preprocessor transforms the format of DBCS constants. If you do not want that transformation, run the DB2 precompiler before the preprocessor. v If you use graphic string constants or mixed data in dynamically prepared SQL statements, and if your application requires the PL/I Version 2 (or later) compiler, the dynamically prepared statements must use the PL/I mixed constant format. – If you prepare the statement from a host variable, change the string assignment to a PL/I mixed string. – If you prepare the statement from a PL/I string, change that to a host variable, and then change the string assignment to a PL/I mixed string. Example: SQLSTMT = ’SELECT <dbdb> FROM table-name’M; EXEC SQL PREPARE STMT FROM :SQLSTMT; v v v v For instructions on preparing SQL statements dynamically, see “Dynamic SQL” on page 258. If you want a DBCS identifier to resemble a PL/I graphic string, you must use a delimited identifier. If you include DBCS characters in comments, you must delimit the characters with a shift-out and shift-in control character. The first shift-in character signals the end of the DBCS string. You can declare host variable names that use DBCS characters in PL/I application programs. The rules for using DBCS variable names in PL/I follow existing rules for DBCS SQL ordinary identifiers, except for length. The maximum length for a host variable is 128 Unicode bytes in DB2. For information about the rules for DBCS SQL ordinary identifiers, see the topic “SQL identifiers” in DB2 SQL Reference. Restrictions: – DBCS variable names must contain DBCS characters only. Mixing single-byte character set (SBCS) characters with DBCS characters in a DBCS variable name produces unpredictable results. – A DBCS variable name cannot continue to the next line. The PL/I preprocessor changes non-Kanji DBCS characters into extended binary coded decimal interchange code (EBCDIC) SBCS characters. To avoid this change, use Kanji DBCS characters for DBCS variable names, or run the PL/I compiler without the PL/I preprocessor. Special PL/I considerations: The following considerations apply to programs written in PL/I: v When compiling a PL/I program that includes SQL statements, you must use the PL/I compiler option CHARSET (60 EBCDIC). v In unusual cases, the generated comments in PL/I can contain a semicolon. The semicolon generates compiler message IEL0239I, which you can ignore. Chapter 3. Including DB2 queries in an application program 255
  • 272.
    v The generatedcode in a PL/I declaration can contain the ADDR function of a field defined as character varying. This produces either message IBM105l l or IBM1180l W, both of which you can ignore. v The precompiler generated code in PL/I source can contain the NULL() function. This produces message IEL0533I, which you can ignore unless you also use NULL as a PL/I variable. If you use NULL as a PL/I variable in a DB2 application, you must also declare NULL as a built-in function (DCL NULL BUILTIN;) to avoid PL/I compiler errors. v The PL/I macro processor can generate SQL statements or host variable DCL statements if you run the macro processor before running the DB2 precompiler. If you use the PL/I macro processor, do not use the PL/I *PROCESS statement in the source to pass options to the PL/I compiler. You can specify the needed options on the COPTION parameter of the DSNH command or the option PARM.PLI=options of the EXEC statement in the DSNHPLI procedure. v Using the PL/I multitasking facility, in which multiple tasks execute SQL statements, causes unpredictable results. Embedding SQL statements in REXX procedures You can code SQL statements in a REXX procedure wherever you can use REXX commands. DB2 REXX Language Support allows all SQL statements that DB2 for z/OS supports, except the following statements: v BEGIN DECLARE SECTION v DECLARE STATEMENT v END DECLARE SECTION v INCLUDE v SELECT INTO v WHENEVER Each SQL statement in a REXX procedure must begin with EXECSQL, in either upper-, lower-, or mixed-case. One of the following items must follow EXECSQL: v An SQL statement enclosed in single or double quotation marks. v A REXX variable that contains an SQL statement. The REXX variable must not be preceded by a colon. For example, you can use either of the following methods to execute the COMMIT statement in a REXX procedure: EXECSQL "COMMIT" rexxvar="COMMIT" EXECSQL rexxvar You cannot execute a SELECT, INSERT, UPDATE, MERGE, or DELETE statement that contains host variables. Instead, you must execute PREPARE on the statement, with parameter markers substituted for the host variables, and then use the host variables in an EXECUTE, OPEN, or FETCH statement. See “Host variables, host variable arrays, and host structures” on page 142 for more information. | | | | | An SQL statement follows rules that apply to REXX commands. The SQL statement can optionally end with a semicolon and can be enclosed in single or double quotation marks, as in the following example: ’EXECSQL COMMIT’; 256 Application Programming and SQL Guide
  • 273.
    Comments: You cannotinclude REXX comments (/* ... */) or SQL comments (--) within SQL statements. However, you can include REXX comments anywhere else in the procedure. Continuation for SQL statements: SQL statements that span lines follow REXX rules for statement continuation. You can break the statement into several strings, each of which fits on a line, and separate the strings with commas or with concatenation operators followed by commas. For example, either of the following statements is valid: EXECSQL , "UPDATE DSN8910.DEPT" , "SET MGRNO = ’000010’" , "WHERE DEPTNO = ’D11’" "EXECSQL " || , " UPDATE DSN8910.DEPT " || , " SET MGRNO = ’000010’" || , " WHERE DEPTNO = ’D11’" Including code: The EXECSQL INCLUDE statement is not valid for REXX. You therefore cannot include externally defined SQL statements in a procedure. Margins: Like REXX commands, SQL statements can begin and end anywhere on a line. Names: You can use any valid REXX name that does not end with a period as a host variable. However, host variable names should not begin with ’SQL’, ’RDI’, ’DSN’, ’RXSQL’, or ’QRW’. Variable names can be at most 64 bytes. Nulls: A REXX null value and an SQL null value are different. The REXX language has a null string (a string of length 0) and a null clause (a clause that contains only blanks and comments). The SQL null value is a special value that is distinct from all nonnull values and denotes the absence of a value. Assigning a REXX null value to a DB2 column does not make the column value null. Statement labels: You can precede an SQL statement with a label, in the same way that you label REXX commands. Handling errors and warnings: DB2 does not support the SQL WHENEVER statement in a REXX procedure. To handle SQL errors and warnings, use the following methods: v To test for SQL errors or warnings, test the SQLCODE or SQLSTATE value and the SQLWARN. values after each EXECSQL call. This method does not detect errors in the REXX interface to DB2. v To test for SQL errors or warnings or errors or warnings from the REXX interface to DB2, test the REXX RC variable after each EXECSQL call. The following table lists the values of the RC variable. You can also use the REXX SIGNAL ON ERROR and SIGNAL ON FAILURE keyword instructions to detect negative values of the RC variable and transfer control to an error routine. Table 62. REXX return codes after SQL statements Return code Meaning 0 No SQL warning or error occurred. +1 An SQL warning occurred. -1 An SQL error occurred. Chapter 3. Including DB2 queries in an application program 257
  • 274.
    Table 62. REXXreturn codes after SQL statements (continued) Return code Meaning -3 The first token after ADDRESS DSNREXX is in error. For a description of the tokens allowed, see “Accessing the DB2 REXX language support application programming interfaces” on page 296. Delimiting an SQL statement You must delimit SQL statements in your program so that DB2 knows when a particular SQL statement ends. For languages other than REXX, delimit an SQL statement in your program with the beginning keyword EXEC SQL and a statement terminator. The terminators for the languages that are described in this information are the following: Language SQL Statement Terminator Assembler End of line or end of last continued line C and C++ Semicolon (;) COBOL END-EXEC. Fortran End of line or end of last continued line PL/I Semicolon (;) For REXX, precede the statement with EXECSQL. If the statement is in a literal string, enclose it in single or double quotation marks. Example: Use EXEC SQL and END-EXEC. to delimit an SQL statement in a COBOL program: EXEC SQL an SQL statement END-EXEC. Including dynamic SQL in your program Dynamic SQL is prepared and executed while the program is running. Before you use dynamic SQL, you should consider whether static SQL or dynamic SQL is the best technique for your application. Also consider the type of dynamic SQL that you want to use. Dynamic SQL Dynamic SQL statements are prepared and executed while the program is running. Use dynamic SQL when you do not know what SQL statements your application needs to execute before run time. Before you decide to use dynamic SQL, you should consider whether using static SQL or dynamic SQL is the best technique for your application. For most DB2 users, static SQL, which is embedded in a host language program and bound before the program runs, provides a straightforward, efficient path to 258 Application Programming and SQL Guide
  • 275.
    DB2 data. Youcan use static SQL when you know before run time what SQL statements your application needs to execute. | | Dynamic SQL prepares and executes the SQL statements within a program, while the program is running. Four types of dynamic SQL are: v Interactive SQL A user enters SQL statements through SPUFI or the command line processor. DB2 prepares and executes those statements as dynamic SQL statements. v Embedded dynamic SQL Your application puts the SQL source in host variables and includes PREPARE and EXECUTE statements that tell DB2 to prepare and run the contents of those host variables at run time. You must precompile and bind programs that include embedded dynamic SQL. v Deferred embedded SQL Deferred embedded SQL statements are neither fully static nor fully dynamic. Like static statements, deferred embedded SQL statements are embedded within applications, but like dynamic statements, they are prepared at run time. DB2 processes deferred embedded SQL statements with bind-time rules. For example, DB2 uses the authorization ID and qualifier determined at bind time as the plan or package owner. Deferred embedded SQL statements are used for DB2 private protocol access to remote data. v Dynamic SQL executed through ODBC functions Your application contains ODBC function calls that pass dynamic SQL statements as arguments. You do not need to precompile and bind programs that use ODBC function calls. Differences between static and dynamic SQL: Static and dynamic SQL are each appropriate for different circumstances. You should consider the differences between the two when determining whether static SQL or dynamic SQL is best for your application. Flexibility of static SQL with host variables When you use static SQL, you cannot change the form of SQL statements unless you make changes to the program. However, you can increase the flexibility of static statements by using host variables. Example: In the following example, the UPDATE statement can update the salary of any employee. At bind time, you know that salaries must be updated, but you do not know until run time whose salaries should be updated, and by how much. 01 IOAREA. 02 EMPID 02 NEW-SALARY PIC X(06). PIC S9(7)V9(2) COMP-3. . . . (Other declarations) READ CARDIN RECORD INTO IOAREA . AT END MOVE ’N’ TO INPUT-SWITCH. . . (Other COBOL statements) EXEC SQL UPDATE DSN8910.EMP SET SALARY = :NEW-SALARY WHERE EMPNO = :EMPID END-EXEC. Chapter 3. Including DB2 queries in an application program 259
  • 276.
    The statement (UPDATE)does not change, nor does its basic structure, but the input can change the results of the UPDATE statement. Flexibility of dynamic SQL What if a program must use different types and structures of SQL statements? If there are so many types and structures that it cannot contain a model of each one, your program might need dynamic SQL. | You can use one of the following programs to execute dynamic SQL: | | DB2 Query Management Facility (DB2 QMF) Provides an alternative interface to DB2 that accepts almost any SQL statement | | | SPUFI Accepts SQL statements from an input data set, and then processes and executes them dynamically | | command line processor Accepts SQL statements from a UNIX® System Services environment. Limitations of dynamic SQL You cannot use some of the SQL statements dynamically. Dynamic SQL processing A program that provides for dynamic SQL accepts as input, or generates, an SQL statement in the form of a character string. You can simplify the programming if you can plan the program not to use SELECT statements, or to use only those that return a known number of values of known types. In the most general case, in which you do not know in advance about the SQL statements that will execute, the program typically takes these steps: 1. Translates the input data, including any parameter markers, into an SQL statement 2. Prepares the SQL statement to execute and acquires a description of the result table 3. Obtains, for SELECT statements, enough main storage to contain retrieved data 4. Executes the statement or fetches the rows of data 5. Processes the information returned 6. Handles SQL return codes. Performance of static and dynamic SQL To access DB2 data, an SQL statement requires an access path. Two big factors in the performance of an SQL statement are the amount of time that DB2 uses to determine the access path at run time and whether the access path is efficient. DB2 determines the access path for a statement at either of these times: v When you bind the plan or package that contains the SQL statement v When the SQL statement executes The time at which DB2 determines the access path depends on these factors: v Whether the statement is executed statically or dynamically v Whether the statement contains input host variables 260 Application Programming and SQL Guide
  • 277.
    Static SQL statementswith no input host variables For static SQL statements that do not contain input host variables, DB2 determines the access path when you bind the plan or package. This combination yields the best performance because the access path is already determined when the program executes. Static SQL statements with input host variables | | | | | | For static SQL statements that have input host variables, the time at which DB2 determines the access path depends on which bind option you specify: REOPT(NONE), REOPT(ONCE), or REOPT(ALWAYS). REOPT(NONE) is the default. Do not specify REOPT(AUTO); this option is applicable only to dynamic statements. DB2 ignores REOPT(AUTO) for static SQL statements, because DB2 can cache only dynamic statements. If you specify REOPT(NONE), DB2 determines the access path at bind time, just as it does when there are no input variables. DB2 ignores REOPT(ONCE) for static SQL statements because DB2 can cache only dynamic SQL statements If you specify REOPT(ALWAYS), DB2 determines the access path at bind time and again at run time, using the values in these types of input variables: v Host variables v Parameter markers v Special registers This means that DB2 must spend extra time determining the access path for statements at run time, but if DB2 determines a significantly better access path using the variable values, you might see an overall performance improvement. In general, using REOPT(ALWAYS) can make static SQL statements with input variables perform like dynamic SQL statements with constants. Dynamic SQL statements For dynamic SQL statements, DB2 determines the access path at run time, when the statement is prepared. This can make the performance worse than that of static SQL statements. However, if you execute the same SQL statement often, you can use the dynamic statement cache to decrease the number of times that those dynamic statements must be prepared. | | | Dynamic SQL statements with input host variables: When you bind applications that contain dynamic SQL statements with input host variables, use the REOPT(ALWAYS) option, the REOPT(ONCE) option, or the REOPT(AUTO) option. Use REOPT(ALWAYS) when you are not using the dynamic statement cache. DB2 determines the access path for statements at each EXECUTE or OPEN of the statement. This ensure the best access path for a statement, but using REOPT(ALWAYS) can increase the cost of frequently used dynamic SQL statements. | | | | Use REOPT(ONCE) or REOPT(AUTO) when you are using the dynamic statements cache: v If you specify REOPT(ONCE), DB2 determines and the access path for statements only at the first EXECUTE or OPEN of the statement. It saves that Chapter 3. Including DB2 queries in an application program 261
  • 278.
    | | | | | | | | access path inthe dynamic statement cache and uses it until the statement is invalidated or removed from the cache. This reuse of the access path reduces the cost of frequently used dynamic SQL statements that contain input host variables; however, it does not account for changes to parameter marker values for dynamic statements. v If you specify REOPT(AUTO), DB2 determines the access path at run time. For each execution of a statement with parameter markers, DB2 generates a new access path if it determines that a new access path will improve performance. | | | | | | | | You should code your PREPARE statements to minimize overhead. With REOPT(AUTO), REOPT(ALWAYS), and REOPT(ONCE), DB2 prepares an SQL statement at the same time as it processes OPEN or EXECUTE for the statement. That is, DB2 processes the statement as if you specify DEFER(PREPARE). However, in the following cases, DB2 prepares the statement twice: v If you execute the DESCRIBE statement before the PREPARE statement in your program v If you use the PREPARE statement with the INTO parameter | | | For the first prepare, DB2 determines the access path without using input variable values. For the second prepare, DB2 uses the input variable values to determine the access path. This extra prepare can decrease performance. If you specify REOPT(ALWAYS), DB2 prepares the statement twice each time it is run. If you specify REOPT(ONCE), DB2 prepares the statement twice only when the statement has never been saved in the cache. If the statement has been prepared and saved in the cache, DB2 will use the saved version of the statement to complete the DESCRIBE statement. If you specify REOPT(AUTO), DB2 initially prepares the statement without using input variable values. If the statement has been saved in the cache, for the subsequent OPEN or EXECUTE, DB2 determines if a new access path is needed according to the input variable values. For a statement that uses a cursor, you can avoid the double prepare by placing the DESCRIBE statement after the OPEN statement in your program. If you use predictive governing, and a dynamic SQL statement that is bound with either REOPT(ALWAYS) or REOPT(ONCE) exceeds a predictive governing warning threshold, your application does not receive a warning SQLCODE. However, it will receive an error SQLCODE from the OPEN or EXECUTE statement. Possible host languages for dynamic SQL applications: Programs that use dynamic SQL are usually written in assembler, C, PL/I, REXX, and COBOL. All SQL in REXX programs is dynamic SQL. You can write non-SELECT and fixed-list SELECT statements in any of the DB2 supported languages. A program containing a varying-list SELECT statement is more difficult to write in Fortran, because the program cannot run without the help of a subroutine to manage address variables (pointers) and storage allocation. Most of the examples in this topic are in PL/I. Longer examples in the form of complete programs are available in the sample applications: 262 Application Programming and SQL Guide
  • 279.
    DSNTEP2 Processes both SELECTand non-SELECT statements dynamically. (PL/I). DSNTIAD Processes only non-SELECT statements dynamically. (Assembler). DSNTIAUL Processes SELECT statements dynamically. (Assembler). Library prefix.SDSNSAMP contains the sample programs. You can view the programs online, or you can print them using ISPF, IEBPTPCH, or your own printing program. Using dynamic SQL in COBOL: You can use all forms of dynamic SQL in all supported versions of COBOL. For a detailed description and a working example of the method, see “Sample COBOL dynamic SQL program” on page 334. Including dynamic SQL for non-SELECT statements in your program The easiest way to use dynamic SQL is to use non-SELECT statements. Because you do not need to dynamically allocate any main storage, you can write your program in any host language, including Fortran. For a sample program written in C that contains dynamic SQL with non-SELECT statements, see “Sample dynamic and static SQL in a C program” on page 331. Your program must take the following steps: 1. Include an SQLCA. The requirements for an SQL communications area (SQLCA) are the same as for static SQL statements. For REXX, DB2 includes the SQLCA automatically. 2. Load the input SQL statement into a data area. The procedure for building or reading the input SQL statement is not discussed here; the statement depends on your environment and sources of information. You can read in complete SQL statements, or you can get information to build the statement from data sets, a user at a terminal, previously set program variables, or tables in the database. If you attempt to execute an SQL statement dynamically that DB2 does not allow, you get an SQL error. 3. Execute the statement. You can use either of these methods: v “Dynamically executing an SQL statement by using EXECUTE IMMEDIATE” on page 283 v “Dynamically executing an SQL statement by using PREPARE and EXECUTE” on page 284. 4. Handle any errors that might result. The requirements are the same as those for static SQL statements. The return code from the most recently executed SQL statement appears in the host variables SQLCODE and SQLSTATE or corresponding fields of the SQLCA. See “Checking the execution of SQL statements” on page 298 for information about the SQLCA and the fields it contains. Including dynamic SQL for fixed-list SELECT statements in your program A fixed-list SELECT statement returns rows that contain a known number of values of a known type. When you use this type of statement, you know in advance exactly what kinds of host variables you need to declare to store the results. Chapter 3. Including DB2 queries in an application program 263
  • 280.
    (For information aboutthe contrasting situation, in which you do not know in advance what host-variable structure you might need, see “Including dynamic SQL for varying-list SELECT statements in your program” on page 266.) The term “fixed-list” does not imply that you must know in advance how many rows of data will be returned. However, you must know the number of columns and the data types of those columns. A fixed-list SELECT statement returns a result table that can contain any number of rows; your program looks at those rows one at a time, using the FETCH statement. Each successive fetch returns the same number of values as the last, and the values have the same data types each time. Therefore, you can specify host variables as you do for static SQL. An advantage of the fixed-list SELECT is that you can write it in any of the programming languages that DB2 supports. Varying-list dynamic SELECT statements require assembler, C, PL/I, and COBOL. For a sample program that is written in C and that illustrates dynamic SQL with fixed-list SELECT statements, see “Sample dynamic and static SQL in a C program” on page 331. To execute a fixed-list SELECT statement dynamically, your program must: 1. Include an SQLCA. 2. Load the input SQL statement into a data area. The preceding two steps are exactly the same as described under “Including dynamic SQL for non-SELECT statements in your program” on page 263. 3. Declare a cursor for the statement name. 4. Prepare the statement. 5. Open the cursor. 6. Fetch rows from the result table. 7. Close the cursor. 8. Handle any resulting errors. This step is the same as for static SQL, except for the number and types of errors that can result. Example: Suppose that your program retrieves last names and phone numbers by dynamically executing SELECT statements of this form: SELECT LASTNAME, PHONENO FROM DSN8910.EMP WHERE ... ; The program reads the statements from a terminal, and the user determines the WHERE clause. As with non-SELECT statements, your program puts the statements into a varying-length character variable; call it DSTRING. Eventually you prepare a statement from DSTRING, but first you must declare a cursor for the statement and give it a name. Declaring a cursor for the statement name: Dynamic SELECT statements cannot use INTO. Therefore, you must use a cursor to put the results into host variables. Example: When you declare the cursor, use the statement name (call it STMT), and give the cursor itself a name (for example, C1): EXEC SQL DECLARE C1 CURSOR FOR STMT; 264 Application Programming and SQL Guide
  • 281.
    Preparing the statement: Preparea statement (STMT) from DSTRING. Example: This is one possible PREPARE statement: EXEC SQL PREPARE STMT FROM :DSTRING ATTRIBUTES :ATTRVAR; ATTRVAR contains attributes that you want to add to the SELECT statement, such as FETCH FIRST 10 ROWS ONLY or OPTIMIZE for 1 ROW. In general, if the SELECT statement has attributes that conflict with the attributes in the PREPARE statement, the attributes on the SELECT statement take precedence over the attributes on the PREPARE statement. However, in this example, the SELECT statement in DSTRING has no attributes specified, so DB2 uses the attributes in ATTRVAR for the SELECT statement. As with non-SELECT statements, the fixed-list SELECT could contain parameter markers. However, this example does not need them. To execute STMT, your program must open the cursor, fetch rows from the result table, and close the cursor. Opening the cursor: The OPEN statement evaluates the SELECT statement named STMT. Example: Without parameter markers, use this statement: EXEC SQL OPEN C1; If STMT contains parameter markers, you must use the USING clause of OPEN to provide values for all of the parameter markers in STMT. Example: If four parameter markers are in STMT, you need the following statement: EXEC SQL OPEN C1 USING :PARM1, :PARM2, :PARM3, :PARM4; Fetching rows from the result table: Example: Your program could repeatedly execute a statement such as this: EXEC SQL FETCH C1 INTO :NAME, :PHONE; The key feature of this statement is the use of a list of host variables to receive the values returned by FETCH. The list has a known number of items (in this case, two items, :NAME and :PHONE) of known data types (both are character strings, of lengths 15 and 4, respectively). You can use this list in the FETCH statement only because you planned the program to use only fixed-list SELECTs. Every row that cursor C1 points to must contain exactly two character values of appropriate length. If the program is to handle anything else, it must use the techniques described under “Including dynamic SQL for varying-list SELECT statements in your program” on page 266. Closing the cursor: This step is the same as for static SQL. Chapter 3. Including DB2 queries in an application program 265
  • 282.
    Example: A WHENEVERNOT FOUND statement in your program can name a routine that contains this statement: EXEC SQL CLOSE C1; Including dynamic SQL for varying-list SELECT statements in your program A varying-list SELECT statement returns rows that contain an unknown number of values of unknown type. When you use this type of statement, you do not know in advance exactly what kinds of host variables you need to declare to store the results. . (For the much simpler situation, in which you do know, see “Including dynamic SQL for fixed-list SELECT statements in your program” on page 263.) Because the varying-list SELECT statement requires pointer variables for the SQL descriptor area, you cannot issue it from a Fortran program. A Fortran program can call a subroutine written in a language that supports pointer variables (such as PL/I or assembler), if you need to use a varying-list SELECT statement. What your application program must do for varying-list SELECT statements: To execute a varying-list SELECT statement dynamically, your program must follow these steps: 1. Include an SQLCA. DB2 performs this step for a REXX procedure. 2. Load the input SQL statement into a data area. Those first two steps are exactly the same as described under “Including dynamic SQL for non-SELECT statements in your program” on page 263; the next step is new: 3. Prepare and execute the statement. This step is more complex than for fixed-list SELECTs. It involves the following steps: a. Include an SQLDA (SQL descriptor area). DB2 performs this step for a REXX procedure. b. Declare a cursor and prepare the variable statement. c. Obtain information about the data type of each column of the result table. d. Determine the main storage needed to hold a row of retrieved data. You do not perform this step for a REXX procedure. e. Put storage addresses in the SQLDA to tell where to put each item of retrieved data. f. Open the cursor. g. Fetch a row. h. Eventually close the cursor and free main storage. Additional complications exist for statements with parameter markers. 4. Handle any errors that might result. Preparing a varying-list SELECT statement: Suppose that your program dynamically executes SQL statements, but this time without any limits on their form. Your program reads the statements from a terminal, and you know nothing about them in advance. They might not even be SELECT statements. 266 Application Programming and SQL Guide
  • 283.
    As with non-SELECTstatements, your program puts the statements into a varying-length character variable; call it DSTRING. Your program goes on to prepare a statement from the variable and then give the statement a name; call it STMT. Now, the program must find out whether the statement is a SELECT. If it is, the program must also find out how many values are in each row, and what their data types are. The information comes from an SQL descriptor area (SQLDA). An SQL descriptor area: The SQLDA is a structure that is used to communicate with your program, and storage for it is usually allocated dynamically at run time. To include the SQLDA in a PL/I or C program, use: EXEC SQL INCLUDE SQLDA; For assembler, use this in the storage definition area of a CSECT: EXEC SQL INCLUDE SQLDA For COBOL, use: EXEC SQL INCLUDE SQLDA END-EXEC. You cannot include an SQLDA in a Fortran, or REXX program. For more information about the SQLDA, see the topic “SQL descriptor area (SQLDA)” in DB2 SQL Reference. Obtaining information about the SQL statement: An SQLDA can contain a variable number of occurrences of SQLVAR, each of which is a set of five fields that describe one column in the result table of a SELECT statement. The number of occurrences of SQLVAR depends on the following factors: v The number of columns in the result table you want to describe. v Whether you want the PREPARE or DESCRIBE to put both column names and labels in your SQLDA. This is the option USING BOTH in the PREPARE or DESCRIBE statement. v Whether any columns in the result table are LOB types or distinct types. The following table shows the minimum number of SQLVAR instances you need for a result table that contains n columns. Table 63. Minimum number of SQLVARs for a result table with n columns Type of DESCRIBE and contents of result table Not USING BOTH USING BOTH No distinct types or LOBs n 2*n Distinct types but no LOBs 2*n 3*n LOBs but no distinct types 2*n 2*n LOBs and distinct types 2*n 3*n Chapter 3. Including DB2 queries in an application program 267
  • 284.
    An SQLDA withn occurrences of SQLVAR is referred to as a single SQLDA, an SQLDA with 2*n occurrences of SQLVAR a double SQLDA, an SQLDA with 3*n occurrences of SQLVAR a triple SQLDA. A program that admits SQL statements of every kind for dynamic execution has two choices: v Provide the largest SQLDA that it could ever need. The maximum number of columns in a result table is 750, so an SQLDA for 750 columns occupies 33 016 bytes for a single SQLDA, 66 016 bytes for a double SQLDA, or 99 016 bytes for a triple SQLDA. Most SELECT statements do not retrieve 750 columns, so the program does not usually use most of that space. v Provide a smaller SQLDA, with fewer occurrences of SQLVAR. From this the program can find out whether the statement was a SELECT and, if it was, how many columns are in its result table. If more columns are in the result than the SQLDA can hold, DB2 returns no descriptions. When this happens, the program must acquire storage for a second SQLDA that is long enough to hold the column descriptions, and ask DB2 for the descriptions again. Although this technique is more complicated to program than the first, it is more general. How many columns should you allow? You must choose a number that is large enough for most of your SELECT statements, but not too wasteful of space; 40 is a good compromise. To illustrate what you must do for statements that return more columns than allowed, the example in this discussion uses an SQLDA that is allocated for at least 100 columns. Declaring a cursor for the statement: As before, you need a cursor for the dynamic SELECT. For example, write: EXEC SQL DECLARE C1 CURSOR FOR STMT; Preparing the statement using the minimum SQLDA: Suppose that your program declares an SQLDA structure with the name MINSQLDA, having 100 occurrences of SQLVAR and SQLN set to 100. To prepare a statement from the character string in DSTRING and also enter its description into MINSQLDA, write this: EXEC SQL PREPARE STMT FROM :DSTRING; EXEC SQL DESCRIBE STMT INTO :MINSQLDA; Equivalently, you can use the INTO clause in the PREPARE statement: EXEC SQL PREPARE STMT INTO :MINSQLDA FROM :DSTRING; Do not use the USING clause in either of these examples. At the moment, only the minimum SQLDA is in use. The following figure shows the contents of the minimum SQLDA in use. Header SQLDAID SQLDABC 100 SQLD Figure 21. The minimum SQLDA structure SQLN determines what SQLVAR gets: 268 Application Programming and SQL Guide
  • 285.
    The SQLN field,which you must set before using DESCRIBE (or PREPARE INTO), tells how many occurrences of SQLVAR the SQLDA is allocated for. If DESCRIBE needs more than that, the results of the DESCRIBE depend on the contents of the result table. Let n indicate the number of columns in the result table. Then: v If the result table contains at least one distinct type column but no LOB columns, you do not specify USING BOTH, and n<=SQLN<2*n, then DB2 returns base SQLVAR information in the first n SQLVAR occurrences, but no distinct type information. Base SQLVAR information includes: – Data type code – Length attribute (except for LOBs) – Column name or label – Host variable address – Indicator variable address v Otherwise, if SQLN is less than the minimum number of SQLVARs specified in Table 63 on page 267, then DB2 returns no information in the SQLVARs. Regardless of whether your SQLDA is big enough, whenever you execute DESCRIBE, DB2 returns the following values, which you can use to build an SQLDA of the correct size: v SQLD is 0 if the SQL statement is not a SELECT. Otherwise, SQLD is the number of columns in the result table. The number of SQLVAR occurrences you need for the SELECT depends on the value in the seventh byte of SQLDAID. v The seventh byte of SQLDAID is 2 if each column in the result table requires two SQLVAR entries. The seventh byte of SQLDAID is 3 if each column in the result table requires three SQLVAR entries. If the statement is not a SELECT: To find out if the statement is a SELECT, your program can query the SQLD field in MINSQLDA. If the field contains 0, the statement is not a SELECT, the statement is already prepared, and your program can execute it. If no parameter markers are in the statement, you can use: EXEC SQL EXECUTE STMT; (If the statement does contain parameter markers, you must use an SQL descriptor area; for instructions, see “Including dynamic SQL for varying-list SELECT statements in your program” on page 266.) Acquiring storage for a second SQLDA if needed: Now you can allocate storage for a second, full-size SQLDA; call it FULSQLDA. The following figure shows its structure. Chapter 3. Including DB2 queries in an application program 269
  • 286.
    Figure 22. Thefull-size SQLDA structure FULSQLDA has a fixed-length header of 16 bytes in length, followed by a varying-length section that consists of structures with the SQLVAR format. If the result table contains LOB columns or distinct type columns, a varying-length section that consists of structures with the SQLVAR2 format follows the structures with SQLVAR format. All SQLVAR structures and SQLVAR2 structures are 44 bytes long. For more information about the two SQLVAR formats, see the topic “DESCRIBE OUTPUT” in DB2 SQL Reference. The number of SQLVAR and SQLVAR2 elements you need is in the SQLD field of MINSQLDA, and the total length you need for FULSQLDA (16 + SQLD * 44) is in the SQLDABC field of MINSQLDA. Allocate that amount of storage. Describing the SELECT statement again: After allocating sufficient space for FULSQLDA, your program must take these steps: 1. Put the total number of SQLVAR and SQLVAR2 occurrences in FULSQLDA into the SQLN field of FULSQLDA. This number appears in the SQLD field of MINSQLDA. 2. Describe the statement again into the new SQLDA: EXEC SQL DESCRIBE STMT INTO :FULSQLDA; After the DESCRIBE statement executes, each occurrence of SQLVAR in the full-size SQLDA (FULSQLDA in our example) contains a description of one column of the result table in five fields. If an SQLVAR occurrence describes a LOB column or distinct type column, the corresponding SQLVAR2 occurrence contains additional information specific to the LOB or distinct type. The following figure shows an SQLDA that describes two columns that are not LOB columns or distinct type columns. 270 Application Programming and SQL Guide
  • 287.
    SQLDA SQLDA header 8816 200 200 SQLVAR element1 (44 bytes) 452 3 Undefined 0 8 WORKDEPT SQLVAR element 2 (44 bytes) 453 4 Undefined 0 7 PHONENO Figure 23. Contents of FULSQLDA after executing DESCRIBE Acquiring storage to hold a row: Before fetching rows of the result table, your program must: 1. Analyze each SQLVAR description to determine how much space you need for the column value. 2. Derive the address of some storage area of the required size. 3. Put this address in the SQLDATA field. If the SQLTYPE field indicates that the value can be null, the program must also put the address of an indicator variable in the SQLIND field. The following figures show the SQL descriptor area after you take certain actions. In Figure 23, the DESCRIBE statement inserted all the values except the first occurrence of the number 200. The program inserted the number 200 before it executed DESCRIBE to tell how many occurrences of SQLVAR to allow. If the result table of the SELECT has more columns than this, the SQLVAR fields describe nothing. The first SQLVAR pertains to the first column of the result table (the WORKDEPT column). SQLVAR element 1 contains fixed-length character strings and does not allow null values (SQLTYPE=452); the length attribute is 3. For information about SQLTYPE values, see the topic “SQLTYPE and SQLLEN” in DB2 SQL Reference. The following figure shows the SQLDA after your program acquires storage for the column values and their indicators, and puts the addresses in the SQLDATA fields of the SQLDA. SQLDA SQLDA header 8816 200 200 SQLVAR element 1 (44 bytes) 452 3 Addr FLDA Addr FLDAI 8 WORKDEPT SQLVAR element 2 (44 bytes) 453 4 Addr FLDB Addr FLDBI 7 PHONENO FLDA CHAR(3) FLDB CHAR(4) Indicator variables (halfword) FLDAI FLDBI Figure 24. SQL descriptor area after analyzing descriptions and acquiring storage The following figure shows the SQLDA after your program executes a FETCH statement. Chapter 3. Including DB2 queries in an application program 271
  • 288.
    SQLDA SQLDA header 8816 200 200 SQLVAR element1 (44 bytes) 452 3 Addr FLDA Addr FLDAI 8 WORKDEPT SQLVAR element 2 (44 bytes) 453 4 Addr FLDB Addr FLDBI 7 PHONENO FLDA CHAR(3) Indicator variables (halfword) FLDAI FLDBI FLDB CHAR(4) E11 4502 0 0 Figure 25. SQL descriptor area after executing FETCH The following table describes the values in the descriptor area. Table 64. Values inserted in the SQLDA Value Field Description SQLDA SQLDAID An “eye-catcher” 8816 SQLDABC The size of the SQLDA in bytes (16 + 44 * 200) 200 SQLN The number of occurrences of SQLVAR, set by the program 200 SQLD The number of occurrences of SQLVAR actually used by the DESCRIBE statement 452 SQLTYPE The value of SQLTYPE in the first occurrence of SQLVAR. It indicates that the first column contains fixed-length character strings, and does not allow nulls. 3 SQLLEN The length attribute of the column Undefined or CCSID value SQLDATA Bytes 3 and 4 contain the CCSID of a string column. Undefined for other types of columns. Undefined SQLIND 8 SQLNAME The number of characters in the column name WORKDEPT SQLNAME+2 The column name of the first column Putting storage addresses in the SQLDA: After analyzing the description of each column, your program must replace the content of each SQLDATA field with the address of a storage area large enough to hold values from that column. Similarly, for every column that allows nulls, the program must replace the content of the SQLIND field. The content must be the address of a halfword that you can use as an indicator variable for the column. The program can acquire storage for this purpose, of course, but the storage areas used do not have to be contiguous. Figure 24 on page 271 shows the content of the descriptor area before the program obtains any rows of the result table. Addresses of fields and indicator variables are already in the SQLVAR. Changing the CCSID for retrieved data: All DB2 string data has an encoding scheme and CCSID associated with it. When you select string data from a table, the selected data generally has the same 272 Application Programming and SQL Guide
  • 289.
    encoding scheme andCCSID as the table. If the application uses some method, such as issuing the DECLARE VARIABLE statement, to change the CCSID of the selected data, the data is converted from the CCSID of the table to the CCSID that is specified by the application. You can set the default application encoding scheme for a plan or package by specifying the value in the APPLICATION ENCODING field of the panel DEFAULTS FOR BIND PACKAGE or DEFAULTS FOR BIND PLAN. The default application encoding scheme for the DB2 subsystem is the value that was specified in the APPLICATION ENCODING field of installation panel DSNTIPF. If you want to retrieve the data in an encoding scheme and CCSID other than the default values, you can use one of the following techniques: v For dynamic SQL, set the CURRENT APPLICATION ENCODING SCHEME special register before you execute the SELECT statements. For example, to set the CCSID and encoding scheme for retrieved data to the default CCSID for Unicode, execute this SQL statement: EXEC SQL SET CURRENT APPLICATION ENCODING SCHEME =’UNICODE’; The initial value of this special register is the application encoding scheme that is determined by the BIND option. v For static and dynamic SQL statements that use host variables and host variable arrays, use the DECLARE VARIABLE statement to associate CCSIDs with the host variables into which you retrieve the data. See “Changing the coded character set ID of host variables” on page 146 for information about this technique. v For static and dynamic SQL statements that use a descriptor, set the CCSID for the retrieved data in the SQLDA. The following text describes that technique. To change the encoding scheme for SQL statements that use a descriptor, set up the SQLDA, and then make these additional changes to the SQLDA: 1. Put the character + in the sixth byte of field SQLDAID. 2. For each SQLVAR entry: a. Set the length field of SQLNAME to 8. b. Set the first two bytes of the data field of SQLNAME to X’0000’. c. Set the third and fourth bytes of the data field of SQLNAME to the CCSID, in hexadecimal, in which you want the results to display, or to X’0000’. X’0000’ indicates that DB2 should use the default CCSID If you specify a nonzero CCSID, it must meet one of the following conditions: v A row in catalog table SYSSTRINGS has a matching value for OUTCCSID. v The Unicode conversion services support conversion to that CCSID. See z/OS C/C++ Programming Guide for information about the conversions supported. If you are modifying the CCSID to retrieve the contents of an ASCII, EBCDIC, or Unicode table on a DB2 for z/OS system, and you previously executed a DESCRIBE statement on the SELECT statement that you are using to retrieve the data, the SQLDATA fields in the SQLDA that you used for the DESCRIBE contain the ASCII or Unicode CCSID for that table. To set the data portion of the SQLNAME fields for the SELECT, move the contents of each SQLDATA field in the SQLDA from the DESCRIBE to each SQLNAME field in the SQLDA for the SELECT. If you are using the same Chapter 3. Including DB2 queries in an application program 273
  • 290.
    SQLDA for theDESCRIBE and the SELECT, be sure to move the contents of the SQLDATA field to SQLNAME before you modify the SQLDATA field for the SELECT. For REXX, you set the CCSID in the stem.n.SQLUSECCSID field instead of setting the SQLDAID and SQLNAME fields. For example, suppose that the table that contains WORKDEPT and PHONENO is defined with CCSID ASCII. To retrieve data for columns WORKDEPT and PHONENO in ASCII CCSID 437 (X’01B5’), change the SQLDA as shown in the following figure. SQLDA header SQLDA+ 8816 200 200 SQLVAR element 1 (44 bytes) 452 3 Addr FLDA Addr FLDAI 8 X’000001B500000000’ SQLVAR element 2 (44 bytes) 453 4 Addr FLDB Addr FLDBI 8 X’000001B500000000’ FLDA CHAR(3) FLDB CHAR(4) Indicator variables (halfword) FLDAI FLDBI Figure 26. SQL descriptor area for retrieving data in ASCII CCSID 437 Specifying that DESCRIBE use column labels in the SQLNAME field: By default, DESCRIBE describes each column in the SQLNAME field by the column name. You can tell it to use column labels instead. Restriction: You cannot use column labels with set operators (UNION, INTERSECT, and EXCEPT). To specify that DESCRIBE use column labels in the SQLNAME field, specify one of the following options when you issue the DESCRIBE statement: USING LABELS Specifies that SQLNAME is to contain labels. If a column has no label, SQLNAME contains nothing. USING ANY Specifies that SQLNAME is to contain labels wherever they exist. If a column has no label, SQLNAME contains the column name. USING BOTH Specifies that SQLNAME is to contain both labels and column names, when both exist. In this case, FULSQLDA must contain a second set of occurrences of SQLVAR. The first set contains descriptions of all the columns with column names; the second set contains descriptions with column labels. If you choose this option, perform the following actions: v Allocate a longer SQLDA for the second DESCRIBE statement ((16 + SQLD * 88 bytes) instead of (16 + SQLD * 44)) v Put double the number of columns (SLQD * 2) in the SQLN field of the second SQLDA. 274 Application Programming and SQL Guide
  • 291.
    These actions ensurethat enough space is available. Otherwise, if not enough space is available, DESCRIBE does not enter descriptions of any of the columns. EXEC SQL DESCRIBE STMT INTO :FULSQLDA USING LABELS; | | | | Some columns, such as those derived from functions or expressions, have neither name nor label; SQLNAME contains nothing for those columns. For example, if you use a UNION to combine two columns that do not have the same name and do not use a label, SQLNAME contains a string of length zero. Describing tables with LOB and distinct type columns: In general, the steps that you perform when you prepare an SQLDA to select rows from a table with LOB and distinct type columns are similar to the steps that you perform if the table has no columns of this type. The only difference is that you need to analyze some additional fields in the SQLDA for LOB or distinct type columns. Example: Suppose that you want to execute this SELECT statement: SELECT USER, A_DOC FROM DOCUMENTS; The USER column cannot contain nulls and is of distinct type ID, defined like this: CREATE DISTINCT TYPE SCHEMA1.ID AS CHAR(20); The A_DOC column can contain nulls and is of type CLOB(1M). The result table for this statement has two columns, but you need four SQLVAR occurrences in your SQLDA because the result table contains a LOB type and a distinct type. Suppose that you prepare and describe this statement into FULSQLDA, which is large enough to hold four SQLVAR occurrences. FULSQLDA looks like the following figure . SQLDA 2 SQLDA header 192 4 4 SQLVAR element 1 (44 bytes) 452 20 Undefined 0 4 USER SQLVAR element 2 (44 bytes) 409 0 Undefined 0 5 A_DOC 7 SCH1.ID SQLVAR2 element 1 (44 bytes) SQLVAR2 element 2 (44 bytes) 1 048 576 11 SYSIBM.CLOB Figure 27. SQL descriptor area after describing a CLOB and distinct type The next steps are the same as for result tables without LOBs or distinct types: 1. Analyze each SQLVAR description to determine the maximum amount of space you need for the column value. For a LOB type, retrieve the length from the SQLLONGL field instead of the SQLLEN field. 2. Derive the address of some storage area of the required size. For a LOB data type, you also need a 4-byte storage area for the length of the LOB data. You can allocate this 4-byte area at the beginning of the LOB data or in a different location. 3. Put this address in the SQLDATA field. Chapter 3. Including DB2 queries in an application program 275
  • 292.
    For a LOBdata type, if you allocated a separate area to hold the length of the LOB data, put the address of the length field in SQLDATAL. If the length field is at beginning of the LOB data area, put 0 in SQLDATAL. When you use a file reference variable for a LOB column, the indicator variable indicates whether the data in the file is null, not whether the data to which SQLDATA points is null. 4. If the SQLTYPE field indicates that the value can be null, the program must also put the address of an indicator variable in the SQLIND field. The following figure shows the contents of FULSQLDA after you fill in pointers to the storage locations. Figure 28. SQL descriptor area after analyzing CLOB and distinct type descriptions and acquiring storage The following figure shows the contents of FULSQLDA after you execute a FETCH statement. Figure 29. SQL descriptor area after executing FETCH on a table with CLOB and distinct type columns Setting an XML host variable in an SQLDA: 276 Application Programming and SQL Guide
  • 293.
    Instead of specifyinghost variables to store XML values from a table, you can create an SQLDA to point to the data areas where DB2 puts the retrieved data. The SQLDA needs to describe the data type for each data area. To set an XML host variable in an SQLDA: 1. Allocate an appropriate SQLDA. For instructions on how to allocate an SQLDA, see the topic “DESCRIBE OUTPUT” in DB2 SQL Reference. 2. Issue a DESCRIBE statement for the SQL statement whose result set you want to store. The DESCRIBE statement populates the SQLDA based on the column definitions. In the SQLDA, an SQLVAR entry is populated for each column in the result set. (Multiple SQLVAR entries are populated for LOB columns and columns with distinct types.) For columns of type XML the associated SQLVAR entry is populated as follows: Table 65. SQLVAR field values for XML columns SQLVAR field Value for an XML column sqltype SQLTYPE 988 for a column that is not nullable or 989 for a nullable column 0 sqllen SQLLEN 0 sqldata SQLDATA 0 sqlind SQLIND The unqualified name or label of the column sqlname SQLNAME 3. Check the SQLTYPE field of each SQLVAR entry. If the SQLTYPE field is 988 or 989, the column in the result set is an XML column. 4. For each XML column, make the following changes to the associated SQLVAR entry: a. Change the SQLTYPE field to indicate the data type of the host variable to receive the XML data. You can retrieve the XML data into a host variable of type XML AS BLOB, XML AS CLOB, or XML AS DBCLOB, or a compatible string data type. If the target host variable type is XML AS BLOB, XML AS CLOB, or XML AS DBCLOB, set the SQLTYPE field to one of the following values: 404 XML AS BLOB 405 nullable XML AS BLOB 408 XML AS CLOB 409 nullable XML AS CLOB Chapter 3. Including DB2 queries in an application program 277
  • 294.
    412 XML AS DBCLOB 413 nullableXML AS DBCLOB If the target host variable type is a string data type, set the SQLTYPE field to a valid string value. For a list of valid string values, see the topic “Field descriptions” in DB2 SQL Reference. Restriction: You cannot use the XML type (988/989) as a target host variable type. b. If the target host variable type is XML AS BLOB, XML AS CLOB, or XML AS DBCLOB, change the first two bytes in the SQLNAME field to X’0000’ and the fifth and sixth bytes to X’0100’. These bytes indicate that the value to be received is an XML value. 5. Populate the extended SQLVAR fields for each XML column as you would for a LOB column, as indicated in the following table. Table 66. Fields for an extended SQLVAR entry for an XML host variable SQLVAR field Value for an XML host variable length attribute for the XML host variable len.sqllonglen SQLLONGL SQLLONGLEN * Reserved pointer to the length of the XML host variable sqldatalen SQLDATAL SQLDATALEN not used sqldatatype_name SQLTNAME SQLDATATYPENAME You can now use the SQLDA to retrieve the XML data into a host variable of type XML AS BLOB, XML AS CLOB, or XML AS DBCLOB, or a compatible string data type. Executing a varying-list SELECT statement dynamically: You can easily retrieve rows of the result table using a varying-list SELECT statement. The statements differ only a little from those for the fixed-list example. Open the cursor: If the SELECT statement contains no parameter marker, this step is simple enough. For example: EXEC SQL OPEN C1; Fetch rows from the result table: This statement differs from the corresponding one for the case of a fixed-list select. Write: EXEC SQL FETCH C1 USING DESCRIPTOR :FULSQLDA; The key feature of this statement is the clause USING DESCRIPTOR :FULSQLDA. That clause names an SQL descriptor area in which the occurrences of SQLVAR 278 Application Programming and SQL Guide
  • 295.
    point to otherareas. Those other areas receive the values that FETCH returns. It is possible to use that clause only because you previously set up FULSQLDA to look like Figure 23 on page 271. Figure 25 on page 272 shows the result of the FETCH. The data areas identified in the SQLVAR fields receive the values from a single row of the result table. Successive executions of the same FETCH statement put values from successive rows of the result table into these same areas. Close the cursor: This step is the same as for the fixed-list case. When no more rows need to be processed, execute the following statement: EXEC SQL CLOSE C1; When COMMIT ends the unit of work containing OPEN, the statement in STMT reverts to the unprepared state. Unless you defined the cursor using the WITH HOLD option, you must prepare the statement again before you can reopen the cursor. Executing arbitrary statements with parameter markers: Consider, as an example, a program that executes dynamic SQL statements of several kinds, including varying-list SELECT statements, any of which might contain a variable number of parameter markers. This program might present your users with lists of choices: choices of operation (update, select, delete); choices of table names; choices of columns to select or update. The program also enables the users to enter lists of employee numbers to apply to the chosen operation. From this, the program constructs SQL statements of several forms, one of which looks like this: SELECT .... FROM DSN8910.EMP WHERE EMPNO IN (?,?,?,...?); The program then executes these statements dynamically. When the number and types of parameters are known: In the preceding example, you do not know in advance the number of parameter markers, and perhaps the kinds of parameter they represent. You can use techniques described previously if you know the number and types of parameters, as in the following examples: v If the SQL statement is not SELECT, name a list of host variables in the EXECUTE statement: WRONG: EXEC SQL EXECUTE STMT; RIGHT: EXEC SQL EXECUTE STMT USING :VAR1, :VAR2, :VAR3; v If the SQL statement is SELECT, name a list of host variables in the OPEN statement: WRONG: EXEC SQL OPEN C1; RIGHT: EXEC SQL OPEN C1 USING :VAR1, :VAR2, :VAR3; In both cases, the number and types of host variables named must agree with the number of parameter markers in STMT and the types of parameter they represent. The first variable (VAR1 in the examples) must have the type expected for the first parameter marker in the statement, the second variable must have the type expected for the second marker, and so on. There must be at least as many variables as parameter markers. Chapter 3. Including DB2 queries in an application program 279
  • 296.
    When the numberand types of parameters are not known: When you do not know the number and types of parameters, you can adapt the SQL descriptor area. Your program can include an unlimited number of SQLDAs, and you can use them for different purposes. Suppose that an SQLDA, arbitrarily named DPARM, describes a set of parameters. The structure of DPARM is the same as that of any other SQLDA. The number of occurrences of SQLVAR can vary, as in previous examples. In this case, every parameter marker must have one SQLVAR. Each occurrence of SQLVAR describes one host variable that replaces one parameter marker at run time. DB2 replaces the parameter markers when a non-SELECT statement executes or when a cursor is opened for a SELECT statement. You must fill in certain fields in DPARM before using EXECUTE or OPEN; you can ignore the other fields. Field Use when describing host variables for parameter markers SQLDAID The seventh byte indicates whether more than one SQLVAR entry is used for each parameter marker. If this byte is not blank, at least one parameter marker represents a distinct type or LOB value, so the SQLDA has more than one set of SQLVAR entries. You do not set this field for a REXX SQLDA. SQLDABC The length of the SQLDA, which is equal to SQLN * 44 + 16. You do not set this field for a REXX SQLDA. SQLN The number of occurrences of SQLVAR allocated for DPARM. You do not set this field for a REXX SQLDA. SQLD The number of occurrences of SQLVAR actually used. This number must not be less than the number of parameter markers. In each occurrence of SQLVAR, put information in the following fields: SQLTYPE, SQLLEN, SQLDATA, SQLIND. SQLTYPE The code for the type of variable, and whether it allows nulls. SQLLEN The length of the host variable. SQLDATA The address of the host variable. For REXX, this field contains the value of the host variable. SQLIND The address of an indicator variable, if needed. For REXX, this field contains a negative number if the value in SQLDATA is null. SQLNAME Ignore. Using the SQLDA with EXECUTE or OPEN: To indicate that the SQLDA called DPARM describes the host variables substituted for the parameter markers at run time, use a USING DESCRIPTOR clause with EXECUTE or OPEN. v For a non-SELECT statement, write: 280 Application Programming and SQL Guide
  • 297.
    EXEC SQL EXECUTESTMT USING DESCRIPTOR :DPARM; v For a SELECT statement, write: EXEC SQL OPEN C1 USING DESCRIPTOR :DPARM; How bind options REOPT(ALWAYS), REOPT(AUTO) and REOPT(ONCE) affect dynamic SQL: When you specify the bind option REOPT(ALWAYS), DB2 reoptimizes the access path at run time for SQL statements that contain host variables, parameter markers, or special registers. The option REOPT(ALWAYS) has the following effects on dynamic SQL statements: v When you specify the option REOPT(ALWAYS), DB2 automatically uses DEFER(PREPARE), which means that DB2 waits to prepare a statement until it encounters an OPEN or EXECUTE statement. v When you execute a DESCRIBE statement and then an EXECUTE statement on a non-SELECT statement, DB2 prepares the statement twice: Once for the DESCRIBE statement and once for the EXECUTE statement. DB2 uses the values in the input variables only during the second PREPARE. These multiple PREPAREs can cause performance to degrade if your program contains many dynamic non-SELECT statements. To improve performance, consider putting the code that contains those statements in a separate package and then binding that package with the option REOPT(NONE). v If you execute a DESCRIBE statement before you open a cursor for that statement, DB2 prepares the statement twice. If, however, you execute a DESCRIBE statement after you open the cursor, DB2 prepares the statement only once. To improve the performance of a program bound with the option REOPT(ALWAYS), execute the DESCRIBE statement after you open the cursor. To prevent an automatic DESCRIBE before a cursor is opened, do not use a PREPARE statement with the INTO clause. v If you use predictive governing for applications bound with REOPT(ALWAYS), DB2 does not return a warning SQLCODE when dynamic SQL statements exceed the predictive governing warning threshold. DB2 does return an error SQLCODE when dynamic SQL statements exceed the predictive governing error threshold. DB2 returns the error SQLCODE for an EXECUTE or OPEN statement. | | | | | | | | | | | | | | | | | When you specify the bind option REOPT(AUTO), DB2 optimizes the access path for SQL statements at the first EXECUTE or OPEN. Each time a statement is executed, DB2 determines if a new access path is needed to improve the performance of the statement. If a new access path will improve the performance, DB2 generates one. The option REOPT(AUTO) has the following effects on dynamic SQL statements: v When you specify the bind option REOPT(AUTO), DB2 optimizes the access path for SQL statements at the first EXECUTE or OPEN. Each time a statement is executed, DB2 determines if a new access path is needed to improve the performance of the statement. If a new access path will improve the performance, DB2 generates one. v When you specify the option REOPT(ONCE), DB2 automatically uses DEFER(PREPARE), which means that DB2 waits to prepare a statement until it encounters an OPEN or EXECUTE statement. v When DB2 prepares a statement using REOPT(AUTO), it saves the access path in the dynamic statement cache. This access path is used each time the statement is run, until DB2 determines that a new access path is needed to improve the Chapter 3. Including DB2 queries in an application program 281
  • 298.
    performance or thestatement that is in the cache is invalidated (or removed from the cache) and needs to be rebound. v The DESCRIBE statement has the following effects on dynamic statements that are bound with REOPT(AUTO): – When you execute a DESCRIBE statement before an EXECUTE statement on a non-SELECT statement, DB2 prepares the statement an extra time if it is not already saved in the cache: Once for the DESCRIBE statement and once for the EXECUTE statement. DB2 uses the values of the input variables only during the second time the statement is prepared. It then saves the statement in the cache. If you execute a DESCRIBE statement before an EXECUTE statement on a non-SELECT statement that has already been saved in the cache, DB2 will always prepare the non-SELECT statement for the DESCRIBE statement, and will prepare the statement again on EXECUTE only if DB2 determines that a new access path different from the one already saved in the cache can improve the performance. – If you execute DESCRIBE on a statement before you open a cursor for that statement, DB2 always prepares the statement on DESCRIBE. However, DB2 will not prepare the statement again on OPEN if the statement has already been saved in the cache and DB2 doesn’t think that a new access path is needed at OPEN time. If you execute DESCRIBE on a statement after you open a cursor for that statement, DB2 prepared the statement only once if it is not already saved in the cache. If the statement is already saved in the cache and you execute DESCRIBE after you open a cursor for that statement, DB2 does not prepare the statement, it used the statement that is saved in the cache. v If you use predictive governing for applications that are bound with REOPT(AUTO), DB2 does not return a warning SQLCODE when dynamic SQL statements exceed the predictive governing warning threshold. DB2 does return an error SQLCODE when dynamic SQL statements exceed the predictive governing error threshold. DB2 returns the error SQLCODE for an EXECUTE or OPEN statement. | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When you specify the bind option REOPT(ONCE), DB2 optimizes the access path only once, at the first EXECUTE or OPEN, for SQL statements that contain host variables, parameter markers, or special registers. The option REOPT(ONCE) has the following effects on dynamic SQL statements: v When you specify the option REOPT(ONCE), DB2 automatically uses DEFER(PREPARE), which means that DB2 waits to prepare a statement until it encounters an OPEN or EXECUTE statement. v When DB2 prepares a statement using REOPT(ONCE), it saves the access path in the dynamic statement cache. This access path is used each time the statement is run, until the statement that is in the cache is invalidated (or removed from the cache) and needs to be rebound. v The DESCRIBE statement has the following effects on dynamic statements that are bound with REOPT(ONCE): – When you execute a DESCRIBE statement before an EXECUTE statement on a non-SELECT statement, DB2 prepares the statement twice if it is not already saved in the cache: Once for the DESCRIBE statement and once for the EXECUTE statement. DB2 uses the values of the input variables only during the second time the statement is prepared. It then saves the statement in the cache. If you execute a DESCRIBE statement before an EXECUTE statement on a non-SELECT statement that has already been saved in the cache, DB2 prepares the non-SELECT statement only for the DESCRIBE statement. 282 Application Programming and SQL Guide
  • 299.
    – If youexecute DESCRIBE on a statement before you open a cursor for that statement, DB2 always prepares the statement on DESCRIBE. However, DB2 will not prepare the statement again on OPEN if the statement has already been saved in the cache. If you execute DESCRIBE on a statement after you open a cursor for that statement, DB2 prepared the statement only once if it is not already saved in the cache. If the statement is already saved in the cache and you execute DESCRIBE after you open a cursor for that statement, DB2 does not prepare the statement, it used the statement that is saved in the cache. To improve the performance of a program that is bound with REOPT(ONCE), execute the DESCRIBE statement after you open a cursor. To prevent an automatic DESCRIBE before a cursor is opened, do not use a PREPARE statement with the INTO clause. v If you use predictive governing for applications that are bound with REOPT(ONCE), DB2 does not return a warning SQLCODE when dynamic SQL statements exceed the predictive governing warning threshold. DB2 does return an error SQLCODE when dynamic SQL statements exceed the predictive governing error threshold. DB2 returns the error SQLCODE for an EXECUTE or OPEN statement. Dynamically executing an SQL statement by using EXECUTE IMMEDIATE In certain situations, you want your program to prepare and dynamically execute a statement immediately after reading it. Suppose that you design a program to read SQL DELETE statements, similar to these, from a terminal: DELETE FROM DSN8910.EMP WHERE EMPNO = ’000190’ DELETE FROM DSN8910.EMP WHERE EMPNO = ’000220’ After reading a statement, the program is to run it immediately. Recall that you must prepare (precompile and bind) static SQL statements before you can use them. You cannot prepare dynamic SQL statements in advance. The SQL statement EXECUTE IMMEDIATE causes an SQL statement to prepare and execute, dynamically, at run time. Declaring the host variableBefore you prepare and execute an SQL statement, you can read it into a host variable. If the maximum length of the SQL statement is 32 KB, declare the host variable as a character or graphic host variable according to the following rules for the host languages: | | | v In assembler, PL/I, COBOL and C, you must declare a string host variable as a varying-length string. v In Fortran, it must be a fixed-length string variable. If the length is greater than 32 KB, you must declare the host variable as a CLOB or DBCLOB, and the maximum is 2 MB. Example: Using a varying-length character host variable: This excerpt is from a C program that reads a DELETE statement into the host variable dstring and executes the statement: EXEC SQL BEGIN DECLARE SECTION; ... struct VARCHAR { short len; char s[40]; Chapter 3. Including DB2 queries in an application program 283
  • 300.
    } dstring; EXEC SQLEND DECLARE SECTION; ... /* Read a DELETE statement into the host variable dstring. */ gets(dstring); EXEC SQL EXECUTE IMMEDIATE :dstring; ... EXECUTE IMMEDIATE causes the DELETE statement to be prepared and executed immediately. Declaring a CLOB or DBLOB host variable: You declare CLOB and DBCLOB host variables according to the rules described in “LOB host variable, LOB locator, and LOB file reference variable declarations” on page 661. The precompiler generates a structure that contains two elements, a 4-byte length field and a data field of the specified length. The names of these fields vary depending on the host language: v In PL/I, assembler, and Fortran, the names are variable_LENGTH and variable_DATA. v In COBOL, the names are variable–LENGTH and variable–DATA. v In C, the names are variable.LENGTH and variable.DATA. Example: Using a CLOB host variable: This excerpt is from a C program that copies an UPDATE statement into the host variable string1 and executes the statement: EXEC SQL BEGIN DECLARE SECTION; ... SQL TYPE IS CLOB(4k) string1; EXEC SQL END DECLARE SECTION; ... /* Copy a statement into the host variable string1. */ strcpy(string1.data, "UPDATE DSN8610.EMP SET SALARY = SALARY * 1.1"); string1.length = 44; EXEC SQL EXECUTE IMMEDIATE :string1; ... EXECUTE IMMEDIATE causes the UPDATE statement to be prepared and executed immediately. Dynamically executing an SQL statement by using PREPARE and EXECUTE As an alternative to executing an SQL statement immediately after it is read, you can prepare and execute the SQL statement in two steps. This two-step method is useful when you need to execute an SQL statement multiple times with different values. Suppose that you want to execute DELETE statements repeatedly using a list of employee numbers. Consider how you would do it if you could write the DELETE statement as a static SQL statement: < Read a value for EMP from the list. > DO UNTIL (EMP = 0); EXEC SQL DELETE FROM DSN8910.EMP WHERE EMPNO = :EMP ; < Read a value for EMP from the list. > END; The loop repeats until it reads an EMP value of 0. 284 Application Programming and SQL Guide
  • 301.
    If you knowin advance that you will use only the DELETE statement and only the table DSN8910.EMP, you can use the more efficient static SQL. Suppose further that several different tables have rows that are identified by employee numbers, and that users enter a table name as well as a list of employee numbers to delete. Although variables can represent the employee numbers, they cannot represent the table name, so you must construct and execute the entire statement dynamically. Your program must now do these things differently: v Use parameter markers instead of host variables v Use the PREPARE statement v Use EXECUTE instead of EXECUTE IMMEDIATE Parameter markers with PREPARE and EXECUTE: Dynamic SQL statements cannot use host variables. Therefore, you cannot dynamically execute an SQL statement that contains host variables. Instead, substitute a parameter marker, indicated by a question mark (?), for each host variable in the statement. You can indicate to DB2 that a parameter marker represents a host variable of a certain data type by specifying the parameter marker as the argument of a CAST specification. When the statement executes, DB2 converts the host variable to the data type in the CAST specification. A parameter marker that you include in a CAST specification is called a typed parameter marker. A parameter marker without a CAST specification is called an untyped parameter marker. Recommendation: Because DB2 can evaluate an SQL statement with typed parameter markers more efficiently than a statement with untyped parameter markers, use typed parameter markers whenever possible. Under certain circumstances you must use typed parameter markers. For information about rules for using untyped or typed parameter markers, see the topic “PREPARE” in DB2 SQL Reference. Example using parameter markers: Suppose that you want to prepare this statement: DELETE FROM DSN8910.EMP WHERE EMPNO = :EMP; You need to prepare a string like this: DELETE FROM DSN8910.EMP WHERE EMPNO = CAST(? AS CHAR(6)) You associate host variable :EMP with the parameter marker when you execute the prepared statement. Suppose that S1 is the prepared statement. Then the EXECUTE statement looks like this: EXECUTE S1 USING :EMP; Using the PREPARE statement: Before you prepare an SQL statement, you can assign it to a host variable. If the length of the statement is greater than 32 KB, you must declare the host variable as a CLOB or DBCLOB. For more information about declaring the host variable, see “Dynamically executing an SQL statement by using EXECUTE IMMEDIATE” on page 283. You can think of PREPARE and EXECUTE as an EXECUTE IMMEDIATE done in two steps. The first step, PREPARE, turns a character string into an SQL statement, and then assigns it a name of your choosing. Example using the PREPARE statement: Assume that the character host variable :DSTRING has the value “DELETE FROM DSN8910.EMP WHERE EMPNO = ?”. To prepare an SQL statement from that string and assign it the name S1, write: Chapter 3. Including DB2 queries in an application program 285
  • 302.
    EXEC SQL PREPARES1 FROM :DSTRING; The prepared statement still contains a parameter marker, for which you must supply a value when the statement executes. After the statement is prepared, the table name is fixed, but the parameter marker enables you to execute the same statement many times with different values of the employee number. Using the EXECUTE statement: The EXECUTE statement executes a prepared SQL statement by naming a list of one or more host variables, one or more host variable arrays, or a host structure. This list supplies values for all of the parameter markers. After you prepare a statement, you can execute it many times within the same unit of work. In most cases, COMMIT or ROLLBACK destroys statements prepared in a unit of work. Then, you must prepare them again before you can execute them again. However, if you declare a cursor for a dynamic statement and use the option WITH HOLD, a commit operation does not destroy the prepared statement if the cursor is still open. You can execute the statement in the next unit of work without preparing it again. Example using the EXECUTE statement: To execute the prepared statement S1 just once, using a parameter value contained in the host variable :EMP, write: EXEC SQL EXECUTE S1 USING :EMP; Preparing and executing the example DELETE statement: The example in this topic began with a DO loop that executed a static SQL statement repeatedly: < Read a value for EMP from the list. > DO UNTIL (EMP = 0); EXEC SQL DELETE FROM DSN8910.EMP WHERE EMPNO = :EMP ; < Read a value for EMP from the list. > END; You can now write an equivalent example for a dynamic SQL statement: < Read a statement containing parameter markers into DSTRING.> EXEC SQL PREPARE S1 FROM :DSTRING; < Read a value for EMP from the list. > DO UNTIL (EMPNO = 0); EXEC SQL EXECUTE S1 USING :EMP; < Read a value for EMP from the list. > END; The PREPARE statement prepares the SQL statement and calls it S1. The EXECUTE statement executes S1 repeatedly, using different values for EMP. Using more than one parameter marker: The prepared statement (S1 in the example) can contain more than one parameter marker. If it does, the USING clause of EXECUTE specifies a list of variables or a host structure. The variables must contain values that match the number and data types of parameters in S1 in the proper order. You must know the number and types of parameters in advance and declare the variables in your program, or you can use an SQLDA (SQL descriptor area). Dynamically executing a data change statement Dynamically executing data change statements with host variable arrays is useful if you want to enter rows of data into different tables or enter a different number of rows. The process is similar for both INSERT and MERGE statements. | | | 286 Application Programming and SQL Guide
  • 303.
    For example, supposethat you want to repeatedly execute a multiple-row INSERT statement with a list of activity IDs, activity keywords, and activity descriptions that are provided by the user. You can use the following static SQL INSERT statement to insert multiple rows of data into the activity table: EXEC SQL INSERT INTO DSN8910.ACT VALUES (:hva_actno, :hva_actkwd, :hva_actdesc) FOR :num_rows ROWS; However, if you want to enter the rows of data into different tables or enter different numbers of rows, you can construct the INSERT statement dynamically. This topic describes the following methods that you can use to execute a data change statement dynamically: v By using host variable arrays that contain the data to be inserted v By using a descriptor to describe the host variable arrays that contain the data Dynamically executing a data change statement by using host variable arrays: To dynamically execute a data change statement by using host variable arrays, perform the following actions in your program: 1. Assign the appropriate INSERT or MERGE statement to a host variable. If needed, use the CAST specification to explicitly assign types to parameter markers that represent host variable arrays. Example: For the activity table, the following string contains an INSERT statement that is to be prepared: INSERT INTO DSN8910.ACT VALUES (CAST(? AS SMALLINT), CAST(? AS CHAR(6)), CAST(? AS VARCHAR(20))) 2. Assign any attributes for the SQL statement to a host variable. 3. Include a PREPARE statement for the SQL statement. 4. Include an EXECUTE statement with the FOR n ROWS clause. Each host variable in the USING clause of the EXECUTE statement represents an array of values for the corresponding column of the target of the SQL statement. You can vary the number of rows without needing to prepare the SQL statement again. Example: The following code prepares and executes an INSERT statement: /* Copy the INSERT string into the host variable sqlstmt */ strcpy(sqlstmt, "INSERT INTO DSN8910.ACT VALUES (CAST(? AS SMALLINT),"); strcat(sqlstmt, " CAST(? AS CHAR(6)), CAST(? AS VARCHAR(20)))"); /* Copy the INSERT attributes into the host variable attrvar */ strcpy(attrvar, "FOR MULTIPLE ROWS"); /* Prepare and execute my_insert using the host variable arrays */ EXEC SQL PREPARE my_insert ATTRIBUTES :attrvar FROM :sqlstmt; EXEC SQL EXECUTE my_insert USING :hva1, :hva2, :hva3 FOR :num_rows ROWS; Dynamically executing a data change statement by using descriptors: You can use an SQLDA structure to specify data types and other information about the host variable arrays that contain the values to insert. To dynamically execute a data change statement by using descriptors, perform the following actions in your program: 1. Set the following fields in the SQLDA structure for your INSERT statement. Chapter 3. Including DB2 queries in an application program 287
  • 304.
    v SQLN v SQLABC vSQLD v SQLVAR v SQLNAME Example: Assume that your program includes the standard SQLDA structure declaration and declarations for the program variables that point to the SQLDA structure. For C application programs, the following example code sets the SQLDA fields: | | | | | | | | | | | | | | | | | | | | | | strcpy(sqldaptr->sqldaid,"SQLDA"); sqldaptr->sqldabc = 192; /* number of bytes of storage allocated for the SQLDA */ sqldaptr->sqln = 4; /* number of SQLVAR occurrences */ sqldaptr->sqld = 4; varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0])); /* Point to first SQLVAR */ varptr->sqltype = 500; /* data type SMALLINT */ varptr->sqllen = 2; varptr->sqldata = (char *) hva1; varptr->sqlname.length = 8; memcpy(varptr->sqlname.data, "x00x00x00x00x00x01x00x14",varptr->sqlname.length); varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 1); /* Point to next SQLVAR */ varptr->sqltype = 452; /* data type CHAR(6) */ varptr->sqllen = 6; varptr->sqldata = (char *) hva2; varptr->sqlname.length = 8; memcpy(varptr->sqlname.data, "x00x00x00x00x00x01x00x14",varptr->sqlname.length); varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 2); /* Point to next SQLVAR */ varptr->sqltype = 448; /* data type VARCHAR(20) */ varptr->sqllen = 20; varptr->sqldata = (char *) hva3; varptr->sqlname.length = 8; memcpy(varptr->sqlname.data, "x00x00x00x00x00x01x00x14",varptr->sqlname.length); The SQLDA structure has the following fields: v SQLDABC indicates the number of bytes of storage that are allocated for the SQLDA. The storage includes a 16-byte header and 44 bytes for each SQLVAR field. The value is SQLN x 44 + 16, or 192 for this example. v SQLN is the number of SQLVAR occurrences, plus one for use by DB2 for the host variable that contains the number n in the FOR n ROWS clause. v SQLD is the number of variables in the SQLDA that are used by DB2 when processing the INSERT statement. v An SQLVAR occurrence specifies the attributes of an element of a host variable array that corresponds to a value provided for a target column of the INSERT. Within each SQLVAR: – SQLTYPE indicates the data type of the elements of the host variable array. – SQLLEN indicates the length of a single element of the host variable array. – SQLDATA points to the corresponding host variable array. Assume that your program allocates the dynamic variable arrays hva1, hva2, and hva3. – SQLNAME has two parts: the LENGTH and the DATA. The LENGTH is 8. The first two bytes of the DATA field is X’0000’. Bytes 5 and 6 of the DATA field are a flag indicating whether the variable is an array or a FOR n ROWS value. Bytes 7 and 8 are a two-byte binary integer representation of the dimension of the array. | | | | | For more information about the SQLDA, see “Including dynamic SQL for varying-list SELECT statements in your program” on page 266 and the topic “SQL descriptor area (SQLDA)” in DB2 SQL Reference. 288 Application Programming and SQL Guide
  • 305.
    2. Assign theappropriate INSERT or MERGE statement to a host variable. Example: The following string contains an INSERT statement that is to be prepared: INSERT INTO DSN8910.ACT VALUES (?, ?, ?) 3. Assign any attributes for the SQL statement to a host variable. 4. Include a PREPARE statement for the SQL statement. 5. Include an EXECUTE statement with the FOR n ROWS clause. The host variable in the USING clause of the EXECUTE statement names the SQLDA that describes the parameter markers in the INSERT statement. Example: The following code prepares and executes an INSERT statement: /* Copy the INSERT string into the host variable sqlstmt */ strcpy(sqlstmt, "INSERT INTO DSN8910.ACT VALUES (?, ?, ?)"); /* Copy the INSERT attributes into the host variable attrvar */ strcpy(attrvar, "FOR MULTIPLE ROWS"); /* Prepare and execute my_insert using the descriptor */ EXEC SQL PREPARE my_insert ATTRIBUTES :attrvar FROM :sqlstmt; EXEC SQL EXECUTE my_insert USING DESCRIPTOR :*sqldaptr FOR :num_rows ROWS; Enabling the dynamic statement cache The dynamic statement cache is a pool in which DB2 saves prepared SQL statements that can be shared among different threads, plans, and packages. By sharing these statements, applications can avoid unnecessary preparation processes and thus improve performance. You must enable the dynamic statement cache before it can be used. To enable the dynamic statement cache to save prepared statements, specify YES on the CACHE DYNAMIC SQL field of installation panel DSNTIP8. For more information about installation panel DSNTIP8, see the topic “Performance and optimization panel: DSNTIP8” in DB2 Installation Guide. Dynamic SQL statements that DB2 can cache: The dynamic statement cache is a pool in which DB2 saves prepared SQL statements that can be shared among different threads, plans, and packages to improve performance. Only certain dynamic SQL statements can be saved in this cache. As the DB2 ability to optimize SQL has improved, the cost of preparing a dynamic SQL statement has grown. Applications that use dynamic SQL might be forced to pay this cost more than once. When an application performs a commit operation, it must issue another PREPARE statement if that SQL statement is to be executed again. For a SELECT statement, the ability to declare a cursor WITH HOLD provides some relief but requires that the cursor be open at the commit point. WITH HOLD also causes some locks to be held for any objects that the prepared statement is dependent on. Also, WITH HOLD offers no relief for SQL statements that are not SELECT statements. DB2 can save prepared dynamic statements in a cache. The cache is a dynamic statement cache pool that all application processes can use to save and retrieve prepared dynamic statements. After an SQL statement has been prepared and is automatically saved in the cache, subsequent prepare requests for that same SQL Chapter 3. Including DB2 queries in an application program 289
  • 306.
    statement can avoidthe costly preparation process by using the statement that is in the cache. Statements that are saved in the cache can be shared among different threads, plans, or packages. Example: Assume that your application program contains a dynamic SQL statement, STMT1, which is prepared and executed multiple times. If you are using the dynamic statement cache when STMT1 is prepared for the first time, it is placed in the cache. When your application program encounters the identical PREPARE statement for STMT1, DB2 uses the already prepared STMT1 that is saved in the dynamic statement cache. The following example shows the identical STMT1 that might appear in your application program: PREPARE EXECUTE COMMIT . . . PREPARE EXECUTE COMMIT . . . STMT1 FROM ... STMT1 Statement is prepared and the prepared statement is put in the cache. STMT1 FROM ... STMT1 Identical statement. DB2 uses the prepared statement from the cache. Eligible statements: The following SQL statements can be saved in the cache: SELECT UPDATE INSERT DELETE MERGE | Distributed and local SQL statements are eligible to be saved. Prepared, dynamic statements that use DB2 private protocol access are also eligible to be saved. Restrictions: Even though static statements that use DB2 private protocol access are dynamic at the remote site, those statements can not be saved in the cache. Statements in plans or packages that are bound with REOPT(ALWAYS) can not be saved in the cache. Statements in plans and packages that are bound with REOPT(ONCE) or REOPT(AUTO) can be saved in the cache. See “Including dynamic SQL for varying-list SELECT statements in your program” on page 266 for more information about REOPT(ALWAYS), REOPT(AUTO), and REOPT(ONCE). | | | | | | Prepared statements cannot be shared among data sharing members. Because each member has its own EDM pool, a cached statement on one member is not available to an application that runs on another member. Conditions for statement sharing: If a prepared version of an identical SQL statement already exists in the dynamic statement cache, certain conditions must still be met before DB2 can reuse that prepared statement. Suppose that S1 and S2 are source statements, and P1 is the prepared version of S1. P1 is in the dynamic statement cache. The following conditions must be met before DB2 can use statement P1 instead of preparing statement S2: v S1 and S2 must be identical. The statements must pass a character by character comparison and must be the same length. If the PREPARE statement for either 290 Application Programming and SQL Guide
  • 307.
    statement contains anATTRIBUTES clause, DB2 concatenates the values in the ATTRIBUTES clause to the statement string before comparing the strings. That is, if A1 is the set of attributes for S1 and A2 is the set of attributes for S2, DB2 compares S1||A1 to S2||A2. If the statement strings are not identical, DB2 cannot use the statement in the cache. For example, assume that S1 and S2 are specified as follows: ’UPDATE EMP SET SALARY=SALARY+50’ In this case, DB2 can use P1 instead of preparing S2. However, assume that S1 is specified as follows: ’UPDATE EMP SET SALARY=SALARY+50’ Assume also that S2 is specified as follows: ’UPDATE EMP SET SALARY=SALARY+50 ’ | | | | | | | | | | | | | | | | | | | | | | | | | | | | In this case, DB2 cannot use P1 for S2. DB2 prepares S2 and saves the prepared version of S2 in the cache. v The authorization ID or role that was used to prepare S1 must be used to prepare S2: – When a plan or package has run behavior, the authorization ID is the current SQLID value. For secondary authorization IDs: - The application process that searches the cache must have the same secondary authorization ID list as the process that inserted the entry into the cache or must have a superset of that list. - If the process that originally prepared the statement and inserted it into the cache used one of the privileges held by the primary authorization ID to accomplish the prepare, that ID must either be part of the secondary authorization ID list of the process searching the cache, or it must be the primary authorization ID of that process. – When a plan or package has bind behavior, the authorization ID is the plan owner’s ID. For a DDF server thread, the authorization ID is the package owner’s ID. – When a package has define behavior, then the authorization ID is the user-defined function or stored procedure owner. – When a package has invoke behavior, then the authorization ID is the authorization ID under which the statement that invoked the user-defined function or stored procedure executed. – If the application process has a role associated with it, DB2 uses the role to search the cache instead of the authorization IDs. If the trusted context that associated the role with the application process is defined with the WITH ROLE AS OBJECT OWNER clause, the role value is used as the default for the CURRENT SCHEMA special register and the SQL path. For an explanation of bind, run, define, and invoke behavior, see “DYNAMICRULES bind option” on page 881. v When the plan or package that contains S2 is bound, the values of these bind options must be the same as when the plan or package that contains S1 was bound: CURRENTDATA DYNAMICRULES ISOLATION Chapter 3. Including DB2 queries in an application program 291
  • 308.
    SQLRULES QUALIFIER v When S2is prepared, the values of the following special registers must be the same as when S1 was prepared: CURRENT DECFLOAT ROUNDING MODE CURRENT DEGREE CURRENT RULES CURRENT PRECISION CURRENT REFRESH AGE CURRENT MAINTAINED TABLE TYPES FOR OPTIMIZATION CURRENT LOCALE LC_CTYPE | | Exception: If you set the CACHEDYN_FREELOCAL subsystem parameter to 1 and a storage shortage occurs, DB2 frees the cached dynamic statements. In this case, DB2 cannot use P1 instead of preparing statement S2, because P1 no longer exists in the statement cache. Finding information about statements in the statement cache: As part of an online monitoring strategy, you can examine all statements in the dynamic statement cache and concentrate on improving specific statements for specific performance characteristics. The EXPLAIN STATEMENT CACHE ALL statement puts statement cache information into the DSN_STATEMENT_CACHE_TABLE table for all queries in the cache that qualify based on the user’s SQLID. If the SQLID has SYSADM authority, all statements are put into the table. EXPLAIN STATEMENT CACHE ALL provides DSN_STATEMENT_CACHE_TABLE with a snapshot of the cache. Example: If you are concerned about CPU time, you can select from the STAT_CPU column in the DSN_STATEMENT_CACHE_TABLE table to identify the queries that consume the most CPU time. Then you can work to improve the performance of those specific queries. For information about creating the DSN_STATEMENT_CACHE_TABLE table and about the columns in the table, see the topic “EXPLAIN” in DB2 SQL Reference. Keeping prepared statements after commit points If your program issues the same dynamic SQL statement in different commit scopes, consider specifying that DB2 keep the prepared versions of these statements after the commit points. This behavior can improve performance. By default, DB2 does not keep these statements after commit points. The bind option KEEPDYNAMIC(YES) lets you hold dynamic statements past a commit point for an application process. An application can issue a PREPARE for a statement once and omit subsequent PREPAREs for that statement. The following example illustrates an application that is written to use KEEPDYNAMIC(YES). PREPARE EXECUTE COMMIT . . . EXECUTE COMMIT . . . EXECUTE COMMIT 292 STMT1 FROM ... STMT1 Statement is prepared. STMT1 Application does not issue PREPARE. STMT1 Again, no PREPARE needed. Application Programming and SQL Guide
  • 309.
    To understand howthe KEEPDYNAMIC bind option works, you need to differentiate between the executable form of a dynamic SQL statement, which is the prepared statement, and the character string form of the statement, which is the statement string. Relationship between KEEPDYNAMIC(YES) and statement caching: When the dynamic statement cache is not active, and you run an application bound with KEEPDYNAMIC(YES), DB2 saves only the statement string for a prepared statement after a commit operation. On a subsequent OPEN, EXECUTE, or DESCRIBE, DB2 must prepare the statement again before performing the requested operation. The following example illustrates this concept. PREPARE EXECUTE COMMIT . . . EXECUTE COMMIT . . . EXECUTE COMMIT STMT1 FROM ... STMT1 Statement is prepared and put in memory. STMT1 Application does not issue PREPARE. DB2 prepares the statement again. STMT1 Again, no PREPARE needed. When the dynamic statement cache is active, and you run an application bound with KEEPDYNAMIC(YES), DB2 retains a copy of both the prepared statement and the statement string. The prepared statement is cached locally for the application process. In general, the statement is globally cached in the EDM pool, to benefit other application processes. If the application issues an OPEN, EXECUTE, or DESCRIBE after a commit operation, the application process uses its local copy of the prepared statement to avoid a prepare and a search of the cache. The following example illustrates this process. PREPARE EXECUTE COMMIT . . . EXECUTE COMMIT . . . EXECUTE COMMIT . . . PREPARE STMT1 FROM ... STMT1 Statement is prepared and put in memory. STMT1 Application does not issue PREPARE. DB2 uses the prepared statement in memory. STMT1 Again, no PREPARE needed. DB2 uses the prepared statement in memory. STMT1 FROM ... Statement is prepared and put in memory. The local instance of the prepared SQL statement is kept in ssnmDBM1 storage until one of the following occurs: v The application process ends. v A rollback operation occurs. v The application issues an explicit PREPARE statement with the same statement name. If the application does issue a PREPARE for the same SQL statement name that has a kept dynamic statement associated with it, the kept statement is discarded and DB2 prepares the new statement. v The statement is removed from memory because the statement has not been used recently, and the number of kept dynamic SQL statements reaches the subsystem default as set during installation. Handling implicit prepare errors: If a statement is needed during the lifetime of an application process, and the statement has been removed from the local cache, DB2 might be able to retrieve it from the global cache. If the statement is not in the Chapter 3. Including DB2 queries in an application program 293
  • 310.
    global cache, DB2must implicitly prepare the statement again. The application does not need to issue a PREPARE statement. However, if the application issues an OPEN, EXECUTE, or DESCRIBE for the statement, the application must be able to handle the possibility that DB2 is doing the prepare implicitly. Any error that occurs during this prepare is returned on the OPEN, EXECUTE, or DESCRIBE. How KEEPDYNAMIC affects applications that use distributed data: If a requester does not issue a PREPARE after a COMMIT, the package at the DB2 for z/OS server must be bound with KEEPDYNAMIC(YES). If both requester and server are DB2 for z/OS subsystems, the DB2 requester assumes that the KEEPDYNAMIC value for the package at the server is the same as the value for the plan at the requester. The KEEPDYNAMIC option has performance implications for DRDA clients that specify WITH HOLD on their cursors: v If KEEPDYNAMIC(NO) is specified, a separate network message is required when the DRDA client issues the SQL CLOSE for the cursor. v If KEEPDYNAMIC(YES) is specified, the DB2 for z/OS server automatically closes the cursor when SQLCODE +100 is detected, which means that the client does not have to send a separate message to close the held cursor. This reduces network traffic for DRDA applications that use held cursors. It also reduces the duration of locks that are associated with the held cursor. Considerations for data sharing: If one member of a data sharing group has enabled the cache but another has not, and an application is bound with KEEPDYNAMIC(YES), DB2 must implicitly prepare the statement again if the statement is assigned to a member without the cache. This can mean a slight reduction in performance. Limiting CPU time for dynamic SQL statements by using the resource limit facility The resource limit facility (or governor) limits the amount of CPU time an SQL statement can take, which prevents SQL statements from making excessive requests. The predictive governing function of the resource limit facility provides an estimate of the processing cost of SQL statements before they run. To predict the cost of an SQL statement, you execute EXPLAIN to put information about the statement cost in DSN_STATEMNT_TABLE. The governor controls only the dynamic SQL manipulative statements SELECT, UPDATE, DELETE, and INSERT. Each dynamic SQL statement used in a program is subject to the same limits. The limit can be a reactive governing limit or a predictive governing limit. If the statement exceeds a reactive governing limit, the statement receives an error SQL code. If the statement exceeds a predictive governing limit, it receives a warning or error SQL code. “Predictive governing” on page 295 explains more about predictive governing SQL codes. Your system administrator can establish the limits for individual plans or packages, for individual users, or for all users who do not have personal limits. Follow the procedures defined by your location for adding, dropping, or modifying entries in the resource limit specification table. For more information about the resource limit specification tables, see the topic “Resource limit tables” in DB2 Performance Monitoring and Tuning Guide. 294 Application Programming and SQL Guide
  • 311.
    Reactive governing: The reactivegoverning function of the resource limit facility stops any dynamic SQL statements that overuse system resources. When a statement exceeds a reactive governing threshold, the application program receives SQLCODE -905. The application must then determine what to do next. If the failed statement involves an SQL cursor, the cursor’s position remains unchanged. The application can then close that cursor. All other operations with the cursor do not run and the same SQL error code occurs. If the failed SQL statement does not involve a cursor, then all changes that the statement made are undone before the error code returns to the application. The application can either issue another SQL statement or commit all work done so far. Predictive governing: The predictive governing function of the resource limit facility provides an estimate of the processing cost of SQL statements before they run. If your installation uses predictive governing, you need to modify your applications to check for the +495 and -495 SQLCODEs that predictive governing can generate after a PREPARE statement executes. The +495 SQLCODE in combination with deferred prepare requires that DB2 do some special processing to ensure that existing applications are not affected by this new warning SQLCODE. For information about setting up the resource limit facility for predictive governing, see the topic “The resource limit facility (governor)” in DB2 Performance Monitoring and Tuning Guide. Handling the +495 SQLCODEIf your requester uses deferred prepare, the presence of parameter markers determines when the application receives the +495 SQLCODE. When parameter markers are present, DB2 cannot do PREPARE, OPEN, and FETCH processing in one message. If SQLCODE +495 is returned, no OPEN or FETCH processing occurs until your application requests it. v If there are parameter markers, the +495 is returned on the OPEN (not the PREPARE). v If there are no parameter markers, the +495 is returned on the PREPARE. Normally with deferred prepare, the PREPARE, OPEN, and first FETCH of the data are returned to the requester. For a predictive governor warning of +495, you would ideally like to have the option to choose beforehand whether you want the OPEN and FETCH of the data to occur. For down-level requesters, you do not have this option. Using predictive governing and down-level DRDA requesters If SQLCODE +495 is returned to the requester, OPEN processing continues but the first block of data is not returned with the OPEN. Thus, if your application does not continue with the query, you have already incurred the performance cost of OPEN processing. Using predictive governing and enabled requesters If your application does not defer the prepare, SQLCODE +495 is returned to the requester and OPEN processing does not occur. Chapter 3. Including DB2 queries in an application program 295
  • 312.
    If your applicationdoes defer prepare processing, the application receives the +495 at its usual time (OPEN or PREPARE). If you have parameter markers with deferred prepare, you receive the +495 at OPEN time as you normally do. However, an additional message is exchanged. Recommendation: Do not use deferred prepare for applications that use parameter markers and that are predictively governed at the server side. Conventions used in examples of coding SQL statements The examples in this information use certain conventions and assumptions. Some of the examples vary from these conventions. Exceptions are noted where they occur. The SQL statements in this information use the following conventions: v The SQL statement is part of a C or COBOL application program. Each SQL example is displayed on several lines, with each clause of the statement on a separate line. v The use of the precompiler options APOST and APOSTSQL are assumed (although they are not the defaults). Therefore, apostrophes (’) are used to delimit character string literals within SQL and host language statements. v The SQL statements access data in the sample tables provided with DB2. The tables contain data that a manufacturing company might keep about its employees and its current projects. v An SQL example does not necessarily show the complete syntax of an SQL statement. For the complete description and syntax of any SQL statement, see the topic “Statements” in DB2 SQL Reference. v Examples do not take referential constraints into account. Related reference ″DB2 sample tables″ (Introduction to DB2 for z/OS) Macros for assembler applications Data set DSN910.SDSNMACS contains all DB2 macros that are available for use. Accessing the DB2 REXX language support application programming interfaces DB2 REXX Language Support includes several application programming interfaces that enable your REXX procedure to connect to a DB2 subsystem and execute SQL statements. DB2 REXX Language Support includes the following application programming interfaces: CONNECT Connects the REXX procedure to a DB2 subsystem. You must execute CONNECT before you can execute SQL statements. The syntax of CONNECT is: 296 Application Programming and SQL Guide
  • 313.
    ’CONNECT’ ’subsystem-ID’ REXX-variable ADDRESS DSNREXX Note: CALLSQLDBS ’ATTACH TO’ ssid is equivalent to ADDRESS DSNREXX ’CONNECT’ ssid. EXECSQL Executes SQL statements in REXX procedures. The syntax of EXECSQL is: EXECSQL ADDRESS DSNREXX ″SQL-statement″ REXX-variable Notes: 1. CALL SQLEXEC is equivalent to EXECSQL. 2. EXECSQL can be enclosed in single or double quotation marks. DISCONNECT Disconnects the REXX procedure from a DB2 subsystem. You should execute DISCONNECT to release resources that are held by DB2. The syntax of DISCONNECT is: ’DISCONNECT’ ADDRESS DSNREXX Note: CALL SQLDBS ’DETACH’ is equivalent to DISCONNECT. These application programming interfaces are available through the DSNREXX host command environment. To make DSNREXX available to the application, invoke the RXSUBCOM function. The syntax is: RXSUBCOM ( ’ADD’ ’DELETE’ , ’DSNREXX’ , ’DSNREXX’ ) The ADD function adds DSNREXX to the REXX host command environment table. The DELETE function deletes DSNREXX from the REXX host command environment table. The following figure shows an example of REXX code that makes DSNREXX available to an application. ’SUBCOM DSNREXX’ /* HOST CMD ENV AVAILABLE? IF RC THEN /* IF NOT, MAKE IT AVAILABLE S_RC = RXSUBCOM(’ADD’,’DSNREXX’,’DSNREXX’) /* ADD HOST CMD ENVIRONMENT ADDRESS DSNREXX /* SEND ALL COMMANDS OTHER /* THAN REXX INSTRUCTIONS TO /* DSNREXX */ */ */ */ */ */ Chapter 3. Including DB2 queries in an application program 297
  • 314.
    /* CALL CONNECT,EXECSQL, AND */ /* DISCONNECT INTERFACES */ . . . S_RC = RXSUBCOM(’DELETE’,’DSNREXX’,’DSNREXX’) /* WHEN DONE WITH */ /* DSNREXX, REMOVE IT. */ Setting the isolation level of SQL statements in a REXX procedure Isolation levels specify the locking behavior for SQL statements. You can set the isolation level for SQL statements in your REXX procedures to repeatable read (RR), read stability (RS), cursor stability (CS), or uncommitted read (UR). To set the isolation level of SQL statements in a REXX procedure: Execute the SET CURRENT PACKAGESET statement to select one of the following DB2 REXX Language Support packages with the isolation level that you need. Table 67. DB2 REXX Language Support packages and associated isolation levels Package namea Isolation level DSNREXRR Repeatable read (RR) DSNREXRS Read stability (RS) DSNREXCS Cursor stability (CS) DSNREXUR Uncommitted read (UR) Note: 1. These packages enable your procedure to access DB2 and are bound when you install DB2 REXX Language Support. For example, to change the isolation level to cursor stability, execute the following SQL statement: "EXECSQL SET CURRENT PACKAGESET=’DSNREXCS’" Checking the execution of SQL statements After executing an SQL statement, your program should check for any errors codes before you commit the data and handle the errors that they represent. You can check the execution of SQL statements in one of the following ways: v By displaying specific fields in the SQLCA. v By testing SQLCODE or SQLSTATE for specific values. v By using the WHENEVER statement in your application program. v By testing indicator variables to detect numeric errors; see “Arithmetic and conversion errors” on page 317. v By using the GET DIAGNOSTICS statement in your application program to return all the condition information that results from the execution of an SQL statement. v By calling DSNTIAR to display the contents of the SQLCA; see “Displaying SQLCA fields by calling DSNTIAR” on page 299. 298 Application Programming and SQL Guide
  • 315.
    Checking the executionof SQL statements by using the SQLCA One way to check whether an SQL statement executed successfully is to use the SQL communication area (SQLCA). This area is set apart for communication with DB2. If you use the SQLCA, include the necessary instructions to display information that is contained in the SQLCA in your application program. Alternatively, you can use the GET DIAGNOSTICS statement, which is an SQL standard, to diagnose problems. v When DB2 processes an SQL statement, it places return codes that indicate the success or failure of the statement execution in SQLCODE and SQLSTATE. For details, see “Checking the execution of SQL statements by using SQLCODE and SQLSTATE” on page 303. v When DB2 processes a FETCH statement, and the FETCH is successful, the contents of SQLERRD(3) in the SQLCA is set to the number of returned rows. v When DB2 processes a multiple-row FETCH statement, the contents of SQLCODE is set to +100 if the last row in the table has been returned with the set of rows. For details, see “Accessing data by using a rowset-positioned cursor” on page 636. | | | v When DB2 processes an UPDATE, INSERT, or DELETE statement, and the statement execution is successful, the contents of SQLERRD(3) in the SQLCA is set to the number of rows that are updated, inserted, or deleted. v When DB2 processes a TRUNCATE statement and the statement execution is successful, SQLERRD(3) in the SQLCA is set to -1. The number of rows that are deleted is not returned. v If SQLWARN0 contains W, DB2 has set at least one of the SQL warning flags (SQLWARN1 through SQLWARNA): – SQLWARN1 contains N for non-scrollable cursors and S for scrollable cursors after an OPEN CURSOR or ALLOCATE CURSOR statement. – SQLWARN4 contains I for insensitive scrollable cursors, S for sensitive static scrollable cursors, and D for sensitive dynamic scrollable cursors, after an OPEN CURSOR or ALLOCATE CURSOR statement, or blank if the cursor is not scrollable. – SQLWARN5 contains a character value of 1 (read only), 2 (read and delete), or 4 (read, delete, and update) to indicate the operation that is allowed on the result table of the cursor. For a description of all the fields in the SQLCA, see the topic “Description of SQLCA fields” in DB2 SQL Reference. Displaying SQLCA fields by calling DSNTIAR If you choose to use the SQLCA as a way of checking whether an SQL statement executed successfully, your program needs to read the data in the appropriate SQLCA fields. One easy way to read these fields is to use the assembler subroutine DSNTIAR. You should check for errors codes before you commit data, and handle the errors that they represent. The assembler subroutine DSNTIAR helps you to obtain a formatted form of the SQLCA and a text message based on the SQLCODE field of the SQLCA. You can retrieve this same message text by using the MESSAGE_TEXT Chapter 3. Including DB2 queries in an application program 299
  • 316.
    condition item fieldof the GET DIAGNOSTICS statement. Programs that require long token message support should code the GET DIAGNOSTICS statement instead of DSNTIAR. DSNTIAR takes data from the SQLCA, formats it into a message, and places the result in a message output area that you provide in your application program. Each time you use DSNTIAR, it overwrites any previous messages in the message output area. You should move or print the messages before using DSNTIAR again, and before the contents of the SQLCA change, to get an accurate view of the SQLCA. DSNTIAR expects the SQLCA to be in a certain format. If your application modifies the SQLCA format before you call DSNTIAR, the results are unpredictable. DSNTIAR: The assembler subroutine DSNTIAR helps you to obtain a formatted form of the SQLCA and a text message based on the SQLCODE field of the SQLCA. DSNTIAR can run either above or below the 16-MB line of virtual storage. The DSNTIAR object module that comes with DB2 has the attributes AMODE(31) and RMODE(ANY). At install time, DSNTIAR links as AMODE(31) and RMODE(ANY). DSNTIAR runs in 31-bit mode if any of the following conditions is true: v DSNTIAR is linked with other modules that also have the attributes AMODE(31) and RMODE(ANY). v DSNTIAR is linked into an application that specifies the attributes AMODE(31) and RMODE(ANY) in its link-edit JCL. v An application loads DSNTIAR. When loading DSNTIAR from another program, be careful how you branch to DSNTIAR. For example, if the calling program is in 24-bit addressing mode and DSNTIAR is loaded above the 16-MB line, you cannot use the assembler BALR instruction or CALL macro to call DSNTIAR, because they assume that DSNTIAR is in 24-bit mode. Instead, you must use an instruction that is capable of branching into 31-bit mode, such as BASSM. You can dynamically link (load) and call DSNTIAR directly from a language that does not handle 31-bit addressing. To do this, link a second version of DSNTIAR with the attributes AMODE(24) and RMODE(24) into another load module library. Alternatively, you can write an intermediate assembler language program that calls DSNTIAR in 31-bit mode and then call that intermediate program in 24-bit mode from your application. For more information on the allowed and default AMODE and RMODE settings for a particular language, see the application programming guide for that language. For details on how the attributes AMODE and RMODE of an application are determined, see the linkage editor and loader user’s guide for the language in which you have written the application. Defining a message output area: If a program calls DSNTIAR, the program must allocate enough storage in the message output area to hold all of the message text. 300 Application Programming and SQL Guide
  • 317.
    You will probablyneed no more than 10 lines, 80-bytes each, for your message output area. An application program can have only one message output area. You must define the message output area in VARCHAR format. In this varying character format, a 2-byte length field precedes the data. The length field indicates to DSNTIAR how many total bytes are in the output message area; the minimum length of the output area is 240-bytes. The following figure shows the format of the message output area, where length is the 2-byte total length field, and the length of each line matches the logical record length (lrecl) you specify to DSNTIAR. Line: 1 2 . . . n-1 n Field sizes (in bytes): 2 Logical record length Figure 30. Format of the message output area When you call DSNTIAR, you must name an SQLCA and an output message area in the DSNTIAR parameters. You must also provide the logical record length (lrecl) as a value between 72 and 240 bytes. DSNTIAR assumes the message area contains fixed-length records of length lrecl. DSNTIAR places up to 10 lines in the message area. If the text of a message is longer than the record length you specify on DSNTIAR, the output message splits into several records, on word boundaries if possible. The split records are indented. All records begin with a blank character for carriage control. If you have more lines than the message output area can contain, DSNTIAR issues a return code of 4. A completely blank record marks the end of the message output area. Possible return codes from DSNTIAR: The assembler subroutine DSNTIAR helps your program read the information in the SQLCA. The subroutine also returns its own return code. Code Meaning 0 Successful execution. 4 More data available than could fit into the provided message area. 8 Logical record length not between 72 and 240, inclusive. 12 Message area not large enough. The message length was 240 or greater. 16 Error in TSO message routine. 20 Module DSNTIA1 could not be loaded. Chapter 3. Including DB2 queries in an application program 301
  • 318.
    SQLCA data error. 24 Ascenario for using DSNTIAR: You can use the assembler subroutine DSNTIAR to generate the error message text in the SQLCA. Suppose you want your DB2 COBOL application to check for deadlocks and timeouts, and you want to make sure your cursors are closed before continuing. You use the statement WHENEVER SQLERROR to transfer control to an error routine when your application receives a negative SQLCODE. In your error routine, you write a section that checks for SQLCODE -911 or -913. You can receive either of these SQLCODEs when a deadlock or timeout occurs. When one of these errors occurs, the error routine closes your cursors by issuing the statement: EXEC SQL CLOSE cursor-name An SQLCODE of 0 or -501 resulting from that statement indicates that the close was successful. To use DSNTIAR to generate the error message text, first follow these steps: 1. Choose a logical record length (lrecl) of the output lines. For this example, assume lrecl is 72 (to fit on a terminal screen) and is stored in the variable named ERROR-TEXT-LEN. 2. Define a message area in your COBOL application. Assuming you want an area for up to 10 lines of length 72, you should define an area of 720 bytes, plus a 2-byte area that specifies the total length of the message output area. 01 77 ERROR-MESSAGE. 02 ERROR-LEN 02 ERROR-TEXT ERROR-TEXT-LEN PIC S9(4) PIC X(72) COMP VALUE +720. OCCURS 10 TIMES INDEXED BY ERROR-INDEX. PIC S9(9) COMP VALUE +72. For this example, the name of the message area is ERROR-MESSAGE. 3. Make sure you have an SQLCA. For this example, assume the name of the SQLCA is SQLCA. To display the contents of the SQLCA when SQLCODE is 0 or -501, call DSNTIAR after the SQL statement that produces SQLCODE 0 or -501: CALL ’DSNTIAR’ USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN. You can then print the message output area just as you would any other variable. Your message might look like this: DSNT408I SQLCODE = -501, ERROR: THE CURSOR IDENTIFIED IN A FETCH OR CLOSE STATEMENT IS NOT OPEN DSNT418I SQLSTATE = 24501 SQLSTATE RETURN CODE DSNT415I SQLERRP = DSNXERT SQL PROCEDURE DETECTING ERROR DSNT416I SQLERRD = -315 0 0 -1 0 0 SQL DIAGNOSTIC INFORMATION DSNT416I SQLERRD = X’FFFFFEC5’ X’00000000’ X’00000000’ X’FFFFFFFF’ X’00000000’ X’00000000’ SQL DIAGNOSTIC INFORMATION 302 Application Programming and SQL Guide
  • 319.
    Checking the executionof SQL statements by using SQLCODE and SQLSTATE Whenever an SQL statement executes, the SQLCODE and SQLSTATE fields of the SQLCA receive a return code. Portable applications should use SQLSTATE instead of SQLCODE, although SQLCODE values can provide additional DB2-specific information about an SQL error or warning. SQLCODE: DB2 returns the following codes in SQLCODE: v If SQLCODE = 0, execution was successful. v If SQLCODE > 0, execution was successful with a warning. v If SQLCODE < 0, execution was not successful. SQLCODE 100 indicates that no data was found. The meaning of SQLCODEs other than 0 and 100 varies with the particular product implementing SQL. SQLSTATE: SQLSTATE enables an application program to check for errors in the same way for different IBM database management systems. For a complete list of possible SQLSTATE values, see the topic “SQLSTATE values—common error codes” in DB2 Codes. Using SQLCODE and SQLSTATE: An advantage to using the SQLCODE field is that it can provide more specific information than the SQLSTATE. Many of the SQLCODEs have associated tokens in the SQLCA that indicate, for example, which object incurred an SQL error. However, an SQL standard application uses only SQLSTATE. You can declare SQLCODE and SQLSTATE (SQLCOD and SQLSTA in Fortran) as stand-alone host variables. If you specify the STDSQL(YES) precompiler option, these host variables receive the return codes, and you should not include an SQLCA in your program. Checking the execution of SQL statements by using the WHENEVER statement The WHENEVER statement causes DB2 to check the SQLCA and continue processing your program, or branch to another area in your program if an error, exception, or warning occurs. The condition handling area of your program can then examine SQLCODE or SQLSTATE to react specifically to the error or exception. The WHENEVER statement is not supported for REXX. For information on REXX error handling, see “Embedding SQL statements in your application” on page 243. The WHENEVER statement enables you to specify what to do if a general condition is true. You can specify more than one WHENEVER statement in your program. When you do this, the first WHENEVER statement applies to all subsequent SQL statements in the source program until the next WHENEVER statement. The WHENEVER statement looks like this: EXEC SQL WHENEVER condition action END-EXEC Chapter 3. Including DB2 queries in an application program 303
  • 320.
    The condition ofthe WHENEVER statement is one of these three values: SQLWARNING Indicates what to do when SQLWARN0 = W or SQLCODE contains a positive value other than 100. DB2 can set SQLWARN0 for several reasons—for example, if a column value is truncated when moved into a host variable. Your program might not regard this as an error. SQLERROR Indicates what to do when DB2 returns an error code as the result of an SQL statement (SQLCODE < 0). NOT FOUND Indicates what to do when DB2 cannot find a row to satisfy your SQL statement or when there are no more rows to fetch (SQLCODE = 100). The action of the WHENEVER statement is one of these two values: CONTINUE Specifies the next sequential statement of the source program. GOTO or GO TO host-label Specifies the statement identified by host-label. For host-label, substitute a single token, preceded by an optional colon. The form of the token depends on the host language. In COBOL, for example, it can be section-name or an unqualified paragraph-name. The WHENEVER statement must precede the first SQL statement it is to affect. However, if your program checks SQLCODE directly, you must check SQLCODE after each SQL statement. Checking the execution of SQL statements by using the GET DIAGNOSTICS statement One way to check whether an SQL statement executed successfully is to ask DB2 to return the diagnostic information about the last SQL statement that was executed. You can use the GET DIAGNOSTICS statement to return diagnostic information about the last SQL statement that was executed. You can request individual items of diagnostic information from the following groups of items: v Statement items, which contain information about the SQL statement as a whole v Condition items, which contain information about each error or warning that occurred during the execution of the SQL statement v Connection items, which contain information about the SQL statement if it was a CONNECT statement In addition to requesting individual items, you can request that GET DIAGNOSTICS return ALL diagnostic items that are set during the execution of the last SQL statement as a single string. For more information about the GET DIAGNOSTICS statement, see the topic “GET DIAGNOSTICS” in DB2 SQL Reference. In SQL procedures, you can also retrieve diagnostic information by using handlers. Handlers tell the procedure what to do if a particular error occurs. For more information about handlers, see “Handlers in an SQL procedure” on page 505. | | | 304 Application Programming and SQL Guide
  • 321.
    | | | | | | Use the GETDIAGNOSTICS statement to handle multiple SQL errors that might result from the execution of a single SQL statement. First, check SQLSTATE (or SQLCODE) to determine whether diagnostic information should be retrieved by using GET DIAGNOSTICS. This method is especially useful for diagnosing problems that result from a multiple-row INSERT that is specified as NOT ATOMIC CONTINUE ON SQLEXCEPTIONand multiple row MERGE statements. Even if you use only the GET DIAGNOSTICS statement in your application program to check for conditions, you must either include the instructions required to use the SQLCA or you must declare SQLSTATE (or SQLCODE) separately in your program. Restriction: If you issue a GET DIAGNOSTICS statement immediately following an SQL statement that uses private protocol access, DB2 returns an error. When you use the GET DIAGNOSTICS statement, you assign the requested diagnostic information to host variables. Declare each target host variable with a data type that is compatible with the data type of the requested item. For a description of available items and their data types, see “Data types for GET DIAGNOSTICS items” on page 307. To retrieve condition information, you must first retrieve the number of condition items (that is, the number of errors and warnings that DB2 detected during the execution of the last SQL statement). The number of condition items is at least one. If the last SQL statement returned SQLSTATE ’00000’ (or SQLCODE 0), the number of condition items is one. Example: Using GET DIAGNOSTICS with multiple-row INSERT: You want to display diagnostic information for each condition that might occur during the execution of a multiple-row INSERT statement in your application program. You specify the INSERT statement as NOT ATOMIC CONTINUE ON SQLEXCEPTION, which means that execution continues regardless of the failure of any single-row insertion. DB2 does not insert the row that was processed at the time of the error. In the following example, the first GET DIAGNOSTICS statement returns the number of rows inserted and the number of conditions returned. The second GET DIAGNOSTICS statement returns the following items for each condition: SQLCODE, SQLSTATE, and the number of the row (in the rowset that was being inserted) for which the condition occurred. EXEC SQL BEGIN DECLARE SECTION; long row_count, num_condns, i; long ret_sqlcode, row_num; char ret_sqlstate[6]; ... EXEC SQL END DECLARE SECTION; ... EXEC SQL INSERT INTO DSN8910.ACT (ACTNO, ACTKWD, ACTDESC) VALUES (:hva1, :hva2, :hva3) FOR 10 ROWS NOT ATOMIC CONTINUE ON SQLEXCEPTION; EXEC SQL GET DIAGNOSTICS :row_count = ROW_COUNT, :num_condns = NUMBER; printf("Number of rows inserted = %dn", row_count); for (i=1; i<=num_condns; i++) { EXEC SQL GET DIAGNOSTICS CONDITION :i Chapter 3. Including DB2 queries in an application program 305
  • 322.
    :ret_sqlcode = DB2_RETURNED_SQLCODE, :ret_sqlstate= RETURNED_SQLSTATE, :row_num = DB2_ROW_NUMBER; printf("SQLCODE = %d, SQLSTATE = %s, ROW NUMBER = %dn", ret_sqlcode, ret_sqlstate, row_num); } In the activity table, the ACTNO column is defined as SMALLINT. Suppose that you declare the host variable array hva1 as an array with data type long, and you populate the array so that the value for the fourth element is 32768. If you check the SQLCA values after the INSERT statement, the value of SQLCODE is equal to 0, the value of SQLSTATE is ’00000’, and the value of SQLERRD(3) is 9 for the number of rows that were inserted. However, the INSERT statement specified that 10 rows were to be inserted. The GET DIAGNOSTICS statement provides you with the information that you need to correct the data for the row that was not inserted. The printed output from your program looks like this: Number of rows inserted = 9 SQLCODE = -302, SQLSTATE = 22003, ROW NUMBER = 4 The value 32768 for the input variable is too large for the target column ACTNO. You can print the MESSAGE_TEXT condition item. For information about SQLCODE -302, see the topic “Error SQL codes” in DB2 Codes. Retrieving statement and condition items: When you use the GET DIAGNOSTICS statement, you assign the requested diagnostic information to host variables. Declare each target host variable with a data type that is compatible with the data type of the requested item. To retrieve condition information, you must first retrieve the number of condition items (that is, the number of errors and warnings that DB2 detected during the execution of the last SQL statement). The number of condition items is at least one. If the last SQL statement returned SQLSTATE ’00000’ (or SQLCODE 0), the number of condition items is one. Example: Using GET DIAGNOSTICS with multiple-row INSERT: You want to display diagnostic information for each condition that might occur during the execution of a multiple-row INSERT statement in your application program. You specify the INSERT statement as NOT ATOMIC CONTINUE ON SQLEXCEPTION, which means that execution continues regardless of the failure of any single-row insertion. DB2 does not insert the row that was processed at the time of the error. In the following example code, the first GET DIAGNOSTICS statement returns the number of rows inserted and the number of conditions returned. The second GET DIAGNOSTICS statement returns the following items for each condition: SQLCODE, SQLSTATE, and the number of the row (in the rowset that was being inserted) for which the condition occurred EXEC SQL BEGIN DECLARE SECTION; long row_count, num_condns, i; long ret_sqlcode, row_num; char ret_sqlstate[6]; ... EXEC SQL END DECLARE SECTION; ... EXEC SQL 306 Application Programming and SQL Guide
  • 323.
    INSERT INTO DSN8810.ACT (ACTNO,ACTKWD, ACTDESC) VALUES (:hva1, :hva2, :hva3) FOR 10 ROWS NOT ATOMIC CONTINUE ON SQLEXCEPTION; EXEC SQL GET DIAGNOSTICS :row_count = ROW_COUNT, :num_condns = NUMBER; printf("Number of rows inserted = %dn", row_count); for (i=1; i<=num_condns; i++) { EXEC SQL GET DIAGNOSTICS CONDITION :i :ret_sqlcode = DB2_RETURNED_SQLCODE, :ret_sqlstate = RETURNED_SQLSTATE, :row_num = DB2_ROW_NUMBER; printf("SQLCODE = %d, SQLSTATE = %s, ROW NUMBER = %dn", ret_sqlcode, ret_sqlstate, row_num); } In the activity table, the ACTNO column is defined as SMALLINT. Suppose that you declare the host variable array hva1 as an array with data type long, and you populate the array so that the value for the fourth element is 32768. If you check the SQLCA values after the INSERT statement, the value of SQLCODE is equal to 0, the value of SQLSTATE is ’00000’, and the value if SQLERRD(3) is 9 for the number of rows that were inserted. However, the INSERT statement specified that 10 rows were to be inserted. The GET DIAGNOSTICS statement provides you with the information that you need to correct the data for the row that was not inserted. The printed output from your program looks like this: Number of rows inserted = 9 SQLCODE = -302, SQLSTATE = 22003, ROW NUMBER = 4 The value 32768 for the input variable is too large for the target column ACTNO. You can print the MESSAGE_TEXT condition item, or see DB2 Codes for information about SQLCODE -302. Data types for GET DIAGNOSTICS items You can use the GET DIAGNOSTICS statement to request statement, condition, and connection information about the last SQL statement that was executed. You must declare each target host variable with a data type that is compatible with the data type of the requested item. The following tables specify the data types for the statement, condition, and connection information items that you can request by using the GET DIAGNOSTICS statement. Table 68. Data types for GET DIAGNOSTICS items that return statement information Item Description Data type DB2_GET_DIAGNOSTICS_DIAGNOSTICS After a GET DIAGNOSTICS statement, VARCHAR(32672) if any error or warning occurred, this item contains all of the diagnostics as a single string. DB2_LAST_ROW After a multiple-row FETCH statement, INTEGER this item contains a value of +100 if the last row in the table is in the rowset that was returned. Chapter 3. Including DB2 queries in an application program 307
  • 324.
    Table 68. Datatypes for GET DIAGNOSTICS items that return statement information (continued) Item Description Data type DB2_NUMBER_PARAMETER_MARKERS After a PREPARE statement, this item contains the number of parameter markers in the prepared statement. INTEGER DB2_NUMBER_RESULT_SETS After a CALL statement that invokes a INTEGER stored procedure, this item contains the number of result sets that are returned by the procedure. DB2_NUMBER_ROWS After an OPEN or FETCH statement DECIMAL(31,0) for which the size of the result table is known, this item contains the number of rows in the result table. After a PREPARE statement, this item contains the estimated number of rows in the result table for the prepared statement. For SENSITIVE DYNAMIC cursors, this item contains the approximate number of rows. DB2_RETURN_STATUS After a CALL statement that invokes an SQL procedure, this item contains the return status if the procedure contains a RETURN statement. INTEGER DB2_SQL_ATTR_CURSOR_HOLD After an ALLOCATE or OPEN statement, this item indicates whether the cursor can be held open across multiple units of work (Y or N). CHAR(1) DB2_SQL_ATTR_CURSOR_ROWSET After an ALLOCATE or OPEN statement, this item indicates whether the cursor can use rowset positioning (Y or N). CHAR(1) DB2_SQL_ATTR_CURSOR_SCROLLABLE After an ALLOCATE or OPEN statement, this item indicates whether the cursor is scrollable (Y or N). CHAR(1) | DB2_SQL_ATTR_CURSOR_SENSITIVITY | | | After an ALLOCATE or OPEN statement, this item indicates whether the cursor shows updates made by other processes (sensitivity I or S). CHAR(1) | DB2_SQL_ATTR_CURSOR_TYPE | | | | | After an ALLOCATE or OPEN CHAR(1) statement, this item indicates whether the cursor is forward (F), declared static (S for INSENSITIVE or SENSITIVE STATIC, or dynamic (D for SENSITIVE DYNAMIC). MORE After any SQL statement, this item indicates whether some conditions items were discarded because of insufficient storage (Y or N). CHAR(1) NUMBER After any SQL statement, this item contains the number of condition items. If no warning or error occurred, or if no previous SQL statement has been executed, the number that is returned is 1. INTEGER 308 Application Programming and SQL Guide
  • 325.
    Table 68. Datatypes for GET DIAGNOSTICS items that return statement information (continued) Item Description ROW_COUNT After an insert, update, delete, or fetch, DECIMAL(31,0) this item contains the number of rows that are deleted, inserted, updated, or fetched. After PREPARE, this item contains the estimated number of result rows in the prepared statement. After TRUNCATE, it contains -1. | Data type Table 69. Data types for GET DIAGNOSTICS items that return condition information Item Description Data type CATALOG_NAME This item contains the server name of the table that owns a constraint that caused an error, or that caused an access rule or check violation. VARCHAR(128) CONDITION_NUMBER This item contains the number of the condition. INTEGER CURSOR_NAME This item contains the name of a cursor in an invalid cursor state. VARCHAR(128) DB2_ERROR_CODE1 This item contains an internal error code. INTEGER DB2_ERROR_CODE2 This item contains an internal error code. INTEGER DB2_ERROR_CODE3 This item contains an internal error code. INTEGER DB2_ERROR_CODE4 This item contains an internal error code. INTEGER DB2_INTERNAL_ERROR_POINTER For some errors, this item contains a negative value that is an internal error pointer. INTEGER DB2_MESSAGE_ID This item contains the message ID that CHAR(10) corresponds to the message that is contained in the MESSAGE_TEXT diagnostic item. DB2_MODULE_DETECTING_ERROR After any SQL statement, this item indicates which module detected the error. CHAR(8) DB2_ORDINAL_TOKEN_n After any SQL statement, this item contains the nth token, where n is a value from 1 to 100. VARCHAR(515) DB2_REASON_CODE After any SQL statement, this item contains INTEGER the reason code for errors that have a reason code token in the message text. DB2_RETURNED_SQLCODE After any SQL statement, this item contains the SQLCODE for the condition. INTEGER DB2_ROW_NUMBER After any SQL statement that involves multiple rows, this item contains the row number on which DB2 detected the condition. DECIMAL(31,0) DB2_TOKEN_COUNT After any SQL statement, this item contains the number of tokens available for the condition. INTEGER MESSAGE_TEXT After any SQL statement, this item contains the message text associated with the SQLCODE. VARCHAR(32672) Chapter 3. Including DB2 queries in an application program 309
  • 326.
    Table 69. Datatypes for GET DIAGNOSTICS items that return condition information (continued) Item Description Data type RETURNED_SQLSTATE After any SQL statement, this item contains the SQLSTATE for the condition. CHAR(5) SERVER_NAME After a CONNECT, DISCONNECT, or SET VARCHAR(128) CONNECTION statement, this item contains the name of the server specified in the statement. Table 70. Data types for GET DIAGNOSTICS items that return connection information Item Description DB2_AUTHENTICATION_TYPE This item contains the authentication type (S, CHAR(1) C, D, E, or blank). For more information about the values for DB2_AUTHENTICATION_TYPE, see the topic “GET DIAGNOSTICS” in DB2 SQL Reference. Data type DB2_AUTHORIZATION_ID This item contains the authorization ID that is used by the connected server. DB2_CONNECTION_STATE This item indicates whether the connection is INTEGER unconnected (-1), local (0), or remote (1). DB2_CONNECTION_STATUS This item indicates whether updates can be INTEGER committed for the current unit of work (1 for Yes, 2 for No). DB2_ENCRYPTION_TYPE This item contains one of the following values that indicates the level of encryption for the connection: A Only the authentication tokens (authid and password) are encrypted D All of the data for the connection is encrypted CHAR(1) DB2_SERVER_CLASS_NAME After a CONNECT or SET CONNECTION statement, this item contains the DB2 server class name. VARCHAR(128) DB2_PRODUCT_ID This item contains the DB2 product signature. VARCHAR(8) VARCHAR(128) Handling SQL error codes You can use the subroutine DSNTIAR or the GET DIAGNOSTICS statement to convert an SQL return code into a text message. Handling SQL error return codes in assembler You can use the subroutine DSNTIAR to convert an SQL return code into a text message. DSNTIAR takes data from the SQLCA, formats it into a message, and places the result in a message output area that you provide in your application program. For concepts and more information about the behavior of DSNTIAR, see “Displaying SQLCA fields by calling DSNTIAR” on page 299. You can also use the MESSAGE_TEXT condition item field of the GET DIAGNOSTICS statement to convert an SQL return code into a text message. 310 Application Programming and SQL Guide
  • 327.
    Programs that requirelong token message support should code the GET DIAGNOSTICS statement instead of DSNTIAR. For more information about GET DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET DIAGNOSTICS statement” on page 304. DSNTIAR syntax: CALL DSNTIAR,(sqlca, message, lrecl),MF=(E,PARM) The DSNTIAR parameters have the following meanings: sqlca An SQL communication area. message An output area, defined as a varying-length string, in which DSNTIAR places the message text. The first halfword contains the length of the remaining area; its minimum value is 240. The output lines of text, each line being the length specified in lrecl, are put into this area. For example, you could specify the format of the output area as: LINES LRECL EQU EQU 10 132 . . . MSGLRECL DC MESSAGE DS ORG MESSAGEL DC MESSAGE1 DS MESSAGE2 DS AL4(LRECL) H,CL(LINES*LRECL) MESSAGE AL2(LINES*LRECL) CL(LRECL) text line 1 CL(LRECL) text line 2 . . . MESSAGEn DS CL(LRECL) text line n . . . CALL DSNTIAR,(SQLCA,MESSAGE,MSGLRECL),MF=(E,PARM) where MESSAGE is the name of the message output area, LINES is the number of lines in the message output area, and LRECL is the length of each line. lrecl A fullword containing the logical record length of output messages, between 72 and 240. The expression MF=(E,PARM) is an z/OS macro parameter that indicates dynamic execution. PARM is the name of a data area that contains a list of pointers to the call parameters of DSNTIAR. See “DB2 sample applications” on page 1013 for instructions on how to access and print the source code for the sample program. CICS: If your CICS application requires CICS storage handling, you must use the subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax: CALL DSNTIAC,(eib,commarea,sqlca,msg,lrecl),MF=(E,PARM) DSNTIAC has extra parameters, which you must use for calls to routines that use CICS commands. Chapter 3. Including DB2 queries in an application program 311
  • 328.
    eib EXEC interface block commarea communicationarea For more information on these parameters, see the appropriate application programming guide for CICS. The remaining parameter descriptions are the same as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the same way. You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you must also define them in the CSD. For an example of CSD entry generation statements for use with DSNTIAC, see member DSN8FRDO in the data set prefix.SDSNSAMP. The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and link-edits DSNTIAC, are also in the data set prefix.SDSNSAMP. Handling SQL error return codes in C or C++ You can use the subroutine DSNTIAR to convert an SQL return code into a text message. DSNTIAR takes data from the SQLCA, formats it into a message, and places the result in a message output area that you provide in your application program. For concepts and more information about the behavior of DSNTIAR, see “Displaying SQLCA fields by calling DSNTIAR” on page 299. You can also use the MESSAGE_TEXT condition item field of the GET DIAGNOSTICS statement to convert an SQL return code into a text message. Programs that require long token message support should code the GET DIAGNOSTICS statement instead of DSNTIAR. For more information about GET DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET DIAGNOSTICS statement” on page 304. DSNTIAR syntax: rc = dsntiar(&sqlca, &message, &lrecl); The DSNTIAR parameters have the following meanings: &sqlca An SQL communication area. &message An output area, in VARCHAR format, in which DSNTIAR places the message text. The first halfword contains the length of the remaining area; its minimum value is 240. The output lines of text, each line being the length specified in &lrecl, are put into this area. For example, you could specify the format of the output area as: #define data_len 132 #define data_dim 10 struct error_struct { short int error_len; char error_text[data_dim][data_len]; . } error_message = {data_dim * data_len}; . . rc = dsntiar(&sqlca, &error_message, &data_len); 312 Application Programming and SQL Guide
  • 329.
    where error_message isthe name of the message output area, data_dim is the number of lines in the message output area, and data_len is the length of each line. &lrecl A fullword containing the logical record length of output messages, between 72 and 240. To inform your compiler that DSNTIAR is an assembler language program, include one of the following statements in your application. For C, include: #pragma linkage (dsntiar,OS) For C++, include a statement similar to this: extern "OS" short int dsntiar(struct sqlca *sqlca, struct error_struct *error_message, int *data_len); Examples of calling DSNTIAR from an application appear in the DB2 sample C program DSN8BD3 and in the sample C++ program DSN8BE3. Both are in the library DSN8910.SDSNSAMP. See “DB2 sample applications” on page 1013 for instructions on how to access and print the source code for the sample programs. CICS: If your CICS application requires CICS storage handling, you must use the subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax: rc = DSNTIAC(&eib, &commarea, &sqlca, &message, &lrecl); DSNTIAC has extra parameters, which you must use for calls to routines that use CICS commands. &eib EXEC interface block &commarea communication area For more information on these parameters, see the appropriate application programming guide for CICS. The remaining parameter descriptions are the same as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the same way. You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you must also define them in the CSD. For an example of CSD entry generation statements for use with DSNTIAC, see job DSNTEJ5A. The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and link-edits DSNTIAC, are in the data set prefix.SDSNSAMP. Handling SQL error return codes in COBOL: You can use the MESSAGE_TEXT condition item field of the GET DIAGNOSTICS statement to convert an SQL return code into a text message. Programs that require long token message support should code the GET DIAGNOSTICS statement instead of DSNTIAR. For more information about GET DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET DIAGNOSTICS statement” on page 304. Chapter 3. Including DB2 queries in an application program 313
  • 330.
    You can usethe subroutine DSNTIAR to convert an SQL return code into a text message. DSNTIAR takes data from the SQLCA, formats it into a message, and places the result in a message output area that you provide in your application program. For concepts and more information on the behavior of DSNTIAR, see “Displaying SQLCA fields by calling DSNTIAR” on page 299. DSNTIAR syntax: CALL ’DSNTIAR’ USING sqlca message lrecl. The DSNTIAR parameters have the following meanings: sqlca An SQL communication area. message An output area, in VARCHAR format, in which DSNTIAR places the message text. The first halfword contains the length of the remaining area; its minimum value is 240. The output lines of text, each line being the length specified in lrecl, are put into this area. For example, you could specify the format of the output area as: 01 ERROR-MESSAGE. 02 ERROR-LEN 02 ERROR-TEXT PIC S9(4) COMP VALUE +1320. PIC X(132) OCCURS 10 TIMES INDEXED BY ERROR-INDEX. PIC S9(9) COMP VALUE +132. 77 ERROR-TEXT-LEN . . . CALL ’DSNTIAR’ USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN. where ERROR-MESSAGE is the name of the message output area containing 10 lines of length 132 each, and ERROR-TEXT-LEN is the length of each line. lrecl A fullword containing the logical record length of output messages, between 72 and 240. An example of calling DSNTIAR from an application appears in the DB2 sample assembler program DSN8BC3, which is contained in the library DSN8910.SDSNSAMP. See “DB2 sample applications” on page 1013 for instructions on how to access and print the source code for the sample program. CICSIf you call DSNTIAR dynamically from a CICS COBOL application program, be sure you do the following: v Compile the COBOL application with the NODYNAM option. v Define DSNTIAR in the CSD. If your CICS application requires CICS storage handling, you must use the subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax: CALL ’DSNTIAC’ USING eib commarea sqlca msg lrecl. DSNTIAC has extra parameters, which you must use for calls to routines that use CICS commands. eib EXEC interface block commarea communication area 314 Application Programming and SQL Guide
  • 331.
    For more informationon these parameters, see the appropriate application programming guide for CICS. The remaining parameter descriptions are the same as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the same way. You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you must also define them in the CSD. For an example of CSD entry generation statements for use with DSNTIAC, see job DSNTEJ5A. The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and link-edits DSNTIAC, are in the data set prefix.SDSNSAMP. Handling SQL error return codes in Fortran: You can use the subroutine DSNTIR to convert an SQL return code into a text message. DSNTIR builds a parameter list and calls DSNTIAR for you. DSNTIAR takes data from the SQLCA, formats it into a message, and places the result in a message output area that you provide in your application program. For concepts and more information on the behavior of DSNTIAR, see “Displaying SQLCA fields by calling DSNTIAR” on page 299. You can also use the MESSAGE_TEXT condition item field of the GET DIAGNOSTICS statement to convert an SQL return code into a text message. Programs that require long token message support should code the GET DIAGNOSTICS statement instead of DSNTIAR. For more information about GET DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET DIAGNOSTICS statement” on page 304. DSNTIR syntax: CALL DSNTIR ( error-length, message, return-code ) The DSNTIR parameters have the following meanings: error-length The total length of the message output area. message An output area, in VARCHAR format, in which DSNTIAR places the message text. The first halfword contains the length of the remaining area; its minimum value is 240. The output lines of text are put into this area. For example, you could specify the format of the output area as: INTEGER ERRLEN /1320/ CHARACTER*132 ERRTXT(10) INTEGER ICODE . . . CALL DSNTIR ( ERRLEN, ERRTXT, ICODE ) where ERRLEN is the total length of the message output area, ERRTXT is the name of the message output area, and ICODE is the return code. return-code Accepts a return code from DSNTIAR. An example of calling DSNTIR (which then calls DSNTIAR) from an application appears in the DB2 sample assembler program DSN8BF3, which is contained in the Chapter 3. Including DB2 queries in an application program 315
  • 332.
    library DSN8910.SDSNSAMP. See“DB2 sample applications” on page 1013 for instructions on how to access and print the source code for the sample program. Handling SQL error return codes in PL/I: You can use the subroutine DSNTIAR to convert an SQL return code into a text message. DSNTIAR takes data from the SQLCA, formats it into a message, and places the result in a message output area that you provide in your application program. For concepts and more information on the behavior of DSNTIAR, see “Displaying SQLCA fields by calling DSNTIAR” on page 299. You can also use the MESSAGE_TEXT condition item field of the GET DIAGNOSTICS statement to convert an SQL return code into a text message. Programs that require long token message support should code the GET DIAGNOSTICS statement instead of DSNTIAR. For more information about GET DIAGNOSTICS, see “Checking the execution of SQL statements by using the GET DIAGNOSTICS statement” on page 304. DSNTIAR syntax: CALL DSNTIAR ( sqlca, message, lrecl ); The DSNTIAR parameters have the following meanings: sqlca An SQL communication area. message An output area, in VARCHAR format, in which DSNTIAR places the message text. The first halfword contains the length of the remaining area; its minimum value is 240. The output lines of text, each line being the length specified in lrecl, are put into this area. For example, you could specify the format of the output area as: DCL DATA_LEN FIXED BIN(31) INIT(132); DCL DATA_DIM FIXED BIN(31) INIT(10); DCL 1 ERROR_MESSAGE AUTOMATIC, 3 ERROR_LEN FIXED BIN(15) UNAL INIT((DATA_LEN*DATA_DIM)), 3 ERROR_TEXT(DATA_DIM) CHAR(DATA_LEN); . . . CALL DSNTIAR ( SQLCA, ERROR_MESSAGE, DATA_LEN ); where ERROR_MESSAGE is the name of the message output area, DATA_DIM is the number of lines in the message output area, and DATA_LEN is the length of each line. lrecl A fullword containing the logical record length of output messages, between 72 and 240. Because DSNTIAR is an assembler language program, you must include the following directives in your PL/I application: DCL DSNTIAR ENTRY OPTIONS (ASM,INTER,RETCODE); An example of calling DSNTIAR from an application appears in the DB2 sample assembler program DSN8BP3, contained in the library DSN8910.SDSNSAMP. See “DB2 sample applications” on page 1013 for instructions on how to access and print the source code for the sample program. 316 Application Programming and SQL Guide
  • 333.
    CICS: If yourCICS application requires CICS storage handling, you must use the subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax: CALL DSNTIAC (eib, commarea, sqlca, msg, lrecl); DSNTIAC has extra parameters, which you must use for calls to routines that use CICS commands. eib EXEC interface block commarea communication area For more information on these parameters, see the appropriate application programming guide for CICS. The remaining parameter descriptions are the same as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the same way. You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you must also define them in the CSD. For an example of CSD entry generation statements for use with DSNTIAC, see job DSNTEJ5A. The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and link-edits DSNTIAC, are in the data set prefix.SDSNSAMP. Arithmetic and conversion errors You can track arithmetic and conversion errors by using indicator variables. An indicator variable contains a small integer value that indicates some information about the associated host variable. Numeric or character conversion errors or arithmetic expression errors can set an indicator variable to -2. For example, division by zero and arithmetic overflow do not necessarily halt the execution of a SELECT statement. If you use indicator variables and an error occurs in the SELECT list, the statement can continue to execute and return good data for rows in which the error does not occur. For rows in which a conversion or arithmetic expression error does occur, the indicator variable indicates that one or more selected items have no meaningful value. The indicator variable flags this error with a -2 for the affected host variable and an SQLCODE of +802 (SQLSTATE ’01519’) in the SQLCA. Writing applications that enable users to create and modify tables You can write a DB2 application that enables users to create new tables, add columns to them, increase the length of character columns, rearrange the columns, and delete columns. Question: How can I write an SQL application that allows users to create new tables, add columns to them, increase the length of character columns, rearrange the columns, and delete columns? | | | | | | Answer: Your program can dynamically execute CREATE TABLE and ALTER TABLE statements entered by users to create new tables, add columns to existing tables, or change the data types of existing columns. Added columns initially contain either the null value or a default value. Both statements, like any data definition statement, are relatively expensive to execute; consider the effects of locks. Chapter 3. Including DB2 queries in an application program 317
  • 334.
    You cannot rearrangeor delete columns in a table without dropping the entire table. You can, however, create a view on the table, which includes only the columns you want, in the order you want. This has the same effect as redefining the table. For a description of dynamic SQL execution, see “Dynamic SQL” on page 258. Saving SQL statements that are translated from end user requests If your program translates requests from end users into SQL statements and allows users to save their requests, your program can improve performance by saving those translated statements. Question: A program translates requests from end users into SQL statements before executing them, and users can save a request. How can the corresponding SQL statement be saved? Answer: You can save the corresponding SQL statements in a table with a column having a data type of VARCHAR(n), where n is the maximum length of any SQL statement. You must save the source SQL statements, not the prepared versions. That means that you must retrieve and then prepare each statement before executing the version stored in the table. In essence, your program prepares an SQL statement from a character string and executes it dynamically. (For a description of dynamic SQL, see “Dynamic SQL” on page 258.) Retrieving data from DB2 tables in REXX programs Although all output data in REXX programs is string data, you can determine the data type that the data represents from its format and from the data type of the column from which the data was retrieved. The following table gives the format for each type of output data. Table 71. SQL output data types and REXX data formats SQL data type | SMALLINTINTEGERBIGINT | | | DECIMAL(p,s) REXX output data format A string of numerics that does not contain leading zeroes, a decimal point, or an exponent identifier. If the string represents a negative number, it begins with a minus (-) sign. The numeric value is between -9223372036854775808 and 9223372036854775807, inclusive. A string of numerics with one of the following formats: v Contains a decimal point but not an exponent identifier. The string is padded with zeroes to match the scale of the corresponding table column. If the value represents a negative number, it begins with a minus (-) sign. v Does not contain a decimal point or an exponent identifier. The numeric value is less than -2147483647 or greater than 2147483647. If the value is negative, it begins with a minus (-) sign. FLOAT(n) REALDOUBLE 318 A string that represents a number in scientific notation. The string consists of a numeric, a decimal point, a series of numerics, and an exponent identifier. The exponent identifier is an E followed by a minus (-) sign and a series of numerics if the number is between -1 and 1. Otherwise, the exponent identifier is an E followed by a series of numerics. If the string represents a negative number, it begins with a minus (-) sign. Application Programming and SQL Guide
  • 335.
    Table 71. SQLoutput data types and REXX data formats (continued) SQL data type | | | | | | REXX output data format DECFLOAT REXX emulates the DECFLOAT data type with DOUBLE, so support for DECFLOAT is limited to the REXX support for DOUBLE. The following special values are not supported: v INFINITY v SNAN v NAN CHAR(n)VARCHAR(n) A character string of length n bytes. The string is not enclosed in single or double quotation marks. GRAPHIC(n) VARGRAPHIC(n) A string of length 2*n bytes. Each pair of bytes represents a double-byte character. This string does not contain a leading G, is not enclosed in quotation marks, and does not contain shift-out or shift-in characters. Because you cannot use the SELECT INTO statement in a REXX procedure, to retrieve data from a DB2 table you must prepare a SELECT statement, open a cursor for the prepared statement, and then fetch rows into host variables or an SQLDA using the cursor. The following example demonstrates how you can retrieve data from a DB2 table using an SQLDA: SQLSTMT= , ’SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME,’ , ’ WORKDEPT, PHONENO, HIREDATE, JOB,’ , ’ EDLEVEL, SEX, BIRTHDATE, SALARY,’ , ’ BONUS, COMM’ , ’ FROM EMP’ EXECSQL DECLARE C1 CURSOR FOR S1 EXECSQL PREPARE S1 INTO :OUTSQLDA FROM :SQLSTMT EXECSQL OPEN C1 Do Until(SQLCODE ¬= 0) EXECSQL FETCH C1 USING DESCRIPTOR :OUTSQLDA If SQLCODE = 0 Then Do Line = ’’ Do I = 1 To OUTSQLDA.SQLD Line = Line OUTSQLDA.I.SQLDATA End I Say Line End End XML data in embedded SQL applications Embedded SQL applications that are written in assembler language, C, C++, COBOL, or PL/I can update and retrieve data in XML columns. In embedded SQL applications, you can: v Store an entire XML document in an XML column using INSERT or UPDATE statements. v Retrieve an entire XML document from an XML column using SELECT statements. v Retrieve a sequence from a document in an XML column by using the SQL XMLQUERY function within a SELECT or FETCH statement, to retrieve the sequence into a serialized XML string in the database, and then retrieve the data into an application variable. Recommendation: Follow these guidelines when you write embedded SQL applications: Chapter 3. Including DB2 queries in an application program 319
  • 336.
    v Avoid usingthe XMLPARSE and XMLSERIALIZE functions. Let DB2 do the conversions between the external and internal XML formats implicitly. v Use XML host variables for input and output. Doing so allows DB2 to process values as XML data instead of character or binary string data. If the application cannot use XML host variables, it should use binary string host variables to minimize character conversion issues. v Avoid character conversion by using UTF-8 host variables for input and output of XML values whenever possible. Host variable data types for XML data in embedded SQL applications DB2 provides XML host variable types for Assembler, C, C++, COBOL, and PL/I. Those types are: v XML AS BLOB v XML AS CLOB v XML AS DBCLOB v XML AS BLOB_FILE v XML AS CLOB_FILE v XML AS DBCLOB_FILE The XML host variable types are compatible only with the XML column data type. You can use BLOB, CLOB, DBCLOB, CHAR, VARCHAR, GRAPHIC, VARGRAPHIC, BINARY, or VARBINARY host variables to update XML columns. You can convert the host variable data types to the XML type using the XMLPARSE function, or you can let the DB2 database server perform the conversion implicitly. You can use BLOB, CLOB, DBCLOB, CHAR, VARCHAR, GRAPHIC, VARGRAPHIC, BINARY, or VARBINARY host variables to retrieve data from XML columns. You can convert the XML data to the host variable type using the XMLSERIALIZE function, or you can let the DB2 database server perform the conversion implicitly. The following examples show you how to declare XML host variables in each supported language. In each table, the left column contains the declaration that you code in your application program. The right column contains the declaration that DB2 generates. Declarations of XML host variables in assembler The following table shows assembler language declarations for some typical XML types. Table 72. Example of assembler XML variable declarations You declare this variable DB2 generates this variable BLOB_XML SQL TYPE IS XML AS BLOB 1M BLOB_XML DS 0FL4 BLOB_XML_LENGTH DS FL4 BLOB_XML_DATA DS CL655351 ORG *+(983041) 320 Application Programming and SQL Guide
  • 337.
    Table 72. Exampleof assembler XML variable declarations (continued) You declare this variable DB2 generates this variable CLOB_XML SQL TYPE IS XML AS CLOB 40000K CLOB_XML DS 0FL4 CLOB_XML_LENGTH DS FL4 CLOB_XML_DATA DS CL655351 ORG *+(40894465) DBCLOB_XML SQL TYPE IS XML AS DBCLOB 4000K DBCLOB_XML DS 0FL4 DBCLOB_XML_LENGTH DS FL4 DBCLOB_XML_DATA DS GL655342 ORG *+(4030466) | | | | | | BLOB_XML_FILE SQL TYPE IS XML AS BLOB_FILE BLOB_XML_FILE DS 0FL4 BLOB_XML_FILE_NAME_LENGTH DS FL4 BLOB_XML_FILE_DATA_LENGTH DS FL4 BLOB_XML_FILE_FILE_OPTIONS DS FL4 BLOB_XML_FILE_NAME DS CL255 | | | | | | CLOB_XML_FILE SQL TYPE IS XML AS CLOB_FILE CLOB_XML_FILE DS 0FL4 CLOB_XML_FILE_NAME_LENGTH DS FL4 CLOB_XML_FILE_DATA_LENGTH DS FL4 CLOB_XML_FILE_FILE_OPTIONS DS FL4 CLOB_XML_FILE_NAME DS CL255 | | | | | | DBCLOB_XML_FILE SQL TYPE IS XML AS DBCLOB_FILE DBCLOB_XML_FILE DS 0FL4 DBCLOB_XML_FILE_NAME_LENGTH DS FL4 DBCLOB_XML_FILE_DATA_LENGTH DS FL4 DBCLOB_XML_FILE_FILE_OPTIONS DS FL4 DBCLOB_XML_FILE_NAME DS CL255 Notes: 1. Because assembler language allows character declarations of no more than 65535 bytes, DB2 separates the host language declarations for XML AS BLOB and XML AS CLOB host variables that are longer than 65535 bytes into two parts. 2. Because assembler language allows graphic declarations of no more than 65534 bytes, DB2 separates the host language declarations for XML AS DBCLOB host variables that are longer than 65534 bytes into two parts. Declarations of XML host variables in C The following table shows C and C++ language declarations that are generated by the DB2 precompiler for some typical XML types. The declarations that the DB2 coprocessor generates might be different. Table 73. Examples of C language variable declarations You declare this variable DB2 generates this variable SQL TYPE IS XML AS BLOB (1M) blob_xml; struct { unsigned long length; char data??(1048576??); } blob_xml; SQL TYPE IS XML AS CLOB(40000K) clob_xml; struct { unsigned long length; char data??(40960000??); } clob_xml; SQL TYPE IS XML AS DBCLOB (4000K) dbclob_xml; struct { unsigned long length; unsigned short data??(4096000??); } dbclob_xml; Chapter 3. Including DB2 queries in an application program 321
  • 338.
    Table 73. Examplesof C language variable declarations (continued) You declare this variable DB2 generates this variable | SQL TYPE IS XML AS BLOB_FILE blob_xml_file; | | | | | | struct { unsigned long name_length; unsigned long data_length; unsigned long file_options; char name??(255??); } blob_xml_file; | SQL TYPE IS XML AS CLOB_FILE clob_xml_file; | | | | | | struct { unsigned long name_length; unsigned long data_length; unsigned long file_options; char name??(255??); } clob_xml_file; | SQL TYPE IS XML AS DBCLOB_FILE dbclob_xml_file; | | | | | | struct { unsigned long name_length; unsigned long data_length; unsigned long file_options; char name??(255??); } dbclob_xml_file; Declarations of XML host variables in COBOL The declarations that are generated for COBOL differ, depending on whether you use the DB2 precompiler or the DB2 coprocessor. The following table shows COBOL declarations that the DB2 precompiler generates for some typical XML types. Table 74. Examples of COBOL variable declarations by the DB2 precompiler You declare this variable DB2 precompiler generates this variable 01 BLOB-XML USAGE IS SQL TYPE IS XML AS BLOB(1M). 01 CLOB-XML USAGE IS SQL TYPE IS XML AS CLOB(40000K). 01 01 322 Application Programming and SQL Guide BLOB-XML. BLOB-XML-LENGTH PIC 9(9) COMP. 02 BLOB-XML-DATA. 49 FILLER PIC X(32767).1 49 FILLER PIC X(32767). Repeat 30 times . . . 49 FILLER PIC X(1048576-32*32767). 02 CLOB-XML. CLOB-XML-LENGTH PIC 9(9) COMP. 02 CLOB-XML-DATA. 49 FILLER PIC X(32767).1 49 FILLER PIC X(32767). Repeat 1248 times . . . 49 FILLER PIC X(40960000-1250*32767). 02
  • 339.
    Table 74. Examplesof COBOL variable declarations by the DB2 precompiler (continued) You declare this variable DB2 precompiler generates this variable 01 DBCLOB-XML USAGE IS SQL TYPE IS XML AS DBCLOB(4000K). 01 | | | | | 01 BLOB-XML-FILE USAGE IS SQL TYPE IS XML AS BLOB-FILE. 01 | | | | | 01 CLOB-XML-FILE USAGE IS SQL TYPE IS XML AS CLOB-FILE. 01 | | | | | 01 DBCLOB-XML-FILE USAGE IS SQL TYPE IS XML AS DBCLOB-FILE. 01 DBCLOB-XML. DBCLOB-XML-LENGTH PIC 9(9) COMP. 02 DBCLOB-XML-DATA. 49 FILLER PIC G(32767) USAGE DISPLAY-1.2 49 FILLER PIC G(32767) USAGE DISPLAY-1. Repeat 123 times . . . 49 FILLER PIC G(4096000-125*32767) USAGE DISPLAY-1. 02 49 49 49 49 BLOB-XML-FILE. BLOB-XML-FILE-NAME-LENGTH PIC S9(9) COMP-5 SYNC. BLOB-XML-FILE-DATA-LENGTH PIC S9(9) COMP-5. BLOB-XML-FILE-FILE-OPTION PIC S9(9) COMP-5. BLOB-XML-FILE-NAME PIC X(255). 49 49 49 49 CLOB-XML-FILE. CLOB-XML-FILE-NAME-LENGTH PIC S9(9) COMP-5 SYNC. CLOB-XML-FILE-DATA-LENGTH PIC S9(9) COMP-5. CLOB-XML-FILE-FILE-OPTION PIC S9(9) COMP-5. CLOB-XML-FILE-NAME PIC X(255). 49 49 49 49 DBCLOB-XML-FILE. DBCLOB-XML-FILE-NAME-LENGTH PIC S9(9) COMP-5 SYNC. DBCLOB-XML-FILE-DATA-LENGTH PIC S9(9) COMP-5. DBCLOB-XML-FILE-FILE-OPTION PIC S9(9) COMP-5. DBCLOB-XML-FILE-NAME PIC X(255). Notes: 1. For XML AS BLOB or XML AS CLOB host variables that are greater than 32767 bytes in length, DB2 creates multiple host language declarations of 32767 or fewer bytes. 2. For XML AS DBCLOB host variables that are greater than 32767 double-byte characters in length, DB2 creates multiple host language declarations of 32767 or fewer double-byte characters. Declarations of XML host variables in PL/I The declarations that are generated for PL/I differ, depending on whether you use the DB2 precompiler or the DB2 coprocessor. The following table shows PL/I declarations that the DB2 precompiler generates for some typical XML types. Table 75. Examples of PL/I variable declarations You declare this variable DB2 precompiler generates this variable DCL BLOB_XML SQL TYPE IS XML AS BLOB (1M); DCL 1 2 2 BLOB_XML, BLOB_XML_LENGTH BIN FIXED(31), BLOB_XML_DATA,1 3 BLOB_XML_DATA1 (32) CHAR(32767), 3 BLOB_XML_DATA2 CHAR(32); Chapter 3. Including DB2 queries in an application program 323
  • 340.
    Table 75. Examplesof PL/I variable declarations (continued) You declare this variable DB2 precompiler generates this variable DCL CLOB_XML SQL TYPE IS XML AS CLOB (40000K); DCL 1 2 2 DCL DBCLOB_XML SQL TYPE IS XML AS DBCLOB (4000K); CLOB_XML, CLOB_XML_LENGTH BIN FIXED(31), CLOB_XML_DATA,1 3 CLOB_XML_DATA1 (1250) CHAR(32767), 3 CLOB_XML_DATA2 CHAR(1250); DCL 1 2 2 | DCL BLOB_XML_FILE | SQL TYPE IS XML AS BLOB_FILE; | | | | DCL | DCL CLOB_XML_FILE SQL TYPE IS XML AS CLOB_FILE; | | | | | DCL | DCL DBCLOB_XML_FILE SQL TYPE IS XML AS DBCLOB_FILE; | | | | | DBCLOB_XML, DBCLOB_XML_LENGTH BIN FIXED(31), DBCLOB_XML_DATA,2 3 DBCLOB_XML_DATA1 (250 ) GRAPHIC(16383), 3 DBCLOB_XML_DATA2 GRAPHIC(250); DCL 1 2 2 2 2 BLOB_XML_FILE, BLOB_XML_FILE_NAME_LENGTH BIN FIXED(31) ALIGNED, BLOB_XML_FILE_DATA_LENGTH BIN FIXED(31), BLOB_XML_FILE_FILE_OPTIONS BIN FIXED(31), BLOB_XML_FILE_NAME CHAR(255); 2 2 2 2 CLOB_XML_FILE, CLOB_XML_FILE_NAME_LENGTH BIN FIXED(31) ALIGNED, CLOB_XML_FILE_DATA_LENGTH BIN FIXED(31), CLOB_XML_FILE_FILE_OPTIONS BIN FIXED(31), CLOB_XML_FILE_NAME CHAR(255); 2 2 2 2 DBCLOB_XML_FILE, DBCLOB_XML_FILE_NAME_LENGTH BIN FIXED(31) ALIGNED, DBCLOB_XML_FILE_DATA_LENGTH BIN FIXED(31), DBCLOB_XML_FILE_FILE_OPTIONS BIN FIXED(31), DBCLOB_XML_FILE_NAME CHAR(255); 1 1 Notes: | 1. For XML AS BLOB or XML AS CLOB host variables that are greater than 32767 bytes in length, DB2 creates host language declarations in the following way: | v If the length of the XML is greater than 32767 bytes and evenly divisible by 32767, DB2 creates an array of | 32767-byte strings. The dimension of the array is length/32767. | v If the length of the XML is greater than 32767 bytes but not evenly divisible by 32767, DB2 creates two | declarations: The first is an array of 32767 byte strings, where the dimension of the array, n, is length/32767. | The second is a character string of length length-n*32767. | | 2. For XML AS DBCLOB host variables that are greater than 16383 double-byte characters in length, DB2 creates host language declarations in the following way: | v If the length of the XML is greater than 16383 characters and evenly divisible by 16383, DB2 creates an array of | 16383-character strings. The dimension of the array is length/16383. | v If the length of the XML is greater than 16383 characters but not evenly divisible by 16383, DB2 creates two | declarations: The first is an array of 16383 byte strings, where the dimension of the array, m, is length/16383. | The second is a character string of length length-m*16383. | XML column updates in embedded SQL applications When you update or insert data into XML columns of a DB2 table, the input data must be in the serialized string format. The encoding of XML data can be derived from the data itself, which is known as internally encoded data, or from external sources, which is known as externally encoded data. XML data that is sent to the database server as binary data is treated 324 Application Programming and SQL Guide
  • 341.
    as internally encodeddata. XML data that is sent to the database server as character data is treated as externally encoded data. Externally encoded data can have internal encoding. That is, the data might be sent to the database server as character data, but the data contains encoding information. DB2 does not enforce consistency of the internal and external encoding. When the internal and external encoding information differs, the external encoding takes precedence. However, if there is a difference between the external and internal encoding, intervening character conversion might have occurred on the data, and there might be data loss. Character data in XML columns is stored in UTF-8 encoding. The database server handles conversion of the data from its internal or external encoding to UTF-8. The following examples demonstrate how to update XML columns in assembler, C, COBOL, and PL/I applications. The examples use a table named MYCUSTOMER, which is a copy of the sample CUSTOMER table. Example: The following example shows an assembler program that inserts data from XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML column. The XML AS BLOB data is inserted as binary data, so the database server honors the internal encoding. The XML AS CLOB and CLOB data is inserted as character data, so the database server honors the external encoding. ********************************************************************** * UPDATE AN XML COLUMN WITH DATA IN AN XML AS CLOB HOST VARIABLE * ********************************************************************** EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBUF WHERE CID = 1000 ********************************************************************** * UPDATE AN XML COLUMN WITH DATA IN AN XML AS BLOB HOST VARIABLE * ********************************************************************** EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBLOB WHERE CID = 1000 ********************************************************************** * UPDATE AN XML COLUMN WITH DATA IN A CLOB HOST VARIABLE. USE * * THE XMLPARSE FUNCTION TO CONVERT THE DATA TO THE XML TYPE. * ********************************************************************** EXEC SQL UPDATE MYCUSTOMER SET INFO = XMLPARSE(DOCUMENT :CLOBBUF) WHERE CID = 1000 ... LTORG ****************************** * HOST VARIABLE DECLARATIONS * ****************************** XMLBUF SQL TYPE IS XML AS CLOB 10K XMLBLOB SQL TYPE IS XML AS BLOB 10K CLOBBUF SQL TYPE IS CLOB 10K + + + + + + + + + Example: The following example shows a C language program that inserts data from XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML column. The XML AS BLOB data is inserted as binary data, so the database server honors the internal encoding. The XML AS CLOB and CLOB data is inserted as character data, so the database server honors the external encoding. Chapter 3. Including DB2 queries in an application program 325
  • 342.
    /******************************/ /* Host variabledeclarations */ /******************************/ EXEC SQL BEGIN DECLARE SECTION; SQL TYPE IS XML AS CLOB( 10K ) xmlBuf; SQL TYPE IS XML AS BLOB( 10K ) xmlblob; SQL TYPE IS CLOB( 10K ) clobBuf; EXEC SQL END DECLARE SECTION; /******************************************************************/ /* Update an XML column with data in an XML AS CLOB host variable */ /******************************************************************/ EXEC SQL UPDATE MYCUSTOMER SET INFO = :xmlBuf where CID = 1000; /******************************************************************/ /* Update an XML column with data in an XML AS BLOB host variable */ /******************************************************************/ EXEC SQL UPDATE MYCUSTOMER SET INFO = :xmlblob where CID = 1000; /******************************************************************/ /* Update an XML column with data in a CLOB host variable. Use */ /* the XMLPARSE function to convert the data to the XML type. */ /******************************************************************/ EXEC SQL UPDATE MYCUSTOMER SET INFO = XMLPARSE(DOCUMENT :clobBuf) where CID = 1000; Example: The following example shows a COBOL program that inserts data from XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML column. The XML AS BLOB data is inserted as binary data, so the database server honors the internal encoding. The XML AS CLOB and CLOB data is inserted as character data, so the database server honors the external encoding. ****************************** * Host variable declarations * ****************************** 01 XMLBUF USAGE IS SQL TYPE IS XML as CLOB(10K). 01 XMLBLOB USAGE IS SQL TYPE IS XML AS BLOB(10K). 01 CLOBBUF USAGE IS SQL TYPE IS CLOB(10K). ******************************************************************* * Update an XML column with data in an XML AS CLOB host variable * ******************************************************************* EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBUF where CID = 1000. ******************************************************************* * Update an XML column with data in an XML AS BLOB host variable * ******************************************************************* EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBLOB where CID = 1000. ******************************************************************* * Update an XML column with data in a CLOB host variable. Use * * the XMLPARSE function to convert the data to the XML type. * ******************************************************************* EXEC SQL UPDATE MYCUSTOMER SET INFO = XMLPARSE(DOCUMENT :CLOBBUF) where CID = 1000. Example: The following example shows a PL/I program that inserts data from XML AS BLOB, XML AS CLOB, and CLOB host variables into an XML column. The XML AS BLOB data is inserted as binary data, so the database server honors the internal encoding. The XML AS CLOB and CLOB data is inserted as character data, so the database server honors the external encoding. /******************************/ /* Host variable declarations */ /******************************/ DCL XMLBUF SQL TYPE IS XML AS CLOB(10K), XMLBLOB SQL TYPE IS XML AS BLOB(10K), CLOBBUF SQL TYPE IS CLOB(10K); /*******************************************************************/ /* Update an XML column with data in an XML AS CLOB host variable */ /*******************************************************************/ EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBUF where CID = 1000; /*******************************************************************/ 326 Application Programming and SQL Guide
  • 343.
    /* Update anXML column with data in an XML AS BLOB host variable */ /*******************************************************************/ EXEC SQL UPDATE MYCUSTOMER SET INFO = :XMLBLOB where CID = 1000; /*******************************************************************/ /* Update an XML column with data in a CLOB host variable. Use */ /* the XMLPARSE function to convert the data to the XML type. */ /*******************************************************************/ EXEC SQL UPDATE MYCUSTOMER SET INFO = XMLPARSE(DOCUMENT :CLOBBUF) where CID = 1000; XML data retrieval in embedded SQL applications In an embedded SQL application, if you retrieve the data into a character host variable, DB2 converts the data from UTF-8 encoding to the application encoding. If you retrieve the data into binary host variable, DB2 does not convert the data to another encoding. The output data is in the serialized string format. DB2 might add an XML encoding specification to the retrieved data, depending on whether you call the XMLSERIALIZE function when you retrieve the data. If you do not call the XMLSERIALIZE function, DB2 adds the correct XML encoding specification to the retrieved data. If you call the XMLSERIALIZE function, DB2 adds an internal XML encoding declaration for UTF-8 encoding if you specify INCLUDING XMLDECLARATION in the function call. When you use INCLUDING XMLDECLARATION, you need to ensure that the retrieved data is not converted from UTF-8 encoding to another encoding. The following examples demonstrate how to retrieve data from XML columns in assembler, C, COBOL, and PL/I applications. The examples use a table named MYCUSTOMER, which is a copy of the sample CUSTOMER table. Example: The following example shows an assembler program that retrieves data from an XML column into XML AS BLOB, XML AS CLOB, and CLOB host variables. The data that is retrieved into an XML AS BLOB host variable is retrieved as binary data, so the database server generates an XML declaration with UTF-8 encoding. The data that is retrieved into an XML AS CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration that is consistent with the external encoding. The data that is retrieved into a CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration. That declaration might not be consistent with the external encoding. ********************************************************************** * RETRIEVE XML COLUMN DATA INTO AN XML AS CLOB HOST VARIABLE * ********************************************************************** EXEC SQL SELECT INFO INTO :XMLBUF FROM MYCUSTOMER WHERE CID = 1000 ********************************************************************** * RETRIEVE XML COLUMN DATA INTO AN XML AS BLOB HOST VARIABLE * ********************************************************************** EXEC SQL SELECT INFO INTO :XMLBLOB FROM MYCUSTOMER WHERE CID = 1000 ********************************************************************** * RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE. * * BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE * * XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML * + + + + + + + + Chapter 3. Including DB2 queries in an application program 327
  • 344.
    * TYPE TOTHE CLOB TYPE. * ********************************************************************** EXEC SQL SELECT XMLSERIALIZE(INFO AS CLOB(10K)) INTO :CLOBBUF FROM MYCUSTOMER WHERE CID = 1000 ... LTORG ****************************** * HOST VARIABLE DECLARATIONS * ****************************** XMLBUF SQL TYPE IS XML AS CLOB 10K XMLBLOB SQL TYPE IS XML AS BLOB 10K CLOBBUF SQL TYPE IS CLOB 10K + + + + Example: The following example shows a C language program that retrieves data from an XML column into XML AS BLOB, XML AS CLOB, and CLOB host variables. The data that is retrieved into an XML AS BLOB host variable is retrieved as binary data, so the database server generates an XML declaration with UTF-8 encoding. The data that is retrieved into an XML AS CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration that is consistent with the external encoding. The data that is retrieved into a CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration. That declaration might not be consistent with the external encoding. /******************************/ /* Host variable declarations */ /******************************/ EXEC SQL BEGIN DECLARE SECTION; SQL TYPE IS XML AS CLOB( 10K ) xmlBuf; SQL TYPE IS XML AS BLOB( 10K ) xmlBlob; SQL TYPE IS CLOB( 10K ) clobBuf; EXEC SQL END DECLARE SECTION; /**********************************************************************/ /* Retrieve data from an XML column into an XML AS CLOB host variable */ /**********************************************************************/ EXEC SQL SELECT INFO INTO :xmlBuf from myTable where CID = 1000; /**********************************************************************/ /* Retrieve data from an XML column into an XML AS BLOB host variable */ /**********************************************************************/ EXEC SQL SELECT INFO INTO :xmlBlob from myTable where CID = 1000; /**********************************************************************/ /* RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE. */ /* BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE */ /* XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML */ /* TYPE TO THE CLOB TYPE. */ /**********************************************************************/ EXEC SQL SELECT XMLSERIALIZE(INFO AS CLOB(10K)) INTO :clobBuf from myTable where CID = 1000; Example: The following example shows a COBOL program that retrieves data from an XML column into XML AS BLOB, XML AS CLOB, and CLOB host variables. The data that is retrieved into an XML AS BLOB host variable is retrieved as binary data, so the database server generates an XML declaration with UTF-8 encoding. The data that is retrieved into an XML AS CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration that is consistent with the external encoding. The data that is retrieved into a CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration. That declaration might not be consistent with the external encoding. 328 Application Programming and SQL Guide
  • 345.
    ****************************** * Host variabledeclarations * ****************************** 01 XMLBUF USAGE IS SQL TYPE IS XML AS CLOB(10K). 01 XMLBLOB USAGE IS SQL TYPE IS XML AS BLOB(10K). 01 CLOBBUF USAGE IS SQL TYPE IS CLOB(10K). ********************************************************************** * Retrieve data from an XML column into an XML AS CLOB host variable * ********************************************************************** EXEC SQL SELECT INFO INTO :XMLBUF FROM MYTABLE WHERE CID = 1000. ********************************************************************** * Retrieve data from an XML column into an XML AS BLOB host variable * ********************************************************************** EXEC SQL SELECT INFO INTO :XMLBLOB FROM MYTABLE WHERE CID = 1000. ********************************************************************** * RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE. * * BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE * * XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML * * TYPE TO THE CLOB TYPE. * ********************************************************************** EXEC SQL SELECT XMLSERIALIZE(INFO AS CLOB(10K)) INTO :CLOBBUF FROM MYTABLE WHERE ID= 1000. Example: The following example shows a PL/I program that retrieves data from an XML column into XML AS BLOB, XML AS CLOB, and CLOB host variables. The data that is retrieved into an XML AS BLOB host variable is retrieved as binary data, so the database server generates an XML declaration with UTF-8 encoding. The data that is retrieved into an XML AS CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration that is consistent with the external encoding. The data that is retrieved into a CLOB host variable is retrieved as character data, so the database server generates an XML declaration with an internal encoding declaration. That declaration might not be consistent with the external encoding. /******************************/ /* Host variable declarations */ /******************************/ DCL XMLBUF SQL TYPE IS XML AS CLOB(10K), XMLBLOB SQL TYPE IS XML AS BLOB(10K), CLOBBUF SQL TYPE IS CLOB(10K); /**********************************************************************/ /* Retrieve data from an XML column into an XML AS CLOB host variable */ /**********************************************************************/ EXEC SQL SELECT INFO INTO :XMLBUF FROM MYTABLE WHERE CID = 1000; /**********************************************************************/ /* Retrieve data from an XML column into an XML AS BLOB host variable */ /**********************************************************************/ EXEC SQL SELECT INFO INTO :XMLBLOB FROM MYTABLE WHERE CID = 1000; /**********************************************************************/ /* RETRIEVE DATA FROM AN XML COLUMN INTO A CLOB HOST VARIABLE. */ /* BEFORE SENDING THE DATA TO THE APPLICATION, INVOKE THE */ /* XMLSERIALIZE FUNCTION TO CONVERT THE DATA FROM THE XML */ /* TYPE TO THE CLOB TYPE. */ /**********************************************************************/ EXEC SQL SELECT XMLSERIALIZE(INFO AS CLOB(10K)) INTO :CLOBBUF FROM MYTABLE WHERE CID = 1000; Object-oriented extensions in COBOL When you use object-oriented extensions in a COBOL application, you need to consider where to place SQL statements, the SQLCA, the SQLDA, and host variable declarations, and the rules for host variables. Chapter 3. Including DB2 queries in an application program 329
  • 346.
    Where to placeSQL statements in your application: A COBOL source data set or member can contain the following elements: v Multiple programs v Multiple class definitions, each of which contains multiple methods You can put SQL statements in only the first program or class in the source data set or member. However, you can put SQL statements in multiple methods within a class. If an application consists of multiple data sets or members, each of the data sets or members can contain SQL statements. Where to place the SQLCA, SQLDA, and host variable declarations: You can put the SQLCA, SQLDA, and SQL host variable declarations in the WORKING-STORAGE SECTION of a program, class, or method. An SQLCA or SQLDA in a class WORKING-STORAGE SECTION is global for all the methods of the class. An SQLCA or SQLDA in a method WORKING-STORAGE SECTION is local to that method only. If a class and a method within the class both contain an SQLCA or SQLDA, the method uses the SQLCA or SQLDA that is local. Rules for host variables: You can declare COBOL variables that are used as host variables in the WORKING-STORAGE SECTION or LINKAGE-SECTION of a program, class, or method. You can also declare host variables in the LOCAL-STORAGE SECTION of a method. The scope of a host variable is the method, class, or program within which it is defined. Cursors and statement names in REXX In REXX applications that contain SQL statements, you must use a predefined set of names for cursors or prepared statements. The following names are valid for cursors and prepared statements in REXX applications: c1 to c100 Cursor names for DECLARE CURSOR, OPEN, CLOSE, and FETCH statements. By default, c1 to c100 are defined with the WITH RETURN clause, and c51 to c100 are defined with the WITH HOLD clause. You can use the ATTRIBUTES clause of the PREPARE statement to override these attributes or add additional attributes. For example, you might want to add attributes to make your cursor scrollable. c101 to c200 Cursor names for ALLOCATE, DESCRIBE, FETCH, and CLOSE statements that are used to retrieve result sets in a program that calls a stored procedure. s1 to s100 Prepared statement names for DECLARE STATEMENT, PREPARE, DESCRIBE, and EXECUTE statements. Use only the predefined names for cursors and statements. When you associate a cursor name with a statement name in a DECLARE CURSOR statement, the cursor name and the statement must have the same number. For example, if you declare cursor c1, you need to declare it for statement s1: EXECSQL ’DECLARE C1 CURSOR FOR S1’ Do not use any of the predefined names as host variables names. 330 Application Programming and SQL Guide
  • 347.
    Programming examples You canwrite DB2 programs in assembler language, C, C++, COBOL, Fortran, PL/I or REXX. These programs can access a local or remote DB2 subsystem and can execute static or dynamic SQL statements. This information contains several such programming examples. To prepare and run these applications, use the JCL in DSN910.SDSNSAMP as a model for your JCL. For a list JCL procedures for preparing sample programs, see “DB2 sample applications” on page 1013. For information on the appropriate compiler options to use for each language, see the following topics in DB2 Installation Guide: v “Special considerations for COBOL programs” v “Special considerations for C and C++ programs” v “Special considerations for PL/I programs” Sample dynamic and static SQL in a C program Programs that access DB2 can contain static SQL, dynamic SQL, or both. This example shows a C program that contains both static and dynamic SQL. The following figure illustrates dynamic SQL and static SQL embedded in a C program. Each section of the program is identified with a comment. Section 1 of the program shows static SQL; sections 2, 3, and 4 show dynamic SQL. The function of each section is explained in detail in the prologue to the program. /**********************************************************************/ /* Descriptive name = Dynamic SQL sample using C language */ /* */ /* Function = To show examples of the use of dynamic and static */ /* SQL. */ /* */ /* Notes = This example assumes that the EMP and DEPT tables are */ /* defined. They need not be the same as the DB2 Sample */ /* tables. */ /* */ /* Module type = C program */ /* Processor = DB2 precompiler, C compiler */ /* Module size = see link edit */ /* Attributes = not reentrant or reusable */ /* */ /* Input = */ /* */ /* symbolic label/name = DEPT */ /* description = arbitrary table */ /* symbolic label/name = EMP */ /* description = arbitrary table */ /* */ /* Output = */ /* */ /* symbolic label/name = SYSPRINT */ /* description = print results via printf */ /* */ /* Exit-normal = return code 0 normal completion */ /* */ /* Exit-error = */ /* */ /* Return code = SQLCA */ /* */ /* Abend codes = none */ /* */ /* External references = none */ Chapter 3. Including DB2 queries in an application program 331
  • 348.
    /* /* /* /* */ */ */ */ Control-blocks = SQLCA - sql communicationarea /* Logic specification: */ /* */ /* There are four SQL sections. */ /* */ /* 1) STATIC SQL 1: using static cursor with a SELECT statement. */ /* Two output host variables. */ /* 2) Dynamic SQL 2: Fixed-list SELECT, using same SELECT statement */ /* used in SQL 1 to show the difference. The prepared string */ /* :iptstr can be assigned with other dynamic-able SQL statements. */ /* 3) Dynamic SQL 3: Insert with parameter markers. */ /* Using four parameter markers which represent four input host */ /* variables within a host structure. */ /* 4) Dynamic SQL 4: EXECUTE IMMEDIATE */ /* A GRANT statement is executed immediately by passing it to DB2 */ /* via a varying string host variable. The example shows how to */ /* set up the host variable before passing it. */ /* */ /**********************************************************************/ #include "stdio.h" #include "stdefs.h" EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE SQLDA; EXEC SQL BEGIN DECLARE SECTION; short edlevel; struct { short len; char x1[56]; } stmtbf1, stmtbf2, inpstr; struct { short len; char x1[15]; } lname; short hv1; struct { char deptno[4]; struct { short len; char x[36]; } deptname; char mgrno[7]; char admrdept[4]; } hv2; short ind[4]; EXEC SQL END DECLARE SECTION; EXEC SQL DECLARE EMP TABLE (EMPNO CHAR(6) FIRSTNAME VARCHAR(12) MIDINIT CHAR(1) LASTNAME VARCHAR(15) WORKDEPT CHAR(3) PHONENO CHAR(4) HIREDATE DECIMAL(6) JOBCODE DECIMAL(3) EDLEVEL SMALLINT SEX CHAR(1) BIRTHDATE DECIMAL(6) SALARY DECIMAL(8,2) FORFNAME VARGRAPHIC(12) FORMNAME GRAPHIC(1) FORLNAME VARGRAPHIC(15) FORADDR VARGRAPHIC(256) ) EXEC SQL DECLARE DEPT TABLE ( DEPTNO DEPTNAME 332 Application Programming and SQL Guide CHAR(3) VARCHAR(36) , , , , , , , , , , , , , , , ; , ,
  • 349.
    MGRNO ADMRDEPT CHAR(6) CHAR(3) , ); main () { printf("??/n*** begin ofprogram ***"); EXEC SQL WHENEVER SQLERROR GO TO HANDLERR; EXEC SQL WHENEVER SQLWARNING GO TO HANDWARN; EXEC SQL WHENEVER NOT FOUND GO TO NOTFOUND; /******************************************************************/ /* Assign values to host variables which will be input to DB2 */ /******************************************************************/ strcpy(hv2.deptno,"M92"); strcpy(hv2.deptname.x,"DDL"); hv2.deptname.len = strlen(hv2.deptname.x); strcpy(hv2.mgrno,"123456"); strcpy(hv2.admrdept,"abc"); /******************************************************************/ /* Static SQL 1: DECLARE CURSOR, OPEN, FETCH, CLOSE */ /* Select into :edlevel, :lname */ /******************************************************************/ printf("??/n*** begin declare ***"); EXEC SQL DECLARE C1 CURSOR FOR SELECT EDLEVEL, LASTNAME FROM EMP WHERE EMPNO = ’000010’; printf("??/n*** begin open ***"); EXEC SQL OPEN C1; printf("??/n*** begin fetch EXEC SQL FETCH C1 INTO :edlevel, :lname; printf("??/n*** returned values printf("??/n??/nedlevel = printf("??/nlname = ***"); ***"); printf("??/n*** begin close ***"); EXEC SQL CLOSE C1; /******************************************************************/ /* Dynamic SQL 2: PREPARE, DECLARE CURSOR, OPEN, FETCH, CLOSE */ /* Select into :edlevel, :lname */ /******************************************************************/ sprintf (inpstr.x1, "SELECT EDLEVEL, LASTNAME FROM EMP WHERE EMPNO = ’000010’"); inpstr.len = strlen(inpstr.x1); printf("??/n*** begin prepare ***"); EXEC SQL PREPARE STAT1 FROM :inpstr; printf("??/n*** begin declare ***"); EXEC SQL DECLARE C2 CURSOR FOR STAT1; printf("??/n*** begin open ***"); EXEC SQL OPEN C2; printf("??/n*** begin fetch EXEC SQL FETCH C2 INTO :edlevel, :lname; printf("??/n*** returned values printf("??/n??/nedlevel = printf("??/nlname = ***"); ***"); printf("??/n*** begin close ***"); EXEC SQL CLOSE C2; /******************************************************************/ /* Dynamic SQL 3: PREPARE with parameter markers */ /* Insert into with four values. */ /******************************************************************/ sprintf (stmtbf1.x1, "INSERT INTO DEPT VALUES (?,?,?,?)"); stmtbf1.len = strlen(stmtbf1.x1); printf("??/n*** begin prepare ***"); EXEC SQL PREPARE s1 FROM :stmtbf1; printf("??/n*** begin execute ***"); EXEC SQL EXECUTE s1 USING :hv2:ind; Chapter 3. Including DB2 queries in an application program 333
  • 350.
    printf("??/n*** following are expectedinsert results ***"); printf("??/n hv2.deptno = printf("??/n hv2.deptname.len = printf("??/n hv2.deptname.x = printf("??/n hv2.mgrno = printf("??/n hv2.admrdept = EXEC SQL COMMIT; /******************************************************************/ /* Dynamic SQL 4: EXECUTE IMMEDIATE */ /* Grant select */ /******************************************************************/ sprintf (stmtbf2.x1, "GRANT SELECT ON EMP TO USERX"); stmtbf2.len = strlen(stmtbf2.x1); printf("??/n*** begin execute immediate ***"); EXEC SQL EXECUTE IMMEDIATE :stmtbf2; printf("??/n*** end of program ***"); goto progend; HANDWARN: HANDLERR: NOTFOUND: ; printf("??/n SQLCODE = printf("??/n SQLWARN0 = printf("??/n SQLWARN1 = printf("??/n SQLWARN2 = printf("??/n SQLWARN3 = printf("??/n SQLWARN4 = printf("??/n SQLWARN5 = printf("??/n SQLWARN6 = printf("??/n SQLWARN7 = progend: ; } Sample COBOL dynamic SQL program This example shows how to code dynamic varying-list SELECT statements in a COBOL program. Varying-List SELECT statements are statements for which you do not know the number of columns returned and their data types when you write the program. “Dynamic SQL” on page 258 describes three variations of dynamic SQL statements: v Non-SELECT statements v Fixed-List SELECT statements In this case, you know the number of columns returned and their data types when you write the program. v Varying-List SELECT statements. In this case, you do not know the number of columns returned and their data types when you write the program. This section documents a technique of coding varying list SELECT statements in COBOL. For a list of the supported versions of COBOL, see DB2 Program Directory . This example program does not support BLOB, CLOB, or DBCLOB data types. Pointers and based variables in the sample COBOL program COBOL has a POINTER type and a SET statement that provide pointers and based variables. The SET statement sets a pointer from the address of an area in the linkage section or another pointer; the statement can also set the address of an area in the linkage 334 Application Programming and SQL Guide
  • 351.
    section. DSN8BCU2 in“Example of the sample COBOL program” provides these uses of the SET statement. The SET statement does not permit the use of an address in the WORKING-STORAGE section. Storage allocation for the sample COBOL program COBOL does not provide a means to allocate main storage within a program. You can achieve the same end by having an initial program which allocates the storage, and then calls a second program that manipulates the pointer. (COBOL does not permit you to directly manipulate the pointer because errors and abends are likely to occur.) The initial program is extremely simple. It includes a working storage section that allocates the maximum amount of storage needed. This program then calls the second program, passing the area or areas on the CALL statement. The second program defines the area in the linkage section and can then use pointers within the area. If you need to allocate parts of storage, the best method is to use indexes or subscripts. You can use subscripts for arithmetic and comparison operations. Example of the sample COBOL program The following example shows an example of the initial program DSN8BCU1 that allocates the storage and calls the second program DSN8BCU2. DSN8BCU2 then defines the passed storage areas in its linkage section and includes the USING clause on its PROCEDURE DIVISION statement. Defining the pointers, then redefining them as numeric, permits some manipulation of the pointers that you cannot perform directly. For example, you cannot add the column length to the record pointer, but you can add the column length to the numeric value that redefines the pointer. The following example is the initial program that allocates storage. **** DSN8BCU1- DB2 SAMPLE BATCH COBOL UNLOAD PROGRAM *********** * * * MODULE NAME = DSN8BCU1 * * * * DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION * * UNLOAD PROGRAM * * BATCH * * ENTERPRISE COBOL FOR Z/OS * * * * FUNCTION = THIS MODULE PROVIDES THE STORAGE NEEDED BY * * DSN8BCU2 AND CALLS THAT PROGRAM. * * * * NOTES = * * DEPENDENCIES = NONE. * * * * RESTRICTIONS = * * THE MAXIMUM NUMBER OF COLUMNS IS 750, * * WHICH IS THE SQL LIMIT. * * * * DATA RECORDS ARE LIMITED TO 32700 BYTES, * * INCLUDING DATA, LENGTHS FOR VARCHAR DATA, * * AND SPACE FOR NULL INDICATORS. * * * * MODULE TYPE = COBOL PROGRAM * * PROCESSOR = ENTERPRISE COBOL FOR Z/OS * * * Chapter 3. Including DB2 queries in an application program 335
  • 352.
    * * * MODULE SIZE =SEE LINK EDIT ATTRIBUTES = REENTRANT * * * * ENTRY POINT = DSN8BCU1 * * PURPOSE = SEE FUNCTION * * LINKAGE = INVOKED FROM DSN RUN * * INPUT = NONE * * OUTPUT = NONE * * * * EXIT-NORMAL = RETURN CODE 0 NORMAL COMPLETION * * * * EXIT-ERROR = * * RETURN CODE = NONE * * ABEND CODES = NONE * * ERROR-MESSAGES = NONE * * * * EXTERNAL REFERENCES = * * ROUTINES/SERVICES = * * DSN8BCU2 - ACTUAL UNLOAD PROGRAM * * * * DATA-AREAS = NONE * * CONTROL-BLOCKS = NONE * * * * TABLES = NONE * * CHANGE-ACTIVITY = NONE * * * * *PSEUDOCODE* * * * * PROCEDURE * * CALL DSN8BCU2. * * END. * *---------------------------------------------------------------* / IDENTIFICATION DIVISION. *----------------------PROGRAM-ID. DSN8BCU1 * ENVIRONMENT DIVISION. * CONFIGURATION SECTION. DATA DIVISION. * WORKING-STORAGE SECTION. * 01 WORKAREA-IND. 02 WORKIND PIC S9(4) COMP OCCURS 750 TIMES. 01 RECWORK. 02 RECWORK-LEN PIC S9(8) COMP VALUE 32700. 02 RECWORK-CHAR PIC X(1) OCCURS 32700 TIMES. * PROCEDURE DIVISION. * CALL ’DSN8BCU2’ USING WORKAREA-IND RECWORK. GOBACK. The following example is the called program that does pointer manipulation. **** DSN8BCU2- DB2 SAMPLE BATCH COBOL UNLOAD PROGRAM * * MODULE NAME = DSN8BCU2 * * DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION * UNLOAD PROGRAM * BATCH * ENTERPRISE COBOL FOR Z/OS * * 336 Application Programming and SQL Guide *********** * * * * * * * * *
  • 353.
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * FUNCTION = THISMODULE ACCEPTS A TABLE NAME OR VIEW NAME AND UNLOADS THE DATA IN THAT TABLE OR VIEW. READ IN A TABLE NAME FROM SYSIN. PUT DATA FROM THE TABLE INTO DD SYSREC01. WRITE RESULTS TO SYSPRINT. NOTES = DEPENDENCIES = NONE. RESTRICTIONS = THE SQLDA IS LIMITED TO 33016 BYTES. THIS SIZE ALLOWS FOR THE DB2 MAXIMUM OF 750 COLUMNS. DATA RECORDS ARE LIMITED TO 32700 BYTES, INCLUDING DATA, LENGTHS FOR VARCHAR DATA, AND SPACE FOR NULL INDICATORS. TABLE OR VIEW NAMES ARE ACCEPTED, AND ONLY ONE NAME IS ALLOWED PER RUN. MODULE TYPE = COBOL PROGRAM PROCESSOR = DB2 PRECOMPILER * * * * * * * * * * * * * * * * * * * * * * * * * * * * ENTRY POINT = DSN8BCU2 * PURPOSE = SEE FUNCTION * LINKAGE = * CALL ’DSN8BCU2’ USING WORKAREA-IND RECWORK. * * INPUT = SYMBOLIC LABEL/NAME = WORKAREA-IND * DESCRIPTION = INDICATOR VARIABLE ARRAY * 01 WORKAREA-IND. * 02 WORKIND PIC S9(4) COMP OCCURS 750 TIMES. * * SYMBOLIC LABEL/NAME = RECWORK * DESCRIPTION = WORK AREA FOR OUTPUT RECORD * 01 RECWORK. * 02 RECWORK-LEN PIC S9(8) COMP. * * SYMBOLIC LABEL/NAME = SYSIN * DESCRIPTION = INPUT REQUESTS - TABLE OR VIEW * * MODULE SIZE = SEE LINK EDIT ATTRIBUTES = REENTRANT OUTPUT = SYMBOLIC LABEL/NAME = SYSPRINT DESCRIPTION = PRINTED RESULTS * * * SYMBOLIC LABEL/NAME = SYSREC01 * DESCRIPTION = UNLOADED TABLE DATA * * EXIT-NORMAL = RETURN CODE 0 NORMAL COMPLETION * EXIT-ERROR = * RETURN CODE = NONE * ABEND CODES = NONE * ERROR-MESSAGES = * DSNT490I SAMPLE COBOL DATA UNLOAD PROGRAM RELEASE 3.0* - THIS IS THE HEADER, INDICATING A NORMAL * - START FOR THIS PROGRAM. * DSNT493I SQL ERROR, SQLCODE = NNNNNNNN * - AN SQL ERROR OR WARNING WAS ENCOUNTERED * - ADDITIONAL INFORMATION FROM DSNTIAR * - FOLLOWS THIS MESSAGE. * DSNT495I SUCCESSFUL UNLOAD XXXXXXXX ROWS OF * TABLE TTTTTTTT * - THE UNLOAD WAS SUCCESSFUL. XXXXXXXX IS * Chapter 3. Including DB2 queries in an application program 337
  • 354.
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - THE NUMBEROF ROWS UNLOADED. TTTTTTTT - IS THE NAME OF THE TABLE OR VIEW FROM - WHICH IT WAS UNLOADED. DSNT496I UNRECOGNIZED DATA TYPE CODE OF NNNNN - THE PREPARE RETURNED AN INVALID DATA - TYPE CODE. NNNNN IS THE CODE, PRINTED - IN DECIMAL. USUALLY AN ERROR IN - THIS ROUTINE OR A NEW DATA TYPE. DSNT497I RETURN CODE FROM MESSAGE ROUTINE DSNTIAR - THE MESSAGE FORMATTING ROUTINE DETECTED - AN ERROR. SEE THAT ROUTINE FOR RETURN - CODE INFORMATION. USUALLY AN ERROR IN - THIS ROUTINE. DSNT498I ERROR, NO VALID COLUMNS FOUND - THE PREPARE RETURNED DATA WHICH DID NOT - PRODUCE A VALID OUTPUT RECORD. - USUALLY AN ERROR IN THIS ROUTINE. DSNT499I NO ROWS FOUND IN TABLE OR VIEW - THE CHOSEN TABLE OR VIEWS DID NOT - RETURN ANY ROWS. ERROR MESSAGES FROM MODULE DSNTIAR - WHEN AN ERROR OCCURS, THIS MODULE - PRODUCES CORRESPONDING MESSAGES. EXTERNAL REFERENCES = ROUTINES/SERVICES = DSNTIAR - TRANSLATE SQLCA INTO MESSAGES DATA-AREAS = NONE CONTROL-BLOCKS = SQLCA - SQL COMMUNICATION AREA TABLES = NONE CHANGE-ACTIVITY = NONE * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *PSEUDOCODE* * * PROCEDURE * * EXEC SQL DECLARE DT CURSOR FOR SEL END-EXEC. * * EXEC SQL DECLARE SEL STATEMENT END-EXEC. * * INITIALIZE THE DATA, OPEN FILES. * * OBTAIN STORAGE FOR THE SQLDA AND THE DATA RECORDS. * * READ A TABLE NAME. * * OPEN SYSREC01. * * BUILD THE SQL STATEMENT TO BE EXECUTED * * EXEC SQL PREPARE SQL STATEMENT INTO SQLDA END-EXEC. * * SET UP ADDRESSES IN THE SQLDA FOR DATA. * * INITIALIZE DATA RECORD COUNTER TO 0. * * EXEC SQL OPEN DT END-EXEC. * * DO WHILE SQLCODE IS 0. * * EXEC SQL FETCH DT USING DESCRIPTOR SQLDA END-EXEC. * * ADD IN MARKERS TO DENOTE NULLS. * * WRITE THE DATA TO SYSREC01. * * INCREMENT DATA RECORD COUNTER. * * END. * * EXEC SQL CLOSE DT END-EXEC. * * INDICATE THE RESULTS OF THE UNLOAD OPERATION. * * CLOSE THE SYSIN, SYSPRINT, AND SYSREC01 FILES. * * END. * *---------------------------------------------------------------* / IDENTIFICATION DIVISION. *----------------------PROGRAM-ID. DSN8BCU2 * ENVIRONMENT DIVISION. *-------------------CONFIGURATION SECTION. INPUT-OUTPUT SECTION. 338 Application Programming and SQL Guide
  • 355.
    FILE-CONTROL. SELECT SYSIN ASSIGN TODA-S-SYSIN. SELECT SYSPRINT ASSIGN TO UT-S-SYSPRINT. SELECT SYSREC01 ASSIGN TO DA-S-SYSREC01. * DATA DIVISION. *------------* FILE SECTION. FD SYSIN RECORD CONTAINS 80 CHARACTERS BLOCK CONTAINS 0 RECORDS LABEL RECORDS ARE OMITTED RECORDING MODE IS F. 01 CARDREC PIC X(80). * FD SYSPRINT RECORD CONTAINS 120 CHARACTERS LABEL RECORDS ARE OMITTED DATA RECORD IS MSGREC RECORDING MODE IS F. 01 MSGREC PIC X(120). * FD 01 SYSREC01 RECORD CONTAINS 5 TO 32704 CHARACTERS LABEL RECORDS ARE OMITTED DATA RECORD IS REC01 RECORDING MODE IS V. REC01. 02 REC01-LEN PIC S9(8) COMP. 02 REC01-CHAR PIC X(1) OCCURS 1 TO 32700 TIMES DEPENDING ON REC01-LEN. / WORKING-STORAGE SECTION. * ***************************************************** * STRUCTURE FOR INPUT * ***************************************************** 01 IOAREA. 02 TNAME PIC X(72). 02 FILLER PIC X(08). 01 STMTBUF. 49 STMTLEN PIC S9(4) COMP VALUE 92. 49 STMTCHAR PIC X(92). 01 STMTBLD. 02 FILLER PIC X(20) VALUE ’SELECT * FROM’. 02 STMTTAB PIC X(72). * ***************************************************** * REPORT HEADER STRUCTURE * ***************************************************** 01 HEADER. 02 FILLER PIC X(35) VALUE ’ DSNT490I SAMPLE COBOL DATA UNLOAD ’. 02 FILLER PIC X(85) VALUE ’PROGRAM RELEASE 3.0’. 01 MSG-SQLERR. 02 FILLER PIC X(31) VALUE ’ DSNT493I SQL ERROR, SQLCODE = ’. 02 MSG-MINUS PIC X(1). 02 MSG-PRINT-CODE PIC 9(8). 02 FILLER PIC X(81) VALUE ’ ’. 01 UNLOADED. 02 FILLER PIC X(28) VALUE ’ DSNT495I SUCCESSFUL UNLOAD ’. Chapter 3. Including DB2 queries in an application program 339
  • 356.
    01 01 02 ROWS PIC 9(8). 02FILLER PIC X(15) VALUE ’ ROWS OF TABLE ’. 02 TABLENAM PIC X(72) VALUE ’ ’. BADTYPE. 02 FILLER PIC X(42) VALUE ’ DSNT496I UNRECOGNIZED DATA TYPE CODE OF ’. 02 TYPCOD PIC 9(8). 02 FILLER PIC X(71) VALUE ’ ’. MSGRETCD. 02 FILLER PIC X(42) VALUE ’ DSNT497I RETURN CODE FROM MESSAGE ROUTINE’. 02 FILLER PIC X(9) VALUE ’DSNTIAR ’. 02 RETCODE PIC 9(8). 02 FILLER PIC X(62) VALUE ’ ’. 01 MSGNOCOL. 02 FILLER PIC X(120) VALUE ’ DSNT498I ERROR, NO VALID COLUMNS FOUND’. 01 MSG-NOROW. 02 FILLER PIC X(120) VALUE ’ DSNT499I NO ROWS FOUND IN TABLE OR VIEW’. ***************************************************** * WORKAREAS * ***************************************************** 77 NOT-FOUND PIC S9(8) COMP VALUE +100. ***************************************************** * VARIABLES FOR ERROR-MESSAGE FORMATTING * 00 ***************************************************** 01 ERROR-MESSAGE. 02 ERROR-LEN PIC S9(4) COMP VALUE +960. 02 ERROR-TEXT PIC X(120) OCCURS 8 TIMES INDEXED BY ERROR-INDEX. 77 ERROR-TEXT-LEN PIC S9(8) COMP VALUE +120. ***************************************************** * SQL DESCRIPTOR AREA * ***************************************************** EXEC SQL INCLUDE SQLDA END-EXEC. * * DATA TYPES FOUND IN SQLTYPE, AFTER REMOVING THE NULL BIT * 77 VARCTYPE PIC S9(4) COMP VALUE +448. 77 CHARTYPE PIC S9(4) COMP VALUE +452. 77 VARLTYPE PIC S9(4) COMP VALUE +456. 77 VARGTYPE PIC S9(4) COMP VALUE +464. 77 GTYPE PIC S9(4) COMP VALUE +468. 77 LVARGTYP PIC S9(4) COMP VALUE +472. 77 FLOATYPE PIC S9(4) COMP VALUE +480. 77 DECTYPE PIC S9(4) COMP VALUE +484. 77 INTTYPE PIC S9(4) COMP VALUE +496. 77 HWTYPE PIC S9(4) COMP VALUE +500. 77 DATETYP PIC S9(4) COMP VALUE +384. 77 TIMETYP PIC S9(4) COMP VALUE +388. 77 TIMESTMP PIC S9(4) COMP VALUE +392. * ***************************************************** * THE REDEFINES CLAUSES BELOW ARE FOR 31-BIT ADDRESSING. * IF YOUR COMPILER SUPPORTS ONLY 24-BIT ADDRESSING, * CHANGE THE DECLARATIONS TO THESE: * 01 RECNUM REDEFINES RECPTR PICTURE S9(8) COMPUTATIONAL. * 01 IRECNUM REDEFINES IRECPTR PICTURE S9(8) COMPUTATIONAL. ***************************************************** 01 RECPTR POINTER. 01 RECNUM REDEFINES RECPTR PICTURE S9(9) COMPUTATIONAL. 01 IRECPTR POINTER. 01 IRECNUM REDEFINES IRECPTR PICTURE S9(9) COMPUTATIONAL. 01 I PICTURE S9(4) COMPUTATIONAL. 340 Application Programming and SQL Guide
  • 357.
    01 01 01 01 01 01 01 01 01 01 J PICTURE S9(4) COMPUTATIONAL. DUMMYPICTURE S9(4) COMPUTATIONAL. MYTYPE PICTURE S9(4) COMPUTATIONAL. COLUMN-IND PICTURE S9(4) COMPUTATIONAL. COLUMN-LEN PICTURE S9(4) COMPUTATIONAL. COLUMN-PREC PICTURE S9(4) COMPUTATIONAL. COLUMN-SCALE PICTURE S9(4) COMPUTATIONAL. INDCOUNT PIC S9(4) COMPUTATIONAL. ROWCOUNT PIC S9(4) COMPUTATIONAL. WORKAREA2. 02 WORKINDPTR POINTER OCCURS 750 TIMES. ***************************************************** * DECLARE CURSOR AND STATEMENT FOR DYNAMIC SQL ***************************************************** * EXEC SQL DECLARE DT CURSOR FOR SEL END-EXEC. EXEC SQL DECLARE SEL STATEMENT END-EXEC. * ***************************************************** * SQL INCLUDE FOR SQLCA * ***************************************************** EXEC SQL INCLUDE SQLCA END-EXEC. * 77 ONE PIC S9(4) COMP VALUE +1. 77 TWO PIC S9(4) COMP VALUE +2. 77 FOUR PIC S9(4) COMP VALUE +4. 77 QMARK PIC X(1) VALUE ’?’. * LINKAGE SECTION. 01 LINKAREA-IND. 02 IND PIC S9(4) COMP OCCURS 750 TIMES. 01 LINKAREA-REC. 02 REC1-LEN PIC S9(8) COMP. 02 REC1-CHAR PIC X(1) OCCURS 1 TO 32700 TIMES DEPENDING ON REC1-LEN. 01 LINKAREA-QMARK. 02 INDREC PIC X(1). / PROCEDURE DIVISION USING LINKAREA-IND LINKAREA-REC. * ***************************************************** * SQL RETURN CODE HANDLING * ***************************************************** EXEC SQL WHENEVER SQLERROR GOTO DBERROR END-EXEC. EXEC SQL WHENEVER SQLWARNING GOTO DBERROR END-EXEC. EXEC SQL WHENEVER NOT FOUND CONTINUE END-EXEC. * ***************************************************** * MAIN PROGRAM ROUTINE * ***************************************************** SET IRECPTR TO ADDRESS OF REC1-CHAR(1). * **OPEN FILES OPEN INPUT SYSIN OUTPUT SYSPRINT OUTPUT SYSREC01. * **WRITE HEADER WRITE MSGREC FROM HEADER AFTER ADVANCING 2 LINES. * **GET FIRST INPUT READ SYSIN RECORD INTO IOAREA. * **MAIN ROUTINE PERFORM PROCESS-INPUT THROUGH IND-RESULT. * PROG-END. * **CLOSE FILES CLOSE SYSIN SYSPRINT Chapter 3. Including DB2 queries in an application program 341
  • 358.
    SYSREC01. GOBACK. / *************************************************************** * * * PERFORMED SECTION: * * PROCESSING FORTHE TABLE OR VIEW JUST READ * * * *************************************************************** PROCESS-INPUT. * MOVE TNAME TO STMTTAB. MOVE STMTBLD TO STMTCHAR. EXEC SQL PREPARE SEL INTO :SQLDA FROM :STMTBUF END-EXEC. *************************************************************** * * * SET UP ADDRESSES IN THE SQLDA FOR DATA. * * * *************************************************************** IF SQLD = ZERO THEN WRITE MSGREC FROM MSGNOCOL AFTER ADVANCING 2 LINES GO TO IND-RESULT. MOVE ZERO TO ROWCOUNT. MOVE ZERO TO REC1-LEN. SET RECPTR TO IRECPTR. MOVE ONE TO I. PERFORM COLADDR UNTIL I > SQLD. **************************************************************** * * * SET LENGTH OF OUTPUT RECORD. * * EXEC SQL OPEN DT END-EXEC. * * DO WHILE SQLCODE IS 0. * * EXEC SQL FETCH DT USING DESCRIPTOR :SQLDA END-EXEC. * * ADD IN MARKERS TO DENOTE NULLS. * * WRITE THE DATA TO SYSREC01. * * INCREMENT DATA RECORD COUNTER. * * END. * * * **************************************************************** * **OPEN CURSOR EXEC SQL OPEN DT END-EXEC. PERFORM BLANK-REC. EXEC SQL FETCH DT USING DESCRIPTOR :SQLDA END-EXEC. * **NO ROWS FOUND * **PRINT ERROR MESSAGE IF SQLCODE = NOT-FOUND WRITE MSGREC FROM MSG-NOROW AFTER ADVANCING 2 LINES ELSE * **WRITE ROW AND * **CONTINUE UNTIL * **NO MORE ROWS PERFORM WRITE-AND-FETCH UNTIL SQLCODE IS NOT EQUAL TO ZERO. * EXEC SQL WHENEVER NOT FOUND GOTO CLOSEDT END-EXEC. * CLOSEDT. EXEC SQL CLOSE DT END-EXEC. * **************************************************************** * * * INDICATE THE RESULTS OF THE UNLOAD OPERATION. * * * **************************************************************** IND-RESULT. 342 Application Programming and SQL Guide
  • 359.
    MOVE TNAME TOTABLENAM. MOVE ROWCOUNT TO ROWS. WRITE MSGREC FROM UNLOADED AFTER ADVANCING 2 LINES. GO TO PROG-END. * WRITE-AND-FETCH. * ADD IN MARKERS TO DENOTE NULLS. MOVE ONE TO INDCOUNT. PERFORM NULLCHK UNTIL INDCOUNT = SQLD. MOVE REC1-LEN TO REC01-LEN. WRITE REC01 FROM LINKAREA-REC. ADD ONE TO ROWCOUNT. PERFORM BLANK-REC. EXEC SQL FETCH DT USING DESCRIPTOR :SQLDA END-EXEC. * NULLCHK. IF IND(INDCOUNT) < 0 THEN SET ADDRESS OF LINKAREA-QMARK TO WORKINDPTR(INDCOUNT) MOVE QMARK TO INDREC. ADD ONE TO INDCOUNT. ***************************************************** * BLANK OUT RECORD TEXT FIRST * ***************************************************** BLANK-REC. MOVE ONE TO J. PERFORM BLANK-MORE UNTIL J > REC1-LEN. BLANK-MORE. MOVE ’ ’ TO REC1-CHAR(J). ADD ONE TO J. * COLADDR. SET SQLDATA(I) TO RECPTR. **************************************************************** * * DETERMINE THE LENGTH OF THIS COLUMN (COLUMN-LEN) * THIS DEPENDS ON THE DATA TYPE. MOST DATA TYPES HAVE * THE LENGTH SET, BUT VARCHAR, GRAPHIC, VARGRAPHIC, AND * DECIMAL DATA NEED TO HAVE THE BYTES CALCULATED. * THE NULL ATTRIBUTE MUST BE SEPARATED TO SIMPLIFY MATTERS. * **************************************************************** MOVE SQLLEN(I) TO COLUMN-LEN. * COLUMN-IND IS 0 FOR NO NULLS AND 1 FOR NULLS DIVIDE SQLTYPE(I) BY TWO GIVING DUMMY REMAINDER COLUMN-IND. * MYTYPE IS JUST THE SQLTYPE WITHOUT THE NULL BIT MOVE SQLTYPE(I) TO MYTYPE. SUBTRACT COLUMN-IND FROM MYTYPE. * SET THE COLUMN LENGTH, DEPENDENT ON DATA TYPE EVALUATE MYTYPE WHEN CHARTYPE CONTINUE, WHEN DATETYP CONTINUE, WHEN TIMETYP CONTINUE, WHEN TIMESTMP CONTINUE, WHEN FLOATYPE CONTINUE, WHEN VARCTYPE ADD TWO TO COLUMN-LEN, WHEN VARLTYPE ADD TWO TO COLUMN-LEN, WHEN GTYPE MULTIPLY COLUMN-LEN BY TWO GIVING COLUMN-LEN, WHEN VARGTYPE PERFORM CALC-VARG-LEN, WHEN LVARGTYP PERFORM CALC-VARG-LEN, WHEN HWTYPE MOVE TWO TO COLUMN-LEN, Chapter 3. Including DB2 queries in an application program 343
  • 360.
    WHEN INTTYPE MOVE FOUR TOCOLUMN-LEN, WHEN DECTYPE PERFORM CALC-DECIMAL-LEN, WHEN OTHER PERFORM UNRECOGNIZED-ERROR, END-EVALUATE. ADD COLUMN-LEN TO RECNUM. ADD COLUMN-LEN TO REC1-LEN. **************************************************************** * * * IF THIS COLUMN CAN BE NULL, AN INDICATOR VARIABLE IS * * NEEDED. WE ALSO RESERVE SPACE IN THE OUTPUT RECORD TO * * NOTE THAT THE VALUE IS NULL. * * * **************************************************************** MOVE ZERO TO IND(I). IF COLUMN-IND = ONE THEN SET SQLIND(I) TO ADDRESS OF IND(I) SET WORKINDPTR(I) TO RECPTR ADD ONE TO RECNUM ADD ONE TO REC1-LEN. * ADD ONE TO I. * PERFORMED PARAGRAPH TO CALCULATE COLUMN LENGTH * FOR A DECIMAL DATA TYPE COLUMN CALC-DECIMAL-LEN. DIVIDE COLUMN-LEN BY 256 GIVING COLUMN-PREC REMAINDER COLUMN-SCALE. MOVE COLUMN-PREC TO COLUMN-LEN. ADD ONE TO COLUMN-LEN. DIVIDE COLUMN-LEN BY TWO GIVING COLUMN-LEN. * PERFORMED PARAGRAPH TO CALCULATE COLUMN LENGTH * FOR A VARGRAPHIC DATA TYPE COLUMN CALC-VARG-LEN. MULTIPLY COLUMN-LEN BY TWO GIVING COLUMN-LEN. ADD TWO TO COLUMN-LEN. * PERFORMED PARAGRAPH TO NOTE AN UNRECOGNIZED * DATA TYPE COLUMN UNRECOGNIZED-ERROR. * * ERROR MESSAGE FOR UNRECOGNIZED DATA TYPE * MOVE SQLTYPE(I) TO TYPCOD. WRITE MSGREC FROM BADTYPE AFTER ADVANCING 2 LINES. GO TO IND-RESULT. * ***************************************************** * SQL ERROR OCCURRED - GET MESSAGE * ***************************************************** DBERROR. * **SQL ERROR MOVE SQLCODE TO MSG-PRINT-CODE. IF SQLCODE < 0 THEN MOVE ’-’ TO MSG-MINUS. WRITE MSGREC FROM MSG-SQLERR AFTER ADVANCING 2 LINES. CALL ’DSNTIAR’ USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN. IF RETURN-CODE = ZERO PERFORM ERROR-PRINT VARYING ERROR-INDEX FROM 1 BY 1 UNTIL ERROR-INDEX GREATER THAN 8 ELSE * **ERROR FOUND IN DSNTIAR * **PRINT ERROR MESSAGE MOVE RETURN-CODE TO RETCODE WRITE MSGREC FROM MSGRETCD AFTER ADVANCING 2 LINES. 344 Application Programming and SQL Guide
  • 361.
    GO TO PROG-END. * ***************************************************** * PRINTMESSAGE TEXT * ***************************************************** ERROR-PRINT. WRITE MSGREC FROM ERROR-TEXT (ERROR-INDEX) AFTER ADVANCING 1 LINE. Sample COBOL program using DRDA access with CONNECT statements This example demonstrates how to access distributed data by using DRDA access in a COBOL program. The following figure contains a sample COBOL program that uses two-phase commit and DRDA to access distributed data. IDENTIFICATION DIVISION. PROGRAM-ID. TWOPHASE. AUTHOR. REMARKS. ***************************************************************** * * * MODULE NAME = TWOPHASE * * * * DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION USING * * TWO PHASE COMMIT AND THE DRDA DISTRIBUTED * * ACCESS METHOD WITH CONNECT STATEMENTS * * * * COPYRIGHT = 5665-DB2 (C) COPYRIGHT IBM CORP 1982, 1989 * * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083 * * * * STATUS = VERSION 5 * * * * FUNCTION = THIS MODULE DEMONSTRATES DISTRIBUTED DATA ACCESS * * USING 2 PHASE COMMIT BY TRANSFERRING AN EMPLOYEE * * FROM ONE LOCATION TO ANOTHER. * * * * NOTE: THIS PROGRAM ASSUMES THE EXISTENCE OF THE * * TABLE SYSADM.EMP AT LOCATIONS STLEC1 AND * * STLEC2. * * * * MODULE TYPE = COBOL PROGRAM * * PROCESSOR = DB2 PRECOMPILER, ENTERPRISE COBOL FOR Z/OS * * MODULE SIZE = SEE LINK EDIT * * ATTRIBUTES = NOT REENTRANT OR REUSABLE * * * * ENTRY POINT = * * PURPOSE = TO ILLUSTRATE 2 PHASE COMMIT * * LINKAGE = INVOKE FROM DSN RUN * * INPUT = NONE * * OUTPUT = * * SYMBOLIC LABEL/NAME = SYSPRINT * * DESCRIPTION = PRINT OUT THE DESCRIPTION OF EACH * * STEP AND THE RESULTANT SQLCA * * * * EXIT NORMAL = RETURN CODE 0 FROM NORMAL COMPLETION * * * * EXIT ERROR = NONE * * * * EXTERNAL REFERENCES = * * ROUTINE SERVICES = NONE * * DATA-AREAS = NONE * * CONTROL-BLOCKS = * * SQLCA SQL COMMUNICATION AREA * Chapter 3. Including DB2 queries in an application program 345
  • 362.
    * * TABLES =NONE * * CHANGE-ACTIVITY = NONE * * * * PSEUDOCODE * * MAINLINE. * Perform CONNECT-TO-SITE-1 to establish * a connection to the local connection. * If the previous operation was successful Then * Do. * | Perform PROCESS-CURSOR-SITE-1 to obtain the * | information about an employee that is * | transferring to another location. * | If the information about the employee was obtained * | successfully Then * | Do. * | | Perform UPDATE-ADDRESS to update the information * | | to contain current information about the * | | employee. * | | Perform CONNECT-TO-SITE-2 to establish * | | a connection to the site where the employee is * | | transferring to. * | | If the connection is established successfully * | | Then * | | Do. * | | | Perform PROCESS-SITE-2 to insert the * | | | employee information at the location * | | | where the employee is transferring to. * | | End if the connection was established * | | successfully. * | End if the employee information was obtained * | successfully. * End if the previous operation was successful. * Perform COMMIT-WORK to COMMIT the changes made to STLEC1 * and STLEC2. * * PROG-END. * Close the printer. * Return. * * CONNECT-TO-SITE-1. * Provide a text description of the following step. * Establish a connection to the location where the * employee is transferring from. * Print the SQLCA out. * * PROCESS-CURSOR-SITE-1. * Provide a text description of the following step. * Open a cursor that will be used to retrieve information * about the transferring employee from this site. * Print the SQLCA out. * If the cursor was opened successfully Then * Do. * | Perform FETCH-DELETE-SITE-1 to retrieve and * | delete the information about the transferring * | employee from this site. * | Perform CLOSE-CURSOR-SITE-1 to close the cursor. * End if the cursor was opened successfully. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 346 * * * * * * * * * * FETCH-DELETE-SITE-1. Provide a text description of the following step. Fetch information about the transferring employee. Application Programming and SQL Guide
  • 363.
    * Print the SQLCAout. * * If the information was retrieved successfully Then * * Do. * * | Perform DELETE-SITE-1 to delete the employee * * | at this site. * * End if the information was retrieved successfully. * * * * DELETE-SITE-1. * * Provide a text description of the following step. * * Delete the information about the transferring employee * * from this site. * * Print the SQLCA out. * * * * CLOSE-CURSOR-SITE-1. * * Provide a text description of the following step. * * Close the cursor used to retrieve information about * * the transferring employee. * * Print the SQLCA out. * * * * UPDATE-ADDRESS. * * Update the address of the employee. * * Update the city of the employee. * * Update the location of the employee. * * * * CONNECT-TO-SITE-2. * * Provide a text description of the following step. * * Establish a connection to the location where the * * employee is transferring to. * * Print the SQLCA out. * * * * PROCESS-SITE-2. * * Provide a text description of the following step. * * Insert the employee information at the location where * * the employee is being transferred to. * * Print the SQLCA out. * * * * COMMIT-WORK. * * COMMIT all the changes made to STLEC1 and STLEC2. * * * ***************************************************************** ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT PRINTER, ASSIGN TO S-OUT1. DATA DIVISION. FILE SECTION. FD PRINTER RECORD CONTAINS 120 CHARACTERS DATA RECORD IS PRT-TC-RESULTS LABEL RECORD IS OMITTED. 01 PRT-TC-RESULTS. 03 PRT-BLANK PIC X(120). WORKING-STORAGE SECTION. ***************************************************************** * Variable declarations * ***************************************************************** 01 H-EMPTBL. 05 H-EMPNO PIC X(6). 05 H-NAME. 49 H-NAME-LN PIC S9(4) COMP-4. 49 H-NAME-DA PIC X(32). 05 H-ADDRESS. Chapter 3. Including DB2 queries in an application program 347
  • 364.
    05 05 05 05 05 05 05 05 05 05 05 05 01 49 H-ADDRESS-LN PIC S9(4)COMP-4. 49 H-ADDRESS-DA PIC X(36). H-CITY. 49 H-CITY-LN PIC S9(4) COMP-4. 49 H-CITY-DA PIC X(36). H-EMPLOC PIC X(4). H-SSNO PIC X(11). H-BORN PIC X(10). H-SEX PIC X(1). H-HIRED PIC X(10). H-DEPTNO PIC X(3). H-JOBCODE PIC S9(3)V COMP-3. H-SRATE PIC S9(5) COMP. H-EDUC PIC S9(5) COMP. H-SAL PIC S9(6)V9(2) COMP-3. H-VALIDCHK PIC S9(6)V COMP-3. H-EMPTBL-IND-TABLE. 02 H-EMPTBL-IND PIC S9(4) COMP OCCURS 15 TIMES. ***************************************************************** * Includes for the variables used in the COBOL standard * * language procedures and the SQLCA. * ***************************************************************** EXEC SQL INCLUDE COBSVAR END-EXEC. EXEC SQL INCLUDE SQLCA END-EXEC. ***************************************************************** * Declaration for the table that contains employee information * ***************************************************************** EXEC SQL DECLARE SYSADM.EMP TABLE (EMPNO CHAR(6) NOT NULL, NAME VARCHAR(32), ADDRESS VARCHAR(36) , CITY VARCHAR(36) , EMPLOC CHAR(4) NOT NULL, SSNO CHAR(11), BORN DATE, SEX CHAR(1), HIRED CHAR(10), DEPTNO CHAR(3) NOT NULL, JOBCODE DECIMAL(3), SRATE SMALLINT, EDUC SMALLINT, SAL VALCHK END-EXEC. DECIMAL(8,2) NOT NULL, DECIMAL(6)) ***************************************************************** * Constants * ***************************************************************** 77 77 77 77 77 SITE-1 SITE-2 TEMP-EMPNO TEMP-ADDRESS-LN TEMP-CITY-LN PIC PIC PIC PIC PIC X(16) X(16) X(6) 99 99 VALUE VALUE VALUE VALUE VALUE ’STLEC1’. ’STLEC2’. ’080000’. 15. 18. ***************************************************************** * Declaration of the cursor that will be used to retrieve * * information about a transferring employee * ***************************************************************** EXEC SQL DECLARE C1 CURSOR FOR SELECT EMPNO, NAME, ADDRESS, CITY, EMPLOC, 348 Application Programming and SQL Guide
  • 365.
    SSNO, BORN, SEX,HIRED, DEPTNO, JOBCODE, SRATE, EDUC, SAL, VALCHK FROM SYSADM.EMP WHERE EMPNO = :TEMP-EMPNO END-EXEC. PROCEDURE DIVISION. A101-HOUSE-KEEPING. OPEN OUTPUT PRINTER. ***************************************************************** * An employee is transferring from location STLEC1 to STLEC2. * * Retrieve information about the employee from STLEC1, delete * * the employee from STLEC1 and insert the employee at STLEC2 * * using the information obtained from STLEC1. * ***************************************************************** MAINLINE. PERFORM CONNECT-TO-SITE-1 IF SQLCODE IS EQUAL TO 0 PERFORM PROCESS-CURSOR-SITE-1 IF SQLCODE IS EQUAL TO 0 PERFORM UPDATE-ADDRESS PERFORM CONNECT-TO-SITE-2 IF SQLCODE IS EQUAL TO 0 PERFORM PROCESS-SITE-2. PERFORM COMMIT-WORK. PROG-END. CLOSE PRINTER. GOBACK. ***************************************************************** * Establish a connection to STLEC1 * ***************************************************************** CONNECT-TO-SITE-1. MOVE ’CONNECT TO STLEC1 ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL CONNECT TO :SITE-1 END-EXEC. PERFORM PTSQLCA. ***************************************************************** * When a connection has been established successfully at STLEC1,* * open the cursor that will be used to retrieve information * * about the transferring employee. * ***************************************************************** PROCESS-CURSOR-SITE-1. MOVE ’OPEN CURSOR C1 ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL OPEN C1 END-EXEC. PERFORM PTSQLCA. IF SQLCODE IS EQUAL TO ZERO PERFORM FETCH-DELETE-SITE-1 PERFORM CLOSE-CURSOR-SITE-1. ***************************************************************** * Retrieve information about the transferring employee. * * Provided that the employee exists, perform DELETE-SITE-1 to * * delete the employee from STLEC1. * ***************************************************************** Chapter 3. Including DB2 queries in an application program 349
  • 366.
    FETCH-DELETE-SITE-1. MOVE ’FETCH C1 ’TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL FETCH C1 INTO :H-EMPTBL:H-EMPTBL-IND END-EXEC. PERFORM PTSQLCA. IF SQLCODE IS EQUAL TO ZERO PERFORM DELETE-SITE-1. ***************************************************************** * Delete the employee from STLEC1. * ***************************************************************** DELETE-SITE-1. MOVE ’DELETE EMPLOYEE ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME MOVE ’DELETE EMPLOYEE ’ TO STNAME EXEC SQL DELETE FROM SYSADM.EMP WHERE EMPNO = :TEMP-EMPNO END-EXEC. PERFORM PTSQLCA. ***************************************************************** * Close the cursor used to retrieve information about the * * transferring employee. * ***************************************************************** CLOSE-CURSOR-SITE-1. MOVE ’CLOSE CURSOR C1 ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL CLOSE C1 END-EXEC. PERFORM PTSQLCA. ***************************************************************** * Update certain employee information in order to make it * * current. * ***************************************************************** UPDATE-ADDRESS. MOVE TEMP-ADDRESS-LN MOVE ’1500 NEW STREET’ MOVE TEMP-CITY-LN MOVE ’NEW CITY, CA 97804’ MOVE ’SJCA’ TO TO TO TO TO H-ADDRESS-LN. H-ADDRESS-DA. H-CITY-LN. H-CITY-DA. H-EMPLOC. ***************************************************************** * Establish a connection to STLEC2 * ***************************************************************** CONNECT-TO-SITE-2. MOVE ’CONNECT TO STLEC2 ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL CONNECT TO :SITE-2 END-EXEC. PERFORM PTSQLCA. ***************************************************************** * Using the employee information that was retrieved from STLEC1 * * and updated previously, insert the employee at STLEC2. 350 Application Programming and SQL Guide *
  • 367.
    ***************************************************************** PROCESS-SITE-2. MOVE ’INSERT EMPLOYEE ’TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL INSERT INTO SYSADM.EMP VALUES (:H-EMPNO, :H-NAME, :H-ADDRESS, :H-CITY, :H-EMPLOC, :H-SSNO, :H-BORN, :H-SEX, :H-HIRED, :H-DEPTNO, :H-JOBCODE, :H-SRATE, :H-EDUC, :H-SAL, :H-VALIDCHK) END-EXEC. PERFORM PTSQLCA. ***************************************************************** * COMMIT any changes that were made at STLEC1 and STLEC2. * ***************************************************************** COMMIT-WORK. MOVE ’COMMIT WORK ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL COMMIT END-EXEC. PERFORM PTSQLCA. ***************************************************************** * Include COBOL standard language procedures * ***************************************************************** INCLUDE-SUBS. EXEC SQL INCLUDE COBSSUB END-EXEC. Sample COBOL program using private protocol access This example demonstrates how to access distributed data by using DB2 private protocol access in a COBOL program The following sample program demonstrates distributed access data using DB2 private protocol access with two-phase commit. IDENTIFICATION DIVISION. PROGRAM-ID. TWOPHASE. AUTHOR. REMARKS. ***************************************************************** * * * MODULE NAME = TWOPHASE * * * * DESCRIPTIVE NAME = DB2 SAMPLE APPLICATION USING * * TWO PHASE COMMIT AND DRDA WITH * * THREE-PART NAMES * * * * COPYRIGHT = 5665-DB2 (C) COPYRIGHT IBM CORP 1982, 1989 * Chapter 3. Including DB2 queries in an application program 351
  • 368.
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * REFER TO COPYRIGHTINSTRUCTIONS FORM NUMBER G120-2083 * * STATUS = VERSION 5 * * FUNCTION = THIS MODULE DEMONSTRATES DISTRIBUTED DATA ACCESS * USING 2 PHASE COMMIT BY TRANSFERRING AN EMPLOYEE * FROM ONE LOCATION TO ANOTHER. * * NOTE: THIS PROGRAM ASSUMES THE EXISTENCE OF THE * TABLE SYSADM.EMP AT LOCATIONS STLEC1 AND * STLEC2. * * MODULE TYPE = COBOL PROGRAM * PROCESSOR = DB2 PRECOMPILER, ENTERPRISE COBOL FOR Z/OS * MODULE SIZE = SEE LINK EDIT * ATTRIBUTES = NOT REENTRANT OR REUSABLE * * ENTRY POINT = * PURPOSE = TO ILLUSTRATE 2 PHASE COMMIT * LINKAGE = INVOKE FROM DSN RUN * INPUT = NONE * OUTPUT = * SYMBOLIC LABEL/NAME = SYSPRINT * DESCRIPTION = PRINT OUT THE DESCRIPTION OF EACH * STEP AND THE RESULTANT SQLCA * * EXIT NORMAL = RETURN CODE 0 FROM NORMAL COMPLETION * * EXIT ERROR = NONE * * EXTERNAL REFERENCES = * ROUTINE SERVICES = NONE * DATA-AREAS = NONE * CONTROL-BLOCKS = * SQLCA SQL COMMUNICATION AREA * * TABLES = NONE * * CHANGE-ACTIVITY = NONE * * * * * PSEUDOCODE * * MAINLINE. * Perform PROCESS-CURSOR-SITE-1 to obtain the information * about an employee that is transferring to another * location. * If the information about the employee was obtained * successfully Then * Do. * | Perform UPDATE-ADDRESS to update the information to * | contain current information about the employee. * | Perform PROCESS-SITE-2 to insert the employee * | information at the location where the employee is * | transferring to. * End if the employee information was obtained * successfully. * Perform COMMIT-WORK to COMMIT the changes made to STLEC1 * and STLEC2. * * PROG-END. * Close the printer. * Return. * * PROCESS-CURSOR-SITE-1. * Provide a text description of the following step. 352 Application Programming and SQL Guide * * * * * * * * * * * * * * * * * * * * * * * * * *
  • 369.
    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Open a cursorthat will be used to retrieve information about the transferring employee from this site. Print the SQLCA out. If the cursor was opened successfully Then Do. | Perform FETCH-DELETE-SITE-1 to retrieve and | delete the information about the transferring | employee from this site. | Perform CLOSE-CURSOR-SITE-1 to close the cursor. End if the cursor was opened successfully. FETCH-DELETE-SITE-1. Provide a text description of the following step. Fetch information about the transferring employee. Print the SQLCA out. If the information was retrieved successfully Then Do. | Perform DELETE-SITE-1 to delete the employee | at this site. End if the information was retrieved successfully. DELETE-SITE-1. Provide a text description of the following step. Delete the information about the transferring employee from this site. Print the SQLCA out. CLOSE-CURSOR-SITE-1. Provide a text description of the following step. Close the cursor used to retrieve information about the transferring employee. Print the SQLCA out. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * UPDATE-ADDRESS. * * Update the address of the employee. * * Update the city of the employee. * * Update the location of the employee. * * * * PROCESS-SITE-2. * * Provide a text description of the following step. * * Insert the employee information at the location where * * the employee is being transferred to. * * Print the SQLCA out. * * * * COMMIT-WORK. * * COMMIT all the changes made to STLEC1 and STLEC2. * * * ***************************************************************** ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT PRINTER, ASSIGN TO S-OUT1. DATA DIVISION. FILE SECTION. FD PRINTER RECORD CONTAINS 120 CHARACTERS DATA RECORD IS PRT-TC-RESULTS LABEL RECORD IS OMITTED. 01 PRT-TC-RESULTS. 03 PRT-BLANK PIC X(120). WORKING-STORAGE SECTION. ***************************************************************** Chapter 3. Including DB2 queries in an application program 353
  • 370.
    * Variable declarations * ***************************************************************** 01 H-EMPTBL. 05H-EMPNO PIC X(6). 05 H-NAME. 49 H-NAME-LN PIC S9(4) COMP-4. 49 H-NAME-DA PIC X(32). 05 H-ADDRESS. 49 H-ADDRESS-LN PIC S9(4) COMP-4. 49 H-ADDRESS-DA PIC X(36). 05 H-CITY. 49 H-CITY-LN PIC S9(4) COMP-4. 49 H-CITY-DA PIC X(36). 05 H-EMPLOC PIC X(4). 05 H-SSNO PIC X(11). 05 H-BORN PIC X(10). 05 H-SEX PIC X(1). 05 H-HIRED PIC X(10). 05 H-DEPTNO PIC X(3). 05 H-JOBCODE PIC S9(3)V COMP-3. 05 H-SRATE PIC S9(5) COMP. 05 H-EDUC PIC S9(5) COMP. 05 H-SAL PIC S9(6)V9(2) COMP-3. 05 H-VALIDCHK PIC S9(6)V COMP-3. 01 H-EMPTBL-IND-TABLE. 02 H-EMPTBL-IND PIC S9(4) COMP OCCURS 15 TIMES. ***************************************************************** * Includes for the variables used in the COBOL standard * * language procedures and the SQLCA. * ***************************************************************** EXEC SQL INCLUDE COBSVAR END-EXEC. EXEC SQL INCLUDE SQLCA END-EXEC. ***************************************************************** * Declaration for the table that contains employee information * ***************************************************************** EXEC SQL DECLARE SYSADM.EMP TABLE (EMPNO CHAR(6) NOT NULL, NAME VARCHAR(32), ADDRESS VARCHAR(36) , CITY VARCHAR(36) , EMPLOC CHAR(4) NOT NULL, SSNO CHAR(11), BORN DATE, SEX CHAR(1), HIRED CHAR(10), DEPTNO CHAR(3) NOT NULL, JOBCODE DECIMAL(3), SRATE SMALLINT, EDUC SMALLINT, SAL DECIMAL(8,2) NOT NULL, VALCHK DECIMAL(6)) END-EXEC. ***************************************************************** * Constants * ***************************************************************** 77 77 77 354 TEMP-EMPNO TEMP-ADDRESS-LN TEMP-CITY-LN Application Programming and SQL Guide PIC X(6) PIC 99 PIC 99 VALUE ’080000’. VALUE 15. VALUE 18.
  • 371.
    ***************************************************************** * Declaration ofthe cursor that will be used to retrieve * * information about a transferring employee * ***************************************************************** EXEC SQL DECLARE C1 CURSOR FOR SELECT EMPNO, NAME, ADDRESS, CITY, EMPLOC, SSNO, BORN, SEX, HIRED, DEPTNO, JOBCODE, SRATE, EDUC, SAL, VALCHK FROM STLEC1.SYSADM.EMP WHERE EMPNO = :TEMP-EMPNO END-EXEC. PROCEDURE DIVISION. A101-HOUSE-KEEPING. OPEN OUTPUT PRINTER. ***************************************************************** * An employee is transferring from location STLEC1 to STLEC2. * * Retrieve information about the employee from STLEC1, delete * * the employee from STLEC1 and insert the employee at STLEC2 * * using the information obtained from STLEC1. * ***************************************************************** MAINLINE. PERFORM PROCESS-CURSOR-SITE-1 IF SQLCODE IS EQUAL TO 0 PERFORM UPDATE-ADDRESS PERFORM PROCESS-SITE-2. PERFORM COMMIT-WORK. PROG-END. CLOSE PRINTER. GOBACK. ***************************************************************** * Open the cursor that will be used to retrieve information * * about the transferring employee. * ***************************************************************** PROCESS-CURSOR-SITE-1. MOVE ’OPEN CURSOR C1 ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL OPEN C1 END-EXEC. PERFORM PTSQLCA. IF SQLCODE IS EQUAL TO ZERO PERFORM FETCH-DELETE-SITE-1 PERFORM CLOSE-CURSOR-SITE-1. ***************************************************************** * Retrieve information about the transferring employee. * * Provided that the employee exists, perform DELETE-SITE-1 to * * delete the employee from STLEC1. * ***************************************************************** FETCH-DELETE-SITE-1. MOVE ’FETCH C1 ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL FETCH C1 INTO :H-EMPTBL:H-EMPTBL-IND END-EXEC. Chapter 3. Including DB2 queries in an application program 355
  • 372.
    PERFORM PTSQLCA. IF SQLCODEIS EQUAL TO ZERO PERFORM DELETE-SITE-1. ***************************************************************** * Delete the employee from STLEC1. * ***************************************************************** DELETE-SITE-1. MOVE ’DELETE EMPLOYEE ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME MOVE ’DELETE EMPLOYEE ’ TO STNAME EXEC SQL DELETE FROM STLEC1.SYSADM.EMP WHERE EMPNO = :TEMP-EMPNO END-EXEC. PERFORM PTSQLCA. ***************************************************************** * Close the cursor used to retrieve information about the * * transferring employee. * ***************************************************************** CLOSE-CURSOR-SITE-1. MOVE ’CLOSE CURSOR C1 ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL CLOSE C1 END-EXEC. PERFORM PTSQLCA. ***************************************************************** * Update certain employee information in order to make it * * current. * ***************************************************************** UPDATE-ADDRESS. MOVE TEMP-ADDRESS-LN TO H-ADDRESS-LN. MOVE ’1500 NEW STREET’ TO H-ADDRESS-DA. MOVE TEMP-CITY-LN TO H-CITY-LN. MOVE ’NEW CITY, CA 97804’ TO H-CITY-DA. MOVE ’SJCA’ TO H-EMPLOC. ***************************************************************** * Using the employee information that was retrieved from STLEC1 * * and updated previously, insert the employee at STLEC2. ***************************************************************** PROCESS-SITE-2. MOVE ’INSERT EMPLOYEE ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL INSERT INTO STLEC2.SYSADM.EMP VALUES (:H-EMPNO, :H-NAME, :H-ADDRESS, :H-CITY, :H-EMPLOC, :H-SSNO, :H-BORN, :H-SEX, :H-HIRED, :H-DEPTNO, :H-JOBCODE, :H-SRATE, 356 Application Programming and SQL Guide *
  • 373.
    :H-EDUC, :H-SAL, :H-VALIDCHK) END-EXEC. PERFORM PTSQLCA. ***************************************************************** * COMMITany changes that were made at STLEC1 and STLEC2. * ***************************************************************** COMMIT-WORK. MOVE ’COMMIT WORK ’ TO STNAME WRITE PRT-TC-RESULTS FROM STNAME EXEC SQL COMMIT END-EXEC. PERFORM PTSQLCA. ***************************************************************** * Include COBOL standard language procedures * ***************************************************************** INCLUDE-SUBS. EXEC SQL INCLUDE COBSSUB END-EXEC. Sample DB2 REXX application This example REXX application accepts a table name as input and produces a SELECT, INSERT, or UPDATE SQL statement or a LOAD utility statement for the specified table as output. The following example shows a complete DB2 REXX application named DRAW. DRAW must be invoked from the command line of an ISPF edit session. DRAW takes a table or view name as input and produces a SELECT, INSERT, or UPDATE SQL statement or a LOAD utility control statement that includes the columns of the table as output. DRAW syntax: %DRAW object-name ( SSID=ssid TYPE= SELECT INSERT UPDATE LOAD DRAW parameters: object-name The name of the table or view for which DRAW builds an SQL statement or utility control statement. The name can be a one-, two-, or three-part name. The table or view to which object-name refers must exist before DRAW can run. object-name is a required parameter. SSID=ssid Specifies the name of the local DB2 subsystem. S can be used as an abbreviation for SSID. Chapter 3. Including DB2 queries in an application program 357
  • 374.
    If you invokeDRAW from the command line of the edit session in SPUFI, SSID=ssid is an optional parameter. DRAW uses the subsystem ID from the DB2I Defaults panel. TYPE=operation-type The type of statement that DRAW builds. T can be used as an abbreviation for TYPE. operation-type has one of the following values: SELECT Builds a SELECT statement in which the result table contains all columns of object-name. S can be used as an abbreviation for SELECT. INSERT Builds a template for an INSERT statement that inserts values into all columns of object-name. The template contains comments that indicate where the user can place column values. I can be used as an abbreviation for INSERT. UPDATE Builds a template for an UPDATE statement that updates columns of object-name. The template contains comments that indicate where the user can place column values and qualify the update operation for selected rows. U can be used as an abbreviation for UPDATE. LOAD Builds a template for a LOAD utility control statement for object-name. L can be used as an abbreviation for LOAD. TYPE=operation-type is an optional parameter. The default is TYPE=SELECT. DRAW data sets: Edit data set The data set from which you issue the DRAW command when you are in an ISPF edit session. If you issue the DRAW command from a SPUFI session, this data set is the data set that you specify in field 1 of the main SPUFI panel (DSNESP01). The output from the DRAW command goes into this data set. DRAW return codes: Return code Meaning 0 Successful completion. 12 An error occurred when DRAW edited the input file. 20 One of the following errors occurred: v No input parameters were specified. v One of the input parameters was not valid. v An SQL error occurred when the output statement was generated. Examples of DRAW invocation: 358 Application Programming and SQL Guide
  • 375.
    Generate a SELECTstatement for table DSN8910.EMP at the local subsystem. Use the default DB2I subsystem ID. The DRAW invocation is: DRAW DSN8910.EMP (TYPE=SELECT The output is: SELECT "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" , "PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" , "SALARY" , "BONUS" , "COMM" FROM DSN8910.EMP Generate a template for an INSERT statement that inserts values into table DSN8910.EMP at location SAN_JOSE. The local subsystem ID is DSN. The DRAW invocation is: DRAW SAN_JOSE.DSN8910.EMP (TYPE=INSERT SSID=DSN The output is: INSERT INTO SAN_JOSE.DSN8910.EMP ( "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" , "PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" , "SALARY" , "BONUS" , "COMM" ) VALUES ( -- ENTER VALUES BELOW COLUMN NAME DATA TYPE , -- EMPNO CHAR(6) NOT NULL , -- FIRSTNME VARCHAR(12) NOT NULL , -- MIDINIT CHAR(1) NOT NULL , -- LASTNAME VARCHAR(15) NOT NULL , -- WORKDEPT CHAR(3) , -- PHONENO CHAR(4) , -- HIREDATE DATE , -- JOB CHAR(8) , -- EDLEVEL SMALLINT , -- SEX CHAR(1) , -- BIRTHDATE DATE , -- SALARY DECIMAL(9,2) , -- BONUS DECIMAL(9,2) ) -- COMM DECIMAL(9,2) Generate a template for an UPDATE statement that updates values of table DSN8910.EMP. The local subsystem ID is DSN. The DRAW invocation is: DRAW DSN8910.EMP (TYPE=UPDATE SSID=DSN The output is: UPDATE DSN8910.EMP -- COLUMN NAME "EMPNO"= , "FIRSTNME"= , "MIDINIT"= , "LASTNAME"= , "WORKDEPT"= , "PHONENO"= , "HIREDATE"= , "JOB"= , "EDLEVEL"= , "SEX"= , "BIRTHDATE"= SET ENTER VALUES BELOW ------------ DATA TYPE CHAR(6) NOT VARCHAR(12) CHAR(1) NOT VARCHAR(15) CHAR(3) CHAR(4) DATE CHAR(8) SMALLINT CHAR(1) DATE NULL NOT NULL NULL NOT NULL Chapter 3. Including DB2 queries in an application program 359
  • 376.
    , "SALARY"= , "BONUS"= ,"COMM"= WHERE -- DECIMAL(9,2) -- DECIMAL(9,2) -- DECIMAL(9,2) Generate a LOAD control statement to load values into table DSN8910.EMP. The local subsystem ID is DSN. The draw invocation is: DRAW DSN8910.EMP (TYPE=LOAD SSID=DSN The output is: LOAD DATA INDDN SYSREC INTO TABLE DSN8910.EMP ( "EMPNO" POSITION( 1) CHAR(6) , "FIRSTNME" POSITION( 8) VARCHAR , "MIDINIT" POSITION( 21) CHAR(1) , "LASTNAME" POSITION( 23) VARCHAR , "WORKDEPT" POSITION( 39) CHAR(3) NULLIF( 39)=’?’ , "PHONENO" POSITION( 43) CHAR(4) NULLIF( 43)=’?’ , "HIREDATE" POSITION( 48) DATE EXTERNAL NULLIF( 48)=’?’ , "JOB" POSITION( 59) CHAR(8) NULLIF( 59)=’?’ , "EDLEVEL" POSITION( 68) SMALLINT NULLIF( 68)=’?’ , "SEX" POSITION( 71) CHAR(1) NULLIF( 71)=’?’ , "BIRTHDATE" POSITION( 73) DATE EXTERNAL NULLIF( 73)=’?’ , "SALARY" POSITION( 84) DECIMAL EXTERNAL(9,2) NULLIF( 84)=’?’ , "BONUS" POSITION( 90) DECIMAL EXTERNAL(9,2) NULLIF( 90)=’?’ , "COMM" POSITION( 96) DECIMAL EXTERNAL(9,2) NULLIF( 96)=’?’ ) DRAW source code: /* REXX ***************************************************************/ L1 = WHEREAMI() /* DRAW creates basic SQL queries by retrieving the description of a table. You must specify the name of the table or view to be queried. You can specify the type of query you want to compose. You might need to specify the name of the DB2 subsystem. >>--DRAW-----tablename-----|---------------------------|------->< |-(-|-Ssid=subsystem-name-|-| | +-Select-+ | |-Type=-|-Insert-|----| |-Update-| +--Load--+ Ssid=subsystem-name subsystem-name specified the name of a DB2 subsystem. Select Composes a basic query for selecting data from the columns of a table or view. If TYPE is not specified, SELECT is assumed. Using SELECT with the DRAW command produces a query that would retrieve all rows and all columns from the specified table. You can then modify the query as needed. A SELECT query of EMP composed by DRAW looks like this: SELECT "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" , "PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" , 360 Application Programming and SQL Guide
  • 377.
    "SALARY" , "BONUS", "COMM" FROM DSN8910.EMP If you include a location qualifier, the query looks like this: SELECT "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" , "PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" , "SALARY" , "BONUS" , "COMM" FROM STLEC1.DSN8910.EMP To use this SELECT query, type the other clauses you need. If you are selecting from more than one table, use a DRAW command for each table name you want represented. Insert Composes a basic query to insert data into the columns of a table or view. The following example shows an INSERT query of EMP that DRAW composed: INSERT INTO DSN8910.EMP ( "EMPNO" , "FIRSTNME" , "MIDINIT" , "LASTNAME" , "WORKDEPT" , "PHONENO" , "HIREDATE" , "JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" , "SALARY" , "BONUS" , "COMM" ) VALUES ( -- ENTER VALUES BELOW COLUMN NAME DATA TYPE , -- EMPNO CHAR(6) NOT NULL , -- FIRSTNME VARCHAR(12) NOT NULL , -- MIDINIT CHAR(1) NOT NULL , -- LASTNAME VARCHAR(15) NOT NULL , -- WORKDEPT CHAR(3) , -- PHONENO CHAR(4) , -- HIREDATE DATE , -- JOB CHAR(8) , -- EDLEVEL SMALLINT , -- SEX CHAR(1) , -- BIRTHDATE DATE , -- SALARY DECIMAL(9,2) , -- BONUS DECIMAL(9,2) ) -- COMM DECIMAL(9,2) To insert values into EMP, type values to the left of the column names. Update Composes a basic query to change the data in a table or view. The following example shows an UPDATE query of EMP composed by DRAW: UPDATE DSN8910.EMP SET -- COLUMN NAME ENTER VALUES BELOW DATA TYPE "EMPNO"= -- CHAR(6) NOT NULL , "FIRSTNME"= -- VARCHAR(12) NOT NULL , "MIDINIT"= -- CHAR(1) NOT NULL , "LASTNAME"= -- VARCHAR(15) NOT NULL , "WORKDEPT"= -- CHAR(3) , "PHONENO"= -- CHAR(4) , "HIREDATE"= -- DATE , "JOB"= -- CHAR(8) , "EDLEVEL"= -- SMALLINT , "SEX"= -- CHAR(1) , "BIRTHDATE"= -- DATE , "SALARY"= -- DECIMAL(9,2) , "BONUS"= -- DECIMAL(9,2) , "COMM"= -- DECIMAL(9,2) WHERE To use this UPDATE query, type the changes you want to make to the right of the column names, and delete the lines you don’t need. Be sure to complete the WHERE clause. Load Composes a load statement to load the data in a table. The following example shows a LOAD statement of EMP composed by DRAW: LOAD DATA INDDN SYSREC INTO TABLE DSN8910 .EMP ( "EMPNO" POSITION( 1) CHAR(6) Chapter 3. Including DB2 queries in an application program 361
  • 378.
    , , , , "FIRSTNME" "MIDINIT" "LASTNAME" "WORKDEPT" , "PHONENO" , "HIREDATE" ,"JOB" , "EDLEVEL" , "SEX" , "BIRTHDATE" , "SALARY" , "BONUS" , "COMM" POSITION( POSITION( POSITION( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( POSITION( NULLIF( 8) VARCHAR 21) CHAR(1) 23) VARCHAR 39) CHAR(3) 39)=’?’ 43) CHAR(4) 43)=’?’ 48) DATE EXTERNAL 48)=’?’ 59) CHAR(8) 59)=’?’ 68) SMALLINT 68)=’?’ 71) CHAR(1) 71)=’?’ 73) DATE EXTERNAL 73)=’?’ 84) DECIMAL EXTERNAL(9,2) 84)=’?’ 90) DECIMAL EXTERNAL(9,2) 90)=’?’ 96) DECIMAL EXTERNAL(9,2) 96)=’?’ ) To use this LOAD statement, type the changes you want to make, and delete the lines you don’t need. */ L2 = WHEREAMI() /**********************************************************************/ /* TRACE ?R */ /**********************************************************************/ Address ISPEXEC "ISREDIT MACRO (ARGS) NOPROCESS" If ARGS = "" Then Do Do I = L1+2 To L2-2;Say SourceLine(I);End Exit (20) End Parse Upper Var Args Table "(" Parms Parms = Translate(Parms," ",",") Type = "SELECT" /* Default */ SSID = "" /* Default */ "VGET (DSNEOV01)" If RC = 0 Then SSID = DSNEOV01 If (Parms <> "") Then Do Until(Parms = "") Parse Var Parms Var "=" Value Parms If Var = "T" | Var = "TYPE" Then Type = Value Else If Var = "S" | Var = "SSID" Then SSID = Value Else Exit (20) End "CONTROL ERRORS RETURN" "ISREDIT (LEFTBND,RIGHTBND) = BOUNDS" "ISREDIT (LRECL) = DATA_WIDTH" /*LRECL*/ BndSize = RightBnd - LeftBnd + 1 If BndSize > 72 Then BndSize = 72 "ISREDIT PROCESS DEST" Select When rc = 0 Then ’ISREDIT (ZDEST) = LINENUM .ZDEST’ When rc <= 8 Then /* No A or B entered */ Do zedsmsg = ’Enter "A"/"B" line cmd’ zedlmsg = ’DRAW requires an "A" or "B" line command’ ’SETMSG MSG(ISRZ001)’ 362 Application Programming and SQL Guide
  • 379.
    Exit End When rc < Exit12 When rc = zdest = Otherwise Exit 12 End 12 20 Then /* Conflicting line commands - edit sets message */ 20 Then 0 SQLTYPE. = "UNKNOWN TYPE" VCHTYPE = 448; SQLTYPES.VCHTYPE = ’VARCHAR’ CHTYPE = 452; SQLTYPES.CHTYPE = ’CHAR’ LVCHTYPE = 456; SQLTYPES.LVCHTYPE = ’VARCHAR’ VGRTYP = 464; SQLTYPES.VGRTYP = ’VARGRAPHIC’ GRTYP = 468; SQLTYPES.GRTYP = ’GRAPHIC’ LVGRTYP = 472; SQLTYPES.LVGRTYP = ’VARGRAPHIC’ FLOTYPE = 480; SQLTYPES.FLOTYPE = ’FLOAT’ DCTYPE = 484; SQLTYPES.DCTYPE = ’DECIMAL’ INTYPE = 496; SQLTYPES.INTYPE = ’INTEGER’ SMTYPE = 500; SQLTYPES.SMTYPE = ’SMALLINT’ DATYPE = 384; SQLTYPES.DATYPE = ’DATE’ TITYPE = 388; SQLTYPES.TITYPE = ’TIME’ TSTYPE = 392; SQLTYPES.TSTYPE = ’TIMESTAMP’ Address TSO "SUBCOM DSNREXX" /* HOST CMD ENV AVAILABLE? */ IF RC THEN /* NO, LET’S MAKE ONE */ S_RC = RXSUBCOM(’ADD’,’DSNREXX’,’DSNREXX’) /* ADD HOST CMD ENV */ Address DSNREXX "CONNECT" SSID If SQLCODE ^= 0 Then Call SQLCA Address DSNREXX "EXECSQL DESCRIBE TABLE :TABLE INTO :SQLDA" If SQLCODE ^= 0 Then Call SQLCA Address DSNREXX "EXECSQL COMMIT" Address DSNREXX "DISCONNECT" If SQLCODE ^= 0 Then Call SQLCA Select When (Left(Type,1) = "S") Then Call DrawSelect When (Left(Type,1) = "I") Then Call DrawInsert When (Left(Type,1) = "U") Then Call DrawUpdate When (Left(Type,1) = "L") Then Call DrawLoad Otherwise EXIT (20) End Do I = LINE.0 To 1 By -1 LINE = COPIES(" ",LEFTBND-1)||LINE.I ’ISREDIT LINE_AFTER ’zdest’ = DATALINE (Line)’ End line1 = zdest + 1 ’ISREDIT CURSOR = ’line1 0 Exit /**********************************************************************/ WHEREAMI:; RETURN SIGL /**********************************************************************/ /* Draw SELECT */ /**********************************************************************/ DrawSelect: Line.0 = 0 Line = "SELECT" Do I = 1 To SQLDA.SQLD If I > 1 Then Line = Line ’,’ ColName = ’"’SQLDA.I.SQLNAME’"’ Null = SQLDA.I.SQLTYPE//2 If Length(Line)+Length(ColName)+LENGTH(" ,") > BndSize THEN Do L = Line.0 + 1; Line.0 = L Chapter 3. Including DB2 queries in an application program 363
  • 380.
    Line.L = Line Line= " " End Line = Line ColName End I If Line ^= "" Then Do L = Line.0 + 1; Line.0 = L Line.L = Line Line = " " End L = Line.0 + 1; Line.0 = L Line.L = "FROM" TABLE Return /**********************************************************************/ /* Draw INSERT */ /**********************************************************************/ DrawInsert: Line.0 = 0 Line = "INSERT INTO" TABLE "(" Do I = 1 To SQLDA.SQLD If I > 1 Then Line = Line ’,’ ColName = ’"’SQLDA.I.SQLNAME’"’ If Length(Line)+Length(ColName) > BndSize THEN Do L = Line.0 + 1; Line.0 = L Line.L = Line Line = " " End Line = Line ColName If I = SQLDA.SQLD Then Line = Line ’)’ End I If Line ^= "" Then Do L = Line.0 + 1; Line.0 = L Line.L = Line Line = " " End L = Line.0 + 1; Line.0 = L Line.L = " VALUES (" L = Line.0 + 1; Line.0 = L Line.L = , "-- ENTER VALUES BELOW COLUMN NAME DATA TYPE" Do I = 1 To SQLDA.SQLD If SQLDA.SQLD > 1 & I < SQLDA.SQLD Then Line = " , --" Else Line = " ) --" Line = Line Left(SQLDA.I.SQLNAME,18) Type = SQLDA.I.SQLTYPE Null = Type//2 If Null Then Type = Type - 1 Len = SQLDA.I.SQLLEN Prcsn = SQLDA.I.SQLLEN.SQLPRECISION Scale = SQLDA.I.SQLLEN.SQLSCALE Select When (Type = CHTYPE , |Type = VCHTYPE , |Type = LVCHTYPE , |Type = GRTYP , |Type = VGRTYP , |Type = LVGRTYP ) THEN Type = SQLTYPES.Type"("STRIP(LEN)")" When (Type = FLOTYPE ) THEN Type = SQLTYPES.Type"("STRIP((LEN*4)-11) ")" When (Type = DCTYPE ) THEN Type = SQLTYPES.Type"("STRIP(PRCSN)","STRIP(SCALE)")" 364 Application Programming and SQL Guide
  • 381.
    Otherwise Type = SQLTYPES.Type End Line= Line Type If Null = 0 Then Line = Line "NOT NULL" L = Line.0 + 1; Line.0 = L Line.L = Line End I Return /**********************************************************************/ /* Draw UPDATE */ /**********************************************************************/ DrawUpdate: Line.0 = 1 Line.1 = "UPDATE" TABLE "SET" L = Line.0 + 1; Line.0 = L Line.L = , "-- COLUMN NAME ENTER VALUES BELOW DATA TYPE" Do I = 1 To SQLDA.SQLD If I = 1 Then Line = " " Else Line = " ," Line = Line Left(’"’SQLDA.I.SQLNAME’"=’,21) Line = Line Left(" ",20) Type = SQLDA.I.SQLTYPE Null = Type//2 If Null Then Type = Type - 1 Len = SQLDA.I.SQLLEN Prcsn = SQLDA.I.SQLLEN.SQLPRECISION Scale = SQLDA.I.SQLLEN.SQLSCALE Select When (Type = CHTYPE , |Type = VCHTYPE , |Type = LVCHTYPE , |Type = GRTYP , |Type = VGRTYP , |Type = LVGRTYP ) THEN Type = SQLTYPES.Type"("STRIP(LEN)")" When (Type = FLOTYPE ) THEN Type = SQLTYPES.Type"("STRIP((LEN*4)-11) ")" When (Type = DCTYPE ) THEN Type = SQLTYPES.Type"("STRIP(PRCSN)","STRIP(SCALE)")" Otherwise Type = SQLTYPES.Type End Line = Line "--" Type If Null = 0 Then Line = Line "NOT NULL" L = Line.0 + 1; Line.0 = L Line.L = Line End I L = Line.0 + 1; Line.0 = L Line.L = "WHERE" Return /**********************************************************************/ /* Draw LOAD */ /**********************************************************************/ DrawLoad: Line.0 = 1 Line.1 = "LOAD DATA INDDN SYSREC INTO TABLE" TABLE Position = 1 Do I = 1 To SQLDA.SQLD If I = 1 Then Line = " (" Chapter 3. Including DB2 queries in an application program 365
  • 382.
    Else Line = "," Line = Line Left(’"’SQLDA.I.SQLNAME’"’,20) Line = Line "POSITION("RIGHT(POSITION,5)")" Type = SQLDA.I.SQLTYPE Null = Type//2 If Null Then Type = Type - 1 Len = SQLDA.I.SQLLEN Prcsn = SQLDA.I.SQLLEN.SQLPRECISION Scale = SQLDA.I.SQLLEN.SQLSCALE Select When (Type = CHTYPE , |Type = GRTYP ) THEN Type = SQLTYPES.Type"("STRIP(LEN)")" When (Type = FLOTYPE ) THEN Type = SQLTYPES.Type"("STRIP((LEN*4)-11) ")" When (Type = DCTYPE ) THEN Do Type = SQLTYPES.Type "EXTERNAL" Type = Type"("STRIP(PRCSN)","STRIP(SCALE)")" Len = (PRCSN+2)%2 End When (Type = DATYPE , |Type = TITYPE , |Type = TSTYPE ) THEN Type = SQLTYPES.Type "EXTERNAL" Otherwise Type = SQLTYPES.Type End If (Type = GRTYP , |Type = VGRTYP , |Type = LVGRTYP ) THEN Len = Len * 2 If (Type = VCHTYPE , |Type = LVCHTYPE , |Type = VGRTYP , |Type = LVGRTYP ) THEN Len = Len + 2 Line = Line Type L = Line.0 + 1; Line.0 = L Line.L = Line If Null = 1 Then Do Line = " " Line = Line Left(’’,20) Line = Line " NULLIF("RIGHT(POSITION,5)")=’?’" L = Line.0 + 1; Line.0 = L Line.L = Line End Position = Position + Len + 1 End I L = Line.0 + 1; Line.0 = L Line.L = " )" Return /**********************************************************************/ /* Display SQLCA */ /**********************************************************************/ SQLCA: "ISREDIT LINE_AFTER "zdest" = MSGLINE ’SQLSTATE="SQLSTATE"’" "ISREDIT LINE_AFTER "zdest" = MSGLINE ’SQLWARN ="SQLWARN.0",", || SQLWARN.1",", || SQLWARN.2",", || SQLWARN.3",", || SQLWARN.4",", || SQLWARN.5",", || SQLWARN.6",", || SQLWARN.7",", 366 Application Programming and SQL Guide
  • 383.
    "ISREDIT "ISREDIT "ISREDIT "ISREDIT Exit 20 || SQLWARN.8",", ||SQLWARN.9",", || SQLWARN.10"’" LINE_AFTER "zdest" = || SQLERRD.2",", || SQLERRD.3",", || SQLERRD.4",", || SQLERRD.5",", || SQLERRD.6"’" LINE_AFTER "zdest" = LINE_AFTER "zdest" = LINE_AFTER "zdest" = MSGLINE ’SQLERRD ="SQLERRD.1",", MSGLINE ’SQLERRP ="SQLERRP"’" MSGLINE ’SQLERRMC ="SQLERRMC"’" MSGLINE ’SQLCODE ="SQLCODE"’" Example programs that call stored procedures These examples can be used as models when you write applications that call stored procedures. In addition to these example programs, DSN910.SDSNSAMP contains sample jobs DSNTEJ6P and DSNTEJ6S and programs DSN8EP1 and DSN8EP2, which you can run. Example C program that calls a stored procedure This example shows how to call the C language version of the GETPRML stored procedure that uses the GENERAL WITH NULLS linkage convention. Because the stored procedure returns result sets, this program checks for result sets and retrieves the contents of the result sets. The following figure contains the example C program that calls the GETPRML stored procedure. #include <stdio.h> #include <stdlib.h> #include <string.h> main() { /************************************************************/ /* Include the SQLCA and SQLDA */ /************************************************************/ EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE SQLDA; /************************************************************/ /* Declare variables that are not SQL-related. */ /************************************************************/ short int i; /* Loop counter */ /************************************************************/ /* Declare the following: */ /* - Parameters used to call stored procedure GETPRML */ /* - An SQLDA for DESCRIBE PROCEDURE */ /* - An SQLDA for DESCRIBE CURSOR */ /* - Result set variable locators for up to three result */ /* sets */ /************************************************************/ EXEC SQL BEGIN DECLARE SECTION; char procnm[19]; /* INPUT parm -- PROCEDURE name */ char schema[9]; /* INPUT parm -- User’s schema */ long int out_code; /* OUTPUT -- SQLCODE from the */ /* SELECT operation. */ struct { short int parmlen; char parmtxt[254]; } parmlst; /* OUTPUT -- RUNOPTS values */ /* for the matching row in */ /* catalog table SYSROUTINES */ struct indicators { short int procnm_ind; Chapter 3. Including DB2 queries in an application program 367
  • 384.
    short int schema_ind; shortint out_code_ind; short int parmlst_ind; } parmind; /* Indicator variable structure */ struct sqlda *proc_da; /* SQLDA for DESCRIBE PROCEDURE */ struct sqlda *res_da; /* SQLDA for DESCRIBE CURSOR static volatile SQL TYPE IS RESULT_SET_LOCATOR *loc1, *loc2, *loc3; /* Locator variables EXEC SQL END DECLARE SECTION; */ */ /*************************************************************/ /* Allocate the SQLDAs to be used for DESCRIBE */ /* PROCEDURE and DESCRIBE CURSOR. Assume that at most */ /* three cursors are returned and that each result set */ /* has no more than five columns. */ /*************************************************************/ proc_da = (struct sqlda *)malloc(SQLDASIZE(3)); res_da = (struct sqlda *)malloc(SQLDASIZE(5)); /************************************************************/ /* Call the GETPRML stored procedure to retrieve the */ /* RUNOPTS values for the stored procedure. In this */ /* example, we request the PARMLIST definition for the */ /* stored procedure named DSN8EP2. */ /* */ /* The call should complete with SQLCODE +466 because */ /* GETPRML returns result sets. */ /************************************************************/ strcpy(procnm,"dsn8ep2 "); /* Input parameter -- PROCEDURE to be found */ strcpy(schema," "); /* Input parameter -- Schema name for proc */ parmind.procnm_ind=0; parmind.schema_ind=0; parmind.out_code_ind=0; /* Indicate that none of the input parameters */ /* have null values */ parmind.parmlst_ind=-1; /* The parmlst parameter is an output parm. */ /* Mark PARMLST parameter as null, so the DB2 */ /* requester doesn’t have to send the entire */ /* PARMLST variable to the server. This */ /* helps reduce network I/O time, because */ /* PARMLST is fairly large. */ EXEC SQL CALL GETPRML(:procnm INDICATOR :parmind.procnm_ind, :schema INDICATOR :parmind.schema_ind, :out_code INDICATOR :parmind.out_code_ind, :parmlst INDICATOR :parmind.parmlst_ind); if(SQLCODE!=+466) /* If SQL CALL failed, */ { /* print the SQLCODE and any */ /* message tokens */ printf("SQL CALL failed due to SQLCODE = printf("sqlca.sqlerrmc = "); for(i=0;i<sqlca.sqlerrml;i++) printf("i]); printf("n"); } 368 Application Programming and SQL Guide
  • 385.
    else /* If theCALL worked, */ if(out_code!=0) /* Did GETPRML hit an error? */ printf("GETPRML failed due to RC = /**********************************************************/ /* If everything worked, do the following: */ /* - Print out the parameters returned. */ /* - Retrieve the result sets returned. */ /**********************************************************/ else { printf("RUNOPTS = /* Print out the runopts list */ /********************************************************/ /* Use the statement DESCRIBE PROCEDURE to */ /* return information about the result sets in the */ /* SQLDA pointed to by proc_da: */ /* - SQLD contains the number of result sets that were */ /* returned by the stored procedure. */ /* - Each SQLVAR entry has the following information */ /* about a result set: */ /* - SQLNAME contains the name of the cursor that */ /* the stored procedure uses to return the result */ /* set. */ /* - SQLIND contains an estimate of the number of */ /* rows in the result set. */ /* - SQLDATA contains the result locator value for */ /* the result set. */ /********************************************************/ EXEC SQL DESCRIBE PROCEDURE INTO :*proc_da; /********************************************************/ /* Assume that you have examined SQLD and determined */ /* that there is one result set. Use the statement */ /* ASSOCIATE LOCATORS to establish a result set locator */ /* for the result set. */ /********************************************************/ EXEC SQL ASSOCIATE LOCATORS (:loc1) WITH PROCEDURE GETPRML; /********************************************************/ /* Use the statement ALLOCATE CURSOR to associate a */ /* cursor for the result set. */ /********************************************************/ EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :loc1; /********************************************************/ /* Use the statement DESCRIBE CURSOR to determine the */ /* columns in the result set. */ /********************************************************/ EXEC SQL DESCRIBE CURSOR C1 INTO :*res_da; /********************************************************/ /* Call a routine (not shown here) to do the following: */ /* - Allocate a buffer for data and indicator values */ /* fetched from the result table. */ /* - Update the SQLDATA and SQLIND fields in each */ /* SQLVAR of *res_da with the addresses at which to */ /* to put the fetched data and values of indicator */ /* variables. */ /********************************************************/ alloc_outbuff(res_da); /********************************************************/ /* Fetch the data from the result table. */ /********************************************************/ while(SQLCODE==0) Chapter 3. Including DB2 queries in an application program 369
  • 386.
    EXEC SQL FETCHC1 USING DESCRIPTOR :*res_da; } return; } Example COBOL program that calls a stored procedure This example shows how to call the GETPRML stored procedure that uses the GENERAL WITH NULLS linkage convention from a COBOL program on an z/OS system. Because the stored procedure returns result sets, this program checks for result sets and retrieves the contents of the result sets. The following figure contains the example COBOL program that calls the GETPRML stored procedure. IDENTIFICATION DIVISION. PROGRAM-ID. CALPRML. ENVIRONMENT DIVISION. CONFIGURATION SECTION. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT REPOUT ASSIGN TO UT-S-SYSPRINT. DATA DIVISION. FILE SECTION. FD REPOUT RECORD CONTAINS 127 CHARACTERS LABEL RECORDS ARE OMITTED DATA RECORD IS REPREC. 01 REPREC PIC X(127). WORKING-STORAGE SECTION. ***************************************************** * MESSAGES FOR SQL CALL * ***************************************************** 01 SQLREC. 02 BADMSG PIC X(34) VALUE ’ SQL CALL FAILED DUE TO SQLCODE = ’. 02 BADCODE PIC +9(5) USAGE DISPLAY. 02 FILLER PIC X(80) VALUE SPACES. 01 ERRMREC. 02 ERRMMSG PIC X(12) VALUE ’ SQLERRMC = ’. 02 ERRMCODE PIC X(70). 02 FILLER PIC X(38) VALUE SPACES. 01 CALLREC. 02 CALLMSG PIC X(28) VALUE ’ GETPRML FAILED DUE TO RC = ’. 02 CALLCODE PIC +9(5) USAGE DISPLAY. 02 FILLER PIC X(42) VALUE SPACES. 01 RSLTREC. 02 RSLTMSG PIC X(15) VALUE ’ TABLE NAME IS ’. 02 TBLNAME PIC X(18) VALUE SPACES. 02 FILLER PIC X(87) VALUE SPACES. ***************************************************** * WORK AREAS * ***************************************************** 01 PROCNM PIC X(18). 01 SCHEMA PIC X(8). 01 OUT-CODE PIC S9(9) USAGE COMP. 01 PARMLST. 49 PARMLEN PIC S9(4) USAGE COMP. 49 PARMTXT PIC X(254). 01 PARMBUF REDEFINES PARMLST. 49 PARBLEN PIC S9(4) USAGE COMP. 370 Application Programming and SQL Guide
  • 387.
    49 PARMARRY PIC X(127)OCCURS 2 TIMES. NAME. 49 NAMELEN PIC S9(4) USAGE COMP. 49 NAMETXT PIC X(18). 77 PARMIND PIC S9(4) COMP. 77 I PIC S9(4) COMP. 77 NUMLINES PIC S9(4) COMP. ***************************************************** * DECLARE A RESULT SET LOCATOR FOR THE RESULT SET * * THAT IS RETURNED. * ***************************************************** 01 LOC USAGE SQL TYPE IS RESULT-SET-LOCATOR VARYING. 01 ***************************************************** * SQL INCLUDE FOR SQLCA * ***************************************************** EXEC SQL INCLUDE SQLCA END-EXEC. PROCEDURE DIVISION. *-----------------PROG-START. OPEN OUTPUT REPOUT. * OPEN OUTPUT FILE MOVE ’DSN8EP2 ’ TO PROCNM. * INPUT PARAMETER -- PROCEDURE TO BE FOUND MOVE SPACES TO SCHEMA. * INPUT PARAMETER -- SCHEMA IN SYSROUTINES MOVE -1 TO PARMIND. * THE PARMLST PARAMETER IS AN OUTPUT PARM. * MARK PARMLST PARAMETER AS NULL, SO THE DB2 * REQUESTER DOESN’T HAVE TO SEND THE ENTIRE * PARMLST VARIABLE TO THE SERVER. THIS * HELPS REDUCE NETWORK I/O TIME, BECAUSE * PARMLST IS FAIRLY LARGE. EXEC SQL CALL GETPRML(:PROCNM, :SCHEMA, :OUT-CODE, :PARMLST INDICATOR :PARMIND) END-EXEC. * MAKE THE CALL IF SQLCODE NOT EQUAL TO +466 THEN * IF CALL RETURNED BAD SQLCODE MOVE SQLCODE TO BADCODE WRITE REPREC FROM SQLREC MOVE SQLERRMC TO ERRMCODE WRITE REPREC FROM ERRMREC ELSE PERFORM GET-PARMS PERFORM GET-RESULT-SET. PROG-END. CLOSE REPOUT. * CLOSE OUTPUT FILE GOBACK. PARMPRT. MOVE SPACES TO REPREC. WRITE REPREC FROM PARMARRY(I) AFTER ADVANCING 1 LINE. GET-PARMS. * IF THE CALL WORKED, IF OUT-CODE NOT EQUAL TO 0 THEN * DID GETPRML HIT AN ERROR? MOVE OUT-CODE TO CALLCODE WRITE REPREC FROM CALLREC ELSE * EVERYTHING WORKED Chapter 3. Including DB2 queries in an application program 371
  • 388.
    DIVIDE 127 INTOPARMLEN GIVING NUMLINES ROUNDED FIND OUT HOW MANY LINES TO PRINT PERFORM PARMPRT VARYING I FROM 1 BY 1 UNTIL I GREATER THAN NUMLINES. GET-RESULT-SET. ***************************************************** * ASSUME YOU KNOW THAT ONE RESULT SET IS RETURNED, * * AND YOU KNOW THE FORMAT OF THAT RESULT SET. * * ALLOCATE A CURSOR FOR THE RESULT SET, AND FETCH * * THE CONTENTS OF THE RESULT SET. * ***************************************************** EXEC SQL ASSOCIATE LOCATORS (:LOC) WITH PROCEDURE GETPRML END-EXEC. * LINK THE RESULT SET TO THE LOCATOR EXEC SQL ALLOCATE C1 CURSOR FOR RESULT SET :LOC END-EXEC. * LINK THE CURSOR TO THE RESULT SET PERFORM GET-ROWS VARYING I FROM 1 BY 1 UNTIL SQLCODE EQUAL TO +100. GET-ROWS. EXEC SQL FETCH C1 INTO :NAME END-EXEC. MOVE NAME TO TBLNAME. WRITE REPREC FROM RSLTREC AFTER ADVANCING 1 LINE. * Example PL/I program that calls a stored procedure This example shows how to call the GETPRML stored procedure that uses the GENERAL WITH NULLS linkage convention from a PL/I program on an z/OS system. The following figure contains the example PL/I program that calls the GETPRML stored procedure. 372 Application Programming and SQL Guide
  • 389.
    *PROCESS SYSTEM(MVS); CALPRML: PROC OPTIONS(MAIN); /************************************************************/ /*Declare the parameters used to call the GETPRML */ /* stored procedure. */ /************************************************************/ DECLARE PROCNM CHAR(18), /* INPUT parm -- PROCEDURE name */ SCHEMA CHAR(8), /* INPUT parm -- User’s schema */ OUT_CODE FIXED BIN(31), /* OUTPUT -- SQLCODE from the */ /* SELECT operation. */ PARMLST CHAR(254) /* OUTPUT -- RUNOPTS for */ VARYING, /* the matching row in the */ /* catalog table SYSROUTINES */ PARMIND FIXED BIN(15); /* PARMLST indicator variable */ /************************************************************/ /* Include the SQLCA */ /************************************************************/ EXEC SQL INCLUDE SQLCA; /************************************************************/ /* Call the GETPRML stored procedure to retrieve the */ /* RUNOPTS values for the stored procedure. In this */ /* example, we request the RUNOPTS values for the */ /* stored procedure named DSN8EP2. */ /************************************************************/ PROCNM = ’DSN8EP2’; /* Input parameter -- PROCEDURE to be found */ SCHEMA = ’ ’; /* Input parameter -- SCHEMA in SYSROUTINES */ PARMIND = -1; /* The PARMLST parameter is an output parm. */ /* Mark PARMLST parameter as null, so the DB2 */ /* requester doesn’t have to send the entire */ /* PARMLST variable to the server. This */ /* helps reduce network I/O time, because */ /* PARMLST is fairly large. */ EXEC SQL CALL GETPRML(:PROCNM, :SCHEMA, :OUT_CODE, :PARMLST INDICATOR :PARMIND); IF SQLCODE¬=0 THEN /* If SQL CALL failed, DO; PUT SKIP EDIT(’SQL CALL failed due to SQLCODE = ’, SQLCODE) (A(34),A(14)); PUT SKIP EDIT(’SQLERRM = ’, SQLERRM) (A(10),A(70)); END; ELSE /* If the CALL worked, IF OUT_CODE¬=0 THEN /* Did GETPRML hit an error? PUT SKIP EDIT(’GETPRML failed due to RC = ’, OUT_CODE) (A(33),A(14)); ELSE /* Everything worked. PUT SKIP EDIT(’RUNOPTS = ’, PARMLST) (A(11),A(200)); RETURN; END CALPRML; */ */ */ */ Figure 31. Calling a stored procedure from a PL/I program Chapter 3. Including DB2 queries in an application program 373
  • 390.
    Example C storedprocedure with a GENERAL linkage convention This example shows how to call a stored procedure that uses the GENERAL linkage convention from a C program. This example stored procedure does the following: v Searches the DB2 catalog table SYSROUTINES for a row that matches the input parameters from the client program. The two input parameters contain values for NAME and SCHEMA. v Searches the DB2 catalog table SYSTABLES for all tables in which the value of CREATOR matches the value of input parameter SCHEMA. The stored procedure uses a cursor to return the table names. The linkage convention used for this stored procedure is GENERAL. The output parameters from this stored procedure contain the SQLCODE from the SELECT statement and the value of the RUNOPTS column from SYSROUTINES. The CREATE PROCEDURE statement for this stored procedure might look like this: CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN, OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT) LANGUAGE C DETERMINISTIC READS SQL DATA EXTERNAL NAME "GETPRML" COLLID GETPRML ASUTIME NO LIMIT PARAMETER STYLE GENERAL STAY RESIDENT NO RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)" WLM ENVIRONMENT SAMPPROG PROGRAM TYPE MAIN SECURITY DB2 RESULT SETS 2 COMMIT ON RETURN NO; The following example is a C stored procedure with linkage convention GENERAL #pragma runopts(plist(os)) #include <stdlib.h> EXEC SQL INCLUDE SQLCA; /***************************************************************/ /* Declare C variables for SQL operations on the parameters. */ /* These are local variables to the C program, which you must */ /* copy to and from the parameter list provided to the stored */ /* procedure. */ /***************************************************************/ EXEC SQL BEGIN DECLARE SECTION; char PROCNM[19]; char SCHEMA[9]; char PARMLST[255]; EXEC SQL END DECLARE SECTION; /***************************************************************/ /* Declare cursors for returning result sets to the caller. */ /***************************************************************/ EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR SELECT NAME FROM SYSIBM.SYSTABLES 374 Application Programming and SQL Guide
  • 391.
    WHERE CREATOR=:SCHEMA; main(argc,argv) int argc; char*argv[]; { /********************************************************/ /* Copy the input parameters into the area reserved in */ /* the program for SQL processing. */ /********************************************************/ strcpy(PROCNM, argv[1]); strcpy(SCHEMA, argv[2]); /********************************************************/ /* Issue the SQL SELECT against the SYSROUTINES */ /* DB2 catalog table. */ /********************************************************/ strcpy(PARMLST, ""); /* Clear PARMLST */ EXEC SQL SELECT RUNOPTS INTO :PARMLST FROM SYSIBM.ROUTINES WHERE NAME=:PROCNM AND SCHEMA=:SCHEMA; /********************************************************/ /* Copy SQLCODE to the output parameter list. */ /********************************************************/ *(int *) argv[3] = SQLCODE; /********************************************************/ /* Copy the PARMLST value returned by the SELECT back to*/ /* the parameter list provided to this stored procedure.*/ /********************************************************/ strcpy(argv[4], PARMLST); /********************************************************/ /* Open cursor C1 to cause DB2 to return a result set */ /* to the caller. */ /********************************************************/ EXEC SQL OPEN C1; } Example C stored procedure with a GENERAL WITH NULLS linkage convention This example shows how to call a stored procedure that uses the GENERAL WITH NULLS linkage convention from a C program. This example stored procedure does the following: v Searches the DB2 catalog table SYSROUTINES for a row that matches the input parameters from the client program. The two input parameters contain values for NAME and SCHEMA. v Searches the DB2 catalog table SYSTABLES for all tables in which the value of CREATOR matches the value of input parameter SCHEMA. The stored procedure uses a cursor to return the table names. The linkage convention for this stored procedure is GENERAL WITH NULLS. The output parameters from this stored procedure contain the SQLCODE from the SELECT operation, and the value of the RUNOPTS column retrieved from the SYSROUTINES table. The CREATE PROCEDURE statement for this stored procedure might look like this: Chapter 3. Including DB2 queries in an application program 375
  • 392.
    CREATE PROCEDURE GETPRML(PROCNMCHAR(18) IN, SCHEMA CHAR(8) IN, OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT) LANGUAGE C DETERMINISTIC READS SQL DATA EXTERNAL NAME "GETPRML" COLLID GETPRML ASUTIME NO LIMIT PARAMETER STYLE GENERAL WITH NULLS STAY RESIDENT NO RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)" WLM ENVIRONMENT SAMPPROG PROGRAM TYPE MAIN SECURITY DB2 RESULT SETS 2 COMMIT ON RETURN NO; The following example is a C stored procedure with linkage convention GENERAL WITH NULLS. #pragma runopts(plist(os)) #include <stdlib.h> EXEC SQL INCLUDE SQLCA; /***************************************************************/ /* Declare C variables used for SQL operations on the */ /* parameters. These are local variables to the C program, */ /* which you must copy to and from the parameter list provided */ /* to the stored procedure. */ /***************************************************************/ EXEC SQL BEGIN DECLARE SECTION; char PROCNM[19]; char SCHEMA[9]; char PARMLST[255]; struct INDICATORS { short int PROCNM_IND; short int SCHEMA_IND; short int OUT_CODE_IND; short int PARMLST_IND; } PARM_IND; EXEC SQL END DECLARE SECTION; /***************************************************************/ /* Declare cursors for returning result sets to the caller. */ /***************************************************************/ EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR SELECT NAME FROM SYSIBM.SYSTABLES WHERE CREATOR=:SCHEMA; main(argc,argv) int argc; char *argv[]; { /********************************************************/ /* Copy the input parameters into the area reserved in */ /* the local program for SQL processing. */ /********************************************************/ strcpy(PROCNM, argv[1]); strcpy(SCHEMA, argv[2]); /********************************************************/ 376 Application Programming and SQL Guide
  • 393.
    /* Copy nullindicator values for the parameter list. */ /********************************************************/ memcpy(&PARM_IND,(struct INDICATORS *) argv[5], sizeof(PARM_IND)); /********************************************************/ /* If any input parameter is NULL, return an error */ /* return code and assign a NULL value to PARMLST. */ /********************************************************/ if (PARM_IND.PROCNM_IND<0 || PARM_IND.SCHEMA_IND<0 || { *(int *) argv[3] = 9999; /* set output return code */ PARM_IND.OUT_CODE_IND = 0; /* value is not NULL */ PARM_IND.PARMLST_IND = -1; /* PARMLST is NULL */ } else { /********************************************************/ /* If the input parameters are not NULL, issue the SQL */ /* SELECT against the SYSIBM.SYSROUTINES catalog */ /* table. */ /********************************************************/ strcpy(PARMLST, ""); /* Clear PARMLST */ EXEC SQL SELECT RUNOPTS INTO :PARMLST FROM SYSIBM.SYSROUTINES WHERE NAME=:PROCNM AND SCHEMA=:SCHEMA; /********************************************************/ /* Copy SQLCODE to the output parameter list. */ /********************************************************/ *(int *) argv[3] = SQLCODE; PARM_IND.OUT_CODE_IND = 0; /* OUT_CODE is not NULL */ } /********************************************************/ /* Copy the RUNOPTS value back to the output parameter */ /* area. */ /********************************************************/ strcpy(argv[4], PARMLST); /********************************************************/ /* Copy the null indicators back to the output parameter*/ /* area. */ /********************************************************/ memcpy((struct INDICATORS *) argv[5],&PARM_IND, sizeof(PARM_IND)); /********************************************************/ /* Open cursor C1 to cause DB2 to return a result set */ /* to the caller. */ /********************************************************/ EXEC SQL OPEN C1; } Example COBOL stored procedure with a GENERAL linkage convention This example shows how to call a stored procedure that uses the GENERAL linkage convention from a COBOL program. This example stored procedure does the following: v Searches the catalog table SYSROUTINES for a row matching the input parameters from the client program. The two input parameters contain values for NAME and SCHEMA. Chapter 3. Including DB2 queries in an application program 377
  • 394.
    v Searches theDB2 catalog table SYSTABLES for all tables in which the value of CREATOR matches the value of input parameter SCHEMA. The stored procedure uses a cursor to return the table names. This stored procedure is able to return a NULL value for the output host variables. The linkage convention for this stored procedure is GENERAL. The output parameters from this stored procedure contain the SQLCODE from the SELECT operation, and the value of the RUNOPTS column retrieved from the SYSROUTINES table. The CREATE PROCEDURE statement for this stored procedure might look like this: CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN, OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT) LANGUAGE COBOL DETERMINISTIC READS SQL DATA EXTERNAL NAME "GETPRML" COLLID GETPRML ASUTIME NO LIMIT PARAMETER STYLE GENERAL STAY RESIDENT NO RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)" WLM ENVIRONMENT SAMPPROG PROGRAM TYPE MAIN SECURITY DB2 RESULT SETS 2 COMMIT ON RETURN NO; CBL RENT IDENTIFICATION DIVISION. PROGRAM-ID. GETPRML. AUTHOR. EXAMPLE. DATE-WRITTEN. 03/25/98. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. DATA DIVISION. FILE SECTION. WORKING-STORAGE SECTION. EXEC SQL INCLUDE SQLCA END-EXEC. *************************************************** * DECLARE A HOST VARIABLE TO HOLD INPUT SCHEMA *************************************************** 01 INSCHEMA PIC X(8). *************************************************** * DECLARE CURSOR FOR RETURNING RESULT SETS *************************************************** * EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR SELECT NAME FROM SYSIBM.SYSTABLES WHERE CREATOR=:INSCHEMA END-EXEC. * LINKAGE SECTION. *************************************************** * DECLARE THE INPUT PARAMETERS FOR THE PROCEDURE *************************************************** 01 PROCNM PIC X(18). 01 SCHEMA PIC X(8). 378 Application Programming and SQL Guide
  • 395.
    ******************************************************* * DECLARE THEOUTPUT PARAMETERS FOR THE PROCEDURE ******************************************************* 01 OUT-CODE PIC S9(9) USAGE BINARY. 01 PARMLST. 49 PARMLST-LEN PIC S9(4) USAGE BINARY. 49 PARMLST-TEXT PIC X(254). PROCEDURE DIVISION USING PROCNM, SCHEMA, OUT-CODE, PARMLST. ******************************************************* * Issue the SQL SELECT against the SYSIBM.SYSROUTINES * DB2 catalog table. ******************************************************* EXEC SQL SELECT RUNOPTS INTO :PARMLST FROM SYSIBM.ROUTINES WHERE NAME=:PROCNM AND SCHEMA=:SCHEMA END-EXEC. ******************************************************* * COPY SQLCODE INTO THE OUTPUT PARAMETER AREA ******************************************************* MOVE SQLCODE TO OUT-CODE. ******************************************************* * OPEN CURSOR C1 TO CAUSE DB2 TO RETURN A RESULT SET * TO THE CALLER. ******************************************************* EXEC SQL OPEN C1 END-EXEC. PROG-END. GOBACK. Example COBOL stored procedure with a GENERAL WITH NULLS linkage convention This example shows how to call a stored procedure that uses the GENERAL WITH NULLS linkage convention from a COBOL program. This example stored procedure does the following: v Searches the DB2 SYSIBM.SYSROUTINES catalog table for a row that matches the input parameters from the client program. The two input parameters contain values for NAME and SCHEMA. v Searches the DB2 catalog table SYSTABLES for all tables in which the value of CREATOR matches the value of input parameter SCHEMA. The stored procedure uses a cursor to return the table names. The linkage convention for this stored procedure is GENERAL WITH NULLS. The output parameters from this stored procedure contain the SQLCODE from the SELECT operation, and the value of the RUNOPTS column retrieved from the SYSIBM.SYSROUTINES table. The CREATE PROCEDURE statement for this stored procedure might look like this: CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN, OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT) LANGUAGE COBOL DETERMINISTIC READS SQL DATA EXTERNAL NAME "GETPRML" Chapter 3. Including DB2 queries in an application program 379
  • 396.
    COLLID GETPRML ASUTIME NOLIMIT PARAMETER STYLE GENERAL WITH NULLS STAY RESIDENT NO RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)" WLM ENVIRONMENT SAMPPROG PROGRAM TYPE MAIN SECURITY DB2 RESULT SETS 2 COMMIT ON RETURN NO; The following example is a COBOL stored procedure with linkage convention GENERAL WITH NULLS. CBL RENT IDENTIFICATION DIVISION. PROGRAM-ID. GETPRML. AUTHOR. EXAMPLE. DATE-WRITTEN. 03/25/98. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. DATA DIVISION. FILE SECTION. * WORKING-STORAGE SECTION. * EXEC SQL INCLUDE SQLCA END-EXEC. * *************************************************** * DECLARE A HOST VARIABLE TO HOLD INPUT SCHEMA *************************************************** 01 INSCHEMA PIC X(8). *************************************************** * DECLARE CURSOR FOR RETURNING RESULT SETS *************************************************** * EXEC SQL DECLARE C1 CURSOR WITH RETURN FOR SELECT NAME FROM SYSIBM.SYSTABLES WHERE CREATOR=:INSCHEMA END-EXEC. * LINKAGE SECTION. *************************************************** * DECLARE THE INPUT PARAMETERS FOR THE PROCEDURE *************************************************** 01 PROCNM PIC X(18). 01 SCHEMA PIC X(8). *************************************************** * DECLARE THE OUTPUT PARAMETERS FOR THE PROCEDURE *************************************************** 01 OUT-CODE PIC S9(9) USAGE BINARY. 01 PARMLST. 49 PARMLST-LEN PIC S9(4) USAGE BINARY. 49 PARMLST-TEXT PIC X(254). *************************************************** * DECLARE THE STRUCTURE CONTAINING THE NULL * INDICATORS FOR THE INPUT AND OUTPUT PARAMETERS. *************************************************** 01 IND-PARM. 03 PROCNM-IND PIC S9(4) USAGE BINARY. 03 SCHEMA-IND PIC S9(4) USAGE BINARY. 03 OUT-CODE-IND PIC S9(4) USAGE BINARY. 03 PARMLST-IND PIC S9(4) USAGE BINARY. PROCEDURE DIVISION USING PROCNM, SCHEMA, OUT-CODE, PARMLST, IND-PARM. ******************************************************* 380 Application Programming and SQL Guide
  • 397.
    * If anyinput parameter is null, return a null value * for PARMLST and set the output return code to 9999. ******************************************************* IF PROCNM-IND < 0 OR SCHEMA-IND < 0 MOVE 9999 TO OUT-CODE MOVE 0 TO OUT-CODE-IND MOVE -1 TO PARMLST-IND ELSE ******************************************************* * Issue the SQL SELECT against the SYSIBM.SYSROUTINES * DB2 catalog table. ******************************************************* EXEC SQL SELECT RUNOPTS INTO :PARMLST FROM SYSIBM.SYSROUTINES WHERE NAME=:PROCNM AND SCHEMA=:SCHEMA END-EXEC MOVE 0 TO PARMLST-IND ******************************************************* * COPY SQLCODE INTO THE OUTPUT PARAMETER AREA ******************************************************* MOVE SQLCODE TO OUT-CODE MOVE 0 TO OUT-CODE-IND. * ******************************************************* * OPEN CURSOR C1 TO CAUSE DB2 TO RETURN A RESULT SET * TO THE CALLER. ******************************************************* EXEC SQL OPEN C1 END-EXEC. PROG-END. GOBACK. Example PL/I stored procedure with a GENERAL linkage convention This example shows how to call a stored procedure that uses the GENERAL linkage convention from a PL/I program. This example stored procedure searches the DB2 SYSIBM.SYSROUTINES catalog table for a row that matches the input parameters from the client program. The two input parameters contain values for NAME and SCHEMA. The linkage convention for this stored procedure is GENERAL. The output parameters from this stored procedure contain the SQLCODE from the SELECT operation, and the value of the RUNOPTS column retrieved from the SYSIBM.SYSROUTINES table. The CREATE PROCEDURE statement for this stored procedure might look like this: CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN, OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT) LANGUAGE PLI DETERMINISTIC READS SQL DATA EXTERNAL NAME "GETPRML" COLLID GETPRML ASUTIME NO LIMIT PARAMETER STYLE GENERAL STAY RESIDENT NO RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)" Chapter 3. Including DB2 queries in an application program 381
  • 398.
    WLM ENVIRONMENT SAMPPROG PROGRAMTYPE MAIN SECURITY DB2 RESULT SETS 0 COMMIT ON RETURN NO; The following example is a PL/I stored procedure with linkage convention GENERAL. *PROCESS SYSTEM(MVS); GETPRML: PROC(PROCNM, SCHEMA, OUT_CODE, PARMLST) OPTIONS(MAIN NOEXECOPS REENTRANT); DECLARE PROCNM CHAR(18), SCHEMA CHAR(8), /* INPUT parm -- PROCEDURE name */ /* INPUT parm -- User’s SCHEMA */ OUT_CODE FIXED BIN(31), /* /* PARMLST CHAR(254) /* VARYING; /* /* OUTPUT -- SQLCODE from the SELECT operation. OUTPUT -- RUNOPTS for the matching row in SYSIBM.SYSROUTINES */ */ */ */ */ EXEC SQL INCLUDE SQLCA; /************************************************************/ /* Execute SELECT from SYSIBM.SYSROUTINES in the catalog. */ /************************************************************/ EXEC SQL SELECT RUNOPTS INTO :PARMLST FROM SYSIBM.SYSROUTINES WHERE NAME=:PROCNM AND SCHEMA=:SCHEMA; OUT_CODE = SQLCODE; RETURN; END GETPRML; /* return SQLCODE to caller */ Example PL/I stored procedure with a GENERAL WITH NULLS linkage convention This example shows how to call a stored procedure that uses the GENERAL WITH NULLS linkage convention from a PL/I program. This example stored procedure searches the DB2 SYSIBM.SYSROUTINES catalog table for a row that matches the input parameters from the client program. The two input parameters contain values for NAME and SCHEMA. The linkage convention for this stored procedure is GENERAL WITH NULLS. The output parameters from this stored procedure contain the SQLCODE from the SELECT operation, and the value of the RUNOPTS column retrieved from the SYSIBM.SYSROUTINES table. The CREATE PROCEDURE statement for this stored procedure might look like this: CREATE PROCEDURE GETPRML(PROCNM CHAR(18) IN, SCHEMA CHAR(8) IN, OUTCODE INTEGER OUT, PARMLST VARCHAR(254) OUT) LANGUAGE PLI DETERMINISTIC READS SQL DATA EXTERNAL NAME "GETPRML" COLLID GETPRML 382 Application Programming and SQL Guide
  • 399.
    ASUTIME NO LIMIT PARAMETERSTYLE GENERAL WITH NULLS STAY RESIDENT NO RUN OPTIONS "MSGFILE(OUTFILE),RPTSTG(ON),RPTOPTS(ON)" WLM ENVIRONMENT SAMPPROG PROGRAM TYPE MAIN SECURITY DB2 RESULT SETS 0 COMMIT ON RETURN NO; The following example is a PL/I stored procedure with linkage convention GENERAL WITH NULLS. *PROCESS SYSTEM(MVS); GETPRML: PROC(PROCNM, SCHEMA, OUT_CODE, PARMLST, INDICATORS) OPTIONS(MAIN NOEXECOPS REENTRANT); DECLARE PROCNM CHAR(18), SCHEMA CHAR(8), /* INPUT parm -- PROCEDURE name */ /* INPUT parm -- User’s schema */ OUT_CODE FIXED BIN(31), /* OUTPUT -- SQLCODE from /* the SELECT operation. PARMLST CHAR(254) /* OUTPUT -- PARMLIST for VARYING; /* the matching row in /* SYSIBM.SYSROUTINES DECLARE 1 INDICATORS, /* Declare null indicators for /* input and output parameters. 3 PROCNM_IND FIXED BIN(15), 3 SCHEMA_IND FIXED BIN(15), 3 OUT_CODE_IND FIXED BIN(15), 3 PARMLST_IND FIXED BIN(15); */ */ */ */ */ */ */ EXEC SQL INCLUDE SQLCA; IF PROCNM_IND<0 | SCHEMA_IND<0 THEN DO; OUT_CODE = 9999; OUT_CODE_IND = 0; /* If any input parm is NULL, /* Set output return code. */ */ /* Output return code is not NULL.*/ PARMLST_IND = -1; /* Assign NULL value to PARMLST. */ END; ELSE /* If input parms are not NULL, */ DO; /* */ /************************************************************/ /* Issue the SQL SELECT against the SYSIBM.SYSROUTINES */ /* DB2 catalog table. */ /************************************************************/ EXEC SQL SELECT RUNOPTS INTO :PARMLST FROM SYSIBM.SYSROUTINES WHERE NAME=:PROCNM AND SCHEMA=:SCHEMA; PARMLST_IND = 0; /* Mark PARMLST as not NULL. */ OUT_CODE = SQLCODE; OUT_CODE_IND = 0; OUT_CODE_IND = 0; END; RETURN; /* return SQLCODE to caller */ /* Output return code is not NULL.*/ END GETPRML; Chapter 3. Including DB2 queries in an application program 383
  • 400.
  • 401.
    Chapter 4. Creatingand modifying DB2 objects Your application program can create and manipulate DB2 objects, such as tables, views, triggers, distinct types, user-defined functions, and stored procedures. You must have the appropriate authorizations to create such objects. Creating tables Creating a table provides a logically place to store related data on a DB2 subsystem. To create a table, use a CREATE TABLE statement that includes the following elements: v The name of the table v A list of the columns that make up the table. For each column, specify the following information: – The column’s name (for example, SERIAL). – The data type and length attribute (for example, CHAR(8)). – Optionally, a default value. – Optionally, a referential constraint or check constraint. Separate each column description from the next with a comma, and enclose the entire list of column descriptions in parentheses. Example:The following SQL statement creates a table named PRODUCT: CREATE TABLE PRODUCT (SERIAL CHAR(8) NOT NULL, DESCRIPTION VARCHAR(60) DEFAULT, MFGCOST DECIMAL(8,2), MFGDEPT CHAR(3), MARKUP SMALLINT, SALESDEPT CHAR(3), CURDATE DATE DEFAULT); For more information about referential constraints, see “Referential constraints” on page 396 For more information about check constraints, see “Check constraints” on page 394. Identifying column defaults and constraining column inputs: If you want to constrain the input or identify the default of a column, you can use the following values: v NOT NULL, when the column cannot contain null values. v UNIQUE, when the value for each row must be unique, and the column cannot contain null values. v DEFAULT, when the column has one of the following DB2-assigned defaults: – For numeric columns, 0 (zero) is the default value. – For character or graphic fixed-length strings, blank is the default value. – For binary fixed-length strings, a set of hexadecimal zeros is the default value. © Copyright IBM Corp. 1983, 2007 385
  • 402.
    – For variable-lengthstrings, including LOB strings, the empty string (a string of zero-length) is the default value. – For datetime columns, the current value of the associated special register is the default value. v DEFAULT value, when you want to identify one of the following values as the default value: – A constant – NULL – SESSION_USER, which specifies the value of the SESSION_USER special register at the time when a default value is needed for the column – CURRENT SQLID, which specifies the value of the CURRENT SQLID special register at the time when a default value is needed for the column – The name of a cast function that casts a default value (of a built-in data type) to the distinct type of a column Data types When you create a DB2 table, you define each column to have a specific data type. The data type of a column determines what you can and cannot do with the column. When you perform operations on columns, the data must be compatible with the data type of the referenced column. For example, you cannot insert character data, such as a last name, into a column whose data type is numeric. Similarly, you cannot compare columns that contain incompatible data types. The data type for a column can be a distinct type, which is a user-defined data type, or a DB2 built-in data type. As shown in the following figure, DB2 built-in data types have four general categories: datetime, string, numeric, and row identifier (ROWID). 386 Application Programming and SQL Guide
  • 403.
    Figure 32. DB2built-in data types For more detailed information about each built-in data type, see the topic “Data types” in DB2 SQL Reference. For information about distinct types, see “Distinct types” on page 436. The following table shows whether operands of any two data types are compatible, Y (Yes), or incompatible, N (No). Notes are indicated either as a superscript number next to Y or N or as a value in the column of the table. Table 76. Supported casts between built-in data types To data type1 | | | | | | | | | Cast from data type – S M A L L I N T SMALLINT Y Y Y Y Y Y Y Y INTEGER Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y DECIMAL Y Y Y Y Y Y Y Y T I M E S T A M P Y BIGINT V A R B I N A R Y Y Y I N T E G E R B I G I N T D E C I M A L D E C F L O A T V A R G R A P H I C R E A L D O U B L E C H A R V A R C H A R C L O B G R A P H I C D B C L O B B I N A R Y B L O B D A T E T I M E Chapter 4. Creating and modifying DB2 objects R O W X I M D L 387
  • 404.
    Table 76. Supportedcasts between built-in data types (continued) To data type1 V A R G R A P H I C | | | | | | | | Cast from | data type – S M A L L I N T | DECFLOAT Y Y Y Y Y Y Y Y Y REAL Y Y Y Y Y Y Y Y Y DOUBLE Y Y Y Y Y Y Y Y Y CHAR Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y VARCHAR Y Y Y Y Y Y Y Y Y Y Y Y Y Y I N T E G E R B I G I N T D E C I M A L D E C F L O A T R E A L D O U B L E CLOB C H A R Y V A R C H A R Y 2 Y 2 B I N A R Y D A T E T I M E Y Y Y Y Y Y Y Y Y Y Y B L O B Y Y Y Y Y Y Y Y Y Y Y Y3 Y3 Y3 Y R O W X I M D L Y 2 Y Y Y Y Y Y Y Y Y VARGRAPHIC Y Y Y Y Y Y Y Y2 Y2 Y2 Y Y Y Y Y Y 2 2 2 Y Y Y Y Y Y BINARY Y Y Y VARBINARY Y Y Y BLOB Y Y Y Y Y DATE Y Y Y TIMESTAMP Y Y ROWID Y Y Y TIME Y D B C L O B T I M E S T A M P GRAPHIC DBCLOB Y C L O B G R A P H I C V A R B I N A R Y Y | XML Y Y Y Y Y Y Y Y Y Y Y Note: 1. Other synonyms for the listed data types are considered to be the same as the synonym listed. Some exceptions exist when the cast involves character string data if the subtype is FOR BIT DATA. 2. The result length for these casts is 3 * LENGTH(graphic string). 3. These data types are castable between each other only if the data is Unicode. Storing LOB data in a table Because DB2 handles LOB data differently than other kinds of data, in some cases, you need to take additional actions when defining LOB columns and inserting the LOB data. To store LOB data in DB2: 1. Define one or more columns of the appropriate LOB type and optionally a row identifier (ROWID) column by executing a CREATE TABLE statement or one or more ALTER TABLE statements. 388 Application Programming and SQL Guide
  • 405.
    | | | | | | | | Define only oneROWID column, even if the table is to have multiple LOB columns. If you do not create a ROWID column before you define a LOB column, DB2 creates an implicitly hidden ROWID column and appends it as the last column of the table. If you add a ROWID column after you add a LOB column, the table has two ROWID columns: the implicitly-created, hidden, column and the explicitly-created column. In this case, DB2 ensures that the values of the two ROWID columns are always identical. If DB2 implicitly creates the table space for this table or CURRENT RULES is set to STD, DB2 creates the necessary auxiliary objects for you and you can skip steps 2 and 3. The LOB table space that DB2 creates inherits the COMPRESS value of the base table space. 2. If you explicitly created the table space for this table and the CURRENT RULES special register is not set to STD, create a LOB table space and auxiliary table by using the CREATE LOB TABLESPACE and CREATE AUXILIARY TABLE statements. v If your base table is nonpartitioned, create one LOB table space and for each column create one auxiliary table. v If your base table is partitioned, create one LOB table space for each partition and one auxiliary table for each column. For example, if your base table has three partitions, you must create three LOB table spaces and three auxiliary tables for each LOB column. 3. If you explicitly created the table space for this table and the CURRENT RULES special register is not set to STD, create one index for each auxiliary table by using the CREATE INDEX statement. 4. Insert the LOB data into DB2 by using one of the following techniques: v If the total length of a LOB column and the base table row is less than 32 KB, use the LOAD utility and specify the base table. v Otherwise, use INSERT, UPDATE, or MERGE statements and specify the base table. If you use the INSERT statement, ensure that you application has enough storage available to hold the entire value that is to be put into the LOB column. Example: Adding a CLOB column: Suppose that you want to add a resume for each employee to the employee table. The employee resumes are no more than 5 MB in size. Because the employee resumes contain single-byte characters, you can define the resumes to DB2 as CLOBs. You therefore need to add a column of data type CLOB with a length of 5 MB to the employee table. If you want to define a ROWID column explicitly, you must define it before you define the CLOB column. First, execute an ALTER TABLE statement to add the ROWID column, and then execute another ALTER TABLE statement to add the CLOB column. The following statements create these columns: ALTER TABLE EMP ADD ROW_ID ROWID NOT NULL GENERATED ALWAYS; COMMIT; ALTER TABLE EMP ADD EMP_RESUME CLOB(5M); COMMIT; | | | If you explicitly created the table space for this table and the CURRENT RULES special register is not set to STD, you then need to define a LOB table space and an auxiliary table to hold the employee resumes. You also need to define an index on Chapter 4. Creating and modifying DB2 objects 389
  • 406.
    | | | | | | | | | | | | | | the auxiliary table.You must define the LOB table space in the same database as the associated base table. The following statements create these objects: | You can then load your employee resumes into DB2. In your application, you can define a host variable to hold the resume, copy the resume data from a file into the host variable, and then execute an UPDATE statement to copy the data into DB2. Although the LOB data is stored in the auxiliary table, your UPDATE statement specifies the name of the base table. The following code declares a host variable to store the resume in the C language: CREATE LOB TABLESPACE RESUMETS IN DSN8D91A LOG NO COMPRESS YES; COMMIT; CREATE AUXILIARY TABLE EMP_RESUME_TAB IN DSN8D91A.RESUMETS STORES DSN8910.EMP COLUMN EMP_RESUME; CREATE UNIQUE INDEX XEMP_RESUME ON EMP_RESUME_TAB; COMMIT; SQL TYPE is CLOB (5M) resumedata; The following UPDATE statement copies the data into DB2: UPDATE EMP SET EMP_RESUME=:resumedata WHERE EMPNO=:employeenum; In this statement, employeenum is a host variable that identifies the employee who is associated with a resume. Large objects (LOBs) The term large object and the acronym LOB refer to DB2 objects that you can use to store large amounts of data. A LOB is a varying-length character string that can contain up to 2 GB - 1 of data. The three LOB data types are: v Binary large object (BLOB) Use a BLOB to store binary data such as pictures, voice, and mixed media. v Character large object (CLOB) Use a CLOB to store SBCS or mixed character data, such as documents. v Double-byte character large object (DBCLOB) Use a DBCLOB to store data that consists of only DBCS data. You can use DB2 to store LOB data, but this data is stored differently than other kinds of data. Although a table can have a LOB column, the actual LOB data is stored in a another table, which called the auxiliary table. This auxiliary table exists in a separate table space called a LOB table space. One auxiliary table must exist for each LOB column. The table with the LOB column is called the base table. The base table has a ROWID column that DB2 uses to locate the data in the auxiliary table. The auxiliary table must have exactly one index. Implicitly hidden ROWID columns If you do not create a ROWID column before you define a LOB column, DB2 creates an implicitly hidden ROWID column for you. This column is accessible 390 Application Programming and SQL Guide
  • 407.
    only if youreference the column directly. It is not included in the results of SELECT * statements or DESCRIBE statements. DB2 assigns the GENERATED ALWAYS attribute and the name DB2_GENERATED_ROWID_FOR_LOBSnn to a an implicitly hidden ROWID column. DB2 appends the identifier nn only if the column name already exists in the table. If so, DB2 appends 00 and increments by 1 until the name is unique within the row. For more information about when DB2 creates implicitly hidden ROWID columns, see the following topics in DB2 SQL Reference: v “CREATE TABLE” v “ALTER TABLE” v “ALTER VIEW” For more information about selecting hidden columns, see the topic “select-clause” in DB2 SQL Reference. Identity columns An identity column contains a unique numeric value for each row in the table. DB2 can automatically generate sequential numeric values for this column as rows are inserted into the table. Thus, identity columns are ideal for primary key values, such as employee numbers or product numbers. Using identity columns as keys: If you define a column with the AS IDENTITY attribute, and with the GENERATED ALWAYS and NO CYCLE attributes, DB2 automatically generates a monotonically increasing or decreasing sequential number for the value of that column when a new row is inserted into the table. However, for DB2 to guarantee that the values of the identity column are unique, you should define a unique index on that column. You can use identity columns for primary keys that are typically unique sequential numbers, for example, order numbers or employee numbers. By doing so, you can avoid the concurrency problems that can result when an application generates its own unique counter outside the database. Recommendation: Set the values of the foreign keys in the dependent tables after loading the parent table. If you use an identity column as a parent key in a referential integrity structure, loading data into that structure could be quite complicated. The values for the identity column are not known until the table is loaded because the column is defined as GENERATED ALWAYS. You v If v If v If might have gaps in identity column values for the following reasons: other applications are inserting values into the same identity column DB2 terminates abnormally before it assigns all the cached values your application rolls back a transaction that inserts identity values Defining an identity column: You can define an identity column as either GENERATED BY DEFAULT or GENERATED ALWAYS: Chapter 4. Creating and modifying DB2 objects 391
  • 408.
    v If youdefine the column as GENERATED BY DEFAULT, you can insert a value, and DB2 provides a default value if you do not supply one. v If you define the column as GENERATED ALWAYS, DB2 always generates a value for the column, and you cannot insert data into that column. If you want the values to be unique, you must define the identity column with GENERATED ALWAYS and NO CYCLE and define a unique index on that column. For more information, see “Rules for inserting data into an identity column” on page 564. The values that DB2 generates for an identity column depend on how the column is defined. The START WITH option determines the first value that DB2 generates. The values advance by the INCREMENT BY value in ascending or descending order. The MINVALUE and MAXVALUE options determine the minimum and maximum values that DB2 generates. The CYCLE or NO CYCLE option determines whether DB2 wraps values when it has generated all values between the START WITH value and MAXVALUE if the values are ascending, or between the START WITH value and MINVALUE if the values are descending. Example: Suppose that table T1 is defined with GENERATED ALWAYS and CYCLE: CREATE TABLE T1 (CHARCOL1 CHAR(1), IDENTCOL1 SMALLINT GENERATED ALWAYS AS IDENTITY (START WITH -1, INCREMENT BY 1, CYCLE, MINVALUE -3, MAXVALUE 3)); Now suppose that you execute the following INSERT statement eight times: INSERT INTO T1 (CHARCOL1) VALUES (’A’); When DB2 generates values for IDENTCOL1, it starts with -1 and increments by 1 until it reaches the MAXVALUE of 3 on the fifth INSERT. To generate the value for the sixth INSERT, DB2 cycles back to MINVALUE, which is -3. T1 looks like this after the eight INSERTs are executed: CHARCOL1 ======== A A A A A A A A IDENTCOL1 ========= -1 0 1 2 3 -3 -2 -1 The value of IDENTCOL1 for the eighth INSERT repeats the value of IDENTCOL1 for the first INSERT. Identity columns as primary keys: The SELECT from INSERT statement enables you to insert a row into a parent table with its primary key defined as a DB2-generated identity column, and retrieve the value of the primary or parent key. You can then use this generated 392 Application Programming and SQL Guide
  • 409.
    value as aforeign key in a dependent table. For information about the SELECT from INSERT statement, see “Selecting values while inserting data” on page 569. In addition, you can use the IDENTITY_VAL_LOCAL function to return the most recently assigned value for an identity column. For more information about the IDENTITY_VAL_LOCAL function, see the topic “IDENTITY_VAL_LOCAL” in DB2 SQL Reference. Example: Using SELECT from INSERT: Suppose that an EMPLOYEE table and a DEPARTMENT table are defined in the following way: CREATE TABLE EMPLOYEE (EMPNO INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL, NAME CHAR(30) NOT NULL, SALARY DECIMAL(7,2) NOT NULL, WORKDEPT SMALLINT); CREATE TABLE DEPARTMENT (DEPTNO SMALLINT NOT NULL PRIMARY KEY, DEPTNAME VARCHAR(30), MGRNO INTEGER NOT NULL, CONSTRAINT REF_EMPNO FOREIGN KEY (MGRNO) REFERENCES EMPLOYEE (EMPNO) ON DELETE RESTRICT); ALTER TABLE EMPLOYEE ADD CONSTRAINT REF_DEPTNO FOREIGN KEY (WORKDEPT) REFERENCES DEPARTMENT (DEPTNO) ON DELETE SET NULL; When you insert a new employee into the EMPLOYEE table, to retrieve the value for the EMPNO column, you can use the following SELECT from INSERT statement: EXEC SQL SELECT EMPNO INTO :hv_empno FROM FINAL TABLE (INSERT INTO EMPLOYEE (NAME, SALARY, WORKDEPT) VALUES (’New Employee’, 75000.00, 11)); The SELECT statement returns the DB2-generated identity value for the EMPNO column in the host variable :hv_empno. You can then use the value in :hv_empno to update the MGRNO column in the DEPARTMENT table with the new employee as the department manager: EXEC SQL UPDATE DEPARTMENT SET MGRNO = :hv_empno WHERE DEPTNO = 11; Creating tables for data integrity You can use entities such as constraints, triggers, and unique indexes to ensure that only valid data is added to your tables. For example, you might need to ensure that all items in your inventory table have valid item numbers and prevent items without valid item numbers from being added. Ways to maintain data integrity When you add or modify data in a DB2 table, you need to ensure that the data is valid. Two techniques that you can use to ensure valid data are constraints and triggers. Constraints are rules that limit the values that you can insert, delete, or update in a table. There are two types of constraints: Chapter 4. Creating and modifying DB2 objects 393
  • 410.
    v Check constraintsdetermine the values that a column can contain. Check constraints are discussed in “Check constraints.” v Referential constraints preserve relationships between tables. Referential constraints are discussed in “Referential constraints” on page 396. A specific type of referential constraints, the informational referential constraint, is discussed in “Informational referential constraints” on page 398. Triggers are a series of actions that are invoked when a table is updated. Triggers are discussed in “Creating triggers” on page 417. Check constraints: A check constraint is a rule that specifies the values that are allowed in one or more columns of every row of a base table. For example, you can define a check constraint to ensure that all values in a column that contains ages are positive numbers. Check constraints designate the values that specific columns of a base table can contain, providing you a method of controlling the integrity of data entered into tables. You can create tables with check constraints using the CREATE TABLE statement, or you can add the constraints with the ALTER TABLE statement. However, if the check integrity is compromised or cannot be guaranteed for a table, the table space or partition that contains the table is placed in a check pending state. Check integrity is the condition that exists when each row of a table conforms to the check constraints defined on that table. For example, you might want to make sure that no salary can be below 15000 dollars. To do this, you can create the following check constraint: CREATE TABLE EMPSAL (ID INTEGER SALARY INTEGER NOT NULL, CHECK (SALARY >= 15000)); Using check constraints makes your programming task easier, because you do not need to enforce those constraints within application programs or with a validation routine. Define check constraints on one or more columns in a table when that table is created or altered. Check constraint considerations The syntax of a check constraint is checked when the constraint is defined, but the meaning of the constraint is not checked. The following examples show mistakes that are not caught. Column C1 is defined as INTEGER NOT NULL. Allowable but mistaken check constraints: v A self-contradictory check constraint: CHECK (C1 > 5 AND C1 < 2) v Two check constraints that contradict each other: CHECK (C1 > 5) CHECK (C1 < 2) v Two check constraints, one of which is redundant: CHECK (C1 > 0) CHECK (C1 >= 1) v A check constraint that contradicts the column definition: CHECK (C1 IS NULL) 394 Application Programming and SQL Guide
  • 411.
    v A checkconstraint that repeats the column definition: CHECK (C1 IS NOT NULL) A check constraint is not checked for consistency with other types of constraints. For example, a column in a dependent table can have a referential constraint with a delete rule of SET NULL. You can also define a check constraint that prohibits nulls in the column. As a result, an attempt to delete a parent row fails, because setting the dependent row to null violates the check constraint. Similarly, a check constraint is not checked for consistency with a validation routine, which is applied to a table before a check constraint. If the routine requires a column to be greater than or equal to 10 and a check constraint requires the same column to be less than 10, table inserts are not possible. Plans and packages do not need to be rebound after check constraints are defined on or removed from a table. When check constraints are enforced | | After check constraints are defined on a table, any change must satisfy those constraints if it is made by: v The LOAD utility with the option ENFORCE CONSTRAINT v An SQL insert operation v An SQL update operation A row satisfies a check constraint if its condition evaluates either to true or to unknown. A condition can evaluate to unknown for a row if one of the named columns contains the null value for that row. Any constraint defined on columns of a base table applies to the views defined on that base table. When you use ALTER TABLE to add a check constraint to already populated tables, the enforcement of the check constraint is determined by the value of the CURRENT RULES special register as follows: v If the value is STD, the check constraint is enforced immediately when it is defined. If a row does not conform, the check constraint is not added to the table and an error occurs. v If the value is DB2, the check constraint is added to the table description but its enforcement is deferred. Because there might be rows in the table that violate the check constraint, the table is placed in CHECK-pending status. CHECK-pending status: To maintain data integrity DB2 enforces check constraints and referential constraints on data in a table. When either of these constraints are violated or might be violated, DB2 places the table space or partition that contains the table in CHECK-pending status. Table check violations place a table space or partition in CHECK-pending status when any of these conditions exist: v A check constraint is defined on a populated table using the ALTER TABLE statement, and the value of the CURRENT RULES special register is DB2. v The LOAD utility is run with CONSTRAINTS NO, and check constraints are defined on the table. v CHECK DATA is run on a table that contains violations of check constraints. v A point-in-time RECOVER introduces violations of check constraints. Chapter 4. Creating and modifying DB2 objects 395
  • 412.
    Referential constraints: A referentialconstraint is a rule that specifies that the only valid values for a particular column are those values that exist in another specified table column. For example, this constraint can ensure that all customer IDs in a transaction table exist in the ID column of a customer table. A table can serve as the “master list” of all occurrences of an entity. In the sample application, the employee table serves that purpose for employees; the numbers that appear in that table are the only valid employee numbers. Likewise, the department table provides a master list of all valid department numbers; the project activity table provides a master list of activities performed for projects; and so on. The following figure shows the relationships that exist among the tables in the sample application. Arrows point from parent tables to dependent tables. CASCADE DEPT SET NULL RESTRICT SET NULL EMP RESTRICT CASCADE ACT PROJ RESTRICT RESTRICT RESTRICT PROJACT RESTRICT EMPPROJACT Figure 33. Relationships among tables in the sample application When a table refers to an entity for which there is a master list, it should identify an occurrence of the entity that actually appears in the master list; otherwise, either the reference is invalid or the master list is incomplete. Referential constraints enforce the relationship between a table and a master list. Restrictions on cycles of dependent tables: A cycle is a set of two or more tables that are ordered so that each is a dependent of the one before it, and the first is a dependent of the last. Every table in the cycle is a descendent of itself. DB2 restricts certain operations on cycles. In the sample application, the employee and department tables are a cycle; each is a dependent of the other. 396 Application Programming and SQL Guide
  • 413.
    DB2 does notallow you to create a cycle in which a delete operation on a table involves that same table. Enforcing that principle creates rules about adding a foreign key to a table: v In a cycle of two tables, neither delete rule can be CASCADE. v In a cycle of more than two tables, two or more delete rules must not be CASCADE. For example, in a cycle with three tables, two of the delete rules must be other than CASCADE. This concept is illustrated in The following figure. The cycle on the left is valid because two or more of the delete rules are not CASCADE. The cycle on the right is invalid because it contains two cascading deletes. Valid cycle Invalid cycle TABLE1 RESTRICT TABLE2 CASCADE SET NULL TABLE3 TABLE1 CASCADE CASCADE TABLE2 SET NULL TABLE3 Figure 34. Valid and invalid delete cycles Alternatively, a delete operation on a self-referencing table must involve the same table, and the delete rule there must be CASCADE or NO ACTION. Recommendation: Avoid creating a cycle in which all the delete rules are RESTRICT and none of the foreign keys allows nulls. If you do this, no row of any of the tables can ever be deleted. Referential constraints on tables with multilevel security with row-level granularity: You cannot use referential constraints on a security label column, which is used for multilevel security with row-level granularity. However, you can use referential constraints on other columns in the row. DB2 does not enforce multilevel security with row-level granularity when it is already enforcing referential constraints. Referential constraints are enforced when the following situations occur: v An insert operation is applied to a dependent table. v An update operation is applied to a foreign key of a dependent table, or to the parent key of a parent table. v A delete operation is applied to a parent table. In addition to all referential constraints being enforced, the DB2 system enforces all delete rules for all dependent rows that are affected by the delete operation. If all referential constraints and delete rules are not satisfied, the delete operation will not succeed. v The LOAD utility with the ENFORCE CONSTRAINTS option is run on a dependent table. v The CHECK DATA utility is run. For more information about multilevel security with row-level granularity, see the topic “Multilevel security” in DB2 Administration Guide. Chapter 4. Creating and modifying DB2 objects 397
  • 414.
    Informational referential constraints: Aninformational referential constraint is a referential constraint that DB2 does not enforce during normal operations. Use these constraints only when referential integrity can be enforced by another means, such as when retrieving data from other sources. These constraints might improve performance by enabling the query to qualify for automatic query rewrite. DB2 ignores informational referential constraints during insert, update, and delete operations. Some utilities ignore these constraints; other utilities recognize them. For example, CHECK DATA and LOAD ignore these constraints. QUIESCE TABLESPACESET recognizes these constraints by quiescing all table spaces related to the specified table space. You should use this type of referential constraint only when an application process verifies the data in a referential integrity relationship. For example, when inserting a row in a dependent table, the application should verify that a foreign key exists as a primary or unique key in the parent table. To define an informational referential constraint, use the NOT ENFORCED option of the referential constraint definition in a CREATE TABLE or ALTER TABLE statement. For more information about the NOT ENFORCED option, see the topic “CREATE TABLE” in DB2 SQL Reference. Informational referential constraints are often useful, especially in a data warehouse environment, for several reasons: v To avoid the overhead of enforcement by DB2. Typically, data in a data warehouse has been extracted and cleansed from other sources. Referential integrity might already be guaranteed. In this situation, enforcement by DB2 is unnecessary. v To allow more queries to qualify for automatic query rewrite. Automatic query rewrite is a process that examines a submitted query that references source tables and, if appropriate, rewrites the query so that it executes against a materialized query table that has been derived from those source tables. This process uses informational referential constraints to determine whether the query can use a materialized query table. Automatic query rewrite results in a significant reduction in query run time, especially for decision-support queries that operate over huge amounts of data. For more information about materialized query tables and automatic query rewrite, see the topic “Using materialized query tables” in DB2 Performance Monitoring and Tuning Guide. Defining a parent key and unique index A parent key is either a primary key or a unique key in the parent table of a referential constraint. The values of a parent key determine the valid values of the foreign key in the constraint. You must create a unique index on a parent key. The primary key of a table, if one exists, uniquely identifies each occurrence of an entity in the table. The PRIMARY KEY clause of the CREATE TABLE or ALTER TABLE statements identifies the column or columns of the primary key. Each identified column must be defined as NOT NULL. Another way to allow only unique values in a column is to specify the UNIQUE clause when you create or alter a table. For more information about the UNIQUE clause, see the topics “CREATE TABLE” and “ALTER TABLE” in DB2 SQL Reference. | | | | 398 Application Programming and SQL Guide
  • 415.
    A table thatis to be a parent of dependent tables must have a primary or a unique key; the foreign keys of the dependent tables refer to the primary or unique key. Otherwise, a primary key is optional. Consider defining a primary key if each row of your table does pertain to a unique occurrence of some entity. If you define a primary key, an index must be created (the primary index) on the same set of columns, in the same order as those columns. If you are defining referential constraints for DB2 to enforce, read “Ways to maintain data integrity” on page 393 before creating or altering any of the tables involved. A table can have no more than one primary key. A primary key has the same restrictions as index keys: v The key can include no more than 64 columns. v You cannot specify a column name twice. v The sum of the column length attributes cannot be greater than 2000. You define a list of columns as the primary key of a table with the PRIMARY KEY clause in the CREATE TABLE statement. To add a primary key to an existing table, use the PRIMARY KEY clause in an ALTER TABLE statement. In this case, a unique index must already exist. Recommendations for defining primary keys: Consider the following items when you plan for primary keys: v The theoretical model of a relational database suggests that every table should have a primary key to uniquely identify the entities it describes. However, you must weigh that model against the potential cost of index maintenance overhead. DB2 does not require you to define a primary key for tables with no dependents. v Choose a primary key whose values will not change over time. Choosing a primary key with persistent values enforces the good practice of having unique identifiers that remain the same for the lifetime of the entity occurrence. v A primary key column should not have default values unless the primary key is a single TIMESTAMP column. v Choose the minimum number of columns to ensure uniqueness of the primary key. v A view that can be updated that is defined on a table with a primary key should include all columns of the key. Although this is necessary only if the view is used for inserts, the unique identification of rows can be useful if the view is used for updates, deletes, or selects. v Drop a primary key later if you change your database or application using SQL. Parent key columns: A parent key is either a primary key or a unique key in the parent table of a referential constraint. This key consists of a column or set of columns. The values of a parent key determine the valid values of the foreign key in the constraint. If every row in a table represents relationships for a unique entity, the table should have one column or a set of columns that provides a unique identifier for the rows of the table. This column (or set of columns) is called the parent key of the table. To ensure that the parent key does not contain duplicate values, you must create a unique index on the column or columns that constitute the parent key. Defining the parent key is called entity integrity, because it requires each entity to have a unique key. Chapter 4. Creating and modifying DB2 objects 399
  • 416.
    In some cases,using a timestamp as part of the key can be helpful, for example when a table does not have a “natural” unique key or if arrival sequence is the key. Primary keys for some of the sample tables are: Table Key Column Employee table EMPNO Department table DEPTNO Project table PROJNO Table 77 shows part of the project table which has the primary key column, PROJNO. Table 77. Part of the project table with the primary key column, PROJNO PROJNO PROJNAME DEPTNO MA2100 WELD LINE AUTOMATION D01 MA2110 W L PROGRAMMING D11 Table 78 shows part of the project activity table, which has a primary key that contains more than one column. The primary key is a composite key, which consists of the PRONNO, ACTNO, and ACSTDATE columns. Table 78. Part of the Project activities table with a composite primary key PROJNO ACTNO ACSTAFF ACSTDATE ACENDATE AD3100 10 .50 1982-01-01 1982-07-01 AD3110 10 1.00 1982-01-01 1983-01-01 AD3111 60 .50 1982-03-15 1982-04-15 Defining a foreign key Use foreign keys to enforce referential relationships between tables. A foreign key is a column or set of columns that reference the parent key in the parent table. You define a list of columns as a foreign key of a table with the FOREIGN KEY clause in the CREATE TABLE statement. A foreign key can refer to either a unique or a primary key of the parent table. If the foreign key refers to a non-primary unique key, you must specify the column names of the key explicitly. If the column names of the key are not specified explicitly, the default is to refer to the column names of the primary key of the parent table. The column names you specify identify the columns of the parent key. The privilege set must include the ALTER or the REFERENCES privilege on the columns of the parent key. A unique index must exist on the parent key columns of the parent table. The relationship name: You can choose a constraint name for the relationship that is defined by a foreign key. If you do not choose a name, DB2 generates one from 400 Application Programming and SQL Guide
  • 417.
    the name ofthe first column of the foreign key, in the same way that it generates the name of an implicitly created table space. For example, the names of the relationships in which the employee-to-project activity table is a dependent would, by default, be recorded (in column RELNAME of SYSIBM.SYSFOREIGNKEYS) as EMPNO and PROJNO. The following example shows a CREATE TABLE statement that specifies constraint names REPAPA and REPAE for the foreign keys in the employee-to-project activity table. CREATE TABLE DSN8910.EMPPROJACT (EMPNO CHAR(6) NOT NULL, PROJNO CHAR(6) NOT NULL, ACTNO SMALLINT NOT NULL, CONSTRAINT REPAPA FOREIGN KEY (PROJNO, ACTNO) REFERENCES DSN8910.PROJACT ON DELETE RESTRICT, CONSTRAINT REPAE FOREIGN KEY (EMPNO) REFERENCES DSN8910.EMP ON DELETE RESTRICT) IN DATABASE DSN8D91A; The name is used in error messages, queries to the catalog, and DROP FOREIGN KEY statements. Hence, you might want to choose one if you are experimenting with your database design and have more than one foreign key beginning with the same column (otherwise DB2 generates the name). Indexes on foreign keys: Although not required, an index on a foreign key is strongly recommended if rows of the parent table are often deleted. The validity of the delete statement, and its possible effect on the dependent table, can be checked through the index. You can create an index on the columns of a foreign key in the same way you create one on any other set of columns. Most often it is not a unique index. If you do create a unique index on a foreign key, it introduces an additional constraint on the values of the columns. To let an index on the foreign key be used on the dependent table for a delete operation on a parent table, the columns of the index on the foreign key must be identical to and in the same order as the columns in the foreign key. A foreign key can also be the primary key; then the primary index is also a unique index on the foreign key. In that case, every row of the parent table has at most one dependent row. The dependent table might be used to hold information that pertains to only a few of the occurrences of the entity described by the parent table. For example, a dependent of the employee table might contain information that applies only to employees working in a different country. The primary key can share columns of the foreign key if the first n columns of the foreign key are the same as the primary key’s columns. Again, the primary index serves as an index on the foreign key. In the sample project activity table, the primary index (on PROJNO, ACTNO, ACSTDATE) serves as an index on the foreign key on PROJNO. It does not serve as an index on the foreign key on ACTNO, because ACTNO is not the first column of the index. The FOREIGN KEY clause in ALTER TABLE: You can add a foreign key to an existing table; in fact, that is sometimes the only way to proceed. To make a table self-referencing, you must add a foreign key after creating it. Chapter 4. Creating and modifying DB2 objects 401
  • 418.
    When a foreignkey is added to a populated table, the table space is put into check pending status. Maintaining referential integrity when using data encryption If you use encrypted data in a referential constraint, the primary key of the parent table and the foreign key of the dependent table must have the same encrypted value. The encrypted value should be extracted from the parent table (the primary key) and used for the dependent table (the foreign key). You can do this in one of the following two ways: v Use the FINAL TABLE clause on a SELECT from UPDATE, SELECT from INSERT, or SELECT from MERGE statement. v Use the ENCRYPT_TDES function to encrypt the foreign key using the same password as the primary key. The encrypted value of the foreign key will be the same as the encrypted value of the primary key. | | The SET ENCRYPTION PASSWORD statement sets the password that will be used for the ENCRYPT_TDES function. For more information about the SET ENCRYPTION PASSWORD special register, see the topic “ENCRYPTION PASSWORD” in DB2 SQL Reference. For more information about the ENCRYPT_TDES statement, see the topic “ENCRYPT_TDES” in DB2 SQL Reference. Creating work tables for the EMP and DEPT sample tables Before testing SQL statements that insert, update, and delete rows in the DSN8910.EMP and DSN8910.DEPT sample tables, you should create duplicates of these tables, so that the original sample tables remain intact. These duplicate tables are called work tables. This topic shows how to create the department and employee work tables and how to fill a work table with the contents of another table: Each of these topics assumes that you logged on by using your own authorization ID. The authorization ID qualifies the name of each object that you create. For example, if your authorization ID is SMITH, and you create table YDEPT, the name of the table is SMITH.YDEPT. If you want to access table DSN8910.DEPT, you must refer to it by its complete name. If you want to access your own table YDEPT, you need only to refer to it as YDEPT. Use the following statements to create a new department table called YDEPT, modeled after the existing table, DSN8910.DEPT, and an index for YDEPT: CREATE TABLE YDEPT LIKE DSN8910.DEPT; CREATE UNIQUE INDEX YDEPTX ON YDEPT (DEPTNO); If you want DEPTNO to be a primary key, as in the sample table, explicitly define the key. Use an ALTER TABLE statement, as in the following example: ALTER TABLE YDEPT PRIMARY KEY(DEPTNO); 402 Application Programming and SQL Guide
  • 419.
    You can usean INSERT statement to copy the rows of the result table of a fullselect from one table to another. The following statement copies all of the rows from DSN8910.DEPT to your own YDEPT work table: INSERT INTO YDEPT SELECT * FROM DSN8910.DEPT; For information about using the INSERT statement, see “Inserting rows by using the INSERT statement” on page 561. You can use the following statements to create a new employee table called YEMP: CREATE TABLE YEMP (EMPNO CHAR(6) FIRSTNME VARCHAR(12) MIDINIT CHAR(1) LASTNAME VARCHAR(15) WORKDEPT CHAR(3) PRIMARY KEY NOT NULL, NOT NULL, NOT NULL, NOT NULL, REFERENCES YDEPT ON DELETE SET NULL, PHONENO CHAR(4) UNIQUE NOT NULL, HIREDATE DATE , JOB CHAR(8) , EDLEVEL SMALLINT , SEX CHAR(1) , BIRTHDATE DATE , SALARY DECIMAL(9, 2) , BONUS DECIMAL(9, 2) , COMM DECIMAL(9, 2) ); This statement also creates a referential constraint between the foreign key in YEMP (WORKDEPT) and the primary key in YDEPT (DEPTNO). It also restricts all phone numbers to unique numbers. If you want to change a table definition after you create it, use the ALTER TABLE statement with a RENAME clause. If you want to change a table name after you create it, use the RENAME statement. You can change a table definition by using the ALTER TABLE statement only in certain ways. For example, you can add and drop constraints on columns in a table. You can also change the data type of a column within character data types, within numeric data types, and within graphic data types. You can add a column to a table. However, you cannot use the ALTER TABLE statement to drop a column from a table. For more information about changing a table definition by using ALTER TABLE, see the topic “Altering DB2 tables” in DB2 Administration Guide. For more information about the syntax of the ALTER TABLE statement, see the topic “ALTER TABLE” in DB2 SQL Reference. For more information about the syntax of the RENAME statement, see the topic “RENAME” in DB2 SQL Reference. Creating created temporary tables Use created temporary tables when you need to store data for only the life of an application process, but you want to share the table definition. DB2 does not perform logging and locking operations for created temporary tables, so that SQL statements that use these tables can execute queries efficiently. Each application process has its own instance of the created temporary table. Chapter 4. Creating and modifying DB2 objects 403
  • 420.
    You create thedefinition of a created temporary table using the SQL CREATE GLOBAL TEMPORARY TABLE statement. Example: The following statement creates the definition of a table called TEMPPROD: CREATE GLOBAL TEMPORARY TABLE TEMPPROD (SERIAL CHAR(8) NOT NULL, DESCRIPTION VARCHAR(60) NOT NULL, MFGCOST DECIMAL(8,2), MFGDEPT CHAR(3), MARKUP SMALLINT, SALESDEPT CHAR(3), CURDATE DATE NOT NULL); Example: You can also create this same definition by copying the definition of a base table (named PROD) by using the LIKE clause: CREATE GLOBAL TEMPORARY TABLE TEMPPROD LIKE PROD; The SQL statements in the previous examples create identical definitions for the TEMPPROD table, but these tables differ slightly from the PROD sample table PROD. The PROD sample table contains two columns, DESCRIPTION and CURDATE, that are defined as NOT NULL WITH DEFAULT. Because created temporary tables do not support non-null default values, the DESCRIPTION and CURDATE columns in the TEMPPROD table are defined as NOT NULL and do not have defaults. After you run one of the two CREATE statements, the definition of TEMPPROD exists, but no instances of the table exist. To create an instance of TEMPPROD, you must use TEMPPROD in an application. DB2 creates an instance of the table when TEMPPROD is specified in one of the following SQL statements: v OPEN v SELECT v INSERT v DELETE Restriction: You cannot use the MERGE statement with created temporary tables. An instance of a created temporary table exists at the current server until one of the following actions occurs: v The application process ends. v The remote server connection through which the instance was created terminates. v The unit of work in which the instance was created completes. When you run a ROLLBACK statement, DB2 deletes the instance of the created temporary table. When you run a COMMIT statement, DB2 deletes the instance of the created temporary table unless a cursor for accessing the created temporary table is defined with the WITH HOLD clause and is open. Example: Suppose that you create a definition of TEMPPROD and then run an application that contains the following statements: EXEC EXEC EXEC . . . EXEC . . . EXEC 404 SQL DECLARE C1 CURSOR FOR SELECT * FROM TEMPPROD; SQL INSERT INTO TEMPPROD SELECT * FROM PROD; SQL OPEN C1; SQL COMMIT; SQL CLOSE C1; Application Programming and SQL Guide
  • 421.
    When you runthe INSERT statement, DB2 creates an instance of TEMPPROD and populates that instance with rows from table PROD. When the COMMIT statement runs, DB2 deletes all rows from TEMPPROD. However, assume that you change the declaration of cursor C1 to the following declaration: EXEC SQL DECLARE C1 CURSOR WITH HOLD FOR SELECT * FROM TEMPPROD; In this case, DB2 does not delete the contents of TEMPPROD until the application ends because C1, a cursor that is defined with the WITH HOLD clause, is open when the COMMIT statement runs. In either case, DB2 drops the instance of TEMPPROD when the application ends. To drop the definition of TEMPPROD, you must run the following statement: DROP TABLE TEMPPROD; Temporary tables Use temporary tables when you need to store data for only the duration of an application process. Depending on whether you want to share the table definition, you can create a created temporary table or a declared temporary table. The two kinds of temporary tables are: v Created temporary tables, which you define using a CREATE GLOBAL TEMPORARY TABLE statement v Declared temporary tables, which you define using a DECLARE GLOBAL TEMPORARY TABLE statement SQL statements that use temporary tables can run faster because of the following reasons: v DB2 does no logging (for created temporary tables) or limited logging (for declared temporary tables). v DB2 does no locking (for created temporary tables) or limited locking (for declared temporary tables). Temporary tables are especially useful when you need to sort or query intermediate result tables that contain a large number of rows, but you want to store only a small subset of those rows permanently. Temporary tables can also return result sets from stored procedures. The following topics provide more details about created temporary tables and declared temporary tables: v “Creating created temporary tables” on page 403 v “Creating declared temporary tables” For more information, see “Writing an external procedure to return result sets to a DRDA client” on page 545. Creating declared temporary tables Use declared temporary tables when you need to store data for only the life of an application process and do not need to share the table definition. The definition of this table exists only while the application process runs. DB2 performs limited logging and locking operations for declared temporary tables. You create an instance of a declared temporary table by using the SQL DECLARE GLOBAL TEMPORARY TABLE statement. That instance is known only to the Chapter 4. Creating and modifying DB2 objects 405
  • 422.
    application process inwhich the table is declared, so you can declare temporary tables with the same name in different applications. The qualifier for a declared temporary table is SESSION. Before you can define declared temporary tables, you must have a WORKFILE database that has at least one table space with a 32-KB page size. | | To create a declared temporary table, specify the DECLARE GLOBAL TEMPORARY TABLE statement. In that statement, specify the columns that the table is to contain by performing one of the following actions: v Specify all the columns in the table. Unlike columns of created temporary tables, columns of declared temporary tables can include the WITH DEFAULT clause. v Use a LIKE clause to copy the definition of a base table, created temporary table, or view. If the base table, created temporary table, or view from which you select columns has identity columns, you can specify that the corresponding columns in the declared temporary table are also identity columns. To include these identity columns, specify the INCLUDING IDENTITY COLUMN ATTRIBUTES clause when you define the declared temporary table. If the source table has a row change timestamp column, you can specify that those column attributes are inherited in the declared temporary table by specifying INCLUDING ROW CHANGE TIMESTAMP COLUMN ATTRIBUTES. v Use a fullselect to choose specific columns from a base table, created temporary table, or view. If you want the declared temporary table columns to inherit the defaults for columns of the table or view that is named in the fullselect, specify the INCLUDING COLUMN DEFAULTS clause. If you want the declared temporary table columns to have default values that correspond to their data types, specify the USING TYPE DEFAULTS clause. | | | Example: The following statement defines a declared temporary table called TEMPPROD by explicitly specifying the columns. DECLARE GLOBAL (SERIAL DESCRIPTION PRODCOUNT MFGCOST MFGDEPT MARKUP SALESDEPT CURDATE TEMPORARY TABLE TEMPPROD CHAR(8) NOT NULL WITH DEFAULT ’99999999’, VARCHAR(60) NOT NULL, INTEGER GENERATED ALWAYS AS IDENTITY, DECIMAL(8,2), CHAR(3), SMALLINT, CHAR(3), DATE NOT NULL); Example: The following statement defines a declared temporary table called TEMPPROD by copying the definition of a base table. The base table has an identity column that the declared temporary table also uses as an identity column. DECLARE GLOBAL TEMPORARY TABLE TEMPPROD LIKE BASEPROD INCLUDING IDENTITY COLUMN ATTRIBUTES; Example: The following statement defines a declared temporary table called TEMPPROD by selecting columns from a view. The view has an identity column that the declared temporary table also uses as an identity column. The declared temporary table inherits its default column values from the default column values of a base table on which the view is based. 406 Application Programming and SQL Guide
  • 423.
    DECLARE GLOBAL TEMPORARYTABLE TEMPPROD AS (SELECT * FROM PRODVIEW) DEFINITION ONLY INCLUDING IDENTITY COLUMN ATTRIBUTES INCLUDING COLUMN DEFAULTS; After you run a DECLARE GLOBAL TEMPORARY TABLE statement, the definition of the declared temporary table exists as long as the application process runs. If you need to delete the definition before the application process completes, you can do that with the DROP TABLE statement. For example, to drop the definition of TEMPPROD, run the following statement: DROP TABLE SESSION.TEMPPROD; DB2 creates an empty instance of a declared temporary table when it runs the DECLARE GLOBAL TEMPORARY TABLE statement. You can then perform the following actions: v Populate the declared temporary table by using INSERT statements v Modify the table using searched or positioned UPDATE or DELETE statements v Query the table using SELECT statements v Create indexes on the declared temporary table The ON COMMIT clause that you specify in the DECLARE GLOBAL TEMPORARY TABLE statement determines whether DB2 keeps or deletes all the rows from the table when you run a COMMIT statement in an application with a declared temporary table. ON COMMIT DELETE ROWS, which is the default, causes all rows to be deleted from the table at a commit point, unless a held cursor is open on the table at the commit point. ON COMMIT PRESERVE ROWS causes the rows to remain past the commit point. Example: Suppose that you run the following statement in an application program: EXEC SQL DECLARE GLOBAL TEMPORARY TABLE TEMPPROD AS (SELECT * FROM BASEPROD) DEFINITION ONLY INCLUDING IDENTITY COLUMN ATTRIBUTES INCLUDING COLUMN DEFAULTS ON COMMIT PRESERVE ROWS; EXEC SQL INSERT INTO SESSION.TEMPPROD SELECT * FROM BASEPROD; . . . EXEC SQL COMMIT; . . . When DB2 runs the preceding DECLARE GLOBAL TEMPORARY TABLE statement, DB2 creates an empty instance of TEMPPROD. The INSERT statement populates that instance with rows from table BASEPROD. The qualifier, SESSION, must be specified in any statement that references TEMPPROD. When DB2 executes the COMMIT statement, DB2 keeps all rows in TEMPPROD because TEMPPROD is defined with ON COMMIT PRESERVE ROWS. When the program ends, DB2 drops TEMPPROD. Providing a unique key for a table Use ROWID columns or identity columns to store unique values for each row in a table. Chapter 4. Creating and modifying DB2 objects 407
  • 424.
    Question: How canI provide a unique identifier for a table that has no unique column? Answer: Add a column with the data type ROWID or an identity column. ROWID columns and identity columns contain a unique value for each row in the table. You can define the column as GENERATED ALWAYS, which means that you cannot insert values into the column, or GENERATED BY DEFAULT, which means that DB2 generates a value if you do not specify one. If you define the ROWID or identity column as GENERATED BY DEFAULT, you need to define a unique index that includes only that column to guarantee uniqueness. | Fixing tables with incomplete definitions | | | | If a table has an incomplete definition, you cannot load the table, insert data, retrieve data, update data, delete data, or create foreign keys that reference the primary key. You can drop the table, create the primary index, and drop or create other indexes. | | To check if a table has an incomplete definition, look at the TABLESTATUS column in SYSIBM.SYSTABLES. The value P indicates that the definition is incomplete. | | | | | A table definition is incomplete in any of the following circumstances: v If the table is defined with a primary or unique key and all of the following conditions are true: – The table space for the table was explicitly created. – The statement is not being run with schema processor. – The table does not have a primary or unique index for the defined primary or unique key. | | | | | | | v If the table has a ROWID column that is defined as generated by default and all of the following conditions are true: – The table space for the table was explicitly created. – The SET CURRENT RULES special register is not set to STD. – No index is defined on the ROWID column. v If the table has a LOB column and all of the following conditions are true: – The table space for the table was explicitly created. – The SET CURRENT RULES special register is not set to STD. – No auxiliary LOB objects are defined for the LOB column. | | | You can complete the table definition by performing one of the following actions, depending on why the table definition was incomplete: v Creating a primary index or altering the table to drop the primary key. | | v Creating a unique index or altering the table to drop the unique key. v Defining an index on the ROWID column. v Creating the necessary LOB objects. | | | | | | | | | Example of creating a primary index: To create the primary index for the project activity table, issue the following SQL statement: | | If you later drop the primary index, the table reverts to incomplete definition status. CREATE UNIQUE INDEX XPROJAC1 ON DSN8910.PROJACT (PROJNO, ACTNO, ACSTDATE); 408 Application Programming and SQL Guide
  • 425.
    Dropping tables When youdrop a table, you delete the data and the table definition. You also delete all synonyms, views, indexes, and referential and check constraints that are associated with that table. The following SQL statement drops the YEMP table: DROP TABLE YEMP; Use the DROP TABLE statement with care: Dropping a table is not equivalent to deleting all its rows. When you drop a table, you lose more than its data and its definition. You lose all synonyms, views, indexes, and referential and check constraints that are associated with that table. You also lose all authorities that are granted on the table. For more information about the syntax of the DROP statement, see the topic “DROP” in DB2 SQL Reference. Defining a view A view is a named specification of a result table. Use views to control which users have access to certain data or to simplify writing SQL statements. Use the CREATE VIEW statement to define a view and give the view a name, just as you do for a table. The view that is created with the following statement shows each department manager’s name with the department data in the DSN8910.DEPT table. CREATE VIEW VDEPTM AS SELECT DEPTNO, MGRNO, LASTNAME, ADMRDEPT FROM DSN8910.DEPT, DSN8910.EMP WHERE DSN8910.EMP.EMPNO = DSN8910.DEPT.MGRNO; When a program accesses the data that is defined by a view, DB2 uses the view definition to return a set of rows that the program can access with SQL statements. Example: To see the departments that are administered by department D01 and the managers of those departments, run the following statement, which returns information from the VDEPTM view: SELECT DEPTNO, LASTNAME FROM VDEPTM WHERE ADMRDEPT = ’DO1’; | | | | | | When you create a view, you can reference the SESSION_USER and CURRENT SQLID special registers in the CREATE VIEW statement. When referencing the view, DB2 uses the value of the SESSION_USER or CURRENT SQLID special register that belongs to the user of the SQL statement (SELECT, UPDATE, INSERT, or DELETE) rather than the creator of the view. In other words, a reference to a special register in a view definition refers to its run-time value. A column in a view might be based on a column in a base table that is an identity column. The column in the view is also an identity column,except under any of the following circumstances: v The column appears more than once in the view. v The view is based on a join of two or more tables. v The view is based on the union of two or more tables. Chapter 4. Creating and modifying DB2 objects 409
  • 426.
    v Any columnin the view is derived from an expression that refers to an identity column. You can use views to limit access to certain kinds of data, such as salary information. Alternatively, you can use the IMPLICITLY HIDDEN clause of a CREATE TABLE statement define a column of a table to be hidden from some operations. | | | | You can also use views for the following actions: v Make a subset of a table’s data available to an application. For example, a view based on the employee table might contain rows only for a particular department. v Combine columns from two or more tables and make the combined data available to an application. By using a SELECT statement that matches values in one table with those in another table, you can create a view that presents data from both tables. However, you can only select data from this type of view. You cannot update, delete, or insert data using a view that joins two or more tables. v Combine rows from two or more tables and make the combined data available to an application. By using two or more subselects that are connected by a set operator such as UNION, you can create a view that presents data from several tables. However, you can only select data from this type of view. You cannot update, delete, or insert data using a view that contains UNION operations. v Present computed data, and make the resulting data available to an application. You can compute such data using any function or operation that you can use in a SELECT statement. Views A view does not contain data; it is a stored definition of a set of rows and columns. A view can present any or all of the data in one or more tables and, in most cases, is interchangeable with a table. Although you cannot modify an existing view, you can drop it and create a new one if your base tables change in a way that affects the view. Dropping and creating views does not affect the base tables or their data. Restrictions when changing data through a view Some views are read-only and thus cannot be used to update the table data. For those views that are updatable, several restrictions apply. Consider the following restrictions when changing data through a view: v You must have the appropriate authorization to insert, update, or delete rows using the view. v When you use a view to insert a row into a table, the view definition must specify all the columns in the base table that do not have a default value. The row that is being inserted must contain a value for each of those columns. v Views that you can use to update data are subject to the same referential constraints and check constraints as the tables that you used to define the views. You can use the WITH CHECK option of the CREATE VIEW statement to specify the constraint that every row that is inserted or updated through the 410 Application Programming and SQL Guide
  • 427.
    view must conformto the definition of the view. You can select every row that is inserted or updated through a view that is created with the WITH CHECK option. | | For complex views, you can make insert, update and delete operations possible by defining INSTEAD OF triggers. For more information about INSTEAD OF triggers, see “Inserting, updating, and deleting data in views by using INSTEAD OF triggers” on page 426. For more information about read-only views, see the topic “CREATE VIEW” in DB2 SQL Reference. Dropping a view When you drop a view, you also drop all views that are defined on that view. The base table is not affected. Example: The following SQL statement drops the VDEPTM view: DROP VIEW VDEPTM; Creating a common table expression Creating a common table expression saves you the overhead of creating and dropping a regular view that you need to use only once. Also, during statement preparation, DB2 does not need to access the catalog for the view, which saves you additional overhead. Use the WITH clause to create a common table expression. You can use a common table expression in a SELECT statement by using the WITH clause at the beginning of the statement. Example: WITH clause in a SELECT statement: The following statement finds the department with the highest total pay. The query involves two levels of aggregation. First, you need to determine the total pay for each department by using the SUM function and order the results by using the GROUP BY clause. You then need to find the department with highest total pay based on the total pay for each department. WITH DTOTAL (deptno, totalpay) AS (SELECT deptno, sum(salary+bonus) FROM DSN8810.EMP GROUP BY deptno) SELECT deptno FROM DTOTAL WHERE totalpay = (SELECT max(totalpay) FROM DTOTAL); The result table for the common table expression, DTOTAL, contains the department number and total pay for each department in the employee table. The fullselect in the previous example uses the result table for DTOTAL to find the department with the highest total pay. The result table for the entire statement looks similar to the following results: DEPTNO ====== D11 Chapter 4. Creating and modifying DB2 objects 411
  • 428.
    Using common tableexpressions with views: You can use common table expressions before a fullselect in a CREATE VIEW statement. This technique is useful if you need to use the results of a common table expression in more than one query. Example: Using a WITH clause in a CREATE VIEW statement: The following statement finds the departments that have a greater-than-average total pay and saves the results as the view RICH_DEPT: CREATE VIEW RICH_DEPT (deptno) AS WITH DTOTAL (deptno, totalpay) AS (SELECT deptno, sum(salary+bonus) FROM DSN8910.EMP GROUP BY deptno) SELECT deptno FROM DTOTAL WHERE totalpay > (SELECT AVG(totalpay) FROM DTOTAL); The fullselect in the previous example uses the result table for DTOTAL to find the departments that have a greater-than-average total pay. The result table is saved as the RICH_DEPT view and looks similar to the following results: DEPTNO ====== A00 D11 D21 Using common table expressions when you use INSERT: You can use common table expressions before a fullselect in an INSERT statement. Example: Using a common table expression in an INSERT statement: The following statement uses the result table for VITALDEPT to find the manager’s number for each department that has a greater-than-average number of senior engineers. Each manager’s number is then inserted into the vital_mgr table. INSERT INTO vital_mgr (mgrno) WITH VITALDEPT (deptno, se_count) AS (SELECT deptno, count(*) FROM DSN8910.EMP WHERE job = ’senior engineer’ GROUP BY deptno) SELECT d.manager FROM DSN8910.DEPT d, VITALDEPT s WHERE d.deptno = s.deptno AND s.se_count > (SELECT AVG(se_count) FROM VITALDEPT); Common table expressions Acommon table expression is like a temporary view that is defined and used for the duration of an SQL statement. You can define a common table expression wherever you can have a fullselect statement. For example, you can include a common table expression in a SELECT, INSERT, or CREATE VIEW statement. | | | Each common table expression must have a unique name and be defined only once. However, you can reference a common table expression many times in the same SQL statement. Unlike regular views or nested table expressions, which 412 Application Programming and SQL Guide
  • 429.
    derive their resulttables for each reference, all references to common table expressions in a given statement share the same result table. You can use a common table expression in the following situations: v When you want to avoid creating a view (when general use of the view is not required, and positioned updates or deletes are not used) v When the desired result table is based on host variables v When the same result table needs to be shared in a fullselect v When the results need to be derived using recursion Examples of recursive common table expressions Recursive SQL is very useful in bill of materials (BOM) applications. These examples illustrate some of the capability of a recursive common table expression for BOM applications. Consider a table of parts with associated subparts and the quantity of subparts required by each part. For more information about recursive SQL, refer to “Creating recursive SQL by using common table expressions” on page 612. For the examples in this topic, create the following table: CREATE TABLE PARTLIST (PART VARCHAR(8), SUBPART VARCHAR(8), QUANTITY INTEGER); Assume that the PARTLIST table is populated with the values that are in Table 79: Table 79. PARTLIST table PART SUBPART QUANTITY 00 01 5 00 05 3 01 02 2 01 03 3 01 04 4 01 06 3 02 05 7 02 06 6 03 07 6 04 08 10 04 09 11 05 10 10 05 11 10 06 12 10 06 13 10 07 14 8 07 12 8 Chapter 4. Creating and modifying DB2 objects 413
  • 430.
    Example 1: Singlelevel explosion: Single level explosion answers the question, ″What parts are needed to build the part identified by ’01’?″. The list will include the direct subparts, subparts of the subparts and so on. However, if a part is used multiple times, its subparts are only listed once. WITH RPL (PART, SUBPART, QUANTITY) AS (SELECT ROOT.PART, ROOT.SUBPART, ROOT.QUANTITY FROM PARTLIST ROOT WHERE ROOT.PART = ’01’ UNION ALL SELECT CHILD.PART, CHILD.SUBPART, CHILD.QUANTITY FROM RPL PARENT, PARTLIST CHILD WHERE PARENT.SUBPART = CHILD.PART) SELECT DISTINCT PART, SUBPART, QUANTITY FROM RPL ORDER BY PART, SUBPART, QUANTITY; The preceding query includes a common table expression, identified by the name RPL, that expresses the recursive part of this query. It illustrates the basic elements of a recursive common table expression. The first operand (fullselect) of the UNION, referred to as the initialization fullselect, gets the direct subparts of part ’01’. The FROM clause of this fullselect refers to the source table and will never refer to itself (RPL in this case). The result of this first fullselect goes into the common table expression RPL. As in this example, the UNION must always be a UNION ALL. The second operand (fullselect) of the UNION uses RPL to compute subparts of subparts by using the FROM clause to refer to the common table expression RPL and the source table PARTLIST with a join of a part from the source table (child) to a subpart of the current result contained in RPL (parent). The result goes then back to RPL again. The second operand of UNION is used repeatedly until no more subparts exist. The SELECT DISTINCT in the main fullselect of this query ensures the same part/subpart is not listed more than once. The result of the query is shown in Table 80: Table 80. Result table for example 1 PART QUANTITY 01 02 2 01 03 3 01 04 4 01 06 3 02 05 7 02 06 6 03 07 6 04 08 10 04 09 11 05 10 10 05 11 10 06 12 10 06 414 SUBPART 13 10 Application Programming and SQL Guide
  • 431.
    Table 80. Resulttable for example 1 (continued) PART SUBPART QUANTITY 07 12 8 17 14 8 Observe in the result that part ’01’ contains subpart ’02’ which contains subpart ’06’ and so on. Further, boo pdfe that part ’06’ is reached twice, once through part ’01’ directly and another time through part ’02’. In the output, however, the subparts of part ’06’ are listed only once (this is the result of using a SELECT DISTINCT). Remember that with recursive common table expressions it is possible to introduce an infinite loop. In this example, an infinite loop would be created if the search condition of the second operand that joins the parent and child tables was coded as follows: WHERE PARENT.SUBPART = CHILD.SUBPART This infinite loop is created by not coding what is intended. You should carefully determining what to code so that there is a definite end of the recursion cycle. The result produced by this example could be produced in an application program without using a recursive common table expression. However, such an application would require coding a different query for every level of recursion. Furthermore, the application would need to put all of the results back in the database to order the final result. This approach complicates the application logic and does not perform well. The application logic becomes more difficult and inefficient for other bill of material queries, such as summarized and indented explosion queries. Example 2: Summarized explosion: A summarized explosion answers the question, ″What is the total quantity of each part required to build part ’01’?″ The main difference from a single level explosion is the need to aggregate the quantities. A single level explosion indicates the quantity of subparts required for the part whenever it is required. It does not indicate how many of each subpart is needed to build part ’01’. WITH RPL (PART, SUBPART, QUANTITY) AS ( SELECT ROOT.PART, ROOT.SUBPART, ROOT.QUANTITY FROM PARTLIST ROOT WHERE ROOT.PART = ’01’ UNION ALL SELECT PARENT.PART, CHILD.SUBPART, PARENT.QUANTITY*CHILD.QUANTITY FROM RPL PARENT, PARTLIST CHILD WHERE PARENT.SUBPART = CHILD.PART ) SELECT PART, SUBPART, SUM(QUANTITY) AS "Total QTY Used" FROM RPL GROUP BY PART, SUBPART ORDER BY PART, SUBPART; In the preceding query, the select list of the second operand of the UNION in the recursive common table expression, identified by the name RPL, shows the aggregation of the quantity. To determine how many of each subpart is used, the quantity of the parent is multiplied by the quantity per parent of a child. If a part is used multiple times in different places, it requires another final aggregation. This Chapter 4. Creating and modifying DB2 objects 415
  • 432.
    is done bythe grouping the parts and subparts in the common table expression RPL and using the SUM column function in the select list of the main fullselect. The result of the query is shown in Table 81: Table 81. Result table for example 2 PART SUBPART Total QTY Used 01 02 2 01 03 3 01 04 4 01 05 14 01 06 15 01 07 18 01 08 40 01 09 44 01 10 140 01 11 140 01 12 294 01 13 150 01 14 144 Consider the total quantity for subpart ’06’. The value of 15 is derived from a quantity of 3 directly for part ’01’ and a quantity of 6 for part ’02’ which is needed two times by part ’01’. Example 3: Controlling depth: You can control the depth of a recursive query to answer the question, ″What are the first two levels of parts that are needed to build part ’01’?″ For the sake of clarity in this example, the level of each part is included in the result table. WITH RPL (LEVEL, PART, SUBPART, QUANTITY) AS ( SELECT 1, ROOT.PART, ROOT.SUBPART, ROOT.QUANTITY FROM PARTLIST ROOT WHERE ROOT.PART = ’01’ UNION ALL SELECT PARENT.LEVEL+1, CHILD.PART, CHILD.SUBPART, CHILD.QUANTITY FROM RPL PARENT, PARTLIST CHILD WHERE PARENT.SUBPART = CHILD.PART AND PARENT.LEVEL < 2 ) SELECT PART, LEVEL, SUBPART, QUANTITY FROM RPL; This query is similar to the query in example 1. The column LEVEL is introduced to count the level each subpart is from the original part. In the initialization fullselect, the value for the LEVEL column is initialized to 1. In the subsequent fullselect, the level from the parent table increments by 1. To control the number of levels in the result, the second fullselect includes the condition that the level of the parent must be less than 2. This ensures that the second fullselect only processes children to the second level. 416 Application Programming and SQL Guide
  • 433.
    The result ofthe query is shown in Table 82: Table 82. Result table for example 3 PART LEVEL SUBPART QUANTITY 01 1 02 2 01 1 03 3 01 1 04 4 01 1 06 3 02 2 05 7 02 2 06 6 03 2 07 6 04 2 08 10 04 2 09 11 06 2 12 10 06 2 13 10 Creating triggers A trigger is a set of SQL statements that execute when a certain event occurs in a table. Use triggers to control changes in DB2 databases. Triggers are more powerful than constraints, because they can monitor a broader range of changes and perform a broader range of actions than constraints can. Using triggers for active data: For example, a constraint can disallow an update to the salary column of the employee table if the new value is over a certain amount. A trigger can monitor the amount by which the salary changes, as well as the salary value. If the change is above a certain amount, the trigger might substitute a valid value and call a user-defined function to send a boo pdfe to an administrator about the invalid update. Triggers also move application logic into DB2, which can result in faster application development and easier maintenance. For example, you can write applications to control salary changes in the employee table, but each application program that changes the salary column must include logic to check those changes. A better method is to define a trigger that controls changes to the salary column. Then DB2 does the checking for any application that modifies salaries. Example of creating and using a trigger: Triggers automatically execute a set of SQL statements whenever a specified event occurs. These SQL statements can perform tasks such as validation and editing of table changes, reading and modifying tables, or invoking functions or stored procedures that perform operations both inside and outside DB2. You create triggers using the CREATE TRIGGER statement. The following figure shows an example of a CREATE TRIGGER statement. 1 CREATE TRIGGER REORDER 2 3 4 AFTER UPDATE OF ON_HAND, MAX_STOCKED ON PARTS Chapter 4. Creating and modifying DB2 objects 417
  • 434.
    5 REFERENCING NEW ASN_ROW 6 FOR EACH ROW MODE DB2SQL 7 WHEN (N_ROW.ON_HAND < 0.10 * N_ROW.MAX_STOCKED) 8 BEGIN ATOMIC CALL ISSUE_SHIP_REQUEST(N_ROW.MAX_STOCKED N_ROW.ON_HAND, N_ROW.PARTNO); END The parts of this trigger are: 1 Trigger name (REORDER) 2 Trigger activation time (AFTER) 3 Triggering event (UPDATE) 4 Subject table name (PARTS) 5 New transition variable correlation name (N_ROW) 6 Granularity (FOR EACH ROW) 7 Trigger condition (WHEN...) 8 Trigger body (BEGIN ATOMIC...END;) When you execute this CREATE TRIGGER statement, DB2 creates a trigger package called REORDER and associates the trigger package with table PARTS. DB2 records the timestamp when it creates the trigger. If you define other triggers on the PARTS table, DB2 uses this timestamp to determine which trigger to activate first. The trigger is now ready to use. After DB2 updates columns ON_HAND or MAX_STOCKED in any row of table PARTS, trigger REORDER is activated. The trigger calls a stored procedure called ISSUE_SHIP_REQUEST if, after a row is updated, the quantity of parts on hand is less than 10% of the maximum quantity stocked. In the trigger condition, the qualifier N_ROW represents a value in a modified row after the triggering event. When you no longer want to use trigger REORDER, you can delete the trigger by executing the statement: DROP TRIGGER REORDER; Executing this statement drops trigger REORDER and its associated trigger package named REORDER. If you drop table PARTS, DB2 also drops trigger REORDER and its trigger package. Parts of a trigger: A trigger contains the following parts: v trigger name v subject table v trigger activation time v triggering event v granularity v transition variables 418 Application Programming and SQL Guide
  • 435.
    v transition tables vtriggered action Trigger name: Use an ordinary identifier to name your trigger. You can use a qualifier or let DB2 determine the qualifier. When DB2 creates a trigger package for the trigger, it uses the qualifier for the collection ID of the trigger package. DB2 uses these rules to determine the qualifier: v If you use static SQL to execute the CREATE TRIGGER statement, DB2 uses the authorization ID in the bind option QUALIFIER for the plan or package that contains the CREATE TRIGGER statement. If the bind command does not include the QUALIFIER option, DB2 uses the owner of the package or plan. | | v If you use dynamic SQL to execute the CREATE TRIGGER statement, DB2 uses the authorization ID in special register CURRENT SCHEMA. Subject table: When you perform an insert, update, or delete operation on this table, the trigger is activated. You must name a local table in the CREATE TRIGGER statement. You cannot define a trigger on a catalog table or on a view. Trigger activation time: The two choices for trigger activation time are NO CASCADE BEFORE and AFTER. NO CASCADE BEFORE means that the trigger is activated before DB2 makes any changes to the subject table, and that the triggered action does not activate any other triggers. AFTER means that the trigger is activated after DB2 makes changes to the subject table and can activate other triggers. Triggers with an activation time of NO CASCADE BEFORE are known as before triggers. Triggers with an activation time of AFTER are known as after triggers. Triggering event: Every trigger is associated with an event. A trigger is activated when the triggering event occurs in the subject table. The triggering event is one of the following SQL operations: v insert v update v delete A triggering event can also be an update or delete operation that occurs as the result of a referential constraint with ON DELETE SET NULL or ON DELETE CASCADE. Triggers are not activated as the result of updates made to tables by DB2 utilities, with the exception of the LOAD utility when it is specified with the RESUME YES and SHRLEVEL CHANGE options. For more information about these options, see the topic “LOAD” in DB2 Utility Guide and Reference. When the triggering event for a trigger is an update operation, the trigger is called an update trigger. Similarly, triggers for insert operations are called insert triggers, and triggers for delete operations are called delete triggers. Chapter 4. Creating and modifying DB2 objects 419
  • 436.
    The SQL statementthat performs the triggering SQL operation is called the triggering SQL statement. Each triggering event is associated with one subject table and one SQL operation. The following trigger is defined with an insert triggering event: CREATE TRIGGER NEW_HIRE AFTER INSERT ON EMP FOR EACH ROW MODE DB2SQL BEGIN ATOMIC UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1; END If the triggering SQL operation is an update operation, the event can be associated with specific columns of the subject table. In this case, the trigger is activated only if the update operation updates any of the specified columns. The following trigger, PAYROLL1, which invokes user-defined function named PAYROLL_LOG, is activated only if an update operation is performed on the SALARY or BONUS column of table PAYROLL: CREATE TRIGGER PAYROLL1 AFTER UPDATE OF SALARY, BONUS ON PAYROLL FOR EACH STATEMENT MODE DB2SQL BEGIN ATOMIC VALUES(PAYROLL_LOG(USER, ’UPDATE’, CURRENT TIME, CURRENT DATE)); END Granularity: The triggering SQL statement might modify multiple rows in the table. The granularity of the trigger determines whether the trigger is activated only once for the triggering SQL statement or once for every row that the SQL statement modifies. The granularity values are: v FOR EACH ROW The trigger is activated once for each row that DB2 modifies in the subject table. If the triggering SQL statement modifies no rows, the trigger is not activated. However, if the triggering SQL statement updates a value in a row to the same value, the trigger is activated. For example, if an UPDATE trigger is defined on table COMPANY_STATS, the following SQL statement will activate the trigger. UPDATE COMPANY_STATS SET NBEMP = NBEMP; v FOR EACH STATEMENT The trigger is activated once when the triggering SQL statement executes. The trigger is activated even if the triggering SQL statement modifies no rows. Triggers with a granularity of FOR EACH ROW are known as row triggers. Triggers with a granularity of FOR EACH STATEMENT are known as statement triggers. Statement triggers can only be after triggers. The following statement is an example of a row trigger: CREATE TRIGGER NEW_HIRE AFTER INSERT ON EMP FOR EACH ROW MODE DB2SQL BEGIN ATOMIC UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1; END Trigger NEW_HIRE is activated once for every row inserted into the employee table. 420 Application Programming and SQL Guide
  • 437.
    Transition variables: When youcode a row trigger, you might need to refer to the values of columns in each updated row of the subject table. To do this, specify transition variables in the REFERENCING clause of your CREATE TRIGGER statement. The two types of transition variables are: v Old transition variables, specified with the OLD transition-variable clause, capture the values of columns before the triggering SQL statement updates them. You can define old transition variables for update and delete triggers. v New transition variables, specified with the NEW transition-variable clause, capture the values of columns after the triggering SQL statement updates them. You can define new transition variables for update and insert triggers. The following example uses transition variables and invocations of the IDENTITY_VAL_LOCAL function to access values that are assigned to identity columns. Suppose that you have created tables T and S, with the following definitions: CREATE TABLE T (ID SMALLINT GENERATED BY DEFAULT AS IDENTITY (START WITH 100), C2 SMALLINT, C3 SMALLINT, C4 SMALLINT); CREATE TABLE S (ID SMALLINT GENERATED ALWAYS AS IDENTITY, C1 SMALLINT); Define a before insert trigger on T that uses the IDENTITY_VAL_LOCAL built-in function to retrieve the current value of identity column ID, and uses transition variables to update the other columns of T with the identity column value. CREATE TRIGGER TR1 NO CASCADE BEFORE INSERT ON T REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL BEGIN ATOMIC SET N.C3 =N.ID; SET N.C4 =IDENTITY_VAL_LOCAL(); SET N.ID =N.C2 *10; SET N.C2 =IDENTITY_VAL_LOCAL(); END Now suppose that you execute the following INSERT statement: INSERT INTO S (C1) VALUES (5); This statement inserts a row into S with a value of 5 for column C1 and a value of 1 for identity column ID. Next, suppose that you execute the following SQL statement, which activates trigger TR1: INSERT INTO T (C2) VALUES (IDENTITY_VAL_LOCAL()); This insert statement, and the subsequent activation of trigger TR1, have the following results: v The INSERT statement obtains the most recent value that was assigned to an identity column (1), and inserts that value into column C2 of table T. 1 is the value that DB2 inserted into identity column ID of table S. v When the INSERT statement executes, DB2 inserts the value 100 into identity column ID column of C2. Chapter 4. Creating and modifying DB2 objects 421
  • 438.
    v The firststatement in the body of trigger TR1 inserts the value of transition variable N.ID (100) into column C3. N.ID is the value that identity column ID contains after the INSERT statement executes. v The second statement in the body of trigger TR1 inserts the null value into column C4. By definition, the result of the IDENTITY_VAL_LOCAL function in the triggered action of a before insert trigger is the null value. v The third statement in the body of trigger TR1 inserts 10 times the value of transition variable N.C2 (10*1) into identity column ID of table T. N.C2 is the value that column C2 contains after the INSERT is executed. v The fourth statement in the body of trigger TR1 inserts the null value into column C2. By definition, the result of the IDENTITY_VAL_LOCAL function in the triggered action of a before insert trigger is the null value. Transition tables: If you want to refer to the entire set of rows that a triggering SQL statement modifies, rather than to individual rows, use a transition table. Like transition variables, transition tables can appear in the REFERENCING clause of a CREATE TRIGGER statement. Transition tables are valid for both row triggers and statement triggers. The two types of transition tables are: v Old transition tables, specified with the OLD TABLE transition-table-name clause, capture the values of columns before the triggering SQL statement updates them. You can define old transition tables for update and delete triggers. v New transition tables, specified with the NEW TABLE transition-table-name clause, capture the values of columns after the triggering SQL statement updates them. You can define new transition variables for update and insert triggers. The scope of old and new transition table names is the trigger body. If another table exists that has the same name as a transition table, any unqualified reference to that name in the trigger body points to the transition table. To reference the other table in the trigger body, you must use the fully qualified table name. The following example uses a new transition table to capture the set of rows that are inserted into the INVOICE table: CREATE TRIGGER LRG_ORDR AFTER INSERT ON INVOICE REFERENCING NEW TABLE AS N_TABLE FOR EACH STATEMENT MODE DB2SQL BEGIN ATOMIC SELECT LARGE_ORDER_ALERT(CUST_NO, TOTAL_PRICE, DELIVERY_DATE) FROM N_TABLE WHERE TOTAL_PRICE > 10000; END The SELECT statement in LRG_ORDER causes user-defined function LARGE_ORDER_ALERT to execute for each row in transition table N_TABLE that satisfies the WHERE clause (TOTAL_PRICE > 10000). Triggered action: When a trigger is activated, a triggered action occurs. Every trigger has one triggered action, which consists of a trigger condition and a trigger body. Trigger condition: 422 Application Programming and SQL Guide
  • 439.
    If you wantthe triggered action to occur only when certain conditions are true, code a trigger condition. A trigger condition is similar to a predicate in a SELECT, except that the trigger condition begins with WHEN, rather than WHERE. If you do not include a trigger condition in your triggered action, the trigger body executes every time the trigger is activated. For a row trigger, DB2 evaluates the trigger condition once for each modified row of the subject table. For a statement trigger, DB2 evaluates the trigger condition once for each execution of the triggering SQL statement. If the trigger condition of a before trigger has a fullselect, the fullselect cannot reference the subject table. The following example shows a trigger condition that causes the trigger body to execute only when the number of ordered items is greater than the number of available items: CREATE TRIGGER CK_AVAIL NO CASCADE BEFORE INSERT ON ORDERS REFERENCING NEW AS NEW_ORDER FOR EACH ROW MODE DB2SQL WHEN (NEW_ORDER.QUANTITY > (SELECT ON_HAND FROM PARTS WHERE NEW_ORDER.PARTNO=PARTS.PARTNO)) BEGIN ATOMIC VALUES(ORDER_ERROR(NEW_ORDER.PARTNO, NEW_ORDER.QUANTITY)); END Trigger body: In the trigger body, you code the SQL statements that you want to execute whenever the trigger condition is true. If the trigger body consists of more than one statement, it must begin with BEGIN ATOMIC and end with END. You cannot include host variables or parameter markers in your trigger body. If the trigger body contains a WHERE clause that references transition variables, the comparison operator cannot be LIKE. The statements you can use in a trigger body depend on the activation time of the trigger. For a list of valid SQL statements for triggers, see the ″Allowable SQL statements″ table in the topic “CREATE TRIGGER” in DB2 SQL Reference. The following list provides more detailed information about SQL statements that are valid in triggers: v fullselect, CALL, and VALUES Use a fullselect or the VALUES statement in a trigger body to conditionally or unconditionally invoke a user-defined function. Use the CALL statement to invoke a stored procedure. See “Invoking stored procedures and user-defined functions from triggers” on page 425 for more information on invoking user-defined functions and stored procedures from triggers. A fullselect in the trigger body of a before trigger cannot reference the subject table. v SIGNAL Use the SIGNAL statement in the trigger body to report an error condition and back out any changes that are made by the trigger, as well as actions that result from referential constraints on the subject table. When DB2 executes the SIGNAL Chapter 4. Creating and modifying DB2 objects 423
  • 440.
    statement, it returnsan SQLCA to the application with SQLCODE -438. The SQLCA also includes the following values, which you supply in the SIGNAL statement: – A 5-character value that DB2 uses as the SQLSTATE – An error message that DB2 places in the SQLERRMC field In the following example, the SIGNAL statement causes DB2 to return an SQLCA with SQLSTATE 75001 and terminate the salary update operation if an employee’s salary increase is over 20%: CREATE TRIGGER SAL_ADJ BEFORE UPDATE OF SALARY ON EMP REFERENCING OLD AS OLD_EMP NEW AS NEW_EMP FOR EACH ROW MODE DB2SQL WHEN (NEW_EMP.SALARY > (OLD_EMP.SALARY * 1.20)) BEGIN ATOMIC SIGNAL SQLSTATE ’75001’ (’Invalid Salary Increase - Exceeds 20%’); END v SET transition-variable Because before triggers operate on rows of a table before those rows are modified, you cannot perform operations in the body of a before trigger that directly modify the subject table. You can, however, use the SET transition-variable statement to modify the values in a row before those values go into the table. For example, this trigger uses a new transition variable to fill in today’s date for the new employee’s hire date: CREATE TRIGGER HIREDATE NO CASCADE BEFORE INSERT ON EMP REFERENCING NEW AS NEW_VAR FOR EACH ROW MODE DB2SQL BEGIN ATOMIC SET NEW_VAR.HIRE_DATE = CURRENT_DATE; END v INSERT, DELETE (searched), UPDATE (searched), and MERGE Because you can include INSERT, DELETE (searched), UPDATE (searched), and MERGE statements in your trigger body, execution of the trigger body might cause activation of other triggers. See “Trigger cascading” on page 428 for more information. | | | | | If any SQL statement in the trigger body fails during trigger execution, DB2 rolls back all changes that are made by the triggering SQL statement and the triggered SQL statements. However, if the trigger body executes actions that are outside of DB2’s control or are not under the same commit coordination as the DB2 subsystem in which the trigger executes, DB2 cannot undo those actions. Examples of external actions that are not under DB2’s control are: v Performing updates that are not under RRS commit control v Sending an electronic mail message If the trigger executes external actions that are under the same commit coordination as the DB2 subsystem under which the trigger executes, and an error occurs during trigger execution, DB2 places the application process that issued the triggering statement in a must-rollback state. The application must then execute a rollback operation to roll back those external actions. Examples of external actions that are under the same commit coordination as the triggering SQL operation are: v Executing a distributed update operation v From a user-defined function or stored procedure, executing an external action that affects an external resource manager that is under RRS commit control. 424 Application Programming and SQL Guide
  • 441.
    Invoking stored proceduresand user-defined functions from triggers A trigger body can include only SQL statements. To perform actions or use logic that is not available in SQL statements, create user-defined functions or stored procedures that can be invoked from within the trigger body. “User-defined functions” on page 443 contains detailed information on how to write and prepare user-defined functions and stored procedures. | | | Because a before trigger must not modify any table, functions and procedures that you invoke from a trigger cannot include INSERT, UPDATE, DELETE, or MERGE statements that modify the subject table. To invoke a user-defined function from a trigger, code a SELECT statement or VALUES statement. Use a SELECT statement to execute the function conditionally. The number of times the user-defined function executes depends on the number of rows in the result table of the SELECT statement. For example, in this trigger, the SELECT statement causes user-defined function LARGE_ORDER_ALERT to execute for each row in transition table N_TABLE with an order of more than 10000: CREATE TRIGGER LRG_ORDR AFTER INSERT ON INVOICE REFERENCING NEW TABLE AS N_TABLE FOR EACH STATEMENT MODE DB2SQL BEGIN ATOMIC SELECT LARGE_ORDER_ALERT(CUST_NO, TOTAL_PRICE, DELIVERY_DATE) FROM N_TABLE WHERE TOTAL_PRICE > 10000; END Use the VALUES statement to execute a function unconditionally; that is, once for each execution of a statement trigger or once for each row in a row trigger. In this example, user-defined function PAYROLL_LOG executes every time an update operation occurs that activates trigger PAYROLL1: CREATE TRIGGER PAYROLL1 AFTER UPDATE ON PAYROLL FOR EACH STATEMENT MODE DB2SQL BEGIN ATOMIC VALUES(PAYROLL_LOG(USER, ’UPDATE’, CURRENT TIME, CURRENT DATE)); END To invoke a stored procedure from a trigger, use a CALL statement. The parameters of this stored procedure call must be constants, transition variables, table locators, or expressions. Passing transition tables to user-defined functions and stored procedures: When you call a user-defined function or stored procedure from a trigger, you might want to give the function or procedure access to the entire set of modified rows. That is, you want to pass a pointer to the old or new transition table. You do this using table locators. Most of the code for using a table locator is in the function or stored procedure that receives the locator. “Accessing transition tables in a user-defined function or stored procedure” on page 473 explains how a function defines a table locator and uses it to receive a transition table. To pass the transition table from a trigger, specify the parameter TABLE transition-table-name when you invoke the function or Chapter 4. Creating and modifying DB2 objects 425
  • 442.
    stored procedure. Thiscauses DB2 to pass a table locator for the transition table to the user-defined function or stored procedure. For example, this trigger passes a table locator for a transition table NEWEMPS to stored procedure CHECKEMP: CREATE TRIGGER EMPRAISE AFTER UPDATE ON EMP REFERENCING NEW TABLE AS NEWEMPS FOR EACH STATEMENT MODE DB2SQL BEGIN ATOMIC CALL CHECKEMP(TABLE NEWEMPS); END Inserting, updating, and deleting data in views by using INSTEAD OF triggers | | | | | | INSTEAD OF triggers are triggers that execute instead of the INSERT, UPDATE, or DELETE statement that activates the trigger. You can define these triggers on views only. Use INSTEAD OF triggers to insert, update, and delete data in complex views. | | | | | | | | Complex views are those views that are defined on expressions or multiple tables. In some cases, those views are read only. In these cases, INSTEAD OF triggers make the insert, update and delete operations possible. If the complex view is not read only, you can request an insert, update, or delete operation. However, DB2 automatically decides how to perform that operation on the base tables that are referenced in the view. With INSTEAD OF triggers, you can define exactly how DB2 is to execute an insert, update, or delete operation on the view. You no longer leave the decision to DB2. | To insert, update, or delete data in a view by using INSTEAD OF triggers: 1. Define one or more INSTEAD OF triggers on the view by using a CREATE TRIGGER statement. You can create one trigger for each of the following operations: INSERT, UPDATE, and DELETE. These triggers define the action that DB2 is to take for each of these operations. For information about the syntax of the CREATE TRIGGER statement, see the topic “CREATE TRIGGERS” in DB2 SQL Reference. 2. Submit a INSERT, UPDATE, or DELETE statement on the view. DB2 executes the appropriate INSTEAD OF trigger. | | | | | | | | | | | | | | | Example: Suppose that you create the following view on the sample tables DSN8910.EMP and DSN8910.DEPT: | | | | | | | | | | | | Suppose that you also define the following three INSTEAD OF triggers: CREATE VIEW EMPV (EMPNO, FIRSTNME, MIDINIT, LASTNAME, PHONENO, HIREDATE,DEPTNAME) AS SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, PHONENO, HIREDATE, DEPTNAME FROM DSN8910.EMP, DSN8910.DEPT WHERE DSN8910.EMP.WORKDEPT = DSN8910.DEPT.DEPTNO CREATE TRIGGER EMPV_INSERT INSTEAD OF INSERT ON EMPV REFERENCING NEW AS NEWEMP FOR EACH ROW MODE DB2SQL INSERT INTO DSN8910.EMP (EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, PHONENO, HIREDATE) VALUES(NEWEMP.EMPNO, NEWEMP.FIRSTNME, NEWEMP.MIDINIT, NEWEMP.LASTNAME, COALESCE((SELECT D.DEPTNO FROM DSN8910.DEPT AS D WHERE D.DEPTNAME = NEWEMP.DEPTNAME), RAISE_ERROR(’70001’, ’Unknown department name’)), NEWEMP.PHONENO, NEWEMP.HIREDATE) 426 Application Programming and SQL Guide
  • 443.
    | | | | | | | | | | | | | | | | | | | | | CREATE TRIGGER EMPV_UPDATEINSTEAD OF UPDATE ON EMPV REFERENCING NEW AS NEWEMP OLD AS OLDEMP FOR EACH ROW MODE DB2SQL BEGIN ATOMIC UPDATE DSN8910.EMP AS E SET (E.FIRSTNME, E.MIDINIT, E.LASTNAME, E.WORKDEPT, E.PHONENO, E.HIREDATE) = (NEWEMP.FIRSTNME, NEWEMP.MIDINIT, NEWEMP.LASTNAME, COALESCE((SELECT D.DEPTNO FROM DSN8910.DEPT AS D WHERE D.DEPTNAME = OLDEMP.DEPTNAME), RAISE_ERROR (’70001’, ’Unknown department name’)) NEWEMP.PHONENO, NEWEMP.HIREDATE) WHERE NEWEMP.EMPNO = E.EMPNO; UPDATE DSN8910.DEPT D SET D.DEPTNAME=NEWEMP.DEPTNAME WHERE D.DEPTNAME=OLDEMP.DEPTNAME; END | | Because the view is on a query with an inner join, the view is read only. However, the INSTEAD OF triggers makes insert, update, and delete operations possible. | | Table 83 describes what happens for various insert, update, and delete operations on the EMPV view. | Table 83. Results of INSTEAD OF triggers | SQL statement Result | | | | | | | | | | INSERT INTO EMPV VALUES (...) The EMPV_INSERT trigger is activated. This trigger inserts the row into the base table DSN8910.EMP if the department name matches a value in the WORKDEPT column in the DSN8910.DEPT table. Otherwise, an error is returned. If a query had been used instead of a VALUES clause on the INSERT statement, the trigger body would be processed for each row from the query. | | | | | | UPDATE EMPV SET DEPTNAME=’PLANNING & STRATEGY’ WHERE DEPTNAME=’PLANNING’ The EMPV_UPDATE trigger is activated. This trigger updates the DEPTNAME column in the DSN8910.DEPT for the any qualifying rows. | | | | | | DELETE FROM EMPV WHERE HIREDATE<’1910-01-01’ The EMPV_DELETE trigger is activated. This trigger deletes the qualifying rows from the DSN8910.EMP table. | CREATE TRIGGER EMPV_DELETE INSTEAD OF DELETE ON EMPV REFERENCING OLD AS OLDEMP FOR EACH ROW MODE DB2SQL DELETE FROM DSN8910.EMP AS E WHERE E.EMPNO = OLDEMP.EMPNO Trigger packages A trigger package is a special type of package that is created only when you execute a CREATE TRIGGER statement. A trigger package executes only when its associated trigger is activated. As with any other package, DB2 marks a trigger package invalid when you drop a table, index, or view on which the trigger package depends. DB2 executes an automatic rebind the next time the trigger is activated. However, if the automatic rebind fails, DB2 does not mark the trigger package as inoperative. Chapter 4. Creating and modifying DB2 objects 427
  • 444.
    Unlike other packages,a trigger package is freed if you drop the table on which the trigger is defined, so you can recreate the trigger package only by recreating the table and the trigger. You can use the subcommand REBIND TRIGGER PACKAGE to rebind a trigger package that DB2 has marked as inoperative. You can also use REBIND TRIGGER PACKAGE to change the option values with which DB2 originally bound the trigger package. You can change only a limited subset of the default bind options that DB2 used when creating the package. For a description of these options, see the topic “REBIND TRIGGER PACKAGE (DSN)” in DB2 Command Reference. Trigger cascading When a trigger performs an SQL operation, it might modify the subject table or other tables with triggers, so DB2 also activates those triggers. This situation is called trigger cascading. A trigger that is activated as the result of another trigger can be activated at the same level as the original trigger or at a different level. Two triggers, A and B, are activated at different levels if trigger B is activated after trigger A is activated and completes before trigger A completes. If trigger B is activated after trigger A is activated and completes after trigger A completes, then the triggers are at the same level. For example, in these cases, trigger A and trigger B are activated at the same level: v Table X has two triggers that are defined on it, A and B. A is a before trigger and B is an after trigger. An update to table X causes both trigger A and trigger B to activate. v Trigger A updates table X, which has a referential constraint with table Y, which has trigger B defined on it. The referential constraint causes table Y to be updated, which activates trigger B. In these cases, trigger A and trigger B are activated at different levels: v Trigger A is defined on table X, and trigger B is defined on table Y. Trigger B is an update trigger. An update to table X activates trigger A, which contains an UPDATE statement on table B in its trigger body. This UPDATE statement activates trigger B. v Trigger A calls a stored procedure. The stored procedure contains an INSERT statement for table X, which has insert trigger B defined on it. When the INSERT statement on table X executes, trigger B is activated. When triggers are activated at different levels, it is called trigger cascading. Trigger cascading can occur only for after triggers because DB2 does not support cascading of before triggers. To prevent the possibility of endless trigger cascading, DB2 supports only 16 levels of cascading of triggers, stored procedures, and user-defined functions. If a trigger, user-defined function, or stored procedure at the 17th level is activated, DB2 returns SQLCODE -724 and backs out all SQL changes in the 16 levels of cascading. However, as with any other SQL error that occurs during trigger execution, if any action occurs that is outside the control of DB2, that action is not backed out. You can write a monitor program that issues IFI READS requests to collect DB2 trace information about the levels of cascading of triggers, user-defined functions, 428 Application Programming and SQL Guide
  • 445.
    and stored proceduresin your programs. For information on how to write a monitor program, see the topic “Invoking IFI from your program” in DB2 Performance Monitoring and Tuning Guide. Order of multiple triggers You can create multiple triggers for the same subject table, event, and activation time. The order in which those triggers are activated is the order in which the triggers were created. DB2 records the timestamp when each CREATE TRIGGER statement executes. When an event occurs in a table that activates more than one trigger, DB2 uses the stored timestamps to determine which trigger to activate first. DB2 always activates all before triggers that are defined on a table before the after triggers that are defined on that table, but within the set of before triggers, the activation order is by timestamp, and within the set of after triggers, the activation order is by timestamp. In this example, triggers NEWHIRE1 and NEWHIRE2 have the same triggering event (INSERT), the same subject table (EMP), and the same activation time (AFTER). Suppose that the CREATE TRIGGER statement for NEWHIRE1 is run before the CREATE TRIGGER statement for NEWHIRE2: CREATE TRIGGER NEWHIRE1 AFTER INSERT ON EMP FOR EACH ROW MODE DB2SQL BEGIN ATOMIC UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1; END CREATE TRIGGER NEWHIRE2 AFTER INSERT ON EMP REFERENCING NEW AS N_EMP FOR EACH ROW MODE DB2SQL BEGIN ATOMIC UPDATE DEPTS SET NBEMP = NBEMP + 1 WHERE DEPT_ID = N_EMP.DEPT_ID; END When an insert operation occurs on table EMP, DB2 activates NEWHIRE1 first because NEWHIRE1 was created first. Now suppose that someone drops and re-creates NEWHIRE1. NEWHIRE1 now has a later timestamp than NEWHIRE2, so the next time an insert operation occurs on EMP, NEWHIRE2 is activated before NEWHIRE1. If two row triggers are defined for the same action, the trigger that was created earlier is activated first for all affected rows. Then the second trigger is activated for all affected rows. In the previous example, suppose that an INSERT statement with a fullselect inserts 10 rows into table EMP. NEWHIRE1 is activated for all 10 rows, then NEWHIRE2 is activated for all 10 rows. Interactions between triggers and referential constraints When you create triggers, you need to understand the interactions among the triggers and constraints on your tables and the effect that the order of processing of those constraints and triggers can have on the results. In general, the following steps occur when triggering SQL statement S1 performs an insert, update, or delete operation on table T1: Chapter 4. Creating and modifying DB2 objects 429
  • 446.
    1. DB2 determinesthe rows of T1 to modify. Call that set of rows M1. The contents of M1 depend on the SQL operation: v For a delete operation, all rows that satisfy the search condition of the statement for a searched delete operation, or the current row for a positioned delete operation v For an insert operation, the row identified by the VALUES statement, or the rows identified by the result table of a SELECT clause within the INSERT statement v For an update operation, all rows that satisfy the search condition of the statement for a searched update operation, or the current row for a positioned update operation 2. DB2 processes all before triggers that are defined on T1, in order of creation. Each before trigger executes the triggered action once for each row in M1. If M1 is empty, the triggered action does not execute. If an error occurs when the triggered action executes, DB2 rolls back all changes that are made by S1. 3. DB2 makes the changes that are specified in statement S1 to table T1, unless an INSTEAD OF trigger is defined for that action. If an appropriate INSTEAD OF trigger is defined, DB2 executes the trigger instead of the statement and skips the remaining steps in this list. | | | | | If an error occurs, DB2 rolls back all changes that are made by S1. 4. If M1 is not empty, DB2 applies all the following constraints and checks that are defined on table T1: v Referential constraints v Check constraints v Checks that are due to updates of the table through views defined WITH CHECK OPTION Application of referential constraints with rules of DELETE CASCADE or DELETE SET NULL are activated before delete triggers or before update triggers on the dependent tables. If any constraint is violated, DB2 rolls back all changes that are made by constraint actions or by statement S1. 5. DB2 processes all after triggers that are defined on T1, and all after triggers on tables that are modified as the result of referential constraint actions, in order of creation. Each after row trigger executes the triggered action once for each row in M1. If M1 is empty, the triggered action does not execute. Each after statement trigger executes the triggered action once for each execution of S1, even if M1 is empty. If any triggered actions contain SQL insert, update, or delete operations, DB2 repeats steps 1 through 5 for each operation. If an error occurs when the triggered action executes, or if a triggered action is at the 17th level of trigger cascading, DB2 rolls back all changes that are made in step 5 and all previous steps. For example, table DEPT is a parent table of EMP, with these conditions: v The DEPTNO column of DEPT is the primary key. v The WORKDEPT column of EMP is the foreign key. v The constraint is ON DELETE SET NULL. Suppose the following trigger is defined on EMP: 430 Application Programming and SQL Guide
  • 447.
    CREATE TRIGGER EMPRAISE AFTERUPDATE ON EMP REFERENCING NEW TABLE AS NEWEMPS FOR EACH STATEMENT MODE DB2SQL BEGIN ATOMIC VALUES(CHECKEMP(TABLE NEWEMPS)); END Also suppose that an SQL statement deletes the row with department number E21 from DEPT. Because of the constraint, DB2 finds the rows in EMP with a WORKDEPT value of E21 and sets WORKDEPT in those rows to null. This is equivalent to an update operation on EMP, which has update trigger EMPRAISE. Therefore, because EMPRAISE is an after trigger, EMPRAISE is activated after the constraint action sets WORKDEPT values to null. Interactions between triggers and tables that have multilevel security with row-level granularity A BEFORE trigger affects the value of the transition variable that is associated with a security label column. If a subject table has a security label column, the column in the transition table or transition variable that corresponds to the security label column in the subject table does not inherit the security label attribute. This means that the multilevel security check with row-level granularity is not enforced for the transition table or the transition variable. If you add a security label column to a subject table using the ALTER TABLE statement, the rules are the same as when you add any column to a subject table because the column in the transition table or the transition variable that corresponds to the security label column does not inherit the security label attribute. If the ID you are using does not have write-down privilege and you execute an insert or update operation, the security label value of your ID is assigned to the security label column for the rows that you are inserting or updating. When a BEFORE trigger is activated, the value of the transition variable that corresponds to the security label column is the security label of the ID if either of the following conditions is true: v The user does not have write-down privilege v The value for the security label column is not specified If the user does not have write-down privilege, and the trigger changes the transition variable that corresponds to the security label column, the value of the security label column is changed back to the security label value of the user before the row is written to the page. For more information about multilevel security with row-level granularity, see the topic “Multilevel security” in DB2 Administration Guide. Triggers that return inconsistent results When you create triggers and write SQL statements that activate those triggers, you need to ensure that executing those statements on the same set of data always produces the same results. Two common reasons that you can get inconsistent results are: v Positioned UPDATE or DELETE statements that use uncorrelated subqueries cause triggers to operate on a larger result table than you intended. Chapter 4. Creating and modifying DB2 objects 431
  • 448.
    v DB2 doesnot always process rows in the same order, so triggers that propagate rows of a table can generate different result tables at different times. The following examples demonstrate these situations. Example: Effect of an uncorrelated subquery on a triggered action: Suppose that tables T1 and T2 look like this: Table T1 A1 == 1 2 Table T2 B1 == 1 2 The following trigger is defined on T1: CREATE TRIGGER TR1 AFTER UPDATE OF T1 FOR EACH ROW MODE DB2SQL BEGIN ATOMIC DELETE FROM T2 WHERE B1 = 2; END Now suppose that an application executes the following statements to perform a positioned update operation: EXEC SQL BEGIN DECLARE SECTION; long hv1; EXEC SQL END DECLARE SECTION; . . . EXEC SQL DECLARE C1 CURSOR FOR SELECT A1 FROM T1 WHERE A1 IN (SELECT B1 FROM T2) . FOR UPDATE OF A1; . . EXEC SQL OPEN C1; . . . while(SQLCODE>=0 && SQLCODE!=100) { EXEC SQL FETCH C1 INTO :hv1; UPDATE T1 SET A1=5 WHERE CURRENT OF C1; } When DB2 executes the FETCH statement that positions cursor C1 for the first time, DB2 evaluates the subselect, SELECT B1 FROM T2, to produce a result table that contains the two rows of column T2: 1 2 When DB2 executes the positioned UPDATE statement for the first time, trigger TR1 is activated. When the body of trigger TR1 executes, the row with value 2 is deleted from T2. However, because SELECT B1 FROM T2 is evaluated only once, when the FETCH statement is executed again, DB2 finds the second row of T1, even though the second row of T2 was deleted. The FETCH statement positions the cursor to the second row of T1, and the second row of T1 is updated. The update operation causes the trigger to be activated again, which causes DB2 to attempt to delete the second row of T2, even though that row was already deleted. To avoid processing of the second row after it should have been deleted, use a correlated subquery in the cursor declaration: 432 Application Programming and SQL Guide
  • 449.
    DCL C1 CURSORFOR SELECT A1 FROM T1 X WHERE EXISTS (SELECT B1 FROM T2 WHERE X.A1 = B1) FOR UPDATE OF A1; In this case, the subquery, SELECT B1 FROM T2 WHERE X.A1 = B1, is evaluated for each FETCH statement. The first time that the FETCH statement executes, it positions the cursor to the first row of T1. The positioned UPDATE operation activates the trigger, which deletes the second row of T2. Therefore, when the FETCH statement executes again, no row is selected, so no update operation or triggered action occurs. Example: Effect of row processing order on a triggered action: The following example shows how the order of processing rows can change the outcome of an after row trigger. Suppose that tables T1, T2, and T3 look like this: Table T1 A1 == 1 2 Table T2 B1 == (empty) Table T3 C1 == (empty) The following trigger is defined on T1: CREATE TRIGGER TR1 AFTER UPDATE ON T1 REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO T2 VALUES(N.C1); INSERT INTO T3 (SELECT B1 FROM T2); END Now suppose that a program executes the following UPDATE statement: UPDATE T1 SET A1 = A1 + 1; The contents of tables T2 and T3 after the UPDATE statement executes depend on the order in which DB2 updates the rows of T1. If DB2 updates the first row of T1 first, after the UPDATE statement and the trigger execute for the first time, the values in the three tables are: Table T1 A1 == 2 2 Table T2 B1 == 2 Table T3 C1 == 2 After the second row of T1 is updated, the values in the three tables are: Table T1 A1 == 2 3 Table T2 B1 == 2 3 Table T3 C1 == 2 2 3 However, if DB2 updates the second row of T1 first, after the UPDATE statement and the trigger execute for the first time, the values in the three tables are: Chapter 4. Creating and modifying DB2 objects 433
  • 450.
    Table T1 A1 == 1 3 Table T2 B1 == 3 TableT3 C1 == 3 After the first row of T1 is updated, the values in the three tables are: Table T1 A1 == 2 3 Table T2 B1 == 3 2 Table T3 C1 == 3 3 2 Sequence objects A sequence is a user-defined object that generates a sequence of numeric values according to the specification with which the sequence was created. Sequences, unlike identity columns, are not associated with tables. Applications refer to a sequence object to get its current or next value. The sequence of numeric values is generated in a monotonically ascending or descending order. The relationship between sequences and tables is controlled by the application, not by DB2. Your application can reference a sequence object and coordinate the value as keys across multiple rows and tables. However, a table column that gets its values from a sequence object does not necessarily have unique values in that column. Even if the sequence object has been defined with the NO CYCLE clause, some other application might insert values into that table column other than values you obtain by referencing that sequence object. DB2 always generates sequence numbers in order of request. However, in a data sharing group where the sequence values are cached by multiple DB2 members simultaneously, the sequence value assignments might not be in numeric order. Additionally, you might have gaps in sequence number values for the following reasons: v If DB2 terminates abnormally before it assigns all the cached values v If your application rolls back a transaction that increments the sequence v If the statement containing NEXT VALUE fails after it increments the sequence You create a sequence object with the CREATE SEQUENCE statement, alter it with the ALTER SEQUENCE statement, and drop it with the DROP SEQUENCE statement. You grant access to a sequence with the GRANT (privilege) ON SEQUENCE statement, and revoke access to the sequence with the REVOKE (privilege) ON SEQUENCE statement. The values that DB2 generates for a sequence depend on how the sequence is created. The START WITH option determines the first value that DB2 generates. The values advance by the INCREMENT BY value in ascending or descending order. The MINVALUE and MAXVALUE options determine the minimum and maximum values that DB2 generates. The CYCLE or NO CYCLE option determines whether DB2 wraps values when it has generated all values between the START WITH value and MAXVALUE if the values are ascending, or between the START WITH value and MINVALUE if the values are descending. 434 Application Programming and SQL Guide
  • 451.
    Keys across multipletables: You can use the same sequence number as a key value in two separate tables by first generating the sequence value with a NEXT VALUE expression to insert the first row in the first table. You can then reference this same sequence value with a PREVIOUS VALUE expression to insert the other rows in the second table. Example: Suppose that an ORDERS table and an ORDER_ITEMS table are defined in the following way: CREATE TABLE ORDERS (ORDERNO INTEGER NOT NULL, ORDER_DATE DATE DEFAULT, CUSTNO SMALLINT PRIMARY KEY (ORDERNO)); CREATE TABLE ORDER_ITEMS (ORDERNO INTEGER NOT NULL, PARTNO INTEGER NOT NULL, QUANTITY SMALLINT NOT NULL, PRIMARY KEY (ORDERNO,PARTNO), CONSTRAINT REF_ORDERNO FOREIGN KEY (ORDERNO) REFERENCES ORDERS (ORDERNO) ON DELETE CASCADE); You create a sequence named ORDER_SEQ to use as key values for both the ORDERS and ORDER_ITEMS tables: CREATE SEQUENCE ORDER_SEQ AS INTEGER START WITH 1 INCREMENT BY 1 NO MAXVALUE NO CYCLE CACHE 20; You can then use the same sequence number as a primary key value for the ORDERS table and as part of the primary key value for the ORDER_ITEMS table: INSERT INTO ORDERS (ORDERNO, CUSTNO) VALUES (NEXT VALUE FOR ORDER_SEQ, 12345); INSERT INTO ORDER_ITEMS (ORDERNO, PARTNO, QUANTITY) VALUES (PREVIOUS VALUE FOR ORDER_SEQ, 987654, 2); The NEXT VALUE expression in the first INSERT statement generates a sequence number value for the sequence object ORDER_SEQ. The PREVIOUS VALUE expression in the second INSERT statement retrieves that same value because it was the sequence number most recently generated for that sequence object within the current application process. DB2 object relational extensions With the object extensions of DB2, you can incorporate object-oriented concepts and methodologies into your relational database by extending DB2 with richer sets of data types and funct