0% found this document useful (0 votes)
508 views1,030 pages

DB2 - Application Programming & SQL Guide - Ver 7

Uploaded by

api-3798739
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
508 views1,030 pages

DB2 - Application Programming & SQL Guide - Ver 7

Uploaded by

api-3798739
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1030

DB2 Universal Database for OS/390 and z/OS 

Application Programming
and SQL Guide
Version 7

SC26-9933-01
DB2 Universal Database for OS/390 and z/OS 

Application Programming
and SQL Guide
Version 7

SC26-9933-01
Note
Before using this information and the product it supports, be sure to read the
general information under “Notices” on page 949.

Second Edition, Softcopy Only (August 2001)


This edition applies to Version 7 of IBM DATABASE 2 Universal Database Server for OS/390 and z/OS (DB2 for
OS/390 and z/OS), 5675-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.
This softcopy version is based on the printed edition of the book and includes the changes indicated in the printed
version by vertical bars. Additional changes made to this softcopy version of the book since the hardcopy book was
published are indicated by the hash (#) symbol in the left-hand margin. Editorial changes that have no technical
significance are not noted.
This and other books in the DB2 for OS/390 and z/OS library are periodically updated with technical changes. These
updates are made available to licensees of the product on CD-ROM and on the Web (currently at
www.ibm.com/software/data/db2/os390/library.html). Check these resources to ensure that you are using the most
current information.
© Copyright International Business Machines Corporation 1983, 2001. All rights reserved.
US Government Users Restricted Rights – Use, duplication or disclosure restricted by GSA ADP Schedule Contract
with IBM Corp.
Contents
About this book . . . . . . . . . . . . . . . . . . . . . . . . xix
Who should read this book . . . . . . . . . . . . . . . . . . . . xix
Product terminology and citations . . . . . . . . . . . . . . . . . . xix
How to read the syntax diagrams . . . . . . . . . . . . . . . . . . xix
How to send your comments. . . . . . . . . . . . . . . . . . . . xxi

Summary of changes to this book . . . . . . . . . . . . . . . . xxiii

Part 1. Using SQL queries . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

Chapter 1. Retrieving data . . . . . . . . . . . . . . . . . . . . 3


Result tables . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Selecting columns: SELECT . . . . . . . . . . . . . . . . . . . . 5
Selecting all columns: SELECT * . . . . . . . . . . . . . . . . . . 5
Selecting some columns: SELECT column-name . . . . . . . . . . . . 6
Selecting DB2 data that is not in a table: Using SYSDUMMY1 . . . . . . . 7
Selecting derived columns: SELECT expression . . . . . . . . . . . . 7
Eliminating duplicate rows: DISTINCT . . . . . . . . . . . . . . . . 7
Naming result columns: AS . . . . . . . . . . . . . . . . . . . . 7
Selecting rows using search conditions: WHERE . . . . . . . . . . . . . 8
Putting the rows in order: ORDER BY . . . . . . . . . . . . . . . . . 9
Specifying the sort key . . . . . . . . . . . . . . . . . . . . . 9
Referencing derived columns. . . . . . . . . . . . . . . . . . . 10
Summarizing group values: GROUP BY . . . . . . . . . . . . . . . 10
Subjecting groups to conditions: HAVING . . . . . . . . . . . . . . . 11
Merging lists of values: UNION . . . . . . . . . . . . . . . . . . . 12
Using UNION to eliminate duplicates . . . . . . . . . . . . . . . . 12
Using UNION ALL to keep duplicates. . . . . . . . . . . . . . . . 13
Using 15-digit and 31-digit precision for decimal numbers . . . . . . . . . 13
Finding information in the DB2 catalog . . . . . . . . . . . . . . . . 14
Displaying a list of tables you can use . . . . . . . . . . . . . . . 14
Displaying a list of columns in a table . . . . . . . . . . . . . . . 15

Chapter 2. Working with tables and modifying data . . . . . . . . . . 17


Working with tables . . . . . . . . . . . . . . . . . . . . . . . 17
Creating your own tables: CREATE TABLE . . . . . . . . . . . . . 17
Working with temporary tables . . . . . . . . . . . . . . . . . . 19
Dropping tables: DROP TABLE . . . . . . . . . . . . . . . . . . 23
Working with views . . . . . . . . . . . . . . . . . . . . . . . 23
Defining a view: CREATE VIEW . . . . . . . . . . . . . . . . . 23
Changing data through a view . . . . . . . . . . . . . . . . . . 24
Dropping views: DROP VIEW . . . . . . . . . . . . . . . . . . 25
Modifying DB2 data . . . . . . . . . . . . . . . . . . . . . . . 25
Inserting a row: INSERT . . . . . . . . . . . . . . . . . . . . 25
Updating current values: UPDATE . . . . . . . . . . . . . . . . . 29
Deleting rows: DELETE. . . . . . . . . . . . . . . . . . . . . 31

Chapter 3. Joining data from more than one table . . . . . . . . . . . 33


Inner join . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Full outer join . . . . . . . . . . . . . . . . . . . . . . . . . 35
Left outer join . . . . . . . . . . . . . . . . . . . . . . . . . 36
Right outer join . . . . . . . . . . . . . . . . . . . . . . . . . 37

© Copyright IBM Corp. 1983, 2001 iii


SQL rules for statements containing join operations . . . . . . . . . . . 37
Using more than one type of join in an SQL statement . . . . . . . . . . 38
Using nested table expressions and user-defined table functions in joins . . . 39

Chapter 4. Using subqueries . . . . . . . . . . . . . . . . . . . 43


Conceptual overview . . . . . . . . . . . . . . . . . . . . . . . 43
Correlated and uncorrelated subqueries. . . . . . . . . . . . . . . 44
Subqueries and predicates . . . . . . . . . . . . . . . . . . . 44
The subquery result table . . . . . . . . . . . . . . . . . . . . 44
Tables in subqueries of UPDATE, DELETE, and INSERT statements . . . . 45
How to code a subquery . . . . . . . . . . . . . . . . . . . . . 45
Basic predicate . . . . . . . . . . . . . . . . . . . . . . . . 45
Quantified predicates: ALL, ANY, and SOME . . . . . . . . . . . . . 45
Using the IN keyword . . . . . . . . . . . . . . . . . . . . . 46
Using the EXISTS keyword . . . . . . . . . . . . . . . . . . . 46
Using correlated subqueries . . . . . . . . . . . . . . . . . . . . 47
An example of a correlated subquery. . . . . . . . . . . . . . . . 47
Using correlation names in references . . . . . . . . . . . . . . . 48
Using correlated subqueries in an UPDATE statement . . . . . . . . . 49
Using correlated subqueries in a DELETE statement . . . . . . . . . . 49

Chapter 5. Executing SQL from your terminal using SPUFI . . . . . . . 51


Allocating an input data set and using SPUFI. . . . . . . . . . . . . . 51
Changing SPUFI defaults (optional) . . . . . . . . . . . . . . . . . 54
Entering SQL statements . . . . . . . . . . . . . . . . . . . . . 56
Processing SQL statements . . . . . . . . . . . . . . . . . . . . 57
Browsing the output . . . . . . . . . . . . . . . . . . . . . . . 58
Format of SELECT statement results . . . . . . . . . . . . . . . . 58
Content of the messages . . . . . . . . . . . . . . . . . . . . 59

Part 2. Coding SQL in your host application program . . . . . . . . . . . . . 61

Chapter 6. Basics of coding SQL in an application program . . . . . . . 65


Conventions used in examples of coding SQL statements . . . . . . . . . 66
Delimiting an SQL statement . . . . . . . . . . . . . . . . . . . . 66
Declaring table and view definitions . . . . . . . . . . . . . . . . . 67
Accessing data using host variables and host structures. . . . . . . . . . 67
Using host variables . . . . . . . . . . . . . . . . . . . . . . 68
Using host structures . . . . . . . . . . . . . . . . . . . . . 72
Checking the execution of SQL statements . . . . . . . . . . . . . . 74
SQLCODE and SQLSTATE . . . . . . . . . . . . . . . . . . . 74
The WHENEVER statement . . . . . . . . . . . . . . . . . . . 75
Handling arithmetic or conversion errors . . . . . . . . . . . . . . 75
Handling SQL error return codes . . . . . . . . . . . . . . . . . 76

Chapter 7. Using a cursor to retrieve a set of rows . . . . . . . . . . 81


How to use a cursor . . . . . . . . . . . . . . . . . . . . . . . 81
Step 1: Declare the cursor. . . . . . . . . . . . . . . . . . . . 81
Step 2: Open the cursor . . . . . . . . . . . . . . . . . . . . 83
Step 3: Specify what to do at end-of-data . . . . . . . . . . . . . . 83
Step 4: Execute SQL statements . . . . . . . . . . . . . . . . . 83
Using FETCH statements . . . . . . . . . . . . . . . . . . . . 84
Using positioned UPDATE statements . . . . . . . . . . . . . . . 84
Using positioned DELETE statements . . . . . . . . . . . . . . . 85
Step 5: Close the cursor . . . . . . . . . . . . . . . . . . . . 85
Types of cursors . . . . . . . . . . . . . . . . . . . . . . . . 85

iv Application Programming and SQL Guide


| Scrollable and non-scrollable cursors . . . . . . . . . . . . . . . . 85
Held and non-held cursors . . . . . . . . . . . . . . . . . . . 91
Examples of using cursors . . . . . . . . . . . . . . . . . . . . 92

Chapter 8. Generating declarations for your tables using DCLGEN . . .


. 95
Invoking DCLGEN through DB2I . . . . . . . . . . . . . . . . .
. 95
Including the data declarations in your program . . . . . . . . . . . .
. 99
DCLGEN support of C, COBOL, and PL/I languages . . . . . . . . . .
. 99
Example: Adding a table declaration and host-variable structure to a library 101
Step 1. Specify COBOL as the host language . . . . . . . . . . . . 101
Step 2. Create the table declaration and host structure. . . . . . . . . 102
Step 3. Examine the results. . . . . . . . . . . . . . . . . . . 104

Chapter 9. Embedding SQL statements in host languages . . . . . . . 107


Coding SQL statements in an assembler application. . . . . . . . . . . 107
Defining the SQL communications area . . . . . . . . . . . . . . 107
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 108
Embedding SQL statements . . . . . . . . . . . . . . . . . . 109
Using host variables . . . . . . . . . . . . . . . . . . . . . 111
Declaring host variables . . . . . . . . . . . . . . . . . . . . 111
Determining equivalent SQL and assembler data types. . . . . . . . . 114
Determining compatibility of SQL and assembler data types . . . . . . . 118
Using indicator variables . . . . . . . . . . . . . . . . . . . . 119
Handling SQL error return codes . . . . . . . . . . . . . . . . . 119
Macros for assembler applications . . . . . . . . . . . . . . . . 121
Coding SQL statements in a C or a C⁺⁺ application . . . . . . . . . . . 121
Defining the SQL communication area . . . . . . . . . . . . . . . 121
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 122
Embedding SQL statements . . . . . . . . . . . . . . . . . . 123
Using host variables . . . . . . . . . . . . . . . . . . . . . 124
Declaring host variables . . . . . . . . . . . . . . . . . . . . 125
Using host structures . . . . . . . . . . . . . . . . . . . . . 129
Determining equivalent SQL and C data types . . . . . . . . . . . . 131
Determining compatibility of SQL and C data types . . . . . . . . . . 136
Using indicator variables . . . . . . . . . . . . . . . . . . . . 138
Handling SQL error return codes . . . . . . . . . . . . . . . . . 139
Considerations for C⁺⁺ . . . . . . . . . . . . . . . . . . . . 140
Coding SQL statements in a COBOL application . . . . . . . . . . . . 141
Defining the SQL communication area . . . . . . . . . . . . . . . 141
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 142
Embedding SQL statements . . . . . . . . . . . . . . . . . . 142
Using host variables . . . . . . . . . . . . . . . . . . . . . 146
Declaring host variables . . . . . . . . . . . . . . . . . . . . 147
Using host structures . . . . . . . . . . . . . . . . . . . . . 152
Determining equivalent SQL and COBOL data types . . . . . . . . . 155
Determining compatibility of SQL and COBOL data types . . . . . . . . 159
Using indicator variables . . . . . . . . . . . . . . . . . . . . 160
Handling SQL error return codes . . . . . . . . . . . . . . . . . 161
Considerations for object-oriented extensions in COBOL . . . . . . . . 163
Coding SQL statements in a FORTRAN application . . . . . . . . . . . 164
Defining the SQL communication area . . . . . . . . . . . . . . . 164
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 164
Embedding SQL statements . . . . . . . . . . . . . . . . . . 165
Using host variables . . . . . . . . . . . . . . . . . . . . . 167
Declaring host variables . . . . . . . . . . . . . . . . . . . . 167
Determining equivalent SQL and FORTRAN data types . . . . . . . . 169

Contents v
Determining compatibility of SQL and FORTRAN data types. . . . . . . 172
Using indicator variables . . . . . . . . . . . . . . . . . . . . 172
Handling SQL error return codes . . . . . . . . . . . . . . . . . 173
Coding SQL statements in a PL/I application . . . . . . . . . . . . . 174
Defining the SQL communication area . . . . . . . . . . . . . . . 174
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 174
Embedding SQL statements . . . . . . . . . . . . . . . . . . 175
Using host variables . . . . . . . . . . . . . . . . . . . . . 177
Declaring host variables . . . . . . . . . . . . . . . . . . . . 178
Using host structures . . . . . . . . . . . . . . . . . . . . . 181
Determining equivalent SQL and PL/I data types . . . . . . . . . . . 182
Determining compatibility of SQL and PL/I data types . . . . . . . . . 186
Using indicator variables . . . . . . . . . . . . . . . . . . . . 187
Handling SQL error return codes . . . . . . . . . . . . . . . . . 188
Coding SQL statements in a REXX application. . . . . . . . . . . . . 189
Defining the SQL communication area . . . . . . . . . . . . . . . 189
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 190
Accessing the DB2 REXX Language Support application programming
interfaces . . . . . . . . . . . . . . . . . . . . . . . . 190
Embedding SQL statements in a REXX procedure . . . . . . . . . . 192
Using cursors and statement names . . . . . . . . . . . . . . . 194
Using REXX host variables and data types . . . . . . . . . . . . . 194
Using indicator variables . . . . . . . . . . . . . . . . . . . . 197
Setting the isolation level of SQL statements in a REXX procedure . . . . 198

Chapter 10. Using constraints to maintain data integrity . . . . . . . . 201


Using table check constraints . . . . . . . . . . . . . . . . . . . 201
Constraint considerations . . . . . . . . . . . . . . . . . . . 201
When table check constraints are enforced . . . . . . . . . . . . . 202
How table check constraints set check pending status . . . . . . . . . 202
Using referential constraints. . . . . . . . . . . . . . . . . . . . 203
Parent key columns. . . . . . . . . . . . . . . . . . . . . . 203
Defining a parent key and a unique index . . . . . . . . . . . . . 204
Defining a foreign key . . . . . . . . . . . . . . . . . . . . . 206

Chapter 11. Using triggers for active data . . . . . . . . . . . . . 209


Example of creating and using a trigger . . . . . . . . . . . . . . . 209
Parts of a trigger . . . . . . . . . . . . . . . . . . . . . . . . 211
Invoking stored procedures and user-defined functions from triggers . . . . . 217
Passing transition tables to user-defined functions and stored procedures 217
Trigger cascading . . . . . . . . . . . . . . . . . . . . . . . 218
Ordering of multiple triggers. . . . . . . . . . . . . . . . . . . . 219
Interactions among triggers and referential constraints . . . . . . . . . . 219
Creating triggers to obtain consistent results . . . . . . . . . . . . . 221

Part 3. Using DB2 object-relational extensions . . . . . . . . . . . . . . . . 225

Chapter 12. Introduction to DB2 object-relational extensions . . . . . . 227

Chapter 13. Programming for large objects (LOBs) . . . . . . . . . . 229


Introduction to LOBs . . . . . . . . . . . . . . . . . . . . . . 229
Declaring LOB host variables and LOB locators . . . . . . . . . . . . 232
LOB materialization . . . . . . . . . . . . . . . . . . . . . . . 236
Using LOB locators to save storage . . . . . . . . . . . . . . . . . 236
Deferring evaluation of a LOB expression to improve performance . . . . 237
Indicator variables and LOB locators . . . . . . . . . . . . . . . 240

vi Application Programming and SQL Guide


Valid assignments for LOB locators . . . . . . . . . . . . . . . . 240

Chapter 14. Creating and using user-defined functions . . . . . . . . 241


Overview of user-defined function definition, implementation, and invocation 241
Example of creating and using a user-defined scalar function . . . . . . 242
User-defined function samples shipped with DB2 . . . . . . . . . . . 243
Defining a user-defined function . . . . . . . . . . . . . . . . . . 244
Components of a user-defined function definition . . . . . . . . . . . 244
Examples of user-defined function definitions . . . . . . . . . . . . 246
Implementing an external user-defined function . . . . . . . . . . . . 248
Writing a user-defined function . . . . . . . . . . . . . . . . . 248
Preparing a user-defined function for execution . . . . . . . . . . . 284
Testing a user-defined function . . . . . . . . . . . . . . . . . 286
| Implementing an SQL scalar function . . . . . . . . . . . . . . . . 288
Invoking a user-defined function . . . . . . . . . . . . . . . . . . 289
Syntax for user-defined function invocation . . . . . . . . . . . . . 289
Ensuring that DB2 executes the intended user-defined function . . . . . 290
Casting of user-defined function arguments . . . . . . . . . . . . . 296
What happens when a user-defined function abnormally terminates . . . . 297
Nesting SQL Statements . . . . . . . . . . . . . . . . . . . . 297
Recommendations for user-defined function invocation . . . . . . . . . 299

Chapter 15. Creating and using distinct types . . . . . . . . . . . . 301


Introduction to distinct types . . . . . . . . . . . . . . . . . . . 301
Using distinct types in application programs . . . . . . . . . . . . . . 302
Comparing distinct types . . . . . . . . . . . . . . . . . . . . 302
Assigning distinct types . . . . . . . . . . . . . . . . . . . . 303
Using distinct types in UNIONs . . . . . . . . . . . . . . . . . 305
Invoking functions with distinct types . . . . . . . . . . . . . . . 305
Combining distinct types with user-defined functions and LOBs . . . . . . 306

Part 4. Designing a DB2 database application . . . . . . . . . . . . . . . . 311

Chapter 16. Planning for DB2 program preparation . . . . . . . . . . 315


Planning to process SQL statements . . . . . . . . . . . . . . . . 316
Planning to bind . . . . . . . . . . . . . . . . . . . . . . . . 317
Deciding how to bind DBRMs . . . . . . . . . . . . . . . . . . 317
Planning for changes to your application . . . . . . . . . . . . . . 319

Chapter 17. Planning for concurrency . . . . . . . . . . . . . . . 325


Definitions of concurrency and locks . . . . . . . . . . . . . . . . 325
Effects of DB2 locks . . . . . . . . . . . . . . . . . . . . . . 326
Suspension. . . . . . . . . . . . . . . . . . . . . . . . . 326
Timeout . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Deadlock . . . . . . . . . . . . . . . . . . . . . . . . . 327
Basic recommendations to promote concurrency . . . . . . . . . . . . 329
Recommendations for database design . . . . . . . . . . . . . . 330
Recommendations for application design . . . . . . . . . . . . . . 330
Aspects of transaction locks . . . . . . . . . . . . . . . . . . . 333
The size of a lock . . . . . . . . . . . . . . . . . . . . . . 333
The duration of a lock . . . . . . . . . . . . . . . . . . . . . 335
The mode of a lock . . . . . . . . . . . . . . . . . . . . . . 336
The object of a lock. . . . . . . . . . . . . . . . . . . . . . 338
Lock tuning . . . . . . . . . . . . . . . . . . . . . . . . . . 339
Bind options . . . . . . . . . . . . . . . . . . . . . . . . 339
Isolation overriding with SQL statements . . . . . . . . . . . . . . 351

Contents vii
The statement LOCK TABLE . . . . . . . . . . . . . . . . . . 352
Access paths . . . . . . . . . . . . . . . . . . . . . . . . 353
LOB locks . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Relationship between transaction locks and LOB locks . . . . . . . . . 355
Hierarchy of LOB locks . . . . . . . . . . . . . . . . . . . . 356
LOB and LOB table space lock modes. . . . . . . . . . . . . . . 357
Duration of locks . . . . . . . . . . . . . . . . . . . . . . . 357
Instances when locks on LOB table space are not taken . . . . . . . . 358
The LOCK TABLE statement . . . . . . . . . . . . . . . . . . 358

Chapter 18. Planning for recovery . . . . . . . . . . . . . . . . 359


Unit of work in TSO (batch and online) . . . . . . . . . . . . . . . 359
Unit of work in CICS . . . . . . . . . . . . . . . . . . . . . . 360
Unit of work in IMS (online) . . . . . . . . . . . . . . . . . . . . 361
Planning ahead for program recovery: Checkpoint and restart . . . . . . 362
When are checkpoints important? . . . . . . . . . . . . . . . . 363
Checkpoints in MPPs and transaction-oriented BMPs . . . . . . . . . 364
Checkpoints in batch-oriented BMPs . . . . . . . . . . . . . . . 364
Specifying checkpoint frequency . . . . . . . . . . . . . . . . . 365
Unit of work in DL/I batch and IMS batch . . . . . . . . . . . . . . . 365
Commit and rollback coordination . . . . . . . . . . . . . . . . 365
Restart and recovery in IMS (batch). . . . . . . . . . . . . . . . 367
Using savepoints to undo selected changes within a unit of work . . . . . . 367

Chapter 19. Planning to access distributed data . . . . . . . . . . . 369


Introduction to accessing distributed data . . . . . . . . . . . . . . . 369
Coding for distributed data by two methods . . . . . . . . . . . . . . 371
Using three-part table names . . . . . . . . . . . . . . . . . . 372
Using explicit CONNECT statements . . . . . . . . . . . . . . . 373
Coding considerations for access methods . . . . . . . . . . . . . . 374
Preparing programs For DRDA access. . . . . . . . . . . . . . . . 376
Precompiler options. . . . . . . . . . . . . . . . . . . . . . 376
BIND PACKAGE options . . . . . . . . . . . . . . . . . . . . 376
BIND PLAN options. . . . . . . . . . . . . . . . . . . . . . 377
Checking BIND PACKAGE options . . . . . . . . . . . . . . . . 378
Coordinating updates to two or more data sources . . . . . . . . . . . 379
How to have coordinated updates . . . . . . . . . . . . . . . . 379
What you can do without two-phase commit. . . . . . . . . . . . . 380
Miscellaneous topics for distributed data . . . . . . . . . . . . . . . 381
Improving performance for remote access . . . . . . . . . . . . . 381
Maximizing LOB performance in a distributed environment . . . . . . . 382
Use bind options that improve performance . . . . . . . . . . . . . 383
Use block fetch . . . . . . . . . . . . . . . . . . . . . . . 385
Specifying OPTIMIZE FOR n ROWS . . . . . . . . . . . . . . . 388
| Specifying FETCH FIRST n ROWS ONLY . . . . . . . . . . . . . 390
DB2 for OS/390 and z/OS support for the rowset parameter . . . . . . . 391
| Accessing data with a scrollable cursor when the requester is down-level 392
Maintaining data currency . . . . . . . . . . . . . . . . . . . 392
Copying a table from a remote location . . . . . . . . . . . . . . 392
Transmitting mixed data . . . . . . . . . . . . . . . . . . . . 392
| Retrieving data from ASCII or Unicode tables . . . . . . . . . . . . 392
Considerations for moving from DB2 private protocol access to DRDA
access . . . . . . . . . . . . . . . . . . . . . . . . . 393

Part 5. Developing your application . . . . . . . . . . . . . . . . . . . . . 395

viii Application Programming and SQL Guide


Chapter 20. Preparing an application program to run . . . . . . . . . 397
Steps in program preparation . . . . . . . . . . . . . . . . . . . 397
Step 1: Process SQL statements . . . . . . . . . . . . . . . . . 398
Step 2: Compile (or assemble) and link-edit the application . . . . . . . 411
Step 3: Bind the application . . . . . . . . . . . . . . . . . . . 412
Step 4: Run the application . . . . . . . . . . . . . . . . . . . 424
Using JCL procedures to prepare applications . . . . . . . . . . . . . 428
Available JCL procedures . . . . . . . . . . . . . . . . . . . 428
Including code from SYSLIB data sets . . . . . . . . . . . . . . . 429
Starting the precompiler dynamically . . . . . . . . . . . . . . . 430
An alternative method for preparing a CICS program . . . . . . . . . 432
Using JCL to prepare a program with object-oriented extensions . . . . . 433
Using ISPF and DB2 Interactive (DB2I) . . . . . . . . . . . . . . . 434
DB2I help . . . . . . . . . . . . . . . . . . . . . . . . . 434
The DB2I Primary Option Menu . . . . . . . . . . . . . . . . . 434
The DB2 Program Preparation panel . . . . . . . . . . . . . . . 436
DB2I Defaults Panel 1 . . . . . . . . . . . . . . . . . . . . . 440
DB2I Defaults Panel 2 . . . . . . . . . . . . . . . . . . . . . 442
The Precompile panel . . . . . . . . . . . . . . . . . . . . . 443
The Bind Package panel . . . . . . . . . . . . . . . . . . . . 446
The Bind Plan panel . . . . . . . . . . . . . . . . . . . . . 450
The Defaults for Bind or Rebind Package or Plan panels . . . . . . . . 453
The System Connection Types panel . . . . . . . . . . . . . . . 458
Panels for entering lists of values . . . . . . . . . . . . . . . . 459
The Program Preparation: Compile, Link, and Run panel . . . . . . . . 460

Chapter 21. Testing an application program . . . . . . . . . . . . . 463


Establishing a test environment . . . . . . . . . . . . . . . . . . 463
Designing a test data structure . . . . . . . . . . . . . . . . . 463
Filling the tables with test data. . . . . . . . . . . . . . . . . . 465
Testing SQL statements using SPUFI . . . . . . . . . . . . . . . . 466
Debugging your program . . . . . . . . . . . . . . . . . . . . . 466
Debugging programs in TSO . . . . . . . . . . . . . . . . . . 466
Debugging programs in IMS . . . . . . . . . . . . . . . . . . 467
Debugging programs in CICS . . . . . . . . . . . . . . . . . . 468
Locating the problem . . . . . . . . . . . . . . . . . . . . . . 472
Analyzing error and warning messages from the precompiler . . . . . . 473
SYSTERM output from the precompiler . . . . . . . . . . . . . . 473
SYSPRINT output from the precompiler . . . . . . . . . . . . . . 474

Chapter 22. Processing DL/I batch applications . . . . . . . . . . . 479


Planning to use DL/I batch . . . . . . . . . . . . . . . . . . . . 479
Features and functions of DB2 DL/I batch support . . . . . . . . . . 479
Requirements for using DB2 in a DL/I batch job . . . . . . . . . . . 480
Authorization . . . . . . . . . . . . . . . . . . . . . . . . 480
Program design considerations . . . . . . . . . . . . . . . . . . 480
Address spaces . . . . . . . . . . . . . . . . . . . . . . . 480
Commits . . . . . . . . . . . . . . . . . . . . . . . . . . 480
SQL statements and IMS calls. . . . . . . . . . . . . . . . . . 481
Checkpoint calls . . . . . . . . . . . . . . . . . . . . . . . 481
Application program synchronization . . . . . . . . . . . . . . . 481
Checkpoint and XRST considerations . . . . . . . . . . . . . . . 481
Synchronization call abends . . . . . . . . . . . . . . . . . . 482
Input and output data sets . . . . . . . . . . . . . . . . . . . . 482
DB2 DL/I Batch Input . . . . . . . . . . . . . . . . . . . . . 482
DB2 DL/I batch output. . . . . . . . . . . . . . . . . . . . . 484

Contents ix
Program preparation considerations . . . . . . . . . . . . . . . . . 484
Precompiling . . . . . . . . . . . . . . . . . . . . . . . . 484
Binding . . . . . . . . . . . . . . . . . . . . . . . . . . 484
Link-editing . . . . . . . . . . . . . . . . . . . . . . . . . 485
Loading and running . . . . . . . . . . . . . . . . . . . . . 485
Restart and recovery . . . . . . . . . . . . . . . . . . . . . . 486
JCL example of a batch backout . . . . . . . . . . . . . . . . . 486
JCL example of restarting a DL/I batch job . . . . . . . . . . . . . 487
Finding the DL/I batch checkpoint ID . . . . . . . . . . . . . . . 488

Part 6. Additional programming techniques . . . . . . . . . . . . . . . . . 489

Chapter 23. Coding dynamic SQL in application programs . . . . . . . 497


Choosing between static and dynamic SQL . . . . . . . . . . . . . . 498
Host variables make static SQL flexible . . . . . . . . . . . . . . 498
Dynamic SQL is completely flexible . . . . . . . . . . . . . . . . 498
What dynamic SQL cannot do . . . . . . . . . . . . . . . . . . 498
What an application program using dynamic SQL does . . . . . . . . 499
Performance of static and dynamic SQL . . . . . . . . . . . . . . 499
Caching dynamic SQL statements . . . . . . . . . . . . . . . . . 500
Using the dynamic statement cache. . . . . . . . . . . . . . . . 501
Keeping prepared statements after commit points . . . . . . . . . . 502
Limiting dynamic SQL with the resource limit facility . . . . . . . . . . . 505
Writing an application to handle reactive governing . . . . . . . . . . 505
Writing an application to handle predictive governing . . . . . . . . . 505
Using predictive governing and downlevel DRDA requesters. . . . . . . 506
Using predictive governing and enabled requesters . . . . . . . . . . 506
Choosing a host language for dynamic SQL applications . . . . . . . . . 506
Dynamic SQL for non-SELECT statements . . . . . . . . . . . . . . 507
Dynamic execution using EXECUTE IMMEDIATE. . . . . . . . . . . 507
Dynamic execution using PREPARE and EXECUTE . . . . . . . . . 508
Dynamic SQL for fixed-list SELECT statements . . . . . . . . . . . . 511
What your application program must do . . . . . . . . . . . . . . 511
Dynamic SQL for varying-list SELECT statements . . . . . . . . . . . 513
What your application program must do . . . . . . . . . . . . . . 513
Preparing a varying-list SELECT statement . . . . . . . . . . . . . 513
Executing a varying-list SELECT statement dynamically . . . . . . . . 523
Executing arbitrary statements with parameter markers . . . . . . . . 524
How bind option REOPT(VARS) affects dynamic SQL . . . . . . . . . 525
Using dynamic SQL in COBOL . . . . . . . . . . . . . . . . . . 526

Chapter 24. Using stored procedures for client/server processing . . . . 527


Introduction to stored procedures. . . . . . . . . . . . . . . . . . 527
An example of a simple stored procedure . . . . . . . . . . . . . . 528
Setting up the stored procedures environment . . . . . . . . . . . . . 532
Defining your stored procedure to DB2 . . . . . . . . . . . . . . 533
Refreshing the stored procedures environment (for system administrators) 537
Moving stored procedures to a WLM-established environment (for system
administrators). . . . . . . . . . . . . . . . . . . . . . . 538
Redefining stored procedures defined in SYSIBM.SYSPROCEDURES 539
Writing and preparing an external stored procedure . . . . . . . . . . . 539
Language requirements for the stored procedure and its caller . . . . . . 540
Calling other programs . . . . . . . . . . . . . . . . . . . . 540
Using reentrant code . . . . . . . . . . . . . . . . . . . . . 540
Writing a stored procedure as a main program or subprogram . . . . . . 541
Restrictions on a stored procedure . . . . . . . . . . . . . . . . 543

x Application Programming and SQL Guide


| Using COMMIT and ROLLBACK statements in a stored procedure . . . . 544
Using special registers in a stored procedure . . . . . . . . . . . . 544
Accessing other sites in a stored procedure . . . . . . . . . . . . . 546
Writing a stored procedure to access IMS databases . . . . . . . . . 547
Writing a stored procedure to return result sets to a DRDA client . . . . . 547
Preparing a stored procedure . . . . . . . . . . . . . . . . . . 549
Binding the stored procedure . . . . . . . . . . . . . . . . . . 550
Writing a REXX stored procedure . . . . . . . . . . . . . . . . 551
Writing and preparing an SQL procedure . . . . . . . . . . . . . . . 554
Comparison of an SQL procedure and an external procedure . . . . . . 555
Statements that you can include in a procedure body . . . . . . . . . 556
Declaring and using variables in an SQL procedure . . . . . . . . . . 557
Parameter style for an SQL procedure . . . . . . . . . . . . . . . 559
Terminating statements in an SQL procedure . . . . . . . . . . . . 559
Handling errors in an SQL procedure . . . . . . . . . . . . . . . 559
Examples of SQL procedures . . . . . . . . . . . . . . . . . . 561
Preparing an SQL procedure . . . . . . . . . . . . . . . . . . 563
Writing and preparing an application to use stored procedures . . . . . . . 572
Forms of the CALL statement . . . . . . . . . . . . . . . . . . 572
Authorization for executing stored procedures . . . . . . . . . . . . 574
Linkage conventions . . . . . . . . . . . . . . . . . . . . . 574
Using indicator variables to speed processing . . . . . . . . . . . . 596
Declaring data types for passed parameters. . . . . . . . . . . . . 597
Writing a DB2 for OS/390 and z/OS client program or SQL procedure to
receive result sets . . . . . . . . . . . . . . . . . . . . . 602
Accessing transition tables in a stored procedure . . . . . . . . . . . 608
Calling a stored procedure from a REXX Procedure . . . . . . . . . . 608
Preparing a client program . . . . . . . . . . . . . . . . . . . 612
Running a stored procedure . . . . . . . . . . . . . . . . . . . 613
How DB2 determines which version of a stored procedure to run . . . . . 614
Using a single application program to call different versions of a stored
procedure . . . . . . . . . . . . . . . . . . . . . . . . 614
Running multiple stored procedures concurrently . . . . . . . . . . . 615
Accessing non-DB2 resources . . . . . . . . . . . . . . . . . . 616
Testing a stored procedure . . . . . . . . . . . . . . . . . . . . 618
Debugging the stored procedure as a stand-alone program on a workstation 618
Debugging with the Debug Tool and IBM VisualAge® COBOL . . . . . . 619
Debugging an SQL procedure or C language stored procedure with the
Debug Tool and C/C⁺⁺ Productivity Tools for OS/390 . . . . . . . . 619
Debugging with CODE/370 . . . . . . . . . . . . . . . . . . . 620
Using the MSGFILE run-time option. . . . . . . . . . . . . . . . 622
Using driver applications . . . . . . . . . . . . . . . . . . . . 622
Using SQL INSERTs . . . . . . . . . . . . . . . . . . . . . 622

Chapter 25. Tuning your queries . . . . . . . . . . . . . . . . . 625


General tips and questions . . . . . . . . . . . . . . . . . . . . 625
Is the query coded as simply as possible? . . . . . . . . . . . . . 625
Are all predicates coded correctly? . . . . . . . . . . . . . . . . 625
Are there subqueries in your query? . . . . . . . . . . . . . . . 626
Does your query involve column functions? . . . . . . . . . . . . . 627
Do you have an input variable in the predicate of a static SQL query? 627
Do you have a problem with column correlation? . . . . . . . . . . . 627
Can your query be written to use a noncolumn expression? . . . . . . . 627
Writing efficient predicates . . . . . . . . . . . . . . . . . . . . 628
Properties of predicates . . . . . . . . . . . . . . . . . . . . 628
Predicates in the ON clause . . . . . . . . . . . . . . . . . . 631

Contents xi
General rules about predicate evaluation . . . . . . . . . . . . . . . 631
Order of evaluating predicates . . . . . . . . . . . . . . . . . . 632
Summary of predicate processing . . . . . . . . . . . . . . . . 632
Examples of predicate properties . . . . . . . . . . . . . . . . . 636
Predicate filter factors . . . . . . . . . . . . . . . . . . . . . 637
DB2 predicate manipulation . . . . . . . . . . . . . . . . . . . 642
Column correlation . . . . . . . . . . . . . . . . . . . . . . 645
Using host variables efficiently . . . . . . . . . . . . . . . . . . . 648
Using REOPT(VARS) to change the access path at run time . . . . . . 648
Rewriting queries to influence access path selection. . . . . . . . . . 649
Writing efficient subqueries . . . . . . . . . . . . . . . . . . . . 652
Correlated subqueries . . . . . . . . . . . . . . . . . . . . . 653
Noncorrelated subqueries . . . . . . . . . . . . . . . . . . . 654
Subquery transformation into join. . . . . . . . . . . . . . . . . 655
Subquery tuning . . . . . . . . . . . . . . . . . . . . . . . 657
| Using scrollable cursors efficiently . . . . . . . . . . . . . . . . . 658
Writing efficient queries on views with UNION operators . . . . . . . . . 659
Special techniques to influence access path selection . . . . . . . . . . 660
Obtaining information about access paths . . . . . . . . . . . . . 661
Minimizing overhead for retrieving few rows: OPTIMIZE FOR n ROWS 661
| Fetching a limited number of rows: FETCH FIRST n ROWS ONLY . . . . 663
Reducing the number of matching columns . . . . . . . . . . . . . 664
Adding extra local predicates . . . . . . . . . . . . . . . . . . 665
Creating indexes for efficient star schemas . . . . . . . . . . . . . 666
Rearranging the order of tables in a FROM clause . . . . . . . . . . 668
Updating catalog statistics . . . . . . . . . . . . . . . . . . . 668
Using a subsystem parameter . . . . . . . . . . . . . . . . . . 670

Chapter 26. Using EXPLAIN to improve SQL performance . . . . . . . 671


Obtaining PLAN_TABLE information from EXPLAIN . . . . . . . . . . . 672
Creating PLAN_TABLE . . . . . . . . . . . . . . . . . . . . 672
Populating and maintaining a plan table . . . . . . . . . . . . . . 677
Reordering rows from a plan table . . . . . . . . . . . . . . . . 678
Asking questions about data access . . . . . . . . . . . . . . . . 679
Is access through an index? (ACCESSTYPE is I, I1, N or MX) . . . . . . 679
Is access through more than one index? (ACCESSTYPE=M) . . . . . . 679
How many columns of the index are used in matching? (MATCHCOLS=n) 680
Is the query satisfied using only the index? (INDEXONLY=Y) . . . . . . 681
Is direct row access possible? (PRIMARY_ACCESSTYPE = D) . . . . . 681
Is a view or nested table expression materialized? . . . . . . . . . . 685
Was a scan limited to certain partitions? (PAGE_RANGE=Y) . . . . . . 685
What kind of prefetching is done? (PREFETCH = L, S, or blank) . . . . . 686
Is data accessed or processed in parallel? (PARALLELISM_MODE is I, C,
or X) . . . . . . . . . . . . . . . . . . . . . . . . . . 686
Are sorts performed? . . . . . . . . . . . . . . . . . . . . . 686
Is a subquery transformed into a join? . . . . . . . . . . . . . . . 687
When are column functions evaluated? (COLUMN_FN_EVAL) . . . . . . 687
Interpreting access to a single table . . . . . . . . . . . . . . . . . 687
Table space scans (ACCESSTYPE=R PREFETCH=S) . . . . . . . . . 688
Index access paths . . . . . . . . . . . . . . . . . . . . . . 689
UPDATE using an index . . . . . . . . . . . . . . . . . . . . 693
Interpreting access to two or more tables (join) . . . . . . . . . . . . 693
Definitions and examples. . . . . . . . . . . . . . . . . . . . 694
Nested loop join (METHOD=1) . . . . . . . . . . . . . . . . . 696
Merge scan join (METHOD=2). . . . . . . . . . . . . . . . . . 697
Hybrid join (METHOD=4). . . . . . . . . . . . . . . . . . . . 699

xii Application Programming and SQL Guide


Star schema (star join) . . . . . . . . . . . . . . . . . . . . 701
Interpreting data prefetch. . . . . . . . . . . . . . . . . . . . . 705
Sequential prefetch (PREFETCH=S) . . . . . . . . . . . . . . . 705
List prefetch (PREFETCH=L) . . . . . . . . . . . . . . . . . . 706
Sequential detection at execution time . . . . . . . . . . . . . . . 707
Determining sort activity . . . . . . . . . . . . . . . . . . . . . 709
Sorts of data . . . . . . . . . . . . . . . . . . . . . . . . 709
Sorts of RIDs . . . . . . . . . . . . . . . . . . . . . . . . 710
The effect of sorts on OPEN CURSOR . . . . . . . . . . . . . . 710
Processing for views and nested table expressions . . . . . . . . . . . 710
Merge . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
Materialization . . . . . . . . . . . . . . . . . . . . . . . . 711
Using EXPLAIN to determine when materialization occurs . . . . . . . 713
| Using EXPLAIN to determine UNION activity and query rewrite . . . . . 715
Performance of merge versus materialization . . . . . . . . . . . . 716
Estimating a statement’s cost . . . . . . . . . . . . . . . . . . . 717
Creating a statement table . . . . . . . . . . . . . . . . . . . 717
Populating and maintaining a statement table . . . . . . . . . . . . 719
Retrieving rows from a statement table . . . . . . . . . . . . . . 719
Understanding the implications of cost categories. . . . . . . . . . . 720

Chapter 27. Parallel operations and query performance . . . . . . . . 721


Comparing the methods of parallelism . . . . . . . . . . . . . . . . 722
Enabling parallel processing . . . . . . . . . . . . . . . . . . . 724
When parallelism is not used . . . . . . . . . . . . . . . . . . . 725
Interpreting EXPLAIN output . . . . . . . . . . . . . . . . . . . 726
A method for examining PLAN_TABLE columns for parallelism . . . . . . 726
PLAN_TABLE examples showing parallelism . . . . . . . . . . . . 726
Tuning parallel processing . . . . . . . . . . . . . . . . . . . . 727
Disabling query parallelism . . . . . . . . . . . . . . . . . . . . 728

Chapter 28. Programming for the Interactive System Productivity Facility


(ISPF) . . . . . . . . . . . . . . . . . . . . . . . . . . . 729
Using ISPF and the DSN command processor . . . . . . . . . . . . . 729
Invoking a single SQL program through ISPF and DSN . . . . . . . . . 730
Invoking multiple SQL programs through ISPF and DSN . . . . . . . . . 731
Invoking multiple SQL programs through ISPF and CAF . . . . . . . . . 731

Chapter 29. Programming for the call attachment facility (CAF) . . . . . 733
Call attachment facility capabilities and restrictions . . . . . . . . . . . 733
Capabilities when using CAF . . . . . . . . . . . . . . . . . . 733
CAF requirements . . . . . . . . . . . . . . . . . . . . . . 734
How to use CAF . . . . . . . . . . . . . . . . . . . . . . . . 736
Summary of connection functions . . . . . . . . . . . . . . . . 737
Accessing the CAF language interface. . . . . . . . . . . . . . . 739
General properties of CAF connections . . . . . . . . . . . . . . 740
CAF function descriptions . . . . . . . . . . . . . . . . . . . 741
CONNECT: Syntax and usage . . . . . . . . . . . . . . . . . . 743
OPEN: Syntax and usage . . . . . . . . . . . . . . . . . . . 747
CLOSE: Syntax and usage . . . . . . . . . . . . . . . . . . . 749
DISCONNECT: Syntax and usage . . . . . . . . . . . . . . . . 750
TRANSLATE: Syntax and usage . . . . . . . . . . . . . . . . . 751
Summary of CAF behavior . . . . . . . . . . . . . . . . . . . 753
Sample scenarios . . . . . . . . . . . . . . . . . . . . . . . 754
A single task with implicit connections . . . . . . . . . . . . . . . 754
A single task with explicit connections . . . . . . . . . . . . . . . 754

Contents xiii
Several tasks . . . . . . . . . . . . . . . . . . . . . . . . 754
Exits from your application . . . . . . . . . . . . . . . . . . . . 755
Attention exits . . . . . . . . . . . . . . . . . . . . . . . . 755
Recovery routines . . . . . . . . . . . . . . . . . . . . . . 755
Error messages and dsntrace . . . . . . . . . . . . . . . . . . . 756
CAF return codes and reason codes . . . . . . . . . . . . . . . . 756
Subsystem support subcomponent codes (X'00F3') . . . . . . . . . . 757
Program examples . . . . . . . . . . . . . . . . . . . . . . . 757
Sample JCL for using CAF . . . . . . . . . . . . . . . . . . . 757
Sample assembler code for using CAF . . . . . . . . . . . . . . 757
Loading and deleting the CAF language interface. . . . . . . . . . . 758
Establishing the connection to DB2 . . . . . . . . . . . . . . . . 758
Checking return codes and reason codes. . . . . . . . . . . . . . 760
Using dummy entry point DSNHLI . . . . . . . . . . . . . . . . 763
Variable declarations . . . . . . . . . . . . . . . . . . . . . 764

Chapter 30. Programming for the Recoverable Resource Manager


Services attachment facility (RRSAF) . . . . . . . . . . . . . . 767
RRSAF capabilities and restrictions . . . . . . . . . . . . . . . . . 767
Capabilities of RRSAF applications . . . . . . . . . . . . . . . . 767
RRSAF requirements . . . . . . . . . . . . . . . . . . . . . 768
How to use RRSAF. . . . . . . . . . . . . . . . . . . . . . . 769
Accessing the RRSAF language interface . . . . . . . . . . . . . 770
General properties of RRSAF connections . . . . . . . . . . . . . 772
Summary of connection functions . . . . . . . . . . . . . . . . 773
RRSAF function descriptions . . . . . . . . . . . . . . . . . . 774
Summary of RRSAF behavior . . . . . . . . . . . . . . . . . . 796
Sample scenarios . . . . . . . . . . . . . . . . . . . . . . . 797
A single task . . . . . . . . . . . . . . . . . . . . . . . . 797
Multiple tasks . . . . . . . . . . . . . . . . . . . . . . . . 798
Calling SIGNON to reuse a DB2 thread . . . . . . . . . . . . . . 798
Switching DB2 threads between tasks . . . . . . . . . . . . . . . 798
RRSAF return codes and reason codes . . . . . . . . . . . . . . . 799
Program examples . . . . . . . . . . . . . . . . . . . . . . . 800
Sample JCL for using RRSAF . . . . . . . . . . . . . . . . . . 800
Loading and deleting the RRSAF language interface . . . . . . . . . 800
Using dummy entry point DSNHLI . . . . . . . . . . . . . . . . 800
Establishing a connection to DB2. . . . . . . . . . . . . . . . . 801

Chapter 31. Programming considerations for CICS . . . . . . . . . . 803


Controlling the CICS attachment facility from an application . . . . . . . . 803
Improving thread reuse . . . . . . . . . . . . . . . . . . . . . 803
Detecting whether the CICS attachment facility is operational . . . . . . . 803

Chapter 32. Programming techniques: Questions and answers . . . . . 805


Providing a unique key for a table . . . . . . . . . . . . . . . . . 805
| Scrolling through previously retrieved data . . . . . . . . . . . . . . 805
| Using a scrollable cursor . . . . . . . . . . . . . . . . . . . . 805
| Using a ROWID or identity column . . . . . . . . . . . . . . . . 806
| Scrolling through a table in any direction . . . . . . . . . . . . . . . 807
Updating data as it is retrieved from the database . . . . . . . . . . . 808
| Updating previously retrieved data . . . . . . . . . . . . . . . . . 808
Updating thousands of rows . . . . . . . . . . . . . . . . . . . 808
Retrieving thousands of rows . . . . . . . . . . . . . . . . . . . 809
Using SELECT * . . . . . . . . . . . . . . . . . . . . . . . . 809
| Optimizing retrieval for a small set of rows . . . . . . . . . . . . . . 809

xiv Application Programming and SQL Guide


Adding data to the end of a table. . . . . . . . . . . . . . . . . . 810
Translating requests from end users into SQL statements. . . . . . . . . 810
Changing the table definition . . . . . . . . . . . . . . . . . . . 810
Storing data that does not have a tabular format . . . . . . . . . . . . 811
Finding a violated referential or check constraint . . . . . . . . . . . . 811

Part 7. Appendixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 813

Appendix A. DB2 sample tables . . . . . . . . . . . . . . . . . 815


Activity table (DSN8710.ACT) . . . . . . . . . . . . . . . . . . . 815
Content . . . . . . . . . . . . . . . . . . . . . . . . . . 815
Relationship to other tables . . . . . . . . . . . . . . . . . . . 815
Department table (DSN8710.DEPT) . . . . . . . . . . . . . . . . . 816
Content . . . . . . . . . . . . . . . . . . . . . . . . . . 816
Relationship to other tables . . . . . . . . . . . . . . . . . . . 816
Employee table (DSN8710.EMP) . . . . . . . . . . . . . . . . . . 817
Content . . . . . . . . . . . . . . . . . . . . . . . . . . 818
Relationship to other tables . . . . . . . . . . . . . . . . . . . 818
Employee photo and resume table (DSN8710.EMP_PHOTO_RESUME) . . . 820
Content . . . . . . . . . . . . . . . . . . . . . . . . . . 821
Relationship to other tables . . . . . . . . . . . . . . . . . . . 821
Project table (DSN8710.PROJ) . . . . . . . . . . . . . . . . . . 822
Content . . . . . . . . . . . . . . . . . . . . . . . . . . 822
Relationship to other tables . . . . . . . . . . . . . . . . . . . 823
Project activity table (DSN8710.PROJACT) . . . . . . . . . . . . . . 823
Content . . . . . . . . . . . . . . . . . . . . . . . . . . 823
Relationship to other tables . . . . . . . . . . . . . . . . . . . 823
Employee to project activity table (DSN8710.EMPPROJACT) . . . . . . . 824
Content . . . . . . . . . . . . . . . . . . . . . . . . . . 824
Relationship to other tables . . . . . . . . . . . . . . . . . . . 824
Relationships among the tables . . . . . . . . . . . . . . . . . . 825
Views on the sample tables . . . . . . . . . . . . . . . . . . . . 825
Storage of sample application tables . . . . . . . . . . . . . . . . 828
Storage group . . . . . . . . . . . . . . . . . . . . . . . . 829
Databases . . . . . . . . . . . . . . . . . . . . . . . . . 829
Table spaces . . . . . . . . . . . . . . . . . . . . . . . . 829

Appendix B. Sample applications . . . . . . . . . . . . . . . . . 833


Types of sample applications . . . . . . . . . . . . . . . . . . . 833
Using the applications . . . . . . . . . . . . . . . . . . . . . . 835
TSO . . . . . . . . . . . . . . . . . . . . . . . . . . . 836
IMS . . . . . . . . . . . . . . . . . . . . . . . . . . . 838
CICS . . . . . . . . . . . . . . . . . . . . . . . . . . . 838

Appendix C. How to run sample programs DSNTIAUL, DSNTIAD, and


DSNTEP2 . . . . . . . . . . . . . . . . . . . . . . . . . 839
Running DSNTIAUL . . . . . . . . . . . . . . . . . . . . . . 840
Running DSNTIAD . . . . . . . . . . . . . . . . . . . . . . . 843
Running DSNTEP2 . . . . . . . . . . . . . . . . . . . . . . . 845

Appendix D. Programming examples . . . . . . . . . . . . . . . 849


Sample COBOL dynamic SQL program . . . . . . . . . . . . . . . 849
Pointers and based variables . . . . . . . . . . . . . . . . . . 849
Storage allocation . . . . . . . . . . . . . . . . . . . . . . 849
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 850
Sample dynamic and static SQL in a C program . . . . . . . . . . . . 863

Contents xv
Example DB2 REXX application . . . . . . . . . . . . . . . . . . 866
Sample COBOL program using DRDA access . . . . . . . . . . . . . 880
Sample COBOL program using DB2 private protocol access . . . . . . . 888
Examples of using stored procedures . . . . . . . . . . . . . . . . 894
Calling a stored procedure from a C program . . . . . . . . . . . . 895
Calling a stored procedure from a COBOL program . . . . . . . . . . 898
Calling a stored procedure from a PL/I program . . . . . . . . . . . 901
C stored procedure: GENERAL . . . . . . . . . . . . . . . . . 903
C stored procedure: GENERAL WITH NULLS . . . . . . . . . . . . 905
COBOL stored procedure: GENERAL . . . . . . . . . . . . . . . 907
COBOL stored procedure: GENERAL WITH NULLS. . . . . . . . . . 910
PL/I stored procedure: GENERAL . . . . . . . . . . . . . . . . 912
PL/I stored procedure: GENERAL WITH NULLS . . . . . . . . . . . 913

Appendix E. REBIND subcommands for lists of plans or packages . . . 915


Overview of the procedure for generating lists of REBIND commands . . . . 915
Sample SELECT statements for generating REBIND commands . . . . . . 915
Sample JCL for running lists of REBIND commands . . . . . . . . . . . 918

Appendix F. SQL reserved words . . . . . . . . . . . . . . . . . 921

Appendix G. Characteristics of SQL statements in DB2 for OS/390 and


z/OS . . . . . . . . . . . . . . . . . . . . . . . . . . . 923
Actions allowed on SQL statements . . . . . . . . . . . . . . . . . 923
SQL statements allowed in external functions and stored procedures . . . . 926
SQL statements allowed in SQL procedures. . . . . . . . . . . . . . 928

Appendix H. Program preparation options for remote packages . . . . . 933

Appendix I. Stored procedures shipped with DB2 . . . . . . . . . . 935


The WLM environment refresh stored procedure (WLM_REFRESH) . . . . . 935
Environment . . . . . . . . . . . . . . . . . . . . . . . . 935
Authorization required . . . . . . . . . . . . . . . . . . . . . 935
WLM_REFRESH syntax diagram. . . . . . . . . . . . . . . . . 936
WLM_REFRESH option descriptions . . . . . . . . . . . . . . . 936
Example of WLM_REFRESH invocation . . . . . . . . . . . . . . 936
# The CICS transaction invocation stored procedure (DSNACICS) . . . . . . 937
# Environment . . . . . . . . . . . . . . . . . . . . . . . . 937
# Authorization required . . . . . . . . . . . . . . . . . . . . . 937
# DSNACICS syntax diagram . . . . . . . . . . . . . . . . . . . 938
# DSNACICS option descriptions . . . . . . . . . . . . . . . . . 938
# DSNACICX user exit . . . . . . . . . . . . . . . . . . . . . 940
# Example of DSNACICS invocation . . . . . . . . . . . . . . . . 942
# DSNACICS output . . . . . . . . . . . . . . . . . . . . . . 943
# DSNACICS restrictions . . . . . . . . . . . . . . . . . . . . 944
# DSNACICS debugging . . . . . . . . . . . . . . . . . . . . 944

Appendix J. Summary of changes to DB2 for OS/390 and z/OS Version 7 945
Enhancements for managing data . . . . . . . . . . . . . . . . . 945
Enhancements for reliability, scalability, and availability. . . . . . . . . . 945
Easier development and integration of e-business applications . . . . . . . 946
Improved connectivity . . . . . . . . . . . . . . . . . . . . . . 947
Features of DB2 for OS/390 and z/OS . . . . . . . . . . . . . . . . 948
Migration considerations . . . . . . . . . . . . . . . . . . . . . 948

Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . 949

xvi Application Programming and SQL Guide


Programming interface information . . . . . . . . . . . . . . . . . 950
Trademarks. . . . . . . . . . . . . . . . . . . . . . . . . . 951

Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . 953

Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . 971

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . X-1
.

Contents xvii
xviii Application Programming and SQL Guide
About this book
This book discusses how to design and write application programs that access
DB2® for OS/390® (DB2), a highly flexible relational database management system
(DBMS).

Important
In this version of DB2 for OS/390 and z/OS, some utility functions are
available as optional products. 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.

Who should read this book


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

Product terminology and citations


In this book, DB2 Universal Database™ Server for OS/390 and z/OS is referred to
as "DB2 for OS/390 and z/OS." In cases where the context makes the meaning
clear, DB2 for OS/390 and z/OS is referred to as "DB2." When this book refers to
other books in this library, a short title is used. (For example, "See DB2 SQL
Reference" is a citation to IBM® DATABASE 2™ Universal Database Server for
OS/390 and z/OS SQL Reference.)

When referring to a DB2 product other than DB2 for OS/390 and z/OS, this book
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.
C and C language
Represent the C programming language.
CICS® Represents CICS/ESA® and CICS Transaction Server for OS/390.
IMS™ Represents IMS or IMS/ESA®.
MVS Represents the MVS element of OS/390.
OS/390
Represents the OS/390 or z/OS operating system.
®
RACF
Represents the functions that are provided by the RACF component of the
SecureWay® Security Server for OS/390 or by the RACF component of the
OS/390 Security Server.

How to read the syntax diagrams


The following rules apply to the syntax diagrams used in this book:

© Copyright IBM Corp. 1983, 2001 xix


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 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.

xx Application Programming and SQL Guide


 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 Keywords appear in uppercase (for example, FROM). They 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.

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 OS/390 and z/OS documentation.
You can use any of the following methods to provide comments:
v Send your comments by e-mail to [email protected] 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, page number, or a help topic title).
v Send your comments from the Web. Visit the Web site at:

http://www.ibm.com/software/db2os390

The Web site has a feedback page that you can use to send comments.
v Complete the readers’ comment form at the back of the book and return it by
mail, by fax (800-426-7773 for the United States and Canada), or by giving it to
an IBM representative.

About this book xxi


xxii Application Programming and SQL Guide
Summary of changes to this book
| The principal changes to this book are:
| v Information that is duplicated in other books has been removed from “Chapter 1.
| Retrieving data” on page 3.
| v Chapter 7. Using a cursor to retrieve a set of rows explains how to use scrollable
| cursors.
# v Chapter 20. Preparing an application program to run contains information on how
# to use an SQL statement coprocessor for COBOL or PL/I programs.
| v Chapter 24. Using stored procedures for client/server processing contains
| information on enhancements to stored procedures, such as the ability to issue
| COMMIT and ROLLBACK statements in stored procedures.
| v Appendix I. Stored procedures shipped with DB2 is a new appendix that
| describes the WLM environment refresh stored procedure.

© Copyright IBM Corp. 1983, 2001 xxiii


xxiv Application Programming and SQL Guide
Part 1. Using SQL queries
Chapter 1. Retrieving data . . . . . . . . . . . . . . . . . . . . 3
Result tables . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Selecting columns: SELECT . . . . . . . . . . . . . . . . . . . . 5
Selecting all columns: SELECT * . . . . . . . . . . . . . . . . . . 5
Selecting some columns: SELECT column-name . . . . . . . . . . . . 6
Selecting DB2 data that is not in a table: Using SYSDUMMY1 . . . . . . . 7
Selecting derived columns: SELECT expression . . . . . . . . . . . . 7
Eliminating duplicate rows: DISTINCT . . . . . . . . . . . . . . . . 7
Naming result columns: AS . . . . . . . . . . . . . . . . . . . . 7
Selecting rows using search conditions: WHERE . . . . . . . . . . . . . 8
Putting the rows in order: ORDER BY . . . . . . . . . . . . . . . . . 9
Specifying the sort key . . . . . . . . . . . . . . . . . . . . . 9
Referencing derived columns. . . . . . . . . . . . . . . . . . . 10
Summarizing group values: GROUP BY . . . . . . . . . . . . . . . 10
Subjecting groups to conditions: HAVING . . . . . . . . . . . . . . . 11
Merging lists of values: UNION . . . . . . . . . . . . . . . . . . . 12
Using UNION to eliminate duplicates . . . . . . . . . . . . . . . . 12
Using UNION ALL to keep duplicates. . . . . . . . . . . . . . . . 13
Using 15-digit and 31-digit precision for decimal numbers . . . . . . . . . 13
Finding information in the DB2 catalog . . . . . . . . . . . . . . . . 14
Displaying a list of tables you can use . . . . . . . . . . . . . . . 14
Displaying a list of columns in a table . . . . . . . . . . . . . . . 15

Chapter 2. Working with tables and modifying data . . . . . . . . . . 17


Working with tables . . . . . . . . . . . . . . . . . . . . . . . 17
Creating your own tables: CREATE TABLE . . . . . . . . . . . . . 17
Identifying defaults . . . . . . . . . . . . . . . . . . . . . 18
Creating work tables . . . . . . . . . . . . . . . . . . . . . 18
Creating a new department table . . . . . . . . . . . . . . . . 18
Creating a new employee table . . . . . . . . . . . . . . . . . 19
Working with temporary tables . . . . . . . . . . . . . . . . . . 19
Working with created temporary tables . . . . . . . . . . . . . . 20
Working with declared temporary tables. . . . . . . . . . . . . . 21
Dropping tables: DROP TABLE . . . . . . . . . . . . . . . . . . 23
Working with views . . . . . . . . . . . . . . . . . . . . . . . 23
Defining a view: CREATE VIEW . . . . . . . . . . . . . . . . . 23
Changing data through a view . . . . . . . . . . . . . . . . . . 24
Dropping views: DROP VIEW . . . . . . . . . . . . . . . . . . 25
Modifying DB2 data . . . . . . . . . . . . . . . . . . . . . . . 25
Inserting a row: INSERT . . . . . . . . . . . . . . . . . . . . 25
Filling a table from another table: Mass INSERT . . . . . . . . . . 26
Inserting data into a ROWID column . . . . . . . . . . . . . . . 27
Inserting data into an identity column . . . . . . . . . . . . . . . 27
Using an INSERT statement in an application program . . . . . . . . 29
Updating current values: UPDATE . . . . . . . . . . . . . . . . . 29
Deleting rows: DELETE. . . . . . . . . . . . . . . . . . . . . 31
Deleting every row in a table . . . . . . . . . . . . . . . . . . 31

Chapter 3. Joining data from more than one table . . . . . . . . . . . 33


Inner join . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Full outer join . . . . . . . . . . . . . . . . . . . . . . . . . 35
Left outer join . . . . . . . . . . . . . . . . . . . . . . . . . 36

© Copyright IBM Corp. 1983, 2001 1


Right outer join . . . . . . . . . . . . . . . . . . . . . . . . . 37
SQL rules for statements containing join operations . . . . . . . . . . . 37
Using more than one type of join in an SQL statement . . . . . . . . . . 38
Using nested table expressions and user-defined table functions in joins . . . 39

Chapter 4. Using subqueries . . . . . . . . . . . . . . . . . . . 43


Conceptual overview . . . . . . . . . . . . . . . . . . . . . . . 43
Correlated and uncorrelated subqueries. . . . . . . . . . . . . . . 44
Subqueries and predicates . . . . . . . . . . . . . . . . . . . 44
The subquery result table . . . . . . . . . . . . . . . . . . . . 44
Tables in subqueries of UPDATE, DELETE, and INSERT statements . . . . 45
How to code a subquery . . . . . . . . . . . . . . . . . . . . . 45
Basic predicate . . . . . . . . . . . . . . . . . . . . . . . . 45
Quantified predicates: ALL, ANY, and SOME . . . . . . . . . . . . . 45
Using the IN keyword . . . . . . . . . . . . . . . . . . . . . 46
Using the EXISTS keyword . . . . . . . . . . . . . . . . . . . 46
Using correlated subqueries . . . . . . . . . . . . . . . . . . . . 47
An example of a correlated subquery. . . . . . . . . . . . . . . . 47
Using correlation names in references . . . . . . . . . . . . . . . 48
Using correlated subqueries in an UPDATE statement . . . . . . . . . 49
Using correlated subqueries in a DELETE statement . . . . . . . . . . 49

Chapter 5. Executing SQL from your terminal using SPUFI . . . . . . . 51


Allocating an input data set and using SPUFI. . . . . . . . . . . . . . 51
Changing SPUFI defaults (optional) . . . . . . . . . . . . . . . . . 54
Entering SQL statements . . . . . . . . . . . . . . . . . . . . . 56
Processing SQL statements . . . . . . . . . . . . . . . . . . . . 57
Browsing the output . . . . . . . . . . . . . . . . . . . . . . . 58
Format of SELECT statement results . . . . . . . . . . . . . . . . 58
Content of the messages . . . . . . . . . . . . . . . . . . . . 59

2 Application Programming and SQL Guide


Chapter 1. Retrieving data
You can retrieve data using the SQL statement SELECT to specify a result table.
This chapter describes how to use SELECT statements interactively to retrieve data
from DB2 tables.

For more advanced topics on using SELECT statements, see “Chapter 4. Using
subqueries” on page 43, “Chapter 19. Planning to access distributed data” on
page 369, and Chapter 4 of DB2 SQL Reference.

Examples of SQL statements illustrate the concepts that this chapter discusses.
Consider developing SQL statements similar to these examples and then execute
them dynamically using SPUFI or Query Management Facility (QMF).

Result tables
The data retrieved through SQL is always in the form of a table, which is called a
result table. Like the tables from which you retrieve the data, a result table has rows
and columns. A program fetches this data one row at a time.

Example: SELECT statement: This SELECT statement retrieves the last name,
first name, and phone number of employees in department D11 from the sample
employee table:
SELECT LASTNAME, FIRSTNME, PHONENO
FROM DSN8710.EMP
WHERE WORKDEPT = 'D11'
ORDER BY LASTNAME;

The result table looks like this:


LASTNAME FIRSTNME PHONENO
=============== ============ ========
ADAMSON BRUCE 4510
BROWN DAVID 4501
JOHN REBA 0672
JONES WILLIAM 0942
LUTZ JENNIFER 0672
PIANKA ELIZABETH 3782
SCOUTTEN MARILYN 1682
STERN IRVING 6423
WALKER JAMES 2986
YAMAMOTO KIYOSHI 2890
YOSHIMURA MASATOSHI 2890

The result table displays in this form after SPUFI fetches and formats it. The format
of your results might be different.

Data types
When you create a DB2 table, you define each column to have a specific data type.
The data type can be a built-in data type or a distinct type. This section discusses
built-in data types. For information on distinct types, see “Chapter 15. Creating and
using distinct types” on page 301. The data type of a column determines what you
can and cannot do with it. 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, like a last name, into a column whose data type is
numeric. Similarly, you cannot compare columns containing incompatible data
types.

© Copyright IBM Corp. 1983, 2001 3


To better understand the concepts presented in this chapter, you must know the
data types of the columns to which an example refers. As shown in Figure 1, the
data types have four general categories: string, datetime, numeric, and ROWID.

Figure 1. DB2 data types

For more detailed information on each data type, see Chapter 2 of DB2 SQL
Reference.

Table 1 on page 5 shows whether operands of any two data types are compatible
(Yes) or incompatible (No).

4 Application Programming and SQL Guide


Table 1. Compatibility of data types for assignments and comparisons. Y indicates that the data types are compatible.
N indicates no compatibility. For any number in a column, read the corresponding note at the bottom of the table.
Char-
Binary Decimal Floating acter Graphic Binary Time- Row Distinct
Operands integer number point string string string Date Time stamp ID type
Binary Y Y Y N N N N N N N 2
Integer
Decimal Y Y Y N N N N N N N 2
Number
Floating Y Y Y N N N N N N N 2
Point
| Character N N N Y N4,5 N3 1 1 1 N 2
String
| Graphic N N N N4,5 Y N 1,4 1,4 1,4 N 2
String
Binary N N N N3 N Y N N N N 2
String
| Date N N N 1 1,4 N Y N N N 2
| Time N N N 1 1,4 N N Y N N 2
| Time- N N N 1 1,4 N N N Y N 2
stamp
Row ID N N N N N N N N N Y 2
Distinct 2 2 2 2 2 2 2 2 2 2 Y2
Type
Notes:
1. The compatibility of datetime values is limited to assignment and comparison:
v Datetime values can be assigned to string columns and to string variables, as explained in Chapter 2 of DB2
SQL Reference.
v A valid string representation of a date can be assigned to a date column or compared to a date.
v A valid string representation of a time can be assigned to a time column or compared to a time.
v A valid string representation of a timestamp can be assigned to a timestamp column or compared to a
timestamp.
2. A value with a distinct type is comparable only to a value that is defined with the same distinct type. In general,
DB2 supports assignments between a distinct type value and its source data type. For additional information, see
Chapter 2 of DB2 SQL Reference.
3. All character strings, even those with subtype FOR BIT DATA, are not compatible with binary strings.
| 4. These data types are compatible if the graphic string is Unicode UTF-16. On assignment and comparison from
| Graphic to Character, the resulting length is 3 * (LENGTH(graphic string)).
| 5. Character strings with subtype FOR BIT DATA are not compatible with Unicode UTF-16 Graphic Data.

Selecting columns: SELECT


You have several options for selecting columns from a database for your result
tables. This section describes how to select columns using a variety of techniques.

Selecting all columns: SELECT *


You do not need to know the column names to select DB2 data. Use an asterisk (*)
in the SELECT clause to indicate that you want to retrieve from each selected row
of the named table.

Chapter 1. Retrieving data 5


Example: SELECT *: This SQL statement selects all columns from the department
table:
SELECT *
FROM DSN8710.DEPT;

The result table looks like this:


DEPTNO DEPTNAME MGRNO ADMRDEPT LOCATION
====== ==================================== ====== ======== ========
A00 SPIFFY COMPUTER SERVICE DIV. 000010 A00 --------
B01 PLANNING 000020 A00 --------
C01 INFORMATION CENTER 000030 A00 --------
D01 DEVELOPMENT CENTER ------ A00 --------
D11 MANUFACTURING SYSTEMS 000060 D01 --------
D21 ADMINISTRATION SYSTEMS 000070 D01 --------
E01 SUPPORT SERVICES 000050 A00 --------
E11 OPERATIONS 000090 E01 --------
E21 SOFTWARE SUPPORT 000100 E01 --------
F22 BRANCH OFFICE F2 ------ E01 --------
G22 BRANCH OFFICE G2 ------ E01 --------
H22 BRANCH OFFICE H2 ------ E01 --------
I22 BRANCH OFFICE I2 ------ E01 --------
J22 BRANCH OFFICE J2 ------ E01 --------

Because the example does not specify a WHERE clause, the statement retrieves
data from all rows.

The dashes for MGRNO and LOCATION in the result table indicate null values.

SELECT * is recommended mostly for use with dynamic SQL and view definitions.
You can use SELECT * in static SQL, but this is not recommended; if you add a
column to the table to which SELECT * refers, the program might reference
columns for which you have not defined receiving host variables. For more
information on host variables, see “Accessing data using host variables and host
structures” on page 67.

If you list the column names in a static SELECT statement instead of using an
asterisk, you can avoid the problem just mentioned. You can also see the
relationship between the receiving host variables and the columns in the result
table.

Selecting some columns: SELECT column-name


Select the column or columns you want by naming each column. All columns
appear in the order you specify, not in their order in the table.

Example: SELECT column-name: This SQL statement selects only the MGRNO
and DEPTNO columns from the department table:
SELECT MGRNO, DEPTNO
FROM DSN8710.DEPT;

The result table looks like this:


MGRNO DEPTNO
====== ======
000010 A00
000020 B01
000030 C01
------ D01
000050 E01
000060 D11
000070 D21

6 Application Programming and SQL Guide


000090 E11
000100 E21
------ F22
------ G22
------ H22
------ I22
------ J22

With a single SELECT statement, you can select data from one column or as many
as 750 columns.

Selecting DB2 data that is not in a table: Using SYSDUMMY1


DB2 provides an EBCDIC table, SYSIBM.SYSDUMMY1, that you can use to select
DB2 data that is not in a table.

For example, if you want to execute a DB2 built-in function on host variable, you
can use an SQL statement like this:
SELECT RAND(:HRAND)
FROM SYSIBM.SYSDUMMY1;

Selecting derived columns: SELECT expression


You can select columns derived from a constant, an expression, or a function.

Example: SELECT with an expression: This SQL statement generates a result


table in which the second column is a derived column that is generated by adding
the values of the SALARY, BONUS, and COMM columns.
SELECT EMPNO, (SALARY + BONUS + COMM)
FROM DSN8710.EMP;

Derived columns in a result table, such as (SALARY + BONUS + COMM), do not


have names. The AS clause lets you give names to unnamed columns. See
“Naming result columns: AS” for information on the AS clause.

If you want to order the rows of data in the result table, use the ORDER BY clause
described in “Putting the rows in order: ORDER BY” on page 9.

Eliminating duplicate rows: DISTINCT


The DISTINCT keyword removes duplicate rows from your result, so that each row
contains unique data.

Example: SELECT DISTINCT: The following SELECT statement lists unique


department numbers for administrating departments:
SELECT DISTINCT ADMRDEPT
FROM DSN8710.DEPT;

The result table looks like this:


ADMRDEPT
========
A00
D01
E01

Naming result columns: AS


With AS, you can name result columns in a SELECT clause. This is particularly
useful for a column that is derived from an expression or a function. For syntax and
more information, see Chapter 2 of DB2 SQL Reference.

Chapter 1. Retrieving data 7


The following examples show different ways to use the AS clause.

Example: SELECT with AS CLAUSE: The expression SALARY+BONUS+COMM


has the name TOTAL_SAL.
SELECT SALARY+BONUS+COMM AS TOTAL_SAL
FROM DSN8710.EMP
ORDER BY TOTAL_SAL;

Example: CREATE VIEW with AS clause: You can specify result column names in
the select-clause of a CREATE VIEW statement. You do not need to supply the
column list of CREATE VIEW, because the AS keyword names the derived column.
The columns in the view EMP_SAL are EMPNO and TOTAL_SAL.
CREATE VIEW EMP_SAL AS
SELECT EMPNO,SALARY+BONUS+COMM AS TOTAL_SAL
FROM DSN8710.EMP;

Example: UNION ALL with AS clause: You can use the AS clause to give the
same name to corresponding columns of tables in a union. The third result column
from the union of the two tables has the name TOTAL_VALUE, even though it
contains data derived from columns with different names:
SELECT 'On hand' AS STATUS, PARTNO, QOH * COST AS TOTAL_VALUE
FROM PART_ON_HAND
UNION ALL
SELECT 'Ordered' AS STATUS, PARTNO, QORDER * COST AS TOTAL_VALUE
FROM ORDER_PART
ORDER BY PARTNO, TOTAL_VALUE;

The column STATUS and the derived column TOTAL_VALUE have the same name
in the first and second result tables, and are combined in the union of the two result
tables:
STATUS PARTNO TOTAL_VALUE
----------- ------ -----------
On hand 00557 345.60
Ordered
. 00557 150.50
.
.

For information on unions, see “Merging lists of values: UNION” on page 12.

Example: FROM clause with AS clause: Use the AS clause in a FROM clause to
assign a name to a derived column that you want to refer to in a GROUP BY
clause. Using the AS clause in the first SELECT clause causes an error, because
the names assigned in the AS clause do not yet exist when the GROUP BY
executes. However, you can use an AS clause of a subselect in the outer GROUP
BY clause, because the subselect is at a lower level than the GROUP BY that
references the name. This SQL statement names HIREYEAR in the nested table
expression, which lets you use the name of that result column in the GROUP BY
clause:
SELECT HIREYEAR, AVG(SALARY)
FROM (SELECT YEAR(HIREDATE) AS HIREYEAR, SALARY
FROM DSN8710.EMP) AS NEWEMP
GROUP BY HIREYEAR;

Selecting rows using search conditions: WHERE


Use a WHERE clause to select the rows that meet certain conditions. A WHERE
clause specifies a search condition. A search condition consists of one or more
predicates. A predicate specifies a test you want DB2 to apply to each table row.

8 Application Programming and SQL Guide


DB2 evaluates a predicate for a row as true, false, or unknown. Results are
unknown only if an operand is null.

If a search condition contains a column of a distinct type, the value to which that
column is compared must be of the same distinct type, or you must cast the value
to the distinct type. See “Chapter 15. Creating and using distinct types” on page 301
for more information.

The next sections illustrate different comparison operators that you can use in a
predicate in a WHERE clause. The following table lists the comparison operators.
Table 2. Comparison operators used in conditions
Type of Specified with... Example
comparison
Equal to null IS NULL PHONENO IS NULL
Equal to = DEPTNO = 'X01'
Not equal to <> DEPTNO <> 'X01'
Less than < AVG(SALARY) < 30000
Less than or equal to <= AGE <= 25
Not less than >= AGE >= 21
Greater than > SALARY > 2000
Greater than or equal to >= SALARY >= 5000
Not greater than <= SALARY <= 5000
Similar to another value LIKE NAME LIKE '%SMITH%' or STATUS LIKE 'N_'
At least one of two OR HIREDATE < '1965-01-01' OR SALARY < 16000
conditions
Both of two conditions AND HIREDATE < '1965-01-01' AND SALARY < 16000
Between two values BETWEEN SALARY BETWEEN 20000 AND 40000
Equals a value in a set IN (X, Y, Z) DEPTNO IN ('B01', 'C01', 'D01')

You can also search for rows that do not satisfy one of the above conditions, by
using the NOT keyword before the specified condition.

Putting the rows in order: ORDER BY


To retrieve rows in a specific order, use the ORDER BY clause. Using ORDER BY
is the only way to guarantee that your rows are ordered as you want them. The
following sections show you how to use the ORDER BY clause.

Specifying the sort key


| The order of the selected rows depends on the sort keys that you identify in the
| ORDER BY clause. A sort key can be a column name, an integer that represents
| the number of a column in the result table, or an expression. DB2 orders the rows
| by the first sort key, followed by the second sort key, and so on.

You can list the rows in ascending or descending order. Null values appear last in
an ascending sort and first in a descending sort.

Chapter 1. Retrieving data 9


DB2 sorts strings in the collating sequence associated with the encoding scheme of
the table. DB2 sorts numbers algebraically and sorts datetime values
chronologically.

Example: ORDER BY clause with a column name as the sort key: Retrieve the
employee numbers, last names, and hire dates of employees in department A00 in
ascending order of hire dates:
SELECT EMPNO, LASTNAME, HIREDATE
FROM DSN8710.EMP
WHERE WORKDEPT = 'A00'
ORDER BY HIREDATE ASC;

This is the result:


EMPNO LASTNAME HIREDATE
====== =============== ==========
000110 LUCCHESI 1958-05-16
000120 O'CONNELL 1963-12-05
000010 HAAS 1965-01-01
200010 HEMMINGER 1965-01-01
200120 ORLANDO 1972-05-05

Example: ORDER BY clause with an expression as the sort key: Retrieve the
employee numbers, salaries, commissions, and total compensation (salary plus
commission) for employees with a total compensation of greater than 40000. Order
the results by total compensation:
SELECT EMPNO, SALARY, COMM, SALARY+COMM AS "TOTAL COMP"
FROM DSN8710.EMP
WHERE SALARY+COMM = 40000
ORDER BY SALARY+COMM;

This is the result:


EMPNO SALARY COMM TOTAL COMP
====== ======== ======= ==========
000030 38250.00 3060.00 41310.00
000050 40175.00 3214.00 43389.00
000020 41250.00 3300.00 44550.00
000110 46500.00 3720.00 50220.00
200010 46500.00 4220.00 50720.00
000010 52750.00 4220.00 56970.00

Referencing derived columns


If you use the AS clause to name an unnamed column in a SELECT statement, you
can use that name in the ORDER BY clause. For example, the following SQL
statement orders the selected information by total salary:
SELECT EMPNO, (SALARY + BONUS + COMM) AS TOTAL_SAL
FROM DSN8710.EMP
ORDER BY TOTAL_SAL;

Summarizing group values: GROUP BY


Use GROUP BY to group rows by the values of one or more columns. You can then
apply column functions to each group.

Except for the columns named in the GROUP BY clause, the SELECT statement
must specify any other selected columns as an operand of one of the column
functions.

10 Application Programming and SQL Guide


The following SQL statement lists, for each department, the lowest and highest
education level within that department.
SELECT WORKDEPT, MIN(EDLEVEL), MAX(EDLEVEL)
FROM DSN8710.EMP
GROUP BY WORKDEPT;

If a column you specify in the GROUP BY clause contains null values, DB2
considers those null values to be equal. Thus, all nulls form a single group.

When it is used, the GROUP BY clause follows the FROM clause and any WHERE
clause, and precedes the ORDER BY clause.

You can also group the rows by the values of more than one column. For example,
the following statement finds the average salary for men and women in departments
A00 and C01:
SELECT WORKDEPT, SEX, AVG(SALARY) AS AVG_SALARY
FROM DSN8710.EMP
WHERE WORKDEPT IN ('A00', 'C01')
GROUP BY WORKDEPT, SEX;

gives this result:


WORKDEPT SEX AVG_SALARY
======== === ===========
A00 F 49625.00000000
A00 M 35000.00000000
C01 F 29722.50000000

DB2 groups the rows first by department number and next (within each department)
by sex before DB2 derives the average SALARY value for each group.

Subjecting groups to conditions: HAVING


Use HAVING to specify a search condition that each retrieved group must satisfy.
The HAVING clause acts like a WHERE clause for groups, and contains the same
kind of search conditions you specify in a WHERE clause. The search condition in
the HAVING clause tests properties of each group rather than properties of
individual rows in the group.

This SQL statement:


SELECT WORKDEPT, AVG(SALARY) AS AVG_SALARY
FROM DSN8710.EMP
GROUP BY WORKDEPT
HAVING COUNT(*) > 1
ORDER BY WORKDEPT;

gives this result:


WORKDEPT AVG_SALARY
======== ===============
A00 40850.00000000
C01 29722.50000000
D11 25147.27272727
D21 25668.57142857
E11 21020.00000000
E21 24086.66666666

Compare the preceding example with the second example shown in “Summarizing
group values: GROUP BY” on page 10. The HAVING COUNT(*) > 1 clause ensures

Chapter 1. Retrieving data 11


that only departments with more than one member display. (In this case,
departments B01 and E01 do not display.)

The HAVING clause tests a property of the group. For example, you could use it to
retrieve the average salary and minimum education level of women in each
department in which all female employees have an education level greater than or
equal to 16. Assuming you only want results from departments A00 and D11, the
following SQL statement tests the group property, MIN(EDLEVEL):
SELECT WORKDEPT, AVG(SALARY) AS AVG_SALARY,
MIN(EDLEVEL) AS MIN_EDLEVEL
FROM DSN8710.EMP
WHERE SEX = 'F' AND WORKDEPT IN ('A00', 'D11')
GROUP BY WORKDEPT
HAVING MIN(EDLEVEL) >= 16;

The SQL statement above gives this result:


WORKDEPT AVG_SALARY MIN_EDLEVEL
======== =============== ============
A00 49625.00000000 18
D11 25817.50000000 17

When you specify both GROUP BY and HAVING, the HAVING clause must follow
the GROUP BY clause. A function in a HAVING clause can include DISTINCT if you
have not used DISTINCT anywhere else in the same SELECT statement. You can
also connect multiple predicates in a HAVING clause with AND and OR, and you
can use NOT for any predicate of a search condition.

Merging lists of values: UNION


Using the UNION keyword, you can combine two or more SELECT statements to
form a single result table. When DB2 encounters the UNION keyword, it processes
each SELECT statement to form an interim result table, and then combines the
interim result table of each statement. If you use UNION to combine two columns
with the same name, the result table inherits that name.

When you use the UNION statement, the SQLNAME field of the SQLDA contains
the column names of the first operand.

Using UNION to eliminate duplicates


You can use UNION to eliminate duplicates when merging lists of values obtained
from several tables. For example, you can obtain a combined list of employee
numbers that includes both of the following:
v People in department D11
v People whose assignments include projects MA2112, MA2113, and AD3111.

For example, this SQL statement:


SELECT EMPNO
FROM DSN8710.EMP
WHERE WORKDEPT = 'D11'
UNION
SELECT EMPNO
FROM DSN8710.EMPPROJACT
WHERE PROJNO = 'MA2112' OR
PROJNO = 'MA2113' OR
PROJNO = 'AD3111'
ORDER BY EMPNO;

12 Application Programming and SQL Guide


gives a combined result table containing employee numbers in ascending order with
no duplicates listed.

If you have an ORDER BY clause, it must appear after the last SELECT statement
that is part of the union. In this example, the first column of the final result table
determines the final order of the rows.

Using UNION ALL to keep duplicates


If you want to keep duplicates in the result of a UNION, specify the optional
keyword ALL after the UNION keyword.

This SQL statement:


SELECT EMPNO
FROM DSN8710.EMP
WHERE WORKDEPT = 'D11'
UNION ALL
SELECT EMPNO
FROM DSN8710.EMPPROJACT
WHERE PROJNO = 'MA2112' OR
PROJNO = 'MA2113' OR
PROJNO = 'AD3111'
ORDER BY EMPNO;

gives a combined result table containing employee numbers in ascending order,


and includes duplicate numbers.

Using 15-digit and 31-digit precision for decimal numbers


DB2 allows two sets of rules for determining the precision and scale of the result of
an operation with decimal numbers.
v DEC15 rules allow a maximum precision of 15 digits in the result of an operation.
Those rules are in effect when both operands have precisions of 15 or less,
unless one of the circumstances that imply DEC31 rules applies.
v DEC31 rules allow a maximum precision of 31 digits in the result. Those rules
are in effect if any of the following is true:
– Either operand of the operation has a precision greater than 15.
– The operation is in a dynamic SQL statement, and any of the following
conditions is true:
# - The current value of special register CURRENT PRECISION is DEC31 or
# D31.s. The number s is between 1 and 9 and represents the minimum
# scale to be used for division operations.
# - The installation option for DECIMAL ARITHMETIC on panel DSNTIPF is
# DEC31, D31.s, or 31; the installation option for USE FOR
DYNAMICRULES on panel DSNTIPF is YES; and the value of CURRENT
PRECISION has not been set by the application.
- The SQL statement has bind, define, or invoke behavior; the statement is in
an application precompiled with option DEC(31); the installation option for
USE FOR DYNAMICRULES on panel DSNTIPF is NO; and the value of
CURRENT PRECISION has not been set by the application. See “Using
DYNAMICRULES to specify behavior of dynamic SQL statements” on
page 418 for an explanation of bind, define, and invoke behavior.
# – The operation is in an embedded (static) SQL statement that you precompiled
# with the DEC(31), DEC31, or D31.s option, or with the default for that option
# when the install option DECIMAL ARITHMETIC is DEC31 or 31. The number
# s is between 1 and 9 and represents the minimum scale to be used for

Chapter 1. Retrieving data 13


# division operations. (See “Step 1: Process SQL statements” on page 398 for
# information on precompiling and a list of all precompiler options.)

# The choice of whether to use DEC15 or DEC31 is a trade-off:


# v Choose DEC15 or D15.s to avoid an error when the calculated scale of the result
# of a simple multiply or divide operation is less than 0. Although this error can
# occur with either set of rules, it is more common with DEC31 rules.
# v Choose DEC31 or D31.s to reduce the chance of overflow, or when dealing with
# precisions greater than 15.
# The number s is between 1 and 9 and represents the minimum scale to be used for
# division operations.

# Avoiding decimal arithmetic errors: For static SQL statements, the simplest way
# to avoid a division error is to override DEC31 rules by specifying the precompiler
# option DEC(15). In some cases it is possible to avoid a division error by specifying
# D31.s. That reduces the probability of errors for statements embedded in the
# program. (The number s is between 1 and 9 and represents the minimum scale to
# be used for division operations.)

If the dynamic SQL statements have bind, define, or invoke behavior and the value
of the installation option for USE FOR DYNAMICRULES on panel DSNTIPF is NO,
# you can use the precompiler option DEC(15), DEC15, or D15.s to override DEC31
rules.

For a dynamic statement, or for a single static statement, use the scalar function
DECIMAL to specify values of the precision and scale for a result that causes no
errors.

For a dynamic statement, before you execute the statement, set the value of
# special register CURRENT PRECISION to DEC15 or D15.s.

Even if you use DEC31 rules, multiplication operations can sometimes cause
overflow because the precision of the product is greater than 31. To avoid overflow
from multiplication of large numbers, use the MULTIPLY_ALT built-in function
instead of the multiplication operator.

Finding information in the DB2 catalog


The examples below show you how to access the DB2 system catalog tables to:
v List the tables that you can access
v List the column names of a table

The contents of the DB2 system catalog tables can be a useful reference tool when
you begin to develop an SQL statement or an application program.

Displaying a list of tables you can use


The catalog table, SYSIBM.SYSTABAUTH, lists table privileges granted to
authorization IDs. To display the tables that you have authority to access (by
privileges granted either to your authorization ID or to PUBLIC), you can execute an
SQL statement like that shown in the following example. To do this, you must have
the SELECT privilege on SYSIBM.SYSTABAUTH.
SELECT DISTINCT TCREATOR, TTNAME
FROM SYSIBM.SYSTABAUTH
WHERE GRANTEE IN (USER, 'PUBLIC', 'PUBLIC*') AND GRANTEETYPE = ' ';

14 Application Programming and SQL Guide


If your DB2 subsystem uses an exit routine for access control authorization,
you cannot rely on catalog queries to tell you what tables you can access. When
such an exit routine is installed, both RACF and DB2 control table access.

Displaying a list of columns in a table


Another catalog table, SYSIBM.SYSCOLUMNS, describes every column of every
table. Suppose you execute the previous example (displaying a list of tables you
can access) and now want to display information about table DSN8710.DEPT. To
execute the following example, you must have the SELECT privilege on
SYSIBM.SYSCOLUMNS.
SELECT NAME, COLTYPE, SCALE, LENGTH
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'DEPT'
AND TBCREATOR = 'DSN8710';

If the table about which you display column information includes LOB or ROWID
columns, the LENGTH field for those columns contains the number of bytes those
column occupy in the base table, rather than the length of the LOB or ROWID data.
To determine the maximum length of data for a LOB or ROWID column, include the
LENGTH2 column in your query. For example:
SELECT NAME, COLTYPE, LENGTH, LENGTH2
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'EMP_PHOTO_RESUME'
AND TBCREATOR = 'DSN8710';

Chapter 1. Retrieving data 15


16 Application Programming and SQL Guide
Chapter 2. Working with tables and modifying data
This chapter discusses these topics:
v Creating your own tables: CREATE TABLE
v “Working with temporary tables” on page 19
v “Dropping tables: DROP TABLE” on page 23
v “Defining a view: CREATE VIEW” on page 23
v “Changing data through a view” on page 24
v “Dropping views: DROP VIEW” on page 25
v “Inserting a row: INSERT” on page 25
v “Updating current values: UPDATE” on page 29
v “Deleting rows: DELETE” on page 31
See DB2 SQL Reference for more information about working with tables and data.

Working with tables


You might need to create or drop the tables that you are working with. You might
create new tables, copy existing tables, add columns, add or drop referential and
check constraints, or make any number of changes. This section discusses how to
create and work with tables.

Creating your own tables: CREATE TABLE


Use the CREATE TABLE statement to create a table. 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);

The elements of the CREATE statement are:


v CREATE TABLE, which names the table PRODUCT.
v A list of the columns that make up the table. For each column, specify:
– The column’s name (for example, SERIAL).
– The data type and length attribute (for example, CHAR(8)). For further
information about data types, see “Data types” on page 3.
v The encoding scheme for the table.
| Specify CCSID EBCDIC to use an EBCDIC encoding scheme, CCSID ASCII to
| use an ASCII encoding scheme, or CCSID UNICODE to use a Unicode encoding
| scheme. If the CREATE TABLE statement does not have a LIKE clause, the
| default is the encoding scheme of the table space in which the table resides. If
| the CREATE TABLE statement has a LIKE clause, the default CCSID is the
| CCSID of the table in the LIKE clause. See “Creating work tables” on page 18 for
| examples of using the LIKE clause.
v Optionally, a default value. See “Identifying defaults” on page 18.
v Optionally, a referential constraint or table check constraint. See “Using
referential constraints” on page 203 and “Using table check constraints” on
page 201.

© Copyright IBM Corp. 1983, 2001 17


Identifying defaults
If you want to constrain the inputs or identify the defaults, you can describe the
columns using:
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 fields, zero is the default value.
– For fixed-length strings, blank is the default value.
– For variable-length strings, including LOB strings, the empty string (string of
zero-length) is the default value.
– For datetime fields, the current value of the associated special register is the
default value.
v DEFAULT value, when you want to identify one of the following as the default
value:
– A constant
– USER, which uses the run-time value of the USER special register
– CURRENT SQLID, which uses the SQL authorization ID of the process
– NULL
– The name of a cast function, to cast a default value to the distinct type of a
column

You must separate each column description from the next with a comma, and
enclose the entire list of column descriptions in parentheses.

Creating work tables


Before testing SQL statements that insert, update, and delete rows, you should
create work tables (duplicates of the DSN8710.EMP and DSN8710.DEPT tables),
so that the original sample tables remain intact. This section shows how to create
two work tables and how to fill a work table with the contents of another table.

Each example shown in this chapter assumes you logged on using your own
authorization ID. The authorization ID qualifies the name of each object 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 DSN8710.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”.

Creating a new department table


Use the following statements to create a new department table called YDEPT,
modeled after an existing table called DSN8710.DEPT, and an index for YDEPT:
CREATE TABLE YDEPT
LIKE DSN8710.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:
ALTER TABLE YDEPT
PRIMARY KEY(DEPTNO);

You can use an INSERT statement with a SELECT clause to copy rows from one
table to another. The following statement copies all of the rows from
DSN8710.DEPT to your own YDEPT work table.

18 Application Programming and SQL Guide


INSERT INTO YDEPT
SELECT *
FROM DSN8710.DEPT;

For information on the INSERT statement, see “Modifying DB2 data” on page 25.

Creating a new employee table


You can use the following statements to create a new employee table called YEMP.
CREATE TABLE YEMP
(EMPNO CHAR(6) PRIMARY KEY NOT NULL,
FIRSTNME VARCHAR(12) NOT NULL,
MIDINIT CHAR(1) NOT NULL,
LASTNAME VARCHAR(15) NOT NULL,
WORKDEPT CHAR(3) 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 statement ALTER
TABLE.

If you want to change a table name after you create it, use the statement RENAME
TABLE. For details on the ALTER TABLE and RENAME TABLE statements, see
Chapter 5 of DB2 SQL Reference. You cannot drop a column from a table or
change a column definition. However, you can add and drop constraints on columns
in a table.

Working with temporary tables


When you need a table only for the life of an application process, you can create a
temporary table. There are two kinds of temporary tables:
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:
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 large numbers of rows, but you want to store only a small
subset of those rows permanently.

Chapter 2. Working with tables and modifying data 19


Temporary tables can also return result sets from stored procedures. For more
information, see “Writing a stored procedure to return result sets to a DRDA client”
on page 547. The following sections provide more details on created temporary
tables and declared temporary tables.

Working with created temporary tables


You create the definition of a created temporary table using the SQL statement
CREATE GLOBAL TEMPORARY TABLE.

Example: This 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 a definition by copying the definition of a base table:
CREATE GLOBAL TEMPORARY TABLE TEMPPROD LIKE PROD;

The SQL statements in the previous examples create identical definitions, even
though table PROD contains two columns, DESCRIPTION and CURDATE, that are
defined as NOT NULL WITH DEFAULT. Because created temporary tables do not
support WITH DEFAULT, DB2 changes the definitions of DESCRIPTION and
CURDATE to NOT NULL when you use the second method to define TEMPPROD.

After you execute one of the two CREATE statements, the definition of TEMPPROD
exists, but no instances of the table exist. To drop the definition of TEMPPROD, you
must execute this statement:
DROP TABLE TEMPPROD;

To create an instance of TEMPPROD, you must use TEMPPROD in an application.


DB2 creates an instance of the table when TEMPPROD appears in one of these
SQL statements:
v OPEN
v SELECT
v INSERT
v DELETE

An instance of a created temporary table exists at the current server until one of the
following actions occurs:
v The remote server connection under which the instance was created terminates.
v The unit of work under which the instance was created completes.
When you execute a ROLLBACK statement, DB2 deletes the instance of the
created temporary table. When you execute a COMMIT statement, DB2 deletes
the instance of the created temporary table unless a cursor for accessing the
created temporary table is defined WITH HOLD and is open.
v The application process ends.

For example, suppose that you create a definition of TEMPPROD and then run an
application that contains these statements:
EXEC SQL DECLARE C1 CURSOR FOR SELECT * FROM TEMPPROD;
EXEC SQL INSERT INTO TEMPPROD SELECT * FROM PROD;
EXEC SQL OPEN C1;

20 Application Programming and SQL Guide


.
.
.

EXEC
. SQL COMMIT;
.
.

EXEC SQL CLOSE C1;

When you execute the INSERT statement, DB2 creates an instance of TEMPPROD
and populates that instance with rows from table PROD. When the COMMIT
statement is executed, DB2 deletes all rows from TEMPPROD. If, however, you
change the declaration of C1 to:
EXEC SQL DECLARE C1 CURSOR WITH HOLD
FOR SELECT * FROM TEMPPROD;

DB2 does not delete the contents of TEMPPROD until the application ends
because C1, a cursor defined WITH HOLD, is open when the COMMIT statement is
executed. In either case, DB2 drops the instance of TEMPPROD when the
application ends.

Working with declared temporary tables


You create an instance of a declared temporary table using the SQL statement
DECLARE GLOBAL TEMPORARY TABLE. That instance is known only to the
application process in which the table is declared, so you can declare temporary
tables with the same name in different applications.

Before you can define declared temporary tables, you must create a special
database and table spaces for them. You do that by executing the CREATE
DATABASE statement with the AS TEMP clause, and then creating segmented
table spaces in that database. A DB2 subsystem can have only one database for
declared temporary tables, but that database can contain more than one table
space.

Example: These statements create a database and table space for declared
temporary tables:
CREATE DATABASE DTTDB AS TEMP;
CREATE TABLESPACE DTTTS IN DTTDB
SEGSIZE 4;

You can define a declared temporary table in any of the following ways:
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 or created temporary table that you copy has identity columns,
you can specify that the corresponding columns in the declared temporary table
are also identity columns. Do that by specifying the INCLUDING IDENTITY
COLUMN ATTRIBUTES clause when you define the declared temporary table.
v Use a fullselect to choose specific columns from 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. Do that by specifying the
INCLUDING IDENTITY COLUMN ATTRIBUTES clause when you define the
declared temporary table.

Chapter 2. Working with tables and modifying data 21


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: This statement defines a declared temporary table called TEMPPROD by


explicitly specifying the columns.
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD
(SERIAL CHAR(8) NOT NULL WITH DEFAULT '99999999',
DESCRIPTION VARCHAR(60) NOT NULL,
PRODCOUNT INTEGER GENERATED ALWAYS AS IDENTITY,
MFGCOST DECIMAL(8,2),
MFGDEPT CHAR(3),
MARKUP SMALLINT,
SALESDEPT CHAR(3),
CURDATE DATE NOT NULL);

Example: This 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: This 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 the default column values from the view definition.
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD
AS (SELECT * FROM PRODVIEW)
DEFINITION ONLY
INCLUDING IDENTITY COLUMN ATTRIBUTES
INCLUDING COLUMN DEFAULTS;

After you execute 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, execute this statement:
DROP TABLE SESSION.TEMPPROD;

DB2 creates an empty instance of a declared temporary table when it executes the
DECLARE GLOBAL TEMPORARY TABLE statement. You can populate the
declared temporary table using INSERT statements, modify the table using
searched or positioned UPDATE or DELETE statements, and query the table using
SELECT statements. You can also create indexes on the declared temporary table.

When you execute a COMMIT statement in an application with a declared


temporary table, DB2 deletes all the rows from the table or keeps the rows,
depending on the ON COMMIT clause that you specify in the DECLARE GLOBAL
TEMPORARY TABLE statement. ON COMMIT DELETE ROWS, which is the
default, causes all rows to be deleted from the table at a commit point, unless there
is a held cursor open on the table at the commit point. ON COMMIT PRESERVE
ROWS causes the rows to remain past the commit point.

For example, suppose that you execute these statement in an application program:

22 Application Programming and SQL Guide


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 executes the 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.

Dropping tables: DROP TABLE


This 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 both its data
and its definition. You lose all synonyms, views, indexes, and referential and check
constraints associated with that table. You also lose all authorities granted on the
table.

For more information on the DROP statement, see Chapter 5 of DB2 SQL
Reference.

Working with views


This section discusses how to use CREATE VIEW and DROP VIEW to control your
view of existing tables. 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.

Defining a view: CREATE VIEW


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. Using views can 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.
CREATE VIEW VDEPTM AS
SELECT DEPTNO, MGRNO, LASTNAME, ADMRDEPT
FROM DSN8710.DEPT, DSN8710.EMP
WHERE DSN8710.EMP.EMPNO = DSN8710.DEPT.MGRNO;

This view shows each department manager’s name with the department data in the
DSN8710.DEPT table.

Chapter 2. Working with tables and modifying data 23


When a program accesses the data defined by a view, DB2 uses the view definition
to return a set of rows the program can access with SQL statements. Now that the
view VDEPTM exists, you can retrieve data using the view. To see the departments
administered by department D01 and the managers of those departments, execute
the following statement:
SELECT DEPTNO, LASTNAME
FROM VDEPTM
WHERE ADMRDEPT = 'DO1';

When you create a view, you can reference the USER and CURRENT SQLID
special registers in the CREATE VIEW statement. When referencing the view, DB2
uses the value of the USER or CURRENT SQLID 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 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. You can also use views to do the following:
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 for a particular department only.
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 UNION or
| UNION ALL operators, 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.

Changing data through a view


Some views are read-only, while others are subject to update or insert restrictions.
(See Chapter 5 of DB2 SQL Reference for more information about read-only views.)
If a view does not have update restrictions, there are some additional things to
consider:
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 being
inserted must contain a value for each of those columns.

24 Application Programming and SQL Guide


v Views that you can use to update data are subject to the same referential
constraints and table check constraints as the tables you used to define the
views.

Dropping views: DROP VIEW


When you drop a view, you also drop all views defined on that view. This SQL
statement drops the VDEPTM view:
DROP VIEW VDEPTM;

Modifying DB2 data


This section discusses how to add or modify data in an existing table using the
statements INSERT, UPDATE, and DELETE.

Inserting a row: INSERT


Use an INSERT statement to add new rows to a table or view. Using an INSERT
statement, you can do the following:
v Specify the values to insert in a single row. You can specify constants, host
variables, expressions, DEFAULT, or NULL.
v Include a SELECT statement in the INSERT statement to tell DB2 that another
table or view contains the data for the new row (or rows). “Filling a table from
another table: Mass INSERT” on page 26, explains how to use the SELECT
statement within an INSERT statement to add rows to a table.

In either case, for every row you insert, you must provide a value for any column
that does not have a default value. For a column that meets one of these
conditions, you can specify DEFAULT to tell DB2 to insert the default value for that
column:
v Is nullable.
v Is defined with a default value.
v Has data type ROWID. ROWID columns always have default values.
v Is an identity column. Identity columns always have default values.

The values that you can insert into a ROWID column or identity column depend on
whether the column is defined with GENERATED ALWAYS or GENERATED BY
DEFAULT. See “Inserting data into a ROWID column” on page 27 and “Inserting
data into an identity column” on page 27 for more information.

You can name all columns for which you are providing values. Alternatively, you can
omit the column name list.

For static insert statements, it is a good idea to name all columns for which you are
providing values because:
v Your insert statement is independent of the table format. (For example, you do
not have to change the statement when a column is added to the table.)
v You can verify that you are giving the values in order.
v Your source statements are more self-descriptive.

If you do not name the columns in a static insert statement, and a column is added
to the table being inserted into, an error can occur if the insert statement is
rebound. An error will occur after any rebind of the insert statement unless you
change the insert statement to include a value for the new column. This is true,
even if the new column has a default value.

Chapter 2. Working with tables and modifying data 25


When you list the column names, you must specify their corresponding values in
the same order as in the list of column names.

For example,
INSERT INTO YDEPT (DEPTNO, DEPTNAME, MGRNO, ADMRDEPT, LOCATION)
VALUES ('E31', 'DOCUMENTATION', '000010', 'E01', ' ');

After inserting a new department row into your YDEPT table, you can use a
SELECT statement to see what you have loaded into the table. This SQL
statement:
SELECT *
FROM YDEPT
WHERE DEPTNO LIKE 'E%'
ORDER BY DEPTNO;

shows you all the new department rows that you have inserted:
DEPTNO DEPTNAME MGRNO ADMRDEPT LOCATION
====== ==================================== ====== ======== ===========
E01 SUPPORT SERVICES 000050 A00 -----------
E11 OPERATIONS 000090 E01 -----------
E21 SOFTWARE SUPPORT 000100 E01 -----------
E31 DOCUMENTATION 000010 E01 -----------

There are other ways to enter data into tables:


v You can copy one table into another, as explained in “Filling a table from another
table: Mass INSERT”.
v You can write an application program to enter large amounts of data into a table.
For details, see “Part 2. Coding SQL in your host application program” on
page 61.
v You can use the DB2 LOAD utility to enter data from other sources. See Part 2
of DB2 Utility Guide and Reference for more information about the LOAD utility.

Filling a table from another table: Mass INSERT


| Use a fullselect within an INSERT statement to select rows from one table to insert
| into another table.

This SQL statement creates a table named TELE:


CREATE TABLE TELE
(NAME2 VARCHAR(15) NOT NULL,
NAME1 VARCHAR(12) NOT NULL,
PHONE CHAR(4));

This statement copies data from DSN8710.EMP into the newly created table:
INSERT INTO TELE
SELECT LASTNAME, FIRSTNME, PHONENO
FROM DSN8710.EMP
WHERE WORKDEPT = 'D21';

The two previous statements create and fill a table, TELE, that looks like this:
NAME2 NAME1 PHONE
=============== ============ =====
PULASKI EVA 7831
JEFFERSON JAMES 2094
MARINO SALVATORE 3780
SMITH DANIEL 0961
JOHNSON SYBIL 8953
PEREZ MARIA 9001
MONTEVERDE ROBERT 3780

26 Application Programming and SQL Guide


The CREATE TABLE statement example creates a table which, at first, is empty.
The table has columns for last names, first names, and phone numbers, but does
not have any rows.

The INSERT statement fills the newly created table with data selected from the
DSN8710.EMP table: the names and phone numbers of employees in Department
D21.

Example: The following CREATE statement creates a table that contains an


employee’s department name as well as the phone number. The fullselect fills the
DLIST table with data from rows selected from two existing tables, DSN8710.DEPT
and DSN8710.EMP.
CREATE TABLE DLIST
(DEPT CHAR(3) NOT NULL,
DNAME VARCHAR(36) ,
LNAME VARCHAR(15) NOT NULL,
FNAME VARCHAR(12) NOT NULL,
INIT CHAR ,
PHONE CHAR(4) );
INSERT INTO DLIST
SELECT DEPTNO, DEPTNAME, LASTNAME, FIRSTNME, MIDINIT, PHONENO
FROM DSN8710.DEPT, DSN8710.EMP
WHERE DEPTNO = WORKDEPT;

Inserting data into a ROWID column


A row ID is a value that uniquely identifies a row in a table. A column or a host
variable can have a row ID data type. A ROWID column enables queries to be
written that navigate directly to a row in the table. Each value in a ROWID column
must be unique, and DB2 maintains the values permanently.

Before you insert data into a ROWID column, you must know how the ROWID
column is defined. ROWID columns can be defined as GENERATED ALWAYS or
GENERATED BY DEFAULT. GENERATED ALWAYS means that DB2 generates a
value for the column, and you cannot insert data into that column. If the column is
defined as GENERATED BY DEFAULT, you can insert a value, and DB2 provides a
default value if you do not supply one. For example, suppose that tables T1 and T2
have two columns: an integer column and a ROWID column. For the following
statement to execute successfully, ROWIDCOL2 must be defined as GENERATED
BY DEFAULT.
INSERT INTO T2 (INTCOL2,ROWIDCOL2)
SELECT INTCOL1, ROWIDCOL1 FROM T1;

If ROWIDCOL2 is defined as GENERATED ALWAYS, you cannot insert the ROWID


column data from T1 into T2, but you can insert the integer column data. To insert
only the integer data, use one of the following methods:
v Specify only the integer column in your INSERT statement:
INSERT INTO T2 (INTCOL2)
SELECT INTCOL1 FROM T1;
v Specify the OVERRIDING USER VALUE clause in your INSERT statement to tell
DB2 to ignore any values that you supply for system-generated columns:
INSERT INTO T2 (INTCOL2,ROWIDCOL2) OVERRIDING USER VALUE
SELECT INTCOL1, ROWIDCOL1 FROM T1;

Inserting data into an identity column


An identity column is a numeric column with ascending or descending values. For
an identity column to be the most useful, those values should also be unique.

Chapter 2. Working with tables and modifying data 27


An identity column is defined in a CREATE TABLE or ALTER TABLE statement. The
column has a SMALLINT, INTEGER, or DECIMAL(p,0) data type and is defined
with the AS IDENTITY clause. The AS IDENTITY clause specifies that the column is
an identity column. The column is also defined with the GENERATED ALWAYS or
GENERATED BY DEFAULT clause. GENERATED ALWAYS means that DB2
generates a value for the column, and you cannot insert data into that column. If
the column is defined as GENERATED BY DEFAULT, you can insert a value, and
DB2 provides a default value if you do not supply one.

Before you insert data into an identity column, you must know whether the column
is defined as GENERATED ALWAYS or GENERATED BY DEFAULT. If you try to
insert a value into an identity column that is defined as GENERATED ALWAYS, the
insert operation fails.

| The values that DB2 generates for an identity column depend on how the column is
| defined. The START WITH parameter determines the first value that DB2
| generates. The MINVALUE and MAXVALUE parameters determine the minimum
| and maximum values that DB2 generates. The CYCLE or NO CYCLE parameter
| 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.

| Identity columns that are defined with GENERATED ALWAYS and NO CYCLE are
| guaranteed to have unique values. For identity columns that are defined as
| GENERATED BY DEFAULT and NO CYCLE, only the values that DB2 generates
| are guaranteed to be unique among each other. To guarantee unique values in an
| identity column, you need to create a unique index on the identity column.

Example: Inserting into an identity column that is defined with GENERATED


BY DEFAULT: Suppose that tables T1 and T2 have two columns: a character
column and an integer column that is defined as an identity column. For the
following statement to execute successfully, IDENTCOL2 must be defined as
GENERATED BY DEFAULT.
INSERT INTO T2 (CHARCOL2,IDENTCOL2)
SELECT CHARCOL1, IDENTCOL1 FROM T1;

If IDENTCOL2 is defined as GENERATED ALWAYS, you cannot insert the identity


column data from T1 into T2, but you can insert the character column data. To
insert only the character data, use one of the following methods:
v Specify only the character column in your INSERT statement:
INSERT INTO T2 (CHARCOL2)
SELECT CHARCOL1 FROM T1;
v Specify the OVERRIDING USER VALUE clause in your INSERT statement to tell
DB2 to ignore any values that you supply for system-generated columns:
INSERT INTO T2 (CHARCOL2,IDENTCOL2) OVERRIDING USER VALUE
SELECT CHARCOL1, IDENTCOL1 FROM T1;

| Example: Inserting into an identity column that is defined with CYCLE:


| Suppose that table T1 is defined like this:
| CREATE TABLE T1
| (CHARCOL1 CHAR(1),
| IDENTCOL1 SMALLINT GENERATED ALWAYS AS IDENTITY
| (START WITH -1,

28 Application Programming and SQL Guide


| INCREMENT BY 1,
| CYCLE,
| MINVALUE -3,
| MAXVALUE 3));

| Now suppose that you execute the following INSERT statement six 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 six INSERTs are executed:
| CHARCOL1 IDENTCOL1
| ======== =========
| A -1
| A 0
| A 1
| A 2
| A 3
| A -3

| Using an INSERT statement in an application program


If DB2 finds an error while executing the INSERT statement, it inserts nothing into
the table, and sets error codes in the SQLCODE and SQLSTATE host variables or
corresponding fields of the SQLCA. If the INSERT statement is successful,
SQLERRD(3) is set to the number of rows inserted. See Appendix C of DB2 SQL
Reference for more information.

Examples: This statement inserts information about a new employee into the
YEMP table. Because YEMP has a foreign key WORKDEPT referencing the
primary key DEPTNO in YDEPT, the value inserted for WORKDEPT (E31) must be
a value of DEPTNO in YDEPT or null.
INSERT INTO YEMP
VALUES ('000400', 'RUTHERFORD', 'B', 'HAYES', 'E31',
'5678', '1983-01-01', 'MANAGER', 16, 'M', '1943-07-10', 24000,
500, 1900);

The following statement also inserts a row into the YEMP table. However, the
statement does not specify a value for every column. Because the unspecified
columns allow nulls, DB2 inserts null values into the columns not specified.
Because YEMP has a foreign key WORKDEPT referencing the primary key
DEPTNO in YDEPT, the value inserted for WORKDEPT (D11) must be a value of
DEPTNO in YDEPT or null.
INSERT INTO YEMP
(EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, PHONENO, JOB)
VALUES ('000410', 'MILLARD', 'K', 'FILLMORE', 'D11', '4888', 'MANAGER');

Updating current values: UPDATE


To change the data in a table, use the UPDATE statement. You can also use the
UPDATE statement to delete a value from a row’s column (without removing the
row) by changing the column’s value to NULL.

For example, suppose an employee relocates. To update several items of the


employee’s data in the YEMP work table to reflect the move, you can execute:
UPDATE YEMP
SET JOB = 'MANAGER ',
PHONENO ='5678'
WHERE EMPNO = '000400';

Chapter 2. Working with tables and modifying data 29


You cannot update rows in a created temporary table, but you can update rows in a
declared temporary table.

The SET clause names the columns that you want to update and provides the
values you want to assign to those columns. You can replace a column value with
any of the following items:
v A null value
The column to which you assign the null value must not be defined as NOT
NULL.
v An expression
An expression can be any of the following items:
– A column
– A constant
| – A fullselect that returns a scalar or a row
– A host variable
– A special register

Next, identify the rows to update:


v To update a single row, use a WHERE clause that locates one, and only one,
row
v To update several rows, use a WHERE clause that locates only the rows you
want to update.

If you omit the WHERE clause; DB2 updates every row in the table or view with the
values you supply.

If DB2 finds an error while executing your UPDATE statement (for instance, an
update value that is too large for the column), it stops updating and returns error
codes in the SQLCODE and SQLSTATE host variables or related fields in the
SQLCA. No rows in the table change (rows already changed, if any, are restored to
their previous values). If the UPDATE statement is successful, SQLERRD(3) is set
to the number of rows updated.

Examples: The following statement supplies a missing middle initial and changes
the job for employee 000200.
UPDATE YEMP
SET MIDINIT = 'H', JOB = 'FIELDREP'
WHERE EMPNO = '000200';

The following statement gives everyone in department D11 a $400 raise. The
statement can update several rows.
UPDATE YEMP
SET SALARY = SALARY + 400.00
WHERE WORKDEPT = 'D11';

The following statement sets the salary and bonus for employee 000190 to the
average salary and minimum bonus for all employees.
UPDATE YEMP
SET (SALARY, BONUS) =
(SELECT AVG(SALARY), MIN(BONUS)
FROM EMP)
WHERE EMPNO = '000190';

30 Application Programming and SQL Guide


Deleting rows: DELETE
You can use the DELETE statement to remove entire rows from a table. The
DELETE statement removes zero or more rows of a table, depending on how many
rows satisfy the search condition you specified in the WHERE clause. If you omit a
WHERE clause from a DELETE statement, DB2 removes all the rows from the
table or view you have named. The DELETE statement does not remove specific
columns from the row.

You can use DELETE to remove all rows from a created temporary table or
declared temporary table. However, you can use DELETE with a WHERE clause to
remove only selected rows from a declared temporary table.

This DELETE statement deletes each row in the YEMP table that has an employee
number 000060.
DELETE FROM YEMP
WHERE EMPNO = '000060';

When this statement executes, DB2 deletes any row from the YEMP table that
meets the search condition.

If DB2 finds an error while executing your DELETE statement, it stops deleting data
and returns error codes in the SQLCODE and SQLSTATE host variables or related
fields in the SQLCA. The data in the table does not change.

If the DELETE is successful, SQLERRD(3) in the SQLCA contains the number of


deleted rows. This number includes only the number of rows deleted in the table
specified in the DELETE statement. It does not include those rows deleted
according to the CASCADE rule.

Deleting every row in a table


The DELETE statement is a powerful statement that deletes all rows of a table
unless you specify a WHERE clause to limit it. (With segmented table spaces,
deleting all rows of a table is very fast.) For example, this statement:
DELETE FROM YDEPT;

deletes every row in the YDEPT table. If the statement executes, the table
continues to exist (that is, you can insert rows into it) but it is empty. All existing
views and authorizations on the table remain intact when using DELETE. By
comparison, using DROP TABLE drops all views and authorizations, which can
invalidate plans and packages. For information on the DROP statement, see
“Dropping tables: DROP TABLE” on page 23.

Chapter 2. Working with tables and modifying data 31


32 Application Programming and SQL Guide
Chapter 3. Joining data from more than one table
Sometimes the information you want to see is not in a single table. To form a row of
the result table, you might want to retrieve some column values from one table and
some column values from another table. You can use a SELECT statement to
retrieve and join column values from two or more tables into a single row.

DB2 supports these types of joins: inner join, left outer join, right outer join, and full
outer join.

You can specify joins in the FROM clause of a query: Figure 2 below shows the
ways to combine tables using outer join functions.

Figure 2. Outer joins of two tables. Each join is on column PROD#.

The result table contains data joined from all of the tables, for rows that satisfy the
search conditions.

The result columns of a join have names if the outermost SELECT list refers to
base columns. But, if you use a function (such as COALESCE or VALUE) to build a
column of the result, then that column does not have a name unless you use the
AS clause in the SELECT list.

To distinguish the different types of joins, the examples in this section use the
following two tables:
The PARTS table The PRODUCTS table
PART PROD# SUPPLIER PROD# PRODUCT PRICE
======= ===== ============ ===== =========== =====
WIRE 10 ACWF 505 SCREWDRIVER 3.70
OIL 160 WESTERN_CHEM 30 RELAY 7.55
MAGNETS 10 BATEMAN 205 SAW 18.90
PLASTIC 30 PLASTIK_CORP 10 GENERATOR 45.75
BLADES 205 ACE_STEEL

© Copyright IBM Corp. 1983, 2001 33


Inner join
To request an inner join, execute a SELECT statement in which you specify the
tables that you want to join in the FROM clause, and specify a WHERE clause or
an ON clause to indicate the join condition. The join condition can be any simple or
compound search condition that does not contain a subquery reference. See
Chapter 4 of DB2 SQL Reference for the complete syntax of a join condition.

In the simplest type of inner join, the join condition is column1=column2. For
example, you can join the PARTS and PRODUCTS tables on the PROD# column to
get a table of parts with their suppliers and the products that use the parts.

Either one of these examples:


SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT
FROM PARTS, PRODUCTS
WHERE PARTS.PROD# = PRODUCTS.PROD#;

or
SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT
FROM PARTS INNER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#;

gives this result:


PART SUPPLIER PROD# PRODUCT
======= ============ ===== ==========
WIRE ACWF 10 GENERATOR
MAGNETS BATEMAN 10 GENERATOR
PLASTIC PLASTIK_CORP 30 RELAY
BLADES ACE_STEEL 205 SAW

Notice three things about the example:


v There is a part in the parts table (OIL) whose product (#160) is not in the
products table. There is a product (SCREWDRIVER, #505) that has no parts
listed in the parts table. Neither OIL nor SCREWDRIVER appears in the result of
the join.
An outer join, however, includes rows where the values in the joined columns do
not match.
v There is an explicit syntax to express that this join is not an outer join but an
inner join. You can use INNER JOIN in the FROM clause instead of the comma.
Use ON to specify the join condition (rather than WHERE) when you explicitly
join tables in the FROM clause.
v If you do not specify a WHERE clause in the first form of the query, the result
table contains all possible combinations of rows for the tables identified in the
FROM clause. You can obtain the same result by specifying a join condition that
is always true in the second form of the query. For example:
SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT
FROM PARTS INNER JOIN PRODUCTS
ON 1=1;

In either case, the number of rows in the result table is the product of the number
of rows in each table.

You can specify more complicated join conditions to obtain different sets of results.
For example, to eliminate the suppliers that begin with the letter A from the table of
parts, suppliers, product numbers and products, write a query like this:

34 Application Programming and SQL Guide


SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT
FROM PARTS INNER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#
AND SUPPLIER NOT LIKE 'A%';

The result of the query is all rows that do not have a supplier that begins with A:
PART SUPPLIER PROD# PRODUCT
======= ============ ===== ==========
MAGNETS BATEMAN 10 GENERATOR
PLASTIC PLASTIK_CORP 30 RELAY

Example of joining a table to itself using an inner join: The following example
joins table DSN8710.PROJ to itself and returns the number and name of each
“major” project followed by the number and name of the project that is part of it. In
this example, A indicates the first instance of table DSN8710.PROJ and B indicates
a second instance of this table. The join condition is such that the value in column
PROJNO in table DSN8710.PROJ A must be equal to a value in column MAJPROJ
in table DSN8710.PROJ B.

The SQL statement is:


SELECT A.PROJNO, A.PROJNAME, B.PROJNO, B.PROJNAME
FROM DSN8710.PROJ A, DSN8710.PROJ B
WHERE A.PROJNO = B.MAJPROJ;

The result table is:


PROJNO PROJNAME PROJNO PROJNAME
====== ======================== ======= ========================
AD3100 ADMIN SERVICES AD3110 GENERAL AD SYSTEMS
AD3110 GENERAL AD SYSTEMS AD3111 PAYROLL PROGRAMMING
AD3110
. GENERAL AD SYSTEMS AD3112 PERSONNEL PROGRAMMG
.
.

OP2010 SYSTEMS SUPPORT OP2013 DB/DC SUPPORT

In this example, the comma in the FROM clause implicitly specifies an inner join,
and acts the same as if the INNER JOIN keywords had been used. When you use
the comma for an inner join, you must specify the join condition on the WHERE
clause. When you use the INNER JOIN keywords, you must specify the join
condition on the ON clause.

Full outer join


The clause FULL OUTER JOIN includes unmatched rows from both tables. Missing
values in a row of the result table contain nulls.

The join condition for a full outer join must be a simple search condition that
compares two columns or cast functions that contain columns.

For example, the following query performs a full outer join of the PARTS and
PRODUCTS tables:
SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT
FROM PARTS FULL OUTER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#;

The result table from the query is:


PART SUPPLIER PROD# PRODUCT
======= ============ ===== ==========
WIRE ACWF 10 GENERATOR

Chapter 3. Joining data from more than one table 35


MAGNETS BATEMAN 10 GENERATOR
PLASTIC PLASTIK_CORP 30 RELAY
BLADES ACE_STEEL 205 SAW
OIL WESTERN_CHEM 160 -----------
------- ------------ --- SCREWDRIVER

Example of Using COALESCE (or VALUE): “COALESCE” is the keyword


specified by the SQL standard as a synonym for the VALUE function. The function,
by either name, can be particularly useful in full outer join operations, because it
returns the first nonnull value.

You probably noticed that the result of the example for “Full outer join” on page 35
is null for SCREWDRIVER, even though the PRODUCTS table contains a product
number for SCREWDRIVER. If you select PRODUCTS.PROD# instead, PROD# is
null for OIL. If you select both PRODUCTS.PROD# and PARTS.PROD#, the result
contains two columns, with both columns contain some null values. We can merge
data from both columns into a single column, eliminating the null values, using the
COALESCE function.

With the same PARTS and PRODUCTS tables, this example:


SELECT PART, SUPPLIER,
COALESCE(PARTS.PROD#, PRODUCTS.PROD#) AS PRODNUM, PRODUCT
FROM PARTS FULL OUTER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#;

gives this result:


PART SUPPLIER PRODNUM PRODUCT
======= ============ ======= ===========
WIRE ACWF 10 GENERATOR
MAGNETS BATEMAN 10 GENERATOR
PLASTIC PLASTIK_CORP 30 RELAY
BLADES ACE_STEEL 205 SAW
OIL WESTERN_CHEM 160 -----------
------- ------------ 505 SCREWDRIVER

The AS clause (AS PRODNUM) provides a name for the result of the COALESCE
function.

Left outer join


The clause LEFT OUTER JOIN includes rows from the table that is specified before
LEFT OUTER JOIN that have no matching values in the table that is specified after
LEFT OUTER JOIN.

As in an inner join, the join condition can be any simple or compound search
condition that does not contain a subquery reference.

For example, to include rows from the PARTS table that have no matching values in
the PRODUCTS table and include only prices greater than 10.00, execute this
query:
SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT, PRICE
FROM PARTS LEFT OUTER JOIN PRODUCTS
ON PARTS.PROD#=PRODUCTS.PROD#
AND PRODUCTS.PRICE>10.00;

The result of the query is:

36 Application Programming and SQL Guide


PART SUPPLIER PROD# PRODUCT PRICE
======= ============ ===== ========== =====
WIRE ACWF 10 GENERATOR 45.75
MAGNETS BATEMAN 10 GENERATOR 45.75
PLASTIC PLASTIK_CORP 30 ----------- -------
BLADES ACE_STEEL 205 SAW 18.90
OIL WESTERN_CHEM 160 ----------- -------

# Because the PARTS table can have nonmatching rows, and the PRICE column is
# not in the PARTS table, rows in which PRICE is less than or equal to 10.00 are not
# included in the result of the join.

Right outer join


The clause RIGHT OUTER JOIN includes rows from the table that is specified after
RIGHT OUTER JOIN that have no matching values in the table that is specified
before RIGHT OUTER JOIN.

As in an inner join, the join condition can be any simple or compound search
condition that does not contain a subquery reference.

For example, to include rows from the PRODUCTS table that have no matching
values in the PARTS table and include prices greater than 10.00, execute this
query:
SELECT PART, SUPPLIER, PRODUCTS.PROD#, PRODUCT, PRICE
FROM PARTS RIGHT OUTER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#
AND PRODUCTS.PRICE>10.00;

gives this result:


# PART SUPPLIER PROD# PRODUCT PRICE
# ======= ============ ===== ========== =====
# WIRE ACWF 10 GENERATOR 45.75
# MAGNETS BATEMAN 10 GENERATOR 45.75
# BLADES ACE_STEEL 205 SAW 18.90
# ---------- ------------ 30 RELAY 7.55
# ---------- ------------ 505 SCREWDRIVER 3.70

# Because the PRODUCTS table can have nonmatching rows, and the PRICE
# column is in the PRODUCTS table, rows in which PRICE is less than or equal to
# 10.00 are also included in the result of the join. The predicate PRODUCTS.PRICE
# is greater than 10.00 does not eliminate any rows. When PRODUCTS.PRICE is
# less than or equal to 10.00, the PARTS columns in the result table contain null.

SQL rules for statements containing join operations


SQL rules dictate that the result of a SELECT statement look as if the clauses had
been evaluated in this order:
v FROM
v WHERE
v GROUP BY
v HAVING
v SELECT

A join operation is part of a FROM clause; therefore, for the purpose of predicting
which rows will be returned from a SELECT statement containing a join operation,
assume that the join operation is performed first.

Chapter 3. Joining data from more than one table 37


For example, suppose that you want to obtain a list of part names, supplier names,
product numbers, and product names from the PARTS and PRODUCTS tables.
These categories correspond to the PART, SUPPLIER, PROD#, and PRODUCT
columns. You want to include rows from either table where the PROD# value does
not match a PROD# value in the other table, which means that you need to do a
full outer join. You also want to exclude rows for product number 10. If you code a
SELECT statement like this:
SELECT PART, SUPPLIER,
VALUE(PARTS.PROD#,PRODUCTS.PROD#) AS PRODNUM, PRODUCT
FROM PARTS FULL OUTER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#
WHERE PARTS.PROD# <> '10' AND PRODUCTS.PROD# <> '10';

you get this table:


PART SUPPLIER PRODNUM PRODUCT
======= ============ ======= ===========
PLASTIC PLASTIK_CORP 30 RELAY
BLADES ACE_STEEL 205 SAW

which is not the desired result. DB2 performs the join operation first, then applies
the WHERE clause. The WHERE clause excludes rows where PROD# has a null
value, so the result is the same as if you had specified an inner join.

A correct SELECT statement to produce the list is:


SELECT PART, SUPPLIER,
VALUE(X.PROD#, Y.PROD#) AS PRODNUM, PRODUCT
FROM
(SELECT PART, SUPPLIER, PROD# FROM PARTS WHERE PROD# <> '10') X
FULL OUTER JOIN
(SELECT PROD#, PRODUCT FROM PRODUCTS WHERE PROD# <> '10') Y
ON X.PROD# = Y.PROD#;

In this case, DB2 applies the WHERE clause to each table separately, so that no
rows are eliminated because PROD# is null. DB2 then performs the full outer join
operation, and the desired table is obtained:
PART SUPPLIER PRODNUM PRODUCT
======= ============ ======= ===========
OIL WESTERN_CHEM 160 -----------
BLADES ACE_STEEL 205 SAW
PLASTIC PLASTIK_CORP 30 RELAY
------- ------------ 505 SCREWDRIVER

Using more than one type of join in an SQL statement


When you need to join more than two tables, you can use more than one join type
in the FROM clause. Suppose you wanted a result table showing all the employees,
their department names, and the projects they are responsible for, if any. You would
need to join three tables to get all the information. For example, you might use a
SELECT statement similar to the following:
SELECT EMPNO, LASTNAME, DEPTNAME, PROJNO
FROM DSN8710.EMP INNER JOIN DSN8710.DEPT
ON WORKDEPT = DSN8710.DEPT.DEPTNO
LEFT OUTER JOIN DSN8710.PROJ
ON EMPNO = RESPEMP
WHERE LASTNAME > 'S';

The result table is:

38 Application Programming and SQL Guide


EMPNO LASTNAME DEPTNAME PROJNO
====== ========= ====================== ======
000020 THOMPSON PLANNING PL2100
000060 STERN MANUFACTURING SYSTEMS MA2110
000100 SPENSER SOFTWARE SUPPORT OP2010
000170 YOSHIMURA MANUFACTURING SYSTEMS ------
000180 SCOUTTEN MANUFACTURING SYSTEMS ------
000190 WALKER MANUFACTURING SYSTEMS ------
000250 SMITH ADMINISTRATION SYSTEMS AD3112
000280 SCHNEIDER OPERATIONS ------
000300 SMITH OPERATIONS ------
000310 SETRIGHT OPERATIONS ------
200170 YAMAMOTO MANUFACTURING SYSTEMS ------
200280 SCHWARTZ OPERATIONS ------
200310 SPRINGER OPERATIONS ------
200330 WONG SOFTWARE SUPPORT ------

Using nested table expressions and user-defined table functions in


joins
An operand of a join can be more complex than the name of a single table. You can
use:
v A nested table expression
A nested table expression is a fullselect enclosed in parentheses, followed by a
correlation name.
v A user-defined table function
A user-defined table function is a user-defined function that returns a table.

The following query contains a nested table expression:


SELECT PROJECT, COALESCE(PROJECTS.PROD#, PRODNUM) AS PRODNUM,
PRODUCT, PART, UNITS
FROM PROJECTS LEFT JOIN
(SELECT PART,
COALESCE(PARTS.PROD#, PRODUCTS.PROD#) AS PRODNUM,
PRODUCTS.PRODUCT
FROM PARTS FULL OUTER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#) AS TEMP
ON PROJECTS.PROD# = PRODNUM;

The nested table expression is this:


(SELECT PART,
COALESCE(PARTS.PROD#, PRODUCTS.PROD#) AS PRODNUM,
PRODUCTS.PRODUCT
FROM PARTS FULL OUTER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#) AS TEMP

The correlation name is TEMP.

Example of using a simple nested table expression:


SELECT CHEAP_PARTS.PROD#, CHEAP_PARTS.PRODUCT
FROM (SELECT PROD#, PRODUCT
FROM PRODUCTS
WHERE PRICE < 10) AS CHEAP_PARTS;

gives this result:


PROD# PRODUCT
===== ===========
505 SCREWDRIVER
30 RELAY

Chapter 3. Joining data from more than one table 39


In the example, the correlation name is CHEAP_PARTS. There are two correlated
references to CHEAP_PARTS: CHEAP_PARTS.PROD# and
CHEAP_PARTS.PRODUCT. Those references are valid because they do not occur
in the same FROM clause where CHEAP_PARTS is defined.

Example of a fullselect as the left operand of a join:


SELECT PART, SUPPLIER, PRODNUM, PRODUCT
FROM (SELECT PART, PROD# AS PRODNUM, SUPPLIER
FROM PARTS
WHERE PROD# < '200') AS PARTX
LEFT OUTER JOIN PRODUCTS
ON PRODNUM = PROD#;

gives this result:


PART SUPPLIER PRODNUM PRODUCT
======= ============ ======= ==========
WIRE ACWF 10 GENERATOR
MAGNETS BATEMAN 10 GENERATOR
OIL WESTERN_CHEM 160 ----------

Because PROD# is a character field, DB2 does a character comparison to


determine the set of rows in the result. Therefore, because '30' is greater than '200',
the row in which PROD# is equal to '30' does not appear in the result.

Example of a join with a table function:

You can join the results of a user-defined table function with a table, just as you can
join two tables. For example, suppose CVTPRICE is a table function that converts
the prices in the PRODUCTS table to the currency you specify and returns the
PRODUCTS table with the prices in those units. You can obtain a table of parts,
suppliers, and product prices with the prices in your choice of currency by executing
a query like this:
SELECT PART, SUPPLIER, PARTS.PROD#, Z.PRODUCT, Z.PRICE
FROM PARTS, TABLE(CVTPRICE(:CURRENCY)) AS Z
WHERE PARTS.PROD# = Z.PROD#;

Examples of correlated references in table references:

You can include correlated references in nested table expressions or as arguments


to table functions. The basic rule that applies for both these cases is that the
correlated reference must be from a table specification at a higher level in the
hierarchy of subqueries. You can also use a correlated reference and the table
specification to which it refers in the same FROM clause if the table specification
appears to the left of the correlated reference and the correlated reference is in one
of the following clauses:
v A nested table expression preceded by the keyword TABLE
v The argument of a table function

A table function or a table expression that contains correlated references to other


tables in the same FROM clause cannot participate in a full outer join or a right
outer join.

The following examples illustrate valid uses of correlated references in table


specifications:
SELECT T.C1, Z.C5
FROM T, TABLE(TF3(T.C2)) AS Z
WHERE T.C3 = Z.C4;

40 Application Programming and SQL Guide


The correlated reference T.C2 is valid because the table specification, to which it
refers, T, is to its left. If you specify the join in the opposite order, with T following
TABLE(TF3(T.C2), then T.C2 is invalid.
SELECT D.DEPTNO, D.DEPTNAME,
EMPINFO.AVGSAL, EMPINFO.EMPCOUNT
FROM DEPT D,
TABLE(SELECT AVG(E.SALARY) AS AVGSAL,
COUNT(*) AS EMPCOUNT
FROM EMP E
WHERE E.WORKDEPT=D.DEPTNO) AS EMPINFO;

The correlated reference D.DEPTNO is valid because the nested table expression
within which it appears is preceded by TABLE and the table specification D appears
to the left of the nested table expression in the FROM clause. If you remove the
keyword TABLE, D.DEPTNO is invalid.

Chapter 3. Joining data from more than one table 41


42 Application Programming and SQL Guide
Chapter 4. Using subqueries
You should use a subquery when you need to narrow your search condition based
on information in an interim table. For example, you might want to find all employee
numbers in one table that also exist for a given project in a second table.

This chapter presents a conceptual overview of subqueries, shows how to include


subqueries in either a WHERE or a HAVING clause, and shows how to use
correlated subqueries.

Conceptual overview
Suppose you want a list of the employee numbers, names, and commissions of all
employees working on a particular project, say project number MA2111. The first
part of the SELECT statement is easy to write:
SELECT EMPNO, LASTNAME, COMM
FROM DSN8710.EMP
WHERE EMPNO
.
.
.

But you cannot go further because the DSN8710.EMP table does not include
project number data. You do not know which employees are working on project
MA2111 without issuing another SELECT statement against the
DSN8710.EMPPROJACT table.

You can use a subquery to solve this problem. A subquery is a subselect or a


fullselect in a WHERE clause. The SELECT statement surrounding the subquery is
called the outer SELECT.
SELECT EMPNO, LASTNAME, COMM
FROM DSN8710.EMP
WHERE EMPNO IN
(SELECT EMPNO
FROM DSN8710.EMPPROJACT
WHERE PROJNO = 'MA2111');

To better understand what results from this SQL statement, imagine that DB2 goes
through the following process:
1. DB2 evaluates the subquery to obtain a list of EMPNO values:
(SELECT EMPNO
FROM DSN8710.EMPPROJACT
WHERE PROJNO = 'MA2111');

which results in an interim result table:


(From EMPPROJACT)

000200
000200
000220

2. The interim result table then serves as a list in the search condition of the outer
SELECT. Effectively, DB2 executes this statement:

© Copyright IBM Corp. 1983, 2001 43


SELECT EMPNO, LASTNAME, COMM
FROM DSN8710.EMP
WHERE EMPNO IN
('000200', '000220');

As a consequence, the result table looks like this:

Fetch EMPNO LASTNAME COMM


1 000200 BROWN 2217
2 000220 LUTZ 2387

Correlated and uncorrelated subqueries


Subqueries supply information needed to qualify a row (in a WHERE clause) or a
group of rows (in a HAVING clause). The subquery produces a result table used to
qualify the row or group of rows selected. The subquery executes only once, if the
subquery is the same for every row or group.

This kind of subquery is uncorrelated. In the previous query, for example, the
content of the subquery is the same for every row of the table DSN8710.EMP.

Subqueries that vary in content from row to row or group to group are correlated
subqueries. For information on correlated subqueries, see “Using correlated
subqueries” on page 47. All of the information preceding that section applies to both
correlated and uncorrelated subqueries.

Subqueries and predicates


A subquery is always part of a predicate. The predicate is of the form:
operand operator (subquery)

The predicate can be part of a WHERE or HAVING clause. A WHERE or HAVING


clause can include predicates that contain subqueries. A predicate containing a
subquery, like any other search predicate, can be enclosed in parentheses, can be
preceded by the keyword NOT, and can be linked to other predicates through the
keywords AND and OR. For example, the WHERE clause of a query could look
something like this:
WHERE X IN (subquery1) AND (Y > SOME (subquery2) OR Z IS NULL)

Subqueries can also appear in the predicates of other subqueries. Such subqueries
are nested subqueries at some level of nesting. For example, a subquery within a
subquery within an outer SELECT has a level of nesting of 2. DB2 allows nesting
down to a level of 15, but few queries require a nesting level greater than 1.

The relationship of a subquery to its outer SELECT is the same as the relationship
of a nested subquery to a subquery, and the same rules apply, except where
otherwise noted.

The subquery result table


| A subquery must produce a result table that has the same number of columns as
| the number of columns on the left side of the comparison operator. For example,
| both of the following SELECT statements are acceptable:

44 Application Programming and SQL Guide


| SELECT EMPNO, LASTNAME
| FROM DSN8710.EMP
| WHERE SALARY=
| (SELECT AVG(SALARY)
| FROM DSN8710.EMP);
| SELECT EMPNO, LASTNAME
| FROM DSN8710.EMP
| WHERE (SALARY, BONUS) IN
| (SELECT AVG(SALARY), AVG(BONUS)
| FROM DSN8710.EMP);

| Except for a subquery of a basic predicate, the result table can contain more than
| one row.

Tables in subqueries of UPDATE, DELETE, and INSERT statements


| The following rules apply to a table that is used in a subquery for an UPDATE,
| DELETE, or INSERT statement:
| v When you use a subquery in an INSERT statement, the subquery can use the
| same table as the INSERT statement.
| v When you use a subquery in a searched UPDATE or DELETE statement (an
| UPDATE or DELETE that does not use a cursor), the subquery can use the
| same table as the UPDATE or DELETE statement.
| v When you use a subquery in a positioned UPDATE or DELETE statement (an
| UPDATE or DELETE that uses a cursor), the subquery cannot use the same
| table as the UPDATE or DELETE statement.

How to code a subquery


There are a number of ways to specify a subquery in either a WHERE or HAVING
clause. They are as follows:
v Basic predicate
v Quantified Predicates: ALL, ANY, and SOME
v Using the IN Keyword
v Using the EXISTS Keyword

Basic predicate
You can use a subquery immediately after any of the comparison operators. If you
do, the subquery can return at most one value. DB2 compares that value with the
value to the left of the comparison operator.

For example, the following SQL statement returns the employee numbers, names,
and salaries for employees whose education level is higher than the average
company-wide education level.
SELECT EMPNO, LASTNAME, SALARY
FROM DSN8710.EMP
WHERE EDLEVEL >
(SELECT AVG(EDLEVEL)
FROM DSN8710.EMP);

Quantified predicates: ALL, ANY, and SOME


| You can use a subquery after a comparison operator followed by the keyword ALL,
| ANY, or SOME. The number of columns and rows that the subquery can return for
| a quantified predicate depends on the type of quantified predicate:

Chapter 4. Using subqueries 45


| v For = SOME, = ANY, or <> ALL, the subquery can return one or many rows and
| one or many columns. The number of columns in the result table must match the
| number of columns on the left side of the operator.
| v For all other quantified predicates, the subquery can return one or many rows,
| but no more than one column.

Use ALL to indicate that the operands on the left side of the comparison must
compare in the same way with all the values the subquery returns. For example,
suppose you use the greater-than comparison operator with ALL:
WHERE column > ALL (subquery)

To satisfy this WHERE clause, the column value must be greater than all the values
that the subquery returns. A subquery that returns an empty result table satisfies the
predicate.

| Now suppose that you use the <> operator with ALL in a WHERE clause like this:
| WHERE column1, column2, ... columnn <> ALL (subquery)

| To satisfy this WHERE clause, each column value must be unequal to all the values
| in the corresponding column of the result table that the subquery returns. A
| subquery that returns an empty result table satisfies the predicate.

Use ANY or SOME to indicate that the values on the left side of the operator must
compare in the indicated way to at least one of the values that the subquery
returns. For example, suppose you use the greater-than comparison operator with
ANY:
WHERE expression > ANY (subquery)

To satisfy this WHERE clause, the value in the expression must be greater than at
least one of the values (that is, greater than the lowest value) that the subquery
returns. A subquery that returns an empty result table does not satisfy the predicate.

| Now suppose that you use the = operator with SOME in a WHERE clause like this:
| WHERE column1, column1, ... columnn = SOME (subquery)

| To satisfy this WHERE clause, each column value must be equal to at least one of
| the values in the corresponding column of the result table that the subquery returns.
| A subquery that returns an empty result table does not satisfy the predicate.

If a subquery that returns one or more null values gives you unexpected results,
see the description of quantified predicates in Chapter 2 of DB2 SQL Reference.

Using the IN keyword


| You can use IN to say that the value or values on the left side of the IN operator
| must be among the values that are returned by the subquery. Using IN is equivalent
| to using = ANY or = SOME.

Using the EXISTS keyword


In the subqueries presented thus far, DB2 evaluates the subquery and uses the
result as part of the WHERE clause of the outer SELECT. In contrast, when you
use the keyword EXISTS, DB2 simply checks whether the subquery returns one or
more rows. Returning one or more rows satisfies the condition; returning no rows
does not satisfy the condition. For example:

46 Application Programming and SQL Guide


SELECT EMPNO,LASTNAME
FROM DSN8710.EMP
WHERE EXISTS
(SELECT *
FROM DSN8710.PROJ
WHERE PRSTDATE > '1986-01-01');

In the example, the search condition is true if any project represented in the
DSN8710.PROJ table has an estimated start date which is later than 1 January
1986. This example does not show the full power of EXISTS, because the result is
always the same for every row examined for the outer SELECT. As a consequence,
either every row appears in the results, or none appear. A correlated subquery is
more powerful, because the subquery would change from row to row.

As shown in the example, you do not need to specify column names in the
subquery of an EXISTS clause. Instead, you can code SELECT *. You can also use
the EXISTS keyword with the NOT keyword in order to select rows when the data
or condition you specify does not exist; that is, you can code
WHERE NOT EXISTS (SELECT ...);

Using correlated subqueries


In the subqueries previously described, DB2 executes the subquery once,
substitutes the result of the subquery in the right side of the search condition, and
evaluates the outer-level SELECT based on the value of the search condition. You
can also write a subquery that DB2 has to re-evaluate when it examines a new row
(in a WHERE clause) or group of rows (in a HAVING clause) as it executes the
outer SELECT. This is called a correlated subquery.

User-defined functions in correlated subqueries: Use care when you invoke a


user-defined function in a correlated subquery, and that user-defined function uses
a scratchpad. DB2 does not refresh the scratchpad between invocations of the
subquery. This can cause undesirable results because the scratchpad keeps values
across the invocations of the subquery.

An example of a correlated subquery


Suppose that you want a list of all the employees whose education levels are
higher than the average education levels in their respective departments. To get this
information, DB2 must search the DSN8710.EMP table. For each employee in the
table, DB2 needs to compare the employee’s education level to the average
education level for the employee’s department.

This is the point at which a correlated subquery differs from an uncorrelated


subquery. The earlier example of uncorrelated subqueries compares the education
level to the average of the entire company, which requires looking at the entire
table. A correlated subquery evaluates only the department which corresponds to
the particular employee.

In the subquery, you tell DB2 to compute the average education level for the
department number in the current row. A query that does this follows:
SELECT EMPNO, LASTNAME, WORKDEPT, EDLEVEL
FROM DSN8710.EMP X
WHERE EDLEVEL >
(SELECT AVG(EDLEVEL)
FROM DSN8710.EMP
WHERE WORKDEPT = X.WORKDEPT);

Chapter 4. Using subqueries 47


A correlated subquery looks like an uncorrelated one, except for the presence of
one or more correlated references. In the example, the single correlated reference
is the occurrence of X.WORKDEPT in the WHERE clause of the subselect. In this
clause, the qualifier X is the correlation name defined in the FROM clause of the
outer SELECT statement. X designates rows of the first instance of DSN8710.EMP.
At any time during the execution of the query, X designates the row of
DSN8710.EMP to which the WHERE clause is being applied.

Consider what happens when the subquery executes for a given row of
DSN8710.EMP. Before it executes, X.WORKDEPT receives the value of the
WORKDEPT column for that row. Suppose, for example, that the row is for
CHRISTINE HAAS. Her work department is A00, which is the value of WORKDEPT
for that row. The subquery executed for that row is therefore:
(SELECT AVG(EDLEVEL)
FROM DSN8710.EMP
WHERE WORKDEPT = 'A00');

The subquery produces the average education level of Christine’s department. The
outer subselect then compares this to Christine’s own education level. For some
other row for which WORKDEPT has a different value, that value appears in the
subquery in place of A00. For example, in the row for MICHAEL L THOMPSON, this
value is B01, and the subquery for his row delivers the average education level for
department B01.

The result table produced by the query has the following values:
(From EMP)

Fetch EMPNO LASTNAME WORKDEPT EDLEVEL


1 000010 HAAS A00 18
2 000030 KWAN C01 20
3 000070 PULASKI D21 16
4 000090 HENDERSON E11 16

Using correlation names in references


A correlated reference can appear in a subquery, in a nested table expression, or
as an argument of a user-defined table function. For information on correlated
references in nested table expressions and table functions, see “Using nested table
expressions and user-defined table functions in joins” on page 39. In a subquery,
the reference should be of the form X.C, where X is a correlation name and C is
the name of a column in the table that X represents.

Any number of correlated references can appear in a subquery. There are no


restrictions on variety. For example, you can define one correlated name in a
reference in the outer SELECT, and another in a nested subquery.

When you use a correlation name in a subquery, the subquery can be the
outer-level SELECT, or any of the subqueries that contain the reference. Suppose,
for example, that a query contains subqueries A, B, and C, and that A contains B
and B contains C. Then C could use a correlation name defined in B, A, or the
outer SELECT.

You can define a correlation name for each table name appearing in a FROM
clause. Append the correlation name after its table name. Leave one or more
blanks between a table name and its correlation name. You can include the word
AS between the table name and the correlation name to increase the readability of

48 Application Programming and SQL Guide


the SQL statement. The following example demonstrates the use of a correlation
name in the search condition of a subquery:
SELECT EMPNO, LASTNAME, WORKDEPT, EDLEVEL
FROM DSN8710.EMP AS X
WHERE EDLEVEL >
(SELECT AVG(EDLEVEL)
FROM DSN8710.EMP
WHERE WORKDEPT = X.WORKDEPT);

The following example demonstrates the use of a correlation name in the select list
of a subquery:
UPDATE BP1TBL T1
SET (KEY1, CHAR1, VCHAR1) =
(SELECT VALUE(T2.KEY1,T1.KEY1), VALUE(T2.CHAR1,T1.CHAR1), VALUE(T2.VCHAR1,T1.VCHAR1)
FROM BP2TBL T2
WHERE (T2.KEY1 = T1.KEY1))
WHERE KEY1 IN
(SELECT KEY1
FROM BP2TBL T3
WHERE KEY2 > 0);

Using correlated subqueries in an UPDATE statement


When you use a correlated subquery in an UPDATE statement, the correlation
name refers to the rows you are updating. For example, when all activities of a
project must complete before September 1997, your department considers that
project to be a priority project. You can use the following SQL statement to evaluate
the projects in the DSN8710.PROJ table, and write a 1 (a flag to indicate
PRIORITY) in the PRIORITY column (a column you have added to DSN8710.PROJ
for this purpose) for each priority project:
UPDATE DSN8710.PROJ X
SET PRIORITY = 1
WHERE DATE('1997-09-01') >
(SELECT MAX(ACENDATE)
FROM DSN8710.PROJACT
WHERE PROJNO = X.PROJNO);

As DB2 examines each row in the DSN8710.PROJ table, it determines the


maximum activity end date (ACENDATE) for all activities of the project (from the
DSN8710.PROJACT table). If the end date of each activity associated with the
project is before September 1997, the current row in the DSN8710.PROJ table
qualifies and DB2 updates it.

Using correlated subqueries in a DELETE statement


When you use a correlated subquery in a DELETE statement, the correlation name
represents the row you delete. DB2 evaluates the correlated subquery once for
each row in the table named in the DELETE statement to decide whether or not to
delete the row.

For example, suppose that a department considers a project to be complete when


the combined amount of time currently spent on it is half a person’s time or less.
The department then deletes the rows for that project from the DSN8710.PROJ
table. In the example statements that follow, PROJ and PROJACT are independent
tables; that is, they are separate tables with no referential constraints defined on
them.

Chapter 4. Using subqueries 49


DELETE FROM DSN8710.PROJ X
WHERE .5 >
(SELECT SUM(ACSTAFF)
FROM DSN8710.PROJACT
WHERE PROJNO = X.PROJNO);

To process this statement, DB2 determines for each project (represented by a row
in the DSN8710.PROJ table) whether or not the combined staffing for that project is
less than 0.5. If it is, DB2 deletes that row from the DSN8710.PROJ table.

To continue this example, suppose DB2 deletes a row in the DSN8710.PROJ table.
You must also delete rows related to the deleted project in the DSN8710.PROJACT
table. To do this, use:
DELETE FROM DSN8710.PROJACT X
WHERE NOT EXISTS
(SELECT *
FROM DSN8710.PROJ
WHERE PROJNO = X.PROJNO);

DB2 determines, for each row in the DSN8710.PROJACT table, whether a row with
the same project number exists in the DSN8710.PROJ table. If not, DB2 deletes the
row in DSN8710.PROJACT.

| A subquery of a searched DELETE statement (a DELETE statement that does not


| use a cursor) can reference the same table from which rows are deleted. In the
| following statement, which deletes the employee with the highest salary from each
| department, the employee table appears in the outer DELETE and in the subselect:
| DELETE FROM YEMP X
| WHERE SALARY =(SELECT MAX(SALARY) FROM YEMP Y
| WHERE X.WORKDEPT =Y.WORKDEPT);

| This example uses copies of the employee and department table that do not have
| referential constraints.

DB2 restricts delete operations for dependent tables that are involved in referential
constraints. If a DELETE statement has a subquery that references a table involved
in the deletion, the last delete rule in the path to that table must be RESTRICT or
NO ACTION. For example, without referential constraints, the following statement
deletes departments from the department table whose managers are not listed
correctly in the employee table:
DELETE FROM DSN8710.DEPT THIS
WHERE NOT DEPTNO =
(SELECT WORKDEPT
FROM DSN8710.EMP
WHERE EMPNO = THIS.MGRNO);

With the referential constraints defined for the sample tables, the statement causes
an error. The deletion involves the table referred to in the subquery (DSN8710.EMP
is a dependent table of DSN8710.DEPT) and the last delete rule in the path to EMP
is SET NULL, not RESTRICT or NO ACTION. If the statement could execute, its
results would again depend on the order in which DB2 accesses the rows.

50 Application Programming and SQL Guide


Chapter 5. Executing SQL from your terminal using SPUFI
This chapter explains how to enter and execute SQL statements at a TSO terminal
using the SPUFI (SQL processor using file input) facility. You can execute most of
the interactive SQL examples shown in Part 1. Using SQL queries by following the
instructions provided in this chapter and using the sample tables shown in
“Appendix A. DB2 sample tables” on page 815. The instructions assume that ISPF
is available to you.

Allocating an input data set and using SPUFI


Before you use SPUFI, you should allocate an input data set, if one does not
already exist. This data set will contain one or more SQL statements that you want
to execute. For information on ISPF and allocating data sets, refer to ISPF V4
User's Guide.

To use SPUFI, select SPUFI from the DB2I Primary Option Menu as shown in
Figure 3.

DSNEPRI DB2I PRIMARY OPTION MENU SSID: DSN


COMMAND ===> 1

Select one of the following DB2 functions and press ENTER.

1 SPUFI (Process SQL statements)


2 DCLGEN (Generate SQL and source language declarations)
3 PROGRAM PREPARATION (Prepare a DB2 application program to run)
4 PRECOMPILE (Invoke DB2 precompiler)
5 BIND/REBIND/FREE (BIND, REBIND, or FREE plans or packages)
6 RUN (RUN an SQL program)
7 DB2 COMMANDS (Issue DB2 commands)
8 UTILITIES (Invoke DB2 utilities)
D DB2I DEFAULTS (Set global parameters)
X EXIT (Leave DB2I)

PRESS: END to exit HELP for more information

Figure 3. The DB2I primary option menu with option 1 selected

The SPUFI panel then displays as shown in Figure 4 on page 52.

From then on, when the SPUFI panel displays, the data entry fields on the panel
contain the values that you previously entered. You can specify data set names and
processing options each time the SPUFI panel displays, as needed. Values you do
not change remain in effect.

© Copyright IBM Corp. 1983, 2001 51


DSNESP01 SPUFI SSID: DSN
===>
Enter the input data set name: (Can be sequential or partitioned)
1 DATA SET NAME..... ===> EXAMPLES(XMP1)
2 VOLUME SERIAL..... ===> (Enter if not cataloged)
3 DATA SET PASSWORD. ===> (Enter if password protected)

Enter the output data set name: (Must be a sequential data set)
4 DATA SET NAME..... ===> RESULT

Specify processing options:


5 CHANGE DEFAULTS... ===> Y (Y/N - Display SPUFI defaults panel?)
6 EDIT INPUT........ ===> Y (Y/N - Enter SQL statements?)
7 EXECUTE........... ===> Y (Y/N - Execute SQL statements?)
8 AUTOCOMMIT........ ===> Y (Y/N - Commit after successful run?)
9 BROWSE OUTPUT..... ===> Y (Y/N - Browse output data set?)

For remote SQL processing:


10 CONNECT LOCATION ===>

PRESS: ENTER to process END to exit HELP for more information

Figure 4. The SPUFI panel filled in

Fill out the SPUFI panel as follows:


1,2,3 INPUT DATA SET NAME
Identify the input data set in fields 1 through 3. This data set contains one
or more SQL statements that you want to execute. Allocate this data set
before you use SPUFI, if one does not already exist.
v The name must conform to standard TSO naming conventions.
v The data set can be empty before you begin the session. You can then
add the SQL statements by editing the data set from SPUFI.
v The data set can be either sequential or partitioned, but it must have the
following DCB characteristics:
– A record format (RECFM) of either F or FB.
– A logical record length (LRECL) of either 79 or 80. Use 80 for any
data set that the EXPORT command of QMF did not create.
v Data in the data set can begin in column 1. It can extend to column 71 if
the logical record length is 79, and to column 72 if the logical record
length is 80. SPUFI assumes that the last 8 bytes of each record are for
sequence numbers.

If you use this panel a second time, the name of the data set you
previously used displays in the field DATA SET NAME. To create a new
member of an existing partitioned data set, change only the member name.
4 OUTPUT DATA SET NAME
Enter the name of a data set to receive the output of the SQL statement.
You do not need to allocate the data set before you do this.
If the data set exists, the new output replaces its content. If the data set
does not exist, DB2 allocates a data set on the device type specified on the
CURRENT SPUFI DEFAULTS panel and then catalogs the new data set.
The device must be a direct-access storage device, and you must be
authorized to allocate space on that device.
Attributes required for the output data set are:

52 Application Programming and SQL Guide


v Organization: sequential
v Record format: F, FB, FBA, V, VB, or VBA
v Record length: 80 to 32768 bytes, not less than the input data set

Figure 4 on page 52 shows the simplest choice, entering RESULT. SPUFI


allocates a data set named userid.RESULT and sends all output to that
data set. If a data set named userid.RESULT already exists, SPUFI sends
DB2 output to it, replacing all existing data.
5 CHANGE DEFAULTS
Allows you to change control values and characteristics of the output data
set and format of your SPUFI session. If you specify Y(YES) you can look
at the SPUFI defaults panel. See “Changing SPUFI defaults (optional)” on
page 54 for more information about the values you can specify and how
they affect SPUFI processing and output characteristics. You do not need to
change the SPUFI defaults for this example.
6 EDIT INPUT
To edit the input data set, leave Y(YES) on line 6. You can use the ISPF
editor to create a new member of the input data set and enter SQL
statements in it. (To process a data set that already contains a set of SQL
statements you want to execute immediately, enter N(NO). Specifying N
bypasses the step described in “Entering SQL statements” on page 56.)
7 EXECUTE
To execute SQL statements contained in the input data set, leave Y(YES)
on line 7.
SPUFI handles the SQL statements that can be dynamically prepared. For
those SQL statements, see “Appendix G. Characteristics of SQL statements
in DB2 for OS/390 and z/OS” on page 923.
8 AUTOCOMMIT
To make changes to the DB2 data permanent, leave Y(YES) on line 8.
Specifying Y makes SPUFI issue COMMIT if all statements execute
successfully. If all statements do not execute successfully, SPUFI issues a
ROLLBACK statement, which deletes changes already made to the file
(back to the last commit point). Please read about the COMMIT and the
ROLLBACK functions in “Unit of work in TSO (batch and online)” on
page 359 or Chapter 5 of DB2 SQL Reference.
If you specify N, DB2 displays the SPUFI COMMIT OR ROLLBACK panel
after it executes the SQL in your input data set. That panel prompts you to
COMMIT, ROLLBACK, or DEFER any updates made by the SQL. If you
enter DEFER, you neither commit nor roll back your changes.
9 BROWSE OUTPUT
To look at the results of your query, leave Y(YES) on line 9. SPUFI saves
the results in the output data set. You can look at them at any time, until
you delete or write over the data set. For more information, see “Format of
SELECT statement results” on page 58.
10 CONNECT LOCATION
Specify the name of the database server, if applicable, to which you want to
submit SQL statements. SPUFI then issues a type 2 CONNECT statement
to this server.

Chapter 5. Executing SQL from your terminal using SPUFI 53


SPUFI is a locally bound package. SQL statements in the input data set
can process only if the CONNECT statement is successful. If the connect
request fails, the output data set contains the resulting SQL return codes
and error messages.

Changing SPUFI defaults (optional)


When you finish with the SPUFI panel, press the ENTER key. Because you
specified YES on line 5 of the SPUFI panel, the next panel you see is the SPUFI
Defaults panel. SPUFI provides default values the first time you use SPUFI, for all
options except the DB2 subsystem name. Any changes you make to these values
remain in effect until you change the values again. Figure 5 shows the initial default
values.

DSNESP02 CURRENT SPUFI DEFAULTS SSID: DSN


===>
Enter the following to control your SPUFI session:
1 SQL TERMINATOR ===> ; (SQL Statement Terminator)
2 ISOLATION LEVEL ===> RR (RR=Repeatable Read, CS=Cursor Stability)
3 MAX SELECT LINES ===> 250 (Maximum number of lines to be
returned from a SELECT)
Output data set characteristics:
4 RECORD LENGTH ... ===> 4092 (LRECL= logical record length)
5 BLOCKSIZE ....... ===> 4096 (Size of one block)
6 RECORD FORMAT.... ===> VB (RECFM= F, FB, FBA, V, VB, or VB)
7 DEVICE TYPE...... ===> SYSDA (Must be a DASD unit name)

Output format characteristics:


8 MAX NUMERIC FIELD ===> 33 (Maximum width for numeric field)
9 MAX CHAR FIELD .. ===> 80 (Maximum width for character field)
10 COLUMN HEADING .. ===> NAMES (NAMES, LABELS, ANY, or BOTH)

PRESS: ENTER to process END to exit HELP for more information

Figure 5. The SPUFI defaults panel

Specify values for the following options on the CURRENT SPUFI DEFAULTS panel.
All fields must contain a value.
1 SQL TERMINATOR
Allows you to specify the character that you use to end each SQL
statement. You can specify any character except one of those listed in
Table 3. A semicolon is the default.
Table 3. Invalid special characters for the SQL terminator
Hexadecimal
Name Character Representation
blank X'40'
comma , X'5E'
double quote " X'7F'
left parenthesis ( X'4D'
right parenthesis ) X'5D'
single quote ' X'7D'
underscore _ X'6D'

54 Application Programming and SQL Guide


Use a character other than a semicolon if you plan to execute a statement
that contains embedded semicolons. For example, suppose you choose the
character # as the statement terminator. Then a CREATE TRIGGER
statement with embedded semicolons looks like this:
CREATE TRIGGER NEW_HIRE
AFTER INSERT ON EMP
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
UPDATE COMPANY_STATS SET NBEMP = NBEMP + 1;
END#

Be careful to choose a character for the SQL terminator that is not used
within the statement.

You can also set or change the SQL terminator within a SPUFI input data
set using the --#SET TERMINATOR statement. See “Entering SQL statements”
on page 56 for details.
2 ISOLATION LEVEL
Allows you to specify the isolation level for your SQL statements. See “The
ISOLATION option” on page 343 for more information.
3 MAX SELECT LINES
The maximum number of output lines that a SELECT statement can return.
To limit the number of rows retrieved, enter another maximum number
greater than 1.
4 RECORD LENGTH
The record length must be at least 80 bytes. The maximum record length
depends on the device type you use. The default value allows a 4092-byte
record.
Each record can hold a single line of output. If a line is longer than a
record, the last fields in the line truncate. SPUFI discards fields beyond the
record length.
5 BLOCKSIZE
Follow the normal rules for selecting the block size. For record format F, the
block size is equal to record length. For FB and FBA, choose a block size
that is an even multiple of LRECL. For VB and VBA only, the block size
must be 4 bytes larger than the block size for FB or FBA.
6 RECORD FORMAT
Specify F, FB, FBA, V, VB, or VBA. FBA and VBA formats insert a printer
control character after the number of lines specified in the LINES/PAGE OF
LISTING field on the DB2I Defaults panel. The record format default is VB
(variable-length blocked).
7 DEVICE TYPE
Allows you to specify a standard MVS name for direct-access storage
device types. The default is SYSDA. SYSDA specifies that MVS is to select
an appropriate direct access storage device.
8 MAX NUMERIC FIELD
The maximum width of a numeric value column in your output. Choose a
value greater than 0. The IBM-supplied default is 20. For more information,
see “Format of SELECT statement results” on page 58.
9 MAX CHAR FIELD
The maximum width of a character value column in your output. DATETIME
and GRAPHIC data strings are externally represented as characters, and

Chapter 5. Executing SQL from your terminal using SPUFI 55


SPUFI includes their defaults with the default values for character fields.
Choose a value greater than 0. The IBM-supplied default is 80. For more
information, see “Format of SELECT statement results” on page 58.
10 COLUMN HEADING
You can specify NAMES, LABELS, ANY or BOTH for column headings.
v NAME (default) uses column names only.
v LABEL uses column labels. Leave the title blank if there is no label.
v ANY uses existing column labels or column names.
v BOTH creates two title lines, one with names and one with labels.

Column names are the column identifiers that you can use in SQL
statements. If an SQL statement has an AS clause for a column, SPUFI
displays the contents of the AS clause in the heading, rather than the
column name. You define column labels with LABEL ON statements.

When you have entered your SPUFI options, press the ENTER key to continue.
SPUFI then processes the next processing option for which you specified YES. If all
other processing options are NO, SPUFI displays the SPUFI panel.

If you press the END key, you return to the SPUFI panel, but you lose all the
changes you made on the SPUFI Defaults panel. If you press ENTER, SPUFI
saves your changes.

Entering SQL statements


Next, SPUFI lets you edit the input data set. Initially, editing consists of entering an
SQL statement into the input data set. You can also edit an input data set that
contains SQL statements and you can change, delete, or insert SQL statements.

The ISPF Editor shows you an empty EDIT panel.

On the panel, use the ISPF EDIT program to enter SQL statements that you want
to execute, as shown in Figure 6 on page 57.

Move the cursor to the first input line and enter the first part of an SQL statement.
You can enter the rest of the SQL statement on subsequent lines, as shown in
Figure 6 on page 57. Indenting your lines and entering your statements on several
lines make your statements easier to read, and do not change how your statements
process.

You can put more than one SQL statement in the input data set. You can put an
SQL statement on one line of the input data set or on more than one line. DB2
executes the statements in the order you placed them in the data set. Do not put
more than one SQL statement on a single line. The first one executes, but DB2
ignores the other SQL statements on the same line.

In your SPUFI input data set, end each SQL statement with the statement
terminator that you specified in the CURRENT SPUFI DEFAULTS panel.

When you have entered your SQL statements, press the END PF key to save the
file and to execute the SQL statements.

56 Application Programming and SQL Guide


EDIT --------userid.EXAMPLES(XMP1) --------------------- COLUMNS 001 072
COMMAND INPUT ===> SAVE SCROLL ===> PAGE
********************************** TOP OF DATA ***********************
000100 SELECT LASTNAME, FIRSTNME, PHONENO
000200 FROM DSN8710.EMP
000300 WHERE WORKDEPT= 'D11'
000400 ORDER BY LASTNAME;
********************************* BOTTOM OF DATA *********************

Figure 6. The edit panel: After entering an SQL statement

Pressing the END PF key saves the data set. You can save the data set and
continue editing it by entering the SAVE command. In fact, it is a good practice to
save the data set after every 10 minutes or so of editing.

Figure 6 shows what the panel looks like if you enter the sample SQL statement,
followed by a SAVE command.

You can bypass the editing step by resetting the EDIT INPUT processing option:
EDIT INPUT ... ===> NO

You can put comments about SQL statements either on separate lines or on the
same line. In either case, use two hyphens (--) to begin a comment. Specify any
text other than #SET TERMINATOR after the comment. DB2 ignores everything to
the right of the two hyphens.

Use the text --SET TERMINATOR character in a SPUFI input data set as an
instruction to SPUFI to interpret character as a statement terminator. You can
specify any single-byte character except one of the characters that are listed in
Table 3 on page 54. The terminator that you specify overrides a terminator that you
specified in option 1 of the CURRENT SPUFI DEFAULTS panel or in a previous
--SET TERMINATOR statement.

Processing SQL statements


SPUFI passes the input data set to DB2 for processing. DB2 executes the SQL
statement in the input data set EXAMPLES(XMP1), and sends the output to the
output data set userid.RESULT.

You can bypass the DB2 processing step by resetting the EXECUTE processing
option:
EXECUTE ..... ===> NO

Your SQL statement might take a long time to execute, depending on how large a
table DB2 has to search, or on how many rows DB2 has to process. To interrupt
DB2’s processing, press the PA1 key and respond to the prompting message that
asks you if you really want to stop processing. This cancels the executing SQL
statement and returns you to the ISPF-PDF menu.

What happens to the output data set? This depends on how much of the input data
set DB2 was able to process before you interrupted its processing. DB2 might not
have opened the output data set yet, or the output data set might contain all or part
of the results data produced so far.

Chapter 5. Executing SQL from your terminal using SPUFI 57


Browsing the output
SPUFI formats and displays the output data set using the ISPF Browse program.
Figure 7 shows the output from the sample program. An output data set contains
these items for each SQL statement that DB2 executes:
v The executed SQL statement, copied from the input data set
v The results of executing the SQL statement
v The formatted SQLCA, if an error occurs during statement execution

At the end of the data set are summary statistics that describe the processing of the
input data set as a whole.

When executing a SELECT statement using SPUFI, the message “SQLCODE IS


100” indicates an error-free result. If the message SQLCODE IS 100 is the only
result, DB2 is unable to find any rows that satisfy the condition specified in the
statement.

For all other types of SQL statements executed with SPUFI, the message
“SQLCODE IS 0” indicates an error-free result.

BROWSE-- userid.RESULT COLUMNS 001 072


COMMAND INPUT ===> SCROLL ===> PAGE
--------+---------+---------+---------+---------+---------+---------+---------+
SELECT LASTNAME, FIRSTNME, PHONENO 00010000
FROM DSN8710.EMP 00020000
WHERE WORKDEPT = 'D11' 00030000
ORDER BY LASTNAME; 00040000
---------+---------+---------+---------+---------+---------+---------+---------+
LASTNAME FIRSTNME PHONENO
ADAMSON BRUCE 4510
BROWN DAVID 4501
JOHN REBA 0672
JONES WILLIAM 0942
LUTZ JENNIFER 0672
PIANKA ELIZABETH 3782
SCOUTTEN MARILYN 1682
STERN IRVING 6423
WALKER JAMES 2986
YAMAMOTO KIYOSHI 2890
YOSHIMURA MASATOSHI 2890
DSNE610I NUMBER OF ROWS DISPLAYED IS 11
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 100
---------+---------+---------+---------+---------+---------+----
---------+---------+---------+---------+---------+---------+----
DSNE617I COMMIT PERFORMED, SQLCODE IS 0
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 0
---------+---------+---------+---------+---------+---------+----
DSNE601I SQL STATEMENTS ASSUMED TO BE BETWEEN COLUMNS 1 AND 72
DSNE620I NUMBER OF SQL STATEMENTS PROCESSED IS 1
DSNE621I NUMBER OF INPUT RECORDS READ IS 4
DSNE622I NUMBER OF OUTPUT RECORDS WRITTEN IS 30

Figure 7. Result data set from the sample problem

Format of SELECT statement results


The results of SELECT statements follow these rules:
v If a column’s numeric or character data cannot display completely:
– Character values that are too wide truncate on the right.
– Numeric values that are too wide display as asterisks (*).

58 Application Programming and SQL Guide


– For columns other than LOB columns, if truncation occurs, the output data set
contains a warning message. Because LOB columns are generally longer
than the value you choose for field MAX CHAR FIELD on panel CURRENT
SPUFI DEFAULTS, SPUFI displays no warning message when it truncates
LOB column output.

You can change the amount of data displayed for numeric and character columns
by changing values on the CURRENT SPUFI DEFAULTS panel, as described in
“Changing SPUFI defaults (optional)” on page 54.
v A null value displays as a series of hyphens (-).
v A ROWID or BLOB column value displays in hexadecimal.
v A CLOB column value displays in the same way as a VARCHAR column value.
v A DBCLOB column value displays in the same way as a VARGRAPHIC column
value.
v A heading identifies each selected column, and repeats at the top of each output
page. The contents of the heading depend on the value you specified in field
COLUMN HEADING of the CURRENT SPUFI DEFAULTS panel.

Content of the messages


Each message contains the following:
v The SQLCODE, if the statement executes successfully
v The formatted SQLCA, if the statement executes unsuccessfully
v What character positions of the input data set that SPUFI scanned to find SQL
statements. This information helps you check the assumptions SPUFI made
about the location of line numbers (if any) in your input data set.
v Some overall statistics:
– Number of SQL statements processed
– Number of input records read (from the input data set)
– Number of output records written (to the output data set).

Other messages that you could receive from the processing of SQL statements
include:
v The number of rows that DB2 processed, that either:
– Your SELECT statement retrieved
– Your UPDATE statement modified
– Your INSERT statement added to a table
– Your DELETE statement deleted from a table
v Which columns display truncated data because the data was too wide

Chapter 5. Executing SQL from your terminal using SPUFI 59


60 Application Programming and SQL Guide
Part 2. Coding SQL in your host application program
Chapter 6. Basics of coding SQL in an application program . . . . . . . 65
Conventions used in examples of coding SQL statements . . . . . . . . . 66
Delimiting an SQL statement . . . . . . . . . . . . . . . . . . . . 66
Declaring table and view definitions . . . . . . . . . . . . . . . . . 67
Accessing data using host variables and host structures. . . . . . . . . . 67
Using host variables . . . . . . . . . . . . . . . . . . . . . . 68
Retrieving data into a host variable . . . . . . . . . . . . . . . 68
Inserting and updating data . . . . . . . . . . . . . . . . . . 69
Searching data . . . . . . . . . . . . . . . . . . . . . . . 70
Using indicator variables with host variables . . . . . . . . . . . . 70
Assignments and comparisons using different data types . . . . . . . 71
| Changing the coded character set ID of host variables . . . . . . . . 72
Using host structures . . . . . . . . . . . . . . . . . . . . . 72
Example: Using a host structure . . . . . . . . . . . . . . . . 72
Using indicator variables with host structures . . . . . . . . . . . . 73
Checking the execution of SQL statements . . . . . . . . . . . . . . 74
SQLCODE and SQLSTATE . . . . . . . . . . . . . . . . . . . 74
The WHENEVER statement . . . . . . . . . . . . . . . . . . . 75
Handling arithmetic or conversion errors . . . . . . . . . . . . . . 75
Handling SQL error return codes . . . . . . . . . . . . . . . . . 76
Defining a message output area . . . . . . . . . . . . . . . . 76
Possible return codes from DSNTIAR . . . . . . . . . . . . . . 77
Preparing to use DSNTIAR . . . . . . . . . . . . . . . . . . 77
A scenario for using DSNTIAR . . . . . . . . . . . . . . . . . 78

Chapter 7. Using a cursor to retrieve a set of rows . . . . . . . . . . 81


How to use a cursor . . . . . . . . . . . . . . . . . . . . . . . 81
Step 1: Declare the cursor. . . . . . . . . . . . . . . . . . . . 81
Step 2: Open the cursor . . . . . . . . . . . . . . . . . . . . 83
Step 3: Specify what to do at end-of-data . . . . . . . . . . . . . . 83
Step 4: Execute SQL statements . . . . . . . . . . . . . . . . . 83
Using FETCH statements . . . . . . . . . . . . . . . . . . . . 84
Using positioned UPDATE statements . . . . . . . . . . . . . . . 84
Using positioned DELETE statements . . . . . . . . . . . . . . . 85
Step 5: Close the cursor . . . . . . . . . . . . . . . . . . . . 85
Types of cursors . . . . . . . . . . . . . . . . . . . . . . . . 85
| Scrollable and non-scrollable cursors . . . . . . . . . . . . . . . . 85
| Using a non-scrollable cursor . . . . . . . . . . . . . . . . . 85
| Using a scrollable cursor . . . . . . . . . . . . . . . . . . . 86
| Creating declared temporary tables for scrollable cursors . . . . . . . 91
Held and non-held cursors . . . . . . . . . . . . . . . . . . . 91
Examples of using cursors . . . . . . . . . . . . . . . . . . . . 92

Chapter 8. Generating declarations for your tables using DCLGEN . . . . 95


Invoking DCLGEN through DB2I . . . . . . . . . . . . . . . . . . 95
Including the data declarations in your program . . . . . . . . . . . . . 99
DCLGEN support of C, COBOL, and PL/I languages . . . . . . . . . . . 99
Example: Adding a table declaration and host-variable structure to a library 101
Step 1. Specify COBOL as the host language . . . . . . . . . . . . 101
Step 2. Create the table declaration and host structure. . . . . . . . . 102
Step 3. Examine the results. . . . . . . . . . . . . . . . . . . 104

Chapter 9. Embedding SQL statements in host languages . . . . . . . 107

© Copyright IBM Corp. 1983, 2001 61


Coding SQL statements in an assembler application. . . . . . . . . . . 107
Defining the SQL communications area . . . . . . . . . . . . . . 107
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 108
If you specify STDSQL(NO). . . . . . . . . . . . . . . . . . 108
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 108
Embedding SQL statements . . . . . . . . . . . . . . . . . . 109
Using host variables . . . . . . . . . . . . . . . . . . . . . 111
Declaring host variables . . . . . . . . . . . . . . . . . . . . 111
Determining equivalent SQL and assembler data types. . . . . . . . . 114
Notes on assembler variable declaration and usage . . . . . . . . . 117
Determining compatibility of SQL and assembler data types . . . . . . . 118
Using indicator variables . . . . . . . . . . . . . . . . . . . . 119
Handling SQL error return codes . . . . . . . . . . . . . . . . . 119
Macros for assembler applications . . . . . . . . . . . . . . . . 121
Coding SQL statements in a C or a C⁺⁺ application . . . . . . . . . . . 121
Defining the SQL communication area . . . . . . . . . . . . . . . 121
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 122
If you specify STDSQL(NO). . . . . . . . . . . . . . . . . . 122
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 122
Embedding SQL statements . . . . . . . . . . . . . . . . . . 123
Using host variables . . . . . . . . . . . . . . . . . . . . . 124
Declaring host variables . . . . . . . . . . . . . . . . . . . . 125
Using host structures . . . . . . . . . . . . . . . . . . . . . 129
Determining equivalent SQL and C data types . . . . . . . . . . . . 131
Notes on C variable declaration and usage . . . . . . . . . . . . 134
Notes on syntax differences for constants . . . . . . . . . . . . 136
Determining compatibility of SQL and C data types . . . . . . . . . . 136
Using indicator variables . . . . . . . . . . . . . . . . . . . . 138
Handling SQL error return codes . . . . . . . . . . . . . . . . . 139
Considerations for C⁺⁺ . . . . . . . . . . . . . . . . . . . . 140
Coding SQL statements in a COBOL application . . . . . . . . . . . . 141
Defining the SQL communication area . . . . . . . . . . . . . . . 141
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 141
If you specify STDSQL(NO). . . . . . . . . . . . . . . . . . 141
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 142
Embedding SQL statements . . . . . . . . . . . . . . . . . . 142
Using host variables . . . . . . . . . . . . . . . . . . . . . 146
Declaring host variables . . . . . . . . . . . . . . . . . . . . 147
Using host structures . . . . . . . . . . . . . . . . . . . . . 152
Determining equivalent SQL and COBOL data types . . . . . . . . . 155
Notes on COBOL variable declaration and usage . . . . . . . . . . 158
Determining compatibility of SQL and COBOL data types . . . . . . . . 159
Using indicator variables . . . . . . . . . . . . . . . . . . . . 160
Handling SQL error return codes . . . . . . . . . . . . . . . . . 161
Considerations for object-oriented extensions in COBOL . . . . . . . . 163
Coding SQL statements in a FORTRAN application . . . . . . . . . . . 164
Defining the SQL communication area . . . . . . . . . . . . . . . 164
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 164
If you specify STDSQL(NO). . . . . . . . . . . . . . . . . . 164
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 164
Embedding SQL statements . . . . . . . . . . . . . . . . . . 165
Using host variables . . . . . . . . . . . . . . . . . . . . . 167
Declaring host variables . . . . . . . . . . . . . . . . . . . . 167
Determining equivalent SQL and FORTRAN data types . . . . . . . . 169
Notes on FORTRAN variable declaration and usage . . . . . . . . 170
Notes on syntax differences for constants . . . . . . . . . . . . 171

62 Application Programming and SQL Guide


Determining compatibility of SQL and FORTRAN data types. . . . . . . 172
Using indicator variables . . . . . . . . . . . . . . . . . . . . 172
Handling SQL error return codes . . . . . . . . . . . . . . . . . 173
Coding SQL statements in a PL/I application . . . . . . . . . . . . . 174
Defining the SQL communication area . . . . . . . . . . . . . . . 174
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 174
If you specify STDSQL(NO). . . . . . . . . . . . . . . . . . 174
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 174
Embedding SQL statements . . . . . . . . . . . . . . . . . . 175
Using host variables . . . . . . . . . . . . . . . . . . . . . 177
Declaring host variables . . . . . . . . . . . . . . . . . . . . 178
Using host structures . . . . . . . . . . . . . . . . . . . . . 181
Determining equivalent SQL and PL/I data types . . . . . . . . . . . 182
Notes on PL/I variable declaration and usage . . . . . . . . . . . 185
Determining compatibility of SQL and PL/I data types . . . . . . . . . 186
Using indicator variables . . . . . . . . . . . . . . . . . . . . 187
Handling SQL error return codes . . . . . . . . . . . . . . . . . 188
Coding SQL statements in a REXX application. . . . . . . . . . . . . 189
Defining the SQL communication area . . . . . . . . . . . . . . . 189
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 190
Accessing the DB2 REXX Language Support application programming
interfaces . . . . . . . . . . . . . . . . . . . . . . . . 190
Embedding SQL statements in a REXX procedure . . . . . . . . . . 192
Using cursors and statement names . . . . . . . . . . . . . . . 194
Using REXX host variables and data types . . . . . . . . . . . . . 194
Determining equivalent SQL and REXX data types . . . . . . . . . 194
Letting DB2 determine the input data type . . . . . . . . . . . . 194
Ensuring that DB2 correctly interprets character input data . . . . . . 196
Passing the data type of an input variable to DB2 . . . . . . . . . 196
Retrieving data from DB2 tables . . . . . . . . . . . . . . . . 197
Using indicator variables . . . . . . . . . . . . . . . . . . . . 197
Setting the isolation level of SQL statements in a REXX procedure . . . . 198

Chapter 10. Using constraints to maintain data integrity . . . . . . . . 201


Using table check constraints . . . . . . . . . . . . . . . . . . . 201
Constraint considerations . . . . . . . . . . . . . . . . . . . 201
When table check constraints are enforced . . . . . . . . . . . . . 202
How table check constraints set check pending status . . . . . . . . . 202
Using referential constraints. . . . . . . . . . . . . . . . . . . . 203
Parent key columns. . . . . . . . . . . . . . . . . . . . . . 203
Defining a parent key and a unique index . . . . . . . . . . . . . 204
Incomplete definition . . . . . . . . . . . . . . . . . . . . 205
Recommendations for defining primary keys . . . . . . . . . . . 205
Defining a foreign key . . . . . . . . . . . . . . . . . . . . . 206
The relationship name . . . . . . . . . . . . . . . . . . . . 206
Indexes on foreign keys . . . . . . . . . . . . . . . . . . . 207
The FOREIGN KEY clause in ALTER TABLE . . . . . . . . . . . 207
Restrictions on cycles of dependent tables . . . . . . . . . . . . 207

Chapter 11. Using triggers for active data . . . . . . . . . . . . .


209
Example of creating and using a trigger . . . . . . . . . . . . . . .
209
Parts of a trigger . . . . . . . . . . . . . . . . . . . . . . . .
211
Invoking stored procedures and user-defined functions from triggers . . . . .
217
Passing transition tables to user-defined functions and stored procedures 217
Trigger cascading . . . . . . . . . . . . . . . . . . . . . . . 218
Ordering of multiple triggers. . . . . . . . . . . . . . . . . . . . 219

Part 2. Coding SQL in your host application program 63


Interactions among triggers and referential constraints . . . . . . . . . . 219
Creating triggers to obtain consistent results . . . . . . . . . . . . . 221

64 Application Programming and SQL Guide


Chapter 6. Basics of coding SQL in an application program
Suppose you are writing an application program to access data in a DB2 database.
When your program executes an SQL statement, the program needs to
communicate with DB2. When DB2 finishes processing an SQL statement, DB2
sends back a return code, and your program should test the return code to examine
the results of the operation.

To communicate with DB2, you need to:


v Choose a method for communicating with DB2. You can use one of these
methods:
– Static SQL
– Embedded dynamic SQL
– Open Database Connectivity (ODBC)
– JDBC application support
This book discusses embedded SQL. See “Chapter 23. Coding dynamic SQL in
application programs” on page 497 for a comparison of static and embedded
dynamic SQL and an extended discussion of embedded dynamic SQL.

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 and is therefore a better choice than ODBC for making DB2 calls
from Java applications.

For more information on using JDBC, see DB2 ODBC Guide and Reference.
v Delimit SQL statements, as described in “Delimiting an SQL statement” on
page 66.
v Declare the tables you use, as described in “Declaring table and view definitions”
on page 67. (This is optional.)
v Declare the data items used to pass data between DB2 and a host language, as
described in “Accessing data using host variables and host structures” on
page 67.
v Code SQL statements to access DB2 data. See “Accessing data using host
variables and host structures” on page 67.
For information about using the SQL language, see “Part 1. Using SQL queries”
on page 1 and in DB2 SQL Reference. Details about how to use SQL
statements within an application program are described in “Chapter 9.
Embedding SQL statements in host languages” on page 107.
v Declare a communications area (SQLCA), or handle exceptional conditions that
DB2 indicates with return codes, in the SQLCA. See “Checking the execution of
SQL statements” on page 74 for more information.

In addition to these basic requirements, you should also consider several special
topics:
v “Chapter 7. Using a cursor to retrieve a set of rows” on page 81 discusses how to
use a cursor in your application program to select a set of rows and then process
the set one row at a time.

© Copyright IBM Corp. 1983, 2001 65


v “Chapter 8. Generating declarations for your tables using DCLGEN” on page 95
discusses how to use DB2’s declarations generator, DCLGEN, to obtain accurate
SQL DECLARE statements for tables and views.

This section includes information about using SQL in application programs written in
assembler, C, COBOL, FORTRAN, PL/I, and REXX. You can also use SQL in
application programs written in Ada, APL2®, BASIC, and Prolog. See the following
publications for more information about these languages:
Ada IBM Ada/370 SQL Module Processor for DB2 Database Manager
User's Guide
APL2 APL2 Programming: Using Structured Query Language (SQL)
BASIC IBM BASIC/MVS Language Reference
Prolog/MVS & VM
IBM SAA AD/Cycle® Prolog/MVS & VM Programmer's Guide

Conventions used in examples of coding SQL statements


The SQL statements shown in this section use the following conventions:
v The SQL statement is part of a COBOL application program. Each SQL example
shows 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). Hence, 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. For a description of the tables, see
“Appendix A. DB2 sample tables” on page 815.
v An SQL example does not necessarily show the complete syntax of an SQL
statement. For the complete description and syntax of any of the statements
described in this book, see Chapter 5 of DB2 SQL Reference.
v Examples do not take referential constraints into account. For more information
about how referential constraints affect SQL statements, and examples of how
SQL statements operate with referential constraints, see “Chapter 2. Working with
tables and modifying data” on page 17.

Some of the examples vary from these conventions. Exceptions are noted where
they occur.

Delimiting an SQL statement


For languages other than REXX, bracket an SQL statement in your program
between EXEC SQL and a statement terminator. The terminators for the languages
described in this book are:
Language SQL Statement Terminator
Assembler End of line or end of last continued line
C Semicolon (;)
COBOL END-EXEC
FORTRAN End of line or end of last continued line
PL/I Semicolon (;)

66 Application Programming and SQL Guide


For REXX, precede the statement with EXECSQL. If the statement is in a literal
string, enclose it in single or double quotation marks.

For example, use EXEC SQL and END-EXEC to delimit an SQL statement in a
COBOL program:
EXEC SQL
an SQL statement
END-EXEC.

Declaring table and view definitions


Before your program issues SQL statements that retrieve, update, delete, or insert
data, you should declare the tables and views your program accesses. To do this,
include an SQL DECLARE statement in your program.

You do not have to declare tables or views, but there are advantages if you do. 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 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.

A 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 DSN8710.DEPT table looks
like this:
EXEC SQL
DECLARE DSN8710.DEPT TABLE
(DEPTNO CHAR(3) NOT NULL,
DEPTNAME VARCHAR(36) NOT NULL,
MGRNO CHAR(6) ,
ADMRDEPT CHAR(3) NOT NULL,
LOCATION CHAR(16) )

END-EXEC.

As an alternative to coding the DECLARE statement yourself, you can use


DCLGEN, the declarations generator supplied with DB2. For more information about
using DCLGEN, see “Chapter 8. Generating declarations for your tables using
DCLGEN” on page 95.

When you declare a table or view that contains a column with a distinct type, it is
best to declare that column with the source type of the distinct type, rather than 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.

Accessing data using host variables and host structures


You can access data using host variables and host structures.

Chapter 6. Basics of coding SQL in an application program 67


A host variable is a data item declared in the host language for use within an SQL
statement. Using host variables, you can:
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 in the host variable to a special register, such as CURRENT
SQLID and CURRENT DEGREE
v Insert null values in columns 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 structure is a group of host variables that an SQL statement can refer to
using a single name. You can use host structures in all languages except REXX.
Use host language statements to define the host structures.

Using host variables


You can use any valid host variable name in an SQL statement. You must declare
the name in the host program before you use it. (For more information see the
appropriate language section in “Chapter 9. Embedding SQL statements in host
languages” on page 107.)

To optimize performance, make sure the host language declaration maps as closely
as possible to the data type of the associated data in the database; see “Chapter 9.
Embedding SQL statements in host languages” on page 107. For more performance
suggestions, see “Part 6. Additional programming techniques” on page 489.

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 “Chapter 23. Coding dynamic SQL in
application programs” on page 497 for more information.)

Host variables follow the naming conventions of the host language. A colon (:) must
precede host variables used in SQL to tell DB2 that the variable is not a column
name. A colon must not precede host variables outside of SQL statements.

For more information about declaring host variables, see the appropriate language
section:
v Assembler: “Using host variables” on page 111
v C: “Using host variables” on page 124
v COBOL: “Using host variables” on page 146
v FORTRAN: “Using host variables” on page 167
v PL/I: “Using host variables” on page 177.
v REXX: “Using REXX host variables and data types” on page 194.

Retrieving data into a host variable


You can use a host variable to specify a program data area to contain the column
values of a retrieved row or rows.

Retrieving a single row of data: The INTO clause of the SELECT statement
names one or more host variables to contain the column values returned. The
named variables correspond one-to-one with the list of column names in the
SELECT list.

68 Application Programming and SQL Guide


For example, suppose you are retrieving the EMPNO, LASTNAME, and
WORKDEPT column values from rows in the DSN8710.EMP table. You can define
a data area in your program to hold each column, then name the data areas with
an INTO clause, as in the following example. (Notice that a colon precedes each
host variable):
EXEC SQL
SELECT EMPNO, LASTNAME, WORKDEPT
INTO :CBLEMPNO, :CBLNAME, :CBLDEPT
FROM DSN8710.EMP
WHERE EMPNO = :EMPID
END-EXEC.

In the DATA DIVISION of the 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 DSN8710.EMP table.

If the SELECT statement returns more than one row, this is an error, and any data
returned is undefined and unpredictable.

Retrieving Multiple Rows of Data: If you do not know how many rows DB2 will
return, or if you expect more than one row to return, then you must use an
alternative to the SELECT ... INTO statement.

The DB2 cursor enables an application to process a set of rows and retrieve one
row at a time from the result table. For information on using cursors, see
“Chapter 7. Using a cursor to retrieve a set of rows” on page 81.

Specifying a list of items in a 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:
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 DSN8710.EMP
WHERE EMPNO = :PERSON
END-EXEC.

The results shown below have column headings that represent the names of the
host variables:
EMP-NUM PERSON-NAME EMP-SAL EMP-RAISE EMP-TTL
======= =========== ======= ========= =======
000220 LUTZ 29840 4476 34316

Inserting and updating data


You can set or change a value in a DB2 table to the value of a host variable. To do
this, you can use the host variable name in the SET clause of UPDATE or the
VALUES clause of INSERT. This example changes an employee’s phone number:
EXEC SQL
UPDATE DSN8710.EMP
SET PHONENO = :NEWPHONE
WHERE EMPNO = :EMPID
END-EXEC.

Chapter 6. Basics of coding SQL in an application program 69


Searching data
You can use a host variable to specify a value in the predicate of a search condition
or to replace a constant in an expression. For example, if you have defined a field
called EMPID that contains an employee number, you can retrieve the name of the
employee whose number is 000110 with:
MOVE '000110' TO EMPID.
EXEC SQL
SELECT LASTNAME
INTO :PGM-LASTNAME
FROM DSN8710.EMP
WHERE EMPNO = :EMPID
END-EXEC.

Using indicator variables with host variables


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 an input host variable value 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 into host variables: If the value for the column you retrieve is
null, DB2 puts a negative value in the indicator variable. 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 “Handling arithmetic or conversion errors” on
page 75 for more information.

If you do not use an indicator variable and DB2 retrieves a null value, an error
results.

When DB2 retrieves the value of a column, you can test the indicator variable. If the
indicator variable’s value is less than zero, the column value is null. When the
column value is null, the value of the host variable does not change from its
previous value.

You can also use an indicator variable to verify that a retrieved character string
value is not truncated. If the indicator variable contains a positive integer, the
integer is the original length of the string.

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 EXEC SQL


SELECT PHONENO SELECT PHONENO
INTO :CBLPHONE:INDNULL INTO :CBLPHONE INDICATOR :INDNULL
FROM DSN8710.EMP FROM DSN8710.EMP
WHERE EMPNO = :EMPID WHERE EMPNO = :EMPID
END-EXEC. 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.

70 Application Programming and SQL Guide


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 using host variables: You can use an
indicator variable to insert a null value from a host variable into a column. When
DB2 processes INSERT and UPDATE statements, it checks the indicator variable (if
it 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 it is possible that the new value for column PHONENO might be null,
you can code:
EXEC SQL
UPDATE DSN8710.EMP
SET PHONENO = :NEWPHONE:PHONEIND
WHERE EMPNO = :EMPID
END-EXEC.

When NEWPHONE contains other than a null value, set PHONEIND to zero by
preceding the statement with:
MOVE 0 TO PHONEIND.

When NEWPHONE contains a null value, set PHONEIND to a negative value by


preceding the statement with:
MOVE -1 TO PHONEIND.

Use IS NULL to test for a null column value: You cannot determine whether a
column value is null by comparing a host variable with an indicator variable that is
set -1 to the column. Two DB2 null values are not equal to each other. To test
whether a column has a null value, use the IS NULL comparison operator. For
example, the following code does not select the employees who do no have a
phone number:
MOVE -1 TO PHONE-IND.
EXEC SQL
SELECT LASTNAME
INTO :PGM-LASTNAME
FROM DSN8710.EMP
WHERE PHONENO = :PHONE-HV:PHONE-IND
END-EXEC.

To obtain that information, use a statement like this one:


EXEC SQL
SELECT LASTNAME
INTO :PGM-LASTNAME
FROM DSN8710.EMP
WHERE PHONENO IS NULL
END-EXEC.

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. If you assign or
compare data, see Chapter 2 of DB2 SQL Reference for the rules associated with
these operations.

Chapter 6. Basics of coding SQL in an application program 71


| Changing the coded character set ID of host variables
| All DB2 string data, other than BLOB data, has an encoding scheme and a coded
| character set ID (CCSID) associated with it. 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. See “Changing the CCSID for retrieved data” on page 519 for
| information on changing the CCSID in 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
| you refer 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 OS/390 and 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;
| wchar_t hvjpnname[11];
| EXEC SQL DECLARE :hvjpnname VARIABLE CCSID 1200;
| struct {
| short len;
| char d[30];
| } hvengname;
| EXEC SQL DECLARE :hvengname VARIABLE CCSID 1208;
| EXEC SQL END DECLARE SECTION;

| Using host structures


You can substitute a host structure for one or more host variables. You can also use
indicator variables (or structures) with host structures.

Example: Using a host structure


In the following example, assume that your COBOL program includes the following
SQL statement:

72 Application Programming and SQL Guide


EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT
INTO :EMPNO, :FIRSTNME, :MIDINIT, :LASTNAME, :WORKDEPT
FROM DSN8710.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 DSN8710.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 details about coding a host
structure in your program, see “Chapter 9. Embedding SQL statements in host
languages” on page 107. For more information on using DCLGEN and the
restrictions that apply to the C language, see “Chapter 8. Generating declarations
for your tables using DCLGEN” on page 95.

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 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 allows DB2 to notify your program about each null value
returned to a host variable in the host structure. For example:
01 PEMP-ROW.
10 EMPNO PIC X(6).
10 FIRSTNME.
49 FIRSTNME-LEN PIC S9(4) USAGE COMP.
49 FIRSTNME-TEXT PIC X(12).
10 MIDINIT PIC X(1).
10 LASTNAME.
49 LASTNAME-LEN PIC S9(4) USAGE COMP.
49 LASTNAME-TEXT PIC X(15).
10 WORKDEPT PIC X(3).
10 EMP-BIRTHDATE PIC X(10).
01 INDICATOR-TABLE.
. 02 EMP-IND PIC S9(4) COMP OCCURS 6 TIMES.
.
.

MOVE
. '000230' TO EMPNO.
.
.

EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, BIRTHDATE
INTO :PEMP-ROW:EMP-IND
FROM DSN8710.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.

Chapter 6. Basics of coding SQL in an application program 73


Because this example selects rows from the table DSN8710.EMP, some of the
values in EMP-IND are always zero. The first four columns of each row are defined
NOT NULL. In the above 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 “Chapter 1. Retrieving data”
on page 3.

Checking the execution of SQL statements


A program that includes SQL statements needs to have an area set apart for
communication with DB2 — an SQL communication area (SQLCA). When DB2
processes an SQL statement in your program, it places return codes in the
SQLCODE and SQLSTATE host variables or corresponding fields of the SQLCA.
The return codes indicate whether the statement executed succeeded or failed.

Because the SQLCA is a valuable problem-diagnosis tool, it is a good idea to


include the instructions necessary to display some of the information contained in
the SQLCA in your application programs. For example, the contents of
SQLERRD(3)—which indicates the number of rows that DB2 updates, inserts, or
deletes—could be useful. If SQLWARN0 contains W, DB2 has set at least one of
the SQL warning flags (SQLWARN1 through SQLWARNA). See Appendix C of DB2
SQL Reference for a description of all the fields in the SQLCA.

SQLCODE and SQLSTATE


Whenever an SQL statement executes, the SQLCODE and SQLSTATE fields of the
SQLCA receive a return code. Although both fields serve basically the same
purpose (indicating whether the statement executed successfully) there are some
differences between the two fields.

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 no data was found.

The meaning of SQLCODEs other than 0 and 100 varies with the particular product
implementing SQL.

SQLSTATE: SQLSTATE allows an application program to check for errors in the


same way for different IBM database management systems. See Appendix C of
DB2 Messages and Codes for a complete list of possible SQLSTATE values.

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.

To conform to the SQL standard, 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.

74 Application Programming and SQL Guide


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 exists as a result of executing an SQL statement. 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 a REXX procedure” on
page 192.

The WHENEVER statement allows 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

Condition is one of these three values:


SQLWARNING
Indicates what to do when SQLWARN0 = W or SQLCODE contains a
positive value other than 100. SQLWARN0 can be set for several different
reasons — for example, if a column value truncates when it moves into a
host variable. It is possible your program would 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).

Action 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 a 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, it must check SQLCODE after
the SQL statement executes.

Handling arithmetic or conversion errors


Numeric or character conversion errors or arithmetic expression errors can set an
indicator variable to -2. For example, division by zero and arithmetic overflow does
not necessarily halt the execution of a SELECT statement. If the 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, if you use indicator variables.

Chapter 6. Basics of coding SQL in an application program 75


For rows in which the error does occur, 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.

Handling SQL error return codes


You should check for errors 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 find the programming language specific syntax and details for calling
DSNTIAR on the following pages:
For assembler programs, see page 119
For C programs, see page 139
For COBOL programs, see page 161
For FORTRAN programs, see page 173
For PL/I programs, see page 188

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.

Defining a message output area


The calling program must allocate enough storage in the message output area to
hold all of the message text. You will probably not need more than 10 lines of 80
bytes each for your message output area. Your 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 two-byte length field precedes the data. The length field tells
DSNTIAR how many total bytes are in the output message area; its minimum value
is 240.

Figure 8 on page 77 shows the format of the message output area, where length is
the two-byte total length field, and the length of each line matches the logical record
length (lrecl) you specify to DSNTIAR.

76 Application Programming and SQL Guide


Figure 8. Format of the message output area

When you call DSNTIAR, you must name an SQLCA and an output message area
in its 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


Code Meaning
0 Successful execution.
4 More data was available than could fit into the provided message area.
8 The logical record length was not between 72 and 240, inclusive.
12 The message area was not large enough. The message length was 240 or
greater.
16 Error in TSO message routine.
20 Module DSNTIA1 could not be loaded.
24 SQLCA data error.

Preparing to use DSNTIAR


DSNTIAR can run either above or below the 16MB 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).
Thus, DSNTIAR runs in 31-bit mode if:
v Linked with other modules that also have the attributes AMODE(31) and
RMODE(ANY),
v Linked into an application that specifies the attributes AMODE(31) and
RMODE(ANY) in its link-edit JCL, or
v An application loads it.

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-megabyte line, you cannot use the assembler
BALR instruction or CALL macro to call DSNTIAR, because they assume that

Chapter 6. Basics of coding SQL in an application program 77


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 (OS/VS COBOL, for example). To do this, link a
second version of DSNTIAR with the attributes AMODE(24) and RMODE(24) into
another load module library. Or, you can write an intermediate assembler language
program that calls DSNTIAR in 31-bit mode; 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.

A scenario for using DSNTIAR


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 there is a deadlock or timeout.
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 from that statement indicates that the close was
successful.

You can use DSNTIAR in the error routine to generate the complete message text
associated with the negative SQLCODEs.
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 length of the message output area.
01 ERROR-MESSAGE.
02 ERROR-LEN PIC S9(4) COMP VALUE +720.
02 ERROR-TEXT PIC X(72) OCCURS 10 TIMES
INDEXED BY ERROR-INDEX.
77 ERROR-TEXT-LEN 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, you should first
format the message by calling 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 the following:

78 Application Programming and SQL Guide


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

Chapter 6. Basics of coding SQL in an application program 79


80 Application Programming and SQL Guide
Chapter 7. Using a cursor to retrieve a set of rows
Use a cursor in an application program to retrieve rows from a table or from a result
set that is returned by a stored procedure. This chapter explains how your
application program can use a cursor to retrieve rows from a table. For information
on using a cursor to retrieve rows from a result set, see “Chapter 24. Using stored
procedures for client/server processing” on page 527.

How to use a cursor


When you execute a SELECT statement, you retrieve a set of rows. That set of
rows is called the result table. In an application program, you need a way to retrieve
one row at a time from the result table into host variables. A cursor performs that
function.

The basic steps in using a cursor are:


1. Execute a DECLARE CURSOR statement to define the result table on which
the cursor operates. See “Step 1: Declare the cursor”.
2. Execute an OPEN CURSOR to make the cursor available to the application.
See “Step 2: Open the cursor” on page 83.
3. Specify what the program does when all rows have been retrieved. See “Step 3:
Specify what to do at end-of-data” on page 83.
4. Execute multiple SQL statements to retrieve data from the table or modify
selected rows of the table. See “Step 4: Execute SQL statements” on page 83.
5. Execute a CLOSE CURSOR statement to make the cursor unavailable to the
application. “Step 5: Close the cursor” on page 85.

Your program can have several cursors, each of which performs the previous steps.

Step 1: Declare the cursor


To define and identify a set of rows to be accessed with a cursor, issue a
DECLARE CURSOR statement. The DECLARE CURSOR statement names a
cursor and specifies a SELECT statement. The SELECT statement defines the
criteria for the rows that will make up the result table. See Chapter 4 of DB2 SQL
Reference for a complete list of clauses that you can use in the SELECT statement.

The following example shows a simple form of the DECLARE CURSOR statement:
EXEC SQL
DECLARE C1 CURSOR FOR
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, SALARY
FROM DSN8710.EMP
END-EXEC.

You can use this cursor to list select information on employees.

More complicated cursors might include WHERE clauses or joins of several tables.
For example, suppose that you want to use a cursor to list employees who work on
a certain project. Declare a cursor like this to identify those employees:
EXEC SQL
DECLARE C2 CURSOR FOR
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, SALARY
FROM DSN8710.EMP X
WHERE EXISTS

© Copyright IBM Corp. 1983, 2001 81


(SELECT *
FROM DSN8710.PROJ Y
WHERE X.EMPNO=Y.RESPEMP
AND Y.PROJNO=:GOODPROJ);

| Updating a column: You can update columns in the rows that you retrieve.
| Updating a row after you use a cursor to retrieve it is called a positioned update. If
| you intend to perform any positioned updates on the identified table, include the
| FOR UPDATE clause. The FOR UPDATE clause has two forms. The first form is
| FOR UPDATE OF column-list. Use this form when you know in advance which
| columns you need to update. The second form of the FOR UPDATE clause is FOR
| UPDATE, with no column list. Use this form when you might use the cursor to
| update any of the columns of the table.

For example, you can use this cursor to update only the SALARY column of the
employee table:
EXEC SQL
DECLARE C1 CURSOR FOR
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, SALARY
FROM DSN8710.EMP X
WHERE EXISTS
(SELECT *
FROM DSN8710.PROJ Y
WHERE X.EMPNO=Y.RESPEMP
AND Y.PROJNO=:GOODPROJ)
FOR UPDATE OF SALARY;

If you might use the cursor to update any column of the employee table, define the
cursor like this:
EXEC SQL
DECLARE C1 CURSOR FOR
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, SALARY
FROM DSN8710.EMP X
WHERE EXISTS
(SELECT *
FROM DSN8710.PROJ Y
WHERE X.EMPNO=Y.RESPEMP
AND Y.PROJNO=:GOODPROJ)
FOR UPDATE;

| DB2 must do more processing when you use the FOR UPDATE clause without a
| column list than when you use the FOR UPDATE OF clause with a column list.
| Therefore, if you intend to update only a few columns of a table, your program can
| run more efficiently if you include a column list.

The precompiler options NOFOR and STDSQL affect the use of the FOR UPDATE
clause in static SQL statements. For information on these options, see Table 48 on
| page 403. If you do not specify the FOR UPDATE clause in a DECLARE CURSOR
| statement, and you do not specify the STDSQL(YES) option or the NOFOR
| precompiler options, you receive an error if you execute a positioned UPDATE
| statement.

You can update a column of the identified table even though it is not part of the
result table. In this case, you do not need to name the column in the SELECT
statement. When the cursor retrieves a row (using FETCH) that contains a column
value you want to update, you can use UPDATE ... WHERE CURRENT OF to
identify the row that is to be updated.

82 Application Programming and SQL Guide


Read-only result table: Some result tables cannot be updated—for example, the
result of joining two or more tables. Read-only result table specifications are
described in greater detail in the discussion of DECLARE CURSOR in Chapter 5 of
DB2 SQL Reference.

Step 2: Open the cursor


To tell DB2 that you are ready to process the first row of the result table, execute
the OPEN statement in your program. DB2 then uses the SELECT statement within
DECLARE CURSOR to identify a set of rows. If you use host variables in that
SELECT statement, DB2 uses the current value of the variables to select the rows.
The result table that satisfies the search condition might contain zero, one, or many
rows. An example of an OPEN statement is:
EXEC SQL
OPEN C1
END-EXEC.

If you use the CURRENT DATE, CURRENT TIME, or CURRENT TIMESTAMP


special registers in a cursor, DB2 determines the values in those special registers
only when it opens the cursor. DB2 uses the values that it obtained at OPEN time
for all subsequent FETCH statements.

Two factors that influence the amount of time that DB2 requires to process the
OPEN statement are:
v Whether DB2 must perform any sorts before it can retrieve rows from the result
table
v Whether DB2 uses parallelism to process the SELECT statement associated with
the cursor
For more information, see “The effect of sorts on OPEN CURSOR” on page 710.

Step 3: Specify what to do at end-of-data


To determine if the program has retrieved the last row of data, test the SQLCODE
field for a value of 100 or the SQLSTATE field for a value of ’02000’. These codes
occur when a FETCH statement has retrieved the last row in the result table and
your program issues a subsequent FETCH. For example:
IF SQLCODE = 100 GO TO DATA-NOT-FOUND.

An alternative to this technique is to code the WHENEVER NOT FOUND statement.


The WHENEVER NOT FOUND statement can branch to another part of your
program that issues a CLOSE statement. For example, to branch to label
DATA-NOT-FOUND when the FETCH statement does not return a row, use this
statement:
EXEC SQL
WHENEVER NOT FOUND GO TO DATA-NOT-FOUND
END-EXEC.

Your program must anticipate and handle an end-of-data whenever you use a
cursor to fetch a row. For further information about the WHENEVER NOT FOUND
statement, see “Checking the execution of SQL statements” on page 74.

Step 4: Execute SQL statements


You execute one of these SQL statements using the cursor:
v A FETCH statement
v A positioned UPDATE statement

Chapter 7. Using a cursor to retrieve a set of rows 83


v A positioned DELETE statement

Using FETCH statements


Execute a FETCH statement for one of the following purposes:
v To copy data from a row of the result table into one or more host variables
v To position the cursor before you perform a positioned update or positioned
delete operation
The following example shows a FETCH statement retrieves selected columns from
the employee table:
EXEC SQL
FETCH C1 INTO
:HV-EMPNO, :HV-FIRSTNME, :HV-MIDINIT, :HV-LASTNAME, :HV-SALARY
END-EXEC.

The SELECT statement within DECLARE CURSOR statement identifies the result
table from which you fetch rows, but DB2 does not retrieve any data until your
application program executes a FETCH statement.

When your program executes the FETCH statement, DB2 uses the cursor to point
to a row in the result table. That row is called the current row. DB2 then copies the
current row contents into the program host variables that you specified on the INTO
clause of FETCH. This sequence repeats each time you issue FETCH, until you
have processed all rows in the result table.

The row that DB2 points to when you execute a FETCH statement depends on
whether the cursor is declared as a scrollable or non-scrollable. See “Scrollable and
non-scrollable cursors” on page 85 for more information.

When you query a remote subsystem with FETCH, consider using block fetch for
better performance. For more information see “Use block fetch” on page 385. Block
fetch processes rows ahead of the current row. You cannot use a block fetch when
you perform a positioned update or delete operation.

Using positioned UPDATE statements


After your program has executed a FETCH statement to retrieve the current row,
you can use a positioned UPDATE statement to modify the data in that row. An
example of a positioned UPDATE statement is:
UPDATE DSN8710.EMP
SET SALARY = 50000
WHERE CURRENT OF C1
END-EXEC.

A positioned UPDATE statement updates the row that the cursor points to.

A positioned UPDATE statement must meet these conditions:


v You cannot update a row if your update violates any unique, check, or referential
constraints.
v You cannot use an UPDATE statement to modify the rows of a created temporary
table. However, you can use an UPDATE statement to modify the rows of a
declared temporary table.
v If the right side of the SET clause in the UPDATE statement contains a fullselect,
that fullselect cannot include a correlated name for a table that is being updated.

84 Application Programming and SQL Guide


Using positioned DELETE statements
After your program has executed a FETCH statement to retrieve the current row,
you can use a positioned DELETE statement to delete that row. A example of a
positioned DELETE statement looks like this:
EXEC SQL
DELETE FROM DSN8710.EMP
WHERE CURRENT OF C1
END-EXEC.

A positioned DELETE statement deletes the row that cursor-name points to.

A positioned DELETE statement must meet these conditions:


v You cannot use a DELETE statement with a cursor to delete rows from a created
temporary table. However, you can use a DELETE statement with a cursor to
delete rows from a declared temporary table.
v After you have deleted a row, you cannot update or delete another row using that
cursor until you execute a FETCH statement to position the cursor on another
row.
v You cannot delete a row if doing so violates any referential constraints.

Step 5: Close the cursor


If you finish processing the rows of the result table and you want to use the cursor
again, issue a CLOSE statement to close the cursor. An example of a CLOSE
statement looks like this:
EXEC SQL
CLOSE C1
END-EXEC.

If you finish processing the rows of the result table, and you do not want to use the
cursor, you can let DB2 automatically close the cursor when your program
terminates.

Types of cursors
Cursors can be scrollable or not scrollable. They can also be held or not held. The
following sections discuss these characteristics in more detail.

| Scrollable and non-scrollable cursors


| When you declare a cursor, you tell DB2 whether you want the cursor to be
| scrollable or non-scrollable by including or omitting the SCROLL clause. This clause
| determines whether the cursor moves sequentially forward through the result table
| or can move randomly through the result table.

| Using a non-scrollable cursor


| The simplest type of cursor is a non-scrollable cursor. A non-scrollable cursor
| always moves sequentially forward in the result table. When you open the cursor,
| the cursor is positioned before the first row in the result table. When you execute
| the first FETCH, the cursor is positioned on the first row. When you execute
| subsequent FETCH statements, the cursor moves one row ahead for each FETCH.
| After each FETCH statement, the cursor is positioned on the row that you fetched.
| After you execute a positioned UPDATE or positioned DELETE operation, the
| cursor stays at the current row of the result table. You cannot retrieve rows
| backward or move to a specific position in a result table with a non-scrollable
| cursor.

Chapter 7. Using a cursor to retrieve a set of rows 85


| Using a scrollable cursor
| To make a cursor scrollable, you declare it as scrollable. To use a scrollable cursor,
| you execute FETCH statements that indicate where you want to position the cursor.

| If you want to order the rows of the cursor's result set, and you also want the cursor
| to be updatable, you need to declare the cursor as scrollable, even if you use it
| only to retrieve rows sequentially. You can use the ORDER BY clause in the
| declaration of an updatable cursor only if you declare the cursor as scrollable.

| Declaring a scrollable cursor: To indicate that a cursor is scrollable, you declare


| it with the SCROLL keyword. The following examples show a characteristic of
| scrollable cursors: the sensitivity.

| Figure 9 shows a declaration for an insensitive scrollable cursor.

|
| EXEC SQL DECLARE C1 INSENSITIVE SCROLL CURSOR FOR
| SELECT DEPTNO, DEPTNAME, MGRNO
| FROM DSN8710.DEPT
| ORDER BY DEPTNO
| END-EXEC.

|
| Figure 9. Declaration for an insensitive scrollable cursor
|
| Declaring a scrollable cursor with the INSENSITIVE keyword has the following
| effects:
| v The size, the order of the rows, and the values for each row of the result table do
| not change after you open the cursor.
| v The result table is read-only. Therefore, you cannot declare the cursor with the
| FOR UPDATE clause, and you cannot use the cursor for positioned update or
| delete operations.

| Figure 10 shows a declaration for a sensitive scrollable cursor.

|
| EXEC SQL DECLARE C2 SENSITIVE STATIC SCROLL CURSOR FOR
| SELECT DEPTNO, DEPTNAME, MGRNO
| FROM DSN8710.DEPT
| ORDER BY DEPTNO
| END-EXEC.

|
| Figure 10. Declaration for a sensitive scrollable cursor
|
| Declaring a cursor as SENSITIVE has the following effects:
| v When you execute positioned UPDATE and DELETE statements with the cursor,
| those updates are visible in the result table.
| v When the current value of a row no longer satisfies the SELECT statement for
| the cursor, that row is no longer visible in the result table.
| v When a row of the result table is deleted from the underlying table, the row is no
| longer visible in the result table.
| v Changes that are made to the underlying table by other cursors or other
| application processes can be visible in the result table, depending on whether the
| FETCH statements that you use with the cursor are FETCH INSENSITIVE or
| FETCH SENSITIVE statements.

86 Application Programming and SQL Guide


| In DB2 Version 7, when you declare a cursor as SENSITIVE, you must also declare
| it as STATIC. Declaring the cursor as STATIC has the following effects:
| v The size of the result table does not grow after you open the cursor.
| Rows that are inserted into the underlying table are not added to the result table.
| v The order of the rows does not change after you open the cursor.
| If the cursor declaration contains an ORDER BY clause, and columns that are in
| the ORDER BY clause are updated after you open the cursor, the order of rows
| in the result table does not change.

| Determining attributes of a cursor by checking the SQLCA: After you open a


| cursor, you can determine the following attributes of the cursor by checking the
| SQLWARN1, SQLWARN4, and SQLWARN5 fields of the SQLCA:
| SQLWARN1
| Whether the cursor is scrollable or non-scrollable
| SQLWARN4
| Whether the cursor is sensitive or insensitive
| SQLWARN5
| Whether the cursor is read-only, readable and deletable, or readable, deletable,
| and updatable

| If the OPEN statement executes with no errors or warnings, DB2 does not set
| SQLWARN0 when it sets SQLWARN1, SQLWARN4, or SQLWARN5. See Appendix
| C of DB2 SQL Reference for specific information on fields in the SQLCA.

| Retrieving rows with a scrollable cursor: When you open any cursor, the cursor
| is positioned before the first row of the result table. You move a scrollable cursor
| around in the result table by specifying a fetch orientation keyword in a FETCH
| statement. A fetch orientation keyword indicates the absolute or relative position of
| the cursor when the FETCH statement is executed. Table 4 lists the fetch
| orientation keywords that you can specify and their meanings.
| Table 4. Positions for a scrollable cursor
| Keyword in FETCH statement Cursor position when the FETCH is executed
| BEFORE Before the first row
| FIRST or ABSOLUTE +1 At the first row
| LAST or ABSOLUTE −1 At the last row
| AFTER After the last row
1
| ABSOLUTE To an absolute row number, from before the first
| row forward or from after the last row backward
| RELATIVE1 Forward or backward a relative number of rows
| CURRENT At the current row
| PRIOR or RELATIVE −1 To the previous row
| NEXT or RELATIVE +1 To the next row (default)
| Note:
| 1. ABSOLUTE and RELATIVE are described in greater detail in the discussion of FETCH in
| Chapter 5 of DB2 SQL Reference.
|

| For example, to use the cursor that is declared in Figure 9 on page 86 to fetch the
| fifth row of the result table, use a FETCH statement like this:

Chapter 7. Using a cursor to retrieve a set of rows 87


| EXEC SQL FETCH ABSOLUTE +5 C1 INTO :HVDEPTNO, :DEPTNAME, :MGRNO;

# To fetch the fifth row from the end of the result table, use this FETCH statement:
# EXEC SQL FETCH ABSOLUTE -5 C1 INTO :HVDEPTNO, :DEPTNAME, :MGRNO;

# When you declare a cursor as SENSITIVE, changes that other processes or


| cursors make to the underlying table can be visible to the result table of your
| cursor. Whether those changes are visible depends on whether you specify the
| SENSITIVE or INSENSITIVE keyword when you execute FETCH statements with
| the cursor. When you specify FETCH INSENSITIVE, changes that other processes
| or cursors make to the underlying table are not visible in the result table. When you
| specify FETCH SENSITIVE, changes that other processes or cursors make to the
| underlying table are visible in the result table. Table 5 summarizes the sensitivity
| values and their effects on the result table of a scrollable cursor.
| Table 5. How sensitivity affects the result table for a scrollable cursor
| DECLARE sensitivity FETCH sensitivity
| INSENSITIVE SENSITIVE
| INSENSITIVE No changes to the underlying table Not valid.
| are visible in the result table.
| Positioned UPDATE and DELETE
| statements using the cursor are not
| allowed.
| SENSITIVE Only changes that are made by the All changes are visible in the result
| cursor are visible in the result table. table.
|

| Determining the number of rows in the result table for a scrollable cursor:
| You can determine how many rows are in the result table of an INSENSITIVE or
| SENSITIVE STATIC scrollable cursor. To do that, execute a FETCH statement, such
| as FETCH AFTER, that positions the cursor after the last row. Then examine the
| SQLCA. Fields SQLERRD(1) and SQLERRD(2) (fields sqlerrd[0] and sqlerrd[1] for
| C and C⁺⁺) contain the number of rows in the result table.

| Holes in the result table: Scrollable cursors that are declared as INSENSITIVE
| or SENSITIVE STATIC follow a static model, which means that DB2 determines the
| size of the result table and the order of the rows when you open the cursor.
| Updating or deleting rows from the underlying table after the cursor is open can
| result in holes in the result table. A hole in the result table occurs when a delete or
| update operation results in a difference between the result table and the underlying
| base table.

| The following examples demonstrate how holes can occur.

| Example: Creating a delete hole: Suppose that table A consists of one integer
| column, COL1, which has the following values:
|
|

88 Application Programming and SQL Guide


| Now suppose that you declare the following cursor, which you use to delete rows
| from A:
| EXEC SQL DECLARE C3 SENSITIVE STATIC SCROLL CURSOR FOR
| SELECT COL1
| FROM A
| FOR UPDATE OF COL1;

| Now you execute the following SQL statements:


| EXEC SQL OPEN C3;
| EXEC SQL FETCH ABSOLUTE +3 C3 INTO :HVCOL1;
| EXEC SQL DELETE FROM A WHERE CURRENT OF C3;

| The positioned delete statement creates a delete hole, as shown in Figure 11.
|
|

|
| Figure 11. Creating a delete hole
|
| After you execute the positioned delete statement, the third row is deleted from the
| result table, but the result table does not shrink to fill the space that the deleted row
| creates.

| Example: Creating an update hole: Suppose that you declare the following cursor,
| which you use to update rows in A:
| EXEC SQL DECLARE C4 SENSITIVE STATIC SCROLL CURSOR FOR
| SELECT COL1
| FROM A
| WHERE COL1<6;

| Now you execute the following SQL statements:


| EXEC SQL OPEN C4;
| UPDATE A SET COL1=COL1+1;

| The searched UPDATE statement creates an update hole, as shown in Figure 12.
|
|

|
| Figure 12. Creating an update hole
|

Chapter 7. Using a cursor to retrieve a set of rows 89


| After you execute the searched UPDATE statement, the last row no longer qualifies
| for the result table, but the result table does not shrink to fill the space that the
| disqualified row creates.

| If you try to fetch from a delete hole, DB2 issues an SQL warning. If you try to
| update or delete the delete hole, DB2 issues an SQL error. You can remove a
| delete hole only by opening the scrollable cursor, setting a savepoint, executing a
| positioned DELETE statement with the scrollable cursor, and rolling back to the
| savepoint.

| If you try to fetch from an update hole, DB2 issues an SQL warning. If you try to
| delete the update hole, DB2 issues an SQL error. However, you can convert an
| update hole back to a result table row by updating the row in the base table, as
| shown in Figure 13. You can update the base table with a searched UPDATE
| statement in the same application process, or a searched or positioned UPDATE
| statement in another application process. After you update the base table, if the row
| qualifies for the result table, the update hole disappears.
|
|

|
| Figure 13. Removing an update hole
|
| A hole becomes visible to a cursor when a cursor operation returns a non-zero
| SQLCODE. The point at which a hole becomes visible depends on the following
| factors:
| v Whether the scrollable cursor creates the hole
| v Whether the FETCH statement is FETCH SENSITIVE or FETCH INSENSITIVE

| If the scrollable cursor creates the hole, the hole is visible when you execute a
| FETCH statement for the row that contains the hole. The FETCH statement can be
| FETCH INSENSITIVE or FETCH SENSITIVE.

| If an update or delete operation outside the scrollable cursor creates the hole, the
| hole is visible at the following times:
| v If you execute a FETCH SENSITIVE statement for the row that contains the hole,
| the hole is visible when you execute the FETCH statement.
| v If you execute a FETCH INSENSITIVE statement, the hole is not visible when
| you execute the FETCH statement. DB2 returns the row as it was before the
| update or delete operation occurred. However, if you follow the FETCH
| INSENSITIVE statement with a positioned UPDATE or DELETE statement, the
| hole becomes visible.

90 Application Programming and SQL Guide


| Creating declared temporary tables for scrollable cursors
| DB2 uses declared temporary tables for processing scrollable cursors. Therefore,
| before you can use a scrollable cursor, your database administrator needs to create
| a TEMP database and TEMP table spaces for those declared temporary tables. If
| there is more than one TEMP table space in the subsystem, DB2 chooses the table
| spaces to use for scrollable cursors.

| The page size of the TEMP table space must be large enough to hold the longest
| row in the declared temporary table. See Part 2 of DB2 Installation Guide for
| information on calculating the page size for TEMP table spaces that are used for
| scrollable cursors.

Held and non-held cursors


When you declare a cursor, you tell DB2 whether you want the cursor to be held or
not held by including or omitting the WITH HOLD clause. A held cursor, which is
declared WITH HOLD, does not close after a commit operation. A cursor that is not
held closes after a commit operation.

After a commit operation, a held cursor is positioned after the last row retrieved and
before the next logical row of the result table to be returned.

A held cursor can close when:


v You issue a CLOSE cursor, ROLLBACK, or CONNECT statement
v You issue a CAF CLOSE function call or an RRSAF TERMINATE THREAD
function call
v The application program terminates.

If the program abnormally terminates, the cursor position is lost. To prepare for
restart, your program must reposition the cursor.

The following restrictions apply to cursors that are declared WITH HOLD:
v Do not use DECLARE CURSOR WITH HOLD with the new user signon from a
DB2 attachment facility, because all open cursors are closed.
v Do not declare a WITH HOLD cursor in a thread that could become inactive. If
you do, its locks are held indefinitely.

IMS

You cannot use DECLARE CURSOR...WITH HOLD in message processing


programs (MPP) and message-driven batch message processing (BMP). Each
message is a new user for DB2; whether or not you declare them using WITH
HOLD, no cursors continue for new users. You can use WITH HOLD in
non-message-driven BMP and DL/I batch programs.

Chapter 7. Using a cursor to retrieve a set of rows 91


CICS

In CICS applications, you can use DECLARE CURSOR...WITH HOLD to


indicate that a cursor should not close at a commit or sync point. However,
SYNCPOINT ROLLBACK closes all cursors, and end-of-task (EOT) closes all
cursors before DB2 reuses or terminates the thread. Because
pseudo-conversational transactions usually have multiple EXEC CICS
RETURN statements and thus span multiple EOTs, the scope of a held cursor
is limited. Across EOTs, you must reopen and reposition a cursor declared
WITH HOLD, as if you had not specified WITH HOLD.

You should always close cursors that you no longer need. If you let DB2 close
a CICS attachment cursor, the cursor might not close until the CICS
attachment facility reuses or terminates the thread.

The following cursor declaration causes the cursor to maintain its position in the
DSN8710.EMP table after a commit point:
EXEC SQL
DECLARE EMPLUPDT CURSOR WITH HOLD FOR
SELECT EMPNO, LASTNAME, PHONENO, JOB, SALARY, WORKDEPT
FROM DSN8710.EMP
WHERE WORKDEPT < 'D11'
ORDER BY EMPNO
END-EXEC.

Examples of using cursors


The following examples show the SQL statements that you must include in a
COBOL program to define and use a cursor.

Figure 14 on page 93 shows how to use a non-scrollable cursor to perform FETCH


and positioned UPDATE operations.

92 Application Programming and SQL Guide


**************************************************
* Declare a cursor that will be used to update *
* the JOB and WORKDEPT columns of the EMP table. *
**************************************************
EXEC SQL
DECLARE THISEMP CURSOR FOR
SELECT EMPNO, LASTNAME,
WORKDEPT, JOB
FROM DSN8710.EMP
WHERE WORKDEPT = 'D11'
FOR UPDATE OF JOB
END-EXEC.
**************************************************
* Open the cursor *
**************************************************
EXEC SQL
OPEN THISEMP
END-EXEC.
**************************************************
* Indicate what action to take when all rows *
* in the result table have been fetched. *
**************************************************
EXEC SQL
WHENEVER NOT FOUND
GO TO CLOSE-THISEMP
END-EXEC.
**************************************************
* Fetch a row to position the cursor. *
**************************************************
EXEC SQL
FETCH THISEMP
INTO :EMP-NUM, :NAME2,
:DEPT, :JOB-NAME
END-EXEC.
**************************************************
* Update the row that the cursor points to. *
**************************************************
EXEC SQL
UPDATE DSN8710.EMP
SET JOB = :NEW-JOB
WHERE CURRENT OF THISEMP
END-EXEC.
**************************************************
* Branch back to fetch and process the next row. *
**************************************************
.
.
.

**************************************************
* Close the cursor *
**************************************************
CLOSE-THISEMP.
EXEC SQL
CLOSE THISEMP
END-EXEC.

Figure 14. Performing cursor operations with a non-scrollable cursor

Figure 15 on page 94 shows how to use a scrollable cursor to retrieve data


backward from a table.

Chapter 7. Using a cursor to retrieve a set of rows 93


**************************************************
* Declare a cursor that will be used to retrieve *
* the data backward from the EMP table. The *
* cursor should have access to changes by other *
* processes. *
**************************************************
EXEC SQL
DECLARE THISEMP SENSITIVE STATIC SCROLL CURSOR FOR
SELECT EMPNO, LASTNAME, WORKDEPT, JOB
FROM DSN8710.EMP
END-EXEC.
**************************************************
* Open the cursor *
**************************************************
EXEC SQL
OPEN THISEMP
END-EXEC.
**************************************************
* Indicate what action to take when all rows *
* in the result table have been fetched. *
**************************************************
EXEC SQL
WHENEVER NOT FOUND GO TO CLOSE-THISEMP
END-EXEC.
**************************************************
* Position the cursor after the last row of the *
* result table. This FETCH statement cannot *
* include the SENSITIVE or INSENSITIVE keyword *
* and cannot contain an INTO clause. *
**************************************************
EXEC SQL
FETCH AFTER THISEMP
END-EXEC.
**************************************************
* Fetch the previous row in the table. *
**************************************************
EXEC SQL
FETCH SENSITIVE PRIOR THISEMP
INTO :EMP-NUM, :NAME2, :DEPT, :JOB-NAME
END-EXEC.
**************************************************
* Check that the fetched row is not a hole *
* (SQLCODE +222). If the row is not a *
* hole, print the row contents. *
**************************************************
IF SQLCODE IS GREATER THAN OR EQUAL TO 0 AND
SQLCODE IS NOT EQUAL TO +100 AND
SQLCODE IS NOT EQUAL TO +222 THEN
PERFORM PRINT-RESULTS.
**************************************************
* Branch back to fetch the previous row. *
**************************************************
.
.
.

**************************************************
* Close the cursor *
**************************************************
CLOSE-THISEMP.
EXEC SQL
CLOSE THISEMP
END-EXEC.

Figure 15. Performing cursor operations with a scrollable cursor

94 Application Programming and SQL Guide


Chapter 8. Generating declarations for your tables using
DCLGEN
DCLGEN, the declarations generator supplied with DB2, produces a DECLARE
statement you can use in a C, COBOL, or PL/I program, so that you do not need to
code the statement yourself. For detailed syntax of DCLGEN, see Chapter 2 of 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 matching PL/I, or 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 DCLGEN with
the table or view name before you precompile your program. To use the
declarations generated by DCLGEN in your program, use the SQL INCLUDE
statement.

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. Next, fill in the DCLGEN panel with the information it needs to build
the declarations. Then press ENTER.
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.
If you wish to start DCLGEN in the foreground, and your table names include
DBCS characters, you must input 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.

Invoking DCLGEN through DB2I


The easiest way to start DCLGEN is through DB2I. Figure 16 on page 96 shows the
DCLGEN panel you reach by selecting option 2, DCLGEN, on the DB2I Primary
Option Menu. For more instructions on using DB2I, see “Using ISPF and DB2
Interactive (DB2I)” on page 434.

© Copyright IBM Corp. 1983, 2001 95


DSNEDP01 DCLGEN SSID: DSN
===>

Enter table name for which declarations are required:


1 SOURCE TABLE NAME ===> (Unqualified table name)
2 TABLE OWNER ===> (Optional)
3 AT LOCATION ..... ===> (Optional)

Enter destination data set: (Can be sequential or partitioned)


4 DATA SET NAME ... ===>
5 DATA SET PASSWORD ===> (If password protected)

Enter options as desired:


6 ACTION .......... ===> (ADD new or REPLACE old declaration)
7 COLUMN LABEL .... ===> (Enter YES for column label)
8 STRUCTURE NAME .. ===> (Optional)
9 FIELD NAME PREFIX ===> (Optional)
10 DELIMIT DBCS .... ===> (Enter YES to delimit DBCS identifiers)
11 COLUMN SUFFIX ... ===> (Enter YES to append column name)
12 INDICATOR VARS .. ===> (Enter YES for indicator variables)

PRESS: ENTER to process END to exit HELP for more information

Figure 16. 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 have to enclose DBCS table names in apostrophes. If you do


not enclose the table name in apostrophes, DB2 translates lowercase
characters to uppercase.

DCLGEN does not treat the underscore as a special character. 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 built from the table name.
2 TABLE OWNER
Is the owner 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.

96 Application Programming and SQL Guide


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
TABLE NAME field. The value of the AT LOCATION field prefixes the table
name on the SQL DECLARE statement as follows:
location_name.owner_id.table_name

For example, for the location PLAINS_GA:


PLAINS_GA.CARTER.CROP_YIELD_89

If you do not specify a location, then this option defaults to the local location
name. This field applies to DB2 private protocol access only (that is, the
location you name must be another DB2 for OS/390 and 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; there is no default.
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)

and 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 does not display on your terminal, and 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 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 declared on any columns of the
table or view as comments in the data declarations. (The SQL statement
LABEL ON 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

Chapter 8. Generating declarations for your tables using DCLGEN 97


alphabetic, then enclose the name in apostrophes. If you use special
characters, be careful to avoid name conflicts.
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.
C language 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, be careful to 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, 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 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, then 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);
where n is the number of columns in the table. For example, if you define a
table:

98 Application Programming and SQL Guide


CREATE TABLE HASNULLS (CHARCOL1 CHAR(1), CHARCOL2 CHAR(1));

and you request an array of indicator variables for a COBOL program,


DCLGEN might generate the following host variable declaration:
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.

DCLGEN generates a table or column name in the DECLARE statement as a


non-delimited identifier unless at least one of the following 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.

Including the data 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 DSN8710.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 DSN8710.EMP. (A COBOL record description is a two-level host structure that
corresponds to the columns of a table’s row. For information on host structures, see
“Chapter 9. Embedding SQL statements in host languages” on page 107.) 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.

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 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.

DCLGEN support of C, COBOL, and PL/I languages


DCLGEN derives variable names from the source in the database. In Table 6 on
page 100, var represents variable names that DCLGEN provides when it is
necessary to clarify the host language declaration.

Chapter 8. Generating declarations for your tables using DCLGEN 99


Table 6. Declarations generated by DCLGEN
SQL Data Type6 C COBOL PL/I
SMALLINT short int PIC S9(4) BIN FIXED(15)
USAGE COMP
INTEGER long int PIC S9(9) BIN FIXED(31)
USAGE COMP
# DECIMAL(p,s) or decimal(p,s)4 PIC S9(p-s)V9(s) DEC FIXED(p,s)
# NUMERIC(p,s) USAGE COMP-3 If p>15, the PL/I
# compiler must
# support this
# precision, or
# a warning
# is generated.
REAL or float USAGE COMP-1 BIN FLOAT(n)
FLOAT(n)
1 <= n <= 21
DOUBLE PRECISION, double USAGE COMP-2 BIN FLOAT(n)
DOUBLE,
or FLOAT(n)
CHAR(1) char PIC X(1) CHAR(1)
CHAR(n) char var [n+1] PIC X(n) CHAR(n)
VARCHAR(n) struct 10 var. CHAR(n) VAR
{short int var_len; 49 var_LEN PIC 9(4)
char var_data[n]; USAGE COMP.
} var; 49 var_TEXT PIC X(n).
GRAPHIC(1) wchar_t PIC G(1) GRAPHIC(1)
GRAPHIC(n) wchar_t var[n+1]; PIC G(n) USAGE GRAPHIC(n)
n > 1 DISPLAY-1.1
or
PIC N(n).1
VARGRAPHIC(n) struct VARGRAPH 10 var. GRAPHIC(n) VAR
{short len; 49 var_LEN PIC 9(4)
wchar_t data[n]; USAGE COMP.
} var; 49 var_TEXT PIC G(n)
USAGE
DISPLAY-1.1
or
10 var.
49 var_LEN PIC 9(4)
USAGE COMP.
49 var_TEXT
PIC N(n).1
BLOB(n)5 SQL TYPE IS USAGE SQL TYPE IS SQL TYPE IS
BLOB_LOCATOR BLOB-LOCATOR BLOB_LOCATOR
CLOB(n)5 SQL TYPE IS USAGE SQL TYPE IS SQL TYPE IS
CLOB_LOCATOR CLOB-LOCATOR CLOB_LOCATOR
DBCLOB(n)5 SQL TYPE IS USAGE SQL TYPE IS SQL TYPE IS
DBCLOB_LOCATOR DBCLOB-LOCATOR DBCLOB_LOCATOR
ROWID SQL TYPE IS ROWID USAGE SQL TYPE IS ROWID SQL TYPE IS ROWID
2 2
DATE char var[11] PIC X(10) CHAR(10)2
TIME char var[9]3 PIC X(8)3 CHAR(8)3
TIMESTAMP char var[27] PIC X(26) CHAR(26)

100 Application Programming and SQL Guide


Notes to Table 6 on page 100:
1. DCLGEN chooses the format based on the character you specify as the DBCS
symbol on the COBOL Defaults panel.
2. This declaration is used unless there is a date installation exit for formatting
dates, in which case the length is that specified for the LOCAL DATE LENGTH
installation option.
3. This declaration is used unless there is a time installation exit for formatting
times, in which case the length is that specified for the LOCAL TIME LENGTH
installation option.
4. 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.
5. For a BLOB, CLOB, or DBCLOB data type, DCLGEN generates a LOB locator.
6. For a distinct type, DCLGEN generates the host language equivalent of the
source data type.

For further details about the DCLGEN subcommand, see Chapter 2 of DB2
Command Reference.

Example: Adding a table declaration and host-variable structure to a


library
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 DSN8710.VPHONE.
v The host-variable structure is for COBOL.
v The structure receives the default name DCLVPHONE.

Information 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 COBOL as the application language as shown in Figure 17 on page 102,


and then press Enter. The COBOL Defaults panel then displays as shown in
Figure 18 on page 102.

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.

Chapter 8. Generating declarations for your tables using DCLGEN 101


DSNEOP01 DB2I DEFAULTS
COMMAND ===>_

Change defaults as desired:

1 DB2 NAME ............. ===> DSN (Subsystem identifier)


2 DB2 CONNECTION RETRIES ===> 0 (How many retries for DB2 connection)
3 APPLICATION LANGUAGE ===> COBOL (ASM, C, CPP, COBOL, COB2, IBMCOB,
FORTRAN,PLI)
4 LINES/PAGE OF LISTING ===> 80 (A number from 5 to 999)
5 MESSAGE LEVEL ........ ===> I (Information, Warning, Error, Severe)
6 SQL STRING DELIMITER ===> DEFAULT (DEFAULT, ' or ")
7 DECIMAL POINT ........ ===> . (. or ,)
8 STOP IF RETURN CODE >= ===> 8 (Lowest terminating return code)
9 NUMBER OF ROWS ===> 20 (For ISPF Tables)
10 CHANGE HELP BOOK NAMES?===> NO (YES to change HELP data set names)
11 DB2I JOB STATEMENT: (Optional if your site has a SUBMIT exit)
===> //USRT001A JOB (ACCOUNT),'NAME'
===> //*
===> //*
===> //*

PRESS: ENTER to process END to cancel HELP for more information

Figure 17. DB2I defaults panel—changing the application language

DSNEOP02 COBOL DEFAULTS


COMMAND ===>_

Change defaults as desired:

1 COBOL STRING DELIMITER ===> (DEFAULT, ' or ")


2 DBCS SYMBOL FOR DCLGEN ===> (G/N - Character in PIC clause)

Figure 18. The COBOL defaults panel. Shown only if the field APPLICATION LANGUAGE on
the DB2I Defaults panel is COBOL, COB2, or IBMCOB.

Step 2. Create the table declaration and host structure


Select option 2 on the DB2I Primary Option menu, and press Enter to display the
DCLGEN panel.

Fill in the fields as shown in Figure 19 on page 103, and then press Enter.

102 Application Programming and SQL Guide


DSNEDP01 DCLGEN SSID: DSN
===>
Enter table name for which declarations are required:

1 SOURCE TABLE NAME ===> DSN8710.VPHONE


2 TABLE OWNER ===>
3 AT LOCATION ..... ===> (Location of table, 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)

PRESS: ENTER to process END to exit HELP for more information

Figure 19. DCLGEN panel—selecting source table and destination data set

If the operation succeeds, a message displays at the top of your screen as shown
in Figure 20.

DSNE905I EXECUTION COMPLETE, MEMBER VPHONEC ADDED


***

Figure 20. Successful completion message

DB2 then displays the screen as shown in Figure 21 on page 104. Press Enter to
return to the DB2I Primary Option menu.

Chapter 8. Generating declarations for your tables using DCLGEN 103


DSNEDP01 DCLGEN SSID: DSN
===>
DSNE294I SYSTEM RETCODE=000 USER OR DSN RETCODE=0
Enter table name for which declarations are required:
1 SOURCE TABLE NAME ===> DSN8710.VPHONE
2 TABLE OWNER ===>
3 AT LOCATION ..... ===> (Location of table, 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 ===> (Enter YES to delimit DBCS identifiers)
11 COLUMN SUFFIX ... ===> (Enter YES to append column name)
12 INDICATOR VARS .. ===> (Enter YES for indicator variables)

PRESS: ENTER to process END to exit HELP for more information

Figure 21. DCLGEN panel—displaying system and user return codes

Step 3. Examine the results


To browse or edit the results, first exit from DB2I by entering X on the command
line of the DB2I Primary Option menu. The ISPF/PDF menu is then displayed, and
you can select either the browse or the edit option to view the results.

For this example, the data set to edit is prefix.TEMP.COBOL(VPHONEC), which is


shown in Figure 22 on page 105.

104 Application Programming and SQL Guide


***** DCLGEN TABLE(DSN8710.VPHONE) ***
***** LIBRARY(SYSADM.TEMP.COBOL(VPHONEC)) ***
***** QUOTE ***
***** ... IS THE DCLGEN COMMAND THAT MADE THE FOLLOWING STATEMENTS ***
EXEC SQL DECLARE DSN8710.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 DSN8710.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 ******

Figure 22. DCLGEN results displayed in edit mode

Chapter 8. Generating declarations for your tables using DCLGEN 105


106 Application Programming and SQL Guide
Chapter 9. Embedding SQL statements in host languages
This chapter provides detailed information about using each of the following
languages to write embedded SQL application programs:
v “Coding SQL statements in an assembler application”
v “Coding SQL statements in a C or a C⁺⁺ application” on page 121
v “Coding SQL statements in a COBOL application” on page 141
v “Coding SQL statements in a FORTRAN application” on page 164
v “Coding SQL statements in a PL/I application” on page 174.
v “Coding SQL statements in a REXX application” on page 189.

For each language, there are unique instructions or details about:


v Defining the SQL communications area
v Defining SQL descriptor areas
v Embedding SQL statements
v Using host variables
v Declaring host variables
v Determining equivalent SQL data types
v Determining if SQL and host language data types are compatible
v Using indicator variables or host structures, depending on the language
v Handling SQL error return codes

For information on reading the syntax diagrams in this chapter, see “How to read
the syntax diagrams” on page xix.

For information on writing embedded SQL application programs in Java, see DB2
Application Programming Guide and Reference for Java.

Coding SQL statements in an assembler application


This section helps you with the programming techniques that are unique to coding
SQL statements within an assembler program.

Defining the SQL communications area


An assembler program that contains SQL statements must include one or both of
the following host variables:
v An SQLCODE variable declared as a fullword integer
v An SQLSTATE variable declared as a character string of length 5 (CL5)
Or,
v An SQLCA, which contains the SQLCODE and SQLSTATE variables.

DB2 sets the SQLCODE and SQLSTATE values after each SQL statement
executes. An application can check these variables 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 SQLCODE or SQLSTATE, or an SQLCA, in your program


depends on whether you specify the precompiler option STDSQL(YES) to conform
to SQL standard, or STDSQL(NO) to conform to DB2 rules.

© Copyright IBM Corp. 1983, 2001 107


Assembler
If you specify STDSQL(YES)
When you use 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 and SQLSTATE within a BEGIN
DECLARE SECTION and END DECLARE SECTION statement in your program
declarations.

If you specify STDSQL(NO)


When you use the precompiler option STDSQL(NO), include an SQLCA explicitly.
You can code the SQLCA in an assembler program, either directly or by using the
SQL INCLUDE statement. The SQL INCLUDE statement requests a standard
SQLCA declaration:
EXEC SQL INCLUDE SQLCA

If your program is reentrant, you must include the SQLCA within a unique data area
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.

See Chapter 5 of DB2 SQL Reference for more information about the INCLUDE
statement and Appendix C of DB2 SQL Reference for a complete description of
SQLCA fields.

Defining SQL descriptor areas


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
v DESCRIBE TABLE host-variable INTO descriptor-name
v EXECUTE...USING DESCRIPTOR descriptor-name
v FETCH...USING DESCRIPTOR descriptor-name
v OPEN...USING DESCRIPTOR descriptor-name
v PREPARE...INTO descriptor-name
Unlike the SQLCA, there can be more than one SQLDA in a program, and an
SQLDA can have any valid name. You can code an SQLDA in an assembler
program either directly or by using the SQL INCLUDE statement. The SQL
INCLUDE statement requests a standard SQLDA declaration:
EXEC SQL INCLUDE SQLDA

You must place SQLDA declarations before the first SQL statement that references
the data descriptor unless you use the precompiler option TWOPASS. See Chapter
5 of DB2 SQL Reference for more information about the INCLUDE statement and
Appendix C of DB2 SQL Reference for a complete description of SQLDA fields.

108 Application Programming and SQL Guide


Assembler
Embedding SQL statements
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 DSN8710.DEPT X
SET MGRNO = :MGRNUM X
WHERE DEPTNO = :INTDEPT

Comments: You cannot include assembler comments in SQL statements. However,


you can include SQL comments in any embedded SQL statement if you specify the
precompiler option STDSQL(YES).

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: The precompiler option MARGINS allows you 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.

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.

The first character of a host variable 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.

Chapter 9. Embedding SQL statements in host languages 109


Assembler
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 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.

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
.
.
.

&XPROGRM 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
*

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.

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 generated by an SQL statement.

110 Application Programming and SQL Guide


Assembler

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 SAVE REGISTER 13
LA 13,SAVED POINT TO SAVE AREA
EXEC SQL . . .
L 13,SAVER13 RESTORE REGISTER 13

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.

Using host variables


You must explicitly declare each host variable before its first use in an SQL
statement if you specify the precompiler option ONEPASS. If you specify the
precompiler option TWOPASS, you must declare the host variable before its use in
the statement DECLARE CURSOR.

You can precede the assembler statements that define host variables with the
statement BEGIN DECLARE SECTION, and follow the assembler statements with
the statement END DECLARE SECTION. You must use the statements BEGIN
DECLARE SECTION and END DECLARE SECTION when you use the precompiler
option STDSQL(YES).

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.

A colon (:) must precede all host variables in an SQL statement.

An SQL statement that uses a host variable must be within the scope of the
statement that declares the variable.

Declaring host variables


Only some of the valid assembler declarations are valid host variable declarations.
If the declaration for a host variable is not valid, then any SQL statement that
references the variable might result in the message ″UNDECLARED HOST
VARIABLE″.

Chapter 9. Embedding SQL statements in host languages 111


Assembler
Numeric host variables: The following figure shows the syntax for valid numeric
host variable declarations. The numeric value specifies the scale of the packed
decimal variable. If value does not include a decimal point, the scale is 0.

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 floating point
or System/390 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 System/390
floating point before storing it.

 variable-name DC H 
DS 1 L2
F
L4
P ’value’
Ln
E
L4
EH
L4
EB
L4
D
L8
DH
L8
DB
L8

Figure 23. Numeric host variables

Character host variables: There are three valid forms for character host variables:
v Fixed-length strings
v Varying-length strings
v CLOBs

The following figures show the syntax for forms other than CLOBs. See Figure 30
on page 114 for the syntax of CLOBs.

 variable-name DC C 
DS 1 Ln

Figure 24. Fixed-length character strings

 variable-name DC H , CLn 
DS 1 L2 1

Figure 25. Varying-length character strings

Graphic host variables: There are three valid forms for graphic host variables:

112 Application Programming and SQL Guide


Assembler
v Fixed-length strings
v Varying-length strings
v DBCLOBs

The following figures show the syntax for forms other than DBCLOBs. See
Figure 30 on page 114 for the syntax of DBCLOBs. In the syntax diagrams, value
denotes one or more DBCS characters, and the symbols < and > represent shift-out
and shift-in characters.

 variable-name DC G 
DS Ln
’<value>’
Ln’<value>’

Figure 26. Fixed-length graphic strings

 variable-name DS H , GLn 
DC L2 ’m’ ’<value>’

Figure 27. Varying-length graphic strings

Result set locators: The following figure shows the syntax for declarations of result
set locators. See “Chapter 24. Using stored procedures for client/server processing”
on page 527 for a discussion of how to use these host variables.

 variable-name DC F 
DS 1 L4

Figure 28. Result set locators

Table Locators: The following figure shows the syntax for declarations of table
locators. See “Accessing transition tables in a user-defined function or stored
procedure” on page 279 for a discussion of how to use these host variables.

 variable-name SQL TYPE IS TABLE LIKE table-name AS LOCATOR 

Figure 29. Table locators

LOB variables and locators: The following figure shows the syntax for
declarations of BLOB, CLOB, and DBCLOB host variables and locators.

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.

See “Chapter 13. Programming for large objects (LOBs)” on page 229 for a
discussion of how to use these host variables.

Chapter 9. Embedding SQL statements in host languages 113


Assembler

 variable-name SQL TYPE IS BINARY LARGE OBJECT length 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR

Figure 30. LOB variables and locators

ROWIDs: The following figure shows the syntax for declarations of ROWID
variables. See “Chapter 13. Programming for large objects (LOBs)” on page 229 for
a discussion of how to use these host variables.

 variable-name SQL TYPE IS ROWID 

Figure 31. ROWID variables

Determining equivalent SQL and assembler data types


Table 7 describes the SQL data type, and base SQLTYPE and SQLLEN values, that
the precompiler uses for the host variables it finds in SQL statements. If a host
variable appears with an indicator variable, the SQLTYPE is the base SQLTYPE
plus 1.
Table 7. SQL data types the precompiler uses for assembler declarations
Assembler Data SQLTYPE SQLLEN SQL Data Type
Type of Host of Host
Variable Variable
DS HL2 500 2 SMALLINT
DS FL4 496 4 INTEGER
DS P’value’ 484 p in byte 1, DECIMAL(p,s)
DS PLn’value’ or s in byte 2
DS PLn See the description for DECIMAL(p,s) in
1<=n<=16 Table 8 on page 115.
DS EL4 480 4 REAL or FLOAT (n)
DS EHL4 1<=n<=21
DS EBL4
DS DL8 480 8 DOUBLE PRECISION,
DS DHL8 or FLOAT (n)
DS DBL8 22<=n<=53
DS CLn 452 n CHAR(n)
1<=n<=255
DS HL2,CLn 448 n VARCHAR(n)
1<=n<=255
DS HL2,CLn 456 n VARCHAR(n)
n>255
DS GLm 468 n GRAPHIC(n)2
2<=m<=2541

114 Application Programming and SQL Guide


Assembler
Table 7. SQL data types the precompiler uses for assembler declarations (continued)
Assembler Data SQLTYPE SQLLEN SQL Data Type
Type of Host of Host
Variable Variable
DS HL2,GLm 464 n VARGRAPHIC(n)2
2<=m<=2541
DS HL2,GLm 472 n VARGRAPHIC(n)2
m>2541
DS FL4 972 4 Result set locator2
SQL TYPE IS 976 4 Table locator2
TABLE LIKE table-name
AS LOCATOR
SQL TYPE IS 960 4 BLOB locator2
BLOB_LOCATOR
SQL TYPE IS 964 4 CLOB locator3
CLOB_LOCATOR
SQL TYPE IS 968 4 DBCLOB locator3
DBCLOB_LOCATOR
SQL TYPE IS 404 n BLOB(n)
BLOB(n)
1≤n≤2147483647
SQL TYPE IS 408 n CLOB(n)
CLOB(n)
1≤n≤2147483647
SQL TYPE IS 412 n DBCLOB(n)2
DBCLOB(n)
1≤n≤10737418232
SQL TYPE IS ROWID 904 40 ROWID
Note:
1. m is the number of bytes.
2. n is the number of double-byte characters.
3. This data type cannot be used as a column type.

Table 8 helps you define host variables that receive output from the database. You
can use Table 8 to determine the assembler data type that is equivalent to a given
SQL data type. For example, if you retrieve TIMESTAMP data, you can use the
table to define a suitable host variable in the program that receives the data value.

| Table 8 shows direct conversions between DB2 data types and host data types.
| However, a number of DB2 data types are compatible. When you do assignments
| or comparisons of data that have compatible data types, DB2 does conversions
| between those compatible data types. See Table 1 on page 5 for information on
| compatible data types.
Table 8. SQL data types mapped to typical assembler declarations
SQL Data Type Assembler Equivalent Notes
SMALLINT DS HL2
INTEGER DS F

Chapter 9. Embedding SQL statements in host languages 115


Assembler
Table 8. SQL data types mapped to typical assembler declarations (continued)
SQL Data Type Assembler Equivalent Notes
DECIMAL(p,s) or DS P’value’ DS PLn’value’ DS p is precision; s is scale. 1<=p<=31 and 0<=s<=p.
NUMERIC(p,s) PLn 1<=n<=16. value is a literal value that includes a
decimal point. You must use Ln, value, or both. It is
recommended that you use only value.

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 1<=n<=21
DS EHL4
DS EBL41
DOUBLE PRECISION, DS DL8 22<=n<=53
DOUBLE, or FLOAT(n) DS DHL8
DS DBL81
CHAR(n) DS CLn 1<=n<=255
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 x and m are expressed in bytes. n is the number of
HL2’m’,GLx’<value>’ double-byte characters. < and > represent shift-out
and shift-in characters.
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 Use this data type only in a user-defined function or
TABLE LIKE stored procedure to receive rows of a transition table.
table-name Do not use this data type as a column type.
AS LOCATOR
BLOB locator SQL TYPE IS Use this data type only to manipulate data in BLOB
BLOB_LOCATOR columns. Do not use this data type as a column type.
CLOB locator SQL TYPE IS Use this data type only to manipulate data in CLOB
CLOB_LOCATOR columns. Do not use this data type as a column type.
DBCLOB locator SQL TYPE IS Use this data type only to manipulate data in DBCLOB
DBCLOB_LOCATOR columns. Do not use this data type as a column type.

116 Application Programming and SQL Guide


Assembler
Table 8. SQL data types mapped to typical assembler declarations (continued)
SQL Data Type Assembler Equivalent Notes
BLOB(n) SQL TYPE IS 1≤n≤2147483647
BLOB(n)
CLOB(n) SQL TYPE IS 1≤n≤2147483647
CLOB(n)
DBCLOB(n) SQL TYPE IS n is the number of double-byte characters.
DBCLOB(n) 1≤n≤1073741823
ROWID SQL TYPE IS ROWID
Note:
1. IEEE floating point host variables are not supported in user-defined functions and stored procedures.

Notes on assembler variable declaration and usage


You should be aware of the following 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
System/390 floating point format. However, your host variable data can be in
System/390 floating point format or IEEE floating point format. DB2 uses the
FLOAT(S390|IEEE) precompiler option to determine whether your floating point host
variables are in IEEE floating point format or System/390 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 as well as SQL data types. You cannot use locators as column
types. For information on how to use these data types, see the following sections:
Table locator “Accessing transition tables in a user-defined function or stored
procedure” on page 279
LOB locators “Chapter 13. Programming for large objects (LOBs)” on page 229

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.

Chapter 9. Embedding SQL statements in host languages 117


Assembler
Determining compatibility of SQL and assembler data types
Assembler host variables used in SQL statements must be type compatible with the
columns with which you intend to use them.
v Numeric data types are compatible with each other: A SMALLINT, INTEGER,
DECIMAL, or FLOAT column is compatible with a numeric assembler host
variable.
v Character data types are compatible with each other: A CHAR, VARCHAR, or
CLOB column is compatible with a fixed-length or varying-length assembler
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.
| – 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: A GRAPHIC, VARGRAPHIC,
or DBCLOB column is compatible with a fixed-length or varying-length assembler
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 Datetime data types are compatible with character host variables. A DATE, TIME,
or TIMESTAMP column is compatible with a fixed-length or varying-length
assembler character host variable.
| v A BLOB column or a BLOB locator is compatible only with a BLOB 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. For information on assigning
and comparing distinct types, see “Chapter 15. Creating and using distinct types”
on page 301.

When necessary, DB2 automatically converts a fixed-length string to a


varying-length string, or a varying-length string to a fixed-length string.

118 Application Programming and SQL Guide


Assembler
Using indicator variables
An indicator variable is a 2-byte integer (DS HL2). If you provide an indicator
variable for the variable X, then 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, then 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. For
more information on indicator variables, see “Using indicator variables with host
variables” on page 70 or Chapter 2 of DB2 SQL Reference.

Example:

Given the statement:


EXEC SQL FETCH CLS_CURSOR INTO :CLSCD, X
:DAY :DAYIND, X
:BGN :BGNIND, X
:END :ENDIND

You can declare variables as follows:


CLSCD DS CL7
DAY DS HL2
BGN DS CL8
END DS CL8
DAYIND DS HL2 INDICATOR VARIABLE FOR DAY
BGNIND DS HL2 INDICATOR VARIABLE FOR BGN
ENDIND DS HL2 INDICATOR VARIABLE FOR END

The following figure shows the syntax for a valid indicator variable.

 variable-name DC H 
DS 1 L2

Figure 32. Indicator variable

Handling SQL error return codes


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
“Handling SQL error return codes” on page 76.

DSNTIAR syntax
CALL DSNTIAR,(sqlca, message, lrecl),MF=(E,PARM)

The DSNTIAR parameters have the following meanings:

Chapter 9. Embedding SQL statements in host languages 119


Assembler
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 EQU 10
LRECL EQU 132
.
.
.

MESSAGE DS H,CL(LINES*LRECL)
ORG MESSAGE
MESSAGEL DC AL2(LINES*LRECL)
MESSAGE1 DS CL(LRECL) text line 1
MESSAGE2 DS CL(LRECL) text line 2
.
.
.

MESSAGEn DS CL(LRECL) text line n


.
.
.

CALL DSNTIAR,(SQLCA, MESSAGE, LRECL),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 MVS macro parameter that indicates dynamic


execution. PARM is the name of a data area that contains a list of pointers to
DSNTIAR’s call parameters.

An example of calling DSNTIAR from an application appears in the DB2 sample


assembler program DSNTIAD, contained in the library prefix.SDSNSAMP. See
“Appendix B. Sample applications” on page 833 for instructions on how to access
and print the source code for the sample program.

120 Application Programming and SQL Guide


Assembler

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.
eib EXEC interface block
commarea communication area

For more information on these new 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.

Macros for assembler applications


Data set DSN710.SDSNMACS contains all DB2 macros available for use.

Coding SQL statements in a C or a C⁺⁺ application


This section helps you with the programming techniques that are unique to coding
SQL statements within a C or C⁺⁺ program. Throughout this book, C is used to
represent either C/370™ or C⁺⁺, except where noted otherwise.

Defining the SQL communication area


A C program that contains SQL statements must include one or both of the
following host variables:
v An SQLCODE variable declared as long integer. For example:
long SQLCODE;
v An SQLSTATE variable declared as a character array of length 6. For example:
char SQLSTATE[6];
Or,
v An SQLCA, which contains the SQLCODE and SQLSTATE variables.

DB2 sets the SQLCODE and SQLSTATE values after each SQL statement
executes. An application can check these variable 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.

Chapter 9. Embedding SQL statements in host languages 121


C
Whether you define SQLCODE or SQLSTATE host variables, or an SQLCA, in your
program depends on whether you specify the precompiler option STDSQL(YES) to
conform to SQL standard, or STDSQL(NO) to conform to DB2 rules.

If you specify STDSQL(YES)


When you use 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 and SQLSTATE within the statements
BEGIN DECLARE SECTION and END DECLARE SECTION in your program
declarations.

If you specify STDSQL(NO)


When you use the precompiler option STDSQL(NO), include an SQLCA explicitly.
You can code the SQLCA in a C program either directly or by using the SQL
INCLUDE statement. The SQL INCLUDE requests a standard SQLCA declaration:
EXEC SQL INCLUDE SQLCA;

A standard declaration includes both a structure definition and a static data area
named 'sqlca'. See Chapter 5 of DB2 SQL Reference for more information about
the INCLUDE statement and Appendix C of DB2 SQL Reference for a complete
description of SQLCA fields.

Defining SQL descriptor areas


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
v DESCRIBE TABLE host-variable INTO descriptor-name
v EXECUTE...USING DESCRIPTOR descriptor-name
v FETCH...USING DESCRIPTOR descriptor-name
v OPEN...USING DESCRIPTOR descriptor-name
v PREPARE...INTO descriptor-name

Unlike the SQLCA, more than one SQLDA can exist in a program, and an SQLDA
can have any valid name. You can code an SQLDA in a C program either directly or
by using the SQL INCLUDE statement. The SQL INCLUDE statement requests a
standard SQLDA declaration:
EXEC SQL INCLUDE SQLDA;

A standard declaration includes only a structure definition with the name 'sqlda'.
See Chapter 5 of DB2 SQL Reference for more information about the INCLUDE
statement and Appendix C of DB2 SQL Reference for a complete description of
SQLDA fields.

You must place SQLDA declarations before the first SQL statement that references
the data descriptor, unless you use the precompiler option TWOPASS. You can
place an SQLDA declaration wherever C allows a structure definition. Normal C
scoping rules apply.

122 Application Programming and SQL Guide


C
Embedding SQL statements
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
semi-colon (;). The EXEC and SQL keywords must appear all 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 SQL words.
# However, if you use the FOLD precompiler suboption, DB2 folds lowercase letters
# in SBCS SQL ordinary identifiers to uppercase. For information on host language
# precompiler options, see Table 48 on page 403.

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:
EXEC SQL
UPDATE DSN8710.DEPT
SET MGRNO = :mgr_num
WHERE DEPTNO = :int_dept;

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 cannot nest comments.

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. You can include SQL comments in any
embedded SQL statement if you specify the precompiler option STDSQL(YES).

Continuation for SQL statements: You can use a backslash to continue a


character-string constant or delimited identifier on the following line.

Declaring tables and views: Your C program should use 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. For details, see “Chapter 8. Generating declarations for your tables
using DCLGEN” on page 95.

Including code: To include SQL statements or C host variable declarations from a


member of a partitioned data set, add the following SQL statement in the source
code where you want to embed the statements:
EXEC SQL INCLUDE member-name;

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.

Names: You can use any valid C name for a host variable, subject to the following
restrictions:

Chapter 9. Embedding SQL statements in host languages 123


C
v Do not use DBCS characters.
v Do not use external entry names or access plan names that begin with 'DSN'
and host variable 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 which 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 nonnull values
and denotes the absence of a (nonnull) value. In this chapter, NUL is the null
character in C and NULL is the SQL null value.

Sequence numbers: The source statements that the DB2 precompiler generates
do not include sequence numbers.

Statement labels: You can precede SQL statements with a label, if you wish.

Trigraphs: 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 trigraphs that DB2 supports are
the same as those that the C/370 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 Use of the C/370 multi-tasking facility, where multiple tasks execute SQL
statements, causes unpredictable results.
v You must run the DB2 precompiler before running the C preprocessor.
v The 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.
Please refer to the appropriate C documentation for further information on C
preprocessor directives.

Using host variables


You must explicitly declare each host variable before its first use in an SQL
statement if you specify the ONEPASS precompiler option. If you use the
precompiler option TWOPASS, you must declare each host variable before its first
use in the statement DECLARE CURSOR.

Precede C statements that define the host variables with the statement BEGIN
DECLARE SECTION, and follow the C statements with the statement END
DECLARE SECTION. You can have more than one host variable declaration
section in your program.

A colon (:) must precede all host variables in an SQL statement.

The names of host variables must be unique within the program, even if the host
variables are in different blocks, classes, or procedures. You can qualify the host
variable names with a structure name to make them unique.

124 Application Programming and SQL Guide


C
An SQL statement that uses a host variable must be within the scope of that
variable.

Host variables must be scalar variables or host structures; they cannot be elements
of vectors or arrays (subscripted variables) unless you use the character arrays to
hold strings. You can use an array of indicator variables when you associate the
array with a host structure.

Declaring host variables


Only some of the valid C 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 following figure shows the syntax for valid numeric
host variable declarations.

 float 
auto const double
extern volatile int
static short
sqlint32
int
long
decimal ( integer )
, integer

  variable-name ; 
=expression

Figure 33. Numeric host variables

Character host variables: There are four valid forms for character host variables:
v Single-character form
v NUL-terminated character form
v VARCHAR structured form
v CLOBs

The following figures show the syntax for forms other than CLOBs. See Figure 42
on page 129 for the syntax of CLOBs.

 char  variable-name ; 
auto const unsigned =expression
extern volatile
static
Figure 34. Single-character form

Chapter 9. Embedding SQL statements in host languages 125


C

 char 
auto const unsigned
extern volatile
static

  variable-name [ length ] ; 
=expression

Figure 35. NUL-terminated character form

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).

int
 struct { short var-1 ; 
auto const tag
extern volatile
static
 char var-2 [ length ] ; } 
unsigned

  variable-name ; 
={ expression, expression }

Figure 36. VARCHAR structured form

Notes:
v var-1 and var-2 must be simple variable references. You cannot use them as host
variables.
v You can use the struct tag to define other data areas, which you cannot use as
host variables.

Example:
EXEC SQL BEGIN DECLARE SECTION;

/* valid declaration of host variable vstring */

struct VARCHAR {
short len;
char s[10];
} vstring;

/* invalid declaration of host variable wstring */

struct VARCHAR wstring;

Graphic host variables: There are four valid forms for graphic host variables:

126 Application Programming and SQL Guide


C
v Single-graphic form
v NUL-terminated graphic form
v VARGRAPHIC structured form.
v DBCLOBs

You can use the C data type wchar_t to define a host variable that inserts, updates,
deletes, and selects data from GRAPHIC or VARGRAPHIC columns.

The following figures show the syntax for forms other than DBCLOBs. See
Figure 42 on page 129 for the syntax of DBCLOBs.

 wchar_t  variable-name ; 
auto const =expression
extern volatile
static
Figure 37. Single-graphic form

The single-graphic form declares a fixed-length graphic string of length 1. You


cannot use array notation in variable-name.

 wchar_t  variable-name [ length ] ; 


auto const =expression
extern volatile
static
Figure 38. Nul-terminated graphic form

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.

int
 struct { short var-1 ; 
auto const tag
extern volatile
static
,

 wchar_t var-2 [ length ] ; }  variable-name ; 


={ expression,expression }

Figure 39. VARGRAPHIC structured form

Notes:

Chapter 9. Embedding SQL statements in host languages 127


C
v length must be a decimal integer constant greater than 1 and not greater than
16352.
v var-1 must be less than or equal to length.
v var-1 and var-2 must be simple variable references. You cannot use them as host
variables.
v You can use the struct tag to define other data areas, which you cannot use as
host variables.

Example:
EXEC SQL BEGIN DECLARE SECTION;

/* valid declaration of host variable vgraph */

struct VARGRAPH {
short len;
wchar_t d[10];
} vgraph;

/* invalid declaration of host variable wgraph */

struct VARGRAPH wgraph;

Result set locators: The following figure shows the syntax for declarations of result
set locators. See “Chapter 24. Using stored procedures for client/server processing”
on page 527 for a discussion of how to use these host variables.

 SQL TYPE IS RESULT_SET_LOCATOR VARYING 


auto const
extern volatile
static
register

  variable-name ; 
= init-value

Figure 40. Result set locators

Table Locators: The following figure shows the syntax for declarations of table
locators. See “Accessing transition tables in a user-defined function or stored
procedure” on page 279 for a discussion of how to use these host variables.

128 Application Programming and SQL Guide


C

 SQL TYPE IS TABLE LIKE table-name AS LOCATOR 


auto const
extern volatile
static
register

  variable-name ; 
init-value

Figure 41. Table locators

LOB Variables and Locators: The following figure shows the syntax for
declarations of BLOB, CLOB, and DBCLOB host variables and locators. See
“Chapter 13. Programming for large objects (LOBs)” on page 229 for a discussion of
how to use these host variables.

 SQL TYPE IS 
auto const
extern volatile
static
register

 BINARY LARGE OBJECT ( length )  variable-name ; 


BLOB K init-value
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR
Figure 42. LOB variables and locators

ROWIDs: The following figure shows the syntax for declarations of ROWID
variables. See “Chapter 13. Programming for large objects (LOBs)” on page 229 for
a discussion of how to use these host variables.

 variable-name SQL TYPE IS ROWID ; 


auto const
extern volatile
static
register

Figure 43. ROWID variables

Using host structures


A C host structure contains an ordered group of data fields. For example:

Chapter 9. Embedding SQL statements in host languages 129


C
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 figure shows the syntax for valid host structures.

 struct { 
auto const packed tag
extern volatile
static

  float var-1 ; } 
double
int
short
sqlint32
int
long
decimal ( integer )
, integer
varchar structure
vargraphic structure
SQL TYPE IS ROWID
LOB data type
char var-2 ;
unsigned [ length ]
wchar_t var-5 ;
[ length ]

 variable-name ; 
= expression

Figure 44. Host structures

int
 struct { short var-3 ; 
tag signed
 char var-4 [ length ] ; } 
unsigned

Figure 45. varchar-structure

130 Application Programming and SQL Guide


C

int
 struct { short var-6 ; wchar_t var-7 [ length ] ; } 
tag signed

Figure 46. VARGRAPHIC-structure

 SQL TYPE IS BINARY LARGE OBJECT ( length ) 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR

Figure 47. LOB data type

Determining equivalent SQL and C data types


Table 9 describes the SQL data type, and base SQLTYPE and SQLLEN values, that
the precompiler uses for the host variables it finds in SQL statements. If a host
variable appears with an indicator variable, the SQLTYPE is the base SQLTYPE
plus 1.
Table 9. SQL data types the precompiler uses for C declarations
C Data Type SQLTYPE of SQLLEN of SQL Data Type
Host Host
Variable Variable
short int 500 2 SMALLINT
long int 496 4 INTEGER
1
decimal(p,s) 484 p in byte 1, DECIMAL(p,s)1
s in byte 2
float 480 4 FLOAT (single precision)
double 480 8 FLOAT (double precision)
Single-character 452 1 CHAR(1)
form
NUL-terminated 460 n VARCHAR (n-1)
character form
VARCHAR structured 448 n VARCHAR(n)
form
1<=n<=255
VARCHAR structured 456 n VARCHAR(n)
form
n>255
Single-graphic 468 1 GRAPHIC(1)
form
NUL-terminated 400 n VARGRAPHIC (n-1)
graphic form
(wchar_t)

Chapter 9. Embedding SQL statements in host languages 131


C
Table 9. SQL data types the precompiler uses for C declarations (continued)
C Data Type SQLTYPE of SQLLEN of SQL Data Type
Host Host
Variable Variable
VARGRAPHIC 464 n VARGRAPHIC(n)
structured form
1<=n<128
VARGRAPHIC 472 n VARGRAPHIC(n)
structured form
n>127
SQL TYPE IS 972 4 Result set locator2
RESULT_SET_LOCATOR
SQL TYPE IS 976 4 Table locator2
TABLE LIKE
table-name
AS LOCATOR
SQL TYPE IS 960 4 BLOB locator2
BLOB_LOCATOR
SQL TYPE IS 964 4 CLOB locator2
CLOB_LOCATOR
SQL TYPE IS 968 4 DBCLOB locator2
DBCLOB_LOCATOR
SQL TYPE IS 404 n BLOB(n)
BLOB(n)
1≤n≤2147483647
SQL TYPE IS 408 n CLOB(n)
CLOB(n)
1≤n≤2147483647
SQL TYPE IS DBCLOB(n) 412 n DBCLOB(n)3
1≤n≤1073741823
SQL TYPE IS ROWID 904 40 ROWID
Notes:
1. p is the precision in SQL terminology which is the total number of digits. In C this is called the size.
s is the scale in SQL terminology which is the number of digits to the right of the decimal point. In C, this is called
the precision.
2. Do not use this data type as a column type.
3. n is the number of double-byte characters.

Table 10 on page 133 helps you define host variables that receive output from the
database. You can use the table to determine the C data type that is equivalent to a
given SQL data type. For example, if you retrieve TIMESTAMP data, you can use
the table to define a suitable host variable in the program that receives the data
value.

| Table 10 on page 133 shows direct conversions between DB2 data types and host
| data types. However, a number of DB2 data types are compatible. When you do
| assignments or comparisons of data that have compatible data types, DB2 does
| conversions between those compatible data types. See Table 1 on page 5 for
| information on compatible data types.

132 Application Programming and SQL Guide


C
Table 10. SQL data types mapped to typical C declarations
SQL C Data Type Notes
Data Type
SMALLINT short int
INTEGER long int
DECIMAL(p,s) decimal You can use the double data type if your C
or compiler does not have a decimal data
NUMERIC(p,s) type; however, double is not an exact
equivalent.
REAL or float 1<=n<=21
FLOAT(n)
DOUBLE PRECISION double 22<=n<=53
or FLOAT(n)
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
(\0\0), 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.
DATE 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.
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.

Chapter 9. Embedding SQL statements in host languages 133


C
Table 10. SQL data types mapped to typical C declarations (continued)
SQL C Data Type Notes
Data Type
TIMESTAMP 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 Use this data type only for receiving result
RESULT_SET_LOCATOR sets. Do not use this data type as a
column type.
Table locator SQL TYPE IS Use this data type only in a user-defined
TABLE LIKE table-name function or stored procedure to receive
AS LOCATOR rows of a transition table. Do not use this
data type as a column type.
BLOB locator SQL TYPE IS Use this data type only to manipulate data
BLOB_LOCATOR in BLOB columns. Do not use this data
type as a column type.
CLOB locator SQL TYPE IS Use this data type only to manipulate data
CLOB_LOCATOR in CLOB columns. Do not use this data
type as a column type.
DBCLOB locator SQL TYPE IS Use this data type only to manipulate data
DBCLOB_LOCATOR in DBCLOB columns. Do not use this data
type as a column type.
BLOB(n) SQL TYPE IS 1≤n≤2147483647
BLOB(n)
CLOB(n) SQL TYPE IS 1≤n≤2147483647
CLOB(n)
DBCLOB(n SQL TYPE IS n is the number of double-byte characters.
DBCLOB(n) 1≤n≤1073741823
ROWID SQL TYPE IS ROWID

Notes on C variable declaration and usage


You should be aware of the following 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
the pointer.

SQL data types with no C equivalent: If your C compiler does not have a decimal
data type, then there is no exact equivalent 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. Hence, 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 get a string
representation of a decimal number.

134 Application Programming and SQL Guide


C
v The DECIMAL function to explicitly convert a value to a decimal data type, as in
this example:
long duration=10100; /* 1 year and 1 month */
char result_dt[11];

EXEC SQL SELECT START_DATE + DECIMAL(:duration,8,0)


INTO :result_dt FROM TABLE1;

Floating point host variables: All floating point data is stored in DB2 in
System/390 floating point format. However, your host variable data can be in
System/390 floating point format or IEEE floating point format. DB2 uses the
FLOAT(S390|IEEE) precompiler option to determine whether your floating point host
variables are in IEEE floating point or System/390 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 in user-defined function: The SQLUDF file, which is in


| data set DSN710.SDSNC.H, contains many data declarations for C language
| user-defined functions. SQLUDF contains the typedef sqldbchar, which you can use
| instead of wchar_t. Using sqldbchar 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.

Special Purpose C Data Types: The locator data types are C data types as well
as SQL data types. You cannot use locators as column types. For information on
how to use these data types, see the following sections:
Result set locator
“Chapter 24. Using stored procedures for client/server processing”
on page 527
Table locator “Accessing transition tables in a user-defined function or stored
procedure” on page 279
LOB locators “Chapter 13. Programming for large objects (LOBs)” on page 229

String host variables:

If you assign a string of length n to a NUL-terminated variable with a length that is:
v less than or equal to n, then DB2 inserts the characters into the host variable as
long as the characters fit up to length (n-1) and appends a NUL at the end of the
string. DB2 sets SQLWARN[1] to W and any indicator variable you provide to the
original length of the source string.
v equal to n+1, then DB2 inserts the characters into the host variable and appends
a NUL at the end of the string.
v greater than n+1, then the rules depend on whether the source string is a value
of a fixed-length string column or a varying-length string column. See Chapter 2
of DB2 SQL Reference for more information.

PREPARE or DESCRIBE statements: You cannot use a host variable that is of the
NUL-terminated form in either a PREPARE or DESCRIBE statement.

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.

Chapter 9. Embedding SQL statements in host languages 135


C
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 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


You should be aware of the following syntax differences for constants.

Decimal constants versus REAL (floating) 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 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 quotes have different meanings in C and SQL. In C,
you can use quotes to delimit string constants, and apostrophes to delimit character
constants. The following examples illustrate the use of quotes and apostrophes in
C.
Quotes
printf( "%d lines read. \n", num_lines);
Apostrophes
#define NUL '\0'

In SQL, you can use quotes to delimit identifiers and apostrophes to delimit string
constants. The following examples illustrate the use of apostrophes and quotes in
SQL.
Quotes
SELECT "COL#1" FROM TBL1;
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.

Determining compatibility of SQL and C data types


C host variables used in SQL statements must be type compatible with the columns
with which you intend to use them:

136 Application Programming and SQL Guide


C
v Numeric data types are compatible with each other: A SMALLINT, INTEGER,
DECIMAL, or FLOAT column is compatible with any C host variable defined as
type short int, long int, decimal, float, or double.
v Character data types are compatible with each other: A CHAR, VARCHAR, or
CLOB column is compatible with a single character, NUL-terminated, or
VARCHAR structured form of a C 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.
| – 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. A GRAPHIC, VARGRAPHIC,
or DBCLOB column is compatible with a single character, NUL-terminated, or
VARGRAPHIC structured form of a C graphic 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 Datetime data types are compatible with character host variables: A DATE, TIME,
or TIMESTAMP column is compatible with a single-character, NUL-terminated, or
VARCHAR structured form of a C character host variable.
| v A BLOB column or a BLOB locator is compatible only with a BLOB 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. For information on assigning
and comparing distinct types, see “Chapter 15. Creating and using distinct types”
on page 301.

When necessary, DB2 automatically converts a fixed-length string to a


varying-length string, or a varying-length string to a fixed-length string.

Varying-length strings: For varying-length BIT data, use the VARCHAR structured
form. Some C string manipulation functions process NUL-terminated strings and

Chapter 9. Embedding SQL statements in host languages 137


C
others process strings that are not NUL-terminated. The C string manipulation
functions that process NUL-terminated strings cannot handle bit data; the functions
might misinterpret a NUL character to be a NUL-terminator.

Using indicator variables


An indicator variable is a 2-byte integer (short int). If you provide an indicator
variable for the variable X, then 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, then 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. For
more information about indicator variables, see “Using indicator variables with host
variables” on page 70.

Example:

Given the 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 a valid indicator variable.

,
int
 short  variable-name ; 
auto const signed
extern volatile
static
Figure 48. Indicator variable

The following figure shows the syntax for a valid indicator array.

138 Application Programming and SQL Guide


C

int
 short 
auto const signed
extern volatile
static
,

  variable-name [ dimension ] ; 
= expression

Figure 49. Host structure indicator array

Note:

Dimension must be an integer constant between 1 and 32767.

Handling SQL error return codes


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
“Handling SQL error return codes” on page 76.

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);

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 length of each line.
&lrecl
A fullword containing the logical record length of output messages, between 72
and 240.

Chapter 9. Embedding SQL statements in host languages 139


C
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 DSN8710.SDSNSAMP. See “Appendix B. Sample applications” on page 833
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:
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 new 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.

Considerations for C⁺⁺


When you code SQL in a C⁺⁺ program, be aware of the following:

Using C⁺⁺ data types as host variables: You can use class members as host
variables. Class members used as host variables are accessible to any SQL
statement within the class.

You cannot use class objects as host variables.

140 Application Programming and SQL Guide


COBOL

Coding SQL statements in a COBOL application


This section helps you with the programming techniques that are unique to coding
SQL statements within a COBOL program.

Except where noted otherwise, this information pertains to all COBOL compilers
supported by DB2 for OS/390 and z/OS.

Defining the SQL communication area


A COBOL program that contains SQL statements must include one or both of the
following host variables:
v An SQLCODE variable declared as PIC S9(9) BINARY, PIC S9(9) COMP-4, PIC
S9(9) COMP-5, or PICTURE S9(9) COMP
v An SQLSTATE variable declared as PICTURE X(5)
Or,
v An SQLCA, which contains the SQLCODE and SQLSTATE variables.

DB2 sets the SQLCODE and SQLSTATE values after each SQL statement
executes. An application can check these variables value 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 SQLCODE or SQLSTATE, or an SQLCA, in your program


depends on whether you specify the precompiler option STDSQL(YES) to conform
to SQL standard, or STDSQL(NO) to conform to DB2 rules.

If you specify STDSQL(YES)


When you use 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.

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 that SQLCA, so your application
programs should not make assumptions about its structure or location.

If you declare an SQLSTATE variable, it must not be an element of a structure. You


must declare the host variables SQLCODE and SQLSTATE within the statements
BEGIN DECLARE SECTION and END DECLARE SECTION in your program
declarations.

If you specify STDSQL(NO)


When you use the precompiler option STDSQL(NO), include an SQLCA explicitly.
You can code the SQLCA in a COBOL program either directly or by using the SQL
INCLUDE statement. The SQL INCLUDE statement requests a standard SQLCA
declaration:
EXEC SQL INCLUDE SQLCA END-EXEC.

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. You can declare a stand-alone SQLCODE variable in either the
WORKING-STORAGE SECTION or LINKAGE SECTION.

Chapter 9. Embedding SQL statements in host languages 141


COBOL
See Chapter 5 of DB2 SQL Reference for more information about the INCLUDE
statement and Appendix C of DB2 SQL Reference for a complete description of
SQLCA fields.

Defining SQL descriptor areas


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
v DESCRIBE TABLE host-variable INTO descriptor-name
v EXECUTE...USING DESCRIPTOR descriptor-name
v FETCH...USING DESCRIPTOR descriptor-name
v OPEN...USING DESCRIPTOR descriptor-name
v PREPARE...INTO descriptor-name

Unlike the SQLCA, there can be more than one SQLDA in a program, and an
SQLDA can have any valid name. The DB2 SQL INCLUDE statement does not
provide an SQLDA mapping for COBOL. You can define the SQLDA using one of
the following two methods:
v For COBOL programs compiled with any compiler except the OS/VS COBOL
compiler, you can code the SQLDA declarations in your program. For more
information, see “Using dynamic SQL in COBOL” on page 526. 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.
v For COBOL programs compiled with any COBOL compiler, you can call a
subroutine (written in C, PL/I, or assembler language) that uses the DB2
INCLUDE SQLDA statement to define the SQLDA. The subroutine can also
include SQL statements for any dynamic SQL functions you need. You must use
this method if you compile your program using OS/VS COBOL. The SQLDA
definition includes the POINTER data type, which OS/VS COBOL does not
support. For more information on using dynamic SQL, see “Chapter 23. Coding
dynamic SQL in application programs” on page 497.

You must place SQLDA declarations before the first SQL statement that references
the data descriptor. An SQL statement that uses a host variable must be within the
scope of the statement that declares the variable.

Embedding SQL statements


You can code SQL statements in the COBOL program sections shown in Table 11.
Table 11. Allowable SQL statements for COBOL program sections
SQL Statement Program Section
BEGIN DECLARE SECTION WORKING-STORAGE SECTION
END DECLARE SECTION or LINKAGE SECTION
INCLUDE SQLCA WORKING-STORAGE SECTION
or LINKAGE SECTION
INCLUDE text-file-name PROCEDURE DIVISION or DATA DIVISION1
DECLARE TABLE DATA DIVISION or PROCEDURE DIVISION
DECLARE CURSOR
Other PROCEDURE DIVISION

142 Application Programming and SQL Guide


COBOL
Table 11. Allowable SQL statements for COBOL program sections (continued)
SQL Statement Program Section
1
Note: 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 the SQL statement appears between two COBOL statements,
the period is optional and might not be appropriate. If the statement appears in an
IF...THEN set of COBOL statements, leave off the ending period to avoid
inadvertently ending the IF statement. 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 a COBOL program as follows:


EXEC SQL
UPDATE DSN8710.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, except between the keywords EXEC and
SQL. The precompiler also treats COBOL debugging and page eject lines (D or / in
column 7) as comment lines. For an SQL INCLUDE statement, DB2 treats any text
that follows the period after END-EXEC and is on the same line as END-EXEC as a
comment.

In addition, you can include SQL comments in any embedded SQL statement if you
specify the precompiler option STDSQL(YES).

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 quotation mark 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 quotation mark as the first nonblank character in area B of
the continuation line for a character string constant.

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
details, see “Chapter 8. Generating declarations for your tables using DCLGEN” on
page 95.

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

Chapter 9. Embedding SQL statements in host languages 143


COBOL
to use variable-list SELECT statements, use an SQLDA. See “Defining SQL
descriptor areas” on page 142 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.

You cannot nest SQL INCLUDE statements. Do not use COBOL verbs to include
SQL statements or COBOL host variable declarations, or use the SQL INCLUDE
statement to include CICS preprocessor related code. In general, use the SQL
INCLUDE only for SQL-related coding.

Margins: Code SQL statements in columns 12 through 72. If EXEC SQL starts
before column 12, the DB2 precompiler does not recognize the SQL statement.

The precompiler option MARGINS allows you to set new left and right margins
between 1 and 80. However, you must not code the statement EXEC SQL before
column 12.

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 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. If
you then compile the COBOL program using OS/VS COBOL, the compiler issues
messages IKF3002I and IKF3004I. If you compile the program using VS COBOL
II or later compilers, you can eliminate these messages.
v Use of the COBOL compiler options DYNAM and NODYNAM depends on the
operating environment.

144 Application Programming and SQL Guide


COBOL

TSO and IMS

You can specify the option DYNAM when compiling a COBOL program if
you use VS COBOL II or COBOL/370™, or if you use OS/VS COBOL with
the VS COBOL II or COBOL/370 run-time libraries.

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 and CAF

You must specify the option NODYNAM when you compile a COBOL
program that includes SQL statements. You cannot use DYNAM.

Because stored procedures use CAF, you must also compile COBOL stored
procedures with the option NODYNAM.

v To avoid truncating numeric values, specify the COBOL compiler option:


– 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 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 COBOL binary integer host variables as if you had
specified the COBOL compiler option TRUNC(BIN).
v If a 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 The REPLACE statement has no effect on SQL statements. It affects only the
COBOL statements that the precompiler generates.
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 in Chapter 2 of DB2 SQL Reference when you name SQL
# identifiers. 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.

Chapter 9. Embedding SQL statements in host languages 145


COBOL
– You can use hyphens in SQL identifiers under either of the following
circumstances:
- The application program is a local application that runs on DB2 UDB for
OS/390 Version 6 or later.
- The application program accesses remote sites, and the local site and
remote sites are DB2 UDB for OS/390 Version 6 or later.
v If you include an SQL statement in a COBOL PERFORM ... THRU paragraph and
also specify the SQL statement WHENEVER ... GO, then the COBOL compiler
returns the warning message IGYOP3094. That message might indicate a
problem, depending on the intention behind the code. The usage is not advised.
v If you are using VS COBOL II or COBOL/370 with the option NOCMPR2, then
the following additional restrictions apply:
– All SQL statements and any host variables they reference must be within the
first program when using nested programs or batch compilation.
– DB2 COBOL programs must have a DATA DIVISION and a PROCEDURE
DIVISION. Both divisions and the WORKING-STORAGE section must be
present in programs that use the DB2 precompiler.

Product-sensitive Programming Interface

If you pass host variables with address changes into a program more than once,
then the called program must reset SQL-INIT-FLAG. 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.
End of Product-sensitive Programming Interface

Using host variables


You must explicitly declare all host variables 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 before its first use in an
SQL statement.

You can precede COBOL statements that define the host variables with the
statement BEGIN DECLARE SECTION, and follow the statements with the
statement END DECLARE SECTION. You must use the statements BEGIN
DECLARE SECTION and END DECLARE SECTION when you use the precompiler
option STDSQL(YES).

A colon (:) must precede all host variables in an SQL statement.

The names of host variables should be unique within the source data set or
member, even if the host variables are in different blocks, classes, or procedures.
You can qualify the host variable names with a structure name to make them
unique.

An SQL statement that uses a host variable must be within the scope of the
statement that declares the variable.

You cannot define host variables, other than indicator variables, as arrays. You can
specify OCCURS only when defining an indicator structure. You cannot specify
OCCURS for any other type of host variable.

146 Application Programming and SQL Guide


COBOL
Declaring host 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 following figures show the syntax for valid numeric
host variable declarations.

 01 variable-name COMPUTATIONAL-1 
77 IS COMP-1
level-1 USAGE COMPUTATIONAL-2
COMP-2

 . 
IS
VALUE numeric-constant

Figure 50. Numeric host variables

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.

IS
 01 variable-name PICTURE S9(4) 
77 PIC S9999 IS
level-1 S9(9) USAGE
S999999999
 BINARY . 
COMPUTATIONAL-4 IS
COMP-4 VALUE numeric-constant
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

Figure 51. Integer and small integer

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. BINARY, COMP, COMPUTATIONAL, COMPUTATIONAL-4, COMP-4 ,
COMPUTATIONAL-5, COMP-5 are equivalent.
3. Any specification for scale is ignored.

Chapter 9. Embedding SQL statements in host languages 147


COBOL

IS
 01 variable-name PICTURE picture-string 
77 PIC IS
level-1 USAGE
 PACKED-DECIMAL 
COMPUTATIONAL-3 IS
COMP-3 VALUE numeric-constant
IS CHARACTER
DISPLAY SIGN LEADING SEPARATE

 . 

Figure 52. Decimal

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 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 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).

Character host variables: There are three valid forms of character host variables:
v Fixed-length strings
v Varying-length strings
v CLOBs

The following figures show the syntax for forms other than CLOBs. See Figure 59
on page 151 for the syntax of CLOBs.

IS
 01 variable-name PICTURE picture-string 
77 PIC
level-1
 . 
DISPLAY IS
IS VALUE character-constant
USAGE

Figure 53. Fixed-length character strings

Note:

level-1 indicates a COBOL level between 2 and 48.

148 Application Programming and SQL Guide


COBOL

 01 variable-name . 
level-1

IS
 49 var-1 PICTURE S9(4) BINARY 
PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
 . 
IS
VALUE numeric-constant

IS
 49 var-2 PICTURE picture-string 
PIC DISPLAY
IS
USAGE
 . 
IS
VALUE character-constant

Figure 54. Varying-length character strings

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. The picture-string associated with these forms must be X(m) (or XX...X, with m
instances of X), with 1 <= m <= 255 for fixed-length strings; for other strings, m
cannot be greater than the maximum size of a varying-length character string.
DB2 uses the full length of the S9(4) variable even though IBM COBOL for MVS
and VM 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(OPT) or NOTRUNC COBOL compiler option (whichever is appropriate)
to avoid data truncation.
3. You cannot directly reference var-1 and var-2 as host variables.
# 4. You cannot use an intervening REDEFINE at level 49.

Graphic character host variables: There are three valid forms for graphic
character host variables:
v Fixed-length strings
v Varying-length strings
v DBCLOBs

The following figures show the syntax for forms other than DBCLOBs. See
Figure 59 on page 151 for the syntax of DBCLOBs.

Chapter 9. Embedding SQL statements in host languages 149


COBOL

IS
 01 variable-name PICTURE picture-string 
level-1 PIC
77

IS
 USAGE DISPLAY-1 

 . 
IS
VALUE graphic-constant

Figure 55. Fixed-length graphic strings

Note:

level-1 indicates a COBOL level between 2 and 48.

IS
 01 variable-name . 49 var-1 PICTURE S9(4) 
level-1 PIC S9999 IS
USAGE
 BINARY . 49 var-2 PICTURE 
COMPUTATIONAL-4 IS PIC
COMP-4 VALUE numeric-constant
COMPUTATIONAL-5
COMP-5

IS IS
 picture-string USAGE DISPLAY-1 . 
IS
VALUE graphic-constant

Figure 56. Varying-length graphic strings

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. The picture-string associated with these forms must be G(m) (or GG...G, with m
instances of G), with 1 <= m <= 127 for fixed-length strings. You can use N in
place of G for COBOL graphic variable declarations. If you use N for graphic
variable declarations, USAGE DISPLAY-1 is optional. For strings other than
fixed-length, m cannot be greater than the maximum size of a varying-length
graphic string.
DB2 uses the full size of the S9(4) variable even though some COBOL
implementations restrict the maximum length of varying-length graphic string to
9999. This can cause data truncation errors when COBOL statements execute
and might effectively limit the maximum length of variable-length graphic strings
to 9999. Consider using the TRUNC(OPT) or NOTRUNC COBOL compiler
option (which ever is appropriate) to avoid data truncation.
3. You cannot directly reference var-1 and var-2 as host variables.

150 Application Programming and SQL Guide


COBOL
Result set locators: The following figure shows the syntax for declarations of result
set locators. See “Chapter 24. Using stored procedures for client/server processing”
on page 527 for a discussion of how to use these host variables.

 01 variable-name SQL TYPE IS RESULT-SET-LOCATOR VARYING . 


IS
USAGE

Figure 57. Result set locators

Table Locators: The following figure shows the syntax for declarations of table
locators. See “Accessing transition tables in a user-defined function or stored
procedure” on page 279 for a discussion of how to use these host variables.

 01 variable-name SQL TYPE IS TABLE LIKE table-name 


level-1 IS
USAGE

 AS LOCATOR . 

Figure 58. Table locators

Note:

level-1 indicates a COBOL level between 2 and 48.

LOB Variables and Locators: The following figure shows the syntax for
declarations of BLOB, CLOB, and DBCLOB host variables and locators. See
“Chapter 13. Programming for large objects (LOBs)” on page 229 for a discussion of
how to use these host variables.

 01 variable-name SQL TYPE IS 


level-1 IS
USAGE

 BINARY LARGE OBJECT ( length ) 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB-LOCATOR
CLOB-LOCATOR
DBCLOB-LOCATOR

Figure 59. LOB variables and locators

Note:

level-1 indicates a COBOL level between 2 and 48.

Chapter 9. Embedding SQL statements in host languages 151


COBOL
ROWIDs: The following figure shows the syntax for declarations of ROWID
variables. See “Chapter 13. Programming for large objects (LOBs)” on page 229 for
a discussion of how to use these host variables.

 01 variable-name SQL TYPE IS ROWID . 


level-1 IS
USAGE

Figure 60. ROWID variables

Note:

level-1 indicates a COBOL level between 2 and 48.

Using host structures


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 precompiler does not recognize host variables or host structures on any
subordinate levels after one of these items:
v A COBOL item that must begin in area A
v Any SQL statement (except SQL INCLUDE)
v Any SQL statement within an included member

When the precompiler encounters one of the above items in a host structure, it
therefore considers the structure to be complete.

Figure 61 on page 153 shows the syntax for valid host structures.

152 Application Programming and SQL Guide


COBOL

 level-1 variable-name . 

  level-2 var-1 COMPUTATIONAL-1 . 


IS COMP-1
USAGE COMPUTATIONAL-2
COMP-2
IS
PICTURE usage-clause .
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

Figure 61. Host structures in COBOL

 BINARY 
IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP
PACKED-DECIMAL
COMPUTATIONAL-3
COMP-3
IS
DISPLAY SIGN LEADING SEPARATE
CHARACTER

 
IS
VALUE constant

Figure 62. Usage-clause

Chapter 9. Embedding SQL statements in host languages 153


COBOL

IS
 PICTURE picture-string 
PIC DISPLAY
IS
USAGE
 
IS
VALUE constant

Figure 63. CHAR-inner-variable

IS
 49 var-2 PICTURE S9(4) BINARY 
PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP
IS
 . 49 var-3 PICTURE picture-string 
IS PIC
VALUE numeric-constant
 . 
DISPLAY IS
IS VALUE constant
USAGE

Figure 64. VARCHAR-inner-variables

IS
 49 var-4 PICTURE S9(4) BINARY 
PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP
IS
 . 49 var-5 PICTURE picture-string 
IS PIC
VALUE numeric-constant
 . 
DISPLAY-1 IS
IS VALUE graphic-constant
USAGE

Figure 65. VARGRAPHIC-inner-variables

154 Application Programming and SQL Guide


COBOL

 SQL TYPE IS BINARY LARGE OBJECT ( length ) 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB-LOCATOR
CLOB-LOCATOR
DBCLOB-LOCATOR

Figure 66. LOB data type

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.
5. You cannot use picture-string for floating point elements but must use it for other
data types.

Determining equivalent SQL and COBOL data types


Table 12 describes the SQL data type, and base SQLTYPE and SQLLEN values,
that the precompiler uses for the host variables it finds in SQL statements. If a host
variable appears with an indicator variable, the SQLTYPE is the base SQLTYPE
plus 1.
Table 12. SQL data types the precompiler uses for COBOL declarations
COBOL Data Type SQLTYPE of Host SQLLEN of Host Variable SQL Data Type
Variable
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) 484 i+d in byte 1, d in byte 2 DECIMAL(i+d,d) or
PACKED-DECIMAL NUMERIC(i+d,d)
S9(i)V9(d) DISPLAY SIGN 504 i+d in byte 1, d in byte 2 No exact equivalent. Use
LEADING SEPARATE DECIMAL(i+d,d) or
NUMERIC(i+d,d)
S9(4) COMP-4, S9(4) COMP-5, 500 2 SMALLINT
or BINARY
S9(9) COMP-4, S9(9) COMP-5, 496 4 INTEGER
or BINARY
Fixed-length character data 452 m CHAR(m)
Varying-length character data 448 m VARCHAR(m)
1<=m<=255
Varying-length character data 456 m VARCHAR(m)
m>255

Chapter 9. Embedding SQL statements in host languages 155


COBOL
Table 12. SQL data types the precompiler uses for COBOL declarations (continued)
COBOL Data Type SQLTYPE of Host SQLLEN of Host Variable SQL Data Type
Variable
Fixed-length graphic data 468 m GRAPHIC(m)
Varying-length graphic data 464 m VARGRAPHIC(m)
1<=m<=127
Varying-length graphic data 472 m VARGRAPHIC(m)
m>127
SQL TYPE IS 972 4 Result set locator1
RESULT-SET-LOCATOR
SQL TYPE IS 976 4 Table locator1
TABLE LIKE table-name
AS LOCATOR
SQL TYPE IS 960 4 BLOB locator1
BLOB-LOCATOR
SQL TYPE IS 964 4 CLOB locator1
CLOB-LOCATOR
USAGE IS 968 4 DBCLOB locator1
SQL TYPE IS
DBCLOB-LOCATOR
USAGE IS SQL TYPE IS 404 n BLOB(n)
BLOB(n) 1≤n≤2147483647
USAGE IS SQL TYPE IS 408 n CLOB(n)
CLOB(n) 1≤n≤2147483647
USAGE IS SQL TYPE IS 412 n DBCLOB(m)2
DBCLOB(m) 1≤m≤10737418232
SQL TYPE IS ROWID 904 40 ROWID
Notes:
1. Do not use this data type as a column type.
2. m is the number of double-byte characters.

Table 13 helps you define host variables that receive output from the database. You
can use the table to determine the COBOL data type that is equivalent to a given
SQL data type. For example, if you retrieve TIMESTAMP data, you can use the
table to define a suitable host variable in the program that receives the data value.

| Table 13 shows direct conversions between DB2 data types and host data types.
| However, a number of DB2 data types are compatible. When you do assignments
| or comparisons of data that have compatible data types, DB2 does conversions
| between those compatible data types. See Table 1 on page 5 for information on
| compatible data types.
Table 13. SQL data types mapped to typical COBOL declarations
SQL Data Type COBOL Data Type Notes
SMALLINT S9(4) COMP-4,
S9(4) COMP-5,
or BINARY
INTEGER S9(9) COMP-4,
S9(9) COMP-5,
or BINARY

156 Application Programming and SQL Guide


COBOL
Table 13. SQL data types mapped to typical COBOL declarations (continued)
SQL Data Type COBOL Data Type Notes
DECIMAL(p,s) or S9(p-s)V9(s) COMP-3 or p is precision; s is scale. 0<=s<=p<=31. If
NUMERIC(p,s) S9(p-s)V9(s) s=0, use S9(p)V or S9(p). If s=p, use
PACKED-DECIMAL SV9(s). If the COBOL compiler does not
DISPLAY SIGN support 31–digit decimal numbers, there is
LEADING SEPARATE no exact equivalent. Use COMP-2.
REAL or FLOAT (n) COMP-1 1<=n<=21
DOUBLE PRECISION, COMP-2 22<=n<=53
DOUBLE
or FLOAT (n)
CHAR(n) Fixed-length character string. For example, 1<=n<=255
01 VAR-NAME PIC X(n).
VARCHAR(n) Varying-length character string. For The inner variables must have a level of
example, 49.
01 VAR-NAME.
49 VAR-LEN PIC S9(4) USAGE BINARY.
49 VAR-TEXT PIC X(n).
GRAPHIC(n) Fixed-length graphic string. For example, n refers to the number
01 VAR-NAME PIC G(n) of double-byte characters, not
USAGE IS DISPLAY-1. to the number of bytes.
1<=n<=127
VARGRAPHIC(n) Varying-length graphic string. For example, n refers to the number of double-byte
01 VAR-NAME. characters, not to the number of bytes.
49 VAR-LEN PIC S9(4) USAGE BINARY.
49 VAR-TEXT PIC G(n) The inner variables must have a level of
USAGE IS DISPLAY-1. 49.

DATE Fixed-length character string of length n. If you are using a date exit routine, n is
For example, determined by that routine. Otherwise, n
01 VAR-NAME PIC X(n). must be at least 10.

TIME Fixed-length character string of length n. If you are using a time exit routine, n is
For example, determined by that routine. Otherwise, n
01 VAR-NAME PIC X(n). must be at least 6; to include seconds, n
must be at least 8.
TIMESTAMP Fixed-length character string of length of n must be at least 19. To include
length n. For example, microseconds, n must be 26; if n is less
01 VAR-NAME PIC X(n). than 26, truncation occurs on the
microseconds part.
Result set locator SQL TYPE IS Use this data type only for
RESULT-SET-LOCATOR receiving result sets.
Do not use this data type as a
column type.
Table locator SQL TYPE IS Use this data type only in a user-defined
TABLE LIKE table-name function or stored procedure to receive
AS LOCATOR rows of a transition table. Do not use this
data type as a column type.
BLOB locator USAGE IS Use this data type only to manipulate data
SQL TYPE IS in BLOB columns. Do not use this data
BLOB-LOCATOR type as a column type.
CLOB locator USAGE IS Use this data type only to manipulate data
SQL TYPE IS in CLOB columns. Do not use this data
CLOB-LOCATOR type as a column type.

Chapter 9. Embedding SQL statements in host languages 157


COBOL
Table 13. SQL data types mapped to typical COBOL declarations (continued)
SQL Data Type COBOL Data Type Notes
DBCLOB locator USAGE IS Use this data type only to manipulate data
SQL TYPE IS in DBCLOB columns. Do not use this data
DBCLOB-LOCATOR type as a column type.
BLOB(n) USAGE IS 1≤n≤2147483647
SQL TYPE IS
BLOB(n)
CLOB(n) USAGE IS SQL TYPE IS CLOB(n) 1≤n≤2147483647
DBCLOB(n) USAGE IS n is the number of double-byte characters.
SQL TYPE IS 1≤n≤1073741823
DBCLOB(n)
ROWID SQL TYPE IS ROWID

Notes on COBOL variable declaration and usage


You should be aware of the following when you declare COBOL variables.

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, then the fractional part of the
value could 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 could
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. Hence, 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.

Special Purpose COBOL Data Types: The locator data types are COBOL data
types as well as SQL data types. You cannot use locators as column types. For
information on how to use these data types, see the following sections:
Result set locator
“Chapter 24. Using stored procedures for client/server processing”
on page 527
Table locator “Accessing transition tables in a user-defined function or stored
procedure” on page 279
LOB locators “Chapter 13. Programming for large objects (LOBs)” on page 229

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 processing with the COBOL options
TRUNC(OPT) or NOTRUNC) and can place larger values in the host variable than
would be allowed in the specified number of digits in the COBOL declaration.

158 Application Programming and SQL Guide


COBOL
However, this can cause data truncation when COBOL statements execute. 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(5) COMP. 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, then 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 and VARGRAPHIC data types: If your varying-length character host


variables receive values whose length is greater than 9999 characters, compile the
applications in which you use those host variables with the option TRUNC(BIN).
TRUNC(BIN) lets the length field for the character string receive a value of up to
32767.

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 ten
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 could truncate the value.

Determining compatibility of SQL and COBOL data types


COBOL host variables used in SQL statements must be type compatible with the
columns with which you intend to use them:
v Numeric data types are compatible with each other: A SMALLINT, INTEGER,
DECIMAL, REAL, or DOUBLE PRECISION column is compatible with a COBOL
host variable of PICTURE S9(4), PICTURE S9(9), COMP-3, COMP-1, COMP-4,
COMP-5, COMP-2, BINARY, or PACKED-DECIMAL. A DECIMAL column is also
compatible with a COBOL host variable declared as DISPLAY SIGN IS LEADING
SEPARATE.
v Character data types are compatible with each other: A CHAR, VARCHAR, or
CLOB column is compatible with a fixed-length or varying-length COBOL
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.
| – 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.

Chapter 9. Embedding SQL statements in host languages 159


COBOL
v Graphic data types are compatible with each other. A GRAPHIC, VARGRAPHIC,
or DBCLOB column is compatible with a fixed-length or varying length COBOL
graphic string 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 Datetime data types are compatible with character host variables. A DATE, TIME,
or TIMESTAMP column is compatible with a fixed-length or varying length
COBOL character host variable.
| v A BLOB column or a BLOB locator is compatible only with a BLOB 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. For information on assigning
and comparing distinct types, see “Chapter 15. Creating and using distinct types”
on page 301.

When necessary, DB2 automatically converts a fixed-length string to a


varying-length string, or a varying-length string to a fixed-length string.

Using indicator variables


An indicator variable is a 2-byte integer (PIC S9(4) USAGE BINARY). If you provide
an indicator variable for the variable X, then 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, then 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. 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. For more
information about indicator variables, see “Using indicator variables with host
variables” on page 70.

Example: Given the statement:


EXEC SQL FETCH CLS_CURSOR INTO :CLS-CD,
:DAY :DAY-IND,
:BGN :BGN-IND,
:END :END-IND
END-EXEC.

160 Application Programming and SQL Guide


COBOL
You can declare the variables as follows:
77 CLS-CD PIC X(7).
77 DAY PIC S9(4) BINARY.
77 BGN PIC X(8).
77 END PIC X(8).
77 DAY-IND PIC S9(4) BINARY.
77 BGN-IND PIC S9(4) BINARY.
77 END-IND PIC S9(4) BINARY.

The following figure shows the syntax for a valid indicator variable.

IS
 01 variable-name PICTURE S9(4) BINARY 
77 PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP
 . 
IS
VALUE constant

Figure 67. Indicator variable

The following figure shows the syntax for valid indicator array declarations.

IS
 level-1 variable-name PICTURE S9(4) 
PIC S9999 IS
USAGE
 BINARY OCCURS dimension . 
COMPUTATIONAL-4 TIMES IS
COMP-4 VALUE constant
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

Figure 68. Host structure indicator array

Note: level-1 must be an integer between 2 and 48.

Handling SQL error return codes


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
“Handling SQL error return codes” on page 76.

DSNTIAR syntax
CALL ’DSNTIAR’ USING sqlca message lrecl.

Chapter 9. Embedding SQL statements in host languages 161


COBOL
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 PIC S9(4) COMP VALUE +1320.
02 ERROR-TEXT PIC X(132) OCCURS 10 TIMES
INDEXED BY ERROR-INDEX.
77
. ERROR-TEXT-LEN PIC S9(9) COMP VALUE +132.
.
.

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, contained in the library DSN8710.SDSNSAMP. See
“Appendix B. Sample applications” on page 833 for instructions on how to access
and print the source code for the sample program.

162 Application Programming and SQL Guide


COBOL

CICS

If you call DSNTIAR dynamically from a CICS VS COBOL II or CICS


COBOL/370 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

For more information on these new 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.

Considerations for object-oriented extensions in COBOL


When you use object-oriented extensions in an IBM COBOL for MVS & VM
application, be aware of the following:

Where to Place SQL Statements in Your Application: An IBM COBOL for MVS &
VM 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.

Chapter 9. Embedding SQL statements in host languages 163


COBOL
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.

Coding SQL statements in a FORTRAN application


This section helps you with the programming techniques that are unique to coding
SQL statements within a FORTRAN program.

Defining the SQL communication area


A FORTRAN program that contains SQL statements must include one or both of the
following host variables:
v An SQLCOD variable declared as INTEGER*4
v An SQLSTA (or SQLSTATE) variable declared as CHARACTER*5
Or,
v An SQLCA, which contains the SQLCOD and SQLSTA variables.

DB2 sets the SQLCOD and SQLSTA (or SQLSTATE) values after each SQL
statement executes. An application can check these variables value 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 SQLCOD and SQLSTA (or
SQLSTATE) variables.

Whether you define SQLCOD or SQLSTA (or SQLSTATE), or an SQLCA, in your


program depends on whether you specify the precompiler option STDSQL(YES) to
conform to SQL standard, or STDSQL(NO) to conform to DB2 rules.

If you specify STDSQL(YES)


When you use 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 SQLSTA (or SQLSTATE) variable, it must not be an element of a


structure. You must declare the host variables SQLCOD and SQLSTA (or
SQLSTATE) within the statements BEGIN DECLARE SECTION and END
DECLARE SECTION in your program declarations.

If you specify STDSQL(NO)


When you use the precompiler option STDSQL(NO), include an SQLCA explicitly.
You can code the SQLCA in a FORTRAN program either directly or by using the
SQL INCLUDE statement. The SQL INCLUDE statement requests a standard
SQLCA declaration:
EXEC SQL INCLUDE SQLCA

See Chapter 5 of DB2 SQL Reference for more information about the INCLUDE
statement and Appendix C of DB2 SQL Reference for a complete description of
SQLCA fields.

Defining SQL descriptor areas


The following statements require an SQLDA:
v CALL...USING DESCRIPTOR descriptor-name
v DESCRIBE statement-name INTO descriptor-name

164 Application Programming and SQL Guide


FORTRAN
v DESCRIBE CURSOR host-variable INTO descriptor-name
v DESCRIBE INPUT statement-name INTO descriptor-name
v DESCRIBE PROCEDURE host-variable INTO descriptor-name
v DESCRIBE TABLE host-variable INTO descriptor-name
v EXECUTE...USING DESCRIPTOR descriptor-name
v FETCH...USING DESCRIPTOR descriptor-name
v OPEN...USING DESCRIPTOR descriptor-name
v PREPARE...INTO descriptor-name

Unlike the SQLCA, there can be more than one SQLDA in a program, and an
SQLDA can have any valid name. DB2 does not support the INCLUDE SQLDA
statement for FORTRAN programs. If present, an error message results.

You can have a FORTRAN program call a subroutine (written in C, PL/I or


assembler language) that uses the DB2 INCLUDE SQLDA statement to define the
SQLDA and also includes the necessary SQL statements for the dynamic SQL
functions you wish to perform. See “Chapter 23. Coding dynamic SQL in application
programs” on page 497 for more information about dynamic SQL.

You must place SQLDA declarations before the first SQL statement that references
the data descriptor.

Embedding SQL statements


FORTRAN source statements must be fixed-length 80-byte records. The DB2
precompiler does not support free-form source input.

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.

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 statement UPDATE in a FORTRAN program as follows:


EXEC SQL
C UPDATE DSN8710.DEPT
C SET MGRNO = :MGRNUM
C WHERE DEPTNO = :INTDEPT

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 if you
specify the precompiler option STDSQL(YES).

The DB2 precompiler does not support the exclamation point (!) as a comment
recognition character in FORTRAN programs.

Chapter 9. Embedding SQL statements in host languages 165


FORTRAN
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 section have Cs in the sixth
column to indicate that they are continuations of the statement EXEC SQL.

Declaring tables and views: Your FORTRAN program should also include the
statement DECLARE TABLE 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 fields returned are fixed. If you want to use
variable-list SELECT statements, you need to use an SQLDA. See “Defining SQL
descriptor areas” on page 164 for more information on SQLDA.

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.

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' and 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 labelled SQL statement
generates a FORTRAN statement CONTINUE with that label before it generates
the code that executes the SQL statement. Therefore, a labelled 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 statement
WHENEVER must be a label in the FORTRAN source and must refer to a
statement in the same subprogram. The statement WHENEVER only applies to
SQL statements in the same subprogram.

166 Application Programming and SQL Guide


FORTRAN
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 of VS FORTRAN with the following restrictions:


v There is no support for the parallel option. 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.

Using host variables


You must explicitly declare all host variables used in SQL statements. You cannot
implicitly declare any host variables through default typing or by using the IMPLICIT
statement. You must explicitly declare each host variable before its first use in an
SQL statement.

You can precede FORTRAN statements that define the host variables with a BEGIN
DECLARE SECTION statement and follow the statements with an END DECLARE
SECTION statement. You must use the statements BEGIN DECLARE SECTION
and END DECLARE SECTION when you use the precompiler option
STDSQL(YES).

A colon (:) must precede all host variables in an SQL statement.

The names of host variables should be unique within the program, even if the host
variables are in different blocks, functions, or subroutines.

When you declare a character host variable, you must 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 its associated SQL statement executes.

An SQL statement that uses a host variable must be within the scope of the
statement that declares the variable.

Host variables must be scalar variables; they cannot be elements of vectors or


arrays (subscripted variables).

You must 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. See
Appendix C of DB2 SQL Reference for more information.

Declaring host variables


Only some of the valid FORTRAN 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 following figure shows the syntax for valid numeric
host variable declarations.

Chapter 9. Embedding SQL statements in host languages 167


FORTRAN

 INTEGER*2  variable-name 
*4 / numeric-constant /
INTEGER
*4
REAL
REAL*8
DOUBLE PRECISION
Figure 69. Numeric host variables

Character host variables: The following figure shows the syntax for valid character
host variable declarations other than CLOBs. See Figure 72 for the syntax of
CLOBs.

 CHARACTER  variable-name 
*n *n / character-constant /

Figure 70. Character host variables

Result set locators: The following figure shows the syntax for declarations of result
set locators. See “Chapter 24. Using stored procedures for client/server processing”
on page 527 for a discussion of how to use these host variables.

 SQL TYPE IS RESULT_SET_LOCATOR VARYING  variable-name 

Figure 71. Result set locators

LOB Variables and Locators: The following figure shows the syntax for
declarations of BLOB and CLOB host variables and locators. See “Chapter 13.
Programming for large objects (LOBs)” on page 229 for a discussion of how to use
these host variables.

 SQL TYPE IS BINARY LARGE OBJECT length variable-name 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
BLOB_LOCATOR
CLOB_LOCATOR

Figure 72. LOB variables and locators

ROWIDs: The following figure shows the syntax for declarations of ROWID
variables. See “Chapter 13. Programming for large objects (LOBs)” on page 229 for
a discussion of how to use these host variables.

168 Application Programming and SQL Guide


FORTRAN

 SQL TYPE IS ROWID variable-name 

Figure 73. ROWID variables

Determining equivalent SQL and FORTRAN data types


Table 14 describes the SQL data type, and base SQLTYPE and SQLLEN values,
that the precompiler uses for the host variables it finds in SQL statements. If a host
variable appears with an indicator variable, the SQLTYPE is the base SQLTYPE
plus 1.
Table 14. SQL data types the precompiler uses for FORTRAN declarations
FORTRAN Data Type SQLTYPE of Host SQLLEN of Host Variable SQL Data Type
Variable
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)
SQL TYPE IS 972 4 Result set locator.
RESULT_SET_LOCATOR Do not use this data
type as a column type.
SQL TYPE IS 960 4 BLOB locator.
BLOB_LOCATOR Do not use this data
type as a column type.
SQL TYPE IS 964 4 CLOB locator.
CLOB_LOCATOR Do not use this data
type as a column type.
SQL TYPE IS 404 n BLOB(n)
BLOB(n)
1≤n≤2147483647
SQL TYPE IS 408 n CLOB(n)
CLOB(n)
1≤n≤2147483647
SQL TYPE IS ROWID 904 40 ROWID

Table 15 on page 170 helps you define host variables that receive output from the
database. You can use the table to determine the FORTRAN data type that is
equivalent to a given SQL data type. For example, if you retrieve TIMESTAMP data,
you can use the table to define a suitable host variable in the program that receives
the data value.

| Table 15 on page 170 shows direct conversions between DB2 data types and host
| data types. However, a number of DB2 data types are compatible. When you do
| assignments or comparisons of data that have compatible data types, DB2 does
| conversions between those compatible data types. See Table 1 on page 5 for
| information on compatible data types.

Chapter 9. Embedding SQL statements in host languages 169


FORTRAN
Table 15. SQL data types mapped to typical FORTRAN declarations
SQL Data Type FORTRAN Equivalent Notes
SMALLINT INTEGER*2
INTEGER INTEGER*4
DECIMAL(p,s) or no exact equivalent Use REAL*8
NUMERIC(p,s)
FLOAT(n) REAL*4 1<=n<=21
single precision
FLOAT(n) REAL*8 22<=n<=53
double precision
CHAR(n) CHARACTER*n 1<=n<=255
VARCHAR(n) no exact equivalent Use a character host variable large enough
to contain the largest expected VARCHAR
value.
GRAPHIC(n) not supported
VARGRAPHIC(n) not supported
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 Use this data type only for receiving result
RESULT_SET_LOCATOR sets. Do not use this data type as a
column type.
BLOB locator SQL TYPE IS Use this data type only to manipulate data
BLOB_LOCATOR in BLOB columns. Do not use this data
type as a column type.
CLOB locator SQL TYPE IS Use this data type only to manipulate data
CLOB_LOCATOR in CLOB columns. Do not use this data
type as a column type.
DBCLOB locator not supported
BLOB(n) SQL TYPE IS 1≤n≤2147483647
BLOB(n)
CLOB(n) SQL TYPE IS 1≤n≤2147483647
CLOB(n)
DBCLOB(n) not supported
ROWID SQL TYPE IS ROWID

Notes on FORTRAN variable declaration and usage


You should be aware of the following when you declare FORTRAN variables.

170 Application Programming and SQL Guide


FORTRAN
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.

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 variables, 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.

Special-purpose FORTRAN data types: The locator data types are FORTRAN
data types as well as SQL data types. You cannot use locators as column types.
For information on how to use these data types, see the following sections:
Result set locator
“Chapter 24. Using stored procedures for client/server processing”
on page 527
LOB locators “Chapter 13. Programming for large objects (LOBs)” on page 229

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 a


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 eight 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).

Chapter 9. Embedding SQL statements in host languages 171


FORTRAN
Determining compatibility of SQL and FORTRAN data types
Host variables must be type compatible with the column values with which you
intend to use them.
v Numeric data types are compatible with each other. For example, if a column
value is INTEGER, you must declare the host variable as INTEGER*2,
INTEGER*4, REAL, REAL*4, REAL*8, or DOUBLE PRECISION.
v Character data types are compatible with each other. A CHAR, VARCHAR, or
CLOB column is compatible with FORTRAN 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.
| – 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 Datetime data types are compatible with character host variables: A DATE, TIME,
or TIMESTAMP column is compatible with a FORTRAN character host variable.
| v A BLOB column or a BLOB locator is compatible only with a BLOB 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. For information on assigning
and comparing distinct types, see “Chapter 15. Creating and using distinct types”
on page 301.

Using indicator variables


An indicator variable is a 2-byte integer (INTEGER*2). If you provide an indicator
variable for the variable X, then 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, then 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. For
more information about indicator variables, see “Using indicator variables with host
variables” on page 70.

Example: Given the statement:


EXEC SQL FETCH CLS_CURSOR INTO :CLSCD,
C :DAY :DAYIND,
C :BGN :BGNIND,
C :END :ENDIND

172 Application Programming and SQL Guide


FORTRAN
You can declare variables as follows:
CHARACTER*7 CLSCD
INTEGER*2 DAY
CHARACTER*8 BGN, END
INTEGER*2 DAYIND, BGNIND, ENDIND

The following figure shows the syntax for a valid indicator variable.

 INTEGER*2 variable-name 
/ numeric-constant /

Figure 74. Indicator variable

Handling SQL error return codes


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 “Handling SQL error return
codes” on page 76.

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, contained in the library
DSN8710.SDSNSAMP. See “Appendix B. Sample applications” on page 833 for
instructions on how to access and print the source code for the sample program.

Chapter 9. Embedding SQL statements in host languages 173


PL/I

Coding SQL statements in a PL/I application


This section helps you with the programming techniques that are unique to coding
SQL statements within a PL/I program.

Defining the SQL communication area


A PL/I program that contains SQL statements must include one or both of the
following host variables:
v An SQLCODE variable declared as BIN FIXED (31)
v An SQLSTATE variable declared as CHARACTER(5)
Or,
v An SQLCA, which contains the SQLCODE and SQLSTATE variables.

DB2 sets the SQLCODE and SQLSTATE values after each SQL statement
executes. An application can check these variables value 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 SQLCODE or SQLSTATE, or an SQLCA, in your program


depends on whether you specify the precompiler option STDSQL(YES) to conform
to SQL standard, or STDSQL(NO) to conform to DB2 rules.

If you specify STDSQL(YES)


When you use 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 and SQLSTATE within the statements
BEGIN DECLARE SECTION and END DECLARE SECTION in your program
declarations.

If you specify STDSQL(NO)


When you use the precompiler option STDSQL(NO), include an SQLCA explicitly.
You can code the SQLCA in a PL/I program either directly or by using the SQL
INCLUDE statement. The SQL INCLUDE statement requests a standard SQLCA
declaration:
EXEC SQL INCLUDE SQLCA;

See Chapter 5 of DB2 SQL Reference for more information about the INCLUDE
statement and Appendix C of DB2 SQL Reference for a complete description of
SQLCA fields.

Defining SQL descriptor areas


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
v DESCRIBE TABLE host-variable INTO descriptor-name
v EXECUTE...USING DESCRIPTOR descriptor-name
v FETCH...USING DESCRIPTOR descriptor-name
v OPEN...USING DESCRIPTOR descriptor-name

174 Application Programming and SQL Guide


PL/I
v PREPARE...INTO descriptor-name
Unlike the SQLCA, there can be more than one SQLDA in a program, and an
SQLDA can have any valid name. You can code an SQLDA in a PL/I program either
directly or by using the SQL INCLUDE statement. Using the SQL INCLUDE
statement requests a standard SQLDA declaration:
EXEC SQL INCLUDE SQLDA;

You must declare an SQLDA before the first SQL statement that references that
data descriptor, unless you use the precompiler option TWOPASS. See Chapter 5
of DB2 SQL Reference for more information about the INCLUDE statement and
Appendix C of DB2 SQL Reference for a complete description of SQLDA fields.

Embedding SQL statements


The first statement of the PL/I program must be the statement PROCEDURE with
OPTIONS(MAIN), unless the program is a stored procedure. A stored procedure
application can run as a subroutine. See “Chapter 24. Using stored procedures for
client/server processing” on page 527 for more information.

You can code SQL statements in a PL/I program wherever you can use executable
statements.

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 all on one line, but the
remainder of the statement can appear on subsequent lines.

You might code an UPDATE statement in a PL/I program as follows:


EXEC SQL UPDATE DSN8710.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 static SQL statement if you specify the
precompiler option STDSQL(YES).

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 also 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 details, see “Chapter 8. Generating declarations for your tables
using DCLGEN” on page 95.

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;

Chapter 9. Embedding SQL statements in host languages 175


PL/I
You cannot nest SQL INCLUDE statements. Do not use the statement PL/I
%INCLUDE 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 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. IEL0378 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 statements INCLUDE text-file-name and END DECLARE
SECTION 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:
v If you use DBCS in the PL/I source, then DB2 rules for the following language
elements apply:
– Graphic strings
– Graphic string constants
– Host identifiers
– Mixed data in character strings
– MIXED DATA option
See Chapter 2 of DB2 SQL Reference for detailed information about language
elements.
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 compiler, then 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.
For example:
# SQLSTMT = 'SELECT <dbdb> FROM table-name'M;
# EXEC SQL PREPARE STMT FROM :SQLSTMT;

For instructions on preparing SQL statements dynamically, see “Chapter 23.


Coding dynamic SQL in application programs” on page 497.

176 Application Programming and SQL Guide


PL/I
v If you want a DBCS identifier to resemble PL/I graphic string, you must use a
delimited identifier.
v 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.
v 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 64 single-byte characters in DB2. Please see
Chapter 2 of DB2 SQL Reference for the rules for DBCS SQL ordinary identifiers.
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.
v 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.
v The generated code in a PL/I declaration can contain the ADDR function of a
field defined as character varying. This produces message IEL0872, 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 have also
used NULL as a PL/I variable. If you use NULL as a PL/I variable in a DB2
application, then 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 Use of the PL/I multitasking facility, where multiple tasks execute SQL
statements, causes unpredictable results. See the RUN(DSN) command in
Chapter 2 of DB2 Command Reference.

Using host variables


You must explicitly declare all host variable before their first use in the SQL
statements, unless you specify the precompiler option TWOPASS. If you specify the
precompiler option TWOPASS, you must declare the host variables before its use in
the statement DECLARE CURSOR.

You can precede PL/I statements that define the host variables with the statement
BEGIN DECLARE SECTION, and follow the statements with the statement END

Chapter 9. Embedding SQL statements in host languages 177


PL/I
DECLARE SECTION. You must use the statements BEGIN DECLARE SECTION
and END DECLARE SECTION when you use the precompiler option
STDSQL(YES).

| A colon (:) must precede all host variables in an SQL statement, with the following
| exception. If the SQL statement meets the following conditions, a host variable in
| the SQL statement cannot be preceded by a colon:
| v The SQL statement is an EXECUTE IMMEDIATE or PREPARE statement.
| v The SQL statement is in a program that also contains a DECLARE VARIABLE
| statement.
| v The host variable is part of a string expression, but the host variable is not the
| only component of the string expression.

| The names of host variables should be unique within the program, even if the host
variables are in different blocks or procedures. You can qualify the host variable
names with a structure name to make them unique.

An SQL statement that uses a host variable must be within the scope of the
statement that declares the variable.

Host variables must be scalar variables or structures of scalars. You cannot declare
host variables as arrays, although you can use an array of indicator variables when
you associate the array with a host structure.

Declaring host variables


Only some of the valid PL/I declarations are valid host variable declarations. The
precompiler uses the data attribute defaults specified in the statement PL/I
DEFAULT. 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″.

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 figure shows the syntax for valid numeric
host variable declarations.

178 Application Programming and SQL Guide


PL/I

 DECLARE variable-name 
DCL ,

(  variable-name )

 BINARY FIXED 
BIN ( precision )
DECIMAL ,scale
DEC FLOAT ( precision )

 
Alignment and/or Scope and/or Storage

Figure 75. Numeric host variables

Notes:
1. You can specify host variable attributes in any order 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 for only DECIMAL FIXED.

Character host variables: The following figure shows the syntax for valid character
host variable declarations, other than CLOBs. See Figure 80 on page 180 for the
syntax of CLOBs.

 DECLARE variable-name CHARACTER ( length ) 


DCL , CHAR VARYING
VAR
(  variable-name )

 
Alignment and/or Scope and/or Storage

Figure 76. Character host variables

Graphic host variables: The following figure shows the syntax for valid graphic
host variable declarations, other than DBCLOBs. See Figure 80 on page 180 for the
syntax of DBCLOBs.

 DECLARE variable-name GRAPHIC ( length ) 


DCL , VARYING
VAR
(  variable-name )

 
Alignment and/or Scope and/or Storage

Figure 77. Graphic host variables

Chapter 9. Embedding SQL statements in host languages 179


PL/I
Result set locators: The following figure shows the syntax for valid result set
locator declarations. See “Chapter 24. Using stored procedures for client/server
processing” on page 527 for a discussion of how to use these host variables.

 DECLARE variable-name SQL TYPE IS RESULT_SET_LOCATOR VARYING 


DCL ,

(  variable-name )

 
Alignment and/or Scope and/or Storage

Figure 78. Result set locators

Table Locators: The following figure shows the syntax for declarations of table
locators. See “Accessing transition tables in a user-defined function or stored
procedure” on page 279 for a discussion of how to use these host variables.

 DCL variable-name SQL TYPE IS TABLE LIKE table-name AS LOCATOR 


DECLARE ,

(  variable-name )

Figure 79. Table locators

LOB Variables and Locators: The following figure shows the syntax for
declarations of BLOB, CLOB, and DBCLOB host variables and locators. See
“Chapter 13. Programming for large objects (LOBs)” on page 229 for a discussion of
how to use these host variables.

 DCL variable-name SQL TYPE IS 


DECLARE ,

(  variable-name )

 BINARY LARGE OBJECT ( length ) 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR

Figure 80. LOB variables and locators

ROWIDs: The following figure shows the syntax for declarations of ROWID
variables. See “Chapter 13. Programming for large objects (LOBs)” on page 229 for
a discussion of how to use these host variables.

180 Application Programming and SQL Guide


PL/I

 DCL variable-name SQL TYPE IS ROWID 


DECLARE ,

(  variable-name )

Figure 81. ROWID variables

Using host structures


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 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 valid host structures.

 DECLARE level-1 variable-name , 


DCL Scope and/or storage

  level-2 var-1 data-type-specification ; 


,

(  var-2 )

Figure 82. Host structures

Chapter 9. Embedding SQL statements in host languages 181


PL/I

 BINARY FIXED 
BIN ( precision )
DECIMAL ,scale
DEC FLOAT
( precision )
CHARACTER
CHAR ( integer ) VARYING
VARY
GRAPHIC
( integer ) VARYING
VARY
SQL TYPE IS ROWID
LOB data type

Figure 83. Data type specification

 SQL TYPE IS BINARY LARGE OBJECT ( length ) 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR

Figure 84. LOB data type

Note: You can specify a scale for only DECIMAL FIXED.

Determining equivalent SQL and PL/I data types


Table 16 describes the SQL data type, and base SQLTYPE and SQLLEN values,
that the precompiler uses for the host variables it finds in SQL statements. If a host
variable appears with an indicator variable, the SQLTYPE is the base SQLTYPE
plus 1.
Table 16. SQL data types the precompiler uses for PL/I declarations
PL/I Data Type SQLTYPE of Host SQLLEN of Host Variable SQL Data Type
Variable
BIN FIXED(n) 1<=n<=15 500 2 SMALLINT
BIN FIXED(n) 16<=n<=31 496 4 INTEGER
# DEC FIXED(p,s) 484 p in byte 1, s in byte 2 DECIMAL(p,s)
# 0<=p<=31 and
# 0<=s<=p1
BIN FLOAT(p) 480 4 REAL or FLOAT(n)
1<=p<=21 1<=n<=21
BIN FLOAT(p) 480 8 DOUBLE PRECISION or
22<=p<=53 FLOAT(n)
22<=n<=53
DEC FLOAT(m) 480 4 FLOAT (single precision)
1<=m<=6

182 Application Programming and SQL Guide


PL/I
Table 16. SQL data types the precompiler uses for PL/I declarations (continued)
PL/I Data Type SQLTYPE of Host SQLLEN of Host Variable SQL Data Type
Variable
DEC FLOAT(m) 480 8 FLOAT (double precision)
7<=m<=16
CHAR(n) 452 n CHAR(n)
CHAR(n) VARYING 448 n VARCHAR(n)
1<=n<=255
CHAR(n) VARYING 456 n VARCHAR(n)
n>255
GRAPHIC(n) 468 n GRAPHIC(n)
GRAPHIC(n) VARYING 464 n VARGRAPHIC(n)
1<=n<=127
GRAPHIC(n) VARYING n>127 472 n VARGRAPHIC(n)
SQL TYPE IS 972 4 Result set locator2
RESULT_SET_LOCATOR
SQL TYPE IS 976 4 Table locator2
TABLE LIKE table-name
AS LOCATOR
SQL TYPE IS 960 4 BLOB locator2
BLOB_LOCATOR
SQL TYPE IS 964 4 CLOB locator2
CLOB_LOCATOR
SQL TYPE IS 968 4 DBCLOB locator2
DBCLOB_LOCATOR
SQL TYPE IS BLOB(n) 404 n BLOB(n)
1≤n≤2147483647
SQL TYPE IS CLOB(n) 408 n CLOB(n)
1≤n≤2147483647
SQL TYPE IS DBCLOB(n) 412 n DBCLOB(n)3
1≤n≤10737418233
SQL TYPE IS ROWID 904 40 ROWID
Note:
# 1. 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).
2. Do not use this data type as a column type.
3. n is the number of double-byte characters.

Table 17 on page 184 helps you define host variables that receive output from the
database. You can use the table to determine the PL/I data type that is equivalent
to a given SQL data type. For example, if you retrieve TIMESTAMP data, you can
use the table to define a suitable host variable in the program that receives the data
value.

| Table 17 on page 184 shows direct conversions between DB2 data types and host
| data types. However, a number of DB2 data types are compatible. When you do
| assignments or comparisons of data that have compatible data types, DB2 does
| conversions between those compatible data types. See Table 1 on page 5 for
| information on compatible data types.

Chapter 9. Embedding SQL statements in host languages 183


PL/I
Table 17. SQL data types mapped to typical PL/I declarations
SQL Data Type PL/I Equivalent Notes
SMALLINT BIN FIXED(n) 1<=n<=15
INTEGER BIN FIXED(n) 16<=n<=31
# DECIMAL(p,s) or If p<16: p is precision;
# NUMERIC(p,s) DEC FIXED(p) or s is scale.
# DEC FIXED(p,s) 1<=p<=31
# and 0<=s<=p
# If p>15, the PL/I compiler must support
# 31-digit decimal variables. (See 185 for
# more information.)
REAL or BIN FLOAT(p) or 1<=n<=21,
FLOAT(n) DEC FLOAT(m) 1<=p<=21 and
1<=m<=6
DOUBLE PRECISION, BIN FLOAT(p) or 22<=n<=53,
DOUBLE, or DEC FLOAT(m) 22<=p<=53 and
FLOAT(n) 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.
DATE CHAR(n) If you are using a date exit routine, that
routine determines n; otherwise, n must be
at least 10.
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 Use this data type only for receiving result
RESULT_SET_LOCATOR sets. Do not use this data type as a
column type.
Table locator SQL TYPE IS Use this data type only in a user-defined
TABLE LIKE table-name function or stored procedure to receive
AS LOCATOR rows of a transition table. Do not use this
data type as a column type.
BLOB locator SQL TYPE IS Use this data type only to manipulate data
BLOB_LOCATOR in BLOB columns. Do not use this data
type as a column type.
CLOB locator SQL TYPE IS Use this data type only to manipulate data
CLOB_LOCATOR in CLOB columns. Do not use this data
type as a column type.
DBCLOB locator SQL TYPE IS Use this data type only to manipulate data
DBCLOB_LOCATOR in DBCLOB columns. Do not use this data
type as a column type.

184 Application Programming and SQL Guide


PL/I
Table 17. SQL data types mapped to typical PL/I declarations (continued)
SQL Data Type PL/I Equivalent Notes
BLOB(n) SQL TYPE IS 1≤n≤2147483647
BLOB(n)
CLOB(n) SQL TYPE IS 1≤n≤2147483647
CLOB(n)
DBCLOB(n SQL TYPE IS n is the number of double-byte characters.
DBCLOB(n) 1≤n≤1073741823
ROWID 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.

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, then the fractional part of the
value could 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
# System/390 floating point format. However, your host variable data can be in
# System/390 floating point format or IEEE floating point format. DB2 uses the
# FLOAT(S390|IEEE) precompiler option to determine whether your floating point host
# variables are in IEEE floating point format or System/390 floating point format. If
# you use this option for a PL/I program, you must compile the program using IBM
# Enterprise PL/I for z/OS and OS/390 Version 3 Release 1 or later. 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 locator data types are PL/I data types as
well as SQL data types. You cannot use locators as column types. For information
on how to use these data types, see the following sections:
Result set locator
“Chapter 24. Using stored procedures for client/server processing”
on page 527

Chapter 9. Embedding SQL statements in host languages 185


PL/I
Table locator “Accessing transition tables in a user-defined function or stored
procedure” on page 279
LOB locators “Chapter 13. Programming for large objects (LOBs)” on page 229

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 could truncate the value.

Determining compatibility of SQL and PL/I data types


When you use PL/I host variables in SQL statements, the variables must be type
compatible with the columns with which you use them.
v Numeric data types are compatible with each other. A SMALLINT, INTEGER,
DECIMAL, or FLOAT column is compatible with a PL/I host variable of BIN
FIXED(15), BIN FIXED(31), DECIMAL(s,p), 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. 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.
| – 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. 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.

186 Application Programming and SQL Guide


PL/I
| – 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 Datetime data types are compatible with character host variables. A DATE, TIME,
or TIMESTAMP column is compatible with a fixed-length or varying-length PL/I
character host variable.
| v A BLOB column or a BLOB locator is compatible only with a BLOB 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. For information on assigning
and comparing distinct types, see “Chapter 15. Creating and using distinct types”
on page 301.

When necessary, DB2 automatically converts a fixed-length string to a


varying-length string, or a varying-length string to a fixed-length string.

Using indicator variables


An indicator variable is a 2-byte integer (BIN FIXED(15)). If you provide an indicator
variable for the variable X, then 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, then 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. For
more information about indicator variables, see “Using indicator variables with host
variables” on page 70.

Example:

Given the 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 CLS_CD CHAR(7);
DCL DAY BIN FIXED(15);
DCL BGN CHAR(8);
DCL END CHAR(8);
DCL (DAY_IND, BGN_IND, END_IND) BIN FIXED(15);

Chapter 9. Embedding SQL statements in host languages 187


PL/I
You can specify host variable attributes in any order 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 a valid indicator variable.

 DECLARE variable-name BINARY FIXED(15) ; 


DCL BIN

Figure 85. Indicator variable

The following figure shows the syntax for a valid indicator array.

 DECLARE variable-name ( dimension ) BINARY 


DCL , BIN

(  variable-name ( dimension ) )

 FIXED(15) ; 
Alignment and/or Scope and/or Storage

Figure 86. Indicator array

Handling SQL error return codes


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
“Handling SQL error return codes” on page 76.

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 );

188 Application Programming and SQL Guide


PL/I
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 DSN8710.SDSNSAMP. See
“Appendix B. Sample applications” on page 833 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 );

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 new 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.

Coding SQL statements in a REXX application


This section helps you with the programming techniques that are unique to coding
SQL statements in a REXX procedure. For an example of a complete DB2 REXX
procedure, see “Example DB2 REXX application” on page 866.

Defining the SQL communication area


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:

Chapter 9. Embedding SQL statements in host languages 189


REXX
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.
See “Accessing the DB2 REXX Language Support application programming
interfaces” for a discussion of the methods for connecting a REXX application to
DB2.
v You cannot use the INCLUDE SQLCA statement to include an SQLCA in a REXX
program.

DB2 sets the SQLCODE and SQLSTATE values after each SQL statement
executes. An application can check these variable values to determine whether the
last SQL statement was successful.

See Appendix C of DB2 SQL Reference for information on the fields in the REXX
SQLCA.

Defining SQL descriptor areas


The following statements require an SQL descriptor area (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
v DESCRIBE TABLE host-variable INTO descriptor-name
v EXECUTE...USING DESCRIPTOR descriptor-name
v FETCH...USING DESCRIPTOR descriptor-name
v OPEN...USING DESCRIPTOR descriptor-name
v PREPARE...INTO descriptor-name

A REXX procedure can contain more than one SQLDA. 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. DB2 does not support
the INCLUDE SQLDA statement in REXX.

See Appendix C of DB2 SQL Reference for information on the fields in a REXX
SQLDA.

Accessing the DB2 REXX Language Support application programming


interfaces
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:

190 Application Programming and SQL Guide


REXX

(1)
 'CONNECT' 'subsystem-ID' 
ADDRESS DSNREXX REXX-variable

Notes:
1 CALL SQLDBS 'ATTACH TO' ssid is equivalent to ADDRESS DSNREXX 'CONNECT' ssid.

EXECSQL
Executes SQL statements in REXX procedures. The syntax of EXECSQL is:

(1)
 "EXECSQL" "SQL-statement" 
ADDRESS DSNREXX REXX-variable

Notes:
1 CALL SQLEXEC is equivalent to EXECSQL.

See “Embedding SQL statements in a REXX procedure” on page 192 for more
information.
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:

(1)
 'DISCONNECT' 
ADDRESS DSNREXX

Notes:
1 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' , 'DSNREXX' , 'DSNREXX' ) 


'DELETE'

The ADD function adds DSNREXX to the REXX host command environment table.
The DELETE function deletes DSNREXX from the REXX host command
environment table.

Chapter 9. Embedding SQL statements in host languages 191


REXX
Figure 87 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 */
/* CALL CONNECT, EXECSQL, AND */
. /* DISCONNECT INTERFACES */
.
.

S_RC = RXSUBCOM('DELETE','DSNREXX','DSNREXX')
/* WHEN DONE WITH */
/* DSNREXX, REMOVE IT. */

Figure 87. Making DSNREXX available to an application

Embedding SQL statements in a REXX procedure


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
OS/390 and 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, 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 “Using REXX host
variables and data types” on page 194 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';

192 Application Programming and SQL Guide


REXX
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 DSN8710.DEPT" ,
"SET MGRNO = '000010'" ,
"WHERE DEPTNO = 'D11'"
"EXECSQL " || ,
" UPDATE DSN8710.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. Table 18 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 18. 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 9. Embedding SQL statements in host languages 193


REXX

Using cursors and statement names


In REXX SQL applications, 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 SQL 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.

Using REXX host variables and data types


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.

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'

Determining equivalent SQL and REXX data types


All REXX data is string data. Therefore, when a REXX procedure assigns input data
to a table column, DB2 converts the data from a string type to the table 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.

Letting DB2 determine the input data type


You can let DB2 assign a data type to input data based on the format of the input
string. Table 19 on page 195 shows the SQL data types that DB2 assigns to input

194 Application Programming and SQL Guide


REXX
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.

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.
Table 19. SQL input data types and REXX data formats
SQL data type SQLTYPE for data REXX input data format
assigned by DB2 type
INTEGER 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.
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 -2147483647
or greater than 2147483647.
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'"

Chapter 9. Embedding SQL statements in host languages 195


REXX
"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.

Ensuring that DB2 correctly interprets character input data


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 variable to DB2


In some cases, you might want to determine the data type of input data for DB2.
For example, 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. For example,
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:
INSQLDA.SQLD = 1 /* SQLDA contains one variable */
INSQLDA.1.SQLTYPE = 453 /* Type of the variable is CHAR, */
/* and the value can be null */
INSQLDA.1.SQLLEN = 1 /* Length of the variable is 1 */
INSQLDA.1.SQLDATA = 'H' /* Value in variable is H */
INSQLDA.1.SQLIND = 0 /* Input variable is not null */
SQLSTMT="UPDATE EMP" ,
"SET MIDINIT = ?" ,
"WHERE EMPNO = '000200'"
"EXECSQL PREPARE S100 FROM :SQLSTMT"
"EXECSQL EXECUTE S100 USING" ,
"DESCRIPTOR :INSQLDA"

196 Application Programming and SQL Guide


REXX
Retrieving data from DB2 tables
Although all output data 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. Table 20 gives the format for each type of output data.
Table 20. SQL output data types and REXX data formats
SQL data type REXX output data format
SMALLINT A string of numerics that does not contain leading zeroes, a decimal point, or an
INTEGER exponent identifier. If the string represents a negative number, it begins with a minus
(−) sign. The numeric value is between -2147483647 and 2147483647, inclusive.
DECIMAL(p,s) 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) A string that represents a number in scientific notation. The string consists of a numeric,
REAL a decimal point, a series of numerics, and an exponent identifier. The exponent
DOUBLE 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.
CHAR(n) A character string of length n bytes. The string is not enclosed in single or double
VARCHAR(n) quotation marks.
GRAPHIC(n) A string of length 2*n bytes. Each pair of bytes represents a double-byte character. This
VARGRAPHIC(n) 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

Using indicator variables


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 null.

Chapter 9. Embedding SQL statements in host languages 197


REXX
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 DSN8710.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')

Setting the isolation level of SQL statements in a REXX procedure


When you install DB2 REXX Language Support, you bind four packages for
accessing DB2, each with a different isolation level:
Package name Isolation level
DSNREXRR Repeatable read (RR)
DSNREXRS Read stability (RS)
DSNREXCS Cursor stability (CS)
DSNREXUR Uncommitted read (UR)

198 Application Programming and SQL Guide


REXX
To change the isolation level for SQL statements in a REXX procedure, execute the
SET CURRENT PACKAGESET statement to select the package with the isolation
level you need. For example, to change the isolation level to cursor stability,
execute this SQL statement:
"EXECSQL SET CURRENT PACKAGESET='DSNREXCS'"

Chapter 9. Embedding SQL statements in host languages 199


REXX

200 Application Programming and SQL Guide


Chapter 10. Using constraints to maintain data integrity
When you modify DB2 tables, you need to ensure that the data is valid. DB2
provides two ways to help you maintain valid data: 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:
v Table check constraints determine the values that a column can contain. Table
check constraints are discussed in “Using table check constraints”.
v Referential constraints preserve relationships between tables. Referential
constraints are discussed in “Using referential constraints” on page 203.

Triggers are a series of actions that are invoked when a table is updated. Triggers
are discussed in “Chapter 11. Using triggers for active data” on page 209.

Using table check constraints


Table 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 table 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:

CREATE TABLE EMPSAL


(ID INTEGER NOT NULL,
SALARY INTEGER CHECK (SALARY >= 15000));

Figure 88. Creating a simple table check constraint

Using table 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 table check constraints on one or more columns in a table
when that table is created or altered.

Constraint considerations
The syntax of a table 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:

© Copyright IBM Corp. 1983, 2001 201


CHECK (C1 > 0)
CHECK (C1 >= 1)
v A check constraint that contradicts the column definition:
CHECK (C1 IS NULL)
v A check constraint that repeats the column definition:
CHECK (C1 IS NOT NULL)

A table 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 table 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 table check constraints are defined on or removed
from a table.

When table check constraints are enforced


After table 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 statement
v An SQL UPDATE statement
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 table 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 table 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.

How table check constraints set check pending status


Maintaining check integrity requires enforcing check constraints on data in a table.
When check integrity is compromised or cannot be guaranteed, the table space or
partition that contains the table is placed in check pending status. The definition of
that status includes violations of table check constraints as well as referential
constraints.

Table check violations place a table space or partition in check pending status when
any of these conditions exist:

202 Application Programming and SQL Guide


v A table 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 table check constraints are
defined on the table.
v CHECK DATA is run on a table that contains violations of table check constraints.
v A point-in-time RECOVER introduces violations of table check constraints.

Using referential constraints


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.

CASCADE
DEPT

SET SET
NULL NULL

RESTRICT EMP

RESTRICT

CASCADE ACT

PROJ
RESTRICT RESTRICT

PROJACT
RESTRICT

RESTRICT

EMPPROJACT

Figure 89. Relationships among tables in the sample application. Arrows point from parent
tables to dependent tables.

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.

Parent key columns


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 10. Using constraints to maintain data integrity 203


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

Figure 90 shows part of the project table with the primary key column indicated.

Project table
Primary key column

PROJNO PROJNAME DEPTNO

MA2100 WELD LINE AUTOMATION D01


MA2110 W L PROGRAMMING D11

Figure 90. A primary key on a table

Figure 91 shows a primary key containing more than one column; the primary key is
a composite key.

Project activity table


Primary key columns

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

Figure 91. A composite primary key. The PROJNO, ACTNO, and ACSTDATE columns are all
parts of the key.

Defining a parent key and a unique index


The information in this section (up to “Defining a foreign key” on page 206) is
General-use Programming Interface and Associated Guidance Information, as
defined in “Notices” on page 949.

The primary key of a table, if one exists, uniquely identifies each occurrence of an
entity about which the table contains information. 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 create a table using the
UNIQUE clause of the CREATE TABLE or ALTER TABLE statement. Like the
PRIMARY KEY clause, specifying a UNIQUE clause prevents use of the table until
you create an index to enforce the uniqueness of the key. And if you use the
UNIQUE clause in an ALTER TABLE statement, a unique index must already exist.
For more information about the UNIQUE clause, see Chapter 5 of DB2 SQL
Reference.

204 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 “Chapter 10. Using constraints to maintain data
integrity” on page 201 before creating or altering any of the tables involved.

A table can have no more than one primary key. A primary key obeys the same
restrictions as do index keys:
v The key can include no more than 64 columns.
v No column can be named twice.
v The sum of the column length attributes cannot be greater than 255.

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.

Incomplete definition
If a table is created with a primary key, its primary index is the first unique index
created on its primary key columns, with the same order of columns as the primary
key columns. The columns of the primary index can be in either ascending or
descending order. The table has an incomplete definition until you create an index
on the parent key. This incomplete definition status is recorded as a P in the
TABLESTATUS column of SYSIBM.SYSTABLES. Use of a table with an incomplete
definition is severely restricted: you can drop the table, create the primary index,
and drop or create other indexes; you cannot load the table, insert data, retrieve
data, update data, delete data, or create foreign keys that reference the primary
key.

Because of these restrictions, plan to create the primary index soon after creating
the table. For example, to create the primary index for the project activity table,
issue:
CREATE UNIQUE INDEX XPROJAC1
ON DSN8710.PROJACT (PROJNO, ACTNO, ACSTDATE);

Creating the primary index resets the incomplete definition status and its associated
restrictions. But if you drop the primary index, it reverts to incomplete definition
status; to reset the status, you must create the primary index or alter the table to
drop the primary key.

If the primary key is added later with ALTER TABLE, a unique index on the key
columns must already exist. If more than one unique index is on those columns,
DB2 chooses one arbitrarily to be the primary index.

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.

Chapter 10. Using constraints to maintain data integrity 205


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.

Defining a foreign key


The information in this section is General-use Programming Interface and
Associated Guidance Information, as defined in “Notices” on page 949.

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 (an identifier of up to 8 bytes) for the
relationship that is defined by a foreign key. If you do not choose a name, DB2
generates one from 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. In the following sample
CREATE TABLE statement, these constraints are named REPAPA and REPAE.

| CREATE TABLE DSN8710.EMPPROJACT


| (EMPNO CHAR(6) NOT NULL,
| PROJNO CHAR(6) NOT NULL,
| ACTNO SMALLINT NOT NULL,
| CONSTRAINT REPAPA FOREIGN KEY (PROJNO, ACTNO)
| REFERENCES DSN8710.PROJACT ON DELETE RESTRICT,
| CONSTRAINT REPAE FOREIGN KEY (EMPNO)
| REFERENCES DSN8710.EMP ON DELETE RESTRICT )
| IN DATABASE DSN8D71A;

Figure 92. Specifying constraint names for foreign keys

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).

206 Application Programming and SQL Guide


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 leading 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.

When a foreign key is added to a populated table, the table space is put into check
pending status.

Restrictions on cycles of dependent tables


A cycle is a set of two or more tables that can be 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. In the sample application, the employee and
department tables are a cycle; each is a dependent of the other.

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 Figure 93 on
page 208.
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.

Chapter 10. Using constraints to maintain data integrity 207


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.

Valid Invalid
cycle cycle
TABLE1 TABLE1

RESTRICT CASCADE CASCADE CASCADE

TABLE2 TABLE3 TABLE2 TABLE3


SET NULL SET NULL

Figure 93. Valid and invalid delete cycles. The left cycle is valid because two or more delete
rules are not CASCADE. The cycle on the right is invalid because of the two cascading
deletes.

208 Application Programming and SQL Guide


Chapter 11. Using triggers for active data
Triggers are sets of SQL statements that execute when a certain event occurs in a
DB2 table. Like constraints, triggers can be used to control changes in DB2
databases. Triggers are more powerful, however, because they can monitor a
broader range of changes and perform a broader range of actions than constraints
can. 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 notice 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.

This chapter presents the following information about triggers:


v “Example of creating and using a trigger”
v “Parts of a trigger” on page 211
v “Invoking stored procedures and user-defined functions from triggers” on
page 217
v “Trigger cascading” on page 218
v “Ordering of multiple triggers” on page 219
v “Interactions among triggers and referential constraints” on page 219
v “Creating triggers to obtain consistent results” on page 221

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. Figure 94 on page 210
shows an example of a CREATE TRIGGER statement.

© Copyright IBM Corp. 1983, 2001 209


1
CREATE TRIGGER REORDER
2 3 4
AFTER UPDATE OF ON_HAND, MAX_STOCKED ON PARTS
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

Figure 94. Example of a trigger

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.

210 Application Programming and SQL Guide


Parts of a trigger
This section gives you the information you need to code each of the trigger parts:
v Trigger name
v Subject table
v Trigger activation time
v Triggering event
v Granularity
v Transition variables
v Transition tables
v Triggered action, which consists of a trigger condition and trigger body

Trigger name: Use a short, 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 SQLID.

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.

When the triggering event for a trigger is an update operation, the trigger is called
an update trigger. Similiarly, triggers for insert operations are called insert triggers,
and triggers for delete operations are called delete triggers.

The SQL statement that performs the triggering SQL operation is called the
triggering SQL statement.

Chapter 11. Using triggers for active data 211


The following example shows a trigger that 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

Each triggering event is associated with one subject table and one SQL operation. 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.

For example, the following trigger, PAYROLL1, which invokes user-defined function
named PAYROLL_LOG, is activated only if an update operation is performed on
columns SALARY or BONUS 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.

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

212 Application Programming and SQL Guide


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.
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.

Chapter 11. Using triggers for active data 213


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: 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.

214 Application Programming and SQL Guide


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. The trigger body begins with BEGIN
ATOMIC and ends 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. Table 21 summarizes which SQL statements you can use in which types of
triggers.
Table 21. Valid SQL statements for triggers and trigger activation times
SQL Statement Valid for Activation Time
Before After
SELECT Yes Yes
VALUES Yes Yes
CALL Yes Yes
SIGNAL SQLSTATE Yes Yes
SET transition-variable Yes No
INSERT No Yes
UPDATE No Yes
DELETE No Yes

The following list provides more detailed information about SQL statements that are
valid in triggers:
v SELECT, VALUES, and CALL
Use the SELECT or 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 217 for more information on invoking user-defined
functions and stored procedures from triggers.
A SELECT statement in the trigger body of a before trigger cannot reference the
subject table.
v SET transition-variable

Chapter 11. Using triggers for active data 215


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 SIGNAL SQLSTATE
Use the SIGNAL SQLSTATE 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 SQLSTATE statement, it returns an SQLCA to the
application with SQLCODE -438. The SQLCA also includes the following values,
which you supply in the SIGNAL SQLSTATE statement:
– A five-character value that DB2 uses as the SQLSTATE
– An error message that DB2 places in the SQLERRMC field
In the following example, the SIGNAL SQLSTATE 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 INSERT, UPDATE, and DELETE
Because you can include INSERT, UPDATE, and DELETE statements in your
trigger body, execution of the trigger body might cause activation of other
triggers. See “Trigger cascading” on page 218 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

216 Application Programming and SQL Guide


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.

Invoking stored procedures and user-defined functions from triggers


A trigger body can include only SQL statements and built-in functions. Therefore, if
you want the trigger to perform actions or use logic that is not available in SQL
statements or built-in functions, you need to write a user-defined function or stored
procedure and invoke that function or stored procedure from the trigger body.
“Chapter 14. Creating and using user-defined functions” on page 241 and
“Chapter 24. Using stored procedures for client/server processing” on page 527
contain 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, or DELETE 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 literals, 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.

Chapter 11. Using triggers for active data 217


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 279 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 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

Trigger cascading
An SQL operation that a trigger performs might modify the subject table or other
tables with triggers, so DB2 also activates those triggers. 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,

218 Application Programming and SQL Guide


and stored procedures in your programs. See Appendixes (Volume 2) of DB2
Administration Guide for information on how to write a monitor program.

Ordering 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
recreates 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 among 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:
1. DB2 determines the rows of T1 to modify. Call that set of rows M1. The
contents of M1 depend on the SQL operation:

Chapter 11. Using triggers for active data 219


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.
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 contraints 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:
CREATE TRIGGER EMPRAISE
AFTER UPDATE ON EMP
REFERENCING NEW TABLE AS NEWEMPS

220 Application Programming and SQL Guide


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.

Creating triggers to obtain consistent 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.
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 Table T2
A1 B1
== ==
1 1
2 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)

Chapter 11. Using triggers for active data 221


{
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:
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 Table T2 Table T3
A1 B1 C1
== == ==
1 (empty) (empty)
2

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;

222 Application Programming and SQL Guide


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 Table T2 Table T3
A1 B1 C1
== == ==
2 2 2
2

After the second row of T1 is updated, the values in the three tables are:
Table T1 Table T2 Table T3
A1 B1 C1
== == ==
2 2 2
3 3 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:
Table T1 Table T2 Table T3
A1 B1 C1
== == ==
1 3 3
3

After the first row of T1 is updated, the values in the three tables are:
Table T1 Table T2 Table T3
A1 B1 C1
== == ==
2 3 3
3 2 3
2

Chapter 11. Using triggers for active data 223


224 Application Programming and SQL Guide
Part 3. Using DB2 object-relational extensions
Chapter 12. Introduction to DB2 object-relational extensions . . . . . . 227

Chapter 13. Programming for large objects (LOBs) . . . . . . . . . . 229


Introduction to LOBs . . . . . . . . . . . . . . . . . . . . . . 229
Declaring LOB host variables and LOB locators . . . . . . . . . . . . 232
LOB materialization . . . . . . . . . . . . . . . . . . . . . . . 236
Using LOB locators to save storage . . . . . . . . . . . . . . . . . 236
Deferring evaluation of a LOB expression to improve performance . . . . 237
Indicator variables and LOB locators . . . . . . . . . . . . . . . 240
Valid assignments for LOB locators . . . . . . . . . . . . . . . . 240

Chapter 14. Creating and using user-defined functions . . . . . . . . 241


Overview of user-defined function definition, implementation, and invocation 241
Example of creating and using a user-defined scalar function . . . . . . 242
User-defined function samples shipped with DB2 . . . . . . . . . . . 243
Defining a user-defined function . . . . . . . . . . . . . . . . . . 244
Components of a user-defined function definition . . . . . . . . . . . 244
Examples of user-defined function definitions . . . . . . . . . . . . 246
Implementing an external user-defined function . . . . . . . . . . . . 248
Writing a user-defined function . . . . . . . . . . . . . . . . . 248
Restrictions on user-defined function programs . . . . . . . . . . 249
Coding your user-defined function as a main program or as a subprogram 249
Parallelism considerations . . . . . . . . . . . . . . . . . . 249
Passing parameter values to and from a user-defined function . . . . . 251
Examples of passing parameters in a user-defined function . . . . . . 263
Using special registers in a user-defined function . . . . . . . . . . 276
Using a scratchpad in a user-defined function . . . . . . . . . . . 277
Accessing transition tables in a user-defined function or stored procedure 279
Preparing a user-defined function for execution . . . . . . . . . . . 284
Making a user-defined function reentrant . . . . . . . . . . . . . 285
Determining the authorization ID for user-defined function invocation 285
Preparing user-defined functions to run concurrently. . . . . . . . . 285
Testing a user-defined function . . . . . . . . . . . . . . . . . 286
| Implementing an SQL scalar function . . . . . . . . . . . . . . . . 288
Invoking a user-defined function . . . . . . . . . . . . . . . . . . 289
Syntax for user-defined function invocation . . . . . . . . . . . . . 289
Ensuring that DB2 executes the intended user-defined function . . . . . 290
How DB2 chooses candidate functions . . . . . . . . . . . . . 291
How DB2 chooses the best fit among candidate functions . . . . . . 293
How you can simplify function resolution . . . . . . . . . . . . . 294
Using DSN_FUNCTION_TABLE to see how DB2 resolves a function 295
Casting of user-defined function arguments . . . . . . . . . . . . . 296
What happens when a user-defined function abnormally terminates . . . . 297
Nesting SQL Statements . . . . . . . . . . . . . . . . . . . . 297
Recommendations for user-defined function invocation . . . . . . . . . 299

Chapter 15. Creating and using distinct types . . . . . . . . . . . . 301


Introduction to distinct types . . . . . . . . . . . . . . . . . . . 301
Using distinct types in application programs . . . . . . . . . . . . . . 302
Comparing distinct types . . . . . . . . . . . . . . . . . . . . 302
Assigning distinct types . . . . . . . . . . . . . . . . . . . . 303
Assigning column values to columns with different distinct types . . . . 303
Assigning column values with distinct types to host variables . . . . . 304

© Copyright IBM Corp. 1983, 2001 225


Assigning host variable values to columns with distinct types . . . . . 304
Using distinct types in UNIONs . . . . . . . . . . . . . . . . . 305
Invoking functions with distinct types . . . . . . . . . . . . . . . 305
Combining distinct types with user-defined functions and LOBs . . . . . . 306

226 Application Programming and SQL Guide


Chapter 12. Introduction to 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 functions. With those extensions, you can store instances of
object-oriented data types in columns of tables and operate on them using functions
in SQL statements. In addition, you can control the types of operations that users
can perform on those data types.

The object extensions that DB2 provides are:


v Large objects (LOBs)
The VARCHAR and VARGRAPHIC data types have a storage limit of 32 KB.
Although this might be sufficient for small- to medium-size text data, applications
often need to store large text documents. They might also need to store a wide
variety of additional data types such as audio, video, drawings, mixed text and
graphics, and images. DB2 provides three data types to store these data objects
as strings of up to 2 GB - 1 in size. The three data types are binary large
objects (BLOBs), character large objects (CLOBs), and double-byte character
large objects (DBCLOBs).
For a detailed discussion of LOBs, see “Chapter 13. Programming for large
objects (LOBs)” on page 229.
v Distinct types
A distinct type is a user-defined data type that shares its internal representation
with a built-in data type but is considered to be a separate and incompatible type
for semantic purposes. For example, you might want to define a picture type or
an audio type, both of which have quite different semantics, but which use the
built-in data type BLOB for their internal representation.
For a detailed discussion of distinct types, see “Chapter 15. Creating and using
distinct types” on page 301.
v User-defined functions
The built-in functions that are supplied with DB2 are a useful set of functions, but
they might not satisfy all of your requirements. For those cases, you can use
user-defined functions. For example, a built-in function might perform a
calculation you need, but the function does not accept the distinct types you want
to pass to it. You can then define a function based on a built-in function, called a
sourced user-defined function, that accepts your distinct types. You might need to
perform another calculation in your SQL statements for which there is no built-in
function. In that situation, you can define and write an external user-defined
function.
For a detailed discussion of user-defined functions, see “Chapter 14. Creating
and using user-defined functions” on page 241.

© Copyright IBM Corp. 1983, 2001 227


228 Application Programming and SQL Guide
Chapter 13. Programming for 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.

This chapter presents the following information about LOBs:


v “Introduction to LOBs”
v “Declaring LOB host variables and LOB locators” on page 232
v “LOB materialization” on page 236
v “Using LOB locators to save storage” on page 236

Introduction to LOBs
Working with LOBs involves defining the LOBs to DB2, moving the LOB data into
DB2 tables, then using SQL operations to manipulate the data. This chapter
concentrates on manipulating LOB data using SQL statements. For information on
defining LOBs to DB2, see Chapter 5 of DB2 SQL Reference. For information on
how DB2 utilities manipulate LOB data, see Part 2 of DB2 Utility Guide and
Reference.

These are the basic steps for defining LOBs and moving the data into DB2:
1. Define a column of the appropriate LOB type and a row identifier (ROWID)
column in a DB2 table. Define only one ROWID column, even if there are
multiple LOB columns in the table.
The LOB column holds information about the LOB, not the LOB data itself. The
table that contains the LOB information is called the base table. DB2 uses the
ROWID column to locate your LOB data. You need only one ROWID column in
a table that contains one or more LOB columns. You can define the LOB
column and the ROWID column in a CREATE TABLE or ALTER TABLE
statement. If you are adding a LOB column and a ROWID column to an existing
table, you must use two ALTER TABLE statements. Add the ROWID with the
first ALTER TABLE statement and the LOB column with the second.
2. Create a table space and table to hold the LOB data.
The table space and table are called a LOB table space and an auxiliary table.
If your base table is nonpartitioned, you must create one LOB table space and
one auxiliary table for each LOB column. If your base table is partitioned, for
each LOB column, you must create one LOB table space and one auxiliary
table for each partition. For example, if your base table has three partitions, you
must create three LOB table spaces and three auxiliary tables for each LOB
column. Create these objects using the CREATE LOB TABLESPACE and
CREATE AUXILIARY TABLE statements.
3. Create an index on the auxiliary table.

© Copyright IBM Corp. 1983, 2001 229


Each auxiliary table must have exactly one index. Use CREATE INDEX for this
task.
4. Put the LOB data into DB2.
If the total length of a LOB column and the base table row is less than 32 KB,
you can use the LOAD utility to put the data in DB2. Otherwise, you must use
INSERT or UPDATE statements. Even though the data is stored in the auxiliary
table, the LOAD utility statement or INSERT statement specifies the base table.
Using INSERT can be difficult because your application needs enough storage
to hold the entire value that goes into the LOB column.

For example, suppose you want to add a resume for each employee to the
employee table. Employee resumes are no more than 5 MB in size. The employee
resumes contain single-byte characters, so 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 a ROWID column has not been defined in the table,
you need to add the ROWID column before you add the CLOB column. Execute an
ALTER TABLE statement to add the ROWID column, and then execute another
ALTER TABLE statement to add the CLOB column. You might use statements like
this:
ALTER TABLE EMP
ADD ROW_ID ROWID NOT NULL GENERATED ALWAYS;
COMMIT;
ALTER TABLE EMP
ADD EMP_RESUME CLOB(1M);
COMMIT;

Next, you need to define a LOB table space and an auxiliary table to hold the
employee resumes. You also need to define an index on the auxiliary table. You
must define the LOB table space in the same database as the associated base
table. You can use statements like this:
CREATE LOB TABLESPACE RESUMETS
IN DSN8D71A
LOG NO;
COMMIT;
CREATE AUXILIARY TABLE EMP_RESUME_TAB
IN DSN8D71A.RESUMETS
STORES DSN8710.EMP
COLUMN EMP_RESUME;
CREATE UNIQUE INDEX XEMP_RESUME
ON EMP_RESUME_TAB;
COMMIT;

If the value of bind option SQLRULES is STD, or if special register CURRENT


RULES has been set in the program and has the value STD, DB2 creates the LOB
table space, auxiliary table, and auxiliary index for you when you execute the
ALTER statement to add the LOB column.

Now that your DB2 objects for the LOB data are defined, you can load your
employee resumes into DB2. To do this in an SQL 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 data goes into the auxiliary table, your UPDATE statement specifies
the name of the base table. The C language declaration of the host variable might
be:
SQL TYPE is CLOB (5K) resumedata;

The UPDATE statement looks like this:

230 Application Programming and SQL Guide


UPDATE EMP SET EMP_RESUME=:resumedata
WHERE EMPNO=:employeenum;

In this example, employeenum is a host variable that identifies the employee who is
associated with a resume.

After your LOB data is in DB2, you can write SQL applications to manipulate the
data. You can use most SQL statements with LOBs. For example, you can use
statements like these to extract information about an employee's department from
the resume:
EXEC SQL BEGIN DECLARE SECTION;
long deptInfoBeginLoc;
long deptInfoEndLoc;
SQL TYPE IS CLOB_LOCATOR resume;
SQL TYPE IS CLOB_LOCATOR deptBuffer;
EXEC
. SQL END DECLARE SECTION;
.
.

EXEC SQL DECLARE C1 CURSOR FOR


. SELECT EMPNO, EMP_RESUME FROM EMP;
.
.

EXEC
. SQL FETCH C1 INTO :employeenum, :resume;
.
.

EXEC SQL SET :deptInfoBeginLoc =


POSSTR(:resumedata, 'Department Information');

EXEC SQL SET :deptInfoEndLoc =


POSSTR(:resumedata, 'Education');

EXEC SQL SET :deptBuffer =


SUBSTR(:resume, :deptInfoBeginLoc,
:deptInfoEndLoc - :deptInfoBeginLoc);

These statements use host variables of data type large object locator (LOB locator).
LOB locators let you manipulate LOB data without moving the LOB data into host
variables. By using LOB locators, you need much smaller amounts of memory for
your programs. LOB locators are discussed in “Using LOB locators to save storage”
on page 236.

Sample LOB applications: Table 22 lists the sample programs that DB2 provides
to assist you in writing applications to manipulate LOB data. All programs reside in
data set DSN710.SDSNSAMP.
Table 22. LOB samples shipped with DB2
Member that Language Function
contains
source code
DSNTEJ7 JCL Demonstrates how to create a table with LOB columns, an
auxiliary table, and an auxiliary index. Also demonstrates
how to load LOB data that is 32KB or less into a LOB table
space.
DSN8DLPL C Demonstrates the use of LOB locators and UPDATE
statements to move binary data into a column of type
BLOB.
DSN8DLRV C Demonstrates how to use a locator to manipulate data of
type CLOB.

Chapter 13. Programming for large objects (LOBs) 231


Table 22. LOB samples shipped with DB2 (continued)
Member that Language Function
contains
source code
DSNTEP2 PL/I Demonstrates how to allocate an SQLDA for rows that
include LOB data and use that SQLDA to describe an input
statement and fetch data from LOB columns.

For instructions on how to prepare and run the sample LOB applications, see Part 2
of DB2 Installation Guide.

Declaring LOB host variables and LOB locators


When you write applications to manipulate LOB data, you need to declare host
variables to hold the LOB data or LOB locator variables to point to the LOB data.
See “Using LOB locators to save storage” on page 236 for information on what LOB
locators are and when you should use them instead of host variables.

You can declare LOB host variables and LOB locators in assembler, C, C⁺⁺,
COBOL, FORTRAN, and PL/I. For each host variable or locator of SQL type BLOB,
CLOB, or DBCLOB that you declare, DB2 generates an equivalent declaration that
uses host language data types. When you refer to a LOB host variable or locator in
an SQL statement, you must use the variable you specified 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. See “Part 2. Coding SQL in your host
application program” on page 61 for the syntax of LOB declarations in each
language and for host language equivalents for each LOB type.

DB2 supports host variable declarations for LOBs with lengths of up to 2 GB - 1.


However, the size of a LOB host variable is limited by the restrictions of the host
language and the amount of storage available to the program.

The following examples show you how to declare LOB 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 LOB host variables in assembler: Table 23 shows assembler


language declarations for some typical LOB types.
Table 23. Example of assembler LOB variable declarations
You Declare this Variable DB2 Generates this Variable
blob_var SQL TYPE IS BLOB 1M blob_var DS 0FL4
blob_var_length DS FL4
blob_var_data DS CL655351
ORG blob_var_data+(1048476-65535)
clob_var SQL TYPE IS CLOB 40000K clob_var DS 0FL4
clob_var_length DS FL4
clob_var_data DS CL655351
ORG clob_var_data +(40960000-65535)
dbclob-var SQL TYPE IS DBCLOB 4000K dbclob_var DS 0FL4
dbclob_var_length DS FL4
dbclob_var_data DS GL655342
ORG dbclob_var_data+(8192000-65534)

232 Application Programming and SQL Guide


Table 23. Example of assembler LOB variable declarations (continued)
You Declare this Variable DB2 Generates this Variable
blob_loc SQL TYPE IS BLOB_LOCATOR blob_loc DS FL4
clob_loc SQL TYPE IS CLOB_LOCATOR clob_loc DS FL4
dbclob_var SQL TYPE IS DBCLOB_LOCATOR dbclob_loc DS FL4
Notes:
1. Because assembler language allows character declarations of no more than 65535 bytes,
DB2 separates the host language declarations for BLOB and 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 DBCLOB host variables that are longer
than 65534 bytes into two parts.

Declarations of LOB host variables in C: Table 24 shows C and C⁺⁺ language


declarations for some typical LOB types.
Table 24. Examples of C language variable declarations
You Declare this Variable DB2 Generates this Variable
SQL TYPE IS BLOB (1M) blob_var; struct {
unsigned long length;
char data[1048576];
} blob_var;
SQL TYPE IS CLOB(40000K) clob_var; struct {
unsigned long length;
char data[40960000];
} clob_var;
SQL TYPE IS DBCLOB (4000K) dbclob_var; struct {
unsigned long length;
wchar_t data[4096000];
} dbclob_var;
SQL TYPE IS BLOB_LOCATOR blob_loc; unsigned long blob_loc;
SQL TYPE IS CLOB_LOCATOR clob_loc; unsigned long clob_loc;
SQL TYPE IS DBCLOB_LOCATOR dbclob_loc; unsigned long dbclob_loc;

Declarations of LOB host variables in COBOL: Table 25 shows COBOL


declarations for some typical LOB types.
Table 25. Examples of COBOL variable declarations
You Declare this Variable DB2 Generates this Variable
01 BLOB-VAR USAGE IS 01 BLOB-VAR.
SQL TYPE IS BLOB(1M). 02 BLOB-VAR-LENGTH
PIC 9(9) COMP.
02 BLOB-VAR-DATA.
49 FILLER PIC X(32767).1
49 FILLER PIC X(32767).
Repeat 30 times
.
.
.

49 FILLER
PIC X(1048576-32*32767).

Chapter 13. Programming for large objects (LOBs) 233


Table 25. Examples of COBOL variable declarations (continued)
You Declare this Variable DB2 Generates this Variable
01 CLOB-VAR USAGE IS 01 CLOB-VAR.
SQL TYPE IS CLOB(40000K). 02 CLOB-VAR-LENGTH
PIC 9(9) COMP.
02 CLOB-VAR-DATA.
49 FILLER PIC X(32767).1
49 FILLER PIC X(32767).
Repeat 1248 times
.
.
.

49 FILLER
PIC X(40960000-1250*32767).
01 DBCLOB-VAR USAGE IS 01 DBCLOB-VAR.
SQL TYPE IS DBCLOB(4000K). 02 DBCLOB-VAR-LENGTH
PIC 9(9) COMP.
02 DBCLOB-VAR-DATA.
49 FILLER PIC G(32767)
USAGE DISPLAY-1.2
49 FILLER PIC G(32767)
USAGE DISPLAY-1.
Repeat 1248 times
.
.
.

49 FILLER
PIC X(20480000-1250*32767)
USAGE DISPLAY-1.
01 BLOB-LOC USAGE IS SQL 01 BLOB-LOC PIC S9(9) USAGE IS BINARY.
TYPE IS BLOB-LOCATOR.
01 CLOB-LOC USAGE IS SQL 01 CLOB-LOC PIC S9(9) USAGE IS BINARY.
TYPE IS CLOB-LOCATOR.
01 DBCLOB-LOC USAGE IS SQL 01 DBCLOB-LOC PIC S9(9) USAGE IS BINARY.
TYPE IS DBCLOB-LOCATOR.
Notes:
1. Because the COBOL language allows character declarations of no more than 32767
bytes, for BLOB or CLOB host variables that are greater than 32767 bytes in length, DB2
creates multiple host language declarations of 32767 or fewer bytes.
2. Because the COBOL language allows graphic declarations of no more than 32767
double-byte characters, for 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 LOB host variables in FORTRAN: Table 26 shows FORTRAN


declarations for some typical LOB types.
Table 26. Examples of FORTRAN variable declarations
You Declare this Variable DB2 Generates this Variable
SQL TYPE IS BLOB(1M) blob_var CHARACTER blob_var(1048580)
INTEGER*4 blob_var_LENGTH
CHARACTER blob_var_DATA
EQUIVALENCE( blob_var(1),
+ blob_var_LENGTH )
EQUIVALENCE( blob_var(5),
+ blob_var_DATA )

234 Application Programming and SQL Guide


Table 26. Examples of FORTRAN variable declarations (continued)
You Declare this Variable DB2 Generates this Variable
SQL TYPE IS CLOB(40000K) clob_var CHARACTER clob_var(4096004)
INTEGER*4 clob_var_length
CHARACTER clob_var_data
EQUIVALENCE( clob_var(1),
+ clob_var_length )
EQUIVALENCE( clob_var(5),
+ clob_var_data )
SQL TYPE IS BLOB_LOCATOR blob_loc INTEGER*4 blob_loc
SQL TYPE IS CLOB_LOCATOR clob_loc INTEGER*4 clob_loc

Declarations of LOB host variables in PL/I: Table 27 shows PL/I declarations for
some typical LOB types.
Table 27. Examples of PL/I variable declarations
You Declare this Variable DB2 Generates this Variable
DCL BLOB_VAR DCL 1 BLOB_VAR,
SQL TYPE IS BLOB (1M); 2 BLOB_VAR_LENGTH FIXED BINARY(31),
2 BLOB_VAR_DATA,1
3 BLOB_VAR_DATA1(32)
CHARACTER(32767),
3 BLOB_VAR_DATA2
CHARACTER(1048576-32*32767);
DCL CLOB_VAR DCL 1 CLOB_VAR,
SQL TYPE IS CLOB (40000K); 2 CLOB_VAR_LENGTH FIXED BINARY(31),
2 CLOB_VAR_DATA,1
3 CLOB_VAR_DATA1(1250)
CHARACTER(32767),
3 CLOB_VAR_DATA2
CHARACTER(40960000-1250*32767);
DCL DBCLOB_VAR DCL 1 DBCLOB_VAR,
SQL TYPE IS DBCLOB (4000K); 2 DBCLOB_VAR_LENGTH FIXED BINARY(31),
2 DBCLOB_VAR_DATA,2
3 DBCLOB_VAR_DATA1(2500)
GRAPHIC(16383),
3 DBCLOB_VAR_DATA2
GRAPHIC(40960000-2500*16383);
DCL blob_loc DCL blob_loc FIXED BINARY(31);
SQL TYPE IS BLOB_LOCATOR;
DCL clob_loc DCL clob_loc FIXED BINARY(31);
SQL TYPE IS CLOB_LOCATOR;
DCL dbclob_loc SQL TYPE IS DCL dbclob_loc FIXED BINARY(31);
DBCLOB_LOCATOR;

Chapter 13. Programming for large objects (LOBs) 235


Table 27. Examples of PL/I variable declarations (continued)
You Declare this Variable DB2 Generates this Variable
Notes:
1. Because the PL/I language allows character declarations of no more than 32767 bytes,
for BLOB or 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 LOB 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 LOB 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. Because the PL/I language allows graphic declarations of no more than 16383
double-byte characters, DB2 creates host language declarations in the following way:
v If the length of the LOB 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 LOB 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.

LOB materialization
LOB materialization means that DB2 places a LOB value into contiguous storage in
a data space. Because LOB values can be very large, DB2 avoids materializing
LOB data until absolutely necessary. However, DB2 must materialize LOBs when
your application program:
v Calls a user-defined function with a LOB as an argument
v Moves a LOB into or out of a stored procedure
v Assigns a LOB host variable to a LOB locator host variable
v Converts a LOB from one CCSID to another

Data spaces for LOB materialization: The amount of storage that is used in data
spaces for LOB materialization depends on a number of factors including:
v The size of the LOBs
v The number of LOBs that need to be materialized in a statement

DB2 allocates a certain number of data spaces for LOB materialization. If there is
insufficient space available in a data space for LOB materialization, your application
receives SQLCODE -904.

Although you cannot completely avoid LOB materialization, you can minimize it by
using LOB locators, rather than LOB host variables in your application programs.
See “Using LOB locators to save storage” for information on how to use LOB
locators.

Using LOB locators to save storage


To retrieve LOB data from a DB2 table, you can define host variables that are large
enough to hold all of the LOB data. This requires your application to allocate large
amounts of storage, and requires DB2 to move large amounts of data, which can
be inefficient or impractical. Instead, you can use LOB locators. LOB locators let

236 Application Programming and SQL Guide


you manipulate LOB data without retrieving the data from the DB2 table. Using LOB
locators for LOB data retrieval is a good choice in the following situations:
v When you move only a small part of a LOB to a client program
v When the entire LOB does not fit in the application's memory
v When the program needs a temporary LOB value from a LOB expression but
does not need to save the result
v When performance is important

A LOB locator is associated with a LOB value or expression, not with a row in a
DB2 table or a physical storage location in a table space. Therefore, after you
select a LOB value using a locator, the value in the locator normally does not
change until the current unit of work ends. However the value of the LOB itself can
change.

If you want to remove the association between a LOB locator and its value before a
unit of work ends, execute the FREE LOCATOR statement. To keep the association
between a LOB locator and its value after the unit of work ends, execute the HOLD
LOCATOR statement. After you execute a HOLD LOCATOR statement, the locator
keeps the association with the corresponding value until you execute a FREE
LOCATOR statement or the program ends.

If you execute HOLD LOCATOR or FREE LOCATOR dynamically, you cannot use
EXECUTE IMMEDIATE. For more information on HOLD LOCATOR and FREE
LOCATOR, see Chapter 5 of DB2 SQL Reference.

Deferring evaluation of a LOB expression to improve performance


DB2 moves no bytes of a LOB value until a program assigns a LOB expression to a
target destination. This means that when you use a LOB locator with string
functions and operators, you can create an expression that DB2 does not evaluate
until the time of assignment. This is called deferring evaluation of a LOB
expression. Deferring evaluation can improve LOB I/O performance.

The following example is a C language program that defers evaluation of a LOB


expression. The program runs on a client and modifies LOB data at a server. The
program searches for a particular resume (EMPNO = '000130') in the
EMP_RESUME table. It then uses LOB locators to rearrange a copy of the resume
(with EMPNO = 'A00130'). In the copy, the Department Information Section appears
at the end of the resume. The program then inserts the copy into EMP_RESUME
without modifying the original resume.

Because the program uses LOB locators, rather than placing the LOB data into host
variables, no LOB data is moved until the INSERT statement executes. In addition,
no LOB data moves between the client and the server.

Chapter 13. Programming for large objects (LOBs) 237


EXEC SQL INCLUDE SQLCA;

/**************************/
/* Declare host variables */ 1
/**************************/
EXEC SQL BEGIN DECLARE SECTION;
char userid[9];
char passwd[19];
long HV_START_DEPTINFO;
long HV_START_EDUC;
long HV_RETURN_CODE;
SQL TYPE IS CLOB_LOCATOR HV_NEW_SECTION_LOCATOR;
SQL TYPE IS CLOB_LOCATOR HV_DOC_LOCATOR1;
SQL TYPE IS CLOB_LOCATOR HV_DOC_LOCATOR2;
SQL TYPE IS CLOB_LOCATOR HV_DOC_LOCATOR3;
EXEC SQL END DECLARE SECTION;

Figure 95. Example of deferring evaluation of LOB expressions (Part 1 of 2)

238 Application Programming and SQL Guide


/*************************************************/
/* Delete any instance of "A00130" from previous */
/* executions of this sample */
/*************************************************/
EXEC SQL DELETE FROM EMP_RESUME WHERE EMPNO = 'A00130';

/*************************************************/
/* Use a single row select to get the document */ 2
/*************************************************/
EXEC SQL SELECT RESUME
INTO :HV_DOC_LOCATOR1
FROM EMP_RESUME
WHERE EMPNO = '000130'
AND RESUME_FORMAT = 'ascii';
/*****************************************************/
/* Use the POSSTR function to locate the start of */
/* sections "Department Information" and "Education" */ 3
/*****************************************************/
EXEC SQL SET :HV_START_DEPTINFO =
POSSTR(:HV_DOC_LOCATOR1, 'Department Information');

EXEC SQL SET :HV_START_EDUC =


POSSTR(:HV_DOC_LOCATOR1, 'Education');

/*******************************************************/
/* Replace Department Information section with nothing */
/*******************************************************/
EXEC SQL SET :HV_DOC_LOCATOR2 =
SUBSTR(:HV_DOC_LOCATOR1, 1, :HV_START_DEPTINFO -1)
|| SUBSTR (:HV_DOC_LOCATOR1, :HV_START_EDUC);
/*******************************************************/
/* Associate a new locator with the Department */
/* Information section */
/*******************************************************/
EXEC SQL SET :HV_NEW_SECTION_LOCATOR =
SUBSTR(:HV_DOC_LOCATOR1, :HV_START_DEPTINFO,
:HV_START_EDUC -:HV_START_DEPTINFO);

/*******************************************************/
/* Append the Department Information to the end */
/* of the resume */
/*******************************************************/
EXEC SQL SET :HV_DOC_LOCATOR3 =
:HV_DOC_LOCATOR2 || :HV_NEW_SECTION_LOCATOR;
/*******************************************************/
/* Store the modified resume in the table. This is */ 4
/* where the LOB data really moves. */
/*******************************************************/
EXEC SQL INSERT INTO EMP_RESUME VALUES ('A00130', 'ascii',
:HV_DOC_LOCATOR3, DEFAULT);

/*********************/
/* Free the locators */ 5
/*********************/
EXEC SQL FREE LOCATOR :HV_DOC_LOCATOR1, :HV_DOC_LOCATOR2, :HV_DOC_LOCATOR3;

Figure 95. Example of deferring evaluation of LOB expressions (Part 2 of 2)

Notes on Figure 95 on page 238:

1 Declare the LOB locators here.


2 This SELECT statement associates LOB locator HV_DOC_LOCATOR1 with the
value of column RESUME for employee number 000130.
3 The next five SQL statements use LOB locators to manipulate the resume data
without moving the data.

Chapter 13. Programming for large objects (LOBs) 239


4 Evaluation of the LOB expressions in the previous statements has been deferred
until execution of this INSERT statement.
5 Free all LOB locators to release them from their associated values.

Indicator variables and LOB locators


For host variables other than LOB locators, when you select a null value into a host
variable, DB2 assigns a negative value to the associated indicator variable.
However, for LOB locators, DB2 uses indicator variables differently. A LOB locator is
never null. When you select a LOB column using a LOB locator and the LOB
column contains a null value, DB2 assigns a null value to the associated indicator
variable. The value in the LOB locator does not change. In a client/server
environment, this null information is recorded only at the client.

When you use LOB locators to retrieve data from columns that can contain null
values, define indicator variables for the LOB locators, and check the indicator
variables after you fetch data into the LOB locators. If an indicator variable is null
after a fetch operation, you cannot use the value in the LOB locator.

Valid assignments for LOB locators


Although you usually use LOB locators for assigning data to and retrieving data
from LOB columns, you can also use LOB locators to assign data to CHAR,
VARCHAR, GRAPHIC, or VARGRAPHIC columns. However, you cannot fetch data
from CHAR, VARCHAR, GRAPHIC, or VARGRAPHIC columns into LOB locators.

240 Application Programming and SQL Guide


Chapter 14. Creating and using user-defined functions
A user-defined function is an extension to the SQL language. A user-defined
function is similar to a host language subprogram or function. However, a
user-defined function is often the better choice for an SQL application because you
can invoke a user-defined function in an SQL statement.

This chapter presents the following information about user-defined functions:


v “Overview of user-defined function definition, implementation, and invocation”
v “Defining a user-defined function” on page 244
v “Implementing an external user-defined function” on page 248
v “Implementing an SQL scalar function” on page 288
v “Invoking a user-defined function” on page 289

| This chapter contains information that applies to all user-defined functions and
| specific information about user-defined functions in languages other than Java™.
| For information on writing, preparing, and running Java user-defined functions, see
| DB2 Application Programming Guide and Reference for Java.

Overview of user-defined function definition, implementation, and


invocation
The types of user-defined functions are:
v Sourced user-defined functions, which are based on existing built-in functions or
user-defined functions
v External user-defined functions, which a programmer writes in a host language
| v SQL user-defined functions, which contain the source code for the user-defined
| function in the user-defined function definition.

User-defined functions can also be categorized as a user-defined scalar functions


or a user-defined table functions:
v A user-defined scalar function returns a single-value answer each time it is
invoked.
v A user-defined table function returns a table to the SQL statement that references
it.
External user-defined functions can be user-defined scalar functions or user-defined
| table functions. Sourced and SQL user-defined functions cannot be user-defined
table functions.

Creating and using a user-defined function involves these steps:


v Setting up the environment for user-defined functions
A system administrator probably performs this step. The user-defined function
environment is shown in Figure 96 on page 242. The steps for setting up and
maintaining the user-defined function environment are the same as for setting up
and maintaining the environment for stored procedures in WLM-established
address spaces. See “Chapter 24. Using stored procedures for client/server
processing” on page 527 for this information.
v Writing and preparing the user-defined function
This step is necessary only for an external user-defined function.
The person who performs this step is called the user-defined function
implementer.

© Copyright IBM Corp. 1983, 2001 241


v Defining the user-defined function to DB2
The person who performs this step is called the user-defined function definer.
v Invoking the user-defined function from an SQL application
The person who performs this step is called the user-defined function invoker.

Figure 96. The user-defined function environment

Example of creating and using a user-defined scalar function


Suppose that your organization needs a user-defined scalar function that calculates
the bonus that each employee receives. All employee data, including salaries,
commissions, and bonuses, is kept in the employee table, EMP. The input fields for
the bonus calculation function are the values of the SALARY and COMM columns.
The output from the function goes into the BONUS column. Because this function
gets its input from a DB2 table and puts the output in a DB2 table, a convenient
way to manipulate the data is through a user-defined function.

The user-defined function's definer and invoker determine that this new user-defined
function should have these characteristics:
v The user-defined function name is CALC_BONUS.
v The two input fields are of type DECIMAL(9,2).
v The output field is of type DECIMAL(9,2).
v The program for the user-defined function is written in COBOL and has a load
module name of CBONUS.

Because no built-in function or user-defined function exists on which to build a


sourced user-defined function, the function implementer must code an external
user-defined function. The implementer performs the following steps:
v Writes the user-defined function, which is a COBOL program
v Precompiles, compiles, and links the program
v Binds a package if the user-defined function contains SQL statements
v Tests the program thoroughly
v Grants execute authority on the user-defined function package to the definer

The user-defined function definer executes this CREATE FUNCTION statement to


register CALC_BONUS to DB2:

242 Application Programming and SQL Guide


CREATE FUNCTION CALC_BONUS(DECIMAL(9,2),DECIMAL(9,2))
RETURNS DECIMAL(9,2)
EXTERNAL NAME 'CBONUS'
PARAMETER STYLE DB2SQL
LANGUAGE COBOL;

The definer then grants execute authority on CALC_BONUS to all invokers.

User-defined function invokers write and prepare application programs that invoke
CALC_BONUS. An invoker might write a statement like this, which uses the
user-defined function to update the BONUS field in the employee table:
UPDATE EMP
SET BONUS = CALC_BONUS(SALARY,COMM);

An invoker can execute this statement either statically or dynamically.

User-defined function samples shipped with DB2


To assist you in defining, implementing, and invoking your user-defined functions,
DB2 provides a number of sample user-defined functions. All user-defined function
code is in data set DSN710.SDSNSAMP.

Table 28 summarizes the characteristics of the sample user-defined functions.


Table 28. User-defined function samples shipped with DB2
User-defined Language Member that Purpose
function name contains
source code
ALTDATE1 C DSN8DUAD Converts the current date to a
user-specified format
ALTDATE2 C DSN8DUCD Converts a date from one format to
another
ALTTIME3 C DSN8DUAT Converts the current time to a
user-specified format
ALTTIME4 C DSN8DUCT Converts a time from one format to
another
DAYNAME C⁺⁺ DSN8EUDN Returns the day of the week for a
user-specified date
MONTHNAME C⁺⁺ DSN8EUMN Returns the month for a user-specified
date
CURRENCY C DSN8DUCY Formats a floating-point number as a
currency value
TABLE_NAME C DSN8DUTI Returns the unqualified table name for a
table, view, or alias
TABLE_QUALIF C DSN8DUTI Returns the qualifier for a table, view, or
alias
TABLE_LOCATION C DSN8DUTI Returns the location for a table, view, or
alias
WEATHER C DSN8DUWF Returns a table of weather information
from a EBCDIC data set

Chapter 14. Creating and using user-defined functions 243


Table 28. User-defined function samples shipped with DB2 (continued)
User-defined Language Member that Purpose
function name contains
source code
Notes:
1. This version of ALTDATE has one input parameter, of type VARCHAR(13).
2. This version of ALTDATE has three input parameters, of type VARCHAR(17),
VARCHAR(13), and VARCHAR(13).
3. This version of ALTTIME has one input parameter, of type VARCHAR(14).
4. This version of ALTTIME has three input parameters, of type VARCHAR(11),
VARCHAR(14), and VARCHAR(14).

Member DSN8DUWC contains a client program that shows you how to invoke the
WEATHER user-defined table function.

Member DSNTEJ2U shows you how to define and prepare the sample user-defined
functions and the client program.

Defining a user-defined function


Before you can define a user-defined function to DB2, you must determine the
characteristics of the user-defined function, such as the user-defined function name,
schema (qualifier), and number and data types of the input parameters and the
types of the values returned. Then you execute a CREATE FUNCTION statement to
register the information in the DB2 catalog. If you discover after you define the
function that any of these characteristics is not appropriate for the function, you can
use an ALTER FUNCTION statement to change information in the definition. You
cannot use ALTER FUNCTION to change some of the characteristics of a
user-defined function definition. See Chapter 5 of DB2 SQL Reference for
information on which characteristics you can change with ALTER FUNCTION.

Components of a user-defined function definition


The characteristics you include in a CREATE FUNCTION or ALTER FUNCTION
statement depend on whether the user-defined function is external or sourced.
Table 29 lists the characteristics of a user-defined function, the corresponding
parameters in the CREATE FUNCTION and ALTER FUNCTION statements, and
which parameters are valid for sourced and external user-defined functions.
| Table 29. Characteristics of a user-defined function
| Characteristic CREATE FUNCTION or ALTER Valid in Valid in Valid in SQL
| FUNCTION parameter sourced external function?
| function? function?
| User-defined function FUNCTION Yes Yes Yes
| name
| Input parameter types FUNCTION Yes Yes Yes
| and encoding schemes
| Output parameter types RETURNS Yes Yes Yes2
| and encoding schemes RETURNS TABLE1
| Specific name SPECIFIC Yes Yes Yes
| External name EXTERNAL NAME No Yes No

244 Application Programming and SQL Guide


| Table 29. Characteristics of a user-defined function (continued)
| Characteristic CREATE FUNCTION or ALTER Valid in Valid in Valid in SQL
| FUNCTION parameter sourced external function?
| function? function?
| Language LANGUAGE ASSEMBLE No Yes Yes3
| LANGUAGE C
| LANGUAGE COBOL
| LANGUAGE PLI
| LANGUAGE JAVA
| LANGUAGE SQL
| Deterministic or not NOT DETERMINISTIC No Yes Yes
| deterministic DETERMINISTIC
| Types of SQL statements NO SQL No Yes4 Yes5
| in the function CONTAINS SQL
| READS SQL DATA
| MODIFIES SQL DATA
| Name of source function SOURCE Yes No No
| Parameter style PARAMETER STYLE DB2SQL No Yes Yes
| PARAMETER STYLE JAVA
| Address space for FENCED No Yes Yes
| user-defined functions
| Call with null input RETURNS NULL ON NULL INPUT No Yes Yes
| CALLED ON NULL INPUT
| External actions EXTERNAL ACTION No Yes Yes
| NO EXTERNAL ACTION
| Scratchpad specification NO SCRATCHPAD No Yes Yes
| SCRATCHPAD length
| Call function after SQL NO FINAL CALL No Yes Yes
| processing FINAL CALL
| Consider function for ALLOW PARALLEL No Yes4 Yes
| parallel processing DISALLOW PARALLEL
| Package collection NO COLLID No Yes No
| COLLID collection-id
| WLM environment WLM ENVIRONMENT name No Yes No
| WLM ENVIRONMENT name,*
| CPU time for a function ASUTIME NO LIMIT No Yes Yes
| invocation ASUTIME LIMIT integer
| Load module stays in STAY RESIDENT NO No Yes Yes
| memory STAY RESIDENT YES
| Program type PROGRAM TYPE MAIN No Yes Yes
| PROGRAM TYPE SUB
| Security SECURITY DB2 No Yes Yes
| SECURITY USER
| SECURITY DEFINER
| Run-time options RUN OPTIONS options No Yes Yes
| Pass DB2 environment NO DBINFO No Yes Yes
| information DBINFO
| Expected number of rows CARDINALITY integer No Yes1 No
| returned

Chapter 14. Creating and using user-defined functions 245


| Table 29. Characteristics of a user-defined function (continued)
| Characteristic CREATE FUNCTION or ALTER Valid in Valid in Valid in SQL
| FUNCTION parameter sourced external function?
| function? function?
| Function resolution is STATIC DISPATCH No No Yes
| based on the declared
| parameter types
| SQL expression that RETURN expression No No Yes
| evaluates to the value
| returned by the function
| Encoding scheme for all PARAMETER CCSID EBCDIC No Yes Yes
| string parameters PARAMETER CCSID ASCII
| PARAMETER CCSID UNICODE
| Notes:
| 1. RETURNS TABLE and CARDINALITY are valid only for user-defined table functions.
| 2. An SQL user-defined function can return only one parameter.
| 3. LANGUAGE SQL is valid only for an SQL user-defined function.
| 4. MODIFIES SQL DATA and ALLOW PARALLEL are not valid for user-defined table functions.
| 5. MODIFIES SQL DATA and NO SQL are not valid for SQL user-defined functions.
|

For a complete explanation of the parameters in a CREATE FUNCTION or ALTER


FUNCTION statement, see Chapter 5 of DB2 SQL Reference.

Examples of user-defined function definitions


Example: Definition for an external user-defined scalar function: A programmer
has written a user-defined function that searches for a string of maximum length
200 in a CLOB value whose maximum length is 500 KB. The output from the
user-defined function is of type float, but users require integer output for their SQL
statements. The user-defined function is written in C and contains no SQL
statements. This CREATE FUNCTION statement defines the user-defined function:
CREATE FUNCTION FINDSTRING (CLOB(500K), VARCHAR(200))
RETURNS INTEGER
CAST FROM FLOAT
SPECIFIC FINDSTRINCLOB
EXTERNAL NAME 'FINDSTR'
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION
FENCED;

Example: Definition for an external user-defined scalar function that overloads


an operator: A programmer has written a user-defined function that overloads the
built-in SQL division operator (/). That is, this user-defined function is invoked when
an application program executes a statement like either of the following:
UPDATE TABLE1 SET INTCOL1=INTCOL2/INTCOL3;
UPDATE TABLE1 SET INTCOL1="/"(INTCOL2,INTCOL3);

The user-defined function takes two integer values as input. The output from the
user-defined function is of type integer. The user-defined function is in the MATH
schema, is written in assembler, and contains no SQL statements. This CREATE
FUNCTION statement defines the user-defined function:

246 Application Programming and SQL Guide


CREATE FUNCTION MATH."/" (INT, INT)
RETURNS INTEGER
SPECIFIC DIVIDE
EXTERNAL NAME 'DIVIDE'
LANGUAGE ASSEMBLE
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION
FENCED;

Suppose you want the FINDSTRING user-defined function to work on BLOB data
types, as well as CLOB types. You can define another instance of the user-defined
function that specifies a BLOB type as input:
CREATE FUNCTION FINDSTRING (BLOB(500K), VARCHAR(200))
RETURNS INTEGER
CAST FROM FLOAT
SPECIFIC FINDSTRINBLOB
EXTERNAL NAME 'FNDBLOB'
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION
FENCED;

Each instance of FINDSTRING uses a different application program to implement


the user-defined function.

Example: Definition for a sourced user-defined function: Suppose you need a


user-defined function that finds a string in a value with a distinct type of BOAT.
BOAT is based on a BLOB data type. User-defined function FINDSTRING has
already been defined. FINDSTRING takes a BLOB data type and performs the
required function. You can therefore define a sourced user-defined function based
on FINDSTRING to do the string search on values of type BOAT. This CREATE
FUNCTION statement defines the sourced user-defined function:
CREATE FUNCTION FINDSTRING (BOAT, VARCHAR(200))
RETURNS INTEGER
SPECIFIC FINDSTRINBOAT
SOURCE SPECIFIC FINDSTRINBLOB;

Example: Definition for a user-defined table function: An application


programmer has written a user-defined function that receives two values and
returns a table. The two input values are:
v A character string of maximum length 30 that describes a subject
v A character string of maximum length 255 that contains text to search for
The user-defined function scans documents on the subject for the search string and
returns a list of documents that match the search criteria, with an abstract for each
document. The list is in the form of a two-column table. The first column is a
character column of length 16 that contains document IDs. The second column is a
varying-character column of maximum length 5000 that contains document
abstracts.

The user-defined function is written in COBOL, uses SQL only to perform queries,
always produces the same output for given input, and should not execute as a
parallel task. The program is reentrant, and successive invocations of the
user-defined function share information. You expect an invocation of the
user-defined function to return about 20 rows.

Chapter 14. Creating and using user-defined functions 247


The following CREATE FUNCTION statement defines the user-defined function:
CREATE FUNCTION DOCMATCH (VARCHAR(30), VARCHAR(255))
RETURNS TABLE (DOC_ID CHAR(16), DOC_ABSTRACT VARCHAR(5000))
EXTERNAL NAME 'DOCMTCH'
LANGUAGE COBOL
PARAMETER STYLE DB2SQL
READS SQL DATA
DETERMINISTIC
NO EXTERNAL ACTION
FENCED
SCRATCHPAD
FINAL CALL
DISALLOW PARALLEL
CARDINALITY 20;

Implementing an external user-defined function


This section discusses these steps in implementing an external user-defined
function:
v “Writing a user-defined function”
v “Preparing a user-defined function for execution” on page 284
v “Testing a user-defined function” on page 286

Writing a user-defined function


A user-defined function is similar to any other SQL program. When you write a
user-defined function, you can include static or dynamic SQL statements, IFI calls,
and DB2 commands issued through IFI calls.

Your user-defined function can also access remote data using the following
methods:
v DB2 private protocol access using three-part names or aliases for three-part
names
v DRDA access using three-part names or aliases for three-part names
v DRDA access using CONNECT or SET CONNECTION statements
The user-defined function and the application that calls it can access the same
remote site if both use the same protocol.

You can write an external user-defined function in assembler, C, C⁺⁺, COBOL, PL/I,
or Java. User-defined functions that are written in COBOL can include
object-oriented extensions, just as other DB2 COBOL programs can. For
information on writing Java user-defined functions, see DB2 Application
Programming Guide and Reference for Java.

The following sections include additional information that you need when you write
a user-defined function:
v “Restrictions on user-defined function programs” on page 249
v “Coding your user-defined function as a main program or as a subprogram” on
page 249
v “Parallelism considerations” on page 249
v “Passing parameter values to and from a user-defined function” on page 251
v “Examples of passing parameters in a user-defined function” on page 263
v “Using special registers in a user-defined function” on page 276
v “Using a scratchpad in a user-defined function” on page 277
v “Accessing transition tables in a user-defined function or stored procedure” on
page 279

248 Application Programming and SQL Guide


Restrictions on user-defined function programs
Observe these restrictions when you write a user-defined function:
v Because DB2 uses the Recoverable Resource Manager Services attachment
facility (RRSAF) as its interface with your user-defined function, you must not
include RRSAF calls in your user-defined function. DB2 rejects any RRSAF calls
that it finds in a user-defined function.
v If your user-defined function is not defined with parameters SCRATCHPAD or
EXTERNAL ACTION, the user-defined function is not guaranteed to execute
under the same task each time it is invoked.
v You cannot execute COMMIT or ROLLBACK statements in your user-defined
function.
v You must close all open cursors in a user-defined scalar function. DB2 returns an
SQL error if a user-defined scalar function does not close all cursors before it
completes.
v When you choose the language in which to write a user-defined function
program, be aware of restrictions on the number of parameters that can be
passed to a routine in that language. User-defined table functions in particular
can require large numbers of parameters. Consult the programming guide for the
language in which you plan to write the user-defined function for information on
the number of parameters that can be passed.

Coding your user-defined function as a main program or as a


subprogram
You can code your user-defined function as either a main program or a
subprogram. The way that you code your program must agree with the way you
defined the user-defined function: with the PROGRAM TYPE MAIN or PROGRAM
TYPE SUB parameter. The main difference is that when a main program starts,
Language Environment allocates the application program storage that the external
user-defined function uses. When a main program ends, Language Environment®
closes files and releases dynamically allocated storage.

If you code your user-defined function as a subprogram and manage the storage
and files yourself, you can get better performance. The user-defined function should
always free any allocated storage before it exits. To keep data between invocations
of the user-defined function, use a scratchpad.

You must code a user-defined table function that accesses external resources as a
subprogram. Also ensure that the definer specifies the EXTERNAL ACTION
parameter in the CREATE FUNCTION or ALTER FUNCTION statement. Program
variables for a subprogram persist between invocations of the user-defined function,
and use of the EXTERNAL ACTION parameter ensures that the user-defined
function stays in the same address space from one invocation to another.

Parallelism considerations
If the definer specifies the parameter ALLOW PARALLEL in the definition of a
user-defined scalar function, and the invoking SQL statement runs in parallel, the
function can run under a parallel task. DB2 executes a separate instance of the
user-defined function for each parallel task. When you write your function program,
you need to understand how the following parameter values interact with ALLOW
PARALLEL so that you can avoid unexpected results:
v SCRATCHPAD
When an SQL statement invokes a user-defined function that is defined with the
ALLOW PARALLEL parameter, DB2 allocates one scratchpad for each parallel
task of each reference to the function. This can lead to unpredictable or incorrect
results.

Chapter 14. Creating and using user-defined functions 249


For example, suppose that the user-defined function uses the scratchpad to
count the number of times it is invoked. If a scratchpad is allocated for each
parallel task, this count is the number of invocations done by the parallel task
and not for the entire SQL statement, which is not the desired result.
v FINAL CALL
If a user-defined function performs an external action, such as sending a note,
for each final call to the function, one note is sent for each parallel task instead
of once for the function invocation.
v EXTERNAL ACTION
Some user-defined functions with external actions can receive incorrect results if
the function is executed by parallel tasks.
For example, if the function sends a note for each initial call to the function, one
note is sent for each parallel task instead of once for the function invocation.
v NOT DETERMINISTIC
A user-defined function that is not deterministic can generate incorrect results if it
is run under a parallel task.
For example, suppose that you execute the following query under parallel tasks:
SELECT * FROM T1 WHERE C1 = COUNTER();

COUNTER is a user-defined function that increments a variable in the scratchpad


every time it is invoked. Counter is nondeterministic because the same input
does not always produce the same output. Table T1 contains one column, C1,
that has these values:
1
2
3
4
5
6
7
8
9
10

When the query is executed with no parallelism, DB2 invokes COUNTER once
for each row of table T1, and there is one scratchpad for counter, which DB2
initializes the first time that COUNTER executes. COUNTER returns 1 the first
time it executes, 2 the second time, and so on. The result table for the query is
therefore:
1
2
3
4
5
6
7
8
9
10

Now suppose that the query is run with parallelism, and DB2 creates three
parallel tasks. DB2 executes the predicate WHERE C1 = COUNTER() for each
parallel task. This means that each parallel task invokes its own instance of the
user-defined function and has its own scratchpad. DB2 initializes the scratchpad
to zero on the first call to the user-defined function for each parallel task.

250 Application Programming and SQL Guide


If parallel task 1 processes rows 1 to 3, parallel task 2 processes rows 4 to 6,
and parallel task 3 processes rows 7 to 10, the following results occur:
– When parallel task 1 executes, C1 has values 1, 2, and 3, and COUNTER
returns values 1, 2, and 3, so the query returns values 1, 2, and 3.
– When parallel task 2 executes, C1 has values 4, 5, and 6, but COUNTER
returns values 1, 2, and 3, so the query returns no rows.
– When parallel task 3, executes, C1 has values 7, 8, 9, and 10, but COUNTER
returns values 1, 2, 3, and 4, so the query returns no rows.
Thus, instead of returning the 10 rows that you might expect from the query, DB2
returns only 3 rows.

Passing parameter values to and from a user-defined function


To receive parameters from and pass parameters to a function invoker, you must
understand the structure of the parameter list, the meaning of each parameter, and
whether DB2 or your user-defined function sets the value of each parameter. This
section explains the parameters and gives examples of how a user-defined function
in each host language receives the parameter list.

Figure 97 on page 252 shows the structure of the parameter list that DB2 passes to
a user-defined function. An explanation of each parameter follows.

Chapter 14. Creating and using user-defined functions 251


Figure 97. Parameter conventions for a user-defined function

Input parameter values: DB2 obtains the input parameters from the invoker's
parameter list, and your user-defined function receives those parameters according
to the rules of the host language in which the user-defined function is written. The
number of input parameters is the same as the number of parameters in the
user-defined function invocation. If one of the parameters in the function invocation
is an expression, DB2 evaluates the expression and assigns the result of the
expression to the parameter.

252 Application Programming and SQL Guide


For all data types except LOBs, ROWIDs, and locators, see the tables listed in
Table 30 for the host data types that are compatible with the data types in the
user-defined function definition. For LOBs, ROWIDs, and locators, see tables
Table 31, Table 32, Table 33 on page 254, and Table 34 on page 255.
Table 30. Listing of tables of compatible data types
Language Compatible data types table
Assembler Table 8 on page 115
C Table 10 on page 133
COBOL Table 13 on page 156
PL/I Table 17 on page 184

Table 31. Compatible assembler language declarations for LOBs, ROWIDs, and locators
SQL data type in definition Assembler declaration
TABLE LOCATOR DS FL4
BLOB LOCATOR
CLOB LOCATOR
DBCLOB LOCATOR
BLOB(n) If n <= 65535:
var DS 0FL4
var_length DS FL4
var_data DS CLn
If n > 65535:
var DS 0FL4
var_length DS FL4
var_data DS CL65535
ORG var_data+(n-65535)
CLOB(n) If n <= 65535:
var DS 0FL4
var_length DS FL4
var_data DS CLn
If n > 65535:
var DS 0FL4
var_length DS FL4
var_data DS CL65535
ORG var_data+(n-65535)
DBCLOB(n) If m (=2*n) <= 65534:
var DS 0FL4
var_length DS FL4
var_data DS CLm
If m > 65534:
var DS 0FL4
var_length DS FL4
var_data DS CL65534
ORG var_data+(m-65534)
ROWID DS HL2,CL40

Table 32. Compatible C language declarations for LOBs, ROWIDs, and locators
SQL data type in definition C declaration
TABLE LOCATOR unsigned long
BLOB LOCATOR
CLOB LOCATOR
DBCLOB LOCATOR

Chapter 14. Creating and using user-defined functions 253


Table 32. Compatible C language declarations for LOBs, ROWIDs, and locators (continued)
SQL data type in definition C declaration
BLOB(n) struct
{unsigned long length;
char data[n];
} var;
CLOB(n) struct
{unsigned long length;
char var_data[n];
} var;
DBCLOB(n) struct
{unsigned long length;
wchar_t* data[n];
} var;
ROWID struct {
short int length;
char data[40];
} var;
Note: *The SQLUDF file, which is in data set DSN710.SDSNC.H, includes the typedef
sqldbchar, which you can use instead of wchar_t. Using sqldbchar lets you manipulate DBCS
and Unicode UTF-16 data in the same format in which it is stored in DB2. sqldbchar also
makes applications easier to port to other DB2 platforms.

Table 33. Compatible COBOL declarations for LOBs, ROWIDs, and locators
SQL data type in definition COBOL declaration
TABLE LOCATOR 01 var PIC S9(9) USAGE IS BINARY.
BLOB LOCATOR
CLOB LOCATOR
DBCLOB LOCATOR
BLOB(n) If n <= 32767:
01 var.
49 var-LENGTH PIC 9(9)
USAGE COMP.
49 var-DATA PIC X(n).
If length > 32767:
01 var.
02 var-LENGTH PIC S9(9)
USAGE COMP.
02 var-DATA.
49 FILLER
PIC X(32767).
49 FILLER
PIC X(32767).
.
.
.

49 FILLER
PIC X(mod(n,32767)).

254 Application Programming and SQL Guide


Table 33. Compatible COBOL declarations for LOBs, ROWIDs, and locators (continued)
SQL data type in definition COBOL declaration
CLOB(n) If n <= 32767:
01 var.
49 var-LENGTH PIC 9(9)
USAGE COMP.
49 var-DATA PIC X(n).
If length > 32767:
01 var.
02 var-LENGTH PIC S9(9)
USAGE COMP.
02 var-DATA.
49 FILLER
PIC X(32767).
49 FILLER
PIC X(32767).
.
.
.

49 FILLER
PIC X(mod(n,32767)).
DBCLOB(n) If n <= 32767:
01 var.
49 var-LENGTH PIC 9(9)
USAGE COMP.
49 var-DATA PIC G(n)
USAGE DISPLAY-1.
If length > 32767:
01 var.
02 var-LENGTH PIC S9(9)
USAGE COMP.
02 var-DATA.
49 FILLER
PIC G(32767)
USAGE DISPLAY-1.
49 FILLER
PIC G(32767).
USAGE DISPLAY-1.
.
.
.

49 FILLER
PIC G(mod(n,32767))
USAGE DISPLAY-1.
ROWID 01 var.
49 var-LEN PIC 9(4)
USAGE COMP.
49 var-DATA PIC X(40).

Table 34. Compatible PL/I declarations for LOBs, ROWIDs, and locators
SQL data type in definition PL/I
TABLE LOCATOR BIN FIXED(31)
BLOB LOCATOR
CLOB LOCATOR
DBCLOB LOCATOR

Chapter 14. Creating and using user-defined functions 255


Table 34. Compatible PL/I declarations for LOBs, ROWIDs, and locators (continued)
SQL data type in definition PL/I
BLOB(n) If n <= 32767:
01 var,
03 var_LENGTH
BIN FIXED(31),
03 var_DATA
CHAR(n);
If n > 32767:
01 var,
02 var_LENGTH
BIN FIXED(31),
02 var_DATA,
03 var_DATA1(n)
CHAR(32767),
03 var_DATA2
CHAR(mod(n,32767));
CLOB(n) If n <= 32767:
01 var,
03 var_LENGTH
BIN FIXED(31),
03 var_DATA
CHAR(n);
If n > 32767:
01 var,
02 var_LENGTH
BIN FIXED(31),
02 var_DATA,
03 var_DATA1(n)
CHAR(32767),
03 var_DATA2
CHAR(mod(n,32767));
DBCLOB(n) If n <= 16383:
01 var,
03 var_LENGTH
BIN FIXED(31),
03 var_DATA
GRAPHIC(n);
If n > 16383:
01 var,
02 var_LENGTH
BIN FIXED(31),
02 var_DATA,
03 var_DATA1(n)
GRAPHIC(16383),
03 var_DATA2
GRAPHIC(mod(n,16383));
ROWID CHAR(40) VAR;

Result parameters: Set these values in your user-defined function before exiting.
For a user-defined scalar function, you return one result parameter. For a
user-defined table function, you return the same number of parameters as columns
in the RETURNS TABLE clause of the CREATE FUNCTION statement. DB2
allocates a buffer for each result parameter value and passes the buffer address to
the user-defined function. Your user-defined function places each result parameter
value in its buffer. You must ensure that the length of the value you place in each

256 Application Programming and SQL Guide


output buffer does not exceed the buffer length. Use the SQL data type and length
in the CREATE FUNCTION statement to determine the buffer length.

See “Passing parameter values to and from a user-defined function” on page 251 to
determine the host data type to use for each result parameter value. If the CREATE
FUNCTION statement contains a CAST FROM clause, use a data type that
corresponds to the SQL data type in the CAST FROM clause. Otherwise, use a
data type that corresponds to the SQL data type in the RETURNS or RETURNS
TABLE clause.

To improve performance for user-defined table functions that return many columns,
you can pass values for a subset of columns to the invoker. For example, a
user-defined table function might be defined to return 100 columns, but the invoker
needs values for only two columns. Use the DBINFO parameter to indicate to DB2
the columns for which you will return values. Then return values for only those
columns. See the explanation of DBINFO below for information on how to indicate
the columns of interest.

Input parameter indicators: These are SMALLINT values, which DB2 sets before
it passes control to the user-defined function. You use the indicators to determine
whether the corresponding input parameters are null. The number and order of the
indicators are the same as the number and order of the input parameters. On entry
to the user-defined function, each indicator contains one of these values:
0 The input parameter value is not null.
negative The input parameter value is null.

Code the user-defined function to check all indicators for null values unless the
user-defined function is defined with RETURNS NULL ON NULL INPUT. A
user-defined function defined with RETURNS NULL ON NULL INPUT executes only
if all input parameters are not null.

Result indicators: These are SMALLINT values, which you must set before the
user-defined function ends to indicate to the invoking program whether each result
parameter value is null. A user-defined scalar function has one result indicator. A
user-defined table function has the same number of result indicators as the number
of result parameters. The order of the result indicators is the same as the order of
the result parameters. Set each result indicator to one of these values:
0 or positive The result parameter is not null.
negative The result parameter is null.

SQLSTATE value: This is a CHAR(5) value, which you must set before the
user-defined function ends. The user-defined function can return one of these
SQLSTATE values:
00000 Use this value to indicate that the user-defined function executed
without any warnings or errors.
01Hxx Use these values to indicate that the user-defined function detected
a warning condition. xx can be any two single-byte alphanumeric
characters. DB2 returns SQLCODE +462 if the user-defined
function sets the SQLSTATE to 01Hxx.
02000 Use this value to indicate that there no more rows are to be
returned from a user-defined table function.
38yxx Use these values to indicate that the user-defined function detected

Chapter 14. Creating and using user-defined functions 257


an error condition. y can be any single-byte alphanumeric character
except 5. xx can be any two single-byte alphanumeric characters.
However, if an SQL statement in the user-defined function returns
one of the following SQLSTATEs, passing that SQLSTATE back to
the invoker is recommended.
38001 The user-defined function attempted to execute an
SQL statement, but the user-defined function is
defined with NO SQL. DB2 returns SQLCODE -487
with this SQLSTATE.
38002 The user-defined function attempted to execute an
SQL statement that requires that the user-defined
function is defined with MODIFIES SQL DATA, but
the user-defined function is not defined with
MODIFIES SQL DATA. DB2 returns SQLCODE
-577 with this SQLSTATE.
38003 The user-defined function executed a COMMIT or
ROLLBACK statement, which is not permitted in a
user-defined function. DB2 returns SQLCODE -751
with this SQLSTATE.
38004 The user-defined function attempted to execute an
SQL statement that requires that the user-defined
function is defined with READS SQL DATA or
MODIFIES SQL DATA, but the user-defined
function is not defined with either of these options.
DB2 returns SQLCODE -579 with this SQLSTATE.

When your user-defined function returns an SQLSTATE of 38yxx other than one of
the four listed above, DB2 returns SQLCODE -443.

If the user-defined function returns an SQLSTATE that is not permitted for a


user-defined function, DB2 replaces that SQLSTATE with 39001 and returns
SQLCODE -463.

If both the user-defined function and DB2 set an SQLSTATE value, DB2 returns its
SQLSTATE value to the invoker.

User-defined function name: DB2 sets this value in the parameter list before the
user-defined function executes. This value is VARCHAR(137): 8 bytes for the
schema name, 1 byte for a period, and 128 bytes for the user-defined function
name. If you use the same code to implement multiple versions of a user-defined
function, you can use this parameter to determine which version of the function the
invoker wants to execute.

Specific name: DB2 sets this value in the parameter list before the user-defined
function executes. This value is VARCHAR(128) and is either the specific name
from the CREATE FUNCTION statement or a specific name that DB2 generated. If
you use the same code to implement multiple versions of a user-defined function,
you can use this parameter to determine which version of the function the invoker
wants to execute.

Diagnostic message: This is a VARCHAR(70) value, which your user-defined


function can set before exiting. Use this area to pass descriptive information about
an error or warning to the invoker.

258 Application Programming and SQL Guide


DB2 allocates a 70-byte buffer for this area and passes you the buffer address in
the parameter list. Ensure that you do not write more than 70 bytes to the buffer. At
least the first 17 bytes of the value you put in the buffer appear in the SQLERRMC
field of the SQLCA that is returned to the invoker. The exact number of bytes
depends on the number of other tokens in SQLERRMC. Do not use X'FF' in your
diagnostic message. DB2 uses this value to delimit tokens.

Scratchpad: If the definer specified SCRATCHPAD in the CREATE FUNCTION


statement, DB2 allocates a buffer for the scratchpad area and passes its address to
the user-defined function. Before the user-defined function is invoked for the first
time in an SQL statement, DB2 sets the length of the scratchpad in the first 4 bytes
of the buffer and then sets the scratchpad area to X'00'. DB2 does not reinitialize
the scratchpad between invocations of a correlated subquery.

You must ensure that your user-defined function does not write more bytes to the
scratchpad than the scratchpad length.

Call type: For a user-defined scalar function, if the definer specified FINAL CALL in
the CREATE FUNCTION statement, DB2 passes this parameter to the user-defined
function. For a user-defined table function, DB2 always passes this parameter to
the user-defined function.

On entry to a user-defined scalar function, the call type parameter has one of the
following values:
-1 This is the first call to the user-defined function for the SQL statement. For
a first call, all input parameters are passed to the user-defined function. In
addition, the scratchpad, if allocated, is set to binary zeros.
0 This is a normal call. For a normal call, all the input parameters are passed
to the user-defined function. If a scratchpad is also passed, DB2 does not
modify it.
1 This is a final call. For a final call, no input parameters are passed to the
user-defined function. If a scratchpad is also passed, DB2 does not modify
it.
This type of final call occurs when the invoking application explicitly closes
a cursor. When a value of 1 is passed to a user-defined function, the
user-defined function can execute SQL statements.
255 This is a final call. For a final call, no input parameters are passed to the
user-defined function. If a scratchpad is also passed, DB2 does not modify
it.
This type of final call occurs when the invoking application executes a
COMMIT or ROLLBACK statement, or when the invoking application
abnormally terminates. When a value of 255 is passed to the user-defined
function, the user-defined function cannot execute any SQL statements,
except for CLOSE CURSOR. If the user-defined function executes any
close cursor statements during this type of final call, the user-defined
function should tolerate SQLCODE -501 because DB2 might have already
closed cursors before the final call.

During the first call, your user-defined scalar function should acquire any system
resources it needs. During the final call, the user-defined scalar function should
release any resources it acquired during the first call. The user-defined scalar
function should return a result value only during normal calls. DB2 ignores any

Chapter 14. Creating and using user-defined functions 259


results that are returned during a final call. However, the user-defined scalar
function can set the SQLSTATE and diagnostic message area during the final call.

If an invoking SQL statement contains more than one user-defined scalar function,
and one of those user-defined functions returns an error SQLSTATE, DB2 invokes
all of the user-defined functions for a final call, and the invoking SQL statement
receives the SQLSTATE of the first user-defined function with an error.

On entry to a user-defined table function, the call type parameter has one of the
following values:
-2 This is the first call to the user-defined function for the SQL statement. A
first call occurs only if the FINAL CALL keyword is specified in the
user-defined function definition. For a first call, all input parameters are
passed to the user-defined function. In addition, the scratchpad, if allocated,
is set to binary zeros.
-1 This is the open call to the user-defined function by an SQL statement. If
FINAL CALL is not specified in the user-defined function definition, all input
parameters are passed to the user-defined function, and the scratchpad, if
allocated, is set to binary zeros during the open call. If FINAL CALL is
specified for the user-defined function, DB2 does not modify the scratchpad.
0 This is a fetch call to the user-defined function by an SQL statement. For a
fetch call, all input parameters are passed to the user-defined function. If a
scratchpad is also passed, DB2 does not modify it.
1 This is a close call. For a close call, no input parameters are passed to the
user-defined function. If a scratchpad is also passed, DB2 does not modify
it.
2 This is a final call. This type of final call occurs only if FINAL CALL is
specified in the user-defined function definition. For a final call, no input
parameters are passed to the user-defined function. If a scratchpad is also
passed, DB2 does not modify it.
This type of final call occurs when the invoking application executes a
CLOSE CURSOR statement.
255 This is a final call. For a final call, no input parameters are passed to the
user-defined function. If a scratchpad is also passed, DB2 does not modify
it.
This type of final call occurs when the invoking application executes a
COMMIT or ROLLBACK statement, or when the invoking application
abnormally terminates. When a value of 255 is passed to the user-defined
function, the user-defined function cannot execute any SQL statements,
except for CLOSE CURSOR. If the user-defined function executes any
close cursor statements during this type of final call, the user-defined
function should tolerate SQLCODE -501 because DB2 might have already
closed cursors before the final call.

If a user-defined table function is defined with FINAL CALL, the user-defined


function should allocate any resources it needs during the first call and release
those resources during the final call that sets a value of 2.

If a user-defined table function is defined with NO FINAL CALL, the user-defined


function should allocate any resources it needs during the open call and release
those resources during the close call.

260 Application Programming and SQL Guide


During a fetch call, the user-defined table function should return a row. If the
user-defined function has no more rows to return, it should set the SQLSTATE to
02000.

During the close call, a user-defined table function can set the SQLSTATE and
diagnostic message area.

If a user-defined table function is invoked from a subquery, the user-defined table


function receives a CLOSE call for each invocation of the subquery within the
higher level query, and a subsequent OPEN call for the next invocation of the
subquery within the higher level query.

DBINFO: If the definer specified DBINFO in the CREATE FUNCTION statement,


DB2 passes the DBINFO structure to the user-defined function. DBINFO contains
information about the environment of the user-defined function caller. It contains the
following fields, in the order shown:
Location name length
An unsigned 2-byte integer field. It contains the length of the location name in
the next field.
Location name
A 128-byte character field. It contains the name of the location to which the
invoker is currently connected.
Authorization ID length
An unsigned 2-byte integer field. It contains the length of the authorization ID in
the next field.
Authorization ID
A 128-byte character field. It contains the authorization ID of the application
from which the user-defined function is invoked, padded on the right with
blanks. If this user-defined function is nested within other user-defined
functions, this value is the authorization ID of the application that invoked the
highest-level user-defined function.
Subsystem code page
A 48-byte structure that consists of 10 integer fields and an eight-byte reserved
area. These fields provide information about the CCSIDs and encoding scheme
of the subsystem from which the user-defined function is invoked. The first nine
fields are arranged in an array of three inner structures, each of which contains
three integer fields. The three fields in each inner structure contain an SBCS, a
DBCS, and a mixed CCSID. The first of the three inner structures is for
EBCDIC CCSIDs. The second inner structure is for ASCII CCSIDs. The third
inner structure is for Unicode CCSIDs. The last integer field in the outer
structure is an index into the array of inner structures.
Table qualifier length
An unsigned 2-byte integer field. It contains the length of the table qualifier in
the next field. If the table name field is not used, this field contains 0.
Table qualifier
A 128-byte character field. It contains the qualifier of the table that is specified
in the table name field.
Table name length
An unsigned 2-byte integer field. It contains the length of the table name in the
next field. If the table name field is not used, this field contains 0.

Chapter 14. Creating and using user-defined functions 261


Table name
A 128-byte character field. This field contains the name of the table that the
UPDATE or INSERT modifies if the reference to the user-defined function in the
invoking SQL statement is in one of the following places:
v The right side of a SET clause in an UPDATE statement
v In the VALUES list of an INSERT statement
Otherwise, this field is blank.
Column name length
An unsigned 2-byte integer field. It contains the length of the column name in
the next field. If no column name is passed to the user-defined function, this
field contains 0.
Column name
A 128-byte character field. This field contains the name of the column that the
UPDATE or INSERT modifies if the reference to the user-defined function in the
invoking SQL statement is in one of the following places:
v The right side of a SET clause in an UPDATE statement
v In the VALUES list of an INSERT statement
Otherwise, this field is blank.
Product information
An 8-byte character field that identifies the product on which the user-defined
function executes. This field has the form pppvvrrm, where:
v ppp is a 3-byte product code:
DSN DB2 for OS/390 and z/OS
ARI DB2 Server for VSE & VM
QSQ DB2 for AS/400®
SQL DB2 Universal Database
v vv is a 2-digit version identifier.
v rr is a 2-digit release identifier.
v m is a 1-digit modification level identifier.
Operating system
A 4-byte integer field. It identifies the operating system on which the program
that invokes the user-defined function runs. The value is one of these:
0 Unknown
1 OS/2®
3 Windows®
4 AIX
5 Windows NT®
6 HP-UX
7 Solaris
8 OS/390
13 Siemens Nixdorf
15 Windows 95
16 SCO Unix

262 Application Programming and SQL Guide


Number of entries in table function column list
An unsigned 2-byte integer field.
Reserved area
24 bytes.
Table function column list pointer
If a table function is defined, this field is a pointer to an array that contains 1000
2-byte integers. DB2 dynamically allocates the array. If a table function is not
defined, this pointer is null.
Only the first n entries, where n is the value in the field entitled number of
entries in table function column list, are of interest. n is greater than or equal to
0 and less than or equal to the number result columns defined for the
user-defined function in the RETURNS TABLE clause of the CREATE
FUNCTION statement. The values correspond to the numbers of the columns
that the invoking statement needs from the table function. A value of 1 means
the first defined result column, 2 means the second defined result column, and
so on. The values can be in any order. If n is equal to 0, the first array element
is 0. This is the case for a statement like the following one, where the invoking
statement needs no column values.
SELECT COUNT(*) FROM TABLE(TF(...)) AS QQ

This array represents an opportunity for optimization. The user-defined function


does not need to return all values for all the result columns of the table function.
Instead, the user-defined function can return only those columns that are
needed in the particular context, which you identify by number in the array.
However, if this optimization complicates the user-defined function logic enough
to cancel the perfomance benefit, you might choose to return every defined
column.
Unique application identifier
This field is a pointer to a string that uniquely identifies the application's
connection to DB2. The string is regenerated for each connection to DB2.
The string is the LUWID, which consists of a fully-qualified LU network name
followed by a period and an LUW instance number. The LU network name
consists of a 1- to 8-character network ID, a period, and a 1- to 8-character
network LU name. The LUW instance number consists of 12 hexadecimal
characters that uniquely identify the unit of work.
Reserved area
20 bytes.

See the following section for examples of declarations of passed parameters in


each language. If you write your user-defined function in C or C⁺⁺, you can use the
declarations in member SQLUDF of DSN710.SDSNC.H for many of the passed
parameters. To include SQLUDF, make these changes to your program:
v Put this statement in your source code:
#include <sqludf.h>
v Include the DSN710.SDSNC.H data set in the SYSLIB concatenation for the
compile step of your program preparation job.
v Specify the NOMARGINS and NOSEQUENCE options in the compile step of
your program preparation job.

Examples of passing parameters in a user-defined function


The following examples show how a user-defined function that is written in each of
the supported host languages receives the parameter list that is passed by DB2.

Chapter 14. Creating and using user-defined functions 263


These examples assume that the user-defined function is defined with the
SCRATCHPAD, FINAL CALL, and DBINFO parameters.

Assembler: Figure 98 shows the parameter conventions for a user-defined scalar


function that is written as a main program that receives two parameters and returns
one result. For an assembler language user-defined function that is a subprogram,
the conventions are the same. In either case, you must include the CEEENTRY and
CEEEXIT macros.

MYMAIN CEEENTRY AUTO=PROGSIZE,MAIN=YES,PLIST=OS


USING PROGAREA,R13

L R7,0(R1) GET POINTER TO PARM1


MVC PARM1(4),0(R7) MOVE VALUE INTO LOCAL COPY OF PARM1
L R7,4(R1) GET POINTER TO PARM2
MVC PARM1(4),0(R7) MOVE VALUE INTO LOCAL COPY OF PARM2
L R7,12(R1) GET POINTER TO INDICATOR 1
MVC F_IND1(2),0(R7) MOVE PARM1 INDICATOR TO LOCAL STORAGE
LH R7,F_IND1 MOVE PARM1 INDICATOR INTO R7
LTR R7,R7 CHECK IF IT IS NEGATIVE
BM NULLIN IF SO, PARM1 IS NULL
L R7,16(R1) GET POINTER TO INDICATOR 2
MVC F_IND2(2),0(R7) MOVE PARM2 INDICATOR TO LOCAL STORAGE
LH R7,F_IND2 MOVE PARM2 INDICATOR INTO R7
LTR R7,R7 CHECK IF IT IS NEGATIVE
BM NULLIN IF SO, PARM2 IS NULL
.
.
.

L R7,8(R1) GET ADDRESS OF AREA FOR RESULT


NULLIN MVC 0(9,R7),RESULT MOVE A VALUE INTO RESULT AREA
L R7,20(R1) GET ADDRESS OF AREA FOR RESULT IND
MVC 0(2,R7),=H'0' MOVE A VALUE INTO INDICATOR AREA
.
.
.

CEETERM RC=0
*******************************************************************
* VARIABLE DECLARATIONS AND EQUATES *
*******************************************************************
R1 EQU 1 REGISTER 1
R7 EQU 7 REGISTER 7
PPA CEEPPA , CONSTANTS DESCRIBING THE CODE BLOCK
LTORG , PLACE LITERAL POOL HERE
PROGAREA DSECT
ORG *+CEEDSASZ LEAVE SPACE FOR DSA FIXED PART
PARM1 DS F PARAMETER 1
PARM2 DS F PARAMETER 2
RESULT DS CL9 RESULT
F_IND1 DS H INDICATOR FOR PARAMETER 1
F_IND2 DS H INDICATOR FOR PARAMETER 2
F_INDR DS H INDICATOR FOR RESULT

PROGSIZE EQU *-PROGAREA


CEEDSA , MAPPING OF THE DYNAMIC SAVE AREA
CEECAA , MAPPING OF THE COMMON ANCHOR AREA
END MYMAIN

Figure 98. How an assembler language user-defined function receives parameters

C or C⁺⁺:

264 Application Programming and SQL Guide


For C or C⁺⁺ user-defined functions, the conventions for passing parameters are
different for main programs and subprograms.

For subprograms, you pass the parameters directly. For main programs, you use
the standard argc and argv variables to access the input and output parameters:
v The argv variable contains an array of pointers to the parameters that are passed
to the user-defined function. All string parameters that are passed back to DB2
must be null terminated.
– argv[0] contains the address of the load module name for the user-defined
function.
– argv[1] through argv[n] contain the addresses of parameters 1 through n.
v The argc variable contains the number of parameters that are passed to the
external user-defined function, including argv[0].

Figure 99 on page 266 shows the parameter conventions for a user-defined scalar
function that is written as a main program that receives two parameters and returns
one result.

Chapter 14. Creating and using user-defined functions 265


#include <stdlib.h>
#include <stdio.h>

main(argc,argv)
int argc;
char *argv[];
{
/***************************************************/
/* Assume that the user-defined function invocation*/
/* included 2 input parameters in the parameter */
/* list. Also assume that the definition includes */
/* the SCRATCHPAD, FINAL CALL, and DBINFO options, */
/* so DB2 passes the scratchpad, calltype, and */
/* dbinfo parameters. */
/* The argv vector contains these entries: */
/* argv[0] 1 load module name */
/* argv[1-2] 2 input parms */
/* argv[3] 1 result parm */
/* argv[4-5] 2 null indicators */
/* argv[6] 1 result null indicator */
/* argv[7] 1 SQLSTATE variable */
/* argv[8] 1 qualified func name */
/* argv[9] 1 specific func name */
/* argv[10] 1 diagnostic string */
/* argv[11] 1 scratchpad */
/* argv[12] 1 call type */
/* argv[13] + 1 dbinfo */
/* ------ */
/* 14 for the argc variable */
/***************************************************/
if argc<>14
{
.
.
.

/**********************************************************/
/* This section would contain the code executed if the */
/* user-defined function is invoked with the wrong number */
/* of parameters. */
/**********************************************************/
}

Figure 99. How a C or C⁺⁺ user-defined function that is written as a main program receives
parameters (Part 1 of 2)

266 Application Programming and SQL Guide


/***************************************************/
/* Assume the first parameter is an integer. */
/* The code below shows how to copy the integer */
/* parameter into the application storage. */
/***************************************************/
int parm1;
parm1 = *(int *) argv[1];

/***************************************************/
/* Access the null indicator for the first */
/* parameter on the invoked user-defined function */
/* as follows: */
/***************************************************/
short int ind1;
ind1 = *(short int *) argv[4];

/***************************************************/
/* Use the expression below to assign */
/* 'xxxxx' to the SQLSTATE returned to caller on */
/* the SQL statement that contains the invoked */
/* user-defined function. */
/***************************************************/
strcpy(argv[7],"xxxxx/0");

/***************************************************/
/* Obtain the value of the qualified function */
/* name with this expression. */
/***************************************************/
char f_func[28];
strcpy(f_func,argv[8]);
/***************************************************/
/* Obtain the value of the specific function */
/* name with this expression. */
/***************************************************/
char f_spec[19];
strcpy(f_spec,argv[9]);

/***************************************************/
/* Use the expression below to assign */
/* 'yyyyyyyy' to the diagnostic string returned */
/* in the SQLCA associated with the invoked */
/* user-defined function. */
/***************************************************/
strcpy(argv[10],"yyyyyyyy/0");

/***************************************************/
/* Use the expression below to assign the */
/* result of the function. */
/***************************************************/
char l_result[11];
strcpy(argv[3],l_result);

.
.
.

Figure 99. How a C or C⁺⁺ user-defined function that is written as a main program receives
parameters (Part 2 of 2)

Figure 100 on page 268 shows the parameter conventions for a user-defined scalar
function written as a C subprogram that receives 2 parameters and returns one
result.

Chapter 14. Creating and using user-defined functions 267


#pragma runopts(plist(os))
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define SQLUDF_ASCII 0 /* ASCII */


#define SQLUDF_EBCDIC 1 /* EBCDIC */
#define SQLUDF_UNICODE 2 /* UNICODE */
struct sqludf_scratchpadstruct sqludf_scratchpad
{
unsigned long length; /* length of scratchpad data */
char data[SQLUDF_SCRATCHPAD_LEN]; /* scratchpad data */
};
struct sqludf_dbinfo
{
unsigned short dbnamelen; /* database name length */
unsigned char dbname[128]; /* database name */
unsigned short authidlen; /* appl auth id length */
unsigned char authid[128]; /* appl authorization ID */
| struct db2_cdpg
| {
| struct db2_ccsids
| {
| unsigned long db2_sbcs;
| unsigned long db2_dbcs;
| unsigned long db2_mixed;
| } db2_ccsids_t[3];
|
| unsigned long db2_encoding_scheme;
| unsigned char reserved[8];
| };
unsigned short tbqualiflen; /* table qualifier length */
unsigned char tbqualif[128]; /* table qualifer name */
unsigned short tbnamelen; /* table name length */
unsigned char tbname[128]; /* table name */
unsigned short colnamelen; /* column name length */
unsigned char colname[128]; /* column name */
unsigned char relver[8]; /* Database release & version */
unsigned long platform; /* Database platform */
unsigned short numtfcol; /* # of Tab Fun columns used */
unsigned char reserv1[24]; /* reserved */
unsigned short *tfcolnum; /* table fn column list */
unsigned short *appl_id; /* LUWID for DB2 connection */
unsigned char reserv2[20]; /* reserved */
};

Figure 100. How a C language user-defined function that is written as a subprogram receives
parameters (Part 1 of 2)

268 Application Programming and SQL Guide


void myfunc(long *parm1, char parm2[11], char result[11],
short *f_ind1, short *f_ind2, short *f_indr,
char udf_sqlstate[6], char udf_fname[138],
char udf_specname[129], char udf_msgtext[71],
struct sqludf_scratchpad *udf_scratchpad,
long *udf_call_type,
struct sql_dbinfo *udf_dbinfo);
{
/***************************************************/
/* Declare local copies of parameters */
/***************************************************/
int l_p1;
char l_p2[11];
short int l_ind1;
short int l_ind2;
char ludf_sqlstate[6]; /* SQLSTATE */
char ludf_fname[138]; /* function name */
char ludf_specname[129]; /* specific function name */
char ludf_msgtext[71] /* diagnostic message text*/
sqludf_scratchpad *ludf_scratchpad; /* scratchpad */
long *ludf_call_type; /* call type */
sqludf_dbinfo *ludf_dbinfo /* dbinfo */
/***************************************************/
/* Copy each of the parameters in the parameter */
/* list into a local variable to demonstrate */
/* how the parameters can be referenced. */
/***************************************************/

l_p1 = *parm1;
strcpy(l_p2,parm2);
l_ind1 = *f_ind1;
l_ind1 = *f_ind2;
strcpy(ludf_sqlstate,udf_sqlstate);
strcpy(ludf_fname,udf_fname);
strcpy(ludf_specname,udf_specname);
l_udf_call_type = *udf_call_type;
strcpy(ludf_msgtext,udf_msgtext);
memcpy(&ludf_scratchpad,udf_scratchpad,sizeof(ludf_scratchpad));
memcpy(&ludf_dbinfo,udf_dbinfo,sizeof(ludf_dbinfo));
.
.
.

Figure 100. How a C language user-defined function that is written as a subprogram receives
parameters (Part 2 of 2)

Figure 101 on page 270 shows the parameter conventions for a user-defined scalar
function that is written as a C⁺⁺ subprogram that receives two parameters and
returns one result. This example demonstrates that you must use an extern "C"
modifier to indicate that you want the C⁺⁺ subprogram to receive parameters
according to the C linkage convention. This modifier is necessary because the
CEEPIPI CALL_SUB interface, which DB2 uses to call the user-defined function,
passes parameters using the C linkage convention.

Chapter 14. Creating and using user-defined functions 269


#pragma runopts(plist(os))
#include <stdlib.h>
#include <stdio.h>
#define SQLUDF_ASCII 0 /* ASCII */
#define SQLUDF_EBCDIC 1 /* EBCDIC */
#define SQLUDF_UNICODE 2 /* UNICODE */
struct sqludf_scratchpad
{
unsigned long length; /* length of scratchpad data */
char data[SQLUDF_SCRATCHPAD_LEN]; /* scratchpad data */
};
struct sqludf_dbinfo
{
unsigned short dbnamelen; /* database name length */
unsigned char dbname[128]; /* database name */
unsigned short authidlen; /* appl auth id length */
unsigned char authid[128]; /* appl authorization ID */
| struct db2_cdpg
| {
| struct db2_ccsids
| {
| unsigned long db2_sbcs;
| unsigned long db2_dbcs;
| unsigned long db2_mixed;
| } db2_ccsids_t[3];
|
| unsigned long db2_encoding_scheme;
| unsigned char reserved[8];
| };
unsigned short tbqualiflen; /* table qualifier length */
unsigned char tbqualif[128]; /* table qualifer name */
unsigned short tbnamelen; /* table name length */
unsigned char tbname[128]; /* table name */
unsigned short colnamelen; /* column name length */
unsigned char colname[128]; /* column name */
unsigned char relver[8]; /* Database release & version */
unsigned long platform; /* Database platform */
unsigned short numtfcol; /* # of Tab Fun columns used */
unsigned char reserv1[24]; /* reserved */
unsigned short *tfcolnum; /* table fn column list */
unsigned short *appl_id; /* LUWID for DB2 connection */
unsigned char reserv2[20]; /* reserved */
};
extern "C" void myfunc(long *parm1, char parm2[11],
char result[11], short *f_ind1, short *f_ind2, short *f_indr,
char udf_sqlstate[6], char udf_fname[138],
char udf_specname[129], char udf_msgtext[71],
struct sqludf_scratchpad *udf_scratchpad,
long *udf_call_type,
struct sql_dbinfo *udf_dbinfo);

Figure 101. How a C⁺⁺ user-defined function that is written as a subprogram receives
parameters (Part 1 of 2)

270 Application Programming and SQL Guide


{
/***************************************************/
/* Define local copies of parameters. */
/***************************************************/
int l_p1;
char l_p2[11];
short int l_ind1;
short int l_ind2;
char ludf_sqlstate[6]; /* SQLSTATE */
char ludf_fname[138]; /* function name */
char ludf_specname[129]; /* specific function name */
char ludf_msgtext[71] /* diagnostic message text*/
sqludf_scratchpad *ludf_scratchpad; /* scratchpad */
long *ludf_call_type; /* call type */
sqludf_dbinfo *ludf_dbinfo /* dbinfo */
/***************************************************/
/* Copy each of the parameters in the parameter */
/* list into a local variable to demonstrate */
/* how the parameters can be referenced. */
/***************************************************/
l_p1 = *parm1;
strcpy(l_p2,parm2);
l_ind1 = *f_ind1;
l_ind1 = *f_ind2;
strcpy(ludf_sqlstate,udf_sqlstate);
strcpy(ludf_fname,udf_fname);
strcpy(ludf_specname,udf_specname);
l_udf_call_type = *udf_call_type;
strcpy(ludf_msgtext,udf_msgtext);
memcpy(&ludf_scratchpad,udf_scratchpad,sizeof(ludf_scratchpad));
memcpy(&ludf_dbinfo,udf_dbinfo,sizeof(ludf_dbinfo));
.
.
.

Figure 101. How a C⁺⁺ user-defined function that is written as a subprogram receives
parameters (Part 2 of 2)

COBOL: Figure 102 on page 272 shows the parameter conventions for a
user-defined table function that is written as a main program that receives two
parameters and returns two results. For a COBOL user-defined function that is a
subprogram, the conventions are the same.

Chapter 14. Creating and using user-defined functions 271


CBL APOST,RES,RENT
IDENTIFICATION DIVISION.
.
.
.

DATA DIVISION.
.
.
.

LINKAGE SECTION.
*********************************************************
* Declare each of the parameters *
*********************************************************
01 UDFPARM1 PIC S9(9) USAGE COMP.
01 UDFPARM2 PIC X(10).
.
.
.

*********************************************************
* Declare these variables for result parameters *
*********************************************************
01 UDFRESULT1 PIC X(10).
01 UDFRESULT2 PIC X(10).
.
.
.

*********************************************************
* Declare a null indicator for each parameter *
*********************************************************
01 UDF-IND1 PIC S9(4) USAGE COMP.
01 UDF-IND2 PIC S9(4) USAGE COMP.
.
.
.

*********************************************************
* Declare a null indicator for result parameter *
*********************************************************
01 UDF-RIND1 PIC S9(4) USAGE COMP.
01 UDF-RIND2 PIC S9(4) USAGE COMP.
.
.
.

*********************************************************
* Declare the SQLSTATE that can be set by the *
* user-defined function *
*********************************************************
01 UDF-SQLSTATE PIC X(5).
*********************************************************
* Declare the qualified function name *
*********************************************************
01 UDF-FUNC.
49 UDF-FUNC-LEN PIC 9(4) USAGE BINARY.
49 UDF-FUNC-TEXT PIC X(137).
*********************************************************
* Declare the specific function name *
*********************************************************
01 UDF-SPEC.
49 UDF-SPEC-LEN PIC 9(4) USAGE BINARY.
49 UDF-SPEC-TEXT PIC X(128).

Figure 102. How a COBOL user-defined function receives parameters (Part 1 of 3)

272 Application Programming and SQL Guide


*********************************************************
* Declare SQL diagnostic message token *
*********************************************************
01 UDF-DIAG.
49 UDF-DIAG-LEN PIC 9(4) USAGE BINARY.
49 UDF-DIAG-TEXT PIC X(70).
*********************************************************
* Declare the scratchpad *
*********************************************************
01 UDF-SCRATCHPAD.
49 UDF-SPAD-LEN PIC 9(9) USAGE BINARY.
49 UDF-SPAD-TEXT PIC X(100).
*********************************************************
* Declare the call type *
*********************************************************
01 UDF-CALL-TYPE PIC 9(9) USAGE BINARY.
*****************************************************
* CONSTANTS FOR DB2-EBCODING-SCHEME. *
*****************************************************
77 SQLUDF-ASCII PIC 9(9) VALUE 1.
77 SQLUDF-EBCDIC PIC 9(9) VALUE 2.
77 SQLUDF-UNICODE PIC 9(9) VALUE 3.
*********************************************************
* Declare the DBINFO structure
*********************************************************
01 UDF-DBINFO.
* Location length and name
02 UDF-DBINFO-LOCATION.
49 UDF-DBINFO-LLEN PIC 9(4) USAGE BINARY.
49 UDF-DBINFO-LOC PIC X(128).
* Authorization ID length and name
02 UDF-DBINFO-AUTHORIZATION.
49 UDF-DBINFO-ALEN PIC 9(4) USAGE BINARY.
49 UDF-DBINFO-AUTH PIC X(128).
* CCSIDs for DB2 for OS/390
02 UDF-DBINFO-CCSID PIC X(48).
02 UDF-DBINFO-CDPG REDEFINES UDF-DBINFO-CCSID.
03 DB2-CCSIDS OCCURS 3 TIMES.
04 DB2-SBCS PIC 9(9) USAGE BINARY.
04 DB2-DBCS PIC 9(9) USAGE BINARY.
04 DB2-MIXED PIC 9(9) USAGE BINARY.
03 DB2-ENCODING-SCHEME PIC 9(9) USAGE BINARY.
03 DB2-CCSID-RESERVED PIC X(8).
* Schema length and name
02 UDF-DBINFO-SCHEMA0.
49 UDF-DBINFO-SLEN PIC 9(4) USAGE BINARY.
49 UDF-DBINFO-SCHEMA PIC X(128).
* Table length and name
02 UDF-DBINFO-TABLE0.
49 UDF-DBINFO-TLEN PIC 9(4) USAGE BINARY.
49 UDF-DBINFO-TABLE PIC X(128).
* Column length and name
02 UDF-DBINFO-COLUMN0.
49 UDF-DBINFO-CLEN PIC 9(4) USAGE BINARY.
49 UDF-DBINFO-COLUMN PIC X(128).
* DB2 release level
02 UDF-DBINFO-VERREL PIC X(8).

Figure 102. How a COBOL user-defined function receives parameters (Part 2 of 3)

Chapter 14. Creating and using user-defined functions 273


* Unused
02 FILLER PIC X(2).
* Database Platform
02 UDF-DBINFO-PLATFORM PIC 9(9) USAGE BINARY.
* # of entries in Table Function column list
02 UDF-DBINFO-NUMTFCOL PIC 9(4) USAGE BINARY.
* reserved
02 UDF-DBINFO-RESERV1 PIC X(24).
* Unused
02 FILLER PIC X(2).
* Pointer to Table Function column list
02 UDF-DBINFO-TFCOLUMN PIC 9(9) USAGE BINARY.
* Pointer to Application ID
02 UDF-DBINFO-APPLID PIC 9(9) USAGE BINARY.
* reserved
02 UDF-DBINFO-RESERV2 PIC X(20).
*
PROCEDURE DIVISION USING UDFPARM1, UDFPARM2, UDFRESULT1,
UDFRESULT2, UDF-IND1, UDF-IND2,
UDF-RIND1, UDF-RIND2,
UDF-SQLSTATE, UDF-FUNC, UDF-SPEC,
UDF-DIAG, UDF-SCRATCHPAD,
UDF-CALL-TYPE, UDF-DBINFO.

Figure 102. How a COBOL user-defined function receives parameters (Part 3 of 3)

PL/I: Figure 103 on page 275 shows the parameter conventions for a user-defined
scalar function that is written as a main program that receives two parameters and
returns one result. For a PL/I user-defined function that is a subprogram, the
conventions are the same.

274 Application Programming and SQL Guide


*PROCESS SYSTEM(MVS);
MYMAIN: PROC(UDF_PARM1, UDF_PARM2, UDF_RESULT,
UDF_IND1, UDF_IND2, UDF_INDR,
UDF_SQLSTATE, UDF_NAME, UDF_SPEC_NAME,
UDF_DIAG_MSG, UDF_SCRATCHPAD,
UDF_CALL_TYPE, UDF_DBINFO)
OPTIONS(MAIN NOEXECOPS REENTRANT);

DCL UDF_PARM1 BIN FIXED(31); /* first parameter */


DCL UDF_PARM2 CHAR(10); /* second parameter */
DCL UDF_RESULT CHAR(10); /* result parameter */
DCL UDF_IND1 BIN FIXED(15); /* indicator for 1st parm */
DCL UDF_IND2 BIN FIXED(15); /* indicator for 2nd parm */
DCL UDF_INDR BIN FIXED(15); /* indicator for result */
DCL UDF_SQLSTATE CHAR(5); /* SQLSTATE returned to DB2 */
DCL UDF_NAME CHAR(137) VARYING; /* Qualified function name */
DCL UDF_SPEC_NAME CHAR(128) VARYING; /* Specific function name */
DCL UDF_DIAG_MSG CHAR(70) VARYING; /* Diagnostic string */
DCL 01 UDF_SCRATCHPAD /* Scratchpad */
03 UDF_SPAD_LEN BIN FIXED(31),
03 UDF_SPAD_TEXT CHAR(100);
DCL UDF_CALL_TYPE BIN FIXED(31); /* Call Type */
DCL DBINFO PTR;
/* CONSTANTS FOR DB2_ENCODING_SCHEME */
DCL SQLUDF_ASCII BIN FIXED(15) INIT(1);
DCL SQLUDF_EBCDIC BIN FIXED(15) INIT(2);
DCL SQLUDF_MIXED BIN FIXED(15) INIT(3);
DCL 01 UDF_DBINFO BASED(DBINFO), /* Dbinfo */
03 UDF_DBINFO_LLEN BIN FIXED(15), /* location length */
03 UDF_DBINFO_LOC CHAR(128), /* location name */
03 UDF_DBINFO_ALEN BIN FIXED(15), /* auth ID length */
03 UDF_DBINFO_AUTH CHAR(128), /* authorization ID */
03 UDF_DBINFO_CDPG, /* CCSIDs for DB2 for OS/390*/
05 DB2_CCSIDS(3),
07 R1 BIN FIXED(15), /* Reserved */
07 DB2_SBCS BIN FIXED(15), /* SBCS CCSID */
07 R2 BIN FIXED(15), /* Reserved */
07 DB2_DBCS BIN FIXED(15), /* DBCS CCSID */
07 R3 BIN FIXED(15), /* Reserved */
07 DB2_MIXED BIN FIXED(15), /* MIXED CCSID */
05 DB2_ENCODING_SCHEME BIN FIXED(31),
05 DB2_CCSID_RESERVED CHAR(8),

Figure 103. How a PL/I user-defined function receives parameters (Part 1 of 2)

03 UDF_DBINFO_SLEN BIN FIXED(15), /* schema length */


03 UDF_DBINFO_SCHEMA CHAR(128), /* schema name */
03 UDF_DBINFO_TLEN BIN FIXED(15), /* table length */
03 UDF_DBINFO_TABLE CHAR(128), /* table name */
03 UDF_DBINFO_CLEN BIN FIXED(15), /* column length */
03 UDF_DBINFO_COLUMN CHAR(128), /* column name */
03 UDF_DBINFO_RELVER CHAR(8), /* DB2 release level */
03 UDF_DBINFO_PLATFORM BIN FIXED(31), /* database platform*/
03 UDF_DBINFO_NUMTFCOL BIN FIXED(15), /* # of TF cols used*/
03 UDF_DBINFO_RESERV1 CHAR(24), /* reserved */
03 UDF_DBINFO_TFCOLUMN PTR, /* -> table fun col list */
03 UDF_DBINFO_APPLID PTR, /* -> application id */
03 UDF_DBINFO_RESERV2 CHAR(20); /* reserved */
.
.
.

Figure 103. How a PL/I user-defined function receives parameters (Part 2 of 2)

Chapter 14. Creating and using user-defined functions 275


Using special registers in a user-defined function
You can use all special registers in a user-defined function. However, you can
modify only some of those special registers. After a user-defined function
completes, DB2 restores all special registers to the values they had before
invocation.

Table 35 shows information you need when you use special registers in a
user-defined function.
| Table 35. Characteristics of special registers in a user-defined function
| Special register Initial value when Initial value when Function
| INHERIT SPECIAL DEFAULT SPECIAL can use
| REGISTERS option is REGISTERS option is SET
| specified specified statement
| to modify?
| CURRENT The value of bind option The value of bind option Yes
| APPLICATION ENCODING for the ENCODING for the
| ENCODING SCHEME user-defined function user-defined function
| package1 package1
| CURRENT DATE New value for each SQL New value for each SQL Not
| statement in the statement in the applicable5
| user-defined function user-defined function
| package2 package2
| CURRENT DEGREE Inherited from invoker3 The value of field Yes
| CURRENT DEGREE on
| installation panel
| DSNTIP4
| CURRENT LOCALE Inherited from invoker The value of field Yes
| LC_CTYPE CURRENT DEGREE on
| installation panel
| DSNTIP4
| CURRENT MEMBER New value for each SET New value for each SET No
| host-variable=CURRENT host-variable=CURRENT
| MEMBER statement MEMBER statement
| CURRENT The value of bind option The value of bind option Yes
| OPTIMIZATION HINT OPTHINT for the OPTHINT for the
| user-defined function user-defined function
| package or inherited package
| from invoker6
| CURRENT Inherited from invoker4 Inherited from invoker4 Yes
| PACKAGESET
| CURRENT PATH The value of bind option The value of bind option Yes
| PATH for the PATH for the
| user-defined function user-defined function
| package or inherited package
| from invoker6
| CURRENT PRECISION Inherited from invoker The value of field Yes
| DECIMAL ARITHMETIC
| on installation panel
| DSNTIP4
| CURRENT RULES Inherited from invoker The value of bind option Yes
| SQLRULES for the
| user-defined function
| package
| CURRENT SERVER Inherited from invoker Inherited from invoker Yes

276 Application Programming and SQL Guide


| Table 35. Characteristics of special registers in a user-defined function (continued)
| Special register Initial value when Initial value when Function
| INHERIT SPECIAL DEFAULT SPECIAL can use
| REGISTERS option is REGISTERS option is SET
| specified specified statement
| to modify?
| CURRENT SQLID The primary The primary Yes8
| authorization ID of the authorization ID of the
| application process or application process
| inherited from invoker7
| CURRENT TIME New value for each SQL New value for each SQL Not
| statement in the statement in the applicable5
| user-defined function user-defined function
| package2 package2
| CURRENT TIMESTAMP New value for each SQL New value for each SQL Not
| statement in the statement in the applicable5
| user-defined function user-defined function
| package2 package2
| CURRENT TIMEZONE Inherited from invoker Inherited from invoker Not
| applicable5
| CURRENT USER Primary authorization ID Primary authorization ID Not
| of the application of the application applicable5
| process process
| Notes:
| 1. If the ENCODING bind option is not specified, the initial value is the value that was
| specified in field APPLICATION ENCODING of installation panel DSNTIPF.
| 2. If the user-defined function is invoked within the scope of a trigger, DB2 uses the
| timestamp for the triggering SQL statement as the timestamp for all SQL statements in
| the function package.
| 3. DB2 allows parallelism at only one level of a nested SQL statement. If you set the value
| of the CURRENT DEGREE special register to ANY, and parallelism is disabled, DB2
| ignores the CURRENT DEGREE value.
| 4. If the user-defined function definer specifies a value for COLLID in the CREATE
| FUNCTION statement, DB2 sets CURRENT PACKAGESET to the value of COLLID.
| 5. Not applicable because no SET statement exists for the special register.
| 6. If a program within the scope of the invoking program issues a SET statement for the
| special register before the user-defined function is invoked, the special register inherits
| the value from the SET statement. Otherwise, the special register contains the value that
| is set by the bind option for the user-defined function package.
| 7. If a program within the scope of the invoking program issues a SET CURRENT SQLID
| statement before the user-defined function is invoked, the special register inherits the
| value from the SET statement. Otherwise, CURRENT SQLID contains the authorization
| ID of the application process.
| 8. If the user-defined function package uses a value other than RUN for the
| DYNAMICRULES bind option, the SET CURRENT SQLID statement can be executed but
| does not affect the authorization ID that is used for the dynamic SQL statements in the
| user-defined function package. The DYNAMICRULES value determines the authorization
| ID that is used for dynamic SQL statements. See “Using DYNAMICRULES to specify
| behavior of dynamic SQL statements” on page 418 for more information on
| DYNAMICRULES values and authorization IDs.
|

Using a scratchpad in a user-defined function


You can use a scratchpad to save information between invocations of a
user-defined function. To indicate that a scratchpad should be allocated when the

Chapter 14. Creating and using user-defined functions 277


user-defined function executes, the function definer specifies the SCRATCHPAD
parameter in the CREATE FUNCTION statement.

The scratchpad consists of a 4-byte length field, followed by the scratchpad area.
The definer can specify the length of the scratchpad area in the CREATE
FUNCTION statement. The specified length does not include the length field. The
default size is 100 bytes. DB2 initializes the scratchpad for each function to binary
zeros at the beginning of execution for each subquery of an SQL statement and
does not examine or change the content thereafter. On each invocation of the
user-defined function, DB2 passes the scratchpad to the user-defined function. You
can therefore use the scratchpad to preserve information between invocations of a
reentrant user-defined function.

Figure 104 on page 279 demonstrates how to enter information in a scratchpad for
a user-defined function defined like this:
CREATE FUNCTION COUNTER()
RETURNS INT
SCRATCHPAD
FENCED
NOT DETERMINISTIC
NO SQL
NO EXTERNAL ACTION
LANGUAGE C
PARAMETER STYLE DB2SQL
EXTERNAL NAME 'UDFCTR';

The scratchpad length is not specified, so the scratchpad has the default length of
100 bytes, plus 4 bytes for the length field. The user-defined function increments an
integer value and stores it in the scratchpad on each execution.

278 Application Programming and SQL Guide


#pragma linkage(ctr,fetchable)
#include <stdlib.h>
#include <stdio.h>
/* Structure scr defines the passed scratchpad for function ctr */
struct scr {
long len;
long countr;
char not_used[96];
};
/***************************************************************/
/* Function ctr: Increments a counter and reports the value */
/* from the scratchpad. */
/* */
/* Input: None */
/* Output: INTEGER out the value from the scratchpad */
/***************************************************************/
void ctr(
long *out, /* Output answer (counter) */
short *outnull, /* Output null indicator */
char *sqlstate, /* SQLSTATE */
char *funcname, /* Function name */
char *specname, /* Specific function name */
char *mesgtext, /* Message text insert */
struct scr *scratchptr) /* Scratchpad */
{
*out = ++scratchptr->countr; /* Increment counter and */
/* copy to output variable */
*outnull = 0; /* Set output null indicator*/
return;
}
/* end of user-defined function ctr */

Figure 104. Example of coding a scratchpad in a user-defined function

Accessing transition tables in a user-defined function or stored


procedure
When you write a user-defined function, external stored procedure, or SQL
procedure that is invoked from a trigger, you might need access to transition tables
for the trigger. This section describes how to access transition variables in a
user-defined function, but the same techniques apply to a stored procedure.

To access transition tables in a user-defined function, use table locators, which are
pointers to the transition tables. You declare table locators as input parameters in
the CREATE FUNCTION statement using the TABLE LIKE table-name AS
LOCATOR clause. See Chapter 5 of DB2 SQL Reference for more information.

The five basic steps to accessing transition tables in a user-defined function are:
1. Declare input parameters to receive table locators. You must define each
parameter that receives a table locator as an unsigned 4-byte integer.
2. Declare table locators. You can declare table locators in assembler, C, C⁺⁺,
COBOL, PL/I, and in an SQL procedure compound statement. The syntax for
declaring table locators in C, C⁺⁺, COBOL, and PL/I is described in “Chapter 9.
Embedding SQL statements in host languages” on page 107. The syntax for
declaring table locators in an SQL procedure is described in Chapter 6 of DB2
SQL Reference.
3. Declare a cursor to access the rows in each transition table.
4. Assign the input parameter values to the table locators.

Chapter 14. Creating and using user-defined functions 279


5. Access rows from the transition tables using the cursors that are declared for
the transition tables.

The following examples show how a user-defined function that is written in C, C⁺⁺,
COBOL, or PL/I accesses a transition table for a trigger. The transition table,
NEWEMP, contains modified rows of the employee sample table. The trigger is
defined like this:
CREATE TRIGGER EMPRAISE
AFTER UPDATE ON EMP
REFERENCING NEW TABLE AS NEWEMPS
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
VALUES (CHECKEMP(TABLE NEWEMPS));
END;

The user-defined function definition looks like this:


CREATE FUNCTION CHECKEMP(TABLE LIKE EMP AS LOCATOR)
RETURNS INTEGER
EXTERNAL NAME 'CHECKEMP'
PARAMETER STYLE DB2SQL
LANGUAGE language;

Assembler: Figure 105 on page 281 shows how an assembler program accesses
rows of transition table NEWEMPS.

280 Application Programming and SQL Guide


CHECKEMP CSECT
SAVE (14,12) ANY SAVE SEQUENCE
LR R12,R15 CODE ADDRESSABILITY
USING CHECKEMP,R12 TELL THE ASSEMBLER
LR R7,R1 SAVE THE PARM POINTER
USING PARMAREA,R7 SET ADDRESSABILITY FOR PARMS
USING SQLDSECT,R8 ESTABLISH ADDRESSIBILITY TO SQLDSECT
L R6,PROGSIZE GET SPACE FOR USER PROGRAM
GETMAIN R,LV=(6) GET STORAGE FOR PROGRAM VARIABLES
LR R10,R1 POINT TO THE ACQUIRED 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
ST R13,FOUR(R10) CHAIN THE SAVEAREA PTRS
ST R10,EIGHT(R13) CHAIN SAVEAREA FORWARD
LR R13,R10 POINT TO THE SAVEAREA
USING PROGAREA,R13 SET ADDRESSABILITY
ST R6,GETLENTH SAVE THE LENGTH OF THE GETMAIN
.
.
.

************************************************************
* Declare table locator host variable TRIGTBL *
************************************************************
TRIGTBL SQL TYPE IS TABLE LIKE EMP AS LOCATOR
************************************************************
* Declare a cursor to retrieve rows from the transition *
* table *
************************************************************
EXEC SQL DECLARE C1 CURSOR FOR X
SELECT LASTNAME FROM TABLE(:TRIGTBL LIKE EMP) X
WHERE SALARY > 100000
************************************************************
* Copy table locator for trigger transition table *
************************************************************
L R2,TABLOC GET ADDRESS OF LOCATOR
L R2,0(0,R2) GET LOCATOR VALUE
ST R2,TRIGTBL
EXEC SQL OPEN C1
EXEC SQL FETCH C1 INTO :NAME
.
.
.

. EXEC SQL CLOSE C1


.
.

Figure 105. How an assembler user-defined function accesses a transition table (Part 1 of 2)

Chapter 14. Creating and using user-defined functions 281


PROGAREA DSECT WORKING STORAGE FOR THE PROGRAM
SAVEAREA DS 18F THIS ROUTINE'S SAVE AREA
GETLENTH
. DS A GETMAIN LENGTH FOR THIS AREA
.
.

NAME
. DS CL24
.
.

DS 0D
PROGSIZE EQU *-PROGAREA DYNAMIC WORKAREA SIZE
PARMAREA DSECT
TABLOC
. DS A INPUT PARAMETER FOR TABLE LOCATOR
.
.

END CHECKEMP

Figure 105. How an assembler user-defined function accesses a transition table (Part 2 of 2)

C or C⁺⁺: Figure 106 shows how a C or C⁺⁺ program accesses rows of transition
table NEWEMPS.

int CHECK_EMP(int trig_tbl_id)


{
.
.
.

/**********************************************************/
/* Declare table locator host variable trig_tbl_id */
/**********************************************************/
EXEC SQL BEGIN DECLARE SECTION;
SQL TYPE IS TABLE LIKE EMP AS LOCATOR trig_tbl_id;
char name[25];
EXEC SQL END DECLARE SECTION;
.
.
.

/**********************************************************/
/* Declare a cursor to retrieve rows from the transition */
/* table */
/**********************************************************/
EXEC SQL DECLARE C1 CURSOR FOR
SELECT NAME FROM TABLE(:trig_tbl_id LIKE EMPLOYEE)
WHERE SALARY > 100000;
/**********************************************************/
/* Fetch a row from transition table */
/**********************************************************/
EXEC SQL OPEN C1;
EXEC SQL FETCH C1 INTO :name;
.
.
.

EXEC SQL CLOSE C1;


.
.
.

Figure 106. How a C or C⁺⁺ user-defined function accesses a transition table

COBOL: Figure 107 on page 283 shows how a COBOL program accesses rows of
transition table NEWEMPS.

282 Application Programming and SQL Guide


IDENTIFICATION DIVISION.
PROGRAM-ID. CHECKEMP.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 NAME PIC X(24).
.
.
.

LINKAGE SECTION.
*********************************************************
* Declare table locator host variable TRIG-TBL-ID *
*********************************************************
01 TRIG-TBL-ID SQL TYPE IS TABLE LIKE EMP AS LOCATOR.
.
.
.

PROCEDURE DIVISION USING TRIG-TBL-ID.


.
.
.

*********************************************************
* Declare cursor to retrieve rows from transition table *
*********************************************************
EXEC SQL DECLARE C1 CURSOR FOR
SELECT NAME FROM TABLE(:TRIG-TBL-ID LIKE EMP)
WHERE SALARY > 100000 END-EXEC.
*********************************************************
* Fetch a row from transition table *
*********************************************************
EXEC SQL OPEN C1 END-EXEC.
EXEC SQL FETCH C1 INTO :NAME END-EXEC.
.
.
.

EXEC SQL CLOSE C1 END-EXEC.


.
.
.

PROG-END.
GOBACK.

Figure 107. How a COBOL user-defined function accesses a transition table

PL/I: Figure 108 on page 284 shows how a PL/I program accesses rows of
transition table NEWEMPS.

Chapter 14. Creating and using user-defined functions 283


CHECK_EMP: PROC(TRIG_TBL_ID) RETURNS(BIN FIXED(31))
OPTIONS(MAIN NOEXECOPS REENTRANT);
/****************************************************/
/* Declare table locator host variable TRIG_TBL_ID */
/****************************************************/
DECLARE TRIG_TBL_ID SQL TYPE IS TABLE LIKE EMP AS LOCATOR;
DECLARE NAME CHAR(24);
.
.
.

/****************************************************/
/* Declare a cursor to retrieve rows from the */
/* transition table */
/****************************************************/
EXEC SQL DECLARE C1 CURSOR FOR
SELECT NAME FROM TABLE(:TRIG_TBL_ID LIKE EMP)
WHERE SALARY > 100000;
/****************************************************/
/* Retrieve rows from the transition table */
/****************************************************/
EXEC SQL OPEN C1;
EXEC SQL FETCH C1 INTO :NAME;
.
.
.

EXEC SQL CLOSE C1;


.
.
.

END CHECK_EMP;

Figure 108. How a PL/I user-defined function accesses a transition table

Preparing a user-defined function for execution


To prepare a user-defined function for execution, perform these steps:
1. Precompile the user-defined function program and bind the DBRM into a
package.
You need to do this only if your user-defined function contains SQL statements.
You do not need to bind a plan for the user-defined function.
2. Compile the user-defined function program and link-edit it with Language
Environment and RRSAF.
You must compile the program with a compiler that supports Language
Environment and link-edit the appropriate Language Environment components
with the user-defined function. You must also link-edit the user-defined function
with RRSAF.
For the minimum compiler and Language Environment requirements for
user-defined functions, see DB2 Release Planning Guide.
The program preparation JCL samples DSNHASM, DSNHC, DSNHCPP,
DSNHICOB, and DSNHPLI show you how to precompile, compile, and link-edit
assembler, C, C⁺⁺, COBOL, and PL/I DB2 programs. If your DB2 subsystem
has been installed to work with Language Environment, you can use this
sample JCL when you prepare your user-defined functions. For object-oriented
programs in C⁺⁺ or COBOL, see JCL samples DSNHCPP2 and DSNHICB2 for
program preparation hints.
3. For a user-defined function that contains SQL statements, grant EXECUTE
authority on the user-defined function package to the function definer.

284 Application Programming and SQL Guide


Making a user-defined function reentrant
Compiling and link-editing your user-defined function as reentrant is recommended.
(For an assembler program, you must also code the user-defined function to be
reentrant.) Reentrant user-defined functions have the following advantages:
v The operating system does not need to load the user-defined function into
storage every time the user-defined function is called.
v Multiple tasks in a WLM-established stored procedures address space can share
a single copy of the user-defined function. This decreases the amount of virtual
storage that is needed for code in the address space.

Preparing user-defined functions that contain multiple programs: If your


user-defined function consists of several programs, you must bind each program
that contains SQL statements into a separate package. The definer of the
user-defined function must have EXECUTE authority for all packages that are part
of the user-defined function.

When the primary program of a user-defined function calls another program, DB2
uses the CURRENT PACKAGESET special register to determine the collection to
search for the called program's package. The primary program can change this
collection ID by executing the statement SET CURRENT PACKAGESET. If the
value of CURRENT PACKAGESET is blank, DB2 uses the method described in
“The order of search” on page 416 to search for the package.

Determining the authorization ID for user-defined function


invocation
If your user-defined function is invoked statically, the authorization ID under which
the user-defined function is invoked is the owner of the package that contains the
user-defined function invocation.

If the user-defined function is invoked dynamically, the authorization ID under which


the user-defined function is invoked depends on the value of bind parameter
DYNAMICRULES for the package that contains the function invocation.

While a user-defined function is executing, the authorization ID under which static


SQL statements in the user-defined function package execute is the owner of the
user-defined function package. The authorization ID under which dynamic SQL
statements in the user-defined function package execute depends on the value of
DYNAMICRULES with which the user-defined function package was bound.

DYNAMICRULES influences a number of features of an application program. For


information on how DYNAMICRULES works, see “Using DYNAMICRULES to
specify behavior of dynamic SQL statements” on page 418. For more information on
the authorization needed to invoke and execute SQL statements in a user-defined
function, see Chapter 5 of DB2 SQL Reference and Part 3 (Volume 1) of DB2
Administration Guide.

Preparing user-defined functions to run concurrently


Multiple user-defined functions and stored procedures can run concurrently, each
under its own OS/390 task (TCB).

To maximize the number of user-defined functions and stored procedures that can
run concurrently, follow these preparation recommendations:
v Ask the system administrator to set the region size parameter in the startup
procedures for the WLM-established stored procedures address spaces to
REGION=0. This lets an address space obtain the largest possible amount of
storage below the 16-MB line.

Chapter 14. Creating and using user-defined functions 285


v Limit storage required by application programs below the 16-MB line by:
– Link-editing programs with the AMODE(31) and RMODE(ANY) attributes
– Compiling COBOL programs with the RES and DATA(31) options
v Limit storage that is required by Language Environment by using these run-time
options:
HEAP(,,ANY) Allocates program heap storage above the
16-MB line
STACK(,,ANY,) Allocates program stack storage above the
16-MB line
STORAGE(,,,4K) Reduces reserve storage area below the line to 4
KB
BELOWHEAP(4K,,) Reduces the heap storage below the line to 4 KB
LIBSTACK(4K,,) Reduces the library stack below the line to 4 KB
ALL31(ON) Causes all programs contained in the external
user-defined function to execute with AMODE(31)
and RMODE(ANY)

The definer can list these options as values of the RUN OPTIONS parameter of
CREATE FUNCTION, or the system administrator can establish these options as
defaults during Language Environment installation.

For example, the RUN OPTIONS option parameter could contain:


H(,,ANY),STAC(,,ANY,),STO(,,,4K),BE(4K,,),LIBS(4K,,),ALL31(ON)
v Ask the system administrator to set the NUMTCB parameter for WLM-established
stored procedures address spaces to a value greater than 1. This lets more than
one TCB run in an address space. Be aware that setting NUMTCB to a value
greater than 1 also reduces your level of application program isolation. For
example, a bad pointer in one application can overwrite memory that is allocated
by another application.

Testing a user-defined function


Some commonly used debugging tools, such as TSO TEST, are not available in the
environment where user-defined functions run. This section describes some
alternative testing strategies.

CODE/370: You can use the CoOperative Development Environment/370 licensed


program, which works with Language Environment, to test DB2 for OS/390 and
z/OS user-defined functions written in any of the supported languages. You can use
CODE/370 either interactively or in batch mode.

Using CODE/370 interactively: To test a user-defined function interactively using


CODE/370, you must use the CODE/370 PWS Debug Tool on a workstation. You
must also have CODE/370 installed on the OS/390 system where the user-defined
function runs. To debug your user-defined function using the PWS Debug Tool:
1. Compile the user-defined function with the TEST option. This places information
in the program that the Debug Tool uses.
2. Invoke the debug tool. One way to do that is to specify the Language
Environment run-time TEST option. The TEST option controls when and how
the Debug Tool is invoked. The most convenient place to specify run-time
options is with the RUN OPTIONS parameter of CREATE FUNCTION or ALTER

286 Application Programming and SQL Guide


FUNCTION. See “Components of a user-defined function definition” on
page 244 for more information on the RUN OPTIONS parameter.
For example, suppose that you code this option:
TEST(ALL,*,PROMPT,JBJONES%SESSNA:)

The parameter values cause the following things to happen:


ALL
The Debug Tool gains control when an attention interrupt, abend, or
program or Language Environment condition of Severity 1 and above
occurs.
* Debug commands will be entered from the terminal.
PROMPT
The Debug Tool is invoked immediately after Language Environment
initialization.
JBJONES%SESSNA:
CODE/370 initiates a session on a workstation identified to APPC/MVS as
JBJONES with a session ID of SESSNA.
3. If you want to save the output from your debugging session, issue a command
that names a log file. For example, the following command starts logging to a
file on the workstation called dbgtool.log.
SET LOG ON FILE dbgtool.log;

This should be the first command that you enter from the terminal or include in
your commands file.

Using CODE/370 in batch mode: To test your user-defined function in batch


mode, you must have the CODE/370 Mainframe Interface (MFI) Debug Tool
installed on the OS/390 system where the user-defined function runs. To debug
your user-defined function in batch mode using the MFI Debug Tool:
1. If you plan to use the Language Environment run-time TEST option to invoke
CODE/370, compile the user-defined function with the TEST option. This places
information in the program that the Debug Tool uses during a debugging
session.
2. Allocate a log data set to receive the output from CODE/370. Put a DD
statement for the log data set in the start-up procedure for the stored
procedures address space.
3. Enter commands in a data set that you want CODE/370 to execute. Put a DD
statement for that data set in the start-up procedure for the stored procedures
address space. To define the data set that contains MFI Debug Tool commands
to CODE/370, specify its data set name or DD name in the TEST run-time
option. For example, this option tells CODE/370 to look for the commands in the
data set that is associated with DD name TESTDD:
TEST(ALL,TESTDD,PROMPT,*)

The first command in the commands data set should be:


SET LOG ON FILE ddname;

This command directs output from your debugging session to the log data set
you defined in step 2. For example, if you defined a log data set with DD name
INSPLOG in the start-up procedure for the stored procedures address space,
the first command should be:
SET LOG ON FILE INSPLOG;

Chapter 14. Creating and using user-defined functions 287


4. Invoke the Debug Tool. Two possible methods are:
v Specify the Language Environment run-time TEST option. The most
convenient place to do that is in the RUN OPTIONS parameter of CREATE
FUNCTION or ALTER FUNCTION.
v Put CEETEST calls in the user-defined function source code. If you use this
approach for an existing user-defined function, you must compile, link-edit,
and bind the user-defined function again. Then you must issue the STOP
FUNCTION SPECIFIC and START FUNCTION SPECIFIC commands to
reload the user-defined function.

You can combine the Language Environment run-time TEST option with
CEETEST calls. For example, you might want to use TEST to name the
commands data set but use CEETEST calls to control when the Debug Tool
takes control.

For more information on CODE/370, see CoOperative Development


Environment/370: Debug Tool.

Route debugging messages to SYSPRINT: You can include simple print


statements in your user-defined function code that you route to SYSPRINT. Then
use System Display and Search Facility (SDSF) to examine the SYSPRINT
contents while the WLM-established stored procedure address space is running.
You can serialize I/O by running the WLM-established stored procedure address
space with NUMTCB=1.

Driver applications: You can write a small driver application that calls the
user-defined function as a subprogram and passes the parameter list for the
user-defined function. You can then test and debug the user-defined function as a
normal DB2 application under TSO. You can then use TSO TEST and other
commonly used debugging tools.

SQL INSERT: You can use SQL to insert debugging information into a DB2 table.
This allows other machines in the network (such as a workstation) to easily access
the data in the table using DRDA access.

DB2 discards the debugging information if the application executes the ROLLBACK
statement. To prevent the loss of the debugging data, code the calling application
so that it retrieves the diagnostic data before executing the ROLLBACK statement.

| Implementing an SQL scalar function


| An SQL scalar function is a user-defined function in which the CREATE FUNCTION
| statement contains the source code. The source code is a single SQL expression
| that evaluates to a single value. The SQL scalar function can return only one
| parameter. You specify the SQL expression in the RETURN clause of the CREATE
| FUNCTION statement. The value of the SQL expression must be compatible with
| the data type of the parameter in the RETURNS clause.

| See “Defining a user-defined function” on page 244 and Chapter 5 of DB2 SQL
| Reference for a description of the parameters that you can specify in the CREATE
| FUNCTION statement for an SQL scalar function.

| To prepare an SQL scalar function for execution, you execute the CREATE
| FUNCTION statement, either statically or dynamically.

288 Application Programming and SQL Guide


| Example: Creating an SQL scalar function: Create an SQL scalar function that
| returns the tangent of the input value. Use the built-in SIN and COS functions to
| calculate the tangent.
| CREATE FUNCTION TAN (X DOUBLE)
| RETURNS DOUBLE
| LANGUAGE SQL
| CONTAINS SQL
| NO EXTERNAL ACTION
| DETERMINISTIC
| RETURN SIN(X)/COS(X);
|
Invoking a user-defined function
You can invoke a sourced or external user-defined scalar function in an SQL
statement wherever you use an expression. For a table function, you can invoke the
user-defined function only in the FROM clause of a SELECT statement. The
invoking SQL statement can be in a stand-alone program, a stored procedure, a
trigger body, or another user-defined function.

See the following sections for details you should know before you invoke a
user-defined function:
v “Syntax for user-defined function invocation”
v “Ensuring that DB2 executes the intended user-defined function” on page 290
v “Casting of user-defined function arguments” on page 296
v “What happens when a user-defined function abnormally terminates” on page 297

Syntax for user-defined function invocation


Use the syntax shown in Figure 109 when you invoke a user-defined scalar
function:

|  function-name ( ) 
ALL ,
DISTINCT
 expression
TABLE transition-table-name
|
||
| Figure 109. Syntax for user-defined scalar function invocation
|
Use the syntax shown in Figure 110 on page 290 when you invoke a table function:

Chapter 14. Creating and using user-defined functions 289


 TABLE ( function-name ( ) ) correlation-clause 
,
 expression
TABLE transition-table-name

correlation-clause:

AS
 correlation-name 
,

(  column-name )

Figure 110. Syntax for table function invocation

See Chapter 2 of DB2 SQL Reference for more information about the syntax of
user-defined function invocation.

Ensuring that DB2 executes the intended user-defined function


Several user-defined functions with the same name but different numbers or types
of parameters can exist in a DB2 subsystem. Several user-defined functions with
the same name can have the same number of parameters, as long as the data
types of any of the first 30 parameters are different. In addition, several
user-defined functions might have the same name as a built-in function. When you
invoke a function, DB2 must determine which user-defined function or built-in
function to execute. This process is known as function resolution. You need to
understand DB2's function resolution process to ensure that you invoke the
user-defined function that you want to invoke.

DB2 performs these steps for function resolution:


1. Determines if any function instances are candidates for execution. If no
candidates exist, DB2 issues an SQL error message.
| 2. Compares the data types of the input parameters to determine which candidates
| fit the invocation best.
| DB2 does not compare data types for input parameters that are untyped
| parameter markers.
| For a qualified function invocation, if there are no parameter markers in the
| invocation, the result of the data type comparison is one best fit. That best fit is
| the choice for execution. If there are parameter markers in the invocation, there
| might be more than one best fit. DB2 issues an error if there is more than one
| best fit.
| For an unqualified function invocation, DB2 might find multiple best fits because
| the same function name with the same input parameters can exist in different
| schemas, or because there are parameter markers in the invocation.
3. If two or more candidates fit the unqualified function invocation equally well
because the same function name with the same input parameters exists in
different schemas, DB2 chooses the user-defined function whose schema name
is earliest in the SQL path.
For example, suppose functions SCHEMA1.X and SCHEMA2.X fit a function
invocation equally well. Assume that the SQL path is:
"SCHEMA2", "SYSPROC", "SYSIBM", "SCHEMA1", "SYSFUN"

290 Application Programming and SQL Guide


Then DB2 chooses function SCHEMA2.X.

| If two or more candidates fit the unqualified function invocation equally well
| because the function invocation contains parameter markers, DB2 issues an
| error.

The remainder of this section discusses details of the function resolution process
and gives suggestions on how you can ensure that DB2 picks the right function.

How DB2 chooses candidate functions


An instance of a user-defined function is a candidate for execution only if it meets
all of the following criteria:
v If the function name is qualified in the invocation, the schema of the function
instance matches the schema in the function invocation.
If the function name is unqualified in the invocation, the schema of the function
instance matches a schema in the invoker's SQL path.
v The name of the function instance matches the name in the function invocation.
v The number of input parameters in the function instance matches the number of
input parameters in the function invocation.
v The function invoker is authorized to execute the function instance.
v The type of each of the input parameters in the function invocation matches or is
promotable to the type of the corresponding parameter in the function instance.
| If an input parameter in the function invocation is an untyped parameter marker,
| DB2 considers that parameter to be a match or promotable.
For a function invocation that passes a transition table, the data type, length,
precision, and scale of each column in the transition table must match exactly the
data type, length, precision, and scale of each column of the table that is named
in the function instance definition. For information on transition tables, see
“Chapter 11. Using triggers for active data” on page 209.
v The create timestamp for a user-defined function must be older than the BIND or
REBIND timestamp for the package or plan in which the user-defined function is
invoked.
If DB2 authorization checking is in effect, and DB2 performs an automatic rebind
on a plan or package that contains a user-defined function invocation, any
user-defined functions that were created after the original BIND or REBIND of the
invoking plan or package are not candidates for execution.
If you use an access control authorization exit routine, some user-defined
functions that were not candidates for execution before the original BIND or
REBIND of the invoking plan or package might become candidates for execution
during the automatic rebind of the invoking plan or package. See Appendix B
(Volume 2) of DB2 Administration Guide for information about function resolution
with access control authorization exit routines.
If a user-defined function is invoked during an automatic rebind, and that
user-defined function is invoked from a trigger body and receives a transition
table, then the form of the invoked function that DB2 uses for function selection
includes only the columns of the transition table that existed at the time of the
original BIND or REBIND of the package or plan for the invoking program.
| During an automatic rebind, DB2 does not consider built-in functions for function
| resolution if those built-in functions were introduced in a later release of DB2
| than the release in which the BIND or REBIND of the invoking plan or package
| occurred.
| When you explicitly bind or rebind a plan or package, the plan or package
| receives a release dependency marker. When DB2 performs an automatic rebind

Chapter 14. Creating and using user-defined functions 291


| of a query that contains a function invocation, a built-in function is a candidate for
| function resolution only if the release dependency marker of the built-in function
| is the same as or lower than the release dependency marker of the plan or
| package that contains the function invocation.

To determine whether a data type is promotable to another data type, see Table 36.
The first column lists data types in function invocations. The second column lists
data types to which the types in the first column can be promoted, in order from
best fit to worst fit. For example, suppose that in this statement, the data type of A
is SMALLINT:
SELECT USER1.ADDTWO(A) FROM TABLEA;

Two instances of USER1.ADDTWO are defined: one with an input parameter of


type INTEGER and one with an input parameter of type DECIMAL. Both function
instances are candidates for execution because the SMALLINT type is promotable
to either INTEGER or DECIMAL. However, the instance with the INTEGER type is a
better fit because INTEGER is higher in the list than DECIMAL.
Table 36. Promotion of data types
Data type in function invocation Possible fits (in best-to-worst order)
CHAR or GRAPHIC CHAR or GRAPHIC
VARCHAR or VARGRAPHIC
CLOB or DBCLOB
VARCHAR or VARGRAPHIC VARCHAR or VARGRAPHIC
CLOB or DBCLOB
CLOB or DBCLOB1 CLOB or DBCLOB
1
BLOB BLOB
SMALLINT SMALLINT
INTEGER
DECIMAL
REAL
DOUBLE
INTEGER INTEGER
DECIMAL
REAL
DOUBLE
DECIMAL DECIMAL
REAL
DOUBLE
REAL2 REAL
DOUBLE
DOUBLE3 DOUBLE
DATE DATE
TIME TIME
TIMESTAMP TIMESTAMP
ROWID ROWID
Distinct type Distinct type with same name

292 Application Programming and SQL Guide


Table 36. Promotion of data types (continued)
Data type in function invocation Possible fits (in best-to-worst order)
Notes:
1. This promotion also applies if the parameter type in the invocation is a LOB locator for a
LOB with this data type.
2. The FLOAT type with a length of less than 22 is equivalent to REAL.
3. The FLOAT type with a length of greater than or equal to 22 is equivalent to DOUBLE.

How DB2 chooses the best fit among candidate functions


More than one function instance might be a candidate for execution. In that case,
DB2 determines which function instances are the best fit for the invocation by
comparing parameter data types.

If the data types of all parameters in a function instance are the same as those in
the function invocation, that function instance is a best fit. If no exact match exists,
DB2 compares data types in the parameter lists from left to right, using this method:
1. DB2 compares the data types of the first parameter in the function invocation to
the data type of the first parameter in each function instance.
| If the first parameter in the invocation is an untyped parameter marker, DB2
| does not do the comparison.
2. For the first parameter, if one function instance has a data type that fits the
function invocation better than the data types in the other instances, that
function is a best fit. Table 36 on page 292 shows the possible fits for each data
type, in best-to-worst order.
| 3. If the data types of the first parameter are the same for all function instances, or
| if the first parameter in the function invocation is an untyped parameter marker,
| DB2 repeats this process for the next parameter. DB2 continues this process for
| each parameter until it finds a best fit.

Example of function resolution: Suppose that a program contains the following


statement:
SELECT FUNC(VCHARCOL,SMINTCOL,DECCOL) FROM T1;

In user-defined function FUNC, VCHARCOL has data type VARCHAR, SMINTCOL


has data type SMALLINT, and DECCOL has data type DECIMAL. Also suppose that
two function instances with the following definitions meet the criteria in “How DB2
chooses candidate functions” on page 291 and are therefore candidates for
execution.
Candidate 1:
CREATE FUNCTION FUNC(VARCHAR(20),INTEGER,DOUBLE)
RETURNS DECIMAL(9,2)
EXTERNAL NAME 'FUNC1'
PARAMETER STYLE DB2SQL
LANGUAGE COBOL;

Candidate 2:
CREATE FUNCTION FUNC(VARCHAR(20),REAL,DOUBLE)
RETURNS DECIMAL(9,2)
EXTERNAL NAME 'FUNC2'
PARAMETER STYLE DB2SQL
LANGUAGE COBOL;

DB2 compares the data type of the first parameter in the user-defined function
invocation to the data types of the first parameters in the candidate functions.
Because the first parameter in the invocation has data type VARCHAR, and both

Chapter 14. Creating and using user-defined functions 293


candidate functions also have data type VARCHAR, DB2 cannot determine the
better candidate based on the first parameter. Therefore, DB2 compares the data
types of the second parameters.

The data type of the second parameter in the invocation is SMALLINT. INTEGER,
which is the data type of candidate 1, is a better fit to SMALLINT than REAL, which
is the data type of candidate 2. Therefore, candidate 1 is DB2's choice for
execution.

How you can simplify function resolution


When you use the following techniques, you can simplify function resolution:
v When you invoke a function, use the qualified name. This causes DB2 to search
for functions only in the schema you specify. This has two advantages:
– DB2 is less likely to choose a function that you did not intend to use. Several
functions might fit the invocation equally well. DB2 picks the function whose
schema name is earliest in the SQL path, which might not be the function you
want.
– The number of candidate functions is smaller, so DB2 takes less time for
function resolution.
v Cast parameters in a user-defined function invocation to the types in the
user-defined function definition. For example, if an input parameter for
user-defined function FUNC is defined as DECIMAL(13,2), and the value you
want to pass to the user-defined function is an integer value, cast the integer
value to DECIMAL(13,2):
SELECT FUNC(CAST (INTCOL AS DECIMAL(13,2))) FROM T1;
v Avoid defining user-defined function numeric parameters as SMALLINT or REAL.
Use INTEGER or DOUBLE instead. An invocation of a user-defined function
defined with parameters of type SMALLINT or REAL must use parameters of the
same types. For example, if user-defined function FUNC is defined with a
parameter of type SMALLINT, only an invocation with a parameter of type
SMALLINT resolves correctly. An invocation like this does not resolve to FUNC
because the constant 123 is of type INTEGER, not SMALLINT:
SELECT FUNC(123) FROM T1;
v Avoid defining user-defined function string parameters with fixed-length string
| types. If you define a parameter with a fixed-length string type (CHAR or
| GRAPHIC), you can invoke the user-defined function only with a fixed-length
| string parameter. However, if you define the parameter with a varying-length
| string type (VARCHAR or VARGRAPHIC), you can invoke the user-defined
| function with either a fixed-length string parameter or a varying-length string
| parameter.
If you must define parameters for a user-defined function as CHAR, and you call
the user-defined function from a C program or SQL procedure, you need to cast
the corresponding parameter values in the user-defined function invocation to
CHAR to ensure that DB2 invokes the correct function. For example, suppose
that a C program calls user-defined function CVRTNUM, which takes one input
parameter of type CHAR(6). Also suppose that you declare host variable
empnumbr as char empnumbr[6]. When you invoke CVRTNUM, cast empnumbr
to CHAR:
UPDATE EMP
SET EMPNO=CVRTNUM(CHAR(:empnumbr))
WHERE EMPNO = :empnumbr;

294 Application Programming and SQL Guide


Using DSN_FUNCTION_TABLE to see how DB2 resolves a
function
You can use DB2's EXPLAIN tool to obtain information about how DB2 resolves
functions. DB2 stores the information in a table called DSN_FUNCTION_TABLE,
which you create. DB2 puts a row in DSN_FUNCTION_TABLE for each function
that is referenced in an SQL statement when one of the following events occurs:
v You execute the SQL EXPLAIN statement on an SQL statement that contains
user-defined function invocations.
v You run a program whose plan is bound with EXPLAIN(YES), and the program
executes an SQL statement that contains user-defined function invocations.

Before you use EXPLAIN to obtain information about function resolution, create
DSN_FUNCTION_TABLE. The table definition looks like this:
CREATE TABLE DSN_FUNCTION_TABLE
(QUERYNO INTEGER NOT NULL WITH DEFAULT,
QBLOCKNO INTEGER NOT NULL WITH DEFAULT,
APPLNAME CHAR(8) NOT NULL WITH DEFAULT,
PROGNAME CHAR(8) NOT NULL WITH DEFAULT,
COLLID CHAR(18) NOT NULL WITH DEFAULT,
GROUP_MEMBER CHAR(8) NOT NULL WITH DEFAULT,
EXPLAIN_TIME TIMESTAMP NOT NULL WITH DEFAULT,
SCHEMA_NAME CHAR(8) NOT NULL WITH DEFAULT,
FUNCTION_NAME CHAR(18) NOT NULL WITH DEFAULT,
SPEC_FUNC_NAME CHAR(18) NOT NULL WITH DEFAULT,
FUNCTION_TYPE CHAR(2) NOT NULL WITH DEFAULT,
VIEW_CREATOR CHAR(8) NOT NULL WITH DEFAULT,
VIEW_NAME CHAR(18) NOT NULL WITH DEFAULT,
PATH VARCHAR(254) NOT NULL WITH DEFAULT,
FUNCTION_TEXT VARCHAR(254) NOT NULL WITH DEFAULT);

Columns QUERYNO, QBLOCKNO, APPLNAME, PROGNAME, COLLID, and


GROUP_MEMBER have the same meanings as in the PLAN_TABLE. See
“Chapter 26. Using EXPLAIN to improve SQL performance” on page 671 for
explanations of those columns. The meanings of the other columns are:
EXPLAIN_TIME
Timestamp when the EXPLAIN statement was executed.
SCHEMA_NAME
Schema name of the function that is invoked in the explained statement.
FUNCTION_NAME
Name of the function that is invoked in the explained statement.
SPEC_FUNC_NAME
Specific name of the function that is invoked in the explained statement.
FUNCTION_TYPE
The type of function that is invoked in the explained statement. Possible values
are:
SU Scalar function
TU Table function
VIEW_CREATOR
The creator of the view, if the function that is specified in the
FUNCTION_NAME column is referenced in a view definition. Otherwise, this
field is blank.

Chapter 14. Creating and using user-defined functions 295


VIEW_NAME
The name of the view, if the function that is specified in the FUNCTION_NAME
column is referenced in a view definition. Otherwise, this field is blank.
PATH
The value of the SQL path when DB2 resolved the function reference.
FUNCTION_TEXT
The text of the function reference (the function name and parameters). If the
function reference exceeds 100 bytes, this column contains the first 100 bytes.
For a function specified in infix notation, FUNCTION_TEXT contains only the
function name. For example, suppose a user-defined function named / is in the
function reference A/B. Then FUNCTION_TEXT contains only /, not A/B.

Casting of user-defined function arguments


Whenever you invoke a user-defined function, DB2 assigns your input parameter
values to parameters with the data types and lengths in the user-defined function
definition. See Chapter 2 of DB2 SQL Reference for information on how DB2
assigns values when the data types of the source and target differ.

When you invoke a user-defined function that is sourced on another function, DB2
casts your parameters to the data types and lengths of the sourced function.

The following example demonstrates what happens when the parameter definitions
of a sourced function differ from those of the function on which it is sourced.

Suppose that external user-defined function TAXFN1 is defined like this:


CREATE FUNCTION TAXFN1(DEC(6,0))
RETURNS DEC(5,2)
PARAMETER STYLE DB2SQL
LANGUAGE C
EXTERNAL NAME TAXPROG;

Sourced user-defined function TAXFN2, which is sourced on TAXFN1, is defined


like this:
CREATE FUNCTION TAXFN2(DEC(8,2))
RETURNS DEC(5,0)
SOURCE TAXFN1;

You invoke TAXFN2 using this SQL statement:


UPDATE TB1
SET SALESTAX2 = TAXFN2(PRICE2);

TB1 is defined like this:


CREATE TABLE TB1
(PRICE1 DEC(6,0),
SALESTAX1 DEC(5,2),
PRICE2 DEC(9,2),
SALESTAX2 DEC(7,2));

Now suppose that PRICE2 has the DECIMAL(9,2) value 0001234.56. DB2 must
first assign this value to the data type of the input parameter in the definition of
TAXFN2, which is DECIMAL(8,2). The input parameter value then becomes
001234.56. Next, DB2 casts the parameter value to a source function parameter,
which is DECIMAL(6,0). The parameter value then becomes 001234. (When you
cast a value, that value is truncated, rather than rounded.)

296 Application Programming and SQL Guide


Now, if TAXFN1 returns the DECIMAL(5,2) value 123.45, DB2 casts the value to
DECIMAL(5,0), which is the result type for TAXFN2, and the value becomes 00123.
This is the value that DB2 assigns to column SALESTAX2 in the UPDATE
statement.

| Casting of parameter markers: You can use untyped parameter markers in a


| function invocation. However, DB2 cannot compare the data types of untyped
| parameter markers to the data types of candidate functions. Therefore, DB2 might
| find more than one function that qualifies for invocation. If this happens, an SQL
| error occurs. To ensure that DB2 picks the right function to execute, cast the
| parameter markers in your function invocation to the data types of the parameters
| in the function that you want to execute. For example, suppose that two versions of
| function FX exist. One version of FX is defined with a parameter of type of
| DECIMAL(9,2), and the other is defined with a parameter of type INTEGER. You
| want to invoke FX with a parameter marker, and you want DB2 to execute the
| version of FX that has a DECIMAL(9,2) parameter. You need to cast the parameter
| marker to a DECIMAL(9,2) type:
| SELECT FX(CAST(? AS DECIMAL(9,2))) FROM T1;

| What happens when a user-defined function abnormally terminates


When an external user-defined function abnormally terminates, your program
receives SQLCODE -430 for the invoking statement, and DB2 places the unit of
work that contains the invoking statement in a must-rollback state. Include code in
your program to check for a user-defined function abend and to roll back the unit of
work that contains the user-defined function invocation.

Nesting SQL Statements


An SQL statement can explicitly invoke user-defined functions or stored procedures
or can implicitly activate triggers that invoke user-defined functions or stored
procedures. This is known as nesting of SQL statements. DB2 supports up to 16
levels of nesting. Figure 111 on page 298 shows an example of SQL statement
nesting.

Chapter 14. Creating and using user-defined functions 297


Trigger TR1 is defined on table T3:
CREATE TRIGGER TR1
AFTER UPDATE ON T3
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
CALL SP3(PARM1);
END

Program P1 (nesting level 1) contains:


SELECT UDF1(C1) FROM T1;

UDF1 (nesting level 2) contains:


CALL SP2(C2);

SP2 (nesting level 3) contains:


UPDATE T3 SET C3=1;

SP3 (nesting level 4) contains:


. SELECT UDF4(C4) FROM T4;
.
.

SP16 (nesting level 16) cannot invoke stored procedures


or user-defined functions

Figure 111. Nested SQL statements

DB2 has the following restrictions on nested SQL statements:


v Restrictions for SELECT statements:
When you execute a SELECT statement on a table, you cannot execute INSERT,
UPDATE, or DELETE statements on the same table at a lower level of nesting.
For example, suppose that you execute this SQL statement at level 1 of nesting:
SELECT UDF1(C1) FROM T1;

You cannot execute this SQL statement at a lower level of nesting:


INSERT INTO T1 VALUES(...);
v Restrictions for INSERT, UPDATE, and DELETE Statements:
When you execute an INSERT, DELETE, or UPDATE statement on a table, you
cannot access that table from a user-defined function or stored procedure that is
at a lower level of nesting.
For example, suppose that you execute this SQL statement at level 1 of nesting:
DELETE FROM T1 WHERE UDF3(T1.C1) = 3;

You cannot execute this SELECT statement at a lower level of nesting:


SELECT * FROM T1;

Although trigger activations count in the levels of SQL statement nesting, the
previous restrictions on SQL statements do not apply to SQL statements that are
executed in the trigger body. For example, suppose that trigger TR1 is defined on
table T1:
CREATE TRIGGER TR1
AFTER INSERT ON T1
FOR EACH STATEMENT MODE DB2SQL
BEGIN ATOMIC
UPDATE T1 SET C1=1;
END

Now suppose that you execute this SQL statement at level 1 of nesting:

298 Application Programming and SQL Guide


INSERT INTO T1 VALUES(...);

Although the UPDATE statement in the trigger body is at level 2 of nesting and
modifies the same table that the triggering statement updates, DB2 can execute the
INSERT statement successfully.

Recommendations for user-defined function invocation


Invoke user-defined functions with external actions and nondeterministic
user-defined functions from select lists: It is better to invoke user-defined functions
with external actions and nondeterministic user-defined functions from select lists,
rather than predicates.

The access path that DB2 chooses for a predicate determines whether a
user-defined function in that predicate is executed. To ensure that DB2 executes the
external action for each row of the result set, put the user-defined function
invocation in the SELECT list.

Invoking a nondeterministic user-defined function from a predicate can yield


undesirable results. The following example demonstrates this idea.

Suppose that you execute this query:


SELECT COUNTER(), C1, C2 FROM T1 WHERE COUNTER() = 2;

Table T1 looks like this:


C1 C2
-- --
1 b
2 c
3 a

COUNTER is a user-defined function that increments a variable in the scratchpad


each time it is invoked.

DB2 invokes an instance of COUNTER in the predicate 3 times. Assume that


COUNTER is invoked for row 1 first, for row 2 second, and for row 3 third. Then
COUNTER returns 1 for row 1, 2 for row 2, and 3 for row 3. Therefore, row 2
satisfies the predicate WHERE COUNTER()=2, so DB2 evaluates the SELECT list
for row 2. DB2 uses a different instance of COUNTER in the select list from the
instance in the predicate. Because the instance of COUNTER in the select list is
invoked only once, it returns a value of 1. Therefore, the result of the query is:
COUNTER() C1 C2
--------- -- --
1 2 c

This is not the result you might expect.

The results can differ even more, depending on the order in which DB2 retrieves
the rows from the table. Suppose that an ascending index is defined on column C2.
Then DB2 retrieves row 3 first, row 1 second, and row 2 third. This means that row
1 satisfies the predicate WHERE COUNTER()=2. The value of COUNTER in the
select list is again 1, so the result of the query in this case is:
COUNTER() C1 C2
--------- -- --
1 1 b

Chapter 14. Creating and using user-defined functions 299


| Understanding the interaction between scrollable cursors and nondeterministic
| user-defined functions or user-defined functions with external actions: When you
| use a scrollable cursor, you might retrieve the same row multiple times while the
| cursor is open. If the select list of the cursor's SELECT statement contains a
| user-defined function, that user-defined function is executed each time you retrieve
| a row. Therefore, if the user-defined function has an external action, and you
| retrieve the same row multiple times, the external action is executed multiple times
| for that row.

| A similar situation occurs with scrollable cursors and nondeterministic functions. The
| result of a nondeterministic user-defined function can be different each time you
| execute the user-defined function. If the select list of a scrollable cursor contains a
| nondeterministic user-defined function, and you use that cursor to retrieve the same
| row multiple times, the results can differ each time you retrieve the row.

| A nondeterministic user-defined function in the predicate of a scrollable cursor's


| SELECT statement does not change the result of the predicate while the cursor is
| open. DB2 evaluates a user-defined function in the predicate only once while the
| cursor is open.

300 Application Programming and SQL Guide


Chapter 15. Creating and using distinct types
A distinct type is a data type that you define using the CREATE DISTINCT TYPE
statement. Each distinct type has the same internal representation as a built-in data
type. You can use distinct types in the same way that you use built-in data types, in
any type of SQL application except for a DB2 private protocol application.

This chapter presents the following information about distinct types:


v “Introduction to distinct types”
v “Using distinct types in application programs” on page 302
v “Combining distinct types with user-defined functions and LOBs” on page 306

Introduction to distinct types


Suppose you want to define some audio and video data in a DB2 table. You can
define columns for both types of data as BLOB, but you might want to use a data
type that more specifically describes the data. To do that, define distinct types. You
can then use those types when you define columns in a table or manipulate the
data in those columns. For example, you can define distinct types for the audio and
video data like this:
CREATE DISTINCT TYPE AUDIO AS BLOB (1M);
CREATE DISTINCT TYPE VIDEO AS BLOB (1M);

Then, your CREATE TABLE statement might look like this:


CREATE TABLE VIDEO_CATALOG;
(VIDEO_NUMBER CHAR(6) NOT NULL,
VIDEO_SOUND AUDIO,
VIDEO_PICS VIDEO,
ROW_ID ROWID NOT NULL GENERATED ALWAYS);

You must define a column of type ROWID in the table because tables with any type
of LOB columns require a ROWID column, and internally, the VIDEO_CATALOG
table contains two LOB columns. For more information on LOB data, see
“Chapter 13. Programming for large objects (LOBs)” on page 229.

After you define distinct types and columns of those types, you can use those data
types in the same way you use built-in types. You can use the data types in
assignments, comparisons, function invocations, and stored procedure calls.
However, when you assign one column value to another or compare two column
values, those values must be of the same distinct type. For example, you must
assign a column value of type VIDEO to a column of type VIDEO, and you can
compare a column value of type AUDIO only to a column of type AUDIO. When you
assign a host variable value to a column with a distinct type, you can use any host
data type that is compatible with the source data type of the distinct type. For
example, to receive an AUDIO or VIDEO value, you can define a host variable like
this:
SQL TYPE IS BLOB (1M) HVAV;

When you use a distinct type as an argument to a function, a version of that


function that accepts that distinct type must exist. For example, if function SIZE
takes a BLOB type as input, you cannot automatically use a value of type AUDIO
as input. However, you can create a sourced user-defined function that takes the
AUDIO type as input. For example:

© Copyright IBM Corp. 1983, 2001 301


CREATE FUNCTION SIZE(AUDIO)
RETURNS INTEGER
SOURCE SIZE(BLOB(1M));

Using distinct types in application programs


The main reason to use distinct types is because DB2 enforces strong typing for
distinct types. Strong typing ensures that only functions, procedures, comparisons,
and assignments that are defined for a data type can be used.

For example, if you have defined a user-defined function to convert U.S. dollars to
euro currency, you do not want anyone to use this same user-defined function to
convert Japanese Yen to euros because the U.S. dollars to euros function returns
the wrong amount. Suppose you define three distinct types:
CREATE DISTINCT TYPE US_DOLLAR AS DECIMAL(9,2) WITH COMPARISONS;
CREATE DISTINCT TYPE EURO AS DECIMAL(9,2) WITH COMPARISONS;
CREATE DISTINCT TYPE JAPANESE_YEN AS DECIMAL(9,2) WITH COMPARISONS;

If a conversion function is defined that takes an input parameter of type


US_DOLLAR as input, DB2 returns an error if you try to execute the function with
an input parameter of type JAPANESE_YEN.

Comparing distinct types


The basic rule for comparisons is that the data types of the operands must be
compatible. The compatibility rule defines, for example, that all numeric types
(SMALLINT, INTEGER, FLOAT, and DECIMAL) are compatible. That is, you can
compare an INTEGER value with a value of type FLOAT. However, you cannot
compare an object of a distinct type to an object of a different type. You can
compare an object with a distinct type only to an object with exactly the same
distinct type.

DB2 does not let you compare data of a distinct type directly to data of its source
type. However, you can compare a distinct type to its source type by using a cast
function.

For example, suppose you want to know which products sold more than US
$100 000.00 in the US in the month of July in 1992 (7/92). Because you cannot
compare data of type US_DOLLAR with instances of data of the source type of
US_DOLLAR (DECIMAL) directly, you must use a cast function to cast data from
DECIMAL to US_DOLLAR or from US_DOLLAR to DECIMAL. Whenever you
create a distinct type, DB2 creates two cast functions, one to cast from the source
type to the distinct type and the other to cast from the distinct type to the source
type. For distinct type US_DOLLAR, DB2 creates a cast function called DECIMAL
and a cast function called US_DOLLAR. When you compare an object of type
US_DOLLAR to an object of type DECIMAL, you can use one of those cast
functions to make the data types identical for the comparison. Suppose table
US_SALES is defined like this:
CREATE TABLE US_SALES
(PRODUCT_ITEM INTEGER,
MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12),
YEAR INTEGER CHECK (YEAR > 1985),
TOTAL US_DOLLAR);

Then you can cast DECIMAL data to US_DOLLAR like this:

302 Application Programming and SQL Guide


SELECT PRODUCT_ITEM
FROM US_SALES
WHERE TOTAL > US_DOLLAR(100000.00)
AND MONTH = 7
AND YEAR = 1992;

The casting satisfies the requirement that the compared data types are identical.

You cannot use host variables in statements that you prepare for dynamic
execution. As explained in “Using parameter markers” on page 508, you can
substitute parameter markers for host variables when you prepare a statement, and
then use host variables when you execute the statement.

If you use a parameter marker in a predicate of a query, and the column to which
you compare the value represented by the parameter marker is of a distinct type,
you must cast the parameter marker to the distinct type, or cast the column to its
source type.

For example, suppose distinct type CNUM is defined like this:


CREATE DISTINCT TYPE CNUM AS INTEGER WITH COMPARISONS;

Table CUSTOMER is defined like this:


CREATE TABLE CUSTOMER
(CUST_NUM CNUM NOT NULL,
FIRST_NAME CHAR(30) NOT NULL,
LAST_NAME CHAR(30) NOT NULL,
PHONE_NUM CHAR(20) WITH DEFAULT,
PRIMARY KEY (CUST_NUM));

In an application program, you prepare a SELECT statement that compares the


CUST_NUM column to a parameter marker. Because CUST_NUM is of a distinct
type, you must cast the distinct type to its source type:
SELECT FIRST_NAME, LAST_NAME, PHONE_NUM FROM CUSTOMER
WHERE CAST(CUST_NUM AS INTEGER) = ?

Alternatively, you can cast the parameter marker to the distinct type:
SELECT FIRST_NAME, LAST_NAME, PHONE_NUM FROM CUSTOMER
WHERE CUST_NUM = CAST (? AS CNUM)

Assigning distinct types


For assignments from columns to columns or from constants to columns of distinct
types, the type of that value to be assigned must match the type of the object to
which the value is assigned, or you must be able to cast one type to the other.

If you need to assign a value of one distinct type to a column of another distinct
type, a function must exist that converts the value from one type to another.
Because DB2 provides cast functions only between distinct types and their source
types, you must write the function to convert from one distinct type to another.

Assigning column values to columns with different distinct types


Suppose tables JAPAN_SALES and JAPAN_SALES_98 are defined like this:
CREATE TABLE JAPAN_SALES
(PRODUCT_ITEM INTEGER,
MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12),
YEAR INTEGER CHECK (YEAR > 1985),
TOTAL JAPANESE_YEN);

Chapter 15. Creating and using distinct types 303


CREATE TABLE JAPAN_SALES_98
(PRODUCT_ITEM INTEGER,
TOTAL US_DOLLAR);

You need to insert values from the TOTAL column in JAPAN_SALES into the
TOTAL column of JAPAN_SALES_98. Because INSERT statements follow
assignment rules, DB2 does not let you insert the values directly from one column
to the other because the columns are of different distinct types. Suppose that a
user-defined function called US_DOLLAR has been written that accepts values of
type JAPANESE_YEN as input and returns values of type US_DOLLAR. You can
then use this function to insert values into the JAPAN_SALES_98 table:
INSERT INTO JAPAN_SALES_98
SELECT PRODUCT_ITEM, US_DOLLAR(TOTAL)
FROM JAPAN_SALES
WHERE YEAR = 1998;

Assigning column values with distinct types to host variables


The rules for assigning distinct types to host variables or host variables to columns
of distinct types differ from the rules for constants and columns.

You can assign a column value of a distinct type to a host variable if you can assign
a column value of the distinct type's source type to the host variable. In the
following example, you can assign SIZECOL1 and SIZECOL2, which has distinct
type SIZE, to host variables of type double and short because the source type of
SIZE, which is INTEGER, can be assigned to host variables of type double or short.
EXEC SQL BEGIN DECLARE SECTION;
double hv1;
short hv2;
EXEC SQL END DECLARE SECTION;
CREATE DISTINCT TYPE SIZE AS INTEGER;
CREATE
. TABLE TABLE1 (SIZECOL1 SIZE, SIZECOL2 SIZE);
.
.

SELECT SIZECOL1, SIZECOL2


INTO :hv1, :hv2
FROM TABLE1;

Assigning host variable values to columns with distinct types


When you assign a value in a host variable to a column with a distinct type, the
type of the host variable must be castable to the distinct type. For a table of base
data types and the base data types to which they can be cast, see Table 36 on
page 292.

In this example, values of host variable hv2 can be assigned to columns SIZECOL1
and SIZECOL2, because C data type short is equivalent to DB2 data type
SMALLINT, and SMALLINT is promotable to data type INTEGER. However, values
of hv1 cannot be assigned to SIZECOL1 and SIZECOL2, because C data type
double, which is equivalent to DB2 data type DOUBLE, is not promotable to data
type INTEGER.
EXEC SQL BEGIN DECLARE SECTION;
double hv1;
short hv2;
EXEC SQL END DECLARE SECTION;
CREATE DISTINCT TYPE SIZE AS INTEGER;
CREATE
. TABLE TABLE1 (SIZECOL1 SIZE, SIZECOL2 SIZE);
.
.

INSERT INTO TABLE1

304 Application Programming and SQL Guide


VALUES (:hv1,:hv1); /* Invalid statement */
INSERT INTO TABLE1
VALUES (:hv2,:hv2); /* Valid statement */

Using distinct types in UNIONs


As with comparisons, DB2 enforces strong typing of distinct types in UNIONs.
When you use a UNION to combine column values from several tables, the
combined columns must be of the same types. For example, suppose you create a
view that combines the values of the US_SALES, EUROPEAN_SALES, and
JAPAN_SALES tables. The TOTAL columns in the three tables are of different
distinct types, so before you combine the table values, you must convert the types
of two of the TOTAL columns to the type of the third TOTAL column. Assume that
the US_DOLLAR type has been chosen as the common distinct type. Because DB2
does not generate cast functions to convert from one distinct type to another, two
user-defined functions must exist:
v A function that converts values of type EURO to US_DOLLAR
v A function that converts values of type JAPANESE_YEN to US_DOLLAR
Assume that these functions exist, and that both are called US_DOLLAR. Then you
can execute a query like this to display a table of combined sales:
SELECT PRODUCT_ITEM, MONTH, YEAR, TOTAL
FROM US_SALES
UNION
SELECT PRODUCT_ITEM, MONTH, YEAR, US_DOLLAR(TOTAL)
FROM EUROPEAN_SALES
UNION
SELECT PRODUCT_ITEM, MONTH, YEAR, US_DOLLAR(TOTAL)
FROM JAPAN_SALES;

Because the result type of both US_DOLLAR functions is US_DOLLAR, you have
satisfied the requirement that the distinct types of the combined columns are the
same.

Invoking functions with distinct types


DB2 enforces strong typing when you pass arguments to a function. This means
that:
v You can pass arguments that have distinct types to a function if either of the
following conditions is true:
– A version of the function that accepts those distinct types is defined.
This also applies to infix operators. If you want to use one of the five built-in
infix operators (||, /, *, +, -) with your distinct types, you must define a version
of that operator that accepts the distinct types.
– You can cast your distinct types to the argument types of the function.
v If you pass arguments to a function that accepts only distinct types, the
arguments you pass must have the same distinct types as in the function
definition. If the types are different, you must cast your arguments to the distinct
types in the function definition.
If you pass constants or host variables to a function that accepts only distinct
types, you must cast the constants or host variables to the distinct types that the
function accepts.

The following examples demonstrate how to use distinct types as arguments in


function invocations.

Chapter 15. Creating and using distinct types 305


Example: Defining a function with distinct types as arguments: Suppose you
want to invoke the built-in function HOUR with a distinct type that is defined like
this:
CREATE DISTINCT TYPE FLIGHT_TIME AS TIME WITH COMPARISONS;

The HOUR function takes only the TIME or TIMESTAMP data type as an argument,
so you need a sourced function that is based on the HOUR function that accepts
the FLIGHT_TIME data type. You might declare a function like this:
CREATE FUNCTION HOUR(FLIGHT_TIME)
RETURNS INTEGER
SOURCE SYSIBM.HOUR(TIME);

Example: Casting function arguments to acceptable types: Another way you


can invoke the HOUR function is to cast the argument of type FLIGHT_TIME to the
TIME data type before you invoke the HOUR function. Suppose table
FLIGHT_INFO contains column DEPARTURE_TIME, which has data type
FLIGHT_TIME, and you want to use the HOUR function to extract the hour of
departure from the departure time. You can cast DEPARTURE_TIME to the TIME
data type, and then invoke the HOUR function:
SELECT HOUR(CAST(DEPARTURE_TIME AS TIME)) FROM FLIGHT_INFO;

Example: Using an infix operator with distinct type arguments: Suppose you
want to add two values of type US_DOLLAR. Before you can do this, you must
define a version of the + function that accepts values of type US_DOLLAR as
operands:
CREATE FUNCTION "+"(US_DOLLAR,US_DOLLAR)
RETURNS US_DOLLAR
SOURCE SYSIBM."+"(DECIMAL(9,2),DECIMAL(9,2));

Because the US_DOLLAR type is based on the DECIMAL(9,2) type, the source
function must be the version of + with arguments of type DECIMAL(9,2).

Example: Casting constants and host variables to distinct types to invoke a


user-defined function: Suppose function CDN_TO_US is defined like this:
CREATE FUNCTION EURO_TO_US(EURO)
RETURNS US_DOLLAR
EXTERNAL NAME 'CDNCVT'
PARAMETER STYLE DB2SQL
LANGUAGE C;

This means that EURO_TO_US accepts only the EURO type as input. Therefore, if
you want to call CDN_TO_US with a constant or host variable argument, you must
cast that argument to distinct type EURO:
SELECT * FROM US_SALES
WHERE TOTAL = EURO_TO_US(EURO(:H1));
SELECT * FROM US_SALES
WHERE TOTAL = EURO_TO_US(EURO(10000));

Combining distinct types with user-defined functions and LOBs


The example in this section demonstrates the following concepts:
v Creating a distinct type based on a LOB data type
v Defining a user-defined function with a distinct type as an argument
v Creating a table with a distinct type column that is based on a LOB type
v Defining a LOB table space, auxiliary table, and auxiliary index

306 Application Programming and SQL Guide


v Inserting data from a host variable into a distinct type column based on a LOB
column
v Executing a query that contains a user-defined function invocation
v Casting a LOB locator to the input data type of a user-defined function

Suppose you keep electronic mail documents that are sent to your company in a
DB2 table. The DB2 data type of an electronic mail document is a CLOB, but you
define it as a distinct type so that you can control the types of operations that are
performed on the electronic mail. The distinct type is defined like this:
CREATE DISTINCT TYPE E_MAIL AS CLOB(5M);

You have also defined and written user-defined functions to search for and return
the following information about an electronic mail document:
v Subject
v Sender
v Date sent
v Message content
v Indicator of whether the document contains a user-specified string
The user-defined function definitions look like this:
CREATE FUNCTION SUBJECT(E_MAIL)
RETURNS VARCHAR(200)
EXTERNAL NAME 'SUBJECT'
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION;
CREATE FUNCTION SENDER(E_MAIL)
RETURNS VARCHAR(200)
EXTERNAL NAME 'SENDER'
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION;
CREATE FUNCTION SENDING_DATE(E_MAIL)
RETURNS DATE
EXTERNAL NAME 'SENDDATE'
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION;
CREATE FUNCTION CONTENTS(E_MAIL)
RETURNS CLOB(1M)
EXTERNAL NAME 'CONTENTS'
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION;
CREATE FUNCTION CONTAINS(E_MAIL, VARCHAR (200))
RETURNS INTEGER
EXTERNAL NAME 'CONTAINS'
LANGUAGE C
PARAMETER STYLE DB2SQL
NO SQL
DETERMINISTIC
NO EXTERNAL ACTION;

Chapter 15. Creating and using distinct types 307


The table that contains the electronic mail documents is defined like this:
CREATE TABLE DOCUMENTS
(LAST_UPDATE_TIME TIMESTAMP,
DOC_ROWID ROWID NOT NULL GENERATED ALWAYS,
A_DOCUMENT E_MAIL);

Because the table contains a column with a source data type of CLOB, the table
requires a ROWID column and an associated LOB table space, auxiliary table, and
index on the auxiliary table. Use statements like this to define the LOB table space,
the auxiliary table, and the index:
CREATE LOB TABLESPACE DOCTSLOB
LOG YES
GBPCACHE SYSTEM;

CREATE AUX TABLE DOCAUX_TABLE


IN DOCTSLOB
STORES DOCUMENTS COLUMN A_DOCUMENT;

CREATE INDEX A_IX_DOC ON DOCAUX_TABLE;

To populate the document table, you write code that executes an INSERT statement
to put the first part of a document in the table, and then executes multiple UPDATE
statements to concatenate the remaining parts of the document. For example:
EXEC SQL BEGIN DECLARE SECTION;
char hv_current_time[26];
SQL TYPE IS CLOB (1M) hv_doc;
EXEC SQL END DECLARE SECTION;
/* Determine the current time and put this value */
/* into host variable hv_current_time. */
/* Read up to 1 MB of document data from a file */
/*
. into host variable hv_doc. */
.
.

/* Insert the time value and the first 1 MB of */


/* document data into the table. */
EXEC SQL INSERT INTO DOCUMENTS
VALUES(:hv_current_time, DEFAULT, E_MAIL(:hv_doc));

/* While there is more document data in the */


/* file, read up to 1 MB more of data, and then */
/* use an UPDATE statement like this one to */
/* concatenate the data in the host variable */
/* to the existing data in the table. */
EXEC SQL UPDATE DOCUMENTS
SET A_DOCUMENT = A_DOCUMENT || E_MAIL(:hv_doc)
WHERE LAST_UPDATE_TIME = :hv_current_time;

Now that the data is in the table, you can execute queries to learn more about the
documents. For example, you can execute this query to determine which
documents contain the word 'performance':
SELECT SENDER(A_DOCUMENT), SENDING_DATE(A_DOCUMENT),
SUBJECT(A_DOCUMENT)
FROM DOCUMENTS
WHERE CONTAINS(A_DOCUMENT,'performance') = 1;

Because the electronic mail documents can be very large, you might want to use
LOB locators to manipulate the document data instead of fetching all of a document
into a host variable. You can use a LOB locator on any distinct type that is defined
on one of the LOB types. The following example shows how you can cast a LOB
locator as a distinct type, and then use the result in a user-defined function that
takes a distinct type as an argument:

308 Application Programming and SQL Guide


EXEC SQL BEGIN DECLARE SECTION
long hv_len;
char hv_subject[200];
SQL TYPE IS CLOB_LOCATOR hv_email_locator;
EXEC
. SQL END DECLARE SECTION
.
.

/* Select a document into a CLOB locator. */


EXEC SQL SELECT A_DOCUMENT, SUBJECT(A_DOCUMENT)
INTO :hv_email_locator, :hv_subject
FROM DOCUMENTS
. WHERE LAST_UPDATE_TIME = :hv_current_time;
.
.

/* Extract the subject from the document. The */


/* SUBJECT function takes an argument of type */
/* E_MAIL, so cast the CLOB locator as E_MAIL. */
EXEC SQL SET :hv_subject =
. SUBJECT(CAST(:hv_email_locator AS E_MAIL));
.
.

Chapter 15. Creating and using distinct types 309


310 Application Programming and SQL Guide
Part 4. Designing a DB2 database application
Chapter 16. Planning for DB2 program preparation . . . . . . . . . . 315
Planning to process SQL statements . . . . . . . . . . . . . . . . 316
Planning to bind . . . . . . . . . . . . . . . . . . . . . . . . 317
Deciding how to bind DBRMs . . . . . . . . . . . . . . . . . . 317
Binding with a package list only . . . . . . . . . . . . . . . . 317
Binding all DBRMs to a plan . . . . . . . . . . . . . . . . . 318
Binding with both DBRMs and a package list . . . . . . . . . . . 318
Advantages of packages . . . . . . . . . . . . . . . . . . . 318
Planning for changes to your application . . . . . . . . . . . . . . 319
Dropping objects . . . . . . . . . . . . . . . . . . . . . . 320
Rebinding a package . . . . . . . . . . . . . . . . . . . . 320
Rebinding a plan. . . . . . . . . . . . . . . . . . . . . . 321
Rebinding lists of plans and packages . . . . . . . . . . . . . . 322
Working with trigger packages . . . . . . . . . . . . . . . . . 322
Automatic rebinding. . . . . . . . . . . . . . . . . . . . . 322

Chapter 17. Planning for concurrency . . . . . . . . . . . . . . . 325


Definitions of concurrency and locks . . . . . . . . . . . . . . . . 325
Effects of DB2 locks . . . . . . . . . . . . . . . . . . . . . . 326
Suspension. . . . . . . . . . . . . . . . . . . . . . . . . 326
Timeout . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Deadlock . . . . . . . . . . . . . . . . . . . . . . . . . 327
Basic recommendations to promote concurrency . . . . . . . . . . . . 329
Recommendations for database design . . . . . . . . . . . . . . 330
Recommendations for application design . . . . . . . . . . . . . . 330
Aspects of transaction locks . . . . . . . . . . . . . . . . . . . 333
The size of a lock . . . . . . . . . . . . . . . . . . . . . . 333
Definition . . . . . . . . . . . . . . . . . . . . . . . . 333
Hierarchy of lock sizes . . . . . . . . . . . . . . . . . . . 333
General effects of size. . . . . . . . . . . . . . . . . . . . 334
Effects of table spaces of different types . . . . . . . . . . . . . 334
The duration of a lock . . . . . . . . . . . . . . . . . . . . . 335
Definition . . . . . . . . . . . . . . . . . . . . . . . . 335
Effects . . . . . . . . . . . . . . . . . . . . . . . . . 335
The mode of a lock . . . . . . . . . . . . . . . . . . . . . . 336
Definition . . . . . . . . . . . . . . . . . . . . . . . . 336
Modes of page and row locks . . . . . . . . . . . . . . . . . 336
Modes of table, partition, and table space locks . . . . . . . . . . 337
Lock mode compatibility . . . . . . . . . . . . . . . . . . . 337
The object of a lock. . . . . . . . . . . . . . . . . . . . . . 338
Definition and examples . . . . . . . . . . . . . . . . . . . 338
Indexes and data-only locking . . . . . . . . . . . . . . . . . 339
Lock tuning . . . . . . . . . . . . . . . . . . . . . . . . . . 339
Bind options . . . . . . . . . . . . . . . . . . . . . . . . 339
The ACQUIRE and RELEASE options . . . . . . . . . . . . . . 339
Advantages and disadvantages of the combinations . . . . . . . . . 341
The ISOLATION option . . . . . . . . . . . . . . . . . . . 343
Advantages and disadvantages of the isolation values . . . . . . . . 343
The CURRENTDATA option. . . . . . . . . . . . . . . . . . 347
When plan and package options differ . . . . . . . . . . . . . . 350
The effect of WITH HOLD for a cursor . . . . . . . . . . . . . . 350
Isolation overriding with SQL statements . . . . . . . . . . . . . . 351
The statement LOCK TABLE . . . . . . . . . . . . . . . . . . 352

© Copyright IBM Corp. 1983, 2001 311


The purpose of LOCK TABLE . . . . . . . . . . . . . . . . . 352
The effect of LOCK TABLE . . . . . . . . . . . . . . . . . . 352
Recommendations for using LOCK TABLE . . . . . . . . . . . . 352
Access paths . . . . . . . . . . . . . . . . . . . . . . . . 353
LOB locks . . . . . . . . . . . . . . . . . . . . . . . . . . 355
Relationship between transaction locks and LOB locks . . . . . . . . . 355
Hierarchy of LOB locks . . . . . . . . . . . . . . . . . . . . 356
LOB and LOB table space lock modes. . . . . . . . . . . . . . . 357
Modes of LOB locks . . . . . . . . . . . . . . . . . . . . 357
Modes of LOB table space locks . . . . . . . . . . . . . . . . 357
Duration of locks . . . . . . . . . . . . . . . . . . . . . . . 357
Duration of locks on LOB table spaces . . . . . . . . . . . . . 357
Duration of LOB locks . . . . . . . . . . . . . . . . . . . . 357
Instances when locks on LOB table space are not taken . . . . . . . . 358
The LOCK TABLE statement . . . . . . . . . . . . . . . . . . 358

Chapter 18. Planning for recovery . . . . . . . . . . . . . . . . 359


Unit of work in TSO (batch and online) . . . . . . . . . . . . . . . 359
Unit of work in CICS . . . . . . . . . . . . . . . . . . . . . . 360
Unit of work in IMS (online) . . . . . . . . . . . . . . . . . . . . 361
Planning ahead for program recovery: Checkpoint and restart . . . . . . 362
What symbolic checkpoint does . . . . . . . . . . . . . . . . 362
What restart does . . . . . . . . . . . . . . . . . . . . . 363
When are checkpoints important? . . . . . . . . . . . . . . . . 363
Checkpoints in MPPs and transaction-oriented BMPs . . . . . . . . . 364
Checkpoints in batch-oriented BMPs . . . . . . . . . . . . . . . 364
Specifying checkpoint frequency . . . . . . . . . . . . . . . . . 365
Unit of work in DL/I batch and IMS batch . . . . . . . . . . . . . . . 365
Commit and rollback coordination . . . . . . . . . . . . . . . . 365
Using ROLL . . . . . . . . . . . . . . . . . . . . . . . 366
Using ROLB . . . . . . . . . . . . . . . . . . . . . . . 366
In batch programs . . . . . . . . . . . . . . . . . . . . . 366
Restart and recovery in IMS (batch). . . . . . . . . . . . . . . . 367
Using savepoints to undo selected changes within a unit of work . . . . . . 367

Chapter 19. Planning to access distributed data . . . . . . . . . . . 369


Introduction to accessing distributed data . . . . . . . . . . . . . . . 369
Coding for distributed data by two methods . . . . . . . . . . . . . . 371
Using three-part table names . . . . . . . . . . . . . . . . . . 372
Using explicit CONNECT statements . . . . . . . . . . . . . . . 373
Releasing connections . . . . . . . . . . . . . . . . . . . 373
Coding considerations for access methods . . . . . . . . . . . . . . 374
Preparing programs For DRDA access. . . . . . . . . . . . . . . . 376
Precompiler options. . . . . . . . . . . . . . . . . . . . . . 376
BIND PACKAGE options . . . . . . . . . . . . . . . . . . . . 376
BIND PLAN options. . . . . . . . . . . . . . . . . . . . . . 377
Checking BIND PACKAGE options . . . . . . . . . . . . . . . . 378
Coordinating updates to two or more data sources . . . . . . . . . . . 379
How to have coordinated updates . . . . . . . . . . . . . . . . 379
What you can do without two-phase commit. . . . . . . . . . . . . 380
Miscellaneous topics for distributed data . . . . . . . . . . . . . . . 381
Improving performance for remote access . . . . . . . . . . . . . 381
Code efficient queries . . . . . . . . . . . . . . . . . . . . 381
Maximizing LOB performance in a distributed environment . . . . . . . 382
Use bind options that improve performance . . . . . . . . . . . . . 383
DEFER(PREPARE) . . . . . . . . . . . . . . . . . . . . . 383

312 Application Programming and SQL Guide


PKLIST . . . . . . . . . . . . . . . . . . . . . . . . . 383
REOPT(VARS) . . . . . . . . . . . . . . . . . . . . . . 384
CURRENTDATA(NO) . . . . . . . . . . . . . . . . . . . . 385
KEEPDYNAMIC(YES) . . . . . . . . . . . . . . . . . . . . 385
DBPROTOCOL(DRDA) . . . . . . . . . . . . . . . . . . . 385
Use block fetch . . . . . . . . . . . . . . . . . . . . . . . 385
When DB2 uses block fetch for non-scrollable cursors . . . . . . . . 386
| When DB2 uses block fetch for scrollable cursors . . . . . . . . . 386
Specifying OPTIMIZE FOR n ROWS . . . . . . . . . . . . . . . 388
| Specifying FETCH FIRST n ROWS ONLY . . . . . . . . . . . . . 390
DB2 for OS/390 and z/OS support for the rowset parameter . . . . . . . 391
| Accessing data with a scrollable cursor when the requester is down-level 392
Maintaining data currency . . . . . . . . . . . . . . . . . . . 392
Copying a table from a remote location . . . . . . . . . . . . . . 392
Transmitting mixed data . . . . . . . . . . . . . . . . . . . . 392
Identifying the server at run time . . . . . . . . . . . . . . . . 392
| Retrieving data from ASCII or Unicode tables . . . . . . . . . . . . 392
Considerations for moving from DB2 private protocol access to DRDA
access . . . . . . . . . . . . . . . . . . . . . . . . . 393

Part 4. Designing a DB2 database application 313


314 Application Programming and SQL Guide
Chapter 16. Planning for DB2 program preparation
DB2 application programs include SQL statements. You need to process those SQL
statements, using either the DB2 precompiler or an SQL statement coprocessor that
is provided with a compiler. Either type of SQL statement processor does the
following things:
v Replaces the SQL statements in your source programs with calls to DB2
language interface modules
v Creates a database request module (DBRM), which communicates your SQL
requests to DB2 during the bind process

Figure 112 illustrates the program preparation process when you use the DB2
precompiler. Figure 113 on page 316 illustrates the program preparation process
when you use an SQL statement coprocessor. “Chapter 20. Preparing an
application program to run” on page 397 supplies specific details about
accomplishing these steps.

After you have processed SQL statements in your source program, you create a
load module, possibly one or more packages, and an application plan. Creating a
load module involves compiling and link-editing the modified source code that is
produced by the precompiler. Creating a package or an application plan, a process
unique to DB2, involves binding one or more DBRMs.

Figure 112. Program preparation with the DB2 precompiler

© Copyright IBM Corp. 1983, 2001 315


Figure 113. Program preparation with an SQL statement coprocessor

Planning to process SQL statements


When you process SQL statements in an application program, you can specify a
number of options. Most of the options do not affect the way you design or code the
program. Those options describe the basic characteristics of the source program or
indicate how you want the output listings to look. For example, there are options
that specify:
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.

A few options, however, can 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.

| Before you begin writing your program, review the list of options in Table 48 on
| page 403. You can specify any of those options whether you use the DB2
| precompiler or an SQL statement coprocessor. However, the SQL statement
| coprocessor might ignore certain options because there are compiler options that
| provide the same information.

316 Application Programming and SQL Guide


Planning to bind
Depending upon how you design your DB2 application, you might bind all your
DBRMs in one operation, creating only a single application plan. Or, you might bind
some or all of your DBRMs into separate packages in separate operations. After
that, you must still bind the entire application as a single plan, listing the included
packages or collections and binding any DBRMs not already bound into packages.
Regardless of what the plan contains, you must bind a plan before the application
can run.

Binding or rebinding a package or plan in use: 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.

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.

Options for binding and rebinding: Several of the options of BIND PACKAGE
and BIND PLAN 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 a particular IMS region—you do not have to enforce this in your code.
Several other options are discussed at length in later chapters, particularly the ones
that affect your program’s use of locks, such as the option ISOLATION. Before you
finish reading this chapter, you might want to review those options in Chapter 2 of
DB2 Command Reference.

Preliminary steps: Before you bind, consider the following:


v Determine how you want to bind the DBRMs. You can bind them into packages,
directly into plans, or use a combination of both methods.
v Develop a naming convention and strategy for the most effective and efficient
use of your plans and packages.
v Determine when your application should acquire locks on the objects it uses: on
all objects when the plan is first allocated, or on each object in turn when that
object is first used. For a description of the consequences of either choice, see
“The ACQUIRE and RELEASE options” on page 339.

Deciding how to bind DBRMs


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

Input to binding the plan can include DBRMs only, a package list only, or a
combination of the two. When choosing one of those alternatives for your
application, consider the impact of rebinding and see “Planning for changes to your
application” on page 319.

Binding with a package list only


At one extreme, you can bind each DBRM into its own package. Input to binding a
package is a single DBRM only. A one-to-one correspondence between programs
and packages might easily allow you to keep track of each. However, your
application could consist of too many packages to track easily.

Chapter 16. Planning for DB2 program preparation 317


Binding a plan that includes only a package list makes maintenance easier when
the application changes significantly over time.

Binding all DBRMs to a plan


At the other extreme, you can bind all your DBRMs to a single plan. This approach
has the disadvantage that a change to even one DBRM requires rebinding the
entire plan, even though most DBRMs are unchanged.

Binding all DBRMs to a plan 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.

Binding with both DBRMs and a package list


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

Advantages of packages
You must decide how to use packages based on your application design and your
operational objectives. Keep in mind the following:

Ease of maintenance: 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 associated with the changed SQL statement.

Incremental development of your program: Binding packages into package


collections allows you to add packages to an existing application plan without
having to bind the entire plan again. A collection is a group of associated packages.
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 even 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.

Versioning: 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.

Flexibility in using bind options: The options of BIND PLAN apply to all DBRMs
bound directly to the plan. The options of BIND PACKAGE apply only to the single
DBRM 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
used by the same plan.

Flexibility in using name qualifiers: 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.

318 Application Programming and SQL Guide


CICS

With packages, you probably do not need dynamic plan selection and its
accompanying exit routine. A package listed within a plan is not accessed until
it is executed. However, it is possible to use dynamic plan selection and
packages together. Doing so can reduce the number of plans in an
application, and hence less effort to maintain the dynamic plan exit routine.
See “Using packages with dynamic plan selection” on page 423 for information
on using packages with dynamic plan selection.

Planning for changes to your application


As you design your application, consider what will happen to your plans and
packages when you make changes to your application.

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.
v To bind a new plan or package, other than a trigger package, use the
subcommand BIND PLAN or BIND PACKAGE with the option
ACTION(REPLACE).
To bind a new trigger package, recreate the trigger associated with the trigger
package.
v To rebind an existing plan or package, other than a trigger package, use the
REBIND subcommand.
To rebind trigger package, use the REBIND TRIGGER PACKAGE subcommand.
Table 37 tells which action particular types of change require. For more information
on trigger packages, see “Working with trigger packages” on page 322.

If you want to change the bind options in effect when the plan or package runs,
review the descriptions of those options in Chapter 2 of DB2 Command Reference.
Not all options of BIND are also available on REBIND.

A plan or package can also become invalid for reasons that do not depend on
operations in your program: for example, if an index is dropped that is used as an
access path by one of your queries. In those cases, DB2 might rebind the plan or
package automatically, the next time it is used. (For details about that operation,
see “Automatic rebinding” on page 322.)
Table 37. Changes requiring BIND or REBIND
Change made: Minimum action necessary:
Drop a table, index or other object, If a table with a trigger is dropped, recreate the trigger
and recreate the object if you recreate the table. Otherwise, no change is
required; automatic rebind is attempted at the next run.
Revoke an authorization to use an None required; automatic rebind is attempted at the
object next run. Automatic rebind fails if authorization is still
not available; then you must issue REBIND for the
package or plan.
Run RUNSTATS to update catalog Issue REBIND for the package or plan to possibly
statistics change the access path chosen.

Chapter 16. Planning for DB2 program preparation 319


Table 37. Changes requiring BIND or REBIND (continued)
Change made: Minimum action necessary:
Add an index to a table Issue REBIND for the package or plan to use the
index.
Change bind options Issue REBIND for the package or plan, or issue BIND
with ACTION(REPLACE) if the option you want is not
available on REBIND.
Change statements in host language Precompile, compile, and link the application program.
and SQL statements Issue BIND with ACTION(REPLACE) for the package
or plan.

Dropping objects
If you drop an object that a package depends on, the following occurs:
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 outside of that
plan, the object is not dropped, and the package does not become invalid.
v If the package is appended to a running plan, and the drop occurs within that
plan, the package becomes invalid.

In all cases, the plan does not become invalid unless it has a DBRM referencing
the dropped object. If the package or plan becomes invalid, automatic rebind occurs
the next time the package or plan is allocated.

Rebinding a package
Table 38 clarifies which packages are bound, depending on how you specify
collection-id (coll-id) package-id (pkg-id), and version-id (ver-id) on the REBIND
PACKAGE subcommand. For syntax and descriptions of this subcommand, see
Chapter 2 of DB2 Command Reference.

REBIND PACKAGE does not apply to packages for which you do not have the
BIND privilege. An asterisk (*) used as an identifier for collections, packages, or
versions does not apply to packages at remote sites.
Table 38. Behavior of REBIND PACKAGE specification. “All” means all collections, packages,
or versions at the local DB2 server for which the authorization ID that issues the command
has the BIND privilege. The symbol 'v .' stands for a required period in the command syntax;
'.' stands for an asterisk.
INPUT Collections Packages Versions
Affected Affected Affected
. all all all
.v.v(.) all all all
.v. all all all
.v.v(ver-id) all all ver-id
.v.v() all all empty string
coll-idv. coll-id all all
coll-idv.v(.) coll-id all all
coll-idv.v(ver-id) coll-id all ver-id
coll-idv.v() coll-id all empty string
coll-idvpkg-idv(.) coll-id pkg-id all

320 Application Programming and SQL Guide


Table 38. Behavior of REBIND PACKAGE specification (continued). “All” means all
collections, packages, or versions at the local DB2 server for which the authorization ID that
issues the command has the BIND privilege. The symbol 'v .' stands for a required period in
the command syntax; '.' stands for an asterisk.
INPUT Collections Packages Versions
Affected Affected Affected
coll-idvpkg-id coll-id pkg-id empty string
coll-idvpkg-idv() coll-id pkg-id empty string
coll-idvpkg-idv(ver-id) coll-id pkg-id ver-id
.vpkg-idv(.) all pkg-id all
.vpkg-id all pkg-id empty string
.vpkg-idv() all pkg-id empty string
.vpkg-idv(ver-id) all pkg-id ver-id

The following example shows the options for rebinding a package at the remote
location, SNTERSA. The collection is GROUP1, the package ID is PROGA, and the
version ID is V1. The connection types shown in the REBIND subcommand replace
connection types specified on the original BIND subcommand. For information on
the REBIND subcommand options, see DB2 Command Reference.
REBIND PACKAGE(SNTERSA.GROUP1.PROGA.(V1)) ENABLE(CICS,REMOTE)

You can use the asterisk on the REBIND subcommand for local packages, but not
for packages at remote sites. Any of the following commands rebinds all versions of
all packages in all collections, at the local DB2 system, for which you have the
BIND privilege.

REBIND PACKAGE (*)


REBIND PACKAGE (*.*)
REBIND PACKAGE (*.*.(*))

Either of the following commands rebinds all versions of all packages in the local
collection LEDGER for which you have the BIND privilege.

REBIND PACKAGE (LEDGER.*)


REBIND PACKAGE (LEDGER.*.(*))

Either of the following commands rebinds the empty string version of the package
DEBIT in all collections, at the local DB2 system, for which you have the BIND
privilege.

REBIND PACKAGE (*.DEBIT)


REBIND PACKAGE (*.DEBIT.())

Rebinding a plan
Using the PKLIST keyword replaces any previously specified package list. Omitting
the PKLIST keyword allows the use of the previous package list for rebinding. Using
the NOPKLIST keyword deletes any package list specified when the plan was
previously bound.

The following example rebinds PLANA and changes the package list.

REBIND PLAN(PLANA) PKLIST(GROUP1.*) MEMBER(ABC)

Chapter 16. Planning for DB2 program preparation 321


The following example rebinds the plan and drops the entire package list.

REBIND PLAN(PLANA) NOPKLIST

Rebinding lists of plans and packages


You can generate a list of REBIND subcommands for a set of plans or packages
that cannot be described by using asterisks, using information in the DB2 catalog.
You can then issue the list of subcommands through DSN.

One situation in which the technique is particularly useful is in completing a rebind


operation that has terminated for lack of resources. A rebind for many objects, say
REBIND PACKAGE (*) for an ID with SYSADM authority, terminates if a needed
resource becomes unavailable. As a result, some objects are successfully rebound
and others are not. If you repeat the subcommand, DB2 attempts to rebind all the
objects again. But if you generate a rebind subcommand for each object that was
not rebound, and issue those, DB2 does not repeat any work already done and is
not likely to run out of resources.

For a description of the technique and several examples of its use, see
“Appendix E. REBIND subcommands for lists of plans or packages” on page 915.

Working with 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 the
trigger with which it is associated 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 activates. However, if the automatic
rebind fails, DB2 does not mark the trigger package inoperative.

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 inoperative. You can also use REBIND TRIGGER
PACKAGE to change the option values with which DB2 originally bound the trigger
package. The default values for the options that you can change are:
v CURRENTDATA(YES)
v EXPLAIN(YES)
v FLAG(I)
v ISOLATION(RR)
v IMMEDWRITE(NO)
v RELEASE(COMMIT)
When you run REBIND TRIGGER PACKAGE, you can change only the values of
options CURRENTDATA, EXPLAIN, FLAG, IMMEDWRITE, ISOLATION, and
RELEASE.

Automatic rebinding
Automatic rebind might occur if an authorized user invokes a plan or package when
the attributes of the data on which the plan or package depends change, or if the
environment in which the package executes changes. Whether the automatic rebind
occurs depends on the value of the field AUTO BIND on installation panel
DSNTIPO. The options used for an automatic rebind are the options used during
the most recent bind process.

322 Application Programming and SQL Guide


In most cases, DB2 marks a plan or package that needs to be automatically
rebound as invalid. A few common situations in which DB2 marks a plan or package
as invalid are:
v When a table, index, or view on which the plan or package depends is dropped
v When the authorization of the owner to access any of those objects is revoked
v When the authorization to execute a stored procedure is revoked from a plan or
package owner, and the plan or package uses the CALL literal form to call the
stored procedure
v When a table on which the plan or package depends is altered to add a TIME,
TIMESTAMP, or DATE column
v When a created temporary table on which the plan or package depends is
altered to add a column
v When a user-defined function on which the plan or package depends is altered
v When a table is altered to add a self-referencing constraint or a constraint with a
delete rule of SET NULL or CASCADE

Whether a plan or package is valid is recorded in column VALID of catalog tables


SYSPLAN and SYSPACKAGE.

In the following cases, DB2 might automatically rebind a plan or package that has
not been marked as invalid:
v A plan or package is bound in a different release of DB2 from the release in
which it was first used.
v A plan or package has a location dependency and runs at a location other than
the one at which it was bound. This can happen when members of a data
sharing group are defined with location names, and a package runs on a different
member from the one on which it was bound.

DB2 marks a plan or package as inoperative if an automatic rebind fails. Whether a


plan or package is operative is recorded in column OPERATIVE of SYSPLAN and
SYSPACKAGE.

Whether EXPLAIN runs during automatic rebind depends on the value of the field
EXPLAIN PROCESSING on installation panel DSNTIPO, and on whether you
specified EXPLAIN(YES). Automatic rebind fails for all EXPLAIN errors except
“PLAN_TABLE not found.”

The SQLCA is not available during automatic rebind. Therefore, if you encounter
lock contention during an automatic rebind, DSNT501I messages cannot
accompany any DSNT376I messages that you receive. To see the matching
DSNT501I messages, you must issue the subcommand REBIND PLAN or REBIND
PACKAGE.

Chapter 16. Planning for DB2 program preparation 323


324 Application Programming and SQL Guide
Chapter 17. Planning for concurrency
This chapter begins with an overview of concurrency and locks in the following
sections:
v “Definitions of concurrency and locks”,
v “Effects of DB2 locks” on page 326, and
v “Basic recommendations to promote concurrency” on page 329.

After the basic recommendations, the chapter tells what you can do about a major
technique that DB2 uses to control concurrency.
v Transaction locks mainly control access by SQL statements. Those locks are
the ones over which you have the most control.
– “Aspects of transaction locks” on page 333 describes the various types of
transaction locks that DB2 uses and how they interact.
– “Lock tuning” on page 339 describes what you can change to control locking.
Your choices include:
- “Bind options” on page 339
- “Isolation overriding with SQL statements” on page 351
- “The statement LOCK TABLE” on page 352

Under those headings, lock (with no qualifier) refers to transaction lock.

Two other techniques also control concurrency in some situations.


v Claims and drains control access by DB2 utilities and commands. For
information about them, see Part 5 (Volume 2) of DB2 Administration Guide.
v Physical locks are of concern only if you are using DB2 data sharing. For
information about that, see DB2 Data Sharing: Planning and Administration.

Definitions of concurrency and locks


Definition: Concurrency is the ability of more than one application process to
access the same data at essentially the same time.

Example: An application for order entry is used by many transactions


simultaneously. Each transaction makes inserts in tables of invoices and invoice
items, reads a table of data about customers, and reads and updates data about
items on hand. Two operations on the same data, by two simultaneous
transactions, might be separated only by microseconds. To the users, the
operations appear concurrent.

Conceptual background: Concurrency must be controlled to prevent lost updates


and such possibly undesirable effects as unrepeatable reads and access to
uncommitted data.
Lost updates. Without concurrency control, two processes, A and B, might both
read the same row from the database, and both calculate new values for one of
its columns, based on what they read. If A updates the row with its new value,
and then B updates the same row, A’s update is lost.
Access to uncommitted data. Also without concurrency control, process A
might update a value in the database, and process B might read that value
before it was committed. Then, if A’s value is not later committed, but backed
out, B’s calculations are based on uncommitted (and presumably incorrect) data.
Unrepeatable reads. Some processes require the following sequence of events:
A reads a row from the database and then goes on to process other SQL

© Copyright IBM Corp. 1983, 2001 325


requests. Later, A reads the first row again and must find the same values it
read the first time. Without control, process B could have changed the row
between the two read operations.

To prevent those situations from occurring unless they are specifically allowed, DB2
might use locks to control concurrency.

What do locks do? A lock associates a DB2 resource with an application process
in a way that affects how other processes can access the same resource. The
process associated with the resource is said to “hold” or “own” the lock. DB2 uses
locks to ensure that no process accesses data that has been changed, but not yet
committed, by another process.

What do you do about locks? To preserve data integrity, your application process
acquires locks implicitly, that is, under DB2 control. It is not necessary for a process
to request a lock explicitly to conceal uncommitted data. Therefore, sometimes you
need not do anything about DB2 locks. Nevertheless processes acquire, or avoid
acquiring, locks based on certain general parameters. You can make better use of
your resources and improve concurrency by understanding the effects of those
parameters.

Effects of DB2 locks


The effects of locks that you want to minimize are suspension, timeout, and
deadlock.

Suspension
Definition: An application process is suspended when it requests a lock that is
already held by another application process and cannot be shared. The suspended
process temporarily stops running.

Order of precedence for lock requests: Incoming lock requests are queued.
Requests for lock promotion, and requests for a lock by an application process that
already holds a lock on the same object, precede requests for locks by new
applications. Within those groups, the request order is “first in, first out”.

Example: Using an application for inventory control, two users attempt to reduce
the quantity on hand of the same item at the same time. The two lock requests are
queued. The second request in the queue is suspended and waits until the first
request releases its lock.

Effects: The suspended process resumes running when:


v All processes that hold the conflicting lock release it.
v The requesting process times out or deadlocks and the process resumes to deal
with an error condition.

Timeout
Definition: An application process is said to time out when it is terminated because
it has been suspended for longer than a preset interval.

Example: An application process attempts to update a large table space that is


being reorganized by the utility REORG TABLESPACE with SHRLEVEL NONE. It is
likely that the utility job will not release control of the table space before the
application process times out.

326 Application Programming and SQL Guide


Effects: DB2 terminates the process, issues two messages to the console, and
returns SQLCODE -911 or -913 to the process (SQLSTATEs '40001' or '57033').
Reason code 00C9008E is returned in the SQLERRD(3) field of the SQLCA. If
statistics trace class 3 is active, DB2 writes a trace record with IFCID 0196.

IMS

If you are using IMS, and a timeout occurs, the following actions take place:
v In a DL/I batch application, the application process abnormally terminates
with a completion code of 04E and a reason code of 00D44033 or
00D44050.
v In any IMS environment except DL/I batch:
– DB2 performs a rollback operation on behalf of your application process
to undo all DB2 updates that occurred during the current unit of work.
– For a non-message driven BMP, IMS issues a rollback operation on
behalf of your application. If this operation is successful, IMS returns
control to your application, and the application receives SQLCODE -911.
If the operation is unsuccessful, IMS issues user abend code 0777, and
the application does not receive an SQLCODE.
– For an MPP, IFP, or message driven BMP, IMS issues user abend code
0777, rolls back all uncommitted changes, and reschedules the
transaction. The application does not receive an SQLCODE.

COMMIT and ROLLBACK operations do not time out. The command STOP
DATABASE, however, may time out and send messages to the console, but it will
retry up to 15 times.

Deadlock
Definition: A deadlock occurs when two or more application processes each hold
locks on resources that the others need and without which they cannot proceed.

Example: Figure 114 on page 328 illustrates a deadlock between two transactions.

Chapter 17. Planning for concurrency 327


Table N
(3)
Job EMPLJCHG 000010 Page A
Suspend
(1) OK

Table M (2) OK
(4)
000300 Page B Job PROJNCHG
Suspend

Notes:
1. Jobs EMPLJCHG and PROJNCHG are two transactions. Job EMPLJCHG
accesses table M, and acquires an exclusive lock for page B, which contains
record 000300.
2. Job PROJNCHG accesses table N, and acquires an exclusive lock for page A,
which contains record 000010.
3. Job EMPLJCHG requests a lock for page A of table N while still holding the lock
on page B of table M. The job is suspended, because job PROJNCHG is
holding an exclusive lock on page A.
4. Job PROJNCHG requests a lock for page B of table M while still holding the
lock on page A of table N. The job is suspended, because job EMPLJCHG is
holding an exclusive lock on page B. The situation is a deadlock.

Figure 114. A deadlock example

Effects: After a preset time interval (the value of DEADLOCK TIME), DB2 can roll
back the current unit of work for one of the processes or request a process to
terminate. That frees the locks and allows the remaining processes to continue. If
statistics trace class 3 is active, DB2 writes a trace record with IFCID 0172. Reason
code 00C90088 is returned in the SQLERRD(3) field of the SQLCA.

It is possible for two processes to be running on distributed DB2 subsystems, each


trying to access a resource at the other location. In that case, neither subsystem
can detect that the two processes are in deadlock; the situation resolves only when
one process times out.

Indications of deadlocks: In some cases, a deadlock can occur if two application


processes attempt to update data in the same page or table space.

TSO, Batch, and CAF

When a deadlock or timeout occurs in these environments, DB2 attempts to


roll back the SQL for one of the application processes. If the ROLLBACK is
successful, that application receives SQLCODE -911. If the ROLLBACK fails,
and the application does not abend, the application receives SQLCODE -913.

328 Application Programming and SQL Guide


IMS

If you are using IMS, and a deadlock occurs, the following actions take place:
v In a DL/I batch application, the application process abnormally terminates
with a completion code of 04E and a reason code of 00D44033 or
00D44050.
v In any IMS environment except DL/I batch:
– DB2 performs a rollback operation on behalf of your application process
to undo all DB2 updates that occurred during the current unit of work.
– For a non-message driven BMP, IMS issues a rollback operation on
behalf of your application. If this operation is successful, IMS returns
control to your application, and the application receives SQLCODE -911.
If the operation is unsuccessful, IMS issues user abend code 0777, and
the application does not receive an SQLCODE.
– For an MPP, IFP, or message driven BMP, IMS issues user abend code
0777, rolls back all uncommitted changes, and reschedules the
transaction. The application does not receive an SQLCODE.

CICS

If you are using CICS and a deadlock occurs, the CICS attachment facility
decides whether or not to roll back one of the application processes, based on
the value of the ROLBE or ROLBI parameter. If your application process is
chosen for rollback, it receives one of two SQLCODEs in the SQLCA:
-911 A SYNCPOINT command with the ROLLBACK option was
issued on behalf of your application process. All updates
(CICS commands and DL/I calls, as well as SQL statements)
that occurred during the current unit of work have been
undone. (SQLSTATE '40001')
-913 A SYNCPOINT command with the ROLLBACK option was not
issued. DB2 rolls back only the incomplete SQL statement that
encountered the deadlock or timed out. CICS does not roll
back any resources. Your application process should either
issue a SYNCPOINT command with the ROLLBACK option
itself or terminate. (SQLSTATE '57033')

Consider using the DSNTIAC subroutine to check the SQLCODE and display
the SQLCA. Your application must take appropriate actions before resuming.

Basic recommendations to promote concurrency


Recommendations are grouped roughly by their scope, as:
v “Recommendations for database design” on page 330
v “Recommendations for application design” on page 330

Chapter 17. Planning for concurrency 329


Recommendations for database design
Keep like things together: Cluster tables relevant to the same application into the
same database, and give each application process that creates private tables a
private database in which to do it. In the ideal model, each application process uses
as few databases as possible.

Keep unlike things apart: Give users different authorization IDs for work with
different databases; for example, one ID for work with a shared database and
another for work with a private database. This effectively adds to the number of
possible (but not concurrent) application processes while minimizing the number of
databases each application process can access.

Plan for batch inserts: If your application does sequential batch insertions,
excessive contention on the space map pages for the table space can occur. This
problem is especially apparent in data sharing, where contention on the space map
means the added overhead of page P-lock negotiation. For these types of
applications, consider using the MEMBER CLUSTER option of CREATE
TABLESPACE. This option causes DB2 to disregard the clustering index (or implicit
clustering index) when assigning space for the SQL INSERT statement. For more
information about using this option in data sharing, see Chapter 6 of DB2 Data
Sharing: Planning and Administration. For the syntax, see Chapter 5 of DB2 SQL
Reference.

Use LOCKSIZE ANY until you have reason not to: LOCKSIZE ANY is the default
for CREATE TABLESPACE. It allows DB2 to choose the lock size, and DB2 usually
chooses LOCKSIZE PAGE and LOCKMAX SYSTEM for non-LOB table spaces. For
| LOB table spaces, it chooses LOCKSIZE LOB and LOCKMAX SYSTEM. You
| should use LOCKSIZE TABLESPACE or LOCKSIZE TABLE only for read-only table
| spaces or tables, or when concurrent access to the object is not needed. Before
you choose LOCKSIZE ROW, you should estimate whether there will be an
increase in overhead for locking and weigh that against the increase in concurrency.

Examine small tables: For small tables with high concurrency requirements,
estimate the number of pages in the data and in the index. If the index entries are
short or they have many duplicates, then the entire index can be one root page and
a few leaf pages. In this case, spread out your data to improve concurrency, or
consider it a reason to use row locks.

Partition the data: Online queries typically make few data changes, but they occur
often. Batch jobs are just the opposite; they run for a long time and change many
rows, but occur infrequently. The two do not run well together. You might be able to
separate online applications from batch, or two batch jobs from each other. To
separate online and batch applications, provide separate partitions. Partitioning can
also effectively separate batch jobs from each other.

Fewer rows of data per page: By using the MAXROWS clause of CREATE or
ALTER TABLESPACE, you can specify the maximum number of rows that can be
on a page. For example, if you use MAXROWS 1, each row occupies a whole
page, and you confine a page lock to a single row. Consider this option if you have
a reason to avoid using row locking, such as in a data sharing environment where
row locking overhead can be excessive.

Recommendations for application design


Access data in a consistent order: When different applications access the same
data, try to make them do so in the same sequence. For example, make both

330 Application Programming and SQL Guide


access rows 1,2,3,5 in that order. In that case, the first application to access the
data delays the second, but the two applications cannot deadlock. For the same
reason, try to make different applications access the same tables in the same order.

Commit work as soon as is practical: To avoid unnecessary lock contentions,


issue a COMMIT statement as soon as possible after reaching a point of
consistency, even in read-only applications. To prevent unsuccessful SQL
statements (such as PREPARE) from holding locks, issue a ROLLBACK statement
after a failure. Statements issued through SPUFI can be committed immediately by
the SPUFI autocommit feature.

Taking commit points frequently in a long running unit of recovery (UR) has the
following benefits:
v Reduces lock contention
v Improves the effectiveness of lock avoidance, especially in a data sharing
environment
v Reduces the elapsed time for DB2 system restart following a system failure
v Reduces the elapsed time for a unit of recovery to rollback following an
application failure or an explicit rollback request by the application
v Provides more opportunity for utilities, such as online REORG, to break in

| Consider using the UR CHECK FREQ field or the UR LOG WRITE CHECK field of
| installation panel DSNTIPN to help you identify those applications that are not
| committing frequently. UR CHECK FREQ, which identifies when too many
| checkpoints have occurred without a UR issuing a commit, is helpful in monitoring
| overall system activity. UR LOG WRITE CHECK enables you to detect applications
| that might write too many log records between commit points, potentially creating a
| lengthy recovery situation for critical tables.

Even though an application might conform to the commit frequency standards of the
installation under normal operational conditions, variation can occur based on
system workload fluctuations. For example, a low-priority application might issue a
commit frequently on a system that is lightly loaded. However, under a heavy
system load, the use of the CPU by the application may be pre-empted, and, as a
result, the application may violate the rule set by the UR CHECK FREQ parameter.
For this reason, add logic to your application to commit based on time elapsed
since last commit, and not solely based on the amount of SQL processing
performed. In addition, take frequent commit points in a long running unit of work
that is read-only to reduce lock contention and to provide opportunities for utilities,
such as online REORG, to access the data.

Retry an application after deadlock or timeout: Include logic in a batch program


so that it retries an operation after a deadlock or timeout. Such a method could help
you recover from the situation without assistance from operations personnel. Field
SQLERRD(3) in the SQLCA returns a reason code that indicates whether a
deadlock or timeout occurred.

Close cursors: If you define a cursor using the WITH HOLD option, the locks it
needs can be held past a commit point. Use the CLOSE CURSOR statement as
soon as possible in your program to cause those locks to be released and the
resources they hold to be freed at the first commit point that follows the CLOSE
CURSOR statement. Whether page or row locks are held for WITH HOLD cursors
is controlled by the RELEASE LOCKS parameter on panel DSNTIP4.

Chapter 17. Planning for concurrency 331


Free locators: If you have executed, the HOLD LOCATOR statement, the LOB
locator holds locks on LOBs past commit points. Use the FREE LOCATOR
statement to release these locks.

Bind plans with ACQUIRE(USE): ACQUIRE(USE), which indicates that DB2 will
acquire table and table space locks when the objects are first used and not when
the plan is allocated, is the best choice for concurrency. Packages are always
| bound with ACQUIRE(USE), by default. ACQUIRE(ALLOCATE) can provide better
| protection against timeouts. Consider ACQUIRE(ALLOCATE) for applications that
| need gross locks instead of intent locks or that run with other applications that may
| request gross locks instead of intent locks. Acquiring the locks at plan allocation
| also prevents any one transaction in the application from incurring the cost of
| acquiring the table and table space locks. If you need ACQUIRE(ALLOCATE), you
| might want to bind all DBRMs directly to the plan.

Bind with ISOLATION(CS) and CURRENTDATA(NO) typically: ISOLATION(CS)


lets DB2 release acquired row and page locks as soon as possible.
CURRENTDATA(NO) lets DB2 avoid acquiring row and page locks as often as
possible. After that, in order of decreasing preference for concurrency, use these
bind options:
1. ISOLATION(CS) with CURRENTDATA(YES), when data returned to the
application must not be changed before your next FETCH operation.
2. ISOLATION(RS), when data returned to the application must not be changed
before your application commits or rolls back. However, you do not care if other
application processes insert additional rows.
3. ISOLATION(RR), when data evaluated as the result of a query must not be
changed before your application commits or rolls back. New rows cannot be
inserted into the answer set.

| For updatable scrollable cursors, ISOLATION(CS) provides the additional advantage


| of letting DB2 use optimistic concurrency control to further reduce the amount of
| time that locks are held. For more information about optimistic concurrency control,
| see “Advantages and disadvantages of the isolation values” on page 343.

Use ISOLATION(UR) cautiously: UR isolation acquires almost no locks on rows or


pages. It is fast and causes little contention, but it reads uncommitted data. Do not
use it unless you are sure that your applications and end users can accept the
logical inconsistencies that can occur.

Use global transactions:The Recoverable Resource Manager Services attachment


facility (RRSAF) relies on an OS/390 component called OS/390 Transaction
Management and Recoverable Resource Manager Services (OS/390 RRS). OS/390
RRS provides system-wide services for coordinating two-phase commit operations
across MVS products. For RRSAF applications and IMS transactions that run under
OS/390 RRS, you can group together a number of DB2 agents into a single global
transaction. A global transaction allows multiple DB2 agents to participate in a
single global transaction and thus share the same locks and access the same data.
When two agents that are in a global transaction access the same DB2 object
within a unit of work, those agents will not deadlock with each other. The following
restrictions apply:
v There is no Parallel Sysplex support for global transactions.
v Because each of the ″branches″ of a global transaction are sharing locks,
uncommitted updates issued by one branch of the transaction are visible to other
branches of the transaction.

332 Application Programming and SQL Guide


v Claim/drain processing is not supported across the branches of a global
transaction, which means that attempts to issue CREATE, DROP, ALTER,
GRANT, or REVOKE may deadlock or timeout if they are requested from
different branches of the same global transaction.
v Attempts to update a partitioning key may deadlock or timeout because of the
same restrictions on claim/drain processing.
v LOCK TABLE may deadlock or timeout across the branches of a global
transaction.

For information on how to make an agent part of a global transaction for RRSAF
applications, see “Chapter 30. Programming for the Recoverable Resource Manager
Services attachment facility (RRSAF)” on page 767.

Aspects of transaction locks


Transaction locks have the following four basic aspects:
v “The size of a lock”
v “The duration of a lock” on page 335
v “The mode of a lock” on page 336
v “The object of a lock” on page 338

Knowing the aspects helps you understand why a process suspends or times out or
why two processes deadlock.

The size of a lock


Definition
The size (sometimes scope or level) of a lock on data in a table describes the
amount of data controlled. The possible sizes of locks are table space, table,
partition, page, and row. This section contains information about locking for
non-LOB data. See “LOB locks” on page 355 for information on locking for LOBs.

Hierarchy of lock sizes


The same piece of data can be controlled by locks of different sizes. A table space
lock (the largest size) controls the most data, all the data in an entire table space. A
page or row lock controls only the data in a single page or row.

As Figure 115 on page 334 suggests, row locks and page locks occupy an equal
place in the hierarchy of lock sizes.

Chapter 17. Planning for concurrency 333


Segmented table space Simple table space LOB table space

Table space lock Table space lock LOB table space lock

Table lock

Row lock Page lock Row lock Page lock LOB lock

Partitioned table space

Partitioned table space lock

Row lock Page lock Row lock Page lock Row lock Page lock

Partitioned table space with LOCKPART YES

Partition lock Partition lock Partition lock

Row lock Page lock Row lock Page lock Row lock Page lock

Figure 115. Sizes of objects locked

General effects of size


Locking larger or smaller amounts of data allows you to trade performance for
concurrency. Using page or row locks instead of table or table space locks has the
following effects:
v Concurrency usually improves, meaning better response times and higher
throughput rates for many users.
v Processing time and use of storage increases. That is especially evident in batch
processes that scan or update a large number of rows.
Using only table or table space locks has the following effects:
v Processing time and storage usage is reduced.
v Concurrency can be reduced, meaning longer response times for some users but
better throughput for one user.

Effects of table spaces of different types


v The LOCKPART clause of CREATE and ALTER TABLESPACE lets you control
how DB2 locks partitioned table spaces. The default, LOCKPART NO, means
that one lock is used to lock the entire partitioned table space when any partition
is accessed. LOCKPART NO is the value you want in most cases.
With LOCKPART YES, individual partitions are locked only as they are accessed.

334 Application Programming and SQL Guide


One case for using LOCKPART YES is for some data sharing applications, as
described in Chapter 6 of DB2 Data Sharing: Planning and Administration. There
are also benefits to non-data-sharing applications that use partitioned table
spaces. For these applications, it might be desirable to acquire gross locks (S, U,
or X) on partitions to avoid numerous lower level locks and yet still maintain
concurrency. When locks escalate and the table space is defined with
LOCKPART YES, applications that access different partitions of the same table
space do not conflict during update activity.
Restrictions: If any of the following conditions are true, DB2 must lock all
partitions when LOCKPART YES is used:
– The plan is bound with ACQUIRE(ALLOCATE).
– The table space is defined with LOCKSIZE TABLESPACE.
– LOCK TABLE IN EXCLUSIVE MODE or LOCK TABLE IN SHARE MODE is
used (without the PART option).

No matter how LOCKPART is defined, utility jobs can control separate partitions
of a table space or index space and can run concurrently with operations on
other partitions.
v A simple table space can contain more than one table. A lock on the table
space locks all the data in every table. A single page of the table space can
contain rows from every table. A lock on a page locks every row in the page, no
matter what tables the data belongs to. Thus, a lock needed to access data from
one table can make data from other tables temporarily unavailable. That effect
can be partly undone by using row locks instead of page locks. But that step
does not relieve the sweeping effect of a table space lock.
v In a segmented table space, rows from different tables are contained in different
pages. Locking a page does not lock data from more than one table. Also, DB2
can acquire a table lock, which locks only the data from one specific table.
Because a single row, of course, contains data from only one table, the effect of
a row lock is the same as for a simple or partitioned table space: it locks one row
of data from one table.
v In a LOB table space, pages are not locked. Because there is no concept of a
row in a LOB table space, rows are not locked. Instead, LOBs are locked. See
“LOB locks” on page 355 for more information.

The duration of a lock


Definition
The duration of a lock is the length of time the lock is held. It varies according to
when the lock is acquired and when it is released.

Effects
For maximum concurrency, locks on a small amount of data held for a short
duration are better than locks on a large amount of data held for a long duration.
However, acquiring a lock requires processor time, and holding a lock requires
storage; thus, acquiring and holding one table space lock is more economical than
acquiring and holding many page locks. Consider that trade-off to meet your
performance and concurrency objectives.

Duration of partition, table, and table space locks: Partition, table, and table
space locks can be acquired when a plan is first allocated, or you can delay
acquiring them until the resource they lock is first used. They can be released at
the next commit point or be held until the program terminates.

Chapter 17. Planning for concurrency 335


On the other hand, LOB table space locks are always acquired when needed and
released at a commit or held until the program terminates. See “LOB locks” on
page 355 for information about locking LOBs and LOB table spaces.

Duration of page and row locks: If a page or row is locked, DB2 acquires the lock
only when it is needed. When the lock is released depends on many factors, but it
is rarely held beyond the next commit point.

For information about controlling the duration of locks, see “Bind options” on
page 339.

The mode of a lock


Definition
The mode (sometimes state) of a lock tells what access to the locked object is
permitted to the lock owner and to any concurrent processes.

The possible modes for page and row locks and the modes for partition, table, and
table space locks are listed below. See “LOB locks” on page 355 for more
information about modes for LOB locks and locks on LOB table spaces.

When a page or row is locked, the table, partition, or table space containing it is
also locked. In that case, the table, partition, or table space lock has one of the
intent modes: IS, IX, or SIX. The modes S, U, and X of table, partition, and table
space locks are sometimes called gross modes. In the context of reading, SIX is a
gross mode lock because you don’t get page or row locks; in this sense, it is like an
S lock.

Example: An SQL statement locates John Smith in a table of customer data and
changes his address. The statement locks the entire table space in mode IX and
the specific row that it changes in mode X.

Modes of page and row locks


Modes and their effects are listed in the order of increasing control over resources.
S (SHARE) The lock owner and any concurrent processes can read, but not
change, the locked page or row. Concurrent processes can acquire
S or U locks on the page or row or might read data without
acquiring a page or row lock.
U (UPDATE) The lock owner can read, but not change, the locked page or row.
Concurrent processes can acquire S locks or might read data
without acquiring a page or row lock, but no concurrent process can
acquire a U lock.
U locks reduce the chance of deadlocks when the lock owner is
reading a page or row to determine whether to change it, because
the owner can start with the U lock and then promote the lock to an
X lock to change the page or row.
X (EXCLUSIVE)
The lock owner can read or change the locked page or row. A
concurrent process can access the data if the process runs with UR
isolation. (A concurrent process that is bound with cursor stability
and CURRENTDATA(NO) can also read X-locked data if DB2 can
tell that the data is committed.)

336 Application Programming and SQL Guide


Modes of table, partition, and table space locks
Modes and their effects are listed in the order of increasing control over resources.
IS (INTENT SHARE) The lock owner can read data in the table, partition,
or table space, but not change it. Concurrent
processes can both read and change the data. The
lock owner might acquire a page or row lock on any
data it reads.
IX (INTENT EXCLUSIVE) The lock owner and concurrent processes can read
and change data in the table, partition, or table
space. The lock owner might acquire a page or row
lock on any data it reads; it must acquire one on
any data it changes.
S (SHARE) The lock owner and any concurrent processes can
read, but not change, data in the table, partition, or
table space. The lock owner does not need page or
row locks on data it reads.
U (UPDATE) The lock owner can read, but not change, the
locked data; however, the owner can promote the
lock to an X lock and then can change the data.
Processes concurrent with the U lock can acquire S
locks and read the data, but no concurrent process
can acquire a U lock. The lock owner does not
need page or row locks.
U locks reduce the chance of deadlocks when the
lock owner is reading data to determine whether to
change it. U locks are acquired on a table space
when locksize is TABLESPACE and the statement
is SELECT FOR UPDATE OF. Similarly, U locks are
acquired on a table when lock size is TABLE and
the statement is SELECT FOR UPDATE OF.
SIX (SHARE with INTENT EXCLUSIVE)
The lock owner can read and change data in the
table, partition, or table space. Concurrent
processes can read data in the table, partition, or
table space, but not change it. Only when the lock
owner changes data does it acquire page or row
locks.
X (EXCLUSIVE) The lock owner can read or change data in the
table, partition, or table space. A concurrent process
can access the data if the process runs with UR
isolation or if data in a LOCKPART(YES) table
space is running with CS isolation and
CURRENTDATA(NO). The lock owner does not
need page or row locks.

Lock mode compatibility


The major effect of the lock mode is to determine whether one lock is compatible
with another.

Definition: Locks of some modes do not shut out all other users. Assume that
application process A holds a lock on a table space that process B also wants to
access. DB2 requests, on behalf of B, a lock of some particular mode. If the mode
of A’s lock permits B’s request, the two locks (or modes) are said to be compatible.

Chapter 17. Planning for concurrency 337


Effects of incompatibility: If the two locks are not compatible, B cannot proceed.
It must wait until A releases its lock. (And, in fact, it must wait until all existing
incompatible locks are released.)

Compatible lock modes: Compatibility for page and row locks is easy to define.
Table 39 shows whether page locks of any two modes, or row locks of any two
modes, are compatible (Yes) or not (No). No question of compatibility of a page lock
with a row lock can arise, because a table space cannot use both page and row
locks.
Table 39. Compatibility of page lock and row lock modes
Lock Mode S U X

S Yes Yes No
U Yes No No
X No No No

Compatibility for table space locks is slightly more complex. Table 40 shows
whether or not table space locks of any two modes are compatible.
Table 40. Compatibility of table and table space (or partition) lock modes
Lock Mode IS IX S U SIX X

IS Yes Yes Yes Yes Yes No


IX Yes Yes No No No No
S Yes No Yes Yes No No
U Yes No Yes No No No
SIX Yes No No No No No
X No No No No No No

The object of a lock


Definition and examples
The object of a lock is the resource being locked.

You might have to consider locks on any of the following objects:


v User data in target tables. A target table is a table that is accessed specifically
in an SQL statement, either by name or through a view. Locks on those tables
are the most common concern, and the ones over which you have most control.
v User data in related tables. Operations subject to referential constraints can
require locks on related tables. For example, if you delete from a parent table,
DB2 might delete rows from the dependent table as well. In that case, DB2 locks
data in the dependent table as well as in the parent table.
Similarly, operations on rows that contain LOB values might require locks on the
LOB table space and possibly on LOB values within that table space. See “LOB
locks” on page 355 for more information.
If your application uses triggers, any triggered SQL statements can cause
additional locks to be acquired.
v DB2 internal objects. Most of these you are never aware of, but you might
notice the following locks on internal objects:
– Portions of the DB2 catalog
– The skeleton cursor table (SKCT) representing an application plan
– The skeleton package table (SKPT) representing a package
– The database descriptor (DBD) representing a DB2 database

338 Application Programming and SQL Guide


For information about any of those, see Part 5 (Volume 2) of DB2 Administration
Guide.

Indexes and data-only locking


No index page locks are acquired during processing. Instead, DB2 uses a
technique called data-only locking to serialize changes. Index page latches are
acquired to serialize changes within a page and guarantee that the page is
physically consistent. Acquiring page latches ensures that transactions accessing
the same index page concurrently do not see the page in a partially changed state.

The underlying data page or row locks are acquired to serialize the reading and
updating of index entries to ensure the data is logically consistent, meaning that the
data is committed and not subject to rollback or abort. The data locks can be held
for a long duration such as until commit. However, the page latches are only held
for a short duration while the transaction is accessing the page. Because the index
pages are not locked, hot spot insert scenarios (which involve several transactions
trying to insert different entries into the same index page at the same time) do not
cause contention problems in the index.

A query that uses index-only access might lock the data page or row, and that lock
can contend with other processes that lock the data. However, using lock avoidance
techniques can reduce the contention. See “Lock avoidance” on page 348 for more
information about lock avoidance.

Lock tuning
This section describes what you can change to affect how a particular application
uses transaction locks, under:
v “Bind options”
v “Isolation overriding with SQL statements” on page 351
v “The statement LOCK TABLE” on page 352

Bind options
These options determine when an application process acquires and releases its
locks and to what extent it isolates its actions from possible effects of other
processes acting concurrently.

These options of bind operations are relevant to transaction locks:


v “The ACQUIRE and RELEASE options”
v “The ISOLATION option” on page 343
v “The CURRENTDATA option” on page 347

The ACQUIRE and RELEASE options


Effects: The ACQUIRE and RELEASE options of bind determine when DB2 locks
an object (table, partition, or table space) your application uses and when it
releases the lock. (The ACQUIRE and RELEASE options do not affect page, row, or
LOB locks.) The options apply to static SQL statements, which are bound before
your program executes. If your program executes dynamic SQL statements, the
objects they lock are locked when first accessed and released at the next commit
point though some locks acquired for dynamic SQL may be held past commit
points. See “The RELEASE option and dynamic statement caching” on page 340.
Option Effect

Chapter 17. Planning for concurrency 339


ACQUIRE(ALLOCATE) Acquires the lock when the object is allocated. This
option is not allowed for BIND or REBIND
PACKAGE.
ACQUIRE(USE) Acquires the lock when the object is first accessed.
RELEASE(DEALLOCATE) Releases the lock when the object is deallocated
(the application ends). The value has no effect on
dynamic SQL statements, which always use
RELEASE(COMMIT), unless you are using dynamic
statement caching. For information about the
RELEASE option with dynamic statement caching,
see “The RELEASE option and dynamic statement
caching”.
RELEASE(COMMIT) Releases the lock at the next commit point, unless
there are held cursors or held locators. If the
application accesses the object again, it must
acquire the lock again.

Example: An application selects employee names and telephone numbers from a


table, according to different criteria. Employees can update their own telephone
numbers. They can perform several searches in succession. The application is
bound with the options ACQUIRE(USE) and RELEASE(DEALLOCATE), for these
reasons:
v The alternative to ACQUIRE(USE), ACQUIRE(ALLOCATE), gets a lock of mode
IX on the table space as soon as the application starts, because that is needed if
an update occurs. But most uses of the application do not update the table and
so need only the less restrictive IS lock. ACQUIRE(USE) gets the IS lock when
the table is first accessed, and DB2 promotes the lock to mode IX if that is
needed later.
v Most uses of this application do not update and do not commit. For those uses,
there is little difference between RELEASE(COMMIT) and
RELEASE(DEALLOCATE). But administrators might update several phone
numbers in one session with the application, and the application commits after
each update. In that case, RELEASE(COMMIT) releases a lock that DB2 must
acquire again immediately. RELEASE(DEALLOCATE) holds the lock until the
application ends, avoiding the processing needed to release and acquire the lock
several times.

Effect of LOCKPART YES: Partition locks follow the same rules as table space
locks, and all partitions are held for the same duration. Thus, if one package is
using RELEASE(COMMIT) and another is using RELEASE(DEALLOCATE), all
partitions use RELEASE(DEALLOCATE).

The RELEASE option and dynamic statement caching: Generally, the


RELEASE option has no effect on dynamic SQL statements with one exception.
When you use the bind options RELEASE(DEALLOCATE) and
KEEPDYNAMIC(YES), and your subsystem is installed with YES for field CACHE
DYNAMIC SQL on panel DSNTIP4, DB2 retains prepared SELECT, INSERT,
UPDATE, and DELETE statements in memory past commit points. For this reason,
DB2 can honor the RELEASE(DEALLOCATE) option for these dynamic statements.
The locks are held until deallocation, or until the commit after the prepared
statement is freed from memory, in the following situations:
v The application issues a PREPARE statement with the same statement identifier.
v The statement is removed from memory because it has not been used.

340 Application Programming and SQL Guide


v An object that the statement is dependent on is dropped or altered, or a privilege
needed by the statement is revoked.
v RUNSTATS is run against an object that the statement is dependent on.

If a lock is to be held past commit and it is an S, SIX, or X lock on a table space or


a table in a segmented table space, DB2 sometimes demotes that lock to an intent
lock (IX or IS) at commit. DB2 demotes a gross lock if it was acquired for one of the
following reasons:
v DB2 acquired the gross lock because of lock escalation.
v The application issued a LOCK TABLE.
v The application issued a mass delete (DELETE FROM ... without a WHERE
clause).

For table spaces defined as LOCKPART YES, lock demotion occurs as with other
table spaces; that is, the lock is demoted at the table space level, not the partition
level.

Recommendation: Choose a combination of values for ACQUIRE and RELEASE


based on the characteristics of the particular application.

Advantages and disadvantages of the combinations


ACQUIRE(ALLOCATE) / RELEASE(DEALLOCATE): In some cases, this
combination can avoid deadlocks by locking all needed resources as soon as the
program starts to run. This combination is most useful for a long-running application
that runs for hours and accesses various tables, because it prevents an untimely
deadlock from wasting that processing.
v All tables or table spaces used in DBRMs bound directly to the plan are locked
when the plan is allocated.
v All tables or table spaces are unlocked only when the plan terminates.
v The locks used are the most restrictive needed to execute all SQL statements in
the plan regardless of whether the statements are actually executed.
v Restrictive states are not checked until the page set is accessed. Locking when
the plan is allocated insures that the job is compatible with other SQL jobs.
Waiting until the first access to check restrictive states provides greater
availability; however, it is possible that an SQL transaction could:
– Hold a lock on a table space or partition that is stopped
– Acquire a lock on a table space or partition that is started for DB2 utility
access only (ACCESS(UT))
– Acquire an exclusive lock (IX, X) on a table space or partition that is started
for read access only (ACCESS(RO)), thus prohibiting access by readers

Disadvantages: This combination reduces concurrency. It can lock resources in


high demand for longer than needed. Also, the option ACQUIRE(ALLOCATE) turns
off selective partition locking; if you are accessing a table space defined with
LOCKPART YES, all partitions are locked.

Restriction: This combination is not allowed for BIND PACKAGE. Use this
combination if processing efficiency is more important than concurrency. It is a good
choice for batch jobs that would release table and table space locks only to
reacquire them almost immediately. It might even improve concurrency, by allowing
batch jobs to finish sooner. Generally, do not use this combination if your
application contains many SQL statements that are often not executed.

Chapter 17. Planning for concurrency 341


ACQUIRE(USE) / RELEASE(DEALLOCATE): This combination results in the
most efficient use of processing time in most cases.
v A table, partition, or table space used by the plan or package is locked only if it is
needed while running.
v All tables or table spaces are unlocked only when the plan terminates.
v The least restrictive lock needed to execute each SQL statement is used, with
the exception that if a more restrictive lock remains from a previous statement,
that lock is used without change.

Disadvantages: This combination can increase the frequency of deadlocks.


Because all locks are acquired in a sequence that is predictable only in an actual
run, more concurrent access delays might occur.

ACQUIRE(USE) / RELEASE(COMMIT): This combination is the default


combination and provides the greatest concurrency, but it requires more processing
time if the application commits frequently.
v A table or table space is locked only when needed. That locking is important if
the process contains many SQL statements that are rarely used or statements
that are intended to access data only in certain circumstances.
v All tables and table spaces are unlocked when:

TSO, Batch, and CAF


An SQL COMMIT or ROLLBACK statement is issued, or your application
process terminates

IMS
A CHKP or SYNC call (for single-mode transactions), a GU call to the I/O
PCB, or a ROLL or ROLB call is completed

CICS
A SYNCPOINT command is issued.

Exception: If the cursor is defined WITH HOLD, table or table space locks
necessary to maintain cursor position are held past the commit point. (See “The
effect of WITH HOLD for a cursor” on page 350 for more information.
v The least restrictive lock needed to execute each SQL statement is used except
when a more restrictive lock remains from a previous statement. In that case,
that lock is used without change.

Disadvantages: This combination can increase the frequency of deadlocks.


Because all locks are acquired in a sequence that is predictable only in an actual
run, more concurrent access delays might occur.

ACQUIRE(ALLOCATE) / RELEASE(COMMIT): This combination is not allowed; it


results in an error message from BIND.

342 Application Programming and SQL Guide


The ISOLATION option
Effects: Specifies the degree to which operations are isolated from the possible
| effects of other operations acting concurrently. Based on this information, DB2
| releases S and U locks on rows or pages as soon as possible.

Recommendations: Choose a value of ISOLATION based on the characteristics


of the particular application.

Advantages and disadvantages of the isolation values


The various isolation levels offer less or more concurrency at the cost of more or
less protection from other application processes. The values you choose should be
based primarily on the needs of the application. This section presents the isolation
levels in order from the one offering the least concurrency (RR) to that offering the
most (UR).
ISOLATION (RR)
Allows the application to read the same pages or rows more than once
without allowing any UPDATE, INSERT, or DELETE by another process. All
accessed rows or pages are locked, even if they do not satisfy the
predicate.
Figure 116 shows that all locks are held until the application commits. In the
following example, the rows held by locks L2 and L4 satisfy the predicate.

Application

Request row Request next row

Time line

Lock Lock Lock Lock Lock


L L1 L2 L3 L4
DB2

Figure 116. How an application using RR isolation acquires locks. All locks are held until the
application commits.

Applications that use repeatable read can leave rows or pages locked for
longer periods, especially in a distributed environment, and they can claim
more logical partitions than similar applications using cursor stability.

They are also subject to being drained more often by utility operations.

Because so many locks can be taken, lock escalation might take place.
Frequent commits release the locks and can help avoid lock escalation.

With repeatable read, lock promotion occurs for table space scan to prevent
the insertion of rows that might qualify for the predicate. (If access is via
index, DB2 locks the key range. If access is via table space scans, DB2
locks the table, partition, or table space.)
ISOLATION (RS)
Allows the application to read the same pages or rows more than once
without allowing qualifying rows to be updated or deleted by another

Chapter 17. Planning for concurrency 343


process. It offers possibly greater concurrency than repeatable read,
because although other applications cannot change rows that are returned
to the original application, they can insert new rows or update rows that did
not satisfy the original application’s search condition. Only those rows or
pages that satisfy the stage 1 predicate (and all rows or pages evaluated
during stage 2 processing) are locked until the application commits.
Figure 117 illustrates this. In the example, the rows held by locks L2 and L4
satisfy the predicate.

Application

Request row Request next row

Time line

Lock Unlock Lock Unlock Lock Lock Unlock Lock


L L L1 L1 L2 L3 L3 L4
DB2

Figure 117. How an application using RS isolation acquires locks when no lock avoidance
techniques are used. Locks L2 and L4 are held until the application commits. The other locks
aren’t held.

Applications using read stability can leave rows or pages locked for long
periods, especially in a distributed environment.

If you do use read stability, plan for frequent commit points.


ISOLATION (CS)
Allows maximum concurrency with data integrity. However, after the process
leaves a row or page, another process can change the data. With
CURRENTDATA(NO), the process doesn’t have to leave a row or page to
allow another process to change the data. If the first process returns to
read the same row or page, the data is not necessarily the same. Consider
these consequences of that possibility:
v For table spaces created with LOCKSIZE ROW, PAGE, or ANY, a
change can occur even while executing a single SQL statement, if the
statement reads the same row more than once. In the following example:
SELECT * FROM T1
WHERE COL1 = (SELECT MAX(COL1) FROM T1);

data read by the inner SELECT can be changed by another transaction


before it is read by the outer SELECT. Therefore, the information
returned by this query might be from a row that is no longer the one with
the maximum value for COL1.
v In another case, if your process reads a row and returns later to update
it, that row might no longer exist or might not exist in the state that it did
when your application process originally read it. That is, another
application might have deleted or updated the row. If your application is
doing non-cursor operations on a row under the cursor, make sure
the application can tolerate “not found” conditions.
Similarly, assume another application updates a row after you read it. If
your process returns later to update it based on the value you originally
read, you are, in effect, erasing the update made by the other process. If

344 Application Programming and SQL Guide


you use isolation (CS) with update, your process might need to lock
out concurrent updates. One method is to declare a cursor with the
clause FOR UPDATE OF.

General-use Programming Interface

| For packages and plans that contain updatable scrollable cursors,


| ISOLATION(CS) lets DB2 use optimistic concurrency control. DB2 can use
| optimistic concurrency control to shorten the amount of time that locks are
| held in the following situations:
| v Between consecutive fetch operations
| v Between fetch operations and subsequent positioned update or delete
| operations

| Figure 118 and Figure 119 show processing of positioned update and delete
| operations without optimistic concurrency control and with optimistic
| concurrency control.
|

Figure 118. Positioned updates and deletes without optimistic concurrency control

Figure 119. Positioned updates and deletes with optimistic concurrency control

| Optimistic concurrency control consists of the following steps:


| 1. When the application requests a fetch operation to position the cursor
| on a row, DB2 locks that row, executes the FETCH, and releases the
| lock.
| 2. When the application requests a positioned update or delete operation
| on the row, DB2 performs the following steps:
| a. Locks the row.

Chapter 17. Planning for concurrency 345


| b. Reevaluates the predicate to ensure that the row still qualifies for
| the result table.
| c. For columns that are in the result table, compares current values in
| the row to the values of the row when step 1 was executed.
| Performs the positioned update or delete operation only if the values
| match.

End of General-use Programming Interface

ISOLATION (UR)
Allows the application to read while acquiring few locks, at the risk of
reading uncommitted data. UR isolation applies only to read-only
operations: SELECT, SELECT INTO, or FETCH from a read-only result
table.
There is an element of uncertainty about reading uncommitted data.
Example: An application tracks the movement of work from station to
station along an assembly line. As items move from one station to another,
the application subtracts from the count of items at the first station and
adds to the count of items at the second. Assume you want to query the
count of items at all the stations, while the application is running
concurrently.
What can happen if your query reads data that the application has changed
but has not committed?
If the application subtracts an amount from one record before adding it
to another, the query could miss the amount entirely.
If the application adds first and then subtracts, the query could add the
amount twice.

If those situations can occur and are unacceptable, do not use UR isolation.

Restrictions: You cannot use UR isolation for the types of statement listed
below. If you bind with ISOLATION(UR), and the statement does not specify
WITH RR or WITH RS, then DB2 uses CS isolation for:
v INSERT, UPDATE, and DELETE
v Any cursor defined with FOR UPDATE OF

When can you use uncommitted read (UR)? You can probably use UR
isolation in cases like the following ones:
v When errors cannot occur.
Example: A reference table, like a table of descriptions of parts by part
number. It is rarely updated, and reading an uncommitted update is
probably no more damaging than reading the table 5 seconds earlier. Go
ahead and read it with ISOLATION(UR).
Example: The employee table of Spiffy Computer, our hypothetical user.
For security reasons, updates can be made to the table only by members
of a single department. And that department is also the only one that can
query the entire table. It is easy to restrict queries to times when no
updates are being made and then run with UR isolation.
v When an error is acceptable.
Example: Spiffy wants to do some statistical analysis on employee data.
A typical question is, “What is the average salary by sex within education

346 Application Programming and SQL Guide


level?” Because reading an occasional uncommitted record cannot affect
the averages much, UR isolation can be used.
v When the data already contains inconsistent information.
Example: Spiffy gets sales leads from various sources. The data is often
inconsistent or wrong, and end users of the data are accustomed to
dealing with that. Inconsistent access to a table of data on sales leads
does not add to the problem.

Do NOT use uncommitted read (UR):


When the computations must balance
When the answer must be accurate
When you are not sure it can do no damage

Restrictions on concurrent access: An application using UR isolation cannot run


concurrently with a utility that drains all claim classes. Also, the application must
acquire the following locks:
v A special mass delete lock acquired in S mode on the target table or table space.
A “mass delete” is a DELETE statement without a WHERE clause; that operation
must acquire the lock in X mode and thus cannot run concurrently.
v An IX lock on any table space used in the work file database. That lock prevents
dropping the table space while the application is running.
v If LOB values are read, LOB locks and a lock on the LOB table space. If the
LOB lock is not available because it is held by another application in an
incompatible lock state, the UR reader skips the LOB and moves on to the next
LOB that satisfies the query.

The CURRENTDATA option


The CURRENTDATA option has different effects, depending on if access is local or
remote:
v For local access, the option tells whether the data upon which your cursor is
positioned must remain identical to (or “current with”) the data in the local base
table. For cursors positioned on data in a work file, the CURRENTDATA option
has no effect. This effect only applies to read-only or ambiguous cursors in plans
or packages bound with CS isolation.
A cursor is “ambiguous” if DB2 cannot tell whether it is used for update or
read-only purposes. If the cursor appears to be used only for read-only, but
dynamic SQL could modify data through the cursor, then the cursor is
ambiguous. If you use CURRENTDATA to indicate an ambiguous cursor is
read-only when it is actually targeted by dynamic SQL for modification, you’ll get
an error. See “Problems with ambiguous cursors” on page 349 for more
information about ambiguous cursors.
v For a request to a remote system, CURRENTDATA has an effect for ambiguous
cursors using isolation levels RR, RS, or CS. For ambiguous cursors, it turns
block fetching on or off. (Read-only cursors and UR isolation always use block
fetch.) Turning on block fetch offers best performance, but it means the cursor is
not current with the base table at the remote site.

Local access: Locally, CURRENTDATA(YES) means that the data upon which
the cursor is positioned cannot change while the cursor is positioned on it. If the
cursor is positioned on data in a local base table or index, then the data returned
with the cursor is current with the contents of that table or index. If the cursor is
positioned on data in a work file, the data returned with the cursor is current only
with the contents of the work file; it is not necessarily current with the contents of
the underlying table or index.

Chapter 17. Planning for concurrency 347


Figure 120 shows locking with CURRENTDATA(YES).

Application
Request Request next
row or page row or page

Time line

Lock Unlock Lock Unlock Lock Unlock Lock Unlock Lock


L L L1 L1 L2 L2 L3 L3 L4
DB2

Figure 120. How an application using isolation CS with CURRENTDATA(YES) acquires locks.
This figure shows access to the base table. The L2 and L4 locks are released after DB2
moves to the next row or page. When the application commits, the last lock is released.

As with work files, if a cursor uses query parallelism, data is not necessarily current
with the contents of the table or index, regardless of whether a work file is used.
Therefore, for work file access or for parallelism on read-only queries, the
CURRENTDATA option has no effect.

If you are using parallelism but want to maintain currency with the data, you have
the following options:
v Disable parallelism (Use SET DEGREE = ’1’ or bind with DEGREE(1)).
v Use isolation RR or RS (parallelism can still be used).
v Use the LOCK TABLE statement (parallelism can still be used).

For local access, CURRENTDATA(NO) is similar to CURRENTDATA(YES) except


for the case where a cursor is accessing a base table rather than a result table in a
work file. In those cases, although CURRENTDATA(YES) can guarantee that the
cursor and the base table are current, CURRENTDATA(NO) makes no such
guarantee.

Remote access: For access to a remote table or index, CURRENTDATA(YES)


turns off block fetching for ambiguous cursors. The data returned with the cursor is
current with the contents of the remote table or index for ambiguous cursors. See
“Use block fetch” on page 385 for more information about the effect of
CURRENTDATA on block fetch.

Lock avoidance: With CURRENTDATA(NO), you have much greater opportunity


for avoiding locks. DB2 can test to see if a row or page has committed data on it. If
it has, DB2 does not have to obtain a lock on the data at all. Unlocked data is
returned to the application, and the data can be changed while the cursor is
positioned on the row. (For SELECT statements in which no cursor is used, such as
those that return a single row, a lock is not held on the row unless you specify
WITH RS or WITH RR on the statement.)

To take the best advantage of this method of avoiding locks, make sure all
applications that are accessing data concurrently issue COMMITs frequently.

Figure 121 on page 349 shows how DB2 can avoid taking locks and Table 41 on
page 349 summarizes the factors that influence lock avoidance.

348 Application Programming and SQL Guide


Application
Request Request next
row or page row or page

Time line

Test and avoid locks Test and avoid locks

DB2

Figure 121. Best case of avoiding locks using CS isolation with CURRENTDATA(NO). This
figure shows access to the base table. If DB2 must take a lock, then locks are released when
DB2 moves to the next row or page, or when the application commits (the same as
CURRENTDATA(YES)).

Table 41. Lock avoidance factors. “Returned data” means data that satisfies the predicate.
“Rejected data” is that which does not satisfy the predicate.
Avoid Avoid
locks on locks on
Isolation CURRENTDATA Cursor type
returned rejected
data? data?
UR N/A Read-only N/A N/A
Read-only
YES Updatable No
Ambiguous
CS Yes
Read-only Yes
NO Updatable No
Ambiguous Yes
Read-only
RS N/A Updatable No Yes
Ambiguous
Read-only
RR N/A Updatable No No
Ambiguous

Problems with ambiguous cursors: As shown in Table 41, ambiguous cursors


can sometimes prevent DB2 from using lock avoidance techniques. However,
misuse of an ambiguous cursor can cause your program to receive a -510
SQLCODE:
v The plan or package is bound with CURRENTDATA(NO)
v An OPEN CURSOR statement is performed before a dynamic DELETE WHERE
CURRENT OF statement against that cursor is prepared
v One of the following conditions is true for the open cursor:
– Lock avoidance is successfully used on that statement.
– Query parallelism is used.
– The cursor is distributed, and block fetching is used.

Chapter 17. Planning for concurrency 349


In all cases, it is a good programming technique to eliminate the ambiguity by
declaring the cursor with one of the clauses FOR FETCH ONLY or FOR UPDATE
OF.

When plan and package options differ


A plan bound with one set of options can include packages in its package list that
were bound with different sets of options. In general, statements in a DBRM bound
as a package use the options that the package was bound with, and statements in
DBRMs bound to a plan use the options that the plan was bound with.

For example, the plan value for CURRENTDATA has no effect on the packages
executing under that plan. If you do not specify a CURRENTDATA option explicitly
when you bind a package, the default is CURRENTDATA(YES).

The rules are slightly different for the bind options RELEASE and ISOLATION. The
values of those two options are set when the lock on the resource is acquired and
usually stay in effect until the lock is released. But a conflict can occur if a
statement that is bound with one pair of values requests a lock on a resource that
is already locked by a statement that is bound with a different pair of values. DB2
resolves the conflict by resetting each option with the available value that causes
the lock to be held for the greatest duration.

If the conflict is between RELEASE(COMMIT) and RELEASE(DEALLOCATE), then


the value used is RELEASE(DEALLOCATE).

Table 42 shows how conflicts between isolation levels are resolved. The first column
is the existing isolation level, and the remaining columns show what happens when
another isolation level is requested by a new application process.
Table 42. Resolving isolation conflicts
UR CS RS RR
UR n/a CS RS RR
CS CS n/a RS RR
RS RS RS n/a RR
RR RR RR RR n/a

The effect of WITH HOLD for a cursor


For a cursor defined as WITH HOLD, the cursor position is maintained past a
commit point. Hence, locks and claims needed to maintain that position are not
released immediately, even if they were acquired with ISOLATION(CS) or
RELEASE(COMMIT).

For locks and claims needed for cursor position, the rules described above differ as
follows:

Page and row locks: If your installation specifies NO on the RELEASE LOCKS
field of installation panel DSNTIP4, as described in Part 5 (Volume 2) of DB2
Administration Guide, a page or row lock is held past the commit point. This page
or row lock is not necessary for cursor position, but the NO option is provided for
compatibility that might rely on this lock. However, an X or U lock is demoted to an
S lock at that time. (Because changes have been committed, exclusive control is no
longer needed.) After the commit point, the lock is released at the next commit
point, provided that no cursor is still positioned on that page or row.

A YES for RELEASE LOCKS means that no data page or row locks are held past
commit.

350 Application Programming and SQL Guide


Table, table space, and DBD locks: All necessary locks are held past the commit
point. After that, they are released according to the RELEASE option under which
they were acquired: for COMMIT, at the next commit point after the cursor is closed;
for DEALLOCATE, when the application is deallocated.

Claims: All claims, for any claim class, are held past the commit point. They are
released at the next commit point after all held cursors have moved off the object or
have been closed.

Isolation overriding with SQL statements


Function of the WITH clause: You can override the isolation level with which a
plan or package is bound by the WITH clause on certain SQL statements.

Example: This statement:


SELECT MAX(BONUS), MIN(BONUS), AVG(BONUS)
INTO :MAX, :MIN, :AVG
FROM DSN8710.EMP
WITH UR;

finds the maximum, minimum, and average bonus in the sample employee table.
The statement is executed with uncommitted read isolation, regardless of the value
of ISOLATION with which the plan or package containing the statement is bound.

Rules for the WITH clause: The WITH clause:


v Can be used on these statements:
– Select-statement
– SELECT INTO
– Searched delete
– INSERT from fullselect
– Searched update
v Cannot be used on subqueries.
v Can specify the isolation levels that specifically apply to its statement. (For
example, because WITH UR applies only to read-only operations, you cannot
use it on an INSERT statement.)
v Overrides the isolation level for the plan or package only for the statement in
which it appears.

Using KEEP UPDATE LOCKS on the WITH clause: You can use the clause
KEEP UPDATE LOCKS clause when you specify a SELECT with FOR UPDATE
OF. This option is only valid when you use WITH RR or WITH RS. By using this
clause, you tell DB2 to acquire an X lock instead of an U or S lock on all the
qualified pages or rows.

Here is an example:
SELECT ...
FOR UPDATE OF WITH RS KEEP UPDATE LOCKS;

With read stability (RS) isolation, a row or page rejected during stage 2 processing
still has the X lock held on it, even though it is not returned to the application.

With repeatable read (RR) isolation, DB2 acquires the X locks on all pages or rows
that fall within the range of the selection expression.

Chapter 17. Planning for concurrency 351


All X locks are held until the application commits. Although this option can reduce
concurrency, it can prevent some types of deadlocks and can better serialize
access to data.

The statement LOCK TABLE


For information about using LOCK TABLE on an auxiliary table, see “The LOCK
TABLE statement” on page 358.

The purpose of LOCK TABLE


Use the LOCK TABLE statement to override DB2’s rules for choosing initial lock
attributes. Two examples are:
LOCK TABLE table-name IN SHARE MODE;
LOCK TABLE table-name PART n IN EXCLUSIVE MODE;

Executing the statement requests a lock immediately, unless a suitable lock exists
already, as described below. The bind option RELEASE determines when locks
acquired by LOCK TABLE or LOCK TABLE with the PART option are released.

You can use LOCK TABLE on any table, including auxiliary tables of LOB table
spaces. See “The LOCK TABLE statement” on page 358 for information about
locking auxiliary tables.

LOCK TABLE has no effect on locks acquired at a remote server.

The effect of LOCK TABLE


Table 43 shows the modes of locks acquired in segmented and nonsegmented table
spaces for the SHARE and EXCLUSIVE modes of LOCK TABLE. Auxiliary tables of
LOB table spaces are considered nonsegmented table spaces and have the same
locking behavior.
Table 43. Modes of locks acquired by LOCK TABLE. LOCK TABLE on partitions behave the
same as nonsegmented table spaces.
Segmented Table Space
Nonsegmented
LOCK TABLE IN Table Space Table Table Space
EXCLUSIVE MODE X X IX
SHARE MODE S or SIX S or SIX IS
Note: The SIX lock is acquired if the process already holds an IX lock. SHARE MODE has
no effect if the process already has a lock of mode SIX, U, or X.

Recommendations for using LOCK TABLE


Use LOCK TABLE to prevent other application processes from changing any row in
a table or partition that your process is accessing. For example, suppose that you
access several tables. You can tolerate concurrent updates on all the tables except
one; for that one, you need RR or RS isolation. There are several ways to handle
the situation:
v Bind the application plan with RR or RS isolation. But that affects all the tables
you access and might reduce concurrency.
v Design the application to use packages and access the exceptional table in only
a few packages. Bind those packages with RR or RS isolation and the plan with
CS isolation. Only the tables accessed within those packages are accessed with
RR or RS isolation.

352 Application Programming and SQL Guide


v Add the clause WITH RR or WITH RS to statements that must be executed with
RR or RS isolation. Statements that do not use WITH are executed as specified
by the bind option ISOLATION.
v Bind the application plan with CS isolation and execute LOCK TABLE for the
exceptional table. (If there are other tables in the same table space, see the
caution that follows.) LOCK TABLE locks out changes by any other process,
giving the exceptional table a degree of isolation even more thorough than
repeatable read. All tables in other table spaces are shared for concurrent
update.

Caution when using LOCK TABLE with simple table spaces: The statement
locks all tables in a simple table space, even though you name only one table. No
other process can update the table space for the duration of the lock. If the lock is
in exclusive mode, no other process can read the table space, unless that process
is running with UR isolation.

Additional examples of LOCK TABLE: You might want to lock a table or partition
that is normally shared for any of the following reasons:
Taking a“snapshot”
If you want to access an entire table throughout a unit of work as it
was at a particular moment, you must lock out concurrent changes.
If other processes can access the table, use LOCK TABLE IN
SHARE MODE. (RR isolation is not enough; it locks out changes
only from rows or pages you have already accessed.)
Avoiding overhead
If you want to update a large part of a table, it can be more efficient
to prevent concurrent access than to lock each page as it is
updated and unlock it when it is committed. Use LOCK TABLE IN
EXCLUSIVE MODE.
Preventing timeouts
Your application has a high priority and must not risk timeouts from
contention with other application processes. Depending on whether
your application updates or not, use either LOCK IN EXCLUSIVE
MODE or LOCK TABLE IN SHARE MODE.

Access paths
The access path used can affect the mode, size, and even the object of a lock. For
example, an UPDATE statement using a table space scan might need an X lock on
the entire table space. If rows to be updated are located through an index, the
same statement might need only an IX lock on the table space and X locks on
individual pages or rows.

If you use the EXPLAIN statement to investigate the access path chosen for an
SQL statement, then check the lock mode in column TSLOCKMODE of the
resulting PLAN_TABLE. If the table resides in a nonsegmented table space, or is
defined with LOCKSIZE TABLESPACE, the mode shown is that of the table space
lock. Otherwise, the mode is that of the table lock.

Chapter 17. Planning for concurrency 353


The important points about DB2 locks:
v You usually do not have to lock data explicitly in your program.
v DB2 ensures that your program does not retrieve uncommitted data unless you
specifically allow that.
v Any page or row where your program updates, inserts, or deletes stays locked at
least until the end of a unit of work, regardless of the isolation level. No other
process can access the object in any way until then, unless you specifically allow
that access to that process.
v Commit often for concurrency. Determine points in your program where changed
data is consistent. At those points, issue:

TSO, Batch, and CAF


An SQL COMMIT statement

IMS
A CHKP or SYNC call, or (for single-mode transactions) a GU call to the I/O
PCB

CICS
A SYNCPOINT command.

v Bind with ACQUIRE(USE) to improve concurrency.


v Set ISOLATION (usually RR, RS, or CS) when you bind the plan or package.
– With RR (repeatable read), all accessed pages or rows are locked until the
next commit point. (See “The effect of WITH HOLD for a cursor” on page 350
for information about cursor position locks for cursors defined WITH HOLD.)
– With RS (read stability), all qualifying pages or rows are locked until the next
commit point. (See “The effect of WITH HOLD for a cursor” on page 350 for
information about cursor position locks for cursors defined WITH HOLD.)
– With CS (cursor stability), only the pages or rows currently accessed can be
locked, and those locks might be avoided. (You can access one page or row
for each open cursor.)
v You can also set isolation for specific SQL statements, using WITH.
v A deadlock can occur if two processes each hold a resource that the other
needs. One process is chosen as “victim”, its unit of work is rolled back, and an
SQL error code is issued.

Figure 122. Summary of DB2 locks (Part 1 of 2)

354 Application Programming and SQL Guide


v You can lock an entire nonsegmented table space, or an entire table in a
segmented table space, by the statement LOCK TABLE:
– To let other users retrieve, but not update, delete, or insert, issue:
LOCK TABLE table-name IN SHARE MODE
– To prevent other users from accessing rows in any way, except by using UR
isolation, issue:
LOCK TABLE table-name IN EXCLUSIVE MODE

Figure 122. Summary of DB2 locks (Part 2 of 2)

LOB locks
The locking activity for LOBs is described separately from transaction locks
because the purpose of LOB locks is different than that of regular transaction locks.

Terminology: A lock that is taken on a LOB value in a LOB table space is called a
LOB lock.

In this section: The following topics are described:


v “Relationship between transaction locks and LOB locks”
v “Hierarchy of LOB locks” on page 356
v “LOB and LOB table space lock modes” on page 357
v “Duration of locks” on page 357
v “Instances when locks on LOB table space are not taken” on page 358
v “The LOCK TABLE statement” on page 358

Relationship between transaction locks and LOB locks


As described in “Introduction to LOBs” on page 229, LOB column values are stored
in a different table space, a LOB table space, from the values in the base table. An
application that reads or updates a row in a table that contains LOB columns
obtains its normal transaction locks on the base table. The locks on the base table
also control concurrency for the LOB table space. When locks are not acquired on
the base table, such as for ISO(UR), DB2 maintains data consistency by using
locks on the LOB table space. Even when locks are acquired on the base table,
DB2 still obtains locks on the LOB table space.

DB2 also obtains locks on the LOB table space and the LOB values stored in that
LOB table space, but those locks have the following primary purposes:
v To determine whether space from a deleted LOB can be reused by an inserted or
updated LOB
Storage for a deleted LOB is not reused until no more readers (including held
locators) are on the LOB and the delete operation has been committed.
v To prevent deallocating space for a LOB that is currently being read
A LOB can be deleted from one application’s point-of-view while a reader from
another application is reading the LOB. The reader continues reading the LOB
because all readers, including those readers that are using uncommitted read
isolation, acquire S-locks on LOBs to prevent the storage for the LOB they are
reading from being deallocated. That lock is held until commit. A held LOB
| locator or a held cursor cause the LOB lock and LOB table space lock to be held
past commit.

Chapter 17. Planning for concurrency 355


In summary, the main purpose of LOB locks is for managing the space used by
LOBs and to ensure that LOB readers do not read partially updated LOBs.
Applications need to free held locators so that the space can be reused.

Table 44 shows the relationship between the action that is occurring on the LOB
value and the associated LOB table space and LOB locks that are acquired.
Table 44. Locks that are acquired for operations on LOBs. This table does not account for
gross locks that can be taken because of LOCKSIZE TABLESPACE, the LOCK TABLE
statement, or lock escalation.
Action on LOB value LOB table space
lock LOB lock Comment
Read (including UR) IS S Prevents storage from being
reused while the LOB is
being read or while locators
are referencing the LOB
Insert IX X Prevents other processes
from seeing a partial LOB
Delete IS S To hold space in case the
delete is rolled back. (The X
is on the base table row or
page.) Storage is not
reusable until the delete is
committed and no other
readers of the LOB exist.
Update IS->IX Two LOB Operation is a delete
locks: an followed by an insert.
S-lock for the
delete and an
X-lock for the
insert.
Update the LOB to null IS S No insert, just a delete.
or zero-length
Update a null or IX X No delete, just an insert.
zero-length LOB to a
value

ISOLATION(UR) or ISOLATION(CS): When an application is reading rows using


uncommitted read or lock avoidance, no page or row locks are taken on the base
table. Therefore, these readers must take an S LOB lock to ensure that they are not
reading a partial LOB or a LOB value that is inconsistent with the base row.

Hierarchy of LOB locks


Just as page locks (or row locks) and table space locks have a hierarchical
relationship, LOB locks and locks on LOB table spaces have a hierarchical
relationship. (See Figure 115 on page 334 for a picture of the hierarchical
relationship.) If the LOB table space is locked with a gross lock, then LOB locks are
not acquired. In a data sharing environment, the lock on the LOB table space is
used to determine whether the lock on the LOB must be propagated beyond the
local IRLM.

356 Application Programming and SQL Guide


LOB and LOB table space lock modes
Modes of LOB locks
The following LOB lock modes are possible:
S (SHARE) The lock owner and any concurrent processes can read, update, or
delete the locked LOB. Concurrent processes can acquire an S lock
on the LOB. The purpose of the S lock is to reserve the space used
by the LOB.
X (EXCLUSIVE)
The lock owner can read or change the locked LOB. Concurrent
processes cannot access the LOB.

Modes of LOB table space locks


The following locks modes are possible on the LOB table space:
IS (INTENT SHARE)
The lock owner can update LOBs to null or zero-length, or read or
delete LOBs in the LOB table space. Concurrent processes can
both read and change LOBs in the same table space. The lock
owner acquires a LOB lock on any data that it reads or deletes.
IX (INTENT EXCLUSIVE)
The lock owner and concurrent processes can read and change
data in the LOB table space. The lock owner acquires a LOB lock
on any data it accesses.
S (SHARE) The lock owner and any concurrent processes can read and delete
LOBs in the LOB table space. The lock owner does not need LOB
locks.
SIX (SHARE with INTENT EXCLUSIVE)
The lock owner can read and change data in the LOB table space.
If the lock owner is inserting (INSERT or UPDATE), the lock owner
obtains a LOB lock. Concurrent processes can read or delete data
in the LOB table space (or update to a null or zero-length LOB).
X (EXCLUSIVE)
The lock owner can read or change LOBs in the LOB table space.
| The lock owner does not need LOB locks. Concurrent processes
| cannot access the data.

Duration of locks
Duration of locks on LOB table spaces
Locks on LOB table spaces are acquired when they are needed; that is, the
ACQUIRE option of BIND has no effect on when the table space lock on the LOB
table space is taken. The table space lock is released according to the value
specified on the RELEASE option of BIND (except when a cursor is defined WITH
HOLD or if a held LOB locator exists).

Duration of LOB locks


Locks on LOBs are taken when they are needed and are usually released at
commit. However, if that LOB value is assigned to a LOB locator, the S lock
remains until the application commits.

If the application uses HOLD LOCATOR, the LOB lock is not freed until the first
commit operation after a FREE LOCATOR statement is issued, or until the thread is
deallocated.

Chapter 17. Planning for concurrency 357


A note about held cursors: If a cursor is defined WITH HOLD, LOB locks are held
through commit operations.

| A note about INSERT with fullselect: Because LOB locks are held until commit
and because locks are put on each LOB column in both a source table and a target
table, it is possible that a statement such as an INSERT with a fullselect that
involves LOB columns can accumulate many more locks than a similar statement
that does not involve LOB columns. To prevent system problems caused by too
many locks, you can:
v Ensure that you have lock escalation enabled for the LOB table spaces that are
involved in the INSERT. In other words, make sure that LOCKMAX is non-zero
for those LOB table spaces.
v Alter the LOB table space to change the LOCKSIZE to TABLESPACE before
executing the INSERT with fullselect.
v Increase the LOCKMAX value on the table spaces involved and ensure that the
user lock limit is sufficient.
v Use LOCK TABLE statements to lock the LOB table spaces. (Locking the
auxiliary table that is contained in the LOB table space locks the LOB table
space.)

Instances when locks on LOB table space are not taken


A lock might not be acquired on a LOB table space at all. For example, if a row is
deleted from a table and the value of the LOB column is null, the LOB table space
associated with that LOB column is not locked. DB2 does not access the LOB table
space if the application:
v Selects a LOB that is null or zero length
v Deletes a row where the LOB is null or zero length
v Inserts a null or zero length LOB
v Updates a null or zero-length LOB to null or zero-length

The LOCK TABLE statement


“The statement LOCK TABLE” on page 352 describes how and why you might use
a LOCK TABLE statement on a table. The reasons for using LOCK TABLE on an
auxiliary table are somewhat different than that for regular tables.
v You can use LOCK TABLE to control the number of locks acquired on the
auxiliary table.
v You can use LOCK TABLE IN SHARE MODE to prevent other applications from
inserting LOBs.
With auxiliary tables, LOCK TABLE IN SHARE MODE does not prevent any
changes to the auxiliary table. The statement does prevent LOBs from being
inserted into the auxiliary table, but it does not prevent deletes. Updates are
generally restricted also, except where the LOB is updated to a null value or a
zero-length string.
v You can use LOCK TABLE IN EXCLUSIVE MODE to prevent other applications
from accessing LOBs.
With auxiliary tables, LOCK TABLE IN EXCLUSIVE MODE also prevents access
from uncommitted readers.
v Either statement eliminates the need for lower-level LOB locks.

358 Application Programming and SQL Guide


Chapter 18. Planning for recovery
During recovery, when a DB2 database is restoring to its most recent consistent
state, you must back out any uncommitted changes to data that occurred before the
program abend or system failure. You must do this without interfering with other
system activities.

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 runtime environment
intercept the abend. For example, if your program uses Language Environment, and
you want DB2 to roll back work automatically when an abend occurs in the
program, specify the runtime options ABTERMENC(ABEND) and TRAP(ON).

A unit of work is a logically distinct procedure containing 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 DSN8710.EMP exchange
offices. You need to exchange their office phone numbers in the PHONENO
column. You would 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.

When a unit of work completes, all locks implicitly acquired by that unit of work after
it begins are released, allowing a new unit of work to begin.

The amount of processing time used by a unit of work in your program determines
the length of time 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 must be as short as possible to minimize the interference between the
programs. The remainder of this chapter describes the way a unit of work functions
in various environments. For more information on unit of work, see Chapter 1 of
DB2 SQL Reference or Part 4 (Volume 1) of DB2 Administration Guide.

Unit of work in TSO (batch and online)


A unit of work starts when the first DB2 object updates occur.

A unit of work ends when one of the following conditions occur:


v The program issues a subsequent COMMIT statement. At this point in the
processing, your program is confident the data is consistent; all data changes
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, does not want to make the data changes permanent.
v The program terminates and returns to the DSN command processor, which
returns to the TSO Terminal Monitor Program (TMP).

A commit point occurs when you issue a COMMIT statement or your program
terminates normally. You should issue a COMMIT statement only when you are sure

© Copyright IBM Corp. 1983, 2001 359


the data is in a consistent state. For example, a bank transaction might transfer
funds from account A to account B. The transaction first subtracts the amount of the
transfer from account A, and then adds the amount to account B. Both events,
taken together, are a unit of work. When both events complete (and not before), the
data in the two accounts is consistent. The program can then issue a COMMIT
statement. A ROLLBACK statement causes any data changes, made since the last
commit point, to be backed out.

Before you can connect to another DBMS you must issue a COMMIT statement. If
the system fails at this point, DB2 cannot know that 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.

If your program abends or the system fails, DB2 backs out uncommitted data
changes. Changed data returns to its original condition without interfering with other
system activities.

Unit of work in CICS


In CICS, 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. Generally, a unit of work is
a sequence of actions that must complete before any of the individual actions in the
sequence can complete. For example, the actions of decrementing an inventory file
and incrementing a reorder file by the same quantity can constitute a unit of work:
both steps must complete before either step is complete. (If one action occurs and
not the other, the database loses its integrity, or consistency.)

A unit of work is marked as complete by a commit or synchronization (sync) point,


defined as follows:
v Implicitly at the end of a transaction, signalled 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 can
occur when the batch DL/I program is sharing a database with CICS applications
through the database sharing facility.

Consider the inventory example, in which the quantity of items sold is subtracted
from the inventory file and then added to the reorder file. When both transactions
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 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 used in programs, so
that DB2 and non-DB2 data are consistent.

360 Application Programming and SQL Guide


If the system fails, DB2 backs out uncommitted changes to data. Changed data
returns to its original condition without interfering with other system activities.
Sometimes, DB2 data does not return to a consistent state immediately. DB2 does
not process indoubt data (data that is neither uncommitted nor committed) until the
CICS attachment facility is also restarted. To ensure that DB2 and CICS are
synchronized, restart both DB2 and the CICS attachment facility.

Unit of work in IMS (online)


In IMS, a unit of work starts:
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:


v The program issues a subsequent CHKP or SYNC call, or (for single-mode
transactions) issues a GU call to the I/O PCB. At this point in the processing, the
data is consistent. All data changes 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.

A commit point can occur in a program as the result of any one of the following four
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. The SYNC call is a Fast Path system service
call to request commit point processing. You can use a SYNC call only in a
nonmessage-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. IMS considers a new message the
start of a new unit of work in the program. Unless you define the transaction as
single- or multiple-mode on the TRANSACT statement of the APPLCTN macro
for the program, retrieving a new message does not signal a commit point. For
more information about the APPLCTN macro, see the IMS Install Volume 2:
System Definition and Tailoring.
– If you specify single-mode, a commit point in DB2 occurs each time the
program issues a call to retrieve a new message. Specifying single-mode can
simplify recovery; you can restart the program from the most recent call for a
new message if the program abends. When IMS restarts the program, the
program starts by processing the next message.
– If you specify multiple-mode, a commit point occurs when the program issues
a checkpoint call or when it terminates normally. Those are the only times
during the program that IMS sends the program’s output messages to their
destinations. Because there are fewer commit points to process 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

Chapter 18. Planning for recovery 361


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 that IMS does
not. 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.

At the time of a commit point:


v IMS and DB2 can release locks that the program has held on data since the last
commit point. That 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. Your program
must issue CLOSE CURSOR statements before a checkpoint call or a GU to the
message queue, not after.
v IMS and DB2 make the program’s changes to the data base permanent.

If the program abends before reaching the commit point:


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).

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, people at terminals, and other application programs do not
receive inaccurate information from the terminating application program.

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

If the system fails, DB2 backs out uncommitted changes to data. Changed data
returns to its original state without interfering with other system activities.
Sometimes DB2 data does not return to a consistent state immediately. DB2 does
not process data in an indoubt state until you restart IMS. To ensure that DB2 and
IMS are synchronized, you must restart both DB2 and IMS.

Planning ahead for program recovery: Checkpoint and restart


Both IMS and DB2 handle recovery in an IMS application program that accesses
DB2 data. IMS coordinates the process and DB2 participates by handling recovery
for DB2 data.

There are two calls available to IMS programs to simplify program recovery: the
symbolic checkpoint call and the restart call.

What symbolic checkpoint does


Symbolic checkpoint calls indicate to IMS that the program has reached a sync
point. Such calls also establish places in the program from which you can restart
the program.

A CHKP call causes IMS to:

362 Application Programming and SQL Guide


v Inform DB2 that the changes 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 containing the checkpoint identification 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.
v Sign on to DB2 again, which resets special registers as follows:
– CURRENT PACKAGESET to blanks
– CURRENT SERVER to blanks
– CURRENT SQLID to blanks
– CURRENT DEGREE to 1
Your program must restore those registers if their values are needed after the
checkpoint.

Programs that issue symbolic checkpoint calls can specify as many as seven data
areas in the program to be restored at restart. Symbolic checkpoint calls do not
support OS/VS files; if your program accesses OS/VS files, you can convert those
files to GSAM and use symbolic checkpoints. DB2 always recovers to the last
checkpoint. You must restart the program from that point.

What restart does


The restart call (XRST), which you must use with symbolic checkpoints, provides a
method for restarting a program after an abend. It 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.

When are checkpoints important?


Issuing checkpoint calls releases locked resources. The decision about whether or
not 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 (there is a special Fast Path call for
these programs, but they can 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:


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

Chapter 18. Planning for recovery 363


v Programs that, by their nature, must have exclusive use of the database.

Checkpoints in MPPs and transaction-oriented BMPs


Single-mode programs: 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—the get-unique call.

Multiple-mode programs: 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 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.

There are three considerations in issuing checkpoint calls in multiple-mode


programs:
v How long it takes to back out and recover that unit of processing.
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 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.

Checkpoints in batch-oriented BMPs


Issuing checkpoints in a batch-oriented BMP is important for several reasons:
v To commit changes to the database
v To establish places from which the program can be restarted
v To release locked DB2 and IMS data that IMS has enqueued for the program.

Checkpoints also close all open cursors, which means you must reopen the cursors
you want and re-establish positioning.

If a batch-oriented BMP does not issue checkpoints frequently enough, IMS can
abend that BMP or another application program for one of these reasons:
v 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 needing those segments. (The exception to this 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 If IMS is using program isolation enqueuing, the space needed to enqueue
information about the segments that the program has read and updated must not
exceed the amount defined for the IMS system. If a BMP enqueues too many

364 Application Programming and SQL Guide


segments, the amount of storage needed for the enqueued segments can
exceed the amount of storage available. If that happens, IMS terminates the
program abnormally with an abend code of U0775. You then have to increase the
program’s checkpoint frequency before rerunning the program. The amount of
storage available is specified during IMS system definition. For more information,
see IMS Install Volume 2: System Definition and Tailoring.

When you issue a DL/I CHKP call from an application program using 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 do this is to put such information in a data area included in the DL/I
CHKP call. There can be undesirable performance implications of re-establishing
position within a DB2 database as a result of the commit processing that takes
place because of a DL/I CHKP call. 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.

Another limitation of processing DB2 databases in a BMP program is that you can
restart the program only from the latest checkpoint and not from any checkpoint, as
in IMS.

Specifying checkpoint frequency


You must specify checkpoint frequency in your program in a way that makes it easy
to change in case the frequency you initially specify is not right. Some ways to do
this are:
v Use a counter in your program to keep track of elapsed time and issue a
checkpoint call after a certain time interval.
v Use a counter to keep track of the number of root segments your program
accesses. Issue a checkpoint call after a certain number of root segments.
v Use a counter to keep track of the number of updates your program performs.
Issue a checkpoint call after a certain number of updates.

Unit of work in DL/I batch and IMS batch


This section describes how to coordinate commit and rollback operations for DL/I
batch, and how to restart and recover in IMS batch.

Commit and rollback coordination


DB2 coordinates commit and rollback for DL/I batch, with the following
considerations:
v DB2 and DL/I changes are committed as the result of IMS CHKP calls. However,
you lose the application program database positioning in DL/I. In addition, the
program database positioning in DB2 can be affected as follows:
– If you did not specify the WITH HOLD option for a cursor, then you lose the
position of that cursor.
– If you specified the WITH HOLD option for a cursor and the application is
message-driven, then you lose the position of that cursor.
– If you specified the WITH HOLD option for a cursor and the application is
operating in DL/I batch or DL/I BMP, then you retain the position of that
cursor.

Chapter 18. Planning for recovery 365


v DB2 automatically backs out changes whenever the application program abends.
To back out DL/I changes, you must use the DL/I batch backout utility.
v You cannot use SQL statements COMMIT and ROLLBACK in the DB2 DL/I batch
support environment, because IMS coordinates the unit of work. Issuing COMMIT
causes SQLCODE -925 (SQLSTATE '2D521'); issuing ROLLBACK causes
SQLCODE -926 (SQLSTATE '2D521').
v If the system fails, a unit of work resolves automatically when DB2 and IMS
batch programs reconnect. If there is an indoubt unit of work, it resolves at
reconnect time.
v You can use IMS rollback calls, ROLL and ROLB, to back out DB2 and DL/I
changes to the last commit point. When you issue a ROLL call, DL/I terminates
your program with an abend. When you issue a ROLB call, DL/I returns control
to your program after the call.
How ROLL and ROLB affect DL/I changes in a batch environment depends on
the IMS system log used and the back out options specified, as the following
summary indicates:
– A ROLL call with tape logging (BKO specification does not matter), or disk
logging and BKO=NO specified. DL/I does not back out updates and abend
U0778 occurs. DB2 backs out updates to the previous checkpoint.
– A ROLB call with tape logging (BKO specification does not matter), or disk
logging and BKO=NO specified. DL/I does not back out updates and an AL
status code returns 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.
– A ROLL call with disk logging and BKO=YES specified. DL/I backs out
updates and abend U0778 occurs. DB2 backs out updates to the previous
checkpoint.
– A ROLB call with disk logging and BKO=YES specified. DL/I backs out
databases and control passes back to the application program. DB2 backs out
updates to the previous checkpoint.

Using ROLL
Issuing a ROLL call causes IMS to terminate the program with a user abend code
U0778. This terminates the program without a storage dump.

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

Using ROLB
The advantage of using ROLB is that IMS returns control to the program after
executing ROLB, thus the program can continue processing. The options for ROLB
are:
v The call function, ROLB
v The name of the I/O PCB.

In batch programs
If your IMS system log is on direct access storage, and if the run option BKO is Y to
specify dynamic back out, you can use the ROLB call in a batch program. The
ROLB call backs out the database updates since the last commit point and returns
control to your program. 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. You
must, however, have an I/O PCB for your program. Specify CMPAT=YES on the
CMPAT keyword in the PSBGEN statement for your program’s PSB. For more
information on using the CMPAT keyword, see IMS Utilities Reference: System.

366 Application Programming and SQL Guide


Restart and recovery in IMS (batch)
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.
For more information, refer to IMS Application Programming: Design Guide.

Using savepoints to undo selected changes within a unit of work


Savepoints let you undo selected changes within a transaction. Your application can
set any number of savepoints using SQL SAVEPOINT statements, and then use
SQL ROLLBACK TO SAVEPOINT statements to indicate which changes within the
unit of work to undo. When the application no longer uses a savepoint, it can delete
that savepoint using the SQL RELEASE SAVEPOINT statement.

You can write a ROLLBACK TO SAVEPOINT statement with or without a savepoint


name. If you do not specify a savepoint name, DB2 rolls back work to the most
recently created savepoint.

Example: 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.
EXEC
. SQL SAVEPOINT A;
.
.

EXEC
. SQL SAVEPOINT B;
.
.

EXEC SQL ROLLBACK TO SAVEPOINT;

When savepoints are active, you cannot access remote sites using three-part
names or aliases for three-part names. You can, however, use DRDA access with
explicit CONNECT statements when savepoints are active. 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.

Example: Setting savepoints during distributed processing: Suppose that an


application performs these 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
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.

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.

Example: Setting a savepoint multiple times: Suppose that the following actions
take place 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.

Chapter 18. Planning for recovery 367


4. Stored procedure P executes ROLLBACK TO SAVEPOINT S.
When DB2 executes ROLLBACK to SAVEPOINT S, 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.

If you do not want a savepoint to have different values within a unit of work, you
can use the UNIQUE option in the SAVEPOINT statement. If an application
executes a SAVEPOINT statement for a savepoint that was previously defined as
unique, an SQL error occurs.

Savepoints are automatically released at the end of a unit of work. However, if you
no longer need a savepoint before the end of a transaction, you should execute the
SQL RELEASE SAVEPOINT statement. Releasing savepoints is essential if you
need to use three-part names to access remote locations.

Restrictions on using savepoints: You cannot use savepoints in global


transactions, triggers, or user-defined functions, or in stored procedures,
user-defined functions, or triggers that are nested within triggers or user-defined
functions.

For more information on the SAVEPOINT, ROLLBACK TO SAVEPOINT, and


RELEASE SAVEPOINT statements, see Chapter 5 of DB2 SQL Reference.

368 Application Programming and SQL Guide


Chapter 19. Planning to access distributed data
An instance of DB2 for OS/390 and z/OS can communicate with other instances of
the same product and with some other products. This chapter:
1. Introduces some background material, in “Introduction to accessing distributed
data”. A key point is that there are two methods of access that you ought to
consider.
2. Tells how to design programs to for distributed access, using a sample task as
illustration, in “Coding for distributed data by two methods” on page 371.
3. Discusses some considerations for choosing an access method, in “Coding
considerations for access methods” on page 374.
4. Tells how to prepare programs that use the one method that requires special
preparation, in “Preparing programs For DRDA access” on page 376.
5. Describes special considerations for a possibly complex situation, in
“Coordinating updates to two or more data sources” on page 379.
6. Concludes with “Miscellaneous topics for distributed data” on page 381.

Introduction to accessing distributed data


Definitions: Distributed data is data that resides on some 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.

In this chapter, we assume that you are requesting services from a remote DBMS.
That DBMS is a server in that situation, and your local system is a requester or
client.

Your application can be connected to many DBMSs at one time; the one 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 truly remote in the physical sense: thousands of miles
away. But that is not necessary; it could even be another subsystem of the same
operating system your local DBMS runs under. We assume that your local DBMS is
an instance of DB2 for OS/390 and z/OS. A remote server could be an instance of
DB2 for OS/390 and z/OS also, or an instance of one of many other products.

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. (If you need more information about location names or the
communications database, see Part 3 of DB2 Installation Guide.)

Example 1: You can write a query like this to access data at a remote server:
SELECT * FROM CHICAGO.DSN8710.EMP
WHERE EMPNO = '0001000';

The mode of access depends on whether you bind your DBRMs into packages and
on the value of field DATABASE PROTOCOL in installation panel DSNTIP5 or the
value of bind option DBPROTOCOL. Bind option DBPROTOCOL overrides the
installation setting.

Example 2: You can also write statements like these to accomplish the same task:

© Copyright IBM Corp. 1983, 2001 369


# EXEC SQL
# CONNECT TO CHICAGO;
# EXEC SQL
# SELECT * FROM DSN8710.EMP
# WHERE EMPNO = '0001000';

# Before you can execute the query at location CHICAGO, you must bind the
# application as a remote package at the CHICAGO server. Before you can run the
# application, you must also bind a local plan with a package list that includes the
# remote package.

Example 3: You can call a stored procedure, which is a subroutine that can contain
many SQL statements. Your program executes this:
EXEC SQL
CONNECT TO ATLANTA;
EXEC SQL
CALL procedure_name (parameter_list);

The parameter list is a list of host variables that is passed to the stored procedure
and into which it returns the results of its execution. The stored procedure must
already exist at location ATLANTA.

Two methods of access: The examples above show two different methods for
accessing distributed data.
v Example 1 shows a statement that can be executed with DB2 private protocol
access or DRDA access.
If you bind the DBRM that contains the statement into a plan at the local DB2
and specify the bind option DBPROTOCOL(PRIVATE), you access the server
using DB2 private protocol access.
If you bind the DBRM that contains the statement using one of these methods,
you access the server using DRDA access.
Method 1:
– Bind the DBRM into a package at the local DB2 using the bind option
DBPROTOCOL(DRDA®).
– Bind the DBRM into a package at the remote location (CHICAGO).
– Bind the packages into a plan using bind option DBPROTOCOL(DRDA).

Method 2:
– Bind the DBRM into a package at the remote location.
| – Bind the remote package and the DBRM into a plan at the local site, using the
bind option DBPROTOCOL(DRDA).
v Examples 2 and 3 show statements that are executed with DRDA access only.
When you use these methods for DRDA access, your application must include an
explicit CONNECT statement to switch your connection from one system to
another.

Planning considerations for choosing an access method: DB2 private protocol


access and DRDA access differ in several ways. To choose between them, you
must know:
v What kind of server you are querying.
DB2 private protocol access is available only to supported releases of DB2 for
OS/390 and z/OS.

370 Application Programming and SQL Guide


DRDA access is available to all DBMSs that implement Distributed Relational
Database Architecture (DRDA). Those include supported releases of DB2 for
OS/390 and z/OS, other members of the DB2 family of IBM products, and many
products of other companies.
v What operations the server must perform.
DB2 private protocol access supports only data manipulation statements:
INSERT, UPDATE, DELETE, SELECT, OPEN, FETCH, and CLOSE. You cannot
invoke user-defined functions and stored procedures or use LOBs or distinct
types in applications that use DB2 private protocol access.
DRDA access allows any statement that the server can execute.
v What performance you expect.
DRDA access has some significant advantages over DB2 private protocol
access:
– DRDA access uses a more compact format for sending data over the network,
which improves the performance on slow network links.
– Queries sent 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.
A DBRM for statements executed by DRDA access is bound to a package at
the server once. Those statements can include PREPARE and EXECUTE, so
your application can accept dynamic statements to be executed at the server.
But binding the package is an extra step in program preparation.
– You can use stored procedures with DRDA access.
While a stored procedure is running, it requires no message traffic over the
network. That reduces the biggest hindrance to high performance for
distributed data.

Recommendation: Use DRDA access whenever possible.

Other planning considerations: Authorization to connect to a remote server and


to use resources there must be granted at the server to the appropriate
authorization ID. For information when the server is DB2 for OS/390 and z/OS, see
Part 3 (Volume 1) of DB2 Administration Guide. For information about other servers,
see the documentation for the appropriate product.

If you update two or more DBMSs you must consider how updates can be
coordinated, so that units of work at the two DBMSs are either both committed or
both rolled back. Be sure to read “Coordinating updates to two or more data
sources” on page 379.

You can use the resource limit facility at the server to govern distributed SQL
statements. Governing is by plan for DB2 private protocol access and by package
for DRDA access. See “Considerations for moving from DB2 private protocol access
to DRDA access” on page 393 for information on changes you need to make to
your resource limit facility tables when you move from DB2 private protocol access
to DRDA access.

Coding for distributed data by two methods


This section illustrates the two ways to code applications for distributed access by
the following hypothetical application:
Spiffy Computer has a master project table that supplies information about all
projects currently active throughout the company. Spiffy has several branches in

Chapter 19. Planning to access distributed data 371


various locations around the world, each a DB2 location maintaining a copy of
the project table named DSN8710.PROJ. The main branch location occasionally
inserts data into all copies of the table. The application that makes the inserts
uses a table of location names. For each row inserted, the application executes
an INSERT statement in DSN8710.PROJ for each location.

Using three-part table names


You can use three-part table names to access data at a remote location through
DRDA access or DB2 private protocol access. When you use three-part table
names, the way you code your application is the same, regardless of the access
method you choose. You determine the access method when you bind the SQL
statements into a package or plan. If you use DRDA access, you must bind the
DBRMs for the SQL statements to be executed at the server to packages that
reside at that server.

Because platforms other than DB2 for OS/390 and z/OS might not support the
three-part name syntax, you should not code applications with three-part names if
you plan to port those applications to other platforms.

In a three-part table name, the first part denotes the location. The local DB2 makes
and breaks an implicit connection to a remote server as needed.

Spiffy’s application uses a location name to construct a three-part table name in an


INSERT statement. It then prepares the statement and executes it dynamically.
(See “Chapter 23. Coding dynamic SQL in application programs” on page 497 for
the technique.) The values to be inserted are transmitted to the remote location and
substituted for the parameter markers in the INSERT statement.

The following overview shows how the application uses three-part names:
Read input values
Do for all locations
Read location name
Set up statement to prepare
Prepare statement
Execute statement
End loop
Commit

After the application obtains a location name, for example 'SAN_JOSE', it next
creates the following character string:
INSERT INTO SAN_JOSE.DSN8710.PROJ VALUES (?,?,?,?,?,?,?,?)

The application assigns the character string to the variable INSERTX and then
executes these statements:
EXEC SQL
PREPARE STMT1 FROM :INSERTX;

EXEC SQL
EXECUTE STMT1 USING :PROJNO, :PROJNAME, :DEPTNO, :RESPEMP,
:PRSTAFF, :PRSTDATE, :PRENDATE, :MAJPROJ;

The host variables for Spiffy’s project table match the declaration for the sample
project table in “Project table (DSN8710.PROJ)” on page 822.

To keep the data consistent at all locations, the application commits the work only
when the loop has executed for all locations. Either every location has committed
the INSERT or, if a failure has prevented any location from inserting, all other

372 Application Programming and SQL Guide


locations have rolled back the INSERT. (If a failure occurs during the commit
process, the entire unit of work can be indoubt.)

Programming hint: You might find it convenient to use aliases when creating
character strings that become prepared statements, instead of using full three-part
names like SAN_JOSE.DSN8710.PROJ. For information on aliases, see the section
on CREATE ALIAS in DB2 SQL Reference.

Using explicit CONNECT statements


With this method the application program explicitly connects to each new server.
You must bind the DBRMs for the SQL statements to be executed at the server to
packages that reside at that server.

In this example, Spiffy’s application executes CONNECT for each server in turn and
the server executes INSERT. In this case the tables to be updated each have the
same name, though each is defined at a different server. The application executes
the statements in a loop, with one iteration for each server.

The application connects to each new server by means of a host variable in the
CONNECT statement. CONNECT changes the special register CURRENT SERVER
to show the location of the new server. The values to insert in the table are
transmitted to a location as input host variables.

The following overview shows how the application uses explicit CONNECTs:
Read input values
Do for all locations
Read location name
Connect to location
Execute insert statement
End loop
Commit
Release all

The application inserts a new location name into the variable LOCATION_NAME,
and executes the following statements:
EXEC SQL
CONNECT TO :LOCATION_NAME;

EXEC SQL
INSERT INTO DSN8710.PROJ VALUES (:PROJNO, :PROJNAME, :DEPTNO, :RESPEMP,
:PRSTAFF, :PRSTDATE, :PRENDATE, :MAJPROJ);

To keep the data consistent at all locations, the application commits the work only
when the loop has executed for all locations. Either every location has committed
the INSERT or, if a failure has prevented any location from inserting, all other
locations have rolled back the INSERT. (If a failure occurs during the commit
process, the entire unit of work can be indoubt.)

The host variables for Spiffy’s project table match the declaration for the sample
project table in “Project table (DSN8710.PROJ)” on page 822. LOCATION_NAME is
a character-string variable of length 16.

Releasing connections
When you connect to remote locations explicitly, you must also break those
connections explicitly. You have considerable flexibility in determining how long
connections remain open, so the RELEASE statement differs significantly from
CONNECT.

Chapter 19. Planning to access distributed data 373


Differences between CONNECT and RELEASE:
v CONNECT makes an immediate connection to exactly one remote system.
CONNECT (Type 2) does not release any current connection.
v RELEASE
– Does not immediately break a connection. The RELEASE statement labels
connections for release at the next commit point. A connection so labeled is in
the release-pending state and can still be used before the next commit point.
– Can specify a single connection or a set of connections for release at the next
commit point. The examples that follow show some of the possibilities.

Examples: Using the RELEASE statement, you can place any of the following in
the release-pending state.
v A specific connection that the next unit of work does not use:
EXEC SQL RELEASE SPIFFY1;
v The current SQL connection, whatever its location name:
EXEC SQL RELEASE CURRENT;
v All connections except the local connection:
EXEC SQL RELEASE ALL;
v All DB2 private protocol connections. If the first phase of your application
program uses DB2 private protocol access and the second phase uses DRDA
access, then open DB2 private protocol connections from the first phase could
cause a CONNECT operation to fail in the second phase. To prevent that error,
execute the following statement before the commit operation that separates the
two phases:
EXEC SQL RELEASE ALL PRIVATE;

PRIVATE refers to DB2 private protocol connections, which exist only between
instances of DB2 for OS/390 and z/OS.

Coding considerations for access methods


Stored procedures: If you use DRDA access, your program can call stored
procedures at other systems that support them. Stored procedures behave like
subroutines that can contain SQL statements as well as other operations. Read
about them in “Chapter 24. Using stored procedures for client/server processing” on
page 527.

SQL Limitations at Dissimilar Servers: Generally, a program using DRDA access


can use SQL statements and clauses that are supported by a remote server even if
they are not supported by the local server. DB2 SQL Reference tells what DB2 for
OS/390 and z/OS supports; similar documentation is usually available for other
products. The following examples suggest what to expect from dissimilar servers:
v They support SELECT, INSERT, UPDATE, DELETE, DECLARE CURSOR, and
FETCH, but details vary.
Example: SQL/DS™ does not support the clause WITH HOLD on DECLARE
CURSOR.
v Data definition statements vary more widely.
Example: SQL/DS does not support CREATE DATABASE. It does support
ACQUIRE DBSPACE for a similar purpose.
v Statements can have different limits.

374 Application Programming and SQL Guide


Example: A query in DB2 for OS/390 and z/OS can have 750 columns; for
another system, the maximum might be 255. But a query using 255 or fewer
columns could execute in both systems.
v Some statements are not sent to the server but are processed completely by the
requester. You cannot use those statements in a remote package even though
the server supports them. For a list of those statements, see “Appendix G.
Characteristics of SQL statements in DB2 for OS/390 and z/OS” on page 923.
v In general, if a statement to be executed at a remote server contains host
variables, a DB2 requester assumes them to be input host variables unless it
supports the syntax of the statement and can determine otherwise. If the
assumption is not valid, the server rejects the statement.

Three-part names and multiple servers: If you use a three-part name, or an alias
that resolves to one, in a statement executed at a remote server by DRDA access,
and if the location name is not that of the server, then the method by which the
remote server accesses data at the named location depends on the value of
DBPROTOCOL. If the package at the first remote server is bound with
DBPROTOCOL(PRIVATE), DB2 uses DB2 private protocol access to access the
second remote server. If the package at the first remote server is bound with
DBPROTOCOL(DRDA), DB2 uses DRDA access to access the second remote
server. We recommend that you follow these steps so that access to the second
remote server is by DRDA access:
v Rebind the package at the first remote server with DBPROTOCOL(DRDA).
v Bind the package that contains the three-part name at the second server.

Accessing declared temporary tables using three-part names: You can access
a remote declared temporary table using a three-part name only if you use DRDA
access. However, if you combine explicit CONNECT statements and three-part
names in your application, a reference to a remote declared temporary table must
be a forward reference. For example, you can perform the following series of
actions, which includes a forward reference to a declared temporary table:
EXEC SQL CONNECT TO CHICAGO; /* Connect to the remote site */
EXEC SQL
DECLARE GLOBAL TEMPORARY TABLE T1 /* Define the temporary table */
(CHARCOL CHAR(6) NOT NULL); /* at the remote site */
EXEC SQL CONNECT RESET; /* Connect back to local site */
EXEC SQL INSERT INTO CHICAGO.SESSION.T1
(VALUES 'ABCDEF'); /* Access the temporary table*/
/* at the remote site (forward reference) */

However, you cannot perform the following series of actions, which includes a
backward reference to the declared temporary table:
EXEC SQL
DECLARE GLOBAL TEMPORARY TABLE T1 /* Define the temporary table */
(CHARCOL CHAR(6) NOT NULL); /* at the local site (ATLANTA)*/
EXEC SQL CONNECT TO CHICAGO; /* Connect to the remote site */
EXEC SQL INSERT INTO ATLANTA.SESSION.T1
(VALUES 'ABCDEF'); /* Cannot access temp table */
/* from the remote site (backward reference)*/

Savepoints: In a distributed environment, 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