0% found this document useful (0 votes)
930 views1,141 pages

DB2 V8 Application Programming and SQL Guide

This edition applies to Version 8 of DB2 Universal Database for z / OS. Specific changes are indicated by a vertical bar to the left of a change. Editorial changes that have no technical significance are not noted.

Uploaded by

api-3731933
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)
930 views1,141 pages

DB2 V8 Application Programming and SQL Guide

This edition applies to Version 8 of DB2 Universal Database for z / OS. Specific changes are indicated by a vertical bar to the left of a change. Editorial changes that have no technical significance are not noted.

Uploaded by

api-3731933
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/ 1141

DB2 Universal Database for z/OS


Version 8

Application Programming
and SQL Guide

SC18-7415-00
DB2 Universal Database for z/OS
®


Version 8

Application Programming
and SQL Guide

SC18-7415-00
Note
Before using this information and the product it supports, be sure to read the general information under “Notices” on page
1037.

First Edition (March 2004)


This edition applies to Version 8 of IBM DB2 Universal Database for z/OS (DB2 UDB for z/OS), product number
5625-DB2, and to any subsequent releases until otherwise indicated in new editions. Make sure you are using the
correct edition for the level of the product.
Specific changes are indicated by a vertical bar to the left of a change. A vertical bar to the left of a figure caption
indicates that the figure has changed. Editorial changes that have no technical significance are not noted.
© Copyright International Business Machines Corporation 1983, 2004. 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
Terminology and citations . . . . . . . . . . . . . . . . . . . . . xix
How to read the syntax diagrams . . . . . . . . . . . . . . . . . . xx
Accessibility . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
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 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 . . . . . . . . . . . . . . . . . . . . . 10
Referencing derived columns. . . . . . . . . . . . . . . . . . . 10
Summarizing group values: GROUP BY . . . . . . . . . . . . . . . . 11
Subjecting groups to conditions: HAVING . . . . . . . . . . . . . . . 12
Merging lists of values: UNION . . . . . . . . . . . . . . . . . . . 13
Using UNION to eliminate duplicates . . . . . . . . . . . . . . . . 13
Using UNION ALL to keep duplicates. . . . . . . . . . . . . . . . 13
| Creating common table expressions: WITH . . . . . . . . . . . . . . 14
| Using WITH instead of CREATE VIEW: . . . . . . . . . . . . . . . 14
| Using common table expressions with CREATE VIEW: . . . . . . . . . 15
| Using common table expressions when you use INSERT: . . . . . . . . 15
| Using recursive SQL . . . . . . . . . . . . . . . . . . . . . . 15
Accessing DB2 data that is not in a table . . . . . . . . . . . . . . . 16
Using 15-digit and 31-digit precision for decimal numbers . . . . . . . . . 16
Finding information in the DB2 catalog . . . . . . . . . . . . . . . . 18
Displaying a list of tables you can use . . . . . . . . . . . . . . . 18
Displaying a list of columns in a table . . . . . . . . . . . . . . . 18

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


Working with tables . . . . . . . . . . . . . . . . . . . . . . . 19
Creating your own tables: CREATE TABLE . . . . . . . . . . . . . 19
Working with temporary tables . . . . . . . . . . . . . . . . . . 21
Dropping tables: DROP TABLE . . . . . . . . . . . . . . . . . . 25
Working with views . . . . . . . . . . . . . . . . . . . . . . . 25
Defining a view: CREATE VIEW . . . . . . . . . . . . . . . . . 25
Changing data through a view . . . . . . . . . . . . . . . . . . 26
Dropping views: DROP VIEW . . . . . . . . . . . . . . . . . . 27
Modifying DB2 data . . . . . . . . . . . . . . . . . . . . . . . 27
Inserting rows: INSERT . . . . . . . . . . . . . . . . . . . . . 27
| Selecting values as you insert: SELECT from INSERT . . . . . . . . . 31
Updating current values: UPDATE . . . . . . . . . . . . . . . . . 36
© Copyright IBM Corp. 1983, 2004 iii
Deleting rows: DELETE . . . . . . . . . . . . . . . . . . . . . 37

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


Inner join . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Full outer join . . . . . . . . . . . . . . . . . . . . . . . . . 41
Left outer join . . . . . . . . . . . . . . . . . . . . . . . . . 42
Right outer join . . . . . . . . . . . . . . . . . . . . . . . . . 43
SQL rules for statements containing join operations . . . . . . . . . . . 44
Using more than one join in an SQL statement . . . . . . . . . . . . . 45
Using nested table expressions and user-defined table functions in joins . . . 46
Using correlated references in table specifications in joins . . . . . . . . . 47

Chapter 4. Using subqueries . . . . . . . . . . . . . . . . . . . 49


Conceptual overview . . . . . . . . . . . . . . . . . . . . . . . 49
Correlated and uncorrelated subqueries . . . . . . . . . . . . . . . 50
Subqueries and predicates . . . . . . . . . . . . . . . . . . . 50
The subquery result table . . . . . . . . . . . . . . . . . . . . 50
Tables in subqueries of UPDATE, DELETE, and INSERT statements . . . . 51
How to code a subquery . . . . . . . . . . . . . . . . . . . . . 51
Basic predicate . . . . . . . . . . . . . . . . . . . . . . . . 51
Quantified predicate : ALL, ANY, or SOME . . . . . . . . . . . . . . 51
IN keyword . . . . . . . . . . . . . . . . . . . . . . . . . 52
EXISTS keyword . . . . . . . . . . . . . . . . . . . . . . . 52
Using correlated subqueries . . . . . . . . . . . . . . . . . . . . 53
An example of a correlated subquery . . . . . . . . . . . . . . . . 53
Using correlation names in references . . . . . . . . . . . . . . . 54
Using correlated subqueries in an UPDATE statement . . . . . . . . . 55
Using correlated subqueries in a DELETE statement . . . . . . . . . . 55

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


Allocating an input data set and using SPUFI . . . . . . . . . . . . . . 59
Changing SPUFI defaults (optional) . . . . . . . . . . . . . . . . . 60
Entering SQL statements . . . . . . . . . . . . . . . . . . . . . 60
Using the ISPF editor . . . . . . . . . . . . . . . . . . . . . 60
| Retrieving Unicode UTF-16 graphic data . . . . . . . . . . . . . . 61
Entering comments . . . . . . . . . . . . . . . . . . . . . . 62
Setting the SQL terminator character . . . . . . . . . . . . . . . . 62
Processing SQL statements . . . . . . . . . . . . . . . . . . . . 62
Browsing the output . . . . . . . . . . . . . . . . . . . . . . . 63
Format of SELECT statement results . . . . . . . . . . . . . . . . 64
Content of the messages . . . . . . . . . . . . . . . . . . . . 64

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

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


Conventions used in examples of coding SQL statements . . . . . . . . . 70
Delimiting an SQL statement . . . . . . . . . . . . . . . . . . . . 70
Declaring table and view definitions . . . . . . . . . . . . . . . . . 71
Accessing data using host variables, variable arrays, and structures . . . . . 71
Using host variables . . . . . . . . . . . . . . . . . . . . . . 72
| Using host variable arrays . . . . . . . . . . . . . . . . . . . . 78
Using host structures . . . . . . . . . . . . . . . . . . . . . 80
Checking the execution of SQL statements . . . . . . . . . . . . . . 82
Using the SQL communication area (SQLCA) . . . . . . . . . . . . 82
SQLCODE and SQLSTATE . . . . . . . . . . . . . . . . . . . 83
Using the WHENEVER statement . . . . . . . . . . . . . . . . . 83

iv Application Programming and SQL Guide


Handling arithmetic or conversion errors . . . . . . . . . . . . . . 84
| Using the GET DIAGNOSTICS statement . . . . . . . . . . . . . . 84
Calling DSNTIAR to display SQLCA fields . . . . . . . . . . . . . . 89

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


Accessing data by using a row-positioned cursor . . . . . . . . . . . . 93
Step 1: Declare the cursor. . . . . . . . . . . . . . . . . . . . 93
Step 2: Open the cursor . . . . . . . . . . . . . . . . . . . . 95
Step 3: Specify what to do at end-of-data . . . . . . . . . . . . . . 95
Step 4: Execute SQL statements . . . . . . . . . . . . . . . . . 96
Step 5: Close the cursor . . . . . . . . . . . . . . . . . . . . 98
| Accessing data by using a rowset-positioned cursor . . . . . . . . . . . 98
| Step 1: Declare the rowset cursor . . . . . . . . . . . . . . . . . 98
| Step 2: Open the rowset cursor . . . . . . . . . . . . . . . . . . 98
| Step 3: Specify what to do at end-of-data for a rowset cursor . . . . . . . 99
| Step 4: Execute SQL statements with a rowset cursor . . . . . . . . . 99
| Step 5: Close the rowset cursor . . . . . . . . . . . . . . . . . 103
Types of cursors . . . . . . . . . . . . . . . . . . . . . . . . 103
Scrollable and non-scrollable cursors . . . . . . . . . . . . . . . 103
Held and non-held cursors . . . . . . . . . . . . . . . . . . . 112
Examples of using cursors . . . . . . . . . . . . . . . . . . . . 114

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


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

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


Coding SQL statements in an assembler application. . . . . . . . . . . 129
Defining the SQL communications area . . . . . . . . . . . . . . 129
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 130
Embedding SQL statements . . . . . . . . . . . . . . . . . . 131
Using host variables . . . . . . . . . . . . . . . . . . . . . 133
Declaring host variables . . . . . . . . . . . . . . . . . . . . 133
Determining equivalent SQL and assembler data types . . . . . . . . 136
Determining compatibility of SQL and assembler data types . . . . . . . 140
Using indicator variables . . . . . . . . . . . . . . . . . . . . 141
Handling SQL error return codes . . . . . . . . . . . . . . . . . 142
Macros for assembler applications . . . . . . . . . . . . . . . . 143
Coding SQL statements in a C or C++ application . . . . . . . . . . . 143
Defining the SQL communication area . . . . . . . . . . . . . . . 143
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 144
Embedding SQL statements . . . . . . . . . . . . . . . . . . 145
| Using host variables and host variable arrays . . . . . . . . . . . . 146
Declaring host variables . . . . . . . . . . . . . . . . . . . . 147
| Declaring host variable arrays . . . . . . . . . . . . . . . . . . 153
Using host structures . . . . . . . . . . . . . . . . . . . . . 158
Determining equivalent SQL and C data types . . . . . . . . . . . . 160
Determining compatibility of SQL and C data types . . . . . . . . . . 166
Using indicator variables and indicator variable arrays . . . . . . . . . 167
Handling SQL error return codes . . . . . . . . . . . . . . . . . 169
Coding considerations for C and C++ . . . . . . . . . . . . . . . 170

Contents v
Coding SQL statements in a COBOL application . . . . . . . . . . . . 170
Defining the SQL communication area . . . . . . . . . . . . . . . 170
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 171
Embedding SQL statements . . . . . . . . . . . . . . . . . . 172
| Using host variables and host variable arrays . . . . . . . . . . . . 175
Declaring host variables . . . . . . . . . . . . . . . . . . . . 176
| Declaring host variable arrays . . . . . . . . . . . . . . . . . . 183
Using host structures . . . . . . . . . . . . . . . . . . . . . 189
Determining equivalent SQL and COBOL data types . . . . . . . . . 194
Determining compatibility of SQL and COBOL data types . . . . . . . . 198
Using indicator variables and indicator variable arrays . . . . . . . . . 199
Handling SQL error return codes . . . . . . . . . . . . . . . . . 201
Coding considerations for object-oriented extensions in COBOL . . . . . 202
Coding SQL statements in a Fortran application . . . . . . . . . . . . 203
Defining the SQL communication area . . . . . . . . . . . . . . . 203
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 204
Embedding SQL statements . . . . . . . . . . . . . . . . . . 204
Using host variables . . . . . . . . . . . . . . . . . . . . . 206
Declaring host variables . . . . . . . . . . . . . . . . . . . . 207
Determining equivalent SQL and Fortran data types . . . . . . . . . . 208
Determining compatibility of SQL and Fortran data types . . . . . . . . 211
Using indicator variables . . . . . . . . . . . . . . . . . . . . 211
Handling SQL error return codes . . . . . . . . . . . . . . . . . 212
Coding SQL statements in a PL/I application . . . . . . . . . . . . . 213
Defining the SQL communication area . . . . . . . . . . . . . . . 213
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 214
Embedding SQL statements . . . . . . . . . . . . . . . . . . 214
| Using host variables and host variable arrays . . . . . . . . . . . . 217
Declaring host variables . . . . . . . . . . . . . . . . . . . . 217
| Declaring host variable arrays . . . . . . . . . . . . . . . . . . 220
Using host structures . . . . . . . . . . . . . . . . . . . . . 223
Determining equivalent SQL and PL/I data types . . . . . . . . . . . 224
Determining compatibility of SQL and PL/I data types . . . . . . . . . 228
Using indicator variables and indicator variable arrays . . . . . . . . . 229
Handling SQL error return codes . . . . . . . . . . . . . . . . . 230
Coding considerations for PL/I . . . . . . . . . . . . . . . . . . 232
Coding SQL statements in a REXX application . . . . . . . . . . . . . 232
Defining the SQL communication area . . . . . . . . . . . . . . . 232
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 233
Accessing the DB2 REXX Language Support application programming
interfaces . . . . . . . . . . . . . . . . . . . . . . . . 233
Embedding SQL statements in a REXX procedure . . . . . . . . . . 235
Using cursors and statement names . . . . . . . . . . . . . . . 237
Using REXX host variables and data types . . . . . . . . . . . . . 237
Using indicator variables . . . . . . . . . . . . . . . . . . . . 241
Setting the isolation level of SQL statements in a REXX procedure . . . . 241

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


Using check constraints . . . . . . . . . . . . . . . . . . . . . 243
Check constraint considerations . . . . . . . . . . . . . . . . . 243
When check constraints are enforced . . . . . . . . . . . . . . . 244
How check constraints set check pending status . . . . . . . . . . . 244
Using referential constraints. . . . . . . . . . . . . . . . . . . . 245
Parent key columns. . . . . . . . . . . . . . . . . . . . . . 245
Defining a parent key and a unique index . . . . . . . . . . . . . 246
Defining a foreign key . . . . . . . . . . . . . . . . . . . . . 248

vi Application Programming and SQL Guide


| Referential constraints on tables with multilevel security with row-level
| granularity . . . . . . . . . . . . . . . . . . . . . . . . 250
| Using informational referential constraints . . . . . . . . . . . . . . 250

| Chapter 11. Using DB2-generated values as keys . . . . . . . . . . 253


| Using ROWID columns as keys . . . . . . . . . . . . . . . . . . 253
| Defining a ROWID column . . . . . . . . . . . . . . . . . . . 253
| Direct row access . . . . . . . . . . . . . . . . . . . . . . 253
| Considerations for using ROWID columns . . . . . . . . . . . . . 254
| Using identity columns as keys . . . . . . . . . . . . . . . . . . 254
| Defining an identity column . . . . . . . . . . . . . . . . . . . 255
| Parent keys and foreign keys . . . . . . . . . . . . . . . . . . 256
| Considerations for using identity columns . . . . . . . . . . . . . . 257
| Using values obtained from sequence objects as keys . . . . . . . . . . 257
| Creating a sequence object . . . . . . . . . . . . . . . . . . . 257
| Referencing a sequence object . . . . . . . . . . . . . . . . . 258
| Keys across multiple tables . . . . . . . . . . . . . . . . . . . 258
| Considerations for using sequence numbers . . . . . . . . . . . . 259

Chapter 12. Using triggers for active data . . . . . . . . . . . . .


261
Example of creating and using a trigger . . . . . . . . . . . . . . .
261
Parts of a trigger . . . . . . . . . . . . . . . . . . . . . . . .
263
Trigger name . . . . . . . . . . . . . . . . . . . . . . . .
263
Subject table . . . . . . . . . . . . . . . . . . . . . . . .
263
Trigger activation time . . . . . . . . . . . . . . . . . . . . .
263
Triggering event . . . . . . . . . . . . . . . . . . . . . . .
263
Granularity . . . . . . . . . . . . . . . . . . . . . . . . .
264
Transition variables . . . . . . . . . . . . . . . . . . . . . .
265
Transition tables . . . . . . . . . . . . . . . . . . . . . . .
266
Triggered action . . . . . . . . . . . . . . . . . . . . . . .
267
Invoking stored procedures and user-defined functions from triggers . . . . .
269
Passing transition tables to user-defined functions and stored procedures 270
Trigger cascading . . . . . . . . . . . . . . . . . . . . . . . 270
Ordering of multiple triggers. . . . . . . . . . . . . . . . . . . . 271
Interactions between triggers and referential constraints . . . . . . . . . 272
| Interactions between triggers and tables that have multilevel security with
| row-level granularity . . . . . . . . . . . . . . . . . . . . . . 273
Creating triggers to obtain consistent results . . . . . . . . . . . . . 274

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

Chapter 13. Introduction to DB2 object-relational extensions . . . . . . 279

Chapter 14. Programming for large objects (LOBs) . . . . . . . . . . 281


Introduction to LOBs . . . . . . . . . . . . . . . . . . . . . . 281
Declaring LOB host variables and LOB locators . . . . . . . . . . . . 284
LOB materialization . . . . . . . . . . . . . . . . . . . . . . . 288
Using LOB locators to save storage . . . . . . . . . . . . . . . . . 288
Deferring evaluation of a LOB expression to improve performance . . . . 289
Indicator variables and LOB locators . . . . . . . . . . . . . . . 291
Valid assignments for LOB locators . . . . . . . . . . . . . . . . 292

Chapter 15. Creating and using user-defined functions . . . . . . . . 293


Overview of user-defined function definition, implementation, and invocation 293
Example of creating and using a user-defined scalar function . . . . . . 294
User-defined function samples shipped with DB2 . . . . . . . . . . . 295

Contents vii
Defining a user-defined function . . . . . . . . . . . . . . . . . . 296
Components of a user-defined function definition . . . . . . . . . . . 296
Examples of user-defined function definitions . . . . . . . . . . . . 298
Implementing an external user-defined function . . . . . . . . . . . . 300
Writing a user-defined function . . . . . . . . . . . . . . . . . 300
Preparing a user-defined function for execution . . . . . . . . . . . 333
Testing a user-defined function . . . . . . . . . . . . . . . . . 335
Implementing an SQL scalar function . . . . . . . . . . . . . . . . 338
Invoking a user-defined function . . . . . . . . . . . . . . . . . . 338
Syntax for user-defined function invocation . . . . . . . . . . . . . 338
Ensuring that DB2 executes the intended user-defined function . . . . . 339
Casting of user-defined function arguments . . . . . . . . . . . . . 345
What happens when a user-defined function abnormally terminates . . . . 346
Nesting SQL Statements . . . . . . . . . . . . . . . . . . . . 346
Recommendations for user-defined function invocation . . . . . . . . . 347

Chapter 16. Creating and using distinct types . . . . . . . . . . . . 349


Introduction to distinct types . . . . . . . . . . . . . . . . . . . 349
Using distinct types in application programs . . . . . . . . . . . . . . 350
Comparing distinct types . . . . . . . . . . . . . . . . . . . . 350
Assigning distinct types . . . . . . . . . . . . . . . . . . . . 351
Using distinct types in UNIONs . . . . . . . . . . . . . . . . . 352
Invoking functions with distinct types . . . . . . . . . . . . . . . 353
Combining distinct types with user-defined functions and LOBs . . . . . . 354

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

Chapter 17. Planning for DB2 program preparation . . . . . . . . . . 363


Planning to process SQL statements . . . . . . . . . . . . . . . . 365
Planning to bind . . . . . . . . . . . . . . . . . . . . . . . . 366
Deciding how to bind DBRMs . . . . . . . . . . . . . . . . . . 366
Planning for changes to your application . . . . . . . . . . . . . . 368

Chapter 18. Planning for concurrency . . . . . . . . . . . . . . . 375


Definitions of concurrency and locks . . . . . . . . . . . . . . . . 375
Effects of DB2 locks . . . . . . . . . . . . . . . . . . . . . . 376
Suspension . . . . . . . . . . . . . . . . . . . . . . . . . 376
Timeout . . . . . . . . . . . . . . . . . . . . . . . . . . 376
Deadlock . . . . . . . . . . . . . . . . . . . . . . . . . 377
Basic recommendations to promote concurrency . . . . . . . . . . . . 379
Recommendations for database design . . . . . . . . . . . . . . 380
Recommendations for application design . . . . . . . . . . . . . . 381
Aspects of transaction locks . . . . . . . . . . . . . . . . . . . 384
The size of a lock . . . . . . . . . . . . . . . . . . . . . . 384
The duration of a lock . . . . . . . . . . . . . . . . . . . . . 386
The mode of a lock . . . . . . . . . . . . . . . . . . . . . . 386
The object of a lock. . . . . . . . . . . . . . . . . . . . . . 389
Lock tuning . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Bind options . . . . . . . . . . . . . . . . . . . . . . . . 390
Isolation overriding with SQL statements . . . . . . . . . . . . . . 403
The statement LOCK TABLE . . . . . . . . . . . . . . . . . . 404
Access paths . . . . . . . . . . . . . . . . . . . . . . . . 405
LOB locks . . . . . . . . . . . . . . . . . . . . . . . . . . 408
Relationship between transaction locks and LOB locks . . . . . . . . . 408
Hierarchy of LOB locks . . . . . . . . . . . . . . . . . . . . 409
LOB and LOB table space lock modes. . . . . . . . . . . . . . . 410

viii Application Programming and SQL Guide


Duration of locks . . . . . . . . . . . . . . . . . . . . . . . 410
Instances when locks on LOB table space are not taken . . . . . . . . 411
LOCK TABLE statement . . . . . . . . . . . . . . . . . . . . 411

Chapter 19. Planning for recovery . . . . . . . . . . . . . . . . 413


Unit of work in TSO batch and online . . . . . . . . . . . . . . . . 413
Unit of work in CICS . . . . . . . . . . . . . . . . . . . . . . 414
Unit of work in IMS online . . . . . . . . . . . . . . . . . . . . 415
Planning ahead for program recovery: Checkpoint and restart . . . . . . 417
When are checkpoints important? . . . . . . . . . . . . . . . . 417
Checkpoints in MPPs and transaction-oriented BMPs . . . . . . . . . 418
Checkpoints in batch-oriented BMPs . . . . . . . . . . . . . . . 418
Specifying checkpoint frequency . . . . . . . . . . . . . . . . . 419
Unit of work in DL/I batch and IMS batch . . . . . . . . . . . . . . . 419
Commit and rollback coordination . . . . . . . . . . . . . . . . 419
Restart and recovery in IMS batch . . . . . . . . . . . . . . . . 421
Using savepoints to undo selected changes within a unit of work . . . . . . 421

Chapter 20. Planning to access distributed data . . . . . . . . . . . 423


Introduction to accessing distributed data . . . . . . . . . . . . . . . 423
Coding for distributed data by two methods . . . . . . . . . . . . . . 425
Using three-part table names . . . . . . . . . . . . . . . . . . 425
Using explicit CONNECT statements . . . . . . . . . . . . . . . 427
Coding considerations for access methods . . . . . . . . . . . . . . 429
Preparing programs for DRDA access . . . . . . . . . . . . . . . . 430
Preparing a package for DRDA access . . . . . . . . . . . . . . 430
Binding a package for DRDA access . . . . . . . . . . . . . . . 431
Binding a plan for DRDA access . . . . . . . . . . . . . . . . . 432
Checking BIND PACKAGE options . . . . . . . . . . . . . . . . 433
Coordinating updates to two or more data sources . . . . . . . . . . . 433
How to have coordinated updates . . . . . . . . . . . . . . . . 433
What you can do without two-phase commit . . . . . . . . . . . . . 434
Miscellaneous topics for distributed data . . . . . . . . . . . . . . . 435
Improving performance for remote access . . . . . . . . . . . . . 435
Maximizing LOB performance in a distributed environment . . . . . . . 436
Use bind options that improve performance . . . . . . . . . . . . . 437
Use block fetch . . . . . . . . . . . . . . . . . . . . . . . 440
Limiting the number of DRDA network transmissions . . . . . . . . . 442
Limiting the number of rows returned to DRDA clients . . . . . . . . . 446
DB2 UDB for z/OS support for the rowset parameter . . . . . . . . . 447
Accessing data with a scrollable cursor when the requester is down-level 447
| Accessing data with a rowset-positioned cursor when the requester is
| down-level . . . . . . . . . . . . . . . . . . . . . . . . 447
Maintaining data currency . . . . . . . . . . . . . . . . . . . 447
Copying a table from a remote location . . . . . . . . . . . . . . 447
Transmitting mixed data . . . . . . . . . . . . . . . . . . . . 448
Retrieving data from ASCII or Unicode tables . . . . . . . . . . . . 448
Moving from DB2 private protocol access to DRDA access . . . . . . . 449
| Executing long SQL statements in a distributed environment . . . . . . 450
| Including packages or DBRMs at the requester . . . . . . . . . . . 450

Part 5. Developing your application . . . . . . . . . . . . . . . . . . . . . 451

Chapter 21. Preparing an application program to run . . . . . . . . . 453


Steps in program preparation . . . . . . . . . . . . . . . . . . . 454
Step 1: Process SQL statements . . . . . . . . . . . . . . . . . 454

Contents ix
Step 2: Compile (or assemble) and link-edit the application . . . . . . . 471
Step 3: Bind the application . . . . . . . . . . . . . . . . . . . 472
Step 4: Run the application . . . . . . . . . . . . . . . . . . . 485
Using JCL procedures to prepare applications . . . . . . . . . . . . . 489
Available JCL procedures . . . . . . . . . . . . . . . . . . . 489
Including code from SYSLIB data sets . . . . . . . . . . . . . . . 490
Starting the precompiler dynamically . . . . . . . . . . . . . . . 491
An alternative method for preparing a CICS program . . . . . . . . . 493
Using JCL to prepare a program with object-oriented extensions . . . . . 495
Using ISPF and DB2 Interactive (DB2I) . . . . . . . . . . . . . . . 495
DB2I help . . . . . . . . . . . . . . . . . . . . . . . . . 495
DB2I Primary Option Menu . . . . . . . . . . . . . . . . . . . 495

Chapter 22. Testing an application program . . . . . . . . . . . . . 499


Establishing a test environment . . . . . . . . . . . . . . . . . . 499
Designing a test data structure . . . . . . . . . . . . . . . . . 499
Filling the tables with test data . . . . . . . . . . . . . . . . . . 501
Testing SQL statements using SPUFI . . . . . . . . . . . . . . . . 502
Debugging your program . . . . . . . . . . . . . . . . . . . . . 502
Debugging programs in TSO . . . . . . . . . . . . . . . . . . 502
Debugging programs in IMS . . . . . . . . . . . . . . . . . . 503
Debugging programs in CICS . . . . . . . . . . . . . . . . . . 504
Locating the problem . . . . . . . . . . . . . . . . . . . . . . 508
Analyzing error and warning messages from the precompiler . . . . . . 509
SYSTERM output from the precompiler . . . . . . . . . . . . . . 509
SYSPRINT output from the precompiler . . . . . . . . . . . . . . 510

Chapter 23. Processing DL/I batch applications . . . . . . . . . . . 515


Planning to use DL/I batch . . . . . . . . . . . . . . . . . . . . 515
Features and functions of DB2 DL/I batch support . . . . . . . . . . 515
Requirements for using DB2 in a DL/I batch job . . . . . . . . . . . 516
Authorization . . . . . . . . . . . . . . . . . . . . . . . . 516
Program design considerations . . . . . . . . . . . . . . . . . . 516
Address spaces . . . . . . . . . . . . . . . . . . . . . . . 516
Commits . . . . . . . . . . . . . . . . . . . . . . . . . . 516
SQL statements and IMS calls . . . . . . . . . . . . . . . . . . 517
Checkpoint calls . . . . . . . . . . . . . . . . . . . . . . . 517
Application program synchronization . . . . . . . . . . . . . . . 517
Checkpoint and XRST considerations . . . . . . . . . . . . . . . 517
Synchronization call abends . . . . . . . . . . . . . . . . . . 518
Input and output data sets . . . . . . . . . . . . . . . . . . . . 518
DB2 DL/I batch Input . . . . . . . . . . . . . . . . . . . . . 518
DB2 DL/I batch output . . . . . . . . . . . . . . . . . . . . . 520
Program preparation considerations . . . . . . . . . . . . . . . . . 520
Precompiling . . . . . . . . . . . . . . . . . . . . . . . . 520
Binding . . . . . . . . . . . . . . . . . . . . . . . . . . 520
Link-editing . . . . . . . . . . . . . . . . . . . . . . . . . 521
Loading and running . . . . . . . . . . . . . . . . . . . . . 521
Restart and recovery . . . . . . . . . . . . . . . . . . . . . . 522
JCL example of a batch backout . . . . . . . . . . . . . . . . . 522
JCL example of restarting a DL/I batch job . . . . . . . . . . . . . 523
Finding the DL/I batch checkpoint ID . . . . . . . . . . . . . . . 524

Part 6. Additional programming techniques . . . . . . . . . . . . . . . . . 525

Chapter 24. Coding dynamic SQL in application programs . . . . . . . 535

x Application Programming and SQL Guide


Choosing between static and dynamic SQL . . . . . . . . . . . . . . 536
Host variables make static SQL flexible . . . . . . . . . . . . . . 536
Dynamic SQL is completely flexible . . . . . . . . . . . . . . . . 536
What dynamic SQL cannot do . . . . . . . . . . . . . . . . . . 536
What an application program using dynamic SQL does . . . . . . . . 537
Performance of static and dynamic SQL . . . . . . . . . . . . . . 537
Caching dynamic SQL statements . . . . . . . . . . . . . . . . . 539
Using the dynamic statement cache . . . . . . . . . . . . . . . . 540
Keeping prepared statements after commit points . . . . . . . . . . 541
Limiting dynamic SQL with the resource limit facility . . . . . . . . . . . 543
Writing an application to handle reactive governing . . . . . . . . . . 544
Writing an application to handle predictive governing . . . . . . . . . 544
Using predictive governing and downlevel DRDA requesters . . . . . . . 544
Using predictive governing and enabled requesters . . . . . . . . . . 544
Choosing a host language for dynamic SQL applications . . . . . . . . . 545
Dynamic SQL for non-SELECT statements . . . . . . . . . . . . . . 545
Dynamic execution using EXECUTE IMMEDIATE. . . . . . . . . . . 546
Dynamic execution using PREPARE and EXECUTE . . . . . . . . . 547
| Dynamic execution of a multiple-row INSERT statement . . . . . . . . 549
Using DESCRIBE INPUT to put parameter information in an SQLDA . . . 551
Dynamic SQL for fixed-list SELECT statements . . . . . . . . . . . . 552
What your application program must do . . . . . . . . . . . . . . 552
Dynamic SQL for varying-list SELECT statements . . . . . . . . . . . 554
What your application program must do . . . . . . . . . . . . . . 554
Preparing a varying-list SELECT statement . . . . . . . . . . . . . 555
Executing a varying-list SELECT statement dynamically . . . . . . . . 564
Executing arbitrary statements with parameter markers . . . . . . . . 565
How bind options REOPT(ALWAYS) and REOPT(ONCE) affect dynamic
SQL . . . . . . . . . . . . . . . . . . . . . . . . . . 567
Using dynamic SQL in COBOL . . . . . . . . . . . . . . . . . . 568

Chapter 25. Using stored procedures for client/server processing . . . . 569


Introduction to stored procedures . . . . . . . . . . . . . . . . . . 569
An example of a simple stored procedure . . . . . . . . . . . . . . 570
Setting up the stored procedures environment . . . . . . . . . . . . . 574
Defining your stored procedure to DB2 . . . . . . . . . . . . . . 575
Refreshing the stored procedures environment (for system administrators) 579
Moving stored procedures to a WLM-established environment (for system
administrators) . . . . . . . . . . . . . . . . . . . . . . . 580
Writing and preparing an external stored procedure . . . . . . . . . . . 581
Language requirements for the stored procedure and its caller . . . . . . 581
Calling other programs . . . . . . . . . . . . . . . . . . . . 582
Using reentrant code . . . . . . . . . . . . . . . . . . . . . 582
Writing a stored procedure as a main program or subprogram . . . . . . 583
Restrictions on a stored procedure . . . . . . . . . . . . . . . . 585
Using COMMIT and ROLLBACK statements in a stored procedure . . . . 586
Using special registers in a stored procedure . . . . . . . . . . . . 586
Accessing other sites in a stored procedure . . . . . . . . . . . . . 589
Writing a stored procedure to access IMS databases . . . . . . . . . 590
Writing a stored procedure to return result sets to a DRDA client . . . . . 590
Preparing a stored procedure . . . . . . . . . . . . . . . . . . 592
Binding the stored procedure . . . . . . . . . . . . . . . . . . 593
Writing a REXX stored procedure . . . . . . . . . . . . . . . . 594
Writing and preparing an SQL procedure . . . . . . . . . . . . . . . 597
Comparison of an SQL procedure and an external procedure . . . . . . 598
Statements that you can include in a procedure body . . . . . . . . . 600

Contents xi
Declaring and using variables in an SQL procedure . . . . . . . . . . 601
Parameter style for an SQL procedure . . . . . . . . . . . . . . . 602
Terminating statements in an SQL procedure . . . . . . . . . . . . 602
Handling SQL conditions in an SQL procedure . . . . . . . . . . . . 603
Examples of SQL procedures . . . . . . . . . . . . . . . . . . 607
Preparing an SQL procedure . . . . . . . . . . . . . . . . . . 609
Writing and preparing an application to use stored procedures . . . . . . . 621
Forms of the CALL statement . . . . . . . . . . . . . . . . . . 621
Authorization for executing stored procedures . . . . . . . . . . . . 623
Linkage conventions . . . . . . . . . . . . . . . . . . . . . 623
Using indicator variables to speed processing . . . . . . . . . . . . 643
Declaring data types for passed parameters . . . . . . . . . . . . . 643
Writing a DB2 UDB for z/OS client program or SQL procedure to receive
result sets . . . . . . . . . . . . . . . . . . . . . . . . 648
Accessing transition tables in a stored procedure . . . . . . . . . . . 654
Calling a stored procedure from a REXX Procedure . . . . . . . . . . 654
Preparing a client program . . . . . . . . . . . . . . . . . . . 658
Running a stored procedure . . . . . . . . . . . . . . . . . . . 659
How DB2 determines which version of a stored procedure to run . . . . . 660
Using a single application program to call different versions of a stored
procedure . . . . . . . . . . . . . . . . . . . . . . . . 660
Running multiple stored procedures concurrently . . . . . . . . . . . 661
| Running multiple instances of a stored procedure concurrently . . . . . . 662
Accessing non-DB2 resources . . . . . . . . . . . . . . . . . . 663
Testing a stored procedure . . . . . . . . . . . . . . . . . . . . 664
Debugging the stored procedure as a stand-alone program on a workstation 664
Debugging with the Debug Tool and IBM VisualAge COBOL . . . . . . . 665
Debugging an SQL procedure or C language stored procedure with the
Debug Tool and C/C++ Productivity Tools for z/OS . . . . . . . . . 665
Debugging with Debug Tool for z/OS interactively and in batch mode . . . 666
Using the MSGFILE run-time option . . . . . . . . . . . . . . . . 668
Using driver applications . . . . . . . . . . . . . . . . . . . . 668
Using SQL INSERT statements . . . . . . . . . . . . . . . . . 669

Chapter 26. Tuning your queries . . . . . . . . . . . . . . . . . 671


General tips and questions . . . . . . . . . . . . . . . . . . . . 671
Is the query coded as simply as possible? . . . . . . . . . . . . . 671
Are all predicates coded correctly? . . . . . . . . . . . . . . . . 671
Are there subqueries in your query? . . . . . . . . . . . . . . . 672
Does your query involve aggregate functions? . . . . . . . . . . . . 673
Do you have an input variable in the predicate of an SQL query? . . . . . 674
Do you have a problem with column correlation? . . . . . . . . . . . 674
Can your query be written to use a noncolumn expression? . . . . . . . 674
| Can materialized query tables help your query performance? . . . . . . 674
| Does the query contain encrypted data? . . . . . . . . . . . . . . 675
Writing efficient predicates . . . . . . . . . . . . . . . . . . . . 675
Properties of predicates . . . . . . . . . . . . . . . . . . . . 675
Predicates in the ON clause . . . . . . . . . . . . . . . . . . 678
General rules about predicate evaluation . . . . . . . . . . . . . . . 679
Order of evaluating predicates . . . . . . . . . . . . . . . . . . 679
Summary of predicate processing . . . . . . . . . . . . . . . . 680
Examples of predicate properties . . . . . . . . . . . . . . . . . 684
Predicate filter factors . . . . . . . . . . . . . . . . . . . . . 685
Column correlation . . . . . . . . . . . . . . . . . . . . . . 691
DB2 predicate manipulation . . . . . . . . . . . . . . . . . . . 694
| Predicates with encrypted data . . . . . . . . . . . . . . . . . 698

xii Application Programming and SQL Guide


Using host variables efficiently . . . . . . . . . . . . . . . . . . . 698
| Changing the access path at run time . . . . . . . . . . . . . . . 699
Rewriting queries to influence access path selection. . . . . . . . . . 702
Writing efficient subqueries . . . . . . . . . . . . . . . . . . . . 705
Correlated subqueries . . . . . . . . . . . . . . . . . . . . . 705
Noncorrelated subqueries . . . . . . . . . . . . . . . . . . . 706
Subquery transformation into join . . . . . . . . . . . . . . . . . 707
Subquery tuning . . . . . . . . . . . . . . . . . . . . . . . 709
Using scrollable cursors efficiently . . . . . . . . . . . . . . . . . 710
| Writing efficient queries on tables with data-partitioned secondary indexes 711
Special techniques to influence access path selection . . . . . . . . . . 713
Obtaining information about access paths . . . . . . . . . . . . . 713
Fetching a limited number of rows: FETCH FIRST n ROWS ONLY . . . . 714
Minimizing overhead for retrieving few rows: OPTIMIZE FOR n ROWS 714
| Favoring index access . . . . . . . . . . . . . . . . . . . . . 717
| Using the CARDINALITY clause to improve the performance of queries with
| user-defined table function references . . . . . . . . . . . . . . 717
Reducing the number of matching columns . . . . . . . . . . . . . 718
Creating indexes for efficient star join processing . . . . . . . . . . . 720
Rearranging the order of tables in a FROM clause . . . . . . . . . . 723
Updating catalog statistics . . . . . . . . . . . . . . . . . . . 723
Using a subsystem parameter . . . . . . . . . . . . . . . . . . 724

Chapter 27. Using EXPLAIN to improve SQL performance . . . . . . . 727


Obtaining PLAN_TABLE information from EXPLAIN . . . . . . . . . . . 728
Creating PLAN_TABLE . . . . . . . . . . . . . . . . . . . . 728
Populating and maintaining a plan table . . . . . . . . . . . . . . 735
Reordering rows from a plan table . . . . . . . . . . . . . . . . 736
Asking questions about data access . . . . . . . . . . . . . . . . 737
Is access through an index? (ACCESSTYPE is I, I1, N or MX) . . . . . . 737
Is access through more than one index? (ACCESSTYPE=M) . . . . . . 737
How many columns of the index are used in matching? (MATCHCOLS=n) 738
Is the query satisfied using only the index? (INDEXONLY=Y) . . . . . . 739
Is direct row access possible? (PRIMARY_ACCESSTYPE = D) . . . . . 739
Is a view or nested table expression materialized? . . . . . . . . . . 743
Was a scan limited to certain partitions? (PAGE_RANGE=Y) . . . . . . 743
What kind of prefetching is expected? (PREFETCH = L, S, D, or blank) 744
Is data accessed or processed in parallel? (PARALLELISM_MODE is I, C,
or X) . . . . . . . . . . . . . . . . . . . . . . . . . . 744
Are sorts performed? . . . . . . . . . . . . . . . . . . . . . 744
Is a subquery transformed into a join? . . . . . . . . . . . . . . . 745
When are aggregate functions evaluated? (COLUMN_FN_EVAL) . . . . . 745
| How many index screening columns are used? . . . . . . . . . . . 745
| Is a complex trigger WHEN clause used? (QBLOCKTYPE=TRIGGR) . . . 746
Interpreting access to a single table . . . . . . . . . . . . . . . . . 746
Table space scans (ACCESSTYPE=R PREFETCH=S) . . . . . . . . . 746
Index access paths . . . . . . . . . . . . . . . . . . . . . . 747
UPDATE using an index . . . . . . . . . . . . . . . . . . . . 752
Interpreting access to two or more tables (join) . . . . . . . . . . . . 752
Definitions and examples of join operations . . . . . . . . . . . . . 752
Nested loop join (METHOD=1) . . . . . . . . . . . . . . . . . 755
Merge scan join (METHOD=2) . . . . . . . . . . . . . . . . . . 757
Hybrid join (METHOD=4) . . . . . . . . . . . . . . . . . . . . 758
Star join (JOIN_TYPE=’S’) . . . . . . . . . . . . . . . . . . . 760
Interpreting data prefetch. . . . . . . . . . . . . . . . . . . . . 767
Sequential prefetch (PREFETCH=S) . . . . . . . . . . . . . . . 767

Contents xiii
| Dynamic prefetch (PREFETCH=D) . . . . . . . . . . . . . . . . 768
List prefetch (PREFETCH=L) . . . . . . . . . . . . . . . . . . 768
Sequential detection at execution time . . . . . . . . . . . . . . . 769
Determining sort activity . . . . . . . . . . . . . . . . . . . . . 771
Sorts of data . . . . . . . . . . . . . . . . . . . . . . . . 771
Sorts of RIDs . . . . . . . . . . . . . . . . . . . . . . . . 772
The effect of sorts on OPEN CURSOR . . . . . . . . . . . . . . 772
Processing for views and nested table expressions . . . . . . . . . . . 773
Merge . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
Materialization . . . . . . . . . . . . . . . . . . . . . . . . 774
Using EXPLAIN to determine when materialization occurs . . . . . . . 776
Using EXPLAIN to determine UNION activity and query rewrite . . . . . 777
Performance of merge versus materialization . . . . . . . . . . . . 778
Estimating a statement’s cost . . . . . . . . . . . . . . . . . . . 779
Creating a statement table . . . . . . . . . . . . . . . . . . . 780
Populating and maintaining a statement table . . . . . . . . . . . . 782
Retrieving rows from a statement table . . . . . . . . . . . . . . 782
Understanding the implications of cost categories . . . . . . . . . . . 782

Chapter 28. Parallel operations and query performance . . . . . . . . 785


Comparing the methods of parallelism . . . . . . . . . . . . . . . . 785
Enabling parallel processing . . . . . . . . . . . . . . . . . . . 788
When parallelism is not used . . . . . . . . . . . . . . . . . . . 789
Interpreting EXPLAIN output . . . . . . . . . . . . . . . . . . . 790
A method for examining PLAN_TABLE columns for parallelism . . . . . . 790
PLAN_TABLE examples showing parallelism . . . . . . . . . . . . 790
Tuning parallel processing . . . . . . . . . . . . . . . . . . . . 792
Disabling query parallelism . . . . . . . . . . . . . . . . . . . . 793

Chapter 29. Programming for the Interactive System Productivity Facility


(ISPF) . . . . . . . . . . . . . . . . . . . . . . . . . . . 795
Using ISPF and the DSN command processor . . . . . . . . . . . . . 795
Invoking a single SQL program through ISPF and DSN . . . . . . . . . 796
Invoking multiple SQL programs through ISPF and DSN . . . . . . . . . 797
Invoking multiple SQL programs through ISPF and CAF . . . . . . . . . 797

Chapter 30. Programming for the call attachment facility (CAF) . . . . . 799
Call attachment facility capabilities and restrictions . . . . . . . . . . . 799
Capabilities when using CAF . . . . . . . . . . . . . . . . . . 799
CAF requirements . . . . . . . . . . . . . . . . . . . . . . 800
How to use CAF . . . . . . . . . . . . . . . . . . . . . . . . 802
Summary of connection functions . . . . . . . . . . . . . . . . 804
Accessing the CAF language interface . . . . . . . . . . . . . . . 805
General properties of CAF connections . . . . . . . . . . . . . . 806
CAF function descriptions . . . . . . . . . . . . . . . . . . . 807
CONNECT: Syntax and usage . . . . . . . . . . . . . . . . . . 809
OPEN: Syntax and usage . . . . . . . . . . . . . . . . . . . 813
CLOSE: Syntax and usage . . . . . . . . . . . . . . . . . . . 815
DISCONNECT: Syntax and usage . . . . . . . . . . . . . . . . 816
TRANSLATE: Syntax and usage . . . . . . . . . . . . . . . . . 818
Summary of CAF behavior . . . . . . . . . . . . . . . . . . . 819
Sample scenarios . . . . . . . . . . . . . . . . . . . . . . . 820
A single task with implicit connections . . . . . . . . . . . . . . . 820
A single task with explicit connections . . . . . . . . . . . . . . . 821
Several tasks . . . . . . . . . . . . . . . . . . . . . . . . 821
Exit routines from your application . . . . . . . . . . . . . . . . . 821

xiv Application Programming and SQL Guide


Attention exit routines . . . . . . . . . . . . . . . . . . . . . 821
Recovery routines . . . . . . . . . . . . . . . . . . . . . . 822
Error messages and dsntrace . . . . . . . . . . . . . . . . . . . 822
CAF return codes and reason codes . . . . . . . . . . . . . . . . 822
Subsystem support subcomponent codes (X’00F3’) . . . . . . . . . . 823
Program examples . . . . . . . . . . . . . . . . . . . . . . . 823
Sample JCL for using CAF . . . . . . . . . . . . . . . . . . . 823
Sample assembler code for using CAF . . . . . . . . . . . . . . 824
Loading and deleting the CAF language interface . . . . . . . . . . . 824
Establishing the connection to DB2 . . . . . . . . . . . . . . . . 824
Checking return codes and reason codes. . . . . . . . . . . . . . 826
Using dummy entry point DSNHLI . . . . . . . . . . . . . . . . 828
Variable declarations . . . . . . . . . . . . . . . . . . . . . 829

Chapter 31. Programming for the Resource Recovery Services


attachment facility (RRSAF) . . . . . . . . . . . . . . . . . . 831
RRSAF capabilities and restrictions . . . . . . . . . . . . . . . . . 831
Capabilities of RRSAF applications . . . . . . . . . . . . . . . . 831
RRSAF requirements . . . . . . . . . . . . . . . . . . . . . 832
How to use RRSAF . . . . . . . . . . . . . . . . . . . . . . . 834
Summary of connection functions . . . . . . . . . . . . . . . . 834
| Implicit connections . . . . . . . . . . . . . . . . . . . . . . 835
Accessing the RRSAF language interface . . . . . . . . . . . . . 836
General properties of RRSAF connections . . . . . . . . . . . . . 838
RRSAF function descriptions . . . . . . . . . . . . . . . . . . 840
Summary of RRSAF behavior . . . . . . . . . . . . . . . . . . 865
Sample scenarios . . . . . . . . . . . . . . . . . . . . . . . 867
A single task . . . . . . . . . . . . . . . . . . . . . . . . 867
Multiple tasks . . . . . . . . . . . . . . . . . . . . . . . . 867
Calling SIGNON to reuse a DB2 thread . . . . . . . . . . . . . . 867
Switching DB2 threads between tasks . . . . . . . . . . . . . . . 867
RRSAF return codes and reason codes . . . . . . . . . . . . . . . 868
Program examples . . . . . . . . . . . . . . . . . . . . . . . 869
Sample JCL for using RRSAF . . . . . . . . . . . . . . . . . . 869
Loading and deleting the RRSAF language interface . . . . . . . . . 869
Using dummy entry point DSNHLI . . . . . . . . . . . . . . . . 869
Establishing a connection to DB2. . . . . . . . . . . . . . . . . 870

Chapter 32. Programming considerations for CICS . . . . . . . . . . 873


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

| Chapter 33. Using WebSphere MQ functions from DB2 applications . . . 875


| Introduction to WebSphere MQ message handling and the AMI . . . . . . 875
| Messages . . . . . . . . . . . . . . . . . . . . . . . . . 875
| Services . . . . . . . . . . . . . . . . . . . . . . . . . . 876
| Policies . . . . . . . . . . . . . . . . . . . . . . . . . . 876
| Capabilities of WebSphere MQ functions . . . . . . . . . . . . . . . 876
| Commit environment for WebSphere MQ functions . . . . . . . . . . . 878
| Single-phase commit . . . . . . . . . . . . . . . . . . . . . 878
| Two-phase commit . . . . . . . . . . . . . . . . . . . . . . 879
| How to use WebSphere MQ functions . . . . . . . . . . . . . . . . 879
| Basic messaging . . . . . . . . . . . . . . . . . . . . . . . 879
| Sending messages . . . . . . . . . . . . . . . . . . . . . . 880
| Retrieving messages . . . . . . . . . . . . . . . . . . . . . 881

Contents xv
| Application-to-application connectivity . . . . . . . . . . . . . . . 882

Chapter 34. Programming techniques: Questions and answers . . . . . 887


Providing a unique key for a table . . . . . . . . . . . . . . . . . 887
Scrolling through previously retrieved data . . . . . . . . . . . . . . 887
Using a scrollable cursor . . . . . . . . . . . . . . . . . . . . 887
Using a ROWID or identity column . . . . . . . . . . . . . . . . 888
Scrolling through a table in any direction . . . . . . . . . . . . . . . 889
Updating data as it is retrieved from the database . . . . . . . . . . . 890
Updating previously retrieved data . . . . . . . . . . . . . . . . . 890
Updating thousands of rows . . . . . . . . . . . . . . . . . . . 890
Retrieving thousands of rows . . . . . . . . . . . . . . . . . . . 891
Using SELECT * . . . . . . . . . . . . . . . . . . . . . . . . 891
Optimizing retrieval for a small set of rows . . . . . . . . . . . . . . 891
Adding data to the end of a table . . . . . . . . . . . . . . . . . . 892
Translating requests from end users into SQL statements . . . . . . . . . 892
Changing the table definition . . . . . . . . . . . . . . . . . . . 892
Storing data that does not have a tabular format . . . . . . . . . . . . 893
Finding a violated referential or check constraint . . . . . . . . . . . . 893

Part 7. Appendixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 895

Appendix A. DB2 sample tables . . . . . . . . . . . . . . . . . 897


Activity table (DSN8810.ACT) . . . . . . . . . . . . . . . . . . . 897
Department table (DSN8810.DEPT) . . . . . . . . . . . . . . . . . 898
Employee table (DSN8810.EMP) . . . . . . . . . . . . . . . . . . 899
Employee photo and resume table (DSN8810.EMP_PHOTO_RESUME) . . . 902
Project table (DSN8810.PROJ) . . . . . . . . . . . . . . . . . . 904
Project activity table (DSN8810.PROJACT) . . . . . . . . . . . . . . 905
Employee to project activity table (DSN8810.EMPPROJACT) . . . . . . . 906
| Unicode sample table (DSN8810.DEMO_UNICODE) . . . . . . . . . . 907
Relationships among the sample tables . . . . . . . . . . . . . . . 907
Views on the sample tables . . . . . . . . . . . . . . . . . . . . 908
Storage of sample application tables . . . . . . . . . . . . . . . . 911
Storage group . . . . . . . . . . . . . . . . . . . . . . . . 912
Databases . . . . . . . . . . . . . . . . . . . . . . . . . 912
Table spaces . . . . . . . . . . . . . . . . . . . . . . . . 913

Appendix B. Sample applications . . . . . . . . . . . . . . . . . 915


Types of sample applications . . . . . . . . . . . . . . . . . . . 915
Using the applications . . . . . . . . . . . . . . . . . . . . . . 917
TSO . . . . . . . . . . . . . . . . . . . . . . . . . . . 918
IMS . . . . . . . . . . . . . . . . . . . . . . . . . . . 920
CICS . . . . . . . . . . . . . . . . . . . . . . . . . . . 920

Appendix C. Running the productivity-aid sample programs . . . . . . 921


Running DSNTIAUL . . . . . . . . . . . . . . . . . . . . . . 922
Running DSNTIAD . . . . . . . . . . . . . . . . . . . . . . . 926
Running DSNTEP2 and DSNTEP4 . . . . . . . . . . . . . . . . . 927

Appendix D. Programming examples . . . . . . . . . . . . . . . 931


Sample COBOL dynamic SQL program . . . . . . . . . . . . . . . 931
Pointers and based variables . . . . . . . . . . . . . . . . . . 931
Storage allocation . . . . . . . . . . . . . . . . . . . . . . 931
Example . . . . . . . . . . . . . . . . . . . . . . . . . . 932
Sample dynamic and static SQL in a C program . . . . . . . . . . . . 944

xvi Application Programming and SQL Guide


Sample DB2 REXX application . . . . . . . . . . . . . . . . . . 947
Sample COBOL program using DRDA access . . . . . . . . . . . . . 961
Sample COBOL program using DB2 private protocol access . . . . . . . 969
Examples of using stored procedures . . . . . . . . . . . . . . . . 975
Calling a stored procedure from a C program . . . . . . . . . . . . 976
Calling a stored procedure from a COBOL program . . . . . . . . . . 979
Calling a stored procedure from a PL/I program . . . . . . . . . . . 982
C stored procedure: GENERAL . . . . . . . . . . . . . . . . . 983
C stored procedure: GENERAL WITH NULLS . . . . . . . . . . . . 986
COBOL stored procedure: GENERAL . . . . . . . . . . . . . . . 988
COBOL stored procedure: GENERAL WITH NULLS . . . . . . . . . . 991
PL/I stored procedure: GENERAL . . . . . . . . . . . . . . . . 993
PL/I stored procedure: GENERAL WITH NULLS . . . . . . . . . . . 994

| Appendix E. Recursive common table expression examples . . . . . . 997

Appendix F. REBIND subcommands for lists of plans or packages 1003


Overview of the procedure for generating lists of REBIND commands . . . . 1003
Sample SELECT statements for generating REBIND commands . . . . . . 1003
Sample JCL for running lists of REBIND commands . . . . . . . . . . 1006

Appendix G. SQL reserved words . . . . . . . . . . . . . . . . 1009

Appendix H. Characteristics of SQL statements in DB2 UDB for z/OS 1013


Actions allowed on SQL statements . . . . . . . . . . . . . . . . 1013
SQL statements allowed in external functions and stored procedures . . . . 1016
SQL statements allowed in SQL procedures . . . . . . . . . . . . . 1018

Appendix I. Program preparation options for remote packages . . . . . 1023

Appendix J. DB2-supplied stored procedures . . . . . . . . . . . 1025


WLM environment refresh stored procedure (WLM_REFRESH) . . . . . . 1025
Environment for WLM_REFRESH . . . . . . . . . . . . . . . . 1025
Authorization required for WLM_REFRESH . . . . . . . . . . . . 1026
WLM_REFRESH syntax diagram . . . . . . . . . . . . . . . . 1026
WLM_REFRESH option descriptions . . . . . . . . . . . . . . . 1026
Example of WLM_REFRESH invocation . . . . . . . . . . . . . . 1027
WLM_REFRESH option descriptions . . . . . . . . . . . . . . . 1028
Example of WLM_REFRESH invocation . . . . . . . . . . . . . . 1028
The CICS transaction invocation stored procedure (DSNACICS) . . . . . . 1029
Environment for DSNACICS . . . . . . . . . . . . . . . . . . 1029
Authorization required for DSNACICS . . . . . . . . . . . . . . 1029
DSNACICS syntax diagram . . . . . . . . . . . . . . . . . . 1029
DSNACICS option descriptions . . . . . . . . . . . . . . . . . 1030
DSNACICX user exit . . . . . . . . . . . . . . . . . . . . . 1032
Example of DSNACICS invocation . . . . . . . . . . . . . . . . 1034
DSNACICS output . . . . . . . . . . . . . . . . . . . . . . 1035
DSNACICS restrictions . . . . . . . . . . . . . . . . . . . . 1036
DSNACICS debugging . . . . . . . . . . . . . . . . . . . . 1036

Notices . . . . . . . . . . . . . . . . . . . . . . . . . . 1037
Programming interface information . . . . . . . . . . . . . . . . . 1038
Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . 1039

Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . 1041

Contents xvii
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . 1075

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

xviii Application Programming and SQL Guide


About this book
This book discusses how to design and write application programs that access DB2
Universal Database for z/OS (DB2), a highly flexible relational database
management system (DBMS).

Important
In this version of DB2 UDB for z/OS, the DB2 Utilities Suite is available as an
optional product. You must separately order and purchase a license to such
utilities, and discussion of those utility functions in this publication is not
intended to otherwise imply that you have a license to them. See Part 1 of
DB2 Utility Guide and Reference for packaging details.

Visit the following Web site for information about ordering DB2 books and obtaining
other valuable information about DB2 UDB for z/OS:
www.ibm.com/software/data/db2/zos/library.html

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.

Terminology and citations


In this information, DB2 Universal Database™ for z/OS™ is referred to as "DB2 UDB
for z/OS." In cases where the context makes the meaning clear, DB2 UDB for z/OS
is referred to as "DB2®." When this information refers to titles of books in this
library, a short title is used. (For example, "See DB2 SQL Reference" is a citation to
IBM® DB2 Universal Database for z/OS SQL Reference.)

When referring to a DB2 product other than DB2 UDB for z/OS, this information
uses the product’s full name to avoid ambiguity.

The following terms are used as indicated:


DB2 Represents either the DB2 licensed program or a particular DB2
subsystem.
DB2 PM
Refers to the DB2 Performance Monitor tool, which can be used on its own
or as part of the DB2 Performance Expert for z/OS product.
C, C++, and C language
Represent the C or C++ programming language.
CICS® Represents CICS Transaction Server for z/OS or CICS Transaction Server
for OS/390®.
IMS™ Represents the IMS Database Manager or IMS Transaction Manager.

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

© Copyright IBM Corp. 1983, 2004 xix


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

How to read the syntax diagrams


The following rules apply to the syntax diagrams that are used in this book:
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.

Accessibility
Accessibility features help a user who has a physical disability, such as restricted
mobility or limited vision, to use software products. The major accessibility features
in z/OS products, including DB2 UDB for z/OS, enable users to:
v Use assistive technologies such as screen reader and screen magnifier software
v Operate specific or equivalent features by using only a keyboard
v Customize display attributes such as color, contrast, and font size

Assistive technology products, such as screen readers, function with the DB2 UDB
for z/OS user interfaces. Consult the documentation for the assistive technology
products for specific information when you use assistive technology to access these
interfaces.

Online documentation for Version 8 of DB2 UDB for z/OS is available in the DB2
Information Center, which is an accessible format when used with assistive
technologies such as screen reader or screen magnifier software. The DB2
Information Center for z/OS solutions is available at the following Web site:
http://publib.boulder.ibm.com/infocenter/db2zhelp.

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 UDB for z/OS documentation. You can
use 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 You can also send comments from the Web. Visit the library Web site at:

www.ibm.com/software/db2zos/library.html

This Web site has a feedback page that you can use to send comments.

About this book xxi


v Print and fill out the reader comment form located at the back of this book. You
can give the completed form to your local IBM branch office or IBM
representative, or you can send it to the address printed on the reader comment
form.

xxii Application Programming and SQL Guide


Summary of changes to this book
| The principal changes to this book are:
| v Chapter 1, “Retrieving data,” on page 3 explains how to create and use common
| table expressions in SELECT, CREATE VIEW, and INSERT statements, and also
| describes how to use common table expressions to create recursive SQL.
| v Chapter 2, “Working with tables and modifying data,” on page 19 explains how to
| select column values as you insert rows into a table by using the SELECT from
| INSERT statement.
| v Chapter 6, “Basics of coding SQL in an application program,” on page 69
| contains information on how to use:
| – Host variable arrays, and their indicator arrays, in a multiple-row INSERT
| statement (in a C or C++, COBOL, or PL/I program).
| – The GET DIAGNOSTICS statement to return diagnostic information about the
| last SQL statement that was executed (for example, information about input
| data errors during the execution of a multiple-row INSERT statement).
| v Chapter 7, “Using a cursor to retrieve a set of rows,” on page 93 explains how to
| use:
| – Static and dynamic scrollable cursors.
| – A rowset-positioned cursor in a multiple-row FETCH statement (in a C or C++,
| COBOL, or PL/I program).
| – Positioned updates and deletes with a rowset-positioned cursor.
| v Chapter 9, “Embedding SQL statements in host languages,” on page 129
| contains information on how to declare host variable arrays (for C or C++,
| COBOL, and PL/I) for use with multiple-row INSERT and FETCH statements.
| v Chapter 10, “Using constraints to maintain data integrity,” on page 243 describes
| informational referential constraints (not enforced by DB2), describes referential
| constraints on tables with multi-level security with row-level granularity, and
| explains how to maintain referential integrity when using data encryption.
| v Chapter 11, “Using DB2-generated values as keys,” on page 253 is a new
| chapter that describes the use of ROWID columns for direct row access, identity
| columns as parent keys and foreign keys, and values generated from sequence
| objects as keys across multiple tables.
| v Chapter 12, “Using triggers for active data,” on page 261 describes interactions
| between triggers and tables that use multi-level security with row-level
| granularity.
| v Chapter 21, “Preparing an application program to run,” on page 453 describes
| the new SQL processing options:
| – CCSID, which specifies the CCSID in which the source program is written.
| – NEWFUN, which indicates whether to accept the syntax for DB2 Version 8
| new functions.
| – For C programs, PADNSTR or NOPADNSTR, which indicates whether or not
| output host variables that are NUL-terminated strings are padded with blanks.
| This chapter also describes how the CURRENT PACKAGE PATH special register
| is used in identifying the collection for packages at run time.
| v Chapter 24, “Coding dynamic SQL in application programs,” on page 535
| describes how to use a descriptor when you prepare and execute a multiple-row
| INSERT statement. This chapter also includes information about how bind option
| REOPT(ONCE) affects dynamic SQL statements.

© Copyright IBM Corp. 1983, 2004 xxiii


| v Chapter 25, “Using stored procedures for client/server processing,” on page 569
| describes how to invoke DSNTPSMP (the SQL Procedure Processor that
| prepares SQL procedures for execution) with the SQL CALL statement. This
| chapter also describes new SQL procedure statements and describes how to run
| multiple instances of the same stored procedure at the same time.
| v Chapter 31, “Programming for the Resource Recovery Services attachment
| facility (RRSAF),” on page 831 contains information about using implicit
| connections to DB2 when applications include SQL statements.
| v Chapter 33, “Using WebSphere MQ functions from DB2 applications,” on page
| 875 is a new chapter that describes how to use DB2 WebSphere® MQ functions
| in SQL statements to combine DB2 database access with WebSphere MQ
| message handling.
| v Appendix E, “Recursive common table expression examples,” on page 997 is a
| new appendix that includes examples of using common table expressions to
| create recursive SQL in a bill of materials application.

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 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 . . . . . . . . . . . . . . . . . . . . . 10
Referencing derived columns. . . . . . . . . . . . . . . . . . . 10
Summarizing group values: GROUP BY . . . . . . . . . . . . . . . . 11
Subjecting groups to conditions: HAVING . . . . . . . . . . . . . . . 12
Merging lists of values: UNION . . . . . . . . . . . . . . . . . . . 13
Using UNION to eliminate duplicates . . . . . . . . . . . . . . . . 13
Using UNION ALL to keep duplicates. . . . . . . . . . . . . . . . 13
| Creating common table expressions: WITH . . . . . . . . . . . . . . 14
| Using WITH instead of CREATE VIEW: . . . . . . . . . . . . . . . 14
| Using common table expressions with CREATE VIEW: . . . . . . . . . 15
| Using common table expressions when you use INSERT: . . . . . . . . 15
| Using recursive SQL . . . . . . . . . . . . . . . . . . . . . . 15
Accessing DB2 data that is not in a table . . . . . . . . . . . . . . . 16
Using 15-digit and 31-digit precision for decimal numbers . . . . . . . . . 16
Finding information in the DB2 catalog . . . . . . . . . . . . . . . . 18
Displaying a list of tables you can use . . . . . . . . . . . . . . . 18
Displaying a list of columns in a table . . . . . . . . . . . . . . . 18

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


Working with tables . . . . . . . . . . . . . . . . . . . . . . . 19
Creating your own tables: CREATE TABLE . . . . . . . . . . . . . 19
Identifying defaults . . . . . . . . . . . . . . . . . . . . . 19
Creating work tables . . . . . . . . . . . . . . . . . . . . . 20
Creating a new department table . . . . . . . . . . . . . . . . 20
Creating a new employee table . . . . . . . . . . . . . . . . . 21
Working with temporary tables . . . . . . . . . . . . . . . . . . 21
Working with created temporary tables . . . . . . . . . . . . . . 22
Working with declared temporary tables . . . . . . . . . . . . . . 23
Dropping tables: DROP TABLE . . . . . . . . . . . . . . . . . . 25
Working with views . . . . . . . . . . . . . . . . . . . . . . . 25
Defining a view: CREATE VIEW . . . . . . . . . . . . . . . . . 25
Changing data through a view . . . . . . . . . . . . . . . . . . 26
Dropping views: DROP VIEW . . . . . . . . . . . . . . . . . . 27
Modifying DB2 data . . . . . . . . . . . . . . . . . . . . . . . 27
Inserting rows: INSERT . . . . . . . . . . . . . . . . . . . . . 27
Inserting a single row . . . . . . . . . . . . . . . . . . . . 28
Inserting rows into a table from another table . . . . . . . . . . . . 29
Other ways to insert data . . . . . . . . . . . . . . . . . . . 29
Inserting data into a ROWID column . . . . . . . . . . . . . . . 30
Inserting data into an identity column . . . . . . . . . . . . . . . 30
| Selecting values as you insert: SELECT from INSERT . . . . . . . . . 31
| Result table of the INSERT operation . . . . . . . . . . . . . . 32

© Copyright IBM Corp. 1983, 2004 1


| Selecting values when you insert a single row . . . . . . . . . . . 32
| Selecting values when you insert data into a view . . . . . . . . . . 33
| Selecting values when you insert multiple rows . . . . . . . . . . . 33
| Result table of the cursor when you insert multiple rows . . . . . . . . 34
| What happens if an error occurs . . . . . . . . . . . . . . . . 35
Updating current values: UPDATE . . . . . . . . . . . . . . . . . 36
Deleting rows: DELETE . . . . . . . . . . . . . . . . . . . . . 37
Deleting every row in a table . . . . . . . . . . . . . . . . . . 38

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


Inner join . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Full outer join . . . . . . . . . . . . . . . . . . . . . . . . . 41
Left outer join . . . . . . . . . . . . . . . . . . . . . . . . . 42
Right outer join . . . . . . . . . . . . . . . . . . . . . . . . . 43
SQL rules for statements containing join operations . . . . . . . . . . . 44
Using more than one join in an SQL statement . . . . . . . . . . . . . 45
Using nested table expressions and user-defined table functions in joins . . . 46
Using correlated references in table specifications in joins . . . . . . . . . 47

Chapter 4. Using subqueries . . . . . . . . . . . . . . . . . . . 49


Conceptual overview . . . . . . . . . . . . . . . . . . . . . . . 49
Correlated and uncorrelated subqueries . . . . . . . . . . . . . . . 50
Subqueries and predicates . . . . . . . . . . . . . . . . . . . 50
The subquery result table . . . . . . . . . . . . . . . . . . . . 50
Tables in subqueries of UPDATE, DELETE, and INSERT statements . . . . 51
How to code a subquery . . . . . . . . . . . . . . . . . . . . . 51
Basic predicate . . . . . . . . . . . . . . . . . . . . . . . . 51
Quantified predicate : ALL, ANY, or SOME . . . . . . . . . . . . . . 51
Using the ALL predicate . . . . . . . . . . . . . . . . . . . 51
Using the ANY or SOME predicate . . . . . . . . . . . . . . . 52
IN keyword . . . . . . . . . . . . . . . . . . . . . . . . . 52
EXISTS keyword . . . . . . . . . . . . . . . . . . . . . . . 52
Using correlated subqueries . . . . . . . . . . . . . . . . . . . . 53
An example of a correlated subquery . . . . . . . . . . . . . . . . 53
Using correlation names in references . . . . . . . . . . . . . . . 54
Using correlated subqueries in an UPDATE statement . . . . . . . . . 55
Using correlated subqueries in a DELETE statement . . . . . . . . . . 55
Using tables with no referential constraints. . . . . . . . . . . . . 55
Using a single table . . . . . . . . . . . . . . . . . . . . . 56
Using tables with referential constraints . . . . . . . . . . . . . . 56

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


Allocating an input data set and using SPUFI . . . . . . . . . . . . . . 59
Changing SPUFI defaults (optional) . . . . . . . . . . . . . . . . . 60
Entering SQL statements . . . . . . . . . . . . . . . . . . . . . 60
Using the ISPF editor . . . . . . . . . . . . . . . . . . . . . 60
| Retrieving Unicode UTF-16 graphic data . . . . . . . . . . . . . . 61
Entering comments . . . . . . . . . . . . . . . . . . . . . . 62
Setting the SQL terminator character . . . . . . . . . . . . . . . . 62
Processing SQL statements . . . . . . . . . . . . . . . . . . . . 62
Browsing the output . . . . . . . . . . . . . . . . . . . . . . . 63
Format of SELECT statement results . . . . . . . . . . . . . . . . 64
Content of the messages . . . . . . . . . . . . . . . . . . . . 64

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 interactively use SELECT statements to retrieve data
from DB2 tables.

For more advanced topics on using SELECT statements, see Chapter 4, “Using
subqueries,” on page 49, and Chapter 20, “Planning to access distributed data,” on
page 423.

Examples of SQL statements illustrate the concepts that this chapter discusses.
Consider developing SQL statements similar to these examples and then running
them dynamically using SPUFI or DB2 Query Management Facility (DB2 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: The following 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 DSN8810.EMP
WHERE WORKDEPT = ’D11’
ORDER BY LASTNAME;

The result table looks similar to the following output:


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 6432
WALKER JAMES 2986
YAMAMOTO KIYOSHI 2890
YOSHIMURA MASATOSHI 2890

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 about distinct types, see Chapter 16, “Creating
and using distinct types,” on page 349. The data type of a column determines what
you can and cannot do with the column. When you perform operations on columns,
the data must be compatible with the data type of the referenced column. For
example, you cannot insert character data, like a last name, into a column whose
data type is numeric. Similarly, you cannot compare columns containing
incompatible data types.

To better understand the concepts that are presented in this chapter, you must
understand the data types of the columns to which an example refers. As shown in
© Copyright IBM Corp. 1983, 2004 3
Figure 1, built-in data types have four general categories: datetime, string, numeric,
and row identifier (ROWID).

Figure 1. DB2 data types

For more detailed information about 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,
Y (Yes), or incompatible, N (No). Numbers in the table, either as superscript of Y or
N, or as a value in the column, indicates a note at the bottom of the table.

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.
Binary Decimal Floating Character Graphic Binary Time- Row Distinct
Operands integer number point string string string Date Time stamp ID type
Binary Integer Y Y Y N N N N N N N 2
Decimal Y Y Y N N N N N N N 2
Number
Floating Point Y Y Y N N N N N N N 2
4,5 3
Character N N N Y Y N 1 1 1 N 2
String
Graphic String N N N Y4,5 Y N 1,4 1,4 1,4 N 2
3
Binary String N N N N N Y N N N N 2
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
Timestamp N N N 1 1,4 N N N Y N 2
Row ID N N N N N N N N N Y 2
Distinct Type 2 2 2 2 2 2 2 2 2 2 Y2
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. On assignment and comparison from Graphic to Character, the resulting length in bytes is 3 * (LENGTH(graphic
string)), depending on the CCSIDs.
5. Character strings with subtype FOR BIT DATA are not compatible with 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 all columns of each
selected row of the named table.

Example: SELECT *: The following SQL statement selects all columns from the
department table:
SELECT *
FROM DSN8810.DEPT;

The result table looks similar to the following output:

Chapter 1. Retrieving data 5


DEPTNO DEPTNAME MGRNO ADMRDEPT LOCATION
====== ============================== ====== ======== ========
A00 SPIFFY COMPUTER SERVICES DIV. 000010 A00 --------
B01 PLANNING 000020 A00 --------
C01 INFORMATION CENTER 000030 A00 --------
D01 DEVELOPMENT CENTER ------ A00 --------
D11 MANUFACTURING CENTER 000060 D01 --------
D21 ADMINSTRATION 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 about host variables, see “Accessing data using host variables, variable
arrays, and structures” on page 71.

If you list the column names in a static SELECT statement instead of using an
asterisk, you can avoid the problem created by using SELECT *. 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 to retrieve by naming each column. All
columns appear in the order you specify, not in their order in the table.

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

The result table looks similar to the following output:


MGRNO DEPTNO
====== ======
000010 A00
000020 B01
000030 C01
------ D01
000050 E01
000060 D11
000070 D21
000090 E11
000100 E21
------ F22
------ G22
------ H22
------ I22
------ J22

6 Application Programming and SQL Guide


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

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 DSN8810.EMP;

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


have names. You can use the AS clause to give a name to an unnamed column of
the result table. For information about using the AS clause, see “Naming result
columns: AS.”

To order the rows in a result table by the values in a derived column, specify a
name for the column by using the AS clause, and specify that name in the ORDER
BY clause. For information about using the ORDER BY clause, see “Putting the
rows in order: ORDER BY” on page 9.

Eliminating duplicate rows: DISTINCT


The DISTINCT keyword removes duplicate rows from your result table, 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 DSN8810.DEPT;

The result table looks similar to the following output:


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

Naming result columns: AS


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

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

Example: SELECT with AS CLAUSE: The following example of the SELECT


statement gives the expression SALARY+BONUS+COMM the name TOTAL_SAL.
SELECT SALARY+BONUS+COMM AS TOTAL_SAL
FROM DSN8810.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

Chapter 1. Retrieving data 7


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 DSN8810.EMP;

| For more information about using the CREATE VIEW statement, see “Defining a
| view: CREATE VIEW” on page 25.

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, which is similar to the following partial output:
STATUS PARTNO TOTAL_VALUE
======= ====== ===========
On hand 00557 345.60
Ordered 00557 150.50
.
.
.

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

Example: GROUP BY derived column: You can 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. 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 DSN8810.EMP) AS NEWEMP
GROUP BY HIREYEAR;

You cannot use GROUP BY with a name that is defined with an AS clause for the
derived column YEAR(HIREDATE) in the outer SELECT, because that name does
not exist when the GROUP BY runs. However, you can use GROUP BY with a
name that is defined with an AS clause in the nested table expression, because the
| nested table expression runs before the GROUP BY that references the name. For
| more information about using the GROUP BY clause, see “Summarizing group
| values: GROUP BY” on page 11.

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.

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

8 Application Programming and SQL Guide


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 16, “Creating and using distinct types,” on page
349 for more information about distinct types.

Table 2 lists the type of comparison, the comparison operators, and an example of
how each type of comparison that you can use in a predicate in a WHERE clause.
Table 2. Comparison operators used in conditions
Type of comparison Comparison operator Example
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
Equal to null IS NULL PHONENO IS NULL
| Not equal to or one IS DISTINCT FROM PHONENO IS DISTINCT FROM
| value is equal to null :PHONEHV
Similar to another value LIKE NAME LIKE ’%SMITH%’ or STATUS
LIKE ’N_’
At least one of two OR HIREDATE < ’1965-01-01’ OR SALARY
conditions < 16000
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’)
Note: SALARY BETWEEN 20000 AND 40000 is equivalent to SALARY >= 20000 AND
SALARY <= 40000. For more information about predicates, see Chapter 2 of DB2 SQL
Reference.

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

| You can search for rows that do not satisfy the IS DISTINCT FROM predicate by
| using either of the following predicates:
| v value IS NOT DISTINCT FROM value
| v NOT(value IS DISTINCT FROM value)
| Both of these forms of the predicate create an expression where one value is equal
| to another value or both values are equal to null.

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.

Chapter 1. Retrieving data 9


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.

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 DSN8810.EMP
WHERE WORKDEPT = ’A00’
ORDER BY HIREDATE ASC;

The result table looks similar to the following output:


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: The following
subselect retrieves the employee numbers, salaries, commissions, and total
compensation (salary plus commission) for employees with a total compensation
greater than 40000. Order the results by total compensation:
SELECT EMPNO, SALARY, COMM, SALARY+COMM AS "TOTAL COMP"
FROM DSN8810.EMP
WHERE SALARY+COMM > 40000
ORDER BY SALARY+COMM;

The intermediate result table looks similar to the following output:


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.

Example: ORDER BY clause using a derived column name: The following SQL
statement orders the selected information by total salary:
SELECT EMPNO, (SALARY + BONUS + COMM) AS TOTAL_SAL
FROM DSN8810.EMP
ORDER BY TOTAL_SAL;

10 Application Programming and SQL Guide


Summarizing group values: GROUP BY
| Use GROUP BY to group rows by the values of one or more columns or by the
| results of an expression. You can then apply aggregate functions to each group.

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

Example: GROUP BY clause using one column: The following SQL statement
lists, for each department, the lowest and highest education level within that
department:
SELECT WORKDEPT, MIN(EDLEVEL), MAX(EDLEVEL)
FROM DSN8810.EMP
GROUP BY WORKDEPT;

If a column that 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 group the rows by the values of more than one column.

Example: GROUP BY clause using more than one column: 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 DSN8810.EMP
WHERE WORKDEPT IN (’A00’, ’C01’)
GROUP BY WORKDEPT, SEX;

The result table looks similar to the following output:


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 then (within each department)
by sex before it derives the average SALARY value for each group.

| You can also group the rows by the results of an expression

| Example: GROUP BY clause using a expression: The following statement lists,


| for each department, the lowest and highest education level within that department
| and groups the results by the highest education level:
| SELECT WORKDEPT, MIN(EDLEVEL), MAX(EDLEVEL)
| FROM DSN8810.EMP
| GROUP BY MAX(EDLEVEL);

Chapter 1. Retrieving data 11


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.

Example: HAVING clause: The following SQL statement includes a HAVING


clause that specifies a search condition for groups of work departments in the
employee table:
SELECT WORKDEPT, AVG(SALARY) AS AVG_SALARY
FROM DSN8810.EMP
GROUP BY WORKDEPT
HAVING COUNT(*) > 1
ORDER BY WORKDEPT;

The result table looks similar to the following output:


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 11. The clause, HAVING COUNT(*) > 1, ensures
that only departments with more than one member are displayed. In this case,
departments B01 and E01 do not display because the HAVING clause tests a
property of the group.

Example: HAVING clause used with a GROUP BY clause: Use the HAVING
clause to retrieve the average salary and minimum education level of women in
each department for 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 DSN8810.EMP
WHERE SEX = ’F’ AND WORKDEPT IN (’A00’, ’D11’)
GROUP BY WORKDEPT
HAVING MIN(EDLEVEL) >= 16;

The result table looks similar to the following output:


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.

12 Application Programming and SQL Guide


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.

Example: UNION clause: 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.

The following SQL statement gives a combined result table containing employee
numbers in ascending order with no duplicates listed:
SELECT EMPNO
FROM DSN8810.EMP
WHERE WORKDEPT = ’D11’
UNION
SELECT EMPNO
FROM DSN8810.EMPPROJACT
WHERE PROJNO = ’MA2112’ OR
PROJNO = ’MA2113’ OR
PROJNO = ’AD3111’
ORDER BY EMPNO;

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 final result table of a UNION, specify the
optional keyword ALL after the UNION keyword.

Example: UNION ALL clause: The following SQL statement gives a combined
result table containing employee numbers in ascending order, and includes
duplicate numbers:
SELECT EMPNO
FROM DSN8810.EMP
WHERE WORKDEPT = ’D11’
UNION ALL
SELECT EMPNO
FROM DSN8810.EMPPROJACT
WHERE PROJNO = ’MA2112’ OR
PROJNO = ’MA2113’ OR
PROJNO = ’AD3111’
ORDER BY EMPNO;

Chapter 1. Retrieving data 13


| Creating common table expressions: WITH
| A common table expression is like a temporary view that is defined and used for the
| duration of a SQL statement. You can define a common table expression for the
| SELECT, INSERT, and CREATE VIEW statements.

| Each common table expression must have a unique name and be defined only
| once. However, you can reference a common table expression many times in the
| same SQL statement. Unlike regular views or nested table expressions, which
| derive their result tables for each reference, all references to common table
| expressions in a given statement share the same result table.

| A common table expression can be used in the following situations:


| v When you want to avoid creating a view (when general use of the view is not
| required and positioned updates or deletes are not used)
| v When the desired result table is based on host variables
| v When the same result table needs to be shared in a fullselect
| v When the results need to be derived using recursion

| Using WITH instead of CREATE VIEW:


| Using the WITH clause to create a common table expression saves you the
| overhead of needing to create and drop a regular view that you only need to use
| once. Also, during statement preparation, DB2 does not need to access the catalog
| for the view, which saves you additional overhead.

| You can use a common table expression in a SELECT statement by using the
| WITH clause at the beginning of the statement.

| Example: WITH clause in a SELECT statement: The following statement finds the
| department with the highest total pay. The query involves two levels of aggregation.
| First, you need to determine the total pay for each department by using the SUM
| function and order the results by using the GROUP BY clause. You then need to
| find the department with maximum total pay based on the total pay for each
| department.
| WITH DTOTAL (deptno, totalpay) AS
| (SELECT deptno, sum(salary+bonus)
| FROM DSN8810.EMP
| GROUP BY deptno)
| SELECT deptno
| FROM DTOTAL
| WHERE totalpay = (SELECT max(totalpay)
| FROM DTOTAL);

| The result table for the common table expression, DTOTAL, contains the
| department number and total pay for each department in the employee table. The
| fullselect in the previous example uses the result table for DTOTAL to find the
| department with the highest total pay. The result table for the entire statement looks
| similar to the following results:
| DEPTNO
| ======
| D11

14 Application Programming and SQL Guide


| Using common table expressions with CREATE VIEW:
| You can use common table expressions before a fullselect in a CREATE VIEW
| statement. The common table expression must be placed immediately inside of the
| statement. This is useful if you need to use the results of a common table
| expression in more than one query.

| Example: Using a WITH clause in a CREATE VIEW statement: The following


| statement finds the departments that have a greater than average total pay and
| saves the results as the view RICH_DEPT:
| CREATE VIEW RICH_DEPT (deptno) AS
| WITH DTOTAL (deptno, totalpay) AS
| (SELECT deptno, sum(salary+bonus)
| FROM DSN8810.EMP
| GROUP BY deptno)
| SELECT deptno
| FROM DTOTAL
| WHERE totalpay > (SELECT AVG(totalpay)
| FROM DTOTAL);

| The fullselect in the previous example uses the result table for DTOTAL to find the
| departments that have a greater than average total pay. The result table is saved as
| the RICH_DEPT view and looks similar to the following results:
| DEPTNO
| ======
| A00
| D11
| D21

| Using common table expressions when you use INSERT:


| You can use common table expressions before a fullselect in an INSERT statement.
| The common table expression must be placed immediately inside of the statement.

| Example: Using a WITH clause in an INSERT statement: The following example


| illustrates the use of a common table expression in an INSERT statement.
| INSERT INTO vital_mgr (mgrno) AS
| WITH VITALDEPT (deptno, se_count) AS
| (SELECT deptno, count(*)
| FROM DSN8810.EMP
| WHERE job = ’senior engineer’
| GROUP BY deptno)
| SELECT d.manager
| FROM DSN8810.DEPT d, VITALDEPT s
| WHERE d.deptno = s.deptno
| AND s.se_count > (SELECT AVG(se_count)
| FROM VITALDEPT);

| The fullselect in the previous example uses the result table for VITALDEPT to find
| the manager’s number for departments that have a greater than average number of
| senior engineers. The manager’s number is then inserted into the vital_mgr table.

| Using recursive SQL


| You can use common table expressions to create recursive SQL. If a fullselect of a
| common table expression contains a reference to itself in a FROM clause, the
| common table expression is a recursive common table expression. Queries that use
| recursion are useful in applications like bill of materials applications, network
| planning applications, and reservation systems.

| Recursive common table expressions must follow these rules:

Chapter 1. Retrieving data 15


| v The first fullselect of the first union (the initialization fullselect) must not include a
| reference to the common table expression
| v Each fullselect that is part of the recursion cycle must:
| – Start with SELECT or SELECT ALL. SELECT DISTINCT is not allowed
| – Include only one reference to the common table expression that is part of the
| recursion cycle in it’s FROM clause
| – Not include aggregate functions, a GROUP BY clause, or a HAVING clause
| v The column names must be specified following the table name of the common
| table expression
| v The data types, lengths, and CCSIDs of the column names from the common
| table expression that are referenced in the iterative fullselect must match
| v The UNION statements must be UNION ALL
| v Outer joins must not be part of any recursion cycle
| v Subquery must not be part on any recursion cycle

| It is possible to introduce an infinite loop when developing a recursive common


| table expression. A recursive common table expression is expected to include a
| predicate that will prevent an infinite loop. A warning is issued if one of the following
| is not found in the iterative fullselect of a recursive common table expression:
| v An integer column that increments by a constant
| v A predicate in the WHERE clause in the form of counter_column < constant or
| counter_column < :host variable

| See Appendix E, “Recursive common table expression examples,” on page 997 for
| examples of bill of materials applications that use recursive common table
| expressions.

Accessing DB2 data that is not in a table


You can access DB2 data that is not in a table by returning the value of an SQL
expression in a host variable. The expression does not include a column of a table.
The three ways to return a value in a host variable are as follows:
v Set the contents of a host variable to the value of an expression by using the
SET host-variable assignment statement.
EXEC SQL SET :hvrandval = RAND(:hvrand);
v Use the VALUES INTO statement to return the value of an expression in a host
variable.
EXEC SQL VALUES RAND(:hvrand)
INTO :hvrandval;
v Select the expression from the DB2-provided EBCDIC table, named
SYSIBM.SYSDUMMY1, which consists of one row.
EXEC SQL SELECT RAND(:hvrand)
INTO :hvrandval
FROM SYSIBM.SYSDUMMY1;

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.
DEC15 rules are in effect when both operands have a precision of 15 or less, or
unless the DEC31 rules apply.

16 Application Programming and SQL Guide


v DEC31 rules allow a maximum precision of 31 digits in the result. DEC31 rules
are in effect if any of the following conditions is true:
– Either operand of the operation has a precision greater than 15 digits.
– 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. s is a number between one and nine and represents the minimum
scale to be used for division operations.
| - The installation option for DECIMAL ARITHMETIC on panel DSNTIP4 is
DEC31, D31.s, or 31; the installation option for USE FOR
| DYNAMICRULES on panel DSNTIP4 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 DSNTIP4 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
479 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. s is a number
between one and nine and represents the minimum scale to be used for
division operations. See “Step 1: Process SQL statements” on page 454 for
information about precompiling and for a list of all precompiler options.

Recommendation: Choose DEC31 or D31.s to reduce the chance of overflow, or


when dealing with a precision greater than 15 digits. s is a number between one
and nine 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 you can avoid a division error by specifying D31.s.
This specification reduces the probability of errors for statements that are
embedded in the program. s is a number between one and nine 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 DSNTIP4 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.

Before you execute a dynamic 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.

Chapter 1. Retrieving data 17


Finding information in the DB2 catalog
The following examples show you how to access the DB2 system catalog tables to
list the following objects:
v The tables that you can access
v 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 similar to the one 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 = ’ ’;

In this query, the predicate GRANTEETYPE = ’ ’ selects authorization IDs.

If your DB2 subsystem uses an exit routine for access control authorization, you
cannot rely on catalog queries to tell you the 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 run the previous SQL statements to display a list of tables you
can access and you now want to display information about table DSN8810.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 = ’DSN8810’;

If you display column information about a table that 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, as in the following example:
SELECT NAME, COLTYPE, LENGTH, LENGTH2
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = ’EMP_PHOTO_RESUME’
AND TBCREATOR = ’DSN8810’;

18 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 21
v “Dropping tables: DROP TABLE” on page 25
v “Defining a view: CREATE VIEW” on page 25
v “Changing data through a view” on page 26
v “Dropping views: DROP VIEW” on page 27
v “Inserting rows: INSERT” on page 27
| v “Selecting values as you insert: SELECT from INSERT” on page 31
v “Updating current values: UPDATE” on page 36
v “Deleting rows: DELETE” on page 37
See DB2 SQL Reference for more information about working with tables and data.

Working with tables


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

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 preceding CREATE statement has the following elements:


v CREATE TABLE, which names the table PRODUCT.
v A list of the columns that make up the table. For each column, specify the
following information:
– The column’s name (for example, SERIAL).
– The data type and length attribute (for example, CHAR(8)). For more
information about data types, see “Data types” on page 3.
– Optionally, a default value. See “Identifying defaults.”
– Optionally, a referential constraint or check constraint. See “Using referential
constraints” on page 245 and “Using check constraints” on page 243.

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

Identifying defaults
If you want to constrain the input or identify the default of a column, you can use
the following values:
v NOT NULL, when the column cannot contain null values.

© Copyright IBM Corp. 1983, 2004 19


v UNIQUE, when the value for each row must be unique, and the column cannot
contain null values.
v DEFAULT, when the column has one of the following DB2-assigned defaults:
– For numeric columns, 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 columns, the current value of the associated special register is
the default value.
v DEFAULT value, when you want to identify one of the following values as the
default value:
– A constant
– NULL
– USER, which specifies the value of the USER special register at the time that
an INSERT statement assigns a default value to the column in the row that is
being inserted
– CURRENT SQLID, which specifies the value of the CURRENT SQLID special
register at the time that an INSERT statement assigns a default value to the
column in the row that is being inserted
– The name of a cast function that casts a default value (of a built-in data type)
to the distinct type of a column

Creating work tables


Before testing SQL statements that insert, update, and delete rows, you should
create work tables (duplicates of the DSN8810.EMP and DSN8810.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 that 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 DSN8810.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 the existing table, DSN8810.DEPT, and an index for YDEPT:
CREATE TABLE YDEPT
LIKE DSN8810.DEPT;
CREATE UNIQUE INDEX YDEPTX
ON YDEPT (DEPTNO);

If you want DEPTNO to be a primary key, as in the sample table, explicitly define
the key. Use an ALTER TABLE statement, as in the following example:
ALTER TABLE YDEPT
PRIMARY KEY(DEPTNO);

You can use an INSERT statement to copy the rows of the result table of a
fullselect from one table to another. The following statement copies all of the rows
from DSN8810.DEPT to your own YDEPT work table.
INSERT INTO YDEPT
SELECT *
FROM DSN8810.DEPT;

20 Application Programming and SQL Guide


For information about using the INSERT statement, see “Inserting rows: INSERT”
on page 27.

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.

| You can change a table definition by using the ALTER TABLE statement only in
| certain ways. For example, you can add and drop constraints on columns in a table.
| You can also change the data type of a column within character data types, within
| numeric data types, and within graphic data types. You can add a column to a
| table. However, you cannot drop a column from a table.

| For more information about changing a table definition by using ALTER TABLE, see
| Part 2 (Volume 1) of DB2 Administration Guide. For other details about the ALTER
| TABLE and RENAME TABLE statements, see Chapter 5 of DB2 SQL Reference.

Working with temporary tables


When you need a table only for the duration 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 of the following
reasons:
v DB2 does no logging (for created temporary tables) or limited logging (for
declared temporary tables).
v DB2 does no locking (for created temporary tables) or limited locking (for
declared temporary tables).

Temporary tables are especially useful when you need to sort or query intermediate
result tables that contain a large number of rows, but you want to store only a small
subset of those rows permanently.

Chapter 2. Working with tables and modifying data 21


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 590. 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: The following statement creates the definition of a table called


TEMPPROD:
CREATE GLOBAL TEMPORARY TABLE TEMPPROD
(SERIAL CHAR(8) NOT NULL,
DESCRIPTION VARCHAR(60) NOT NULL,
MFGCOST DECIMAL(8,2),
MFGDEPT CHAR(3),
MARKUP SMALLINT,
SALESDEPT CHAR(3),
CURDATE DATE NOT NULL);

Example: You can also create this same definition by copying the definition of a
base table using the LIKE clause:
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. Unlike the PROD sample table, the
DESCRIPTION and CURDATE columns in the TEMPPROD table are defined as
NOT NULL and do not have defaults, because created temporary tables do not
support non-null default values.

After you run 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 run the following 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 is specified in one of the
following 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 application process ends.
v The remote server connection through which the instance was created
terminates.
v The unit of work in which the instance was created completes.
When you run a ROLLBACK statement, DB2 deletes the instance of the created
temporary table. When you run a COMMIT statement, DB2 deletes the instance
of the created temporary table unless a cursor for accessing the created
temporary table is defined WITH HOLD and is open.

22 Application Programming and SQL Guide


Example: Suppose that you create a definition of TEMPPROD and then run an
application that contains the following statements:
EXEC SQL DECLARE C1 CURSOR FOR SELECT * FROM TEMPPROD;
EXEC SQL INSERT INTO TEMPPROD SELECT * FROM PROD;
EXEC
. SQL OPEN C1;
.
.
EXEC
. SQL COMMIT;
.
.
EXEC SQL CLOSE C1;

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

In this case, DB2 does not delete the contents of TEMPPROD until the application
ends because C1, a cursor defined WITH HOLD, is open when the COMMIT
statement is run. 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. The qualifier for a declared
temporary table is SESSION.

Before you can define declared temporary tables, you must create a special
database and table spaces for them. You do that by running 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. There must be at least one table space with a 8-KB page size in the TEMP
| database to declare a temporary table.

Example: The following 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.

Chapter 2. Working with tables and modifying data 23


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.
If you want the declared temporary table columns to inherit the defaults for
columns of the table or view that is named in the fullselect, specify the
INCLUDING COLUMN DEFAULTS clause. If you want the declared temporary
table columns to have default values that correspond to their data types, specify
the USING TYPE DEFAULTS clause.

Example: The following statement defines a declared temporary table called


TEMPPROD by explicitly specifying the columns.
DECLARE GLOBAL 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: The following statement defines a declared temporary table called


TEMPPROD by copying the definition of a base table. The base table has an
identity column that the declared temporary table also uses as an identity column.
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD LIKE BASEPROD
INCLUDING IDENTITY COLUMN ATTRIBUTES;

Example: The following statement defines a declared temporary table called


TEMPPROD by selecting columns from a view. The view has an identity column
that the declared temporary table also uses as an identity column. The declared
temporary table inherits its default column values from the default column values of
a base table underlying the view.
DECLARE GLOBAL TEMPORARY TABLE TEMPPROD
AS (SELECT * FROM PRODVIEW)
DEFINITION ONLY
INCLUDING IDENTITY COLUMN ATTRIBUTES
INCLUDING COLUMN DEFAULTS;

After you run a DECLARE GLOBAL TEMPORARY TABLE statement, the definition
of the declared temporary table exists as long as the application process runs. If
you need to delete the definition before the application process completes, you can
do that with the DROP TABLE statement. For example, to drop the definition of
TEMPPROD, run the following statement:
DROP TABLE SESSION.TEMPPROD;

DB2 creates an empty instance of a declared temporary table when it runs the
DECLARE GLOBAL TEMPORARY TABLE statement. You can 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.

The ON COMMIT clause that you specify in the DECLARE GLOBAL TEMPORARY
TABLE statement determines whether DB2 keeps or deletes all the rows from the
table when you run a COMMIT statement in an application with a declared
temporary table. ON COMMIT DELETE ROWS, which is the default, causes all

24 Application Programming and SQL Guide


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.

Example: Suppose that you run the following statement in an application program:
EXEC SQL DECLARE GLOBAL TEMPORARY TABLE TEMPPROD
AS (SELECT * FROM BASEPROD)
DEFINITION ONLY
INCLUDING IDENTITY COLUMN ATTRIBUTES
INCLUDING COLUMN DEFAULTS
ON COMMIT PRESERVE ROWS;
EXEC
. SQL INSERT INTO SESSION.TEMPPROD SELECT * FROM BASEPROD;
.
.
EXEC
. SQL COMMIT;
.
.

When DB2 runs the preceding DECLARE GLOBAL TEMPORARY TABLE


statement, DB2 creates an empty instance of TEMPPROD. The INSERT statement
populates that instance with rows from table BASEPROD. The qualifier, SESSION,
must be specified in any statement that references TEMPPROD. When DB2
executes the COMMIT statement, DB2 keeps all rows in TEMPPROD because
TEMPPROD is defined with ON COMMIT PRESERVE ROWS. When the program
ends, DB2 drops TEMPPROD.

Dropping tables: DROP TABLE


The following SQL statement drops the YEMP table:
DROP TABLE YEMP;

Use the DROP TABLE statement with care: Dropping a table is NOT equivalent
to deleting all its rows. When you drop a table, you lose more than its data and its
definition. You lose all synonyms, views, indexes, and referential and check
constraints associated with that table. You also lose all authorities granted on the
table.

For more information about 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
views 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. The view created with the following statement shows each
department manager’s name with the department data in the DSN8810.DEPT table.
CREATE VIEW VDEPTM AS
SELECT DEPTNO, MGRNO, LASTNAME, ADMRDEPT
FROM DSN8810.DEPT, DSN8810.EMP
WHERE DSN8810.EMP.EMPNO = DSN8810.DEPT.MGRNO;

Chapter 2. Working with tables and modifying data 25


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. To see the
departments administered by department D01 and the managers of those
departments, run the following statement, which returns information from the
VDEPTM view:
SELECT DEPTNO, LASTNAME
FROM VDEPTM
WHERE ADMRDEPT = ’DO1’;

When you create a view, you can reference the 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 The view is based on the union 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 for the following actions:
v Make a subset of a table’s data available to an application. For example, a view
based on the employee table might contain rows only for a particular department.
v Combine columns from two or more tables and make the combined data
available to an application. By using a SELECT statement that matches values in
one table with those in another table, you can create a view that presents data
from both tables. However, you can only select data from this type of view. You
cannot update, delete, or insert data using a view that joins two or more
tables.
v Combine rows from two or more tables and make the combined data available to
an application. By using two or more subselects that are connected by 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; other views 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, some additional considerations include:
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.

26 Application Programming and SQL Guide


v Views that you can use to update data are subject to the same referential
constraints and check constraints as the tables you used to define the views.
v You can use the WITH CHECK option of the CREATE VIEW statement to specify
the constraint that every row that is inserted or updated through the view must
conform to the definition of the view. You can select every row that is inserted or
updated through a view that specifies WITH CHECK.

Dropping views: DROP VIEW


When you drop a view, you also drop all views that are defined on the following
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:
v “Inserting rows: INSERT”
v “Selecting values as you insert: SELECT from INSERT” on page 31
v “Updating current values: UPDATE” on page 36
v “Deleting rows: DELETE” on page 37

Inserting rows: INSERT


Use an INSERT statement to add new rows to a table or view. Using an INSERT
statement, you can do the following actions:
v Specify the column values to insert a single row. You can specify constants, host
variables, expressions, DEFAULT, or NULL by using the VALUES clause.
“Inserting a single row” on page 28 explains how to use the VALUES clause of
the INSERT statement to add a single row of column values to a table.
| v In an application program, specify arrays of column values to insert multiple rows
| into a table. “Inserting multiple rows of data from host variable arrays” on page
| 79 explains how to use host variable arrays in the VALUES clause of the
| INSERT FOR n ROWS statement to add multiple rows of column values to a
| table.
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. “Inserting rows into a
table from another table” on page 29 explains how to use the SELECT statement
within an INSERT statement to add multiple rows to a table.

In each 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 the following
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 an 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 30 and “Inserting
data into an identity column” on page 30 for more information.

Chapter 2. Working with tables and modifying data 27


Inserting a single row
You can use the VALUES clause of the INSERT statement to insert a single row of
column values into a table. You can either name all of the columns for which you
are providing values, or you can omit the list of column names. If you omit the
column name list, you must specify values for all of the columns.

Recommendation: For static INSERT statements, name all of the columns for
which you are providing values for because of the following reasons:
v Your INSERT statement is independent of the table format. (For example, you do
not need 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, 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.

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

Example: The following statement inserts information about a new department into
the YDEPT table.
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. The following SQL
statement shows you all the new department rows that you have inserted:
SELECT *
FROM YDEPT
WHERE DEPTNO LIKE ’E%’
ORDER BY DEPTNO;

The result table looks similar to the following output:


DEPTNO DEPTNAME MGRNO ADMRDEPT LOCATION
====== ==================================== ====== ======== ===========
E01 SUPPORT SERVICES 000050 A00 -----------
E11 OPERATIONS 000090 E01 -----------
E21 SOFTWARE SUPPORT 000100 E01 -----------
E31 DOCUMENTATION 000010 E01 -----------

Example: The following 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);

Example: The following statement also inserts a row into the YEMP table. Because
the unspecified columns allow nulls, DB2 inserts null values into the columns that
you do not specify. 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.

28 Application Programming and SQL Guide


INSERT INTO YEMP
(EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT, PHONENO, JOB)
VALUES (’000410’, ’MILLARD’, ’K’, ’FILLMORE’, ’D11’, ’4888’, ’MANAGER’);

Inserting rows into a table from another table


You can copy data from one table into another table. Use a fullselect within an
INSERT statement to select rows from one table to insert into another table.

Example: The following SQL statement creates a table named TELE:


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

The following statement copies data from DSN8810.EMP into the newly created
table:
INSERT INTO TELE
SELECT LASTNAME, FIRSTNME, PHONENO
FROM DSN8810.EMP
WHERE WORKDEPT = ’D21’;

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

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
DSN8810.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 phone number. The fullselect within the
INSERT statement fills the DLIST table with data from rows selected from two
existing tables, DSN8810.DEPT and DSN8810.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 DSN8810.DEPT, DSN8810.EMP
WHERE DEPTNO = WORKDEPT;

Other ways to insert data


Besides using stand-alone INSERT statements, you can use the following two ways
to insert data into a table:
Chapter 2. Working with tables and modifying data 29
v You can write an application program to prompt for and enter large amounts of
data into a table. For details, see Part 2, “Coding SQL in your host application
program,” on page 65.
v You can also 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.

Inserting data into a ROWID column


A ROWID column is a column that is defined with a ROWID data type. You must
have a column with a ROWID data type in a table that contains a LOB column. The
ROWID column is stored in the base table and is used to look up the actual LOB
data in the LOB table space. In addition, a ROWID column enables you to write
queries that navigate directly to a row in a table. For information about using
ROWID columns for direct-row access, see “Using ROWID columns as keys” on
page 253.

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.

Example: Suppose that tables T1 and T2 have two columns: an integer column and
a ROWID column. For the following statement to run successfully, ROWIDCOL2
must be defined as GENERATED BY DEFAULT.
INSERT INTO T2 (INTCOL2,ROWIDCOL2)
SELECT * 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, as in the following
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, as in
the following statement:
INSERT INTO T2 (INTCOL2,ROWIDCOL2) OVERRIDING USER VALUE
SELECT * FROM T1;

Inserting data into an identity column


An identity column is a numeric column, defined in a CREATE TABLE or ALTER
TABLE statement, that has ascending or descending values. For an identity column
to be as useful as possible, its values should also be unique. 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. For information about using identity columns to uniquely identify rows, see
“Using identity columns as keys” on page 254

Before you insert data into an identity column, you must know how the column is
defined. Identity columns are 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

30 Application Programming and SQL Guide


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.

Example: 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 run successfully, IDENTCOL2 must be defined as GENERATED BY
DEFAULT.
INSERT INTO T2 (CHARCOL2,IDENTCOL2)
SELECT * 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, as in the following
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, as in
the following statement:
INSERT INTO T2 (CHARCOL2,IDENTCOL2) OVERRIDING USER VALUE
SELECT * FROM T1;

| Selecting values as you insert: SELECT from INSERT


| You can select values from rows that are being inserted by specifying the INSERT
| statement in the FROM clause of the SELECT statement. When you insert one or
| more new rows into a table, you can retrieve:
| v The value of an automatically generated column such as a ROWID or identity
| column
| v Any default values for columns
| v All values for an inserted row, without specifying individual column names
| v All values that are inserted by a multiple-row INSERT operation
| v Values that are changed by a BEFORE INSERT trigger

| Example: In addition to examples that use the DB2 sample tables, the examples in
| this section use an EMPSAMP table that has the following definition:
| CREATE TABLE EMPSAMP
| (EMPNO INTEGER GENERATED ALWAYS AS IDENTITY,
| NAME CHAR(30),
| SALARY DECIMAL(10,2),
| DEPTNO SMALLINT,
| LEVEL CHAR(30),
| HIRETYPE VARCHAR(30) NOT NULL WITH DEFAULT ’New Hire’,
| HIREDATE DATE NOT NULL WITH DEFAULT);

| Assume that you need to insert a row for a new employee into the EMPSAMP
| table. To find out the values for the generated EMPNO, HIRETYPE, and HIREDATE
| columns, use the following SELECT from INSERT statement:
| SELECT EMPNO, HIRETYPE, HIREDATE
| FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, DEPTNO, LEVEL)
| VALUES(’Mary Smith’, 35000.00, 11, ’Associate’));

| The SELECT statement returns the DB2-generated identity value for the EMPNO
| column, the default value ’New Hire’ for the HIRETYPE column, and the value of
| the CURRENT DATE special register for the HIREDATE column.

Chapter 2. Working with tables and modifying data 31


| Recommendation: Use the SELECT from INSERT statement to insert a row into a
| parent table and retrieve the value of a primary key that was generated by DB2 (a
| ROWID or identity column). In another INSERT statement, specify this generated
| value as a value for a foreign key in a dependent table. For an example of this
| method, see “Parent keys and foreign keys” on page 256.

| Result table of the INSERT operation


| The rows that are inserted into the target table produce a result table whose
| columns can be referenced in the SELECT list of the query. The columns of the
| result table are affected by the columns, constraints, and triggers that are defined
| for the target table:
| v The result table includes DB2-generated values for identity columns, ROWID
| columns, or columns that are based on expressions.
| v Before DB2 generates the result table, it enforces any constraints that affect the
| insert operation (that is, check constraints, unique index constraints, and
| referential integrity constraints).
| v The result table includes any changes that result from a BEFORE trigger that is
| activated by the insert operation. An AFTER trigger does not affect the values in
| the result table. For information about triggers, see Chapter 12, “Using triggers
| for active data,” on page 261.

| Example: Suppose a BEFORE INSERT trigger is created on table EMPSAMP to


| give all new employees at the Associate level a $5000 increase in salary. The
| trigger has the following definition:
| CREATE TRIGGER NEW_ASSOC
| NO CASCADE BEFORE INSERT ON EMPSAMP
| REFERENCING NEW AS NEWSALARY
| FOR EACH ROW MODE DB2SQL
| WHEN LEVEL = ’Associate’
| BEGIN ATOMIC
| SET NEWSALARY.SALARY = NEWSALARY.SALARY + 5000.00;
| END;

| The INSERT statement in the FROM clause of the following SELECT statement
| inserts a new employee into the EMPSAMP table:
| SELECT NAME, SALARY
| FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, LEVEL)
| VALUES(’Mary Smith’, 35000.00, ’Associate’));

| The SELECT statement returns a salary of 40000.00 for Mary Smith instead of the
| initial salary of 35000.00 that was explicitly specified in the INSERT statement.

| Selecting values when you insert a single row


| When you insert a new row into a table, you can retrieve any column in the result
| table of the SELECT from INSERT statement. When you embed this statement in
| an application, you retrieve the row into host variables by using the SELECT ...
| INTO form of the statement. For information about using host variables and
| SELECT ... INTO, see “Using host variables” on page 72.

| Example: You can retrieve all the values for a row that is inserted into a structure:
| EXEC SQL SELECT * INTO :empstruct
| FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, DEPTNO, LEVEL)
| VALUES(’Mary Smith’, 35000.00, 11, ’Associate’));

| For this example, :empstruct is a host variable structure that is declared with
| variables for each of the columns in the EMPSAMP table.

32 Application Programming and SQL Guide


| Selecting values when you insert data into a view
| If the INSERT statement references a view that is defined with a search condition,
| that view must be defined with the WITH CASCADED CHECK OPTION. When you
| insert data into the view, the result table of the SELECT from INSERT statement
| includes only rows that satisfy the view definition.

| Example: Because view V1 is defined with the WITH CASCADED CHECK


| OPTION, you can reference V1 in the INSERT statement:
| CREATE VIEW V1 AS
| SELECT C1, I1 FROM T1 WHERE I1 > 10
| WITH CASCADED CHECK OPTON;
|
| SELECT C1 FROM
| FINAL TABLE (INSERT INTO V1 (I1) VALUES(12));

| The value 12 satisfies the search condition of the view definition, and the result
| table consists of the value for C1 in the inserted row.

| If you use a value that does not satisfy the search condition of the view definition,
| the insert operation fails, and DB2 returns an error.

| Selecting values when you insert multiple rows


| In an application program, to retrieve values from the insertion of multiple rows,
| declare a cursor so that the INSERT statement is in the FROM clause of the
| SELECT statement of the cursor. For information about using cursors, see
| Chapter 7, “Using a cursor to retrieve a set of rows,” on page 93.

| Example: Inserting rows with ROWID values: To see the values of the ROWID
| columns that are inserted into the employee photo and resume table, you can
| declare the following cursor:
| EXEC SQL DECLARE CS1 CURSOR FOR
| SELECT EMP_ROWID
| FROM FINAL TABLE (INSERT INTO DSN8810.EMP_PHOTO_RESUME (EMPNO)
| SELECT EMPNO FROM DSN8810.EMP);

| Example: Using the FETCH FIRST clause: To see only the first five rows that are
| inserted into the employee photo and resume table, use the FETCH FIRST clause:
| EXEC SQL DECLARE CS2 CURSOR FOR
| SELECT EMP_ROWID
| FROM FINAL TABLE (INSERT INTO DSN8810.EMP_PHOTO_RESUME (EMPNO)
| SELECT EMPNO FROM DSN8810.EMP)
| FETCH FIRST 5 ROWS ONLY;

| Example: Using the INPUT SEQUENCE clause: To retrieve rows in the order in
| which they are inserted, use the INPUT SEQUENCE clause:
| EXEC SQL DECLARE CS3 CURSOR FOR
| SELECT EMP_ROWID
| FROM FINAL TABLE (INSERT INTO DSN8810.EMP_PHOTO_RESUME (EMPNO)
| VALUES(:hva_empno)
| FOR 5 ROWS)
| ORDER BY INPUT SEQUENCE;

| The INPUT SEQUENCE clause can be specified only if an INSERT statement is in


| the FROM clause of the SELECT statement. In this example, the rows are inserted
| from an array of employee numbers. For information about the multiple-row INSERT
| statement, see “Inserting multiple rows of data from host variable arrays” on page
| 79.

Chapter 2. Working with tables and modifying data 33


| Example: Inserting rows with multiple encoding CCSIDs: Suppose that you
| want to populate an ASCII table with values from an EBCDIC table and then see
| selected values from the ASCII table. You can use the following cursor to select the
| EBCDIC columns, populate the ASCII table, and then retrieve the ASCII values:
| EXEC SQL DECLARE CS4 CURSOR FOR
| SELECT C1, C2
| FROM FINAL TABLE (INSERT INTO ASCII_TABLE
| SELECT * FROM EBCDIC_TABLE);

| Result table of the cursor when you insert multiple rows


| In an application program, when you insert multiple rows into a table, you declare a
| cursor so that the INSERT statement is in the FROM clause of the SELECT
| statement of the cursor. The result table of the cursor is determined during OPEN
| cursor processing. The result table may or may not be affected by other processes
| in your application.

| Effect on cursor sensitivity: When you declare a scrollable cursor, the cursor
| must be declared with the INSENSITIVE keyword if an INSERT statement is in the
| FROM clause of the cursor specification. The result table is generated during OPEN
| cursor processing and does not reflect any future changes. You cannot declare the
| cursor with the SENSITIVE DYNAMIC or SENSITIVE STATIC keywords. For
| information about cursor sensitivity, see “Using a scrollable cursor” on page 104.

| Effect of searched updates and deletes: When you declare a non-scrollable


| cursor, any searched updates or deletes do not affect the result table of the cursor.
| The rows of the result table are determined during OPEN cursor processing.

| Example: Assume that your application declares a cursor, opens the cursor,
| performs a fetch, updates the table, and then fetches additional rows:
| EXEC SQL DECLARE CS1 CURSOR FOR
| SELECT SALARY
| FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, LEVEL)
| SELECT NAME, INCOME, BAND FROM OLD_EMPLOYEE);
| EXEC SQL OPEN CS1;
| EXEC SQL FETCH CS1 INTO :hv_salary;
| /* print fetch result */
| ...
| EXEC SQL UPDATE EMPSAMP SET SALARY = SALARY + 500;
| while (SQLCODE == 0) {
| EXEC SQL FETCH CS1 INTO :hv_salary;
| /* print fetch result */
| ...
| }

| The fetches that occur after the update processing return the rows that were
| generated during OPEN cursor processing. However, if you use a simple SELECT
| (with no INSERT statement in the FROM clause), the fetches might return the
| updated values, depending on the access path that DB2 uses.

| Effect of WITH HOLD: When you declare a cursor with the WITH HOLD option,
| and open the cursor, all of the rows are inserted into the target table. The WITH
| HOLD option has no effect on the SELECT from INSERT statement of the cursor
| definition. After your application performs a commit, you can continue to retrieve all
| of the inserted rows. For information about held cursors, see “Held and non-held
| cursors” on page 112.

| Example: Assume that the employee table in the DB2 sample application has five
| rows. Your application declares a WITH HOLD cursor, opens the cursor, fetches two
| rows, performs a commit, and then fetches the third row successfully:

34 Application Programming and SQL Guide


| EXEC SQL DECLARE CS2 CURSOR WITH HOLD FOR
| SELECT EMP_ROWID
| FROM FINAL TABLE (INSERT INTO DSN8810.EMP_PHOTO_RESUME (EMPNO)
| SELECT EMPNO FROM DSN8810.EMP);
| EXEC SQL OPEN CS2; /* Inserts 5 rows */
| EXEC SQL FETCH CS2 INTO :hv_rowid; /* Retrieves ROWID for 1st row */
| EXEC SQL FETCH CS2 INTO :hv_rowid; /* Retrieves ROWID for 2nd row */
| EXEC SQL COMMIT; /* Commits 5 rows */
| EXEC SQL FETCH CS2 INTO :hv_rowid; /* Retrieves ROWID for 3rd row */

| Effect of SAVEPOINT and ROLLBACK: When you set a savepoint prior to


| opening the cursor and then roll back to that savepoint, all of the insertions are
| undone. For information about savepoints and ROLLBACK processing, see “Using
| savepoints to undo selected changes within a unit of work” on page 421.

| Example: Assume that your application declares a cursor, sets a savepoint, opens
| the cursor, sets another savepoint, rolls back to the second savepoint, and then
| rolls back to the first savepoint:
| EXEC SQL DECLARE CS3 CURSOR FOR
| SELECT EMP_ROWID
| FROM FINAL TABLE (INSERT INTO DSN8810.EMP_PHOTO_RESUME (EMPNO)
| SELECT EMPNO FROM DSN8810.EMP);
| EXEC SQL SAVEPOINT A ON ROLLBACK RETAIN CURSORS; /* Sets 1st savepoint */
| EXEC SQL OPEN CS3;
| EXEC SQL SAVEPOINT B ON ROLLBACK RETAIN CURSORS; /* Sets 2nd savepoint */
| ...
| EXEC SQL ROLLBACK TO SAVEPOINT B; /* Rows still in DSN8810.EMP_PHOTO_RESUME */
| ...
| EXEC SQL ROLLBACK TO SAVEPOINT A; /* All inserted rows are undone */

| What happens if an error occurs


| In an application program, when you insert one or more rows into a table by using
| the SELECT from INSERT statement, the result table of the insert operation may or
| may not be affected depending on where the error occurred in the application
| processing.

| During SELECT INTO processing: If the insert processing or the select


| processing fails during a SELECT INTO statement, no rows are inserted into the
| target table, and no rows are returned from the result table of the insert operation.

| Example: Assume that the employee table of the DB2 sample application has one
| row, and that the SALARY column has a value of 9 999 000.00.
| EXEC SQL SELECT EMPNO INTO :hv_empno
| FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY)
| SELECT FIRSTNAME || MIDINIT || LASTNAME,
| SALARY + 10000.00
| FROM DSN8810.EMP)

| The addition of 10000.00 causes a decimal overflow to occur, and no rows are
| inserted into the EMPSAMP table.

| During OPEN cursor processing: If the insertion of any row fails during the
| OPEN cursor processing, all previously successful insertions are undone. The result
| table of the INSERT is empty.

| During FETCH processing: If the FETCH statement fails while retrieving rows
| from the result table of the insert operation, a negative SQLCODE is returned to the
| application, but the result table still contains the original number of rows that was
| determined during the OPEN cursor processing. At this point, you can undo all of
| the inserts.

Chapter 2. Working with tables and modifying data 35


| Example: Assume that the result table contains 100 rows and the 90th row that is
| being fetched from the cursor returns a negative SQLCODE:
| EXEC SQL DECLARE CS1 CURSOR FOR
| SELECT EMPNO
| FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY)
| SELECT FIRSTNAME || MIDINIT || LASTNAME, SALARY + 10000.00
| FROM DSN8810.EMP);
| EXEC SQL OPEN CS1; /* Inserts 100 rows */
| while (SQLCODE == 0)
| EXEC SQL FETCH CS1 INTO :hv_empno;
| if (SQLCODE == -904) /* If SQLCODE is -904, undo all inserts */
| EXEC SQL ROLLBACK;
| else /* Else, commit inserts */
| EXEC SQL COMMIT;

| Updating current values: UPDATE


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

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’;

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 in the
SET clause 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
– A host variable
– A special register
In addition, you can replace one or more column values in the SET clause with the
column values in a row that is returned by a fullselect.

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.

36 Application Programming and SQL Guide


If DB2 finds an error while executing your UPDATE statement (for example, an
update value that is too large for the column), it stops updating and returns an error.
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 that are updated.

Example: 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 raise of 400.00. 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’;

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 specify 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 deleted rows in the table
that is specified in the DELETE statement. Rows that are deleted (in other tables)
according to the CASCADE rule are not included in SQLERRD(3).

Chapter 2. Working with tables and modifying data 37


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, the following statement
deletes every row in the YDEPT table:
DELETE FROM YDEPT;

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 about
the DROP statement, see “Dropping tables: DROP TABLE” on page 25.

38 Application Programming and SQL Guide


Chapter 3. Joining data from more than one table
Sometimes the information that 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 the following 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.

The examples in this section use the following two tables to show various types of
joins:
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

Figure 2 illustrates how these two tables can be combined using the three outer join
functions.

Figure 2. Three outer joins from the PARTS and PRODUCTS tables

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, that column does not have a name unless you use the AS
clause in the SELECT list.

© Copyright IBM Corp. 1983, 2004 39


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.

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.

To do this, you can use either one of the following SELECT statements:
SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT
FROM PARTS, PRODUCTS
WHERE PARTS.PROD# = PRODUCTS.PROD#;
SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT
FROM PARTS INNER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#;

The result table looks like the following output:


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 this example:


v A part in the parts table (OIL) has product (#160), which is not in the products
table. A product (SCREWDRIVER, #505) 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 You can explicitly specify that this join is an inner join (not an outer join). Use
INNER JOIN in the FROM clause instead of the comma, and 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, as in the following statement:
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 the following
query:

40 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.
The result table looks like the following output:
PART SUPPLIER PROD# PRODUCT
======= ============ ===== ==========
MAGNETS BATEMAN 10 GENERATOR
PLASTIC PLASTIK_CORP 30 RELAY

Example of joining a table to itself by using an inner join: In the following


example, A indicates the first instance of table DSN8810.PROJ and B indicates the
second instance of this table. The join condition is such that the value in column
PROJNO in table DSN8810.PROJ A must be equal to a value in column MAJPROJ
in table DSN8810.PROJ B.

The following SQL statement joins table DSN8810.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:
SELECT A.PROJNO, A.PROJNAME, B.PROJNO, B.PROJNAME
FROM DSN8810.PROJ A, DSN8810.PROJ B
WHERE A.PROJNO = B.MAJPROJ;

The result table looks similar to the following output:


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 it 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. If any
column of the result table does not have a value, that column has the null value in
the result table.

The join condition for a full outer join must be a simple search condition that
compares two columns or an invocation of a cast function that has a column name
as its argument.

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 looks similar to the following output:

Chapter 3. Joining data from more than one table 41


PART SUPPLIER PROD# PRODUCT
======= ============ ===== ==========
WIRE ACWF 10 GENERATOR
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. This function, by either
name, can be particularly useful in full outer join operations, because it returns the
first non-null value from the pair of join columns.

The product number in the result of the example for “Full outer join” on page 41 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, both of which contain some null values. You can merge data
from both columns into a single column, eliminating the null values, by using the
COALESCE function.

With the same PARTS and PRODUCTS tables, the following example merges the
non-null data from the PROD# columns:
SELECT PART, SUPPLIER,
COALESCE(PARTS.PROD#, PRODUCTS.PROD#) AS PRODNUM, PRODUCT
FROM PARTS FULL OUTER JOIN PRODUCTS
ON PARTS.PROD# = PRODUCTS.PROD#;

The result table looks similar to the following output:


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.

Example: To include rows from the PARTS table that have no matching values in
the PRODUCTS table, and to include prices that exceed $10.00 , run the following
query:
SELECT PART, SUPPLIER, PARTS.PROD#, PRODUCT, PRICE
FROM PARTS LEFT OUTER JOIN PRODUCTS
ON PARTS.PROD#=PRODUCTS.PROD#
AND PRODUCTS.PRICE>10.00;

42 Application Programming and SQL Guide


The result table looks similar to the following output:
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 ----------- -------

A row from the PRODUCTS table is in the result table only if its product number
matches the product number of a row in the PARTS table and the price is greater
than $10.00 for that row. Rows in which the PRICE value does not exceed $10.00
are included in the result of the join, but the PRICE value is set to null.

In this result table, the row for PROD# 30 has null values on the right two columns
because the price of PROD# 30 is less than $10.00. PROD# 160 has null values on
the right two columns because PROD# 160 does not match another product
number.

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.

Example: To include rows from the PRODUCTS table that have no corresponding
rows in the PARTS table, 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;

The result table looks similar to the following output:


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

A row from the PARTS table is in the result table only if its product number matches
the product number of a row in the PRODUCTS table and the price is greater than
10.00 for that row.

Because the PRODUCTS table can have rows with nonmatching product numbers
in the result table, and the PRICE column is in the PRODUCTS table, rows in which
PRICE is less than or equal to 10.00 are included in the result. The PARTS
columns contain null values for these rows in the result table.

Chapter 3. Joining data from more than one table 43


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.

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. 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. Consider the following
SELECT statement:
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’;

The following result is not what you wanted:


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

DB2 performs the join operation first. The result of the join operation includes rows
from one table that do not have corresponding rows from the other table. However,
the WHERE clause then excludes the rows from both tables that have null values
for the PROD# column.

The following statement is a correct SELECT statement to produce the list:


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#;

For this statement, DB2 applies the WHERE clause to each table separately. DB2
then performs the full outer join operation, which includes rows in one table that do
not have a corresponding row in the other table. The final result includes rows with
the null value for the PROD# column and looks similar to the following output:
PART SUPPLIER PRODNUM PRODUCT
======= ============ ======= ===========
OIL WESTERN_CHEM 160 -----------
BLADES ACE_STEEL 205 SAW
PLASTIC PLASTIK_CORP 30 RELAY
------- ------------ 505 SCREWDRIVER

44 Application Programming and SQL Guide


Using more than one join in an SQL statement
Using more than one join: You can join more than two tables. Suppose you want
a result table that shows employees who have projects that they are responsible
for, their projects, and their department names. You need to join three tables to get
all the information. You can use the following SELECT statement:
SELECT EMPNO, LASTNAME, DEPTNAME, PROJNO
FROM DSN8810.EMP, DSN8810.PROJ, DSN8810.DEPT
WHERE EMPNO = RESPEMP
AND WORKDEPT = DSN8810.DEPT.DEPTNO;

The result table looks similar to the following output:


EMPNO LASTNAME DEPTNAME PROJNO
====== ========= =========================== ======
000010 HAAS SPIFFY COMPUTER SERVICE DIV AD3100
000010 HAAS SPIFFY COMPUTER SERVICE DIV MA2100
000020 THOMPSON PLANNING PL2100
000030 KWAN INFORMATION CENTER IF1000
000030 KWAN INFORMATION CENTER IF2000
000050 GEYER SUPPORT SERVICES OP1000
000050 GEYER SUPPORT SERVICES OP2000
000060 STERN MANUFACTURING SYSTEMS MA2110
000070 PULASKI ADMINISTRATION SYSTEMS AD3110
000090 HENDERSON OPERATIONS OP1010
000100 SPENSER SOFTWARE SUPPORT OP2010
000150 ADAMSON MANUFACTURING SYSTEMS MA2112
000160 PIANKA MANUFACTURING SYSTEMS MA2113
000220 LUTZ MANUFACTURING SYSTEMS MA2111
000230 JEFFERSON ADMINISTRATION SYSTEMS AD3111
000250 SMITH ADMINISTRATION SYSTEMS AD3112
000270 PEREZ ADMINISTRATION SYSTEMS AD3113
000320 MEHTA SOFTWARE SUPPORT OP2011
000330 LEE SOFTWARE SUPPORT OP2012
000340 GOUNOT SOFTWARE SUPPORT OP2013

DB2 determines the intermediate and final results of the previous query by
performing the following logical steps:
1. Join the employee and project tables on the employee number, dropping the
rows with no matching employee number in the project table.
2. Join the intermediate result table with the department table on matching
department numbers.
3. Process the select list in the final result table, leaving only four columns.

Using more than one join type: You can use more than one join type in the
FROM clause. Suppose that you want a result table that shows employees whose
last name begins with ’S’ or a letter after ’S’, their department names, and the
projects that they are responsible for, if any. You can use the following SELECT
statement:
SELECT EMPNO, LASTNAME, DEPTNAME, PROJNO
FROM DSN8810.EMP INNER JOIN DSN8810.DEPT
ON WORKDEPT = DSN8810.DEPT.DEPTNO
LEFT OUTER JOIN DSN8810.PROJ
ON EMPNO = RESPEMP
WHERE LASTNAME > ’S’;

The result table looks like similar to the following output:


EMPNO LASTNAME DEPTNAME PROJNO
====== ========= ====================== ======
000020 THOMPSON PLANNING PL2100
000060 STERN MANUFACTURING SYSTEMS MA2110
000100 SPENSER SOFTWARE SUPPORT OP2010

Chapter 3. Joining data from more than one table 45


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

DB2 determines the intermediate and final results of the previous query by
performing the following logical steps:
1. Join the employee and department tables on matching department numbers,
dropping the rows where the last name begins with a letter before ’S’.
2. Join the intermediate result table with the project table on the employee number,
keeping the rows with no matching employee number in the project table.
3. Process the select list in the final result table, leaving only four columns.

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, which is a fullselect enclosed in parentheses and
followed by a correlation name
v A user-defined table function, which is a user-defined function that returns a table

Example of using a nested table expression as the right operand of a join:


The following query contains a fullselect as the right operand of a left outer join with
the PROJECTS table. The correlation name is TEMP.
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 following statement is the nested table expression:


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

Example of using correlated references: In the following example, the correlation


name that is used for the nested table expression is CHEAP_PARTS. The
correlated references are CHEAP_PARTS.PROD# and CHEAP_PARTS.PRODUCT.
SELECT CHEAP_PARTS.PROD#, CHEAP_PARTS.PRODUCT
FROM (SELECT PROD#, PRODUCT
FROM PRODUCTS
WHERE PRICE < 10) AS CHEAP_PARTS;

The result table looks similar to the following output:

46 Application Programming and SQL Guide


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

The correlated references are valid because they do not occur in the table
expression where CHEAP_PARTS is defined. The correlated references are from a
table specification at a higher level in the hierarchy of subqueries.

Example of using a nested table expression as the left operand of a join: The
following query contains a fullselect as the left operand of a left outer join with the
PRODUCTS table. The correlation name is PARTX.
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#;

The result table looks similar to the following output:


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: Using a table function as an operand of a join: 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 similar to the
following query:
SELECT PART, SUPPLIER, PARTS.PROD#, Z.PRODUCT, Z.PRICE
FROM PARTS, TABLE(CVTPRICE(:CURRENCY)) AS Z
WHERE PARTS.PROD# = Z.PROD#;

Using correlated references in table specifications in joins


You can include correlated references in nested table expressions or as arguments
to table functions. The basic rule that applies for both of 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
For more information about correlated references, see “Using correlation names in
references” on page 54.

Chapter 3. Joining data from more than one table 47


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.

Example: In this example, the correlated reference T.C2 is valid because the table
specification, to which it refers, T, is to its left.
SELECT T.C1, Z.C5
FROM T, TABLE(TF3(T.C2)) AS Z
WHERE T.C3 = Z.C4;

If you specify the join in the opposite order, with T following TABLE(TF3(T.C2), then
T.C2 is invalid.

Example: In this example, 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.
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;

If you remove the keyword TABLE, D.DEPTNO is invalid.

48 Application Programming and SQL Guide


Chapter 4. Using subqueries
When you need to narrow your search condition based on information in an interim
table, you can use a subquery. 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 that you want a list of the employee numbers, names, and commissions of
all employees working on a particular project, whose project number is MA2111.
The first part of the SELECT statement is easy to write:
SELECT EMPNO, LASTNAME, COMM
FROM DSN8810.EMP
WHERE EMPNO
.
.
.

But you cannot proceed because the DSN8810.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 DSN8810.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 DSN8810.EMP
WHERE EMPNO IN
(SELECT EMPNO
FROM DSN8810.EMPPROJACT
WHERE PROJNO = ’MA2111’);

To better understand the results of 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 DSN8810.EMPPROJACT
WHERE PROJNO = ’MA2111’);

The result is in an interim result table, similar to the one shown in the following
output:
from EMPNO
=====
200
200
220
2. The interim result table then serves as a list in the search condition of the outer
SELECT. Effectively, DB2 executes this statement:
SELECT EMPNO, LASTNAME, COMM
FROM DSN8810.EMP
WHERE EMPNO IN
(’000200’, ’000220’);

© Copyright IBM Corp. 1983, 2004 49


As a consequence, the result table looks similar to the following output:
EMPNO LASTNAME COMM
====== ======== ====
000200 BROWN 2217
000220 LUTZ 2387

Correlated and uncorrelated subqueries


Subqueries supply information that is needed to qualify a row (in a WHERE clause)
or a group of rows (in a HAVING clause). The subquery produces a result table that
is used to qualify the row or group of selected rows. 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 DSN8810.EMP.

Subqueries that vary in content from row to row or group to group are correlated
subqueries. For information about correlated subqueries, see “Using correlated
subqueries” on page 53. All of the following information that precedes the section
about correlated subqueries 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 can look
something like the following clause:
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 nesting level 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:
SELECT EMPNO, LASTNAME
FROM DSN8810.EMP
WHERE SALARY =
(SELECT AVG(SALARY)
FROM DSN8810.EMP);
SELECT EMPNO, LASTNAME
FROM DSN8810.EMP
WHERE (SALARY, BONUS) IN
(SELECT AVG(SALARY), AVG(BONUS)
FROM DSN8810.EMP);

50 Application Programming and SQL Guide


Except for a subquery of a basic predicate, the result table can contain more than
one row. For more information, see “Basic predicate.”

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


You can specify a subquery in either a WHERE or HAVING clause by using:
v A basic predicate
v A quantified predicate: ALL, ANY, or SOME
v The IN keyword
v 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.

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 DSN8810.EMP
WHERE EDLEVEL >
(SELECT AVG(EDLEVEL)
FROM DSN8810.EMP);

Quantified predicate : ALL, ANY, or 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:
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.

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 ALL predicate


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

Chapter 4. Using subqueries 51


WHERE column > ALL (subquery)

To satisfy this WHERE clause, the column value must be greater than all of 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, column1, ... columnn) <> ALL (subquery)

To satisfy this WHERE clause, each column value must be unequal to all of 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.

Using the ANY or SOME 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.

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.

Example: The following query returns the names of department managers:


SELECT EMPNO,LASTNAME
FROM DSN8810.EMP
WHERE EMPNO IN
(SELECT DISTINCT MGRNO
FROM DSN8810.DEPT);

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.

Example: The search condition in the following query is satisfied if any project that
is represented in the project table has an estimated start date that is later than 1
January 2005:

52 Application Programming and SQL Guide


SELECT EMPNO,LASTNAME
FROM DSN8810.EMP
WHERE EXISTS
(SELECT *
FROM DSN8810.PROJ
WHERE PRSTDATE > ’2005-01-01’);

The result of the subquery is always the same for every row that is examined for
the outer SELECT. Therefore, either every row appears in the result of the outer
SELECT or none appears. A correlated subquery is more powerful than the
uncorrelated subquery that is used in this example because the result of a
correlated subquery is evaluated for each row of the outer SELECT.

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 the following clause:
WHERE NOT EXISTS (SELECT ...);

Using correlated subqueries


In an uncorrelated subquery, DB2 executes the subquery once, substitutes the
result of the subquery in the right side of the search condition, and evaluates the
outer SELECT based on the value of the search condition. You can also write a
subquery that DB2 re-evaluates 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 DSN8810.EMP table. For each employee in the
table, DB2 needs to compare the employee’s education level to the average
education level for that employee’s department.

For this example, you need to use a correlated subquery, which differs from an
uncorrelated subquery. An uncorrelated subquery compares the employee’s
education level to the average of the entire company, which requires looking at the
entire table. A correlated subquery evaluates only the department that 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 DSN8810.EMP X
WHERE EDLEVEL >
(SELECT AVG(EDLEVEL)
FROM DSN8810.EMP
WHERE WORKDEPT = X.WORKDEPT);

Chapter 4. Using subqueries 53


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 that is defined in the FROM clause of
the outer SELECT statement. X designates rows of the first instance of
DSN8810.EMP. At any time during the execution of the query, X designates the row
of DSN8810.EMP to which the WHERE clause is being applied.

Consider what happens when the subquery executes for a given row of
DSN8810.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. Therefore, the following is the subquery that is executed for that row:
(SELECT AVG(EDLEVEL)
FROM DSN8810.EMP
WHERE WORKDEPT = ’A00’);

The subquery produces the average education level of Christine’s department. The
outer SELECT then compares this average 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 is similar to the following output:
EMPNO LASTNAME WORKDEPT EDLEVEL
====== ========= ======== =======
000010 HASS A00 18
000030 KWAN C01 20
000070 PULASKI D21 16
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 about correlated
references in nested table expressions and table functions, see “Using nested table
expressions and user-defined table functions in joins” on page 46. 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, with no restrictions


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

When you use a correlated reference in a subquery, the correlation name can be
defined in the outer SELECT or in 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. The subquery C can use a correlation reference that
is defined in B, A, or the outer SELECT.

You can define a correlation name for each table name in a FROM clause. Specify
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 the SQL
statement.

54 Application Programming and SQL Guide


The following example demonstrates the use of a correlated reference in the search
condition of a subquery:
SELECT EMPNO, LASTNAME, WORKDEPT, EDLEVEL
FROM DSN8810.EMP AS X
WHERE EDLEVEL >
(SELECT AVG(EDLEVEL)
FROM DSN8810.EMP
WHERE WORKDEPT = X.WORKDEPT);

The following example demonstrates the use of a correlated reference 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 2004, your department considers that
project to be a priority project. You can use the following SQL statement to evaluate
the projects in the DSN8810.PROJ table, and write a 1 (a flag to indicate
PRIORITY) in the PRIORITY column (a column you have added to DSN8810.PROJ
for this purpose) for each priority project:
UPDATE DSN8810.PROJ X
SET PRIORITY = 1
WHERE DATE(’2004-09-01’) >
(SELECT MAX(ACENDATE)
FROM DSN8810.PROJACT
WHERE PROJNO = X.PROJNO);

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


maximum activity end date (the ACENDATE column) for all activities of the project
(from the DSN8810.PROJACT table). If the end date of each activity associated
with the project is before September 2004, the current row in the DSN8810.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 that is named in the DELETE statement to decide whether or
not to delete the row.

Using tables with no referential constraints


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 DSN8810.PROJ table. In the
examples in this section, PROJ and PROJACT are independent tables; that is, they
are separate tables with no referential constraints defined on them.

Chapter 4. Using subqueries 55


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

To process this statement, DB2 determines for each project (represented by a row
in the DSN8810.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 DSN8810.PROJ table.

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

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

Using a single table


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 a copy of the employee table for the subquery.

The following statement, without a correlated subquery, yields equivalent results:


DELETE FROM YEMP
WHERE (SALARY, WORKDEPT) IN (SELECT MAX(SALARY), WORKDEPT
FROM YEMP
GROUP BY WORKDEPT);

Using tables with 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 that is
involved in the deletion, the last delete rule in the path to that table must be
| RESTRICT or NO ACTION if the result of the subquery is not materialized before
| the deletion occurs. However, if the result of the subquery is materialized before the
| deletion, the delete rule can also be CASCADE or SET NULL.

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 DSN8810.DEPT THIS
WHERE NOT DEPTNO =
(SELECT WORKDEPT
FROM DSN8810.EMP
WHERE EMPNO = THIS.MGRNO);

56 Application Programming and SQL Guide


With the referential constraints that are defined for the sample tables, this statement
| causes an error because the result table for the subquery is not materialized before
| the deletion occurs. The deletion involves the table that is referred to in the
subquery (DSN8810.EMP is a dependent table of DSN8810.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 depend on the order in which DB2
accesses the rows. Therefore, DB2 prohibits the deletion. See “Materialization” on
page 774 for more information about materialization.

Chapter 4. Using subqueries 57


58 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,” on page 1 by
following the instructions provided in this chapter and using the sample tables
shown in Appendix A, “DB2 sample tables,” on page 897. 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, see z/OS ISPF User’s
Guide Volumes 1 and 2.

To use SPUFI, select SPUFI from the DB2I Primary Option Menu as shown in
Figure 149 on page 496

The SPUFI panel then displays as shown in Figure 3.

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.

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 3. The SPUFI panel filled in

| Fill out the SPUFI panel. You can access descriptions for each of the fields in the
| panel in the DB2I help system. See “DB2I help” on page 495 for more information
| about the DB2I help system.

© Copyright IBM Corp. 1983, 2004 59


Changing SPUFI defaults (optional)
When you finish with the SPUFI panel, press the ENTER key. If 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 that you make to these values remain in
effect until you change the values again. Figure 4 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 4. The SPUFI defaults panel

If you want to change the current default values, specify new values in the fields of
| the panel. All fields must contain a value. The DB2I help system contains detailed
| descriptions of each of the fields of the CURRENT SPUFI DEFAULTS panel.

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.

Using the ISPF editor


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 5 on page 61.

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

60 Application Programming and SQL Guide


Figure 5. Indenting your lines and entering your statements on several lines make
your statements easier to read, without changing 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.

EDIT --------userid.EXAMPLES(XMP1) --------------------- COLUMNS 001 072


COMMAND INPUT ===> SAVE SCROLL ===> PAGE
********************************** TOP OF DATA ***********************
000100 SELECT LASTNAME, FIRSTNME, PHONENO
000200 FROM DSN8810.EMP
000300 WHERE WORKDEPT= ’D11’
000400 ORDER BY LASTNAME;
********************************* BOTTOM OF DATA *********************

Figure 5. 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. Saving the data set after every
10 minutes or so of editing is recommended.

Figure 5 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

| Retrieving Unicode UTF-16 graphic data


| When you request that Unicode UTF-16 graphic data (CCSID 1200) be retrieved by
| DB2 (in SQL statements submitted to SPUFI), DB2 attempts to convert from
| UTF-16 graphic data to EBCDIC graphic data. In many cases, this conversion is not
| valid. For example, if the column G1 contains UTF-16 graphic data, the following
| SELECT statement can result in SQLCODE -332:
| SELECT G1 FROM T1;

| However, you can use the CHAR function to explicitly request the result as
| character data. Instead of using G1 as an item in the select list, use CHAR(G1):
| SELECT CHAR(G1) FROM T1;

| The result of the CHAR function is a UTF-8 string (CCSID 1208) that is then
| converted to EBCDIC when the value is returned to SPUFI. The CCSID of the
| converted data depends on the value of the application-encoding BIND option for
| the SPUFI package. In most cases, the SPUFI result is the EBCDIC system
| CCSID.

Chapter 5. Executing SQL from your terminal using SPUFI 61


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

Setting the SQL terminator character


Use the text --#SET TERMINATOR character in a SPUFI input data set as an
instruction to SPUFI to interpret character as a statement terminator. A semicolon (;)
is the default SQL terminator. You can specify any single-byte character except one
of the characters that are listed in Table 3. 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.
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'

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.

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 must search, or on how many rows DB2 must process. To interrupt
DB2’s processing, press the PA1 key and respond to the prompting message that

62 Application Programming and SQL Guide


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 that are produced so far.

Browsing the output


SPUFI formats and displays the output data set using the ISPF Browse program.
Figure 6 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.

For SELECT statements executed with 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 DSN8810.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 6. Result data set from the sample problem

Chapter 5. Executing SQL from your terminal using SPUFI 63


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 (*).
– 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 60.
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

64 Application Programming and SQL Guide


Part 2. Coding SQL in your host application program
Chapter 6. Basics of coding SQL in an application program . . . . . . . 69
Conventions used in examples of coding SQL statements . . . . . . . . . 70
Delimiting an SQL statement . . . . . . . . . . . . . . . . . . . . 70
Declaring table and view definitions . . . . . . . . . . . . . . . . . 71
Accessing data using host variables, variable arrays, and structures . . . . . 71
Using host variables . . . . . . . . . . . . . . . . . . . . . . 72
Retrieving a single row of data into host variables . . . . . . . . . . 73
Updating data using values in host variables . . . . . . . . . . . . 74
Inserting data from column values that use host variables . . . . . . . 75
Using indicator variables with host variables . . . . . . . . . . . . 75
Assignments and comparisons using different data types . . . . . . . 77
Changing the coded character set ID of host variables . . . . . . . . 77
| Using host variable arrays . . . . . . . . . . . . . . . . . . . . 78
| Retrieving multiple rows of data into host variable arrays . . . . . . . 78
| Inserting multiple rows of data from host variable arrays . . . . . . . . 79
| Using indicator variable arrays with host variable arrays . . . . . . . . 79
Using host structures . . . . . . . . . . . . . . . . . . . . . 80
Retrieving a single row of data into a host structure . . . . . . . . . 80
Using indicator variables with host structures . . . . . . . . . . . . 81
Checking the execution of SQL statements . . . . . . . . . . . . . . 82
Using the SQL communication area (SQLCA) . . . . . . . . . . . . 82
SQLCODE and SQLSTATE . . . . . . . . . . . . . . . . . . . 83
Using the WHENEVER statement . . . . . . . . . . . . . . . . . 83
Handling arithmetic or conversion errors . . . . . . . . . . . . . . 84
| Using the GET DIAGNOSTICS statement . . . . . . . . . . . . . . 84
| Retrieving statement and condition items . . . . . . . . . . . . . 85
| Data types for GET DIAGNOSTICS items . . . . . . . . . . . . . 86
Calling DSNTIAR to display SQLCA fields . . . . . . . . . . . . . . 89
Defining a message output area . . . . . . . . . . . . . . . . 89
Possible return codes from DSNTIAR . . . . . . . . . . . . . . 90
Preparing to use DSNTIAR . . . . . . . . . . . . . . . . . . 90
A scenario for using DSNTIAR . . . . . . . . . . . . . . . . . 91

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


. 93
Accessing data by using a row-positioned cursor . . . . . . . . . . .
. 93
Step 1: Declare the cursor. . . . . . . . . . . . . . . . . . .
. 93
Step 2: Open the cursor . . . . . . . . . . . . . . . . . . .
. 95
Step 3: Specify what to do at end-of-data . . . . . . . . . . . . .
. 95
Step 4: Execute SQL statements . . . . . . . . . . . . . . . .
. 96
Using FETCH statements . . . . . . . . . . . . . . . . . .
. 96
Using positioned UPDATE statements . . . . . . . . . . . . .
. 97
Using positioned DELETE statements . . . . . . . . . . . . .
. 97
Step 5: Close the cursor . . . . . . . . . . . . . . . . . . .
. 98
| Accessing data by using a rowset-positioned cursor . . . . . . . . . .
. 98
| Step 1: Declare the rowset cursor . . . . . . . . . . . . . . . .
. 98
| Step 2: Open the rowset cursor . . . . . . . . . . . . . . . . .
. 98
| Step 3: Specify what to do at end-of-data for a rowset cursor . . . . . .
. 99
| Step 4: Execute SQL statements with a rowset cursor . . . . . . . .
. 99
| Using a multiple-row FETCH statement with host variable arrays . . .
. 99
| Using a multiple-row FETCH statement with a descriptor . . . . . .
. 99
| Using rowset-positioned UPDATE statements . . . . . . . . . . . 101
| Using rowset-positioned DELETE statements . . . . . . . . . . . 102
| Number of rows in a rowset . . . . . . . . . . . . . . . . . . 103

© Copyright IBM Corp. 1983, 2004 65


| Step 5: Close the rowset cursor . . . . . . . . . . . . . . . . . 103
Types of cursors . . . . . . . . . . . . . . . . . . . . . . . . 103
Scrollable and non-scrollable cursors . . . . . . . . . . . . . . . 103
Using a non-scrollable cursor . . . . . . . . . . . . . . . . . 103
Using a scrollable cursor . . . . . . . . . . . . . . . . . . . 104
| Comparison of scrollable cursors . . . . . . . . . . . . . . . . 108
Holes in the result table of a scrollable cursor . . . . . . . . . . . 109
Held and non-held cursors . . . . . . . . . . . . . . . . . . . 112
Examples of using cursors . . . . . . . . . . . . . . . . . . . . 114

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


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

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


Coding SQL statements in an assembler application. . . . . . . . . . . 129
Defining the SQL communications area . . . . . . . . . . . . . . 129
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 130
If you specify STDSQL(NO) . . . . . . . . . . . . . . . . . . 130
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 130
Embedding SQL statements . . . . . . . . . . . . . . . . . . 131
Using host variables . . . . . . . . . . . . . . . . . . . . . 133
Declaring host variables . . . . . . . . . . . . . . . . . . . . 133
Determining equivalent SQL and assembler data types . . . . . . . . 136
Notes on assembler variable declaration and usage . . . . . . . . . 139
Determining compatibility of SQL and assembler data types . . . . . . . 140
Using indicator variables . . . . . . . . . . . . . . . . . . . . 141
Handling SQL error return codes . . . . . . . . . . . . . . . . . 142
Macros for assembler applications . . . . . . . . . . . . . . . . 143
Coding SQL statements in a C or C++ application . . . . . . . . . . . 143
Defining the SQL communication area . . . . . . . . . . . . . . . 143
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 144
If you specify STDSQL(NO) . . . . . . . . . . . . . . . . . . 144
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 144
Embedding SQL statements . . . . . . . . . . . . . . . . . . 145
| Using host variables and host variable arrays . . . . . . . . . . . . 146
Declaring host variables . . . . . . . . . . . . . . . . . . . . 147
| Declaring host variable arrays . . . . . . . . . . . . . . . . . . 153
Using host structures . . . . . . . . . . . . . . . . . . . . . 158
Determining equivalent SQL and C data types . . . . . . . . . . . . 160
Notes on C variable declaration and usage . . . . . . . . . . . . 164
Notes on syntax differences for constants . . . . . . . . . . . . 165
Determining compatibility of SQL and C data types . . . . . . . . . . 166
Using indicator variables and indicator variable arrays . . . . . . . . . 167
Handling SQL error return codes . . . . . . . . . . . . . . . . . 169
Coding considerations for C and C++ . . . . . . . . . . . . . . . 170
Coding SQL statements in a COBOL application . . . . . . . . . . . . 170
Defining the SQL communication area . . . . . . . . . . . . . . . 170
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 171
If you specify STDSQL(NO) . . . . . . . . . . . . . . . . . . 171
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 171

66 Application Programming and SQL Guide


Embedding SQL statements . . . . . . . . . . . . . . . . . . 172
| Using host variables and host variable arrays . . . . . . . . . . . . 175
Declaring host variables . . . . . . . . . . . . . . . . . . . . 176
| Declaring host variable arrays . . . . . . . . . . . . . . . . . . 183
Using host structures . . . . . . . . . . . . . . . . . . . . . 189
Determining equivalent SQL and COBOL data types . . . . . . . . . 194
Notes on COBOL variable declaration and usage . . . . . . . . . . 196
Determining compatibility of SQL and COBOL data types . . . . . . . . 198
Using indicator variables and indicator variable arrays . . . . . . . . . 199
Handling SQL error return codes . . . . . . . . . . . . . . . . . 201
Coding considerations for object-oriented extensions in COBOL . . . . . 202
Coding SQL statements in a Fortran application . . . . . . . . . . . . 203
Defining the SQL communication area . . . . . . . . . . . . . . . 203
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 203
If you specify STDSQL(NO) . . . . . . . . . . . . . . . . . . 204
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 204
Embedding SQL statements . . . . . . . . . . . . . . . . . . 204
Using host variables . . . . . . . . . . . . . . . . . . . . . 206
Declaring host variables . . . . . . . . . . . . . . . . . . . . 207
Determining equivalent SQL and Fortran data types . . . . . . . . . . 208
Notes on Fortran variable declaration and usage . . . . . . . . . . 210
Notes on syntax differences for constants . . . . . . . . . . . . 210
Determining compatibility of SQL and Fortran data types . . . . . . . . 211
Using indicator variables . . . . . . . . . . . . . . . . . . . . 211
Handling SQL error return codes . . . . . . . . . . . . . . . . . 212
Coding SQL statements in a PL/I application . . . . . . . . . . . . . 213
Defining the SQL communication area . . . . . . . . . . . . . . . 213
If you specify STDSQL(YES) . . . . . . . . . . . . . . . . . 213
If you specify STDSQL(NO) . . . . . . . . . . . . . . . . . . 213
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 214
Embedding SQL statements . . . . . . . . . . . . . . . . . . 214
| Using host variables and host variable arrays . . . . . . . . . . . . 217
Declaring host variables . . . . . . . . . . . . . . . . . . . . 217
| Declaring host variable arrays . . . . . . . . . . . . . . . . . . 220
Using host structures . . . . . . . . . . . . . . . . . . . . . 223
Determining equivalent SQL and PL/I data types . . . . . . . . . . . 224
Notes on PL/I variable declaration and usage . . . . . . . . . . . 227
Determining compatibility of SQL and PL/I data types . . . . . . . . . 228
Using indicator variables and indicator variable arrays . . . . . . . . . 229
Handling SQL error return codes . . . . . . . . . . . . . . . . . 230
Coding considerations for PL/I . . . . . . . . . . . . . . . . . . 232
Coding SQL statements in a REXX application . . . . . . . . . . . . . 232
Defining the SQL communication area . . . . . . . . . . . . . . . 232
Defining SQL descriptor areas . . . . . . . . . . . . . . . . . . 233
Accessing the DB2 REXX Language Support application programming
interfaces . . . . . . . . . . . . . . . . . . . . . . . . 233
Embedding SQL statements in a REXX procedure . . . . . . . . . . 235
Using cursors and statement names . . . . . . . . . . . . . . . 237
Using REXX host variables and data types . . . . . . . . . . . . . 237
Determining equivalent SQL and REXX data types . . . . . . . . . 237
Letting DB2 determine the input data type . . . . . . . . . . . . 237
Ensuring that DB2 correctly interprets character input data . . . . . . 239
Passing the data type of an input variable to DB2 . . . . . . . . . 239
Retrieving data from DB2 tables . . . . . . . . . . . . . . . . 240
Using indicator variables . . . . . . . . . . . . . . . . . . . . 241
Setting the isolation level of SQL statements in a REXX procedure . . . . 241

Part 2. Coding SQL in your host application program 67


Chapter 10. Using constraints to maintain data integrity . . . . . . . . 243
Using check constraints . . . . . . . . . . . . . . . . . . . . . 243
Check constraint considerations . . . . . . . . . . . . . . . . . 243
When check constraints are enforced . . . . . . . . . . . . . . . 244
How check constraints set check pending status . . . . . . . . . . . 244
Using referential constraints. . . . . . . . . . . . . . . . . . . . 245
Parent key columns. . . . . . . . . . . . . . . . . . . . . . 245
Defining a parent key and a unique index . . . . . . . . . . . . . 246
Incomplete definition . . . . . . . . . . . . . . . . . . . . 247
Recommendations for defining primary keys . . . . . . . . . . . 247
Defining a foreign key . . . . . . . . . . . . . . . . . . . . . 248
The relationship name . . . . . . . . . . . . . . . . . . . . 248
Indexes on foreign keys . . . . . . . . . . . . . . . . . . . 248
The FOREIGN KEY clause in ALTER TABLE . . . . . . . . . . . 249
Restrictions on cycles of dependent tables . . . . . . . . . . . . 249
| Maintaining referential integrity when using data encryption . . . . . . 250
| Referential constraints on tables with multilevel security with row-level
| granularity . . . . . . . . . . . . . . . . . . . . . . . . 250
| Using informational referential constraints . . . . . . . . . . . . . . 250

| Chapter 11. Using DB2-generated values as keys . . . . . . . . . . 253


| Using ROWID columns as keys . . . . . . . . . . . . . . . . . . 253
| Defining a ROWID column . . . . . . . . . . . . . . . . . . . 253
| Direct row access . . . . . . . . . . . . . . . . . . . . . . 253
| Considerations for using ROWID columns . . . . . . . . . . . . . 254
| Using identity columns as keys . . . . . . . . . . . . . . . . . . 254
| Defining an identity column . . . . . . . . . . . . . . . . . . . 255
| Parent keys and foreign keys . . . . . . . . . . . . . . . . . . 256
| Considerations for using identity columns . . . . . . . . . . . . . . 257
| Using values obtained from sequence objects as keys . . . . . . . . . . 257
| Creating a sequence object . . . . . . . . . . . . . . . . . . . 257
| Referencing a sequence object . . . . . . . . . . . . . . . . . 258
| Keys across multiple tables . . . . . . . . . . . . . . . . . . . 258
| Considerations for using sequence numbers . . . . . . . . . . . . 259

Chapter 12. Using triggers for active data . . . . . . . . . . . . .


261
Example of creating and using a trigger . . . . . . . . . . . . . . .
261
Parts of a trigger . . . . . . . . . . . . . . . . . . . . . . . .
263
Trigger name . . . . . . . . . . . . . . . . . . . . . . . .
263
Subject table . . . . . . . . . . . . . . . . . . . . . . . .
263
Trigger activation time . . . . . . . . . . . . . . . . . . . . .
263
Triggering event . . . . . . . . . . . . . . . . . . . . . . .
263
Granularity . . . . . . . . . . . . . . . . . . . . . . . . .
264
Transition variables . . . . . . . . . . . . . . . . . . . . . .
265
Transition tables . . . . . . . . . . . . . . . . . . . . . . .
266
Triggered action . . . . . . . . . . . . . . . . . . . . . . .
267
Trigger condition . . . . . . . . . . . . . . . . . . . . . .
267
Trigger body . . . . . . . . . . . . . . . . . . . . . . .
267
Invoking stored procedures and user-defined functions from triggers . . . . .
269
Passing transition tables to user-defined functions and stored procedures 270
Trigger cascading . . . . . . . . . . . . . . . . . . . . . . . 270
Ordering of multiple triggers. . . . . . . . . . . . . . . . . . . . 271
Interactions between triggers and referential constraints . . . . . . . . . 272
| Interactions between triggers and tables that have multilevel security with
| row-level granularity . . . . . . . . . . . . . . . . . . . . . . 273
Creating triggers to obtain consistent results . . . . . . . . . . . . . 274

68 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 perform the following actions:


v Choose a method for communicating with DB2. You can use one of the following
methods:
– Static SQL
– Embedded dynamic SQL
– Open Database Connectivity (ODBC)
– JDBC application support
– SQLJ application support
This book discusses embedded SQL. See Chapter 24, “Coding dynamic SQL in
application programs,” on page 535 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. In addition to using JDBC, you can use SQLJ application support
to access DB2. SQLJ is designed to simplify the coding of DB2 calls for Java
applications. For more information about using both JDBC and SQLJ, see DB2
Application Programming Guide and Reference for Java.
v Delimit SQL statements, as described in “Delimiting an SQL statement” on page
70.
v Declare the tables that you use, as described in “Declaring table and view
definitions” on page 71. (This is optional.)
v Declare the data items for passing data between DB2 and a host language,
according to the host language rules described in Chapter 9, “Embedding SQL
statements in host languages,” on page 129.
v Code SQL statements to access DB2 data. See “Accessing data using host
variables, variable arrays, and structures” on page 71.
For information about using the SQL language, see Part 1, “Using SQL queries,”
on page 1 and DB2 SQL Reference. Details about how to use SQL statements
within application programs are described in Chapter 9, “Embedding SQL
statements in host languages,” on page 129.
v Declare an SQL communications area (SQLCA). Alternatively, you can use the
GET DIAGNOSTICS statement to provide diagnostic information about the last
SQL statement that executed. See “Checking the execution of SQL statements”
on page 82 for more information.

In addition to these basic requirements, you should also consider the following
special topics:
v Cursors — Chapter 7, “Using a cursor to retrieve a set of rows,” on page 93
discusses how to use a cursor in your application program to select a set of rows
and then process the set either one row at a time or one rowset at a time.
© Copyright IBM Corp. 1983, 2004 69
v DCLGEN — Chapter 8, “Generating declarations for your tables using DCLGEN,”
on page 121 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, C++, COBOL, Fortran, PL/I, and REXX.

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 C or COBOL application program. Each SQL
example is displayed on several lines, with each clause of the statement on a
separate line.
v The use of the precompiler options APOST and APOSTSQL are assumed
(although they are not the defaults). Therefore, apostrophes (’) are used to
delimit character string literals within SQL and host language statements.
v The SQL statements access data in the sample tables provided with DB2. The
tables contain data that a manufacturing company might keep about its
employees and its current projects. For a description of the tables, see
Appendix A, “DB2 sample tables,” on page 897.
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 19 and “Using referential constraints” on
page 245.

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

Delimiting an SQL statement


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

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

Example: Use EXEC SQL and END-EXEC. to delimit an SQL statement in a COBOL
program:
EXEC SQL
an SQL statement
END-EXEC.

70 Application Programming and SQL Guide


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

You do not need to declare tables or views, but doing so offers advantages. One
advantage is documentation. For example, the DECLARE statement specifies the
structure of the table or view you are working with, and the data type of each
column. You can refer to the DECLARE statement for the column names and data
types in the table or view. Another advantage is that the DB2 precompiler uses your
declarations to make sure that you have used correct column names and data
types in your SQL statements. The DB2 precompiler issues a warning message
when the column names and data types do not correspond to the SQL DECLARE
statements in your program.

One way to declare a table or view is to code a DECLARE statement in the


WORKING-STORAGE SECTION or LINKAGE SECTION within the DATA DIVISION
of your COBOL program. Specify the name of the table and list each column and its
data type. When you declare a table or view, you specify DECLARE table-name
TABLE regardless of whether the table-name refers to a table or a view.

For example, the DECLARE TABLE statement for the DSN8810.DEPT table looks
like the following DECLARE statement in COBOL:
EXEC SQL
DECLARE DSN8810.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 that is supplied with DB2. For more
information about using DCLGEN, see Chapter 8, “Generating declarations for your
tables using DCLGEN,” on page 121.

When you declare a table or view that contains a column with a distinct type,
declare that column with the source type of the distinct type, rather than with the
distinct type itself. When you declare the column with the source type, DB2 can
check embedded SQL statements that reference that column at precompile time.

Accessing data using host variables, variable arrays, and structures


| You can access data by using host variables, host variable arrays, and host
| structures within the SQL statements that you use in your application program.

A host variable is a data item that is 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 that is in the host variable to a special register, such as
CURRENT SQLID and CURRENT DEGREE

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


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 variable array is a data array that is declared in the host language for use
| within an SQL statement. Using host variable arrays, you can:
| v Retrieve data into host variable arrays for your application program’s use
| v Place data into host variable arrays to insert rows into a table

A host structure is a group of host variables that is referred to by a single name.


You can use host structures in all host languages except REXX. Host structures are
defined by statements of the host language. You can refer to a host structure in any
context where you would refer to the list of host variables in the structure. A host
structure reference is equivalent to a reference to each of the host variables within
the structure in the order in which they are defined in the structure declaration.

This section describes:


v “Using host variables”
v “Using host variable arrays” on page 78
v “Using host structures” on page 80

Using host variables


To use a host variable in an SQL statement, you can specify any valid host variable
name that is declared according to the rules of the host language, as described in
Chapter 9, “Embedding SQL statements in host languages,” on page 129. You must
declare the name of the host variable in the host program before you use it.

To optimize performance, make sure that the host language declaration maps as
closely as possible to the data type of the associated data in the database. For
more performance suggestions, see Part 6, “Additional programming techniques,”
on page 525.

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 24, “Coding dynamic SQL in
application programs,” on page 535 for more information.)

Host variables follow the naming conventions of the host language. A colon (:) must
precede host variables that are used in SQL statements so DB2 can distinguish a
variable name from a column name. A colon must not precede host variables
outside of SQL statements.

For more information about declaring host variables, see the appropriate language
section:
v Assembler: “Declaring host variables” on page 133
v C and C++: “Declaring host variables” on page 147
v COBOL: “Declaring host variables” on page 176
v Fortran: “Declaring host variables” on page 207
v PL/I: “Declaring host variables” on page 217
v REXX: “Using REXX host variables and data types” on page 237.

This section describes the following ways to use host variables:


v “Retrieving a single row of data into host variables” on page 73
v “Updating data using values in host variables” on page 74

72 Application Programming and SQL Guide


v “Inserting data from column values that use host variables” on page 75
v “Using indicator variables with host variables” on page 75
v “Assignments and comparisons using different data types” on page 77
v “Changing the coded character set ID of host variables” on page 77

Retrieving a single row of data into host variables


You can use one or more host variables to specify a program data area that is to
contain the column values of a retrieved row. The INTO clause of the SELECT
statement names one or more host variables to contain the retrieved column
values. The named variables correspond one-to-one with the list of column names
in the SELECT statement.

If you do not know how many rows DB2 will return, or if you expect more than one
row to return, you must use an alternative to the SELECT ... INTO statement. The
DB2 cursor enables an application to return a set of rows and fetch either one row
at a time or one rowset at a time from the result table. For information about using
cursors, see Chapter 7, “Using a cursor to retrieve a set of rows,” on page 93.

Example: Retrieving a single row: Suppose you are retrieving the LASTNAME
and WORKDEPT column values from the DSN8810.EMP table for a particular
employee. You can define a host variable in your program to hold each column and
then name the host variables with an INTO clause, as in the following COBOL
example:
MOVE ’000110’ TO CBLEMPNO.
EXEC SQL
SELECT LASTNAME, WORKDEPT
INTO :CBLNAME, :CBLDEPT
FROM DSN8810.EMP
WHERE EMPNO = :CBLEMPNO
END-EXEC.

Note that the host variable CBLEMPNO is preceded by a colon (:) in the SQL
statement, but it is not preceded by a colon in the COBOL MOVE statement. In the
DATA DIVISION section of a COBOL program, you must declare the host variables
CBLEMPNO, CBLNAME, and CBLDEPT to be compatible with the data types in the
columns EMPNO, LASTNAME, and WORKDEPT of the DSN8810.EMP table.

You can use a host variable to specify a value in a search condition. For this
example, you have defined a host variable CBLEMPNO for the employee number,
so that you can retrieve the name and the work department of the employee whose
number is the same as the value of the host variable, CBLEMPNO; in this case,
000110.

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

To prevent undefined and unpredictable data from being returned, you can use the
FETCH FIRST 1 ROW ONLY clause to ensure that only one row is returned. For
example:
EXEC SQL
SELECT LASTNAME, WORKDEPT
INTO :CBLNAME, :CBLDEPT
FROM DSN8810.EMP
FETCH FIRST 1 ROW ONLY
END-EXEC.

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


| You can include an ORDER BY clause in the preceding example. This gives your
| application some control over which row is returned when you use a FETCH FIRST
| 1 ROW ONLY clause in a SELECT INTO statement.
| EXEC SQL
| SELECT LASTNAME, WORKDEPT
| INTO :CBLNAME, :CBLDEPT
| FROM DSN8810.EMP
| ORDER BY LASTNAME
| FETCH FIRST 1 ROW ONLY
| END-EXEC.

| When you specify both the ORDER BY clause and the FETCH FIRST clause,
| ordering is done first and then the first row is returned. This means that the ORDER
| BY clause determines which row is returned. If you specify both the ORDER BY
| clause and the FETCH FIRST clause, ordering is performed on the entire result set
| before the first row is returned.

Example: Specifying expressions in the SELECT clause: When you specify a


list of items in the SELECT clause, you can use more than the column names of
tables and views. You can request a set of column values mixed with host variable
values and constants. For example:
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 DSN8810.EMP
WHERE EMPNO = :PERSON
END-EXEC.

The following results 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

Example: Specifying summary values in the SELECT clause: You can request
| summary values to be returned from aggregate functions. For example:
MOVE ’D11’ TO DEPTID.
EXEC SQL
SELECT WORKDEPT, AVG(SALARY)
INTO :WORK-DEPT, :AVG-SALARY
FROM DSN8810.EMP
WHERE WORKDEPT = :DEPTID
END-EXEC.

Updating data using values in host variables


You can set or change values in a DB2 table to the value of host variables. To do
this, use the host variable name in the SET clause of the UPDATE statement.

Example: Updating a single row: The following example changes an employee’s


phone number:
MOVE ’4246’ TO NEWPHONE.
MOVE ’000110’ TO EMPID.
EXEC SQL
UPDATE DSN8810.EMP
SET PHONENO = :NEWPHONE
WHERE EMPNO = :EMPID
END-EXEC.

74 Application Programming and SQL Guide


Example: Updating multiple rows: The following example gives the employees in
a particular department a salary increase of 10%:
MOVE ’D11’ TO DEPTID.
EXEC SQL
UPDATE DSN8810.EMP
SET SALARY = 1.10 * SALARY
WHERE WORKDEPT = :DEPTID
END-EXEC.

Inserting data from column values that use host variables


You can insert a single row of data into a DB2 table by using the INSERT statement
with column values in the VALUES clause. A column value can be a host variable, a
constant, or any valid combination of host variables and constants.

| To insert multiple rows, you can use the form of the INSERT statement that selects
| values from another table or view. You can also use a form of the INSERT
| statement that inserts multiple rows from values that are provided in host variable
| arrays. For more information, see “Inserting multiple rows of data from host variable
| arrays” on page 79.

| Example: The following example inserts a single row into the activity table:
| EXEC SQL
| INSERT INTO DSN8810.ACT
| VALUES (:HV-ACTNO, :HV-ACTKWD, :HV-ACTDESC)
| 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 the value of an input host variable is null
v Determine the original length of a character string that was truncated during
assignment to a host variable
v Determine that a character value could not be converted during assignment to a
host variable
v Determine the seconds portion of a time value that was truncated during
assignment to a host variable

Retrieving data and testing the indicator variable: When DB2 retrieves the value
of a column into a host variable, you can test the indicator variable that is
associated with that host variable:
v If the value of the indicator variable is less than zero, the column value is null.
The value of the host variable does not change from its previous value. If it is
null because of a numeric or character conversion error, or an arithmetic
expression error, DB2 sets the indicator variable to -2. See “Handling arithmetic
or conversion errors” on page 84 for more information.
v If the indicator variable contains a positive integer, the retrieved value is
truncated, and the integer is the original length of the string.
v If the value of the indicator variable is zero, the column value is nonnull. If the
column value is a character string, the retrieved value is not truncated.

An error occurs if you do not use an indicator variable and DB2 retrieves a null
value.

You can specify an indicator variable, preceded by a colon, immediately after the
host variable. Optionally, you can use the word INDICATOR between the host

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


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 DSN8810.EMP FROM DSN8810.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.

When you use a cursor to fetch a column value, you can use the same technique to
determine whether the column value is null.

Inserting null values into columns by using host variable indicators: You can
use an indicator variable to insert a null value from a host variable into a column.
When DB2 processes INSERT and UPDATE statements, it checks the indicator
variable (if one exists). If the indicator variable is negative, the column value is null.
If the indicator variable is greater than -1, the associated host variable contains a
value for the column.

For example, suppose your program reads an employee ID and a new phone
number, and must update the employee table with the new number. The new
number could be missing if the old number is incorrect, but a new number is not yet
available. If the new value for column PHONENO might be null, you can use an
indicator variable in the UPDATE statement. For example:
EXEC SQL
UPDATE DSN8810.EMP
SET PHONENO = :NEWPHONE:PHONEIND
WHERE EMPNO = :EMPID
END-EXEC.

When NEWPHONE contains a non-null value, set PHONEIND to zero by preceding


the UPDATE statement with the following line:
MOVE 0 TO PHONEIND.

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


preceding the UPDATE statement with the following line:
MOVE -1 TO PHONEIND.

Testing for a null column value: You cannot determine whether a column value is
null by comparing it to a host variable with an indicator variable that is set to -1. To
| test whether a column has a null value, use the IS NULL predicate or the IS
| DISTINCT FROM predicate. For example, the following code does not select the
employees who have no phone number:
MOVE -1 TO PHONE-IND.
EXEC SQL
SELECT LASTNAME
INTO :PGM-LASTNAME
FROM DSN8810.EMP
WHERE PHONENO = :PHONE-HV:PHONE-IND
END-EXEC.

You can use the IS NULL predicate to select employees who have no phone
number, as in the following statement:

76 Application Programming and SQL Guide


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

| To select employees whose phone numbers are equal to the value of :PHONE-HV
| and employees who have no phone number (as in the second example), you would
| need to code two predicates, one to handle the non-null values and another to
| handle the null values, as in the following statement:
| EXEC SQL
| SELECT LASTNAME
| INTO :PGM-LASTNAME
| FROM DSN8810.EMP
| WHERE (PHONENO = :PHONE-HV AND PHONENO IS NOT NULL AND :PHONE-HV IS NOT NULL)
| OR
| (PHONENO IS NULL AND :PHONE-HV:PHONE-IND IS NULL)
| END-EXEC.

| You can simplify the preceding example by coding the statement using the NOT
| form of the IS DISTINCT FROM predicate, as in the following statement:
| EXEC SQL
| SELECT LASTNAME
| INTO :PGM-LASTNAME
| FROM DSN8810.EMP
| WHERE PHONENO IS NOT DISTINCT FROM :PHONE-HV:PHONE-IND
| 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
retrieved data to a host variable or compare retrieved data to a value in a host
variable, see Chapter 2 of DB2 SQL Reference for the rules that are associated
with these operations.

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 561 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
your first reference to that host variable.

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


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 UDB for z/OS subsystem. The subsystem has an EBCDIC application
encoding scheme. The C program retrieves data from the following columns of a
local table that is defined with CCSID UNICODE.
PARTNUM CHAR(10)
JPNNAME GRAPHIC(10)
ENGNAME VARCHAR(30)

Because the application encoding scheme for the subsystem is EBCDIC, the
retrieved data is EBCDIC. To make the retrieved data Unicode, use DECLARE
VARIABLE statements to specify that the data that is retrieved from these columns
is encoded in the default Unicode CCSIDs for the subsystem. Suppose that you
want to retrieve the character data in Unicode CCSID 1208 and the graphic data in
Unicode CCSID 1200. Use DECLARE VARIABLE statements like these:
EXEC SQL BEGIN DECLARE SECTION;
char hvpartnum[11];
EXEC SQL DECLARE :hvpartnum VARIABLE CCSID 1208;
| sqldbchar hvjpnname[11];
EXEC SQL DECLARE :hvjpnname VARIABLE CCSID 1200;
struct {
short len;
char d[30];
} hvengname;
EXEC SQL DECLARE :hvengname VARIABLE CCSID 1208;
EXEC SQL END DECLARE SECTION;

The BEGIN DECLARE SECTION and END DECLARE SECTION statements mark
the beginning and end of a host variable declare section.

| Using host variable arrays


| To use a host variable array in an SQL statement, specify any valid host variable
| array that is declared according to the host language rules that are described in
| Chapter 9, “Embedding SQL statements in host languages,” on page 129. You can
| specify host variable arrays in C or C++, COBOL, and PL/I. You must declare the
| array in the host program before you use it.

| For more information about declaring host variable arrays, see the appropriate
| language section:
| v C or C++: “Declaring host variable arrays” on page 153
| v COBOL: “Declaring host variable arrays” on page 183
| v PL/I: “Declaring host variable arrays” on page 220

| Assembler support for the multiple-row FETCH statement is limited to these


| statements with the USING DESCRIPTOR clause. The DB2 precompiler does not
| recognize declarations of host variable arrays for Assembler; it recognizes these
| declarations only in C, COBOL, and PL/I.

| This section describes the following ways to use host variable arrays:
| v “Retrieving multiple rows of data into host variable arrays”
| v “Inserting multiple rows of data from host variable arrays” on page 79
| v “Using indicator variable arrays with host variable arrays” on page 79

| Retrieving multiple rows of data into host variable arrays


| You can use host variable arrays to specify a program data area to contain multiple
| rows of column values. A DB2 rowset cursor enables an application to retrieve and

78 Application Programming and SQL Guide


| process a set of rows from the result table of the cursor. For information about
| using rowset cursors, see “Accessing data by using a rowset-positioned cursor” on
| page 98.

| Inserting multiple rows of data from host variable arrays


| You can use a form of the INSERT statement to insert multiple rows from values
| that are provided in host variable arrays. Each array contains values for a column of
| the target table. The first value in an array corresponds to the value for that column
| for the first inserted row, the second value in the array corresponds to the value for
| the column in the second inserted row, and so on. DB2 determines the attributes of
| the values based on the declaration of the array.

| Example: You can insert the number of rows that are specified in the host variable
| NUM-ROWS by using the following INSERT statement:
| EXEC SQL
| INSERT INTO DSN8810.ACT
| (ACTNO, ACTKWD, ACTDESC)
| VALUES (:HVA1, :HVA2, :HVA3)
| FOR :NUM-ROWS ROWS
| END-EXEC.

| Assume that the host variable arrays HVA1, HVA2, and HVA3 have been declared
| and populated with the values that are to be inserted into the ACTNO, ACTKWD,
| and ACTDESC columns. The NUM-ROWS host variable specifies the number of
| rows that are to be inserted, which must be less than or equal to the dimension of
| each host variable array.

| Using indicator variable arrays with host variable arrays


| You can use indicator variable arrays with host variable arrays in the same way that
| you use indicator variables with host variables. For details, see “Using indicator
| variables with host variables” on page 75. An indicator variable array must have at
| least as many entries as its host variable array.

| Retrieving data and using indicator arrays: When you retrieve data into a host
| variable array, if a value in its indicator array is negative, you can disregard the
| contents of the corresponding element in the host variable array. If a value in an
| indicator array is:
| -1 The corresponding row in the column that is being retrieved is null.
| -2 DB2 returns a null value because an error occurred in numeric conversion
| or in an arithmetic expression in the corresponding row.
| -3 DB2 returns a null value because a hole was detected for the
| corresponding row during a multiple-row FETCH operation.

| For information about the multiple-row FETCH operation, see “Step 4: Execute SQL
| statements with a rowset cursor” on page 99. For information about holes in the
| result table of a cursor, see “Holes in the result table of a scrollable cursor” on page
| 109.

| Specifying an indicator array: You can specify an indicator variable array,


| preceded by a colon, immediately after the host variable array. Optionally, you can
| use the word INDICATOR between the host variable array and its indicator variable
| array.

| Example: Suppose that you declare a scrollable rowset cursor by using the
| following statement:

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


| EXEC SQL
| DECLARE CURS1 SCROLL CURSOR WITH ROWSET POSITIONING FOR
| SELECT PHONENO
| FROM DSN8810.EMP
| END-EXEC.

| For information about using rowset cursors, see “Accessing data by using a
| rowset-positioned cursor” on page 98.

| The following two specifications of indicator arrays in the multiple-row FETCH


| statement are equivalent:
|
| EXEC SQL EXEC SQL
| FETCH NEXT ROWSET CURS1 FETCH NEXT ROWSET CURS1
| FOR 10 ROWS FOR 10 ROWS
| INTO :CBLPHONE :INDNULL INTO :CBLPHONE INDICATOR :INDNULL
| END-EXEC. END-EXEC.
|

| After the multiple-row FETCH statement, you can test each element of the
| INDNULL array for a negative value. If an element is negative, you can disregard
| the contents of the corresponding element in the CBLPHONE host variable array.

| Inserting null values by using indicator arrays: You can use a negative value in
| an indicator array to insert a null value into a column.

| Example: Assume that host variable arrays hva1 and hva2 have been populated
| with values that are to be inserted into the ACTNO and ACTKWD columns. Assume
| the ACTDESC column allows nulls. To set the ACTDESC column to null, assign -1
| to the elements in its indicator array:
| /* Initialize each indicator array */
| for (i=0; i<10; i++) {
| ind1[i] = 0;
| ind2[i] = 0;
| ind3[i] = -1;
| }
|
| EXEC SQL
| INSERT INTO DSN8810.ACT
| (ACTNO, ACTKWD, ACTDESC)
| VALUES (:hva1:ind1, :hva2:ind2, :hva3:ind3)
| FOR 10 ROWS;

| DB2 ignores the values in the hva3 array and assigns the values in the ARTDESC
| column to null for the 10 rows that are inserted.

Using host structures


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

Retrieving a single row of data into a host structure


In the following example, assume that your COBOL program includes the following
SQL statement:
EXEC SQL
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, WORKDEPT
INTO :EMPNO, :FIRSTNME, :MIDINIT, :LASTNAME, :WORKDEPT
FROM DSN8810.VEMP
WHERE EMPNO = :EMPID
END-EXEC.

80 Application Programming and SQL Guide


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 DSN8810.VEMP
WHERE EMPNO = :EMPID
END-EXEC.

You can declare a host structure yourself, or you can use DCLGEN to generate a
COBOL record description, PL/I structure declaration, or C structure declaration that
corresponds to the columns of a table. For more detailed information about coding
a host structure in your program, see Chapter 9, “Embedding SQL statements in
host languages,” on page 129. For more information about using DCLGEN and the
restrictions that apply to the C language, see Chapter 8, “Generating declarations
for your tables using DCLGEN,” on page 121.

Using indicator variables with host structures


You can define an indicator structure (an array of halfword integer variables) to
support a host structure. You define indicator structures in the DATA DIVISION
section of your COBOL program. If the column values your program retrieves into a
host structure can be null, you can attach an indicator structure name to the host
structure name. This allows DB2 to notify your program about each null value it
returns to a host variable in the host structure. For example:
01 PEMP-ROW.
10 EMPNO 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 DSN8810.EMP
WHERE EMPNO = :EMPNO
END-EXEC.

In this example, EMP-IND is an array containing six values, which you can test for
negative values. If, for example, EMP-IND(6) contains a negative value, the
corresponding host variable in the host structure (EMP-BIRTHDATE) contains a null
value.

Because this example selects rows from the table DSN8810.EMP, some of the
values in EMP-IND are always zero. The first four columns of each row are defined
NOT NULL. In the preceding example, DB2 selects the values for a row of data into
a host structure. You must use a corresponding structure for the indicator variables
to determine which (if any) selected column values are null. For information on
using the IS NULL keyword phrase in WHERE clauses, see “Selecting rows using
search conditions: WHERE” on page 8.

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


Checking the execution of SQL statements
You can check the execution of SQL statements in various ways:
v By displaying specific fields in the SQLCA; see “Using the SQL communication
area (SQLCA).”
v By testing SQLCODE or SQLSTATE for specific values; see “SQLCODE and
SQLSTATE” on page 83.
v By using the WHENEVER statement in your application program; see “Using the
WHENEVER statement” on page 83.
v By testing indicator variables to detect numeric errors; see “Handling arithmetic
or conversion errors” on page 84.
| v By using the GET DIAGNOSTICS statement in your application program to return
| all the condition information that results from the execution of an SQL statement;
| see “Using the GET DIAGNOSTICS statement” on page 84.
v By calling DSNTIAR to display the contents of the SQLCA; see “Calling
DSNTIAR to display SQLCA fields” on page 89.

Using the SQL communication area (SQLCA)


A program that includes SQL statements can have an area set apart for
communication with DB2—an SQL communication area (SQLCA). If you use the
SQLCA, include the necessary instructions to display information that is contained
in the SQLCA in your application program. Alternatively, you can use the GET
DIAGNOSTICS statement, which is an SQL standard, to diagnose problems.
v When DB2 processes an SQL statement, it places return codes that indicate the
success or failure of the statement execution in SQLCODE and SQLSTATE. For
details, see “SQLCODE and SQLSTATE” on page 83.
v When DB2 processes an UPDATE, INSERT, or DELETE statement, and the
statement execution is successful, the contents of SQLERRD(3) in the SQLCA is
set to the number of rows that are updated, inserted, or deleted.
v When DB2 processes a FETCH statement, and the FETCH is successful, the
contents of SQLERRD(3) in the SQLCA is set to the number of returned rows.
| v When DB2 processes a multiple-row FETCH statement, the contents of
| SQLCODE is set to +100 if the last row in the table has been returned with the
| set of rows. For details, see “Accessing data by using a rowset-positioned cursor”
| on page 98.
v If SQLWARN0 contains W, DB2 has set at least one of the SQL warning flags
(SQLWARN1 through SQLWARNA):
– SQLWARN1 contains N for non-scrollable cursors and S for scrollable cursors
after an OPEN CURSOR or ALLOCATE CURSOR statement.
– SQLWARN4 contains I for insensitive scrollable cursors, S for sensitive static
scrollable cursors, and D for sensitive dynamic scrollable cursors, after an
OPEN CURSOR or ALLOCATE CURSOR statement, or blank if the cursor is
not scrollable.
– SQLWARN5 contains a character value of 1 (read only), 2 (read and delete),
or 4 (read, delete, and update) to indicate the operation that is allowed on the
result table of the cursor.

See Appendix C of DB2 SQL Reference for a description of all the fields in the
SQLCA.

82 Application Programming and SQL Guide


SQLCODE and SQLSTATE
Whenever an SQL statement executes, the SQLCODE and SQLSTATE fields of the
SQLCA receive a return code. Portable applications should use SQLSTATE instead
of SQLCODE, although SQLCODE values can provide additional DB2-specific
information about an SQL error or warning.

SQLCODE: DB2 returns the following codes in SQLCODE:


v If SQLCODE = 0, execution was successful.
v If SQLCODE > 0, execution was successful with a warning.
v If SQLCODE < 0, execution was not successful.

SQLCODE 100 indicates that no data was found.

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

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

Using SQLCODE and SQLSTATE: An advantage to using the SQLCODE field is


that it can provide more specific information than the SQLSTATE. Many of the
SQLCODEs have associated tokens in the SQLCA that indicate, for example, which
object incurred an SQL error. However, an SQL standard application uses only
SQLSTATE.

You can declare SQLCODE and SQLSTATE (SQLCOD and SQLSTA in Fortran) as
stand-alone host variables. If you specify the STDSQL(YES) precompiler option,
these host variables receive the return codes, and you should not include an
SQLCA in your program.

Using the WHENEVER statement


The WHENEVER statement causes DB2 to check the SQLCA and continue
processing your program, or branch to another area in your program if an error,
exception, or warning occurs. The condition handling area of your program can then
examine SQLCODE or SQLSTATE to react specifically to the error or exception.

The WHENEVER statement is not supported for REXX. For information on REXX
error handling, see “Embedding SQL statements in a REXX procedure” on page
235.

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

The condition of the WHENEVER statement is one of these three values:


SQLWARNING
Indicates what to do when SQLWARN0 = W or SQLCODE contains a
positive value other than 100. DB2 can set SQLWARN0 for several

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


reasons—for example, if a column value is truncated when moved into a
host variable. Your program might not regard this as an error.
SQLERROR
Indicates what to do when DB2 returns an error code as the result of an
SQL statement (SQLCODE < 0).
NOT FOUND
Indicates what to do when DB2 cannot find a row to satisfy your SQL
statement or when there are no more rows to fetch (SQLCODE = 100).

The action of the WHENEVER statement is one of these two values:


CONTINUE
Specifies the next sequential statement of the source program.
GOTO or GO TO host-label
Specifies the statement identified by host-label. For host-label, substitute a
single token, preceded by 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, you must check SQLCODE
after each SQL statement.

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 do not
necessarily halt the execution of a SELECT statement. If you use indicator variables
and an error occurs in the SELECT list, the statement can continue to execute and
return good data for rows in which the error does not occur.

For rows in which a conversion or arithmetic expression error does occur, the
indicator variable indicates that one or more selected items have no meaningful
value. The indicator variable flags this error with a -2 for the affected host variable
and an SQLCODE of +802 (SQLSTATE ’01519’) in the SQLCA.

| Using the GET DIAGNOSTICS statement


| You can use the GET DIAGNOSTICS statement to return diagnostic information
| about the last SQL statement that was executed. You can request individual items
| of diagnostic information from the following groups of items:
| v Statement items, which contain information about the SQL statement as a whole
| v Condition items, which contain information about each error or warning that
| occurred during the execution of the SQL statement
| v Connection items, which contain information about the SQL statement if it was a
| CONNECT statement
| In addition to requesting individual items, you can request that GET DIAGNOSTICS
| return ALL diagnostic items that are set during the execution of the last SQL
| statement as a single string. For more information, see Chapter 5 of DB2 SQL
| Reference.

| Use the GET DIAGNOSTICS statement to handle multiple SQL errors that might
| result from the execution of a single SQL statement. First, check SQLSTATE (or
| SQLCODE) to determine whether diagnostic information should be retrieved by

84 Application Programming and SQL Guide


| using GET DIAGNOSTICS. This method is especially useful for diagnosing
| problems that result from a multiple-row INSERT that is specified as NOT ATOMIC
| CONTINUE ON SQLEXCEPTION.

| Even if you use only the GET DIAGNOSTICS statement in your application program
| to check for conditions, you must either include the instructions required to use the
| SQLCA or you must declare SQLSTATE (or SQLCODE) separately in your program.

| Restriction: If you issue a GET DIAGNOSTICS statement immediately following an


| SQL statement that uses private protocol access, DB2 returns an error.

| Retrieving statement and condition items


| When you use the GET DIAGNOSTICS statement, you assign the requested
| diagnostic information to host variables. Declare each target host variable with a
| data type that is compatible with the data type of the requested item. For a
| description of available items and their data types, see “Data types for GET
| DIAGNOSTICS items” on page 86.

| To retrieve condition information, you must first retrieve the number of condition
| items (that is, the number of errors and warnings that DB2 detected during the
| execution of the last SQL statement). The number of condition items is at least one.
| If the last SQL statement returned SQLSTATE ’00000’ (or SQLCODE 0), the
| number of condition items is one.

| Example: Using GET DIAGNOSTICS with multiple-row INSERT: You want to


| display diagnostic information for each condition that might occur during the
| execution of a multiple-row INSERT statement in your application program. You
| specify the INSERT statement as NOT ATOMIC CONTINUE ON SQLEXCEPTION,
| which means that execution continues regardless of the failure of any single-row
| insertion. DB2 does not insert the row that was processed at the time of the error.

| In Figure 7 on page 86, the first GET DIAGNOSTICS statement returns the number
| of rows inserted and the number of conditions returned. The second GET
| DIAGNOSTICS statement returns the following items for each condition:
| SQLCODE, SQLSTATE, and the number of the row (in the rowset that was being
| inserted) for which the condition occurred.
|

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


EXEC SQL BEGIN DECLARE SECTION;
long row_count, num_condns, i;
long ret_sqlcode, row_num;
char ret_sqlstate[6];
...
EXEC SQL END DECLARE SECTION;
...
EXEC SQL
INSERT INTO DSN8810.ACT
(ACTNO, ACTKWD, ACTDESC)
VALUES (:hva1, :hva2, :hva3)
FOR 10 ROWS
NOT ATOMIC CONTINUE ON SQLEXCEPTION;

EXEC SQL GET DIAGNOSTICS


:row_count = ROW_COUNT, :num_condns = NUMBER;
printf("Number of rows inserted = %d\n", row_count);

for (i=1; i<=num_condns; i++) {


EXEC SQL GET DIAGNOSTICS CONDITION :i
:ret_sqlcode = DB2_RETURNED_SQLCODE,
:ret_sqlstate = RETURNED_SQLSTATE,
:row_num = DB2_ROW_NUMBER;
printf("SQLCODE = %d, SQLSTATE = %s, ROW NUMBER = %d\n",
ret_sqlcode, ret_sqlstate, row_num);
}

Figure 7. Using GET DIAGNOSTICS to return the number of rows and conditions returned
and condition information

| In the activity table, the ACTNO column is defined as SMALLINT. Suppose that you
| declare the host variable array hva1 as an array with data type long, and you
| populate the array so that the value for the fourth element is 32768.

| If you check the SQLCA values after the INSERT statement, the value of
| SQLCODE is equal to 0, the value of SQLSTATE is ’00000’, and the value of
| SQLERRD(3) is 9 for the number of rows that were inserted. However, the INSERT
| statement specified that 10 rows were to be inserted.

| The GET DIAGNOSTICS statement provides you with the information that you need
| to correct the data for the row that was not inserted. The printed output from your
| program looks like this:
| Number of rows inserted = 9
| SQLCODE = -302, SQLSTATE = 22003, ROW NUMBER = 4

| The value 32768 for the input variable is too large for the target column ACTNO.
| You can print the MESSAGE_TEXT condition item, or see DB2 Messages and
| Codes for information about SQLCODE -302.

| Data types for GET DIAGNOSTICS items


| Table 4 on page 87, Table 5 on page 88, and Table 6 on page 88 specify the data
| types for the statement, condition, and connection information items that you can
| request by using the GET DIAGNOSTICS statement. You must declare each target
| host variable with a data type that is compatible with the data type of the requested
| item.

86 Application Programming and SQL Guide


| Table 4. Data types for GET DIAGNOSTICS items that return statement information
| Item Description Data type
| DB2_GET_DIAGNOSTICS_DIAGNOSTICS After a GET DIAGNOSTICS statement, if any VARCHAR(32672)
| error or warning occurred, this item contains all
| of the diagnostics as a single string.
| DB2_LAST_ROW After a multiple-row FETCH statement, this item INTEGER
| contains a value of +100 if the last row in the
| table is in the rowset that was returned.
| DB2_NUMBER_PARAMETER_MARKERS After a PREPARE statement, this item contains INTEGER
| the number of parameter markers in the prepared
| statement.
| DB2_NUMBER_RESULT_SETS After a CALL statement that invokes a stored INTEGER
| procedure, this item contains the number of result
| sets that are returned by the procedure.
| DB2_NUMBER_ROWS After an OPEN or FETCH statement for which DECIMAL(31,0)
| the size of the result table is known, this item
| contains the number of rows in the result table.
| After a PREPARE statement, this item contains
| the estimated number of rows in the result table
| for the prepared statement. For SENSITIVE
| DYNAMIC cursors, this item contains the
| approximate number of rows.
| DB2_RETURN_STATUS After a CALL statement that invokes an SQL INTEGER
| procedure, this item contains the return status if
| the procedure contains a RETURN statement.
| DB2_SQL_ATTR_CURSOR_HOLD After an ALLOCATE or OPEN statement, this CHAR(1)
| item indicates whether the cursor can be held
| open across multiple units of work (Y or N).
| DB2_SQL_ATTR_CURSOR_ROWSET After an ALLOCATE or OPEN statement, this CHAR(1)
| item indicates whether the cursor can use rowset
| positioning (Y or N).
| DB2_SQL_ATTR_CURSOR_SCROLLABLE After an ALLOCATE or OPEN statement, this CHAR(1)
| item indicates whether the cursor is scrollable (Y
| or N).
| DB2_SQL_ATTR_CURSOR_SENSITIVITY After an ALLOCATE or OPEN statement, this CHAR(1)
| item indicates whether the cursor shows updates
| made by other processes (sensitivity A, I, or S).
| DB2_SQL_ATTR_CURSOR_TYPE After an ALLOCATE or OPEN statement, this CHAR(1)
| item indicates whether the cursor is declared
| static (S for INSENSITIVE or SENSITIVE
| STATIC) or dynamic (D for SENSITIVE
| DYNAMIC).
| MORE After any SQL statement, this item indicates CHAR(1)
| whether some conditions items were discarded
| because of insufficient storage (Y or N).
| NUMBER After any SQL statement, this item contains the INTEGER
| number of condition items. If no warning or error
| occurred, or if no previous SQL statement has
| been executed, the number that is returned is 1.
| ROW_COUNT After DELETE, INSERT, UPDATE, or FETCH, DECIMAL(31,0)
| this item contains the number of rows that are
| deleted, inserted, updated, or fetched. After
| PREPARE, this item contains the estimated
| number of result rows in the prepared statement.

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


|
| Table 5. Data types for GET DIAGNOSTICS items that return condition information
| Item Description Data type
| CATALOG_NAME This item contains the server name of the table that VARCHAR(128)
| owns a constraint that caused an error, or that
| caused an access rule or check violation.
| CONDITION_NUMBER This item contains the number of the condition. INTEGER
| CURSOR_NAME This item contains the name of a cursor in an VARCHAR(128)
| invalid cursor state.
| DB2_ERROR_CODE1 This item contains an internal error code. INTEGER
| DB2_ERROR_CODE2 This item contains an internal error code. INTEGER
| DB2_ERROR_CODE3 This item contains an internal error code. INTEGER
| DB2_ERROR_CODE4 This item contains an internal error code. INTEGER
| DB2_INTERNAL_ERROR_POINTER For some errors, this item contains a negative value INTEGER
| that is an internal error pointer.
| DB2_MESSAGE_ID This item contains the message ID that CHAR(10)
| corresponds to the message that is contained in the
| MESSAGE_TEXT diagnostic item.
| DB2_MODULE_DETECTING_ERROR After any SQL statement, this item indicates which CHAR(8)
| module detected the error.
| DB2_ORDINAL_TOKEN_n After any SQL statement, this item contains the nth VARCHAR(515)
| token, where n is a value from 1 to 100.
| DB2_REASON_CODE After any SQL statement, this item contains the INTEGER
| reason code for errors that have a reason code
| token in the message text.
| DB2_RETURNED_SQLCODE After any SQL statement, this item contains the INTEGER
| SQLCODE for the condition.
| DB2_ROW_NUMBER After any SQL statement that involves multiple DECIMAL(31,0)
| rows, this item contains the row number on which
| DB2 detected the condition.
| DB2_TOKEN_COUNT After any SQL statement, this item contains the INTEGER
| number of tokens available for the condition.
| MESSAGE_TEXT After any SQL statement, this item contains the VARCHAR(32672)
| message text associated with the SQLCODE.
| RETURNED_SQLSTATE After any SQL statement, this item contains the CHAR(5)
| SQLSTATE for the condition.
| SERVER_NAME After a CONNECT, DISCONNECT, or SET VARCHAR(128)
| CONNECTION statement, this item contains the
| name of the server specified in the statement.
|
| Table 6. Data types for GET DIAGNOSTICS items that return connection information
| Item Description Data type
| DB2_AUTHENTICATION_TYPE This item contains the authentication type (S, C, D, CHAR(1)
| E, or blank). For more information, see Chapter 5
| of DB2 SQL Reference.
| DB2_AUTHORIZATION_ID This item contains the authorization ID that is used VARCHAR(128)
| by the connected server.
| DB2_CONNECTION_STATE This item indicates whether the connection is INTEGER
| unconnected (-1), local (0), or remote (1).

88 Application Programming and SQL Guide


| Table 6. Data types for GET DIAGNOSTICS items that return connection information (continued)
| Item Description Data type
| DB2_CONNECTION_STATUS This item indicates whether updates can be INTEGER
| committed for the current unit of work (1 for Yes, 2
| for No).
| DB2_ENCRYPTION_TYPE This item contains one of the following values that CHAR(1)
| indicates the level of encryption for the connection:
| A Only the authentication tokens (authid and
| password) are encrypted
| D All of the data for the connection is
| encrypted
| DB2_SERVER_CLASS_NAME After a CONNECT or SET CONNECTION VARCHAR(128)
| statement, this item contains the DB2 server class
| name.
| DB2_PRODUCT_ID This item contains the DB2 product signature. VARCHAR(8)
|

| For a complete description of the GET DIAGNOSTICS items, see Chapter 5 of DB2
| SQL Reference.

Calling DSNTIAR to display SQLCA fields


You should check for errors codes before you commit data, and handle the errors
that they represent. The assembler subroutine DSNTIAR helps you to obtain a
formatted form of the SQLCA and a text message based on the SQLCODE field of
| the SQLCA. You can retrieve this same message text by using the
| MESSAGE_TEXT condition item field of the GET DIAGNOSTICS statement.
| Programs that require long token message support should code the GET
| DIAGNOSTICS statement instead of DSNTIAR.

You can find the programming language-specific syntax and details for calling
DSNTIAR on the following pages:
For Assembler programs, see page 142
For C programs, see page 169
For COBOL programs, see page 201
For Fortran programs, see page 212
For PL/I programs, see page 230

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 need no more than 10 lines, 80-bytes
each, for your message output area. An application program can have only one
message output area.

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


You must define the message output area in VARCHAR format. In this varying
character format, a 2-byte length field precedes the data. The length field indicates
to DSNTIAR how many total bytes are in the output message area; the minimum
length of the output area is 240-bytes.

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

Figure 8. Format of the message output area

When you call DSNTIAR, you must name an SQLCA and an output message area
in the DSNTIAR parameters. You must also provide the logical record length (lrecl)
as a value between 72 and 240 bytes. DSNTIAR assumes the message area
contains fixed-length records of length lrecl.

DSNTIAR places up to 10 lines in the message area. If the text of a message is


longer than the record length you specify on DSNTIAR, the output message splits
into several records, on word boundaries if possible. The split records are indented.
All records begin with a blank character for carriage control. If you have more lines
than the message output area can contain, DSNTIAR issues a return code of 4. A
completely blank record marks the end of the message output area.

Possible return codes from DSNTIAR


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

Preparing to use DSNTIAR


DSNTIAR can run either above or below the 16-MB line of virtual storage. The
DSNTIAR object module that comes with DB2 has the attributes AMODE(31) and

90 Application Programming and SQL Guide


RMODE(ANY). At install time, DSNTIAR links as AMODE(31) and RMODE(ANY).
DSNTIAR runs in 31-bit mode if any of the following conditions is true:
v DSNTIAR is linked with other modules that also have the attributes AMODE(31)
and RMODE(ANY).
v DSNTIAR is linked into an application that specifies the attributes AMODE(31)
and RMODE(ANY) in its link-edit JCL.
v An application loads DSNTIAR.

When loading DSNTIAR from another program, be careful how you branch to
DSNTIAR. For example, if the calling program is in 24-bit addressing mode and
DSNTIAR is loaded above the 16-MB line, you cannot use the assembler BALR
instruction or CALL macro to call DSNTIAR, because they assume that DSNTIAR is
in 24-bit mode. Instead, you must use an instruction that is capable of branching
into 31-bit mode, such as BASSM.

You can dynamically link (load) and call DSNTIAR directly from a language that
does not handle 31-bit addressing (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. Alternatively, you can write an intermediate assembler
language program that calls DSNTIAR in 31-bit mode and then call that
intermediate program in 24-bit mode from your application.

For more information on the allowed and default AMODE and RMODE settings for a
particular language, see the application programming guide for that language. For
details on how the attributes AMODE and RMODE of an application are determined,
see the linkage editor and loader user’s guide for the language in which you have
written the application.

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 a deadlock or timeout occurs.
When one of these errors occurs, the error routine closes your cursors by issuing
the statement:
EXEC SQL CLOSE cursor-name

An SQLCODE of 0 or -501 resulting from that statement indicates that the close
was successful.

To use DSNTIAR to generate the error message text, first follow these steps:
1. Choose a logical record length (lrecl) of the output lines. For this example,
assume lrecl is 72 (to fit on a terminal screen) and is stored in the variable
named ERROR-TEXT-LEN.
2. Define a message area in your COBOL application. Assuming you want an area
for up to 10 lines of length 72, you should define an area of 720 bytes, plus a
2-byte area that specifies the total length of the message output area.
01 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.

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


For this example, the name of the message area is ERROR-MESSAGE.
3. Make sure you have an SQLCA. For this example, assume the name of the
SQLCA is SQLCA.

To display the contents of the SQLCA when SQLCODE is 0 or -501, call DSNTIAR
after the SQL statement that produces SQLCODE 0 or -501:
CALL ’DSNTIAR’ USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN.

You can then print the message output area just as you would any other variable.
Your message might look like this:
DSNT408I SQLCODE = -501, ERROR: THE CURSOR IDENTIFIED IN A FETCH OR
CLOSE STATEMENT IS NOT OPEN
DSNT418I SQLSTATE = 24501 SQLSTATE RETURN CODE
DSNT415I SQLERRP = DSNXERT SQL PROCEDURE DETECTING ERROR
DSNT416I SQLERRD = -315 0 0 -1 0 0 SQL DIAGNOSTIC INFORMATION
DSNT416I SQLERRD = X’FFFFFEC5’ X’00000000’ X’00000000’
X’FFFFFFFF’ X’00000000’ X’00000000’ SQL DIAGNOSTIC
INFORMATION

92 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
about using a cursor to retrieve rows from a result set that is returned by a stored
procedure, see Chapter 25, “Using stored procedures for client/server processing,”
on page 569.

| When you execute a SELECT statement, you retrieve a set of rows. That set of
| rows is called the result table of the SELECT statement. In an application program,
| you can use either of the following types of cursors to retrieve rows from a result
| table:
| v A row-positioned cursor retrieves at most a single row at a time from the result
| table into host variables. At any point in time, the cursor is positioned on at most
| a single row. For information about how to use a row-positioned cursor, see
| “Accessing data by using a row-positioned cursor.”
| v A rowset-positioned cursor retrieves zero, one, or more rows at a time, as a
| rowset, from the result table into host variable arrays. At any point in time, the
| cursor can be positioned on a rowset. You can reference all of the rows in the
| rowset, or only one row in the rowset, when you use a positioned DELETE or
| positioned UPDATE statement. For information about how to use a
| rowset-positioned cursor, see “Accessing data by using a rowset-positioned
| cursor” on page 98.

Accessing data by using a row-positioned cursor


The basic steps in using a row-positioned 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 95.
3. Specify what the program is to do when all rows have been retrieved. See “Step
3: Specify what to do at end-of-data” on page 95.
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 96.
5. Execute a CLOSE CURSOR statement to make the cursor unavailable to the
application. See “Step 5: Close the cursor” on page 98.

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 are to 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:

© Copyright IBM Corp. 1983, 2004 93


EXEC SQL
DECLARE C1 CURSOR FOR
SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, SALARY
FROM DSN8810.EMP
END-EXEC.

You can use this cursor to list select information about 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 DSN8810.EMP X
WHERE EXISTS
(SELECT *
FROM DSN8810.PROJ Y
WHERE X.EMPNO=Y.RESPEMP
AND Y.PROJNO=:GOODPROJ);

| Declaring cursors for tables that use multilevel security: You can declare a
| cursor that retrieves rows from a table that uses multilevel security with row-level
| granularity. However, the result table for the cursor contains only those rows that
| have a security label value that is equivalent to or dominated by the security label
| value of your ID. Refer to Part 3 (Volume 1) of DB2 Administration Guide for a
| discussion of multilevel security with row-level granularity.

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:
v The first form is FOR UPDATE OF column-list. Use this form when you know in
advance which columns you need to update.
v The second form 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 DSN8810.EMP X
WHERE EXISTS
(SELECT *
FROM DSN8810.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 DSN8810.EMP X
WHERE EXISTS
(SELECT *

94 Application Programming and SQL Guide


FROM DSN8810.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 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 about these options, see Table 63
on page 462. 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.

Read-only result table: Some result tables cannot be updated—for example, the
result of joining two or more tables. The defining characteristics of a read-only result
tables 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 the
search condition of 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
v Whether DB2 uses parallelism to process the SELECT statement of the cursor
For more information, see “The effect of sorts on OPEN CURSOR” on page 772.

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


To determine whether 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:

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


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 causes your program to branch to
another part that then 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 more information about the WHENEVER NOT FOUND
statement, see “Checking the execution of SQL statements” on page 82.

Step 4: Execute SQL statements


You execute one of these SQL statements using the cursor:
v A FETCH statement
v A positioned UPDATE statement
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 that retrieves selected columns
from the employee table:
EXEC SQL
FETCH C1 INTO
:HV-EMPNO, :HV-FIRSTNME, :HV-MIDINIT, :HV-LASTNAME, :HV-SALARY :IND-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 positions the cursor on 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 specify on the INTO
clause of FETCH. This sequence repeats each time you issue FETCH, until you
process 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 103 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 440. Block
fetch processes rows ahead of the current row. You cannot use a block fetch when
you perform a positioned update or delete operation.

96 Application Programming and SQL Guide


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:
EXEC SQL
UPDATE DSN8810.EMP
SET SALARY = 50000
WHERE CURRENT OF C1
END-EXEC.

A positioned UPDATE statement updates the row on which the cursor is positioned.

A positioned UPDATE statement is subject to these restrictions:


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.
| v You cannot use an INSERT statement in the FROM clause of a SELECT
| statement that defines a cursor that is used in a positioned UPDATE statement.
| v A positioned UPDATE statement will fail if the value of the security label column
| of the row where the cursor is positioned is not equivalent to the security label
| value of your user id. If your user id has write down privilege, a positioned
| UPDATE statement will fail if the value of the security label column of the row
| where the cursor is positioned does not dominate the security label value of your
| user id.

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 DSN8810.EMP
WHERE CURRENT OF C1
END-EXEC.

A positioned DELETE statement deletes the row on which the cursor is positioned.

A positioned DELETE statement is subject to these restrictions:


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.
| v You cannot use an INSERT statement in the FROM clause of a SELECT
| statement that defines a cursor that is used in a positioned DELETE statement.
| v A positioned DELETE statement will fail if the value of the security label column
| of the row where the cursor is positioned is not equivalent to the security label
| value of your user id. If your user id has write down privilege, a positioned

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


| DELETE statement will fail if the value of the security label column of the row
| where the cursor is positioned does not dominate the security label value of your
| user id.

Step 5: Close the cursor


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

When you finish processing the rows of the result table, and the cursor is no longer
needed, you can let DB2 automatically close the cursor when the current
transaction terminates or when your program terminates.

Recommendation: To free the resources that are held by the cursor, close the
cursor explicitly by issuing the CLOSE statement.

| Accessing data by using a rowset-positioned cursor


| The basic steps in using a rowset cursor are:
| 1. Execute a DECLARE CURSOR statement to define the result table on which
| the cursor operates. See “Step 1: Declare the rowset cursor.”
| 2. Execute an OPEN CURSOR to make the cursor available to the application.
| See “Step 2: Open the rowset cursor.”
| 3. Specify what the program is to do when all rows have been retrieved. See “Step
| 3: Specify what to do at end-of-data for a rowset cursor” on page 99.
| 4. Execute multiple SQL statements to retrieve data from the table or modify
| selected rows of the table. See “Step 4: Execute SQL statements with a rowset
| cursor” on page 99.
| 5. Execute a CLOSE CURSOR statement to make the cursor unavailable to the
| application. See “Step 5: Close the rowset cursor” on page 103.

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

| Step 1: Declare the rowset cursor


| To enable a cursor to fetch rowsets, use the WITH ROWSET POSITIONING clause
| in the DECLARE CURSOR statement. The following example shows how to declare
| a rowset cursor:
| EXEC SQL
| DECLARE C1 CURSOR WITH ROWSET POSITIONING FOR
| SELECT EMPNO, LASTNAME, SALARY
| FROM DSN8810.EMP
| END-EXEC.

| For restrictions that apply to rowset-positioned cursors and row-positioned cursors,


| see “Step 1: Declare the cursor” on page 93.

| Step 2: Open the rowset cursor


| To tell DB2 that you are ready to process the first rowset of the result table, execute
| the OPEN statement in your program. DB2 then uses the SELECT statement within
| DECLARE CURSOR to identify the rows in the result table. For more information
| about the OPEN CURSOR process, see “Step 2: Open the cursor” on page 95.

98 Application Programming and SQL Guide


| Step 3: Specify what to do at end-of-data for a rowset cursor
| To determine whether the program has retrieved the last row of data in the result
| table, test the SQLCODE field for a value of 100 or the SQLSTATE field for a value
| of ’02000’. With a rowset cursor, these codes occur when a FETCH statement
| retrieves the last row in the result table. However, when the last row has been
| retrieved, the program must still process the rows in the last rowset through that
| last row. For an example of end-of-data processing for a rowset cursor, see
| Figure 18 on page 117.

| To determine the number of retrieved rows, use either of the following values:
| v The contents of the SQLERRD(3) field in the SQLCA
| v The contents of the ROW_COUNT item of GET DIAGNOSTICS

| For information about GET DIAGNOSTICS, see “Using the GET DIAGNOSTICS
| statement” on page 84.

| If you declare the cursor as dynamic scrollable, and SQLCODE has the value 100,
| you can continue with a FETCH statement until no more rows are retrieved.
| Additional fetches might retrieve more rows because a dynamic scrollable cursor is
| sensitive to updates by other application processes. For information about dynamic
| cursors, see “Types of cursors” on page 103.

| Step 4: Execute SQL statements with a rowset cursor


| You can execute these static SQL statements when you use a rowset cursor:
| v A multiple-row FETCH statement that copies a rowset of column values into
| either of the following data areas:
| – Host variable arrays that are declared in your program
| – Dynamically-allocated arrays whose storage addresses are put into an SQL
| descriptor area (SQLDA), along with the attributes of the columns that are to
| be retrieved
| v After either form of the multiple-row FETCH statement, you can issue:
| – A positioned UPDATE statement on the current rowset
| – A positioned DELETE statement on the current rowset

| You must use the WITH ROWSET POSITIONING clause of the DECLARE
| CURSOR statement if you plan to use a rowset-positioned FETCH statement.

| Using a multiple-row FETCH statement with host variable arrays


| The following example shows a FETCH statement that retrieves 20 rows into host
| variable arrays that are declared in your program:
| EXEC SQL
| FETCH NEXT ROWSET FROM C1
| FOR 20 ROWS
| INTO :HVA-EMPNO, :HVA-LASTNAME, :HVA-SALARY :INDA-SALARY
| END-EXEC.

| When your program executes a FETCH statement with the ROWSET keyword, the
| cursor is positioned on a rowset in the result table. That rowset is called the current
| rowset. The dimension of each of the host variable arrays must be greater than or
| equal to the number of rows to be retrieved.

| Using a multiple-row FETCH statement with a descriptor


| Suppose that you want to dynamically allocate the storage needed for the arrays of
| column values that are to be retrieved from the employee table. You must:
| 1. Declare an SQLDA structure and the variables that reference the SQLDA.

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


| 2. Dynamically allocate the SQLDA and the arrays needed for the column values.
| 3. Set the fields in the SQLDA for the column values to be retrieved.
| 4. Open the cursor.
| 5. Fetch the rows.

| Declare the SQLDA: You must first declare the SQLDA structure. The following
| SQL INCLUDE statement requests a standard SQLDA declaration:
| EXEC SQL INCLUDE SQLDA;

| Your program must also declare variables that reference the SQLDA structure, the
| SQLVAR structure within the SQLDA, and the DECLEN structure for the precision
| and scale if you are retrieving a DECIMAL column. For C programs, the code looks
| like this:
| struct sqlda *sqldaptr;
| struct sqlvar *varptr;
| struct DECLEN {
| unsigned char precision;
| unsigned char scale;
| };

| Allocate the SQLDA: Before you can set the fields in the SQLDA for the column
| values to be retrieved, you must dynamically allocate storage for the SQLDA
| structure. For C programs, the code looks like this:
| sqldaptr = (struct sqlda *) malloc (3 * 44 + 16);

| The size of the SQLDA is SQLN * 44 + 16, where the value of the SQLN field is the
| number of output columns.

| Set the fields in the SQLDA: You must set the fields in the SQLDA structure for
| your FETCH statement. Suppose you want to retrieve the columns EMPNO,
| LASTNAME, and SALARY. The C code to set the SQLDA fields for these columns
| looks like this:
| strcpy(sqldaptr->sqldaid,"SQLDA");
| sqldaptr->sqldabc = 148; /* number bytes of storage allocated for the SQLDA */
| sqldaptr->sqln = 3; /* number of SQLVAR occurrences */
| sqldaptr->sqld = 3;
| varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0])); /* Point to first SQLVAR */
| varptr->sqltype = 452; /* data type CHAR(6) */
| varptr->sqllen = 6;
| varptr->sqldata = (char *) hva1;
| varptr->sqlind = (short *) inda1;
| varptr->sqlname.length = 8;
| varptr->sqlname.data = X’0000000000000014’; /* bytes 5-8 array size */
| varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 1); /* Point to next SQLVAR */
| varptr->sqltype = 448; /* data type VARCHAR(15) */
| varptr->sqllen = 15;
| varptr->sqldata = (char *) hva2;
| varptr->sqlind = (short *) inda2;
| varptr->sqlname.length = 8;
| varptr->sqlname.data = X’0000000000000014’; /* bytes 5-8 array size */
| varptr = (struct sqlvar *) (&(sqldaptr->sqlvar[0]) + 2); /* Point to next SQLVAR */
| varptr->sqltype = 485; /* data type DECIMAL(9,2) */
| ((struct DECLEN *) &(varptr->sqllen))->precision = 9;
| ((struct DECLEN *) &(varptr->sqllen))->scale = 2;
| varptr->sqldata = (char *) hva3;
| varptr->sqlind = (short *) inda3;
| varptr->sqlname.length = 8;
| varptr->sqlname.data = X’0000000000000014’; /* bytes 5-8 array size */

| The SQLDA structure has these fields:

100 Application Programming and SQL Guide


| v SQLDABC indicates the number of bytes of storage that are allocated for the
| SQLDA. The storage includes a 16-byte header and 44 bytes for each SQLVAR
| field. The value is SQLN x 44 + 16, or 148 for this example.
| v SQLN is the number of SQLVAR occurrences (or the number of output columns).
| v SQLD is the number of variables in the SQLDA that are used by DB2 when
| processing the FETCH statement.
| v Each SQLVAR occurrence describes a host variable array or buffer into which the
| values for a column in the result table are to be returned. Within each SQLVAR:
| – SQLTYPE indicates the data type of the column.
| – SQLLEN indicates the length of the column. If the data type is DECIMAL, this
| field has two parts: the PRECISION and the SCALE.
| – SQLDATA points to the first element of the array for the column values. For
| this example, assume that your program allocates the dynamic variable arrays
| hva1, hva2, and hva3, and their indicator arrays inda1, inda2, and inda3.
| – SQLIND points to the first element of the array of indicator values for the
| column. If SQLTYPE is an odd number, this attribute is required. (If SQLTYPE
| is an odd number, null values are allowed for the column.)
| – SQLNAME has two parts: the LENGTH and the DATA. The LENGTH is 8. The
| first two bytes of the DATA field is X’0000’. Bytes 5 through 8 of the DATA
| field is a binary integer representation of the dimension of the arrays. For this
| example, assume that the dimension of each array is 20. In general, you can
| vary the number of rows that are to be retrieved.

| For information about using the SQLDA in dynamic SQL, see Chapter 24, “Coding
| dynamic SQL in application programs,” on page 535. For a complete layout of the
| SQLDA and the descriptions given by the INCLUDE statement, see Appendix C of
| DB2 SQL Reference.

| Open the cursor: You can open the cursor only after all of the fields have been
| set in the output SQLDA:
| EXEC SQL OPEN C1;

| Fetch the rows: After the OPEN statement, the program fetches the next rowset:
| EXEC SQL
| FETCH NEXT ROWSET FROM C1
| FOR 20 ROWS
| USING DESCRIPTOR :*sqldaptr;

| The USING clause of the FETCH statement names the SQLDA that describes the
| columns that are to be retrieved.

| Using rowset-positioned UPDATE statements


| After your program executes a FETCH statement to establish the current rowset,
| you can use a positioned UPDATE statement with either of the following clauses:
| v Use WHERE CURRENT OF to modify all of the rows in the current rowset
| v Use FOR ROW n OF ROWSET to modify row n in the current rowset
| For information about restrictions for a positioned UPDATE, see “Using positioned
| UPDATE statements” on page 97.

| Using the WHERE CURRENT OF clause: An example of a positioned UPDATE


| statement that uses the WHERE CURRENT OF clause is:

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


| EXEC SQL
| UPDATE DSN8810.EMP
| SET SALARY = 50000
| WHERE CURRENT OF C1
| END-EXEC.

| When the UPDATE statement is executed, the cursor must be positioned on a row
| or rowset of the result table. If the cursor is positioned on a row, that row is
| updated. If the cursor is positioned on a rowset, all of the rows in the rowset are
| updated.

| Using the FOR ROW n OF ROWSET clause: An example of a positioned


| UPDATE statement that uses the FOR ROW n OF ROWSET clause is:
| EXEC SQL
| UPDATE DSN8810.EMP
| SET SALARY = 50000
| FOR CURSOR C1 FOR ROW 5 OF ROWSET
| END-EXEC.

| When the UPDATE statement is executed, the cursor must be positioned on a


| rowset of the result table. The specified row (in the example, row 5) of the current
| rowset is updated.

| Using rowset-positioned DELETE statements


| After your program executes a FETCH statement to establish the current rowset,
| you can use a positioned DELETE statement with either of the following clauses:
| v Use WHERE CURRENT OF to delete all of the rows in the current rowset
| v Use FOR ROW n OF ROWSET to delete row n in the current rowset
| For information about restrictions for a positioned DELETE, see “Using positioned
| DELETE statements” on page 97.

| Using the WHERE CURRENT OF clause: An example of a positioned DELETE


| statement that uses the WHERE CURRENT OF clause is:
| EXEC SQL
| DELETE FROM DSN8810.EMP
| WHERE CURRENT OF C1
| END-EXEC.

| When the DELETE statement is executed, the cursor must be positioned on a row
| or rowset of the result table. If the cursor is positioned on a row, that row is deleted,
| and the cursor is positioned before the next row of its result table. If the cursor is
| positioned on a rowset, all of the rows in the rowset are deleted, and the cursor is
| positioned before the next rowset of its result table.

| Using the FOR ROW n OF ROWSET clause: An example of a positioned


| DELETE statement that uses the FOR ROW n OF ROWSET clause is:
| EXEC SQL
| DELETE FROM DSN8810.EMP
| FOR CURSOR C1 FOR ROW 5 OF ROWSET
| END-EXEC.

| When the DELETE statement is executed, the cursor must be positioned on a


| rowset of the result table. The specified row of the current rowset is deleted, and
| the cursor remains positioned on that rowset. The deleted row (in the example, row
| 5 of the rowset) cannot be retrieved or updated.

102 Application Programming and SQL Guide


| Number of rows in a rowset
| The number of rows in a rowset is determined either explicitly or implicitly. To
| explicitly set the size of a rowset, use the FOR n ROWS clause in the FETCH
| statement. If a FETCH statement specifies the ROWSET keyword, and not the FOR
| n ROWS clause, the size of the rowset is implicitly set to the size of the rowset that
| was most recently specified in a prior FETCH statement. If a prior FETCH
| statement did not specify the FOR n ROWS clause or the ROWSET keyword, the
| size of the current rowset is implicitly set to 1. For examples of rowset positioning,
| see Table 8 on page 108.

| Step 5: Close the rowset cursor


| If you finish processing the rows of the result table and want to use the cursor
| again, issue a CLOSE statement to close the cursor and then issue an OPEN
| statement to reopen the cursor.

| When you finish processing the rows of the result table, and you no longer need the
| cursor, you can let DB2 automatically close the cursor when the current transaction
| terminates or when your program terminates.

| Recommendation: To free the resources held by the cursor, close the cursor
| explicitly by issuing the CLOSE statement.

Types of cursors
| You can declare cursors, both row-positioned and rowset-positioned, as scrollable
or not scrollable, held or not held, and returnable or not returnable. The following
sections discuss these characteristics:
v “Scrollable and non-scrollable cursors”
v “Held and non-held cursors” on page 112

In addition, you can declare a returnable cursor in a stored procedure by including


the WITH RETURN clause; the cursor can return result sets to a caller of the stored
procedure. For information about returnable cursors, see Chapter 25, “Using stored
procedures for client/server processing,” on page 569.

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 can
| be either row-positioned or rowset-positioned. A row-positioned non-scrollable
| cursor moves forward through its result table one row at a time. Similarly, a
| rowset-positioned non-scrollable cursor moves forward through its result table one
| rowset at a time.

A non-scrollable cursor always moves sequentially forward in the result table. When
the application opens the cursor, the cursor is positioned before the first row (or first
rowset) in the result table. When the application executes the first FETCH, the
cursor is positioned on the first row (or first rowset). When the application executes
subsequent FETCH statements, the cursor moves one row ahead (or one rowset
ahead) for each FETCH. After each FETCH statement, the cursor is positioned on
the row (or rowset) that was fetched.

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


After the application executes a positioned UPDATE or positioned DELETE
statement, the cursor stays at the current row (or rowset) of the result table. You
cannot retrieve rows (or rowsets) backward or move to a specific position in a result
table with a non-scrollable cursor.

Using a scrollable cursor


To make a cursor scrollable, you declare it as scrollable. A scrollable cursor can be
either row-positioned or rowset-positioned. To use a scrollable cursor, you execute
FETCH statements that indicate where you want to position the cursor. For
examples of FETCH statements that position a cursor for both rows and rowsets,
see Table 8 on page 108.

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 (or rowsets) 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 DSN8810.DEPT
ORDER BY DEPTNO
END-EXEC.

Figure 9. Declaration for an insensitive scrollable row 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 the application opens 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 static scrollable cursor.

EXEC SQL DECLARE C2 SENSITIVE STATIC SCROLL CURSOR FOR


SELECT DEPTNO, DEPTNAME, MGRNO
FROM DSN8810.DEPT
ORDER BY DEPTNO
END-EXEC.

Figure 10. Declaration for a sensitive static scrollable row cursor

Declaring a cursor as SENSITIVE STATIC has the following effects:


v When the application executes positioned UPDATE and DELETE statements with
the cursor, those changes are visible in the result table.
v When the current value of a row no longer satisfies the SELECT statement that
was used in the cursor declaration, that row is no longer visible in the result
table.

104 Application Programming and SQL Guide


v When a row of the result table is deleted from the underlying table, that 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.

| Figure 11 shows a declaration for a sensitive dynamic scrollable cursor.


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

Figure 11. Declaration for a sensitive dynamic scrollable cursor

| Declaring a cursor as SENSITIVE DYNAMIC has the following effects:


| v When the application executes positioned UPDATE and DELETE statements with
| the cursor, those changes are visible. In addition, when the application executes
| INSERT, UPDATE, and DELETE statements (within the application but outside
| the cursor), those changes are visible.
| v All committed inserts, updates, and deletes by other application processes are
| visible.
| v Because the FETCH statement executes against the base table, the cursor
| needs no temporary result table. When you define a cursor as SENSITIVE
| DYNAMIC, you cannot specify the INSENSITIVE keyword in a FETCH statement
| for that cursor.
| v If you specify an ORDER BY clause for a SENSITIVE DYNAMIC cursor, DB2
| might choose an index access path if the ORDER BY is fully satisfied by an
| existing index. However, a dynamic scrollable cursor that is declared with an
| ORDER BY clause is not updatable.

Static scrollable cursor: Both the INSENSITIVE cursor and the SENSITIVE
STATIC cursor follow the static cursor model:
v The size of the result table does not grow after the application opens 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 the application opens the cursor.
If the cursor declaration contains an ORDER BY clause, and the columns that
are in the ORDER BY clause are updated after the cursor is opened, the order of
the rows in the result table does not change.

| Dynamic scrollable cursor: When you declare a cursor as SENSITIVE, you can
| declare it either STATIC or DYNAMIC. The SENSITIVE DYNAMIC cursor follows
| the dynamic cursor model:
| v The size and contents of the result table can change with every fetch.
| The base table can change while the cursor is scrolling on it. If another
| application process changes the data, the cursor sees the newly changed data
| when it is committed. If the application process of the cursor changes the data,
| the cursor sees the newly changed data immediately.
| v The order of the rows can change after the application opens the cursor.

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


| If the cursor declaration contains an ORDER BY clause, and columns that are in
| the ORDER BY clause are updated after the cursor is opened, the order of the
| rows in the result table changes.

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
following SQLWARN and SQLERRD fields of the SQLCA:
SQLWARN1
Indicates whether the cursor is scrollable or non-scrollable.
| SQLWARN4
| Indicates whether the cursor is insensitive (I), sensitive static (S), or sensitive
| dynamic (D).
SQLWARN5
Indicates whether the cursor is read-only, readable and deletable, or readable,
deletable, and updatable.
| SQLERRD(1)
| The number of rows in the result table of a cursor when the cursor position is
| after the last row (when SQLCODE is equal to +100). This field is not set for
| dynamic scrollable cursors.
| SQLERRD(2)
| The number of rows in the result table of a cursor when the cursor position is
| after the last row (when SQLCODE is equal to +100). This field is not set for
| dynamic scrollable cursors.
| SQLERRD(3)
| The number of rows in the result table of an INSERT when the SELECT
| statement of the cursor contains the INSERT statement.

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 about fields in the SQLCA.

| Determining attributes of a cursor by using the GET DIAGNOSTICS


| statement: After you open a cursor, you can determine the following attributes of
| the cursor by checking these GET DIAGNOSTICS items:
| DB2_SQL_ATTR_CURSOR_HOLD
| Indicates whether the cursor can be held open across commits (Y or N)
| DB2_SQL_ATTR_CURSOR_ROWSET
| Indicates whether the cursor can use rowset positioning (Y or N)
| DB2_SQL_ATTR_CURSOR_SCROLLABLE
| Indicates whether the cursor is scrollable (Y or N)
| DB2_SQL_ATTR_CURSOR_SENSITIVITY
| Indicates whether the cursor is asensitive, insensitive, or sensitive to changes
| that are made by other processes (A, I, or S)
| DB2_SQL_ATTR_CURSOR_TYPE
| Indicates whether the cursor is declared static (S for INSENSITIVE or
| SENSITIVE STATIC) or dynamic (D for SENSITIVE DYNAMIC)

| For more information about the GET DIAGNOSTICS statement, see “Using the
| GET DIAGNOSTICS statement” on page 84.

106 Application Programming and SQL Guide


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 7 lists the fetch
| orientation keywords that you can specify and their meanings. These keywords
| apply to both row-positioned scrollable cursors and rowset-positioned scrollable
| cursors.
Table 7. Positions for a scrollable cursor
Keyword in FETCH statement Cursor position when FETCH is executed1
BEFORE Before the first row
FIRST or ABSOLUTE +1 On the first row
LAST or ABSOLUTE −1 On the last row
AFTER After the last row
2
ABSOLUTE On an absolute row number, from before the first
row forward or from after the last row backward
RELATIVE2 On the row that is forward or backward a relative
number of rows from the current row
CURRENT On the current row
PRIOR or RELATIVE −1 On the previous row
NEXT On the next row (default)

Notes:
| 1. The cursor position applies to both row position and rowset position, for example, before
| the first row or before the first rowset.
2. ABSOLUTE and RELATIVE are described in greater detail in the discussion of FETCH in
Chapter 5 of DB2 SQL Reference.

Example: To use the cursor that is declared in Figure 9 on page 104 to fetch the
fifth row of the result table, use a FETCH statement like this:
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;

Determining the number of rows in the result table for a static 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. You can then examine the fields SQLERRD(1) and SQLERRD(2) in the
SQLCA (fields sqlerrd[0] and sqlerrd[1] for C and C++) for the number of rows in
| the result table. Alternatively, you can use the GET DIAGNOSTICS statement to
| retrieve the number of rows in the ROW_COUNT statement item.

| FETCH statement interaction between row and rowset positioning: When you
| declare a cursor with the WITH ROWSET POSITIONING clause, you can intermix
| row-positioned FETCH statements with rowset-positioned FETCH statements. For
| information about using a multiple-row FETCH statement, see “Using a multiple-row
| FETCH statement with host variable arrays” on page 99.

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


| Table 8 shows the interaction between row and rowset positioning for a scrollable
| cursor. Assume that you declare the scrollable cursor on a table with 15 rows.
| Table 8. Interaction between row and rowset positioning for a scrollable cursor
| Keywords in FETCH statement Cursor position when FETCH is executed
| FIRST On row 1
| FIRST ROWSET On a rowset of size 1, consisting of row 1
| FIRST ROWSET FOR 5 ROWS On a rowset of size 5, consisting of rows 1, 2, 3,
| 4, and 5
| CURRENT ROWSET On a rowset of size 5, consisting of rows 1, 2, 3,
| 4, and 5
| CURRENT On row 1
| NEXT (default) On row 2
| NEXT ROWSET On a rowset of size 1, consisting of row 3
| NEXT ROWSET FOR 3 ROWS On a rowset of size 3, consisting of rows 4, 5, and
| 6
| NEXT ROWSET On a rowset of size 3, consisting of rows 7, 8, and
| 9
| LAST On row 15
| LAST ROWSET FOR 2 ROWS On a rowset of size 2, consisting of rows 14 and
| 15
| PRIOR ROWSET On a rowset of size 2, consisting of rows 12 and
| 13
| ABSOLUTE 2 On row 2
| ROWSET STARTING AT ABSOLUTE 2 On a rowset of size 3, consisting of rows 2, 3, and
| FOR 3 ROWS 4
| RELATIVE 2 On row 4
| ROWSET STARTING AT ABSOLUTE 2 On a rowset of size 4, consisting of rows 2, 3, 4,
| FOR 4 ROWS and 5
| RELATIVE -1 On row 1
| ROWSET STARTING AT ABSOLUTE 3 On a rowset of size 2, consisting of rows 3 and 4
| FOR 2 ROWS
| ROWSET STARTING AT RELATIVE 4 On a rowset of size 2, consisting of rows 7 and 8
| PRIOR On row 6
| ROWSET STARTING AT ABSOLUTE 13 On a rowset of size 3, consisting of rows 13, 14,
| FOR 5 ROWS and 15
| FIRST ROWSET On a rowset of size 5, consisting of rows 1, 2, 3,
| 4, and 5
| Note: The FOR n ROWS clause and the ROWSET clause are described in greater detail in
| the discussion of FETCH in Chapter 5 of DB2 SQL Reference.
|

| Comparison of scrollable cursors


| When you declare a cursor as SENSITIVE STATIC, changes that other processes
| or cursors make to the underlying table can be visible to the result table of the
| cursor. Whether those changes are visible depends on whether you specify
| SENSITIVE or INSENSITIVE when you execute FETCH statements with the cursor.
| When you specify FETCH INSENSITIVE, changes that other processes or other
| cursors make to the underlying table are not visible in the result table. When you

108 Application Programming and SQL Guide


| specify FETCH SENSITIVE, changes that other processes or cursors make to the
| underlying table are visible in the result table.

| When you declare a cursor as SENSITIVE DYNAMIC, changes that other


| processes or cursors make to the underlying table are visible to the result table
| after the changes are committed.

| Table 9 summarizes the sensitivity values and their effects on the result table of a
| scrollable cursor.
| Table 9. How sensitivity affects the result table for a scrollable cursor
| DECLARE
| sensitivity FETCH INSENSITIVE FETCH SENSITIVE
| INSENSITIVE No changes to the underlying Not valid.
| table are visible in the result
| table. Positioned UPDATE and
| DELETE statements using the
| cursor are not allowed.
| SENSITIVE STATIC Only positioned updates and All updates and deletes are visible
| deletes that are made by the in the result table. Inserts made by
| cursor are visible in the result other processes are not visible in
| table. the result table.
| SENSITIVE Not valid. All committed changes are visible
| DYNAMIC in the result table, including
| updates, deletes, inserts, and
| changes in the order of the rows.
|

| Holes in the result table of a scrollable cursor


| In some situations, you might not be able to fetch a row from the result table of a
| scrollable cursor, depending on how the cursor is declared:
| v 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.
| Deleting or updating rows after a static cursor is open can result in holes in the
| result table, which means that the result table does not shrink to fill the space of
| deleted rows or the space of rows that have been updated and no longer satisfy
| the search condition. You cannot access a delete hole or an update hole of a
| static cursor, although you can remove holes in specific situations; see
| “Removing a delete hole or an update hole” on page 111.
| v Scrollable cursors that are declared as SENSITIVE DYNAMIC follow a dynamic
| model, which means that the size and contents of the result table, and the order
| of the rows, can change after you open the cursor.
| A dynamic cursor scrolls directly on the base table. If the current row of the
| cursor is deleted or if it is updated so that it no longer satisfies the search
| condition, and the next cursor operation is FETCH CURRENT, then DB2 issues
| an SQL warning.

The following examples demonstrate how delete and update holes can occur when
you use a SENSITIVE STATIC scrollable cursor.

Creating a delete hole with a static scrollable cursor: Suppose that table A
consists of one integer column, COL1, which has the values shown in Figure 12 on
page 110.

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


Figure 12. Values for COL1 of table A

Now suppose that you declare the following SENSITIVE STATIC scrollable 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 13.

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

Creating an update hole with a static scrollable cursor: Suppose that you
declare the following SENSITIVE STATIC scrollable 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;

110 Application Programming and SQL Guide


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

Figure 14. Creating an update hole

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.

Removing a delete hole or an update hole: You can remove a delete hole or an
update hole in specific situations.

If you try to fetch from a delete hole, DB2 issues an SQL warning. If you try to
update or delete a 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 an 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 15 on page 112. 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.

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


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

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 the WITH HOLD clause, does not close after a commit operation. A
cursor that is not held closes after a commit operation.

| After a commit operation, the position of a held cursor depends on its type:
| v A non-scrollable cursor that is held is positioned after the last retrieved row and
| before the next logical row. The next row can be returned from the result table
| with a FETCH NEXT statement.

112 Application Programming and SQL Guide


| v A static scrollable cursor that is held is positioned on the last retrieved row. The
| last retrieved row can be returned from the result table with a FETCH CURRENT
| statement.
| v A dynamic scrollable cursor that is held is positioned after the last retrieved row
| and before the next logical row. The next row can be returned from the result
| table with a FETCH NEXT statement. DB2 returns SQLCODE +231 for a FETCH
| CURRENT statement.

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

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
DSN8810.EMP table after a commit point:
EXEC SQL
DECLARE EMPLUPDT CURSOR WITH HOLD FOR
SELECT EMPNO, LASTNAME, PHONENO, JOB, SALARY, WORKDEPT

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


FROM DSN8810.EMP
WHERE WORKDEPT < ’D11’
ORDER BY EMPNO
END-EXEC.

Examples of using cursors


The examples in this section show the SQL statements that you include in a
COBOL program to define and use cursors in the following ways:
v Non-scrollable cursor for row-positioned updates; see Figure 16 on page 115.
v Scrollable cursor to retrieve rows backward; see Figure 17 on page 116.
v Non-scrollable cursor for rowset-positioned updates; see Figure 18 on page 117.
v Scrollable cursor for rowset-positioned operations; see Figure 19 on page 118.

Figure 16 on page 115 shows how to update a row by using a cursor.

114 Application Programming and SQL Guide


**************************************************
* Declare a cursor that will be used to update *
* the JOB column of the EMP table. *
**************************************************
EXEC SQL
DECLARE THISEMP CURSOR FOR
SELECT EMPNO, LASTNAME,
WORKDEPT, JOB
FROM DSN8810.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 FROM THISEMP
INTO :EMP-NUM, :NAME2,
:DEPT, :JOB-NAME
END-EXEC.
**************************************************
* Update the row where the cursor is positioned. *
**************************************************
EXEC SQL
UPDATE DSN8810.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 16. Performing cursor operations with a non-scrollable cursor

Figure 17 on page 116 shows how to retrieve data backward with a cursor.

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


**************************************************
* Declare a cursor to retrieve the data backward *
* from the EMP table. The cursor has access to *
* changes by other processes. *
**************************************************
EXEC SQL
DECLARE THISEMP SENSITIVE STATIC SCROLL CURSOR FOR
SELECT EMPNO, LASTNAME, WORKDEPT, JOB
FROM DSN8810.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 FROM THISEMP
END-EXEC.
**************************************************
* Fetch the previous row in the table. *
**************************************************
EXEC SQL
FETCH SENSITIVE PRIOR FROM THISEMP
INTO :EMP-NUM, :NAME2, :DEPT, :JOB-NAME
END-EXEC.
**************************************************
* Check that the fetched row is not a hole *
* (SQLCODE +222). If not, print the 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 17. Performing cursor operations with a SENSITIVE STATIC scrollable cursor

Figure 18 on page 117 shows how to update an entire rowset with a cursor.

116 Application Programming and SQL Guide


| **************************************************
| * Declare a rowset cursor to update the JOB *
| * column of the EMP table. *
| **************************************************
| EXEC SQL
| DECLARE EMPSET CURSOR
| WITH ROWSET POSITIONING FOR
| SELECT EMPNO, LASTNAME, WORKDEPT, JOB
| FROM DSN8810.EMP
| WHERE WORKDEPT = ’D11’
| FOR UPDATE OF JOB
| END-EXEC.
| **************************************************
| * Open the cursor. *
| **************************************************
| EXEC SQL
| OPEN EMPSET
| END-EXEC.
| **************************************************
| * Indicate what action to take when end-of-data *
| * occurs in the rowset being fetched. *
| **************************************************
| EXEC SQL
| WHENEVER NOT FOUND
| GO TO CLOSE-EMPSET
| END-EXEC.
| **************************************************
| * Fetch next rowset to position the cursor. *
| **************************************************
| EXEC SQL
| FETCH NEXT ROWSET FROM EMPSET
| FOR :SIZE-ROWSET ROWS
| INTO :HVA-EMPNO, :HVA-LASTNAME,
| :HVA-WORKDEPT, :HVA-JOB
| END-EXEC.
| **************************************************
| * Update rowset where the cursor is positioned. *
| **************************************************
| UPDATE-ROWSET.
| EXEC SQL
| UPDATE DSN8810.EMP
| SET JOB = :NEW-JOB
| WHERE CURRENT OF EMPSET
| END-EXEC.
|| . END-UPDATE-ROWSET.
|| .
.
| **************************************************
| * Branch back to fetch the next rowset. *
|| **************************************************
.
|| .
.
| **************************************************
| * Update the remaining rows in the current *
| * rowset and close the cursor. *
| **************************************************
| CLOSE-EMPSET.
| PERFORM UPDATE-ROWSET.
| EXEC SQL
| CLOSE EMPSET
| END-EXEC.

|
| Figure 18. Performing positioned update with a rowset cursor
|
Figure 19 on page 118 shows how to update specific rows with a rowset cursor.

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


| *****************************************************
| * Declare a static scrollable rowset cursor. *
| *****************************************************
| EXEC SQL
| DECLARE EMPSET SENSITIVE STATIC SCROLL CURSOR
| WITH ROWSET POSITIONING FOR
| SELECT EMPNO, WORKDEPT, JOB
| FROM DSN8810.EMP
| FOR UPDATE OF JOB
| END-EXEC.
| *****************************************************
| * Open the cursor. *
| *****************************************************
| EXEC SQL
| OPEN EMPSET
| END-EXEC.
| *****************************************************
| * Fetch next rowset to position the cursor. *
| *****************************************************
| EXEC SQL
| FETCH SENSITIVE NEXT ROWSET FROM EMPSET
| FOR :SIZE-ROWSET ROWS
| INTO :HVA-EMPNO,
| :HVA-WORKDEPT :INDA-WORKDEPT,
| :HVA-JOB :INDA-JOB
| END-EXEC.
| *****************************************************
| * Process fetch results if no error and no hole. *
| *****************************************************
| IF SQLCODE >= 0
| EXEC SQL GET DIAGNOSTICS
| :HV-ROWCNT = ROW_COUNT
| END-EXEC
| PERFORM VARYING N FROM 1 BY 1 UNTIL N > HV-ROWCNT
| IF INDA-WORKDEPT(N) NOT = -3
| EVALUATE HVA-WORKDEPT(N)
| WHEN (’D11’)
| PERFORM UPDATE-ROW
| WHEN (’E11’)
| PERFORM DELETE-ROW
| END-EVALUATE
| END-IF
| END-PERFORM
| IF SQLCODE = 100
| GO TO CLOSE-EMPSET
| END-IF
| ELSE
| EXEC SQL GET DIAGNOSTICS
| :HV-NUMCOND = NUMBER
| END-EXEC
| PERFORM VARYING N FROM 1 BY 1 UNTIL N > HV-NUMCOND
| EXEC SQL GET DIAGNOSTICS CONDITION :N
| :HV-SQLCODE = DB2_RETURNED_SQLCODE,
| :HV-ROWNUM = DB2_ROW_NUMBER
| END-EXEC
| DISPLAY "SQLCODE = " HV-SQLCODE
| DISPLAY "ROW NUMBER = " HV-ROWNUM
| END-PERFORM
| GO TO CLOSE-EMPSET
| END-IF.

|
| Figure 19. Performing positioned update and delete with a sensitive rowset cursor (Part 1 of
| 2)
|

118 Application Programming and SQL Guide


.
.
.
*****************************************************
* Branch back to fetch and process *
* the next rowset. *
*****************************************************
.
.
.
*****************************************************
* Update row N in current rowset. *
*****************************************************
UPDATE-ROW.
EXEC SQL
UPDATE DSN8810.EMP
SET JOB = :NEW-JOB
FOR CURSOR EMPSET FOR ROW :N OF ROWSET
END-EXEC.
END-UPDATE-ROW.
*****************************************************
* Delete row N in current rowset. *
*****************************************************
DELETE-ROW.
EXEC SQL
DELETE FROM DSN8810.EMP
FOR CURSOR EMPSET FOR ROW :N OF ROWSET
END-EXEC.
. END-DELETE-ROW.
.
.
*****************************************************
* Close the cursor. *
*****************************************************
CLOSE-EMPSET.
EXEC SQL
CLOSE EMPSET
END-EXEC.

Figure 19. Performing positioned update and delete with a sensitive rowset cursor (Part 2 of
| 2)

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


120 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 Part 3 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 corresponding PL/I, C structure
declaration, or COBOL record description. You can use DCLGEN for table
declarations only if the table you are declaring already exists.

You must use DCLGEN before you precompile your program. Supply the table or
view name to DCLGEN before you precompile your program. To use the
declarations generated by DCLGEN in your program, use the SQL INCLUDE
statement. For more information about the INCLUDE statement, see Chapter 5 of
DB2 SQL Reference.

DB2 must be active before you can use DCLGEN. You can start DCLGEN in
several different ways:
v From ISPF through DB2I. Select the DCLGEN option on the DB2I Primary Option
Menu panel.
v Directly from TSO. To do this, sign on to TSO, issue the TSO command DSN,
and then issue the subcommand DCLGEN.
v From a CLIST, running in TSO foreground or background, that issues DSN and
then DCLGEN.
v With JCL. Supply the required information, using JCL, and run DCLGEN in batch.
If you want to start DCLGEN in the foreground, and your table names include
DBCS characters, you must provide and display double-byte characters. If you
do not have a terminal that displays DBCS characters, you can enter DBCS
characters using the hex mode of ISPF edit.

Invoking DCLGEN through DB2I


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

© Copyright IBM Corp. 1983, 2004 121


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 20. DCLGEN panel

| The DB2I help system contains detailed descriptions of the fields of the DCLGEN
| panel. For more information about the DB2I help system, see “DB2I help” on page
| 495.

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


non-delimited identifier unless at least one of the following conditions is true:
v The name contains special characters and is not a DBCS string.
v The name is a DBCS string, and you have requested delimited DBCS names.

If you are using an SQL reserved word as an identifier, you must edit the DCLGEN
output in order to add the appropriate SQL delimiters.

DCLGEN produces output that is intended to meet the needs of most users, but
occasionally, you will need to edit the DCLGEN output to work in your specific case.
For example, DCLGEN is unable to determine whether a column that is defined as
NOT NULL also contains the DEFAULT clause, so you must edit the DCLGEN
output to add the DEFAULT clause to the appropriate column definitions.

Including 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 DSN8810.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 DSN8810.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 129.) To get a
122 Application Programming and SQL Guide
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 support of C, COBOL, and PL/I languages


| DCLGEN derives variable names from the source in the database. Table 10 lists the
| type declarations that DCLGEN produces for C, COBOL, and PL/I based on the
| corresponding SQL data types that are contained in the source tables. In Table 10,
var represents variable names that DCLGEN provides.
Table 10. Declarations generated by DCLGEN
SQL data type1 C COBOL PL/I
SMALLINT short int PIC S9(4) USAGE COMP BIN FIXED(15)
INTEGER long int PIC S9(9) USAGE COMP BIN FIXED(31)
2
DECIMAL(p,s) or decimal(p,s) PIC S9(p-s)V9(s) USAGE COMP-3 DEC FIXED(p,s)
NUMERIC(p,s)
If p>15, the PL/I
compiler must support
this precision, or a
warning is generated.
REAL or FLOAT(n) 1 <= n <= float USAGE COMP-1 BIN FLOAT(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).
CLOB(n)3 SQL TYPE IS USAGE SQL TYPE IS CLOB-LOCATOR SQL TYPE IS
CLOB_LOCATOR CLOB_LOCATOR
| GRAPHIC(1) sqldbchar PIC G(1) GRAPHIC(1)
| GRAPHIC(n) n > 1 sqldbchar var[n+1]; PIC G(n) USAGE GRAPHIC(n)
DISPLAY-1.4
or
PIC N(n).4
VARGRAPHIC(n) struct VARGRAPH 10 var. GRAPHIC(n) VAR
{short len; 49 var_LEN PIC 9(4)
| sqldbchar data[n]; USAGE COMP.
} var; 49 var_TEXT PIC G(n)
USAGE DISPLAY-1.4
or
10 var.
49 var_LEN PIC 9(4)
USAGE COMP.
49 var_TEXT PIC N(n).4
DBCLOB(n)5 SQL TYPE IS USAGE SQL TYPE IS SQL TYPE IS
DBCLOB_LOCATOR DBCLOB-LOCATOR DBCLOB_LOCATOR
BLOB(n)5 SQL TYPE IS USAGE SQL TYPE IS BLOB-LOCATOR SQL TYPE IS
BLOB_LOCATOR BLOB_LOCATOR
DATE char var[11]5 PIC X(10)5 CHAR(10)5

Chapter 8. Generating declarations for your tables using DCLGEN 123


Table 10. Declarations generated by DCLGEN (continued)
SQL data type1 C COBOL PL/I
6 6
TIME char var[9] PIC X(8) CHAR(8)6
TIMESTAMP char var[27] PIC X(26) CHAR(26)
ROWID SQL TYPE IS ROWID USAGE SQL TYPE IS ROWID SQL TYPE IS ROWID

Notes:
1. For a distinct type, DCLGEN generates the host language equivalent of the source data type.
2. If your C compiler does not support the decimal data type, edit your DCLGEN output, and replace the decimal
data declarations with declarations of type double.
3. For a BLOB, CLOB, or DBCLOB data type, DCLGEN generates a LOB locator.
4. DCLGEN chooses the format based on the character you specify as the DBCS symbol on the COBOL Defaults
panel.
5. This declaration is used unless a date installation exit routine exists for formatting dates, in which case the length
is that specified for the LOCAL DATE LENGTH installation option.
6. This declaration is used unless a time installation exit routine exists for formatting times, in which case the length
is that specified for the LOCAL TIME LENGTH installation option.

For more details about the DCLGEN subcommand, see Part 3 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 DSN8810.VPHONE.
v The host-variable structure is for COBOL.
v The structure receives the default name DCLVPHONE.

Information that you must enter is in bold-faced type.

Step 1. Specify COBOL as the host language


Select option D on the ISPF/PDF menu to display the DB2I Defaults panel.

Specify COBOL as the application language, as shown in Figure 21 on page 125,


and press Enter.

124 Application Programming and SQL Guide


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, 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 21. DB2I defaults panel—changing the application language

The COBOL Defaults panel is then displayed, as shown in Figure 22. Fill in the
COBOL Defaults panel as necessary. Press Enter to save the new defaults, if any,
and return to the DB2I Primary Option menu.

DSNEOP02 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 22. The COBOL defaults panel. Shown only if the field APPLICATION LANGUAGE on
the DB2I Defaults panel is IBMCOB.

Step 2. Create the table declaration and host structure


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

Fill in the fields as shown in Figure 23 on page 126, and then press Enter.

Chapter 8. Generating declarations for your tables using DCLGEN 125


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

1 SOURCE TABLE NAME ===> DSN8810.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 23. DCLGEN panel—selecting source table and destination data set

If the operation succeeds, a message is displayed at the top of your screen, as


shown in Figure 24.

DSNE905I EXECUTION COMPLETE, MEMBER VPHONEC ADDED


***

Figure 24. Successful completion message

DB2 again displays the DCLGEN screen, as shown in Figure 25. Press Enter to
return to the DB2I Primary Option menu.

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 ===> DSN8810.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 25. DCLGEN panel—displaying system and user return codes

Step 3. Examine the results


To browse or edit the results, exit from DB2I, and select either the browse or the
edit option from the ISPF/PDF menu to view the results.

126 Application Programming and SQL Guide


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

***** DCLGEN TABLE(DSN8810.VPHONE) ***


***** LIBRARY(SYSADM.TEMP.COBOL(VPHONEC)) ***
***** QUOTE ***
***** ... IS THE DCLGEN COMMAND THAT MADE THE FOLLOWING STATEMENTS ***
EXEC SQL DECLARE DSN8810.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 DSN8810.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 26. DCLGEN results displayed in edit mode

Chapter 8. Generating declarations for your tables using DCLGEN 127


128 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 C++ application” on page 143
v “Coding SQL statements in a COBOL application” on page 170
v “Coding SQL statements in a Fortran application” on page 203
v “Coding SQL statements in a PL/I application” on page 213.
v “Coding SQL statements in a REXX application” on page 232.

For each language, this chapter provides 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 Declaring host variable arrays for C or C++, COBOL, and PL/I
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 about reading the syntax diagrams in this chapter, see “How to read
the syntax diagrams” on page xx.

For information about 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)
Alternatively, you can include 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 values to determine whether the last SQL
statement was successful. All SQL statements in the program must be within the
scope of the declaration of the SQLCODE and SQLSTATE variables.

Whether you define the SQLCODE or SQLSTATE variable or an SQLCA in your


program depends on whether you specify the precompiler option STDSQL(YES) to
conform to the SQL standard, or STDSQL(NO) to conform to DB2 rules.

© Copyright IBM Corp. 1983, 2004 129


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
that is acquired for your task (a DSECT). For example, at the beginning of your
program, specify:
PROGAREA DSECT
EXEC SQL INCLUDE SQLCA

As an alternative, you can create a separate storage area for the SQLCA and
provide addressability to that area.

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, a program can have 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.

130 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 DSN8810.DEPT X
SET MGRNO = :MGRNUM X
WHERE DEPTNO = :INTDEPT

| Multiple-row FETCH statements: You can use only the FETCH ... USING
| DESCRIPTOR form of the multiple-row FETCH statement in an assembler program.
| The DB2 precompiler does not recognize declarations of host variable arrays for an
| assembler program.

| Comments: You cannot include assembler comments in SQL statements. However,


| you can include SQL comments in any embedded SQL statement.

Continuation for SQL statements: The line continuation rules for SQL statements
are the same as those for assembler statements, except that you must specify
EXEC SQL within one line. Any part of the statement that does not fit on one line
can appear on subsequent lines, beginning at the continuation margin (column 16,
the default). Every line of the statement, except the last, must have a continuation
character (a non-blank character) immediately after the right margin in column 72.

Declaring tables and views: Your assembler program should include a DECLARE
statement to describe each table and view the program accesses.

Including code: To include SQL statements or assembler host variable declaration


statements from a member of a partitioned data set, place the following SQL
statement in the source code where you want to include the statements:
EXEC SQL INCLUDE member-name

You cannot nest SQL INCLUDE statements.

Margins: 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 that is used in embedded SQL cannot be an
underscore. However, you can use an underscore as the first character in a symbol
that is not used in embedded SQL.

Chapter 9. Embedding SQL statements in host languages 131


Assembler

Statement labels: You can prefix an SQL statement with a label. The first line of an
SQL statement can use a label beginning in the left margin (column 1). If you do
not use a label, leave column 1 blank.

WHENEVER statement: The target for the GOTO clause in an SQL WHENEVER
statement must be a label in the assembler source code and must be within the
scope of the SQL statements that WHENEVER affects.

Special assembler considerations: The following considerations apply to


programs written in assembler:
v To allow for reentrant programs, the precompiler puts all the variables and
structures it generates within a DSECT called SQLDSECT, and it generates an
assembler symbol called SQLDLEN. SQLDLEN contains the length of the
DSECT. Your program must allocate an area of the size indicated by SQLDLEN,
initialize it, and provide addressability to it as the DSECT SQLDSECT.

CICS
An example of code to support reentrant programs, running under CICS,
follows:
DFHEISTG DSECT
DFHEISTG
EXEC SQL INCLUDE SQLCA
*
DS 0F
SQDWSREG EQU R7
SQDWSTOR DS (SQLDLEN)C RESERVE STORAGE TO BE USED FOR SQLDSECT
.
.
.

XXPROGRM DFHEIENT CODEREG=R12,EIBREG=R11,DATAREG=R13


*
*
* SQL WORKING STORAGE
LA SQDWSREG,SQDWSTOR GET ADDRESS OF SQLDSECT
USING SQLDSECT,SQDWSREG AND TELL ASSEMBLER ABOUT IT
*

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 that is generated by an SQL statement.

132 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, any SQL statement that references
the variable might result in the message UNDECLARED HOST VARIABLE.

Numeric host variables: Figure 27 on page 134 shows the syntax for declarations
of numeric host variables. The numeric value specifies the scale of the packed
decimal variable. If value does not include a decimal point, the scale is 0.

Chapter 9. Embedding SQL statements in host languages 133


Assembler

 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 27. Numeric host variables

For floating-point data types (E, EH, EB, D, DH, and DB), DB2 uses the FLOAT
| precompiler option to determine whether the host variable is in IEEE binary
| floating-point or System/390® hexadecimal floating-point format. If the precompiler
option is FLOAT(S390), you need to define your floating-point host variables as E,
EH, D, or DH. If the precompiler option is FLOAT(IEEE), you need to define your
floating-point host variables as EB or DB. DB2 converts all floating-point input data
| to System/390 hexadecimal floating-point before storing it.

Character host variables: The three valid forms for character host variables are:
v Fixed-length strings
v Varying-length strings
v CLOBs

The following figures show the syntax for forms other than CLOBs. See Figure 34
on page 136 for the syntax of CLOBs.

Figure 28 shows the syntax for declarations of fixed-length character strings.

 variable-name DC C 
DS 1 Ln

Figure 28. Fixed-length character strings

Figure 29 shows the syntax for declarations of varying-length character strings.

 variable-name DC H , CLn 
DS 1 L2 1

Figure 29. Varying-length character strings

134 Application Programming and SQL Guide


Assembler

Graphic host variables: The three valid forms for graphic host variables are:
v Fixed-length strings
v Varying-length strings
v DBCLOBs

The following figures show the syntax for forms other than DBCLOBs. See
Figure 34 on page 136 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.

Figure 30 shows the syntax for declarations of fixed-length graphic strings.

 variable-name DC G 
DS Ln
’<value>’
Ln’<value>’

Figure 30. Fixed-length graphic strings

Figure 31 shows the syntax for declarations of varying-length graphic strings.

 variable-name DS H , GLn 
DC L2 ’m’ ’<value>’

Figure 31. Varying-length graphic strings

Result set locators: Figure 32 shows the syntax for declarations of result set
locators. See Chapter 25, “Using stored procedures for client/server processing,” on
page 569 for a discussion of how to use these host variables.

 variable-name DC F 
DS 1 L4

Figure 32. Result set locators

Table Locators: Figure 33 shows the syntax for declarations of table locators. See
“Accessing transition tables in a user-defined function or stored procedure” on page
328 for a discussion of how to use these host variables.

 variable-name SQL TYPE IS TABLE LIKE table-name AS LOCATOR 

Figure 33. Table locators

LOB variables and locators: Figure 34 on page 136 shows the syntax for
declarations of BLOB, CLOB, and DBCLOB host variables and locators. See
Chapter 14, “Programming for large objects (LOBs),” on page 281 for a discussion
of how to use these host variables.

Chapter 9. Embedding SQL statements in host languages 135


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

ROWIDs: Figure 35 shows the syntax for declarations of ROWID host variables.
See Chapter 14, “Programming for large objects (LOBs),” on page 281 for a
discussion of how to use these host variables.

 variable-name SQL TYPE IS ROWID 

Figure 35. ROWID variables

Determining equivalent SQL and assembler data types


Table 11 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 11. SQL data types the precompiler uses for assembler declarations
SQLTYPE of SQLLEN of
Assembler data type host variable host variable SQL data type

DS HL2 500 2 SMALLINT

DS FL4 496 4 INTEGER

DS P’value’ 484 p in byte 1, s in DECIMAL(p,s)


DS PLn’value’ or byte 2
DS PLn See the description for
1<=n<=16 DECIMAL(p,s) in Table 12 on
page 138.

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

136 Application Programming and SQL Guide


Assembler

Table 11. SQL data types the precompiler uses for assembler declarations (continued)
SQLTYPE of SQLLEN of
Assembler data type host variable host variable SQL data type

DS HL2,CLn 456 n VARCHAR(n)


n>255

DS GLm 468 n GRAPHIC(n)2


2<=m<=2541

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

Notes:
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 12 on page 138 helps you define host variables that receive output from the
database. You can use Table 12 on page 138 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 12 on page 138 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 about compatible data types.

Chapter 9. Embedding SQL statements in host languages 137


Assembler

Table 12. SQL data types mapped to typical assembler declarations


SQL data type Assembler equivalent Notes
SMALLINT DS HL2
INTEGER DS F
DECIMAL(p,s) or DS P’value’ p is precision; s is scale. 1<=p<=31 and
NUMERIC(p,s) DS PLn’value’ 0<=s<=p. 1<=n<=16. value is a literal
DS PLn value that includes a decimal point. You
must use Ln, value, or both. Using only
value is recommended.

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 DS DL8 22<=n<=53
PRECISION, DS DHL8
DOUBLE, or DS DBL81
FLOAT(n)
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 x and m are expressed in bytes. n is the
DS HL2’m’,GLx’<value>’ number of 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.

138 Application Programming and SQL Guide


Assembler

Table 12. SQL data types mapped to typical assembler declarations (continued)
SQL data type Assembler equivalent Notes
Table locator SQL TYPE IS Use this data type only in a user-defined
TABLE LIKE function or stored procedure to receive
table-name rows of a transition table. Do not use this
AS LOCATOR 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:
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 considerations when you declare assembler
variables.

Host graphic data type: You can use the assembler data type “host graphic” in
SQL statements when the precompiler option GRAPHIC is in effect. However, you
cannot use assembler DBCS literals in SQL statements, even when GRAPHIC is in
effect.

Character host variables: If you declare a host variable as a character string


without a length, for example DC C ’ABCD’, DB2 interprets it as length 1. To get the
correct length, give a length attribute (for example, DC CL4’ABCD’).

Floating-point host variables: All floating-point data is stored in DB2 in


| System/390 hexadecimal floating-point format. However, your host variable data can
| be in System/390 hexadecimal floating-point format or IEEE binary floating-point
format. DB2 uses the FLOAT precompiler option to determine whether your
floating-point host variables are in IEEE binary floating-point format or System/390
| hexadecimal floating-point format. DB2 does no checking to determine whether the
host variable declarations or format of the host variable contents match the
precompiler option. Therefore, you need to ensure that your floating-point host
variable types and contents match the precompiler option.

Special purpose assembler data types: The locator data types are assembler
language data types and SQL data types. You cannot use locators as column types.
For information about how to use these data types, see the following sections:

Chapter 9. Embedding SQL statements in host languages 139


Assembler

Table locator “Accessing transition tables in a user-defined function or stored


procedure” on page 328
LOB locators Chapter 14, “Programming for large objects (LOBs),” on page 281

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.

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.

140 Application Programming and SQL Guide


Assembler

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 about
assigning and comparing distinct types, see Chapter 16, “Creating and using
distinct types,” on page 349.

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 (DS HL2). If you provide an indicator
variable for the variable X, when DB2 retrieves a null value for X, it puts a negative
value in the indicator variable and does not update X. Your program should check
the indicator variable before using X. If the indicator variable is negative, you know
that X is null and any value you find in X is irrelevant.

When your program uses X to assign a null value to a column, the program should
set the indicator variable to a negative number. DB2 then assigns a null value to the
column and ignores any value in X.

You declare indicator variables in the same way as host variables. You can mix the
declarations of the two types of variables in any way that seems appropriate. For
more information about indicator variables, see “Using indicator variables with host
variables” on page 75 or Chapter 2 of DB2 SQL Reference.

Example: The following example shows a FETCH statement with the declarations
of the host variables that are needed for the FETCH statement:
EXEC SQL FETCH CLS_CURSOR INTO :CLSCD, 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

Figure 36 shows the syntax for declarations of indicator host variables.

 variable-name DC H 
DS 1 L2

Figure 36. Indicator variable

Chapter 9. Embedding SQL statements in host languages 141


Assembler

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 about the behavior of DSNTIAR, see
“Calling DSNTIAR to display SQLCA fields” on page 89.

| You can also use the MESSAGE_TEXT condition item field of the GET
| DIAGNOSTICS statement to convert an SQL return code into a text message.
| Programs that require long token message support should code the GET
| DIAGNOSTICS statement instead of DSNTIAR. For more information about GET
| DIAGNOSTICS, see “Using the GET DIAGNOSTICS statement” on page 84.

DSNTIAR syntax
CALL DSNTIAR,(sqlca, message, lrecl),MF=(E,PARM)

The DSNTIAR parameters have the following meanings:


sqlca
An SQL communication area.
message
An output area, defined as a varying-length string, in which DSNTIAR places
the message text. The first halfword contains the length of the remaining area;
its minimum value is 240.
The output lines of text, each line being the length specified in lrecl, are put into
this area. For example, you could specify the format of the output area as:
LINES 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 z/OS macro parameter that indicates dynamic


execution. PARM is the name of a data area that contains a list of pointers to the
call parameters of DSNTIAR.

142 Application Programming and SQL Guide


Assembler

See Appendix B, “Sample applications,” on page 915 for instructions on how to


access and print the source code for the sample program.

CICS
If your CICS application requires CICS storage handling, you must use the
subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax:
CALL DSNTIAC,(eib,commarea,sqlca,msg,lrecl),MF=(E,PARM)

DSNTIAC has extra parameters, which you must use for calls to routines that
use CICS commands.
eib EXEC interface block
commarea communication area

For more information on these parameters, see the appropriate application


programming guide for CICS. The remaining parameter descriptions are the
same as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the
SQLCA in the same way.

You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you
must also define them in the CSD. For an example of CSD entry generation
statements for use with DSNTIAC, see member DSN8FRDO in the data set
prefix.SDSNSAMP.

The assembler source code for DSNTIAC and job DSNTEJ5A, which
assembles and link-edits DSNTIAC, are also in the data set
prefix.SDSNSAMP.

Macros for assembler applications


Data set DSN810.SDSNMACS contains all DB2 macros that are available for use.

Coding SQL statements in a C or 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 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];
Alternatively, you can include 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 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 143


C

Whether you define the SQLCODE or SQLSTATE variable or an SQLCA in your


program depends on whether you specify the precompiler option STDSQL(YES) to
conform to 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 BEGIN
DECLARE SECTION and END DECLARE SECTION statements 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 statement 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.

144 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
semicolon (;). The EXEC and SQL keywords must appear on one line, but the
remainder of the statement can appear on subsequent lines.

In general, because C is case sensitive, use uppercase letters to enter all SQL
keywords. However, if you use the FOLD precompiler suboption, DB2 folds
lowercase letters in SBCS SQL ordinary identifiers to uppercase. For information
about host language precompiler options, see Table 63 on page 462.

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

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 DECLARE TABLE
statement to describe each table and view the program accesses. You can use the
DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE
statements. For more information, see Chapter 8, “Generating declarations for your
tables using DCLGEN,” on page 121.

Including code: To include SQL statements or C host variable declarations from a


member of a partitioned data set, add the following SQL statement to the source
code where you want to include the statements:
EXEC SQL INCLUDE member-name;

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 145


C

v Do not use DBCS characters.


v Do not use external entry names or access plan names that begin with ’DSN’,
and do not use host variable names that begin with ’SQL’ (in any combination of
uppercase or lowercase letters). These names are reserved for DB2.

Nulls and NULs: C and SQL differ in the way they use the word null. The C
language has a null character (NUL), a null pointer (NULL), and a null statement
(just a semicolon). The C NUL is a single character that compares equal to 0. The
C NULL is a special reserved pointer value that does not point to any valid data
object. The SQL null value is a special value that is distinct from all non-null values
and denotes the absence of a (nonnull) value. 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.

Trigraph characters: Some characters from the C character set are not available
on all keyboards. You can enter these characters into a C source program using a
sequence of three characters called a trigraph. The trigraph characters that DB2
supports are the same as those that the C compiler supports.

WHENEVER statement: The target for the GOTO clause in an SQL WHENEVER
statement must be within the scope of any SQL statements that the statement
WHENEVER affects.

Special C considerations:
v Using the C/370™ multi-tasking facility, in which multiple tasks execute SQL
statements, causes unpredictable results.
v 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.
Refer to the appropriate C documentation for more information about C
preprocessor directives.

| Using host variables and host variable arrays


| You must explicitly declare each host variable and each host variable array before
| using them 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 using it in the DECLARE CURSOR statement.

| Precede C statements that define the host variables and host variable arrays with
| the BEGIN DECLARE SECTION statement, and follow the C statements with the
| END DECLARE SECTION statement. You can have more than one host variable
| declaration section in your program.

| A colon (:) must precede all host variables and all host variable arrays in an SQL
| statement.

146 Application Programming and SQL Guide


C

| The names of host variables and host variable arrays must be unique within the
| program, even if the variables and variable arrays are in different blocks, classes, or
| procedures. You can qualify the names with a structure name to make them unique.

| An SQL statement that uses a host variable or host variable array must be within
| the scope of the statement that declares that variable or array. You define host
| variable arrays for use with multiple-row FETCH and INSERT statements.

Declaring host variables


Only some of the valid C declarations are valid host variable declarations. If the
declaration for a variable is not valid, any SQL statement that references the
variable might result in the message UNDECLARED HOST VARIABLE.

Numeric host variables: Figure 37 shows the syntax for declarations of numeric
host variables.

|  float 
auto const double
extern volatile int
static short
sqlint32
int
long
int
long long
decimal ( integer )
, integer

| ,

  variable-name ; 
*pointer-name =expression

Figure 37. Numeric host variables

| Notes:
| 1. The SQL statement coprocessor is required if you use a pointer as a host
| variable.

Character host variables: The four valid forms for character host variables are:
v Single-character form
v NUL-terminated character form
v VARCHAR structured form
v CLOBs

The following figures show the syntax for forms other than CLOBs. See Figure 46
on page 153 for the syntax of CLOBs.

Figure 38 on page 148 shows the syntax for declarations of single-character host
variables.

Chapter 9. Embedding SQL statements in host languages 147


C

| ,

 char  variable-name ; 
auto const unsigned *pointer-name =expression
extern volatile
static

Figure 38. Single-character form

| Notes:
| 1. The SQL statement coprocessor is required if you use a pointer as a host
| variable.

Figure 39 shows the syntax for declarations of NUL-terminated character host


variables.

 char 
auto const unsigned
extern volatile
static

| ,

  variable-name [ length ] ; 
*pointer-name =expression

Figure 39. 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).
| 4. The SQL statement coprocessor is required if you use a pointer as a host
| variable.

Figure 40 on page 149 shows the syntax for declarations of varying-length


character host variables that use the VARCHAR structured form.

148 Application Programming and SQL Guide


C

int
 struct { short var-1 ; 
auto const tag
extern volatile
static

 char var-2 [ length ] ; } 


unsigned

| ,

  variable-name ; 
*pointer-name ={expression, expression}

Figure 40. VARCHAR structured form

Notes:
1. var-1 and var-2 must be simple variable references. You cannot use them as
host variables.
2. You can use the struct tag to define other data areas that you cannot use as
host variables.
| 3. The SQL statement coprocessor is required if you use a pointer as a host
| variable.

Example: The following examples show valid and invalid declarations of the
VARCHAR structured form:
EXEC SQL BEGIN DECLARE SECTION;

/* valid declaration of host variable VARCHAR vstring */


struct VARCHAR {
short len;
char s[10];
} vstring;

/* invalid declaration of host variable VARCHAR wstring */


struct VARCHAR wstring;

Graphic host variables: The four valid forms for graphic host variables are:
v Single-graphic form
v NUL-terminated graphic form
v VARGRAPHIC structured form.
v DBCLOBs

| You can use the C data type sqldbchar 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 46 on page 153 for the syntax of DBCLOBs.

Figure 41 on page 150 shows the syntax for declarations of single-graphic host
variables.

Chapter 9. Embedding SQL statements in host languages 149


C

| ,

 sqldbchar  variable-name ; 
auto const *pointer-name =expression
extern volatile
static

Figure 41. Single-graphic form

| Notes:
| 1. The SQL statement coprocessor is required if you use a pointer as a host
| variable.

The single-graphic form declares a fixed-length graphic string of length 1. You


cannot use array notation in variable-name.

Figure 42 shows the syntax for declarations of NUL-terminated graphic host


variables.

| ,

 sqldbchar  variable-name [ length ] ; 


auto const *pointer-name =expression
extern volatile
static

Figure 42. 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.
| 5. The SQL statement coprocessor is required if you use a pointer as a host
| variable.

Figure 43 on page 151 shows the syntax for declarations of graphic host variables
that use the VARGRAPHIC structured form.

150 Application Programming and SQL Guide


C

int
 struct { short var-1 ; 
auto const tag
extern volatile
static

| ,

 sqldbchar var-2 [ length ] ; }  variable-name 


*pointer-name ={ expression, expression}

 ; 

Figure 43. VARGRAPHIC structured form

Notes:
1. length must be a decimal integer constant greater than 1 and not greater than
16352.
2. var-1 must be less than or equal to length.
3. var-1 and var-2 must be simple variable references. You cannot use them as
host variables.
4. You can use the struct tag to define other data areas that you cannot use as
host variables.
| 5. The SQL statement coprocessor is required if you use a pointer as a host
| variable.

Example: The following examples show valid and invalid declarations of graphic
host variables that use the VARGRAPHIC structured form:
EXEC SQL BEGIN DECLARE SECTION;

/* valid declaration of host variable structured vgraph */


struct VARGRAPH {
short len;
| sqldbchar d[10];
} vgraph;

/* invalid declaration of host variable structured wgraph */


struct VARGRAPH wgraph;

Result set locators: Figure 44 on page 152 shows the syntax for declarations of
result set locators. See Chapter 25, “Using stored procedures for client/server
processing,” on page 569 for a discussion of how to use these host variables.

Chapter 9. Embedding SQL statements in host languages 151


C

 SQL TYPE IS RESULT_SET_LOCATOR VARYING 


auto const
extern volatile
static
register

| ,

  variable-name ; 
*pointer-name = init-value

Figure 44. Result set locators

Table Locators: Figure 45 shows the syntax for declarations of table locators. See
“Accessing transition tables in a user-defined function or stored procedure” on page
328 for a discussion of how to use these host variables.

 SQL TYPE IS TABLE LIKE table-name AS LOCATOR 


auto const
extern volatile
static
register

| ,

  variable-name ; 
*pointer-name init-value

Figure 45. Table locators

LOB Variables and Locators: Figure 46 on page 153 shows the syntax for
declarations of BLOB, CLOB, and DBCLOB host variables and locators. See
Chapter 14, “Programming for large objects (LOBs),” on page 281 for a discussion
of how to use these host variables.

152 Application Programming and SQL Guide


C

 SQL TYPE IS 
auto const
extern volatile
static
register

| ,

 BINARY LARGE OBJECT ( length )  variable-name 


BLOB K *pointer-name init-value
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR

 ; 

Figure 46. LOB variables and locators

ROWIDs: Figure 47 shows the syntax for declarations of ROWID host variables.
See Chapter 14, “Programming for large objects (LOBs),” on page 281 for a
discussion of how to use these host variables.

|  variable-name SQL TYPE IS ROWID ; 


auto const *pointer-name
extern volatile
static
register

Figure 47. ROWID variables

| Declaring host variable arrays


| Only some of the valid C declarations are valid host variable array declarations. If
| the declaration for a variable array is not valid, then any SQL statement that
| references the variable array might result in the message UNDECLARED HOST
| VARIABLE ARRAY.

| Numeric host variable arrays: Figure 48 on page 154 shows the syntax for
| declarations of numeric host variable arrays.
|

Chapter 9. Embedding SQL statements in host languages 153


C

|  float 
auto const unsigned double
extern volatile int
static long
short
int
long long
decimal ( integer )
, integer

  variable-name [ dimension ] ; 
,

= {  expression }

Figure 48. Numeric host variable arrays

| Note:
| 1. dimension must be an integer constant between 1 and 32767.

| Example: The following example shows a declaration of a numeric host variable


| array:
| EXEC SQL BEGIN DECLARE SECTION;
| /* declaration of numeric host variable array */
| long serial_num[10];
| ...
| EXEC SQL END DECLARE SECTION;

| Character host variable arrays: The three valid forms for character host variable
| arrays are:
| v NUL-terminated character form
| v VARCHAR structured form
| v CLOBs

| The following figures show the syntax for forms other than CLOBs. See Figure 53
| on page 158 for the syntax of CLOBs.

| Figure 49 on page 155 shows the syntax for declarations of NUL-terminated


| character host variable arrays.
|

154 Application Programming and SQL Guide


C

 char 
auto const unsigned
extern volatile
static

  variable-name [ dimension ] [ length ] ; 


,

= {  expression }

Figure 49. NUL-terminated character form

| Notes:
| 1. On input, the strings contained in the variable arrays must be NUL-terminated.
| 2. On output, the strings are NUL-terminated.
| 3. The strings in a NUL-terminated character host variable array map to
| varying-length character strings (except for the NUL).
| 4. dimension must be an integer constant between 1 and 32767.

| Figure 50 shows the syntax for declarations of varying-length character host


| variable arrays that use the VARCHAR structured form.
|

int
 struct { short var-1 ; 
auto const
extern volatile
static

 char var-2 [ length ] ; } 


unsigned

  variable-name [ dimension ] ; 
,

= {  expression }

Figure 50. VARCHAR structured form

| Notes:
| 1. var-1 must be a simple variable reference, and var-2 must be a variable array
| reference.
| 2. You can use the struct tag to define other data areas, which you cannot use as
| host variable arrays.
| 3. dimension must be an integer constant between 1 and 32767.

Chapter 9. Embedding SQL statements in host languages 155


C

| Example: The following examples show valid and invalid declarations of VARCHAR
| host variable arrays:
| EXEC SQL BEGIN DECLARE SECTION;
| /* valid declaration of VARCHAR host variable array */
| struct VARCHAR {
| short len;
| char s[18];
| } name[10];
|
| /* invalid declaration of VARCHAR host variable array */
| struct VARCHAR name[10];

| Graphic host variable arrays: The two valid forms for graphic host variable arrays
| are:
| v NUL-terminated graphic form
| v VARGRAPHIC structured form.

| You can use the C data type sqldbchar to define a host variable array that inserts,
| updates, deletes, and selects data from GRAPHIC or VARGRAPHIC columns.

| Figure 51 shows the syntax for declarations of NUL-terminated graphic host variable
| arrays.
|

 sqldbchar 
auto const unsigned
extern volatile
static

  variable-name [ dimension ] [ length ] ; 


,

= {  expression }

Figure 51. 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 strings contained in the variable arrays must be NUL-terminated.
| 3. On output, the string is NUL-terminated.
| 4. The NUL-terminated graphic form does not accept single-byte characters into
| the variable array.
| 5. dimension must be an integer constant between 1 and 32767.

| Figure 52 on page 157 shows the syntax for declarations of graphic host variable
| arrays that use the VARGRAPHIC structured form.
|

156 Application Programming and SQL Guide


C

int
 struct { short var-1 ; 
auto const
extern volatile
static

|  sqldbchar var-2 [ length ] ; } 


unsigned

  variable-name [ dimension ] ; 
,

= {  expression }

Figure 52. VARGRAPHIC structured form

| Notes:
| 1. length must be a decimal integer constant greater than 1 and not greater than
| 16352.
| 2. var-1 must be a simple variable reference, and var-2 must be a variable array
| reference.
| 3. You can use the struct tag to define other data areas, which you cannot use as
| host variable arrays.
| 4. dimension must be an integer constant between 1 and 32767.

| Example: The following examples show valid and invalid declarations of graphic
| host variable arrays that use the VARGRAPHIC structured form:
| EXEC SQL BEGIN DECLARE SECTION;
| /* valid declaration of host variable array vgraph */
| struct VARGRAPH {
| short len;
| sqldbchar d[10];
| } vgraph[20];
|
| /* invalid declaration of host variable array vgraph */
| struct VARGRAPH vgraph[20];

| LOB variable arrays and locators: Figure 53 on page 158 shows the syntax for
| declarations of BLOB, CLOB, and DBCLOB host variable arrays and locators. See
| Chapter 14, “Programming for large objects (LOBs),” on page 281 for a discussion
| of how to use LOB variables.
|

Chapter 9. Embedding SQL statements in host languages 157


C

 SQL TYPE IS 
auto const
extern volatile
static
register

 BINARY LARGE OBJECT ( length ) 


BLOB K
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB_LOCATOR
CLOB_LOCATOR
DBCLOB_LOCATOR

  variable-name [ dimension ] ; 
,

= {  expression }

Figure 53. LOB variable arrays and locators

| Note:
| 1. dimension must be an integer constant between 1 and 32767.

| ROWIDs: Figure 54 shows the syntax for declarations of ROWID variable arrays.
| See Chapter 14, “Programming for large objects (LOBs),” on page 281 for a
| discussion of how to use these host variable arrays.
|

 SQL TYPE IS ROWID  variable-name [ dimension ] ; 


auto const
extern volatile
static
register

Figure 54. ROWID variable arrays

| Note:
| 1. dimension must be an integer constant between 1 and 32767.

Using host structures


A C host structure contains an ordered group of data fields. For example:

158 Application Programming and SQL Guide


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.

Figure 55 shows the syntax for declarations of host structures.

 struct { 
auto const packed tag
extern volatile
static

  float var-1 ; } 
double
int
short
sqlint32
int
long
int
long long
decimal ( integer )
, integer
varchar structure
vargraphic structure
SQL TYPE IS ROWID
LOB data type
char var-2 ;
unsigned [ length ]
sqldbchar var-5 ;
[ length ]

 variable-name ; 
=expression

Figure 55. Host structures

Figure 56 on page 160 shows the syntax for VARCHAR structures that are used
within declarations of host structures.

Chapter 9. Embedding SQL statements in host languages 159


C

int
 struct { short var-3 ; 
tag signed

 char var-4 [ length ] ; } 


unsigned

Figure 56. VARCHAR-structure

Figure 57 shows the syntax for VARGRAPHIC structures that are used within
declarations of host structures.

| int
 struct { short var-6 ; sqldbchar var-7 [ length ] ; } 
tag signed

Figure 57. VARGRAPHIC-structure

Figure 58 shows the syntax for LOB data types that are used within declarations of
host structures.

 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 58. LOB data type

Determining equivalent SQL and C data types


Table 13 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 13. SQL data types the precompiler uses for C declarations
SQLTYPE of host SQLLEN of host
C data type variable variable SQL data type
short int 500 2 SMALLINT
long int 496 4 INTEGER
4
| long long 484 19 in byte 1, 0 in
byte 2
decimal(p,s)1 484 p in byte 1, s in DECIMAL(p,s)1
byte 2

160 Application Programming and SQL Guide


C

Table 13. SQL data types the precompiler uses for C declarations (continued)
SQLTYPE of host SQLLEN of host
C data type variable variable SQL data type
float 480 4 FLOAT (single
precision)
double 480 8 FLOAT (double
precision)
Single-character form 452 1 CHAR(1)
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 form 468 1 GRAPHIC(1)
NUL-terminated 400 n VARGRAPHIC (n-1)
graphic form
| (sqldbchar)
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 412 n DBCLOB(n)3
DBCLOB(n)
1≤n≤1073741823
SQL TYPE IS ROWID 904 40 ROWID

Chapter 9. Embedding SQL statements in host languages 161


C

Table 13. SQL data types the precompiler uses for C declarations (continued)
SQLTYPE of host SQLLEN of host
C data type variable variable SQL data type

Notes:
1. p is the precision; in SQL terminology, this the total number of digits. In C, this is called
the size.
s is the scale; in SQL terminology, this is the number of digits to the right of the decimal
point. In C, this is called the precision.
| C++ does not support the decimal data type.
2. Do not use this data type as a column type.
3. n is the number of double-byte characters.
4. No exact equivalent. Use DECIMAL(19,0).

Table 14 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 14 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 about
compatible data types.
Table 14. SQL data types mapped to typical C declarations
SQL data type C data type Notes
SMALLINT short int
INTEGER long int
DECIMAL(p,s) or decimal You can use the double data type if your C
NUMERIC(p,s) compiler does not have a decimal data
type; however, double is not an exact
equivalent.
REAL or FLOAT(n) float 1<=n<=21
DOUBLE PRECISION or double 22<=n<=53
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.

162 Application Programming and SQL Guide


C

Table 14. SQL data types mapped to typical C declarations (continued)


SQL data type C data type Notes
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.
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 RESULT_SET_LOCATOR Use this data type only for receiving result
sets. Do not use this data type as a
column type.
Table locator SQL TYPE IS TABLE LIKE table-name AS Use this data type only in a user-defined
LOCATOR function or stored procedure to receive
rows of a transition table. Do not use this
data type as a column type.
BLOB locator SQL TYPE IS BLOB_LOCATOR Use this data type only to manipulate data
in BLOB columns. Do not use this data
type as a column type.
CLOB locator SQL TYPE IS CLOB_LOCATOR Use this data type only to manipulate data
in CLOB columns. Do not use this data
type as a column type.
DBCLOB locator SQL TYPE IS DBCLOB_LOCATOR Use this data type only to manipulate data
in DBCLOB columns. Do not use this data
type as a column type.
BLOB(n) SQL TYPE IS BLOB(n) 1≤n≤2147483647
CLOB(n) SQL TYPE IS CLOB(n) 1≤n≤2147483647

Chapter 9. Embedding SQL statements in host languages 163


C

Table 14. SQL data types mapped to typical C declarations (continued)


SQL data type C data type Notes
DBCLOB(n SQL TYPE IS DBCLOB(n) n is the number of double-byte characters.
1≤n≤1073741823
ROWID SQL TYPE IS ROWID

Notes on C variable declaration and usage


You should be aware of the following considerations when you declare C variables.

C data types with no SQL equivalent: C supports some data types and storage
| classes with no SQL equivalents, for example, register storage class, typedef, long
| long, and the pointer.

SQL data types with no C equivalent: If your C compiler does not have a decimal
data type, no exact equivalent exists for the SQL DECIMAL data type. In this case,
to hold the value of such a variable, you can use:
v An integer or floating-point variable, which converts the value. If you choose
integer, you will lose the fractional part of the number. If the decimal number can
exceed the maximum value for an integer, or if you want to preserve a fractional
value, you can use floating-point numbers. Floating-point numbers are
approximations of real numbers. Therefore, when you assign a decimal number
to a floating-point variable, the result might be different from the original number.
v A character-string host variable. Use the CHAR function to get a string
representation of a decimal number.
v The DECIMAL function to explicitly convert a value to a decimal data type, as in
this example:
long duration=10100; /* 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 hexadecimal floating-point format. However, your host variable data can
| be in System/390 hexadecimal floating-point format or IEEE binary floating-point
format. DB2 uses the FLOAT precompiler option to determine whether your
| floating-point host variables are in IEEE binary floating-point or System/390
| hexadecimal floating-point format. DB2 does no checking to determine whether the
contents of a host variable match the precompiler option. Therefore, you need to
ensure that your floating-point data format matches the precompiler option.

Graphic host variables in user-defined function: The SQLUDF file, which is in


data set DSN810.SDSNC.H, contains many data declarations for C language
| user-defined functions. SQLUDF contains the typedef sqldbchar, which you should
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 and SQL
data types. You cannot use locators as column types. For information about how to
use these data types, see the following sections:

164 Application Programming and SQL Guide


C

Result set locator


Chapter 25, “Using stored procedures for client/server processing,”
on page 569
Table locator “Accessing transition tables in a user-defined function or stored
procedure” on page 328
LOB locators Chapter 14, “Programming for large objects (LOBs),” on page 281

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, DB2 inserts the characters into the host variable up to a
length of (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, DB2 inserts the characters into the host variable and appends a
NUL at the end of the string.
| v Greater than n+1, the rules depend on whether the source string is a value of a
| fixed-length string column or a varying-length string column. If the source is a
| fixed-length string, DB2 pads it with blanks on assignment to the NUL-terminated
| variable depending on whether the precompiler option PADNTSTR is specified. If
| the source is a varying-length string, DB2 assigns it to the first n bytes of the
| variable and appends a NUL at the end of the string. For information about host
| language precompiler options, see Table 63 on page 462.

PREPARE or DESCRIBE statements: You cannot use a host variable that is of the
| NUL-terminated form in either a PREPARE or DESCRIBE statement when you use
| the DB2 precompiler. However, if you use the SQL statement coprocessor for either
| C or C++, you can use host variables of the NUL-terminated form in PREPARE,
| DESCRIBE, and EXECUTE IMMEDIATE statements.

L-literals: DB2 tolerates L-literals in C application programs. DB2 allows properly


formed L-literals, although it does not check for all the restrictions that the C
compiler imposes on the L-literal. You can use DB2 graphic string constants in SQL
statements to work with the L-literal. Do not use L-literals in SQL statements.

Overflow: Be careful of overflow. For example, suppose you retrieve an INTEGER


column value into a short integer host variable and the column value is larger than
32767. You get an overflow warning or an error, depending on whether you provide
an indicator variable.

Truncation: Be careful of truncation. Ensure that the host variable you declare can
contain the data and a NUL terminator, if needed. Retrieving a floating-point or
decimal column value into a long integer host variable removes any fractional part
of the value.

Notes on syntax differences for constants


You should be aware of the following syntax differences for constants.

Decimal constants versus real constants: In C, a string of digits with a decimal


point is interpreted as a real constant. In an SQL statement, such a string is
interpreted as a decimal constant. You must use exponential notation when
specifying a real (that is, floating-point) constant in an SQL statement.

Chapter 9. Embedding SQL statements in host languages 165


C

In C, a real (floating-point) constant can have a suffix of f or F to show a data type


of float or a suffix of l or L to show a type of long double. A floating-point constant in
an SQL statement must not use these suffixes.

Integer constants: In C, you can provide integer constants in hexadecimal form if


the first two characters are 0x or 0X. You cannot use this form in an SQL statement.

In C, an integer constant can have a suffix of u or U to show that it is an unsigned


integer. An integer constant can have a suffix of l or L to show a long integer. You
cannot use these suffixes in SQL statements.

Character and string constants: In C, character constants and string constants


can use escape sequences. You cannot use the escape sequences in SQL
statements. Apostrophes and quotes have different meanings in C and SQL. In C,
you can use double 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 double 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:
v Numeric data types are compatible with each other. A SMALLINT, INTEGER,
DECIMAL, or FLOAT column is compatible with any C host variable that is
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.

166 Application Programming and SQL Guide


C

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 variable. 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 about
assigning and comparing distinct types, see Chapter 16, “Creating and using
distinct types,” on page 349.

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
other functions process strings that are not NUL-terminated. The C string
manipulation functions that process NUL-terminated strings cannot handle bit data
because these functions might misinterpret a NUL character to be a NUL-terminator.

Using indicator variables and indicator variable arrays


| An indicator variable is a 2-byte integer (short int). An indicator variable array is an
| array of 2-byte integers (short int). You use indicator variables and indicator variable
| arrays in similar ways.

Using indicator variables: If you provide an indicator variable for the variable X,
when DB2 retrieves a null value for X, it puts a negative value in the indicator
variable and does not update X. Your program should check the indicator variable
before using X. If the indicator variable is negative, you know that X is null and any
value you find in X is irrelevant.

When your program uses X to assign a null value to a column, the program should
set the indicator variable to a negative number. DB2 then assigns a null value to the
column and ignores any value in X. For more information about indicator variables,
see “Using indicator variables with host variables” on page 75.

Chapter 9. Embedding SQL statements in host languages 167


C

| Using indicator variable arrays: When you retrieve data into a host variable array,
| if a value in its indicator array is negative, you can disregard the contents of the
| corresponding element in the host variable array. For more information about
| indicator variable arrays, see “Using indicator variable arrays with host variable
| arrays” on page 79.

Declaring indicator variables: You declare indicator variables in the same way as
host variables. You can mix the declarations of the two types of variables in any
way that seems appropriate.

Example: The following example shows a FETCH statement with the declarations
of the host variables that are needed for the FETCH statement:
EXEC SQL FETCH CLS_CURSOR INTO :ClsCd,
:Day :DayInd,
:Bgn :BgnInd,
:End :EndInd;

You can declare variables as follows:


EXEC SQL BEGIN DECLARE SECTION;
char ClsCd[8];
char Bgn[9];
char End[9];
short Day, DayInd, BgnInd, EndInd;
EXEC SQL END DECLARE SECTION;

Figure 59 shows the syntax for declarations of an indicator variable.

,
int
 short  variable-name ; 
auto const signed = expression
extern volatile
static

Figure 59. Indicator variable

Declaring indicator variable arrays: Figure 60 shows the syntax for declarations
| of an indicator array or a host structure indicator array.

int
 short 
auto const signed
extern volatile
static

  variable-name [ dimension ] ; 
= expression

Figure 60. Host structure indicator array

Note: The dimension must be an integer constant between 1 and 32767.

168 Application Programming and SQL Guide


C

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 about the behavior of DSNTIAR, see
“Calling DSNTIAR to display SQLCA fields” on page 89.

| You can also use the MESSAGE_TEXT condition item field of the GET
| DIAGNOSTICS statement to convert an SQL return code into a text message.
| Programs that require long token message support should code the GET
| DIAGNOSTICS statement instead of DSNTIAR. For more information about GET
| DIAGNOSTICS, see “Using the GET DIAGNOSTICS statement” on page 84.

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 the length of each
line.
&lrecl
A fullword containing the logical record length of output messages, between 72
and 240.

To inform your compiler that DSNTIAR is an assembler language program, include


one of the following statements in your application.

For C, include:
#pragma linkage (dsntiar,OS)

For C++, include a statement similar to this:


extern "OS" short int dsntiar(struct sqlca *sqlca,
struct error_struct *error_message,
int *data_len);

Chapter 9. Embedding SQL statements in host languages 169


C

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 DSN8810.SDSNSAMP. See Appendix B, “Sample applications,” on page 915
for instructions on how to access and print the source code for the sample
programs.

CICS
If your CICS application requires CICS storage handling, you must use the
subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax:
rc = DSNTIAC(&eib, &commarea, &sqlca, &message, &lrecl);

DSNTIAC has extra parameters, which you must use for calls to routines that
use CICS commands.
&eib EXEC interface block
&commarea
communication area

For more information on these parameters, see the appropriate application


programming guide for CICS. The remaining parameter descriptions are the
same as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the
SQLCA in the same way.

You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you
must also define them in the CSD. For an example of CSD entry generation
statements for use with DSNTIAC, see job DSNTEJ5A.

The assembler source code for DSNTIAC and job DSNTEJ5A, which
assembles and link-edits DSNTIAC, are in the data set prefix.SDSNSAMP.

Coding considerations for C and C++


Using C++ data types as host variables: When you code SQL statements in a
C++ program, you can use class members as host variables. Class members used
as host variables are accessible to any SQL statement within the class. However,
you cannot use class objects as host variables.

| Declaring host variable arrays: For both C and C++, you cannot specify the
| _packed attribute on the structure declarations for varying-length character arrays,
| varying-length graphic arrays, or LOB arrays that are to be used in multiple-row
| INSERT and FETCH statements. In addition, the #pragma pack(1) directive cannot
| be in effect if you plan to use these arrays in multiple-row statements.

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 UDB for z/OS.

Defining the SQL communication area


A COBOL program that contains SQL statements must include one or both of the
following host variables:

170 Application Programming and SQL Guide


COBOL

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)
Alternatively, you can include 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 values to determine whether the last SQL
statement was successful. All SQL statements in the program must be within the
scope of the declaration of the SQLCODE and SQLSTATE variables.

Whether you define the SQLCODE or SQLSTATE variable or an SQLCA in your


program depends on whether you specify the precompiler option STDSQL(YES) to
conform to 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 the structure and location of the
SQLCA.

If you declare an SQLSTATE variable, it must not be an element of a structure. You


must declare the SQLCODE and SQLSTATE variables within the BEGIN DECLARE
SECTION and END DECLARE SECTION statements 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.

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

Chapter 9. Embedding SQL statements in host languages 171


COBOL

v OPEN ... USING DESCRIPTOR descriptor-name


v PREPARE ... INTO descriptor-name

Unlike the SQLCA, a program can have more than one SQLDA, and an SQLDA
can have any valid name. The 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 568. 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 compiler, you can call a subroutine
(written in C, PL/I, or assembler language) that uses the INCLUDE SQLDA
statement to define the SQLDA. The subroutine can also include SQL statements
for any dynamic SQL functions you need. For more information on using dynamic
SQL, see Chapter 24, “Coding dynamic SQL in application programs,” on page
535.

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 15.
Table 15. Allowable SQL statements for COBOL program sections
SQL statement Program section
BEGIN DECLARE SECTION WORKING-STORAGE SECTION or LINKAGE
END DECLARE SECTION 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

Notes:
1. 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, omit 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:

172 Application Programming and SQL Guide


COBOL

EXEC SQL
UPDATE DSN8810.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 on the same line as END-EXEC, as a
comment.

| In addition, you can include SQL comments in any embedded SQL statement.

Continuation for SQL statements: The rules for continuing a character string
constant from one line to the next in an SQL statement embedded in a COBOL
program are the same as those for continuing a non-numeric literal in COBOL.
However, you can use either a quote or an apostrophe as the first nonblank
character in area B of the continuation line. The same rule applies for the
continuation of delimited identifiers and does not depend on the string delimiter
option.

To conform with SQL standard, delimit a character string constant with an


apostrophe, and use a quote as the first nonblank character in area B of the
continuation line for a character string constant.

Declaring tables and views: Your COBOL program should include the statement
DECLARE TABLE to describe each table and view the program accesses. You can
use the DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE
statements. You should include the DCLGEN members in the DATA DIVISION. For
more information, see Chapter 8, “Generating declarations for your tables using
DCLGEN,” on page 121.

Dynamic SQL in a COBOL program: In general, COBOL programs can easily


handle dynamic SQL statements. COBOL programs can handle SELECT
statements if the data types and the number of fields returned are fixed. If you want
to use variable-list SELECT statements, use an SQLDA. See “Defining SQL
descriptor areas” on page 171 for more information on SQLDA.

Including code: To include SQL statements or COBOL host variable declarations


from a member of a partitioned data set, use the following SQL statement in the
source code where you want to include the statements:
EXEC SQL INCLUDE member-name END-EXEC.

If you are using the DB2 precompiler, you cannot nest SQL INCLUDE statements.
In this case, do not use COBOL verbs to include SQL statements or host variable
declarations, and do not use the SQL INCLUDE statement to include CICS
preprocessor related code. In general, if you are using the DB2 precompiler, use
the SQL INCLUDE statement only for SQL-related coding. If you are using the
COBOL SQL coprocessor, none of these restrictions apply.

Margins: You must code EXEC SQL in columns 12 through 72, otherwise the DB2
precompiler does not recognize the SQL statement. Continued lines of a SQL
statement can be in columns 8 through 72.

Chapter 9. Embedding SQL statements in host languages 173


COBOL

Names: You can use any valid COBOL name for a host variable. Do not use
external entry names or access plan names that begin with ’DSN’, and do not use
host variable names that begin with ’SQL’. These names are reserved for DB2.

Sequence numbers: The source statements that the DB2 precompiler generates
do not include sequence numbers.

Statement labels: You can precede executable SQL statements in the


PROCEDURE DIVISION with a paragraph name, if you wish.

WHENEVER statement: The target for the GOTO clause in an SQL statement
WHENEVER must be a section name or unqualified paragraph name in the
PROCEDURE DIVISION.

Special COBOL considerations: The following considerations apply to programs


written in COBOL:
v In a COBOL program that uses elements in a multi-level structure as host
variable names, the DB2 precompiler generates the lowest two-level names. If
you then compile the COBOL program using OS/VS COBOL, the compiler issues
messages IKF3002I and IKF3004I. If you are using a VS COBOL II or later
compiler, you can eliminate these messages.
v Using the COBOL compiler options DYNAM and NODYNAM depends on the
operating environment.

TSO and IMS


You can specify the option DYNAM when compiling a COBOL program if
you use the following guidelines. IMS and DB2 share a common alias
name, DSNHLI, for the language interface module. You must do the
following when you concatenate your libraries:
– If you use IMS with the COBOL option DYNAM, be sure to concatenate
the IMS library first.
– If you run your application program only under DB2, be sure to
concatenate the DB2 library first.

CICS 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, use either of the following methods:


– Use the COMP-5 data type for binary integer host variables.
– 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 is defined
in the PICTURE clause of the binary variable.
- TRUNC(BIN) if the precision of data being moved to each binary variable
might exceed the value in the PICTURE clause.
DB2 assigns values to binary integer host variables as if you had specified the
COBOL compiler option TRUNC(BIN) or used the COMP-5 data type.

174 Application Programming and SQL Guide


COBOL

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 If you use the DB2 precompiler, the REPLACE statement has no effect on SQL
| statements. It affects only the COBOL statements that the precompiler generates.
| If you use the SQL statement coprocessor, the REPLACE statement replaces
| text strings in SQL statements as well as in generated COBOL statements.
| v If you use the DB2 precompiler, no compiler directives should appear between
| the PROCEDURE DIVISION and the DECLARATIVES statement.
v Do not use COBOL figurative constants (such as ZERO and SPACE), symbolic
characters, reference modification, and subscripts within SQL statements.
v Observe the rules 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.
– 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, the COBOL compiler returns
the warning message IGYOP3094. That message might indicate a problem. This
usage is not recommended.
v If you are using the DB2 precompiler and VS COBOL II or later (with the
compiler option NOCMPR2), 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 contain SQL statements.

If you pass host variables with address changes into a program more than once,
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.

If you use the COBOL SQL statement coprocessor, the called program does not
need to reset SQL-INIT-FLAG.

| Using host variables and host variable arrays


| You must explicitly declare all host variables and host variable arrays used in SQL
| statements in the WORKING-STORAGE SECTION or LINKAGE SECTION of your

Chapter 9. Embedding SQL statements in host languages 175


COBOL

| program’s DATA DIVISION. You must explicitly declare each host variable and host
| variable array before using them in an SQL statement.

| You can precede COBOL statements that define the host variables and host
| variable arrays 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 and all host variable arrays in an SQL
| statement.

| The names of host variables and host variable arrays should be unique within the
| source data set or member, even if the variables and variable arrays are in different
| blocks, classes, or procedures. You can qualify the names with a structure name to
| make them unique.

| An SQL statement that uses a host variable or host variable array must be within
| the scope of the statement that declares that variable or array. You define host
| variable arrays for use with multiple-row FETCH and INSERT statements.

| You can specify OCCURS when defining an indicator structure, a host variable
| array, or an indicator variable array. You cannot specify OCCURS for any other type
| of host variable.

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 three valid forms of numeric host variables are:
v Floating-point numbers
v Integers and small integers
v Decimal numbers

Figure 61 shows the syntax for declarations of floating-point or real host variables.

 01 variable-name COMPUTATIONAL-1 
77 IS COMP-1
level-1 USAGE COMPUTATIONAL-2
COMP-2

 . 
IS
VALUE numeric-constant

Figure 61. Floating-point 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.

176 Application Programming and SQL Guide


COBOL

Figure 62 shows the syntax for declarations of integer and small integer host
variables.

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 62. Integer and small integer host variables

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. The COBOL binary integer data types BINARY, COMPUTATIONAL, COMP,
COMPUTATIONAL-4, and COMP-4 are equivalent.
3. COMPUTATIONAL-5 (and COMP-5) are equivalent to the other COBOL binary
integer data types if you compile the other data types with TRUNC(BIN).
4. Any specification for scale is ignored.

Figure 63 shows the syntax for declarations of decimal host variables.

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 63. Decimal host variables

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. PACKED-DECIMAL, COMPUTATIONAL-3, and COMP-3 are equivalent. The
picture-string that is that is associated with these types must have the form
S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9) or S9(i)V.

Chapter 9. Embedding SQL statements in host languages 177


COBOL

3. The picture-string that is associated with SIGN LEADING SEPARATE must have
the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9 or S9...9V with i
instances of 9).

Character host variables: The three valid forms of character host variables are:
v Fixed-length strings
v Varying-length strings
v CLOBs

The following figures show the syntax for forms other than CLOBs. See Figure 70
on page 182 for the syntax of CLOBs.

Figure 64 shows the syntax for declarations of fixed-length character host variables.

IS
 01 variable-name PICTURE picture-string 
77 PIC
level-1

 . 
DISPLAY IS
IS VALUE character-constant
USAGE

Figure 64. Fixed-length character strings

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
| 2. The picture-string that is associated with these forms must be X(m) (or XX...X,
| with m instances of X), with 1 <= m <= 32767 for fixed-length strings. However,
| the maximum length of the CHAR data type (fixed-length character string) in
| DB2 is 255 bytes.

Figure 65 on page 179 shows the syntax for declarations of varying-length


character host variables.

178 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
COMPUTATIONAL
COMP

 . 
IS
VALUE numeric-constant

IS
 49 var-2 PICTURE picture-string 
PIC DISPLAY
IS
USAGE

 . 
IS
VALUE character-constant

Figure 65. Varying-length character strings

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL with
TRUNC(STD) only recognizes values up to 9999. This can cause data
truncation errors when COBOL statements execute and might effectively limit
the maximum length of variable-length character strings to 9999. Consider using
the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation.
3. For fixed-length strings, the picture-string must be X(m) (or XX...X, with m
instances of X), with 1 <= m <= 32767; for other strings, m cannot be greater
than the maximum size of a varying-length character string.
4. You cannot directly reference var-1 and var-2 as host variables.
5. You cannot use an intervening REDEFINE at level 49.

Graphic character host variables: The three valid forms for graphic character host
variables are:
v Fixed-length strings
v Varying-length strings
v DBCLOBs

The following figures show the syntax for forms other than DBCLOBs. See
Figure 70 on page 182 for the syntax of DBCLOBs.

Chapter 9. Embedding SQL statements in host languages 179


COBOL

Figure 66 shows the syntax for declarations of fixed-length graphic host variables.

IS
 01 variable-name PICTURE picture-string 
77 PIC
level-1

 DISPLAY-1 . 
IS NATIONAL IS
USAGE VALUE graphic-constant

Figure 66. Fixed-length graphic strings

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
3. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the SQL statement coprocessor.

Figure 67 on page 181 shows the syntax for declarations of varying-length graphic
host variables.

180 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
COMPUTATIONAL
COMP

 . 
IS
VALUE numeric-constant

IS
 49 var-2 PICTURE picture-string DISPLAY-1 
PIC IS NATIONAL
USAGE

 . 
IS
VALUE graphic-constant

Figure 67. Varying-length graphic strings

Notes:
1. level-1 indicates a COBOL level between 2 and 48.
2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL with
TRUNC(STD) only recognizes values up to 9999. This can cause data
truncation errors when COBOL statements execute and might effectively limit
the maximum length of variable-length character strings to 9999. Consider using
the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation.
3. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
4. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the SQL statement coprocessor.
5. You cannot directly reference var-1 and var-2 as host variables.

Result set locators: Figure 68 on page 182 shows the syntax for declarations of
result set locators. See Chapter 25, “Using stored procedures for client/server
processing,” on page 569 for a discussion of how to use these host variables.

Chapter 9. Embedding SQL statements in host languages 181


COBOL

 01 variable-name SQL TYPE IS RESULT-SET-LOCATOR VARYING . 


IS
USAGE

Figure 68. Result set locators

Table Locators: Figure 69 shows the syntax for declarations of table locators. See
“Accessing transition tables in a user-defined function or stored procedure” on page
328 for a discussion of how to use these host variables.

 01 variable-name SQL TYPE IS TABLE LIKE table-name AS LOCATOR . 


level-1 IS
USAGE

Figure 69. Table locators

Note: level-1 indicates a COBOL level between 2 and 48.

LOB Variables and Locators: Figure 70 shows the syntax for declarations of
BLOB, CLOB, and DBCLOB host variables and locators. See Chapter 14,
“Programming for large objects (LOBs),” on page 281 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 70. LOB variables and locators

Note: level-1 indicates a COBOL level between 2 and 48.

ROWIDs: Figure 71 shows the syntax for declarations of ROWID host variables.
See Chapter 14, “Programming for large objects (LOBs),” on page 281 for a
discussion of how to use these host variables.

 01 variable-name SQL TYPE IS ROWID . 


level-1 IS
USAGE

Figure 71. ROWID variables

182 Application Programming and SQL Guide


COBOL

Note: level-1 indicates a COBOL level between 2 and 48.

| Declaring host variable arrays


| Only some of the valid COBOL declarations are valid host variable array
| declarations. If the declaration for a variable array is not valid, any SQL statement
| that references the variable array might result in the message UNDECLARED
| HOST VARIABLE ARRAY.

| Numeric host variable arrays: The three valid forms of numeric host variable
| arrays are:
| v Floating-point numbers
| v Integers and small integers
| v Decimal numbers

| Figure 72 shows the syntax for declarations of floating-point host variable arrays.
|

 level-1 variable-name COMPUTATIONAL-1 OCCURS dimension 


IS COMP-1 TIMES
USAGE COMPUTATIONAL-2
COMP-2

 . 
IS
VALUE numeric-constant

Figure 72. Floating-point host variable arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. COMPUTATIONAL-1 and COMP-1 are equivalent.
| 3. COMPUTATIONAL-2 and COMP-2 are equivalent.
| 4. dimension must be an integer constant between 1 and 32767.

| Figure 73 on page 184 shows the syntax for declarations of integer and small
| integer host variable arrays.
|

Chapter 9. Embedding SQL statements in host languages 183


COBOL

IS
 level-1 variable-name PICTURE S9(4) 
PIC S9999 IS
S9(9) USAGE
S999999999

 BINARY OCCURS dimension . 


COMPUTATIONAL-4 TIMES IS
COMP-4 VALUE numeric-constant
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

Figure 73. Integer and small integer host variable arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. The COBOL binary integer data types BINARY, COMPUTATIONAL, COMP,
| COMPUTATIONAL-4, and COMP-4 are equivalent.
| 3. COMPUTATIONAL-5 (and COMP-5) are equivalent to the other COBOL binary
| integer data types if you compile the other data types with TRUNC(BIN).
| 4. Any specification for scale is ignored.
| 5. dimension must be an integer constant between 1 and 32767.

| Figure 74 shows the syntax for declarations of decimal host variable arrays.
|

IS
 level-1 variable-name PICTURE picture-string 
PIC IS
USAGE

 PACKED-DECIMAL 
COMPUTATIONAL-3
COMP-3
IS CHARACTER
DISPLAY SIGN LEADING SEPARATE

 OCCURS dimension . 
TIMES IS
VALUE numeric-constant

Figure 74. Decimal host variable arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. PACKED-DECIMAL, COMPUTATIONAL-3, and COMP-3 are equivalent. The
| picture-string that is 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.

184 Application Programming and SQL Guide


COBOL

| 3. The picture-string that is associated with SIGN LEADING SEPARATE must have
| the form S9(i)V9(d) (or S9...9V9...9, with i and d instances of 9 or S9...9V with i
| instances of 9).
| 4. dimension must be an integer constant between 1 and 32767.

| Character host variable arrays: The three valid forms of character host variable
| arrays are:
| v Fixed-length character strings
| v Varying-length character strings
| v CLOBs

| The following figures show the syntax for forms other than CLOBs. See Figure 79
| on page 189 for the syntax of CLOBs.

| Figure 75 shows the syntax for declarations of fixed-length character string arrays.
|

IS
 level-1 variable-name PICTURE picture-string 
PIC DISPLAY
IS
USAGE

 OCCURS dimension . 
TIMES IS
VALUE character-constant

Figure 75. Fixed-length character string arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. The picture-string that is associated with these forms must be X(m) (or XX...X,
| with m instances of X), with 1 <= m <= 32767 for fixed-length strings. However,
| the maximum length of the CHAR data type (fixed-length character string) in
| DB2 is 255 bytes.
| 3. dimension must be an integer constant between 1 and 32767.

| Figure 76 on page 186 shows the syntax for declarations of varying-length


| character string arrays.
|

Chapter 9. Embedding SQL statements in host languages 185


COBOL

 level-1 variable-name OCCURS dimension . 


TIMES

IS
 49 var-1 PICTURE S9(4) BINARY 
PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

 SYNCHRONIZED . 
SYNC IS
VALUE numeric-constant

IS
 49 var-2 PICTURE picture-string 
PIC DISPLAY
IS
USAGE

 . 
IS
VALUE character-constant

Figure 76. Varying-length character string arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL with
| TRUNC(STD) recognizes only values up to 9999. This can cause data
| truncation errors when COBOL statements execute and might effectively limit
| the maximum length of variable-length character strings to 9999. Consider using
| the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation.
| 3. The picture-string that is associated with these forms must be X(m) (or XX...X,
| with m instances of X), with 1 <= m <= 32767 for fixed-length strings; for other
| strings, m cannot be greater than the maximum size of a varying-length
| character string.
| 4. You cannot directly reference var-1 and var-2 as host variable arrays.
| 5. You cannot use an intervening REDEFINE at level 49.
| 6. dimension must be an integer constant between 1 and 32767.

| Example: The following example shows declarations of a fixed-length character


| array and a varying-length character array:
| 01 OUTPUT-VARS.
| 05 NAME OCCURS 10 TIMES.
| 49 NAME-LEN PIC S9(4) COMP-4 SYNC.
| 49 NAME-DATA PIC X(40).
| 05 SERIAL-NUMBER PIC S9(9) COMP-4 OCCURS 10 TIMES.

186 Application Programming and SQL Guide


COBOL

| Graphic character host variable arrays: The three valid forms for graphic
| character host variable arrays are:
| v Fixed-length strings
| v Varying-length strings
| v DBCLOBs

| The following figures show the syntax for forms other than DBCLOBs. See
| Figure 79 on page 189 for the syntax of DBCLOBs.

| Figure 77 shows the syntax for declarations of fixed-length graphic string arrays.
|

IS IS
 level-1 variable-name PICTURE picture-string USAGE DISPLAY-1 
PIC NATIONAL

 OCCURS dimension . 
TIMES IS
VALUE graphic-constant

Figure 77. Fixed-length graphic string arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
| GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
| than the maximum size of a varying-length graphic string.
| 3. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
| USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
| supported only through the SQL statement coprocessor.
| 4. dimension must be an integer constant between 1 and 32767.

| Figure 78 on page 188 shows the syntax for declarations of varying-length graphic
| string arrays.
|

Chapter 9. Embedding SQL statements in host languages 187


COBOL

 level-1 variable-name OCCURS dimension . 


TIMES

IS
 49 var-1 PICTURE S9(4) BINARY 
PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

 SYNCHRONIZED . 
SYNC IS
VALUE numeric-constant

IS IS
 49 var-2 PICTURE picture-string USAGE DISPLAY-1 
PIC NATIONAL

 . 
IS
VALUE graphic-constant

Figure 78. Varying-length graphic string arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. DB2 uses the full length of the S9(4) BINARY variable even though COBOL with
| TRUNC(STD) recognizes only values up to 9999. This can cause data
| truncation errors when COBOL statements execute and might effectively limit
| the maximum length of variable-length character strings to 9999. Consider using
| the TRUNC(BIN) compiler option or USAGE COMP-5 to avoid data truncation.
| 3. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
| GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
| than the maximum size of a varying-length graphic string.
| 4. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
| USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
| supported only through the SQL statement coprocessor.
| 5. You cannot directly reference var-1 and var-2 as host variable arrays.
| 6. dimension must be an integer constant between 1 and 32767.

| LOB variable arrays and locators: Figure 79 on page 189 shows the syntax for
| declarations of BLOB, CLOB, and DBCLOB host variable arrays and locators. See
| Chapter 14, “Programming for large objects (LOBs),” on page 281 for a discussion
| of how to use LOB variables.
|

188 Application Programming and SQL Guide


COBOL

 level-1 variable-name SQL TYPE IS 


IS
USAGE

 BINARY LARGE OBJECT ( length ) OCCURS dimension . 


BLOB K TIMES
CHARACTER LARGE OBJECT M
CHAR LARGE OBJECT G
CLOB
DBCLOB
BLOB LOCATOR
CLOB LOCATOR
DBCLOB LOCATOR

Figure 79. LOB variable arrays and locators

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. dimension must be an integer constant between 1 and 32767.

| ROWIDs: Figure 80 shows the syntax for declarations of ROWID variable arrays.
| See Chapter 14, “Programming for large objects (LOBs),” on page 281 for a
| discussion of how to use these host variables.
|

 level-1 variable-name SQL TYPE IS ROWID OCCURS dimension . 


IS TIMES
USAGE

Figure 80. ROWID variable arrays

| Notes:
| 1. level-1 indicates a COBOL level between 2 and 48.
| 2. dimension must be an integer constant between 1 and 32767.

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.

Chapter 9. Embedding SQL statements in host languages 189


COBOL

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 preceding items in a host structure, it
considers the structure to be complete.

Figure 81 shows the syntax for declarations of host structures.

 level-1 variable-name . 

  level-2 var-1 numeric-usage . 


IS
PICTURE integer-decimal-usage .
PIC picture-string
char-inner-variable .
varchar-inner-variables
vargraphic-inner-variables
SQL TYPE IS ROWID .
IS
USAGE
SQL TYPE IS TABLE LIKE table-name AS LOCATOR .
IS
USAGE
LOB data type .
IS
USAGE

Figure 81. Host structures in COBOL

Figure 82 shows the syntax for numeric-usage items that are used within
declarations of host structures.

 COMPUTATIONAL-1 
IS COMP-1 IS
USAGE COMPUTATIONAL-2 VALUE constant
COMP-2

Figure 82. Numeric-usage

Figure 83 on page 191 shows the syntax for integer and decimal usage items that
are used within declarations of host structures.

190 Application Programming and SQL Guide


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 83. Integer-decimal-usage

Figure 84 shows the syntax for CHAR inner variables that are used within
declarations of host structures.

IS
 PICTURE picture-string 
PIC DISPLAY
IS
USAGE

 
IS
VALUE constant

Figure 84. CHAR-inner-variable

Figure 85 on page 192 shows the syntax for VARCHAR inner variables that are
used within declarations of host structures.

Chapter 9. Embedding SQL statements in host languages 191


COBOL

IS
 49 var-2 PICTURE S9(4) BINARY 
PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

 . 
IS
VALUE numeric-constant

IS
 49 var-3 PICTURE picture-string 
PIC DISPLAY
IS
USAGE

 . 
IS
VALUE character-constant

Figure 85. VARCHAR-inner-variables

Figure 86 on page 193 shows the syntax for VARGRAPHIC inner variables that are
used within declarations of host structures.

192 Application Programming and SQL Guide


COBOL

IS
 49 var-4 PICTURE S9(4) BINARY 
PIC S9999 IS COMPUTATIONAL-4
USAGE COMP-4
COMPUTATIONAL-5
COMP-5
COMPUTATIONAL
COMP

 . 
IS
VALUE numeric-constant

IS
 49 var-5 PICTURE picture-string DISPLAY-1 
PIC IS NATIONAL
USAGE

 . 
IS
VALUE graphic-constant

Figure 86. VARGRAPHIC-inner-variables

Notes:
1. For fixed-length strings, the picture-string is G(m) or N(m) (or, m instances of
GG...G or NN...N), with 1 <= m <= 127; for other strings, m cannot be greater
than the maximum size of a varying-length graphic string.
2. Use USAGE NATIONAL only for Unicode UTF-16 data. In the picture-string for
USAGE NATIONAL, you must use N in place of G. USAGE NATIONAL is
supported only through the SQL statement coprocessor.

Figure 87 shows the syntax for LOB variables and locators that are used within
declarations of host struc